Skip to content
3 changes: 3 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_HEALTH"/>

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

<application
android:name="com.paw.key.PawKeyApplication"
android:allowBackup="true"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.paw.key.core.designsystem.component

import android.util.Log
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
Expand Down Expand Up @@ -38,13 +39,15 @@ import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.paw.key.core.designsystem.theme.PawKeyTheme
import com.paw.key.core.util.noRippleClickable
import kotlin.String

@Composable
fun CourseCard(
title: String,
petName:String,
date: String,
onCLickItem : () -> Unit,
modifier: Modifier = Modifier
) {
Column(
Expand All @@ -53,6 +56,9 @@ fun CourseCard(
.fillMaxWidth()
.size(width = 328.dp , height = 240.dp)
.background(Color.White, shape = RoundedCornerShape(20.dp))
.noRippleClickable {
onCLickItem()
}
) {
// 지도 썸네일
Box(
Expand Down Expand Up @@ -168,6 +174,7 @@ fun CourseCardPreview() {
title = "홍대 주변 좋은 산책 코스",
petName = "반려견 이름",
date = "2025/05/17",
onCLickItem = {}
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,28 +53,6 @@ fun CourseDetail(
modifier = modifier
.fillMaxWidth()
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = ImageVector.vectorResource(R.drawable.ic_arrow_left_black),
contentDescription = "뒤로가기"
)
Box(
modifier = Modifier.weight(1f),
contentAlignment = Alignment.Center
) {
Text(
text = "저장한 산책 루트",
style = PawKeyTheme.typography.body16Sb
)
}
Spacer(modifier = Modifier.width(24.dp))
}

AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data("https://pawkey-server.com/image.jpg")
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/com/paw/key/data/di/RepositoryModule.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.paw.key.data.di

import com.paw.key.data.repositoryimpl.DummyRepositoryImpl
import com.paw.key.data.repositoryimpl.RegionRepositoryImpl
import com.paw.key.data.repositoryimpl.WalkSharedResultRepositoryImpl
import com.paw.key.domain.repository.DummyRepository
import com.paw.key.domain.repository.RegionRepository
import com.paw.key.domain.repository.WalkSharedResultRepository
import dagger.Binds
import dagger.Module
Expand All @@ -25,4 +27,10 @@ interface RepositoryModule {
walkSharedResultRepositoryImpl: WalkSharedResultRepositoryImpl
): WalkSharedResultRepository

/*Home*/
@Binds
@Singleton
fun bindsRegionRepository(
regionRepositoryImpl: RegionRepositoryImpl
): RegionRepository
}
7 changes: 7 additions & 0 deletions app/src/main/java/com/paw/key/data/di/ServiceModule.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.paw.key.data.di

import com.paw.key.data.service.DummyService
import com.paw.key.data.service.RegionService
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
Expand All @@ -17,4 +18,10 @@ object ServiceModule {
fun providesDummyService(retrofit: Retrofit ): DummyService =
retrofit.create(DummyService::class.java)

@Provides
@Singleton
fun providesRegionService(retrofit: Retrofit ): RegionService =
retrofit.create(RegionService::class.java)


}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import kotlinx.serialization.Serializable
@Serializable
data class BaseResponse<T>(
@SerialName("code")
val code: Int,
val code: String,
@SerialName("message")
val message: String,
@SerialName("data")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.paw.key.data.dto.response.region

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class RegionResponseDto(
@SerialName("regionName")
val regionName: String,
@SerialName("geometryDto")
val geometryDto: GeometryDto
)

@Serializable
data class GeometryDto(
@SerialName("type")
val type: String,
@SerialName("coordinates")
val coordinates: List<List<List<List<Double>>>>
)
30 changes: 30 additions & 0 deletions app/src/main/java/com/paw/key/data/mapper/RegionMapper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.paw.key.data.mapper

import com.paw.key.data.dto.response.region.GeometryDto
import com.paw.key.data.dto.response.region.RegionResponseDto
import com.paw.key.domain.model.entity.region.GeometryEntity
import com.paw.key.domain.model.entity.region.RegionDataEntity
import javax.inject.Inject

class RegionMapper @Inject constructor() {
fun mapDtoToEntity(dto: RegionResponseDto): RegionDataEntity {
return RegionDataEntity(
regionName = dto.regionName,
geometry = dto.geometryDto.toEntity()
)
}

private fun GeometryDto.toEntity(): GeometryEntity {
return GeometryEntity(
type = this.type,
coordinates = this.coordinates.map { polygon ->
polygon.map { ring ->
ring.map { point ->
// 서버에서 위도 경도 다름
Pair(point[1], point[0])
}
}
}
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.paw.key.data.remote.datasource

import com.paw.key.data.service.RegionService
import javax.inject.Inject

class RegionDataSource @Inject constructor (
private val regionService: RegionService
) {
suspend fun getRegionGeometry(userId: Int, regionId: Int) = regionService.getRegionGeometry(userId, regionId)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.paw.key.data.repositoryimpl

import com.paw.key.data.mapper.RegionMapper
import com.paw.key.data.remote.datasource.RegionDataSource
import com.paw.key.domain.model.entity.region.RegionDataEntity
import com.paw.key.domain.repository.RegionRepository
import javax.inject.Inject


class RegionRepositoryImpl @Inject constructor(
private val regionDataSource: RegionDataSource,
private val mapper: RegionMapper
) : RegionRepository {
override suspend fun getRegionGeometry(userId: Int, regionId: Int): Result<RegionDataEntity> = runCatching {
regionDataSource.getRegionGeometry(userId, regionId).data.let {
mapper.mapDtoToEntity(it)
}
}
}
15 changes: 15 additions & 0 deletions app/src/main/java/com/paw/key/data/service/RegionService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.paw.key.data.service

import com.paw.key.data.dto.response.BaseResponse
import com.paw.key.data.dto.response.region.RegionResponseDto
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Path

interface RegionService {
@GET("regions/{regionId}/geometry")
suspend fun getRegionGeometry(
@Header("X-USER-ID") userId: Int,
@Path("regionId") regionId: Int,
): BaseResponse<RegionResponseDto>
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
package com.paw.key.domain.model.entity.region

import com.kakao.vectormap.LatLng

data class RegionResponse(
val code: String,
val message: String,
val data: RegionData
)

data class RegionData(
data class RegionDataEntity(
val regionName: String,
val geometryDto: GeometryDto
val geometry: GeometryEntity
)

data class GeometryDto(
data class GeometryEntity(
val type: String,
val coordinates: List<List<List<Pair<Double, Double>>>> // MultiPolygon은 여러 폴리곤의 리스트를 가짐
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.paw.key.domain.repository

import com.paw.key.domain.model.entity.region.RegionDataEntity

interface RegionRepository {
suspend fun getRegionGeometry(userId: Int, regionId: Int): Result<RegionDataEntity>
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,28 +98,32 @@ fun TabListScreen(
CourseCard(
title = "제목을 입력해주세요",
petName = "안녕꼬리",
date = "21/1/1"
date = "21/1/1",
onCLickItem = {}
)
}
item {
CourseCard(
title = "제목을 입력해주세요",
petName = "안녕꼬리",
date = "21/1/1"
date = "21/1/1",
onCLickItem = {}
)
}
item {
CourseCard(
title = "제목을 입력해주세요",
petName = "안녕꼬리",
date = "21/1/1"
date = "21/1/1",
onCLickItem = {}
)
}
item {
CourseCard(
title = "제목을 입력해주세요",
petName = "안녕꼬리",
date = "21/1/1"
date = "21/1/1",
onCLickItem = {}
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.paw.key.presentation.ui.course.walkreview

import android.Manifest
import android.net.Uri
import android.os.Build
import androidx.activity.compose.rememberLauncherForActivityResult
Expand Down Expand Up @@ -56,6 +57,12 @@ fun WalkReviewRoute(

val lifecycleOwner = LocalLifecycleOwner.current

val imagePermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
Manifest.permission.READ_MEDIA_IMAGES
} else {
Manifest.permission.READ_EXTERNAL_STORAGE
}

val pickMultipleMediaLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.PickMultipleVisualMedia(5)
) { uris ->
Expand All @@ -64,6 +71,24 @@ fun WalkReviewRoute(
}
}

val galleryLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.GetMultipleContents()
) { uris: List<Uri> ->
if (uris.isNotEmpty()) {
val limitedUris = uris.take(5)
viewModel.onImagesSelected(limitedUris)
}
}

val permissionLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
galleryLauncher.launch("image/*")
}
}


LaunchedEffect(viewModel.sideEffect, lifecycleOwner) {
viewModel.sideEffect.flowWithLifecycle(lifecycleOwner.lifecycle)
.collect { sideEffect ->
Expand Down Expand Up @@ -110,9 +135,13 @@ fun WalkReviewRoute(
viewModel.onContentTextChanged(it)
},
onClickImage = {
pickMultipleMediaLauncher.launch(
PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageAndVideo)
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
pickMultipleMediaLauncher.launch(
PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageAndVideo)
)
} else {
permissionLauncher.launch(imagePermission)
}
},
onImageDelete = {
viewModel.onImageDelete(it)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ fun HomeLocationSettingScreen(
enabled = isFormValid,
onClick = {
if (isFormValid) {

navigateNext()
}
}
)
Expand Down
Loading