Skip to content

Commit

Permalink
🏗️ Restructured the app using Jetpack Navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
lorenzovngl committed Dec 3, 2023
1 parent cb85980 commit f032474
Show file tree
Hide file tree
Showing 48 changed files with 1,658 additions and 1,657 deletions.
5 changes: 2 additions & 3 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ dependencies {
implementation(libs.core.ktx)
implementation(libs.lifecycle.runtime.ktx)
implementation(libs.activity.compose)
implementation(libs.androidx.navigation.compose)
testImplementation(libs.junit)
androidTestImplementation(libs.test.core.ktx)
androidTestImplementation(libs.androidx.test.ext.junit)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.test.rule.GrantPermissionRule
import com.lorenzovainigli.foodexpirationdates.R
import com.lorenzovainigli.foodexpirationdates.view.activity.MainActivity
import com.lorenzovainigli.foodexpirationdates.view.composable.DateFormatDialog
import com.lorenzovainigli.foodexpirationdates.view.composable.DateFormatRow
import org.junit.Rule
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.rule.GrantPermissionRule
import com.lorenzovainigli.foodexpirationdates.R
import com.lorenzovainigli.foodexpirationdates.view.MainActivity
import com.lorenzovainigli.foodexpirationdates.view.composable.FOOD_CARD
import org.junit.Before
import org.junit.Rule
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import androidx.compose.ui.test.onNodeWithText
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.GrantPermissionRule
import androidx.test.uiautomator.UiDevice
import com.lorenzovainigli.foodexpirationdates.view.activity.MainActivity
import com.lorenzovainigli.foodexpirationdates.view.MainActivity
import junit.framework.TestCase.assertTrue
import org.junit.Rule
import org.junit.Test
Expand Down
12 changes: 1 addition & 11 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
android:theme="@style/Theme.FoodExpirationDates"
tools:targetApi="31">
<activity
android:name=".view.activity.MainActivity"
android:name=".view.MainActivity"
android:exported="true"
android:theme="@style/Theme.CustomSplashScreenTheme">
<intent-filter>
Expand All @@ -25,16 +25,6 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".view.activity.InsertActivity">
</activity>
<activity
android:exported="true"
android:name=".view.activity.InfoActivity">
</activity>
<activity
android:name=".view.activity.SettingsActivity">
</activity>
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@ import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import com.lorenzovainigli.foodexpirationdates.BuildConfig
import com.lorenzovainigli.foodexpirationdates.model.worker.CheckExpirationsWorker
import java.util.Calendar
import java.util.concurrent.TimeUnit

class NotificationManager {

Expand Down Expand Up @@ -59,6 +65,58 @@ class NotificationManager {
}
}

fun scheduleDailyNotification(context: Context, hour: Int, minute: Int) {
val currentTime = Calendar.getInstance()
val dueTime = Calendar.getInstance().apply {
set(Calendar.HOUR_OF_DAY, hour)
set(Calendar.MINUTE, minute)
set(Calendar.SECOND, 0)
}
if (currentTime > dueTime)
dueTime.add(Calendar.DAY_OF_MONTH, 1)
val initialDelay = dueTime.timeInMillis - currentTime.timeInMillis
val formattedTime = formatTimeDifference(initialDelay)
if (BuildConfig.DEBUG) {
Toast.makeText(
context,
"Notification in $formattedTime",
Toast.LENGTH_SHORT
).show()
}
val workRequest = PeriodicWorkRequestBuilder<CheckExpirationsWorker>(
1, TimeUnit.DAYS
)
.setInitialDelay(initialDelay, TimeUnit.MILLISECONDS)
.build()
WorkManager.getInstance(context)
.enqueueUniquePeriodicWork(
CheckExpirationsWorker.workerID,
ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
workRequest
)
}

private fun formatTimeDifference(timeDifference: Long): String {
val days = TimeUnit.MILLISECONDS.toDays(timeDifference)
val hours = TimeUnit.MILLISECONDS.toHours(timeDifference) % 24
val minutes = TimeUnit.MILLISECONDS.toMinutes(timeDifference) % 60
val seconds = TimeUnit.MILLISECONDS.toSeconds(timeDifference) % 60
val formattedTime = StringBuilder()
if (days > 0) {
formattedTime.append("$days day${if (days > 1) "s" else ""} ")
}
if (hours > 0) {
formattedTime.append("$hours hour${if (hours > 1) "s" else ""} ")
}
if (minutes > 0) {
formattedTime.append("$minutes minute${if (minutes > 1) "s" else ""} ")
}
if (seconds > 0) {
formattedTime.append("$seconds second${if (seconds > 1) "s" else ""} ")
}
return formattedTime.toString().trim()
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import com.lorenzovainigli.foodexpirationdates.R
import com.lorenzovainigli.foodexpirationdates.model.repository.ExpirationDateRepository
import com.lorenzovainigli.foodexpirationdates.view.activity.MainActivity
import com.lorenzovainigli.foodexpirationdates.view.MainActivity
import kotlinx.coroutines.flow.first
import java.util.Calendar
import javax.inject.Inject
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@ import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
import androidx.lifecycle.viewmodel.compose.viewModel
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.lorenzovainigli.foodexpirationdates.model.repository.PreferencesRepository
import com.lorenzovainigli.foodexpirationdates.viewmodel.PreferencesViewModel

private val LightColors = lightColorScheme(
primary = md_theme_light_primary,
Expand Down Expand Up @@ -85,16 +91,27 @@ fun FoodExpirationDatesTheme(
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}

darkTheme -> DarkColors
else -> LightColors
}

val systemUiController = rememberSystemUiController()
//val useDarkIcons = isSystemInDarkTheme()
var useDarkIcons: Boolean = !isSystemInDarkTheme()
if (LocalViewModelStoreOwner.current != null) {
val prefsViewModel: PreferencesViewModel = viewModel()
useDarkIcons =
when (prefsViewModel.getThemeMode(LocalContext.current).collectAsState().value) {
PreferencesRepository.Companion.ThemeMode.LIGHT.ordinal -> true
PreferencesRepository.Companion.ThemeMode.DARK.ordinal -> false
else -> !isSystemInDarkTheme()
}
}

SideEffect {
systemUiController.setSystemBarsColor(
color = colorScheme.surface
darkIcons = useDarkIcons,
color = Color.Transparent
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package com.lorenzovainigli.foodexpirationdates.view

import android.os.Build
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.annotation.RequiresApi
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.WindowCompat
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.rememberNavController
import com.lorenzovainigli.foodexpirationdates.di.AppModule
import com.lorenzovainigli.foodexpirationdates.di.DaggerAppComponent
import com.lorenzovainigli.foodexpirationdates.model.NotificationManager
import com.lorenzovainigli.foodexpirationdates.model.repository.PreferencesRepository
import com.lorenzovainigli.foodexpirationdates.ui.theme.FoodExpirationDatesTheme
import com.lorenzovainigli.foodexpirationdates.view.composable.MyScaffold
import com.lorenzovainigli.foodexpirationdates.viewmodel.ExpirationDatesViewModel
import com.lorenzovainigli.foodexpirationdates.viewmodel.PreferencesViewModel
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class MainActivity : ComponentActivity() {

val viewModel: ExpirationDatesViewModel by viewModels()
val preferencesViewModel: PreferencesViewModel by viewModels()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)

val splashScreen = installSplashScreen()
splashScreen.setKeepOnScreenCondition { viewModel.isSplashScreenLoading.value }

DaggerAppComponent.builder()
.appModule(AppModule())
.build()
NotificationManager.setupNotificationChannel(this)
}

@RequiresApi(Build.VERSION_CODES.O)
override fun onResume() {
super.onResume()
val context = this
setContent {
val viewModel: ExpirationDatesViewModel = viewModel()
val prefsViewModel: PreferencesViewModel = viewModel()
val darkThemeState = prefsViewModel.getThemeMode(context).collectAsState().value
val dynamicColorsState = prefsViewModel.getDynamicColors(context).collectAsState().value
val isInDarkTheme = when (darkThemeState) {
PreferencesRepository.Companion.ThemeMode.LIGHT.ordinal -> false
PreferencesRepository.Companion.ThemeMode.DARK.ordinal -> true
else -> isSystemInDarkTheme()
}
FoodExpirationDatesTheme(
darkTheme = isInDarkTheme,
dynamicColor = dynamicColorsState
) {
Surface(
modifier = Modifier
.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
val navController = rememberNavController()
val showSnackbar = remember {
mutableStateOf(false)
}
MyScaffold(
activity = this,
navController = navController,
showSnackbar = showSnackbar
) {
Navigation(
activity = this,
navController = navController,
showSnackbar = showSnackbar
)
}
}
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.lorenzovainigli.foodexpirationdates.view

import android.os.Build
import androidx.annotation.RequiresApi
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.navArgument
import com.lorenzovainigli.foodexpirationdates.view.composable.screen.InfoScreen
import com.lorenzovainigli.foodexpirationdates.view.composable.screen.InsertScreen
import com.lorenzovainigli.foodexpirationdates.view.composable.screen.MainScreen
import com.lorenzovainigli.foodexpirationdates.view.composable.screen.Screen
import com.lorenzovainigli.foodexpirationdates.view.composable.screen.SettingsScreen

@RequiresApi(Build.VERSION_CODES.O)
@Composable
fun Navigation(
activity: MainActivity? = null,
navController: NavHostController,
showSnackbar: MutableState<Boolean>
) {
NavHost(
modifier = Modifier.fillMaxSize(),
navController = navController,
startDestination = Screen.MainScreen.route
) {
composable(route = Screen.MainScreen.route) {
MainScreen(
activity = activity,
navController = navController,
showSnackbar = showSnackbar
)
}
composable(
route = Screen.InsertScreen.route + "?itemId={itemId}",
arguments = listOf(
navArgument("itemId"){
type = NavType.StringType
nullable = true
}
)
){ entry ->
InsertScreen(
activity = activity,
navController = navController,
itemId = entry.arguments?.getString("itemId")
)
}
composable(route = Screen.AboutScreen.route){
InfoScreen()
}
composable(route = Screen.SettingsScreen.route){
SettingsScreen(activity = activity)
}
}
}

//@RequiresApi(Build.VERSION_CODES.O)
//@Preview
//@Composable
//fun NavigationPreview(){
// FoodExpirationDatesTheme {
// Surface(modifier = Modifier.fillMaxSize()) {
// Navigation(
// navController = rememberNavController(),
// coroutineScope = rememberCoroutineScope(),
// snackbarHostState = SnackbarHostState()
// )
// }
// }
//}
Loading

0 comments on commit f032474

Please sign in to comment.