From e785de3ee84cbe6e7b161c9858d1234cd06d5a37 Mon Sep 17 00:00:00 2001 From: Crustack Date: Tue, 31 Mar 2026 22:19:28 +0200 Subject: [PATCH 1/5] Add pin to status bar note action --- .../main/res/drawable/notification_unpin.xml | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 app/src/main/res/drawable/notification_unpin.xml diff --git a/app/src/main/res/drawable/notification_unpin.xml b/app/src/main/res/drawable/notification_unpin.xml new file mode 100644 index 00000000..81b288d8 --- /dev/null +++ b/app/src/main/res/drawable/notification_unpin.xml @@ -0,0 +1,33 @@ + + + + + + + + + \ No newline at end of file From 570f2002b7f09c2bcb98e094dd5695e56c33a3be Mon Sep 17 00:00:00 2001 From: Crustack Date: Wed, 1 Apr 2026 20:34:00 +0200 Subject: [PATCH 2/5] Support changing labels order via drag and drop --- .../11.json | 176 ++++++++++++++++++ .../philkes/notallyx/data/NotallyDatabase.kt | 21 ++- .../philkes/notallyx/data/dao/CommonDao.kt | 12 +- .../com/philkes/notallyx/data/dao/LabelDao.kt | 15 +- .../notallyx/data/imports/NotesImporter.kt | 10 +- .../com/philkes/notallyx/data/model/Label.kt | 2 +- .../activity/main/MainActivity.kt | 14 +- .../activity/main/fragment/LabelsFragment.kt | 70 ++++++- .../fragment/settings/SettingsFragment.kt | 2 +- .../activity/note/SelectLabelsActivity.kt | 10 +- .../view/main/label/LabelAdapter.kt | 10 +- .../view/main/label/LabelListener.kt | 4 + .../presentation/view/main/label/LabelVH.kt | 12 +- .../view/main/label/SelectableLabelAdapter.kt | 18 +- .../view/main/label/SelectableLabelVH.kt | 5 +- .../presentation/viewmodel/BaseNoteModel.kt | 20 +- .../notallyx/utils/backup/ImportExtensions.kt | 4 +- .../utils/backup/MigrationsExtensions.kt | 6 +- .../utils/backup/XmlParserExtensions.kt | 8 +- .../main/res/layout-v26/recycler_label.xml | 19 +- app/src/main/res/layout/recycler_label.xml | 11 ++ 21 files changed, 403 insertions(+), 46 deletions(-) create mode 100644 app/schemas/com.philkes.notallyx.data.NotallyDatabase/11.json diff --git a/app/schemas/com.philkes.notallyx.data.NotallyDatabase/11.json b/app/schemas/com.philkes.notallyx.data.NotallyDatabase/11.json new file mode 100644 index 00000000..3a3b430c --- /dev/null +++ b/app/schemas/com.philkes.notallyx.data.NotallyDatabase/11.json @@ -0,0 +1,176 @@ +{ + "formatVersion": 1, + "database": { + "version": 11, + "identityHash": "80a04d33cf13bc8ca45396f5a5d85e61", + "entities": [ + { + "tableName": "BaseNote", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` TEXT NOT NULL, `folder` TEXT NOT NULL, `color` TEXT NOT NULL, `title` TEXT NOT NULL, `pinned` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `modifiedTimestamp` INTEGER NOT NULL, `labels` TEXT NOT NULL, `body` TEXT NOT NULL, `spans` TEXT NOT NULL, `items` TEXT NOT NULL, `images` TEXT NOT NULL, `files` TEXT NOT NULL, `audios` TEXT NOT NULL, `reminders` TEXT NOT NULL, `viewMode` TEXT NOT NULL, `isPinnedToStatus` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "folder", + "columnName": "folder", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pinned", + "columnName": "pinned", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "modifiedTimestamp", + "columnName": "modifiedTimestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "labels", + "columnName": "labels", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "body", + "columnName": "body", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "spans", + "columnName": "spans", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "items", + "columnName": "items", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "images", + "columnName": "images", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "files", + "columnName": "files", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "audios", + "columnName": "audios", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "reminders", + "columnName": "reminders", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "viewMode", + "columnName": "viewMode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isPinnedToStatus", + "columnName": "isPinnedToStatus", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_BaseNote_id_folder_pinned_timestamp_labels", + "unique": false, + "columnNames": [ + "id", + "folder", + "pinned", + "timestamp", + "labels" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_BaseNote_id_folder_pinned_timestamp_labels` ON `${TABLE_NAME}` (`id`, `folder`, `pinned`, `timestamp`, `labels`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "Label", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`value` TEXT NOT NULL, `order` INTEGER NOT NULL, PRIMARY KEY(`value`))", + "fields": [ + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "order", + "columnName": "order", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "value" + ] + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '80a04d33cf13bc8ca45396f5a5d85e61')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/com/philkes/notallyx/data/NotallyDatabase.kt b/app/src/main/java/com/philkes/notallyx/data/NotallyDatabase.kt index f5a8011e..7895e580 100644 --- a/app/src/main/java/com/philkes/notallyx/data/NotallyDatabase.kt +++ b/app/src/main/java/com/philkes/notallyx/data/NotallyDatabase.kt @@ -33,7 +33,7 @@ import java.io.File import net.zetetic.database.sqlcipher.SupportOpenHelperFactory @TypeConverters(Converters::class) -@Database(entities = [BaseNote::class, Label::class], version = 10) +@Database(entities = [BaseNote::class, Label::class], version = 11) abstract class NotallyDatabase : RoomDatabase() { abstract fun getLabelDao(): LabelDao @@ -162,6 +162,7 @@ abstract class NotallyDatabase : RoomDatabase() { Migration8, Migration9, Migration10, + Migration11 ) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { System.loadLibrary("sqlcipher") @@ -310,5 +311,23 @@ abstract class NotallyDatabase : RoomDatabase() { ) } } + + object Migration11 : Migration(10, 11) { + + override fun migrate(db: SupportSQLiteDatabase) { + db.execSQL("ALTER TABLE `Label` ADD COLUMN `order` INTEGER NOT NULL DEFAULT 0") + val cursor = db.query("SELECT value FROM Label ORDER BY value DESC") + var order = 0 + while (cursor.moveToNext()) { + val value = cursor.getString(0) + db.execSQL( + "UPDATE Label SET `order` = ? WHERE value = ?", + arrayOf(order, value), + ) + order++ + } + cursor.close() + } + } } } diff --git a/app/src/main/java/com/philkes/notallyx/data/dao/CommonDao.kt b/app/src/main/java/com/philkes/notallyx/data/dao/CommonDao.kt index e7f17c81..e4965f51 100644 --- a/app/src/main/java/com/philkes/notallyx/data/dao/CommonDao.kt +++ b/app/src/main/java/com/philkes/notallyx/data/dao/CommonDao.kt @@ -65,7 +65,11 @@ abstract class CommonDao(private val database: NotallyDatabase) { duplicates++ } } - database.getLabelDao().insert(labels) + val labelDao = database.getLabelDao() + val maxOrder = labelDao.getMaxOrder() ?: -1 + labelDao.insert( + labels.mapIndexed { index, label -> Label(label.value, maxOrder + 1 + index) } + ) return ImportResult(inserted = insertedCount, duplicates = duplicates) } @@ -134,7 +138,11 @@ abstract class CommonDao(private val database: NotallyDatabase) { } } - database.getLabelDao().insert(labels) + val labelDaoForRemap = database.getLabelDao() + val maxOrderForRemap = labelDaoForRemap.getMaxOrder() ?: -1 + labelDaoForRemap.insert( + labels.mapIndexed { index, label -> Label(label.value, maxOrderForRemap + 1 + index) } + ) return ImportResult(inserted = insertedCount, duplicates = duplicates) } diff --git a/app/src/main/java/com/philkes/notallyx/data/dao/LabelDao.kt b/app/src/main/java/com/philkes/notallyx/data/dao/LabelDao.kt index ec2d8ca7..d240af55 100644 --- a/app/src/main/java/com/philkes/notallyx/data/dao/LabelDao.kt +++ b/app/src/main/java/com/philkes/notallyx/data/dao/LabelDao.kt @@ -5,15 +5,20 @@ import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query +import androidx.room.Update import com.philkes.notallyx.data.model.Label @Dao interface LabelDao { - @Insert suspend fun insert(label: Label) + @Insert(onConflict = OnConflictStrategy.IGNORE) suspend fun insert(label: Label) @Insert(onConflict = OnConflictStrategy.IGNORE) suspend fun insert(labels: List