OXYGENHUB
# 5ae4af48ddd2 oxygenhub-android / app / src / main / java / io / oxygenhub / android / ui / LoginScreen.kt
4.7 KiB · last changed Set the project up properly (closes #1) 11 days ago source blame history raw
1
package io.oxygenhub.android.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
import androidx.compose.foundation.Image
19
import androidx.compose.ui.res.painterResource
20
import io.oxygenhub.android.R
21
22
@Composable
23
fun LoginScreen(onLoginSuccess: () -> Unit) {
24
    var username by remember { mutableStateOf("") }
25
    var password by remember { mutableStateOf("") }
26
    var serverUrl by remember { mutableStateOf("https://oxygenhub.io") }
27
    var twoFactorCode by remember { mutableStateOf("") }
28
    var is2FaRequired by remember { mutableStateOf(false) }
29
    var isLoading by remember { mutableStateOf(false) }
30
31
    Column(
32
        modifier = Modifier
33
            .fillMaxSize()
34
            .padding(24.dp),
35
        horizontalAlignment = Alignment.CenterHorizontally,
36
        verticalArrangement = Arrangement.Center
37
    ) {
38
        Image(
39
            painter = painterResource(id = R.drawable.mark),
40
            contentDescription = "OxygenHub Logo",
41
            modifier = Modifier.size(64.dp)
42
        )
43
        Spacer(modifier = Modifier.height(16.dp))
44
        Text(
45
            text = "OxygenHub",
46
            fontSize = 36.sp,
47
            fontWeight = FontWeight.Bold,
48
            color = MaterialTheme.colorScheme.primary
49
        )
50
        Spacer(modifier = Modifier.height(8.dp))
51
        Text(
52
            text = "Sign in to delegate your identity",
53
            style = MaterialTheme.typography.bodyLarge,
54
            color = MaterialTheme.colorScheme.onSurfaceVariant
55
        )
56
57
        Spacer(modifier = Modifier.height(48.dp))
58
59
        OutlinedTextField(
60
            value = serverUrl,
61
            onValueChange = { serverUrl = it },
62
            label = { Text("Server URL") },
63
            modifier = Modifier.fillMaxWidth(),
64
            singleLine = true
65
        )
66
67
        Spacer(modifier = Modifier.height(16.dp))
68
69
        OutlinedTextField(
70
            value = username,
71
            onValueChange = { username = it },
72
            label = { Text("Username or Email") },
73
            leadingIcon = { Icon(Icons.Filled.Person, contentDescription = "Username") },
74
            modifier = Modifier.fillMaxWidth(),
75
            singleLine = true
76
        )
77
78
        Spacer(modifier = Modifier.height(16.dp))
79
80
        OutlinedTextField(
81
            value = password,
82
            onValueChange = { password = it },
83
            label = { Text("Password") },
84
            leadingIcon = { Icon(Icons.Filled.Lock, contentDescription = "Password") },
85
            visualTransformation = PasswordVisualTransformation(),
86
            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
87
            modifier = Modifier.fillMaxWidth(),
88
            singleLine = true
89
        )
90
91
        Spacer(modifier = Modifier.height(16.dp))
92
93
        if (is2FaRequired) {
94
            OutlinedTextField(
95
                value = twoFactorCode,
96
                onValueChange = { twoFactorCode = it },
97
                label = { Text("2FA Authenticator Code") },
98
                keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
99
                modifier = Modifier.fillMaxWidth(),
100
                singleLine = true
101
            )
102
            Spacer(modifier = Modifier.height(32.dp))
103
        } else {
104
            Spacer(modifier = Modifier.height(16.dp))
105
        }
106
107
        Button(
108
            onClick = {
109
                if (!is2FaRequired) {
110
                    // Step 1: Simulate checking credentials and discovering 2FA is needed
111
                    is2FaRequired = true
112
                } else {
113
                    // Step 2: Simulate verifying the 2FA code and logging in
114
                    isLoading = true
115
                    onLoginSuccess()
116
                }
117
            },
118
            modifier = Modifier
119
                .fillMaxWidth()
120
                .height(50.dp),
121
            enabled = username.isNotBlank() && password.isNotBlank() && (!is2FaRequired || twoFactorCode.isNotBlank())
122
        ) {
123
            if (isLoading) {
124
                CircularProgressIndicator(
125
                    modifier = Modifier.size(24.dp),
126
                    color = MaterialTheme.colorScheme.onPrimary
127
                )
128
            } else {
129
                Text(if (is2FaRequired) "Verify & Log In" else "Log In", fontSize = 16.sp)
130
            }
131
        }
132
    }
133
}