mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-03 01:39:22 +02:00
Add bottom navigation to all manage child screens
This commit is contained in:
parent
7f60072b69
commit
446e641f52
7 changed files with 306 additions and 27 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2023 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -21,6 +21,7 @@ import io.timelimit.android.data.customtypes.ImmutableBitmask
|
|||
import io.timelimit.android.data.customtypes.ImmutableBitmaskAdapter
|
||||
import io.timelimit.android.data.model.Category
|
||||
import io.timelimit.android.livedata.map
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import java.util.*
|
||||
|
||||
@Dao
|
||||
|
@ -40,6 +41,9 @@ abstract class CategoryDao {
|
|||
@Query("SELECT * FROM category WHERE id = :categoryId")
|
||||
abstract fun getCategoryByIdSync(categoryId: String): Category?
|
||||
|
||||
@Query("SELECT * FROM category WHERE id = :categoryId")
|
||||
abstract fun getCategoryByIdFlow(categoryId: String): Flow<Category?>
|
||||
|
||||
@Query("SELECT * FROM category WHERE child_id = :childId")
|
||||
abstract fun getCategoriesByChildIdSync(childId: String): List<Category>
|
||||
|
||||
|
|
|
@ -108,8 +108,7 @@ class MainModel(application: Application): AndroidViewModel(application) {
|
|||
val screen: Flow<Screen> = state.splitConflated(
|
||||
Case.simple<_, _, State.LaunchState> { LaunchHandling.processLaunchState(state, logic) },
|
||||
Case.simple<_, _, State.Overview> { OverviewHandling.processState(logic, scope, activityCommandInternal, authenticationModelApi, state) },
|
||||
Case.simple<_, _, State.ManageChild.Main> { state -> ManageChildHandling.processState(logic, state, updateMethod(::updateState)) },
|
||||
Case.simple<_, _, State.ManageChild.Apps> { state -> ManageChildHandling.processState(logic, state, updateMethod(::updateState)) },
|
||||
Case.simple<_, _, State.ManageChild> { state -> ManageChildHandling.processState(logic, state, updateMethod(::updateState)) },
|
||||
Case.simple<_, _, State.DiagnoseScreen.DeviceOwner> { DeviceOwnerHandling.processState(logic, scope, authenticationModelApi, state) },
|
||||
Case.simple<_, _, FragmentState> { state ->
|
||||
state.transform {
|
||||
|
|
|
@ -75,6 +75,82 @@ sealed class Screen(
|
|||
override val title = Title.StringResource(R.string.child_apps_title)
|
||||
}
|
||||
|
||||
class ManageChildAdvancedScreen(
|
||||
state: State,
|
||||
toolbarIcons: List<Menu.Icon>,
|
||||
toolbarOptions: List<Menu.Dropdown>,
|
||||
fragment: FragmentState,
|
||||
containerId: Int,
|
||||
override val backStack: List<BackStackItem>
|
||||
): FragmentScreen(state, toolbarIcons, toolbarOptions, fragment, containerId), ScreenWithBackStack, ScreenWithTitle {
|
||||
override val title = Title.StringResource(R.string.manage_child_tab_other)
|
||||
}
|
||||
|
||||
class ManageChildContactsScreen(
|
||||
state: State,
|
||||
toolbarIcons: List<Menu.Icon>,
|
||||
toolbarOptions: List<Menu.Dropdown>,
|
||||
fragment: FragmentState,
|
||||
containerId: Int,
|
||||
override val backStack: List<BackStackItem>
|
||||
): FragmentScreen(state, toolbarIcons, toolbarOptions, fragment, containerId), ScreenWithBackStack, ScreenWithTitle {
|
||||
override val title = Title.StringResource(R.string.contacts_title_long)
|
||||
}
|
||||
|
||||
class ManageChildUsageHistory(
|
||||
state: State,
|
||||
toolbarIcons: List<Menu.Icon>,
|
||||
toolbarOptions: List<Menu.Dropdown>,
|
||||
fragment: FragmentState,
|
||||
containerId: Int,
|
||||
override val backStack: List<BackStackItem>
|
||||
): FragmentScreen(state, toolbarIcons, toolbarOptions, fragment, containerId), ScreenWithBackStack, ScreenWithTitle {
|
||||
override val title = Title.StringResource(R.string.usage_history_title)
|
||||
}
|
||||
|
||||
class ManageChildUsageTasks(
|
||||
state: State,
|
||||
toolbarIcons: List<Menu.Icon>,
|
||||
toolbarOptions: List<Menu.Dropdown>,
|
||||
fragment: FragmentState,
|
||||
containerId: Int,
|
||||
override val backStack: List<BackStackItem>
|
||||
): FragmentScreen(state, toolbarIcons, toolbarOptions, fragment, containerId), ScreenWithBackStack, ScreenWithTitle {
|
||||
override val title = Title.StringResource(R.string.manage_child_tasks)
|
||||
}
|
||||
class ManageCategory(
|
||||
state: State,
|
||||
toolbarIcons: List<Menu.Icon>,
|
||||
toolbarOptions: List<Menu.Dropdown>,
|
||||
fragment: FragmentState,
|
||||
containerId: Int,
|
||||
val categoryName: String,
|
||||
override val backStack: List<BackStackItem>
|
||||
): FragmentScreen(state, toolbarIcons, toolbarOptions, fragment, containerId), ScreenWithBackStack, ScreenWithTitle {
|
||||
override val title = Title.Plain(categoryName)
|
||||
}
|
||||
class ManageCategoryAdvanced(
|
||||
state: State,
|
||||
toolbarIcons: List<Menu.Icon>,
|
||||
toolbarOptions: List<Menu.Dropdown>,
|
||||
fragment: FragmentState,
|
||||
containerId: Int,
|
||||
override val backStack: List<BackStackItem>
|
||||
): FragmentScreen(state, toolbarIcons, toolbarOptions, fragment, containerId), ScreenWithBackStack, ScreenWithTitle {
|
||||
override val title = Title.StringResource(R.string.category_settings)
|
||||
}
|
||||
|
||||
class ManageBlockedTimes(
|
||||
state: State,
|
||||
toolbarIcons: List<Menu.Icon>,
|
||||
toolbarOptions: List<Menu.Dropdown>,
|
||||
fragment: FragmentState,
|
||||
containerId: Int,
|
||||
override val backStack: List<BackStackItem>
|
||||
): FragmentScreen(state, toolbarIcons, toolbarOptions, fragment, containerId), ScreenWithBackStack, ScreenWithTitle {
|
||||
override val title = Title.StringResource(R.string.blocked_time_areas)
|
||||
}
|
||||
|
||||
class DeviceOwnerScreen(
|
||||
state: State,
|
||||
val content: DeviceOwnerHandling.OwnerScreen,
|
||||
|
|
|
@ -117,7 +117,7 @@ sealed class State (val previous: State?): Serializable {
|
|||
|
||||
sealed class Sub(
|
||||
previous: State,
|
||||
previousMain: Main,
|
||||
val previousMain: Main,
|
||||
fragmentClass: Class<out Fragment>
|
||||
): ManageChild(previous, fragmentClass, previousMain.childId, previousMain.previousOverview)
|
||||
|
||||
|
@ -139,11 +139,16 @@ sealed class State (val previous: State?): Serializable {
|
|||
override val arguments: Bundle = ChildTasksFragmentWrapperArgs(previousChild.childId).toBundle()
|
||||
}
|
||||
|
||||
sealed class ManageCategory(previous: State, val previousChild: ManageChild.Main, fragmentClass: Class<out Fragment>): Sub(previous, previousChild, fragmentClass) {
|
||||
sealed class ManageCategory(
|
||||
previous: State,
|
||||
val previousChild: ManageChild.Main,
|
||||
val categoryId: String,
|
||||
fragmentClass: Class<out Fragment>
|
||||
): Sub(previous, previousChild, fragmentClass) {
|
||||
class Main(
|
||||
previousChild: ManageChild.Main,
|
||||
val categoryId: String
|
||||
): ManageCategory(previousChild, previousChild, ManageCategoryFragment::class.java) {
|
||||
categoryId: String
|
||||
): ManageCategory(previousChild, previousChild, categoryId, ManageCategoryFragment::class.java) {
|
||||
@Transient
|
||||
override val arguments: Bundle = ManageCategoryFragmentArgs(
|
||||
childId = previousChild.childId,
|
||||
|
@ -158,8 +163,10 @@ sealed class State (val previous: State?): Serializable {
|
|||
}
|
||||
|
||||
sealed class Sub(
|
||||
previous: State, previousMain: Main, fragmentClass: Class<out Fragment>
|
||||
): ManageCategory(previous, previousMain.previousChild, fragmentClass)
|
||||
previous: State,
|
||||
val previousCategory: Main,
|
||||
fragmentClass: Class<out Fragment>
|
||||
): ManageCategory(previous, previousCategory.previousChild, previousCategory.categoryId, fragmentClass)
|
||||
|
||||
class BlockedTimes(
|
||||
previousCategory: Main
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2023 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package io.timelimit.android.ui.model.managechild
|
||||
|
||||
import io.timelimit.android.R
|
||||
import io.timelimit.android.data.model.Category
|
||||
import io.timelimit.android.logic.AppLogic
|
||||
import io.timelimit.android.ui.model.BackStackItem
|
||||
import io.timelimit.android.ui.model.Screen
|
||||
import io.timelimit.android.ui.model.State
|
||||
import io.timelimit.android.ui.model.Title
|
||||
import io.timelimit.android.ui.model.flow.Case
|
||||
import io.timelimit.android.ui.model.flow.splitConflated
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
object ManageCategoryHandling {
|
||||
fun processState(
|
||||
logic: AppLogic,
|
||||
stateLive: Flow<State.ManageChild.ManageCategory>,
|
||||
parentBackStackLive: Flow<List<BackStackItem>>,
|
||||
updateState: ((State.ManageChild.ManageCategory) -> State) -> Unit
|
||||
): Flow<Screen> = stateLive.splitConflated(
|
||||
Case.withKey<_, _, State.ManageChild.ManageCategory, _>(
|
||||
withKey = { Pair(it.childId, it.categoryId) },
|
||||
producer = { (childId, categoryId), state ->
|
||||
val categoryLive = logic.database.category().getCategoryByIdFlow(categoryId)
|
||||
|
||||
val hasCategoryLive = categoryLive.map { it?.childId == childId }.distinctUntilChanged()
|
||||
val foundCategoryLive = categoryLive.filterNotNull()
|
||||
|
||||
hasCategoryLive.transformLatest { hasCategory ->
|
||||
if (hasCategory) emitAll(
|
||||
state.splitConflated(
|
||||
Case.simple<_, _, State.ManageChild.ManageCategory.Main> { processMainState(it, parentBackStackLive, foundCategoryLive) },
|
||||
Case.simple<_, _, State.ManageChild.ManageCategory.Sub> { processSubState(share(it), parentBackStackLive, foundCategoryLive, updateMethod(updateState)) },
|
||||
)
|
||||
)
|
||||
else updateState { it.previousChild }
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
private fun processMainState(
|
||||
stateLive: Flow<State.ManageChild.ManageCategory.Main>,
|
||||
parentBackStackLive: Flow<List<BackStackItem>>,
|
||||
categoryLive: Flow<Category>
|
||||
): Flow<Screen> = combine(stateLive, categoryLive, parentBackStackLive) { state, category, backStack ->
|
||||
Screen.ManageCategory(
|
||||
state,
|
||||
state.toolbarIcons,
|
||||
state.toolbarOptions,
|
||||
state,
|
||||
R.id.fragment_manage_category,
|
||||
category.title,
|
||||
backStack
|
||||
)
|
||||
}
|
||||
|
||||
private fun processSubState(
|
||||
stateLive: SharedFlow<State.ManageChild.ManageCategory.Sub>,
|
||||
parentBackStackLive: Flow<List<BackStackItem>>,
|
||||
categoryLive: Flow<Category>,
|
||||
updateState: ((State.ManageChild.ManageCategory.Sub) -> State) -> Unit
|
||||
): Flow<Screen> {
|
||||
val subBackStackLive = combine(stateLive, parentBackStackLive, categoryLive) { state, baseBackStack, category ->
|
||||
baseBackStack + BackStackItem(Title.Plain(category.title)) { updateState { state.previousCategory } }
|
||||
}
|
||||
|
||||
return stateLive.splitConflated(
|
||||
Case.simple<_, _, State.ManageChild.ManageCategory.Advanced> { processAdvancedState(it, subBackStackLive) },
|
||||
Case.simple<_, _, State.ManageChild.ManageCategory.BlockedTimes> { processBlockedTimesState(it, subBackStackLive) },
|
||||
)
|
||||
}
|
||||
|
||||
private fun processAdvancedState(
|
||||
stateLive: Flow<State.ManageChild.ManageCategory.Advanced>,
|
||||
parentBackStackLive: Flow<List<BackStackItem>>
|
||||
): Flow<Screen> = combine(stateLive, parentBackStackLive) { state, backStack ->
|
||||
Screen.ManageCategoryAdvanced(
|
||||
state,
|
||||
state.toolbarIcons,
|
||||
state.toolbarOptions,
|
||||
state,
|
||||
R.id.fragment_manage_category_advanced,
|
||||
backStack
|
||||
)
|
||||
}
|
||||
|
||||
private fun processBlockedTimesState(
|
||||
stateLive: Flow<State.ManageChild.ManageCategory.BlockedTimes>,
|
||||
parentBackStackLive: Flow<List<BackStackItem>>
|
||||
): Flow<Screen> = combine(stateLive, parentBackStackLive) { state, backStack ->
|
||||
Screen.ManageBlockedTimes(
|
||||
state,
|
||||
state.toolbarIcons,
|
||||
state.toolbarOptions,
|
||||
state,
|
||||
R.id.fragment_manage_category_blocked_times,
|
||||
backStack
|
||||
)
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ package io.timelimit.android.ui.model.managechild
|
|||
|
||||
import io.timelimit.android.R
|
||||
import io.timelimit.android.data.model.User
|
||||
import io.timelimit.android.data.model.UserType
|
||||
import io.timelimit.android.logic.AppLogic
|
||||
import io.timelimit.android.ui.model.BackStackItem
|
||||
import io.timelimit.android.ui.model.Screen
|
||||
|
@ -38,7 +39,7 @@ object ManageChildHandling {
|
|||
val state3 = share(state2)
|
||||
val userLive = logic.database.user().getUserByIdFlow(childId)
|
||||
|
||||
val hasUserLive = userLive.map { it != null }.distinctUntilChanged()
|
||||
val hasUserLive = userLive.map { it?.type == UserType.Child }.distinctUntilChanged()
|
||||
val foundUserLive = userLive.filterNotNull()
|
||||
|
||||
val baseBackStackLive = state3.map { state ->
|
||||
|
@ -52,7 +53,7 @@ object ManageChildHandling {
|
|||
hasUserLive.transformLatest { hasUser ->
|
||||
if (hasUser) emitAll(state3.splitConflated(
|
||||
Case.simple<_, _, State.ManageChild.Main> { processMainState(it, baseBackStackLive, foundUserLive) },
|
||||
Case.simple<_, _, State.ManageChild.Apps> { processAppsState(share(it), baseBackStackLive, foundUserLive, updateMethod(updateState)) }
|
||||
Case.simple<_, _, State.ManageChild.Sub> { processSubState(logic, share(it), baseBackStackLive, foundUserLive, updateMethod(updateState)) },
|
||||
))
|
||||
else updateState { it.previousOverview }
|
||||
}
|
||||
|
@ -76,27 +77,96 @@ object ManageChildHandling {
|
|||
)
|
||||
}
|
||||
|
||||
private fun processAppsState(
|
||||
stateLive: SharedFlow<State.ManageChild.Apps>,
|
||||
baseBackStackLive: Flow<List<BackStackItem>>,
|
||||
private fun processSubState(
|
||||
logic: AppLogic,
|
||||
stateLive: SharedFlow<State.ManageChild.Sub>,
|
||||
parentBackStackLive: Flow<List<BackStackItem>>,
|
||||
userLive: Flow<User>,
|
||||
updateState: ((State.ManageChild.Apps) -> State) -> Unit
|
||||
updateState: ((State.ManageChild.Sub) -> State) -> Unit
|
||||
): Flow<Screen> {
|
||||
val subBackStackLive = combine(stateLive, baseBackStackLive, userLive) { state, baseBackStack, user ->
|
||||
val subBackStackLive = combine(stateLive, parentBackStackLive, userLive) { state, baseBackStack, user ->
|
||||
baseBackStack + BackStackItem(
|
||||
Title.Plain(user.name)
|
||||
) { updateState { state.previousChild } }
|
||||
) { updateState { state.previousMain } }
|
||||
}
|
||||
|
||||
return stateLive.combine(subBackStackLive) { state, backStack ->
|
||||
Screen.ManageChildAppsScreen(
|
||||
state,
|
||||
state.toolbarIcons,
|
||||
state.toolbarOptions,
|
||||
state,
|
||||
R.id.fragment_manage_child_apps,
|
||||
backStack
|
||||
)
|
||||
}
|
||||
return stateLive.splitConflated(
|
||||
Case.simple<_, _, State.ManageChild.Apps> { processAppsState(it, subBackStackLive) },
|
||||
Case.simple<_, _, State.ManageChild.Advanced> { processAdvancedState(it, subBackStackLive) },
|
||||
Case.simple<_, _, State.ManageChild.Contacts> { processContactsState(it, subBackStackLive) },
|
||||
Case.simple<_, _, State.ManageChild.UsageHistory> { processUsageHistoryState(it, subBackStackLive) },
|
||||
Case.simple<_, _, State.ManageChild.Tasks> { processTasksState(it, subBackStackLive) },
|
||||
Case.simple<_, _, State.ManageChild.ManageCategory> { ManageCategoryHandling.processState(logic, it, subBackStackLive, updateMethod(updateState)) },
|
||||
)
|
||||
}
|
||||
|
||||
private fun processAppsState(
|
||||
stateLive: Flow<State.ManageChild.Apps>,
|
||||
parentBackStackLive: Flow<List<BackStackItem>>
|
||||
): Flow<Screen> = stateLive.combine(parentBackStackLive) { state, backStack ->
|
||||
Screen.ManageChildAppsScreen(
|
||||
state,
|
||||
state.toolbarIcons,
|
||||
state.toolbarOptions,
|
||||
state,
|
||||
R.id.fragment_manage_child_apps,
|
||||
backStack
|
||||
)
|
||||
}
|
||||
|
||||
private fun processAdvancedState(
|
||||
stateLive: Flow<State.ManageChild.Advanced>,
|
||||
parentBackStackLive: Flow<List<BackStackItem>>
|
||||
): Flow<Screen> = stateLive.combine(parentBackStackLive) { state, backStack ->
|
||||
Screen.ManageChildAdvancedScreen(
|
||||
state,
|
||||
state.toolbarIcons,
|
||||
state.toolbarOptions,
|
||||
state,
|
||||
R.id.fragment_manage_child_advanced,
|
||||
backStack
|
||||
)
|
||||
}
|
||||
|
||||
private fun processContactsState(
|
||||
stateLive: Flow<State.ManageChild.Contacts>,
|
||||
parentBackStackLive: Flow<List<BackStackItem>>
|
||||
): Flow<Screen> = stateLive.combine(parentBackStackLive) { state, backStack ->
|
||||
Screen.ManageChildContactsScreen(
|
||||
state,
|
||||
state.toolbarIcons,
|
||||
state.toolbarOptions,
|
||||
state,
|
||||
R.id.fragment_manage_child_contacts,
|
||||
backStack
|
||||
)
|
||||
}
|
||||
|
||||
private fun processUsageHistoryState(
|
||||
stateLive: Flow<State.ManageChild.UsageHistory>,
|
||||
parentBackStackLive: Flow<List<BackStackItem>>
|
||||
): Flow<Screen> = stateLive.combine(parentBackStackLive) { state, backStack ->
|
||||
Screen.ManageChildUsageHistory(
|
||||
state,
|
||||
state.toolbarIcons,
|
||||
state.toolbarOptions,
|
||||
state,
|
||||
R.id.fragment_manage_child_usage_history,
|
||||
backStack
|
||||
)
|
||||
}
|
||||
|
||||
private fun processTasksState(
|
||||
stateLive: Flow<State.ManageChild.Tasks>,
|
||||
parentBackStackLive: Flow<List<BackStackItem>>
|
||||
): Flow<Screen> = stateLive.combine(parentBackStackLive) { state, backStack ->
|
||||
Screen.ManageChildUsageTasks(
|
||||
state,
|
||||
state.toolbarIcons,
|
||||
state.toolbarOptions,
|
||||
state,
|
||||
R.id.fragment_manage_child_tasks,
|
||||
backStack
|
||||
)
|
||||
}
|
||||
}
|
|
@ -32,4 +32,11 @@
|
|||
<item name="fragment_16" type="id" />
|
||||
<item name="fragment_manage_child" type="id" />
|
||||
<item name="fragment_manage_child_apps" type="id" />
|
||||
<item name="fragment_manage_child_advanced" type="id" />
|
||||
<item name="fragment_manage_child_contacts" type="id" />
|
||||
<item name="fragment_manage_child_usage_history" type="id" />
|
||||
<item name="fragment_manage_child_tasks" type="id" />
|
||||
<item name="fragment_manage_category" type="id" />
|
||||
<item name="fragment_manage_category_advanced" type="id" />
|
||||
<item name="fragment_manage_category_blocked_times" type="id" />
|
||||
</resources>
|
Loading…
Add table
Add a link
Reference in a new issue