OXYGENHUB
# e845c208d516 oxygenhub-android / app / src / main / java / com / example / oxygenhub / ui / LoginScreen.kt
3.5 KiB · last changed Android: Add OxygenHub Authentication Login Screen 1 month ago source blame history raw
1
package com.example.oxygenhub.ui
2
3
import androidx.compose.foundation.layout.*
4
import androidx.compose.foundation.text.KeyboardOptions
5
import androidx.compose.material.icons.Icons
6
import androidx.compose.material.icons.filled.Lock
7
import androidx.compose.material.icons.filled.Person
8
import androidx.compose.material3.*
9
import androidx.compose.runtime.*
10
import androidx.compose.ui.Alignment
11
import androidx.compose.ui.Modifier
12
import androidx.compose.ui.text.font.FontWeight
13
import androidx.compose.ui.text.input.KeyboardType
14
import androidx.compose.ui.text.input.PasswordVisualTransformation
15
import androidx.compose.ui.unit.dp
16
import androidx.compose.ui.unit.sp
17
18
@Composable
19
fun LoginScreen(onLoginSuccess: () -> Unit) {
20
    var username by remember { mutableStateOf("") }
21
    var password by remember { mutableStateOf("") }
22
    var serverUrl by remember { mutableStateOf("https://oxygenhub.io") }
23
    var isLoading by remember { mutableStateOf(false) }
24
25
    Column(
26
        modifier = Modifier
27
            .fillMaxSize()
28
            .padding(24.dp),
29
        horizontalAlignment = Alignment.CenterHorizontally,
30
        verticalArrangement = Arrangement.Center
31
    ) {
32
        Text(
33
            text = "OxygenHub",
34
            fontSize = 36.sp,
35
            fontWeight = FontWeight.Bold,
36
            color = MaterialTheme.colorScheme.primary
37
        )
38
        Spacer(modifier = Modifier.height(8.dp))
39
        Text(
40
            text = "Sign in to delegate your identity",
41
            style = MaterialTheme.typography.bodyLarge,
42
            color = MaterialTheme.colorScheme.onSurfaceVariant
43
        )
44
45
        Spacer(modifier = Modifier.height(48.dp))
46
47
        OutlinedTextField(
48
            value = serverUrl,
49
            onValueChange = { serverUrl = it },
50
            label = { Text("Server URL") },
51
            modifier = Modifier.fillMaxWidth(),
52
            singleLine = true
53
        )
54
55
        Spacer(modifier = Modifier.height(16.dp))
56
57
        OutlinedTextField(
58
            value = username,
59
            onValueChange = { username = it },
60
            label = { Text("Username or Email") },
61
            leadingIcon = { Icon(Icons.Filled.Person, contentDescription = "Username") },
62
            modifier = Modifier.fillMaxWidth(),
63
            singleLine = true
64
        )
65
66
        Spacer(modifier = Modifier.height(16.dp))
67
68
        OutlinedTextField(
69
            value = password,
70
            onValueChange = { password = it },
71
            label = { Text("Password") },
72
            leadingIcon = { Icon(Icons.Filled.Lock, contentDescription = "Password") },
73
            visualTransformation = PasswordVisualTransformation(),
74
            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
75
            modifier = Modifier.fillMaxWidth(),
76
            singleLine = true
77
        )
78
79
        Spacer(modifier = Modifier.height(32.dp))
80
81
        Button(
82
            onClick = {
83
                isLoading = true
84
                // TODO: Wire this up to rust-core to authenticate with the API
85
                // For now, we simulate a successful login immediately
86
                onLoginSuccess()
87
            },
88
            modifier = Modifier
89
                .fillMaxWidth()
90
                .height(50.dp),
91
            enabled = username.isNotBlank() && password.isNotBlank()
92
        ) {
93
            if (isLoading) {
94
                CircularProgressIndicator(
95
                    modifier = Modifier.size(24.dp),
96
                    color = MaterialTheme.colorScheme.onPrimary
97
                )
98
            } else {
99
                Text("Log In", fontSize = 16.sp)
100
            }
101
        }
102
    }
103
}