diff --git a/app/build.gradle b/app/build.gradle index 3b3b6cce..674b5c38 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -24,8 +24,8 @@ android { minSdkVersion 21 compileSdk 34 targetSdkVersion 34 - versionCode 21 - versionName "2.0.2" + versionCode 22 + versionName "2.0.3" } applicationVariants.configureEach { variant -> diff --git a/app/src/main/java/org/secuso/privacyfriendlynotes/PFNotesApplication.kt b/app/src/main/java/org/secuso/privacyfriendlynotes/PFNotesApplication.kt index f068f9f9..d2142899 100644 --- a/app/src/main/java/org/secuso/privacyfriendlynotes/PFNotesApplication.kt +++ b/app/src/main/java/org/secuso/privacyfriendlynotes/PFNotesApplication.kt @@ -34,7 +34,7 @@ class PFNotesApplication : Application(), Configuration.Provider { backupRestorer = BackupRestorer() } - override fun getWorkManagerConfiguration(): Configuration { - return Configuration.Builder().setMinimumLoggingLevel(Log.INFO).build() + override val workManagerConfiguration by lazy { + Configuration.Builder().setMinimumLoggingLevel(Log.INFO).build() } } diff --git a/app/src/main/java/org/secuso/privacyfriendlynotes/backup/BackupRestorer.java b/app/src/main/java/org/secuso/privacyfriendlynotes/backup/BackupRestorer.java index d94a3206..569687ce 100644 --- a/app/src/main/java/org/secuso/privacyfriendlynotes/backup/BackupRestorer.java +++ b/app/src/main/java/org/secuso/privacyfriendlynotes/backup/BackupRestorer.java @@ -127,7 +127,9 @@ private void readPreferences(@NonNull JsonReader reader, @NonNull Context contex "settings_dialog_on_trashing", "settings_color_category", "notes_reversed_ordering", - "settings_sketch_undo_redo" -> editor.putBoolean(name, reader.nextBoolean()); + "settings_sketch_undo_redo", + "settings_import_text_title_file_first_line", + "settings_color_category_always_background" -> editor.putBoolean(name, reader.nextBoolean()); case "settings_font_size", "settings_day_night_theme", "notes_ordering" -> editor.putString(name, reader.nextString()); default -> throw new RuntimeException("Unknown preference " + name); } diff --git a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/adapter/ChecklistAdapter.kt b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/adapter/ChecklistAdapter.kt index bacf09b7..41b080ac 100644 --- a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/adapter/ChecklistAdapter.kt +++ b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/adapter/ChecklistAdapter.kt @@ -119,6 +119,7 @@ class ChecklistAdapter( fun removeItem(position: Int) { this.items.removeAt(position) + hasChanged = true notifyItemRemoved(position) } diff --git a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/adapter/NoteAdapter.kt b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/adapter/NoteAdapter.kt index b96fd394..da12ad9a 100644 --- a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/adapter/NoteAdapter.kt +++ b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/adapter/NoteAdapter.kt @@ -80,22 +80,24 @@ class NoteAdapter( if (colorCategory) { mainActivityViewModel.categoryColor(currentNote.category) { + val colorBackground = PreferenceManager.getDefaultSharedPreferences(holder.textViewTitle.context) + .getBoolean("settings_color_category_always_background", false) || !DarkModeUtil.isDarkMode(holder.textViewTitle.context) - if (DarkModeUtil.isDarkMode(holder.textViewTitle.context)) { + if (colorBackground) { val color: Int = it?.let { Color.parseColor(it) } ?: run { val value = TypedValue() - holder.itemView.context.theme.resolveAttribute(R.attr.colorOnBackground, value, true) + holder.itemView.context.theme.resolveAttribute(R.attr.colorSurface, value, true) value.data } - holder.textViewTitle.setTextColor(color) - holder.textViewExtraText.setTextColor(color) + holder.viewNoteItem.setBackgroundColor(color) } else { val color: Int = it?.let { Color.parseColor(it) } ?: run { val value = TypedValue() - holder.itemView.context.theme.resolveAttribute(R.attr.colorSurface, value, true) + holder.itemView.context.theme.resolveAttribute(R.attr.colorOnBackground, value, true) value.data } - holder.viewNoteItem.setBackgroundColor(color) + holder.textViewTitle.setTextColor(color) + holder.textViewExtraText.setTextColor(color) } } } diff --git a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/main/MainActivityViewModel.kt b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/main/MainActivityViewModel.kt index 521780f8..82a1df17 100644 --- a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/main/MainActivityViewModel.kt +++ b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/main/MainActivityViewModel.kt @@ -245,7 +245,8 @@ class MainActivityViewModel(application: Application) : AndroidViewModel(applica throw IllegalArgumentException("Only checklist notes allowed") } return ChecklistUtil.parse(note.content).map { (checked, name) -> - return@map Pair(checked, "[${if (checked) "x" else " "}] $name") + val preview = if (name.length > 30) name.take(30) + "..." else name.take(33) + return@map Pair(checked, "[${if (checked) "x" else " "}] $preview") } } diff --git a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/notes/BaseNoteActivity.kt b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/notes/BaseNoteActivity.kt index 8e9e76ca..ef1626fe 100644 --- a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/notes/BaseNoteActivity.kt +++ b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/notes/BaseNoteActivity.kt @@ -91,6 +91,8 @@ abstract class BaseNoteActivity(noteType: Int) : AppCompatActivity(), View.OnCli } private val etName by lazy { findViewById(R.id.etName) as EditText } + val noteTitle: String + get() = etName.text.toString() private val catSelection by lazy { findViewById(R.id.spinner_category) as AutoCompleteTextView } private lateinit var reminder: MenuItem diff --git a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/notes/ChecklistNoteActivity.kt b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/notes/ChecklistNoteActivity.kt index f8366580..0e888c97 100644 --- a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/notes/ChecklistNoteActivity.kt +++ b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/notes/ChecklistNoteActivity.kt @@ -167,7 +167,7 @@ class ChecklistNoteActivity : BaseNoteActivity(DbContract.NoteEntry.TYPE_CHECKLI } private fun getContentString(): String { - return adapter.getItems().joinToString(System.lineSeparator()) { (checked, name) -> "- [${if (checked) "x" else " "}] $name" } + return adapter.getItems().joinToString(System.lineSeparator()) { (checked, name) -> "- [${if (checked) "x" else " "}] $name" } } private fun addItem() { diff --git a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/notes/TextNoteActivity.kt b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/notes/TextNoteActivity.kt index c27806d1..a4b3068f 100644 --- a/app/src/main/java/org/secuso/privacyfriendlynotes/ui/notes/TextNoteActivity.kt +++ b/app/src/main/java/org/secuso/privacyfriendlynotes/ui/notes/TextNoteActivity.kt @@ -13,31 +13,36 @@ */ package org.secuso.privacyfriendlynotes.ui.notes +import android.app.Activity import android.content.Intent import android.content.res.ColorStateList import android.graphics.Color import android.graphics.Typeface import android.net.Uri import android.os.Bundle +import android.provider.OpenableColumns import android.text.Html import android.text.Spannable import android.text.SpannableStringBuilder import android.text.Spanned import android.text.style.StyleSpan import android.text.style.UnderlineSpan -import android.util.Log import android.view.ContextThemeWrapper import android.view.Menu import android.view.MenuItem import android.view.View import android.widget.EditText +import android.widget.Toast +import androidx.activity.result.contract.ActivityResultContracts import androidx.lifecycle.MutableLiveData +import androidx.preference.PreferenceManager import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.floatingactionbutton.FloatingActionButton import org.secuso.privacyfriendlynotes.R import org.secuso.privacyfriendlynotes.room.DbContract import org.secuso.privacyfriendlynotes.room.model.Note import org.secuso.privacyfriendlynotes.ui.util.ChecklistUtil +import java.io.File import java.io.InputStreamReader import java.io.OutputStream import java.io.PrintWriter @@ -121,6 +126,13 @@ class TextNoteActivity : BaseNoteActivity(DbContract.NoteEntry.TYPE_TEXT) { .setIcon(android.R.drawable.ic_dialog_alert) .show() } + R.id.action_export_plain -> { + val intent = Intent(Intent.ACTION_CREATE_DOCUMENT) + intent.addCategory(Intent.CATEGORY_OPENABLE) + intent.putExtra(Intent.EXTRA_TITLE, noteTitle + getFileExtension()) + intent.type = getMimeType() + saveToExternalStorageResultLauncher.launch(intent) + } else -> {} } @@ -131,13 +143,19 @@ class TextNoteActivity : BaseNoteActivity(DbContract.NoteEntry.TYPE_TEXT) { if (intent != null) { val uri: Uri? = listOf(intent.data, intent.getParcelableExtra(Intent.EXTRA_STREAM)).firstNotNullOfOrNull { it } if (uri != null) { - val text = InputStreamReader(contentResolver.openInputStream(uri)).readLines() - super.setTitle(text[0]) - etContent.setText(Html.fromHtml(text.subList(1, text.size).joinToString("
"))) + val (title: String, text) = InputStreamReader(contentResolver.openInputStream(uri)).readLines().let { + if (it.size > 1 && + PreferenceManager.getDefaultSharedPreferences(this@TextNoteActivity).getBoolean("settings_import_text_title_file_first_line", false)) { + it[0] to it.subList(1, it.size) + } else { + (uri.path?.let { file -> File(file).nameWithoutExtension } ?: "") to it + } + } + super.setTitle(Html.fromHtml(title).toString()) + etContent.setText(Html.fromHtml(text.joinToString("
"))) } - val text = intent.getStringExtra(Intent.EXTRA_TEXT) - if (text != null) { - etContent.setText(Html.fromHtml(text)) + intent.getStringExtra(Intent.EXTRA_TEXT)?.let { + etContent.setText(Html.fromHtml(it)) } } } @@ -424,10 +442,28 @@ class TextNoteActivity : BaseNoteActivity(DbContract.NoteEntry.TYPE_TEXT) { override fun getFileExtension() = ".txt" + private val saveToExternalStorageResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == Activity.RESULT_OK) { + result.data?.data?.let { uri -> + val fileOutputStream: OutputStream? = contentResolver.openOutputStream(uri) + fileOutputStream?.let { + val out = PrintWriter(it) + out.println(Html.toHtml(etContent.text)) + out.close() + Toast.makeText( + applicationContext, + String.format(getString(R.string.toast_file_exported_to), uri.toString()), + Toast.LENGTH_LONG + ).show() + } + fileOutputStream?.close() + } + } + } override fun onSaveExternalStorage(outputStream: OutputStream) { val out = PrintWriter(outputStream) - out.println(Html.toHtml(etContent.text)) + out.println(Html.fromHtml(Html.toHtml(etContent.text)).toString()) out.close() } } \ No newline at end of file diff --git a/app/src/main/res/drawable/baseline_html_24.xml b/app/src/main/res/drawable/baseline_html_24.xml new file mode 100644 index 00000000..f17a2a06 --- /dev/null +++ b/app/src/main/res/drawable/baseline_html_24.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/layout/activity_checklist_note.xml b/app/src/main/res/layout/activity_checklist_note.xml index bccbcf1b..d2d780bf 100644 --- a/app/src/main/res/layout/activity_checklist_note.xml +++ b/app/src/main/res/layout/activity_checklist_note.xml @@ -21,11 +21,10 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:id="@+id/etNewItem" - android:singleLine="true" android:layout_weight="1" android:hint="@string/hint_new_item" android:textColor="?attr/colorOnBackground" - android:inputType="textCapSentences" /> + android:inputType="textCapSentences|textMultiLine" />