Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[강원대 안드로이드 주민철] 4주차 과제 스텝1 #43

Open
wants to merge 30 commits into
base: joominchul
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
8ae483b
Rename[]: 이동 3주차 과제 내용
joominchul Jul 15, 2024
7c76c97
Refactor[]: 변경 warning 부분
joominchul Jul 15, 2024
ba17eaf
Docs[README.md]: 추가 요구 사항 정리
joominchul Jul 15, 2024
4c2c111
Feat[]: 추가 선택 항목 위치, 정보를 지도에 표시
joominchul Jul 16, 2024
c69b181
Refactor[]: 변경 warning 요소
joominchul Jul 16, 2024
2613a7d
Design[bottom_sheet]: 변경 패딩
joominchul Jul 16, 2024
daefd35
Feat[]: 추가 저장된 검색어 선택 시 해당 검색어 검색 결과 표시
joominchul Jul 16, 2024
4bc4784
Feat[]: 추가 카카오지도 onMapError() 호출 시 에러 화면 표시
joominchul Jul 17, 2024
c4ad1b7
Merge branch 'joominchul' into feat-joominchul-step1
joominchul Jul 17, 2024
91bb445
Feat[]: 추가 MapPreferences에서 Document를 받아서 저장 기능
joominchul Jul 20, 2024
9a521a2
Refactor[MapActivity]: 변경 뷰 lazy 초기화
joominchul Jul 20, 2024
7e68e17
Refactor[MainViewModel]: 추가 initLatitude, initLongitude
joominchul Jul 20, 2024
668d100
Refactor[MainViewModel]: 추가 getMapInfo 함수
joominchul Jul 20, 2024
b7891d4
Refactor[MapActivity]: 변경 멤버변수
joominchul Jul 20, 2024
f224649
Refactor[MainViewModel]: 제거 initLatitude, initLongitude getter 함수
joominchul Jul 20, 2024
cd1e93e
Refactor[MapActivity]: 변경 Initial Value들 상수로
joominchul Jul 20, 2024
988f859
Refactor[MapActivity]: 변경 ViewModel 맴액티비티를 오너로 설정
joominchul Jul 21, 2024
244c9fd
Refactor[MapActivity]: 변경 KakaoMap 내에 있는 멤버 변수들
joominchul Jul 21, 2024
505088c
Refactor[MyApplication]: 변경 mapPosition 싱글톤 패턴으로
joominchul Jul 21, 2024
66d2aac
Rename[]: 패키지 삭제 후 이동
joominchul Jul 21, 2024
5949ab8
Refactor[]: 변경 mapPosition
joominchul Jul 22, 2024
6049de6
Refactor[]: 변경 mapPosition
joominchul Jul 22, 2024
3ad3f78
Refactor[]: 추가 콜백 메서드 인터페이스
joominchul Jul 22, 2024
556aef4
Refactor[]: 변경 var
joominchul Jul 22, 2024
82b07ff
Refactor[]: 변경 람다 형식
joominchul Jul 22, 2024
829170b
Comment[]: 삭제 주석
joominchul Jul 22, 2024
21f5470
Refactor[SameName]: 변경 selectedRegion 이름
joominchul Jul 22, 2024
17e03c3
Rename[]: 생성 url 패키지
joominchul Jul 22, 2024
1b75544
Refactor[]: 변경 상수
joominchul Jul 22, 2024
da92697
Refactor[DocumentAdapter]: 변경 placeClicked
joominchul Jul 22, 2024
File filter

Filter by extension

Filter by extension

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

## 1단계 - 카카오맵 API 심화
### 기능 요구 사항
- 저장된 검색어를 선택하면 해당 검색어의 검색 결과가 표시된다.
- 검색 결과 목록 중 하나의 항목을 선택하면 해당 항목의 위치를 지도에 표시한다.
- 앱 종료 시 마지막 위치를 저장하여 다시 앱 실행 시 해당 위치로 포커스 한다.
- 카카오지도 onMapError() 호출 시 에러 화면을 보여준다.
### 프로그래밍 요구 사항
- BottomSheet를 사용한다.
- 카카오 API 사용을 위한 앱 키를 외부에 노출하지 않는다.
- 가능한 MVVM 아키텍처 패턴을 적용하도록 한다.
- 코드 컨벤션을 준수하며 프로그래밍한다.
6 changes: 5 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,13 @@ android {
viewBinding = true
buildConfig = true
}
testOptions {
animationsDisabled = true
}
}

dependencies {
val lifecycle_version = "2.8.3"
val lifecycle_version = "2.8.3"
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version")
implementation("androidx.core:core-ktx:1.12.0")
Expand All @@ -75,5 +78,6 @@ dependencies {
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation("androidx.test:rules:1.5.0")
androidTestImplementation("androidx.test.espresso:espresso-intents:3.5.1")
androidTestImplementation("androidx.test.espresso:espresso-contrib:3.5.1")
}
fun getApiKey(key: String): String = gradleLocalProperties(rootDir, providers).getProperty(key)
11 changes: 11 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/AdapterCallback.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package campus.tech.kakao.map

import campus.tech.kakao.map.dto.Document
import campus.tech.kakao.map.dto.SearchWord

interface AdapterCallback {
fun onWordAdded(document: Document)
fun onDocumentInfoSet(document: Document)
fun onWordDeleted(searchWord: SearchWord)
fun onWordSearched(searchWord: SearchWord)
}
22 changes: 0 additions & 22 deletions app/src/main/java/campus/tech/kakao/map/DTO/Document.kt

This file was deleted.

7 changes: 0 additions & 7 deletions app/src/main/java/campus/tech/kakao/map/DTO/SameName.kt

This file was deleted.

11 changes: 0 additions & 11 deletions app/src/main/java/campus/tech/kakao/map/MainActivity.kt

This file was deleted.

24 changes: 20 additions & 4 deletions app/src/main/java/campus/tech/kakao/map/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ package campus.tech.kakao.map
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import campus.tech.kakao.map.DBHelper.SearchWordDbHelper
import campus.tech.kakao.map.DTO.Document
import campus.tech.kakao.map.DTO.SearchWord
import campus.tech.kakao.map.RetrofitData.Companion.getInstance
import campus.tech.kakao.map.MapPosition.getMapPosition
import campus.tech.kakao.map.dto.RetrofitData.Companion.getInstance
import campus.tech.kakao.map.dto.Document
import campus.tech.kakao.map.dto.SearchWord

class MainViewModel(application: Application): AndroidViewModel(application) {

Expand All @@ -16,6 +16,10 @@ class MainViewModel(application: Application): AndroidViewModel(application) {
private val retrofitData = getInstance()
val documentList: LiveData<List<Document>> get() = retrofitData.getDocuments()

private val initLatitude = "37.402005"
private val initLongitude = "127.108621"


fun addWord(document: Document){
wordDbHelper.addWord(wordfromDocument(document))
}
Expand All @@ -39,4 +43,16 @@ class MainViewModel(application: Application): AndroidViewModel(application) {
super.onCleared()
wordDbHelper.close()
}

fun setMapInfo(document: Document){
getMapPosition(getApplication()).setMapInfo(document)
}

fun getMapInfo():List<String>{
val latitude = getMapPosition(getApplication()).getPreferences("latitude",initLatitude)
val longitude = getMapPosition(getApplication()).getPreferences("longitude",initLongitude)
val placeName = getMapPosition(getApplication()).getPreferences("placeName","")
val addressName = getMapPosition(getApplication()).getPreferences("addressName","")
return listOf(latitude, longitude, placeName, addressName)
}
}
100 changes: 99 additions & 1 deletion app/src/main/java/campus/tech/kakao/map/MapActivity.kt
Original file line number Diff line number Diff line change
@@ -1,54 +1,152 @@
package campus.tech.kakao.map

import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import com.google.android.material.bottomsheet.BottomSheetBehavior
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.camera.CameraUpdate
import com.kakao.vectormap.camera.CameraUpdateFactory
import com.kakao.vectormap.label.LabelOptions
import com.kakao.vectormap.label.LabelStyle
import com.kakao.vectormap.label.LabelStyles
import java.lang.Exception

const val MARKER_WIDTH = 100
const val MARKER_HEIGHT = 100
const val MARKER_TEXT_SIZE = 40
const val ZOOM_LEVEL = 17
class MapActivity : AppCompatActivity() {
private lateinit var mapView: MapView
private var map: KakaoMap? = null
private lateinit var searchBar: LinearLayout
private lateinit var model: MainViewModel
private lateinit var placeName:String
private lateinit var addressName:String
private lateinit var bottomSheetBehavior: BottomSheetBehavior<LinearLayout>
private lateinit var bottomSheet :LinearLayout
private lateinit var bottomSheetName:TextView
private lateinit var bottomSheetAddress :TextView
private var longitude:Double = 0.0
private var latitude:Double = 0.0
companion object{
var documentClicked = false
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_map)
mapView = findViewById(R.id.map_view)
model = ViewModelProvider(this)[MainViewModel::class.java]
getMapInfo()
mapView.start(object : MapLifeCycleCallback() {
override fun onMapDestroy() {

}

override fun onMapError(p0: Exception?) {
Log.e("MapActivity", "onMapError: ${p0?.message}", p0)
setContentView(R.layout.map_error)
mkSpace marked this conversation as resolved.
Show resolved Hide resolved
val errorText = findViewById<TextView>(R.id.map_error_text)
errorText.text = p0?.message
}

}, object: KakaoMapReadyCallback() {
override fun onMapReady(kakaoMap: KakaoMap) {
map = kakaoMap
}

override fun getPosition(): LatLng {
return LatLng.from(latitude, longitude)
}

override fun getZoomLevel(): Int {
return ZOOM_LEVEL
}
})
searchBar = findViewById(R.id.search_bar)
searchBar.setOnClickListener {
val intent = Intent(this@MapActivity, SearchActivity::class.java)
startActivity(intent)
}
initBottomSheet()
}

override fun onResume() {
super.onResume()
getMapInfo()
mapView.resume()
if(documentClicked){
makeMarker()
setBottomSheet()
documentClicked = false
}
else{
map?.labelManager?.layer?.removeAll()
bottomSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN
}
val cameraUpdate: CameraUpdate = CameraUpdateFactory.newCenterPosition(LatLng.from(latitude, longitude))
map?.moveCamera(cameraUpdate)
}

override fun onPause() {
super.onPause()
mapView.pause()
}

private fun getMapInfo(){
val mapInfoList = model.getMapInfo()
latitude = mapInfoList[0].toDouble()
longitude = mapInfoList[1].toDouble()
placeName = mapInfoList[2]
addressName = mapInfoList[3]
}

private fun makeMarker(){
mkSpace marked this conversation as resolved.
Show resolved Hide resolved
val bitmapImage = BitmapFactory.decodeResource(resources, R.drawable.marker)
val markerImage = Bitmap.createScaledBitmap(bitmapImage, MARKER_WIDTH, MARKER_HEIGHT, true)
val styles = map?.labelManager?.addLabelStyles(LabelStyles.from(LabelStyle.from(markerImage).setTextStyles(
MARKER_TEXT_SIZE, Color.BLACK)))
if(styles != null){
val options = LabelOptions.from(LatLng.from(latitude, longitude)).setStyles(styles).setTexts(placeName)
map?.labelManager?.layer?.removeAll()
map?.labelManager?.layer?.addLabel(options)
}
else{
Log.e("MapActivity", "makeMarker: styles is null")
}
}

private fun initBottomSheet(){
bottomSheet = findViewById(R.id.bottom_sheet)
bottomSheetName = findViewById(R.id.name)
bottomSheetAddress = findViewById(R.id.address)
bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet)
bottomSheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback(){
override fun onStateChanged(bottomSheet: View, newState: Int) {
}

override fun onSlide(bottomSheet: View, slideOffset: Float) {
}

})
bottomSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN
}

private fun setBottomSheet(){
bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
bottomSheetName.text = placeName
bottomSheetAddress.text = addressName
}
}
15 changes: 15 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/MapPosition.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package campus.tech.kakao.map

import android.content.Context
import campus.tech.kakao.map.dto.MapPositionPreferences

object MapPosition {
private var mapPosition: MapPositionPreferences? = null

fun getMapPosition(context: Context): MapPositionPreferences {
if (mapPosition == null) {
mapPosition = MapPositionPreferences(context)
}
return mapPosition!!
}
}
2 changes: 2 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/MyApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import com.kakao.vectormap.KakaoMapSdk
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
MapPosition.getMapPosition(this)
KakaoMapSdk.init(this, BuildConfig.KAKAO_API_KEY)
}

}
2 changes: 1 addition & 1 deletion app/src/main/java/campus/tech/kakao/map/RetrofitService.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package campus.tech.kakao.map

import campus.tech.kakao.map.DTO.PlaceResponse
import campus.tech.kakao.map.dto.PlaceResponse
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Header
Expand Down
37 changes: 26 additions & 11 deletions app/src/main/java/campus/tech/kakao/map/SearchActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import campus.tech.kakao.map.Adapter.DocumentAdapter
import campus.tech.kakao.map.Adapter.WordAdapter
import campus.tech.kakao.map.adapter.DocumentAdapter
import campus.tech.kakao.map.adapter.WordAdapter
mkSpace marked this conversation as resolved.
Show resolved Hide resolved
import campus.tech.kakao.map.dto.Document
import campus.tech.kakao.map.dto.SearchWord

class SearchActivity : AppCompatActivity() {
class SearchActivity : AppCompatActivity(), AdapterCallback {

private lateinit var model: MainViewModel
private lateinit var search:EditText
Expand All @@ -29,13 +31,9 @@ class SearchActivity : AppCompatActivity() {
setupUI()
searchResult.layoutManager = LinearLayoutManager(this)
searchWordResult.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
documentAdapter = DocumentAdapter(){ Document ->
model.addWord(Document)
}
wordAdapter = WordAdapter() { SearchWord ->
model.deleteWord(SearchWord)
}
search.doOnTextChanged { text, start, before, count ->
documentAdapter = DocumentAdapter(this)
wordAdapter = WordAdapter(this)
Comment on lines +35 to +36
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

깔끔해졌네요 👍

search.doOnTextChanged { text, _, _, _ ->
val query = text.toString()
if (query.isEmpty()){
noResult.visibility = View.VISIBLE
Expand Down Expand Up @@ -71,7 +69,7 @@ class SearchActivity : AppCompatActivity() {
})
}

fun setupUI(){
private fun setupUI(){
search = findViewById(R.id.search)
clear = findViewById(R.id.search_clear)
noResult = findViewById(R.id.no_search_result)
Expand All @@ -82,5 +80,22 @@ class SearchActivity : AppCompatActivity() {
}
}

override fun onWordAdded(document: Document) {
model.addWord(document)
}

override fun onDocumentInfoSet(document: Document) {
model.setMapInfo(document)
finish()
}

override fun onWordDeleted(searchWord: SearchWord) {
model.deleteWord(searchWord)
}

override fun onWordSearched(searchWord: SearchWord) {
model.searchLocalAPI(searchWord.name)
}


}
Loading