diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 5373128e..c41bcfd2 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -31,6 +31,7 @@ android {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
buildConfigField("String", "BASE_URL", properties["base.url"].toString())
buildConfigField("String", "ACCESS_TOKEN", properties["access.token"].toString())
+ buildConfigField("String", "NAVER_MAP_CLIENT_ID", properties["naver.map.client.id"].toString())
manifestPlaceholders["IO_SENTRY_DSN"] = properties["io.sentry.dsn"] as String
}
@@ -89,6 +90,12 @@ dependencies {
implementation(libs.bundles.okhttp)
implementation(libs.bundles.retrofit)
implementation(libs.kotlin.serialization.json)
+
+ // Naver Map
+ implementation(libs.naver.maps)
+
+ // Location
+ implementation(libs.play.services.location)
}
ktlint {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 988dfb5e..f978e34b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -3,6 +3,8 @@
xmlns:tools="http://schemas.android.com/tools">
+
+
+
R.drawable.ic_map_marker_play_small
+ CategoryType.STUDY.toString() -> R.drawable.ic_map_marker_study_small
+ CategoryType.MULTI.toString() -> R.drawable.ic_map_marker_multi_small
+ else -> R.drawable.ic_map_marker_other_small
+ }
+ )
+}
diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/joingroup/JoinGroupSuccessActivity.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/joingroup/JoinGroupSuccessActivity.kt
new file mode 100644
index 00000000..3510fba4
--- /dev/null
+++ b/app/src/main/java/org/sopt/pingle/presentation/ui/joingroup/JoinGroupSuccessActivity.kt
@@ -0,0 +1,58 @@
+package org.sopt.pingle.presentation.ui.joingroup
+
+import android.os.Bundle
+import android.text.Spannable
+import android.text.SpannableString
+import android.text.style.ForegroundColorSpan
+import android.text.style.TextAppearanceSpan
+import androidx.core.content.ContextCompat
+import org.sopt.pingle.R
+import org.sopt.pingle.databinding.ActivityJoinGroupSuccessBinding
+import org.sopt.pingle.util.base.BindingActivity
+
+class JoinGroupSuccessActivity :
+ BindingActivity(R.layout.activity_join_group_success) {
+ private lateinit var groupName: String
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ initLayout()
+ }
+
+ private fun initLayout() {
+ // TODO 이전 화면에서 Intent를 통해서 groupName을 가져옴
+ groupName = "SOPT"
+
+ binding.tvJoinGroupSuccessDescriptionGroupName.text = SpannableString(
+ getString(
+ R.string.join_group_success_description_group_name,
+ groupName
+ )
+ ).apply {
+ setSpan(
+ TextAppearanceSpan(
+ this@JoinGroupSuccessActivity,
+ R.style.TextAppearance_Pingle_Sub_Semi_16
+ ),
+ GROUP_NAME_START,
+ groupName.length,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
+ )
+ setSpan(
+ ForegroundColorSpan(
+ ContextCompat.getColor(
+ this@JoinGroupSuccessActivity,
+ R.color.g_01
+ )
+ ),
+ GROUP_NAME_START,
+ groupName.length,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
+ )
+ }
+ }
+
+ companion object {
+ const val GROUP_NAME_START = 0
+ }
+}
diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/MainActivity.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/MainActivity.kt
index 92a6236b..51bbda25 100644
--- a/app/src/main/java/org/sopt/pingle/presentation/ui/main/MainActivity.kt
+++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/MainActivity.kt
@@ -63,8 +63,10 @@ class MainActivity : BindingActivity(R.layout.activity_main
}
private inline fun navigateToFragment() {
- supportFragmentManager.commit {
- replace(R.id.fcv_main_all_navi, T::class.java.canonicalName)
+ if (supportFragmentManager.findFragmentById(R.id.fcv_main_all_navi) !is T) {
+ supportFragmentManager.commit {
+ replace(R.id.fcv_main_all_navi, T::class.java.canonicalName)
+ }
}
}
}
diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapFragment.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapFragment.kt
index 8349651d..074d46f3 100644
--- a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapFragment.kt
+++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapFragment.kt
@@ -1,13 +1,179 @@
package org.sopt.pingle.presentation.ui.main.home.map
+import android.Manifest
+import android.content.pm.PackageManager
+import android.location.Location
import android.os.Bundle
import android.view.View
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.add
+import androidx.fragment.app.commit
+import androidx.fragment.app.viewModels
+import androidx.lifecycle.flowWithLifecycle
+import androidx.lifecycle.lifecycleScope
+import com.google.android.gms.location.LocationServices
+import com.naver.maps.geometry.LatLng
+import com.naver.maps.map.CameraAnimation
+import com.naver.maps.map.CameraUpdate
+import com.naver.maps.map.LocationTrackingMode
+import com.naver.maps.map.MapFragment
+import com.naver.maps.map.NaverMap
+import com.naver.maps.map.OnMapReadyCallback
+import com.naver.maps.map.overlay.OverlayImage
+import com.naver.maps.map.util.FusedLocationSource
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
import org.sopt.pingle.R
import org.sopt.pingle.databinding.FragmentMapBinding
+import org.sopt.pingle.presentation.mapper.toMarker
+import org.sopt.pingle.presentation.type.CategoryType
import org.sopt.pingle.util.base.BindingFragment
+import org.sopt.pingle.util.component.PingleChip
+import org.sopt.pingle.util.fragment.showToast
+
+class MapFragment : BindingFragment(R.layout.fragment_map), OnMapReadyCallback {
+ private val mapViewModel by viewModels()
+ private lateinit var naverMap: NaverMap
+ private lateinit var locationSource: FusedLocationSource
-class MapFragment : BindingFragment(R.layout.fragment_map) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
+
+ initMap()
+ initLayout()
+ addListeners()
+ collectData()
+ setLocationTrackingMode()
+ }
+
+ override fun onMapReady(naverMap: NaverMap) {
+ this.naverMap = naverMap.apply {
+ isNightModeEnabled = true
+ mapType = NaverMap.MapType.Navi
+
+ with(uiSettings) {
+ isZoomControlEnabled = false
+ isScaleBarEnabled = false
+ }
+ }
+
+ makeMarkers()
+ }
+
+ private fun initMap() {
+ val mapFragment =
+ childFragmentManager.findFragmentById(R.id.fragment_map_naver_map) as MapFragment?
+ ?: MapFragment.newInstance().also {
+ childFragmentManager.commit {
+ add(R.id.fragment_map_naver_map)
+ setReorderingAllowed(true)
+ }
+ }
+
+ mapFragment.getMapAsync(this@MapFragment)
+ }
+
+ private fun initLayout() {
+ with(binding) {
+ chipMapCategoryPlay.setChipCategoryType(CategoryType.PLAY)
+ chipMapCategoryStudy.setChipCategoryType(CategoryType.STUDY)
+ chipMapCategoryMulti.setChipCategoryType(CategoryType.MULTI)
+ chipMapCategoryOthers.setChipCategoryType(CategoryType.OTHER)
+ }
+ }
+
+ private fun addListeners() {
+ binding.fabMapHere.setOnClickListener {
+ if (::locationSource.isInitialized) {
+ locationSource.lastLocation?.let { location -> moveMapCamera(location) }
+ }
+ }
+
+ binding.cgMapCategory.setOnCheckedStateChangeListener { group, checkedIds ->
+ mapViewModel.setCategory(
+ category = checkedIds.getOrNull(SINGLE_SELECTION)
+ ?.let { group.findViewById(it).categoryType }
+ )
+ }
+ }
+
+ private fun collectData() {
+ mapViewModel.category.flowWithLifecycle(lifecycle).onEach {
+ // TODO 서버 통신 구현 시 삭제 예정
+ showToast(it?.name ?: "null")
+ }.launchIn(lifecycleScope)
+ }
+
+ private fun setLocationTrackingMode() {
+ if (LOCATION_PERMISSIONS.any { permission ->
+ ContextCompat.checkSelfPermission(
+ requireContext(),
+ permission
+ ) == PackageManager.PERMISSION_GRANTED
+ }
+ ) {
+ locationSource = FusedLocationSource(this, LOCATION_PERMISSION_REQUEST_CODE)
+ } else {
+ requestLocationPermission()
+ }
+
+ LocationServices.getFusedLocationProviderClient(requireContext()).lastLocation.addOnSuccessListener { location ->
+ if (::naverMap.isInitialized) {
+ with(naverMap) {
+ locationSource = this@MapFragment.locationSource
+ locationTrackingMode = LocationTrackingMode.NoFollow
+
+ locationOverlay.apply {
+ isVisible = true
+ icon = OverlayImage.fromResource(R.drawable.ic_map_location_overlay)
+ }
+ }
+ }
+
+ moveMapCamera(location)
+ }
+ }
+
+ private fun requestLocationPermission() {
+ val locationPermissionRequest = registerForActivityResult(
+ ActivityResultContracts.RequestMultiplePermissions()
+ ) { permissions ->
+ when {
+ permissions[LOCATION_PERMISSIONS[0]] == true || permissions[LOCATION_PERMISSIONS[1]] == true -> {
+ setLocationTrackingMode()
+ }
+ }
+ }
+
+ locationPermissionRequest.launch(LOCATION_PERMISSIONS)
+ }
+
+ private fun moveMapCamera(location: Location) {
+ if (::naverMap.isInitialized) {
+ naverMap.moveCamera(
+ CameraUpdate.scrollTo(
+ LatLng(
+ location.latitude,
+ location.longitude
+ )
+ ).animate(CameraAnimation.Linear)
+ )
+ }
+ }
+
+ private fun makeMarkers() {
+ mapViewModel.dummyPinList.map { pinEntity ->
+ pinEntity.toMarker().map = naverMap
+ }
+ }
+
+ companion object {
+ private const val LOCATION_PERMISSION_REQUEST_CODE = 1000
+ private val LOCATION_PERMISSIONS = arrayOf(
+ Manifest.permission.ACCESS_FINE_LOCATION,
+ Manifest.permission.ACCESS_COARSE_LOCATION
+ )
+ private const val SINGLE_SELECTION = 0
}
}
diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapViewModel.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapViewModel.kt
new file mode 100644
index 00000000..d4a9947d
--- /dev/null
+++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapViewModel.kt
@@ -0,0 +1,47 @@
+package org.sopt.pingle.presentation.ui.main.home.map
+
+import androidx.lifecycle.ViewModel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import org.sopt.pingle.domain.model.PinEntity
+import org.sopt.pingle.presentation.type.CategoryType
+
+class MapViewModel() : ViewModel() {
+ val dummyPinList = listOf(
+ PinEntity(
+ id = 1,
+ x = 126.9275108,
+ y = 37.5262935,
+ category = "PLAY",
+ meetingCount = 1
+ ),
+ PinEntity(
+ id = 2,
+ x = 126.9283122,
+ y = 37.5259168,
+ category = "STUDY",
+ meetingCount = 2
+ ),
+ PinEntity(
+ id = 3,
+ x = 126.9276423,
+ y = 37.5258711,
+ category = "MULTI",
+ meetingCount = 1
+ ),
+ PinEntity(
+ id = 4,
+ x = 126.9286719,
+ y = 37.5253629,
+ category = "OTHERS",
+ meetingCount = 2
+ )
+ )
+
+ private val _category = MutableStateFlow(null)
+ val category get() = _category.asStateFlow()
+
+ fun setCategory(category: CategoryType?) {
+ _category.value = category
+ }
+}
diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/plan/PlanActivity.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/plan/PlanActivity.kt
index 76c5e81b..d8fe71b3 100644
--- a/app/src/main/java/org/sopt/pingle/presentation/ui/main/plan/PlanActivity.kt
+++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/plan/PlanActivity.kt
@@ -1,13 +1,89 @@
package org.sopt.pingle.presentation.ui.main.plan
import android.os.Bundle
+import androidx.activity.viewModels
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.flowWithLifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.viewpager2.widget.ViewPager2
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
import org.sopt.pingle.R
import org.sopt.pingle.databinding.ActivityPlanBinding
import org.sopt.pingle.util.base.BindingActivity
class PlanActivity : BindingActivity(R.layout.activity_plan) {
+ private val planViewModel: PlanViewModel by viewModels()
+ private lateinit var fragmentList: ArrayList
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_plan)
+
+ setPlanFragmentStateAdapter()
+ addListeners()
+ collectData()
+ }
+
+ private fun setPlanFragmentStateAdapter() {
+ // TODO 차후에 나머지 개최 프로세스 fragment 추가
+ fragmentList = ArrayList()
+ fragmentList.apply {
+ add(PlanTitleFragment())
+ add(PlanDateTimeFragment())
+ add(PlanOpenChattingFragment())
+ }
+
+ val adapter = PlanFragmentStateAdapter(fragmentList, this)
+ with(binding.vpPlan) {
+ this.adapter = adapter
+ isUserInputEnabled = false
+ registerOnPageChangeCallback(object :
+ ViewPager2.OnPageChangeCallback() {
+ override fun onPageSelected(position: Int) {
+ super.onPageSelected(position)
+ planViewModel.setCurrentPage(position)
+ }
+ })
+ }
+ }
+
+ private fun addListeners() {
+ binding.btnPlan.setOnClickListener {
+ when (binding.vpPlan.currentItem) {
+ // TODO 핑글 개최 api 연동
+ fragmentList.size - 1 -> {}
+ else -> {
+ binding.vpPlan.currentItem++
+ }
+ }
+ }
+ binding.toolbar.ivAllTopbarArrowWithTitleArrowLeft.setOnClickListener {
+ when (binding.vpPlan.currentItem) {
+ 0 -> {
+ // TODO 나가기 확인 모달
+ }
+
+ else -> {
+ binding.vpPlan.currentItem--
+ }
+ }
+ }
+ binding.tvPlanClose.setOnClickListener {
+ // TODO 나가기 확인 모달
+ }
+ }
+
+ private fun collectData() {
+ planViewModel.currentPage.flowWithLifecycle(lifecycle).onEach { currentPage ->
+ when (currentPage) {
+ fragmentList.size - 1 -> {
+ binding.btnPlan.text = getString(R.string.plan_pingle)
+ }
+
+ // TODO 다른 다음으로 스트링과 합치기
+ else -> {
+ binding.btnPlan.text = getString(R.string.plan_next)
+ }
+ }
+ }.launchIn(lifecycleScope)
}
}
diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/plan/PlanDateTimeFragment.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/plan/PlanDateTimeFragment.kt
new file mode 100644
index 00000000..e522a8a7
--- /dev/null
+++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/plan/PlanDateTimeFragment.kt
@@ -0,0 +1,13 @@
+package org.sopt.pingle.presentation.ui.main.plan
+
+import android.os.Bundle
+import android.view.View
+import org.sopt.pingle.R
+import org.sopt.pingle.databinding.FragmentPlanDateTimeBinding
+import org.sopt.pingle.util.base.BindingFragment
+
+class PlanDateTimeFragment : BindingFragment(R.layout.fragment_plan_date_time) {
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ }
+}
diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/plan/PlanFragmentStateAdapter.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/plan/PlanFragmentStateAdapter.kt
new file mode 100644
index 00000000..7a784ee4
--- /dev/null
+++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/plan/PlanFragmentStateAdapter.kt
@@ -0,0 +1,15 @@
+package org.sopt.pingle.presentation.ui.main.plan
+
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentActivity
+import androidx.viewpager2.adapter.FragmentStateAdapter
+
+class PlanFragmentStateAdapter(
+ private val fragmentList: ArrayList,
+ fragmentActivity: FragmentActivity
+) : FragmentStateAdapter(fragmentActivity) {
+ override fun getItemCount(): Int = fragmentList.size
+ override fun createFragment(position: Int): Fragment {
+ return fragmentList[position]
+ }
+}
diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/plan/PlanOpenChattingFragment.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/plan/PlanOpenChattingFragment.kt
new file mode 100644
index 00000000..53585426
--- /dev/null
+++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/plan/PlanOpenChattingFragment.kt
@@ -0,0 +1,13 @@
+package org.sopt.pingle.presentation.ui.main.plan
+
+import android.os.Bundle
+import android.view.View
+import org.sopt.pingle.R
+import org.sopt.pingle.databinding.FragmentPlanOpenChattingBinding
+import org.sopt.pingle.util.base.BindingFragment
+
+class PlanOpenChattingFragment : BindingFragment(R.layout.fragment_plan_open_chatting) {
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ }
+}
diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/plan/PlanTitleFragment.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/plan/PlanTitleFragment.kt
new file mode 100644
index 00000000..69fba4ba
--- /dev/null
+++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/plan/PlanTitleFragment.kt
@@ -0,0 +1,13 @@
+package org.sopt.pingle.presentation.ui.main.plan
+
+import android.os.Bundle
+import android.view.View
+import org.sopt.pingle.R
+import org.sopt.pingle.databinding.FragmentPlanTitleBinding
+import org.sopt.pingle.util.base.BindingFragment
+
+class PlanTitleFragment : BindingFragment(R.layout.fragment_plan_title) {
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ }
+}
diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/plan/PlanViewModel.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/plan/PlanViewModel.kt
new file mode 100644
index 00000000..e3d14475
--- /dev/null
+++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/plan/PlanViewModel.kt
@@ -0,0 +1,18 @@
+package org.sopt.pingle.presentation.ui.main.plan
+
+import androidx.lifecycle.ViewModel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class PlanViewModel : ViewModel() {
+ private val _currentPage = MutableStateFlow(FIRST_PAGE_POSITION)
+ val currentPage get() = _currentPage.asStateFlow()
+
+ fun setCurrentPage(position: Int) {
+ _currentPage.value = position
+ }
+
+ companion object {
+ const val FIRST_PAGE_POSITION = 0
+ }
+}
diff --git a/app/src/main/java/org/sopt/pingle/util/component/PingleChip.kt b/app/src/main/java/org/sopt/pingle/util/component/PingleChip.kt
index 773c1893..3f2353ed 100644
--- a/app/src/main/java/org/sopt/pingle/util/component/PingleChip.kt
+++ b/app/src/main/java/org/sopt/pingle/util/component/PingleChip.kt
@@ -16,6 +16,8 @@ class PingleChip @JvmOverloads constructor(
attrs: AttributeSet? = null,
defStyleAttr: Int = R.style.Theme_Pingle_Chip_All
) : Chip(context, attrs, defStyleAttr) {
+ private lateinit var _categoryType: CategoryType
+ val categoryType get() = _categoryType
private fun setColorStateList(
context: Context,
@@ -34,7 +36,9 @@ class PingleChip @JvmOverloads constructor(
)
fun setChipCategoryType(categoryType: CategoryType) {
- val inactivatedOutlinedColor = R.color.g_03
+ this@PingleChip._categoryType = categoryType
+
+ val inactivatedOutlinedColor = R.color.g_09
val inactivatedTextColor = R.color.g_03
val inactivatedChipColor = R.color.g_11
diff --git a/app/src/main/res/drawable/ic_map_location_overlay.xml b/app/src/main/res/drawable/ic_map_location_overlay.xml
new file mode 100644
index 00000000..fd5c7ecc
--- /dev/null
+++ b/app/src/main/res/drawable/ic_map_location_overlay.xml
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_map_marker_multi_small.xml b/app/src/main/res/drawable/ic_map_marker_multi_small.xml
new file mode 100644
index 00000000..0653bbf5
--- /dev/null
+++ b/app/src/main/res/drawable/ic_map_marker_multi_small.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_map_marker_other_small.xml b/app/src/main/res/drawable/ic_map_marker_other_small.xml
new file mode 100644
index 00000000..9772fec0
--- /dev/null
+++ b/app/src/main/res/drawable/ic_map_marker_other_small.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_map_marker_play_small.xml b/app/src/main/res/drawable/ic_map_marker_play_small.xml
new file mode 100644
index 00000000..51c12aa4
--- /dev/null
+++ b/app/src/main/res/drawable/ic_map_marker_play_small.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_map_marker_study_small.xml b/app/src/main/res/drawable/ic_map_marker_study_small.xml
new file mode 100644
index 00000000..4ce2370b
--- /dev/null
+++ b/app/src/main/res/drawable/ic_map_marker_study_small.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_join_group_success.xml b/app/src/main/res/layout/activity_join_group_success.xml
new file mode 100644
index 00000000..08200ab8
--- /dev/null
+++ b/app/src/main/res/layout/activity_join_group_success.xml
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_plan.xml b/app/src/main/res/layout/activity_plan.xml
index fc16e19f..e25ae8f8 100644
--- a/app/src/main/res/layout/activity_plan.xml
+++ b/app/src/main/res/layout/activity_plan.xml
@@ -9,19 +9,77 @@
+ android:layout_height="match_parent">
-
+
+
+
+
+
+
+
+
+
+
+ app:layout_constraintEnd_toEndOf="@id/gl_end"
+ app:layout_constraintStart_toStartOf="@id/gl_start">
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_map.xml b/app/src/main/res/layout/fragment_map.xml
index 8f9f93d5..1a378bc8 100644
--- a/app/src/main/res/layout/fragment_map.xml
+++ b/app/src/main/res/layout/fragment_map.xml
@@ -12,16 +12,78 @@
android:layout_height="match_parent"
tools:context=".presentation.ui.main.home.map.MapFragment">
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_plan_date_time.xml b/app/src/main/res/layout/fragment_plan_date_time.xml
new file mode 100644
index 00000000..67ed5d4c
--- /dev/null
+++ b/app/src/main/res/layout/fragment_plan_date_time.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_plan_open_chatting.xml b/app/src/main/res/layout/fragment_plan_open_chatting.xml
new file mode 100644
index 00000000..67ed5d4c
--- /dev/null
+++ b/app/src/main/res/layout/fragment_plan_open_chatting.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_plan_title.xml b/app/src/main/res/layout/fragment_plan_title.xml
new file mode 100644
index 00000000..67ed5d4c
--- /dev/null
+++ b/app/src/main/res/layout/fragment_plan_title.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index a1daf7c5..920bb21f 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -28,12 +28,25 @@
34dp
36dp
-
+
+ 16dp
+
+
60dp
+
+
56dp
42dp
42dp
-
+ 10dp
+
+
+ 50dp
+
+
+ 4dp
+
+
24dp
24dp
\ 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 1a8770d2..a7b931e2 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -14,11 +14,23 @@
마이핑글
설정
-
+
핑글에 오신걸\n환영합니다!
기존 단체\n입장하기
신규 단체\n개설하기
+
+ 입장하기
+ 단체 입장\n완료!
+ %s에서
+ 핑글 여정을 함께해보세요!
+
+
+ 나중에 만드시겠어요?
+ 나가기
+ 다음으로
+ 핑글 개최하기
+
참여하기
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 32360682..3198761a 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -19,19 +19,19 @@
@@ -49,12 +49,26 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 6eea7139..50ce45ee 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -36,6 +36,8 @@ retrofit = "2.9.0"
retrofit-kotlin-serialization-converter = "1.0.0"
kotlin-serialization-json = "1.5.1"
sentry = "4.1.1"
+naver-maps = "3.17.0"
+play-services-location = "21.0.1"
[libraries]
# AndroidX
@@ -73,6 +75,8 @@ okhttp-logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-i
retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
retrofit-kotlin-serialization-converter = { group = "com.jakewharton.retrofit", name = "retrofit2-kotlinx-serialization-converter", version.ref = "retrofit-kotlin-serialization-converter" }
kotlin-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlin-serialization-json" }
+naver-maps = { group = "com.naver.maps", name = "map-sdk", version.ref = "naver-maps" }
+play-services-location = { group = "com.google.android.gms", name = "play-services-location", version.ref = "play-services-location" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 336fb641..19c4ebfe 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -10,6 +10,7 @@ dependencyResolutionManagement {
repositories {
google()
mavenCentral()
+ maven { setUrl("https://naver.jfrog.io/artifactory/maven/") }
}
}