M12e: contract pass (pair invite kind, admin name in invite links, sync failed flag, rejection actor, device version name, template id, update check result, untouched accounts, D-027 re-stamp, PushEvent in :core:model, snackbar hosts)
Server: E-3 invite_kind; E-12 link ?from=<admin name>, E-4 passes it into kvitt://invite; X-Kvitt-App-Version-Name stored in devices.app_version_name (migration 0003, schema 3); OpenAPI and examples follow. Phone: :core:model, :core:fakes, :data, features and :app updated together; goldens re-recorded for S-20 (version name) and new S-1/S-22 states. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
This commit is contained in:
+9
-2
@@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
@@ -51,16 +52,20 @@ import se.hagstedt.kvitt.design.theme.KvittDimens
|
||||
import se.hagstedt.kvitt.model.ExpenseId
|
||||
import se.hagstedt.kvitt.core.design.R as DesignR
|
||||
|
||||
/** S-12 Analytics drill-down (design-spec S-12, AC-14.8). [onOpenExpense] opens S-8. */
|
||||
/**
|
||||
* S-12 Analytics drill-down (design-spec S-12, AC-14.8). [onOpenExpense] opens S-8. [snackbarHostState] is hosted in
|
||||
* this screen's scaffold ("Utgiften togs bort" after deleting an expense opened from here, D-071).
|
||||
*/
|
||||
@Composable
|
||||
fun DrillDownScreen(
|
||||
onOpenExpense: (ExpenseId) -> Unit,
|
||||
onBack: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
||||
viewModel: DrillDownViewModel = hiltViewModel(),
|
||||
) {
|
||||
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||
DrillDownScreen(state, onOpenExpense, onBack, modifier)
|
||||
DrillDownScreen(state, onOpenExpense, onBack, modifier, snackbarHostState = snackbarHostState)
|
||||
}
|
||||
|
||||
/** The stateless S-12 that previews and screenshot tests render. */
|
||||
@@ -71,11 +76,13 @@ fun DrillDownScreen(
|
||||
onBack: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
scrollState: ScrollState = rememberScrollState(),
|
||||
snackbarHostState: SnackbarHostState? = null,
|
||||
) {
|
||||
val title = drillDownTitle(state)
|
||||
val scrolled by remember(scrollState) { derivedStateOf { scrollState.value > 0 } }
|
||||
KvittScaffold(
|
||||
modifier.fillMaxSize(),
|
||||
snackbarHostState = snackbarHostState,
|
||||
topBar = { KvittTopAppBar(title, navigation = TopBarNavigation.Back, onNavigation = onBack, scrolled = scrolled) },
|
||||
) { padding ->
|
||||
Column(
|
||||
|
||||
+2
-2
@@ -70,8 +70,8 @@ class AnalyticsRulesTest {
|
||||
|
||||
@Test
|
||||
fun loadingOnlyBeforeTheFirstSync() {
|
||||
assertTrue(AnalyticsRules.isFirstSync(SyncSummary(null, 0, 0, clockSkew = false, running = true)))
|
||||
assertFalse(AnalyticsRules.isFirstSync(SyncSummary("2026-10-17T06:00:00.000Z", 3, 0, clockSkew = false, running = false)))
|
||||
assertTrue(AnalyticsRules.isFirstSync(SyncSummary(null, 0, 0, clockSkew = false, running = true, lastAttemptFailed = false)))
|
||||
assertFalse(AnalyticsRules.isFirstSync(SyncSummary("2026-10-17T06:00:00.000Z", 3, 0, clockSkew = false, running = false, lastAttemptFailed = false)))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user