Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

전남대 Android_최영빈_6주차 과제_step1 #63

Open
wants to merge 4 commits into
base: yb0x00
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
# android-map-notification

### 구현할 기능 목록
- 서비스 상태를 나타내는 매개변수를 Firebase의 Remote Config에 등록
- serviceState 값이 ON_SERVICE일 때만 초기 진입 화면이 지도 화면으로 넘어감
- serviceState 값이 ON_SERVICE이 아닌 경우에는 serviceMessage 값을 초기 진입 화면 하단에 표시하고 지도 화면으로 진입하지 않음
15 changes: 15 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties

plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
Expand All @@ -13,13 +15,24 @@ android {
compileSdk = 34

defaultConfig {

ndk {
abiFilters.add("arm64-v8a")
abiFilters.add("armeabi-v7a")
abiFilters.add("x86")
abiFilters.add("x86_64")
}

applicationId = "campus.tech.kakao.map"
minSdk = 26
targetSdk = 34
versionCode = 1
versionName = "1.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

resValue("string", "kakao_api_key", getApiKey("KAKAO_API_KEY"))
buildConfigField("String", "KAKAO_REST_API_KEY", getApiKey("KAKAO_REST_API_KEY"))
}

buildTypes {
Expand All @@ -45,6 +58,8 @@ android {
}
}

fun getApiKey(key: String): String = gradleLocalProperties(rootDir, providers).getProperty(key)

dependencies {

implementation("androidx.core:core-ktx:1.13.1")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package campus.tech.kakao.map

import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.closeSoftKeyboard
import androidx.test.espresso.action.ViewActions.replaceText
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.ext.junit.rules.ActivityScenarioRule
import campus.tech.kakao.map.view.DataSearchActivity
import org.junit.Rule
import org.junit.Test


class DataSearchActivityTest {
@get:Rule
val activityRule = ActivityScenarioRule(DataSearchActivity::class.java)

@Test
fun 검색어_입력시_검색_결과가_나타남() {
onView(withId(R.id.searchBar))
.perform(replaceText("전남대학교"), closeSoftKeyboard())
onView(withId(R.id.searchResulListView))
.check(matches(isDisplayed()))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package campus.tech.kakao.map

import android.content.Intent
import androidx.test.core.app.ApplicationProvider
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.intent.Intents.init
import androidx.test.espresso.intent.Intents.intended
import androidx.test.espresso.intent.Intents.release
import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.rules.ActivityScenarioRule
import campus.tech.kakao.map.view.DataSearchActivity
import campus.tech.kakao.map.view.HomeMapActivity
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test

class HomeMapActivityTest {
@get:Rule
val activityRule: ActivityScenarioRule<HomeMapActivity> =
ActivityScenarioRule(
Intent(
ApplicationProvider.getApplicationContext(),
HomeMapActivity::class.java
).apply {
putExtra("name", "전남대학교 여수캠퍼스")
putExtra("address", "전라남도 여수시 대학로 50")
putExtra("latitude", "34.772884563341")
putExtra("longitude", "127.69954169563")
}
)

@Before
fun setup() {
init()
}

@After
fun teardown() {
release()
}

@Test
fun 목록에서_선택한_장소의_정보가_BottomSheet에_나타남() {
onView(withId(R.id.placeName))
.check(matches(withText("전남대학교 여수캠퍼스")))
onView(withId(R.id.placeAddress))
.check(matches(withText("전라남도 여수시 대학로 50")))
onView(withId(R.id.bottomSheet))
.check(matches(isDisplayed()))
}

@Test
fun 검색바를_클릭하면_검색화면으로_이동() {
onView(withId(R.id.searchbar_home))
.perform(click())
intended(hasComponent(DataSearchActivity::class.java.name))
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package campus.tech.kakao.map

import android.content.Intent
import androidx.test.core.app.ApplicationProvider
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.rules.ActivityScenarioRule
import campus.tech.kakao.map.view.HomeMapActivity
import campus.tech.kakao.map.view.MapErrorActivity
import org.junit.Rule
import org.junit.Test


class MapErrorActivityTest {
@get:Rule
val activityRule : ActivityScenarioRule<HomeMapActivity> =
ActivityScenarioRule(
Intent(
ApplicationProvider.getApplicationContext(),
MapErrorActivity::class.java
).apply {
putExtra("errorMessage","java.lang.Exception:401")
}
)

@Test
fun onMapError_예외설명_에러화면에_나타남() {
onView(withId(R.id.error_detail))
.check(matches(withText("401")))
}
}
15 changes: 14 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<uses-permission android:name="android.permission.INTERNET" />

<application
android:name=".Application"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
Expand All @@ -17,14 +18,26 @@
android:theme="@style/Theme.Map"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:name=".view.SplashActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".view.MapErrorActivity"
android:exported="true" />
<activity
android:name=".view.HomeMapActivity"
android:allowBackup="true"
android:exported="true" />
<activity
android:name=".view.DataSearchActivity"
android:exported="true"
android:windowSoftInputMode="adjustResize" />

</application>

</manifest>
18 changes: 18 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/Application.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package campus.tech.kakao.map

import android.app.Application
import com.google.firebase.FirebaseApp
import com.kakao.vectormap.KakaoMapSdk
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class Application : Application() {
override fun onCreate(){
super.onCreate()
//카카오맵 SDK 초기화
val key = getString(R.string.kakao_api_key)
KakaoMapSdk.init(this, key)

FirebaseApp.initializeApp(this)
}
}
11 changes: 0 additions & 11 deletions app/src/main/java/campus/tech/kakao/map/MainActivity.kt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package campus.tech.kakao.map.adapter

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.TextView
import androidx.lifecycle.viewModelScope
import androidx.recyclerview.widget.RecyclerView
import campus.tech.kakao.map.R
import campus.tech.kakao.map.data.room.SearchHistoryData
import campus.tech.kakao.map.adapter.listener.RecentAdapterListener
import campus.tech.kakao.map.viewModel.SearchHistoryViewModel
import kotlinx.coroutines.launch

class RecentSearchAdapter(
private val searchHistoryDataList: List<SearchHistoryData>,
private val searchHistoryViewModel: SearchHistoryViewModel,
private val adapterListener: RecentAdapterListener
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

class RecentViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val name: TextView = view.findViewById(R.id.recent_search)
val deleteBtn: ImageButton = view.findViewById(R.id.delete_recent)
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view =
LayoutInflater.from(parent.context).inflate(R.layout.recent_search_item, parent, false)
return RecentViewHolder(view)
}

override fun getItemCount(): Int = searchHistoryDataList.count()

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val item = searchHistoryDataList[position]
val viewHolder = holder as RecentViewHolder
viewHolder.name.text = item.name

viewHolder.deleteBtn.setOnClickListener {
searchHistoryViewModel.viewModelScope.launch {
searchHistoryViewModel.deleteRecentData(item.name, item.address)
}
}

viewHolder.name.setOnClickListener {
adapterListener.autoSearch(item.name)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package campus.tech.kakao.map.adapter

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.lifecycle.viewModelScope
import androidx.recyclerview.widget.RecyclerView
import campus.tech.kakao.map.R
import campus.tech.kakao.map.adapter.listener.SearchAdapterListener
import campus.tech.kakao.map.viewModel.SearchHistoryViewModel
import campus.tech.kakao.map.retrofit.Document
import kotlinx.coroutines.launch

class SearchDataAdapter(
private var items: List<Document>,
private val recentViewModel: SearchHistoryViewModel,
private var adapterListener: SearchAdapterListener
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

class SearchDataViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val name: TextView = view.findViewById(R.id.search_data_name)
val address: TextView = view.findViewById(R.id.search_data_address)
val category: TextView = view.findViewById(R.id.search_data_category)
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view =
LayoutInflater.from(parent.context).inflate(R.layout.search_data_item, parent, false)
return SearchDataViewHolder(view)
}

override fun getItemCount(): Int = items.count()

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val item = items[position]
val viewHolder = holder as SearchDataViewHolder
viewHolder.name.text = item.name
viewHolder.address.text = item.address
// API 데이터에 "category_group_code"가 있는 경우 해당 그룹 코드에 맞는 설명을 출력하고, 비어 있는 경우 "category_name"의 일부 문자열을 출력
if (item.categoryCode.isEmpty()) {
viewHolder.category.text = item.categoryTail
} else {
viewHolder.category.text = item.categoryDescription
}
holder.itemView.setOnClickListener {
val searchTime = System.currentTimeMillis()
recentViewModel.viewModelScope.launch {
recentViewModel.addRecentSearchItem(item.name, item.address, searchTime)
}
adapterListener.displaySearchLocation(
item.name,
item.address,
item.latitude,
item.longitude
)
}
}

fun updateData(newItems: List<Document>) {
items = newItems
notifyDataSetChanged()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package campus.tech.kakao.map.adapter.listener

interface RecentAdapterListener {
fun autoSearch(searchData: String)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package campus.tech.kakao.map.adapter.listener

interface SearchAdapterListener {
fun displaySearchLocation(name: String, address: String, latitude: String, longitude: String)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package campus.tech.kakao.map.data

object LocationDataContract {
const val LOCATION_NAME = "name"
const val LOCATION_ADDRESS = "address"
const val LOCATION_LATITUDE = "latitude"
const val LOCATION_LONGITUDE = "longitude"
}
Loading