From 408ba570510a045d4adc98208aa5e42da1c45bb9 Mon Sep 17 00:00:00 2001 From: Kyle Isom Date: Tue, 24 Mar 2026 16:15:58 -0700 Subject: [PATCH] UI polish: toolbar redesign, clipboard, snap fix, startup state Toolbar: - Replace FilterChip with custom ToolButton (no ripple, instant response) - Reorder tools: 0.38 0.5 Line Box Eraser Select - DropdownMenus anchored to buttons via Box wrapper (drop below) - Page indicator styled as OutlinedButton (visible affordance) - Cut/Del/Copy/Paste operations (internal clipboard) Line snap fix: - Check pen position when timer fires instead of canceling on movement - Handles EMR stylus micro-tremor correctly EMR eraser button: - TOOL_TYPE_ERASER events route to eraser handler regardless of active tool - Physical eraser end of pen works as temporary eraser App state: - Startup navigates to last-visited notebook/page via SharedPreferences - Closing notebook (X button) clears last notebook so app starts at list - Updated app icon Co-Authored-By: Claude Opus 4.6 (1M context) --- .../net/metacircular/engpad/EngPadApp.kt | 24 ++ .../net/metacircular/engpad/MainActivity.kt | 7 +- .../engpad/ui/editor/EditorScreen.kt | 9 +- .../engpad/ui/editor/EditorViewModel.kt | 38 +++ .../engpad/ui/editor/PadCanvasView.kt | 42 +-- .../metacircular/engpad/ui/editor/Toolbar.kt | 312 ++++++++++-------- .../engpad/ui/navigation/NavGraph.kt | 15 + .../res/drawable/ic_launcher_background.xml | 8 +- .../res/drawable/ic_launcher_foreground.xml | 29 +- 9 files changed, 316 insertions(+), 168 deletions(-) diff --git a/app/src/main/kotlin/net/metacircular/engpad/EngPadApp.kt b/app/src/main/kotlin/net/metacircular/engpad/EngPadApp.kt index 5761bc5..a1f47db 100644 --- a/app/src/main/kotlin/net/metacircular/engpad/EngPadApp.kt +++ b/app/src/main/kotlin/net/metacircular/engpad/EngPadApp.kt @@ -1,8 +1,32 @@ package net.metacircular.engpad import android.app.Application +import android.content.Context +import androidx.core.content.edit import net.metacircular.engpad.data.db.EngPadDatabase class EngPadApp : Application() { val database: EngPadDatabase by lazy { EngPadDatabase.getInstance(this) } + + fun getLastNotebookId(): Long { + val prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) + return prefs.getLong(KEY_LAST_NOTEBOOK, 0) + } + + fun setLastNotebookId(id: Long) { + getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE).edit { + putLong(KEY_LAST_NOTEBOOK, id) + } + } + + fun clearLastNotebookId() { + getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE).edit { + remove(KEY_LAST_NOTEBOOK) + } + } + + companion object { + private const val PREFS_NAME = "engpad_prefs" + private const val KEY_LAST_NOTEBOOK = "last_notebook_id" + } } diff --git a/app/src/main/kotlin/net/metacircular/engpad/MainActivity.kt b/app/src/main/kotlin/net/metacircular/engpad/MainActivity.kt index dbc2844..d45ba11 100644 --- a/app/src/main/kotlin/net/metacircular/engpad/MainActivity.kt +++ b/app/src/main/kotlin/net/metacircular/engpad/MainActivity.kt @@ -10,13 +10,18 @@ import net.metacircular.engpad.ui.theme.EngPadTheme class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - val database = (application as EngPadApp).database + val app = application as EngPadApp + val database = app.database + val lastNotebookId = app.getLastNotebookId() setContent { EngPadTheme { val navController = rememberNavController() EngPadNavGraph( navController = navController, database = database, + lastNotebookId = lastNotebookId, + onNotebookOpened = { app.setLastNotebookId(it) }, + onNotebookClosed = { app.clearLastNotebookId() }, ) } } diff --git a/app/src/main/kotlin/net/metacircular/engpad/ui/editor/EditorScreen.kt b/app/src/main/kotlin/net/metacircular/engpad/ui/editor/EditorScreen.kt index 916c62b..dd91ec7 100644 --- a/app/src/main/kotlin/net/metacircular/engpad/ui/editor/EditorScreen.kt +++ b/app/src/main/kotlin/net/metacircular/engpad/ui/editor/EditorScreen.kt @@ -46,6 +46,7 @@ fun EditorScreen( val canUndo by viewModel.undoManager.canUndo.collectAsState() val canRedo by viewModel.undoManager.canRedo.collectAsState() val hasSelection by viewModel.hasSelection.collectAsState() + val canPaste by viewModel.canPaste.collectAsState() val currentPageIndex by viewModel.currentPageIndex.collectAsState() val pages by viewModel.pages.collectAsState() @@ -108,14 +109,20 @@ fun EditorScreen( onUndo = { viewModel.undo() }, onRedo = { viewModel.redo() }, hasSelection = hasSelection, + onCutSelection = { + viewModel.cutSelection() + canvasView.clearSelection() + }, onDeleteSelection = { viewModel.deleteSelection() canvasView.clearSelection() }, onCopySelection = { - viewModel.copySelection() + viewModel.copyToClipboard() canvasView.clearSelection() }, + onPaste = { viewModel.paste() }, + canPaste = canPaste, onExportPdf = { val currentPage = pages.getOrNull(currentPageIndex) ?: return@EditorToolbar val file = PdfExporter.exportPages( diff --git a/app/src/main/kotlin/net/metacircular/engpad/ui/editor/EditorViewModel.kt b/app/src/main/kotlin/net/metacircular/engpad/ui/editor/EditorViewModel.kt index 4951db7..75a1d9c 100644 --- a/app/src/main/kotlin/net/metacircular/engpad/ui/editor/EditorViewModel.kt +++ b/app/src/main/kotlin/net/metacircular/engpad/ui/editor/EditorViewModel.kt @@ -40,6 +40,10 @@ class EditorViewModel( val hasSelection: StateFlow = _hasSelection private var selectedIds = emptySet() + private val _canPaste = MutableStateFlow(false) + val canPaste: StateFlow = _canPaste + private var clipboard = emptyList() + // Page navigation private val _pages = MutableStateFlow>(emptyList()) val pages: StateFlow> = _pages @@ -204,6 +208,40 @@ class EditorViewModel( } } + fun cutSelection() { + clipboard = _strokes.value.filter { it.id in selectedIds } + _canPaste.value = clipboard.isNotEmpty() + deleteSelection() + } + + fun copyToClipboard() { + clipboard = _strokes.value.filter { it.id in selectedIds } + _canPaste.value = clipboard.isNotEmpty() + clearSelection() + } + + fun paste() { + if (clipboard.isEmpty()) return + viewModelScope.launch { + val pageId = _currentPageId.value + undoManager.perform( + CopyStrokesAction( + strokes = clipboard, + pageId = pageId, + repository = pageRepository, + onExecute = { copies -> + _strokes.value = _strokes.value + copies + copies.forEach { onStrokeAdded?.invoke(it) } + }, + onUndo = { ids -> + _strokes.value = _strokes.value.filter { it.id !in ids } + ids.forEach { onStrokeRemoved?.invoke(it) } + }, + ) + ) + } + } + fun copySelection() { val toCopy = _strokes.value.filter { it.id in selectedIds } if (toCopy.isEmpty()) return diff --git a/app/src/main/kotlin/net/metacircular/engpad/ui/editor/PadCanvasView.kt b/app/src/main/kotlin/net/metacircular/engpad/ui/editor/PadCanvasView.kt index 8e16589..a971cfb 100644 --- a/app/src/main/kotlin/net/metacircular/engpad/ui/editor/PadCanvasView.kt +++ b/app/src/main/kotlin/net/metacircular/engpad/ui/editor/PadCanvasView.kt @@ -46,10 +46,11 @@ class PadCanvasView(context: Context) : View(context) { // --- Line snap --- private var strokeOriginX = 0f private var strokeOriginY = 0f - private var maxDistFromOrigin = 0f + private var lastStylusX = 0f // Current pen position for snap check + private var lastStylusY = 0f private var isSnappedToLine = false private val handler = Handler(Looper.getMainLooper()) - private val snapRunnable = Runnable { snapToLine() } + private val snapRunnable = Runnable { trySnapToLine() } // --- Box drawing --- private var boxStartX = 0f @@ -342,7 +343,8 @@ class PadCanvasView(context: Context) : View(context) { @Suppress("ClickableViewAccessibility") override fun onTouchEvent(event: MotionEvent): Boolean { return when (event.getToolType(0)) { - MotionEvent.TOOL_TYPE_STYLUS, MotionEvent.TOOL_TYPE_ERASER -> handleStylusInput(event) + MotionEvent.TOOL_TYPE_STYLUS -> handleStylusInput(event) + MotionEvent.TOOL_TYPE_ERASER -> handleEraserInput(event) // EMR pen eraser button MotionEvent.TOOL_TYPE_FINGER -> handleFingerInput(event) else -> super.onTouchEvent(event) } @@ -372,31 +374,25 @@ class PadCanvasView(context: Context) : View(context) { val pt = screenToCanonical(event.x, event.y) strokeOriginX = pt[0] strokeOriginY = pt[1] - maxDistFromOrigin = 0f + lastStylusX = pt[0] + lastStylusY = pt[1] isSnappedToLine = false currentPoints.clear() currentPoints.add(pt[0]) currentPoints.add(pt[1]) currentPath = Path().apply { moveTo(pt[0], pt[1]) } currentPaint = buildPaint(canvasState.penWidthPt, Color.BLACK) - // Start snap timer + // Start snap timer — will check distance when it fires handler.postDelayed(snapRunnable, LINE_SNAP_DELAY_MS) invalidate() return true } MotionEvent.ACTION_MOVE -> { val path = currentPath ?: return true - // Track max distance from origin; cancel snap if pen moved far - if (!isSnappedToLine) { - val pt = screenToCanonical(event.x, event.y) - val dx = pt[0] - strokeOriginX - val dy = pt[1] - strokeOriginY - val dist = Math.sqrt((dx * dx + dy * dy).toDouble()).toFloat() - if (dist > maxDistFromOrigin) maxDistFromOrigin = dist - if (maxDistFromOrigin > LINE_SNAP_MOVE_THRESHOLD) { - handler.removeCallbacks(snapRunnable) - } - } + // Track current position for snap check + val curPt = screenToCanonical(event.x, event.y) + lastStylusX = curPt[0] + lastStylusY = curPt[1] if (isSnappedToLine) { // In snap mode: draw straight line from origin to current point @@ -445,10 +441,17 @@ class PadCanvasView(context: Context) : View(context) { return true } - private fun snapToLine() { - if (currentPath != null) { + /** + * Called by the snap timer. Checks if pen is still near origin — + * if so, activate line snap. If pen has moved far, do nothing. + */ + private fun trySnapToLine() { + if (currentPath == null) return + val dx = lastStylusX - strokeOriginX + val dy = lastStylusY - strokeOriginY + val dist = Math.sqrt((dx * dx + dy * dy).toDouble()).toFloat() + if (dist <= LINE_SNAP_MOVE_THRESHOLD) { isSnappedToLine = true - // Reset path to just origin — next MOVE will draw the straight line currentPath?.reset() currentPath?.moveTo(strokeOriginX, strokeOriginY) currentPoints.clear() @@ -456,6 +459,7 @@ class PadCanvasView(context: Context) : View(context) { currentPoints.add(strokeOriginY) invalidate() } + // If pen has moved far, don't snap — just let freehand continue } // --- Box drawing --- diff --git a/app/src/main/kotlin/net/metacircular/engpad/ui/editor/Toolbar.kt b/app/src/main/kotlin/net/metacircular/engpad/ui/editor/Toolbar.kt index d35ff26..61e211d 100644 --- a/app/src/main/kotlin/net/metacircular/engpad/ui/editor/Toolbar.kt +++ b/app/src/main/kotlin/net/metacircular/engpad/ui/editor/Toolbar.kt @@ -1,17 +1,22 @@ package net.metacircular.engpad.ui.editor +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.combinedClickable +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width -import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.combinedClickable +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.AlertDialog import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.FilterChip +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable @@ -21,9 +26,39 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +/** + * Tool button — simple Surface with border. No ripple animation for fast + * e-ink response. Selected state shown with filled background. + */ +@Composable +private fun ToolButton( + label: String, + selected: Boolean, + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + Surface( + onClick = onClick, + shape = RoundedCornerShape(8.dp), + color = if (selected) Color.Black else Color.White, + contentColor = if (selected) Color.White else Color.Black, + border = BorderStroke(1.dp, Color.Black), + modifier = modifier.padding(end = 4.dp), + ) { + Text( + text = label, + fontSize = 13.sp, + modifier = Modifier.padding(horizontal = 10.dp, vertical = 6.dp), + ) + } +} + +@OptIn(ExperimentalFoundationApi::class) @Composable fun EditorToolbar( currentTool: Tool, @@ -33,8 +68,11 @@ fun EditorToolbar( onUndo: () -> Unit, onRedo: () -> Unit, hasSelection: Boolean, + onCutSelection: () -> Unit, onDeleteSelection: () -> Unit, onCopySelection: () -> Unit, + onPaste: () -> Unit, + canPaste: Boolean, onExportPdf: () -> Unit, onExportJpg: () -> Unit, onClose: () -> Unit, @@ -46,7 +84,6 @@ fun EditorToolbar( onLineStyleChanged: (LineStyle) -> Unit, modifier: Modifier = Modifier, ) { - var showBinderMenu by remember { mutableStateOf(false) } var showGoToPageDialog by remember { mutableStateOf(false) } Row( @@ -54,104 +91,143 @@ fun EditorToolbar( verticalAlignment = Alignment.CenterVertically, ) { // Close button - TextButton(onClick = onClose) { Text("X") } + ToolButton(label = "X", selected = false, onClick = onClose) - // Binder dropdown - TextButton(onClick = { showBinderMenu = true }) { - Text("p$currentPageNumber/$totalPages") - } - DropdownMenu( - expanded = showBinderMenu, - onDismissRequest = { showBinderMenu = false }, - ) { - DropdownMenuItem( - text = { Text("View all pages") }, - onClick = { - showBinderMenu = false - onViewAllPages() - }, - ) - DropdownMenuItem( - text = { Text("Go to page...") }, - onClick = { - showBinderMenu = false - showGoToPageDialog = true - }, - ) + // Page indicator / binder — outlined button style + Box { + var showBinderMenu by remember { mutableStateOf(false) } + OutlinedButton( + onClick = { showBinderMenu = true }, + shape = RoundedCornerShape(8.dp), + border = BorderStroke(1.dp, Color.Black), + ) { + Text("p$currentPageNumber/$totalPages", fontSize = 13.sp) + } + DropdownMenu( + expanded = showBinderMenu, + onDismissRequest = { showBinderMenu = false }, + ) { + DropdownMenuItem( + text = { Text("View all pages") }, + onClick = { + showBinderMenu = false + onViewAllPages() + }, + ) + DropdownMenuItem( + text = { Text("Go to page\u2026") }, + onClick = { + showBinderMenu = false + showGoToPageDialog = true + }, + ) + } } Spacer(modifier = Modifier.width(8.dp)) - // Tool chips - FilterChip( - selected = currentTool == Tool.PEN_FINE, - onClick = { onToolSelected(Tool.PEN_FINE) }, - label = { Text("0.38") }, - modifier = Modifier.padding(end = 4.dp), - ) - FilterChip( - selected = currentTool == Tool.PEN_MEDIUM, - onClick = { onToolSelected(Tool.PEN_MEDIUM) }, - label = { Text("0.5") }, - modifier = Modifier.padding(end = 4.dp), - ) - FilterChip( - selected = currentTool == Tool.ERASER, - onClick = { onToolSelected(Tool.ERASER) }, - label = { Text("Eraser") }, - modifier = Modifier.padding(end = 4.dp), - ) - FilterChip( - selected = currentTool == Tool.SELECT, - onClick = { onToolSelected(Tool.SELECT) }, - label = { Text("Select") }, - modifier = Modifier.padding(end = 4.dp), - ) - FilterChip( - selected = currentTool == Tool.BOX, - onClick = { onToolSelected(Tool.BOX) }, - label = { Text("Box") }, - modifier = Modifier.padding(end = 4.dp), - ) - LineToolChip( - selected = currentTool == Tool.LINE, - lineStyle = lineStyle, - onSelect = { onToolSelected(Tool.LINE) }, - onStyleChanged = onLineStyleChanged, - ) - if (hasSelection) { - TextButton(onClick = onDeleteSelection) { Text("Del") } - TextButton(onClick = onCopySelection) { Text("Copy") } + // Tools: 0.38 0.5 line box eraser select + ToolButton("0.38", currentTool == Tool.PEN_FINE, { onToolSelected(Tool.PEN_FINE) }) + ToolButton("0.5", currentTool == Tool.PEN_MEDIUM, { onToolSelected(Tool.PEN_MEDIUM) }) + + // Line button with long-press for style + Box { + var showLineMenu by remember { mutableStateOf(false) } + val lineLabel = when (lineStyle) { + LineStyle.PLAIN -> "Line" + LineStyle.ARROW -> "\u2192" + LineStyle.DOUBLE_ARROW -> "\u2194" + LineStyle.DASHED -> "- -" + } + Surface( + onClick = { onToolSelected(Tool.LINE) }, + shape = RoundedCornerShape(8.dp), + color = if (currentTool == Tool.LINE) Color.Black else Color.White, + contentColor = if (currentTool == Tool.LINE) Color.White else Color.Black, + border = BorderStroke(1.dp, Color.Black), + modifier = Modifier + .padding(end = 4.dp) + .combinedClickable( + onClick = { onToolSelected(Tool.LINE) }, + onLongClick = { showLineMenu = true }, + ), + ) { + Text( + text = lineLabel, + fontSize = 13.sp, + modifier = Modifier.padding(horizontal = 10.dp, vertical = 6.dp), + ) + } + DropdownMenu( + expanded = showLineMenu, + onDismissRequest = { showLineMenu = false }, + ) { + LineStyle.entries.forEach { style -> + val name = when (style) { + LineStyle.PLAIN -> "Plain line" + LineStyle.ARROW -> "Arrow \u2192" + LineStyle.DOUBLE_ARROW -> "Double \u2194" + LineStyle.DASHED -> "Dashed" + } + DropdownMenuItem( + text = { Text(name) }, + onClick = { + showLineMenu = false + onLineStyleChanged(style) + onToolSelected(Tool.LINE) + }, + ) + } + } } + + ToolButton("Box", currentTool == Tool.BOX, { onToolSelected(Tool.BOX) }) + ToolButton("Eraser", currentTool == Tool.ERASER, { onToolSelected(Tool.ERASER) }) + ToolButton("Select", currentTool == Tool.SELECT, { onToolSelected(Tool.SELECT) }) + + // Selection operations: cut / del / copy / paste + if (hasSelection || canPaste) { + Spacer(modifier = Modifier.width(4.dp)) + if (hasSelection) { + TextButton(onClick = onCutSelection) { Text("Cut") } + TextButton(onClick = onDeleteSelection) { Text("Del") } + TextButton(onClick = onCopySelection) { Text("Copy") } + } + if (canPaste) { + TextButton(onClick = onPaste) { Text("Paste") } + } + } + Spacer(modifier = Modifier.weight(1f)) - var showExportMenu by remember { mutableStateOf(false) } - TextButton(onClick = { showExportMenu = true }) { Text("Export") } - DropdownMenu( - expanded = showExportMenu, - onDismissRequest = { showExportMenu = false }, - ) { - DropdownMenuItem( - text = { Text("Export as PDF") }, - onClick = { - showExportMenu = false - onExportPdf() - }, - ) - DropdownMenuItem( - text = { Text("Export as JPG") }, - onClick = { - showExportMenu = false - onExportJpg() - }, - ) - } - TextButton(onClick = onUndo, enabled = canUndo) { - Text("Undo") + + // Export dropdown — anchored to its button + Box { + var showExportMenu by remember { mutableStateOf(false) } + TextButton(onClick = { showExportMenu = true }) { Text("Export") } + DropdownMenu( + expanded = showExportMenu, + onDismissRequest = { showExportMenu = false }, + ) { + DropdownMenuItem( + text = { Text("PDF") }, + onClick = { + showExportMenu = false + onExportPdf() + }, + ) + DropdownMenuItem( + text = { Text("JPG") }, + onClick = { + showExportMenu = false + onExportJpg() + }, + ) + } } + + TextButton(onClick = onUndo, enabled = canUndo) { Text("Undo") } Spacer(modifier = Modifier.width(4.dp)) - TextButton(onClick = onRedo, enabled = canRedo) { - Text("Redo") - } + TextButton(onClick = onRedo, enabled = canRedo) { Text("Redo") } } if (showGoToPageDialog) { @@ -207,53 +283,3 @@ private fun GoToPageDialog( }, ) } - -@OptIn(ExperimentalFoundationApi::class) -@Composable -private fun LineToolChip( - selected: Boolean, - lineStyle: LineStyle, - onSelect: () -> Unit, - onStyleChanged: (LineStyle) -> Unit, -) { - var showStyleMenu by remember { mutableStateOf(false) } - val label = when (lineStyle) { - LineStyle.PLAIN -> "Line" - LineStyle.ARROW -> "Arrow" - LineStyle.DOUBLE_ARROW -> "\u2194" // ↔ - LineStyle.DASHED -> "Dash" - } - - FilterChip( - selected = selected, - onClick = { onSelect() }, - label = { Text(label) }, - modifier = Modifier - .padding(end = 4.dp) - .combinedClickable( - onClick = { onSelect() }, - onLongClick = { showStyleMenu = true }, - ), - ) - DropdownMenu( - expanded = showStyleMenu, - onDismissRequest = { showStyleMenu = false }, - ) { - LineStyle.entries.forEach { style -> - val styleName = when (style) { - LineStyle.PLAIN -> "Plain line" - LineStyle.ARROW -> "Single arrow \u2192" - LineStyle.DOUBLE_ARROW -> "Double arrow \u2194" - LineStyle.DASHED -> "Dashed line" - } - DropdownMenuItem( - text = { Text(styleName) }, - onClick = { - showStyleMenu = false - onStyleChanged(style) - onSelect() - }, - ) - } - } -} diff --git a/app/src/main/kotlin/net/metacircular/engpad/ui/navigation/NavGraph.kt b/app/src/main/kotlin/net/metacircular/engpad/ui/navigation/NavGraph.kt index e0a418a..0a5d7a6 100644 --- a/app/src/main/kotlin/net/metacircular/engpad/ui/navigation/NavGraph.kt +++ b/app/src/main/kotlin/net/metacircular/engpad/ui/navigation/NavGraph.kt @@ -33,12 +33,25 @@ object Routes { fun EngPadNavGraph( navController: NavHostController, database: EngPadDatabase, + lastNotebookId: Long = 0, + onNotebookOpened: (Long) -> Unit = {}, + onNotebookClosed: () -> Unit = {}, ) { + // Auto-navigate to last notebook on startup + var autoNavigated by remember { mutableStateOf(false) } + LaunchedEffect(lastNotebookId) { + if (!autoNavigated && lastNotebookId > 0) { + autoNavigated = true + navController.navigate(Routes.editor(lastNotebookId)) + } + } + NavHost(navController = navController, startDestination = Routes.NOTEBOOKS) { composable(Routes.NOTEBOOKS) { NotebookListScreen( database = database, onNotebookClick = { notebookId -> + onNotebookOpened(notebookId) navController.navigate(Routes.editor(notebookId)) }, ) @@ -59,6 +72,7 @@ fun EngPadNavGraph( var initialPageId by remember { mutableStateOf(null) } LaunchedEffect(notebookId) { + onNotebookOpened(notebookId) val notebook = notebookRepo.getById(notebookId) ?: return@LaunchedEffect pageSize = PageSize.fromString(notebook.pageSize) // Use last page or fall back to first page @@ -90,6 +104,7 @@ fun EngPadNavGraph( initialPageId = pid, database = database, onClose = { + onNotebookClosed() navController.popBackStack(Routes.NOTEBOOKS, false) }, onViewAllPages = { diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml index 6018b14..046f782 100644 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -4,7 +4,13 @@ android:height="108dp" android:viewportWidth="108" android:viewportHeight="108"> + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml index f114a53..fea5fbd 100644 --- a/app/src/main/res/drawable/ic_launcher_foreground.xml +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -4,8 +4,31 @@ android:height="108dp" android:viewportWidth="108" android:viewportHeight="108"> - + + + + android:strokeColor="#2C2C2C" + android:strokeWidth="2" + android:strokeLineCap="round" + android:pathData="M54,35 L37,67 M54,35 L71,67 M37,67 L71,67" /> + + + + + + + + +