improve login screen UI and logic & fixes for blur

This commit is contained in:
2025-03-29 22:03:37 +03:00
parent 157c0c71fe
commit d46c72f7e6
21 changed files with 610 additions and 795 deletions
@@ -1,135 +0,0 @@
package dev.meloda.fast.ui.basic
import android.os.Build
import android.view.autofill.AutofillManager
import androidx.annotation.RequiresApi
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.autofill.Autofill
import androidx.compose.ui.autofill.AutofillNode
import androidx.compose.ui.autofill.AutofillType
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.layout.boundsInWindow
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalAutofill
import androidx.compose.ui.platform.LocalAutofillTree
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import kotlin.math.roundToInt
fun Modifier.connectNode(handler: AutoFillHandler): Modifier {
return with(handler) { fillBounds() }
}
fun Modifier.defaultFocusChangeAutoFill(handler: AutoFillHandler): Modifier {
return this.then(
Modifier.onFocusChanged {
if (it.isFocused) {
handler.request()
} else {
handler.cancel()
}
}
)
}
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun autoFillRequestHandler(
autofillTypes: List<AutofillType> = listOf(),
onFill: (String) -> Unit,
): AutoFillHandler {
val view = LocalView.current
val context = LocalContext.current
var isFillRecently = remember { false }
val autoFillNode = remember {
AutofillNode(
autofillTypes = autofillTypes,
onFill = {
isFillRecently = true
onFill(it)
}
)
}
val autofill = LocalAutofill.current
LocalAutofillTree.current += autoFillNode
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return EmptyAutoFillHandler
return remember {
@RequiresApi(Build.VERSION_CODES.O)
object : AutoFillHandler {
val autofillManager = context.getSystemService(AutofillManager::class.java)
override fun requestManual() {
autofillManager.requestAutofill(
view,
autoFillNode.id,
autoFillNode.boundingBox?.toAndroidRect() ?: error("BoundingBox is not provided yet")
)
}
override fun requestVerifyManual() {
if (isFillRecently) {
isFillRecently = false
requestManual()
}
}
override val autoFill: Autofill?
get() = autofill
override val autoFillNode: AutofillNode
get() = autoFillNode
override fun request() {
autofill?.requestAutofillForNode(autofillNode = autoFillNode)
}
override fun cancel() {
autofill?.cancelAutofillForNode(autofillNode = autoFillNode)
}
override fun Modifier.fillBounds(): Modifier {
return this.then(
Modifier.onGloballyPositioned {
autoFillNode.boundingBox = it.boundsInWindow()
})
}
}
}
}
fun Rect.toAndroidRect(): android.graphics.Rect {
return android.graphics.Rect(
left.roundToInt(),
top.roundToInt(),
right.roundToInt(),
bottom.roundToInt()
)
}
@OptIn(ExperimentalComposeUiApi::class)
interface AutoFillHandler {
val autoFill: Autofill?
val autoFillNode: AutofillNode?
fun requestVerifyManual()
fun requestManual()
fun request()
fun cancel()
fun Modifier.fillBounds(): Modifier
}
@ExperimentalComposeUiApi
data object EmptyAutoFillHandler : AutoFillHandler {
override val autoFill: Autofill? = null
override val autoFillNode: AutofillNode? = null
override fun requestVerifyManual() {}
override fun requestManual() {}
override fun request() {}
override fun cancel() {}
override fun Modifier.fillBounds(): Modifier = this.then(Modifier)
}
@@ -6,19 +6,26 @@ 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.shape.RoundedCornerShape
import androidx.compose.material3.Button
import androidx.compose.material3.Icon
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.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import dev.meloda.fast.ui.R as UiR
@Composable
fun ErrorView(
modifier: Modifier = Modifier,
iconResId: Int? = UiR.drawable.round_error_24,
text: String,
buttonText: String? = null,
onButtonClick: (() -> Unit)? = null,
@@ -30,6 +37,16 @@ fun ErrorView(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
iconResId?.let {
Icon(
modifier = Modifier.size(120.dp),
painter = painterResource(iconResId),
contentDescription = null,
tint = MaterialTheme.colorScheme.primaryContainer
)
Spacer(modifier = Modifier.height(12.dp))
}
Text(
text = text,
style = MaterialTheme.typography.titleLarge,
@@ -37,9 +54,10 @@ fun ErrorView(
)
buttonText?.let {
Spacer(modifier = Modifier.height(12.dp))
Spacer(modifier = Modifier.height(24.dp))
Button(
onClick = { onButtonClick?.invoke() }
onClick = { onButtonClick?.invoke() },
shape = RoundedCornerShape(6.dp)
) {
Text(text = buttonText)
}
@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,13c-0.55,0 -1,-0.45 -1,-1L11,8c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v4c0,0.55 -0.45,1 -1,1zM13,17h-2v-2h2v2z" />
</vector>