package com.vgmlr.kerf
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.Login
import androidx.compose.material.icons.filled.*
import androidx.compose.material.icons.outlined.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import androidx.compose.ui.platform.LocalUriHandler
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun HomeScreen(vm: KerfViewModel, nav: NavHostController) {
val notesList by vm.allNotes.collectAsState()
val ctx = LocalContext.current
val uriHandler = LocalUriHandler.current
val showMenu = remember { mutableStateOf(false) }
val showVersionDialog = remember { mutableStateOf(false) }
val showSearchDialog = remember { mutableStateOf(false) }
val kerfColors = LocalKerfColors.current!!
val listState = rememberLazyListState()
val importLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.OpenDocument()
) { uri ->
uri?.let {
vm.setSharedFile(KerfUtils.importNoteFromUri(ctx, it))
}
}
VersionDialog(
show = showVersionDialog.value,
onDismiss = { showVersionDialog.value = false },
uriHandler = uriHandler
)
if (showSearchDialog.value) {
SearchDialog(
notes = notesList,
onSelect = { id ->
showSearchDialog.value = false
nav.navigate(KerfScreen.Edit.createRoute(id))
},
onDismiss = { showSearchDialog.value = false }
)
}
Scaffold(
topBar = {
TopAppBar(
title = { },
colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent),
actions = {
Spacer(Modifier.width(BAR_EDGE))
KerfBlankButton(Modifier.weight(1f), label = "kerf")
Spacer(Modifier.width(BAR_GAP))
KerfButton(Icons.Default.Add, "New List") {
vm.addNote { nav.navigate(KerfScreen.Edit.createRoute(it)) }
}
Spacer(Modifier.width(BAR_GAP))
KerfButton(Icons.Default.Search, "Search") { showSearchDialog.value = true }
Spacer(Modifier.width(BAR_GAP))
Box {
KerfMenuTrigger { showMenu.value = true }
KerfDeploy(
expanded = showMenu.value,
onDismiss = { showMenu.value = false },
items = listOf(
KerfDeployItem(Icons.AutoMirrored.Outlined.Login, "Import") {
showMenu.value = false
importLauncher.launch(arrayOf("*/*"))
},
KerfDeployItem(Icons.Outlined.Settings, "Settings") {
showMenu.value = false
nav.navigate(KerfScreen.Settings.route)
},
KerfDeployItem(Icons.Outlined.Park, "Version") {
showMenu.value = false
showVersionDialog.value = true
},
KerfDeployItem(Icons.Filled.Block, "Exit", enabled = false) { }
)
)
}
Spacer(Modifier.width(BAR_EDGE_ACTIONS))
}
)
},
containerColor = MaterialTheme.colorScheme.background,
contentWindowInsets = WindowInsets(0, 0, 0, 0)
) { p ->
val topInset = WindowInsets.statusBars.asPaddingValues().calculateTopPadding()
Surface(
modifier = Modifier
.fillMaxSize()
.padding(bottom = p.calculateBottomPadding()),
shape = RectangleShape,
color = MaterialTheme.colorScheme.background
) {
val navBottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding()
LazyColumn(
state = listState,
contentPadding = PaddingValues(
start = BAR_EDGE,
end = BAR_EDGE,
top = topInset + TOP_BAR_H + 4.dp,
bottom = KerfDimens.PaddingLarge + navBottom
),
verticalArrangement = Arrangement.spacedBy(12.dp),
modifier = Modifier.fillMaxSize()
) {
items(items = notesList, key = { it.id }) { note ->
Card(
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface.copy(alpha = 0.7f)),
shape = RoundedCornerShape(ROUND_END),
border = EDGE,
modifier = Modifier
.fillMaxWidth()
.clickable { nav.navigate(KerfScreen.Edit.createRoute(note.id)) }
) {
Column {
Box(Modifier.fillMaxWidth().background(kerfColors.noteHeaderMain).padding(horizontal = KerfDimens.PaddingLarge, vertical = 12.dp)) {
Text(
text = note.title.ifBlank { "Untitled" },
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.align(Alignment.CenterStart)
)
Row(Modifier.align(Alignment.CenterEnd), verticalAlignment = Alignment.CenterVertically) {
if (note.content.length > 3) {
val itemCount = KerfUtils.countNumberedItems(note.content)
Text(text = "$itemCount / ${note.content.length}", color = MaterialTheme.colorScheme.onPrimary, fontSize = KerfDimens.TextSizeMedium)
}
if (note.isImported) {
Icon(
imageVector = Icons.Outlined.FileDownload,
contentDescription = null,
tint = MaterialTheme.colorScheme.onPrimary,
modifier = Modifier.padding(start = 12.dp).size(20.dp)
)
}
if (note.isPinned) {
Icon(
imageVector = Icons.Outlined.PushPin,
contentDescription = null,
tint = MaterialTheme.colorScheme.onPrimary,
modifier = Modifier.padding(start = 12.dp).size(20.dp)
)
}
IconButton(onClick = { vm.deleteNote(note.id) }, Modifier.padding(start = 8.dp).size(24.dp)) { Icon(Icons.Default.Close, null) }
}
}
Column(Modifier.padding(KerfDimens.PaddingLarge)) {
val visibleLines = note.content.lineSequence().filter { it.isNotBlank() }.toList()
val previewLines = visibleLines.take(7)
previewLines.forEach { line ->
Text(
text = line,
color = MaterialTheme.colorScheme.onSurfaceVariant,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.fillMaxWidth()
)
}
if (visibleLines.size > 7) {
Text(text = "[more]", color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.fillMaxWidth())
}
}
}
}
}
}
}
}
}