163 lines
6.7 KiB
Kotlin
163 lines
6.7 KiB
Kotlin
package cc.n0th1ng.tripmoney
|
|
|
|
import android.os.Build
|
|
import android.os.Bundle
|
|
import androidx.activity.ComponentActivity
|
|
import androidx.activity.compose.ReportDrawnWhen
|
|
import androidx.activity.compose.setContent
|
|
import androidx.activity.enableEdgeToEdge
|
|
import androidx.annotation.RequiresApi
|
|
import androidx.compose.foundation.layout.padding
|
|
import androidx.compose.material3.DrawerValue
|
|
import androidx.compose.material3.Scaffold
|
|
import androidx.compose.material3.rememberDrawerState
|
|
import androidx.compose.runtime.Composable
|
|
import androidx.compose.runtime.collectAsState
|
|
import androidx.compose.runtime.getValue
|
|
import androidx.compose.runtime.mutableStateOf
|
|
import androidx.compose.runtime.remember
|
|
import androidx.compose.runtime.rememberCoroutineScope
|
|
import androidx.compose.runtime.saveable.rememberSaveable
|
|
import androidx.compose.runtime.setValue
|
|
import androidx.compose.ui.Modifier
|
|
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
|
import androidx.navigation.compose.NavHost
|
|
import androidx.navigation.compose.composable
|
|
import androidx.navigation.compose.currentBackStackEntryAsState
|
|
import androidx.navigation.compose.rememberNavController
|
|
import androidx.navigation.navArgument
|
|
import cc.n0th1ng.tripmoney.data.entity.Category
|
|
import cc.n0th1ng.tripmoney.data.entity.Trip
|
|
import cc.n0th1ng.tripmoney.navigation.BottomNavigation
|
|
import cc.n0th1ng.tripmoney.navigation.CustomNavigationDrawer
|
|
import cc.n0th1ng.tripmoney.navigation.Screens
|
|
import cc.n0th1ng.tripmoney.navigation.TopBar
|
|
import cc.n0th1ng.tripmoney.navigation.TopBarSettings
|
|
import cc.n0th1ng.tripmoney.screens.listexpense.ListExpenseScreen
|
|
import cc.n0th1ng.tripmoney.screens.managecategories.ManageCategoriesScreen
|
|
import cc.n0th1ng.tripmoney.screens.settings.SettingsScreen
|
|
import cc.n0th1ng.tripmoney.screens.statistics.StatisticsScreen
|
|
import cc.n0th1ng.tripmoney.screens.trippicker.TripPickerScreen
|
|
import cc.n0th1ng.tripmoney.theme.TripMoneyTheme
|
|
import cc.n0th1ng.tripmoney.viewmodel.ExpenseAndCategoryViewModel
|
|
import cc.n0th1ng.tripmoney.viewmodel.SettingsViewModel
|
|
import cc.n0th1ng.tripmoney.viewmodel.TripViewModel
|
|
import dagger.hilt.android.AndroidEntryPoint
|
|
import kotlinx.coroutines.launch
|
|
|
|
@AndroidEntryPoint
|
|
class MainActivity : ComponentActivity() {
|
|
|
|
@RequiresApi(Build.VERSION_CODES.S)
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
super.onCreate(savedInstanceState)
|
|
enableEdgeToEdge()
|
|
setContent {
|
|
TripMoneyTheme {
|
|
NavigationDrawer()
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
@RequiresApi(Build.VERSION_CODES.S)
|
|
@Composable
|
|
fun NavigationDrawer() {
|
|
val settingsViewModel: SettingsViewModel = hiltViewModel()
|
|
val tripViewModel: TripViewModel = hiltViewModel()
|
|
val expenseAndCategoryViewModel: ExpenseAndCategoryViewModel = hiltViewModel()
|
|
val categories by expenseAndCategoryViewModel.getCategories().collectAsState(emptyList())
|
|
val currentTripId by settingsViewModel.currentTrip.collectAsState()
|
|
val currentTrip by tripViewModel.getTrip(currentTripId).collectAsState(Trip.DUMMY)
|
|
val navController = rememberNavController()
|
|
val navBackStack by navController.currentBackStackEntryAsState()
|
|
val current = navBackStack?.destination?.route
|
|
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
|
|
val scope = rememberCoroutineScope()
|
|
var search by remember { mutableStateOf("") }
|
|
var filter by remember { mutableStateOf(Filter()) }
|
|
val autoOpenPref by settingsViewModel.autoOpenStartupPref.collectAsState()
|
|
var hasHandledStartupOpen by rememberSaveable { mutableStateOf(false) }
|
|
val shouldTriggerAutoOpen = autoOpenPref == true && !hasHandledStartupOpen
|
|
ReportDrawnWhen { !categories.isEmpty() }
|
|
CustomNavigationDrawer(navController, drawerState) {
|
|
Scaffold(
|
|
topBar = {
|
|
if (current == Screens.SETTINGS) TopBarSettings(
|
|
navController
|
|
) else TopBar(
|
|
title = currentTrip?.name ?: "",
|
|
onDrawerClick = {
|
|
scope.launch {
|
|
if (drawerState.isClosed) {
|
|
drawerState.open()
|
|
} else {
|
|
drawerState.close()
|
|
}
|
|
}
|
|
},
|
|
isSearchable = current != null && current.contains(Screens.LIST_EXPENSE),
|
|
onSearchChange = { newSearch -> search = newSearch },
|
|
onFilterChange = { newFilter -> filter = newFilter },
|
|
categories = categories,
|
|
filter = filter
|
|
)
|
|
},
|
|
|
|
bottomBar = { BottomNavigation(navController) }) { innerPadding ->
|
|
NavHost(
|
|
navController = navController,
|
|
startDestination = if (currentTripId == -1) Screens.TRIP_PICKER else Screens.LIST_EXPENSE,
|
|
modifier = Modifier.padding(innerPadding)
|
|
) {
|
|
composable(Screens.LIST_EXPENSE+"?dateToScroll={dateToScroll}",
|
|
arguments = listOf(navArgument("dateToScroll"){defaultValue = ""})) {
|
|
backStackEntry ->
|
|
ListExpenseScreen(
|
|
filter = filter, search = search,
|
|
initialAutoOpen = shouldTriggerAutoOpen,
|
|
onAutoOpenConsumed = { hasHandledStartupOpen = true },
|
|
dateToScroll = backStackEntry.arguments?.getString("dateToScroll")?: "")
|
|
}
|
|
composable(Screens.TRIP_PICKER) {
|
|
TripPickerScreen(navController)
|
|
}
|
|
composable(Screens.STATISTICS) {
|
|
StatisticsScreen(navController)
|
|
}
|
|
composable(Screens.SETTINGS) {
|
|
SettingsScreen(navController)
|
|
}
|
|
composable(Screens.MANAGE_CATEGORIES) {
|
|
ManageCategoriesScreen()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
data class Filter(
|
|
val categories: List<Category> = emptyList(), val startAmount: Double = 0.0,
|
|
val endAmount: Double = Double.MAX_VALUE
|
|
) {
|
|
fun with(category: Category): Filter {
|
|
return this.copy(categories = categories + category)
|
|
}
|
|
|
|
fun withStartAmount(amount: Double): Filter {
|
|
return this.copy(startAmount = amount)
|
|
}
|
|
|
|
fun withEndAmount(amount: Double): Filter {
|
|
return this.copy(endAmount = amount)
|
|
}
|
|
|
|
fun without(category: Category): Filter {
|
|
return this.copy(categories = categories - category)
|
|
}
|
|
|
|
fun isDefault(): Boolean {
|
|
return this.categories.isEmpty() && startAmount == 0.0 && endAmount == Double.MAX_VALUE
|
|
}
|
|
} |