Skip to content

Commit

Permalink
Improve login ui
Browse files Browse the repository at this point in the history
  • Loading branch information
wingio committed Nov 27, 2023
1 parent 0092303 commit b28a382
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 108 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import kotlinx.serialization.Serializable
data class Application(
val name: String,
val website: String? = null,
@SerialName("vapid_key") val vapidKey: String,
@SerialName("vapid_key") val vapidKey: String? = null,
@SerialName("client_id") val clientId: String? = null,
@SerialName("client_secret") val clientSecret: String? = null,
val id: String? = null
Expand Down
125 changes: 74 additions & 51 deletions app/src/main/java/xyz/wingio/dimett/ui/screens/auth/LoginScreen.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package xyz.wingio.dimett.ui.screens.auth

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.widthIn
Expand Down Expand Up @@ -47,21 +51,6 @@ class LoginScreen : Screen {
viewModel: LoginViewModel = getScreenModel()
) {
val navigator = LocalNavigator.currentOrThrow
val ctx = LocalContext.current
var lastTyped by remember {
mutableLongStateOf(0L)
}

// Only send request when user is done typing
LaunchedEffect(Unit) {
while (true) {
lastTyped += 1
delay(1.seconds / 30)
if (lastTyped == 23L) {
viewModel.loadDetails()
}
}
}

IntentHandler { intent ->
viewModel.handleIntent(intent, navigator)
Expand All @@ -77,49 +66,83 @@ class LoginScreen : Screen {
) {
Image(painter = painterResource(R.drawable.ic_app), contentDescription = null)

if (viewModel.nodeInfoLoading) {
CircularProgressIndicator(
modifier = Modifier.size(18.dp),
strokeWidth = 3.dp
)
if(viewModel.loginLoading) {
CircularProgressIndicator()
} else {
Login(viewModel)
}
}
}
}

@Composable
private fun ColumnScope.Login(
viewModel: LoginViewModel
) {
val ctx = LocalContext.current
var lastTyped by remember {
mutableLongStateOf(0L)
}

viewModel.nodeInfo?.let {
InstancePreview(
url = viewModel.instance,
nodeInfo = it
)
// Only send request when user is done typing
LaunchedEffect(Unit) {
while (true) {
lastTyped += 1
delay(1.seconds / 30)
if (lastTyped == 23L) {
viewModel.loadDetails()
}
}
}

if (viewModel.nodeInfoLoading) {
CircularProgressIndicator(
modifier = Modifier.size(18.dp),
strokeWidth = 3.dp
)
}

OutlinedTextField(
value = viewModel.instance,
onValueChange = {
viewModel.instance = it
lastTyped = 0L
viewModel.nodeInfo = null
},
label = { Text(getString(R.string.label_instance)) },
placeholder = { Text("mastodon.online") },
isError = viewModel.didError
AnimatedVisibility(
visible = viewModel.nodeInfo != null
) {
viewModel.nodeInfo?.let {
InstancePreview(
url = viewModel.instance,
nodeInfo = it
)
}
}

if (viewModel.didError) {
Text(
text = getString(R.string.msg_invalid_instance),
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.error,
textAlign = TextAlign.Center,
modifier = Modifier.widthIn(max = 300.dp)
)
}
Spacer(Modifier.height(24.dp))

Button(
onClick = { viewModel.login(ctx) },
enabled = viewModel.nodeInfo != null
) {
Text(getString(R.string.action_login))
}
}
OutlinedTextField(
value = viewModel.instance,
onValueChange = {
viewModel.instance = it
lastTyped = 0L
viewModel.nodeInfo = null
},
label = { Text(getString(R.string.label_instance)) },
placeholder = { Text("mastodon.online") },
isError = viewModel.didError,
singleLine = true
)

if (viewModel.didError) {
Text(
text = getString(R.string.msg_invalid_instance),
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.error,
textAlign = TextAlign.Center,
modifier = Modifier.widthIn(max = 300.dp)
)
}

Button(
onClick = { viewModel.login(ctx) },
enabled = viewModel.nodeInfo != null && viewModel.instanceIsMastodon
) {
Text(getString(R.string.action_login))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,14 @@ class LoginViewModel(
var didError by mutableStateOf(false)
var nodeInfo by mutableStateOf(null as NodeInfo?)

var loginLoading by mutableStateOf(false)
var nodeInfoLoading by mutableStateOf(false)

private var instanceUrl: String? = null

val instanceIsMastodon: Boolean
get() = nodeInfo?.metadata?.features?.contains("mastodon_api") == true || nodeInfo?.software?.name == "mastodon"

fun login(context: Context) {
if (instance.isEmpty()) return
coroutineScope.launch(Dispatchers.IO) {
Expand Down Expand Up @@ -113,6 +117,7 @@ class LoginViewModel(
coroutineScope.launch {
val instance = instanceManager[url] ?: return@launch

loginLoading = true
mastodonRepository.getToken(
instanceUrl = instance.url,
clientId = instance.clientId,
Expand All @@ -132,6 +137,7 @@ class LoginViewModel(
}
}

loginLoading = false
instanceUrl = null // Don't let duplicate intents happen
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ package xyz.wingio.dimett.ui.widgets.auth

import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
Expand All @@ -27,6 +31,7 @@ fun InstancePreview(
url: String,
nodeInfo: NodeInfo
) {
val iconSize = 56.dp
val name = nodeInfo.metadata?.nodeName ?: url

val icon = when (nodeInfo.software.name) {
Expand All @@ -36,24 +41,25 @@ fun InstancePreview(
else -> painterResource(R.drawable.img_logo_fediverse)
}

ElevatedCard(
modifier = Modifier.width(350.dp)
Box(
modifier = Modifier
.width(350.dp)
.padding(bottom = iconSize / 2)
) {
Row(
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(16.dp)
ElevatedCard(
modifier = Modifier
.fillMaxWidth()
.offset(y = iconSize / 2)
) {
Image(
painter = icon,
contentDescription = nodeInfo.software.name,
modifier = Modifier
.size(55.dp)
.shadow(2.dp, CircleShape)
)
Column(
verticalArrangement = Arrangement.spacedBy(3.dp)
verticalArrangement = Arrangement.spacedBy(3.dp),
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Spacer(Modifier.height(16.dp))

Text(
text = name,
style = MaterialTheme.typography.bodyLarge,
Expand Down Expand Up @@ -82,5 +88,14 @@ fun InstancePreview(
}
}

Image(
icon,
contentDescription = null,
modifier = Modifier
.padding(horizontal = 16.dp)
.size(iconSize)
.align(Alignment.TopCenter)
.shadow(10.dp, CircleShape)
)
}
}
17 changes: 0 additions & 17 deletions app/src/test/java/xyz/wingio/dimett/ExampleUnitTest.kt

This file was deleted.

0 comments on commit b28a382

Please sign in to comment.