diff --git a/README.md b/README.md index c1762fa0..ab88c174 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,31 @@ -# android-map-lacation STEP0 +# android-map-location STEP1 ## 개요 -`android-map-search STEP2`의 작업 사항을 옮겨 온 브랜치입니다. \ No newline at end of file +`android-map-location STEP1`에서는 지도 화면과 검색 화면 간의 네비게이션을 추가하고, 검색 기능을 확장하여 저장된 검색어 목록을 관리합니다. + +## 기능 + +- **지도 화면 표시**: 앱을 처음 실행하면 지도 화면이 표시됩니다. +- **검색 화면 이동**: 검색창을 선택하면 검색 화면으로 이동합니다. +- **뒤로 가기로 지도 화면 복귀**: 검색 화면에서 뒤로 가기를 하면 지도 화면으로 돌아옵니다. +- **검색 기능 확장**: 카카오로컬 API를 사용하여 검색어를 입력하면 검색 결과를 표시합니다. + - 검색 결과는 15개 이상 표시됩니다. + - 검색 결과 목록은 세로 스크롤이 가능합니다. + - 검색어는 `X` 버튼을 눌러서 삭제할 수 있습니다. +- **검색 결과 선택**: 검색 결과 목록에서 항목을 선택하면 선택된 항목이 검색어 저장 목록에 추가됩니다. + - 저장된 검색어 목록은 가로 스크롤이 가능합니다. + - 저장된 검색어는 `X` 버튼을 눌러서 삭제할 수 있습니다. + - 저장된 검색어는 앱을 재실행해도 유지됩니다. + +## 기능 요구 사항 + +- 저장된 검색어를 선택하면 해당 검색어의 검색 결과가 표시됩니다. +- 검색 결과 목록 중 하나의 항목을 선택하면 해당 항목의 위치를 지도에 표시합니다. +- 앱 종료 시 마지막 위치를 저장하여 다시 앱 실행 시 해당 위치로 포커스합니다. +- 카카오지도 onMapError() 호출 시 에러 화면을 보여줍니다. + +## 프로그래밍 요구 사항 + +- BottomSheet를 사용합니다. +- 카카오 API 사용을 위한 앱 키를 외부에 노출하지 않습니다. \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f3d4a026..92d8850a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -25,7 +25,7 @@ - + diff --git a/app/src/main/java/campus/tech/kakao/map/AuthenticationErrorActivity.kt b/app/src/main/java/campus/tech/kakao/map/AuthenticationErrorActivity.kt new file mode 100644 index 00000000..8e7e3be2 --- /dev/null +++ b/app/src/main/java/campus/tech/kakao/map/AuthenticationErrorActivity.kt @@ -0,0 +1,21 @@ +package campus.tech.kakao.map + +import android.os.Bundle +import android.widget.ImageView +import android.widget.ProgressBar +import androidx.appcompat.app.AppCompatActivity + +class AuthenticationErrorActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_authentication_error) + + val retryIcon: ImageView = findViewById(R.id.retry_icon) + val loadingIndicator: ProgressBar = findViewById(R.id.loading_indicator) + + retryIcon.setOnClickListener { + loadingIndicator.visibility = ProgressBar.VISIBLE + } + } +} diff --git a/app/src/main/java/campus/tech/kakao/map/MapActivity.kt b/app/src/main/java/campus/tech/kakao/map/MapActivity.kt index 58304986..93e53c4d 100644 --- a/app/src/main/java/campus/tech/kakao/map/MapActivity.kt +++ b/app/src/main/java/campus/tech/kakao/map/MapActivity.kt @@ -1,42 +1,127 @@ package campus.tech.kakao.map import android.content.Intent +import android.graphics.Color import android.os.Bundle +import android.util.Log import android.widget.LinearLayout +import android.widget.TextView import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.bottomsheet.BottomSheetDialog import com.kakao.vectormap.KakaoMap import com.kakao.vectormap.KakaoMapReadyCallback +import com.kakao.vectormap.LatLng import com.kakao.vectormap.MapLifeCycleCallback import com.kakao.vectormap.MapView +import com.kakao.vectormap.label.LabelOptions +import com.kakao.vectormap.label.LabelStyle +import com.kakao.vectormap.label.LabelStyles class MapActivity : AppCompatActivity() { private lateinit var mapView: MapView private lateinit var searchButton: LinearLayout + private lateinit var bottomSheet: BottomSheetDialog + + private var name: String? = null + private var address: String? = null + private var kakaoMap: KakaoMap? = null + private var latitude: String? = null + private var longitude: String? = null override fun onCreate(savedInstanceState: Bundle?) { + Log.d("here", "I'm in MapActivity") super.onCreate(savedInstanceState) setContentView(R.layout.activity_map) mapView = findViewById(R.id.map_view) searchButton = findViewById(R.id.search_button) + val bottomSheetLayout = layoutInflater.inflate(R.layout.layout_map_bottom_sheet_dialog, null) + bottomSheet = BottomSheetDialog(this) + + val defLat = "35.231627" + val defLng = "129.084020" + val lastLatLng = getSharedPreferences("lastLatLng", MODE_PRIVATE) + latitude = lastLatLng.getString("lastLat", defLat) // 기본 위치: 부산대. + longitude = lastLatLng.getString("lastLng", defLng) // 기본 위치: 부산대. + Log.d("sharedPreference", "saveLatLng밖에꺼: $latitude") + Log.d("sharedPreference", "saveLatLng밖에꺼: $longitude") + + // Intent에서 값을 가져옴 + intent?.let { + latitude = it.getStringExtra("mapY") ?: latitude + longitude = it.getStringExtra("mapX") ?: longitude + name = it.getStringExtra("name") + address = it.getStringExtra("address") + } + + Log.d("latlngcheck1", "Intent에서 가져온 값: $latitude, $longitude, $name") mapView.start( object : MapLifeCycleCallback() { - override fun onMapDestroy() {} - override fun onMapError(error: Exception) {} + override fun onMapDestroy() { + } + + override fun onMapError(error: Exception) { + Log.e("MapActivity", "Map error: ${error.message}") + val errorIntent = Intent(this@MapActivity, AuthenticationErrorActivity::class.java) + startActivity(errorIntent) + finish() + } + }, object : KakaoMapReadyCallback() { - override fun onMapReady(kakaoMap: KakaoMap) {} + override fun onMapReady(kakaoMap: KakaoMap) { + Log.d("latlngcheck2", "onMapReady에서: $latitude, $longitude") + this@MapActivity.kakaoMap = kakaoMap + name?.let { + addMarker(kakaoMap, latitude ?: defLat, longitude ?: defLng, it) + saveLatLng(latitude ?: defLat, longitude ?: defLng) // 마커 찍은 위치를 sharedPreference에 저장 + val tvBottomSheetPlaceName = bottomSheetLayout.findViewById(R.id.bottomSheetPlaceName) + val tvBottomSheetPlaceAddress = bottomSheetLayout.findViewById(R.id.bottomsheetPlaceAddress) + tvBottomSheetPlaceName.text = name + tvBottomSheetPlaceAddress.text = address + bottomSheet.setContentView(bottomSheetLayout) + bottomSheet.show() + } + } + + override fun getPosition(): LatLng { + Log.d("latlngcheck3", "getPosition에서: $latitude, $longitude") + val lat = (latitude ?: defLat).toDouble() + val lng = (longitude ?: defLng).toDouble() + return LatLng.from(lat, lng) + } } ) searchButton.setOnClickListener { - val intent = Intent(this@MapActivity, SearchActivity::class.java) - startActivity(intent) + val mapToSearchIntent = Intent(this@MapActivity, SearchActivity::class.java) + startActivity(mapToSearchIntent) + finish() } } + private fun addMarker(kakaoMap: KakaoMap, latitude: String, longitude: String, name: String) { + Log.d("addMarker", "addMarker: $latitude, $longitude, $name") + val styles = kakaoMap.labelManager?.addLabelStyles(LabelStyles.from(LabelStyle.from(R.drawable.location_marker).setTextStyles(25, Color.BLACK))) + val options = LabelOptions.from(LatLng.from(latitude.toDouble(), longitude.toDouble())).setStyles(styles) + val layer = kakaoMap.labelManager?.layer + val label = layer?.addLabel(options) + label?.changeText(name) + } + + private fun saveLatLng(latitude: String, longitude: String) { + val sharedPreference = getSharedPreferences("lastLatLng", MODE_PRIVATE) + sharedPreference.edit().apply { + putString("lastLat", latitude) + putString("lastLng", longitude) + apply() + } + Log.d("sharedPreference", "saveLatLng: ${sharedPreference.getString("lastLat", "default_lat")}") + Log.d("sharedPreference", "saveLatLng: ${sharedPreference.getString("lastLng", "default_lng")}") + } + override fun onResume() { super.onResume() mapView.resume() @@ -46,4 +131,5 @@ class MapActivity : AppCompatActivity() { super.onPause() mapView.pause() } + } diff --git a/app/src/main/java/campus/tech/kakao/map/SearchActivity.kt b/app/src/main/java/campus/tech/kakao/map/SearchActivity.kt index a5df6d6f..e9b0601f 100644 --- a/app/src/main/java/campus/tech/kakao/map/SearchActivity.kt +++ b/app/src/main/java/campus/tech/kakao/map/SearchActivity.kt @@ -1,7 +1,9 @@ package campus.tech.kakao.map import android.content.Intent +import android.content.SharedPreferences import android.os.Bundle +import android.util.Log import android.widget.ImageButton import android.widget.TextView import androidx.appcompat.app.AppCompatActivity @@ -23,9 +25,14 @@ class SearchActivity : AppCompatActivity() { private lateinit var searchHistoryList: MutableList private lateinit var kakaoRepository: KakaoRepository private lateinit var backButton: ImageButton + private lateinit var mapX: String + private lateinit var mapY: String + private lateinit var name: String + private lateinit var address: String override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + Log.d("here", "I'm in SearchActivity") setContentView(R.layout.activity_search) searchView = findViewById(R.id.search_view) @@ -45,6 +52,8 @@ class SearchActivity : AppCompatActivity() { onItemClick = { place -> searchHistoryDB.insertSearchHistory(place) updateSearchHistoryRecyclerView(place) + updateMapPosition(place) + goBackToMap() } ) resultRecyclerView.adapter = resultRecyclerViewAdapter @@ -113,7 +122,21 @@ class SearchActivity : AppCompatActivity() { } private fun goBackToMap() { - val intent = Intent(this, MapActivity::class.java) - startActivity(intent) + val searchToMapIntent = Intent(this, MapActivity::class.java) + searchToMapIntent.putExtra("mapX",mapX) + searchToMapIntent.putExtra("mapY",mapY) + searchToMapIntent.putExtra("name",name) + searchToMapIntent.putExtra("address", address) + Log.d("goBackToMap", "goBackToMap: $mapX, $mapY") + finish() + startActivity(searchToMapIntent) + } + + private fun updateMapPosition(place: Place) { + mapX = place.x + mapY = place.y + name = place.place_name + address = place.address_name + Log.d("goBackToMap", "updateMapPosition: $mapX, $mapY") } } diff --git a/app/src/main/res/drawable/bottom_sheet_background.xml b/app/src/main/res/drawable/bottom_sheet_background.xml new file mode 100644 index 00000000..a9d4de8f --- /dev/null +++ b/app/src/main/res/drawable/bottom_sheet_background.xml @@ -0,0 +1,13 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_retry.png b/app/src/main/res/drawable/ic_retry.png new file mode 100644 index 00000000..04c6c277 Binary files /dev/null and b/app/src/main/res/drawable/ic_retry.png differ diff --git a/app/src/main/res/drawable/location_marker.png b/app/src/main/res/drawable/location_marker.png new file mode 100644 index 00000000..aab4b5ee Binary files /dev/null and b/app/src/main/res/drawable/location_marker.png differ diff --git a/app/src/main/res/layout/activity_authentication_error.xml b/app/src/main/res/layout/activity_authentication_error.xml new file mode 100644 index 00000000..37b4ae91 --- /dev/null +++ b/app/src/main/res/layout/activity_authentication_error.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/layout_map_bottom_sheet_dialog.xml b/app/src/main/res/layout/layout_map_bottom_sheet_dialog.xml new file mode 100644 index 00000000..3417e815 --- /dev/null +++ b/app/src/main/res/layout/layout_map_bottom_sheet_dialog.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + \ No newline at end of file