feat: registration flow
Signed-off-by: Infi <wingit@geist.ga>
This commit is contained in:
parent
11892e54a2
commit
e316c0bf3a
|
|
@ -178,6 +178,9 @@ dependencies {
|
|||
implementation 'com.github.MikeOrtiz:TouchImageView:3.3'
|
||||
implementation "androidx.appcompat:appcompat:1.7.0-alpha02"
|
||||
|
||||
// hCaptcha - captcha provider
|
||||
implementation "com.github.hcaptcha:hcaptcha-android-sdk:3.8.1"
|
||||
|
||||
// JDK Desugaring - polyfill for new Java APIs
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
android:value="false" />
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:name=".activities.MainActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.Revolt">
|
||||
<intent-filter>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package chat.revolt
|
||||
package chat.revolt.activities
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.animation.core.EaseInOutExpo
|
||||
|
|
@ -14,7 +13,9 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.navigation.compose.dialog
|
||||
import chat.revolt.BuildConfig
|
||||
import chat.revolt.api.settings.GlobalState
|
||||
import chat.revolt.screens.SplashScreen
|
||||
import chat.revolt.screens.about.AboutScreen
|
||||
|
|
@ -22,9 +23,12 @@ import chat.revolt.screens.about.AttributionScreen
|
|||
import chat.revolt.screens.about.PlaceholderScreen
|
||||
import chat.revolt.screens.chat.ChatRouterScreen
|
||||
import chat.revolt.screens.chat.dialogs.FeedbackDialog
|
||||
import chat.revolt.screens.login.GreeterScreen
|
||||
import chat.revolt.screens.login.LoginGreetingScreen
|
||||
import chat.revolt.screens.login.LoginScreen
|
||||
import chat.revolt.screens.login.MfaScreen
|
||||
import chat.revolt.screens.register.RegisterDetailsScreen
|
||||
import chat.revolt.screens.register.RegisterGreetingScreen
|
||||
import chat.revolt.screens.register.RegisterVerifyScreen
|
||||
import chat.revolt.screens.settings.AppearanceSettingsScreen
|
||||
import chat.revolt.screens.settings.DebugSettingsScreen
|
||||
import chat.revolt.screens.settings.SettingsScreen
|
||||
|
|
@ -36,7 +40,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||
import io.sentry.android.core.SentryAndroid
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : ComponentActivity() {
|
||||
class MainActivity : FragmentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
|
|
@ -98,7 +102,7 @@ fun AppEntrypoint() {
|
|||
) {
|
||||
composable("splash") { SplashScreen(navController) }
|
||||
|
||||
composable("login/greeting") { GreeterScreen(navController) }
|
||||
composable("login/greeting") { LoginGreetingScreen(navController) }
|
||||
composable("login/login") { LoginScreen(navController) }
|
||||
composable("login/mfa/{mfaTicket}/{allowedAuthTypes}") { backStackEntry ->
|
||||
val mfaTicket = backStackEntry.arguments?.getString("mfaTicket") ?: ""
|
||||
|
|
@ -108,6 +112,14 @@ fun AppEntrypoint() {
|
|||
MfaScreen(navController, allowedAuthTypes, mfaTicket)
|
||||
}
|
||||
|
||||
composable("register/greeting") { RegisterGreetingScreen(navController) }
|
||||
composable("register/details") { RegisterDetailsScreen(navController) }
|
||||
composable("register/verify/{email}") { backStackEntry ->
|
||||
val email = backStackEntry.arguments?.getString("email") ?: ""
|
||||
|
||||
RegisterVerifyScreen(navController, email)
|
||||
}
|
||||
|
||||
composable("chat") { ChatRouterScreen(navController) }
|
||||
|
||||
composable("settings") { SettingsScreen(navController) }
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package chat.revolt.api.routes.account
|
||||
|
||||
import chat.revolt.api.RevoltError
|
||||
import chat.revolt.api.RevoltHttp
|
||||
import chat.revolt.api.RevoltJson
|
||||
import chat.revolt.api.schemas.RsResult
|
||||
import io.ktor.client.request.post
|
||||
import io.ktor.client.request.setBody
|
||||
import io.ktor.client.statement.bodyAsText
|
||||
import io.ktor.http.ContentType
|
||||
import io.ktor.http.contentType
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.SerializationException
|
||||
|
||||
@Serializable
|
||||
data class RegistrationBody(
|
||||
val email: String,
|
||||
val password: String,
|
||||
val invite: String? = null,
|
||||
val captcha: String,
|
||||
)
|
||||
|
||||
suspend fun register(body: RegistrationBody): RsResult<Unit, RevoltError> {
|
||||
val response = RevoltHttp.post("/auth/account/create") {
|
||||
setBody(body)
|
||||
contentType(ContentType.Application.Json)
|
||||
}
|
||||
|
||||
val responseContent = response.bodyAsText()
|
||||
|
||||
try {
|
||||
val error = RevoltJson.decodeFromString(RevoltError.serializer(), responseContent)
|
||||
return RsResult.err(error)
|
||||
} catch (e: SerializationException) {
|
||||
// Not an error
|
||||
}
|
||||
|
||||
return RsResult.ok(Unit)
|
||||
}
|
||||
|
|
@ -28,8 +28,8 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import chat.revolt.R
|
||||
import chat.revolt.RevoltTweenFloat
|
||||
import chat.revolt.RevoltTweenInt
|
||||
import chat.revolt.activities.RevoltTweenFloat
|
||||
import chat.revolt.activities.RevoltTweenInt
|
||||
import chat.revolt.api.schemas.ChannelType
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.net.Uri
|
|||
import androidx.browser.customtabs.CustomTabsIntent
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
|
|
@ -36,14 +37,16 @@ fun AnyLink(text: String, action: () -> Unit, modifier: Modifier = Modifier) {
|
|||
color = MaterialTheme.colorScheme.onBackground.copy(
|
||||
alpha = 0.5f
|
||||
),
|
||||
style = MaterialTheme.typography.titleMedium.copy(
|
||||
style = LocalTextStyle.current.copy(
|
||||
textAlign = TextAlign.Center,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 15.sp
|
||||
),
|
||||
modifier = modifier
|
||||
.padding(horizontal = 2.5.dp, vertical = 3.dp)
|
||||
.clickable(onClick = action)
|
||||
.clickable(
|
||||
onClick = action
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import chat.revolt.R
|
||||
import chat.revolt.RevoltTweenFloat
|
||||
import chat.revolt.RevoltTweenInt
|
||||
import chat.revolt.activities.RevoltTweenFloat
|
||||
import chat.revolt.activities.RevoltTweenInt
|
||||
import chat.revolt.api.RevoltAPI
|
||||
import chat.revolt.components.generic.UserAvatar
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
package chat.revolt.screens.about
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
|
|
@ -51,6 +55,7 @@ fun PlaceholderScreen(
|
|||
color = MaterialTheme.colorScheme.onBackground.copy(
|
||||
alpha = 0.5f
|
||||
),
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 20.dp, vertical = 10.dp)
|
||||
.fillMaxWidth()
|
||||
|
|
|
|||
|
|
@ -28,9 +28,9 @@ import androidx.documentfile.provider.DocumentFile
|
|||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import chat.revolt.R
|
||||
import chat.revolt.RevoltTweenDp
|
||||
import chat.revolt.RevoltTweenFloat
|
||||
import chat.revolt.RevoltTweenInt
|
||||
import chat.revolt.activities.RevoltTweenDp
|
||||
import chat.revolt.activities.RevoltTweenFloat
|
||||
import chat.revolt.activities.RevoltTweenInt
|
||||
import chat.revolt.api.RevoltAPI
|
||||
import chat.revolt.api.routes.microservices.autumn.FileArgs
|
||||
import chat.revolt.components.chat.Message
|
||||
|
|
@ -215,7 +215,7 @@ fun ChannelScreen(
|
|||
memberMap = mapOf(),
|
||||
userMap = RevoltAPI.userCache.toMap(),
|
||||
channelMap = RevoltAPI.channelCache.mapValues { ch ->
|
||||
ch.value.name ?: ch.value.id!!
|
||||
ch.value.name ?: ch.value.id ?: "#DeletedChannel"
|
||||
},
|
||||
emojiMap = RevoltAPI.emojiCache,
|
||||
serverId = channel.server ?: "",
|
||||
|
|
|
|||
|
|
@ -4,12 +4,25 @@ import android.widget.Toast
|
|||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ElevatedButton
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
|
|
@ -23,23 +36,23 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import chat.revolt.R
|
||||
import chat.revolt.api.REVOLT_MARKETING
|
||||
import chat.revolt.components.generic.Weblink
|
||||
|
||||
@Composable
|
||||
fun GreeterScreen(navController: NavController) {
|
||||
fun LoginGreetingScreen(navController: NavController) {
|
||||
val context = LocalContext.current
|
||||
var catTaps by remember { mutableStateOf(0) }
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight(),
|
||||
.fillMaxSize()
|
||||
.padding(vertical = 20.dp, horizontal = 0.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight()
|
||||
.weight(1f),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
|
|
@ -49,8 +62,8 @@ fun GreeterScreen(navController: NavController) {
|
|||
contentDescription = "Revolt Logo",
|
||||
contentScale = ContentScale.Fit,
|
||||
modifier = Modifier
|
||||
.height(60.dp)
|
||||
.padding(bottom = 30.dp)
|
||||
.height(70.dp)
|
||||
.padding(bottom = 10.dp)
|
||||
.clickable(
|
||||
interactionSource = remember(::MutableInteractionSource),
|
||||
indication = null
|
||||
|
|
@ -73,7 +86,7 @@ fun GreeterScreen(navController: NavController) {
|
|||
Text(
|
||||
text = stringResource(R.string.login_onboarding_heading),
|
||||
style = MaterialTheme.typography.displaySmall.copy(
|
||||
fontSize = 30.sp,
|
||||
fontSize = 26.sp,
|
||||
fontWeight = FontWeight.Black,
|
||||
textAlign = TextAlign.Center
|
||||
),
|
||||
|
|
@ -88,6 +101,7 @@ fun GreeterScreen(navController: NavController) {
|
|||
alpha = 0.5f
|
||||
),
|
||||
style = MaterialTheme.typography.titleMedium.copy(
|
||||
fontSize = 16.sp,
|
||||
textAlign = TextAlign.Center,
|
||||
fontWeight = FontWeight.Normal,
|
||||
),
|
||||
|
|
@ -99,18 +113,10 @@ fun GreeterScreen(navController: NavController) {
|
|||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 20.dp, vertical = 30.dp)
|
||||
.width(200.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
ElevatedButton(
|
||||
onClick = { navController.navigate("about/placeholder") },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.testTag("view_signup_page_button")
|
||||
) {
|
||||
Text(text = stringResource(R.string.signup))
|
||||
}
|
||||
|
||||
Button(
|
||||
onClick = { navController.navigate("login/login") },
|
||||
modifier = Modifier
|
||||
|
|
@ -119,6 +125,37 @@ fun GreeterScreen(navController: NavController) {
|
|||
) {
|
||||
Text(text = stringResource(R.string.login))
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
|
||||
ElevatedButton(
|
||||
onClick = { navController.navigate("register/greeting") },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.testTag("view_signup_page_button")
|
||||
) {
|
||||
Text(text = stringResource(R.string.signup))
|
||||
}
|
||||
|
||||
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"
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,24 @@
|
|||
package chat.revolt.screens.login
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ElevatedButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
|
|
@ -118,6 +130,7 @@ fun LoginScreen(
|
|||
}"
|
||||
)
|
||||
}
|
||||
|
||||
"home" -> {
|
||||
navController.navigate("chat") {
|
||||
popUpTo("login/greeting") { inclusive = true }
|
||||
|
|
@ -131,15 +144,13 @@ fun LoginScreen(
|
|||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight(),
|
||||
.fillMaxSize()
|
||||
.padding(20.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight()
|
||||
.weight(1f),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
|
|
@ -199,8 +210,7 @@ fun LoginScreen(
|
|||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 20.dp, vertical = 30.dp),
|
||||
.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Weblink(
|
||||
|
|
@ -217,22 +227,22 @@ fun LoginScreen(
|
|||
.testTag("resend_verification_link")
|
||||
)
|
||||
|
||||
ElevatedButton(
|
||||
onClick = { navController.popBackStack() },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.testTag("exit_login_page_button")
|
||||
) {
|
||||
Text(text = stringResource(R.string.back))
|
||||
}
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
|
||||
Button(
|
||||
onClick = { viewModel.doLogin() },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.testTag("do_login_button")
|
||||
) {
|
||||
Text(text = stringResource(R.string.login))
|
||||
Row {
|
||||
TextButton(onClick = {
|
||||
navController.popBackStack()
|
||||
}) {
|
||||
Text(text = stringResource(R.string.back))
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
|
||||
Button(onClick = {
|
||||
viewModel.doLogin()
|
||||
}) {
|
||||
Text(text = stringResource(R.string.login))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,22 @@
|
|||
package chat.revolt.screens.login
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
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.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ElevatedButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
|
|
@ -132,23 +140,19 @@ fun MfaScreen(
|
|||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight(),
|
||||
.fillMaxSize()
|
||||
.padding(20.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight()
|
||||
.weight(1f)
|
||||
.verticalScroll(
|
||||
rememberScrollState()
|
||||
),
|
||||
.fillMaxWidth()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.mfa_interstitial_header),
|
||||
style = MaterialTheme.typography.displaySmall.copy(
|
||||
|
|
@ -235,6 +239,7 @@ fun MfaScreen(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
"Recovery" -> {
|
||||
CollapsibleCard(title = stringResource(R.string.mfa_recovery_header)) {
|
||||
Column(
|
||||
|
|
@ -279,17 +284,10 @@ fun MfaScreen(
|
|||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 20.dp, vertical = 30.dp)
|
||||
ElevatedButton(
|
||||
onClick = { navController.popBackStack() }
|
||||
) {
|
||||
ElevatedButton(
|
||||
onClick = { navController.popBackStack() },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(text = stringResource(R.string.cancel))
|
||||
}
|
||||
Text(text = stringResource(R.string.cancel))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,220 @@
|
|||
package chat.revolt.screens.register
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import chat.revolt.R
|
||||
import chat.revolt.api.routes.account.RegistrationBody
|
||||
import chat.revolt.api.routes.account.register
|
||||
import chat.revolt.api.routes.misc.getRootRoute
|
||||
import chat.revolt.components.generic.FormTextField
|
||||
import com.hcaptcha.sdk.HCaptcha
|
||||
import com.hcaptcha.sdk.HCaptchaConfig
|
||||
import com.hcaptcha.sdk.HCaptchaSize
|
||||
import com.hcaptcha.sdk.HCaptchaTheme
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class RegisterDetailsScreenViewModel : ViewModel() {
|
||||
var email by mutableStateOf("")
|
||||
var password by mutableStateOf("")
|
||||
var error by mutableStateOf<String?>(null)
|
||||
private var captchaToken by mutableStateOf<String?>(null)
|
||||
|
||||
fun initCaptcha(context: Context, onSuccess: () -> Unit) {
|
||||
viewModelScope.launch {
|
||||
val root = getRootRoute()
|
||||
|
||||
if (!root.features.captcha.enabled) {
|
||||
onSuccess()
|
||||
return@launch
|
||||
}
|
||||
|
||||
val config = HCaptchaConfig.builder().apply {
|
||||
siteKey(root.features.captcha.key)
|
||||
theme(HCaptchaTheme.DARK)
|
||||
size(HCaptchaSize.INVISIBLE)
|
||||
}.build()
|
||||
|
||||
HCaptcha.getClient(context).apply {
|
||||
addOnSuccessListener {
|
||||
captchaToken = it.tokenResult
|
||||
onSuccess()
|
||||
}
|
||||
|
||||
addOnFailureListener {
|
||||
error = it.message
|
||||
}
|
||||
|
||||
setup(config)
|
||||
verifyWithHCaptcha()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun doRegistration(navController: NavController) {
|
||||
val body = RegistrationBody(
|
||||
email = email,
|
||||
password = password,
|
||||
captcha = captchaToken ?: ""
|
||||
)
|
||||
|
||||
viewModelScope.launch {
|
||||
val result = register(body)
|
||||
|
||||
if (result.ok) {
|
||||
navController.navigate("register/verify/${email}")
|
||||
} else {
|
||||
error = result.unwrapError().type
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RegisterDetailsScreen(
|
||||
navController: NavController,
|
||||
viewModel: RegisterDetailsScreenViewModel = viewModel()
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(20.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.register_form_heading),
|
||||
style = MaterialTheme.typography.displaySmall.copy(
|
||||
fontSize = 30.sp,
|
||||
fontWeight = FontWeight.Black,
|
||||
textAlign = TextAlign.Center
|
||||
),
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 10.dp)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.register_data),
|
||||
color = MaterialTheme.colorScheme.onBackground.copy(
|
||||
alpha = 0.5f
|
||||
),
|
||||
style = MaterialTheme.typography.titleMedium.copy(
|
||||
textAlign = TextAlign.Center,
|
||||
fontWeight = FontWeight.Normal,
|
||||
),
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 10.dp)
|
||||
.fillMaxWidth()
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(40.dp))
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
FormTextField(
|
||||
value = viewModel.email,
|
||||
onChange = { viewModel.email = it },
|
||||
label = stringResource(R.string.register_email),
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.register_email_verification_hint),
|
||||
color = MaterialTheme.colorScheme.onBackground.copy(
|
||||
alpha = 0.5f
|
||||
),
|
||||
fontSize = 12.sp,
|
||||
modifier = Modifier.padding(horizontal = 40.dp, vertical = 10.dp)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
|
||||
FormTextField(
|
||||
value = viewModel.password,
|
||||
onChange = { viewModel.password = it },
|
||||
label = stringResource(R.string.register_password),
|
||||
type = KeyboardType.Password
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.register_password_rules),
|
||||
color = MaterialTheme.colorScheme.onBackground.copy(
|
||||
alpha = 0.5f
|
||||
),
|
||||
fontSize = 12.sp,
|
||||
modifier = Modifier.padding(horizontal = 40.dp, vertical = 10.dp)
|
||||
)
|
||||
|
||||
if (!viewModel.error.isNullOrBlank()) {
|
||||
Text(
|
||||
text = viewModel.error!!,
|
||||
color = MaterialTheme.colorScheme.error,
|
||||
modifier = Modifier.padding(horizontal = 40.dp, vertical = 10.dp),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
TextButton(onClick = {
|
||||
navController.popBackStack()
|
||||
}) {
|
||||
Text(text = stringResource(R.string.back))
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
|
||||
Button(
|
||||
onClick = {
|
||||
viewModel.initCaptcha(context) {
|
||||
viewModel.doRegistration(navController)
|
||||
}
|
||||
},
|
||||
enabled = viewModel.email.isNotBlank() && viewModel.password.isNotBlank()
|
||||
) {
|
||||
Text(text = stringResource(R.string.signup))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
package chat.revolt.screens.register
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
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.R
|
||||
|
||||
@Composable
|
||||
fun RegisterGreetingScreen(navController: NavController) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(20.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.register_heading),
|
||||
style = MaterialTheme.typography.displaySmall.copy(
|
||||
fontSize = 30.sp,
|
||||
fontWeight = FontWeight.Black,
|
||||
textAlign = TextAlign.Center
|
||||
),
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 20.dp, vertical = 10.dp)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.revolt_onboarding),
|
||||
contentDescription = stringResource(id = R.string.register_image_alt),
|
||||
modifier = Modifier
|
||||
.size(300.dp)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.register_instructions),
|
||||
color = MaterialTheme.colorScheme.onBackground.copy(
|
||||
alpha = 0.5f
|
||||
),
|
||||
style = MaterialTheme.typography.titleMedium.copy(
|
||||
textAlign = TextAlign.Center,
|
||||
fontWeight = FontWeight.Normal,
|
||||
),
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 20.dp, vertical = 10.dp)
|
||||
.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
|
||||
Row {
|
||||
TextButton(onClick = {
|
||||
navController.popBackStack()
|
||||
}) {
|
||||
Text(text = stringResource(R.string.back))
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
|
||||
Button(onClick = {
|
||||
navController.navigate("register/details")
|
||||
}) {
|
||||
Text(text = stringResource(R.string.next))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
package chat.revolt.screens.register
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
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.text.font.FontWeight
|
||||
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.R
|
||||
|
||||
@Composable
|
||||
fun RegisterVerifyScreen(navController: NavController, email: String) {
|
||||
val intentLauncher =
|
||||
rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) {}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(20.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.check_mail),
|
||||
style = MaterialTheme.typography.displaySmall.copy(
|
||||
fontSize = 30.sp,
|
||||
fontWeight = FontWeight.Black,
|
||||
textAlign = TextAlign.Center
|
||||
),
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 20.dp)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.instructions_at_mail, email),
|
||||
color = MaterialTheme.colorScheme.onBackground.copy(
|
||||
alpha = 0.5f
|
||||
),
|
||||
style = MaterialTheme.typography.titleMedium.copy(
|
||||
textAlign = TextAlign.Center,
|
||||
fontWeight = FontWeight.Normal,
|
||||
),
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 20.dp)
|
||||
.fillMaxWidth()
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.verify_then_choose_username),
|
||||
color = MaterialTheme.colorScheme.onBackground.copy(
|
||||
alpha = 0.5f
|
||||
),
|
||||
style = MaterialTheme.typography.titleMedium.copy(
|
||||
textAlign = TextAlign.Center,
|
||||
fontWeight = FontWeight.Normal,
|
||||
),
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 20.dp)
|
||||
.fillMaxWidth()
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(40.dp))
|
||||
|
||||
Button(onClick = {
|
||||
val intent = Intent(Intent.ACTION_MAIN)
|
||||
intent.addCategory(Intent.CATEGORY_APP_EMAIL)
|
||||
intentLauncher.launch(intent)
|
||||
}) {
|
||||
Text(text = stringResource(R.string.open_mail_app))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -73,9 +73,11 @@ fun RevoltTheme(
|
|||
m3Supported && requestedTheme == Theme.M3Dynamic && systemInDarkTheme -> dynamicDarkColorScheme(
|
||||
context
|
||||
)
|
||||
|
||||
m3Supported && requestedTheme == Theme.M3Dynamic && !systemInDarkTheme -> dynamicLightColorScheme(
|
||||
context
|
||||
)
|
||||
|
||||
requestedTheme == Theme.Revolt -> RevoltColorScheme
|
||||
requestedTheme == Theme.Light -> LightColorScheme
|
||||
requestedTheme == Theme.Amoled -> AmoledColorScheme
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="113.68dp"
|
||||
android:height="186.04dp"
|
||||
android:viewportWidth="113.68"
|
||||
android:viewportHeight="186.04">
|
||||
<path
|
||||
android:pathData="m16.4,82.04c-4.55,-0.64 -8.73,2.52 -9.37,7.07l-6.94,49.6c-0.64,4.55 2.52,8.74 7.07,9.37l74.16,10.38 20.8,27.57 4.54,-32.41 5.02,-35.84 1.93,-13.76c0.64,-4.55 -2.52,-8.73 -7.07,-9.37z"
|
||||
android:strokeWidth="0.445733"
|
||||
android:fillColor="#1c243c" />
|
||||
<path
|
||||
android:pathData="m65.51,116.45c-0.41,2.91 -2.24,4.44 -5.64,3.97l-5.62,-0.79 1.29,-9.22 5.62,0.79c3.39,0.47 4.73,2.5 4.34,5.26zM42.11,100.86 L46.49,109.16 42.34,138.82 51.4,140.09 53.36,126.05 55.54,126.35 61.31,141.48 71.54,142.91 65.02,126.98c5.11,-0.51 9.17,-4.5 9.77,-9.6 0.91,-6.47 -2.92,-12.35 -12.03,-13.63z"
|
||||
android:strokeWidth="1.05602"
|
||||
android:fillColor="#ff4654"
|
||||
android:strokeColor="#ff4654" />
|
||||
<path
|
||||
android:pathData="m105.84,54.37 l-29.08,8.08a3.35,3.35 0,0 0,-2.33 4.13l3.59,12.92a3.35,3.35 0,0 0,4.13 2.33l29.08,-8.08a3.35,3.35 0,0 0,2.33 -4.13l-3.59,-12.92a3.35,3.35 0,0 0,-4.13 -2.33m-13.01,15.8 l-4.85,1.35 1.35,4.85 -3.23,0.9 -1.35,-4.85 -4.85,1.35 -0.9,-3.23 4.85,-1.35 -1.35,-4.85 3.23,-0.9 1.35,4.85 4.85,-1.35m9.06,4.44a2.51,2.51 0,0 1,-3.1 -1.75,2.51 2.51,0 0,1 1.75,-3.1 2.51,2.51 0,0 1,3.1 1.75,2.51 2.51,0 0,1 -1.75,3.1m5.12,-6.64a2.51,2.51 0,0 1,-3.1 -1.75,2.51 2.51,0 0,1 1.75,-3.1 2.51,2.51 0,0 1,3.1 1.75,2.51 2.51,0 0,1 -1.75,3.1z"
|
||||
android:strokeWidth="1.67655"
|
||||
android:fillColor="#6fe465" />
|
||||
<path
|
||||
android:pathData="m25.33,54.07c-0.73,1.26 -2.32,1.69 -3.57,0.96L3.62,44.58c-1.25,-0.72 -1.69,-2.32 -0.96,-3.57 0.73,-1.26 2.33,-1.68 3.57,-0.96l10.2,5.88 1.53,3.9 4.14,-0.63 2.27,1.31c1.26,0.73 1.68,2.33 0.96,3.57M20.53,36.2c-10.2,-5.88 -14.12,0.92 -14.12,0.92l20.41,11.76c0,0 3.92,-6.8 -6.28,-12.68M0.53,47.33c-1.08,1.88 -0.44,4.28 1.44,5.36l13.6,7.84c1.88,1.08 4.28,0.44 5.36,-1.44L21.59,57.95 1.18,46.19Z"
|
||||
android:strokeWidth="1.30846"
|
||||
android:fillColor="#00abff" />
|
||||
<path
|
||||
android:pathData="m80.17,19.65c3.38,0.12 7.09,0.49 10.95,1.22l-1.18,6.16 -26.2,-5c0.19,-1 5.56,-2.36 13.24,-2.43l1.91,-10.02c-1.37,0.14 -2.63,0.79 -3.54,1.8 -0.64,-1.75 -2.17,-3.13 -4.12,-3.5 -1.96,-0.37 -3.88,0.35 -5.12,1.74 1.1,-5.51 7.31,-9.02 14.36,-8.3l0.01,-0.06c0.16,-0.85 0.98,-1.41 1.83,-1.25 0.85,0.16 1.41,0.98 1.25,1.83l-0.01,0.06c6.82,1.92 11.29,7.47 10.3,13 -0.64,-1.75 -2.17,-3.13 -4.12,-3.5 -1.96,-0.37 -3.88,0.35 -5.12,1.74 -0.48,-1.27 -1.41,-2.34 -2.62,-2.99l-1.81,9.48"
|
||||
android:strokeWidth="1.5689"
|
||||
android:fillColor="#fbe94e" />
|
||||
</vector>
|
||||
|
|
@ -32,17 +32,19 @@
|
|||
<string name="password_forgot_instructions">Enter your email and we\'ll send you instructions on how to reset your password.</string>
|
||||
|
||||
<string name="register_heading">Welcome to Revolt</string>
|
||||
<string name="register_image_alt">Use Revolt to chat about stuff.</string>
|
||||
<string name="register_instructions">It\'s like a place to hang out, get together, and talk about stuff. Best part, it\'s on the internet.</string>
|
||||
<string name="register_form_heading">Let\'s get you set up.</string>
|
||||
<string name="register_data">Your data is safe with us. We don\'t sell it, or use it to show you ads.</string>
|
||||
<string name="register_data">Your data is safe with us. We don\'t sell it, and neither do we use it to show you ads.</string>
|
||||
<string name="register_email">Email</string>
|
||||
<string name="register_email_verification_hint">We\'ll send you a verification email to confirm your account.</string>
|
||||
<string name="register_password">Password</string>
|
||||
<string name="register_password_rules">Eight or more, common ones are bad. Try messing around with a sentence.</string>
|
||||
<string name="register_password_rules">Eight or more, common ones are bad. Symbols and numbers recommended.</string>
|
||||
|
||||
<string name="check_mail">Check your mail!</string>
|
||||
<string name="instructions_at_mail">We\'ve sent further instructions to %1$s.</string>
|
||||
<string name="verify_then_choose_username">Verify your email, and then we\'ll get on with choosing your username.</string>
|
||||
<string name="open_mail_app">Open mail app</string>
|
||||
|
||||
<string name="welcome">Welcome!</string>
|
||||
<string name="username_choose_lead">It\'s time to choose a username!</string>
|
||||
|
|
@ -90,12 +92,10 @@
|
|||
<string name="badge_bot_alt">Bot</string>
|
||||
<string name="badge_masquerade_alt">From linked channel</string>
|
||||
|
||||
<string name="tutorial">Welcome to Revolt\'s in-progress Android experience!</string>
|
||||
<string name="select_channel">Select a server and channel by swiping from the left.</string>
|
||||
|
||||
<string name="unknown">Unknown</string>
|
||||
|
||||
<string name="home">Home</string>
|
||||
<string name="menu">Menu</string>
|
||||
<string name="logout">Log out</string>
|
||||
|
||||
<string name="server_plus_alt">Add server</string>
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ buildscript {
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
plugins {
|
||||
id 'com.android.application' version '8.1.0-alpha11' apply false
|
||||
id 'com.android.library' version '8.1.0-alpha11' apply false
|
||||
id 'com.android.application' version '8.2.0-alpha01' apply false
|
||||
id 'com.android.library' version '8.2.0-alpha01' apply false
|
||||
id 'org.jetbrains.kotlin.android' version '1.8.0' apply false
|
||||
id 'org.jetbrains.kotlin.plugin.serialization' version '1.8.0' apply false
|
||||
id "com.google.dagger.hilt.android" version "2.44" apply false
|
||||
|
|
|
|||
Loading…
Reference in New Issue