diff --git "a/3\354\243\274\354\260\250\352\263\274\354\240\234\354\213\244\355\226\211\354\230\201\354\203\201.webm" "b/3\354\243\274\354\260\250\352\263\274\354\240\234\354\213\244\355\226\211\354\230\201\354\203\201.webm"
new file mode 100644
index 00000000..9e7654f5
Binary files /dev/null and "b/3\354\243\274\354\260\250\352\263\274\354\240\234\354\213\244\355\226\211\354\230\201\354\203\201.webm" differ
diff --git a/README.md b/README.md
index e0f925ff..75510c2e 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,35 @@
# android-map-search
+## ๐โโ๏ธ ๊ฐ์
+์ด App์ ์ฌ์ฉ์๊ฐ ๊ฒ์์ด๋ฅผ ์
๋ ฅํ์ฌ ๊ฒ์ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ๊ณ , ์ ํ๋ ํญ๋ชฉ์ ์ ์ฅํ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค. ์ ์ฅ๋ ๊ฒ์์ด ๋ชฉ๋ก์ ์ฑ์ ์ฌ์คํํด๋ ์ ์ง๋๋ค. ๊ฒ์ ๋ฐ์ดํฐ๋ ์นด์นด์ค๋ก์ปฌ API๋ฅผ ์ฌ์ฉํ๊ณ , ์ง๋๋ ์นด์นด์ค์ง๋ SDK๋ฅผ ์ฌ์ฉํ๋ค.
+
+## โจ ์ฃผ์๊ธฐ๋ฅ
+>**STEP1_๊ฒ์ํ๋ฉด**
+- ๊ฒ์์ด๋ฅผ ์
๋ ฅํ๋ฉด ๊ฒ์ ๊ฒฐ๊ณผ๊ฐ 15๊ฐ ์ด์ ํ์๋๋ค
+ - ๊ฒ์ ๊ฒฐ๊ณผ_๋ฐ์ดํฐ๋ ์นด์นด์ค๋ก์ปฌ API๋ฅผ ์ฌ์ฉํ๋ค
+
+>**STEP2_์ง๋ํ๋ฉด**
+- ์ฑ ์ฒ์ ์คํ์ ๊ฒ์ํ๋ฉด X, ์ง๋ํ๋ฉด์ด ํ์๋๋๋ก ํ๋ค
+ - ์ง๋ํ๋ฉด์ ์นด์นด์ค์ง๋ SDK๋ฅผ ์ฌ์ฉํ๋ค
+- `๊ฒ์์ฐฝ ํด๋ฆญ`์ ๊ฒ์ํ๋ฉด์ด์ผ๋ก ์ด๋ํ๋๋ก ํ๋ค
+- ๊ฒ์ํ๋ฉด์์ `๋จ๋ง๊ธฐ_๋ค๋ก๊ฐ๊ธฐ`๋ฅผ ํ๋ฉด ์ง๋ํ๋ฉด์ผ๋ก ๋์์จ๋ค
+
+
+## ๐ฑ ์คํํ๋ฉด
+1. ์ฑ ์ฒ์ ์คํ์, ์ง๋ํ๋ฉด ํ์
+
+
+![์ง๋ํ๋ฉด](https://github.com/arieum/android-map-search/blob/arieum_step2/%EC%B2%AB%ED%99%94%EB%A9%B4_%EC%A7%80%EB%8F%84%ED%99%94%EB%A9%B4.png)
+
+2. ์นด์นด์ค๋ก์ปฌ API๋ก๋ถํฐ ๊ฒ์๊ฒฐ๊ณผ ๋ถ๋ฌ์ค๊ธฐ
+
+
+![๊ฒ์๊ฒฐ๊ณผํ๋ฉด](https://github.com/arieum/android-map-search/blob/arieum_step2/%EA%B2%B0%EA%B3%BC%ED%99%94%EB%A9%B4fromapi.png)
+
+3. ์ ์ฒด์ ์ธ ์ฑ ์คํ์์ + ๊ฒ์ํ๋ฉด์์ ๋ค๋ก๊ฐ๊ธฐ ๋๋ฅด๋ฉด ๋ค์ ์ง๋ํ๋ฉด์ผ๋ก ์ด๋ํ๊ธฐ
+![3์ฃผ์ฐจ๊ณผ์ ์คํ์์](https://github.com/arieum/android-map-search/blob/arieum_step2/3%EC%A3%BC%EC%B0%A8%EA%B3%BC%EC%A0%9C%EC%8B%A4%ED%96%89%EC%98%81%EC%83%81.webm)
+
+## โ๏ธ ์ฌ์ฉ๋ API ๋ฐ SDK
+- ์นด์นด์ค๋ก์ปฌ API_Document โ
+- ์นด์นด์ค์ง๋ SDK_Document โ
+
+![PrayingCatGIF](https://github.com/arieum/android-map-search/assets/143606293/a0bc3779-a19a-4e15-aae0-d7a475662aea)
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index e25e2553..50bd9053 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,3 +1,5 @@
+import java.util.Properties
+
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
@@ -15,6 +17,19 @@ android {
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+
+ val kakaoApiKey = getApiKey("KAKAO_API_KEY")
+ val kakaoRestApiKey = getApiKey("KAKAO_REST_API_KEY")
+
+ buildConfigField("String", "KAKAO_API_KEY", kakaoApiKey)
+ buildConfigField("String", "KAKAO_REST_API_KEY", kakaoRestApiKey)
+
+ ndk {
+ abiFilters.add("arm64-v8a")
+ abiFilters.add("armeabi-v7a")
+ abiFilters.add("x86")
+ abiFilters.add("x86_64")
+ }
}
buildTypes {
@@ -26,10 +41,16 @@ android {
)
}
}
+
+ buildFeatures {
+ buildConfig = true
+ }
+
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
+
kotlinOptions {
jvmTarget = "17"
}
@@ -49,9 +70,19 @@ dependencies {
implementation("androidx.datastore:datastore-preferences:1.0.0")
implementation("com.squareup.retrofit2:retrofit:2.11.0")
implementation("com.squareup.retrofit2:converter-gson:2.11.0")
- implementation("com.kakao.maps.open:android:2.9.5")
+ implementation("com.kakao.sdk:v2-all:2.20.3")
+ implementation("com.kakao.maps.open:android:2.9.7")
implementation("androidx.activity:activity:1.8.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
}
+
+fun getApiKey(key: String): String {
+ val properties = Properties()
+ val localPropertiesFile = rootProject.file("local.properties")
+ if (localPropertiesFile.exists()) {
+ properties.load(localPropertiesFile.inputStream())
+ }
+ return properties.getProperty(key, "")
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 930d7f16..319c53af 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -5,6 +5,7 @@
+
@@ -25,4 +29,4 @@
-
+
\ No newline at end of file
diff --git a/app/src/main/java/campus/tech/kakao/map/KakaoApiService.kt b/app/src/main/java/campus/tech/kakao/map/KakaoApiService.kt
new file mode 100644
index 00000000..2fa4a266
--- /dev/null
+++ b/app/src/main/java/campus/tech/kakao/map/KakaoApiService.kt
@@ -0,0 +1,14 @@
+package campus.tech.kakao.map
+
+import retrofit2.Call
+import retrofit2.http.GET
+import retrofit2.http.Header
+import retrofit2.http.Query
+
+interface KakaoApiService {
+ @GET("v2/local/search/category")
+ fun getPlace(
+ @Header("Authorization") apiKey: String,
+ @Query("category_group_code") categoryGroupCode: String,
+ ): Call
+}
\ No newline at end of file
diff --git a/app/src/main/java/campus/tech/kakao/map/KakaoResponse.kt b/app/src/main/java/campus/tech/kakao/map/KakaoResponse.kt
new file mode 100644
index 00000000..f755e404
--- /dev/null
+++ b/app/src/main/java/campus/tech/kakao/map/KakaoResponse.kt
@@ -0,0 +1,30 @@
+package campus.tech.kakao.map
+
+import com.google.gson.annotations.SerializedName
+
+data class KakaoResponse(
+ val meta: Meta,
+ val documents: List
+)
+
+data class Meta(
+ @SerializedName("same_name") val sameName: Any?,
+ @SerializedName("pageable_count") val pageableCount: Int,
+ @SerializedName("total_count") val totalCount: Int,
+ @SerializedName("is_end") val isEnd: Boolean
+)
+
+data class Document(
+ @SerializedName("place_name") val placeName: String,
+ val distance: String?,
+ @SerializedName("place_url") val placeUrl: String,
+ @SerializedName("category_name") val categoryName: String,
+ @SerializedName("address_name") val addressName: String,
+ @SerializedName("road_address_name") val roadAddressName: String,
+ val id: String,
+ val phone: String?,
+ @SerializedName("category_group_code") val categoryGroupCode: String,
+ @SerializedName("category_group_name") val categoryGroupName: String,
+ val x: String,
+ val y: String
+)
\ No newline at end of file
diff --git a/app/src/main/java/campus/tech/kakao/map/MainActivity.kt b/app/src/main/java/campus/tech/kakao/map/MainActivity.kt
index 95b43803..4af0b885 100644
--- a/app/src/main/java/campus/tech/kakao/map/MainActivity.kt
+++ b/app/src/main/java/campus/tech/kakao/map/MainActivity.kt
@@ -1,11 +1,124 @@
package campus.tech.kakao.map
import android.os.Bundle
+import android.text.Editable
+import android.text.TextWatcher
+import android.widget.EditText
+import android.widget.ImageView
+import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.isGone
+import androidx.core.view.isVisible
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
class MainActivity : AppCompatActivity() {
+
+ private lateinit var input: EditText
+ private lateinit var researchCloseButton: ImageView
+ private lateinit var tabRecyclerView: RecyclerView
+ private lateinit var noResultTextView: TextView
+ private lateinit var recyclerView: RecyclerView
+ private lateinit var placeRepository: PlaceRepository
+ private var placeList = mutableListOf()
+ private var researchList = mutableListOf()
+ private lateinit var resultAdapter: RecyclerViewAdapter
+ private lateinit var tapAdapter: TapViewAdapter
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
+
+ input = findViewById(R.id.input)
+ researchCloseButton = findViewById(R.id.close_button)
+ noResultTextView = findViewById(R.id.no_result_textview)
+ recyclerView = findViewById(R.id.recyclerView)
+ tabRecyclerView = findViewById(R.id.tab_recyclerview)
+
+ placeRepository = PlaceRepository(this)
+ placeRepository.reset()
+ placeList = placeRepository.insertInitialData()
+
+ resultAdapter = RecyclerViewAdapter {
+ placeRepository.insertLog(it)
+ addResearchList(it)
+ }
+ recyclerView.adapter = resultAdapter
+ recyclerView.layoutManager = LinearLayoutManager(this)
+ resultAdapter.submitList(placeList)
+
+ researchList = placeRepository.getResearchEntries().toMutableList()
+ tapAdapter = TapViewAdapter(researchList) {
+ placeRepository.deleteResearchEntry(it)
+ removeResearchList(it)
+ }
+ tabRecyclerView.adapter = tapAdapter
+ tabRecyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
+
+ updateTabRecyclerViewVisibility()
+
+ input.addTextChangedListener(object : TextWatcher {
+ override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
+ // ๋ฏธ์ฌ์ฉ
+ }
+
+ override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
+ // ๋ฏธ์ฌ์ฉ
+ }
+
+ override fun afterTextChanged(s: Editable?) {
+ filterList(s.toString())
+ }
+ })
+
+ researchCloseButton.setOnClickListener {
+ input.setText("")
+ }
+ }
+
+ private fun filterList(query: String) {
+ val filteredList = if (query.isEmpty()) {
+ emptyList()
+ } else {
+ placeList.filter {
+ it.category.category.contains(query, ignoreCase = true) || it.name.contains(query, ignoreCase = true)
+ }
+ }
+
+ if (filteredList.isEmpty()) {
+ noResultTextView.isVisible = true
+ recyclerView.isGone = true
+ } else {
+ noResultTextView.isGone = true
+ recyclerView.isVisible = true
+ resultAdapter.submitList(filteredList.toMutableList())
+ }
+ }
+
+ private fun addResearchList(place: Place) {
+ if (!researchList.contains(place)){
+ researchList.add(place)
+ tapAdapter.notifyItemInserted(researchList.size - 1)
+ updateTabRecyclerViewVisibility()
+ }
+ }
+
+ private fun removeResearchList(it: Place) {
+ val position = researchList.indexOf(it)
+ if (position != -1) {
+ researchList.removeAt(position)
+ tapAdapter.notifyItemRemoved(position)
+ updateTabRecyclerViewVisibility()
+ }
+ }
+
+ private fun updateTabRecyclerViewVisibility() {
+ tabRecyclerView.isVisible = placeRepository.hasResearchEntries()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ input.removeTextChangedListener(null)
}
}
+
diff --git a/app/src/main/java/campus/tech/kakao/map/MapViewActivity.kt b/app/src/main/java/campus/tech/kakao/map/MapViewActivity.kt
new file mode 100644
index 00000000..d81f160d
--- /dev/null
+++ b/app/src/main/java/campus/tech/kakao/map/MapViewActivity.kt
@@ -0,0 +1,60 @@
+package campus.tech.kakao.map
+
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import android.widget.TextView
+import androidx.appcompat.app.AppCompatActivity
+import com.kakao.vectormap.KakaoMap
+import com.kakao.vectormap.KakaoMapReadyCallback
+import com.kakao.vectormap.MapLifeCycleCallback
+import com.kakao.vectormap.MapView
+
+class MapViewActivity : AppCompatActivity() {
+ private lateinit var mapView: MapView
+ private lateinit var searchTextview: TextView
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_map_view)
+
+ mapView = findViewById(R.id.map)
+ searchTextview = findViewById(R.id.search)
+
+ try {
+ mapView.start(object : MapLifeCycleCallback() {
+ override fun onMapDestroy() {
+ Log.d("KakaoMap", "์นด์นด์ค๋งต ์ ์์ข
๋ฃ")
+ }
+
+ override fun onMapError(exception: Exception?) {
+ Log.e("KakaoMap", "์นด์นด์ค๋งต ์ธ์ฆ์คํจ", exception)
+ }
+ }, object : KakaoMapReadyCallback() {
+ override fun onMapReady(map: KakaoMap) {
+ Log.d("KakaoMap", "์นด์นด์ค๋งต ์ ์์คํ")
+ }
+ })
+ Log.d("MapViewActivity", "mapView start called")
+ } catch (e: Exception) {
+ Log.e("MapViewActivity", "Exception during mapView.start", e)
+ }
+
+ searchTextview.setOnClickListener { onSearchTextViewClick() }
+ }
+
+ private fun onSearchTextViewClick() {
+ startActivity(Intent(this@MapViewActivity, MainActivity::class.java))
+ }
+ override fun onResume() {
+ super.onResume()
+ Log.d("MapViewActivity", "onResume called")
+ mapView.resume()
+ }
+
+ override fun onPause() {
+ super.onPause()
+ Log.d("MapViewActivity", "onPause called")
+ mapView.pause()
+ }
+}
diff --git a/app/src/main/java/campus/tech/kakao/map/MyApplication.kt b/app/src/main/java/campus/tech/kakao/map/MyApplication.kt
new file mode 100644
index 00000000..ca5671dc
--- /dev/null
+++ b/app/src/main/java/campus/tech/kakao/map/MyApplication.kt
@@ -0,0 +1,12 @@
+package campus.tech.kakao.map
+
+import android.app.Application
+import com.kakao.vectormap.KakaoMapSdk
+
+class MyApplication : Application() {
+ override fun onCreate() {
+ super.onCreate()
+ val appKey = BuildConfig.KAKAO_API_KEY
+ KakaoMapSdk.init(this, appKey)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/campus/tech/kakao/map/MyPlaceContract.kt b/app/src/main/java/campus/tech/kakao/map/MyPlaceContract.kt
new file mode 100644
index 00000000..bac17b35
--- /dev/null
+++ b/app/src/main/java/campus/tech/kakao/map/MyPlaceContract.kt
@@ -0,0 +1,22 @@
+package campus.tech.kakao.map
+
+import android.provider.BaseColumns
+
+object MyPlaceContract {
+ object Place : BaseColumns {
+ const val TABLE_NAME = "place"
+ const val COLUMN_NAME = "name"
+ const val COLUMN_IMG = "img"
+ const val COLUMN_LOCATION = "location"
+ const val COLUMN_CATEGORY = "category"
+ }
+
+ object Research : BaseColumns {
+ const val TABLE_NAME = "research"
+ const val COLUMN_NAME = "name"
+ const val COLUMN_IMG = "img"
+ const val COLUMN_LOCATION = "location"
+ const val COLUMN_CATEGORY = "category"
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/campus/tech/kakao/map/Place.kt b/app/src/main/java/campus/tech/kakao/map/Place.kt
new file mode 100644
index 00000000..ad5af532
--- /dev/null
+++ b/app/src/main/java/campus/tech/kakao/map/Place.kt
@@ -0,0 +1,11 @@
+package campus.tech.kakao.map
+
+import androidx.annotation.DrawableRes
+
+data class Place(
+ val id: Int? = null,
+ @DrawableRes val img: Int,
+ val name: String,
+ val location: String,
+ val category: PlaceCategory
+)
diff --git a/app/src/main/java/campus/tech/kakao/map/PlaceCategory.kt b/app/src/main/java/campus/tech/kakao/map/PlaceCategory.kt
new file mode 100644
index 00000000..e1596547
--- /dev/null
+++ b/app/src/main/java/campus/tech/kakao/map/PlaceCategory.kt
@@ -0,0 +1,14 @@
+package campus.tech.kakao.map
+
+enum class PlaceCategory(val category: String, val imgId: Int) {
+ CAFE("์นดํ", R.drawable.cafe),
+ PHARMACY("์ฝ๊ตญ", R.drawable.hospital),
+ OTHER("๊ธฐํ", R.drawable.location);
+
+ companion object {
+ fun fromCategory(category: String): PlaceCategory {
+ return entries.find { it.category == category } ?: OTHER
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/campus/tech/kakao/map/PlaceDbHelper.kt b/app/src/main/java/campus/tech/kakao/map/PlaceDbHelper.kt
new file mode 100644
index 00000000..46718a7c
--- /dev/null
+++ b/app/src/main/java/campus/tech/kakao/map/PlaceDbHelper.kt
@@ -0,0 +1,46 @@
+package campus.tech.kakao.map
+
+import android.content.Context
+import android.database.sqlite.SQLiteDatabase
+import android.database.sqlite.SQLiteOpenHelper
+import android.provider.BaseColumns
+import android.util.Log
+
+class PlaceDbHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {
+
+ companion object {
+ // If you change the database schema, you must increment the database version.
+ const val DATABASE_VERSION = 1
+ const val DATABASE_NAME = "MyPlace.db"
+
+ private const val SQL_CREATE_PLACE_TABLE =
+ "CREATE TABLE ${MyPlaceContract.Place.TABLE_NAME} (" +
+ "${BaseColumns._ID} INTEGER PRIMARY KEY AUTOINCREMENT," +
+ "${MyPlaceContract.Place.COLUMN_IMG} INTEGER," +
+ "${MyPlaceContract.Place.COLUMN_NAME} TEXT," +
+ "${MyPlaceContract.Place.COLUMN_CATEGORY} TEXT," +
+ "${MyPlaceContract.Place.COLUMN_LOCATION} TEXT)"
+
+ private const val SQL_CREATE_RESEARCH_TABLE =
+ "CREATE TABLE ${MyPlaceContract.Research.TABLE_NAME} (" +
+ "${BaseColumns._ID} INTEGER PRIMARY KEY AUTOINCREMENT," +
+ "${MyPlaceContract.Research.COLUMN_IMG} INTEGER," +
+ "${MyPlaceContract.Research.COLUMN_NAME} TEXT," +
+ "${MyPlaceContract.Research.COLUMN_CATEGORY} TEXT," +
+ "${MyPlaceContract.Research.COLUMN_LOCATION} TEXT)"
+
+ private const val SQL_DELETE_PLACE = "DROP TABLE IF EXISTS ${MyPlaceContract.Place.TABLE_NAME}"
+ private const val SQL_DELETE_RESEARCH= "DROP TABLE IF EXISTS ${MyPlaceContract.Research.TABLE_NAME}"
+ }
+
+ override fun onCreate(db: SQLiteDatabase?) {
+ Log.d("PlaceDbHelper", "Creating tables")
+ db?.execSQL(SQL_CREATE_PLACE_TABLE)
+ db?.execSQL(SQL_CREATE_RESEARCH_TABLE)
+ }
+
+ override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
+ db?.execSQL(SQL_DELETE_PLACE)
+ db?.execSQL(SQL_DELETE_RESEARCH)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/campus/tech/kakao/map/PlaceRepository.kt b/app/src/main/java/campus/tech/kakao/map/PlaceRepository.kt
new file mode 100644
index 00000000..b6fbef6c
--- /dev/null
+++ b/app/src/main/java/campus/tech/kakao/map/PlaceRepository.kt
@@ -0,0 +1,177 @@
+package campus.tech.kakao.map
+
+import android.content.ContentValues
+import android.content.Context
+import android.provider.BaseColumns
+import android.util.Log
+import androidx.core.database.getIntOrNull
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+
+
+class PlaceRepository(context: Context) {
+ private val dbHelper = PlaceDbHelper(context)
+ private var placeList = mutableListOf()
+
+ fun insertPlace(place: Place) {
+ dbHelper.writableDatabase.use {
+ val values = ContentValues().apply {
+ put(MyPlaceContract.Place.COLUMN_IMG, place.img)
+ put(MyPlaceContract.Place.COLUMN_NAME, place.name)
+ put(MyPlaceContract.Place.COLUMN_CATEGORY, place.category.category)
+ put(MyPlaceContract.Place.COLUMN_LOCATION, place.location)
+ }
+
+ it.insert(MyPlaceContract.Place.TABLE_NAME, null, values)
+ }
+ }
+
+ fun insertLog(place: Place) {
+ dbHelper.writableDatabase.use { db ->
+ db.query(
+ MyPlaceContract.Research.TABLE_NAME,
+ arrayOf(BaseColumns._ID),
+ "${MyPlaceContract.Research.COLUMN_NAME} = ? AND ${MyPlaceContract.Research.COLUMN_IMG} = ? AND ${MyPlaceContract.Research.COLUMN_LOCATION} = ? AND ${MyPlaceContract.Research.COLUMN_CATEGORY} = ?",
+ arrayOf(place.name, place.img.toString(), place.location, place.category.category),
+ null,
+ null,
+ null
+ ).use { cursor ->
+ if (cursor.moveToFirst()) {
+ Log.d("PlaceRepository", "Place already exists: ${place.name}")
+ } else {
+ val values = ContentValues().apply {
+ put(MyPlaceContract.Research.COLUMN_NAME, place.name)
+ put(MyPlaceContract.Research.COLUMN_IMG, place.img)
+ put(MyPlaceContract.Research.COLUMN_LOCATION, place.location)
+ put(MyPlaceContract.Research.COLUMN_CATEGORY, place.category.category)
+ }
+ db.insert(MyPlaceContract.Research.TABLE_NAME, null, values)
+ }
+ }
+ }
+ }
+
+ fun reset() {
+ dbHelper.writableDatabase.use {
+ it.execSQL("DELETE FROM ${MyPlaceContract.Place.TABLE_NAME}")
+ }
+ }
+
+ fun insertInitialData(): MutableList {
+ //kakao์์ ๋ฐ์ดํฐ ๊ฐ์ ธ์์ place ๊ฐ์ฒด ์์ฑํ๊ธฐ
+ val apiKey = "KakaoAK " + BuildConfig.KAKAO_REST_API_KEY
+ RetrofitObject.retrofitService.getPlace(apiKey, "CE7")
+ .enqueue(object : Callback {
+ override fun onResponse(
+ call: Call,
+ response: Response
+ ) {
+ if (response.isSuccessful) {
+ val documentList = response.body()?.documents
+ documentList?.forEach {
+ val place = Place(img = R.drawable.cafe, name = it.placeName, location = it.addressName, category = PlaceCategory.CAFE)
+ placeList.add(place)
+ insertPlace(place)
+ }
+ } else {
+ val errorBody = response.errorBody()?.string()
+ Log.d("KakaoAPI", "Error: $errorBody")
+ }
+ }
+
+ override fun onFailure(call: Call, t: Throwable) {
+ Log.d("KakaoAPI", "Failure: ${t.message}")
+ }
+ })
+
+ RetrofitObject.retrofitService.getPlace(apiKey, "PM9")
+ .enqueue(object : Callback {
+ override fun onResponse(
+ call: Call,
+ response: Response
+ ) {
+ if (response.isSuccessful) {
+ val documentList = response.body()?.documents
+ documentList?.forEach {
+ val place = Place(img = R.drawable.hospital, name = it.placeName, location = it.addressName, category = PlaceCategory.PHARMACY)
+ placeList.add(place)
+ insertPlace(place)
+ }
+ } else {
+ val errorBody = response.errorBody()?.string()
+ Log.d("KakaoAPI", "Error: $errorBody")
+ }
+ }
+
+ override fun onFailure(call: Call, t: Throwable) {
+ Log.d("KakaoAPI", "Failure: ${t.message}")
+ }
+ })
+ return placeList
+ }
+
+ fun hasResearchEntries() : Boolean {
+ dbHelper.readableDatabase.use {
+ it.rawQuery("SELECT COUNT(*) FROM ${MyPlaceContract.Research.TABLE_NAME}", null).use { cursor ->
+ return if (cursor.moveToFirst()) {
+ val count = cursor.getIntOrNull(0) ?: 0
+ count > 0
+ } else {
+ false
+ }
+ }
+ }
+ }
+
+ fun getResearchEntries(): List {
+ val researchList = mutableListOf()
+
+ dbHelper.readableDatabase.use { db ->
+ db.query(
+ MyPlaceContract.Research.TABLE_NAME,
+ arrayOf(
+ MyPlaceContract.Research.COLUMN_IMG,
+ MyPlaceContract.Research.COLUMN_NAME,
+ MyPlaceContract.Research.COLUMN_LOCATION,
+ MyPlaceContract.Research.COLUMN_CATEGORY
+ ),
+ null, null, null, null, null
+ ).use { cursor ->
+ while (cursor.moveToNext()) {
+ val img = cursor.getInt(cursor.getColumnIndexOrThrow(MyPlaceContract.Research.COLUMN_IMG))
+ val name = cursor.getString(cursor.getColumnIndexOrThrow(MyPlaceContract.Research.COLUMN_NAME))
+ val location = cursor.getString(cursor.getColumnIndexOrThrow(MyPlaceContract.Research.COLUMN_LOCATION))
+ val categoryDisplayName = cursor.getString(cursor.getColumnIndexOrThrow(MyPlaceContract.Research.COLUMN_CATEGORY))
+ val category = PlaceCategory.fromCategory(categoryDisplayName)
+ val place = Place(img = img, name = name, location = location, category = category)
+ researchList.add(place)
+ }
+ }
+ }
+
+ return researchList
+ }
+
+ fun deleteResearchEntry(place: Place) {
+ dbHelper.writableDatabase.use {
+ it.delete(
+ MyPlaceContract.Research.TABLE_NAME,
+ "${MyPlaceContract.Research.COLUMN_NAME} = ? AND ${MyPlaceContract.Research.COLUMN_IMG} = ? AND ${MyPlaceContract.Research.COLUMN_LOCATION} = ? AND ${MyPlaceContract.Research.COLUMN_CATEGORY} = ?",
+ arrayOf(place.name, place.img.toString(), place.location, place.category.category)
+ )
+ }
+ }
+
+ object RetrofitObject {
+ val retrofitService: KakaoApiService by lazy { Retrofit.Builder()
+ .baseUrl("https://dapi.kakao.com/")
+ .addConverterFactory(GsonConverterFactory.create())
+ .build()
+ .create(KakaoApiService::class.java)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/campus/tech/kakao/map/RecyclerViewAdapter.kt b/app/src/main/java/campus/tech/kakao/map/RecyclerViewAdapter.kt
new file mode 100644
index 00000000..8b3cb62d
--- /dev/null
+++ b/app/src/main/java/campus/tech/kakao/map/RecyclerViewAdapter.kt
@@ -0,0 +1,53 @@
+package campus.tech.kakao.map
+
+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
+
+class RecyclerViewAdapter(
+ private val onItemClicked: (Place) -> Unit
+) : ListAdapter(
+ object : DiffUtil.ItemCallback(){
+ override fun areItemsTheSame(oldItem: Place, newItem: Place): Boolean {
+ return oldItem.id == newItem.id
+ }
+
+ override fun areContentsTheSame(oldItem: Place, newItem: Place): Boolean {
+ return oldItem == newItem
+ }
+
+ }
+) {
+
+ inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ private val img: ImageView = itemView.findViewById(R.id.place_img)
+ private val name: TextView = itemView.findViewById(R.id.place_name)
+ private val location: TextView = itemView.findViewById(R.id.place_location)
+ private val category: TextView = itemView.findViewById(R.id.place_category)
+
+ fun bind(place: Place) {
+ img.setImageResource(place.category.imgId)
+ name.text = place.name
+ location.text = place.location
+ category.text = place.category.category
+
+ itemView.setOnClickListener { onItemClicked(place) }
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+ val inflater = LayoutInflater.from(parent.context)
+ val view = inflater.inflate(R.layout.place_card, parent, false)
+ return ViewHolder(view)
+ }
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ val place: Place = getItem(position)
+ holder.bind(place)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/campus/tech/kakao/map/TapViewAdapter.kt b/app/src/main/java/campus/tech/kakao/map/TapViewAdapter.kt
new file mode 100644
index 00000000..f42abe21
--- /dev/null
+++ b/app/src/main/java/campus/tech/kakao/map/TapViewAdapter.kt
@@ -0,0 +1,44 @@
+package campus.tech.kakao.map
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+
+class TapViewAdapter(
+ var researchList: MutableList,
+ private val onItemRemoved: (Place) -> Unit
+) : RecyclerView.Adapter() {
+
+ inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ val cancelButton: ImageView
+ val placeName: TextView
+ init {
+ cancelButton = itemView.findViewById(R.id.tab_close_button)
+ placeName = itemView.findViewById(R.id.tab_place_textview)
+
+ cancelButton.setOnClickListener {
+ val position = bindingAdapterPosition
+ if (position != RecyclerView.NO_POSITION) {
+ val item = researchList[position]
+ onItemRemoved(item)
+ }
+ }
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+ val inflater = LayoutInflater.from(parent.context)
+ val view = inflater.inflate(R.layout.tab_card, parent, false)
+ return ViewHolder(view)
+ }
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ val research: Place = researchList[position]
+ holder.placeName.text = research.name
+ }
+
+ override fun getItemCount(): Int = researchList.size
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/cafe.png b/app/src/main/res/drawable/cafe.png
new file mode 100644
index 00000000..180404f3
Binary files /dev/null and b/app/src/main/res/drawable/cafe.png differ
diff --git a/app/src/main/res/drawable/close.png b/app/src/main/res/drawable/close.png
new file mode 100644
index 00000000..69428cf1
Binary files /dev/null and b/app/src/main/res/drawable/close.png differ
diff --git a/app/src/main/res/drawable/detail.png b/app/src/main/res/drawable/detail.png
new file mode 100644
index 00000000..452055ef
Binary files /dev/null and b/app/src/main/res/drawable/detail.png differ
diff --git a/app/src/main/res/drawable/hospital.png b/app/src/main/res/drawable/hospital.png
new file mode 100644
index 00000000..8d39e8f6
Binary files /dev/null and b/app/src/main/res/drawable/hospital.png differ
diff --git a/app/src/main/res/drawable/location.png b/app/src/main/res/drawable/location.png
new file mode 100644
index 00000000..632dcbc1
Binary files /dev/null and b/app/src/main/res/drawable/location.png differ
diff --git a/app/src/main/res/drawable/search_box.xml b/app/src/main/res/drawable/search_box.xml
new file mode 100644
index 00000000..c6bb3b39
--- /dev/null
+++ b/app/src/main/res/drawable/search_box.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 24d17df2..483085b0 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -7,13 +7,58 @@
android:layout_height="match_parent"
tools:context=".MainActivity">
+
+
+
+
+
+
+
+
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ android:visibility="gone" />
diff --git a/app/src/main/res/layout/activity_map_view.xml b/app/src/main/res/layout/activity_map_view.xml
new file mode 100644
index 00000000..baef0053
--- /dev/null
+++ b/app/src/main/res/layout/activity_map_view.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/place_card.xml b/app/src/main/res/layout/place_card.xml
new file mode 100644
index 00000000..b2affbaf
--- /dev/null
+++ b/app/src/main/res/layout/place_card.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/tab_card.xml b/app/src/main/res/layout/tab_card.xml
new file mode 100644
index 00000000..98394122
--- /dev/null
+++ b/app/src/main/res/layout/tab_card.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 469f947e..07a30410 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -10,6 +10,8 @@ dependencyResolutionManagement {
repositories {
google()
mavenCentral()
+ maven("https://devrepo.kakao.com/nexus/repository/kakaomap-releases/")
+ maven("https://devrepo.kakao.com/nexus/content/groups/public/")
}
}
diff --git "a/\352\262\200\354\203\211\352\262\260\352\263\274\354\234\240\354\247\200.webm" "b/\352\262\200\354\203\211\352\262\260\352\263\274\354\234\240\354\247\200.webm"
new file mode 100644
index 00000000..59a82a48
Binary files /dev/null and "b/\352\262\200\354\203\211\352\262\260\352\263\274\354\234\240\354\247\200.webm" differ
diff --git "a/\352\262\200\354\203\211\354\226\264\354\236\205\353\240\245\354\213\234.png" "b/\352\262\200\354\203\211\354\226\264\354\236\205\353\240\245\354\213\234.png"
new file mode 100644
index 00000000..369dba32
Binary files /dev/null and "b/\352\262\200\354\203\211\354\226\264\354\236\205\353\240\245\354\213\234.png" differ
diff --git "a/\352\262\260\352\263\274\355\231\224\353\251\264fromapi.png" "b/\352\262\260\352\263\274\355\231\224\353\251\264fromapi.png"
new file mode 100644
index 00000000..040ad93e
Binary files /dev/null and "b/\352\262\260\352\263\274\355\231\224\353\251\264fromapi.png" differ
diff --git "a/\354\203\201\354\204\270\354\235\264\353\246\204\352\262\200\354\203\211\352\260\200\353\212\245.png" "b/\354\203\201\354\204\270\354\235\264\353\246\204\352\262\200\354\203\211\352\260\200\353\212\245.png"
new file mode 100644
index 00000000..ff4851da
Binary files /dev/null and "b/\354\203\201\354\204\270\354\235\264\353\246\204\352\262\200\354\203\211\352\260\200\353\212\245.png" differ
diff --git "a/\354\262\253 \352\262\200\354\203\211\355\231\224\353\251\264.png" "b/\354\262\253 \352\262\200\354\203\211\355\231\224\353\251\264.png"
new file mode 100644
index 00000000..6b798fae
Binary files /dev/null and "b/\354\262\253 \352\262\200\354\203\211\355\231\224\353\251\264.png" differ
diff --git "a/\354\262\253\355\231\224\353\251\264_\354\247\200\353\217\204\355\231\224\353\251\264.png" "b/\354\262\253\355\231\224\353\251\264_\354\247\200\353\217\204\355\231\224\353\251\264.png"
new file mode 100644
index 00000000..3bc996c5
Binary files /dev/null and "b/\354\262\253\355\231\224\353\251\264_\354\247\200\353\217\204\355\231\224\353\251\264.png" differ
diff --git "a/\354\271\264\353\223\234\355\201\264\353\246\255\354\213\234.png" "b/\354\271\264\353\223\234\355\201\264\353\246\255\354\213\234.png"
new file mode 100644
index 00000000..278d686e
Binary files /dev/null and "b/\354\271\264\353\223\234\355\201\264\353\246\255\354\213\234.png" differ