diff --git a/app/src/main/java/com/pluu/webtoon/ui/AppNavigation.kt b/app/src/main/java/com/pluu/webtoon/ui/AppNavigation.kt index ed1e06ec..139c82ff 100644 --- a/app/src/main/java/com/pluu/webtoon/ui/AppNavigation.kt +++ b/app/src/main/java/com/pluu/webtoon/ui/AppNavigation.kt @@ -12,17 +12,18 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController +import androidx.navigation.navArgument import com.pluu.utils.extraNotNullSerializable import com.pluu.webtoon.Const import com.pluu.webtoon.detail.ui.compose.DetailUi import com.pluu.webtoon.episode.ui.compose.EpisodeUi +import com.pluu.webtoon.model.EpisodeInfo import com.pluu.webtoon.model.ToonInfoWithFavorite import com.pluu.webtoon.navigation.customtabs.chromeCustomTabs import com.pluu.webtoon.navigation.customtabs.navigateChromeCustomTabs import com.pluu.webtoon.setting.ui.LicenseUi import com.pluu.webtoon.setting.ui.SettingsUi import com.pluu.webtoon.ui.model.PalletColor -import com.pluu.webtoon.utils.navigateWithArgument import com.pluu.webtoon.weekly.model.UI_NAV_ITEM import com.pluu.webtoon.weekly.ui.compose.WeeklyUi import timber.log.Timber @@ -80,16 +81,15 @@ private fun NavGraphBuilder.installWeeklyScreen( updateNaviItem(item) }, openEpisode = { item, color -> - navController.navigateWithArgument( - route = Screen.Episode.route, - args = listOf( - Const.EXTRA_TOON to item, - Const.EXTRA_PALLET to color - ) + val toonItem = ToonInfoWithFavorite.toNavigationValue(item) + val palletColor = PalletColor.toNavigationValue(color) + + navController.navigate( + "${Screen.Episode.route}/${toonItem}/${palletColor}" ) }, openSetting = { - navController.navigateWithArgument(Screen.Setting.route) + navController.navigate(Screen.Setting.route) } ) } @@ -98,7 +98,23 @@ private fun NavGraphBuilder.installWeeklyScreen( private fun NavGraphBuilder.installEpisodeScreen( navController: NavController ) { - composable(Screen.Episode.route) { entry -> + composable( + route = Screen.Episode.route + "/{${Const.EXTRA_TOON}}/{${Const.EXTRA_PALLET}}", + arguments = listOf( + navArgument(Const.EXTRA_TOON) { + type = SerializableType( + type = ToonInfoWithFavorite::class.java, + parser = ToonInfoWithFavorite::parseNavigationValue + ) + }, + navArgument(Const.EXTRA_PALLET) { + type = SerializableType( + type = PalletColor::class.java, + parser = PalletColor::parseNavigationValue + ) + } + ) + ) { entry -> // Read, Bundle data val arguments = requireNotNull(entry.arguments) val toon = arguments.extraNotNullSerializable(Const.EXTRA_TOON) @@ -108,13 +124,9 @@ private fun NavGraphBuilder.installEpisodeScreen( webToonItem = toon, palletColor = color, openDetail = { episode -> - navController.navigateWithArgument( - route = Screen.Detail.route, - args = listOf( - Const.EXTRA_EPISODE to episode, - Const.EXTRA_PALLET to color - ) - ) + val episodeItem = EpisodeInfo.toNavigationValue(episode) + val palletColor = PalletColor.toNavigationValue(color) + navController.navigate("${Screen.Detail.route}/${episodeItem}/${palletColor}") }, closeCurrent = navController::navigateUp ) @@ -124,7 +136,23 @@ private fun NavGraphBuilder.installEpisodeScreen( private fun NavGraphBuilder.installDetailScreen( navController: NavController ) { - composable(Screen.Detail.route) { entry -> + composable( + route = Screen.Detail.route + "/{${Const.EXTRA_EPISODE}}/{${Const.EXTRA_PALLET}}", + arguments = listOf( + navArgument(Const.EXTRA_EPISODE) { + type = SerializableType( + type = EpisodeInfo::class.java, + parser = EpisodeInfo::parseNavigationValue + ) + }, + navArgument(Const.EXTRA_PALLET) { + type = SerializableType( + type = PalletColor::class.java, + parser = PalletColor::parseNavigationValue + ) + } + ) + ) { entry -> // Read, Bundle data val arguments = requireNotNull(entry.arguments) val color: PalletColor = arguments.extraNotNullSerializable(Const.EXTRA_PALLET) @@ -144,7 +172,7 @@ private fun NavGraphBuilder.installSettingScreen( SettingsUi( closeCurrent = navController::navigateUp, openLicense = { - navController.navigateWithArgument(Screen.License.route) + navController.navigate(Screen.License.route) } ) } diff --git a/app/src/main/java/com/pluu/webtoon/ui/CreateSerializableType.kt b/app/src/main/java/com/pluu/webtoon/ui/CreateSerializableType.kt new file mode 100644 index 00000000..b747a2e3 --- /dev/null +++ b/app/src/main/java/com/pluu/webtoon/ui/CreateSerializableType.kt @@ -0,0 +1,12 @@ +package com.pluu.webtoon.ui + +import androidx.navigation.NavType + +class SerializableType( + type: Class, + private val parser: (String) -> T +) : NavType.SerializableType(type) { + override fun parseValue(value: String): T { + return parser(value) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pluu/webtoon/utils/NavHostController.kt b/app/src/main/java/com/pluu/webtoon/utils/NavHostController.kt deleted file mode 100644 index 76f0af96..00000000 --- a/app/src/main/java/com/pluu/webtoon/utils/NavHostController.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.pluu.webtoon.utils - -import androidx.core.os.bundleOf -import androidx.navigation.NavController -import androidx.navigation.NavOptions -import androidx.navigation.Navigator -import timber.log.Timber - -/////////////////////////////////////////////////////////////////////////// -// 소스 참고 : https://gist.github.com/Aidanvii7/46f9f014ba4dc58a2ac10625b198769d -/////////////////////////////////////////////////////////////////////////// - -fun NavController.navigateWithArgument( - route: String, - args: List>? = null, - navOptions: NavOptions? = null, - navigatorExtras: Navigator.Extras? = null, -) { - if (currentDestination?.route == route) { - Timber.tag("Logger").d("Skip Navigate ${currentDestination?.route}") - return - } - navigate(route, navOptions, navigatorExtras) - - if (args.isNullOrEmpty()) { - return - } - val bundle = backQueue.lastOrNull()?.arguments - if (bundle != null) { - bundle.putAll(bundleOf(*args.toTypedArray())) - } else { - Timber.w("The last argument of NavBackStackEntry is null.") - } -} \ No newline at end of file diff --git a/features/ui-common/build.gradle.kts b/features/ui-common/build.gradle.kts index 8ada9988..894ad027 100644 --- a/features/ui-common/build.gradle.kts +++ b/features/ui-common/build.gradle.kts @@ -1,6 +1,7 @@ plugins { id("pluu.android.library") id("pluu.android.library.compose") + kotlin("plugin.serialization") } android { @@ -11,6 +12,8 @@ dependencies { api(projects.model) api(projects.uiTheme) + implementation(libs.kotlin.serialization) + // Android UI implementation(libs.androidX.fragment.ktx) diff --git a/features/ui-common/src/main/java/com/pluu/webtoon/ui/compose/Color.kt b/features/ui-common/src/main/java/com/pluu/webtoon/ui/compose/Color.kt new file mode 100644 index 00000000..e1e4a704 --- /dev/null +++ b/features/ui-common/src/main/java/com/pluu/webtoon/ui/compose/Color.kt @@ -0,0 +1,5 @@ +package com.pluu.webtoon.ui.compose + +import androidx.compose.ui.graphics.Color + +fun Color.toLong() = value.toLong() \ No newline at end of file diff --git a/features/ui-common/src/main/java/com/pluu/webtoon/ui/model/PalletColor.kt b/features/ui-common/src/main/java/com/pluu/webtoon/ui/model/PalletColor.kt index 9771a6b4..2cd7a9b5 100644 --- a/features/ui-common/src/main/java/com/pluu/webtoon/ui/model/PalletColor.kt +++ b/features/ui-common/src/main/java/com/pluu/webtoon/ui/model/PalletColor.kt @@ -1,11 +1,21 @@ package com.pluu.webtoon.ui.model -import androidx.compose.ui.graphics.Color +import com.pluu.webtoon.model.utils.parseNavigationValue +import com.pluu.webtoon.model.utils.toNavigationValue import java.io.Serializable +@kotlinx.serialization.Serializable data class PalletColor( - val darkVibrantColor: Color, - val darkMutedColor: Color, - val lightVibrantColor: Color, - val lightMutedColor: Color, -) : Serializable \ No newline at end of file + val darkVibrantColor: Long, + val darkMutedColor: Long, + val lightVibrantColor: Long, + val lightMutedColor: Long, +) : Serializable { + companion object { + fun toNavigationValue(value: PalletColor): String = + value.toNavigationValue() + + fun parseNavigationValue(value: String): PalletColor = + value.parseNavigationValue() + } +} \ No newline at end of file diff --git a/features/ui-detail/src/main/java/com/pluu/webtoon/detail/ui/compose/DetailUi.kt b/features/ui-detail/src/main/java/com/pluu/webtoon/detail/ui/compose/DetailUi.kt index 92dc4a69..065bf7d7 100644 --- a/features/ui-detail/src/main/java/com/pluu/webtoon/detail/ui/compose/DetailUi.kt +++ b/features/ui-detail/src/main/java/com/pluu/webtoon/detail/ui/compose/DetailUi.kt @@ -7,6 +7,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.setValue +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.window.DialogProperties @@ -34,8 +35,8 @@ fun DetailUi( DetailUi( viewModel = hiltViewModel(), featureColor = FeatureColor( - themeColor = palletColor.darkMutedColor, - webToonColor = palletColor.darkVibrantColor + themeColor = Color(palletColor.darkMutedColor), + webToonColor = Color(palletColor.darkVibrantColor) ), closeCurrent = { closeCurrent() }, shareAction = { item -> diff --git a/features/ui-episode/src/main/java/com/pluu/webtoon/episode/ui/compose/EpisodeScreen.kt b/features/ui-episode/src/main/java/com/pluu/webtoon/episode/ui/compose/EpisodeScreen.kt index 343d54fd..2938b563 100644 --- a/features/ui-episode/src/main/java/com/pluu/webtoon/episode/ui/compose/EpisodeScreen.kt +++ b/features/ui-episode/src/main/java/com/pluu/webtoon/episode/ui/compose/EpisodeScreen.kt @@ -55,7 +55,7 @@ internal fun EpisodeScreen( ) { state -> when (state) { ColorTransitionState.START -> MaterialTheme.colorScheme.primaryContainer - ColorTransitionState.END -> palletColor.darkVibrantColor + ColorTransitionState.END -> Color(palletColor.darkVibrantColor) } } diff --git a/features/ui-weekly/src/main/java/com/pluu/webtoon/weekly/image/PalletDarkCalculator.kt b/features/ui-weekly/src/main/java/com/pluu/webtoon/weekly/image/PalletDarkCalculator.kt index 26219346..4713b6bb 100644 --- a/features/ui-weekly/src/main/java/com/pluu/webtoon/weekly/image/PalletDarkCalculator.kt +++ b/features/ui-weekly/src/main/java/com/pluu/webtoon/weekly/image/PalletDarkCalculator.kt @@ -5,6 +5,7 @@ import android.graphics.Bitmap import android.graphics.drawable.Drawable import androidx.compose.ui.graphics.Color import androidx.palette.graphics.Palette +import com.pluu.webtoon.ui.compose.toLong import com.pluu.webtoon.ui.model.PalletColor import com.pluu.webtoon.utils.LoadedState import com.pluu.webtoon.utils.preLoadImage @@ -43,13 +44,18 @@ internal class PalletDarkCalculator( return withContext(Dispatchers.Default) { val p = Palette.from(this@convertPallet).generate() PalletColor( - Color(p.getDarkVibrantColor(android.graphics.Color.BLACK)), - Color(p.getDarkMutedColor(android.graphics.Color.BLACK)), - Color(p.getLightVibrantColor(android.graphics.Color.WHITE)), - Color(p.getLightMutedColor(android.graphics.Color.WHITE)) + p.getDarkVibrantColor(android.graphics.Color.BLACK).toLong(), + p.getDarkMutedColor(android.graphics.Color.BLACK).toLong(), + p.getLightVibrantColor(android.graphics.Color.WHITE).toLong(), + p.getLightMutedColor(android.graphics.Color.WHITE).toLong() ) } } - private fun defaultPalletColor() = PalletColor(Color.Black, Color.Black, Color.White, Color.White) + private fun defaultPalletColor() = PalletColor( + Color.Black.toLong(), + Color.Black.toLong(), + Color.White.toLong(), + Color.White.toLong() + ) } diff --git a/model/build.gradle.kts b/model/build.gradle.kts index 47281af7..f95b1120 100644 --- a/model/build.gradle.kts +++ b/model/build.gradle.kts @@ -1,3 +1,8 @@ plugins { id("pluu.java.library") + kotlin("plugin.serialization") +} + +dependencies { + implementation(libs.kotlin.serialization) } \ No newline at end of file diff --git a/model/src/main/java/com/pluu/webtoon/model/EpisodeInfo.kt b/model/src/main/java/com/pluu/webtoon/model/EpisodeInfo.kt index b280a73c..b40eb39b 100644 --- a/model/src/main/java/com/pluu/webtoon/model/EpisodeInfo.kt +++ b/model/src/main/java/com/pluu/webtoon/model/EpisodeInfo.kt @@ -1,10 +1,13 @@ package com.pluu.webtoon.model +import com.pluu.webtoon.model.utils.parseNavigationValue +import com.pluu.webtoon.model.utils.toNavigationValue import java.io.Serializable typealias ToonId = String typealias EpisodeId = String +@kotlinx.serialization.Serializable data class EpisodeInfo( val id: EpisodeId, val toonId: ToonId, @@ -17,8 +20,17 @@ data class EpisodeInfo( val landingInfo: LandingInfo = LandingInfo.Detail ) : Serializable { val isLock: Boolean = isLoginNeed + + companion object { + fun toNavigationValue(value: EpisodeInfo): String = + value.toNavigationValue() + + fun parseNavigationValue(value: String): EpisodeInfo = + value.parseNavigationValue() + } } +@kotlinx.serialization.Serializable sealed class LandingInfo : Serializable { object Detail : LandingInfo() diff --git a/model/src/main/java/com/pluu/webtoon/model/ToonInfo.kt b/model/src/main/java/com/pluu/webtoon/model/ToonInfo.kt index 700c4836..6e094e97 100644 --- a/model/src/main/java/com/pluu/webtoon/model/ToonInfo.kt +++ b/model/src/main/java/com/pluu/webtoon/model/ToonInfo.kt @@ -1,7 +1,10 @@ package com.pluu.webtoon.model +import com.pluu.webtoon.model.utils.parseNavigationValue +import com.pluu.webtoon.model.utils.toNavigationValue import java.io.Serializable +@kotlinx.serialization.Serializable data class ToonInfo( val id: String, val title: String, @@ -14,9 +17,18 @@ data class ToonInfo( val isLocked: Boolean = false ) : Serializable +@kotlinx.serialization.Serializable data class ToonInfoWithFavorite( val info: ToonInfo, val isFavorite: Boolean = false ) : Serializable { val id: String = info.id + + companion object { + fun toNavigationValue(value: ToonInfoWithFavorite): String = + value.toNavigationValue() + + fun parseNavigationValue(value: String): ToonInfoWithFavorite = + value.parseNavigationValue() + } } diff --git a/model/src/main/java/com/pluu/webtoon/model/utils/Navigation.kt b/model/src/main/java/com/pluu/webtoon/model/utils/Navigation.kt new file mode 100644 index 00000000..d72b01ef --- /dev/null +++ b/model/src/main/java/com/pluu/webtoon/model/utils/Navigation.kt @@ -0,0 +1,11 @@ +package com.pluu.webtoon.model.utils + +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +import java.net.URLEncoder + +inline fun T.toNavigationValue(): String = + URLEncoder.encode(Json.encodeToString(this), "UTF-8") + +inline fun String.parseNavigationValue(): T = + Json.decodeFromString(this) \ No newline at end of file diff --git a/sample/sample-detail/src/main/java/com/pluu/webtoon/detail/sample/MainActivity.kt b/sample/sample-detail/src/main/java/com/pluu/webtoon/detail/sample/MainActivity.kt index 3a56510a..3e826404 100644 --- a/sample/sample-detail/src/main/java/com/pluu/webtoon/detail/sample/MainActivity.kt +++ b/sample/sample-detail/src/main/java/com/pluu/webtoon/detail/sample/MainActivity.kt @@ -12,6 +12,7 @@ import com.pluu.webtoon.Const import com.pluu.webtoon.detail.ui.compose.DetailUi import com.pluu.webtoon.model.EpisodeInfo import com.pluu.webtoon.ui.compose.WebToonTheme +import com.pluu.webtoon.ui.compose.toLong import com.pluu.webtoon.ui.model.PalletColor import dagger.hilt.android.AndroidEntryPoint @@ -44,10 +45,10 @@ class MainActivity : ComponentActivity() { ) val palletColor = PalletColor( - darkVibrantColor = Color(0xFF17438F), - darkMutedColor = Color.Gray, - lightVibrantColor = Color.White, - lightMutedColor = Color.White + darkVibrantColor = 0xFF17438F, + darkMutedColor = Color.Gray.toLong(), + lightVibrantColor = Color.White.toLong(), + lightMutedColor = Color.White.toLong() ) // Put, Episode Information diff --git a/sample/sample-episode/src/main/java/com/pluu/webtoon/episode/sample/MainActivity.kt b/sample/sample-episode/src/main/java/com/pluu/webtoon/episode/sample/MainActivity.kt index 82d5c521..5f762476 100644 --- a/sample/sample-episode/src/main/java/com/pluu/webtoon/episode/sample/MainActivity.kt +++ b/sample/sample-episode/src/main/java/com/pluu/webtoon/episode/sample/MainActivity.kt @@ -14,6 +14,7 @@ import com.pluu.webtoon.episode.ui.compose.EpisodeUi import com.pluu.webtoon.model.ToonInfo import com.pluu.webtoon.model.ToonInfoWithFavorite import com.pluu.webtoon.ui.compose.WebToonTheme +import com.pluu.webtoon.ui.compose.toLong import com.pluu.webtoon.ui.model.PalletColor import dagger.hilt.android.AndroidEntryPoint @@ -48,10 +49,10 @@ class MainActivity : ComponentActivity() { ) ) val palletColor = PalletColor( - darkVibrantColor = Color(0xFF17438F), - darkMutedColor = Color.Gray, - lightVibrantColor = Color.White, - lightMutedColor = Color.White + darkVibrantColor = 0xFF17438F, + darkMutedColor = Color.Gray.toLong(), + lightVibrantColor = Color.White.toLong(), + lightMutedColor = Color.White.toLong() ) // Put, Episode Information