|
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 |
+ |
} |