feat(auth): implement platform selection screen with API URL input

Add platform selection UI with PepChat and Revolt options
Implement clickable platform cards that set the API URL
Create custom styled text field for API URL input
Add confirm button with localized string resource
Fix vertical alignment of placeholder text in text field
This commit is contained in:
AbronStudio 2025-07-26 12:18:06 +03:30
parent f49b25b4e3
commit 80db00ee2a
6 changed files with 69 additions and 58 deletions

View File

@ -1,5 +1,40 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<JavaCodeStyleSettings>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="" withSubpackages="true" static="false" module="true" />
<package name="android" withSubpackages="true" static="true" />
<package name="androidx" withSubpackages="true" static="true" />
<package name="com" withSubpackages="true" static="true" />
<package name="junit" withSubpackages="true" static="true" />
<package name="net" withSubpackages="true" static="true" />
<package name="org" withSubpackages="true" static="true" />
<package name="java" withSubpackages="true" static="true" />
<package name="javax" withSubpackages="true" static="true" />
<package name="" withSubpackages="true" static="true" />
<emptyLine />
<package name="android" withSubpackages="true" static="false" />
<emptyLine />
<package name="androidx" withSubpackages="true" static="false" />
<emptyLine />
<package name="com" withSubpackages="true" static="false" />
<emptyLine />
<package name="junit" withSubpackages="true" static="false" />
<emptyLine />
<package name="net" withSubpackages="true" static="false" />
<emptyLine />
<package name="org" withSubpackages="true" static="false" />
<emptyLine />
<package name="java" withSubpackages="true" static="false" />
<emptyLine />
<package name="javax" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
<emptyLine />
</value>
</option>
</JavaCodeStyleSettings>
<JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>

View File

@ -96,6 +96,7 @@ import chat.revolt.screens.about.AboutScreen
import chat.revolt.screens.about.AttributionScreen
import chat.revolt.screens.chat.ChatRouterScreen
import chat.revolt.screens.chat.views.channel.ChannelScreen
import chat.revolt.screens.chooseplatform.ChoosePlatformScreen
import chat.revolt.screens.create.CreateGroupScreen
import chat.revolt.screens.labs.LabsRootScreen
import chat.revolt.screens.login.LoginGreetingScreen
@ -200,7 +201,7 @@ class MainActivityViewModel @Inject constructor(
Log.d("MainActivity", "We can reach Revolt, checking if we're logged in")
val token = kvStorage.get("sessionToken")
?: return@launch startWithDestination("login/greeting")
?: return@launch startWithDestination("choose-platform")
val id = kvStorage.get("sessionId") ?: ""
Log.d(
@ -563,6 +564,7 @@ fun AppEntrypoint(
)
}
composable("choose-platform") { ChoosePlatformScreen(navController) }
composable("login/greeting") { LoginGreetingScreen(navController) }
composable("login/login") { LoginScreen(navController) }
composable("login/mfa/{mfaTicket}/{allowedAuthTypes}") { backStackEntry ->

View File

@ -22,6 +22,9 @@ fun FormTextField(
type: KeyboardType = KeyboardType.Text,
action: ImeAction = ImeAction.Done,
supportingText: @Composable (() -> Unit)? = null,
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
placeholder: @Composable (() -> Unit)? = null,
singleLine: Boolean = true,
enabled: Boolean = true
) {
@ -29,11 +32,14 @@ fun FormTextField(
value = value,
onValueChange = onChange,
singleLine = singleLine,
placeholder = placeholder,
keyboardOptions = KeyboardOptions(keyboardType = type, imeAction = action),
visualTransformation = if (type == KeyboardType.Password) PasswordVisualTransformation() else VisualTransformation.None,
label = { Text(label) },
supportingText = supportingText,
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
enabled = enabled,
modifier = modifier
)
}
}

View File

@ -14,16 +14,13 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Button
import androidx.compose.material3.ElevatedButton
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
@ -31,7 +28,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
@ -42,12 +38,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import chat.revolt.BuildConfig
import chat.revolt.R
import chat.revolt.api.REVOLT_MARKETING
import chat.revolt.composables.generic.AnyLink
import chat.revolt.composables.generic.Weblink
import com.chuckerteam.chucker.api.Chucker
@OptIn(ExperimentalFoundationApi::class)
@Composable
@ -59,7 +50,7 @@ fun LoginGreetingScreen(navController: NavController) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(vertical = 20.dp, horizontal = 0.dp)
.padding(vertical = 20.dp, horizontal = 16.dp)
.safeDrawingPadding(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
@ -71,13 +62,11 @@ fun LoginGreetingScreen(navController: NavController) {
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painter = painterResource(id = R.drawable.revolt_logo_wide),
colorFilter = ColorFilter.tint(LocalContentColor.current),
painter = painterResource(id = R.drawable.onboarding_fly_image),
contentDescription = "Revolt Logo",
contentScale = ContentScale.Fit,
modifier = Modifier
.height(55.dp)
.padding(bottom = 10.dp)
.padding(bottom = 16.dp)
.combinedClickable(
interactionSource = remember(::MutableInteractionSource),
indication = null,
@ -100,7 +89,14 @@ fun LoginGreetingScreen(navController: NavController) {
}
)
)
}
Column(
modifier = Modifier
.fillMaxWidth(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = stringResource(R.string.login_onboarding_heading),
style = MaterialTheme.typography.displaySmall.copy(
@ -109,7 +105,7 @@ fun LoginGreetingScreen(navController: NavController) {
textAlign = TextAlign.Center
),
modifier = Modifier
.padding(horizontal = 20.dp, vertical = 10.dp)
.padding(bottom = 4.dp)
.fillMaxWidth()
)
@ -124,17 +120,12 @@ fun LoginGreetingScreen(navController: NavController) {
fontWeight = FontWeight.Normal
),
modifier = Modifier
.padding(horizontal = 20.dp, vertical = 10.dp)
.padding(horizontal = 20.dp)
.fillMaxWidth()
)
}
Column(
modifier = Modifier
.width(200.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Spacer(modifier = Modifier.height(32.dp))
Button(
onClick = { navController.navigate("login/login") },
modifier = Modifier
@ -177,33 +168,6 @@ fun LoginGreetingScreen(navController: NavController) {
}
Spacer(modifier = Modifier.height(40.dp))
CompositionLocalProvider(
LocalTextStyle provides LocalTextStyle.current.copy(textAlign = TextAlign.Center)
) {
Weblink(
text = stringResource(R.string.terms_of_service),
url = "$REVOLT_MARKETING/terms"
)
Weblink(
text = stringResource(R.string.privacy_policy),
url = "$REVOLT_MARKETING/privacy"
)
Weblink(
text = stringResource(R.string.community_guidelines),
url = "$REVOLT_MARKETING/aup"
)
if (BuildConfig.DEBUG) {
AnyLink(
text = "Debug: Chucker",
action = {
Chucker.getLaunchIntent(context).apply {
context.startActivity(this)
}
}
)
}
}
}
}
}

View File

@ -1,9 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
android:width="72dp"
android:height="72dp"
android:viewportWidth="72"
android:viewportHeight="72">
<path
android:pathData="M42.7,71.38C42.7,60.74 42.7,53.76 42.7,44.7L35.91,36.62H57.87C60.48,36.62 62.77,37.09 64.72,38.03C66.68,38.97 68.2,40.32 69.29,42.08C70.37,43.85 70.92,45.97 70.92,48.43C70.92,50.92 70.36,53.02 69.24,54.73C68.13,56.44 66.56,57.73 64.55,58.6C62.55,59.47 60.21,59.91 57.53,59.91H48.47V52.57H55.61C56.73,52.57 57.69,52.44 58.47,52.17C59.28,51.88 59.89,51.44 60.31,50.83C60.75,50.21 60.96,49.42 60.96,48.43C60.96,47.44 60.75,46.63 60.31,46C59.89,45.37 59.28,44.91 58.47,44.61C57.69,44.31 56.73,44.15 55.61,44.15H52.24V71.38H42.7ZM63.3,55.43L72.09,71.38H61.72L53.14,55.43H63.3Z"
android:fillColor="#FF005C"/>
android:pathData="M32.888,21.721V31.138H26.569V21.721H32.888ZM51.649,21.721V31.138H45.33V21.721H51.649Z"
android:fillColor="#662D91"/>
<path
android:pathData="M51.648,43.635H45.369V49.953H26.569V43.635H45.33V37.318H51.648V43.635ZM26.569,37.318V43.635H20.25V37.318H26.569ZM26.569,31.138H20.25V21.721H26.569V31.138ZM45.35,31.138H39.03V21.721H45.35V31.138Z"
android:fillColor="#FFDE17"/>
</vector>

View File

@ -7,6 +7,7 @@
<string name="cancel">Cancel</string>
<string name="share">Share</string>
<string name="lets_go">Let\'s go</string>
<string name="confirm">Confirm</string>
<string name="loading">Fetching some info, hang in there…</string>
<string name="rate_limit_toast">Hold your horses! You\'re doing that too often in a short amount of time.</string>