mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-03 09:49:25 +02:00
Refactor OverviewScreen
This commit is contained in:
parent
6b9aebbeaf
commit
2971e3f55d
8 changed files with 315 additions and 242 deletions
|
@ -32,7 +32,7 @@ fun ScreenMultiplexer(
|
||||||
) {
|
) {
|
||||||
when (screen) {
|
when (screen) {
|
||||||
null -> {/* nothing to do */ }
|
null -> {/* nothing to do */ }
|
||||||
is Screen.OverviewScreen -> OverviewScreen(screen.content, executeCommand, modifier = modifier)
|
is Screen.OverviewScreen -> OverviewScreen(screen.content, modifier = modifier)
|
||||||
is Screen.FragmentScreen -> FragmentScreen(screen, fragmentManager, fragmentIds, modifier = modifier)
|
is Screen.FragmentScreen -> FragmentScreen(screen, fragmentManager, fragmentIds, modifier = modifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,11 +16,9 @@
|
||||||
package io.timelimit.android.ui.model
|
package io.timelimit.android.ui.model
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.util.Log
|
|
||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import androidx.lifecycle.asFlow
|
import androidx.lifecycle.asFlow
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import io.timelimit.android.BuildConfig
|
|
||||||
import io.timelimit.android.data.model.UserType
|
import io.timelimit.android.data.model.UserType
|
||||||
import io.timelimit.android.logic.DefaultAppLogic
|
import io.timelimit.android.logic.DefaultAppLogic
|
||||||
import io.timelimit.android.ui.main.ActivityViewModel
|
import io.timelimit.android.ui.main.ActivityViewModel
|
||||||
|
@ -34,10 +32,6 @@ import kotlinx.coroutines.channels.ReceiveChannel
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
|
|
||||||
class MainModel(application: Application): AndroidViewModel(application) {
|
class MainModel(application: Application): AndroidViewModel(application) {
|
||||||
companion object {
|
|
||||||
private const val LOG_TAG = "MainModel"
|
|
||||||
}
|
|
||||||
|
|
||||||
val activityModel = ActivityViewModel(application)
|
val activityModel = ActivityViewModel(application)
|
||||||
|
|
||||||
private val logic = DefaultAppLogic.with(application)
|
private val logic = DefaultAppLogic.with(application)
|
||||||
|
@ -109,13 +103,7 @@ class MainModel(application: Application): AndroidViewModel(application) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun execute(command: UpdateStateCommand) {
|
fun execute(command: UpdateStateCommand) {
|
||||||
state.update { oldState ->
|
command.applyTo(state)
|
||||||
command.transform(oldState) ?: oldState.also {
|
|
||||||
if (BuildConfig.DEBUG) {
|
|
||||||
Log.d(LOG_TAG, "execute($command) did not transform state")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reportAuthenticationScreenClosed() {
|
fun reportAuthenticationScreenClosed() {
|
||||||
|
|
|
@ -15,11 +15,29 @@
|
||||||
*/
|
*/
|
||||||
package io.timelimit.android.ui.model
|
package io.timelimit.android.ui.model
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import io.timelimit.android.BuildConfig
|
||||||
import io.timelimit.android.ui.model.main.OverviewHandling
|
import io.timelimit.android.ui.model.main.OverviewHandling
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
|
|
||||||
sealed class UpdateStateCommand {
|
sealed class UpdateStateCommand {
|
||||||
|
companion object {
|
||||||
|
private const val LOG_TAG = "UpdateStateCommand"
|
||||||
|
}
|
||||||
|
|
||||||
abstract fun transform(state: State): State?
|
abstract fun transform(state: State): State?
|
||||||
|
|
||||||
|
fun applyTo(state: MutableStateFlow<State>) {
|
||||||
|
state.update { oldState ->
|
||||||
|
transform(oldState) ?: oldState.also {
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
Log.d(LOG_TAG, "$this.transform() did not transform state")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object Reset: UpdateStateCommand() {
|
object Reset: UpdateStateCommand() {
|
||||||
override fun transform(state: State) = State.LaunchState
|
override fun transform(state: State) = State.LaunchState
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,6 @@ import kotlinx.coroutines.channels.SendChannel
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
object OverviewHandling {
|
object OverviewHandling {
|
||||||
fun processState(
|
fun processState(
|
||||||
|
@ -104,6 +103,11 @@ object OverviewHandling {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
addUser = {
|
||||||
|
launch {
|
||||||
|
UpdateStateCommand.Overview.AddUser.applyTo(stateLive)
|
||||||
|
}
|
||||||
|
},
|
||||||
skipTaskReview = { task ->
|
skipTaskReview = { task ->
|
||||||
launch {
|
launch {
|
||||||
lock.tryWithLock {
|
lock.tryWithLock {
|
||||||
|
@ -176,16 +180,30 @@ object OverviewHandling {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stateLive.update { state ->
|
UpdateStateCommand.Overview.ManageChild(user.id).applyTo(stateLive)
|
||||||
if (state is State.Overview) State.ManageChild.Main(state, user.id, fromRedirect = false)
|
}
|
||||||
else state
|
UserType.Parent -> UpdateStateCommand.Overview.ManageParent(user.id).applyTo(stateLive)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UserType.Parent -> stateLive.update { state ->
|
},
|
||||||
if (state is State.Overview) State.ManageParent.Main(state, user.id)
|
openDevice = { device ->
|
||||||
else state
|
launch {
|
||||||
|
UpdateStateCommand.Overview.ManageDevice(device.device.id).applyTo(stateLive)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
setupDevice = {
|
||||||
|
launch {
|
||||||
|
UpdateStateCommand.Overview.SetupDevice.applyTo(stateLive)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
showMoreDevices = {
|
||||||
|
launch {
|
||||||
|
UpdateStateCommand.Overview.ShowMoreDevices(it).applyTo(stateLive)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showMoreUsers = {
|
||||||
|
launch {
|
||||||
|
UpdateStateCommand.Overview.ShowAllUsers.applyTo(stateLive)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -367,10 +385,15 @@ object OverviewHandling {
|
||||||
data class Actions(
|
data class Actions(
|
||||||
val hideIntro: () -> Unit,
|
val hideIntro: () -> Unit,
|
||||||
val addDevice: () -> Unit,
|
val addDevice: () -> Unit,
|
||||||
|
val addUser: () -> Unit,
|
||||||
val skipTaskReview: (TaskToReview) -> Unit,
|
val skipTaskReview: (TaskToReview) -> Unit,
|
||||||
val reviewReject: (TaskToReview) -> Unit,
|
val reviewReject: (TaskToReview) -> Unit,
|
||||||
val reviewAccept: (TaskToReview) -> Unit,
|
val reviewAccept: (TaskToReview) -> Unit,
|
||||||
val openUser: (UserItem) -> Unit
|
val openUser: (UserItem) -> Unit,
|
||||||
|
val openDevice: (DeviceItem) -> Unit,
|
||||||
|
val setupDevice: () -> Unit,
|
||||||
|
val showMoreDevices: (OverviewState.DeviceList) -> Unit,
|
||||||
|
val showMoreUsers: () -> Unit
|
||||||
)
|
)
|
||||||
data class IntroFlags(
|
data class IntroFlags(
|
||||||
val showSetupOption: Boolean,
|
val showSetupOption: Boolean,
|
||||||
|
|
|
@ -19,6 +19,8 @@ import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyItemScope
|
import androidx.compose.foundation.lazy.LazyItemScope
|
||||||
|
import androidx.compose.foundation.lazy.LazyListScope
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.*
|
import androidx.compose.material.icons.filled.*
|
||||||
|
@ -28,24 +30,50 @@ import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import io.timelimit.android.BuildConfig
|
import io.timelimit.android.BuildConfig
|
||||||
import io.timelimit.android.R
|
import io.timelimit.android.R
|
||||||
import io.timelimit.android.ui.model.UpdateStateCommand
|
|
||||||
import io.timelimit.android.ui.model.main.OverviewHandling
|
import io.timelimit.android.ui.model.main.OverviewHandling
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
fun LazyListScope.deviceItems(screen: OverviewHandling.OverviewScreen) {
|
||||||
|
item (key = Pair("devices", "header")) {
|
||||||
|
ListCommon.SectionHeader(stringResource(R.string.overview_header_devices), Modifier.animateItemPlacement())
|
||||||
|
}
|
||||||
|
|
||||||
|
items(screen.devices.list, key = { Pair("device", it.device.id) }) {
|
||||||
|
DeviceItem(it, screen.actions.openDevice)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (screen.devices.canAdd) {
|
||||||
|
item (key = Pair("devices", "add")) {
|
||||||
|
ListCommon.ActionListItem(
|
||||||
|
icon = Icons.Default.Add,
|
||||||
|
label = stringResource(R.string.add_device),
|
||||||
|
action = screen.actions.addDevice,
|
||||||
|
modifier = Modifier.animateItemPlacement()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (screen.devices.canShowMore != null) {
|
||||||
|
item (key = Pair("devices", "more")) {
|
||||||
|
ListCommon.ShowMoreItem(
|
||||||
|
modifier = Modifier.animateItemPlacement(),
|
||||||
|
action = { screen.actions.showMoreDevices(screen.devices.canShowMore) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun LazyItemScope.DeviceItem(
|
fun LazyItemScope.DeviceItem(
|
||||||
item: OverviewHandling.DeviceItem,
|
item: OverviewHandling.DeviceItem,
|
||||||
executeCommand: (UpdateStateCommand) -> Unit
|
openAction: (OverviewHandling.DeviceItem) -> Unit
|
||||||
) {
|
) {
|
||||||
ListCardCommon.Card(
|
ListCardCommon.Card(
|
||||||
Modifier
|
Modifier
|
||||||
.animateItemPlacement()
|
.animateItemPlacement()
|
||||||
.padding(horizontal = 8.dp)
|
.padding(horizontal = 8.dp)
|
||||||
.clickable(
|
.clickable(onClick = { openAction(item) })
|
||||||
onClick = {
|
|
||||||
executeCommand(UpdateStateCommand.Overview.ManageDevice(item.device.id))
|
|
||||||
}
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
ListCardCommon.TextWithIcon(
|
ListCardCommon.TextWithIcon(
|
||||||
icon = Icons.Default.Smartphone,
|
icon = Icons.Default.Smartphone,
|
||||||
|
|
|
@ -0,0 +1,196 @@
|
||||||
|
/*
|
||||||
|
* 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.overview.overview
|
||||||
|
|
||||||
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.lazy.LazyListScope
|
||||||
|
import androidx.compose.material.*
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.timelimit.android.R
|
||||||
|
import io.timelimit.android.ui.model.main.OverviewHandling
|
||||||
|
import io.timelimit.android.ui.util.DateUtil
|
||||||
|
import io.timelimit.android.util.TimeTextUtil
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class)
|
||||||
|
fun LazyListScope.introItems(
|
||||||
|
screen: OverviewHandling.OverviewScreen,
|
||||||
|
) {
|
||||||
|
if (screen.intro.showSetupOption) {
|
||||||
|
item (key = Pair("intro", "finish setup")) {
|
||||||
|
ListCardCommon.Card(
|
||||||
|
modifier = Modifier
|
||||||
|
.animateItemPlacement()
|
||||||
|
.padding(horizontal = 8.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.overview_finish_setup_title),
|
||||||
|
style = MaterialTheme.typography.h6
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(stringResource(R.string.overview_finish_setup_text))
|
||||||
|
|
||||||
|
ListCardCommon.ActionButton(
|
||||||
|
label = stringResource(R.string.generic_go),
|
||||||
|
action = screen.actions.setupDevice
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (screen.intro.showOutdatedServer) {
|
||||||
|
item (key = Pair("intro", "outdated server")) {
|
||||||
|
ListCardCommon.Card(
|
||||||
|
modifier = Modifier
|
||||||
|
.animateItemPlacement()
|
||||||
|
.padding(horizontal = 8.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.overview_server_outdated_title),
|
||||||
|
style = MaterialTheme.typography.h6
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(stringResource(R.string.overview_server_outdated_text))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (screen.intro.showServerMessage != null) {
|
||||||
|
item (key = Pair("intro", "server message")) {
|
||||||
|
ListCardCommon.Card(
|
||||||
|
modifier = Modifier
|
||||||
|
.animateItemPlacement()
|
||||||
|
.padding(horizontal = 8.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.overview_server_message),
|
||||||
|
style = MaterialTheme.typography.h6
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(screen.intro.showServerMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (screen.intro.showIntro) {
|
||||||
|
item (key = Pair("intro", "intro")) {
|
||||||
|
val state = remember {
|
||||||
|
DismissState(
|
||||||
|
initialValue = DismissValue.Default,
|
||||||
|
confirmStateChange = {
|
||||||
|
screen.actions.hideIntro()
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
SwipeToDismiss(
|
||||||
|
state = state,
|
||||||
|
background = {},
|
||||||
|
modifier = Modifier.animateItemPlacement()
|
||||||
|
) {
|
||||||
|
ListCardCommon.Card(
|
||||||
|
modifier = Modifier.padding(horizontal = 8.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.overview_intro_title),
|
||||||
|
style = MaterialTheme.typography.h6
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(stringResource(R.string.overview_intro_text))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.generic_swipe_to_dismiss),
|
||||||
|
style = MaterialTheme.typography.subtitle1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (screen.taskToReview != null) {
|
||||||
|
item (key = Pair("intro", "task review")) {
|
||||||
|
ListCardCommon.Card(
|
||||||
|
modifier = Modifier
|
||||||
|
.animateItemPlacement()
|
||||||
|
.padding(horizontal = 8.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.task_review_title),
|
||||||
|
style = MaterialTheme.typography.h6
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.task_review_text, screen.taskToReview.task.childName, screen.taskToReview.task.childTask.taskTitle)
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
stringResource(
|
||||||
|
R.string.task_review_category,
|
||||||
|
TimeTextUtil.time(screen.taskToReview.task.childTask.extraTimeDuration, LocalContext.current),
|
||||||
|
screen.taskToReview.task.categoryTitle
|
||||||
|
),
|
||||||
|
style = MaterialTheme.typography.subtitle1
|
||||||
|
)
|
||||||
|
|
||||||
|
screen.taskToReview.task.childTask.lastGrantTimestamp.let { lastGrantTimestamp ->
|
||||||
|
if (lastGrantTimestamp != 0L) {
|
||||||
|
Text(
|
||||||
|
stringResource(
|
||||||
|
R.string.task_review_last_grant,
|
||||||
|
DateUtil.formatAbsoluteDate(LocalContext.current, lastGrantTimestamp)
|
||||||
|
),
|
||||||
|
style = MaterialTheme.typography.subtitle1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
TextButton(onClick = {
|
||||||
|
screen.actions.skipTaskReview(screen.taskToReview)
|
||||||
|
}) {
|
||||||
|
Text(stringResource(R.string.generic_skip))
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(Modifier.weight(1.0f))
|
||||||
|
|
||||||
|
OutlinedButton(onClick = { screen.actions.reviewReject(screen.taskToReview) }) {
|
||||||
|
Text(stringResource(R.string.generic_no))
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(Modifier.width(8.dp))
|
||||||
|
|
||||||
|
OutlinedButton(onClick = { screen.actions.reviewAccept(screen.taskToReview) }) {
|
||||||
|
Text(stringResource(R.string.generic_yes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.purchase_required_info_local_mode_free),
|
||||||
|
style = MaterialTheme.typography.subtitle1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,30 +15,16 @@
|
||||||
*/
|
*/
|
||||||
package io.timelimit.android.ui.overview.overview
|
package io.timelimit.android.ui.overview.overview
|
||||||
|
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
|
||||||
import androidx.compose.material.*
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.filled.*
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import io.timelimit.android.R
|
|
||||||
import io.timelimit.android.ui.model.UpdateStateCommand
|
|
||||||
import io.timelimit.android.ui.model.main.OverviewHandling
|
import io.timelimit.android.ui.model.main.OverviewHandling
|
||||||
import io.timelimit.android.ui.util.DateUtil
|
|
||||||
import io.timelimit.android.util.TimeTextUtil
|
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
fun OverviewScreen(
|
fun OverviewScreen(
|
||||||
screen: OverviewHandling.OverviewScreen,
|
screen: OverviewHandling.OverviewScreen,
|
||||||
executeCommand: (UpdateStateCommand) -> Unit,
|
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
LazyColumn (
|
LazyColumn (
|
||||||
|
@ -46,198 +32,8 @@ fun OverviewScreen(
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
) {
|
) {
|
||||||
if (screen.intro.showSetupOption) {
|
introItems(screen)
|
||||||
item (key = Pair("intro", "finish setup")) {
|
deviceItems(screen)
|
||||||
ListCardCommon.Card(
|
userItems(screen)
|
||||||
modifier = Modifier
|
|
||||||
.animateItemPlacement()
|
|
||||||
.padding(horizontal = 8.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
stringResource(R.string.overview_finish_setup_title),
|
|
||||||
style = MaterialTheme.typography.h6
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(stringResource(R.string.overview_finish_setup_text))
|
|
||||||
|
|
||||||
ListCardCommon.ActionButton(
|
|
||||||
label = stringResource(R.string.generic_go),
|
|
||||||
action = {
|
|
||||||
executeCommand(UpdateStateCommand.Overview.SetupDevice)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (screen.intro.showOutdatedServer) {
|
|
||||||
item (key = Pair("intro", "outdated server")) {
|
|
||||||
ListCardCommon.Card(
|
|
||||||
modifier = Modifier
|
|
||||||
.animateItemPlacement()
|
|
||||||
.padding(horizontal = 8.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
stringResource(R.string.overview_server_outdated_title),
|
|
||||||
style = MaterialTheme.typography.h6
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(stringResource(R.string.overview_server_outdated_text))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (screen.intro.showServerMessage != null) {
|
|
||||||
item (key = Pair("intro", "servermessage")) {
|
|
||||||
ListCardCommon.Card(
|
|
||||||
modifier = Modifier
|
|
||||||
.animateItemPlacement()
|
|
||||||
.padding(horizontal = 8.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
stringResource(R.string.overview_server_message),
|
|
||||||
style = MaterialTheme.typography.h6
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(screen.intro.showServerMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (screen.intro.showIntro) {
|
|
||||||
item (key = Pair("intro", "intro")) {
|
|
||||||
val state = remember {
|
|
||||||
DismissState(
|
|
||||||
initialValue = DismissValue.Default,
|
|
||||||
confirmStateChange = {
|
|
||||||
screen.actions.hideIntro()
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
SwipeToDismiss(
|
|
||||||
state = state,
|
|
||||||
background = {},
|
|
||||||
modifier = Modifier.animateItemPlacement()
|
|
||||||
) {
|
|
||||||
ListCardCommon.Card(
|
|
||||||
modifier = Modifier.padding(horizontal = 8.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
stringResource(R.string.overview_intro_title),
|
|
||||||
style = MaterialTheme.typography.h6
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(stringResource(R.string.overview_intro_text))
|
|
||||||
|
|
||||||
Text(
|
|
||||||
stringResource(R.string.generic_swipe_to_dismiss),
|
|
||||||
style = MaterialTheme.typography.subtitle1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (screen.taskToReview != null) {
|
|
||||||
item (key = Pair("task", "review")) {
|
|
||||||
ListCardCommon.Card(
|
|
||||||
modifier = Modifier
|
|
||||||
.animateItemPlacement()
|
|
||||||
.padding(horizontal = 8.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
stringResource(R.string.task_review_title),
|
|
||||||
style = MaterialTheme.typography.h6
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(
|
|
||||||
stringResource(R.string.task_review_text, screen.taskToReview.task.childName, screen.taskToReview.task.childTask.taskTitle)
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(
|
|
||||||
stringResource(
|
|
||||||
R.string.task_review_category,
|
|
||||||
TimeTextUtil.time(screen.taskToReview.task.childTask.extraTimeDuration, LocalContext.current),
|
|
||||||
screen.taskToReview.task.categoryTitle
|
|
||||||
),
|
|
||||||
style = MaterialTheme.typography.subtitle1
|
|
||||||
)
|
|
||||||
|
|
||||||
screen.taskToReview.task.childTask.lastGrantTimestamp.let { lastGrantTimestamp ->
|
|
||||||
if (lastGrantTimestamp != 0L) {
|
|
||||||
Text(
|
|
||||||
stringResource(
|
|
||||||
R.string.task_review_last_grant,
|
|
||||||
DateUtil.formatAbsoluteDate(LocalContext.current, lastGrantTimestamp)
|
|
||||||
),
|
|
||||||
style = MaterialTheme.typography.subtitle1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
TextButton(onClick = {
|
|
||||||
screen.actions.skipTaskReview(screen.taskToReview)
|
|
||||||
}) {
|
|
||||||
Text(stringResource(R.string.generic_skip))
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(Modifier.weight(1.0f))
|
|
||||||
|
|
||||||
OutlinedButton(onClick = { screen.actions.reviewReject(screen.taskToReview) }) {
|
|
||||||
Text(stringResource(R.string.generic_no))
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(Modifier.width(8.dp))
|
|
||||||
|
|
||||||
OutlinedButton(onClick = { screen.actions.reviewAccept(screen.taskToReview) }) {
|
|
||||||
Text(stringResource(R.string.generic_yes))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(
|
|
||||||
stringResource(R.string.purchase_required_info_local_mode_free),
|
|
||||||
style = MaterialTheme.typography.subtitle1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
item (key = Pair("devices", "header")) { ListCommon.SectionHeader(stringResource(R.string.overview_header_devices), Modifier.animateItemPlacement()) }
|
|
||||||
items(screen.devices.list, key = { Pair("device", it.device.id) }) {
|
|
||||||
DeviceItem(it, executeCommand)
|
|
||||||
}
|
|
||||||
if (screen.devices.canAdd) {
|
|
||||||
item (key = Pair("devices", "add")) {
|
|
||||||
ListCommon.ActionListItem(
|
|
||||||
icon = Icons.Default.Add,
|
|
||||||
label = stringResource(R.string.add_device),
|
|
||||||
action = screen.actions.addDevice,
|
|
||||||
modifier = Modifier.animateItemPlacement()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (screen.devices.canShowMore != null) {
|
|
||||||
item (key = Pair("devices", "show more")) { ListCommon.ShowMoreItem(modifier = Modifier.animateItemPlacement()) {
|
|
||||||
executeCommand(UpdateStateCommand.Overview.ShowMoreDevices(screen.devices.canShowMore))
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
item (key = Pair("header", "users")) { ListCommon.SectionHeader(stringResource(R.string.overview_header_users), Modifier.animateItemPlacement()) }
|
|
||||||
items(screen.users.list, key = { Pair("user", it.id) }) { UserItem(it, screen.actions) }
|
|
||||||
if (screen.users.canAdd) item (key = Pair("header", "user.create")) {
|
|
||||||
ListCommon.ActionListItem(
|
|
||||||
icon = Icons.Default.Add,
|
|
||||||
label = stringResource(R.string.add_user_title),
|
|
||||||
action = { executeCommand(UpdateStateCommand.Overview.AddUser) },
|
|
||||||
modifier = Modifier.animateItemPlacement()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (screen.users.canShowMore) item (key = Pair("header", "user.more")) {
|
|
||||||
ListCommon.ShowMoreItem (modifier = Modifier.animateItemPlacement()) { executeCommand(UpdateStateCommand.Overview.ShowAllUsers) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,11 @@ import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyItemScope
|
import androidx.compose.foundation.lazy.LazyItemScope
|
||||||
|
import androidx.compose.foundation.lazy.LazyListScope
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.AccountCircle
|
import androidx.compose.material.icons.filled.*
|
||||||
import androidx.compose.material.icons.filled.AlarmOff
|
|
||||||
import androidx.compose.material.icons.filled.Security
|
|
||||||
import androidx.compose.material.icons.filled.Settings
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
@ -33,6 +32,31 @@ import io.timelimit.android.R
|
||||||
import io.timelimit.android.data.model.UserType
|
import io.timelimit.android.data.model.UserType
|
||||||
import io.timelimit.android.ui.model.main.OverviewHandling
|
import io.timelimit.android.ui.model.main.OverviewHandling
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
fun LazyListScope.userItems(screen: OverviewHandling.OverviewScreen) {
|
||||||
|
item (key = Pair("users", "header")) {
|
||||||
|
ListCommon.SectionHeader(stringResource(R.string.overview_header_users), Modifier.animateItemPlacement())
|
||||||
|
}
|
||||||
|
|
||||||
|
items(screen.users.list, key = { Pair("user", it.id) }) { UserItem(it, screen.actions) }
|
||||||
|
|
||||||
|
if (screen.users.canAdd) item (key = Pair("users", "create")) {
|
||||||
|
ListCommon.ActionListItem(
|
||||||
|
icon = Icons.Default.Add,
|
||||||
|
label = stringResource(R.string.add_user_title),
|
||||||
|
action = screen.actions.addUser,
|
||||||
|
modifier = Modifier.animateItemPlacement()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (screen.users.canShowMore) item (key = Pair("users", "more")) {
|
||||||
|
ListCommon.ShowMoreItem (
|
||||||
|
modifier = Modifier.animateItemPlacement(),
|
||||||
|
action = screen.actions.showMoreUsers
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun LazyItemScope.UserItem(
|
fun LazyItemScope.UserItem(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue