From 5f646b6e86c7049d5da3188ac2406b77a0e246e2 Mon Sep 17 00:00:00 2001 From: jiyeon Date: Mon, 22 Jul 2024 14:29:24 +0900 Subject: [PATCH 01/26] update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 73ba54e1..57baed12 100644 --- a/README.md +++ b/README.md @@ -1 +1,3 @@ # android-map-refactoring +## 이전 미션 코드 가져오기 +- 위치 이동 코드를 옮겨 온다. \ No newline at end of file From c11466ca7bd6350434610247b07f52747bc070f7 Mon Sep 17 00:00:00 2001 From: jiyeon Date: Mon, 22 Jul 2024 16:58:41 +0900 Subject: [PATCH 02/26] =?UTF-8?q?android-map-location=EC=9D=98=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 23 +- app/src/main/AndroidManifest.xml | 13 +- .../java/campus/tech/kakao/MyApplication.kt | 29 ++ .../campus/tech/kakao/map/MainActivity.kt | 11 - .../map/adapter/keyword/KeywordAdapter.kt | 45 +++ .../kakao/map/adapter/search/SearchAdapter.kt | 52 ++++ .../tech/kakao/map/api/KakaoLocalApi.kt | 54 ++++ .../java/campus/tech/kakao/map/model/item.kt | 9 + .../map/repository/keyword/KeywordContract.kt | 8 + .../map/repository/keyword/KeywordDbHelper.kt | 44 +++ .../repository/keyword/KeywordRepository.kt | 55 ++++ .../repository/location/LocationContract.kt | 12 + .../repository/location/LocationDbHelper.kt | 36 +++ .../repository/location/LocationSearcher.kt | 51 ++++ .../tech/kakao/map/view/MainActivity.kt | 261 ++++++++++++++++++ .../tech/kakao/map/view/SearchActivity.kt | 106 +++++++ .../viewmodel/OnKeywordItemClickListener.kt | 6 + .../viewmodel/OnSearchItemClickListener.kt | 7 + .../map/viewmodel/keyword/KeywordViewmodel.kt | 30 ++ .../keyword/KeywordViewmodelFactory.kt | 15 + .../kakao/map/viewmodel/main/MainViewmodel.kt | 56 ++++ .../viewmodel/main/MainViewmodelFactory.kt | 14 + .../map/viewmodel/search/SearchViewmodel.kt | 25 ++ .../search/SearchViewmodelFactory.kt | 15 + app/src/main/res/drawable/green_marker.webp | Bin 0 -> 1548 bytes app/src/main/res/drawable/ic_close.xml | 5 + app/src/main/res/drawable/ic_focus.xml | 5 + app/src/main/res/drawable/pin.png | Bin 0 -> 3358 bytes app/src/main/res/layout/activity_main.xml | 98 ++++++- app/src/main/res/layout/activity_search.xml | 78 ++++++ app/src/main/res/layout/empty_activity.xml | 17 ++ app/src/main/res/layout/list_item.xml | 45 +++ app/src/main/res/layout/list_keyword.xml | 24 ++ app/src/main/res/values/strings.xml | 10 + settings.gradle.kts | 12 +- 35 files changed, 1240 insertions(+), 31 deletions(-) create mode 100644 app/src/main/java/campus/tech/kakao/MyApplication.kt delete mode 100644 app/src/main/java/campus/tech/kakao/map/MainActivity.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/adapter/keyword/KeywordAdapter.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/adapter/search/SearchAdapter.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/api/KakaoLocalApi.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/model/item.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordContract.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDbHelper.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordRepository.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/repository/location/LocationDbHelper.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/viewmodel/OnKeywordItemClickListener.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/viewmodel/OnSearchItemClickListener.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodel.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodelFactory.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodel.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodelFactory.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodel.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodelFactory.kt create mode 100644 app/src/main/res/drawable/green_marker.webp create mode 100644 app/src/main/res/drawable/ic_close.xml create mode 100644 app/src/main/res/drawable/ic_focus.xml create mode 100644 app/src/main/res/drawable/pin.png create mode 100644 app/src/main/res/layout/activity_search.xml create mode 100644 app/src/main/res/layout/empty_activity.xml create mode 100644 app/src/main/res/layout/list_item.xml create mode 100644 app/src/main/res/layout/list_keyword.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2c1a15f2..467c51dd 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,3 +1,12 @@ +import java.util.Properties + +fun getApiKey(key: String): String { + val properties = Properties() + val localPropertiesFile = rootProject.file("local.properties") + localPropertiesFile.inputStream().use { properties.load(it) } + return properties.getProperty(key) +} + plugins { id("com.android.application") id("org.jetbrains.kotlin.android") @@ -19,6 +28,10 @@ android { versionName = "1.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + + resValue("string", "KAKAO_API_KEY", getApiKey("kakaoApiKey")) + buildConfigField("String", "KAKAO_REST_API_KEY", getApiKey("kakaoRestApiKey")) + buildConfigField("String", "KAKAO_BASE_URL", getApiKey("kakaoBaseUrl")) } buildTypes { @@ -39,13 +52,13 @@ android { } buildFeatures { + viewBinding = true dataBinding = true buildConfig = true } } dependencies { - implementation("androidx.core:core-ktx:1.13.1") implementation("androidx.appcompat:appcompat:1.7.0") implementation("com.google.android.material:material:1.12.0") @@ -77,4 +90,12 @@ dependencies { androidTestImplementation("androidx.test.espresso:espresso-intents:3.6.1") androidTestImplementation("com.google.dagger:hilt-android-testing:2.48.1") kaptAndroidTest("com.google.dagger:hilt-android-compiler:2.48.1") + + implementation("androidx.datastore:datastore-preferences:1.0.0") + implementation("com.squareup.okhttp3:logging-interceptor:4.9.0") + implementation("androidx.activity:activity:1.8.0") + implementation("com.kakao.sdk:v2-user:2.9.0") + testImplementation("androidx.test.ext:junit:1.1.5") + implementation("androidx.fragment:fragment-ktx:1.3.6") + implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.3.1") } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6bca2f54..198ab145 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,7 +2,11 @@ + + + + + + @@ -21,6 +30,8 @@ + + - + \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/MyApplication.kt b/app/src/main/java/campus/tech/kakao/MyApplication.kt new file mode 100644 index 00000000..8bd13a92 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/MyApplication.kt @@ -0,0 +1,29 @@ +package campus.tech.kakao + +import android.app.Application +import campus.tech.kakao.map.BuildConfig +import com.kakao.vectormap.KakaoMapSdk +import campus.tech.kakao.map.R +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory + +class MyApplication : Application() { + + companion object { + lateinit var retrofit: Retrofit + private set + } + + override fun onCreate() { + super.onCreate() + + // 카카오 지도 SDK 초기화 + KakaoMapSdk.init(this, getString(R.string.KAKAO_API_KEY)) + + // Retrofit 초기화 + retrofit = Retrofit.Builder() + .baseUrl(BuildConfig.KAKAO_BASE_URL) + .addConverterFactory(GsonConverterFactory.create()) + .build() + } +} diff --git a/app/src/main/java/campus/tech/kakao/map/MainActivity.kt b/app/src/main/java/campus/tech/kakao/map/MainActivity.kt deleted file mode 100644 index 95b43803..00000000 --- a/app/src/main/java/campus/tech/kakao/map/MainActivity.kt +++ /dev/null @@ -1,11 +0,0 @@ -package campus.tech.kakao.map - -import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity - -class MainActivity : AppCompatActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) - } -} diff --git a/app/src/main/java/campus/tech/kakao/map/adapter/keyword/KeywordAdapter.kt b/app/src/main/java/campus/tech/kakao/map/adapter/keyword/KeywordAdapter.kt new file mode 100644 index 00000000..0c0bd926 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/adapter/keyword/KeywordAdapter.kt @@ -0,0 +1,45 @@ +package campus.tech.kakao.map.adapter.keyword + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import campus.tech.kakao.map.R +import campus.tech.kakao.map.viewmodel.OnKeywordItemClickListener + +class KeywordAdapter(private val onKeywordItemClickListener: OnKeywordItemClickListener) : + ListAdapter( + object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: String, newItem: String) = oldItem == newItem + override fun areContentsTheSame(oldItem: String, newItem: String) = oldItem == newItem + } + ) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): KeywordViewHolder { + val view = LayoutInflater.from(parent.context).inflate(R.layout.list_keyword, parent, false) + return KeywordViewHolder(view) + } + + override fun onBindViewHolder(holder: KeywordViewHolder, position: Int) { + holder.bindViewHolder(getItem(position), onKeywordItemClickListener) + } + + class KeywordViewHolder(view: View) : RecyclerView.ViewHolder(view) { + private val keywordTextView: TextView = view.findViewById(R.id.keyword) + private val removeIconView: ImageView = view.findViewById(R.id.remove_icon) + + fun bindViewHolder(keyword: String, onKeywordItemClickListener: OnKeywordItemClickListener) { + keywordTextView.text = keyword + keywordTextView.setOnClickListener { + onKeywordItemClickListener.onKeywordItemClick(keyword) + } + removeIconView.setOnClickListener { + onKeywordItemClickListener.onKeywordItemDeleteClick(keyword) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/adapter/search/SearchAdapter.kt b/app/src/main/java/campus/tech/kakao/map/adapter/search/SearchAdapter.kt new file mode 100644 index 00000000..fcfbaa47 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/adapter/search/SearchAdapter.kt @@ -0,0 +1,52 @@ +package campus.tech.kakao.map.adapter.search + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.RelativeLayout +import android.widget.TextView +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import campus.tech.kakao.map.R +import campus.tech.kakao.map.model.Item +import campus.tech.kakao.map.viewmodel.OnSearchItemClickListener + +class SearchAdapter( + private val onSearchItemClickListener: OnSearchItemClickListener +) : ListAdapter( + object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: Item, newItem: Item) = + oldItem.place == newItem.place + + override fun areContentsTheSame(oldItem: Item, newItem: Item) = + oldItem == newItem + } +) { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchViewHolder { + val view = LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false) + return SearchViewHolder(view) + } + + override fun onBindViewHolder(holder: SearchViewHolder, position: Int) { + val item = getItem(position) + holder.bindViewHolder(item, onSearchItemClickListener) + } + + class SearchViewHolder(view: View) : RecyclerView.ViewHolder(view) { + private val itemList: RelativeLayout = view.findViewById(R.id.item_list) + private val place: TextView = view.findViewById(R.id.place_name) + private val address: TextView = view.findViewById(R.id.address) + private val category: TextView = view.findViewById(R.id.category) + + fun bindViewHolder(item: Item, onSearchItemClickListener: OnSearchItemClickListener) { + place.text = item.place + address.text = item.address + category.text = item.category + + itemList.setOnClickListener { + onSearchItemClickListener.onSearchItemClick(item) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/api/KakaoLocalApi.kt b/app/src/main/java/campus/tech/kakao/map/api/KakaoLocalApi.kt new file mode 100644 index 00000000..8b0771f8 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/api/KakaoLocalApi.kt @@ -0,0 +1,54 @@ +package campus.tech.kakao.map.api + +import com.google.gson.annotations.SerializedName +import retrofit2.http.GET +import retrofit2.http.Header +import retrofit2.http.Query + +interface KakaoLocalApi { + @GET("v2/local/search/keyword.json") + suspend fun searchKeyword( + @Header("Authorization") apiKey: String, + @Query("query") query: String, + @Query("page") page: Int = 1, + @Query("size") size: Int = 15 + ): KakaoSearchResponse +} + +// 데이터 모델 +data class KakaoSearchResponse( + @SerializedName("documents") + val documents: List, + + @SerializedName("meta") + val meta: Meta +) + +data class Document( + @SerializedName("place_name") + val placeName: String, + + @SerializedName("address_name") + val addressName: String, + + @SerializedName("category_group_name") + val categoryGroupName: String, + + @SerializedName("y") + val latitude: Double, + + @SerializedName("x") + val longitude: Double + +) + +data class Meta( + @SerializedName("total_count") + val totalCount: Int, + + @SerializedName("pageable_count") + val pageableCount: Int, + + @SerializedName("is_end") + val isEnd: Boolean +) diff --git a/app/src/main/java/campus/tech/kakao/map/model/item.kt b/app/src/main/java/campus/tech/kakao/map/model/item.kt new file mode 100644 index 00000000..27363ca9 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/model/item.kt @@ -0,0 +1,9 @@ +package campus.tech.kakao.map.model + +data class Item( + val place: String, + val address: String, + val category: String, + val latitude: Double, + val longitude:Double +) diff --git a/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordContract.kt b/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordContract.kt new file mode 100644 index 00000000..c27ea5a2 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordContract.kt @@ -0,0 +1,8 @@ +package campus.tech.kakao.map.repository.keyword + +import android.provider.BaseColumns + +object KeywordContract : BaseColumns { + const val TABLE_NAME = "keyword" + const val RECENT_KEYWORD = "recent_keyword" +} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDbHelper.kt b/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDbHelper.kt new file mode 100644 index 00000000..469e36f4 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDbHelper.kt @@ -0,0 +1,44 @@ +package campus.tech.kakao.map.repository.keyword + +import android.content.Context +import android.database.sqlite.SQLiteOpenHelper +import android.database.sqlite.SQLiteDatabase +import android.provider.BaseColumns + +class KeywordDbHelper(context: Context) : + SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) { + + override fun onCreate(db: SQLiteDatabase?) { + db?.let { createDatabase(it) } + } + + override fun onUpgrade( + db: SQLiteDatabase?, + oldVersion: Int, + newVersion: Int + ) { + db?.let { upgradeDatabase(it, oldVersion, newVersion) } + } + + private fun createDatabase(db: SQLiteDatabase) { + db.execSQL(SQL_CREATE_ENTRIES) + } + + private fun upgradeDatabase(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + db.execSQL(SQL_DELETE_ENTRIES) + createDatabase(db) + } + + companion object { + private const val SQL_CREATE_ENTRIES = + "CREATE TABLE ${KeywordContract.TABLE_NAME} (" + + "${BaseColumns._ID} INTEGER PRIMARY KEY," + + "${KeywordContract.RECENT_KEYWORD} TEXT)" + + private const val SQL_DELETE_ENTRIES = + "DROP TABLE IF EXISTS ${KeywordContract.TABLE_NAME}" + + private const val DATABASE_VERSION = 1 + private const val DATABASE_NAME = "keyword.db" + } +} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordRepository.kt b/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordRepository.kt new file mode 100644 index 00000000..fc8efdbb --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordRepository.kt @@ -0,0 +1,55 @@ +package campus.tech.kakao.map.repository.keyword + +import android.content.ContentValues +import android.content.Context + +class KeywordRepository(context: Context) { + + private val dbHelper = KeywordDbHelper(context) + + fun update(keyword: String) { + val db = dbHelper.writableDatabase + val values = ContentValues().apply { + put(KeywordContract.RECENT_KEYWORD, keyword) + } + db.insert(KeywordContract.TABLE_NAME, null, values) + } + + fun read(): List { + val keywords = mutableListOf() + val db = dbHelper.readableDatabase + val projection = arrayOf(KeywordContract.RECENT_KEYWORD) + val cursor = db.query( + KeywordContract.TABLE_NAME, + projection, + null, + null, + null, + null, + null + ) + + with(cursor) { + while (moveToNext()) { + keywords.add(getString(getColumnIndexOrThrow(KeywordContract.RECENT_KEYWORD))) + } + close() + } + return keywords + } + + fun delete(keyword: String) { + val db = dbHelper.writableDatabase + db.delete( + KeywordContract.TABLE_NAME, + "${KeywordContract.RECENT_KEYWORD} = ?", + arrayOf(keyword) + ) + } + + companion object { + fun getInstance(context: Context): KeywordRepository { + return KeywordRepository(context) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt new file mode 100644 index 00000000..db17e41a --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt @@ -0,0 +1,12 @@ +package campus.tech.kakao.map.repository.location + +import android.provider.BaseColumns + +object LocationContract : BaseColumns { + const val TABLE_NAME = "location" + const val PLACE_NAME = "place_name" + const val ADDRESS_NAME = "address_name" + const val CATEGORY_GROUP_NAME = "category_group_name" + const val LATITUDE = "latitude" + const val LONGITUDE = "longitude" +} diff --git a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationDbHelper.kt b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationDbHelper.kt new file mode 100644 index 00000000..270bc19e --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationDbHelper.kt @@ -0,0 +1,36 @@ +package campus.tech.kakao.map.repository.location + +import android.content.Context +import android.database.sqlite.SQLiteDatabase +import android.database.sqlite.SQLiteOpenHelper +import android.provider.BaseColumns + +class LocationDbHelper(context: Context) : + SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) { + + override fun onCreate(db: SQLiteDatabase?) { + db?.execSQL(SQL_CREATE_ENTRIES) + } + + override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) { + db?.execSQL(SQL_DELETE_ENTRIES) + onCreate(db) + } + + companion object { + private const val SQL_CREATE_ENTRIES = + "CREATE TABLE ${LocationContract.TABLE_NAME} (" + + "${BaseColumns._ID} INTEGER PRIMARY KEY," + + "${LocationContract.PLACE_NAME} TEXT," + + "${LocationContract.ADDRESS_NAME} TEXT," + + "${LocationContract.CATEGORY_GROUP_NAME} TEXT," + + "${LocationContract.LATITUDE} REAL," + + "${LocationContract.LONGITUDE} REAL)" + + private const val SQL_DELETE_ENTRIES = + "DROP TABLE IF EXISTS ${LocationContract.TABLE_NAME}" + + private const val DATABASE_VERSION = 1 + private const val DATABASE_NAME = "location.db" + } +} diff --git a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt new file mode 100644 index 00000000..31866b44 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt @@ -0,0 +1,51 @@ +package campus.tech.kakao.map.repository.location + +import android.content.Context +import campus.tech.kakao.map.model.Item + +class LocationSearcher(private val context: Context) { + fun search(keyword: String): List { + val items = mutableListOf() + val dbHelper = LocationDbHelper(context) + val db = dbHelper.readableDatabase + val projection = arrayOf( + LocationContract.PLACE_NAME, + LocationContract.ADDRESS_NAME, + LocationContract.CATEGORY_GROUP_NAME, + LocationContract.LATITUDE, + LocationContract.LONGITUDE + ) + + val selection = "${LocationContract.CATEGORY_GROUP_NAME} = ?" + val selectionArgs = arrayOf(keyword) + val sortOrder = "${LocationContract.CATEGORY_GROUP_NAME} DESC" + val cursor = db.query( + LocationContract.TABLE_NAME, + projection, + selection, + selectionArgs, + null, + null, + sortOrder + ) + + with(cursor) { + while (moveToNext()) { + val placeName = getString(getColumnIndexOrThrow(LocationContract.PLACE_NAME)) + val addressName = getString(getColumnIndexOrThrow(LocationContract.ADDRESS_NAME)) + val categoryGroupName = getString(getColumnIndexOrThrow(LocationContract.CATEGORY_GROUP_NAME)) + val latitude = getDouble(getColumnIndexOrThrow(LocationContract.LATITUDE)) + val longitude = getDouble(getColumnIndexOrThrow(LocationContract.LONGITUDE)) + items.add(Item(placeName, addressName, categoryGroupName, latitude, longitude)) + } + close() + } + return items + } + + companion object { + fun getInstance(context: Context): LocationSearcher { + return LocationSearcher(context) + } + } +} diff --git a/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt b/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt new file mode 100644 index 00000000..17780785 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt @@ -0,0 +1,261 @@ +package campus.tech.kakao.map + +import android.content.Intent +import android.os.Bundle +import android.util.Log +import android.view.View +import android.widget.EditText +import android.widget.FrameLayout +import android.widget.ImageButton +import android.widget.RelativeLayout +import android.widget.TextView +import android.widget.Toast +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts +import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import com.google.android.material.bottomsheet.BottomSheetBehavior +import com.kakao.vectormap.* +import com.kakao.vectormap.camera.CameraAnimation +import com.kakao.vectormap.camera.CameraUpdateFactory +import com.kakao.vectormap.label.LabelLayer +import com.kakao.vectormap.label.LabelOptions +import com.kakao.vectormap.label.LabelStyle +import com.kakao.vectormap.label.LabelStyles +import com.kakao.vectormap.label.LabelTextStyle +import campus.tech.kakao.map.model.Item +import campus.tech.kakao.map.repository.location.LocationSearcher +import campus.tech.kakao.map.view.SearchActivity +import campus.tech.kakao.map.viewmodel.keyword.KeywordViewModel +import campus.tech.kakao.map.viewmodel.keyword.KeywordViewModelFactory +import campus.tech.kakao.map.viewmodel.main.MainViewModel +import campus.tech.kakao.map.viewmodel.main.MainViewModelFactory +import campus.tech.kakao.map.viewmodel.OnSearchItemClickListener +import campus.tech.kakao.map.viewmodel.OnKeywordItemClickListener + +class MainActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeywordItemClickListener { + + private var mapView: MapView? = null + private var kakaoMap: KakaoMap? = null + private var labelLayer: LabelLayer? = null + + private lateinit var errorLayout: RelativeLayout + private lateinit var errorMessage: TextView + private lateinit var errorDetails: TextView + private lateinit var retryButton: ImageButton + private lateinit var bottomSheetBehavior: BottomSheetBehavior + private lateinit var bottomSheetTitle: TextView + private lateinit var bottomSheetAddress: TextView + private lateinit var bottomSheetLayout: FrameLayout + private lateinit var searchResultLauncher: ActivityResultLauncher + private lateinit var locationSearcher: LocationSearcher + private lateinit var keywordViewModel: KeywordViewModel + private lateinit var mainViewModel: MainViewModel + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + locationSearcher = LocationSearcher(this) + + // ViewModel 초기화 + keywordViewModel = ViewModelProvider(this, KeywordViewModelFactory(applicationContext)).get(KeywordViewModel::class.java) + mainViewModel = ViewModelProvider(this, MainViewModelFactory(application)).get(MainViewModel::class.java) + + // ActivityResultLauncher 초기화 + searchResultLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { result -> + handleSearchResult(result.data) + } + + // MapView 초기화 및 맵 라이프사이클 콜백 설정 + mapView = findViewById(R.id.map_view) + mapView?.start(object : MapLifeCycleCallback() { + override fun onMapDestroy() { + Log.d(TAG, "Map destroyed") + } + + override fun onMapError(error: Exception) { + Log.e(TAG, "Map error", error) + showErrorScreen(error) + } + }, object : KakaoMapReadyCallback() { + override fun onMapReady(map: KakaoMap) { + kakaoMap = map + labelLayer = kakaoMap?.labelManager?.layer + Log.d(TAG, "Map is ready") + } + }) + + // 검색창 클릭 시 검색 페이지로 이동 + val searchEditText = findViewById(R.id.search_edit_text) + searchEditText.setOnClickListener { + val intent = Intent(this, SearchActivity::class.java) + searchResultLauncher.launch(intent) + } + + // 에러 화면 초기화 + initializeErrorScreen() + + // BottomSheet 초기화 + initializeBottomSheet() + + // Observe the last marker position + mainViewModel.lastMarkerPosition.observe(this, Observer { item -> + item?.let { + Log.d(TAG, "Loaded last marker position: lat=${it.latitude}, lon=${it.longitude}, placeName=${it.place}, roadAddressName=${it.address}") + addLabel(it) + val position = LatLng.from(it.latitude, it.longitude) + moveCamera(position) + updateBottomSheet(it.place, it.address) + } + }) + } + + private fun initializeErrorScreen() { + errorLayout = findViewById(R.id.error_layout) + errorMessage = findViewById(R.id.error_message) + errorDetails = findViewById(R.id.error_details) + retryButton = findViewById(R.id.retry_button) + retryButton.setOnClickListener { onRetryButtonClick() } + } + + private fun initializeBottomSheet() { + bottomSheetLayout = findViewById(R.id.bottomSheetLayout) + bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetLayout) + bottomSheetTitle = findViewById(R.id.bottomSheetTitle) + bottomSheetAddress = findViewById(R.id.bottomSheetAddress) + + // 처음에는 BottomSheet 숨기기 + bottomSheetLayout.visibility = View.GONE + } + + private fun handleSearchResult(data: Intent?) { + if (data == null) { + showToast("검색 결과를 받아오지 못했습니다.") + return + } + + val placeName = data.getStringExtra("place_name") + val roadAddressName = data.getStringExtra("road_address_name") + val latitude = data.getDoubleExtra("latitude", 0.0) + val longitude = data.getDoubleExtra("longitude", 0.0) + + if (placeName == null || roadAddressName == null) { + showToast("검색 결과가 유효하지 않습니다.") + return + } + + Log.d(TAG, "Search result: $placeName, $roadAddressName, $latitude, $longitude") + + val item = Item(placeName, roadAddressName, "", latitude, longitude) + addLabel(item) + mainViewModel.saveLastMarkerPosition(item) + } + + private fun showToast(message: String) { + Toast.makeText(this, message, Toast.LENGTH_SHORT).show() + } + + override fun onResume() { + super.onResume() + mapView?.resume() // MapView의 resume 호출 + Log.d(TAG, "MapView resumed") + } + + override fun onPause() { + super.onPause() + mapView?.pause() // MapView의 pause 호출 + Log.d(TAG, "MapView paused") + } + + fun showErrorScreen(error: Exception) { + errorLayout.visibility = View.VISIBLE + errorMessage.text = getString(R.string.map_error_message) + errorDetails.text = error.message + mapView?.visibility = View.GONE + } + + private fun onRetryButtonClick() { + errorLayout.visibility = View.GONE + mapView?.visibility = View.VISIBLE + mapView?.start(object : MapLifeCycleCallback() { + override fun onMapDestroy() { + Log.d(TAG, "Map destroyed on retry") + } + + override fun onMapError(error: Exception) { + Log.e(TAG, "Map error on retry", error) + showErrorScreen(error) + } + }, object : KakaoMapReadyCallback() { + override fun onMapReady(kakaoMap: KakaoMap) { + this@MainActivity.kakaoMap = kakaoMap + labelLayer = kakaoMap.labelManager?.layer + Log.d(TAG, "Map is ready on retry") + } + }) + } + + private fun addLabel(item: Item) { + val placeName = item.place + val roadAddressName = item.address + val latitude = item.latitude + val longitude = item.longitude + + val position = LatLng.from(latitude, longitude) + val styles = kakaoMap?.labelManager?.addLabelStyles( + LabelStyles.from( + LabelStyle.from(R.drawable.pin).setZoomLevel(DEFAULT_ZOOM_LEVEL), + LabelStyle.from(R.drawable.pin) + .setTextStyles( + LabelTextStyle.from(this, R.style.labelTextStyle) + ) + .setZoomLevel(DEFAULT_ZOOM_LEVEL) + ) + ) + + labelLayer?.addLabel( + LabelOptions.from(placeName, position).setStyles(styles).setTexts(placeName) + ) + + moveCamera(position) + updateBottomSheet(placeName, roadAddressName) + } + + private fun moveCamera(position: LatLng) { + kakaoMap?.moveCamera( + CameraUpdateFactory.newCenterPosition(position), + CameraAnimation.from(CAMERA_ANIMATION_DURATION, false, false) + ) + } + + private fun updateBottomSheet(placeName: String, roadAddressName: String) { + bottomSheetTitle.text = placeName + bottomSheetAddress.text = roadAddressName + bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED + bottomSheetLayout.visibility = View.VISIBLE + } + + override fun onKeywordItemClick(keyword: String) { + // 아무 작업도 수행하지 않음 + } + + override fun onKeywordItemDeleteClick(keyword: String) { + // 아무 작업도 수행하지 않음 + } + + override fun onSearchItemClick(item: Item) { + // 검색 결과 목록에서 항목을 선택했을 때의 동작을 정의 + addLabel(item) + mainViewModel.saveLastMarkerPosition(item) + } + + companion object { + private const val TAG = "MainActivity" + private const val DEFAULT_ZOOM_LEVEL = 1 + private const val CAMERA_ANIMATION_DURATION = 10 + } +} diff --git a/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt b/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt new file mode 100644 index 00000000..3db1f2c9 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt @@ -0,0 +1,106 @@ +package campus.tech.kakao.map.view + +import android.app.Activity +import android.content.Intent +import android.os.Bundle +import android.view.View +import androidx.appcompat.app.AppCompatActivity +import androidx.core.widget.doAfterTextChanged +import androidx.lifecycle.ViewModelProvider +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.LinearLayoutManager +import campus.tech.kakao.MyApplication +import campus.tech.kakao.map.BuildConfig +import campus.tech.kakao.map.adapter.keyword.KeywordAdapter +import campus.tech.kakao.map.adapter.search.SearchAdapter +import campus.tech.kakao.map.api.KakaoLocalApi +import campus.tech.kakao.map.databinding.ActivitySearchBinding +import campus.tech.kakao.map.model.Item +import campus.tech.kakao.map.viewmodel.OnKeywordItemClickListener +import campus.tech.kakao.map.viewmodel.OnSearchItemClickListener +import campus.tech.kakao.map.viewmodel.keyword.KeywordViewModel +import campus.tech.kakao.map.viewmodel.keyword.KeywordViewModelFactory +import campus.tech.kakao.map.viewmodel.search.SearchViewModel +import campus.tech.kakao.map.viewmodel.search.SearchViewModelFactory + +class SearchActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeywordItemClickListener { + private lateinit var binding: ActivitySearchBinding + private lateinit var searchViewModel: SearchViewModel + lateinit var keywordViewModel: KeywordViewModel + private lateinit var searchAdapter: SearchAdapter + private lateinit var keywordAdapter: KeywordAdapter + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivitySearchBinding.inflate(layoutInflater) + setContentView(binding.root) + + // Retrofit 초기화 + val api = MyApplication.retrofit.create(KakaoLocalApi::class.java) + + // ViewModel 초기화 + searchViewModel = ViewModelProvider(this, SearchViewModelFactory(api))[SearchViewModel::class.java] + keywordViewModel = ViewModelProvider(this, KeywordViewModelFactory(applicationContext))[KeywordViewModel::class.java] + + // 검색 결과 RecyclerView 설정 + searchAdapter = SearchAdapter(this) + binding.searchResultView.apply { + layoutManager = LinearLayoutManager(this@SearchActivity) + adapter = searchAdapter + addItemDecoration(DividerItemDecoration(context, LinearLayoutManager.VERTICAL)) + } + + // 검색어 목록 RecyclerView 설정 + keywordAdapter = KeywordAdapter(this) + binding.keywordHistoryView.apply { + layoutManager = LinearLayoutManager(this@SearchActivity, LinearLayoutManager.HORIZONTAL, false) + adapter = keywordAdapter + } + + // 검색 입력 설정 + binding.searchTextInput.doAfterTextChanged { + searchViewModel.searchLocationData(it.toString()) + } + + // 취소 버튼 클릭 이벤트 설정 + binding.deleteTextInput.setOnClickListener { + binding.searchTextInput.text.clear() + } + + // 검색어 목록 관찰 + keywordViewModel.keywords.observe(this) { + keywordAdapter.submitList(it) + } + + // 검색 결과 관찰하여 UI 업데이트 + searchViewModel.items.observe(this) { + searchAdapter.submitList(it) + binding.searchResultView.visibility = if (it.isEmpty()) View.GONE else View.VISIBLE + binding.emptyView.visibility = if (it.isEmpty()) View.VISIBLE else View.GONE + } + } + + override fun onSearchItemClick(item: Item) { + // 검색 항목 클릭 시 선택된 데이터를 반환하고 검색어 저장 + keywordViewModel.saveKeyword(item.place) + val resultIntent = Intent().apply { + putExtra("place_name", item.place) + putExtra("road_address_name", item.address) + putExtra("latitude", item.latitude) + putExtra("longitude", item.longitude) + } + setResult(Activity.RESULT_OK, resultIntent) + finish() + } + + override fun onKeywordItemClick(keyword: String) { + // 저장된 검색어 클릭 + binding.searchTextInput.setText(keyword) + searchViewModel.searchLocationData(keyword) + } + + override fun onKeywordItemDeleteClick(keyword: String) { + // 저장된 검색어 삭제 + keywordViewModel.deleteKeyword(keyword) + } +} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/OnKeywordItemClickListener.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/OnKeywordItemClickListener.kt new file mode 100644 index 00000000..3118a9c4 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/viewmodel/OnKeywordItemClickListener.kt @@ -0,0 +1,6 @@ +package campus.tech.kakao.map.viewmodel + +interface OnKeywordItemClickListener { + fun onKeywordItemDeleteClick(keyword: String) + fun onKeywordItemClick(keyword: String) +} diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/OnSearchItemClickListener.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/OnSearchItemClickListener.kt new file mode 100644 index 00000000..df72d9f9 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/viewmodel/OnSearchItemClickListener.kt @@ -0,0 +1,7 @@ +package campus.tech.kakao.map.viewmodel + +import campus.tech.kakao.map.model.Item + +interface OnSearchItemClickListener { + fun onSearchItemClick(item: Item) +} diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodel.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodel.kt new file mode 100644 index 00000000..c753ca77 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodel.kt @@ -0,0 +1,30 @@ +package campus.tech.kakao.map.viewmodel.keyword + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import campus.tech.kakao.map.repository.keyword.KeywordRepository + +class KeywordViewModel(private val repository: KeywordRepository) : ViewModel() { + + private val _keywords = MutableLiveData>() + val keywords: LiveData> get() = _keywords + + init { + loadKeywords() + } + + private fun loadKeywords() { + _keywords.value = repository.read() + } + + fun saveKeyword(keyword: String) { + repository.update(keyword) // 여기서 keyword 변수 사용 + loadKeywords() // 업데이트 후 다시 로드하여 UI 업데이트 + } + + fun deleteKeyword(keyword: String) { + repository.delete(keyword) + loadKeywords() // 삭제 후 다시 로드하여 UI 업데이트 + } +} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodelFactory.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodelFactory.kt new file mode 100644 index 00000000..8fbc0893 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodelFactory.kt @@ -0,0 +1,15 @@ +package campus.tech.kakao.map.viewmodel.keyword + +import android.content.Context +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import campus.tech.kakao.map.repository.keyword.KeywordRepository + +class KeywordViewModelFactory(private val context: Context) : ViewModelProvider.Factory { + override fun create(modelClass: Class): T { + if (modelClass.isAssignableFrom(KeywordViewModel::class.java)) { + return KeywordViewModel(KeywordRepository.getInstance(context)) as T + } + throw IllegalArgumentException("Unknown ViewModel class") + } +} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodel.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodel.kt new file mode 100644 index 00000000..c392c430 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodel.kt @@ -0,0 +1,56 @@ +package campus.tech.kakao.map.viewmodel.main + +import android.app.Application +import android.content.Context +import android.content.SharedPreferences +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import campus.tech.kakao.map.model.Item + +class MainViewModel(application: Application) : AndroidViewModel(application) { + + private val sharedPreferences: SharedPreferences = application.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) + private val _lastMarkerPosition = MutableLiveData() + val lastMarkerPosition: LiveData get() = _lastMarkerPosition + + init { + loadLastMarkerPosition() + } + + fun saveLastMarkerPosition(item: Item) { + with(sharedPreferences.edit()) { + putFloat(PREF_LATITUDE, item.latitude.toFloat()) + putFloat(PREF_LONGITUDE, item.longitude.toFloat()) + putString(PREF_PLACE_NAME, item.place) + putString(PREF_ROAD_ADDRESS_NAME, item.address) + apply() + } + _lastMarkerPosition.value = item + } + + private fun loadLastMarkerPosition() { + if (sharedPreferences.contains(PREF_LATITUDE) && sharedPreferences.contains(PREF_LONGITUDE)) { + val latitude = sharedPreferences.getFloat(PREF_LATITUDE, 0.0f).toDouble() + val longitude = sharedPreferences.getFloat(PREF_LONGITUDE, 0.0f).toDouble() + val placeName = sharedPreferences.getString(PREF_PLACE_NAME, "") ?: "" + val roadAddressName = sharedPreferences.getString(PREF_ROAD_ADDRESS_NAME, "") ?: "" + + _lastMarkerPosition.value = if (placeName.isNotEmpty() && roadAddressName.isNotEmpty()) { + Item(placeName, roadAddressName, "", latitude, longitude) + } else { + null + } + } else { + _lastMarkerPosition.value = null + } + } + + companion object { + private const val PREFS_NAME = "LastMarkerPrefs" + private const val PREF_LATITUDE = "lastLatitude" + private const val PREF_LONGITUDE = "lastLongitude" + private const val PREF_PLACE_NAME = "lastPlaceName" + private const val PREF_ROAD_ADDRESS_NAME = "lastRoadAddressName" + } +} diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodelFactory.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodelFactory.kt new file mode 100644 index 00000000..02310acd --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodelFactory.kt @@ -0,0 +1,14 @@ +package campus.tech.kakao.map.viewmodel.main + +import android.app.Application +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider + +class MainViewModelFactory(private val application: Application) : ViewModelProvider.Factory { + override fun create(modelClass: Class): T { + if (modelClass.isAssignableFrom(MainViewModel::class.java)) { + return MainViewModel(application) as T + } + throw IllegalArgumentException("Unknown ViewModel class") + } +} diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodel.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodel.kt new file mode 100644 index 00000000..11d3061b --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodel.kt @@ -0,0 +1,25 @@ +package campus.tech.kakao.map.viewmodel.search + +import androidx.lifecycle.* +import campus.tech.kakao.map.api.KakaoLocalApi +import campus.tech.kakao.map.model.Item +import kotlinx.coroutines.launch + +class SearchViewModel(private val api: KakaoLocalApi) : ViewModel() { + private val _items = MutableLiveData>() + val items: LiveData> + get() = _items + + fun searchLocationData(keyword: String) { + viewModelScope.launch { + try { + val response = api.searchKeyword("KakaoAK ${campus.tech.kakao.map.BuildConfig.KAKAO_REST_API_KEY}", keyword) + _items.value = response.documents.map { + Item(it.placeName, it.addressName, it.categoryGroupName, it.latitude, it.longitude) + } + } catch (e: Exception) { + e.printStackTrace() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodelFactory.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodelFactory.kt new file mode 100644 index 00000000..c8b5450c --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodelFactory.kt @@ -0,0 +1,15 @@ +package campus.tech.kakao.map.viewmodel.search + +import android.content.Context +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import campus.tech.kakao.map.api.KakaoLocalApi + +class SearchViewModelFactory(private val api: KakaoLocalApi) : ViewModelProvider.Factory { + override fun create(modelClass: Class): T { + if (modelClass.isAssignableFrom(SearchViewModel::class.java)) { + return SearchViewModel(api) as T + } + throw IllegalArgumentException("Unknown ViewModel class") + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/green_marker.webp b/app/src/main/res/drawable/green_marker.webp new file mode 100644 index 0000000000000000000000000000000000000000..737fd24a03f32bc4f455f7b7bad3638bc7432716 GIT binary patch literal 1548 zcmV+n2J`t+Nk&El1^@t8MM6+kP&il$0000G0001R005T&06|PpNY4WR00E$O+qNOe z+Bvc^%GtJU+qUiQXWO=4+qP|Yf3sZ}oyEw^LX_@b$jpcv_nyM7CaiJ7^eiqrwlh%3z}EEuuxFFP+G@gvaF7h5^oE-Zzsz6 zUr@eSO7C*g%6m)j-4V3kF`RuUsQ=JWb(6ecbtnG``u}%OuZV%7diE9z4wu-fR>(qO zH9KDk9>2B`m(E0bT&&T8%Q3O`v#~!$Ws41~a#V}112*j@Pe5az-?x3180~y18ikxEAR_5zW}c?^BT~HnZAIZ89#t0tULvP zt*mT~c#D;{BHFRiE&|UPNki0CjI4?_f{_u?d^v37`l4Yu8!HjBD;r&7;TjXyVRI1^ zuh=m%S;#c(;4>CJgYBdM1A%0F_<(^A;4uC%d5`0rU_5!_;ruXhMkg$UuIjE6ARz^+8?rjle^@jY{h|7{|#uZouutGsK)u zg!_p{NjaJb6%)@9ay}7i`freN!w*$!J|yB{EvVZhjfAu&P`O2bfIthV-7Z_Z>~>JS zv#FWc8S3{8YgNz_Iu0n*sBj?k9A;@_4TG+uElsSk(06i~7G;y6^NcbL%4S0E1r^Fw zEP(ExDfb!l|5LHQK%i%{Qky*#z&NGQDFZa7Tvg_3DyXcRu1H2*(AnKm!s-r67bvj+ zv~E&hGl)&T=i0qwYS5+BrP3~-_a~Qr0>SaOT)7ob5qeg*P|*uCuXkZRh^`fuR#1m3 z{2=WIkX<<_DOi~<{2=K^5MCuLC0vCvES9nuq_?h+P|=z;oRn}1#7~kig*qeGQ80lz zEOWFDcm5wX(Qm_ z0lRIi1Cx_&4Cf-jjPcOR1-^?h3v7Cq289rL-{2(~09H^qAPxcm0I(GRodGIw0GI$i zkw}_IrKKXFDt(F&uo4MP+pFh~zsqljd;ob}dnsE!s(>m$-$S$VfUqj@+0vs!B-4@a z&Tfm1iimXI7q+Qn^D-L0Cc zQ~3q$IS$OWb4iw$upWQ_{`gT0KIiyk?DFqlsw{Riwp~Z#SdsExBF<=(Iisb`xMFyB z+2ccM;#j{-r|NWCFN?lFEk5SQ2t|wd1D;7bsYP(Fq!Yw=gT_6@P1M@%6icO8S=*e$&5`!g{l50{9Uj=O$AJrJT zmjUDx25#BzgYaMe&>)^3>W*nmn zlW1*apP!Ngrybh5C3j-0)gb1(U)#C1O8#mMhNN-+Yap7he$ab + + diff --git a/app/src/main/res/drawable/ic_focus.xml b/app/src/main/res/drawable/ic_focus.xml new file mode 100644 index 00000000..b1df2f07 --- /dev/null +++ b/app/src/main/res/drawable/ic_focus.xml @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/pin.png b/app/src/main/res/drawable/pin.png new file mode 100644 index 0000000000000000000000000000000000000000..25c39a11f4dd03dae94e2b39fafabfbd13628e60 GIT binary patch literal 3358 zcmV+(4dL>MP)Px>*hxe|RCr$HU3-jF(`!)0{R$evJWYFgKC%@Wj0k7Wcl@uMB=n%uri9a6SHOUVo%%Q!?z6){Ye9u>6GK5b=4v6_5wV} zIA3pfOR|laFD|{b{^-EKlNnvVivT(BJqb!Eh(O^C}bNu|22 zVp}4H0HnS^;H8YN-)z;e8+ty(7dklqt(E@AG%>p_x#WV=vYgb2rn?bbr8Z>5{zgp; zFW9~Nh#4$X#PE)e$Y3t_z79}l#z?hgC4g)Lzz>zOL~YFf*dn^f?8uxT1tl0T^DAn>YE521*jld-hqF zeEH?3AdYX_1|Q#b7m)7!$w?DHr&vc7h=~URYqJjT#(AbpfsTzEL2hU;MaqbxN^K+H}>Ij#e=IAzY$(gKmKTLJ4T+ux#G4&ql{3HcL+{?U;~ z0yw!)Ra*K*LvS)S0LY|$dfA3tup4GA%a?<t6vQ}Vrw7en@N$&G$fSmT5X#5mGo3PW`)R*7?Eb-Oz|9T~C_ zQNx{#WppBMSuZRIER4qiy^cTwWwWp|60zV_c@;#=h*9Y{IkZlizh(`zm|RJhcl#TO z6Wg}IhYrn=B!HvX!UT42;6GjjEF=R)w!H_fORmQCJp1EfFs#IU>>K^Y*4y@9}5 zCli1|>(_(7z1@soWo3umt zzjvpiq{-ov$LY7<4i`P}fK^`$dS9$w4f~&ez9Nir$|5zkOI7O&6T4o<-pLSMT~4Xe z-^B>^{b!y5ltp&D@rN`GKDztv!bs%w<3rpW=KPuhF@2%X)kFEbp%ko29TW4KIV)Gf z1=n3yzTY8&BO5lrr;k2bn76p`G55Id=zYmB*x*-NdNZ0jjojd-BR(Km@YhX1gIC4!38s*}V??P>b-?gm@w2{LE?IS^F?C#@@;iEw4rIo$|?x z_(p{D8%N`xMNA?XY#q|HBmYOqLj=0s_JeVE4T|pE^)R+NPvmY&h*Qm>3~sU3GG7YbcIl+XXiWuIL!=L7hCSXG}YWvuM6NsO_b zIifCCymiTl3~(f>s%;ZpC@o9O`I!6L?D1TxBohCf=slDrrtnEQm@48@BRONngZOro z^JV4i8X~695i82UbNz~r=x}`=&txN|4-63_*i8lkp+Q~mE5~##|L#ZpO$X;M8u8IE zF#;@J?L8YK5tWef03@TT8ZruDiWpJQqUq3~V>&>SQ3JIgCvLGd>-tnPcdtzmBZ5o> zgIA;-OlEX~NS`F#7fz*2<)xV>X84o(XO`#&CxWmWQ%3x#i}U$raV-%eZo!=fIO+6R zl-Xd$%MV{Ap21Yr^p>q9VunAdn!h*cm83@^snjYf1Y0IX7>hBsIY)Gr6~j*J$cUdu zId8XGN2VfTx}(tsJ)IW$HLjgU86=b@dA)NM^!DyED1Vk%MZ^p*7j7CNdfBQ2PU!g% z{~YH050zk7OpGwz!&od&?OnucMq#vry}V)}JSuVTWU8F~ouV zEl2coyBsuv zBO~ta;@sBEQ`?Ez(%$ZGY-kY61=r>_Uaxm{q=Gq1G4gFErqB@wgZE@K&D3hvNXsZD z<3)Ta!ny55IvgQp_)O}6Ml{uGz(({$3CY%Mw%M)@*Ydb$X-@9_jX5{Z=20IkZo zLQJ961Ojj5b^WJS9WAsLNlHaisbD1-Ms-~yW;nrmeL{58-Dzfbbm)G^;g3RHVC>-Orf-#qKF(~ zLlsEGt@%cx2Bxa++~gW2)pcTo-FP6dGOO!`svOlJuIuF7)g3|CN2QS#{_({ZPde)L ziuxvHUrfC$&kZG$jx0nc`r^tuX2a)N6vD`sgbZ+?OI54#hasv)jQBeTgStLp8TABm;r_26g=}!f`La+K8(D z%1jVW$kqfg>VgH+2M`M-5SwNBN+p@B`gOyaAZBXSB35UbJIJ(F>eTw2V@i zH9?GUE*1#v&~$y?LRGDaTe~$wOd=S(N7MDI#@ASIvz3gtRZGOoL867hRO%nqBBLgW o5%Za82M@L>yLO4Qr>Z~y1A4P?_;Ou}SpWb407*qoM6N<$f;CxGaR2}S literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 24d17df2..7e3b48ae 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,19 +1,95 @@ - - - + + + + + + + + + + + + + + android:layout_gravity="bottom" + android:layout_margin="16dp" + android:background="@android:color/white" + android:elevation="8dp" + android:visibility="gone" + app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"> + + + + + + + + - + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml new file mode 100644 index 00000000..9ebba39b --- /dev/null +++ b/app/src/main/res/layout/activity_search.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/empty_activity.xml b/app/src/main/res/layout/empty_activity.xml new file mode 100644 index 00000000..ada6c2fb --- /dev/null +++ b/app/src/main/res/layout/empty_activity.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/list_item.xml b/app/src/main/res/layout/list_item.xml new file mode 100644 index 00000000..41f75936 --- /dev/null +++ b/app/src/main/res/layout/list_item.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/list_keyword.xml b/app/src/main/res/layout/list_keyword.xml new file mode 100644 index 00000000..0adebbaf --- /dev/null +++ b/app/src/main/res/layout/list_keyword.xml @@ -0,0 +1,24 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e5ba5b9c..78fbe22f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,13 @@ Map + 검색어를 입력해 주세요. + 검색 결과가 없습니다. + 삭제 + + + + 지도 인증을 실패했습니다. 다시 시도해주세요 \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 48bba0fc..3d6cd6d5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,14 +1,10 @@ pluginManagement { repositories { - google { - content { - includeGroupByRegex("com\\.android.*") - includeGroupByRegex("com\\.google.*") - includeGroupByRegex("androidx.*") - } - } + google() mavenCentral() gradlePluginPortal() + maven("https://devrepo.kakao.com/nexus/repository/kakaomap-releases/") + maven ( "https://devrepo.kakao.com/nexus/content/groups/public/" ) } } dependencyResolutionManagement { @@ -17,8 +13,10 @@ dependencyResolutionManagement { google() mavenCentral() maven("https://devrepo.kakao.com/nexus/repository/kakaomap-releases/") + maven ("https://devrepo.kakao.com/nexus/content/groups/public/" ) } } rootProject.name = "android-map-refactoring" include(":app") + From 4668c0497a67fee802094441dff350a8ae3813d2 Mon Sep 17 00:00:00 2001 From: jiyeon Date: Tue, 23 Jul 2024 14:16:18 +0900 Subject: [PATCH 03/26] =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tech/kakao/map/uiTest/MainActivityTest.kt | 36 +++++++++++++++ .../kakao/map/uiTest/SearchActivityTest.kt | 44 +++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 app/src/androidTest/java/campus/tech/kakao/map/uiTest/MainActivityTest.kt create mode 100644 app/src/androidTest/java/campus/tech/kakao/map/uiTest/SearchActivityTest.kt diff --git a/app/src/androidTest/java/campus/tech/kakao/map/uiTest/MainActivityTest.kt b/app/src/androidTest/java/campus/tech/kakao/map/uiTest/MainActivityTest.kt new file mode 100644 index 00000000..c9a04394 --- /dev/null +++ b/app/src/androidTest/java/campus/tech/kakao/map/uiTest/MainActivityTest.kt @@ -0,0 +1,36 @@ +package campus.tech.kakao.map.uiTest + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.ext.junit.rules.ActivityScenarioRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import campus.tech.kakao.map.MainActivity +import campus.tech.kakao.map.R +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class MainActivityTest { + + @get:Rule + val activityScenarioRule = ActivityScenarioRule(MainActivity::class.java) + + @Test + fun testSearchEditText_click_opensSearchActivity() { + onView(withId(R.id.search_edit_text)).perform(click()) + onView(withId(R.id.search_text_input)).check(matches(isDisplayed())) + } + + @Test + fun testMapError_displaysErrorLayout() { + // 에러 고의로 발생시켜서 확인 + activityScenarioRule.scenario.onActivity { activity -> + activity.showErrorScreen(Exception("Test error")) + } + onView(withId(R.id.error_layout)).check(matches(isDisplayed())) + onView(withId(R.id.error_message)).check(matches(withText(R.string.map_error_message))) + } +} diff --git a/app/src/androidTest/java/campus/tech/kakao/map/uiTest/SearchActivityTest.kt b/app/src/androidTest/java/campus/tech/kakao/map/uiTest/SearchActivityTest.kt new file mode 100644 index 00000000..b6e87949 --- /dev/null +++ b/app/src/androidTest/java/campus/tech/kakao/map/uiTest/SearchActivityTest.kt @@ -0,0 +1,44 @@ +package campus.tech.kakao.map.viewTest + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.typeText +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.ext.junit.rules.ActivityScenarioRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import campus.tech.kakao.map.R +import campus.tech.kakao.map.view.SearchActivity +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class SearchActivityTest { + + @get:Rule + var activityScenarioRule = ActivityScenarioRule(SearchActivity::class.java) + + @Test + fun testSearchTextInput_typing_displaysResults() { + onView(withId(R.id.search_text_input)).perform(typeText("카페")) + onView(withId(R.id.search_result_view)).check(matches(isDisplayed())) + } + + @Test + fun testDeleteTextInput_click_clearsSearchText() { + onView(withId(R.id.search_text_input)).perform(typeText("카페")) + onView(withId(R.id.delete_text_input)).perform(click()) + onView(withId(R.id.search_text_input)).check(matches(withText(""))) + } + + @Test + fun testKeywordHistoryView_click_displaysKeywordInSearchTextInput() { + // 미리 검색어를 추가하여 테스트 + activityScenarioRule.scenario.onActivity { activity -> + activity.keywordViewModel.saveKeyword("카페") + } + onView(withId(R.id.keyword_history_view)).perform(click()) + onView(withId(R.id.search_text_input)).check(matches(withText("카페"))) + } +} \ No newline at end of file From aa5836cdfc5b110762c6263947de85923ddf98ff Mon Sep 17 00:00:00 2001 From: jiyeon Date: Wed, 24 Jul 2024 12:28:10 +0900 Subject: [PATCH 04/26] =?UTF-8?q?KAKAO=5FAPI=5FKEY=EB=A5=BC=20BuildConfig?= =?UTF-8?q?=EB=A5=BC=20=ED=86=B5=ED=95=B4=20=EA=B0=80=EC=A0=B8=EC=98=A4?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 2 +- app/src/main/AndroidManifest.xml | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 467c51dd..07d253d4 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -29,7 +29,7 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - resValue("string", "KAKAO_API_KEY", getApiKey("kakaoApiKey")) + buildConfigField("String", "KAKAO_API_KEY", getApiKey("kakaoApiKey")) buildConfigField("String", "KAKAO_REST_API_KEY", getApiKey("kakaoRestApiKey")) buildConfigField("String", "KAKAO_BASE_URL", getApiKey("kakaoBaseUrl")) } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 198ab145..3b241c16 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,7 +4,6 @@ - + android:value="${KAKAO_API_KEY}" /> - @@ -34,4 +32,4 @@ - \ No newline at end of file + From af98667d324568cd7cd7a782acd9f20678616dc7 Mon Sep 17 00:00:00 2001 From: jiyeon Date: Wed, 24 Jul 2024 17:56:15 +0900 Subject: [PATCH 05/26] update README.md --- README.md | 8 ++++++-- app/build.gradle.kts | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 57baed12..2aa9f852 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ # android-map-refactoring -## 이전 미션 코드 가져오기 -- 위치 이동 코드를 옮겨 온다. \ No newline at end of file +## 기능 요구 사항 +- 데이터베이스를 Room으로 변경한다. +- 가능한 모든 부분에 대해서 의존성 주입을 적용한다. +## 프로그래밍 요구 사항 +- 의존성 주입을 위해서 Hilt를 사용한다. +- 코드 컨벤션을 준수하며 프로그래밍한다. \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 07d253d4..467c51dd 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -29,7 +29,7 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - buildConfigField("String", "KAKAO_API_KEY", getApiKey("kakaoApiKey")) + resValue("string", "KAKAO_API_KEY", getApiKey("kakaoApiKey")) buildConfigField("String", "KAKAO_REST_API_KEY", getApiKey("kakaoRestApiKey")) buildConfigField("String", "KAKAO_BASE_URL", getApiKey("kakaoBaseUrl")) } From 331daeb28eaa9df516e68cb2638a46f68404a0de Mon Sep 17 00:00:00 2001 From: jiyeon Date: Wed, 24 Jul 2024 17:56:38 +0900 Subject: [PATCH 06/26] =?UTF-8?q?=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=A3=BC?= =?UTF-8?q?=EC=9E=85=EC=9D=84=20=EC=9C=84=ED=95=9C=20AppModule=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 6 +-- .../campus/tech/kakao/map/di/AppModule.kt | 46 +++++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/campus/tech/kakao/map/di/AppModule.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3b241c16..3d2745a0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -18,10 +18,10 @@ + android:value="@string/KAKAO_API_KEY" /> @@ -32,4 +32,4 @@ - + \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/di/AppModule.kt b/app/src/main/java/campus/tech/kakao/map/di/AppModule.kt new file mode 100644 index 00000000..2cb725e4 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/di/AppModule.kt @@ -0,0 +1,46 @@ +package campus.tech.kakao.di + +import android.content.Context +import campus.tech.kakao.map.api.KakaoLocalApi +import campus.tech.kakao.map.repository.keyword.KeywordRepository +import campus.tech.kakao.map.repository.location.LocationSearcher +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object AppModule { + + @Provides + @Singleton + fun provideRetrofit(): Retrofit { + return Retrofit.Builder() + .baseUrl("https://dapi.kakao.com") + .addConverterFactory(GsonConverterFactory.create()) + .build() + } + + @Provides + @Singleton + fun provideKakaoLocalApi(retrofit: Retrofit): KakaoLocalApi { + return retrofit.create(KakaoLocalApi::class.java) + } + + @Provides + @Singleton + fun provideKeywordRepository(@ApplicationContext context: Context): KeywordRepository { + return KeywordRepository(context) + } + + @Provides + @Singleton + fun provideLocationSearcher(@ApplicationContext context: Context): LocationSearcher { + return LocationSearcher(context) + } +} From 555828979a9892c7ec646bfa37951b187d553a3d Mon Sep 17 00:00:00 2001 From: jiyeon Date: Wed, 24 Jul 2024 17:57:30 +0900 Subject: [PATCH 07/26] =?UTF-8?q?update=20Viewmodel=20-=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=EC=84=B1=20=EC=A3=BC=EC=9E=85=20&=20Factory=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../map/viewmodel/OnKeywordItemClickListener.kt | 2 +- .../map/viewmodel/OnSearchItemClickListener.kt | 2 +- .../map/viewmodel/keyword/KeywordViewmodel.kt | 11 ++++++++--- .../viewmodel/keyword/KeywordViewmodelFactory.kt | 15 --------------- .../kakao/map/viewmodel/main/MainViewmodel.kt | 7 ++++++- .../map/viewmodel/main/MainViewmodelFactory.kt | 14 -------------- .../kakao/map/viewmodel/search/SearchViewmodel.kt | 9 +++++++-- .../viewmodel/search/SearchViewmodelFactory.kt | 15 --------------- 8 files changed, 23 insertions(+), 52 deletions(-) delete mode 100644 app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodelFactory.kt delete mode 100644 app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodelFactory.kt delete mode 100644 app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodelFactory.kt diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/OnKeywordItemClickListener.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/OnKeywordItemClickListener.kt index 3118a9c4..3dbd578a 100644 --- a/app/src/main/java/campus/tech/kakao/map/viewmodel/OnKeywordItemClickListener.kt +++ b/app/src/main/java/campus/tech/kakao/map/viewmodel/OnKeywordItemClickListener.kt @@ -3,4 +3,4 @@ package campus.tech.kakao.map.viewmodel interface OnKeywordItemClickListener { fun onKeywordItemDeleteClick(keyword: String) fun onKeywordItemClick(keyword: String) -} +} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/OnSearchItemClickListener.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/OnSearchItemClickListener.kt index df72d9f9..a892b11f 100644 --- a/app/src/main/java/campus/tech/kakao/map/viewmodel/OnSearchItemClickListener.kt +++ b/app/src/main/java/campus/tech/kakao/map/viewmodel/OnSearchItemClickListener.kt @@ -4,4 +4,4 @@ import campus.tech.kakao.map.model.Item interface OnSearchItemClickListener { fun onSearchItemClick(item: Item) -} +} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodel.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodel.kt index c753ca77..156e4bc3 100644 --- a/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodel.kt +++ b/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodel.kt @@ -4,8 +4,13 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import campus.tech.kakao.map.repository.keyword.KeywordRepository +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject -class KeywordViewModel(private val repository: KeywordRepository) : ViewModel() { +@HiltViewModel +class KeywordViewModel @Inject constructor( + private val repository: KeywordRepository +) : ViewModel() { private val _keywords = MutableLiveData>() val keywords: LiveData> get() = _keywords @@ -19,7 +24,7 @@ class KeywordViewModel(private val repository: KeywordRepository) : ViewModel() } fun saveKeyword(keyword: String) { - repository.update(keyword) // 여기서 keyword 변수 사용 + repository.update(keyword) loadKeywords() // 업데이트 후 다시 로드하여 UI 업데이트 } @@ -27,4 +32,4 @@ class KeywordViewModel(private val repository: KeywordRepository) : ViewModel() repository.delete(keyword) loadKeywords() // 삭제 후 다시 로드하여 UI 업데이트 } -} \ No newline at end of file +} diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodelFactory.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodelFactory.kt deleted file mode 100644 index 8fbc0893..00000000 --- a/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodelFactory.kt +++ /dev/null @@ -1,15 +0,0 @@ -package campus.tech.kakao.map.viewmodel.keyword - -import android.content.Context -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import campus.tech.kakao.map.repository.keyword.KeywordRepository - -class KeywordViewModelFactory(private val context: Context) : ViewModelProvider.Factory { - override fun create(modelClass: Class): T { - if (modelClass.isAssignableFrom(KeywordViewModel::class.java)) { - return KeywordViewModel(KeywordRepository.getInstance(context)) as T - } - throw IllegalArgumentException("Unknown ViewModel class") - } -} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodel.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodel.kt index c392c430..c3facc6f 100644 --- a/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodel.kt +++ b/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodel.kt @@ -7,8 +7,13 @@ import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import campus.tech.kakao.map.model.Item +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject -class MainViewModel(application: Application) : AndroidViewModel(application) { +@HiltViewModel +class MainViewModel @Inject constructor( + application: Application +) : AndroidViewModel(application) { private val sharedPreferences: SharedPreferences = application.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) private val _lastMarkerPosition = MutableLiveData() diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodelFactory.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodelFactory.kt deleted file mode 100644 index 02310acd..00000000 --- a/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodelFactory.kt +++ /dev/null @@ -1,14 +0,0 @@ -package campus.tech.kakao.map.viewmodel.main - -import android.app.Application -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider - -class MainViewModelFactory(private val application: Application) : ViewModelProvider.Factory { - override fun create(modelClass: Class): T { - if (modelClass.isAssignableFrom(MainViewModel::class.java)) { - return MainViewModel(application) as T - } - throw IllegalArgumentException("Unknown ViewModel class") - } -} diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodel.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodel.kt index 11d3061b..45632c5a 100644 --- a/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodel.kt +++ b/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodel.kt @@ -3,9 +3,14 @@ package campus.tech.kakao.map.viewmodel.search import androidx.lifecycle.* import campus.tech.kakao.map.api.KakaoLocalApi import campus.tech.kakao.map.model.Item +import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch +import javax.inject.Inject -class SearchViewModel(private val api: KakaoLocalApi) : ViewModel() { +@HiltViewModel +class SearchViewModel @Inject constructor( + private val api: KakaoLocalApi +) : ViewModel() { private val _items = MutableLiveData>() val items: LiveData> get() = _items @@ -22,4 +27,4 @@ class SearchViewModel(private val api: KakaoLocalApi) : ViewModel() { } } } -} \ No newline at end of file +} diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodelFactory.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodelFactory.kt deleted file mode 100644 index c8b5450c..00000000 --- a/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodelFactory.kt +++ /dev/null @@ -1,15 +0,0 @@ -package campus.tech.kakao.map.viewmodel.search - -import android.content.Context -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import campus.tech.kakao.map.api.KakaoLocalApi - -class SearchViewModelFactory(private val api: KakaoLocalApi) : ViewModelProvider.Factory { - override fun create(modelClass: Class): T { - if (modelClass.isAssignableFrom(SearchViewModel::class.java)) { - return SearchViewModel(api) as T - } - throw IllegalArgumentException("Unknown ViewModel class") - } -} \ No newline at end of file From ef9d5400408944ad97e5128109551bb780ff99d5 Mon Sep 17 00:00:00 2001 From: jiyeon Date: Wed, 24 Jul 2024 17:58:13 +0900 Subject: [PATCH 08/26] update MainActivity & SearchActivity --- .../tech/kakao/map/view/MainActivity.kt | 15 +++++++------- .../tech/kakao/map/view/SearchActivity.kt | 20 ++++++++++--------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt b/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt index 17780785..e10710a2 100644 --- a/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt +++ b/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt @@ -28,18 +28,22 @@ import campus.tech.kakao.map.model.Item import campus.tech.kakao.map.repository.location.LocationSearcher import campus.tech.kakao.map.view.SearchActivity import campus.tech.kakao.map.viewmodel.keyword.KeywordViewModel -import campus.tech.kakao.map.viewmodel.keyword.KeywordViewModelFactory import campus.tech.kakao.map.viewmodel.main.MainViewModel -import campus.tech.kakao.map.viewmodel.main.MainViewModelFactory import campus.tech.kakao.map.viewmodel.OnSearchItemClickListener import campus.tech.kakao.map.viewmodel.OnKeywordItemClickListener +import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject +@AndroidEntryPoint class MainActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeywordItemClickListener { private var mapView: MapView? = null private var kakaoMap: KakaoMap? = null private var labelLayer: LabelLayer? = null + @Inject + lateinit var locationSearcher: LocationSearcher + private lateinit var errorLayout: RelativeLayout private lateinit var errorMessage: TextView private lateinit var errorDetails: TextView @@ -49,7 +53,6 @@ class MainActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeywordIt private lateinit var bottomSheetAddress: TextView private lateinit var bottomSheetLayout: FrameLayout private lateinit var searchResultLauncher: ActivityResultLauncher - private lateinit var locationSearcher: LocationSearcher private lateinit var keywordViewModel: KeywordViewModel private lateinit var mainViewModel: MainViewModel @@ -57,11 +60,9 @@ class MainActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeywordIt super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) - locationSearcher = LocationSearcher(this) - // ViewModel 초기화 - keywordViewModel = ViewModelProvider(this, KeywordViewModelFactory(applicationContext)).get(KeywordViewModel::class.java) - mainViewModel = ViewModelProvider(this, MainViewModelFactory(application)).get(MainViewModel::class.java) + keywordViewModel = ViewModelProvider(this).get(KeywordViewModel::class.java) + mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java) // ActivityResultLauncher 초기화 searchResultLauncher = registerForActivityResult( diff --git a/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt b/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt index 3db1f2c9..7d30e800 100644 --- a/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt +++ b/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt @@ -19,14 +19,19 @@ import campus.tech.kakao.map.model.Item import campus.tech.kakao.map.viewmodel.OnKeywordItemClickListener import campus.tech.kakao.map.viewmodel.OnSearchItemClickListener import campus.tech.kakao.map.viewmodel.keyword.KeywordViewModel -import campus.tech.kakao.map.viewmodel.keyword.KeywordViewModelFactory import campus.tech.kakao.map.viewmodel.search.SearchViewModel -import campus.tech.kakao.map.viewmodel.search.SearchViewModelFactory +import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject +@AndroidEntryPoint class SearchActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeywordItemClickListener { private lateinit var binding: ActivitySearchBinding + + @Inject + lateinit var api: KakaoLocalApi + private lateinit var searchViewModel: SearchViewModel - lateinit var keywordViewModel: KeywordViewModel + private lateinit var keywordViewModel: KeywordViewModel private lateinit var searchAdapter: SearchAdapter private lateinit var keywordAdapter: KeywordAdapter @@ -35,12 +40,9 @@ class SearchActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeyword binding = ActivitySearchBinding.inflate(layoutInflater) setContentView(binding.root) - // Retrofit 초기화 - val api = MyApplication.retrofit.create(KakaoLocalApi::class.java) - // ViewModel 초기화 - searchViewModel = ViewModelProvider(this, SearchViewModelFactory(api))[SearchViewModel::class.java] - keywordViewModel = ViewModelProvider(this, KeywordViewModelFactory(applicationContext))[KeywordViewModel::class.java] + searchViewModel = ViewModelProvider(this).get(SearchViewModel::class.java) + keywordViewModel = ViewModelProvider(this).get(KeywordViewModel::class.java) // 검색 결과 RecyclerView 설정 searchAdapter = SearchAdapter(this) @@ -103,4 +105,4 @@ class SearchActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeyword // 저장된 검색어 삭제 keywordViewModel.deleteKeyword(keyword) } -} \ No newline at end of file +} From c7707acbb503edfbb2a6da8229f72752d5170bdb Mon Sep 17 00:00:00 2001 From: jiyeon Date: Wed, 24 Jul 2024 17:58:38 +0900 Subject: [PATCH 09/26] update repository --- .../tech/kakao/map/repository/location/LocationContract.kt | 2 +- .../tech/kakao/map/repository/location/LocationDbHelper.kt | 2 +- .../tech/kakao/map/repository/location/LocationSearcher.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt index db17e41a..2f092075 100644 --- a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt +++ b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt @@ -9,4 +9,4 @@ object LocationContract : BaseColumns { const val CATEGORY_GROUP_NAME = "category_group_name" const val LATITUDE = "latitude" const val LONGITUDE = "longitude" -} +} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationDbHelper.kt b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationDbHelper.kt index 270bc19e..6f479d85 100644 --- a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationDbHelper.kt +++ b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationDbHelper.kt @@ -33,4 +33,4 @@ class LocationDbHelper(context: Context) : private const val DATABASE_VERSION = 1 private const val DATABASE_NAME = "location.db" } -} +} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt index 31866b44..aae1edf1 100644 --- a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt +++ b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt @@ -48,4 +48,4 @@ class LocationSearcher(private val context: Context) { return LocationSearcher(context) } } -} +} \ No newline at end of file From 780930ec8c06aaf05f674beeb593534d18bd5a02 Mon Sep 17 00:00:00 2001 From: jiyeon Date: Wed, 24 Jul 2024 17:59:53 +0900 Subject: [PATCH 10/26] update api & model package --- app/src/main/java/campus/tech/kakao/map/api/KakaoLocalApi.kt | 2 +- .../main/java/campus/tech/kakao/map/model/{item.kt => Item.kt} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename app/src/main/java/campus/tech/kakao/map/model/{item.kt => Item.kt} (98%) diff --git a/app/src/main/java/campus/tech/kakao/map/api/KakaoLocalApi.kt b/app/src/main/java/campus/tech/kakao/map/api/KakaoLocalApi.kt index 8b0771f8..50333460 100644 --- a/app/src/main/java/campus/tech/kakao/map/api/KakaoLocalApi.kt +++ b/app/src/main/java/campus/tech/kakao/map/api/KakaoLocalApi.kt @@ -51,4 +51,4 @@ data class Meta( @SerializedName("is_end") val isEnd: Boolean -) +) \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/model/item.kt b/app/src/main/java/campus/tech/kakao/map/model/Item.kt similarity index 98% rename from app/src/main/java/campus/tech/kakao/map/model/item.kt rename to app/src/main/java/campus/tech/kakao/map/model/Item.kt index 27363ca9..f18a2a04 100644 --- a/app/src/main/java/campus/tech/kakao/map/model/item.kt +++ b/app/src/main/java/campus/tech/kakao/map/model/Item.kt @@ -6,4 +6,4 @@ data class Item( val category: String, val latitude: Double, val longitude:Double -) +) \ No newline at end of file From bb111708e5f4d9c2c057ffb8009300094e8eca7e Mon Sep 17 00:00:00 2001 From: jiyeon Date: Wed, 24 Jul 2024 18:00:04 +0900 Subject: [PATCH 11/26] update MyApplication --- app/src/main/java/campus/tech/kakao/MyApplication.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/campus/tech/kakao/MyApplication.kt b/app/src/main/java/campus/tech/kakao/MyApplication.kt index 8bd13a92..be3b169b 100644 --- a/app/src/main/java/campus/tech/kakao/MyApplication.kt +++ b/app/src/main/java/campus/tech/kakao/MyApplication.kt @@ -4,9 +4,11 @@ import android.app.Application import campus.tech.kakao.map.BuildConfig import com.kakao.vectormap.KakaoMapSdk import campus.tech.kakao.map.R +import dagger.hilt.android.HiltAndroidApp import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory +@HiltAndroidApp class MyApplication : Application() { companion object { @@ -26,4 +28,4 @@ class MyApplication : Application() { .addConverterFactory(GsonConverterFactory.create()) .build() } -} +} \ No newline at end of file From 981ac9be8d4f70a6642ce3276f94cfcacc8e93ab Mon Sep 17 00:00:00 2001 From: jiyeon Date: Thu, 25 Jul 2024 15:56:00 +0900 Subject: [PATCH 12/26] update Step1 --- .../java/campus/tech/kakao/MyApplication.kt | 20 +----- .../tech/kakao/map/database/AppDatabase.kt | 14 +++++ .../campus/tech/kakao/map/di/AppModule.kt | 2 +- .../java/campus/tech/kakao/map/model/Item.kt | 9 ++- .../campus/tech/kakao/map/model/Keyword.kt | 10 +++ .../map/repository/keyword/KeywordContract.kt | 8 --- .../map/repository/keyword/KeywordDao.kt | 19 ++++++ .../map/repository/keyword/KeywordDbHelper.kt | 44 ------------- .../repository/keyword/KeywordRepository.kt | 62 +++++-------------- .../kakao/map/repository/location/ItemDao.kt | 19 ++++++ .../repository/location/LocationContract.kt | 12 ---- .../repository/location/LocationDbHelper.kt | 36 ----------- .../repository/location/LocationSearcher.kt | 55 ++++------------ .../tech/kakao/map/view/MainActivity.kt | 27 +++----- .../tech/kakao/map/view/SearchActivity.kt | 2 - .../map/viewmodel/keyword/KeywordViewmodel.kt | 18 ++++-- .../kakao/map/viewmodel/main/MainViewmodel.kt | 2 +- .../map/viewmodel/search/SearchViewmodel.kt | 8 ++- 18 files changed, 129 insertions(+), 238 deletions(-) create mode 100644 app/src/main/java/campus/tech/kakao/map/database/AppDatabase.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/model/Keyword.kt delete mode 100644 app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordContract.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDao.kt delete mode 100644 app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDbHelper.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/repository/location/ItemDao.kt delete mode 100644 app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt delete mode 100644 app/src/main/java/campus/tech/kakao/map/repository/location/LocationDbHelper.kt diff --git a/app/src/main/java/campus/tech/kakao/MyApplication.kt b/app/src/main/java/campus/tech/kakao/MyApplication.kt index be3b169b..ab7243a8 100644 --- a/app/src/main/java/campus/tech/kakao/MyApplication.kt +++ b/app/src/main/java/campus/tech/kakao/MyApplication.kt @@ -1,31 +1,15 @@ package campus.tech.kakao import android.app.Application -import campus.tech.kakao.map.BuildConfig import com.kakao.vectormap.KakaoMapSdk +import campus.tech.kakao.map.BuildConfig import campus.tech.kakao.map.R import dagger.hilt.android.HiltAndroidApp -import retrofit2.Retrofit -import retrofit2.converter.gson.GsonConverterFactory @HiltAndroidApp class MyApplication : Application() { - - companion object { - lateinit var retrofit: Retrofit - private set - } - override fun onCreate() { super.onCreate() - - // 카카오 지도 SDK 초기화 KakaoMapSdk.init(this, getString(R.string.KAKAO_API_KEY)) - - // Retrofit 초기화 - retrofit = Retrofit.Builder() - .baseUrl(BuildConfig.KAKAO_BASE_URL) - .addConverterFactory(GsonConverterFactory.create()) - .build() } -} \ No newline at end of file +} diff --git a/app/src/main/java/campus/tech/kakao/map/database/AppDatabase.kt b/app/src/main/java/campus/tech/kakao/map/database/AppDatabase.kt new file mode 100644 index 00000000..03e9618f --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/database/AppDatabase.kt @@ -0,0 +1,14 @@ +package campus.tech.kakao.map.database + +import androidx.room.Database +import androidx.room.RoomDatabase +import campus.tech.kakao.map.model.Keyword +import campus.tech.kakao.map.model.Item +import campus.tech.kakao.map.repository.keyword.KeywordDao +import campus.tech.kakao.map.repository.location.ItemDao + +@Database(entities = [Keyword::class, Item::class], version = 1) +abstract class AppDatabase : RoomDatabase() { + abstract fun keywordDao(): KeywordDao + abstract fun itemDao(): ItemDao +} diff --git a/app/src/main/java/campus/tech/kakao/map/di/AppModule.kt b/app/src/main/java/campus/tech/kakao/map/di/AppModule.kt index 2cb725e4..420b71ba 100644 --- a/app/src/main/java/campus/tech/kakao/map/di/AppModule.kt +++ b/app/src/main/java/campus/tech/kakao/map/di/AppModule.kt @@ -43,4 +43,4 @@ object AppModule { fun provideLocationSearcher(@ApplicationContext context: Context): LocationSearcher { return LocationSearcher(context) } -} +} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/model/Item.kt b/app/src/main/java/campus/tech/kakao/map/model/Item.kt index f18a2a04..a715e872 100644 --- a/app/src/main/java/campus/tech/kakao/map/model/Item.kt +++ b/app/src/main/java/campus/tech/kakao/map/model/Item.kt @@ -1,9 +1,14 @@ package campus.tech.kakao.map.model +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "location") data class Item( + @PrimaryKey(autoGenerate = true) val id: Int = 0, // 기본값 추가 val place: String, val address: String, val category: String, val latitude: Double, - val longitude:Double -) \ No newline at end of file + val longitude: Double +) diff --git a/app/src/main/java/campus/tech/kakao/map/model/Keyword.kt b/app/src/main/java/campus/tech/kakao/map/model/Keyword.kt new file mode 100644 index 00000000..487eae05 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/model/Keyword.kt @@ -0,0 +1,10 @@ +package campus.tech.kakao.map.model + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "keyword") +data class Keyword( + @PrimaryKey(autoGenerate = true) val id: Int = 0, + val recentKeyword: String +) diff --git a/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordContract.kt b/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordContract.kt deleted file mode 100644 index c27ea5a2..00000000 --- a/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordContract.kt +++ /dev/null @@ -1,8 +0,0 @@ -package campus.tech.kakao.map.repository.keyword - -import android.provider.BaseColumns - -object KeywordContract : BaseColumns { - const val TABLE_NAME = "keyword" - const val RECENT_KEYWORD = "recent_keyword" -} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDao.kt b/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDao.kt new file mode 100644 index 00000000..aa4baa48 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDao.kt @@ -0,0 +1,19 @@ +package campus.tech.kakao.map.repository.keyword + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Delete +import campus.tech.kakao.map.model.Keyword + +@Dao +interface KeywordDao { + @Insert + suspend fun insert(keyword: Keyword) + + @Query("SELECT * FROM keyword") + suspend fun getAllKeywords(): List + + @Delete + suspend fun delete(keyword: Keyword) +} diff --git a/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDbHelper.kt b/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDbHelper.kt deleted file mode 100644 index 469e36f4..00000000 --- a/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDbHelper.kt +++ /dev/null @@ -1,44 +0,0 @@ -package campus.tech.kakao.map.repository.keyword - -import android.content.Context -import android.database.sqlite.SQLiteOpenHelper -import android.database.sqlite.SQLiteDatabase -import android.provider.BaseColumns - -class KeywordDbHelper(context: Context) : - SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) { - - override fun onCreate(db: SQLiteDatabase?) { - db?.let { createDatabase(it) } - } - - override fun onUpgrade( - db: SQLiteDatabase?, - oldVersion: Int, - newVersion: Int - ) { - db?.let { upgradeDatabase(it, oldVersion, newVersion) } - } - - private fun createDatabase(db: SQLiteDatabase) { - db.execSQL(SQL_CREATE_ENTRIES) - } - - private fun upgradeDatabase(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { - db.execSQL(SQL_DELETE_ENTRIES) - createDatabase(db) - } - - companion object { - private const val SQL_CREATE_ENTRIES = - "CREATE TABLE ${KeywordContract.TABLE_NAME} (" + - "${BaseColumns._ID} INTEGER PRIMARY KEY," + - "${KeywordContract.RECENT_KEYWORD} TEXT)" - - private const val SQL_DELETE_ENTRIES = - "DROP TABLE IF EXISTS ${KeywordContract.TABLE_NAME}" - - private const val DATABASE_VERSION = 1 - private const val DATABASE_NAME = "keyword.db" - } -} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordRepository.kt b/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordRepository.kt index fc8efdbb..67bab2e0 100644 --- a/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordRepository.kt +++ b/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordRepository.kt @@ -1,55 +1,27 @@ package campus.tech.kakao.map.repository.keyword -import android.content.ContentValues import android.content.Context +import androidx.room.Room +import campus.tech.kakao.map.database.AppDatabase +import campus.tech.kakao.map.model.Keyword class KeywordRepository(context: Context) { - - private val dbHelper = KeywordDbHelper(context) - - fun update(keyword: String) { - val db = dbHelper.writableDatabase - val values = ContentValues().apply { - put(KeywordContract.RECENT_KEYWORD, keyword) - } - db.insert(KeywordContract.TABLE_NAME, null, values) - } - - fun read(): List { - val keywords = mutableListOf() - val db = dbHelper.readableDatabase - val projection = arrayOf(KeywordContract.RECENT_KEYWORD) - val cursor = db.query( - KeywordContract.TABLE_NAME, - projection, - null, - null, - null, - null, - null - ) - - with(cursor) { - while (moveToNext()) { - keywords.add(getString(getColumnIndexOrThrow(KeywordContract.RECENT_KEYWORD))) - } - close() - } - return keywords + private val db = Room.databaseBuilder( + context.applicationContext, + AppDatabase::class.java, "app-database" + ).build() + private val keywordDao = db.keywordDao() + + suspend fun update(keyword: String) { + keywordDao.insert(Keyword(recentKeyword = keyword)) } - fun delete(keyword: String) { - val db = dbHelper.writableDatabase - db.delete( - KeywordContract.TABLE_NAME, - "${KeywordContract.RECENT_KEYWORD} = ?", - arrayOf(keyword) - ) + suspend fun read(): List { + return keywordDao.getAllKeywords().map { it.recentKeyword } } - companion object { - fun getInstance(context: Context): KeywordRepository { - return KeywordRepository(context) - } + suspend fun delete(keyword: String) { + val keywordEntity = keywordDao.getAllKeywords().find { it.recentKeyword == keyword } + keywordEntity?.let { keywordDao.delete(it) } } -} \ No newline at end of file +} diff --git a/app/src/main/java/campus/tech/kakao/map/repository/location/ItemDao.kt b/app/src/main/java/campus/tech/kakao/map/repository/location/ItemDao.kt new file mode 100644 index 00000000..d76fa620 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/repository/location/ItemDao.kt @@ -0,0 +1,19 @@ +package campus.tech.kakao.map.repository.location + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Delete +import campus.tech.kakao.map.model.Item + +@Dao +interface ItemDao { + @Query("SELECT * FROM location WHERE category LIKE :keyword") + suspend fun search(keyword: String): List + + @Insert + suspend fun insert(item: Item) + + @Delete + suspend fun delete(item: Item) +} diff --git a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt deleted file mode 100644 index 2f092075..00000000 --- a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt +++ /dev/null @@ -1,12 +0,0 @@ -package campus.tech.kakao.map.repository.location - -import android.provider.BaseColumns - -object LocationContract : BaseColumns { - const val TABLE_NAME = "location" - const val PLACE_NAME = "place_name" - const val ADDRESS_NAME = "address_name" - const val CATEGORY_GROUP_NAME = "category_group_name" - const val LATITUDE = "latitude" - const val LONGITUDE = "longitude" -} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationDbHelper.kt b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationDbHelper.kt deleted file mode 100644 index 6f479d85..00000000 --- a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationDbHelper.kt +++ /dev/null @@ -1,36 +0,0 @@ -package campus.tech.kakao.map.repository.location - -import android.content.Context -import android.database.sqlite.SQLiteDatabase -import android.database.sqlite.SQLiteOpenHelper -import android.provider.BaseColumns - -class LocationDbHelper(context: Context) : - SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) { - - override fun onCreate(db: SQLiteDatabase?) { - db?.execSQL(SQL_CREATE_ENTRIES) - } - - override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) { - db?.execSQL(SQL_DELETE_ENTRIES) - onCreate(db) - } - - companion object { - private const val SQL_CREATE_ENTRIES = - "CREATE TABLE ${LocationContract.TABLE_NAME} (" + - "${BaseColumns._ID} INTEGER PRIMARY KEY," + - "${LocationContract.PLACE_NAME} TEXT," + - "${LocationContract.ADDRESS_NAME} TEXT," + - "${LocationContract.CATEGORY_GROUP_NAME} TEXT," + - "${LocationContract.LATITUDE} REAL," + - "${LocationContract.LONGITUDE} REAL)" - - private const val SQL_DELETE_ENTRIES = - "DROP TABLE IF EXISTS ${LocationContract.TABLE_NAME}" - - private const val DATABASE_VERSION = 1 - private const val DATABASE_NAME = "location.db" - } -} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt index aae1edf1..4ccb8752 100644 --- a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt +++ b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt @@ -1,51 +1,18 @@ package campus.tech.kakao.map.repository.location import android.content.Context +import androidx.room.Room +import campus.tech.kakao.map.database.AppDatabase import campus.tech.kakao.map.model.Item -class LocationSearcher(private val context: Context) { - fun search(keyword: String): List { - val items = mutableListOf() - val dbHelper = LocationDbHelper(context) - val db = dbHelper.readableDatabase - val projection = arrayOf( - LocationContract.PLACE_NAME, - LocationContract.ADDRESS_NAME, - LocationContract.CATEGORY_GROUP_NAME, - LocationContract.LATITUDE, - LocationContract.LONGITUDE - ) +class LocationSearcher(context: Context) { + private val db = Room.databaseBuilder( + context.applicationContext, + AppDatabase::class.java, "app-database" + ).build() + private val itemDao = db.itemDao() - val selection = "${LocationContract.CATEGORY_GROUP_NAME} = ?" - val selectionArgs = arrayOf(keyword) - val sortOrder = "${LocationContract.CATEGORY_GROUP_NAME} DESC" - val cursor = db.query( - LocationContract.TABLE_NAME, - projection, - selection, - selectionArgs, - null, - null, - sortOrder - ) - - with(cursor) { - while (moveToNext()) { - val placeName = getString(getColumnIndexOrThrow(LocationContract.PLACE_NAME)) - val addressName = getString(getColumnIndexOrThrow(LocationContract.ADDRESS_NAME)) - val categoryGroupName = getString(getColumnIndexOrThrow(LocationContract.CATEGORY_GROUP_NAME)) - val latitude = getDouble(getColumnIndexOrThrow(LocationContract.LATITUDE)) - val longitude = getDouble(getColumnIndexOrThrow(LocationContract.LONGITUDE)) - items.add(Item(placeName, addressName, categoryGroupName, latitude, longitude)) - } - close() - } - return items - } - - companion object { - fun getInstance(context: Context): LocationSearcher { - return LocationSearcher(context) - } + suspend fun search(keyword: String): List { + return itemDao.search("%$keyword%") } -} \ No newline at end of file +} diff --git a/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt b/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt index e10710a2..295015a4 100644 --- a/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt +++ b/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt @@ -12,9 +12,9 @@ import android.widget.TextView import android.widget.Toast import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts +import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModelProvider import com.google.android.material.bottomsheet.BottomSheetBehavior import com.kakao.vectormap.* import com.kakao.vectormap.camera.CameraAnimation @@ -53,16 +53,15 @@ class MainActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeywordIt private lateinit var bottomSheetAddress: TextView private lateinit var bottomSheetLayout: FrameLayout private lateinit var searchResultLauncher: ActivityResultLauncher - private lateinit var keywordViewModel: KeywordViewModel - private lateinit var mainViewModel: MainViewModel + private val keywordViewModel: KeywordViewModel by viewModels() + private val mainViewModel: MainViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) - // ViewModel 초기화 - keywordViewModel = ViewModelProvider(this).get(KeywordViewModel::class.java) - mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java) + // View 초기화 + initializeViews() // ActivityResultLauncher 초기화 searchResultLauncher = registerForActivityResult( @@ -97,12 +96,6 @@ class MainActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeywordIt searchResultLauncher.launch(intent) } - // 에러 화면 초기화 - initializeErrorScreen() - - // BottomSheet 초기화 - initializeBottomSheet() - // Observe the last marker position mainViewModel.lastMarkerPosition.observe(this, Observer { item -> item?.let { @@ -115,22 +108,17 @@ class MainActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeywordIt }) } - private fun initializeErrorScreen() { + private fun initializeViews() { errorLayout = findViewById(R.id.error_layout) errorMessage = findViewById(R.id.error_message) errorDetails = findViewById(R.id.error_details) retryButton = findViewById(R.id.retry_button) retryButton.setOnClickListener { onRetryButtonClick() } - } - private fun initializeBottomSheet() { bottomSheetLayout = findViewById(R.id.bottomSheetLayout) bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetLayout) bottomSheetTitle = findViewById(R.id.bottomSheetTitle) bottomSheetAddress = findViewById(R.id.bottomSheetAddress) - - // 처음에는 BottomSheet 숨기기 - bottomSheetLayout.visibility = View.GONE } private fun handleSearchResult(data: Intent?) { @@ -151,7 +139,8 @@ class MainActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeywordIt Log.d(TAG, "Search result: $placeName, $roadAddressName, $latitude, $longitude") - val item = Item(placeName, roadAddressName, "", latitude, longitude) + // latitude와 longitude 값을 Double로 명시적으로 변환하여 Item 객체를 생성 + val item = Item(place = placeName, address = roadAddressName, category = "", latitude = latitude, longitude = longitude) addLabel(item) mainViewModel.saveLastMarkerPosition(item) } diff --git a/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt b/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt index 7d30e800..e861b115 100644 --- a/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt +++ b/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt @@ -9,8 +9,6 @@ import androidx.core.widget.doAfterTextChanged import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager -import campus.tech.kakao.MyApplication -import campus.tech.kakao.map.BuildConfig import campus.tech.kakao.map.adapter.keyword.KeywordAdapter import campus.tech.kakao.map.adapter.search.SearchAdapter import campus.tech.kakao.map.api.KakaoLocalApi diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodel.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodel.kt index 156e4bc3..3dc67819 100644 --- a/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodel.kt +++ b/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodel.kt @@ -3,9 +3,11 @@ package campus.tech.kakao.map.viewmodel.keyword import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import campus.tech.kakao.map.repository.keyword.KeywordRepository import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject +import kotlinx.coroutines.launch @HiltViewModel class KeywordViewModel @Inject constructor( @@ -20,16 +22,22 @@ class KeywordViewModel @Inject constructor( } private fun loadKeywords() { - _keywords.value = repository.read() + viewModelScope.launch { + _keywords.value = repository.read() + } } fun saveKeyword(keyword: String) { - repository.update(keyword) - loadKeywords() // 업데이트 후 다시 로드하여 UI 업데이트 + viewModelScope.launch { + repository.update(keyword) + loadKeywords() + } } fun deleteKeyword(keyword: String) { - repository.delete(keyword) - loadKeywords() // 삭제 후 다시 로드하여 UI 업데이트 + viewModelScope.launch { + repository.delete(keyword) + loadKeywords() + } } } diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodel.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodel.kt index c3facc6f..67af6aa0 100644 --- a/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodel.kt +++ b/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodel.kt @@ -42,7 +42,7 @@ class MainViewModel @Inject constructor( val roadAddressName = sharedPreferences.getString(PREF_ROAD_ADDRESS_NAME, "") ?: "" _lastMarkerPosition.value = if (placeName.isNotEmpty() && roadAddressName.isNotEmpty()) { - Item(placeName, roadAddressName, "", latitude, longitude) + Item(place = placeName, address = roadAddressName, category = "", latitude = latitude, longitude = longitude) } else { null } diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodel.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodel.kt index 45632c5a..21a7c556 100644 --- a/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodel.kt +++ b/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodel.kt @@ -20,7 +20,13 @@ class SearchViewModel @Inject constructor( try { val response = api.searchKeyword("KakaoAK ${campus.tech.kakao.map.BuildConfig.KAKAO_REST_API_KEY}", keyword) _items.value = response.documents.map { - Item(it.placeName, it.addressName, it.categoryGroupName, it.latitude, it.longitude) + Item( + place = it.placeName, + address = it.addressName, + category = it.categoryGroupName, + latitude = it.latitude, + longitude = it.longitude + ) } } catch (e: Exception) { e.printStackTrace() From c432f98266334710a206a3c75439e3fbd7dea602 Mon Sep 17 00:00:00 2001 From: jiyeon Date: Fri, 26 Jul 2024 15:09:41 +0900 Subject: [PATCH 13/26] =?UTF-8?q?MainActivity=EC=97=90=20dataBinding=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tech/kakao/map/view/MainActivity.kt | 26 +-- app/src/main/res/layout/activity_main.xml | 152 ++++++++++-------- 2 files changed, 98 insertions(+), 80 deletions(-) diff --git a/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt b/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt index 295015a4..78244ce6 100644 --- a/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt +++ b/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt @@ -15,6 +15,7 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer +import androidx.databinding.DataBindingUtil import com.google.android.material.bottomsheet.BottomSheetBehavior import com.kakao.vectormap.* import com.kakao.vectormap.camera.CameraAnimation @@ -24,6 +25,7 @@ import com.kakao.vectormap.label.LabelOptions import com.kakao.vectormap.label.LabelStyle import com.kakao.vectormap.label.LabelStyles import com.kakao.vectormap.label.LabelTextStyle +import campus.tech.kakao.map.databinding.ActivityMainBinding import campus.tech.kakao.map.model.Item import campus.tech.kakao.map.repository.location.LocationSearcher import campus.tech.kakao.map.view.SearchActivity @@ -58,10 +60,14 @@ class MainActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeywordIt override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) + val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main) + binding.lifecycleOwner = this // 생명주기 소유자 성정 + binding.viewModel = mainViewModel // Viewmodel 바인딩 + binding.keywordViewModel = keywordViewModel // Keyword viewmodel 바인딩 // View 초기화 - initializeViews() + // 바인딩을 활용하여 초기화하도록 변경 + initializeViews(binding) // ActivityResultLauncher 초기화 searchResultLauncher = registerForActivityResult( @@ -108,17 +114,17 @@ class MainActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeywordIt }) } - private fun initializeViews() { - errorLayout = findViewById(R.id.error_layout) - errorMessage = findViewById(R.id.error_message) - errorDetails = findViewById(R.id.error_details) - retryButton = findViewById(R.id.retry_button) + private fun initializeViews(binding: ActivityMainBinding) { // 바인딩을 통해 초기화 + errorLayout = binding.errorLayout + errorMessage = binding.errorMessage + errorDetails = binding.errorDetails + retryButton = binding.retryButton retryButton.setOnClickListener { onRetryButtonClick() } - bottomSheetLayout = findViewById(R.id.bottomSheetLayout) + bottomSheetLayout = binding.bottomSheetLayout bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetLayout) - bottomSheetTitle = findViewById(R.id.bottomSheetTitle) - bottomSheetAddress = findViewById(R.id.bottomSheetAddress) + bottomSheetTitle = binding.bottomSheetTitle + bottomSheetAddress = binding.bottomSheetAddress } private fun handleSearchResult(data: Intent?) { diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 7e3b48ae..2e73bac9 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,95 +1,107 @@ - + xmlns:tools="http://schemas.android.com/tools"> - - - + + + + - + tools:context=".MainActivity"> - - - + - - + android:hint="검색어를 입력하세요" + android:layout_alignParentTop="true" + android:layout_margin="16dp" + android:background="@android:drawable/editbox_background"/> - - - + android:gravity="center"> - - - \ No newline at end of file + + + + + + + + + + + + + + + From 02061732d8fc66a5a2f05e8db52b8af61b8f80ff Mon Sep 17 00:00:00 2001 From: jiyeon Date: Fri, 26 Jul 2024 15:15:08 +0900 Subject: [PATCH 14/26] update README.md --- README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 2aa9f852..dc08388c 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # android-map-refactoring ## 기능 요구 사항 -- 데이터베이스를 Room으로 변경한다. -- 가능한 모든 부분에 대해서 의존성 주입을 적용한다. -## 프로그래밍 요구 사항 -- 의존성 주입을 위해서 Hilt를 사용한다. -- 코드 컨벤션을 준수하며 프로그래밍한다. \ No newline at end of file +- MVVM 아키텍처 패턴을 적용한다. +- DataBinding, LiveData를 사용한다. +- 비동기 처리를 Coroutine으로 변경한다. \ No newline at end of file From ee465f35226577fc6d49386594e5ea57a4900f02 Mon Sep 17 00:00:00 2001 From: jiyeon Date: Sun, 28 Jul 2024 22:10:59 +0900 Subject: [PATCH 15/26] =?UTF-8?q?AppDatabase=EB=A5=BC=20Singleton=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20Hilt=EC=9D=84=20=ED=86=B5=ED=95=B4=20=EC=A3=BC?= =?UTF-8?q?=EC=9E=85=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tech/kakao/map/database/AppDatabase.kt | 8 +-- .../campus/tech/kakao/map/di/AppModule.kt | 20 +------ .../tech/kakao/map/di/DatabaseModule.kt | 56 +++++++++++++++++++ .../tech/kakao/map/entity/KeywordEntity.kt | 11 ++++ .../tech/kakao/map/entity/LocationEntity.kt | 15 +++++ .../java/campus/tech/kakao/map/model/Item.kt | 5 -- .../map/repository/keyword/KeywordDao.kt | 15 ++--- .../repository/keyword/KeywordRepository.kt | 28 ++++------ .../kakao/map/repository/location/ItemDao.kt | 14 +---- .../repository/location/LocationContract.kt | 12 ++++ .../repository/location/LocationSearcher.kt | 25 +++++---- .../map/viewmodel/keyword/KeywordViewmodel.kt | 2 +- 12 files changed, 138 insertions(+), 73 deletions(-) create mode 100644 app/src/main/java/campus/tech/kakao/map/di/DatabaseModule.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/entity/KeywordEntity.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/entity/LocationEntity.kt create mode 100644 app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt diff --git a/app/src/main/java/campus/tech/kakao/map/database/AppDatabase.kt b/app/src/main/java/campus/tech/kakao/map/database/AppDatabase.kt index 03e9618f..9b178346 100644 --- a/app/src/main/java/campus/tech/kakao/map/database/AppDatabase.kt +++ b/app/src/main/java/campus/tech/kakao/map/database/AppDatabase.kt @@ -2,13 +2,13 @@ package campus.tech.kakao.map.database import androidx.room.Database import androidx.room.RoomDatabase -import campus.tech.kakao.map.model.Keyword -import campus.tech.kakao.map.model.Item +import campus.tech.kakao.map.entity.KeywordEntity +import campus.tech.kakao.map.entity.LocationEntity import campus.tech.kakao.map.repository.keyword.KeywordDao import campus.tech.kakao.map.repository.location.ItemDao -@Database(entities = [Keyword::class, Item::class], version = 1) +@Database(entities = [KeywordEntity::class, LocationEntity::class], version = 2) abstract class AppDatabase : RoomDatabase() { abstract fun keywordDao(): KeywordDao abstract fun itemDao(): ItemDao -} +} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/di/AppModule.kt b/app/src/main/java/campus/tech/kakao/map/di/AppModule.kt index 420b71ba..138aad92 100644 --- a/app/src/main/java/campus/tech/kakao/map/di/AppModule.kt +++ b/app/src/main/java/campus/tech/kakao/map/di/AppModule.kt @@ -1,13 +1,9 @@ -package campus.tech.kakao.di +package campus.tech.kakao.map.di -import android.content.Context import campus.tech.kakao.map.api.KakaoLocalApi -import campus.tech.kakao.map.repository.keyword.KeywordRepository -import campus.tech.kakao.map.repository.location.LocationSearcher import dagger.Module import dagger.Provides import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory @@ -31,16 +27,4 @@ object AppModule { fun provideKakaoLocalApi(retrofit: Retrofit): KakaoLocalApi { return retrofit.create(KakaoLocalApi::class.java) } - - @Provides - @Singleton - fun provideKeywordRepository(@ApplicationContext context: Context): KeywordRepository { - return KeywordRepository(context) - } - - @Provides - @Singleton - fun provideLocationSearcher(@ApplicationContext context: Context): LocationSearcher { - return LocationSearcher(context) - } -} \ No newline at end of file +} diff --git a/app/src/main/java/campus/tech/kakao/map/di/DatabaseModule.kt b/app/src/main/java/campus/tech/kakao/map/di/DatabaseModule.kt new file mode 100644 index 00000000..810166ff --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/di/DatabaseModule.kt @@ -0,0 +1,56 @@ +package campus.tech.kakao.map.di + +import android.content.Context +import androidx.room.Room +import campus.tech.kakao.map.database.AppDatabase +import campus.tech.kakao.map.repository.keyword.KeywordDao +import campus.tech.kakao.map.repository.location.ItemDao +import campus.tech.kakao.map.repository.keyword.KeywordRepository +import campus.tech.kakao.map.repository.location.LocationSearcher +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object DatabaseModule { + + @Provides + @Singleton + fun provideDatabase(@ApplicationContext context: Context): AppDatabase { + return Room.databaseBuilder( + context.applicationContext, + AppDatabase::class.java, + "app_database" + ) + .fallbackToDestructiveMigration() //필요시 마이그레이션 재생성 + .build() + } + + @Provides + @Singleton + fun provideKeywordDao(database: AppDatabase): KeywordDao { + return database.keywordDao() + } + + @Provides + @Singleton + fun provideItemDao(database: AppDatabase): ItemDao { + return database.itemDao() + } + + @Provides + @Singleton + fun provideKeywordRepository(keywordDao: KeywordDao): KeywordRepository { + return KeywordRepository(keywordDao) + } + + @Provides + @Singleton + fun provideLocationSearcher(itemDao: ItemDao): LocationSearcher { + return LocationSearcher(itemDao) + } +} diff --git a/app/src/main/java/campus/tech/kakao/map/entity/KeywordEntity.kt b/app/src/main/java/campus/tech/kakao/map/entity/KeywordEntity.kt new file mode 100644 index 00000000..4c6aab23 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/entity/KeywordEntity.kt @@ -0,0 +1,11 @@ +package campus.tech.kakao.map.entity + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "keywords") +data class KeywordEntity( + @PrimaryKey(autoGenerate = true) val id: Int = 0, + @ColumnInfo(name = "keyword") val keyword: String +) diff --git a/app/src/main/java/campus/tech/kakao/map/entity/LocationEntity.kt b/app/src/main/java/campus/tech/kakao/map/entity/LocationEntity.kt new file mode 100644 index 00000000..3875c2c4 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/entity/LocationEntity.kt @@ -0,0 +1,15 @@ +package campus.tech.kakao.map.entity + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "location") +data class LocationEntity( + @PrimaryKey(autoGenerate = true) val id: Int = 0, + @ColumnInfo(name = "place_name") val placeName: String, + @ColumnInfo(name = "address_name") val addressName: String, + @ColumnInfo(name = "category_group_name") val categoryGroupName: String, + @ColumnInfo(name = "latitude") val latitude: Double, + @ColumnInfo(name = "longitude") val longitude: Double +) diff --git a/app/src/main/java/campus/tech/kakao/map/model/Item.kt b/app/src/main/java/campus/tech/kakao/map/model/Item.kt index a715e872..0708e2d9 100644 --- a/app/src/main/java/campus/tech/kakao/map/model/Item.kt +++ b/app/src/main/java/campus/tech/kakao/map/model/Item.kt @@ -1,11 +1,6 @@ package campus.tech.kakao.map.model -import androidx.room.Entity -import androidx.room.PrimaryKey - -@Entity(tableName = "location") data class Item( - @PrimaryKey(autoGenerate = true) val id: Int = 0, // 기본값 추가 val place: String, val address: String, val category: String, diff --git a/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDao.kt b/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDao.kt index aa4baa48..09b0b57f 100644 --- a/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDao.kt +++ b/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDao.kt @@ -1,19 +1,20 @@ package campus.tech.kakao.map.repository.keyword import androidx.room.Dao +import androidx.room.Delete import androidx.room.Insert +import androidx.room.OnConflictStrategy import androidx.room.Query -import androidx.room.Delete -import campus.tech.kakao.map.model.Keyword +import campus.tech.kakao.map.entity.KeywordEntity @Dao interface KeywordDao { - @Insert - suspend fun insert(keyword: Keyword) + @Query("SELECT * FROM keywords") + suspend fun getAllKeywords(): List - @Query("SELECT * FROM keyword") - suspend fun getAllKeywords(): List + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertKeyword(keyword: KeywordEntity) @Delete - suspend fun delete(keyword: Keyword) + suspend fun deleteKeyword(keyword: KeywordEntity) } diff --git a/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordRepository.kt b/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordRepository.kt index 67bab2e0..652dd9d3 100644 --- a/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordRepository.kt +++ b/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordRepository.kt @@ -1,27 +1,21 @@ package campus.tech.kakao.map.repository.keyword -import android.content.Context -import androidx.room.Room -import campus.tech.kakao.map.database.AppDatabase -import campus.tech.kakao.map.model.Keyword +import campus.tech.kakao.map.entity.KeywordEntity +import javax.inject.Inject +import javax.inject.Singleton -class KeywordRepository(context: Context) { - private val db = Room.databaseBuilder( - context.applicationContext, - AppDatabase::class.java, "app-database" - ).build() - private val keywordDao = db.keywordDao() +@Singleton +class KeywordRepository @Inject constructor(private val keywordDao: KeywordDao) { - suspend fun update(keyword: String) { - keywordDao.insert(Keyword(recentKeyword = keyword)) + suspend fun read(): List { + return keywordDao.getAllKeywords().map { it.keyword } } - suspend fun read(): List { - return keywordDao.getAllKeywords().map { it.recentKeyword } + suspend fun update(keyword: String) { + keywordDao.insertKeyword(KeywordEntity(keyword = keyword)) } suspend fun delete(keyword: String) { - val keywordEntity = keywordDao.getAllKeywords().find { it.recentKeyword == keyword } - keywordEntity?.let { keywordDao.delete(it) } + keywordDao.deleteKeyword(KeywordEntity(keyword = keyword)) } -} +} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/repository/location/ItemDao.kt b/app/src/main/java/campus/tech/kakao/map/repository/location/ItemDao.kt index d76fa620..3b26aee8 100644 --- a/app/src/main/java/campus/tech/kakao/map/repository/location/ItemDao.kt +++ b/app/src/main/java/campus/tech/kakao/map/repository/location/ItemDao.kt @@ -1,19 +1,11 @@ package campus.tech.kakao.map.repository.location import androidx.room.Dao -import androidx.room.Insert import androidx.room.Query -import androidx.room.Delete -import campus.tech.kakao.map.model.Item +import campus.tech.kakao.map.entity.LocationEntity @Dao interface ItemDao { - @Query("SELECT * FROM location WHERE category LIKE :keyword") - suspend fun search(keyword: String): List - - @Insert - suspend fun insert(item: Item) - - @Delete - suspend fun delete(item: Item) + @Query("SELECT * FROM location WHERE category_group_name = :category") + suspend fun searchByCategory(category: String): List } diff --git a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt new file mode 100644 index 00000000..db17e41a --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt @@ -0,0 +1,12 @@ +package campus.tech.kakao.map.repository.location + +import android.provider.BaseColumns + +object LocationContract : BaseColumns { + const val TABLE_NAME = "location" + const val PLACE_NAME = "place_name" + const val ADDRESS_NAME = "address_name" + const val CATEGORY_GROUP_NAME = "category_group_name" + const val LATITUDE = "latitude" + const val LONGITUDE = "longitude" +} diff --git a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt index 4ccb8752..c87a5382 100644 --- a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt +++ b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt @@ -1,18 +1,23 @@ package campus.tech.kakao.map.repository.location -import android.content.Context -import androidx.room.Room -import campus.tech.kakao.map.database.AppDatabase +import campus.tech.kakao.map.entity.LocationEntity import campus.tech.kakao.map.model.Item +import javax.inject.Inject +import javax.inject.Singleton -class LocationSearcher(context: Context) { - private val db = Room.databaseBuilder( - context.applicationContext, - AppDatabase::class.java, "app-database" - ).build() - private val itemDao = db.itemDao() +@Singleton +class LocationSearcher @Inject constructor(private val itemDao: ItemDao) { suspend fun search(keyword: String): List { - return itemDao.search("%$keyword%") + val locationEntities = itemDao.searchByCategory(keyword) + return locationEntities.map { + Item( + place = it.placeName, + address = it.addressName, + category = it.categoryGroupName, + latitude = it.latitude, + longitude = it.longitude + ) + } } } diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodel.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodel.kt index 3dc67819..826d63c6 100644 --- a/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodel.kt +++ b/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodel.kt @@ -40,4 +40,4 @@ class KeywordViewModel @Inject constructor( loadKeywords() } } -} +} \ No newline at end of file From 12cb5236234ed176a865673792c78593425816b0 Mon Sep 17 00:00:00 2001 From: nJiyeon <150491973+nJiyeon@users.noreply.github.com> Date: Mon, 29 Jul 2024 14:40:53 +0900 Subject: [PATCH 16/26] Delete app/src/main/java/campus/tech/kakao/map/model/item.kt --- app/src/main/java/campus/tech/kakao/map/model/item.kt | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 app/src/main/java/campus/tech/kakao/map/model/item.kt diff --git a/app/src/main/java/campus/tech/kakao/map/model/item.kt b/app/src/main/java/campus/tech/kakao/map/model/item.kt deleted file mode 100644 index 27363ca9..00000000 --- a/app/src/main/java/campus/tech/kakao/map/model/item.kt +++ /dev/null @@ -1,9 +0,0 @@ -package campus.tech.kakao.map.model - -data class Item( - val place: String, - val address: String, - val category: String, - val latitude: Double, - val longitude:Double -) From 2c0fa80c9c1880aa33b2b01476fb779494d09fe5 Mon Sep 17 00:00:00 2001 From: nJiyeon <150491973+nJiyeon@users.noreply.github.com> Date: Mon, 29 Jul 2024 14:41:56 +0900 Subject: [PATCH 17/26] Delete app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDbHelper.kt Delete KeywordDbHelper --- .../map/repository/keyword/KeywordDbHelper.kt | 44 ------------------- 1 file changed, 44 deletions(-) delete mode 100644 app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDbHelper.kt diff --git a/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDbHelper.kt b/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDbHelper.kt deleted file mode 100644 index 469e36f4..00000000 --- a/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDbHelper.kt +++ /dev/null @@ -1,44 +0,0 @@ -package campus.tech.kakao.map.repository.keyword - -import android.content.Context -import android.database.sqlite.SQLiteOpenHelper -import android.database.sqlite.SQLiteDatabase -import android.provider.BaseColumns - -class KeywordDbHelper(context: Context) : - SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) { - - override fun onCreate(db: SQLiteDatabase?) { - db?.let { createDatabase(it) } - } - - override fun onUpgrade( - db: SQLiteDatabase?, - oldVersion: Int, - newVersion: Int - ) { - db?.let { upgradeDatabase(it, oldVersion, newVersion) } - } - - private fun createDatabase(db: SQLiteDatabase) { - db.execSQL(SQL_CREATE_ENTRIES) - } - - private fun upgradeDatabase(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { - db.execSQL(SQL_DELETE_ENTRIES) - createDatabase(db) - } - - companion object { - private const val SQL_CREATE_ENTRIES = - "CREATE TABLE ${KeywordContract.TABLE_NAME} (" + - "${BaseColumns._ID} INTEGER PRIMARY KEY," + - "${KeywordContract.RECENT_KEYWORD} TEXT)" - - private const val SQL_DELETE_ENTRIES = - "DROP TABLE IF EXISTS ${KeywordContract.TABLE_NAME}" - - private const val DATABASE_VERSION = 1 - private const val DATABASE_NAME = "keyword.db" - } -} \ No newline at end of file From 694c18798e1896900ba7818a849492ab1b9aa923 Mon Sep 17 00:00:00 2001 From: nJiyeon <150491973+nJiyeon@users.noreply.github.com> Date: Mon, 29 Jul 2024 14:42:21 +0900 Subject: [PATCH 18/26] Delete app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordContract.kt Delete KeywordContract --- .../tech/kakao/map/repository/keyword/KeywordContract.kt | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordContract.kt diff --git a/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordContract.kt b/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordContract.kt deleted file mode 100644 index c27ea5a2..00000000 --- a/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordContract.kt +++ /dev/null @@ -1,8 +0,0 @@ -package campus.tech.kakao.map.repository.keyword - -import android.provider.BaseColumns - -object KeywordContract : BaseColumns { - const val TABLE_NAME = "keyword" - const val RECENT_KEYWORD = "recent_keyword" -} \ No newline at end of file From bbdcde391202c88306f4335be163b1e1c44eecb5 Mon Sep 17 00:00:00 2001 From: nJiyeon <150491973+nJiyeon@users.noreply.github.com> Date: Mon, 29 Jul 2024 14:43:55 +0900 Subject: [PATCH 19/26] Delete app/src/main/java/campus/tech/kakao/map/repository/location/LocationDbHelper.kt delete LocationDbHelper --- .../repository/location/LocationDbHelper.kt | 36 ------------------- 1 file changed, 36 deletions(-) delete mode 100644 app/src/main/java/campus/tech/kakao/map/repository/location/LocationDbHelper.kt diff --git a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationDbHelper.kt b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationDbHelper.kt deleted file mode 100644 index 270bc19e..00000000 --- a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationDbHelper.kt +++ /dev/null @@ -1,36 +0,0 @@ -package campus.tech.kakao.map.repository.location - -import android.content.Context -import android.database.sqlite.SQLiteDatabase -import android.database.sqlite.SQLiteOpenHelper -import android.provider.BaseColumns - -class LocationDbHelper(context: Context) : - SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) { - - override fun onCreate(db: SQLiteDatabase?) { - db?.execSQL(SQL_CREATE_ENTRIES) - } - - override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) { - db?.execSQL(SQL_DELETE_ENTRIES) - onCreate(db) - } - - companion object { - private const val SQL_CREATE_ENTRIES = - "CREATE TABLE ${LocationContract.TABLE_NAME} (" + - "${BaseColumns._ID} INTEGER PRIMARY KEY," + - "${LocationContract.PLACE_NAME} TEXT," + - "${LocationContract.ADDRESS_NAME} TEXT," + - "${LocationContract.CATEGORY_GROUP_NAME} TEXT," + - "${LocationContract.LATITUDE} REAL," + - "${LocationContract.LONGITUDE} REAL)" - - private const val SQL_DELETE_ENTRIES = - "DROP TABLE IF EXISTS ${LocationContract.TABLE_NAME}" - - private const val DATABASE_VERSION = 1 - private const val DATABASE_NAME = "location.db" - } -} From 3b17d382b78c2d421473003e15b078b18afb55ff Mon Sep 17 00:00:00 2001 From: jiyeon Date: Mon, 29 Jul 2024 14:48:12 +0900 Subject: [PATCH 20/26] =?UTF-8?q?OnKeywordItemClickListener,=20OnSearchIte?= =?UTF-8?q?mClickListener=EB=A5=BC=20view=EB=A1=9C=20=EC=98=AE=EA=B8=B0?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/campus/tech/kakao/MyApplication.kt | 1 - .../tech/kakao/map/adapter/keyword/KeywordAdapter.kt | 2 +- .../campus/tech/kakao/map/adapter/search/SearchAdapter.kt | 2 +- app/src/main/java/campus/tech/kakao/map/di/AppModule.kt | 2 +- .../java/campus/tech/kakao/map/entity/KeywordEntity.kt | 2 +- .../java/campus/tech/kakao/map/entity/LocationEntity.kt | 2 +- app/src/main/java/campus/tech/kakao/map/model/Item.kt | 2 +- app/src/main/java/campus/tech/kakao/map/model/Keyword.kt | 2 +- .../campus/tech/kakao/map/repository/keyword/KeywordDao.kt | 2 +- .../campus/tech/kakao/map/repository/location/ItemDao.kt | 2 +- .../tech/kakao/map/repository/location/LocationContract.kt | 2 +- .../main/java/campus/tech/kakao/map/view/MainActivity.kt | 4 ++-- .../map/{viewmodel => view}/OnKeywordItemClickListener.kt | 2 +- .../map/{viewmodel => view}/OnSearchItemClickListener.kt | 2 +- .../main/java/campus/tech/kakao/map/view/SearchActivity.kt | 7 +------ 15 files changed, 15 insertions(+), 21 deletions(-) rename app/src/main/java/campus/tech/kakao/map/{viewmodel => view}/OnKeywordItemClickListener.kt (77%) rename app/src/main/java/campus/tech/kakao/map/{viewmodel => view}/OnSearchItemClickListener.kt (74%) diff --git a/app/src/main/java/campus/tech/kakao/MyApplication.kt b/app/src/main/java/campus/tech/kakao/MyApplication.kt index ab7243a8..e1d4eaec 100644 --- a/app/src/main/java/campus/tech/kakao/MyApplication.kt +++ b/app/src/main/java/campus/tech/kakao/MyApplication.kt @@ -2,7 +2,6 @@ package campus.tech.kakao import android.app.Application import com.kakao.vectormap.KakaoMapSdk -import campus.tech.kakao.map.BuildConfig import campus.tech.kakao.map.R import dagger.hilt.android.HiltAndroidApp diff --git a/app/src/main/java/campus/tech/kakao/map/adapter/keyword/KeywordAdapter.kt b/app/src/main/java/campus/tech/kakao/map/adapter/keyword/KeywordAdapter.kt index 0c0bd926..7e84e95f 100644 --- a/app/src/main/java/campus/tech/kakao/map/adapter/keyword/KeywordAdapter.kt +++ b/app/src/main/java/campus/tech/kakao/map/adapter/keyword/KeywordAdapter.kt @@ -9,7 +9,7 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import campus.tech.kakao.map.R -import campus.tech.kakao.map.viewmodel.OnKeywordItemClickListener +import campus.tech.kakao.map.view.OnKeywordItemClickListener class KeywordAdapter(private val onKeywordItemClickListener: OnKeywordItemClickListener) : ListAdapter( diff --git a/app/src/main/java/campus/tech/kakao/map/adapter/search/SearchAdapter.kt b/app/src/main/java/campus/tech/kakao/map/adapter/search/SearchAdapter.kt index fcfbaa47..2596d6ac 100644 --- a/app/src/main/java/campus/tech/kakao/map/adapter/search/SearchAdapter.kt +++ b/app/src/main/java/campus/tech/kakao/map/adapter/search/SearchAdapter.kt @@ -10,7 +10,7 @@ import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import campus.tech.kakao.map.R import campus.tech.kakao.map.model.Item -import campus.tech.kakao.map.viewmodel.OnSearchItemClickListener +import campus.tech.kakao.map.view.OnSearchItemClickListener class SearchAdapter( private val onSearchItemClickListener: OnSearchItemClickListener diff --git a/app/src/main/java/campus/tech/kakao/map/di/AppModule.kt b/app/src/main/java/campus/tech/kakao/map/di/AppModule.kt index 138aad92..7d7f2b85 100644 --- a/app/src/main/java/campus/tech/kakao/map/di/AppModule.kt +++ b/app/src/main/java/campus/tech/kakao/map/di/AppModule.kt @@ -27,4 +27,4 @@ object AppModule { fun provideKakaoLocalApi(retrofit: Retrofit): KakaoLocalApi { return retrofit.create(KakaoLocalApi::class.java) } -} +} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/entity/KeywordEntity.kt b/app/src/main/java/campus/tech/kakao/map/entity/KeywordEntity.kt index 4c6aab23..0ec47d18 100644 --- a/app/src/main/java/campus/tech/kakao/map/entity/KeywordEntity.kt +++ b/app/src/main/java/campus/tech/kakao/map/entity/KeywordEntity.kt @@ -8,4 +8,4 @@ import androidx.room.PrimaryKey data class KeywordEntity( @PrimaryKey(autoGenerate = true) val id: Int = 0, @ColumnInfo(name = "keyword") val keyword: String -) +) \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/entity/LocationEntity.kt b/app/src/main/java/campus/tech/kakao/map/entity/LocationEntity.kt index 3875c2c4..15184089 100644 --- a/app/src/main/java/campus/tech/kakao/map/entity/LocationEntity.kt +++ b/app/src/main/java/campus/tech/kakao/map/entity/LocationEntity.kt @@ -12,4 +12,4 @@ data class LocationEntity( @ColumnInfo(name = "category_group_name") val categoryGroupName: String, @ColumnInfo(name = "latitude") val latitude: Double, @ColumnInfo(name = "longitude") val longitude: Double -) +) \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/model/Item.kt b/app/src/main/java/campus/tech/kakao/map/model/Item.kt index 0708e2d9..6ff34e77 100644 --- a/app/src/main/java/campus/tech/kakao/map/model/Item.kt +++ b/app/src/main/java/campus/tech/kakao/map/model/Item.kt @@ -6,4 +6,4 @@ data class Item( val category: String, val latitude: Double, val longitude: Double -) +) \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/model/Keyword.kt b/app/src/main/java/campus/tech/kakao/map/model/Keyword.kt index 487eae05..0b5be24a 100644 --- a/app/src/main/java/campus/tech/kakao/map/model/Keyword.kt +++ b/app/src/main/java/campus/tech/kakao/map/model/Keyword.kt @@ -7,4 +7,4 @@ import androidx.room.PrimaryKey data class Keyword( @PrimaryKey(autoGenerate = true) val id: Int = 0, val recentKeyword: String -) +) \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDao.kt b/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDao.kt index 09b0b57f..f4a188c2 100644 --- a/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDao.kt +++ b/app/src/main/java/campus/tech/kakao/map/repository/keyword/KeywordDao.kt @@ -17,4 +17,4 @@ interface KeywordDao { @Delete suspend fun deleteKeyword(keyword: KeywordEntity) -} +} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/repository/location/ItemDao.kt b/app/src/main/java/campus/tech/kakao/map/repository/location/ItemDao.kt index 3b26aee8..81f9eacf 100644 --- a/app/src/main/java/campus/tech/kakao/map/repository/location/ItemDao.kt +++ b/app/src/main/java/campus/tech/kakao/map/repository/location/ItemDao.kt @@ -8,4 +8,4 @@ import campus.tech.kakao.map.entity.LocationEntity interface ItemDao { @Query("SELECT * FROM location WHERE category_group_name = :category") suspend fun searchByCategory(category: String): List -} +} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt index db17e41a..2f092075 100644 --- a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt +++ b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt @@ -9,4 +9,4 @@ object LocationContract : BaseColumns { const val CATEGORY_GROUP_NAME = "category_group_name" const val LATITUDE = "latitude" const val LONGITUDE = "longitude" -} +} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt b/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt index 2bc3b5a1..de5613fe 100644 --- a/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt +++ b/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt @@ -31,8 +31,8 @@ import campus.tech.kakao.map.repository.location.LocationSearcher import campus.tech.kakao.map.view.SearchActivity import campus.tech.kakao.map.viewmodel.keyword.KeywordViewModel import campus.tech.kakao.map.viewmodel.main.MainViewModel -import campus.tech.kakao.map.viewmodel.OnSearchItemClickListener -import campus.tech.kakao.map.viewmodel.OnKeywordItemClickListener +import campus.tech.kakao.map.view.OnSearchItemClickListener +import campus.tech.kakao.map.view.OnKeywordItemClickListener import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/OnKeywordItemClickListener.kt b/app/src/main/java/campus/tech/kakao/map/view/OnKeywordItemClickListener.kt similarity index 77% rename from app/src/main/java/campus/tech/kakao/map/viewmodel/OnKeywordItemClickListener.kt rename to app/src/main/java/campus/tech/kakao/map/view/OnKeywordItemClickListener.kt index 3dbd578a..a98e667e 100644 --- a/app/src/main/java/campus/tech/kakao/map/viewmodel/OnKeywordItemClickListener.kt +++ b/app/src/main/java/campus/tech/kakao/map/view/OnKeywordItemClickListener.kt @@ -1,4 +1,4 @@ -package campus.tech.kakao.map.viewmodel +package campus.tech.kakao.map.view interface OnKeywordItemClickListener { fun onKeywordItemDeleteClick(keyword: String) diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/OnSearchItemClickListener.kt b/app/src/main/java/campus/tech/kakao/map/view/OnSearchItemClickListener.kt similarity index 74% rename from app/src/main/java/campus/tech/kakao/map/viewmodel/OnSearchItemClickListener.kt rename to app/src/main/java/campus/tech/kakao/map/view/OnSearchItemClickListener.kt index a892b11f..cd986ce6 100644 --- a/app/src/main/java/campus/tech/kakao/map/viewmodel/OnSearchItemClickListener.kt +++ b/app/src/main/java/campus/tech/kakao/map/view/OnSearchItemClickListener.kt @@ -1,4 +1,4 @@ -package campus.tech.kakao.map.viewmodel +package campus.tech.kakao.map.view import campus.tech.kakao.map.model.Item diff --git a/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt b/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt index 23cd1fac..49b3561b 100644 --- a/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt +++ b/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt @@ -14,8 +14,6 @@ import campus.tech.kakao.map.adapter.search.SearchAdapter import campus.tech.kakao.map.api.KakaoLocalApi import campus.tech.kakao.map.databinding.ActivitySearchBinding import campus.tech.kakao.map.model.Item -import campus.tech.kakao.map.viewmodel.OnKeywordItemClickListener -import campus.tech.kakao.map.viewmodel.OnSearchItemClickListener import campus.tech.kakao.map.viewmodel.keyword.KeywordViewModel import campus.tech.kakao.map.viewmodel.search.SearchViewModel import dagger.hilt.android.AndroidEntryPoint @@ -25,8 +23,6 @@ import javax.inject.Inject class SearchActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeywordItemClickListener { private lateinit var binding: ActivitySearchBinding - @Inject - lateinit var api: KakaoLocalApi private lateinit var searchViewModel: SearchViewModel private lateinit var keywordViewModel: KeywordViewModel @@ -103,5 +99,4 @@ class SearchActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeyword // 저장된 검색어 삭제 keywordViewModel.deleteKeyword(keyword) } -} - +} \ No newline at end of file From ea80f634eab07c0cbe66f78b174295ae883b3ad3 Mon Sep 17 00:00:00 2001 From: jiyeon Date: Mon, 29 Jul 2024 14:51:25 +0900 Subject: [PATCH 21/26] =?UTF-8?q?Rebase=20=EC=98=A4=EB=A5=98=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../viewmodel/keyword/KeywordViewmodelFactory.kt | 15 --------------- .../map/viewmodel/main/MainViewmodelFactory.kt | 14 -------------- .../viewmodel/search/SearchViewmodelFactory.kt | 15 --------------- 3 files changed, 44 deletions(-) delete mode 100644 app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodelFactory.kt delete mode 100644 app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodelFactory.kt delete mode 100644 app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodelFactory.kt diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodelFactory.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodelFactory.kt deleted file mode 100644 index 8fbc0893..00000000 --- a/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodelFactory.kt +++ /dev/null @@ -1,15 +0,0 @@ -package campus.tech.kakao.map.viewmodel.keyword - -import android.content.Context -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import campus.tech.kakao.map.repository.keyword.KeywordRepository - -class KeywordViewModelFactory(private val context: Context) : ViewModelProvider.Factory { - override fun create(modelClass: Class): T { - if (modelClass.isAssignableFrom(KeywordViewModel::class.java)) { - return KeywordViewModel(KeywordRepository.getInstance(context)) as T - } - throw IllegalArgumentException("Unknown ViewModel class") - } -} \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodelFactory.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodelFactory.kt deleted file mode 100644 index 02310acd..00000000 --- a/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodelFactory.kt +++ /dev/null @@ -1,14 +0,0 @@ -package campus.tech.kakao.map.viewmodel.main - -import android.app.Application -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider - -class MainViewModelFactory(private val application: Application) : ViewModelProvider.Factory { - override fun create(modelClass: Class): T { - if (modelClass.isAssignableFrom(MainViewModel::class.java)) { - return MainViewModel(application) as T - } - throw IllegalArgumentException("Unknown ViewModel class") - } -} diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodelFactory.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodelFactory.kt deleted file mode 100644 index c8b5450c..00000000 --- a/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodelFactory.kt +++ /dev/null @@ -1,15 +0,0 @@ -package campus.tech.kakao.map.viewmodel.search - -import android.content.Context -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import campus.tech.kakao.map.api.KakaoLocalApi - -class SearchViewModelFactory(private val api: KakaoLocalApi) : ViewModelProvider.Factory { - override fun create(modelClass: Class): T { - if (modelClass.isAssignableFrom(SearchViewModel::class.java)) { - return SearchViewModel(api) as T - } - throw IllegalArgumentException("Unknown ViewModel class") - } -} \ No newline at end of file From 8eb54f68faf36f1e8c76be95c280ecccdd723b71 Mon Sep 17 00:00:00 2001 From: jiyeon Date: Mon, 29 Jul 2024 15:19:37 +0900 Subject: [PATCH 22/26] =?UTF-8?q?by=20viewmodel=EC=9D=84=20=ED=99=9C?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EC=97=AC=20viewmodel=EC=9D=84=20lazy?= =?UTF-8?q?=ED=95=98=EA=B2=8C=20=EB=B0=9B=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tech/kakao/map/view/MainActivity.kt | 11 +++++----- .../tech/kakao/map/view/SearchActivity.kt | 22 ++++++------------- .../map/viewmodel/keyword/KeywordViewmodel.kt | 3 +-- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt b/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt index de5613fe..1bbeadff 100644 --- a/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt +++ b/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt @@ -55,18 +55,19 @@ class MainActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeywordIt private lateinit var bottomSheetAddress: TextView private lateinit var bottomSheetLayout: FrameLayout private lateinit var searchResultLauncher: ActivityResultLauncher + + // ViewModel을 Lazy하게 제공받기 private val keywordViewModel: KeywordViewModel by viewModels() private val mainViewModel: MainViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main) - binding.lifecycleOwner = this // 생명주기 소유자 성정 - binding.viewModel = mainViewModel // Viewmodel 바인딩 - binding.keywordViewModel = keywordViewModel // Keyword viewmodel 바인딩 + binding.lifecycleOwner = this // 생명주기 소유자 설정 + binding.viewModel = mainViewModel // ViewModel 바인딩 + binding.keywordViewModel = keywordViewModel // Keyword ViewModel 바인딩 // View 초기화 - // 바인딩을 활용하여 초기화하도록 변경 initializeViews(binding) // ActivityResultLauncher 초기화 @@ -254,4 +255,4 @@ class MainActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeywordIt private const val DEFAULT_ZOOM_LEVEL = 1 private const val CAMERA_ANIMATION_DURATION = 10 } -} \ No newline at end of file +} diff --git a/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt b/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt index 49b3561b..c56e644e 100644 --- a/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt +++ b/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt @@ -4,42 +4,34 @@ import android.app.Activity import android.content.Intent import android.os.Bundle import android.view.View +import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.core.widget.doAfterTextChanged -import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import campus.tech.kakao.map.adapter.keyword.KeywordAdapter import campus.tech.kakao.map.adapter.search.SearchAdapter -import campus.tech.kakao.map.api.KakaoLocalApi import campus.tech.kakao.map.databinding.ActivitySearchBinding import campus.tech.kakao.map.model.Item import campus.tech.kakao.map.viewmodel.keyword.KeywordViewModel import campus.tech.kakao.map.viewmodel.search.SearchViewModel import dagger.hilt.android.AndroidEntryPoint -import javax.inject.Inject @AndroidEntryPoint class SearchActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeywordItemClickListener { private lateinit var binding: ActivitySearchBinding - - private lateinit var searchViewModel: SearchViewModel - private lateinit var keywordViewModel: KeywordViewModel - private lateinit var searchAdapter: SearchAdapter - private lateinit var keywordAdapter: KeywordAdapter + // ViewModel을 Lazy하게 제공받기 + private val searchViewModel: SearchViewModel by viewModels() + private val keywordViewModel: KeywordViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivitySearchBinding.inflate(layoutInflater) setContentView(binding.root) - // ViewModel 초기화 - searchViewModel = ViewModelProvider(this).get(SearchViewModel::class.java) - keywordViewModel = ViewModelProvider(this).get(KeywordViewModel::class.java) - // 검색 결과 RecyclerView 설정 - searchAdapter = SearchAdapter(this) + var searchAdapter = SearchAdapter(this) binding.searchResultView.apply { layoutManager = LinearLayoutManager(this@SearchActivity) adapter = searchAdapter @@ -47,7 +39,7 @@ class SearchActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeyword } // 검색어 목록 RecyclerView 설정 - keywordAdapter = KeywordAdapter(this) + var keywordAdapter = KeywordAdapter(this) binding.keywordHistoryView.apply { layoutManager = LinearLayoutManager(this@SearchActivity, LinearLayoutManager.HORIZONTAL, false) adapter = keywordAdapter @@ -99,4 +91,4 @@ class SearchActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeyword // 저장된 검색어 삭제 keywordViewModel.deleteKeyword(keyword) } -} \ No newline at end of file +} diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodel.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodel.kt index a9349aed..826d63c6 100644 --- a/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodel.kt +++ b/app/src/main/java/campus/tech/kakao/map/viewmodel/keyword/KeywordViewmodel.kt @@ -40,5 +40,4 @@ class KeywordViewModel @Inject constructor( loadKeywords() } } -} - +} \ No newline at end of file From 2b38b12bedbd495f5c724edb353ca7ae27507b14 Mon Sep 17 00:00:00 2001 From: jiyeon Date: Mon, 29 Jul 2024 15:41:12 +0900 Subject: [PATCH 23/26] update DatabaseModule --- app/src/main/java/campus/tech/kakao/map/di/DatabaseModule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/campus/tech/kakao/map/di/DatabaseModule.kt b/app/src/main/java/campus/tech/kakao/map/di/DatabaseModule.kt index 810166ff..1ce1515b 100644 --- a/app/src/main/java/campus/tech/kakao/map/di/DatabaseModule.kt +++ b/app/src/main/java/campus/tech/kakao/map/di/DatabaseModule.kt @@ -26,7 +26,7 @@ object DatabaseModule { AppDatabase::class.java, "app_database" ) - .fallbackToDestructiveMigration() //필요시 마이그레이션 재생성 + .fallbackToDestructiveMigration() // 필요시 마이그레이션 재생성 .build() } From 76fc3d1028aff9eb9362882cb20783ff0cd3566f Mon Sep 17 00:00:00 2001 From: jiyeon Date: Mon, 29 Jul 2024 15:46:58 +0900 Subject: [PATCH 24/26] =?UTF-8?q?itemDao=EB=A5=BC=20locationDao=EB=A1=9C?= =?UTF-8?q?=20=EB=B0=94=EA=BE=B8=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/campus/tech/kakao/map/database/AppDatabase.kt | 4 ++-- .../java/campus/tech/kakao/map/di/DatabaseModule.kt | 10 +++++----- .../repository/location/{ItemDao.kt => LocationDao.kt} | 4 ++-- .../kakao/map/repository/location/LocationSearcher.kt | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) rename app/src/main/java/campus/tech/kakao/map/repository/location/{ItemDao.kt => LocationDao.kt} (85%) diff --git a/app/src/main/java/campus/tech/kakao/map/database/AppDatabase.kt b/app/src/main/java/campus/tech/kakao/map/database/AppDatabase.kt index 9b178346..e218bfb2 100644 --- a/app/src/main/java/campus/tech/kakao/map/database/AppDatabase.kt +++ b/app/src/main/java/campus/tech/kakao/map/database/AppDatabase.kt @@ -5,10 +5,10 @@ import androidx.room.RoomDatabase import campus.tech.kakao.map.entity.KeywordEntity import campus.tech.kakao.map.entity.LocationEntity import campus.tech.kakao.map.repository.keyword.KeywordDao -import campus.tech.kakao.map.repository.location.ItemDao +import campus.tech.kakao.map.repository.location.LocationDao @Database(entities = [KeywordEntity::class, LocationEntity::class], version = 2) abstract class AppDatabase : RoomDatabase() { abstract fun keywordDao(): KeywordDao - abstract fun itemDao(): ItemDao + abstract fun locationDao(): LocationDao } \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/di/DatabaseModule.kt b/app/src/main/java/campus/tech/kakao/map/di/DatabaseModule.kt index 1ce1515b..f29cf8af 100644 --- a/app/src/main/java/campus/tech/kakao/map/di/DatabaseModule.kt +++ b/app/src/main/java/campus/tech/kakao/map/di/DatabaseModule.kt @@ -4,7 +4,7 @@ import android.content.Context import androidx.room.Room import campus.tech.kakao.map.database.AppDatabase import campus.tech.kakao.map.repository.keyword.KeywordDao -import campus.tech.kakao.map.repository.location.ItemDao +import campus.tech.kakao.map.repository.location.LocationDao import campus.tech.kakao.map.repository.keyword.KeywordRepository import campus.tech.kakao.map.repository.location.LocationSearcher import dagger.Module @@ -38,8 +38,8 @@ object DatabaseModule { @Provides @Singleton - fun provideItemDao(database: AppDatabase): ItemDao { - return database.itemDao() + fun provideItemDao(database: AppDatabase): LocationDao { + return database.locationDao() } @Provides @@ -50,7 +50,7 @@ object DatabaseModule { @Provides @Singleton - fun provideLocationSearcher(itemDao: ItemDao): LocationSearcher { - return LocationSearcher(itemDao) + fun provideLocationSearcher(locationDao: LocationDao): LocationSearcher { + return LocationSearcher(locationDao) } } diff --git a/app/src/main/java/campus/tech/kakao/map/repository/location/ItemDao.kt b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationDao.kt similarity index 85% rename from app/src/main/java/campus/tech/kakao/map/repository/location/ItemDao.kt rename to app/src/main/java/campus/tech/kakao/map/repository/location/LocationDao.kt index 81f9eacf..abe76027 100644 --- a/app/src/main/java/campus/tech/kakao/map/repository/location/ItemDao.kt +++ b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationDao.kt @@ -5,7 +5,7 @@ import androidx.room.Query import campus.tech.kakao.map.entity.LocationEntity @Dao -interface ItemDao { +interface LocationDao { // ItemDao 이름 변경 @Query("SELECT * FROM location WHERE category_group_name = :category") suspend fun searchByCategory(category: String): List -} \ No newline at end of file +} diff --git a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt index 57909855..5cb79cd1 100644 --- a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt +++ b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt @@ -5,10 +5,10 @@ import javax.inject.Inject import javax.inject.Singleton @Singleton -class LocationSearcher @Inject constructor(private val itemDao: ItemDao) { +class LocationSearcher @Inject constructor(private val locationDao: LocationDao) { suspend fun search(keyword: String): List { - val locationEntities = itemDao.searchByCategory(keyword) + val locationEntities = locationDao.searchByCategory(keyword) return locationEntities.map { Item( place = it.placeName, From 7ce9a824e0df89b22cd1bd7d3298b91675cc322f Mon Sep 17 00:00:00 2001 From: jiyeon Date: Mon, 29 Jul 2024 15:47:24 +0900 Subject: [PATCH 25/26] delete LocationContract --- .../map/repository/location/LocationContract.kt | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt diff --git a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt deleted file mode 100644 index 2f092075..00000000 --- a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationContract.kt +++ /dev/null @@ -1,12 +0,0 @@ -package campus.tech.kakao.map.repository.location - -import android.provider.BaseColumns - -object LocationContract : BaseColumns { - const val TABLE_NAME = "location" - const val PLACE_NAME = "place_name" - const val ADDRESS_NAME = "address_name" - const val CATEGORY_GROUP_NAME = "category_group_name" - const val LATITUDE = "latitude" - const val LONGITUDE = "longitude" -} \ No newline at end of file From 874ee985a8e6a620344c3a757d640abdb2505506 Mon Sep 17 00:00:00 2001 From: jiyeon Date: Mon, 29 Jul 2024 16:03:45 +0900 Subject: [PATCH 26/26] =?UTF-8?q?item.kt=EB=A5=BC=20location.kt=EB=A1=9C?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kakao/map/adapter/search/SearchAdapter.kt | 20 +++++----- .../kakao/map/model/{Item.kt => Location.kt} | 2 +- .../repository/location/LocationSearcher.kt | 6 +-- .../tech/kakao/map/view/MainActivity.kt | 40 +++++++++---------- .../map/view/OnSearchItemClickListener.kt | 4 +- .../tech/kakao/map/view/SearchActivity.kt | 16 ++++---- .../kakao/map/viewmodel/main/MainViewmodel.kt | 20 +++++----- .../map/viewmodel/search/SearchViewmodel.kt | 12 +++--- 8 files changed, 60 insertions(+), 60 deletions(-) rename app/src/main/java/campus/tech/kakao/map/model/{Item.kt => Location.kt} (88%) diff --git a/app/src/main/java/campus/tech/kakao/map/adapter/search/SearchAdapter.kt b/app/src/main/java/campus/tech/kakao/map/adapter/search/SearchAdapter.kt index 2596d6ac..39eaf019 100644 --- a/app/src/main/java/campus/tech/kakao/map/adapter/search/SearchAdapter.kt +++ b/app/src/main/java/campus/tech/kakao/map/adapter/search/SearchAdapter.kt @@ -9,17 +9,17 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import campus.tech.kakao.map.R -import campus.tech.kakao.map.model.Item +import campus.tech.kakao.map.model.Location import campus.tech.kakao.map.view.OnSearchItemClickListener class SearchAdapter( private val onSearchItemClickListener: OnSearchItemClickListener -) : ListAdapter( - object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: Item, newItem: Item) = +) : ListAdapter( + object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: Location, newItem: Location) = oldItem.place == newItem.place - override fun areContentsTheSame(oldItem: Item, newItem: Item) = + override fun areContentsTheSame(oldItem: Location, newItem: Location) = oldItem == newItem } ) { @@ -39,13 +39,13 @@ class SearchAdapter( private val address: TextView = view.findViewById(R.id.address) private val category: TextView = view.findViewById(R.id.category) - fun bindViewHolder(item: Item, onSearchItemClickListener: OnSearchItemClickListener) { - place.text = item.place - address.text = item.address - category.text = item.category + fun bindViewHolder(location: Location, onSearchItemClickListener: OnSearchItemClickListener) { + place.text = location.place + address.text = location.address + category.text = location.category itemList.setOnClickListener { - onSearchItemClickListener.onSearchItemClick(item) + onSearchItemClickListener.onSearchItemClick(location) } } } diff --git a/app/src/main/java/campus/tech/kakao/map/model/Item.kt b/app/src/main/java/campus/tech/kakao/map/model/Location.kt similarity index 88% rename from app/src/main/java/campus/tech/kakao/map/model/Item.kt rename to app/src/main/java/campus/tech/kakao/map/model/Location.kt index 6ff34e77..9728800c 100644 --- a/app/src/main/java/campus/tech/kakao/map/model/Item.kt +++ b/app/src/main/java/campus/tech/kakao/map/model/Location.kt @@ -1,6 +1,6 @@ package campus.tech.kakao.map.model -data class Item( +data class Location( val place: String, val address: String, val category: String, diff --git a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt index 5cb79cd1..988fc310 100644 --- a/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt +++ b/app/src/main/java/campus/tech/kakao/map/repository/location/LocationSearcher.kt @@ -1,16 +1,16 @@ package campus.tech.kakao.map.repository.location -import campus.tech.kakao.map.model.Item +import campus.tech.kakao.map.model.Location import javax.inject.Inject import javax.inject.Singleton @Singleton class LocationSearcher @Inject constructor(private val locationDao: LocationDao) { - suspend fun search(keyword: String): List { + suspend fun search(keyword: String): List { val locationEntities = locationDao.searchByCategory(keyword) return locationEntities.map { - Item( + Location( place = it.placeName, address = it.addressName, category = it.categoryGroupName, diff --git a/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt b/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt index 1bbeadff..cdc4b471 100644 --- a/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt +++ b/app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt @@ -16,6 +16,7 @@ import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer import androidx.databinding.DataBindingUtil +import campus.tech.kakao.map.databinding.ActivityMainBinding import com.google.android.material.bottomsheet.BottomSheetBehavior import com.kakao.vectormap.* import com.kakao.vectormap.camera.CameraAnimation @@ -25,8 +26,7 @@ import com.kakao.vectormap.label.LabelOptions import com.kakao.vectormap.label.LabelStyle import com.kakao.vectormap.label.LabelStyles import com.kakao.vectormap.label.LabelTextStyle -import campus.tech.kakao.map.databinding.ActivityMainBinding -import campus.tech.kakao.map.model.Item +import campus.tech.kakao.map.model.Location import campus.tech.kakao.map.repository.location.LocationSearcher import campus.tech.kakao.map.view.SearchActivity import campus.tech.kakao.map.viewmodel.keyword.KeywordViewModel @@ -104,13 +104,13 @@ class MainActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeywordIt } // Observe the last marker position - mainViewModel.lastMarkerPosition.observe(this, Observer { item -> - item?.let { - Log.d(TAG, "Loaded last marker position: lat=${it.latitude}, lon=${it.longitude}, placeName=${it.place}, roadAddressName=${it.address}") - addLabel(it) - val position = LatLng.from(it.latitude, it.longitude) + mainViewModel.lastMarkerPosition.observe(this, Observer { location: Location? -> // 타입 명시적으로 지정 + location?.let { loc -> // 변수 이름을 명확하게 변경 + Log.d(TAG, "Loaded last marker position: lat=${loc.latitude}, lon=${loc.longitude}, placeName=${loc.place}, roadAddressName=${loc.address}") + addLabel(loc) + val position = LatLng.from(loc.latitude, loc.longitude) moveCamera(position) - updateBottomSheet(it.place, it.address) + updateBottomSheet(loc.place, loc.address) } }) } @@ -146,10 +146,10 @@ class MainActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeywordIt Log.d(TAG, "Search result: $placeName, $roadAddressName, $latitude, $longitude") - // latitude와 longitude 값을 Double로 명시적으로 변환하여 Item 객체를 생성 - val item = Item(place = placeName, address = roadAddressName, category = "", latitude = latitude, longitude = longitude) - addLabel(item) - mainViewModel.saveLastMarkerPosition(item) + // latitude와 longitude 값을 Double로 명시적으로 변환하여 Location 객체를 생성 + val location = Location(place = placeName, address = roadAddressName, category = "", latitude = latitude, longitude = longitude) + addLabel(location) + mainViewModel.saveLastMarkerPosition(location) } private fun showToast(message: String) { @@ -196,11 +196,11 @@ class MainActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeywordIt }) } - private fun addLabel(item: Item) { - val placeName = item.place - val roadAddressName = item.address - val latitude = item.latitude - val longitude = item.longitude + private fun addLabel(location: Location) { // 변수 이름 변경 + val placeName = location.place + val roadAddressName = location.address + val latitude = location.latitude + val longitude = location.longitude val position = LatLng.from(latitude, longitude) val styles = kakaoMap?.labelManager?.addLabelStyles( @@ -244,10 +244,10 @@ class MainActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeywordIt // 아무 작업도 수행하지 않음 } - override fun onSearchItemClick(item: Item) { + override fun onSearchItemClick(location: Location) { // 변수 이름 변경 // 검색 결과 목록에서 항목을 선택했을 때의 동작을 정의 - addLabel(item) - mainViewModel.saveLastMarkerPosition(item) + addLabel(location) + mainViewModel.saveLastMarkerPosition(location) } companion object { diff --git a/app/src/main/java/campus/tech/kakao/map/view/OnSearchItemClickListener.kt b/app/src/main/java/campus/tech/kakao/map/view/OnSearchItemClickListener.kt index cd986ce6..178f8eeb 100644 --- a/app/src/main/java/campus/tech/kakao/map/view/OnSearchItemClickListener.kt +++ b/app/src/main/java/campus/tech/kakao/map/view/OnSearchItemClickListener.kt @@ -1,7 +1,7 @@ package campus.tech.kakao.map.view -import campus.tech.kakao.map.model.Item +import campus.tech.kakao.map.model.Location interface OnSearchItemClickListener { - fun onSearchItemClick(item: Item) + fun onSearchItemClick(location: Location) } \ No newline at end of file diff --git a/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt b/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt index c56e644e..31733a8d 100644 --- a/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt +++ b/app/src/main/java/campus/tech/kakao/map/view/SearchActivity.kt @@ -12,7 +12,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import campus.tech.kakao.map.adapter.keyword.KeywordAdapter import campus.tech.kakao.map.adapter.search.SearchAdapter import campus.tech.kakao.map.databinding.ActivitySearchBinding -import campus.tech.kakao.map.model.Item +import campus.tech.kakao.map.model.Location import campus.tech.kakao.map.viewmodel.keyword.KeywordViewModel import campus.tech.kakao.map.viewmodel.search.SearchViewModel import dagger.hilt.android.AndroidEntryPoint @@ -61,21 +61,21 @@ class SearchActivity : AppCompatActivity(), OnSearchItemClickListener, OnKeyword } // 검색 결과 관찰하여 UI 업데이트 - searchViewModel.items.observe(this) { + searchViewModel.locations.observe(this) { searchAdapter.submitList(it) binding.searchResultView.visibility = if (it.isEmpty()) View.GONE else View.VISIBLE binding.emptyView.visibility = if (it.isEmpty()) View.VISIBLE else View.GONE } } - override fun onSearchItemClick(item: Item) { + override fun onSearchItemClick(location: Location) { // 검색 항목 클릭 시 선택된 데이터를 반환하고 검색어 저장 - keywordViewModel.saveKeyword(item.place) + keywordViewModel.saveKeyword(location.place) val resultIntent = Intent().apply { - putExtra("place_name", item.place) - putExtra("road_address_name", item.address) - putExtra("latitude", item.latitude) - putExtra("longitude", item.longitude) + putExtra("place_name", location.place) + putExtra("road_address_name", location.address) + putExtra("latitude", location.latitude) + putExtra("longitude", location.longitude) } setResult(Activity.RESULT_OK, resultIntent) finish() diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodel.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodel.kt index b51b4c05..664483fb 100644 --- a/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodel.kt +++ b/app/src/main/java/campus/tech/kakao/map/viewmodel/main/MainViewmodel.kt @@ -6,7 +6,7 @@ import android.content.SharedPreferences import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import campus.tech.kakao.map.model.Item +import campus.tech.kakao.map.model.Location import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject @@ -16,22 +16,22 @@ class MainViewModel @Inject constructor( ) : AndroidViewModel(application) { private val sharedPreferences: SharedPreferences = application.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) - private val _lastMarkerPosition = MutableLiveData() - val lastMarkerPosition: LiveData get() = _lastMarkerPosition + private val _lastMarkerPosition = MutableLiveData() + val lastMarkerPosition: LiveData get() = _lastMarkerPosition init { loadLastMarkerPosition() } - fun saveLastMarkerPosition(item: Item) { + fun saveLastMarkerPosition(location: Location) { with(sharedPreferences.edit()) { - putFloat(PREF_LATITUDE, item.latitude.toFloat()) - putFloat(PREF_LONGITUDE, item.longitude.toFloat()) - putString(PREF_PLACE_NAME, item.place) - putString(PREF_ROAD_ADDRESS_NAME, item.address) + putFloat(PREF_LATITUDE, location.latitude.toFloat()) + putFloat(PREF_LONGITUDE, location.longitude.toFloat()) + putString(PREF_PLACE_NAME, location.place) + putString(PREF_ROAD_ADDRESS_NAME, location.address) apply() } - _lastMarkerPosition.value = item + _lastMarkerPosition.value = location } private fun loadLastMarkerPosition() { @@ -42,7 +42,7 @@ class MainViewModel @Inject constructor( val roadAddressName = sharedPreferences.getString(PREF_ROAD_ADDRESS_NAME, "") ?: "" _lastMarkerPosition.value = if (placeName.isNotEmpty() && roadAddressName.isNotEmpty()) { - Item(place = placeName, address = roadAddressName, category = "", latitude = latitude, longitude = longitude) + Location(place = placeName, address = roadAddressName, category = "", latitude = latitude, longitude = longitude) } else { null } diff --git a/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodel.kt b/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodel.kt index 21a7c556..c3beb814 100644 --- a/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodel.kt +++ b/app/src/main/java/campus/tech/kakao/map/viewmodel/search/SearchViewmodel.kt @@ -2,7 +2,7 @@ package campus.tech.kakao.map.viewmodel.search import androidx.lifecycle.* import campus.tech.kakao.map.api.KakaoLocalApi -import campus.tech.kakao.map.model.Item +import campus.tech.kakao.map.model.Location import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import javax.inject.Inject @@ -11,16 +11,16 @@ import javax.inject.Inject class SearchViewModel @Inject constructor( private val api: KakaoLocalApi ) : ViewModel() { - private val _items = MutableLiveData>() - val items: LiveData> - get() = _items + private val _locations = MutableLiveData>() + val locations: LiveData> + get() = _locations fun searchLocationData(keyword: String) { viewModelScope.launch { try { val response = api.searchKeyword("KakaoAK ${campus.tech.kakao.map.BuildConfig.KAKAO_REST_API_KEY}", keyword) - _items.value = response.documents.map { - Item( + _locations.value = response.documents.map { + Location( place = it.placeName, address = it.addressName, category = it.categoryGroupName,