diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index cf36b13d..fde94c62 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -20,7 +20,7 @@ android {
defaultConfig {
applicationId = "com.joeloewi.croissant"
- versionCode = 49
+ versionCode = 50
versionName = "1.2.2"
targetSdk = 34
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 785e5a98..b7aa9b91 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -72,9 +72,6 @@
-
diff --git a/app/src/main/kotlin/com/joeloewi/croissant/CroissantApplication.kt b/app/src/main/kotlin/com/joeloewi/croissant/CroissantApplication.kt
index 99cce0e1..0285181e 100644
--- a/app/src/main/kotlin/com/joeloewi/croissant/CroissantApplication.kt
+++ b/app/src/main/kotlin/com/joeloewi/croissant/CroissantApplication.kt
@@ -1,7 +1,13 @@
package com.joeloewi.croissant
import android.app.Application
+import com.google.android.material.color.DynamicColors
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
-class CroissantApplication : Application()
\ No newline at end of file
+class CroissantApplication : Application() {
+ override fun onCreate() {
+ super.onCreate()
+ DynamicColors.applyToActivitiesIfAvailable(this)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/joeloewi/croissant/MainActivity.kt b/app/src/main/kotlin/com/joeloewi/croissant/MainActivity.kt
index 27477bd6..5cf3b29d 100644
--- a/app/src/main/kotlin/com/joeloewi/croissant/MainActivity.kt
+++ b/app/src/main/kotlin/com/joeloewi/croissant/MainActivity.kt
@@ -45,6 +45,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.util.fastForEach
import androidx.compose.ui.window.DialogProperties
import androidx.core.os.bundleOf
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
@@ -62,7 +63,6 @@ import androidx.navigation.compose.navigation
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import androidx.navigation.navDeepLink
-import com.google.android.material.color.DynamicColors
import com.google.firebase.Firebase
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.analytics.analytics
@@ -108,10 +108,9 @@ class MainActivity : AppCompatActivity() {
@SuppressLint("HardwareIds")
override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen()
- enableEdgeToEdge()
super.onCreate(savedInstanceState)
- DynamicColors.applyToActivityIfAvailable(this)
+ enableEdgeToEdge()
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
@@ -125,12 +124,14 @@ class MainActivity : AppCompatActivity() {
}
}
- Firebase.analytics.setUserId(
- Settings.Secure.getString(
- contentResolver,
- Settings.Secure.ANDROID_ID
+ lifecycleScope.launch(Dispatchers.IO + CoroutineExceptionHandler { _, _ -> }) {
+ Firebase.analytics.setUserId(
+ Settings.Secure.getString(
+ contentResolver,
+ Settings.Secure.ANDROID_ID
+ )
)
- )
+ }
setContent {
CroissantTheme {
@@ -155,7 +156,6 @@ class MainActivity : AppCompatActivity() {
}
}
-@SuppressLint("RestrictedApi")
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
@Composable
fun CroissantApp(
@@ -179,7 +179,6 @@ fun CroissantApp(
GlobalDestination.EmptyScreen.route
).toImmutableList()
}
- val currentBackStack by navController.currentBackStack.collectAsStateWithLifecycle()
val windowSizeClass = calculateWindowSizeClass(activity = activity)
val croissantNavigations = remember {
listOf(
@@ -206,9 +205,9 @@ fun CroissantApp(
Scaffold(
contentWindowInsets = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal),
bottomBar = {
- val currentBackStackEntry by navController.currentBackStackEntryFlow.collectAsStateWithLifecycle(
- initialValue = null,
- )
+ val currentBackStackEntry by remember(navController) {
+ navController.currentBackStackEntryFlow
+ }.collectAsStateWithLifecycle(initialValue = null)
val isBottomNavigationBarVisible by remember {
derivedStateOf {
!fullScreenDestinations.any { route ->
@@ -226,26 +225,7 @@ fun CroissantApp(
currentBackStackEntry = { currentBackStackEntry },
onClickNavigationButton = { route ->
navController.navigate(route) {
- val startDestination =
- navController.graph.findStartDestination()
-
- val popUpToDestination =
- if (currentBackStack.any {
- it.destination == startDestination
- }) {
-
- startDestination.route
- ?: activity::class.java.simpleName
- } else if (currentBackStack.any {
- it.destination.route == AttendancesDestination.AttendancesScreen.route
- }) {
-
- AttendancesDestination.AttendancesScreen.route
- } else {
- activity::class.java.simpleName
- }
-
- popUpTo(popUpToDestination) {
+ popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
@@ -372,7 +352,7 @@ fun CroissantNavHost(
},
onClickAttendance = {
navController.value.navigate(
- AttendancesDestination.AttendanceDetailScreen().generateRoute(it.id)
+ AttendancesDestination.AttendanceDetailScreen.generateRoute(it.id)
)
}
)
@@ -390,7 +370,7 @@ fun CroissantNavHost(
},
onNavigateToAttendanceDetailScreen = {
navController.value.navigate(
- AttendancesDestination.AttendanceDetailScreen().generateRoute(it)
+ AttendancesDestination.AttendanceDetailScreen.generateRoute(it)
) {
popUpTo(AttendancesDestination.CreateAttendanceScreen.route) {
inclusive = true
@@ -420,32 +400,54 @@ fun CroissantNavHost(
}
composable(
- route = AttendancesDestination.AttendanceDetailScreen().route,
- arguments = AttendancesDestination.AttendanceDetailScreen().arguments.map { argument ->
- navArgument(argument.first) {
- type = argument.second
- }
+ route = AttendancesDestination.AttendanceDetailScreen.route,
+ arguments = AttendancesDestination.AttendanceDetailScreen.arguments.map { argument ->
+ navArgument(argument.first, argument.second)
},
deepLinks = listOf(
navDeepLink {
uriPattern =
- "$deepLinkUri/${AttendancesDestination.AttendanceDetailScreen().route}"
+ "$deepLinkUri/${AttendancesDestination.AttendanceDetailScreen.route}"
}
)
- ) {
+ ) { navBackStackEntry ->
+ val fromDeeplink = remember(navBackStackEntry.arguments) {
+ navBackStackEntry.arguments?.getBoolean(AttendancesDestination.AttendanceDetailScreen.FROM_DEEPLINK)
+ ?: false
+ }
val newCookie by remember {
- it.savedStateHandle.getStateFlow(COOKIE, "")
+ navBackStackEntry.savedStateHandle.getStateFlow(COOKIE, "")
}.collectAsStateWithLifecycle()
+ LaunchedEffect(fromDeeplink) {
+ if (fromDeeplink) {
+ with(navController.value.graph) {
+ findNode(CroissantNavigation.Attendances.route)?.id?.let {
+ setStartDestination(
+ it
+ )
+ }
+ }
+ }
+ }
+
AttendanceDetailScreen(
newCookie = { newCookie },
- onNavigateUp = { navController.value.navigateUp() },
+ onNavigateUp = {
+ if (fromDeeplink) {
+ with(navController.value) {
+ popBackStack(graph.findStartDestination().id, inclusive = true)
+ }
+ } else {
+ navController.value.navigateUp()
+ }
+ },
onClickRefreshSession = {
navController.value.navigate(AttendancesDestination.LoginHoYoLabScreen.route)
},
onClickLogSummary = { attendanceId, loggableWorker ->
navController.value.navigate(
- AttendancesDestination.AttendanceLogsCalendarScreen().generateRoute(
+ AttendancesDestination.AttendanceLogsCalendarScreen.generateRoute(
attendanceId,
loggableWorker
)
@@ -455,18 +457,16 @@ fun CroissantNavHost(
}
composable(
- route = AttendancesDestination.AttendanceLogsCalendarScreen().route,
- arguments = AttendancesDestination.AttendanceLogsCalendarScreen().arguments.map { argument ->
- navArgument(argument.first) {
- type = argument.second
- }
+ route = AttendancesDestination.AttendanceLogsCalendarScreen.route,
+ arguments = AttendancesDestination.AttendanceLogsCalendarScreen.arguments.map { argument ->
+ navArgument(argument.first, argument.second)
}
) {
AttendanceLogsCalendarScreen(
onNavigateUp = { navController.value.navigateUp() },
onClickDay = { attendanceId, loggableWorker, localDate ->
navController.value.navigate(
- AttendancesDestination.AttendanceLogsDayScreen().generateRoute(
+ AttendancesDestination.AttendanceLogsDayScreen.generateRoute(
attendanceId = attendanceId,
loggableWorker = loggableWorker,
localDate = localDate,
@@ -477,11 +477,9 @@ fun CroissantNavHost(
}
composable(
- route = AttendancesDestination.AttendanceLogsDayScreen().route,
- arguments = AttendancesDestination.AttendanceLogsDayScreen().arguments.map { argument ->
- navArgument(argument.first) {
- type = argument.second
- }
+ route = AttendancesDestination.AttendanceLogsDayScreen.route,
+ arguments = AttendancesDestination.AttendanceLogsDayScreen.arguments.map { argument ->
+ navArgument(argument.first, argument.second)
}
) {
AttendanceLogsDayScreen(
@@ -534,6 +532,13 @@ fun CroissantNavHost(
}
},
onShowDefaultScreen = {
+ with(navController.value.graph) {
+ findNode(CroissantNavigation.Attendances.route)?.id?.let {
+ setStartDestination(
+ it
+ )
+ }
+ }
navController.value.navigate(AttendancesDestination.AttendancesScreen.route) {
popUpTo(activity::class.java.simpleName) {
inclusive = true
@@ -546,6 +551,13 @@ fun CroissantNavHost(
composable(route = GlobalDestination.FirstLaunchScreen.route) {
FirstLaunchScreen(
onNavigateToAttendances = {
+ with(navController.value.graph) {
+ findNode(CroissantNavigation.Attendances.route)?.id?.let {
+ setStartDestination(
+ it
+ )
+ }
+ }
navController.value.navigate(AttendancesDestination.AttendancesScreen.route) {
popUpTo(activity::class.java.simpleName) {
inclusive = true
@@ -615,7 +627,7 @@ private fun CroissantBottomNavigationBar(
NavigationBar(
modifier = modifier
) {
- croissantNavigations.forEach { croissantNavigation ->
+ croissantNavigations.fastForEach { croissantNavigation ->
key(croissantNavigation.route) {
val isSelected by remember(croissantNavigation.route) {
derivedStateOf { currentBackStackEntry()?.destination?.hierarchy?.any { it.route == croissantNavigation.route } == true }
diff --git a/app/src/main/kotlin/com/joeloewi/croissant/ResinStatusWidgetConfigurationActivity.kt b/app/src/main/kotlin/com/joeloewi/croissant/ResinStatusWidgetConfigurationActivity.kt
index 733e957e..1a9011e0 100644
--- a/app/src/main/kotlin/com/joeloewi/croissant/ResinStatusWidgetConfigurationActivity.kt
+++ b/app/src/main/kotlin/com/joeloewi/croissant/ResinStatusWidgetConfigurationActivity.kt
@@ -31,7 +31,6 @@ import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.navigation
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
-import com.google.android.material.color.DynamicColors
import com.google.firebase.Firebase
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.analytics.analytics
@@ -61,7 +60,6 @@ class ResinStatusWidgetConfigurationActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
- DynamicColors.applyToActivityIfAvailable(this)
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
@@ -143,10 +141,7 @@ fun ResinStatusWidgetConfigurationApp() {
composable(
route = ResinStatusWidgetConfigurationDestination.LoadingScreen().route,
arguments = ResinStatusWidgetConfigurationDestination.LoadingScreen().arguments.map { argument ->
- navArgument(argument.first) {
- type = argument.second
- defaultValue = AppWidgetManager.INVALID_APPWIDGET_ID
- }
+ navArgument(argument.first, argument.second)
}
) {
val loadingViewModel: LoadingViewModel = hiltViewModel()
@@ -160,9 +155,7 @@ fun ResinStatusWidgetConfigurationApp() {
composable(
route = ResinStatusWidgetConfigurationDestination.CreateResinStatusWidgetScreen().route,
arguments = ResinStatusWidgetConfigurationDestination.CreateResinStatusWidgetScreen().arguments.map { argument ->
- navArgument(argument.first) {
- type = argument.second
- }
+ navArgument(argument.first, argument.second)
},
) {
val newCookie by remember {
@@ -196,9 +189,7 @@ fun ResinStatusWidgetConfigurationApp() {
composable(
route = ResinStatusWidgetConfigurationDestination.ResinStatusWidgetDetailScreen().route,
arguments = ResinStatusWidgetConfigurationDestination.ResinStatusWidgetDetailScreen().arguments.map { argument ->
- navArgument(argument.first) {
- type = argument.second
- }
+ navArgument(argument.first, argument.second)
}
) {
ResinStatusWidgetDetailScreen()
diff --git a/app/src/main/kotlin/com/joeloewi/croissant/di/EntryPoints.kt b/app/src/main/kotlin/com/joeloewi/croissant/di/EntryPoints.kt
index 4fc6b087..46b525f0 100644
--- a/app/src/main/kotlin/com/joeloewi/croissant/di/EntryPoints.kt
+++ b/app/src/main/kotlin/com/joeloewi/croissant/di/EntryPoints.kt
@@ -16,7 +16,6 @@
package com.joeloewi.croissant.di
-import android.app.Application
import android.content.Context
import androidx.hilt.work.HiltWorkerFactory
import androidx.work.RunnableScheduler
@@ -35,7 +34,6 @@ import kotlin.reflect.KClass
interface InitializerEntryPoint {
fun imageLoader(): ImageLoader
fun hiltWorkerFactory(): HiltWorkerFactory
- fun application(): Application
@DefaultDispatcherExecutor
fun executor(): Executor
diff --git a/app/src/main/kotlin/com/joeloewi/croissant/di/UtilModule.kt b/app/src/main/kotlin/com/joeloewi/croissant/di/UtilModule.kt
index 9e4fabef..7b57d574 100644
--- a/app/src/main/kotlin/com/joeloewi/croissant/di/UtilModule.kt
+++ b/app/src/main/kotlin/com/joeloewi/croissant/di/UtilModule.kt
@@ -51,6 +51,7 @@ object UtilModule {
@ApplicationContext context: Context
): TextToSpeechFactory = TextToSpeechFactory(context)
+ @Singleton
@Provides
fun provideNotificationGenerator(
@ApplicationContext context: Context
diff --git a/app/src/main/kotlin/com/joeloewi/croissant/initializer/DynamicColorInitializer.kt b/app/src/main/kotlin/com/joeloewi/croissant/initializer/DynamicColorInitializer.kt
deleted file mode 100644
index 63eb8e84..00000000
--- a/app/src/main/kotlin/com/joeloewi/croissant/initializer/DynamicColorInitializer.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.joeloewi.croissant.initializer
-
-import android.content.Context
-import androidx.startup.Initializer
-import com.google.android.material.color.DynamicColors
-import com.joeloewi.croissant.di.InitializerEntryPoint
-import com.joeloewi.croissant.di.entryPoints
-
-class DynamicColorInitializer : Initializer {
-
- override fun create(context: Context) {
- val initializerEntryPoint: InitializerEntryPoint by context.entryPoints()
- val application = initializerEntryPoint.application()
-
- DynamicColors.applyToActivitiesIfAvailable(application)
- }
-
- override fun dependencies(): MutableList>> = mutableListOf()
-}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/joeloewi/croissant/receiver/AlarmReceiver.kt b/app/src/main/kotlin/com/joeloewi/croissant/receiver/AlarmReceiver.kt
index f8e27d71..490bdfa6 100644
--- a/app/src/main/kotlin/com/joeloewi/croissant/receiver/AlarmReceiver.kt
+++ b/app/src/main/kotlin/com/joeloewi/croissant/receiver/AlarmReceiver.kt
@@ -31,13 +31,13 @@ import javax.inject.Inject
@AndroidEntryPoint
class AlarmReceiver : BroadcastReceiver() {
+ private val _processLifecycleScope = ProcessLifecycleOwner.get().lifecycleScope
private val _coroutineContext = Dispatchers.IO + CoroutineExceptionHandler { _, throwable ->
Firebase.crashlytics.apply {
log(this@AlarmReceiver.javaClass.simpleName)
recordException(throwable)
}
}
- private val _processLifecycleScope by lazy { ProcessLifecycleOwner.get().lifecycleScope }
@Inject
lateinit var application: Application
@@ -58,9 +58,9 @@ class AlarmReceiver : BroadcastReceiver() {
lateinit var alarmScheduler: AlarmScheduler
override fun onReceive(p0: Context, p1: Intent) {
- when (p1.action) {
- Intent.ACTION_BOOT_COMPLETED, Intent.ACTION_MY_PACKAGE_REPLACED, AlarmManager.ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED -> {
- _processLifecycleScope.launch(_coroutineContext) {
+ _processLifecycleScope.launch(_coroutineContext) {
+ when (p1.action) {
+ Intent.ACTION_BOOT_COMPLETED, Intent.ACTION_MY_PACKAGE_REPLACED, AlarmManager.ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED -> {
getAllOneShotAttendanceUseCase().map { attendance ->
async(SupervisorJob() + Dispatchers.IO + CoroutineExceptionHandler { _, _ -> }) {
attendance.runCatching {
@@ -72,12 +72,9 @@ class AlarmReceiver : BroadcastReceiver() {
}
}.awaitAll()
}
- }
-
- RECEIVE_ATTEND_CHECK_IN_ALARM -> {
- val attendanceId = p1.getLongExtra(ATTENDANCE_ID, Long.MIN_VALUE)
- _processLifecycleScope.launch(_coroutineContext) {
+ RECEIVE_ATTEND_CHECK_IN_ALARM -> {
+ val attendanceId = p1.getLongExtra(ATTENDANCE_ID, Long.MIN_VALUE)
val attendanceWithGames = getOneAttendanceUseCase(attendanceId)
val attendance = attendanceWithGames.attendance
val oneTimeWork = OneTimeWorkRequestBuilder()
@@ -101,10 +98,10 @@ class AlarmReceiver : BroadcastReceiver() {
scheduleForTomorrow = true
)
}
- }
- else -> {
+ else -> {
+ }
}
}
}
diff --git a/app/src/main/kotlin/com/joeloewi/croissant/receiver/MigrationHelper.kt b/app/src/main/kotlin/com/joeloewi/croissant/receiver/MigrationHelper.kt
index a1377c32..c3b1605a 100644
--- a/app/src/main/kotlin/com/joeloewi/croissant/receiver/MigrationHelper.kt
+++ b/app/src/main/kotlin/com/joeloewi/croissant/receiver/MigrationHelper.kt
@@ -22,13 +22,13 @@ import javax.inject.Inject
@AndroidEntryPoint
class MigrationHelper : BroadcastReceiver() {
+ private val _processLifecycleScope = ProcessLifecycleOwner.get().lifecycleScope
private val _coroutineContext = Dispatchers.IO + CoroutineExceptionHandler { _, throwable ->
Firebase.crashlytics.apply {
log(this@MigrationHelper.javaClass.simpleName)
recordException(throwable)
}
}
- private val _processLifecycleScope by lazy { ProcessLifecycleOwner.get().lifecycleScope }
@Inject
lateinit var application: Application
@@ -46,9 +46,9 @@ class MigrationHelper : BroadcastReceiver() {
lateinit var workManager: WorkManager
override fun onReceive(p0: Context, p1: Intent) {
- when (p1.action) {
- Intent.ACTION_MY_PACKAGE_REPLACED -> {
- _processLifecycleScope.launch(_coroutineContext) {
+ _processLifecycleScope.launch(_coroutineContext) {
+ when (p1.action) {
+ Intent.ACTION_MY_PACKAGE_REPLACED -> {
//because work manager's job can be deferred, cancel check in event worker
//instead of work manager, use alarm manager
getAllOneShotAttendanceUseCase().map { attendance ->
@@ -57,10 +57,8 @@ class MigrationHelper : BroadcastReceiver() {
}
}.awaitAll()
}
- }
-
- else -> {
+ else -> {}
}
}
}
diff --git a/app/src/main/kotlin/com/joeloewi/croissant/receiver/ResinStatusWidgetProvider.kt b/app/src/main/kotlin/com/joeloewi/croissant/receiver/ResinStatusWidgetProvider.kt
index 825fe9eb..d55b519f 100644
--- a/app/src/main/kotlin/com/joeloewi/croissant/receiver/ResinStatusWidgetProvider.kt
+++ b/app/src/main/kotlin/com/joeloewi/croissant/receiver/ResinStatusWidgetProvider.kt
@@ -30,7 +30,7 @@ import javax.inject.Inject
@AndroidEntryPoint
class ResinStatusWidgetProvider : AppWidgetProvider() {
- private val _processLifecycleOwner by lazy { ProcessLifecycleOwner.get() }
+ private val _processLifecycleScope = ProcessLifecycleOwner.get().lifecycleScope
private val _coroutineContext = Dispatchers.IO + CoroutineExceptionHandler { _, throwable ->
Firebase.crashlytics.apply {
log(this@ResinStatusWidgetProvider.javaClass.simpleName)
@@ -55,10 +55,8 @@ class ResinStatusWidgetProvider : AppWidgetProvider() {
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
- super.onUpdate(context, appWidgetManager, appWidgetIds)
//this method also called when user put widget on home screen
-
- _processLifecycleOwner.lifecycleScope.launch(_coroutineContext) {
+ _processLifecycleScope.launch(_coroutineContext) {
appWidgetIds.map { appWidgetId ->
async(SupervisorJob() + Dispatchers.IO + CoroutineExceptionHandler { _, _ -> }) {
if (powerManager.isPowerSaveMode && !powerManager.isIgnoringBatteryOptimizationsCompat(
@@ -99,12 +97,12 @@ class ResinStatusWidgetProvider : AppWidgetProvider() {
}
}.awaitAll()
}
+
+ super.onUpdate(context, appWidgetManager, appWidgetIds)
}
override fun onDeleted(context: Context, appWidgetIds: IntArray) {
- super.onDeleted(context, appWidgetIds)
-
- _processLifecycleOwner.lifecycleScope.launch(_coroutineContext) {
+ _processLifecycleScope.launch(_coroutineContext) {
appWidgetIds.run {
map { appWidgetId ->
async(SupervisorJob() + Dispatchers.IO + CoroutineExceptionHandler { _, _ -> }) {
@@ -119,5 +117,7 @@ class ResinStatusWidgetProvider : AppWidgetProvider() {
deleteByAppWidgetIdResinStatusWidgetUseCase(*this)
}
}
+
+ super.onDeleted(context, appWidgetIds)
}
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/joeloewi/croissant/receiver/TimeZoneChangedReceiver.kt b/app/src/main/kotlin/com/joeloewi/croissant/receiver/TimeZoneChangedReceiver.kt
index 0775a157..9a008ba6 100644
--- a/app/src/main/kotlin/com/joeloewi/croissant/receiver/TimeZoneChangedReceiver.kt
+++ b/app/src/main/kotlin/com/joeloewi/croissant/receiver/TimeZoneChangedReceiver.kt
@@ -18,21 +18,21 @@ import javax.inject.Inject
@AndroidEntryPoint
class TimeZoneChangedReceiver @Inject constructor(
) : BroadcastReceiver() {
+ private val _processLifecycleScope = ProcessLifecycleOwner.get().lifecycleScope
private val _coroutineContext = Dispatchers.IO + CoroutineExceptionHandler { _, throwable ->
Firebase.crashlytics.apply {
log(this@TimeZoneChangedReceiver.javaClass.simpleName)
recordException(throwable)
}
}
- private val _processLifecycleScope by lazy { ProcessLifecycleOwner.get().lifecycleScope }
@Inject
lateinit var notificationGenerator: NotificationGenerator
override fun onReceive(context: Context, intent: Intent) {
- when (intent.action) {
- Intent.ACTION_TIMEZONE_CHANGED -> {
- _processLifecycleScope.launch(_coroutineContext) {
+ _processLifecycleScope.launch(_coroutineContext) {
+ when (intent.action) {
+ Intent.ACTION_TIMEZONE_CHANGED -> {
with(notificationGenerator) {
safeNotify(
UUID.randomUUID().toString(),
@@ -41,10 +41,10 @@ class TimeZoneChangedReceiver @Inject constructor(
)
}
}
- }
- else -> {
+ else -> {
+ }
}
}
}
diff --git a/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/CroissantNavigation.kt b/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/CroissantNavigation.kt
index d05f57f5..7478f8d9 100644
--- a/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/CroissantNavigation.kt
+++ b/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/CroissantNavigation.kt
@@ -8,9 +8,11 @@ import androidx.compose.material.icons.filled.TaskAlt
import androidx.compose.material.icons.outlined.Redeem
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material.icons.outlined.TaskAlt
+import androidx.compose.runtime.Immutable
import androidx.compose.ui.graphics.vector.ImageVector
import com.joeloewi.croissant.R
+@Immutable
sealed class CroissantNavigation(
val route: String,
val filledIcon: ImageVector,
diff --git a/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/attendances/AttendancesDestination.kt b/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/attendances/AttendancesDestination.kt
index 35370b2b..8c490ee5 100644
--- a/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/attendances/AttendancesDestination.kt
+++ b/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/attendances/AttendancesDestination.kt
@@ -1,12 +1,18 @@
package com.joeloewi.croissant.ui.navigation.main.attendances
+import android.content.Context
+import android.net.Uri
+import androidx.compose.runtime.Immutable
+import androidx.navigation.NavArgumentBuilder
import androidx.navigation.NavType
+import com.joeloewi.croissant.R
import com.joeloewi.croissant.domain.common.LoggableWorker
+@Immutable
sealed class AttendancesDestination {
- abstract val arguments: List>>
+ abstract val arguments: List Unit>>
protected abstract val plainRoute: String
- val route: String
+ open val route: String
get() = "${plainRoute}${
arguments.map { it.first }.joinToString(
separator = "/",
@@ -18,44 +24,70 @@ sealed class AttendancesDestination {
) { "{$it}" }
}"
- object AttendancesScreen : AttendancesDestination() {
- override val arguments: List>> = listOf()
+ data object AttendancesScreen : AttendancesDestination() {
+ override val arguments: List Unit>> = listOf()
override val plainRoute = "attendancesScreen"
}
- object CreateAttendanceScreen : AttendancesDestination() {
- override val arguments: List>> = listOf()
+ data object CreateAttendanceScreen : AttendancesDestination() {
+ override val arguments: List Unit>> = listOf()
override val plainRoute = "createAttendanceScreen"
}
- object LoginHoYoLabScreen : AttendancesDestination() {
- override val arguments: List>> = listOf()
+ data object LoginHoYoLabScreen : AttendancesDestination() {
+ override val arguments: List Unit>> = listOf()
override val plainRoute = "loginHoYoLabScreen"
}
- class AttendanceDetailScreen : AttendancesDestination() {
- companion object {
- const val ATTENDANCE_ID = "attendanceId"
- }
+ data object AttendanceDetailScreen : AttendancesDestination() {
+ const val ATTENDANCE_ID = "attendanceId"
+ const val FROM_DEEPLINK = "fromDeeplink"
- override val arguments: List>> = listOf(
- ATTENDANCE_ID to NavType.LongType
+ override val arguments: List Unit)>> = listOf(
+ ATTENDANCE_ID to {
+ type = NavType.LongType
+
+ },
+ FROM_DEEPLINK to {
+ type = NavType.BoolType
+ defaultValue = false
+ }
)
override val plainRoute: String = "attendanceDetailScreen"
- fun generateRoute(attendanceId: Long) = "${plainRoute}/${attendanceId}"
- }
+ override val route: String
+ get() = "${plainRoute}/{${ATTENDANCE_ID}}?${FROM_DEEPLINK}={${FROM_DEEPLINK}}"
- class AttendanceLogsCalendarScreen : AttendancesDestination() {
- companion object {
- const val ATTENDANCE_ID = "attendanceId"
- const val LOGGABLE_WORKER = "loggableWorker"
- }
+ fun generateRoute(
+ attendanceId: Long,
+ fromDeeplink: Boolean = false
+ ) = "${plainRoute}/$attendanceId?${FROM_DEEPLINK}={$fromDeeplink}"
+
+ fun generateDeepLinkUri(
+ context: Context,
+ attendanceId: Long,
+ fromDeeplink: Boolean = true
+ ): Uri = Uri.Builder()
+ .scheme(context.getString(R.string.deep_link_scheme))
+ .authority(context.packageName)
+ .appendEncodedPath(plainRoute)
+ .appendPath("$attendanceId")
+ .appendQueryParameter(FROM_DEEPLINK, "$fromDeeplink")
+ .build()
+ }
- override val arguments: List>> = listOf(
- ATTENDANCE_ID to NavType.LongType,
- LOGGABLE_WORKER to NavType.EnumType(LoggableWorker::class.java)
+ data object AttendanceLogsCalendarScreen : AttendancesDestination() {
+ const val ATTENDANCE_ID = "attendanceId"
+ const val LOGGABLE_WORKER = "loggableWorker"
+
+ override val arguments: List Unit>> = listOf(
+ ATTENDANCE_ID to {
+ type = NavType.LongType
+ },
+ LOGGABLE_WORKER to {
+ type = NavType.EnumType(LoggableWorker::class.java)
+ }
)
override val plainRoute: String = "attendanceLogsCalendarScreen"
@@ -64,17 +96,21 @@ sealed class AttendancesDestination {
"${plainRoute}/${attendanceId}/${loggableWorker}"
}
- class AttendanceLogsDayScreen : AttendancesDestination() {
- companion object {
- const val ATTENDANCE_ID = "attendanceId"
- const val LOGGABLE_WORKER = "loggableWorker"
- const val LOCAL_DATE = "localDate"
- }
-
- override val arguments: List>> = listOf(
- ATTENDANCE_ID to NavType.LongType,
- LOGGABLE_WORKER to NavType.EnumType(LoggableWorker::class.java),
- LOCAL_DATE to NavType.StringType
+ data object AttendanceLogsDayScreen : AttendancesDestination() {
+ const val ATTENDANCE_ID = "attendanceId"
+ const val LOGGABLE_WORKER = "loggableWorker"
+ const val LOCAL_DATE = "localDate"
+
+ override val arguments: List Unit>> = listOf(
+ ATTENDANCE_ID to {
+ type = NavType.LongType
+ },
+ LOGGABLE_WORKER to {
+ type = NavType.EnumType(LoggableWorker::class.java)
+ },
+ LOCAL_DATE to {
+ type = NavType.StringType
+ }
)
override val plainRoute: String = "attendanceLogsDayScreen"
diff --git a/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/attendances/screen/AttendanceDetailScreen.kt b/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/attendances/screen/AttendanceDetailScreen.kt
index 81d97a9e..ff417eb0 100644
--- a/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/attendances/screen/AttendanceDetailScreen.kt
+++ b/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/attendances/screen/AttendanceDetailScreen.kt
@@ -1,5 +1,6 @@
package com.joeloewi.croissant.ui.navigation.main.attendances.screen
+import androidx.activity.compose.BackHandler
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
@@ -170,6 +171,10 @@ private fun AttendanceDetailContent(
)
var showConfirmDeleteDialog by remember { mutableStateOf(false) }
+ BackHandler {
+ onNavigateUp()
+ }
+
LaunchedEffect(snackbarHostState) {
withContext(Dispatchers.IO) {
snapshotFlow(newCookie).catch { }.collect {
diff --git a/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/global/GlobalDestination.kt b/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/global/GlobalDestination.kt
index 3bdab030..25d1658e 100644
--- a/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/global/GlobalDestination.kt
+++ b/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/global/GlobalDestination.kt
@@ -1,9 +1,11 @@
package com.joeloewi.croissant.ui.navigation.main.global
-import androidx.navigation.NavType
+import androidx.compose.runtime.Immutable
+import androidx.navigation.NavArgumentBuilder
+@Immutable
sealed class GlobalDestination {
- abstract val arguments: List>>
+ abstract val arguments: List Unit>>
abstract val plainRoute: String
open val route: String
get() = "${plainRoute}${
@@ -18,12 +20,12 @@ sealed class GlobalDestination {
}"
data object EmptyScreen : GlobalDestination() {
- override val arguments: List>> = emptyList()
+ override val arguments: List Unit>> = listOf()
override val plainRoute: String = "EmptyScreen"
}
data object FirstLaunchScreen : GlobalDestination() {
- override val arguments: List>> = listOf()
+ override val arguments: List Unit>> = listOf()
override val plainRoute = "firstLaunchScreen"
}
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/redemptioncodes/RedemptionCodesDestination.kt b/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/redemptioncodes/RedemptionCodesDestination.kt
index 771689fc..5432f8b1 100644
--- a/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/redemptioncodes/RedemptionCodesDestination.kt
+++ b/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/redemptioncodes/RedemptionCodesDestination.kt
@@ -1,9 +1,11 @@
package com.joeloewi.croissant.ui.navigation.main.redemptioncodes
-import androidx.navigation.NavType
+import androidx.compose.runtime.Immutable
+import androidx.navigation.NavArgumentBuilder
+@Immutable
sealed class RedemptionCodesDestination {
- abstract val arguments: List>>
+ abstract val arguments: List Unit>>
protected abstract val plainRoute: String
val route: String by lazy {
"${plainRoute}${
@@ -18,8 +20,8 @@ sealed class RedemptionCodesDestination {
}"
}
- object RedemptionCodesScreen : RedemptionCodesDestination() {
- override val arguments: List>> = listOf()
+ data object RedemptionCodesScreen : RedemptionCodesDestination() {
+ override val arguments: List Unit>> = listOf()
override val plainRoute: String = "redemptionCodesScreen"
}
}
diff --git a/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/settings/SettingsDestination.kt b/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/settings/SettingsDestination.kt
index 8d105aab..fc8b2228 100644
--- a/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/settings/SettingsDestination.kt
+++ b/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/main/settings/SettingsDestination.kt
@@ -1,9 +1,11 @@
package com.joeloewi.croissant.ui.navigation.main.settings
-import androidx.navigation.NavType
+import androidx.compose.runtime.Immutable
+import androidx.navigation.NavArgumentBuilder
+@Immutable
sealed class SettingsDestination {
- abstract val arguments: List>>
+ abstract val arguments: List Unit>>
protected abstract val plainRoute: String
val route: String by lazy {
"${plainRoute}${
@@ -18,13 +20,13 @@ sealed class SettingsDestination {
}"
}
- object SettingsScreen : SettingsDestination() {
- override val arguments: List>> = listOf()
+ data object SettingsScreen : SettingsDestination() {
+ override val arguments: List Unit>> = listOf()
override val plainRoute: String = "settingsScreen"
}
- object DeveloperInfoScreen : SettingsDestination() {
- override val arguments: List>> = listOf()
+ data object DeveloperInfoScreen : SettingsDestination() {
+ override val arguments: List Unit>> = listOf()
override val plainRoute: String = "developerInfoScreen"
}
}
diff --git a/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/widgetconfiguration/resinstatus/ResinStatusWidgetConfigurationNavigation.kt b/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/widgetconfiguration/resinstatus/ResinStatusWidgetConfigurationNavigation.kt
index f0258c98..32b91d78 100644
--- a/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/widgetconfiguration/resinstatus/ResinStatusWidgetConfigurationNavigation.kt
+++ b/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/widgetconfiguration/resinstatus/ResinStatusWidgetConfigurationNavigation.kt
@@ -3,7 +3,7 @@ package com.joeloewi.croissant.ui.navigation.widgetconfiguration.resinstatus
sealed class ResinStatusWidgetConfigurationNavigation(
val route: String = ""
) {
- object Configuration : ResinStatusWidgetConfigurationNavigation(
+ data object Configuration : ResinStatusWidgetConfigurationNavigation(
route = "configuration"
)
}
diff --git a/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/widgetconfiguration/resinstatus/resinstatuswidgetconfiguration/ResinStatusWidgetConfigurationDestination.kt b/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/widgetconfiguration/resinstatus/resinstatuswidgetconfiguration/ResinStatusWidgetConfigurationDestination.kt
index 2f2d2e7a..663aaae0 100644
--- a/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/widgetconfiguration/resinstatus/resinstatuswidgetconfiguration/ResinStatusWidgetConfigurationDestination.kt
+++ b/app/src/main/kotlin/com/joeloewi/croissant/ui/navigation/widgetconfiguration/resinstatus/resinstatuswidgetconfiguration/ResinStatusWidgetConfigurationDestination.kt
@@ -1,9 +1,13 @@
package com.joeloewi.croissant.ui.navigation.widgetconfiguration.resinstatus.resinstatuswidgetconfiguration
+import android.appwidget.AppWidgetManager
+import androidx.compose.runtime.Immutable
+import androidx.navigation.NavArgumentBuilder
import androidx.navigation.NavType
+@Immutable
sealed class ResinStatusWidgetConfigurationDestination {
- abstract val arguments: List>>
+ abstract val arguments: List Unit>>
protected abstract val plainRoute: String
val route: String by lazy {
"${plainRoute}${
@@ -18,14 +22,17 @@ sealed class ResinStatusWidgetConfigurationDestination {
}"
}
- object EmptyScreen : ResinStatusWidgetConfigurationDestination() {
- override val arguments: List>> = listOf()
+ data object EmptyScreen : ResinStatusWidgetConfigurationDestination() {
+ override val arguments: List Unit>> = listOf()
override val plainRoute: String = "emptyScreen"
}
class LoadingScreen(
- override val arguments: List>> = listOf(
- APP_WIDGET_ID to NavType.IntType
+ override val arguments: List Unit>> = listOf(
+ APP_WIDGET_ID to {
+ type = NavType.IntType
+ defaultValue = AppWidgetManager.INVALID_APPWIDGET_ID
+ }
),
override val plainRoute: String = "loadingScreen"
) : ResinStatusWidgetConfigurationDestination() {
@@ -37,8 +44,8 @@ sealed class ResinStatusWidgetConfigurationDestination {
}
class CreateResinStatusWidgetScreen(
- override val arguments: List>> = listOf(
- APP_WIDGET_ID to NavType.IntType
+ override val arguments: List Unit>> = listOf(
+ APP_WIDGET_ID to { type = NavType.IntType }
),
override val plainRoute: String = "createResinStatusWidgetScreen"
) : ResinStatusWidgetConfigurationDestination() {
@@ -50,8 +57,8 @@ sealed class ResinStatusWidgetConfigurationDestination {
}
class ResinStatusWidgetDetailScreen(
- override val arguments: List>> = listOf(
- APP_WIDGET_ID to NavType.IntType
+ override val arguments: List Unit>> = listOf(
+ APP_WIDGET_ID to { type = NavType.IntType }
),
override val plainRoute: String = "resinStatusWidgetDetailScreen"
) : ResinStatusWidgetConfigurationDestination() {
@@ -62,8 +69,8 @@ sealed class ResinStatusWidgetConfigurationDestination {
fun generateRoute(appWidgetId: Int) = "${plainRoute}/${appWidgetId}"
}
- object LoginHoYoLABScreen : ResinStatusWidgetConfigurationDestination() {
- override val arguments: List>> = listOf()
+ data object LoginHoYoLABScreen : ResinStatusWidgetConfigurationDestination() {
+ override val arguments: List Unit>> = listOf()
override val plainRoute: String = "loginHoYoLABScreen"
}
}
diff --git a/app/src/main/kotlin/com/joeloewi/croissant/util/NotificationGenerator.kt b/app/src/main/kotlin/com/joeloewi/croissant/util/NotificationGenerator.kt
index 60b54cc3..6ed573c7 100644
--- a/app/src/main/kotlin/com/joeloewi/croissant/util/NotificationGenerator.kt
+++ b/app/src/main/kotlin/com/joeloewi/croissant/util/NotificationGenerator.kt
@@ -179,14 +179,9 @@ class NotificationGenerator(
addNextIntentWithParentStack(
Intent(
Intent.ACTION_VIEW,
- Uri.Builder()
- .scheme(context.getString(R.string.deep_link_scheme))
- .authority(context.packageName)
- .appendEncodedPath(
- AttendancesDestination.AttendanceDetailScreen()
- .generateRoute(attendanceId)
- )
- .build()
+ AttendancesDestination.AttendanceDetailScreen.generateDeepLinkUri(
+ context, attendanceId
+ )
)
)
getPendingIntent(0, pendingIntentFlagUpdateCurrent)
@@ -238,14 +233,9 @@ class NotificationGenerator(
addNextIntentWithParentStack(
Intent(
Intent.ACTION_VIEW,
- Uri.Builder()
- .scheme(context.getString(R.string.deep_link_scheme))
- .authority(context.packageName)
- .appendEncodedPath(
- AttendancesDestination.AttendanceDetailScreen()
- .generateRoute(attendanceId)
- )
- .build()
+ AttendancesDestination.AttendanceDetailScreen.generateDeepLinkUri(
+ context, attendanceId
+ )
)
)
getPendingIntent(0, pendingIntentFlagUpdateCurrent)