From 321dd127771ff7a367dda7294564a6459dde8c92 Mon Sep 17 00:00:00 2001 From: minjun011026 Date: Tue, 25 Feb 2025 10:42:42 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20MapFragment=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/other.xml | 329 ------------------ .../com/example/ssul/model/CoordinateModel.kt | 3 + .../ssul/{ => view/map}/MapFragment.kt | 239 +++++-------- .../com/example/ssul/view/map/MapViewModel.kt | 96 +++++ .../com/example/ssul/view/map/RouteParser.kt | 75 ++++ .../example/ssul/view/map/StorePopUpView.kt | 4 + 6 files changed, 263 insertions(+), 483 deletions(-) delete mode 100644 .idea/other.xml create mode 100644 app/src/main/java/com/example/ssul/model/CoordinateModel.kt rename app/src/main/java/com/example/ssul/{ => view/map}/MapFragment.kt (66%) create mode 100644 app/src/main/java/com/example/ssul/view/map/MapViewModel.kt create mode 100644 app/src/main/java/com/example/ssul/view/map/RouteParser.kt create mode 100644 app/src/main/java/com/example/ssul/view/map/StorePopUpView.kt diff --git a/.idea/other.xml b/.idea/other.xml deleted file mode 100644 index 104e542..0000000 --- a/.idea/other.xml +++ /dev/null @@ -1,329 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/java/com/example/ssul/model/CoordinateModel.kt b/app/src/main/java/com/example/ssul/model/CoordinateModel.kt new file mode 100644 index 0000000..afc6eda --- /dev/null +++ b/app/src/main/java/com/example/ssul/model/CoordinateModel.kt @@ -0,0 +1,3 @@ +package com.example.ssul.model + +data class \ No newline at end of file diff --git a/app/src/main/java/com/example/ssul/MapFragment.kt b/app/src/main/java/com/example/ssul/view/map/MapFragment.kt similarity index 66% rename from app/src/main/java/com/example/ssul/MapFragment.kt rename to app/src/main/java/com/example/ssul/view/map/MapFragment.kt index 0e26a99..68ededf 100644 --- a/app/src/main/java/com/example/ssul/MapFragment.kt +++ b/app/src/main/java/com/example/ssul/view/map/MapFragment.kt @@ -3,7 +3,6 @@ package com.example.ssul import android.content.Context import android.content.Intent import android.graphics.Color -import android.location.Geocoder import android.os.Bundle import android.view.Gravity import android.view.LayoutInflater @@ -17,54 +16,52 @@ import android.widget.ImageView import android.widget.TextView import android.widget.Toast import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope import com.bumptech.glide.Glide +import com.example.ssul.viewmodel.MapViewModel +import com.example.ssul.viewmodel.RouteParser import com.naver.maps.geometry.LatLng import com.naver.maps.map.CameraUpdate import com.naver.maps.map.LocationTrackingMode import com.naver.maps.map.NaverMap import com.naver.maps.map.overlay.Marker import com.naver.maps.map.overlay.OverlayImage -import com.naver.maps.map.overlay.PolylineOverlay import com.naver.maps.map.util.FusedLocationSource import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import okhttp3.Call -import okhttp3.Callback -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.Response -import org.json.JSONObject import java.io.IOException class MapFragment : Fragment() { private lateinit var naverMap: NaverMap private lateinit var locationSource: FusedLocationSource - private var polyline: PolylineOverlay? = null - private val markerList = mutableListOf() private var selectedMarker: Marker? = null // 선택된 마커 저장 private var storeInfoPopup: View? = null // 팝업 뷰 참조 - private var storeItems: MutableList = mutableListOf() // 전체 가게 리스트 + + private var routeParser: RouteParser? = null // 경로생성기 + private lateinit var mapViewModel: MapViewModel // ViewModel + fun setStoreItems(items: MutableList) { - storeItems = items + mapViewModel = ViewModelProvider(this)[MapViewModel::class.java] + mapViewModel.addStores(items) } - private val geocodingCache = mutableMapOf() // 주소-좌표 캐시 - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { - return inflater.inflate(R.layout.fragment_map, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + routeParser = RouteParser() + setupTagFilters(view) //태그버튼 초기화 setupSearchFunctionality(view) // 검색창 초기화 @@ -86,7 +83,7 @@ class MapFragment : Fragment() { // UI 설정 (현재 위치 버튼 등) naverMap.uiSettings.isLocationButtonEnabled = true setupMapClickListener() // 지도 클릭 이벤트 초기화 - updateMarkers(storeItems) + mapViewModel.storeList.value?.let { updateMarkers(it) } } } @@ -97,7 +94,8 @@ class MapFragment : Fragment() { val storeId = popupView.tag as? Int // 팝업에 저장된 가게 ID 가져오기 storeId?.let { id -> - val sharedPreferences = requireContext().getSharedPreferences("favorite", Context.MODE_PRIVATE) + val sharedPreferences = + requireContext().getSharedPreferences("favorite", Context.MODE_PRIVATE) val isFavorite = sharedPreferences.getBoolean(id.toString(), false) // 버튼 상태 갱신 @@ -115,44 +113,42 @@ class MapFragment : Fragment() { R.id.filter_partner_button to { store: StoreItem -> store.isAssociated } ) - // 현재 활성화된 필터 상태를 저장하는 Set - val activeFilters = mutableSetOf() - - for ((buttonId, filterCondition) in tagFilters) { + // 버튼 클릭 시 ViewModel에 필터 상태 변경 요청 + tagFilters.forEach { (buttonId, _) -> val button = view.findViewById(buttonId) button.setOnClickListener { + mapViewModel.toggleFilter(buttonId) // 필터 상태 변경 + } + } + + // 필터 상태를 관찰하여 마커 업데이트 + mapViewModel.activeFilters.observe(viewLifecycleOwner, Observer { activeFilters -> + for ((buttonId, _) in tagFilters) { + val button = view.findViewById(buttonId) if (activeFilters.contains(buttonId)) { - // 이미 활성화된 필터를 비활성화 - activeFilters.remove(buttonId) - button.setBackgroundResource(R.drawable.filter_non_clicked) - button.setTextAppearance(requireContext(), R.style.filter_text_style) - } else { - // 새로운 필터를 활성화 - activeFilters.add(buttonId) button.setBackgroundResource(R.drawable.filter_clicked) button.setTextAppearance(requireContext(), R.style.filter_selected_text_style) + } else { + button.setBackgroundResource(R.drawable.filter_non_clicked) + button.setTextAppearance(requireContext(), R.style.filter_text_style) } - - // 활성화된 모든 필터 조건을 적용하여 데이터를 필터링 - val filteredStores = storeItems.filter { store -> - activeFilters.all { filterId -> - tagFilters[filterId]?.invoke(store) ?: true - } - } - - // 마커 업데이트 - updateMarkers(filteredStores) } - } + + // 필터 적용 후 마커 업데이트 + val filteredStores = mapViewModel.getFilteredStores() + updateMarkers(filteredStores) + }) } private fun updateMarkers(storeList: List) { clearExistingMarkers() // 기존 마커 제거 - storeList.forEach { store -> - GlobalScope.launch(Dispatchers.IO) { // 비동기로 실행 + viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) { // 비동기로 실행 try { - val coordinates = getCoordinatesFromAddress(store.address) // 좌표 변환 + val coordinates = mapViewModel.getCoordinatesFromAddress( + requireContext(), + store.address + ) // 좌표 변환 if (coordinates != null) { withContext(Dispatchers.Main) { // UI 작업은 메인 스레드에서 처리 val marker = Marker().apply { @@ -167,7 +163,7 @@ class MapFragment : Fragment() { true } } - markerList.add(marker) + mapViewModel.addMarker(marker) } } } catch (e: IOException) { @@ -177,27 +173,6 @@ class MapFragment : Fragment() { } } - // 주소를 좌표로 변환하는 메서드 (캐시 적용) - private fun getCoordinatesFromAddress(address: String): LatLng? { - // 캐시된 값이 있으면 바로 반환 - geocodingCache[address]?.let { return it } - - // 캐시된 값이 없으면 Geocoder를 사용하여 좌표 변환 - return try { - val addresses = Geocoder(requireContext()).getFromLocationName(address, 1) - if (!addresses.isNullOrEmpty()) { - val location = addresses[0] - val latLng = LatLng(location.latitude, location.longitude) - // 좌표를 캐시에 저장 - geocodingCache[address] = latLng - latLng - } else null - } catch (e: IOException) { - e.printStackTrace() - null - } - } - private fun handleMarkerClick(marker: Marker, store: StoreItem) { // 이전 선택된 마커 복구 selectedMarker?.let { @@ -232,7 +207,7 @@ class MapFragment : Fragment() { val partnerTag = findViewById(R.id.partner_status) storeName.text = store.name - storeAddress.text = "주소: ${store.address}" + storeAddress.text = getString(R.string.address_text, store.address) Glide.with(this) .load(store.imageUrl) // 이미지 URL .placeholder(R.drawable.default_image) // 로딩 중 보여줄 이미지 @@ -243,7 +218,8 @@ class MapFragment : Fragment() { partnerTag.visibility = if (store.isAssociated) View.VISIBLE else View.INVISIBLE // SharedPreferences에서 즐겨찾기 상태 로드 - val sharedPreferences = requireContext().getSharedPreferences("favorite", Context.MODE_PRIVATE) + val sharedPreferences = + requireContext().getSharedPreferences("favorite", Context.MODE_PRIVATE) val isFavorite = sharedPreferences.getBoolean(store.id.toString(), false) // 초기 즐겨찾기 버튼 상태 설정 @@ -251,21 +227,24 @@ class MapFragment : Fragment() { // 즐겨찾기 버튼 클릭 리스너 favoriteButton.setOnClickListener { - val sharedPreferences = requireContext().getSharedPreferences("favorite", Context.MODE_PRIVATE) - val isFavorite = sharedPreferences.getBoolean(store.id.toString(), false) // 현재 즐겨찾기 상태 확인 + val btnSharedPreferences = + requireContext().getSharedPreferences("favorite", Context.MODE_PRIVATE) + val btnIsFavorite = + btnSharedPreferences.getBoolean(store.id.toString(), false) // 현재 즐겨찾기 상태 확인 - if (isFavorite) { + if (btnIsFavorite) { // 이미 즐겨찾기 상태 -> 제거 작업 (activity as? MainActivity)?.showMessageBox( message = getString(R.string.remove_favorite), onYesClicked = { - sharedPreferences.edit().remove(store.id.toString()).apply() // 즐겨찾기 상태 제거 + btnSharedPreferences.edit().remove(store.id.toString()) + .apply() // 즐겨찾기 상태 제거 updateFavoriteButtonState(favoriteButton, false) // 버튼 상태 업데이트 } ) } else { // 즐겨찾기 추가 - sharedPreferences.edit().putBoolean(store.id.toString(), true).apply() // 상태 저장 + btnSharedPreferences.edit().putBoolean(store.id.toString(), true).apply() // 상태 저장 updateFavoriteButtonState(favoriteButton, true) // 버튼 상태 업데이트 } } @@ -309,7 +288,7 @@ class MapFragment : Fragment() { private fun setupMapClickListener() { naverMap.setOnMapClickListener { _, _ -> // Restore all markers - updateMarkers(storeItems) + mapViewModel.storeList.value?.let { updateMarkers(it) } // Existing popup and marker reset logic storeInfoPopup?.let { @@ -332,16 +311,11 @@ class MapFragment : Fragment() { } private fun clearExistingMarkers() { - // 기존 마커 제거 - markerList.forEach { it.map = null } - markerList.clear() - + mapViewModel.clearMarkers() // 기존 경로 제거 - polyline?.map = null - polyline = null + routeParser?.clearPolyLine() } - override fun onRequestPermissionsResult( requestCode: Int, permissions: Array, grantResults: IntArray ) { @@ -355,65 +329,6 @@ class MapFragment : Fragment() { private const val LOCATION_PERMISSION_REQUEST_CODE = 1000 } - //경로 받아오기 - private fun fetchRoute(currentLocation: LatLng, destination: LatLng) { - val clientId = "5womszkja3" // 네이버 API Client ID - val clientSecret = "6nCQKXiCGpTayMAo1Ac2QuMS32Cpb7cr6hSLGoAZ" // 네이버 API Client Secret - val url = "https://naveropenapi.apigw.ntruss.com/map-direction/v1/driving" + - "?start=${currentLocation.longitude},${currentLocation.latitude}" + - "&goal=${destination.longitude},${destination.latitude}" + - "&option=trafast" // 옵션: 'trafast' (최적 경로), 'tracomfort' (안전 경로) - - val request = Request.Builder() - .url(url) - .addHeader("X-NCP-APIGW-API-KEY-ID", clientId) - .addHeader("X-NCP-APIGW-API-KEY", clientSecret) - .build() - - OkHttpClient().newCall(request).enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - e.printStackTrace() // 실패 시 로그 출력 - } - - override fun onResponse(call: Call, response: Response) { - if (response.isSuccessful) { - response.body?.string()?.let { responseBody -> - parseRoute(responseBody) - } - } - } - }) - } - - private fun showRouteToStore(markerLocation: LatLng) { - val currentLocation = naverMap.locationOverlay.position // 현재 위치 가져오기 - fetchRoute(currentLocation, markerLocation) - } - - private fun parseRoute(responseBody: String) { - val jsonObject = JSONObject(responseBody) - val route = jsonObject.getJSONObject("route").getJSONArray("trafast").getJSONObject(0) - val path = route.getJSONArray("path") - - val polylineCoords = mutableListOf() - for (i in 0 until path.length()) { - val point = path.getJSONArray(i) - val lat = point.getDouble(1) - val lng = point.getDouble(0) - polylineCoords.add(LatLng(lat, lng)) - } - - activity?.runOnUiThread { - polyline?.map = null - polyline = PolylineOverlay().apply { - coords = polylineCoords - color = 0xFF0000FF.toInt() // 파란색 - width = 10 // 선의 두께 - } - polyline?.map = naverMap - } - } - private fun setupSearchFunctionality(view: View) { val searchTextField = view.findViewById(R.id.search_store_textfield) val searchButton = view.findViewById(R.id.search_button) @@ -426,7 +341,8 @@ class MapFragment : Fragment() { searchTextField.requestFocus() //키보드 표시 - val imm = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + val imm = + requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager imm.showSoftInput(searchTextField, InputMethodManager.SHOW_IMPLICIT) } @@ -438,8 +354,9 @@ class MapFragment : Fragment() { if (actionId == EditorInfo.IME_ACTION_SEARCH) { performSearch(searchTextField.text.toString()) - val imm = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager - imm.hideSoftInputFromWindow(view?.windowToken, 0) + val imm = + requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(view.windowToken, 0) searchTextField.clearFocus() // 검색창 포커스 해제 true } else false @@ -450,22 +367,37 @@ class MapFragment : Fragment() { if (query.isEmpty()) return //필터링 로직 - val filteredStores = storeItems.filter { + val filteredStores = mapViewModel.storeList.value?.filter { it.name.contains(query, ignoreCase = true) } - if (filteredStores.isNotEmpty()) { - updateMarkers(filteredStores) + filteredStores?.let { + if (filteredStores.isNotEmpty()) { + updateMarkers(filteredStores) - val firstStore = filteredStores.first() - val firstMarker = markerList.find { it.captionText == firstStore.name } + val firstStore = filteredStores.first() + val firstMarker = + mapViewModel.markerList.value?.find { it.captionText == firstStore.name } - firstMarker?.let { marker -> - handleMarkerClick(marker, firstStore) - naverMap.moveCamera(CameraUpdate.scrollTo(marker.position)) + firstMarker?.let { marker -> + handleMarkerClick(marker, firstStore) + naverMap.moveCamera(CameraUpdate.scrollTo(marker.position)) + } + } else { + Toast.makeText(context, "$query(은)는 존재하지 않는 술집입니다.", Toast.LENGTH_LONG).show() } - } else { - Toast.makeText(context,"$query(은)는 존재하지 않는 술집입니다.", Toast.LENGTH_LONG).show() + } + } + + private fun showRouteToStore(markerLocation: LatLng) { + val currentLocation = naverMap.locationOverlay.position // 현재 위치 가져오기 + activity?.let { + routeParser?.showRouteToStore( + it, + naverMap, + currentLocation, + markerLocation + ) } } @@ -473,5 +405,4 @@ class MapFragment : Fragment() { private fun dpToPx(dp: Int): Int { return (dp * resources.displayMetrics.density).toInt() } -} - +} \ No newline at end of file diff --git a/app/src/main/java/com/example/ssul/view/map/MapViewModel.kt b/app/src/main/java/com/example/ssul/view/map/MapViewModel.kt new file mode 100644 index 0000000..fc923c6 --- /dev/null +++ b/app/src/main/java/com/example/ssul/view/map/MapViewModel.kt @@ -0,0 +1,96 @@ +package com.example.ssul.viewmodel + +import android.content.Context +import android.graphics.Color +import android.location.Geocoder +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.viewModelScope +import com.example.ssul.R +import com.example.ssul.StoreItem +import com.example.ssul.model.CoordinateRepository +import com.naver.maps.geometry.LatLng +import com.naver.maps.map.NaverMap +import com.naver.maps.map.overlay.Marker +import com.naver.maps.map.overlay.OverlayImage +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.IOException +import java.util.Locale + +class MapViewModel : ViewModel() { + private val _repository = CoordinateRepository() + + private val _activeFilters = MutableLiveData>().apply { value = mutableSetOf() } + val activeFilters: LiveData> get() = _activeFilters + + private val _storeList = MutableLiveData>().apply { value = mutableListOf() } + val storeList: LiveData> get() = _storeList + + private val _markerList = MutableLiveData>().apply { value = mutableListOf() } + val markerList: LiveData> get() = _markerList + + fun addMarker(marker: Marker){ + val currentList = _markerList.value ?: mutableListOf() + currentList.add(marker) + _markerList.value = currentList + } + + fun clearMarkers(){ + _markerList.value?.forEach { it.map = null } + _markerList.value?.clear() + } + + fun addStores(stores : List){ + val currentStores = _storeList.value ?: mutableListOf() + currentStores.addAll(stores) + _storeList.value = currentStores + } + + fun toggleFilter(filterId: Int) { + val currentFilters = _activeFilters.value ?: mutableSetOf() + if (currentFilters.contains(filterId)) { + currentFilters.remove(filterId) // 필터 비활성화 + } else { + currentFilters.add(filterId) // 필터 활성화 + } + _activeFilters.value = currentFilters + } + + fun getFilteredStores(): List { // 리턴 값이 있는 게 좋지 않음 별도로 필터리스트를 갖는 값을 만들고 그걸 View에서 사용하는게 나을듯 + return storeList.value?.filter { store -> + _activeFilters.value?.all { filterId -> + when (filterId) { + R.id.filter_group_button -> store.isFilterGroupChecked + R.id.filter_date_button -> store.isFilterDateChecked + R.id.filter_efficiency_button -> store.isFilterEfficiencyChecked + R.id.filter_partner_button -> store.isAssociated + else -> true + } + } ?: true + } ?: emptyList() + } + + fun getCoordinatesFromAddress(context : Context, address : String) : LatLng? { // 마찬가지 + _repository.getCoordinate(address)?.let { return it } + + val geocoder = Geocoder(context, Locale.getDefault()) + + return try { + val addresses = geocoder.getFromLocationName(address, 1) + if (!addresses.isNullOrEmpty()) { + val location = addresses[0] + val latLng = LatLng(location.latitude, location.longitude) + _repository.setCoordinate(address, latLng) + latLng + } else null + } catch (e: Exception) { + e.printStackTrace() + null + } + } +} +//현재 min api가 24이고 getFromLocation의 바뀐건 33부터 \ No newline at end of file diff --git a/app/src/main/java/com/example/ssul/view/map/RouteParser.kt b/app/src/main/java/com/example/ssul/view/map/RouteParser.kt new file mode 100644 index 0000000..f268685 --- /dev/null +++ b/app/src/main/java/com/example/ssul/view/map/RouteParser.kt @@ -0,0 +1,75 @@ +package com.example.ssul.viewmodel + +import androidx.activity.ComponentActivity +import com.naver.maps.geometry.LatLng +import com.naver.maps.map.NaverMap +import com.naver.maps.map.overlay.PolylineOverlay +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import org.json.JSONObject +import java.io.IOException + +class RouteParser{ + private var polyline: PolylineOverlay? = null + + fun showRouteToStore(activity : ComponentActivity, naverMap: NaverMap,currentLocation: LatLng, destination: LatLng) { + val clientId = "5womszkja3" // 네이버 API Client ID + val clientSecret = "6nCQKXiCGpTayMAo1Ac2QuMS32Cpb7cr6hSLGoAZ" // 네이버 API Client Secret + val url = "https://naveropenapi.apigw.ntruss.com/map-direction/v1/driving" + + "?start=${currentLocation.longitude},${currentLocation.latitude}" + + "&goal=${destination.longitude},${destination.latitude}" + + "&option=trafast" // 옵션: 'trafast' (최적 경로), 'tracomfort' (안전 경로) + + val request = Request.Builder() + .url(url) + .addHeader("X-NCP-APIGW-API-KEY-ID", clientId) + .addHeader("X-NCP-APIGW-API-KEY", clientSecret) + .build() + + OkHttpClient().newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() // 실패 시 로그 출력 + } + + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + response.body?.string()?.let { responseBody -> + parseRoute(activity, naverMap, responseBody) + } + } + } + }) + } + + fun clearPolyLine(){ + polyline?.map = null + polyline = null + } + + private fun parseRoute(activity : ComponentActivity, naverMap: NaverMap, responseBody: String) { + val jsonObject = JSONObject(responseBody) + val route = jsonObject.getJSONObject("route").getJSONArray("trafast").getJSONObject(0) + val path = route.getJSONArray("path") + + val polylineCoords = mutableListOf() + for (i in 0 until path.length()) { + val point = path.getJSONArray(i) + val lat = point.getDouble(1) + val lng = point.getDouble(0) + polylineCoords.add(LatLng(lat, lng)) + } + + activity.runOnUiThread { + polyline?.map = null + polyline = PolylineOverlay().apply { + coords = polylineCoords + color = 0xFF0000FF.toInt() // 파란색 + width = 10 // 선의 두께 + } + polyline?.map = naverMap + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/ssul/view/map/StorePopUpView.kt b/app/src/main/java/com/example/ssul/view/map/StorePopUpView.kt new file mode 100644 index 0000000..25f3a69 --- /dev/null +++ b/app/src/main/java/com/example/ssul/view/map/StorePopUpView.kt @@ -0,0 +1,4 @@ +package com.example.ssul.view.map + +class StorePopUpView { +} \ No newline at end of file From 80c32b78790036fd49861ed427d59b75e49ec127 Mon Sep 17 00:00:00 2001 From: minjun011026 Date: Tue, 25 Feb 2025 17:28:30 +0900 Subject: [PATCH 2/2] =?UTF-8?q?refactor:=20mapFragment=20MVVM=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=20=EB=B0=8F=20UI=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/compiler.xml | 2 +- .idea/gradle.xml | 1 + .idea/misc.xml | 3 +- .idea/runConfigurations.xml | 17 + app/build.gradle.kts | 17 +- .../com/example/ssul/adapter/TabAdapter.kt | 2 +- .../java/com/example/ssul/api/ApiService.kt | 3 +- .../com/example/ssul/model/CoordinateModel.kt | 14 +- .../com/example/ssul/view/map/MapFragment.kt | 786 +++++++++++------- .../com/example/ssul/view/map/MapViewModel.kt | 184 +++- .../com/example/ssul/view/map/RouteParser.kt | 4 +- .../example/ssul/view/map/StorePopUpView.kt | 83 +- app/src/main/res/layout/fragment_map.xml | 2 +- app/src/main/res/values/strings.xml | 2 + gradle/libs.versions.toml | 15 + 15 files changed, 794 insertions(+), 341 deletions(-) create mode 100644 .idea/runConfigurations.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml index b589d56..b86273d 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 0897082..7b3006b 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -4,6 +4,7 @@