diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/notes/NotesWidget.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/notes/NotesWidget.kt index edd91d6c..d00d5aac 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/notes/NotesWidget.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/notes/NotesWidget.kt @@ -1,40 +1,111 @@ package de.mm20.launcher2.ui.launcher.widgets.notes +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.text.BasicTextField -import androidx.compose.material3.LocalContentColor -import androidx.compose.material3.MaterialTheme +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Add +import androidx.compose.material.icons.rounded.Delete +import androidx.compose.material.icons.rounded.MoreVert +import androidx.compose.material.icons.rounded.SaveAlt +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +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.SolidColor +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import de.mm20.launcher2.ui.R import de.mm20.launcher2.ui.component.markdown.MarkdownEditor import de.mm20.launcher2.widgets.NotesWidget +import java.time.ZonedDateTime +import java.time.format.DateTimeFormatter @Composable fun NotesWidget(widget: NotesWidget) { - val viewModel: NotesWidgetVM = viewModel(key = "notes-widget-${widget.id}", factory = NotesWidgetVM.Factory) + val context = LocalContext.current + val viewModel: NotesWidgetVM = + viewModel(key = "notes-widget-${widget.id}", factory = NotesWidgetVM.Factory) LaunchedEffect(widget) { viewModel.updateWidget(widget) } - val text by viewModel.noteText - - MarkdownEditor( - value = text, - onValueChange = { viewModel.setText(it) }, - modifier = Modifier.fillMaxWidth().padding(16.dp), - placeholder = { - Text(stringResource(R.string.notes_widget_placeholder)) + val exportLauncher = rememberLauncherForActivityResult( + contract = ActivityResultContracts.CreateDocument("text/markdown"), + onResult = { + if (it != null) viewModel.exportNote(context, it) } ) + + val text by viewModel.noteText + Column { + MarkdownEditor( + value = text, + onValueChange = { viewModel.setText(it) }, + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + placeholder = { + Text(stringResource(R.string.notes_widget_placeholder)) + } + ) + + AnimatedVisibility(text.isNotBlank()) { + var showMenu by remember { mutableStateOf(false) } + Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.CenterEnd) { + Box { + IconButton(onClick = { showMenu = true }) { + Icon(Icons.Rounded.MoreVert, null) + } + DropdownMenu(expanded = showMenu, onDismissRequest = { showMenu = false }) { + DropdownMenuItem( + text = { Text("New note") }, + leadingIcon = { + Icon(Icons.Rounded.Add, null) + }, + onClick = { /*TODO*/ }, + ) + DropdownMenuItem( + text = { Text(stringResource(R.string.notes_widget_action_save)) }, + leadingIcon = { + Icon(Icons.Rounded.SaveAlt, null) + }, + onClick = { + val fileName = context.getString( + R.string.notes_widget_export_filename, + ZonedDateTime.now().format( + DateTimeFormatter.ISO_INSTANT + ) + ) + exportLauncher.launch("$fileName.md") + showMenu = false + }, + ) + DropdownMenuItem( + text = { Text("Dismiss") }, + leadingIcon = { + Icon(Icons.Rounded.Delete, null) + }, + onClick = { /*TODO*/ }, + ) + } + } + } + } + } } \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/notes/NotesWidgetVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/notes/NotesWidgetVM.kt index b2c56cb0..e982c8a0 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/notes/NotesWidgetVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/notes/NotesWidgetVM.kt @@ -1,5 +1,7 @@ package de.mm20.launcher2.ui.launcher.widgets.notes +import android.content.Context +import android.net.Uri import android.util.Log import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel @@ -8,14 +10,11 @@ import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.viewModelFactory import de.mm20.launcher2.services.widgets.WidgetsService import de.mm20.launcher2.widgets.NotesWidget +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.launch -import org.intellij.markdown.ast.ASTNode -import org.intellij.markdown.ast.getTextInNode -import org.intellij.markdown.flavours.commonmark.CommonMarkFlavourDescriptor -import org.intellij.markdown.parser.MarkdownParser import org.koin.core.component.KoinComponent import org.koin.core.component.get @@ -43,6 +42,17 @@ class NotesWidgetVM( } } + fun exportNote(context: Context, uri: Uri) { + viewModelScope.launch(Dispatchers.IO) { + val text = noteText.value + Log.d("MM20", text) + val outputStream = context.contentResolver.openOutputStream(uri) + outputStream?.use { + it.write(text.toByteArray()) + } + } + } + companion object: KoinComponent { val Factory = viewModelFactory { initializer { diff --git a/core/i18n/src/main/res/values/strings.xml b/core/i18n/src/main/res/values/strings.xml index e8ada5c1..f95e5588 100644 --- a/core/i18n/src/main/res/values/strings.xml +++ b/core/i18n/src/main/res/values/strings.xml @@ -225,6 +225,13 @@ More Write a note… + New note + + Save + + Note_%1$s + Dismiss + Note dismissed. By %1$s