feat(app): add authenticated app shell with top bar and bottom navigation #6
+6
-4
@@ -1,9 +1,11 @@
|
|||||||
package com.flagship.abox.manager.ui.login
|
package com.flagship.abox.manager.ui.login
|
||||||
|
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.compose.ui.test.assertCountEquals
|
||||||
import androidx.compose.ui.test.assertIsEnabled
|
import androidx.compose.ui.test.assertIsEnabled
|
||||||
import androidx.compose.ui.test.assertIsNotEnabled
|
import androidx.compose.ui.test.assertIsNotEnabled
|
||||||
import androidx.compose.ui.test.junit4.createAndroidComposeRule
|
import androidx.compose.ui.test.junit4.createAndroidComposeRule
|
||||||
|
import androidx.compose.ui.test.onAllNodesWithText
|
||||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||||
import androidx.compose.ui.test.onNodeWithText
|
import androidx.compose.ui.test.onNodeWithText
|
||||||
import androidx.compose.ui.test.performClick
|
import androidx.compose.ui.test.performClick
|
||||||
@@ -29,7 +31,7 @@ class LoginScreenTest {
|
|||||||
)
|
)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun backControlsSwitchProviderBeforeLogin() {
|
fun topBackControlSwitchesProviderBeforeLogin() {
|
||||||
var switches = 0
|
var switches = 0
|
||||||
composeRule.setContent {
|
composeRule.setContent {
|
||||||
ABoxTheme {
|
ABoxTheme {
|
||||||
@@ -49,8 +51,8 @@ class LoginScreenTest {
|
|||||||
composeRule.onNodeWithContentDescription("back-to-providers")
|
composeRule.onNodeWithContentDescription("back-to-providers")
|
||||||
.assertIsEnabled()
|
.assertIsEnabled()
|
||||||
.performClick()
|
.performClick()
|
||||||
composeRule.onNodeWithText("Back to providers").performClick()
|
composeRule.onAllNodesWithText("Back to providers").assertCountEquals(0)
|
||||||
assertEquals(2, switches)
|
assertEquals(1, switches)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -94,6 +96,6 @@ class LoginScreenTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
composeRule.onNodeWithContentDescription("back-to-providers").assertIsNotEnabled()
|
composeRule.onNodeWithContentDescription("back-to-providers").assertIsNotEnabled()
|
||||||
composeRule.onNodeWithText("Back to providers").assertIsNotEnabled()
|
composeRule.onAllNodesWithText("Back to providers").assertCountEquals(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ fun ABoxManagerApp(
|
|||||||
is AppSessionUiState.Authenticated -> MainAppShell(
|
is AppSessionUiState.Authenticated -> MainAppShell(
|
||||||
|
|
|||||||
userName = state.username.value,
|
userName = state.username.value,
|
||||||
providerName = state.profile.displayName,
|
providerName = state.profile.displayName,
|
||||||
onSwitchProvider = sessionActionsViewModel::switchProvider,
|
|
||||||
onLogout = sessionActionsViewModel::logout,
|
onLogout = sessionActionsViewModel::logout,
|
||||||
actionInProgress = actionState.inProgress,
|
actionInProgress = actionState.inProgress,
|
||||||
errorMessage = actionState.errorMessage,
|
errorMessage = actionState.errorMessage,
|
||||||
|
|||||||
-79
@@ -1,79 +0,0 @@
|
|||||||
package com.flagship.abox.manager.ui.authenticated
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.widthIn
|
|
||||||
import androidx.compose.foundation.rememberScrollState
|
|
||||||
import androidx.compose.foundation.verticalScroll
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Scaffold
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TopAppBar
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import com.flagship.abox.manager.R
|
|
||||||
import com.flagship.abox.manager.designsystem.ABoxButton
|
|
||||||
import com.flagship.abox.manager.domain.ProviderProfile
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
|
||||||
fun AuthenticatedPlaceholderScreen(
|
|
||||||
profile: ProviderProfile,
|
|
||||||
actionInProgress: Boolean,
|
|
||||||
errorMessage: String?,
|
|
||||||
onLogout: () -> Unit,
|
|
||||||
onSwitchProvider: () -> Unit,
|
|
||||||
) {
|
|
||||||
Scaffold(
|
|
||||||
topBar = {
|
|
||||||
TopAppBar(
|
|
||||||
title = { Text(stringResource(R.string.authenticated_title, profile.displayName)) },
|
|
||||||
)
|
|
||||||
},
|
|
||||||
) { contentPadding ->
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.padding(contentPadding),
|
|
||||||
contentAlignment = Alignment.Center,
|
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.widthIn(max = 520.dp)
|
|
||||||
.fillMaxWidth()
|
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
.padding(24.dp),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
verticalArrangement = Arrangement.spacedBy(14.dp),
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.authenticated_description),
|
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
||||||
)
|
|
||||||
errorMessage?.let { Text(it, color = MaterialTheme.colorScheme.error) }
|
|
||||||
ABoxButton(
|
|
||||||
onClick = onLogout,
|
|
||||||
enabled = !actionInProgress,
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
) {
|
|
||||||
Text(stringResource(R.string.action_logout))
|
|
||||||
}
|
|
||||||
ABoxButton(
|
|
||||||
onClick = onSwitchProvider,
|
|
||||||
enabled = !actionInProgress,
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
) {
|
|
||||||
Text(stringResource(R.string.action_switch_provider))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -184,13 +184,6 @@ fun LoginScreen(
|
|||||||
}
|
}
|
||||||
else Text(stringResource(R.string.action_login))
|
else Text(stringResource(R.string.action_login))
|
||||||
}
|
}
|
||||||
ABoxButton(
|
|
||||||
onClick = onSwitchProvider,
|
|
||||||
enabled = navigationEnabled,
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
) {
|
|
||||||
Text(stringResource(R.string.login_back_to_providers))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-18
@@ -15,7 +15,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
|||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.ExitToApp
|
import androidx.compose.material.icons.automirrored.filled.ExitToApp
|
||||||
import androidx.compose.material.icons.filled.CloudDone
|
import androidx.compose.material.icons.filled.CloudDone
|
||||||
import androidx.compose.material.icons.filled.SwapHoriz
|
|
||||||
import androidx.compose.material3.ButtonDefaults
|
import androidx.compose.material3.ButtonDefaults
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.CardDefaults
|
import androidx.compose.material3.CardDefaults
|
||||||
@@ -50,7 +49,6 @@ fun AccountProviderBottomSheet(
|
|||||||
userName: String,
|
userName: String,
|
||||||
providerName: String,
|
providerName: String,
|
||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
onSwitchProvider: () -> Unit,
|
|
||||||
onLogout: () -> Unit,
|
onLogout: () -> Unit,
|
||||||
actionInProgress: Boolean,
|
actionInProgress: Boolean,
|
||||||
errorMessage: String?,
|
errorMessage: String?,
|
||||||
@@ -146,22 +144,7 @@ fun AccountProviderBottomSheet(
|
|||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
// Action Buttons
|
// Action button
|
||||||
OutlinedButton(
|
|
||||||
onClick = onSwitchProvider,
|
|
||||||
enabled = !actionInProgress,
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
shape = RoundedCornerShape(12.dp),
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.SwapHoriz,
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier.size(20.dp),
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.size(8.dp))
|
|
||||||
Text(stringResource(R.string.account_sheet_switch_provider))
|
|
||||||
}
|
|
||||||
|
|
||||||
ABoxButton(
|
ABoxButton(
|
||||||
onClick = onLogout,
|
onClick = onLogout,
|
||||||
enabled = !actionInProgress,
|
enabled = !actionInProgress,
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ import com.flagship.abox.manager.designsystem.ABoxTopPillBar
|
|||||||
fun MainAppShell(
|
fun MainAppShell(
|
||||||
userName: String,
|
userName: String,
|
||||||
providerName: String,
|
providerName: String,
|
||||||
onSwitchProvider: () -> Unit,
|
|
||||||
onLogout: () -> Unit,
|
onLogout: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
initialTab: MainTab = MainTab.DEVICES,
|
initialTab: MainTab = MainTab.DEVICES,
|
||||||
@@ -125,7 +124,6 @@ fun MainAppShell(
|
|||||||
userName = userName,
|
userName = userName,
|
||||||
providerName = providerName,
|
providerName = providerName,
|
||||||
onDismissRequest = { showAccountSheet = false },
|
onDismissRequest = { showAccountSheet = false },
|
||||||
onSwitchProvider = onSwitchProvider,
|
|
||||||
onLogout = onLogout,
|
onLogout = onLogout,
|
||||||
actionInProgress = actionInProgress,
|
actionInProgress = actionInProgress,
|
||||||
errorMessage = errorMessage,
|
errorMessage = errorMessage,
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
<string name="provider_local_description">无需网络,通过本地模拟设备体验应用。</string>
|
<string name="provider_local_description">无需网络,通过本地模拟设备体验应用。</string>
|
||||||
<string name="login_title">登录 %1$s</string>
|
<string name="login_title">登录 %1$s</string>
|
||||||
<string name="login_provider_context">当前提供方:%1$s</string>
|
<string name="login_provider_context">当前提供方:%1$s</string>
|
||||||
<string name="login_back_to_providers">返回提供方选择</string>
|
|
||||||
<string name="login_username">用户名</string>
|
<string name="login_username">用户名</string>
|
||||||
<string name="login_password">密码</string>
|
<string name="login_password">密码</string>
|
||||||
<string name="login_remember_username">记住用户名</string>
|
<string name="login_remember_username">记住用户名</string>
|
||||||
@@ -35,7 +34,6 @@
|
|||||||
<string name="account_sheet_title">账户与提供方</string>
|
<string name="account_sheet_title">账户与提供方</string>
|
||||||
<string name="account_sheet_signed_in_as">当前登录为</string>
|
<string name="account_sheet_signed_in_as">当前登录为</string>
|
||||||
<string name="account_sheet_provider">当前提供方</string>
|
<string name="account_sheet_provider">当前提供方</string>
|
||||||
<string name="account_sheet_switch_provider">切换提供方</string>
|
|
||||||
<string name="account_sheet_logout">退出登录</string>
|
<string name="account_sheet_logout">退出登录</string>
|
||||||
<string name="account_sheet_close">关闭</string>
|
<string name="account_sheet_close">关闭</string>
|
||||||
<string name="devices_placeholder_title">设备列表</string>
|
<string name="devices_placeholder_title">设备列表</string>
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
<string name="provider_local_description">Explore the app with simulated local devices and no network connection.</string>
|
<string name="provider_local_description">Explore the app with simulated local devices and no network connection.</string>
|
||||||
<string name="login_title">Sign in to %1$s</string>
|
<string name="login_title">Sign in to %1$s</string>
|
||||||
<string name="login_provider_context">Selected provider: %1$s</string>
|
<string name="login_provider_context">Selected provider: %1$s</string>
|
||||||
<string name="login_back_to_providers">Back to providers</string>
|
|
||||||
<string name="login_username">Username</string>
|
<string name="login_username">Username</string>
|
||||||
<string name="login_password">Password</string>
|
<string name="login_password">Password</string>
|
||||||
<string name="login_remember_username">Remember username</string>
|
<string name="login_remember_username">Remember username</string>
|
||||||
@@ -35,7 +34,6 @@
|
|||||||
<string name="account_sheet_title">Account & Provider</string>
|
<string name="account_sheet_title">Account & Provider</string>
|
||||||
<string name="account_sheet_signed_in_as">Signed in as</string>
|
<string name="account_sheet_signed_in_as">Signed in as</string>
|
||||||
<string name="account_sheet_provider">Active Provider</string>
|
<string name="account_sheet_provider">Active Provider</string>
|
||||||
<string name="account_sheet_switch_provider">Switch Provider</string>
|
|
||||||
<string name="account_sheet_logout">Sign Out</string>
|
<string name="account_sheet_logout">Sign Out</string>
|
||||||
<string name="account_sheet_close">Close</string>
|
<string name="account_sheet_close">Close</string>
|
||||||
<string name="devices_placeholder_title">Device List</string>
|
<string name="devices_placeholder_title">Device List</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user
入口缺失
认证态切换到
MainAppShell后不再传递sessionActionsViewModel::switchProvider,新壳层和账户底表也没有切换入口。已登录用户只能先退出登录,原先可直接切换提供方的功能被回退,也与本 PR 描述不符。请将切换回调贯穿到壳层和底表并提供对应操作。