progress to exporting filtered content

This commit is contained in:
2026-01-30 22:21:01 +01:00
parent 61002cada9
commit 29f5716664
7 changed files with 120 additions and 54 deletions

View File

@@ -27,7 +27,7 @@ fun LoginScreen(viewModel: AuthViewModel) {
modifier = modifier,
uiState = uiState,
onRegister = viewModel::signUp,
onTogleForm = viewModel::setFormType
onToggleForm = viewModel::setFormType
)
}

View File

@@ -23,10 +23,8 @@ import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -36,7 +34,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.capitalize
import androidx.compose.ui.unit.dp
import androidx.core.os.LocaleListCompat
import androidx.lifecycle.lifecycleScope
@@ -45,12 +42,10 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import net.tinsae.clocked.biometric.GlobalAuthenticator
import net.tinsae.clocked.ui.components.ShowLoadingScreen
import net.tinsae.clocked.ui.screens.dashboard.DashboardScreen
import net.tinsae.clocked.data.Locale
import net.tinsae.clocked.data.LogRepository
import net.tinsae.clocked.data.Theme
import net.tinsae.clocked.ui.components.TopBar
import net.tinsae.clocked.ui.screens.dashboard.DashboardScreen
import net.tinsae.clocked.ui.screens.history.HistoryScreen
import net.tinsae.clocked.ui.screens.settings.SettingsScreen
import net.tinsae.clocked.ui.screens.settings.SettingsViewModel
@@ -92,17 +87,13 @@ class MainActivity : AppCompatActivity() {
settingsViewModel.uiState
.map { it.pendingCsvContent }
.distinctUntilChanged()
.collect { csvContent ->
.collect {
csvContent ->
if (csvContent != null) {
val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", java.util.Locale.US).format(Date())
createDocumentLauncher.launch("Clocked-Export-$timestamp.csv")
}
}
/*authViewModel.sessionStatus.collect {
if (it is SessionStatus.Authenticated) {
LogRepository.subscribeRealTime()
}
}*/
}
enableEdgeToEdge()
@@ -114,23 +105,14 @@ class MainActivity : AppCompatActivity() {
}
/*override fun onDestroy() {
super.onDestroy()
// When the app is being completely destroyed, ensure the connection is closed.
LogRepository.unsubscribeRealTime()
}*/
}
@Composable
fun AppEntry(settingsViewModel: SettingsViewModel, authViewModel: AuthViewModel) {
val settingsState by settingsViewModel.uiState.collectAsState()
val sessionStatus by authViewModel.sessionStatus.collectAsState()
// Trigger fetching of logs when the session status changes.
LaunchedEffect(sessionStatus) {
if (sessionStatus is SessionStatus.Authenticated){
//LogRepository.
}
}
val useDarkTheme = when (settingsState.theme) {
@@ -148,21 +130,6 @@ fun AppEntry(settingsViewModel: SettingsViewModel, authViewModel: AuthViewModel)
}else{
ClockedApp(settingsViewModel, authViewModel)
}
/*when (sessionStatus) {
/*is SessionStatus.Initializing -> {
// Only show loading for the initial session check.
ShowLoadingScreen()
}*/
is SessionStatus.Authenticated -> {
// Just show the app. The ViewModels inside will manage their own loading UI.
ClockedApp(settingsViewModel, authViewModel)
}
else -> {
LoginScreen(authViewModel)
}
}*/
}
}
@@ -180,7 +147,6 @@ fun updateLocale(context: Context, locale: Locale) {
fun ClockedApp(settingsViewModel: SettingsViewModel, authViewModel: AuthViewModel) {
var currentDestination by rememberSaveable { mutableStateOf(AppDestinations.HOME) }
NavigationSuiteScaffold(
modifier = Modifier.fillMaxSize(),
navigationSuiteItems = {
@@ -190,16 +156,18 @@ fun ClockedApp(settingsViewModel: SettingsViewModel, authViewModel: AuthViewMode
Icon(
imageVector = destination.icon,
contentDescription = stringResource(destination.label),
modifier = Modifier.padding(1.dp).size(24.dp)
modifier = Modifier
//.padding(1.dp)
.size(24.dp)
)
},
alwaysShowLabel = false,
label = { Text(stringResource(destination.label)) },
//label = { Text(stringResource(destination.label)) },
selected = destination == currentDestination,
onClick = { currentDestination = destination }
)
}
}
},
) {
Scaffold(
modifier = Modifier.fillMaxSize(),
@@ -235,10 +203,6 @@ fun ClockedApp(settingsViewModel: SettingsViewModel, authViewModel: AuthViewMode
modifier = modifier,
viewModel = settingsViewModel
)
/*AppDestinations.LOGOUT -> {
authViewModel.logout()
}*/
}
}
}

View File

@@ -41,9 +41,6 @@ class BiometricAuthenticator(private val activity: FragmentActivity) {
onSuccess()
}
override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
}
})
when (biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG or BiometricManager.Authenticators.DEVICE_CREDENTIAL)) {

View File

@@ -42,11 +42,14 @@ fun RegistrationForm(
modifier: Modifier = Modifier,
uiState: AuthUiState,
onRegister: (String, String, String) -> Unit,
onTogleForm: (FormType) -> Unit
onToggleForm: (FormType) -> Unit
) {
var name by rememberSaveable { mutableStateOf("") }
var email by rememberSaveable { mutableStateOf("") }
var password by rememberSaveable { mutableStateOf("") }
var cPassword by rememberSaveable { mutableStateOf("") }
var error: String? by rememberSaveable { mutableStateOf(null) }
Scaffold(modifier = modifier.fillMaxSize()) { innerPadding ->
Column(
@@ -103,6 +106,31 @@ fun RegistrationForm(
singleLine = true,
isError = uiState.error != null
)
Spacer(modifier = Modifier.height(16.dp))
OutlinedTextField(
value = cPassword,
onValueChange = {
run {
cPassword = it
error = if (it != password) {
"Passwords do not match"
} else {
null
}
}
},
label = { Text(stringResource(R.string.confirm_password)) },
modifier = Modifier.fillMaxWidth(),
visualTransformation = PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
singleLine = true,
isError = error != null,
supportingText = {
error?.let {
Text(text = it, color = MaterialTheme.colorScheme.error)
}
}
)
uiState.error?.let {
Spacer(modifier = Modifier.height(8.dp))
@@ -112,7 +140,12 @@ fun RegistrationForm(
Spacer(modifier = Modifier.height(32.dp))
Button(
onClick = { onRegister(name,email, password) },
onClick = {
if (password == cPassword) {
onRegister(name, email, password)
error = null
}
},
modifier = Modifier.fillMaxWidth(),
enabled = !uiState.isLoading
) {
@@ -128,7 +161,7 @@ fun RegistrationForm(
verticalAlignment = Alignment.CenterVertically
) {
Text("Have an account?")
TextButton(onClick = { onTogleForm(FormType.LOGIN) }) {
TextButton(onClick = { onToggleForm(FormType.LOGIN) }) {
Text("Sign in", color = Color.Blue)
}
}
@@ -144,7 +177,7 @@ fun RegisterPreview(){
RegistrationForm(
uiState = AuthUiState(),
onRegister = { _, _, _ -> },
onTogleForm = { _ ->}
onToggleForm = { _ ->}
)
}
}

View File

@@ -0,0 +1,67 @@
package net.tinsae.clocked.ui.screens.editor
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import net.tinsae.clocked.data.Log
import net.tinsae.clocked.ui.components.ListItem
@Composable
private fun EditorScreen(modifier: Modifier = Modifier){
val viewModel = EditorViewModel()
Surface(modifier = modifier.padding(16.dp).fillMaxSize()) {
FilterLogs(modifier = modifier, viewModel = viewModel)
ShowLogs(modifier = modifier, logs = listOf())
}
}
@Composable
private fun FilterLogs(modifier: Modifier = Modifier, viewModel: EditorViewModel){
Column(modifier = modifier) {
Text(modifier = Modifier.fillMaxWidth().padding(16.dp), text = "Filter")
Row(modifier = Modifier.fillMaxWidth()) {
Text(modifier = Modifier.weight(1f).padding(16.dp), text = "By date")
Text(modifier = Modifier.weight(1f).padding(16.dp), text = "from")
Text(modifier = Modifier.weight(1f).padding(16.dp), text = "to")
}
}
}
@Composable
private fun ShowLogs(logs: List<Log>, modifier: Modifier = Modifier){
LazyColumn {
items(logs, key = { it.id }) { log ->
ListItem(
modifier = Modifier.padding(horizontal = 16.dp),
log = log,
onEdit = { },
onDelete = { },
// When the item is clicked, set it as the selected log for the dialog
onClick = { }
)
}
}
}
@Preview
@Composable
private fun EditorPreview () {
EditorScreen();
}

View File

@@ -0,0 +1,4 @@
package net.tinsae.clocked.ui.screens.editor
class EditorViewModel {
}

View File

@@ -74,5 +74,6 @@
<string name="add_entry">Add a new entry</string>
<string name="logout">Log out</string>
<string name="loading">loading</string>
<string name="confirm_password">Confirm password</string>
</resources>