diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 46ac336..1f82419 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -29,5 +29,4 @@ - \ No newline at end of file diff --git a/app/src/main/java/com/gdg/crowdzero_android/di/DataSourceModule.kt b/app/src/main/java/com/gdg/crowdzero_android/di/DataSourceModule.kt index f3fff55..acd7b52 100644 --- a/app/src/main/java/com/gdg/crowdzero_android/di/DataSourceModule.kt +++ b/app/src/main/java/com/gdg/crowdzero_android/di/DataSourceModule.kt @@ -1,9 +1,7 @@ package com.gdg.crowdzero_android.di import com.gdg.data.datasource.CrowdZeroDataSource -import com.gdg.data.datasource.ExampleDataSource import com.gdg.data.datasourceimpl.CrowdZeroDataSourceImpl -import com.gdg.data.datasourceimpl.ExampleDataSourceImpl import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -14,10 +12,6 @@ import javax.inject.Singleton @InstallIn(SingletonComponent::class) abstract class DataSourceModule { - @Binds - @Singleton - abstract fun bindExampleDataSource(exampleDataSourceImpl: ExampleDataSourceImpl): ExampleDataSource - @Binds @Singleton abstract fun bindCrowdZeroDataSource(crowdZeroDataSourceImpl: CrowdZeroDataSourceImpl): CrowdZeroDataSource diff --git a/app/src/main/java/com/gdg/crowdzero_android/di/Qualifier.kt b/app/src/main/java/com/gdg/crowdzero_android/di/Qualifier.kt index 9a81933..fd3dbc4 100644 --- a/app/src/main/java/com/gdg/crowdzero_android/di/Qualifier.kt +++ b/app/src/main/java/com/gdg/crowdzero_android/di/Qualifier.kt @@ -5,7 +5,3 @@ import javax.inject.Qualifier @Qualifier @Retention(AnnotationRetention.BINARY) annotation class CrowdZeroRetrofit - -@Qualifier -@Retention(AnnotationRetention.BINARY) -annotation class AccessToken diff --git a/app/src/main/java/com/gdg/crowdzero_android/di/RepositoryModule.kt b/app/src/main/java/com/gdg/crowdzero_android/di/RepositoryModule.kt index aa23fe8..eeb2230 100644 --- a/app/src/main/java/com/gdg/crowdzero_android/di/RepositoryModule.kt +++ b/app/src/main/java/com/gdg/crowdzero_android/di/RepositoryModule.kt @@ -1,9 +1,7 @@ package com.gdg.crowdzero_android.di import com.gdg.data.repositoryimpl.CrowdZeroRepositoryImpl -import com.gdg.data.repositoryimpl.ExampleRepositoryImpl import com.gdg.domain.repository.CrowdZeroRepository -import com.gdg.domain.repository.ExampleRepository import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -14,10 +12,6 @@ import javax.inject.Singleton @InstallIn(SingletonComponent::class) abstract class RepositoryModule { - @Binds - @Singleton - abstract fun bindExampleRepository(exampleRepositoryImpl: ExampleRepositoryImpl): ExampleRepository - @Binds @Singleton abstract fun bindCrowdZeroRepository(crowdZeroRepositoryImpl: CrowdZeroRepositoryImpl): CrowdZeroRepository diff --git a/app/src/main/java/com/gdg/crowdzero_android/di/ServiceModule.kt b/app/src/main/java/com/gdg/crowdzero_android/di/ServiceModule.kt index fcd6652..7e39b83 100644 --- a/app/src/main/java/com/gdg/crowdzero_android/di/ServiceModule.kt +++ b/app/src/main/java/com/gdg/crowdzero_android/di/ServiceModule.kt @@ -1,7 +1,6 @@ package com.gdg.crowdzero_android.di import com.gdg.data.service.CrowdZeroService -import com.gdg.data.service.ExampleService import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -13,12 +12,6 @@ import javax.inject.Singleton @InstallIn(SingletonComponent::class) object ServiceModule { - @Provides - @Singleton - fun provideExampleService( - @CrowdZeroRetrofit retrofit: Retrofit - ): ExampleService = retrofit.create(ExampleService::class.java) - @Provides @Singleton fun provideCrowdZeroService( diff --git a/app/src/main/java/com/gdg/crowdzero_android/main/MainScreen.kt b/app/src/main/java/com/gdg/crowdzero_android/main/MainScreen.kt index d440268..7077075 100644 --- a/app/src/main/java/com/gdg/crowdzero_android/main/MainScreen.kt +++ b/app/src/main/java/com/gdg/crowdzero_android/main/MainScreen.kt @@ -152,9 +152,7 @@ fun MainScreen( startDestination = navigator.startDestination ) { mapNavGraph(navHostController = navigator.navController) - calendarNavGraph( - paddingValues = paddingValues, navHostController = navigator.navController - ) + calendarNavGraph(paddingValues = paddingValues) detailNavGraph(paddingValues = paddingValues) } } diff --git a/app/src/main/java/com/gdg/crowdzero_android/navigation/CalendarNavigation.kt b/app/src/main/java/com/gdg/crowdzero_android/navigation/CalendarNavigation.kt index ea89664..d2b8dc0 100644 --- a/app/src/main/java/com/gdg/crowdzero_android/navigation/CalendarNavigation.kt +++ b/app/src/main/java/com/gdg/crowdzero_android/navigation/CalendarNavigation.kt @@ -17,8 +17,7 @@ fun NavController.navigateCalendar(navOptions: NavOptions? = null) { } fun NavGraphBuilder.calendarNavGraph( - paddingValues: PaddingValues, - navHostController: NavController + paddingValues: PaddingValues ) { composable { CalendarRoute( diff --git a/app/src/main/java/com/gdg/crowdzero_android/navigation/DetailNavigation.kt b/app/src/main/java/com/gdg/crowdzero_android/navigation/DetailNavigation.kt index 85d1677..a0fd5ac 100644 --- a/app/src/main/java/com/gdg/crowdzero_android/navigation/DetailNavigation.kt +++ b/app/src/main/java/com/gdg/crowdzero_android/navigation/DetailNavigation.kt @@ -11,7 +11,7 @@ import com.gdg.feature.detail.DetailRoute import kotlinx.serialization.Serializable fun NavController.navigateDetail( - id: Long, + id: Int, navOptions: NavOptions? = null ) { navigate( @@ -34,5 +34,5 @@ fun NavGraphBuilder.detailNavGraph( @Serializable data class Detail( - val id: Long + val id: Int ) : Route diff --git a/app/src/main/res/drawable/user_1.png b/app/src/main/res/drawable/user_1.png deleted file mode 100644 index 8a9776d..0000000 Binary files a/app/src/main/res/drawable/user_1.png and /dev/null differ diff --git a/app/src/main/res/drawable/user_2.png b/app/src/main/res/drawable/user_2.png deleted file mode 100644 index 55e2051..0000000 Binary files a/app/src/main/res/drawable/user_2.png and /dev/null differ diff --git a/app/src/main/res/drawable/user_3.PNG b/app/src/main/res/drawable/user_3.PNG deleted file mode 100644 index 69bd2b8..0000000 Binary files a/app/src/main/res/drawable/user_3.PNG and /dev/null differ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 70e1fa3..d8fe54f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,5 +1,5 @@ - CrowdZero-Android + 혼잡제로 지도 diff --git a/core/src/main/java/com/gdg/core/type/LocationType.kt b/core/src/main/java/com/gdg/core/type/LocationType.kt index d4dde29..55d4046 100644 --- a/core/src/main/java/com/gdg/core/type/LocationType.kt +++ b/core/src/main/java/com/gdg/core/type/LocationType.kt @@ -5,7 +5,7 @@ import com.gdg.core.R import com.naver.maps.geometry.LatLng enum class LocationType( - val id: Long, + val id: Int, @StringRes val title: Int, val latLng: LatLng ) { @@ -36,11 +36,11 @@ enum class LocationType( ); // 여의도 companion object { - fun extractTitleResource(id: Long): Int { + fun extractTitleResource(id: Int): Int { return entries.find { it.id == id }?.title ?: GWANGHWAMUN.title } - fun extractLatLng(id: Long): LatLng { + fun extractLatLng(id: Int): LatLng { return entries.find { it.id == id }?.latLng ?: GWANGHWAMUN.latLng } } diff --git a/core/src/main/res/drawable/ic_launcher_background.xml b/core/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 07d5da9..0000000 --- a/core/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/core/src/main/res/drawable/ic_launcher_foreground.xml b/core/src/main/res/drawable/ic_launcher_foreground.xml deleted file mode 100644 index 2b068d1..0000000 --- a/core/src/main/res/drawable/ic_launcher_foreground.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/data/src/main/java/com/gdg/data/datasource/ExampleDataSource.kt b/data/src/main/java/com/gdg/data/datasource/ExampleDataSource.kt deleted file mode 100644 index ef602c9..0000000 --- a/data/src/main/java/com/gdg/data/datasource/ExampleDataSource.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.gdg.data.datasource - -import com.gdg.data.dto.ExampleBaseResponse -import com.gdg.data.dto.response.ExampleResponseDto - -interface ExampleDataSource { - suspend fun getUsers(page: Int): ExampleBaseResponse> -} diff --git a/data/src/main/java/com/gdg/data/datasourceimpl/ExampleDataSourceImpl.kt b/data/src/main/java/com/gdg/data/datasourceimpl/ExampleDataSourceImpl.kt deleted file mode 100644 index 7246aaa..0000000 --- a/data/src/main/java/com/gdg/data/datasourceimpl/ExampleDataSourceImpl.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.gdg.data.datasourceimpl - -import com.gdg.data.datasource.ExampleDataSource -import com.gdg.data.dto.ExampleBaseResponse -import com.gdg.data.dto.response.ExampleResponseDto -import com.gdg.data.service.ExampleService -import javax.inject.Inject - -class ExampleDataSourceImpl @Inject constructor( - private val exampleApiService: ExampleService -) : ExampleDataSource { - override suspend fun getUsers(page: Int): ExampleBaseResponse> { - return exampleApiService.getUsers(page) - } -} diff --git a/data/src/main/java/com/gdg/data/dto/ExampleBaseResponse.kt b/data/src/main/java/com/gdg/data/dto/ExampleBaseResponse.kt deleted file mode 100644 index 16a4c9d..0000000 --- a/data/src/main/java/com/gdg/data/dto/ExampleBaseResponse.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.gdg.data.dto - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class ExampleBaseResponse( - @SerialName("page") val page: Int, - @SerialName("per_page") val perPage: Int, - @SerialName("total") val total: Int, - @SerialName("total_pages") val totalPages: Int, - @SerialName("data") val data: T? = null, - @SerialName("support") val support: Support -) - -@Serializable -data class Support( - @SerialName("url") val url: String, - @SerialName("text") val text: String -) diff --git a/data/src/main/java/com/gdg/data/dto/response/ExampleResponseDto.kt b/data/src/main/java/com/gdg/data/dto/response/ExampleResponseDto.kt deleted file mode 100644 index 6834b28..0000000 --- a/data/src/main/java/com/gdg/data/dto/response/ExampleResponseDto.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.gdg.data.dto.response - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class ExampleResponseDto( - @SerialName("id") val id: Int, - @SerialName("email") val email: String, - @SerialName("first_name") val firstName: String, - @SerialName("last_name") val lastName: String, - @SerialName("avatar") val avatar: String -) diff --git a/data/src/main/java/com/gdg/data/mapper/ResponseCongestionDtoMapper.kt b/data/src/main/java/com/gdg/data/mapper/ResponseCongestionDtoMapper.kt index 906d658..1e55525 100644 --- a/data/src/main/java/com/gdg/data/mapper/ResponseCongestionDtoMapper.kt +++ b/data/src/main/java/com/gdg/data/mapper/ResponseCongestionDtoMapper.kt @@ -4,7 +4,7 @@ import com.gdg.data.dto.response.CongestionResponseDto import com.gdg.domain.entity.CongestionEntity fun CongestionResponseDto.toCongestionEntity() = CongestionEntity( - id = areaId.toLong(), + id = areaId, name = areaNm, level = areaCongestLvl, message = areaCongestMsg, diff --git a/data/src/main/java/com/gdg/data/mapper/ResponseExampleDtoMapper.kt b/data/src/main/java/com/gdg/data/mapper/ResponseExampleDtoMapper.kt deleted file mode 100644 index a899729..0000000 --- a/data/src/main/java/com/gdg/data/mapper/ResponseExampleDtoMapper.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.gdg.data.mapper - -import com.gdg.data.dto.response.ExampleResponseDto -import com.gdg.domain.entity.ExampleEntity - -fun ExampleResponseDto.toExampleEntity() = ExampleEntity( - id, - email, - firstName, - avatar -) diff --git a/data/src/main/java/com/gdg/data/mapper/ResponseWeatherDtoMapper.kt b/data/src/main/java/com/gdg/data/mapper/ResponseWeatherDtoMapper.kt index dcd831d..00b51a0 100644 --- a/data/src/main/java/com/gdg/data/mapper/ResponseWeatherDtoMapper.kt +++ b/data/src/main/java/com/gdg/data/mapper/ResponseWeatherDtoMapper.kt @@ -4,5 +4,5 @@ import com.gdg.data.dto.response.WeatherResponseDto import com.gdg.domain.entity.WeatherEntity fun WeatherResponseDto.toWeatherEntity() = WeatherEntity( - id, areaNm, skyStts, temp, pm25Index, pm10Index + id.toInt(), areaNm, skyStts, temp, pm25Index, pm10Index ) \ No newline at end of file diff --git a/data/src/main/java/com/gdg/data/repositoryimpl/CrowdZeroRepositoryImpl.kt b/data/src/main/java/com/gdg/data/repositoryimpl/CrowdZeroRepositoryImpl.kt index 0e94a74..4e1a0d5 100644 --- a/data/src/main/java/com/gdg/data/repositoryimpl/CrowdZeroRepositoryImpl.kt +++ b/data/src/main/java/com/gdg/data/repositoryimpl/CrowdZeroRepositoryImpl.kt @@ -2,10 +2,9 @@ package com.gdg.data.repositoryimpl import com.gdg.data.datasource.CrowdZeroDataSource import com.gdg.data.mapper.toCongestionEntity -import com.gdg.data.mapper.toExampleEntity +import com.gdg.data.mapper.toRoadEntity import com.gdg.data.mapper.toScheduleEntity import com.gdg.data.mapper.toWeatherEntity -import com.gdg.data.mapper.toRoadEntity import com.gdg.domain.entity.CongestionEntity import com.gdg.domain.entity.RoadEntity import com.gdg.domain.entity.ScheduleEntity diff --git a/data/src/main/java/com/gdg/data/repositoryimpl/ExampleRepositoryImpl.kt b/data/src/main/java/com/gdg/data/repositoryimpl/ExampleRepositoryImpl.kt deleted file mode 100644 index 80bc7c8..0000000 --- a/data/src/main/java/com/gdg/data/repositoryimpl/ExampleRepositoryImpl.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.gdg.data.repositoryimpl - -import com.gdg.data.datasource.ExampleDataSource -import com.gdg.data.mapper.toExampleEntity -import com.gdg.domain.entity.ExampleEntity -import com.gdg.domain.repository.ExampleRepository -import javax.inject.Inject - -class ExampleRepositoryImpl @Inject constructor( - private val exampleDataSource: ExampleDataSource -) : ExampleRepository { - override suspend fun getUsers(page: Int): Result> { - return runCatching { - exampleDataSource.getUsers(page).data?.map { it.toExampleEntity() } ?: emptyList() - } - } -} diff --git a/data/src/main/java/com/gdg/data/service/ApiKeyStorage.kt b/data/src/main/java/com/gdg/data/service/ApiKeyStorage.kt index 6e93f35..202224d 100644 --- a/data/src/main/java/com/gdg/data/service/ApiKeyStorage.kt +++ b/data/src/main/java/com/gdg/data/service/ApiKeyStorage.kt @@ -2,9 +2,6 @@ package com.gdg.data.service object ApiKeyStorage { const val API = "api" - const val V1 = "v1" - const val USERS = "users" - const val PAGE = "page" const val PPLTN = "ppltn" const val WEATHER = "weather" const val AREA_ID = "areaId" diff --git a/data/src/main/java/com/gdg/data/service/ExampleService.kt b/data/src/main/java/com/gdg/data/service/ExampleService.kt deleted file mode 100644 index 1145c63..0000000 --- a/data/src/main/java/com/gdg/data/service/ExampleService.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.gdg.data.service - -import com.gdg.data.dto.ExampleBaseResponse -import com.gdg.data.dto.response.ExampleResponseDto -import com.gdg.data.service.ApiKeyStorage.API -import com.gdg.data.service.ApiKeyStorage.PAGE -import com.gdg.data.service.ApiKeyStorage.USERS -import retrofit2.http.GET -import retrofit2.http.Query - -interface ExampleService { - @GET("/$API/$USERS") - suspend fun getUsers( - @Query(PAGE) page: Int - ): ExampleBaseResponse> -} diff --git a/domain/src/main/java/com/gdg/domain/entity/CongestionEntity.kt b/domain/src/main/java/com/gdg/domain/entity/CongestionEntity.kt index b2083c6..afa5bb1 100644 --- a/domain/src/main/java/com/gdg/domain/entity/CongestionEntity.kt +++ b/domain/src/main/java/com/gdg/domain/entity/CongestionEntity.kt @@ -1,7 +1,7 @@ package com.gdg.domain.entity data class CongestionEntity( - val id: Long, + val id: Int, val name: String, val level: String, val message: String, diff --git a/domain/src/main/java/com/gdg/domain/entity/ExampleEntity.kt b/domain/src/main/java/com/gdg/domain/entity/ExampleEntity.kt deleted file mode 100644 index f5afbd9..0000000 --- a/domain/src/main/java/com/gdg/domain/entity/ExampleEntity.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.gdg.domain.entity - -data class ExampleEntity( - val id: Int, - val email: String, - val firstName: String, - val avatar: String -) diff --git a/domain/src/main/java/com/gdg/domain/entity/PlaceEntity.kt b/domain/src/main/java/com/gdg/domain/entity/PlaceEntity.kt index de8ae11..648f888 100644 --- a/domain/src/main/java/com/gdg/domain/entity/PlaceEntity.kt +++ b/domain/src/main/java/com/gdg/domain/entity/PlaceEntity.kt @@ -1,7 +1,7 @@ package com.gdg.domain.entity data class PlaceEntity( - val id: Long, + val id: Int, val name: String, //장소명 val congestion: String, //인구혼잡도 val min: Int,//인구 실시간 최소 diff --git a/domain/src/main/java/com/gdg/domain/entity/ScheduleEntity.kt b/domain/src/main/java/com/gdg/domain/entity/ScheduleEntity.kt index b01f80d..f306b2e 100644 --- a/domain/src/main/java/com/gdg/domain/entity/ScheduleEntity.kt +++ b/domain/src/main/java/com/gdg/domain/entity/ScheduleEntity.kt @@ -1,7 +1,5 @@ package com.gdg.domain.entity -import java.time.LocalDate - data class ScheduleEntity( val date: String, val duration: String, diff --git a/domain/src/main/java/com/gdg/domain/entity/WeatherEntity.kt b/domain/src/main/java/com/gdg/domain/entity/WeatherEntity.kt index b147f20..a711416 100644 --- a/domain/src/main/java/com/gdg/domain/entity/WeatherEntity.kt +++ b/domain/src/main/java/com/gdg/domain/entity/WeatherEntity.kt @@ -1,10 +1,10 @@ package com.gdg.domain.entity data class WeatherEntity( - val id: Long, + val id: Int, val areaNm: String, val skyStts: String, val temp: Int, val pm25Index: String, val pm10Index: String -) \ No newline at end of file +) diff --git a/domain/src/main/java/com/gdg/domain/repository/ExampleRepository.kt b/domain/src/main/java/com/gdg/domain/repository/ExampleRepository.kt deleted file mode 100644 index 799e555..0000000 --- a/domain/src/main/java/com/gdg/domain/repository/ExampleRepository.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.gdg.domain.repository - -import com.gdg.domain.entity.ExampleEntity - -interface ExampleRepository { - suspend fun getUsers(page: Int): Result> -} diff --git a/feature/src/main/java/com/gdg/feature/detail/DetailRoute.kt b/feature/src/main/java/com/gdg/feature/detail/DetailRoute.kt index ff63f58..9ea9423 100644 --- a/feature/src/main/java/com/gdg/feature/detail/DetailRoute.kt +++ b/feature/src/main/java/com/gdg/feature/detail/DetailRoute.kt @@ -63,7 +63,7 @@ import timber.log.Timber @Composable fun DetailRoute( detailViewModel: DetailViewModel = hiltViewModel(), - id: Long, + id: Int, paddingValues: PaddingValues ) { val mapProperties by remember { @@ -88,8 +88,8 @@ fun DetailRoute( val getCongestionState by detailViewModel.getCongestionState.collectAsStateWithLifecycle() LaunchedEffect(key1 = Unit) { - detailViewModel.getWeather(id.toInt()) - detailViewModel.getCongestion(id.toInt()) + detailViewModel.getWeather(id) + detailViewModel.getCongestion(id) } DetailScreen( @@ -109,7 +109,7 @@ fun DetailRoute( @OptIn(ExperimentalNaverMapApi::class) @Composable fun DetailScreen( - id: Long = 0, + id: Int = 0, paddingValues: PaddingValues = PaddingValues(), weatherState: UiState = UiState.Empty, congestionState: UiState = UiState.Empty, @@ -167,7 +167,7 @@ fun DetailScreen( } when (weatherState) { is UiState.Empty -> { - Timber.e("날씨 api 데이터 없음") + Timber.e(stringResource(R.string.detail_weather_empty)) } is UiState.Loading -> { @@ -184,7 +184,7 @@ fun DetailScreen( } is UiState.Failure -> { - Timber.e("날씨 api 오류 : ${weatherState.msg}") + Timber.e(stringResource(R.string.detail_weather_failure, weatherState.msg)) WeatherItem( data = WeatherEntity( id = id, @@ -230,14 +230,19 @@ fun DetailScreen( ) } when (congestionState) { - is UiState.Empty -> Timber.d("혼잡도 api 데이터 없음") + is UiState.Empty -> Timber.d(stringResource(R.string.detail_congestion_empty)) is UiState.Loading -> LoadingIndicator( modifier = Modifier.align(Alignment.CenterHorizontally) ) is UiState.Success -> CongestionItem(data = congestionState.data) is UiState.Failure -> { - Timber.e("혼잡도 api 오류 : ${congestionState.msg}") + Timber.e( + stringResource( + R.string.detail_congestion_state_failure, + congestionState.msg + ) + ) CongestionItem( data = CongestionEntity( id = id, diff --git a/feature/src/main/java/com/gdg/feature/detail/DetailViewModel.kt b/feature/src/main/java/com/gdg/feature/detail/DetailViewModel.kt index 9347401..6fb6af2 100644 --- a/feature/src/main/java/com/gdg/feature/detail/DetailViewModel.kt +++ b/feature/src/main/java/com/gdg/feature/detail/DetailViewModel.kt @@ -59,5 +59,4 @@ class DetailViewModel @Inject constructor( val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss") return current.format(formatter) } - } diff --git a/feature/src/main/java/com/gdg/feature/example/ExampleItem.kt b/feature/src/main/java/com/gdg/feature/example/ExampleItem.kt deleted file mode 100644 index 72fbd86..0000000 --- a/feature/src/main/java/com/gdg/feature/example/ExampleItem.kt +++ /dev/null @@ -1,69 +0,0 @@ -package com.gdg.feature.example - -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Color.Companion.White -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import coil.compose.AsyncImage -import com.gdg.domain.entity.ExampleEntity - -@Composable -fun ExampleItem( - data: ExampleEntity -) { - Box( - modifier = Modifier - .fillMaxSize() - ) { - Row( - modifier = Modifier - .fillMaxWidth() - .background(White) - .padding(vertical = 10.dp, horizontal = 18.dp), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween - ) { - Column { - Text(text = data.firstName) - Spacer(modifier = Modifier.height(4.dp)) - Text(text = data.email) - } - AsyncImage( - modifier = Modifier - .size(60.dp) - .clip(RoundedCornerShape(12.dp)), - model = data.avatar, - contentDescription = null - ) - } - } -} - -@Preview(showBackground = true) -@Composable -fun ExampleItemPreview() { - ExampleItem( - data = ExampleEntity( - id = 1, - firstName = "John", - email = "", - avatar = "" - ) - ) -} diff --git a/feature/src/main/java/com/gdg/feature/example/ExampleRoute.kt b/feature/src/main/java/com/gdg/feature/example/ExampleRoute.kt deleted file mode 100644 index fe7c426..0000000 --- a/feature/src/main/java/com/gdg/feature/example/ExampleRoute.kt +++ /dev/null @@ -1,118 +0,0 @@ -package com.gdg.feature.example - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.navigationBarsPadding -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.statusBarsPadding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.gdg.core.designsystem.theme.CrowdZeroAndroidTheme -import com.gdg.core.extension.toast -import com.gdg.core.state.UiState -import com.gdg.domain.entity.ExampleEntity -import okhttp3.internal.toImmutableList - -@Composable -fun ExampleRoute( - navigateUp: () -> Unit, - exampleViewModel: ExampleViewModel = hiltViewModel() -) { - val context = LocalContext.current - val state by exampleViewModel.state.collectAsStateWithLifecycle() - - LaunchedEffect(key1 = Unit) { - exampleViewModel.getFollowers(2) - } - - LaunchedEffect(key1 = exampleViewModel.sideEffects) { - exampleViewModel.sideEffects.collect { sideEffect -> - when (sideEffect) { - is ExampleSideEffect.ShowToast -> { - context.toast(sideEffect.message) - } - - is ExampleSideEffect.NavigateUp -> navigateUp() - } - } - } - - when (state.followers) { - is UiState.Empty -> { - // Show empty - } - - is UiState.Loading -> { - Box(modifier = Modifier.fillMaxSize()) { - CircularProgressIndicator( - modifier = Modifier.align(Alignment.Center), - color = Color.Gray - ) - } - } - - is UiState.Success -> { - ExampleScreen( - followers = (state.followers as UiState.Success>).data.toImmutableList() - ) - } - - is UiState.Failure -> { - Column( - modifier = Modifier.fillMaxSize(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center - ) { - Text( - modifier = Modifier.padding(top = 10.dp), - text = "서버 연결에 실패했어요 ㅠ" - ) - } - } - } -} - -@Composable -fun ExampleScreen( - followers: List -) { - Column( - modifier = Modifier - .fillMaxSize() - .statusBarsPadding() - .navigationBarsPadding() - ) { - LazyColumn( - modifier = Modifier.weight(1f) - ) { - items(followers, key = { follower -> follower.id }) { follower -> - ExampleItem(follower) - } - } - } -} - -@Preview(showBackground = true) -@Composable -fun ExampleRoutePreview() { - CrowdZeroAndroidTheme { - ExampleScreen( - followers = emptyList() - ) - } -} diff --git a/feature/src/main/java/com/gdg/feature/example/ExampleSideEffect.kt b/feature/src/main/java/com/gdg/feature/example/ExampleSideEffect.kt deleted file mode 100644 index 16f5f70..0000000 --- a/feature/src/main/java/com/gdg/feature/example/ExampleSideEffect.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.gdg.feature.example - -import androidx.annotation.StringRes - -sealed class ExampleSideEffect { - data object NavigateUp : ExampleSideEffect() - data class ShowToast(@StringRes val message: Int) : ExampleSideEffect() -} diff --git a/feature/src/main/java/com/gdg/feature/example/ExampleState.kt b/feature/src/main/java/com/gdg/feature/example/ExampleState.kt deleted file mode 100644 index e75e4a3..0000000 --- a/feature/src/main/java/com/gdg/feature/example/ExampleState.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.gdg.feature.example - -import com.gdg.core.state.UiState -import com.gdg.domain.entity.ExampleEntity - -data class ExampleState( - var followers: UiState> = UiState.Empty -) diff --git a/feature/src/main/java/com/gdg/feature/example/ExampleViewModel.kt b/feature/src/main/java/com/gdg/feature/example/ExampleViewModel.kt deleted file mode 100644 index f3cd4a9..0000000 --- a/feature/src/main/java/com/gdg/feature/example/ExampleViewModel.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.gdg.feature.example - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.gdg.core.state.UiState -import com.gdg.domain.repository.ExampleRepository -import com.gdg.feature.R -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asSharedFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.launch -import javax.inject.Inject - -@HiltViewModel -class ExampleViewModel @Inject constructor( - private val exampleRepository: ExampleRepository -) : ViewModel() { - private val _state: MutableStateFlow = MutableStateFlow(ExampleState()) - val state: StateFlow get() = _state.asStateFlow() - - private val _sideEffects: MutableSharedFlow = MutableSharedFlow() - val sideEffects: SharedFlow get() = _sideEffects.asSharedFlow() - - fun getFollowers(page: Int) { - viewModelScope.launch { - _state.value = _state.value.copy(followers = UiState.Loading) - exampleRepository.getUsers(page).fold( - onSuccess = { - _state.value = _state.value.copy(followers = UiState.Success(it)) - _sideEffects.emit(ExampleSideEffect.ShowToast(R.string.server_success)) - }, - onFailure = { - _state.value = - _state.value.copy(followers = UiState.Failure(it.message.toString())) - _sideEffects.emit(ExampleSideEffect.ShowToast(R.string.server_failure)) - } - ) - } - } - - fun navigateUp() { - viewModelScope.launch { - _sideEffects.emit(ExampleSideEffect.NavigateUp) - } - } -} diff --git a/feature/src/main/java/com/gdg/feature/map/MapRoute.kt b/feature/src/main/java/com/gdg/feature/map/MapRoute.kt index df3538a..79726ef 100644 --- a/feature/src/main/java/com/gdg/feature/map/MapRoute.kt +++ b/feature/src/main/java/com/gdg/feature/map/MapRoute.kt @@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.statusBarsPadding +import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState @@ -57,9 +58,11 @@ import com.naver.maps.map.overlay.OverlayImage import kotlinx.coroutines.launch import timber.log.Timber +@OptIn(ExperimentalMaterial3Api::class) @Composable fun MapRoute( - mapViewModel: MapViewModel = hiltViewModel(), navigateToDetail: (Long) -> Unit + mapViewModel: MapViewModel = hiltViewModel(), + navigateToDetail: (Int) -> Unit ) { val mapProperties by remember { mutableStateOf( @@ -79,11 +82,17 @@ fun MapRoute( position = CameraPosition(NaverMapConstants.DefaultCameraPosition.target, 13.0) } val getCongestionState by mapViewModel.getCongestionState.collectAsStateWithLifecycle() + val getRoadState by mapViewModel.getRoadState.collectAsStateWithLifecycle() val context = LocalContext.current val roads by mapViewModel.roads.collectAsStateWithLifecycle() + var selectedRoad by remember { mutableStateOf(null) } + var showBottomSheet by remember { mutableStateOf(false) } + val sheetState = rememberModalBottomSheetState() + val listState = rememberLazyListState() LaunchedEffect(Unit) { mapViewModel.getRoads() + listState.scrollToItem(0) } LaunchedEffect(key1 = mapViewModel.sideEffects) { @@ -91,6 +100,31 @@ fun MapRoute( when (sideEffect) { is MapSideEffect.NavigateToDetail -> navigateToDetail(sideEffect.id) is MapSideEffect.ShowToast -> context.toast(sideEffect.message) + is MapSideEffect.ShowBottomSheet -> { + selectedRoad = sideEffect.road + showBottomSheet = sideEffect.road != null + } + } + } + } + + if (showBottomSheet) { + ModalBottomSheet( + sheetState = sheetState, + onDismissRequest = { showBottomSheet = false }, + containerColor = CrowdZeroTheme.colors.white, + shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp) + ) { + when (getRoadState) { + is UiState.Empty -> Timber.e(stringResource(R.string.map_road_empty)) + is UiState.Loading -> LoadingIndicator() + is UiState.Success -> { + selectedRoad?.let { road -> + RoadInfoSheet(road = road) + } + } + + is UiState.Failure -> Timber.e(stringResource(R.string.map_road_failure)) } } } @@ -102,12 +136,14 @@ fun MapRoute( locations = mapViewModel.locations, roads = roads, congestionState = getCongestionState, - getPlaceEntity = { id -> mapViewModel.getCongestion(id.toInt()) }, - onButtonClick = mapViewModel::navigateToDetail + listState = listState, + getPlaceEntity = { id -> mapViewModel.getCongestion(id) }, + onButtonClick = mapViewModel::navigateToDetail, + onRoadMarkerClick = mapViewModel::onRoadMarkerClick ) } -@OptIn(ExperimentalNaverMapApi::class, ExperimentalMaterial3Api::class) +@OptIn(ExperimentalNaverMapApi::class) @Composable fun MapScreen( mapProperties: MapProperties = MapProperties(), @@ -116,15 +152,13 @@ fun MapScreen( locations: List, roads: List, congestionState: UiState = UiState.Empty, - getPlaceEntity: (Long) -> Unit, - onButtonClick: (Long) -> Unit = { } + listState: LazyListState, + getPlaceEntity: (Int) -> Unit, + onButtonClick: (Int) -> Unit = { }, + onRoadMarkerClick: (RoadEntity) -> Unit ) { var selectedLocation by remember { mutableStateOf(null) } - var selectedRoad by remember { mutableStateOf(null) } val coroutineScope = rememberCoroutineScope() - val listState = rememberLazyListState() - val sheetState = rememberModalBottomSheetState() - var showBottomSheet by remember { mutableStateOf(false) } BackHandler( enabled = selectedLocation != null, @@ -159,13 +193,14 @@ fun MapScreen( state = MarkerState(position = LatLng(road.acdntY, road.acdntX)), icon = OverlayImage.fromResource(R.drawable.ic_ban_marker), onClick = { - selectedRoad = road - showBottomSheet = true - coroutineScope.launch { - sheetState.show() - } + cameraPositionState.move( + CameraUpdate.scrollAndZoomTo(LatLng(road.acdntY, road.acdntX), 17.0) + .animate(CameraAnimation.Easing) + ) + onRoadMarkerClick(road) true - }) + } + ) } } } @@ -173,29 +208,34 @@ fun MapScreen( modifier = Modifier .fillMaxWidth() .align(Alignment.TopCenter) - .padding(top = 110.dp, start = 10.dp, end = 10.dp), state = listState + .padding(top = 110.dp, start = 10.dp, end = 10.dp), + state = listState ) { itemsIndexed(locations) { index, location -> - MapChip(title = location, isSelected = selectedLocation == location, onClick = { - if (selectedLocation == location) { - selectedLocation = null - } else { - selectedLocation = location - getPlaceEntity(location.id) - cameraPositionState.move( - CameraUpdate.scrollAndZoomTo(location.latLng, 17.0) - .animate(CameraAnimation.Easing) - ) - } - coroutineScope.launch { - listState.animateScrollToItem(index) + MapChip( + title = location, + isSelected = selectedLocation == location, + onClick = { + if (selectedLocation == location) { + selectedLocation = null + } else { + selectedLocation = location + getPlaceEntity(location.id) + cameraPositionState.move( + CameraUpdate.scrollAndZoomTo(location.latLng, 17.0) + .animate(CameraAnimation.Easing) + ) + } + coroutineScope.launch { + listState.animateScrollToItem(index) + } } - }) + ) } } selectedLocation?.let { location -> when (congestionState) { - is UiState.Empty -> Timber.e("인구 혼잡도 정보 없음") + is UiState.Empty -> Timber.e(stringResource(R.string.map_congestion_empty)) is UiState.Loading -> LoadingIndicator(modifier = Modifier.align(Alignment.BottomCenter)) is UiState.Success -> { if (congestionState.data.id == location.id) { @@ -208,12 +248,12 @@ fun MapScreen( } is UiState.Failure -> { - Timber.e("인구 혼잡도 정보 실패") + Timber.e(stringResource(R.string.map_congestion_failure)) PlaceInfoCard( place = PlaceEntity( id = location.id, name = stringResource(id = location.title), - congestion = "모름", + congestion = stringResource(R.string.place_info_card_congestion_unknown), min = 0, max = 0 ), @@ -224,15 +264,4 @@ fun MapScreen( } } } - - if (showBottomSheet) { - ModalBottomSheet( - sheetState = sheetState, - onDismissRequest = { showBottomSheet = false }, - containerColor = CrowdZeroTheme.colors.white, - shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp) - ) { - RoadInfoSheet(road = selectedRoad) - } - } } diff --git a/feature/src/main/java/com/gdg/feature/map/MapSideEffect.kt b/feature/src/main/java/com/gdg/feature/map/MapSideEffect.kt index 455d344..fdc3538 100644 --- a/feature/src/main/java/com/gdg/feature/map/MapSideEffect.kt +++ b/feature/src/main/java/com/gdg/feature/map/MapSideEffect.kt @@ -1,6 +1,9 @@ package com.gdg.feature.map +import com.gdg.domain.entity.RoadEntity + sealed class MapSideEffect { - data class NavigateToDetail(val id: Long) : MapSideEffect() + data class NavigateToDetail(val id: Int) : MapSideEffect() data class ShowToast(val message: Int) : MapSideEffect() + data class ShowBottomSheet(val road: RoadEntity?) : MapSideEffect() } diff --git a/feature/src/main/java/com/gdg/feature/map/MapViewModel.kt b/feature/src/main/java/com/gdg/feature/map/MapViewModel.kt index 242c00e..a1a747e 100644 --- a/feature/src/main/java/com/gdg/feature/map/MapViewModel.kt +++ b/feature/src/main/java/com/gdg/feature/map/MapViewModel.kt @@ -81,6 +81,18 @@ class MapViewModel @Inject constructor( } } + fun navigateToDetail(id: Int) { + viewModelScope.launch { + _sideEffects.emit(MapSideEffect.NavigateToDetail(id)) + } + } + + fun onRoadMarkerClick(road: RoadEntity) { + viewModelScope.launch { + _sideEffects.emit(MapSideEffect.ShowBottomSheet(road)) + } + } + @Stable val locations = immutableListOf( LocationType.GANGNAM_STATION, @@ -89,11 +101,4 @@ class MapViewModel @Inject constructor( LocationType.SEOUL_STATION, LocationType.YEOUIDO ) - - fun navigateToDetail(id: Long) { - viewModelScope.launch { - _sideEffects.emit(MapSideEffect.NavigateToDetail(id)) - } - } - } diff --git a/feature/src/main/java/com/gdg/feature/map/component/PlaceInfoCard.kt b/feature/src/main/java/com/gdg/feature/map/component/PlaceInfoCard.kt index 7b11883..52cb581 100644 --- a/feature/src/main/java/com/gdg/feature/map/component/PlaceInfoCard.kt +++ b/feature/src/main/java/com/gdg/feature/map/component/PlaceInfoCard.kt @@ -40,7 +40,7 @@ import com.gdg.feature.R fun PlaceInfoCard( place: PlaceEntity?, modifier: Modifier = Modifier, - onButtonClick: (Long) -> Unit + onButtonClick: (Int) -> Unit ) { if (place == null) return diff --git a/feature/src/main/java/com/gdg/feature/splash/SplashScreen.kt b/feature/src/main/java/com/gdg/feature/splash/SplashScreen.kt index 470c1e5..8ce2404 100644 --- a/feature/src/main/java/com/gdg/feature/splash/SplashScreen.kt +++ b/feature/src/main/java/com/gdg/feature/splash/SplashScreen.kt @@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.material3.Text import androidx.compose.runtime.Composable diff --git a/feature/src/main/res/drawable/ic_launcher_background.xml b/feature/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 07d5da9..0000000 --- a/feature/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/feature/src/main/res/drawable/ic_launcher_foreground.xml b/feature/src/main/res/drawable/ic_launcher_foreground.xml deleted file mode 100644 index 2b068d1..0000000 --- a/feature/src/main/res/drawable/ic_launcher_foreground.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/feature/src/main/res/values/strings.xml b/feature/src/main/res/values/strings.xml index beed013..bd87730 100644 --- a/feature/src/main/res/values/strings.xml +++ b/feature/src/main/res/values/strings.xml @@ -1,6 +1,5 @@ - 서버 통신에 성공했습니다 서버 통신에 실패했습니다 @@ -15,6 +14,9 @@ %1$s~%2$s명 실시간 인구 정보를 가져오지 못했어요 %1$s명 + 날씨 api 데이터 없음 + 날씨 api 오류 : %1$s + 혼잡도 api 데이터 없음 혼잡 @@ -23,19 +25,23 @@ 스플래시 - 배경 빌딩 아이콘 상세보기 "인구혼잡도 " "실시간 인구 " %1$s~%2$s명 %1$s명 "배경 빌딩 아이콘" + 모름 통제 발생시간 %1$s 종료예정시간 %1$s [통제] %1$s %1$s 업데이트 제공 서울시 실시간 도로통제정보 + 도로 정보 없음 + 도로 정보 실패 + 인구 혼잡도 정보 없음 + 인구 혼잡도 정보 실패 "날짜별 " @@ -49,6 +55,6 @@ 관할시 해당 날짜의 집회 정보가 없습니다 해당 날짜의 집회 정보를 가져오지 못했어요 - + 혼잡도 api 오류 : %1$s \ No newline at end of file