OXYGENHUB

Android: Add OxygenHub Authentication Login Screen e845c208d516

Author
Andy McCall @andymccall <[email protected]>
When
· 2026-09-30 14:35 UTC
Signature
✔ signed by Andy McCall
Hash
e845c208d51697a4c6da763b76fae820a72c192379721dc7f5488546055aeabf
Depends on
5edf011e4d10 66127df36f3a e0e4a1c48a77
Depended on by
57c0824300db 19e1dbc01b93
In bookmarks
main
In tags
v0.1.0 v0.1.1 v0.1.2 v0.1.3 v0.1.4 v0.1.5 v0.1.6 v0.1.7 v0.1.8 v0.1.9
Edits
5 atoms, 1 tree operation, 2 files

Browse the tree at this change

added app/src/main/java/com/example/oxygenhub/ui/LoginScreen.kt +103 −0
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 +
}
modified app/src/main/java/com/example/oxygenhub/MainActivity.kt +11 −1
…
14 unchanged lines
15 15
16 16
import uniffi.rust_core.oxygenGreeting
17 17
18 +
import com.example.oxygenhub.ui.LoginScreen
18 19
import com.example.oxygenhub.ui.MainScreen
20 +
import androidx.compose.runtime.*
19 21
20 22
class MainActivity : ComponentActivity() {
21 23
    override fun onCreate(savedInstanceState: Bundle?) {
…
1 unchanged lines
23 25
        enableEdgeToEdge()
24 26
        setContent {
25 27
            OxygenHubTheme {
26 -
                MainScreen()
28 +
                var isLoggedIn by remember { mutableStateOf(false) }
29 +
                
30 +
                if (isLoggedIn) {
31 +
                    MainScreen()
32 +
                } else {
33 +
                    LoginScreen(
34 +
                        onLoginSuccess = { isLoggedIn = true }
35 +
                    )
36 +
                }
27 37
            }
28 38
        }
29 39
    }
…
9 unchanged lines