diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..58f2723a --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: bijoyskochar +open_collective: # Replace with a single Open Collective username +ko_fi: bijoyskochar +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: bijoyskochar +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/app/build.gradle b/app/build.gradle index 54230293..1f33484f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,11 +10,11 @@ android { defaultConfig { applicationId "com.bijoysingh.quicknote" - minSdkVersion 17 + minSdkVersion 21 targetSdkVersion 28 - versionCode 125 - versionName '6.9.7' - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + versionCode 156 + versionName '7.5.4' + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 291b20a6..b6ea897a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ @@ -15,20 +16,12 @@ android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" - android:theme="@style/AppTheme"> - - - - + android:theme="@style/AppTheme" + tools:ignore="GoogleAppIndexingWarning"> @@ -40,81 +33,6 @@ android:name="android.app.shortcuts" android:resource="@xml/shortcuts" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/java/com/bijoysingh/quicknote/MaterialNotes.kt b/app/src/main/java/com/bijoysingh/quicknote/MaterialNotes.kt index d9d43e54..0da8f077 100644 --- a/app/src/main/java/com/bijoysingh/quicknote/MaterialNotes.kt +++ b/app/src/main/java/com/bijoysingh/quicknote/MaterialNotes.kt @@ -1,16 +1,17 @@ package com.bijoysingh.quicknote import com.maubis.scarlet.base.config.ApplicationBase -import com.maubis.scarlet.base.config.CoreConfig import com.maubis.scarlet.base.config.MaterialNoteConfig import com.maubis.scarlet.base.export.support.ExternalFolderSync +import com.maubis.scarlet.base.support.utils.Flavor class MaterialNotes : ApplicationBase() { override fun onCreate() { super.onCreate() - CoreConfig.instance = MaterialNoteConfig(this) - CoreConfig.instance.themeController().setup(this) + sAppFlavor = Flavor.NONE + + ApplicationBase.instance = MaterialNoteConfig(this) ExternalFolderSync.setup(this) } } \ No newline at end of file diff --git a/base/build.gradle b/base/build.gradle index 233f9ac3..e05df6f9 100644 --- a/base/build.gradle +++ b/base/build.gradle @@ -17,7 +17,13 @@ android { arguments = ["room.schemaLocation": "$projectDir/schemas".toString()] } } - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + kapt { + arguments { + arg("room.schemaLocation", "$projectDir/schemas") + } + } + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + resValue "string", "file_provider_name", "com.maubis.scarlet.pro.base.support.GenericFileProvider" } buildTypes { @@ -35,50 +41,48 @@ android { dependencies { api project(':markdown') - api "com.android.support:recyclerview-v7:$android_support_version" - api "com.android.support:cardview-v7:$android_support_version" - api "com.android.support:support-v4:$android_support_version" - api "com.android.support:design:$android_support_version" - api "com.android.support:appcompat-v7:$android_support_version" - api 'com.android.support.constraint:constraint-layout:1.1.3' + api 'androidx.recyclerview:recyclerview:1.1.0' + api 'androidx.cardview:cardview:1.0.0' + api 'androidx.legacy:legacy-support-v4:1.0.0' + api 'androidx.appcompat:appcompat:1.1.0' + api 'androidx.constraintlayout:constraintlayout:1.1.3' + + api 'com.google.android.material:material:1.0.0' api 'com.google.code.gson:gson:2.8.5' - api 'com.github.ajalt.reprint:core:3.2.0@aar' - api "com.github.bijoysingh:android-basics:5.0.0" - api "com.github.bijoysingh:ui-basics:0.7.0" + api "com.github.bijoysingh:android-basics:5.1.0-x" + api "com.github.bijoysingh:ui-basics:1.0.0-x" api 'com.github.bijoysingh:floating-bubble:3.0.0' api 'com.evernote:android-job:1.2.6' implementation 'com.google.android:flexbox:0.3.2' - def room_version = "1.1.1" - implementation "android.arch.persistence.room:runtime:$room_version" - implementation "android.arch.persistence.room:testing:$room_version" - annotationProcessor "android.arch.persistence.room:compiler:$room_version" - kapt "android.arch.persistence.room:compiler:$room_version" + api 'androidx.room:room-runtime:2.2.2' + api 'androidx.room:room-testing:2.2.2' + kapt 'androidx.room:room-compiler:2.2.2' + + def biometric_version = "1.0.0" + implementation "androidx.biometric:biometric:$biometric_version" - implementation 'com.github.ajalt.reprint:core:3.2.0@aar' implementation 'com.github.jkwiecien:EasyImage:1.3.1' api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" api 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1' api "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1" - def litho_version = "0.21.0" - implementation "com.facebook.litho:litho-core:$litho_version" - implementation "com.facebook.litho:litho-widget:$litho_version" - implementation 'com.android.support.constraint:constraint-layout:1.1.3' + def litho_version = "0.31.0" + api "com.facebook.litho:litho-core:$litho_version" + api "com.facebook.litho:litho-widget:$litho_version" compileOnly "com.facebook.litho:litho-annotations:$litho_version" kapt "com.facebook.litho:litho-processor:$litho_version" + api 'com.facebook.soloader:soloader:0.5.1' - implementation 'com.facebook.soloader:soloader:0.5.1' - - androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { + androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', { exclude group: 'com.android.support', module: 'support-annotations' }) - testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' } apply plugin: 'kotlin-android-extensions' \ No newline at end of file diff --git a/base/proguard-rules.pro b/base/proguard-rules.pro index f1b42451..edf0b1d3 100644 --- a/base/proguard-rules.pro +++ b/base/proguard-rules.pro @@ -19,3 +19,15 @@ # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile + +-dontwarn android.text.StaticLayout +-dontwarn android.view.DisplayList +-dontwarn android.view.RenderNode +-dontwarn android.view.DisplayListCanvas +-dontwarn android.view.HardwareCanvas + +-dontwarn com.facebook.fbui.** +-dontwarn com.facebook.litho.** + +-dontwarn com.github.bijoysingh.starter.server.** +-keep class com.facebook.yoga.** { *; } diff --git a/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/10.json b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/10.json new file mode 100644 index 00000000..c2d7aaec --- /dev/null +++ b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/10.json @@ -0,0 +1,190 @@ +{ + "formatVersion": 1, + "database": { + "version": 10, + "identityHash": "772aa0db40c8d5c7379af2f0657435e9", + "entities": [ + { + "tableName": "note", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT, `title` TEXT, `description` TEXT, `displayTimestamp` TEXT, `timestamp` INTEGER, `color` INTEGER, `state` TEXT, `locked` INTEGER NOT NULL, `tags` TEXT, `updateTimestamp` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, `uuid` TEXT, `meta` TEXT)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "displayTimestamp", + "columnName": "displayTimestamp", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "locked", + "columnName": "locked", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "tags", + "columnName": "tags", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "updateTimestamp", + "columnName": "updateTimestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "pinned", + "columnName": "pinned", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "meta", + "columnName": "meta", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_note_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX `index_note_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "tag", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `uuid` TEXT)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_tag_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX `index_tag_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "widget", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`widgetId` INTEGER NOT NULL, `noteUUID` TEXT, PRIMARY KEY(`widgetId`))", + "fields": [ + { + "fieldPath": "widgetId", + "columnName": "widgetId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "noteUUID", + "columnName": "noteUUID", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "widgetId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_widget_widgetId", + "unique": false, + "columnNames": [ + "widgetId" + ], + "createSql": "CREATE INDEX `index_widget_widgetId` ON `${TABLE_NAME}` (`widgetId`)" + } + ], + "foreignKeys": [] + } + ], + "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, \"772aa0db40c8d5c7379af2f0657435e9\")" + ] + } +} \ No newline at end of file diff --git a/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/11.json b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/11.json new file mode 100644 index 00000000..2bf7b579 --- /dev/null +++ b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/11.json @@ -0,0 +1,196 @@ +{ + "formatVersion": 1, + "database": { + "version": 11, + "identityHash": "2b7771cb918cb46288978c977be868f2", + "entities": [ + { + "tableName": "note", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT, `title` TEXT, `description` TEXT, `displayTimestamp` TEXT, `timestamp` INTEGER, `color` INTEGER, `state` TEXT, `locked` INTEGER NOT NULL, `tags` TEXT, `updateTimestamp` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, `uuid` TEXT, `meta` TEXT, `disableBackup` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "displayTimestamp", + "columnName": "displayTimestamp", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "locked", + "columnName": "locked", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "tags", + "columnName": "tags", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "updateTimestamp", + "columnName": "updateTimestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "pinned", + "columnName": "pinned", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "meta", + "columnName": "meta", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "disableBackup", + "columnName": "disableBackup", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_note_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX `index_note_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "tag", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `uuid` TEXT)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_tag_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX `index_tag_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "widget", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`widgetId` INTEGER NOT NULL, `noteUUID` TEXT, PRIMARY KEY(`widgetId`))", + "fields": [ + { + "fieldPath": "widgetId", + "columnName": "widgetId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "noteUUID", + "columnName": "noteUUID", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "widgetId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_widget_widgetId", + "unique": false, + "columnNames": [ + "widgetId" + ], + "createSql": "CREATE INDEX `index_widget_widgetId` ON `${TABLE_NAME}` (`widgetId`)" + } + ], + "foreignKeys": [] + } + ], + "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, \"2b7771cb918cb46288978c977be868f2\")" + ] + } +} \ No newline at end of file diff --git a/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/12.json b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/12.json new file mode 100644 index 00000000..10c0d8c8 --- /dev/null +++ b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/12.json @@ -0,0 +1,255 @@ +{ + "formatVersion": 1, + "database": { + "version": 12, + "identityHash": "4fa11b193441aaf148468c857eec12ba", + "entities": [ + { + "tableName": "note", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT, `title` TEXT, `description` TEXT, `displayTimestamp` TEXT, `timestamp` INTEGER, `color` INTEGER, `state` TEXT, `locked` INTEGER NOT NULL, `tags` TEXT, `updateTimestamp` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, `uuid` TEXT, `meta` TEXT, `disableBackup` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "displayTimestamp", + "columnName": "displayTimestamp", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "locked", + "columnName": "locked", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "tags", + "columnName": "tags", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "updateTimestamp", + "columnName": "updateTimestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "pinned", + "columnName": "pinned", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "meta", + "columnName": "meta", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "disableBackup", + "columnName": "disableBackup", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_note_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX `index_note_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "tag", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `uuid` TEXT)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_tag_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX `index_tag_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "widget", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`widgetId` INTEGER NOT NULL, `noteUUID` TEXT, PRIMARY KEY(`widgetId`))", + "fields": [ + { + "fieldPath": "widgetId", + "columnName": "widgetId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "noteUUID", + "columnName": "noteUUID", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "widgetId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_widget_widgetId", + "unique": false, + "columnNames": [ + "widgetId" + ], + "createSql": "CREATE INDEX `index_widget_widgetId` ON `${TABLE_NAME}` (`widgetId`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "folder", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `timestamp` INTEGER, `updateTimestamp` INTEGER NOT NULL, `color` INTEGER, `uuid` TEXT)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "updateTimestamp", + "columnName": "updateTimestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_folder_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX `index_folder_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + } + ], + "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, \"4fa11b193441aaf148468c857eec12ba\")" + ] + } +} \ No newline at end of file diff --git a/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/14.json b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/14.json new file mode 100644 index 00000000..f2cb56ee --- /dev/null +++ b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/14.json @@ -0,0 +1,262 @@ +{ + "formatVersion": 1, + "database": { + "version": 14, + "identityHash": "27a1b0ae4247b917be454c0e96798974", + "entities": [ + { + "tableName": "note", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT, `title` TEXT, `description` TEXT, `displayTimestamp` TEXT, `timestamp` INTEGER, `color` INTEGER, `state` TEXT, `locked` INTEGER NOT NULL, `tags` TEXT, `updateTimestamp` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, `uuid` TEXT, `meta` TEXT, `disableBackup` INTEGER NOT NULL, `folder` TEXT)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "displayTimestamp", + "columnName": "displayTimestamp", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "locked", + "columnName": "locked", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "tags", + "columnName": "tags", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "updateTimestamp", + "columnName": "updateTimestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "pinned", + "columnName": "pinned", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "meta", + "columnName": "meta", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "disableBackup", + "columnName": "disableBackup", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "folder", + "columnName": "folder", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_note_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_note_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "tag", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `uuid` TEXT)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_tag_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_tag_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "widget", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`widgetId` INTEGER NOT NULL, `noteUUID` TEXT, PRIMARY KEY(`widgetId`))", + "fields": [ + { + "fieldPath": "widgetId", + "columnName": "widgetId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "noteUUID", + "columnName": "noteUUID", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "widgetId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_widget_widgetId", + "unique": false, + "columnNames": [ + "widgetId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_widget_widgetId` ON `${TABLE_NAME}` (`widgetId`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "folder", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `timestamp` INTEGER, `updateTimestamp` INTEGER NOT NULL, `color` INTEGER, `uuid` TEXT)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "updateTimestamp", + "columnName": "updateTimestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_folder_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_folder_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "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, '27a1b0ae4247b917be454c0e96798974')" + ] + } +} \ No newline at end of file diff --git a/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/2.json b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/2.json new file mode 100644 index 00000000..3a33850e --- /dev/null +++ b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/2.json @@ -0,0 +1,72 @@ +{ + "formatVersion": 1, + "database": { + "version": 2, + "identityHash": "42138d9525b661262cd3c159b26e8bd1", + "entities": [ + { + "tableName": "note", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT, `title` TEXT, `description` TEXT, `displayTimestamp` TEXT, `timestamp` INTEGER, `color` INTEGER)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "displayTimestamp", + "columnName": "displayTimestamp", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_note_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX `index_note_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + } + ], + "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, \"42138d9525b661262cd3c159b26e8bd1\")" + ] + } +} \ No newline at end of file diff --git a/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/3.json b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/3.json new file mode 100644 index 00000000..285b323b --- /dev/null +++ b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/3.json @@ -0,0 +1,78 @@ +{ + "formatVersion": 1, + "database": { + "version": 3, + "identityHash": "ebac89e10d42fee5041902845b3c4e50", + "entities": [ + { + "tableName": "note", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT, `title` TEXT, `description` TEXT, `displayTimestamp` TEXT, `timestamp` INTEGER, `color` INTEGER, `state` TEXT)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "displayTimestamp", + "columnName": "displayTimestamp", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_note_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX `index_note_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + } + ], + "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, \"ebac89e10d42fee5041902845b3c4e50\")" + ] + } +} \ No newline at end of file diff --git a/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/4.json b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/4.json new file mode 100644 index 00000000..f14c8fac --- /dev/null +++ b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/4.json @@ -0,0 +1,84 @@ +{ + "formatVersion": 1, + "database": { + "version": 4, + "identityHash": "ff9b7d3c13995d9bab939e5f605b7ca0", + "entities": [ + { + "tableName": "note", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT, `title` TEXT, `description` TEXT, `displayTimestamp` TEXT, `timestamp` INTEGER, `color` INTEGER, `state` TEXT, `locked` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "displayTimestamp", + "columnName": "displayTimestamp", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "locked", + "columnName": "locked", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_note_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX `index_note_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + } + ], + "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, \"ff9b7d3c13995d9bab939e5f605b7ca0\")" + ] + } +} \ No newline at end of file diff --git a/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/5.json b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/5.json new file mode 100644 index 00000000..a168b5be --- /dev/null +++ b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/5.json @@ -0,0 +1,125 @@ +{ + "formatVersion": 1, + "database": { + "version": 5, + "identityHash": "ab6ec3e8f6d33797ac91c9254e63e906", + "entities": [ + { + "tableName": "note", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT, `title` TEXT, `description` TEXT, `displayTimestamp` TEXT, `timestamp` INTEGER, `color` INTEGER, `state` TEXT, `locked` INTEGER NOT NULL, `tags` TEXT)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "displayTimestamp", + "columnName": "displayTimestamp", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "locked", + "columnName": "locked", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "tags", + "columnName": "tags", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_note_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX `index_note_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "tag", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_tag_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX `index_tag_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + } + ], + "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, \"ab6ec3e8f6d33797ac91c9254e63e906\")" + ] + } +} \ No newline at end of file diff --git a/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/6.json b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/6.json new file mode 100644 index 00000000..dab4bcd3 --- /dev/null +++ b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/6.json @@ -0,0 +1,137 @@ +{ + "formatVersion": 1, + "database": { + "version": 6, + "identityHash": "44eaaecfdc7e16dab14a93e8938abb28", + "entities": [ + { + "tableName": "note", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT, `title` TEXT, `description` TEXT, `displayTimestamp` TEXT, `timestamp` INTEGER, `color` INTEGER, `state` TEXT, `locked` INTEGER NOT NULL, `tags` TEXT, `updateTimestamp` INTEGER NOT NULL, `pinned` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "displayTimestamp", + "columnName": "displayTimestamp", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "locked", + "columnName": "locked", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "tags", + "columnName": "tags", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "updateTimestamp", + "columnName": "updateTimestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "pinned", + "columnName": "pinned", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_note_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX `index_note_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "tag", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_tag_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX `index_tag_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + } + ], + "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, \"44eaaecfdc7e16dab14a93e8938abb28\")" + ] + } +} \ No newline at end of file diff --git a/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/7.json b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/7.json new file mode 100644 index 00000000..e52a464a --- /dev/null +++ b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/7.json @@ -0,0 +1,143 @@ +{ + "formatVersion": 1, + "database": { + "version": 7, + "identityHash": "f142faa3ea6ca754af78d915e2aaf1ca", + "entities": [ + { + "tableName": "note", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT, `title` TEXT, `description` TEXT, `displayTimestamp` TEXT, `timestamp` INTEGER, `color` INTEGER, `state` TEXT, `locked` INTEGER NOT NULL, `tags` TEXT, `updateTimestamp` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, `uuid` TEXT)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "displayTimestamp", + "columnName": "displayTimestamp", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "locked", + "columnName": "locked", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "tags", + "columnName": "tags", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "updateTimestamp", + "columnName": "updateTimestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "pinned", + "columnName": "pinned", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_note_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX `index_note_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "tag", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_tag_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX `index_tag_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + } + ], + "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, \"f142faa3ea6ca754af78d915e2aaf1ca\")" + ] + } +} \ No newline at end of file diff --git a/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/8.json b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/8.json new file mode 100644 index 00000000..cadcc778 --- /dev/null +++ b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/8.json @@ -0,0 +1,149 @@ +{ + "formatVersion": 1, + "database": { + "version": 8, + "identityHash": "aef5fdefabc56501799ced8a278ae77f", + "entities": [ + { + "tableName": "note", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT, `title` TEXT, `description` TEXT, `displayTimestamp` TEXT, `timestamp` INTEGER, `color` INTEGER, `state` TEXT, `locked` INTEGER NOT NULL, `tags` TEXT, `updateTimestamp` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, `uuid` TEXT)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "displayTimestamp", + "columnName": "displayTimestamp", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "locked", + "columnName": "locked", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "tags", + "columnName": "tags", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "updateTimestamp", + "columnName": "updateTimestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "pinned", + "columnName": "pinned", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_note_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX `index_note_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "tag", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `uuid` TEXT)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_tag_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX `index_tag_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + } + ], + "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, \"aef5fdefabc56501799ced8a278ae77f\")" + ] + } +} \ No newline at end of file diff --git a/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/9.json b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/9.json new file mode 100644 index 00000000..0976510c --- /dev/null +++ b/base/schemas/com.maubis.scarlet.base.database.room.AppDatabase/9.json @@ -0,0 +1,184 @@ +{ + "formatVersion": 1, + "database": { + "version": 9, + "identityHash": "134846fcabba01b20eb0b0b4afd63dae", + "entities": [ + { + "tableName": "note", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT, `title` TEXT, `description` TEXT, `displayTimestamp` TEXT, `timestamp` INTEGER, `color` INTEGER, `state` TEXT, `locked` INTEGER NOT NULL, `tags` TEXT, `updateTimestamp` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, `uuid` TEXT)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "displayTimestamp", + "columnName": "displayTimestamp", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "locked", + "columnName": "locked", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "tags", + "columnName": "tags", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "updateTimestamp", + "columnName": "updateTimestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "pinned", + "columnName": "pinned", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_note_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX `index_note_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "tag", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `uuid` TEXT)", + "fields": [ + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "uid" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_tag_uid", + "unique": false, + "columnNames": [ + "uid" + ], + "createSql": "CREATE INDEX `index_tag_uid` ON `${TABLE_NAME}` (`uid`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "widget", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`widgetId` INTEGER NOT NULL, `noteUUID` TEXT, PRIMARY KEY(`widgetId`))", + "fields": [ + { + "fieldPath": "widgetId", + "columnName": "widgetId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "noteUUID", + "columnName": "noteUUID", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "widgetId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_widget_widgetId", + "unique": false, + "columnNames": [ + "widgetId" + ], + "createSql": "CREATE INDEX `index_widget_widgetId` ON `${TABLE_NAME}` (`widgetId`)" + } + ], + "foreignKeys": [] + } + ], + "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, \"134846fcabba01b20eb0b0b4afd63dae\")" + ] + } +} \ No newline at end of file diff --git a/base/src/androidTest/java/com/maubis/scarlet/base/MigrationTest.java b/base/src/androidTest/java/com/maubis/scarlet/base/MigrationTest.java index cd409dd4..32d92657 100644 --- a/base/src/androidTest/java/com/maubis/scarlet/base/MigrationTest.java +++ b/base/src/androidTest/java/com/maubis/scarlet/base/MigrationTest.java @@ -1,11 +1,11 @@ package com.maubis.scarlet.base; -import android.arch.persistence.db.SupportSQLiteDatabase; -import android.arch.persistence.db.framework.FrameworkSQLiteOpenHelperFactory; -import android.arch.persistence.room.testing.MigrationTestHelper; +import androidx.sqlite.db.SupportSQLiteDatabase; +import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory; +import androidx.room.testing.MigrationTestHelper; import android.database.Cursor; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.github.bijoysingh.starter.util.TextUtils; import com.maubis.scarlet.base.database.room.AppDatabase; @@ -20,6 +20,7 @@ import static com.maubis.scarlet.base.database.room.AppDatabase.MIGRATION_10_11; import static com.maubis.scarlet.base.database.room.AppDatabase.MIGRATION_11_12; import static com.maubis.scarlet.base.database.room.AppDatabase.MIGRATION_12_13; +import static com.maubis.scarlet.base.database.room.AppDatabase.MIGRATION_13_14; import static com.maubis.scarlet.base.database.room.AppDatabase.MIGRATION_2_3; import static com.maubis.scarlet.base.database.room.AppDatabase.MIGRATION_3_4; import static com.maubis.scarlet.base.database.room.AppDatabase.MIGRATION_4_5; @@ -235,6 +236,19 @@ public void migrate11To12() throws IOException { validate(database, select(TABLE_FOLDER, 1)); } + @Test + public void migrate11To13() throws IOException { + SupportSQLiteDatabase database = helper.createDatabase(TEST_DB, 11); + database.execSQL(NOTE_V9); + database.close(); + + database = helper.runMigrationsAndValidate(TEST_DB, 13, false, MIGRATION_11_12, MIGRATION_12_13); + validate(database, select(TABLE_NOTE, 1)); + + database.execSQL(FOLDER_V12); + validate(database, select(TABLE_FOLDER, 1)); + } + @Test public void migrate12To13() throws IOException { SupportSQLiteDatabase database = helper.createDatabase(TEST_DB, 12); @@ -249,6 +263,34 @@ public void migrate12To13() throws IOException { Assert.assertTrue(getValue(database, select(TABLE_NOTE, 2, "folder")).equals("32123124")); } + @Test + public void migrate11To14() throws IOException { + SupportSQLiteDatabase database = helper.createDatabase(TEST_DB, 11); + database.execSQL(NOTE_V9); + database.close(); + + database = helper.runMigrationsAndValidate(TEST_DB, 14, false, MIGRATION_11_12, MIGRATION_12_13, MIGRATION_13_14); + validate(database, select(TABLE_NOTE, 1)); + + database.execSQL(NOTE_V10); + validate(database, select(TABLE_NOTE, 2)); + Assert.assertTrue(getValue(database, select(TABLE_NOTE, 2, "folder")).equals("32123124")); + } + + @Test + public void migrate13To14() throws IOException { + SupportSQLiteDatabase database = helper.createDatabase(TEST_DB, 13); + database.execSQL(NOTE_V9); + database.close(); + + database = helper.runMigrationsAndValidate(TEST_DB, 14, false, MIGRATION_13_14); + validate(database, select(TABLE_NOTE, 1)); + + database.execSQL(NOTE_V10); + validate(database, select(TABLE_NOTE, 2)); + Assert.assertTrue(getValue(database, select(TABLE_NOTE, 2, "folder")).equals("32123124")); + } + private static void validate(SupportSQLiteDatabase database, String query) { Cursor cursor = database.query(query); Assert.assertTrue(cursor.moveToNext()); diff --git a/base/src/main/AndroidManifest.xml b/base/src/main/AndroidManifest.xml index d5a34183..8309489f 100644 --- a/base/src/main/AndroidManifest.xml +++ b/base/src/main/AndroidManifest.xml @@ -1,2 +1,132 @@ + + xmlns:tools="http://schemas.android.com/tools" + package="com.maubis.scarlet.base"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/MainActivity.kt b/base/src/main/java/com/maubis/scarlet/base/MainActivity.kt index 8d404868..977c1984 100644 --- a/base/src/main/java/com/maubis/scarlet/base/MainActivity.kt +++ b/base/src/main/java/com/maubis/scarlet/base/MainActivity.kt @@ -1,33 +1,56 @@ package com.maubis.scarlet.base import android.content.BroadcastReceiver +import android.content.res.Configuration import android.os.Bundle -import android.support.v7.widget.LinearLayoutManager -import android.support.v7.widget.RecyclerView -import android.support.v7.widget.StaggeredGridLayoutManager import android.text.Editable import android.text.TextWatcher import android.view.View import android.view.View.GONE import android.widget.GridLayout.VERTICAL +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.StaggeredGridLayoutManager import com.facebook.litho.ComponentContext import com.facebook.litho.LithoView import com.github.bijoysingh.starter.recyclerview.RecyclerViewBuilder +import com.maubis.scarlet.base.config.ApplicationBase +import com.maubis.scarlet.base.config.ApplicationBase.Companion.instance +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme import com.maubis.scarlet.base.config.CoreConfig -import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb +import com.maubis.scarlet.base.config.auth.IPendingUploadListener import com.maubis.scarlet.base.core.note.NoteState -import com.maubis.scarlet.base.core.note.sort +import com.maubis.scarlet.base.database.room.folder.Folder import com.maubis.scarlet.base.database.room.note.Note import com.maubis.scarlet.base.database.room.tag.Tag import com.maubis.scarlet.base.export.support.NoteExporter import com.maubis.scarlet.base.export.support.PermissionUtils -import com.maubis.scarlet.base.main.HomeNavigationState -import com.maubis.scarlet.base.main.recycler.* -import com.maubis.scarlet.base.main.sheets.AlertBottomSheet +import com.maubis.scarlet.base.main.* +import com.maubis.scarlet.base.main.HomeNavigationMode +import com.maubis.scarlet.base.main.SearchState +import com.maubis.scarlet.base.main.recycler.EmptyRecyclerItem +import com.maubis.scarlet.base.main.recycler.GenericRecyclerItem +import com.maubis.scarlet.base.main.recycler.getAppUpdateInformationItem +import com.maubis.scarlet.base.main.recycler.getBackupInformationItem +import com.maubis.scarlet.base.main.recycler.getInstallProInformationItem +import com.maubis.scarlet.base.main.recycler.getMigrateToProAppInformationItem +import com.maubis.scarlet.base.main.recycler.getReviewInformationItem +import com.maubis.scarlet.base.main.recycler.getSignInInformationItem +import com.maubis.scarlet.base.main.recycler.getThemeInformationItem +import com.maubis.scarlet.base.main.recycler.shouldShowAppUpdateInformationItem +import com.maubis.scarlet.base.main.recycler.shouldShowBackupInformationItem +import com.maubis.scarlet.base.main.recycler.shouldShowInstallProInformationItem +import com.maubis.scarlet.base.main.recycler.shouldShowMigrateToProAppInformationItem +import com.maubis.scarlet.base.main.recycler.shouldShowReviewInformationItem +import com.maubis.scarlet.base.main.recycler.shouldShowSignInformationItem +import com.maubis.scarlet.base.main.recycler.shouldShowThemeInformationItem import com.maubis.scarlet.base.main.sheets.WhatsNewBottomSheet import com.maubis.scarlet.base.main.sheets.openDeleteTrashSheet import com.maubis.scarlet.base.main.specs.MainActivityBottomBar +import com.maubis.scarlet.base.main.specs.MainActivityDisabledSync import com.maubis.scarlet.base.main.specs.MainActivityFolderBottomBar +import com.maubis.scarlet.base.main.specs.MainActivitySyncingNow import com.maubis.scarlet.base.main.utils.MainSnackbar import com.maubis.scarlet.base.note.activity.INoteOptionSheetActivity import com.maubis.scarlet.base.note.folder.FolderRecyclerItem @@ -43,26 +66,39 @@ import com.maubis.scarlet.base.service.getNoteIntentFilter import com.maubis.scarlet.base.settings.sheet.STORE_KEY_LINE_COUNT import com.maubis.scarlet.base.settings.sheet.SettingsOptionsBottomSheet.Companion.KEY_MARKDOWN_ENABLED import com.maubis.scarlet.base.settings.sheet.SettingsOptionsBottomSheet.Companion.KEY_MARKDOWN_HOME_ENABLED -import com.maubis.scarlet.base.settings.sheet.SortingOptionsBottomSheet -import com.maubis.scarlet.base.settings.sheet.UISettingsOptionsBottomSheet import com.maubis.scarlet.base.settings.sheet.sNoteItemLineCount -import com.maubis.scarlet.base.support.SearchConfig +import com.maubis.scarlet.base.settings.sheet.sUIUseGridView +import com.maubis.scarlet.base.support.database.HouseKeeper import com.maubis.scarlet.base.support.database.HouseKeeperJob import com.maubis.scarlet.base.support.database.Migrator import com.maubis.scarlet.base.support.recycler.RecyclerItem import com.maubis.scarlet.base.support.sheets.openSheet import com.maubis.scarlet.base.support.specs.ToolbarColorConfig +import com.maubis.scarlet.base.support.ui.SecuredActivity import com.maubis.scarlet.base.support.ui.ThemeColorType -import com.maubis.scarlet.base.support.ui.ThemedActivity -import com.maubis.scarlet.base.support.unifiedFolderSearchSynchronous -import com.maubis.scarlet.base.support.unifiedSearchSynchronous +import com.maubis.scarlet.base.support.ui.sThemeIsAutomatic +import com.maubis.scarlet.base.support.ui.setThemeFromSystem import com.maubis.scarlet.base.support.utils.shouldShowWhatsNewSheet import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.search_toolbar_main.* import kotlinx.android.synthetic.main.toolbar_trash_info.* -import kotlinx.coroutines.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.async +import kotlinx.coroutines.launch +import kotlinx.coroutines.newSingleThreadContext +import java.util.concurrent.atomic.AtomicBoolean + +class MainActivity : SecuredActivity(), INoteOptionSheetActivity { + companion object { + private const val IS_IN_SEARCH_MODE: String = "IS_IN_SEARCH_MODE" + private const val NAVIGATION_MODE: String = "NAVIGATION_MODE" + private const val SEARCH_TEXT: String = "SEARCH_TEXT" + private const val CURRENT_FOLDER_UUID: String = "CURRENT_FOLDER_UUID" + private const val TAGS_UUIDS: String = "TAGS_UUIDS" + private const val SEARCH_COLORS: String = "SEARCH_COLORS" + } -class MainActivity : ThemedActivity(), INoteOptionSheetActivity { private val singleThreadDispatcher = newSingleThreadContext("singleThreadDispatcher") private lateinit var recyclerView: RecyclerView @@ -72,91 +108,137 @@ class MainActivity : ThemedActivity(), INoteOptionSheetActivity { private lateinit var receiver: BroadcastReceiver private lateinit var tagAndColorPicker: TagsAndColorPickerViewHolder - var config: SearchConfig = SearchConfig(mode = HomeNavigationState.DEFAULT) + private var lastSyncPending: AtomicBoolean = AtomicBoolean(false) + private var lastSyncHappening: AtomicBoolean = AtomicBoolean(false) + + val state: SearchState = SearchState(mode = HomeNavigationMode.DEFAULT) var isInSearchMode: Boolean = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) + handleIntent() // Migrate to the newer version of the tags Migrator(this).start() - config.mode = HomeNavigationState.DEFAULT + state.mode = HomeNavigationMode.DEFAULT setupRecyclerView() setListeners() - notifyThemeChange() + + if (sThemeIsAutomatic) { + setThemeFromSystem(this) + } + sAppTheme.notifyChange(this) if (shouldShowWhatsNewSheet()) { openSheet(this, WhatsNewBottomSheet()) } } + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + + outState.putBoolean(IS_IN_SEARCH_MODE, isInSearchMode) + outState.putString(SEARCH_TEXT, state.text) + outState.putIntegerArrayList(SEARCH_COLORS, ArrayList(state.colors)) + outState.putInt(NAVIGATION_MODE, state.mode.ordinal) + outState.putString(CURRENT_FOLDER_UUID, state.currentFolder?.uuid) + outState.putStringArrayList(TAGS_UUIDS, ArrayList(state.tags.map { it.uuid })) + } + + override fun onRestoreInstanceState(savedInstanceState: Bundle?) { + super.onRestoreInstanceState(savedInstanceState) + + if (savedInstanceState != null) { + isInSearchMode = savedInstanceState.getBoolean(IS_IN_SEARCH_MODE) + state.text = savedInstanceState.getString(SEARCH_TEXT, "") + state.colors = savedInstanceState.getIntegerArrayList(SEARCH_COLORS) ?: ArrayList() + state.mode = HomeNavigationMode.values()[savedInstanceState.getInt(NAVIGATION_MODE)] + savedInstanceState.getString(CURRENT_FOLDER_UUID)?.let { + state.currentFolder = instance.foldersDatabase().getByUUID(it) + } + savedInstanceState.getStringArrayList(TAGS_UUIDS)?.forEach { + instance.tagsDatabase().getByUUID(it)?.let { state.tags.add(it) } + } + } + } + + override fun onConfigurationChanged(configuration: Configuration) { + super.onConfigurationChanged(configuration) + startActivity(MainActivityActions.NIL.intent(this)) + finish() + } + fun setListeners() { - snackbar = MainSnackbar(bottomSnackbar, { setupData() }) + snackbar = MainSnackbar(bottomSnackbar) { loadData() } deleteTrashIcon.setOnClickListener { openDeleteTrashSheet(this@MainActivity) } searchBackButton.setOnClickListener { onBackPressed() } searchCloseIcon.setOnClickListener { onBackPressed() } searchBox.addTextChangedListener(object : TextWatcher { - override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) { - - } + override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {} override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) { startSearch(charSequence.toString()) } - override fun afterTextChanged(editable: Editable) { - - } + override fun afterTextChanged(editable: Editable) {} }) tagAndColorPicker = TagsAndColorPickerViewHolder( - this, - tagsFlexBox, - { tag -> - val isTagSelected = config.tags.filter { it.uuid == tag.uuid }.isNotEmpty() - when (isTagSelected) { - true -> { - config.tags.removeAll { it.uuid == tag.uuid } - startSearch(searchBox.text.toString()) - tagAndColorPicker.notifyChanged() - } - false -> { - openTag(tag) - tagAndColorPicker.notifyChanged() - } + this, + tagsFlexBox, + { tag -> + val isTagSelected = state.tags.filter { it.uuid == tag.uuid }.isNotEmpty() + when (isTagSelected) { + true -> { + state.tags.removeAll { it.uuid == tag.uuid } + startSearch(searchBox.text.toString()) + tagAndColorPicker.notifyChanged() } - }, - { color -> - when (config.colors.contains(color)) { - true -> config.colors.remove(color) - false -> config.colors.add(color) + false -> { + openTag(tag) + tagAndColorPicker.notifyChanged() } - tagAndColorPicker.notifyChanged() - startSearch(searchBox.text.toString()) - }) + } + }, + { color -> + when (state.colors.contains(color)) { + true -> state.colors.remove(color) + false -> state.colors.add(color) + } + tagAndColorPicker.notifyChanged() + startSearch(searchBox.text.toString()) + }) } fun setupRecyclerView() { - val staggeredView = UISettingsOptionsBottomSheet.useGridView val isTablet = resources.getBoolean(R.bool.is_tablet) - val isMarkdownEnabled = CoreConfig.instance.store().get(KEY_MARKDOWN_ENABLED, true) - val isMarkdownHomeEnabled = CoreConfig.instance.store().get(KEY_MARKDOWN_HOME_ENABLED, true) + val isMarkdownEnabled = sAppPreferences.get(KEY_MARKDOWN_ENABLED, true) + val isMarkdownHomeEnabled = sAppPreferences.get(KEY_MARKDOWN_HOME_ENABLED, true) val adapterExtra = Bundle() adapterExtra.putBoolean(KEY_MARKDOWN_ENABLED, isMarkdownEnabled && isMarkdownHomeEnabled) adapterExtra.putInt(STORE_KEY_LINE_COUNT, sNoteItemLineCount) - adapter = NoteAppAdapter(this, staggeredView, isTablet) + adapter = NoteAppAdapter(this, sUIUseGridView, isTablet) adapter.setExtra(adapterExtra) recyclerView = RecyclerViewBuilder(this) - .setView(this, R.id.recycler_view) - .setAdapter(adapter) - .setLayoutManager(getLayoutManager(staggeredView, isTablet)) - .build() + .setView(this, R.id.recycler_view) + .setAdapter(adapter) + .setLayoutManager(getLayoutManager(sUIUseGridView, isTablet)) + .build() + + vSwipeToRefresh.setOnRefreshListener { + when { + instance.authenticator().isLoggedIn(this) + && !instance.authenticator().isLegacyLoggedIn() + && !lastSyncHappening.get() -> instance.authenticator().requestSync(true) + else -> vSwipeToRefresh.isRefreshing = false + } + } } private fun getLayoutManager(isStaggeredView: Boolean, isTabletView: Boolean): RecyclerView.LayoutManager { @@ -168,65 +250,50 @@ class MainActivity : ThemedActivity(), INoteOptionSheetActivity { fun notifyAdapterExtraChanged() { setupRecyclerView() - resetAndSetupData() + resetAndLoadData() } - /** - * Start: Home Navigation Clicks - */ - fun onHomeClick() { + fun onModeChange(mode: HomeNavigationMode) { GlobalScope.launch(Dispatchers.Main) { - config.resetMode(HomeNavigationState.DEFAULT) + state.mode = mode unifiedSearch() notifyModeChange() } } - fun onFavouritesClick() { - GlobalScope.launch(Dispatchers.Main) { - config.resetMode(HomeNavigationState.FAVOURITE) - unifiedSearch() - notifyModeChange() - } + private fun notifyModeChange() { + val isTrash = state.mode === HomeNavigationMode.TRASH + deleteToolbar.visibility = if (isTrash) View.VISIBLE else GONE } - fun onArchivedClick() { + fun onFolderChange(folder: Folder?) { GlobalScope.launch(Dispatchers.Main) { - config.resetMode(HomeNavigationState.ARCHIVED) + state.currentFolder = folder unifiedSearch() - notifyModeChange() + notifyFolderChange() } } - fun onTrashClick() { - GlobalScope.launch(Dispatchers.Main) { - config.resetMode(HomeNavigationState.TRASH) - unifiedSearch() - notifyModeChange() - } - } + private fun notifyFolderChange() { + val componentContext = ComponentContext(this) + lithoPreBottomToolbar.removeAllViews() - fun onLockedClick() { - GlobalScope.launch(Dispatchers.Main) { - config.resetMode(HomeNavigationState.LOCKED) - unifiedSearch() - notifyModeChange() + val currentFolder = state.currentFolder + if (currentFolder != null) { + lithoPreBottomToolbar.addView(LithoView.create(componentContext, + MainActivityFolderBottomBar.create(componentContext) + .folder(currentFolder) + .build())) } + else + notifyDisabledLegacySync() } - private fun notifyModeChange() { - val isTrash = config.mode === HomeNavigationState.TRASH - deleteToolbar.visibility = if (isTrash) View.VISIBLE else GONE - } - - /** - * End: Home Navigation Clicks - */ - private fun handleNewItems(notes: List) { adapter.clearItems() if (!isInSearchMode) { adapter.addItem(GenericRecyclerItem(RecyclerItem.Type.TOOLBAR)) + addInformationItem(1) } if (notes.isEmpty()) { adapter.addItem(EmptyRecyclerItem()) @@ -235,13 +302,12 @@ class MainActivity : ThemedActivity(), INoteOptionSheetActivity { notes.forEach { adapter.addItem(it) } - addInformationItem(1) } private fun addInformationItem(index: Int) { val informationItem = when { shouldShowMigrateToProAppInformationItem(this) -> getMigrateToProAppInformationItem(this) - shouldShowSignInformationItem() -> getSignInInformationItem(this) + shouldShowSignInformationItem(this) -> getSignInInformationItem(this) shouldShowAppUpdateInformationItem() -> getAppUpdateInformationItem(this) shouldShowReviewInformationItem() -> getReviewInformationItem(this) shouldShowInstallProInformationItem() -> getInstallProInformationItem(this) @@ -257,59 +323,101 @@ class MainActivity : ThemedActivity(), INoteOptionSheetActivity { private suspend fun unifiedSearchSynchronous(): List { val allItems = emptyList().toMutableList() - allItems.addAll(unifiedFolderSearchSynchronous(config) - .map { - GlobalScope.async(Dispatchers.IO) { - var notesCount = -1 - if (config.hasFilter()) { - val folderConfig = config.copy() - folderConfig.folders.clear() - folderConfig.folders.add(it) - notesCount = unifiedSearchSynchronous(folderConfig).size - if (notesCount == 0) { - return@async null - } - folderConfig.folders.clear() - } - FolderRecyclerItem( - context = this@MainActivity, - folder = it, - click = { - config.folders.clear() - config.folders.add(it) - unifiedSearch() - notifyFolderChange() - }, - longClick = { - CreateOrEditFolderBottomSheet.openSheet(this@MainActivity, it, { _, _ -> setupData() }) - }, - selected = config.hasFolder(it), - contents = notesCount) - } - } - .map { it.await() } - .filterNotNull()) - allItems.addAll(unifiedSearchSynchronous(config) - .map { GlobalScope.async(Dispatchers.IO) { NoteRecyclerItem(this@MainActivity, it) } } - .map { it.await() }) + if (state.currentFolder != null) { + val allNotes = unifiedSearchSynchronous(state) + allItems.addAll(allNotes + .map { GlobalScope.async(Dispatchers.IO) { NoteRecyclerItem(this@MainActivity, it) } } + .map { it.await() }) + return allItems + } + + val allNotes = unifiedSearchWithoutFolder(state) + val directAcceptableFolders = filterDirectlyValidFolders(state) + allItems.addAll(CoreConfig.foldersDb.getAll() + .map { + GlobalScope.async(Dispatchers.IO) { + val isDirectFolder = directAcceptableFolders.contains(it) + val notesCount = filterFolder(allNotes, it).size + if (state.hasFilter() && notesCount == 0 && !isDirectFolder) { + return@async null + } + + FolderRecyclerItem( + context = this@MainActivity, + folder = it, + click = { onFolderChange(it) }, + longClick = { + CreateOrEditFolderBottomSheet.openSheet(this@MainActivity, it, { _, _ -> loadData() }) + }, + selected = state.currentFolder?.uuid == it.uuid, + contents = notesCount) + } + } + .map { it.await() } + .filterNotNull()) + allItems.addAll(filterOutFolders(allNotes) + .map { GlobalScope.async(Dispatchers.IO) { NoteRecyclerItem(this@MainActivity, it) } } + .map { it.await() }) return allItems } - fun notifyFolderChange() { + private fun notifyDisabledLegacySync() { val componentContext = ComponentContext(this) lithoPreBottomToolbar.removeAllViews() - if (config.folders.isEmpty()) { + if (!instance.authenticator().isLegacyLoggedIn()) { return } - val folder = config.folders.first() lithoPreBottomToolbar.addView(LithoView.create(componentContext, - MainActivityFolderBottomBar.create(componentContext) - .folder(folder) - .build())) + MainActivityDisabledSync.create(componentContext) + .onClick { + instance.authenticator().openTransferDataActivity(componentContext.androidContext)?.run() + } + .build())) } - fun unifiedSearch() { + fun notifySyncingInformation(isSyncHappening: Boolean, isSyncPending: Boolean) { + val componentContext = ComponentContext(this) + if (!instance.authenticator().isLoggedIn(this) + || instance.authenticator().isLegacyLoggedIn()) { + return + } + + if (lastSyncPending.getAndSet(isSyncPending) == isSyncPending + && lastSyncHappening.getAndSet(isSyncHappening) == isSyncHappening) { + return + } + + if (!isSyncPending && !isSyncHappening) { + GlobalScope.launch(Dispatchers.Main) { + lithoSyncingBottomToolbar.removeAllViews() + } + return + } + + GlobalScope.launch(Dispatchers.Main) { + lithoSyncingBottomToolbar.removeAllViews() + lithoSyncingBottomToolbar.addView(LithoView.create(componentContext, + MainActivitySyncingNow.create(componentContext) + .isSyncHappening(isSyncHappening) + .onClick { + if (!lastSyncHappening.get()) { + instance.authenticator().requestSync(true) + } + } + .onLongClick { + if (!lastSyncHappening.get()) { + instance.authenticator().showPendingSync(this@MainActivity) + } + } + .build())) + if (!isSyncHappening && isSyncPending) { + instance.authenticator().requestSync(false) + } + } + } + + private fun unifiedSearch() { GlobalScope.launch(Dispatchers.Main) { val items = GlobalScope.async(Dispatchers.IO) { unifiedSearchSynchronous() } handleNewItems(items.await()) @@ -317,57 +425,68 @@ class MainActivity : ThemedActivity(), INoteOptionSheetActivity { } fun openTag(tag: Tag) { - config.mode = if (config.mode == HomeNavigationState.LOCKED) HomeNavigationState.DEFAULT else config.mode - config.tags.add(tag) + state.mode = if (state.mode == HomeNavigationMode.LOCKED) HomeNavigationMode.DEFAULT else state.mode + state.tags.add(tag) unifiedSearch() notifyModeChange() } override fun onResume() { super.onResume() - CoreConfig.instance.startListener(this) - setupData() + instance.startListener(this) + loadData() registerNoteReceiver() + notifyFolderChange() + + if (isInSearchMode) + enterSearchMode() + + instance.authenticator().setPendingUploadListener(object : IPendingUploadListener { + override fun onPendingSyncsUpdate(isSyncHappening: Boolean) { + notifySyncingInformation(isSyncHappening, lastSyncPending.get()) + GlobalScope.launch(Dispatchers.Main) { + vSwipeToRefresh.isRefreshing = false + } + } + + override fun onPendingStateUpdate(isDataSyncPending: Boolean) { + notifySyncingInformation(lastSyncHappening.get(), isDataSyncPending) + } + }) + instance.authenticator().requestSync(false) } - fun resetAndSetupData() { - config.clear() - setupData() + fun resetAndLoadData() { + state.clear() + loadData() } - fun setupData() { - return when (config.mode) { - HomeNavigationState.FAVOURITE -> onFavouritesClick() - HomeNavigationState.ARCHIVED -> onArchivedClick() - HomeNavigationState.TRASH -> onTrashClick() - HomeNavigationState.LOCKED -> onLockedClick() - HomeNavigationState.DEFAULT -> onHomeClick() - else -> onHomeClick() + fun loadData() = onModeChange(state.mode) + + fun enterSearchMode() { + isInSearchMode = true + searchBox.setText(state.text) + searchToolbar.visibility = View.VISIBLE + tryOpeningTheKeyboard() + GlobalScope.launch(Dispatchers.Main) { + GlobalScope.async(Dispatchers.IO) { tagAndColorPicker.reset() }.await() + tagAndColorPicker.notifyChanged() } + searchBox.requestFocus() } - fun setSearchMode(mode: Boolean) { - isInSearchMode = mode - searchToolbar.visibility = if (isInSearchMode) View.VISIBLE else View.GONE + fun quitSearchMode() { + isInSearchMode = false searchBox.setText("") - - if (isInSearchMode) { - tryOpeningTheKeyboard() - GlobalScope.launch(Dispatchers.Main) { - GlobalScope.async(Dispatchers.IO) { tagAndColorPicker.reset() }.await() - tagAndColorPicker.notifyChanged() - } - searchBox.requestFocus() - } else { - tryClosingTheKeyboard() - config.clearSearchBar() - setupData() - } + tryClosingTheKeyboard() + searchToolbar.visibility = View.GONE + state.clearSearchBar() + loadData() } private fun startSearch(keyword: String) { GlobalScope.launch(singleThreadDispatcher) { - config.text = keyword + state.text = keyword val items = GlobalScope.async(Dispatchers.IO) { unifiedSearchSynchronous() } GlobalScope.launch(Dispatchers.Main) { handleNewItems(items.await()) @@ -377,11 +496,12 @@ class MainActivity : ThemedActivity(), INoteOptionSheetActivity { override fun onBackPressed() { when { - isInSearchMode && searchBox.text.toString().isBlank() -> setSearchMode(false) + isInSearchMode && searchBox.text.toString().isBlank() -> quitSearchMode() isInSearchMode -> searchBox.setText("") - config.hasFilter() -> { - config.clear() - onHomeClick() + state.currentFolder != null -> onFolderChange(null) + state.hasFilter() -> { + state.clear() + onModeChange(HomeNavigationMode.DEFAULT) notifyFolderChange() } else -> super.onBackPressed() @@ -391,6 +511,7 @@ class MainActivity : ThemedActivity(), INoteOptionSheetActivity { override fun onPause() { super.onPause() unregisterReceiver(receiver) + instance.authenticator().setPendingUploadListener(null) } override fun onDestroy() { @@ -401,17 +522,16 @@ class MainActivity : ThemedActivity(), INoteOptionSheetActivity { override fun onStop() { super.onStop() if (PermissionUtils().getStoragePermissionManager(this).hasAllPermissions()) { + HouseKeeper(this).removeOlderClips() NoteExporter().tryAutoExport() } } override fun notifyThemeChange() { setSystemTheme() - - val theme = CoreConfig.instance.themeController() containerLayoutMain.setBackgroundColor(getThemeColor()) - val toolbarIconColor = theme.get(ThemeColorType.TOOLBAR_ICON) + val toolbarIconColor = sAppTheme.get(ThemeColorType.TOOLBAR_ICON) deleteTrashIcon.setColorFilter(toolbarIconColor) deletesAutomatically.setTextColor(toolbarIconColor) @@ -420,18 +540,20 @@ class MainActivity : ThemedActivity(), INoteOptionSheetActivity { private fun registerNoteReceiver() { receiver = SyncedNoteBroadcastReceiver { - setupData() + loadData() } registerReceiver(receiver, getNoteIntentFilter()) } - fun setBottomToolbar() { + private fun setBottomToolbar() { val componentContext = ComponentContext(this) lithoBottomToolbar.removeAllViews() - lithoBottomToolbar.addView(LithoView.create(componentContext, + lithoBottomToolbar.addView( + LithoView.create( + componentContext, MainActivityBottomBar.create(componentContext) - .colorConfig(ToolbarColorConfig()) - .build())) + .colorConfig(ToolbarColorConfig()) + .build())) } /** @@ -439,30 +561,30 @@ class MainActivity : ThemedActivity(), INoteOptionSheetActivity { */ override fun updateNote(note: Note) { note.save(this) - setupData() + loadData() } override fun markItem(note: Note, state: NoteState) { note.mark(this, state) - setupData() + loadData() } override fun moveItemToTrashOrDelete(note: Note) { snackbar.softUndo(this, note) note.softDelete(this) - setupData() + loadData() } override fun notifyTagsChanged(note: Note) { - setupData() + loadData() } override fun getSelectMode(note: Note): String { - return config.mode.name + return state.mode.name } override fun notifyResetOrDismiss() { - setupData() + loadData() } override fun lockedContentIsHidden() = true diff --git a/base/src/main/java/com/maubis/scarlet/base/MainActivityExtensions.kt b/base/src/main/java/com/maubis/scarlet/base/MainActivityExtensions.kt new file mode 100644 index 00000000..00b164ab --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/MainActivityExtensions.kt @@ -0,0 +1,75 @@ +package com.maubis.scarlet.base + +import android.content.Context +import android.content.Intent +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface +import com.maubis.scarlet.base.settings.sheet.ThemeColorPickerBottomSheet +import com.maubis.scarlet.base.settings.sheet.TypefacePickerBottomSheet +import com.maubis.scarlet.base.support.sheets.openSheet +import com.maubis.scarlet.base.support.ui.font.sPreferenceTypeface +import com.maubis.scarlet.base.support.ui.sThemeLabel + +const val INTENT_KEY_ADDITIONAL_ACTION = "additional_action" + +enum class MainActivityActions { + NIL, + COLOR_PICKER, + TYPEFACE_PICKER; + + fun intent(context: Context): Intent { + val intent = Intent(context, MainActivity::class.java) + intent.putExtra(INTENT_KEY_ADDITIONAL_ACTION, this.name) + return intent + } +} + +fun MainActivity.handleIntent() { + val actionFromIntent = intent.getStringExtra(INTENT_KEY_ADDITIONAL_ACTION) + if (actionFromIntent === null || actionFromIntent.isEmpty()) { + return + } + + val action = try { + MainActivityActions.valueOf(actionFromIntent) + } catch (exception: Exception) { + null + } + + if (action === null) { + return + } + performAction(action) +} + +fun MainActivity.performAction(action: MainActivityActions) { + val activity = this + when (action) { + MainActivityActions.NIL -> { + } + MainActivityActions.COLOR_PICKER -> { + openSheet(this, ThemeColorPickerBottomSheet().apply { + this.onThemeChange = { theme -> + if (sThemeLabel != theme.name) { + sThemeLabel = theme.name + sAppTheme.notifyChange(activity) + activity.startActivity(MainActivityActions.COLOR_PICKER.intent(activity)) + activity.finish() + } + } + }) + } + MainActivityActions.TYPEFACE_PICKER -> { + openSheet(this, TypefacePickerBottomSheet().apply { + this.onTypefaceChange = { typeface -> + if (sPreferenceTypeface != typeface.name) { + sPreferenceTypeface = typeface.name + sAppTypeface.notifyChange(activity) + activity.startActivity(MainActivityActions.TYPEFACE_PICKER.intent(activity)) + activity.finish() + } + } + }) + } + } +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/config/ApplicationBase.kt b/base/src/main/java/com/maubis/scarlet/base/config/ApplicationBase.kt index 349bf02a..ead2eec5 100644 --- a/base/src/main/java/com/maubis/scarlet/base/config/ApplicationBase.kt +++ b/base/src/main/java/com/maubis/scarlet/base/config/ApplicationBase.kt @@ -1,14 +1,63 @@ package com.maubis.scarlet.base.config import android.app.Application +import androidx.biometric.BiometricManager import com.evernote.android.job.JobManager import com.facebook.soloader.SoLoader +import com.github.bijoysingh.starter.prefs.Store +import com.github.bijoysingh.starter.prefs.VersionedStore +import com.maubis.scarlet.base.core.note.NoteImage +import com.maubis.scarlet.base.export.remote.FolderRemoteDatabase import com.maubis.scarlet.base.note.reminders.ReminderJobCreator +import com.maubis.scarlet.base.support.ui.ThemeManager +import com.maubis.scarlet.base.support.ui.font.TypefaceController +import com.maubis.scarlet.base.support.utils.DateFormatUtils +import com.maubis.scarlet.base.support.utils.Flavor +import com.maubis.scarlet.base.support.utils.ImageCache +import com.maubis.scarlet.base.support.utils.maybeThrow +import com.maubis.scarlet.base.support.utils.sDateFormat abstract class ApplicationBase : Application() { override fun onCreate() { super.onCreate() + + // Preferences + sAppPreferences = VersionedStore.get(this, "USER_PREFERENCES", 1) + + sBiometricManager = BiometricManager.from(this) + + sDateFormat = DateFormatUtils(this) SoLoader.init(this, false) - JobManager.create(this).addJobCreator(ReminderJobCreator()) + try { + JobManager.create(this).addJobCreator(ReminderJobCreator()) + } catch (exception: Exception) { + maybeThrow(exception) + } + + // Setup Image Cache + sAppImageStorage = NoteImage(this) + sAppImageCache = ImageCache(this) + + // Setup Application Theme + sAppTheme = ThemeManager() + sAppTheme.setup(this) + sAppTypeface = TypefaceController(this) + } + + companion object { + lateinit var instance: CoreConfig + + lateinit var sAppFlavor: Flavor + + lateinit var sAppImageStorage: NoteImage + lateinit var sAppImageCache: ImageCache + + lateinit var sAppPreferences: Store + + lateinit var sAppTheme: ThemeManager + lateinit var sAppTypeface: TypefaceController + lateinit var sBiometricManager: BiometricManager + + var folderSync: FolderRemoteDatabase? = null } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/config/CoreConfig.kt b/base/src/main/java/com/maubis/scarlet/base/config/CoreConfig.kt index 6c6576f4..379816d1 100644 --- a/base/src/main/java/com/maubis/scarlet/base/config/CoreConfig.kt +++ b/base/src/main/java/com/maubis/scarlet/base/config/CoreConfig.kt @@ -1,14 +1,7 @@ package com.maubis.scarlet.base.config -import android.content.Context -import android.graphics.Typeface -import android.support.v4.content.res.ResourcesCompat -import android.support.v7.app.AppCompatActivity -import com.github.ajalt.reprint.core.Reprint -import com.github.bijoysingh.starter.prefs.Store -import com.maubis.markdown.MarkdownConfig -import com.maubis.markdown.MarkdownConfig.Companion.config -import com.maubis.scarlet.base.R +import androidx.appcompat.app.AppCompatActivity +import com.maubis.scarlet.base.config.ApplicationBase.Companion.instance import com.maubis.scarlet.base.config.auth.IAuthenticator import com.maubis.scarlet.base.config.remote.IRemoteConfigFetcher import com.maubis.scarlet.base.core.folder.IFolderActor @@ -17,23 +10,13 @@ import com.maubis.scarlet.base.core.tag.ITagActor import com.maubis.scarlet.base.database.FoldersProvider import com.maubis.scarlet.base.database.NotesProvider import com.maubis.scarlet.base.database.TagsProvider +import com.maubis.scarlet.base.database.remote.IRemoteDatabaseState import com.maubis.scarlet.base.database.room.AppDatabase import com.maubis.scarlet.base.database.room.folder.Folder import com.maubis.scarlet.base.database.room.note.Note import com.maubis.scarlet.base.database.room.tag.Tag -import com.maubis.scarlet.base.export.remote.FolderRemoteDatabase -import com.maubis.scarlet.base.support.ui.IThemeManager -import com.maubis.scarlet.base.support.utils.Flavor -import com.maubis.scarlet.base.support.utils.ImageCache -abstract class CoreConfig(context: Context) { - - init { - Reprint.initialize(context) - config.spanConfig.headingTypeface = ResourcesCompat.getFont(context, R.font.monserrat) ?: Typeface.DEFAULT - FONT_MONSERRAT = config.spanConfig.headingTypeface - FONT_OPEN_SANS = ResourcesCompat.getFont(context, R.font.open_sans) ?: Typeface.DEFAULT - } +abstract class CoreConfig { abstract fun database(): AppDatabase @@ -51,27 +34,15 @@ abstract class CoreConfig(context: Context) { abstract fun folderActions(folder: Folder): IFolderActor - abstract fun themeController(): IThemeManager - abstract fun remoteConfigFetcher(): IRemoteConfigFetcher - abstract fun startListener(activity: AppCompatActivity) - - abstract fun appFlavor(): Flavor + abstract fun remoteDatabaseState(): IRemoteDatabaseState - abstract fun store(): Store - - abstract fun externalFolderSync(): FolderRemoteDatabase - - abstract fun imageCache(): ImageCache + abstract fun startListener(activity: AppCompatActivity) companion object { - lateinit var instance: CoreConfig val notesDb get() = instance.notesDatabase() val tagsDb get() = instance.tagsDatabase() val foldersDb get() = instance.foldersDatabase() - - var FONT_MONSERRAT: Typeface = Typeface.DEFAULT - var FONT_OPEN_SANS: Typeface = Typeface.DEFAULT } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/config/MaterialNoteConfig.kt b/base/src/main/java/com/maubis/scarlet/base/config/MaterialNoteConfig.kt index 559fb162..a60b1736 100644 --- a/base/src/main/java/com/maubis/scarlet/base/config/MaterialNoteConfig.kt +++ b/base/src/main/java/com/maubis/scarlet/base/config/MaterialNoteConfig.kt @@ -1,9 +1,7 @@ package com.maubis.scarlet.base.config import android.content.Context -import android.support.v7.app.AppCompatActivity -import com.github.bijoysingh.starter.prefs.Store -import com.github.bijoysingh.starter.prefs.VersionedStore +import androidx.appcompat.app.AppCompatActivity import com.maubis.scarlet.base.config.auth.IAuthenticator import com.maubis.scarlet.base.config.auth.NullAuthenticator import com.maubis.scarlet.base.config.remote.IRemoteConfigFetcher @@ -17,31 +15,18 @@ import com.maubis.scarlet.base.core.tag.MaterialTagActor import com.maubis.scarlet.base.database.FoldersProvider import com.maubis.scarlet.base.database.NotesProvider import com.maubis.scarlet.base.database.TagsProvider +import com.maubis.scarlet.base.database.remote.IRemoteDatabaseState import com.maubis.scarlet.base.database.room.AppDatabase import com.maubis.scarlet.base.database.room.folder.Folder import com.maubis.scarlet.base.database.room.note.Note import com.maubis.scarlet.base.database.room.tag.Tag -import com.maubis.scarlet.base.export.remote.FolderRemoteDatabase -import com.maubis.scarlet.base.export.support.ExternalFolderSync -import com.maubis.scarlet.base.support.ui.IThemeManager -import com.maubis.scarlet.base.support.ui.ThemeManager -import com.maubis.scarlet.base.support.utils.Flavor -import com.maubis.scarlet.base.support.utils.ImageCache -import java.lang.ref.WeakReference -const val USER_PREFERENCES_STORE_NAME = "USER_PREFERENCES"; -const val USER_PREFERENCES_VERSION = 1; - -open class MaterialNoteConfig(context: Context) : CoreConfig(context) { +open class MaterialNoteConfig(context: Context) : CoreConfig() { val db = AppDatabase.createDatabase(context) val notesProvider = NotesProvider() val tagsProvider = TagsProvider() val foldersProvider = FoldersProvider() - val store = VersionedStore.get(context, USER_PREFERENCES_STORE_NAME, USER_PREFERENCES_VERSION) - val appTheme = ThemeManager() - val externalFolderSync = FolderRemoteDatabase(WeakReference(context)) - val imageCache = ImageCache(context) override fun database(): AppDatabase = db @@ -59,17 +44,14 @@ open class MaterialNoteConfig(context: Context) : CoreConfig(context) { override fun folderActions(folder: Folder): IFolderActor = MaterialFolderActor(folder) - override fun themeController(): IThemeManager = appTheme - override fun remoteConfigFetcher(): IRemoteConfigFetcher = NullRemoteConfigFetcher() - override fun startListener(activity: AppCompatActivity) {} - - override fun appFlavor(): Flavor = Flavor.NONE + override fun remoteDatabaseState(): IRemoteDatabaseState { + return object : IRemoteDatabaseState { + override fun notifyInsert(data: Any, onExecution: () -> Unit) {} + override fun notifyRemove(data: Any, onExecution: () -> Unit) {} + } + } - override fun store(): Store = store - - override fun externalFolderSync(): FolderRemoteDatabase = externalFolderSync - - override fun imageCache(): ImageCache = imageCache + override fun startListener(activity: AppCompatActivity) {} } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/config/auth/IAuthenticator.kt b/base/src/main/java/com/maubis/scarlet/base/config/auth/IAuthenticator.kt index c1881636..5cf57465 100644 --- a/base/src/main/java/com/maubis/scarlet/base/config/auth/IAuthenticator.kt +++ b/base/src/main/java/com/maubis/scarlet/base/config/auth/IAuthenticator.kt @@ -1,18 +1,31 @@ package com.maubis.scarlet.base.config.auth import android.content.Context +import com.maubis.scarlet.base.support.ui.ThemedActivity interface IAuthenticator { fun setup(context: Context) - fun isLoggedIn(): Boolean + fun isLoggedIn(context: Context): Boolean - fun userId(): String? + fun isLegacyLoggedIn(): Boolean + + fun userId(context: Context): String? fun openLoginActivity(context: Context): Runnable? fun openForgetMeActivity(context: Context): Runnable? + fun openTransferDataActivity(context: Context): Runnable? + + fun openLogoutActivity(context: Context): Runnable? + + fun setPendingUploadListener(listener: IPendingUploadListener?) + + fun showPendingSync(activity: ThemedActivity) + + fun requestSync(forced: Boolean) + fun logout() } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/config/auth/IPendingUploadListener.kt b/base/src/main/java/com/maubis/scarlet/base/config/auth/IPendingUploadListener.kt new file mode 100644 index 00000000..365512fc --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/config/auth/IPendingUploadListener.kt @@ -0,0 +1,13 @@ +package com.maubis.scarlet.base.config.auth + +interface IPendingUploadListener { + /** + * Fires when the pending state changes. + */ + fun onPendingStateUpdate(isDataSyncPending: Boolean) + + /** + * Pending Sync Count state change + */ + fun onPendingSyncsUpdate(isSyncHappening: Boolean) +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/config/auth/NullAuthenticator.kt b/base/src/main/java/com/maubis/scarlet/base/config/auth/NullAuthenticator.kt index 275d268d..ce66c911 100644 --- a/base/src/main/java/com/maubis/scarlet/base/config/auth/NullAuthenticator.kt +++ b/base/src/main/java/com/maubis/scarlet/base/config/auth/NullAuthenticator.kt @@ -1,18 +1,31 @@ package com.maubis.scarlet.base.config.auth import android.content.Context +import com.maubis.scarlet.base.support.ui.ThemedActivity class NullAuthenticator : IAuthenticator { + override fun openLoginActivity(context: Context): Runnable? = null override fun openForgetMeActivity(context: Context): Runnable? = null + override fun openTransferDataActivity(context: Context): Runnable? = null + + override fun openLogoutActivity(context: Context): Runnable? = null + override fun logout() {} override fun setup(context: Context) {} - override fun userId(): String? = null + override fun userId(context: Context): String? = null + + override fun isLoggedIn(context: Context): Boolean = false + + override fun isLegacyLoggedIn(): Boolean = false + + override fun setPendingUploadListener(listener: IPendingUploadListener?) {} - override fun isLoggedIn(): Boolean = false + override fun requestSync(forced: Boolean) {} + override fun showPendingSync(activity: ThemedActivity) {} } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/config/remote/RemoteConfig.kt b/base/src/main/java/com/maubis/scarlet/base/config/remote/RemoteConfig.kt index 209be365..0760e7e3 100644 --- a/base/src/main/java/com/maubis/scarlet/base/config/remote/RemoteConfig.kt +++ b/base/src/main/java/com/maubis/scarlet/base/config/remote/RemoteConfig.kt @@ -1,6 +1,5 @@ package com.maubis.scarlet.base.config.remote - class RemoteConfig( - val rc_lite_production_version: Int?, - val rc_full_production_version: Int?) + val rc_lite_production_version: Int?, + val rc_full_production_version: Int?) diff --git a/base/src/main/java/com/maubis/scarlet/base/core/folder/MaterialFolderActor.kt b/base/src/main/java/com/maubis/scarlet/base/core/folder/MaterialFolderActor.kt index d52aff45..ab120899 100644 --- a/base/src/main/java/com/maubis/scarlet/base/core/folder/MaterialFolderActor.kt +++ b/base/src/main/java/com/maubis/scarlet/base/core/folder/MaterialFolderActor.kt @@ -1,19 +1,20 @@ package com.maubis.scarlet.base.core.folder -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase +import com.maubis.scarlet.base.config.ApplicationBase.Companion.folderSync import com.maubis.scarlet.base.database.room.folder.Folder import com.maubis.scarlet.base.export.data.ExportableFolder open class MaterialFolderActor(val folder: Folder) : IFolderActor { override fun offlineSave() { - val id = CoreConfig.instance.foldersDatabase().database().insertFolder(folder) + val id = ApplicationBase.instance.foldersDatabase().database().insertFolder(folder) folder.uid = if (folder.isUnsaved()) id.toInt() else folder.uid - CoreConfig.instance.foldersDatabase().notifyInsertFolder(folder) + ApplicationBase.instance.foldersDatabase().notifyInsertFolder(folder) } override fun onlineSave() { - CoreConfig.instance.externalFolderSync().insert(ExportableFolder(folder)) + folderSync?.insert(ExportableFolder(folder)) } override fun save() { @@ -25,14 +26,14 @@ open class MaterialFolderActor(val folder: Folder) : IFolderActor { if (folder.isUnsaved()) { return } - CoreConfig.instance.foldersDatabase().database().delete(folder) - CoreConfig.instance.foldersDatabase().notifyDelete(folder) + ApplicationBase.instance.foldersDatabase().database().delete(folder) + ApplicationBase.instance.foldersDatabase().notifyDelete(folder) folder.uid = 0 } override fun delete() { offlineDelete() - CoreConfig.instance.externalFolderSync().remove(ExportableFolder(folder)) + folderSync?.remove(ExportableFolder(folder)) } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/core/format/Format.kt b/base/src/main/java/com/maubis/scarlet/base/core/format/Format.kt index 9b140fd1..26ad9b1f 100644 --- a/base/src/main/java/com/maubis/scarlet/base/core/format/Format.kt +++ b/base/src/main/java/com/maubis/scarlet/base/core/format/Format.kt @@ -1,5 +1,6 @@ package com.maubis.scarlet.base.core.format +import com.maubis.scarlet.base.note.creation.sheet.sEditorMoveChecked import org.json.JSONObject import java.util.* @@ -62,17 +63,33 @@ class Format { } fun sectionPreservingSort(formats: List): List { + if (!sEditorMoveChecked) { + return formats + } + val mutableFormats = formats.toMutableList() var index = 0 while (index < formats.size - 1) { val currentItem = mutableFormats[index] val nextItem = mutableFormats[index + 1] - if (currentItem.formatType == FormatType.CHECKLIST_CHECKED && nextItem.formatType == FormatType.CHECKLIST_UNCHECKED) { + if (currentItem.formatType == FormatType.CHECKLIST_CHECKED + && nextItem.formatType == FormatType.CHECKLIST_UNCHECKED) { Collections.swap(mutableFormats, index, index + 1) continue } index += 1 } + while (index > 0) { + val currentItem = mutableFormats[index] + val nextItem = mutableFormats[index - 1] + + if (currentItem.formatType == FormatType.CHECKLIST_UNCHECKED + && nextItem.formatType == FormatType.CHECKLIST_CHECKED) { + Collections.swap(mutableFormats, index, index - 1) + continue + } + index -= 1 + } return mutableFormats } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/core/format/FormatBuilder.kt b/base/src/main/java/com/maubis/scarlet/base/core/format/FormatBuilder.kt index f2e357e1..d751f0cb 100644 --- a/base/src/main/java/com/maubis/scarlet/base/core/format/FormatBuilder.kt +++ b/base/src/main/java/com/maubis/scarlet/base/core/format/FormatBuilder.kt @@ -1,8 +1,8 @@ package com.maubis.scarlet.base.core.format -import com.maubis.markdown.segmenter.TextSegmenter -import com.maubis.scarlet.base.note.toFormat -import com.maubis.scarlet.base.note.toRawFormat +import com.maubis.markdown.segmenter.MarkdownSegmentType +import com.maubis.scarlet.base.note.toInternalFormats +import com.maubis.scarlet.base.support.utils.maybeThrow import org.json.JSONArray import org.json.JSONException import org.json.JSONObject @@ -39,41 +39,15 @@ class FormatBuilder { continue } - val moreFormats = TextSegmenter(format.text).get().map { it.toRawFormat() } - var lastFormat: Format? = null - for (rawFormat in moreFormats) { - val isCheckedType = (rawFormat.formatType == FormatType.CHECKLIST_UNCHECKED || rawFormat.formatType == FormatType.CHECKLIST_CHECKED) - if (lastFormat != null && !isCheckedType) { - lastFormat.text += "\n" - lastFormat.text += rawFormat.text - continue - } - - if (!isCheckedType) { - rawFormat.formatType = FormatType.TEXT - lastFormat = rawFormat - continue - } - - if (lastFormat != null) { - extractedFormats.add(lastFormat) - lastFormat = null - } - - rawFormat.text = rawFormat.text - .removePrefix("[] ") - .removePrefix("[x] ") - .removePrefix("[ ] ") - .removePrefix("[X] ") - extractedFormats.add(rawFormat) - } - if (lastFormat !== null) { - extractedFormats.add(lastFormat) - } - + val moreFormats = format.text.toInternalFormats( + arrayOf( + MarkdownSegmentType.CHECKLIST_CHECKED, + MarkdownSegmentType.CHECKLIST_UNCHECKED)) + extractedFormats.addAll(moreFormats) } return getDescription(extractedFormats) } + fun getFormats(note: String): List { val formats = ArrayList() try { @@ -85,9 +59,11 @@ class FormatBuilder { format.uid = formats.size formats.add(format) } catch (innerException: JSONException) { + maybeThrow(innerException) } } } catch (exception: Exception) { + maybeThrow(exception) } return formats } diff --git a/base/src/main/java/com/maubis/scarlet/base/core/format/FormatType.kt b/base/src/main/java/com/maubis/scarlet/base/core/format/FormatType.kt index af39f361..72be2fd6 100644 --- a/base/src/main/java/com/maubis/scarlet/base/core/format/FormatType.kt +++ b/base/src/main/java/com/maubis/scarlet/base/core/format/FormatType.kt @@ -4,6 +4,9 @@ enum class FormatType { TAG, TEXT, NUMBERED_LIST, + BULLET_1, + BULLET_2, + BULLET_3, IMAGE, HEADING,// HEADING_1 SUB_HEADING, // HEADING_2 @@ -13,5 +16,5 @@ enum class FormatType { CODE, QUOTE, SEPARATOR, - EMPTY, + EMPTY } diff --git a/base/src/main/java/com/maubis/scarlet/base/core/note/INoteActor.kt b/base/src/main/java/com/maubis/scarlet/base/core/note/INoteActor.kt index e02acf65..2496e72f 100644 --- a/base/src/main/java/com/maubis/scarlet/base/core/note/INoteActor.kt +++ b/base/src/main/java/com/maubis/scarlet/base/core/note/INoteActor.kt @@ -1,7 +1,7 @@ package com.maubis.scarlet.base.core.note import android.content.Context -import android.support.v7.app.AppCompatActivity +import androidx.appcompat.app.AppCompatActivity interface INoteActor { diff --git a/base/src/main/java/com/maubis/scarlet/base/core/note/MaterialNoteActor.kt b/base/src/main/java/com/maubis/scarlet/base/core/note/MaterialNoteActor.kt index 24a35df4..ddbc6764 100644 --- a/base/src/main/java/com/maubis/scarlet/base/core/note/MaterialNoteActor.kt +++ b/base/src/main/java/com/maubis/scarlet/base/core/note/MaterialNoteActor.kt @@ -3,23 +3,29 @@ package com.maubis.scarlet.base.core.note import android.app.NotificationManager import android.content.Context import android.os.AsyncTask -import android.os.Build -import android.support.v7.app.AppCompatActivity +import androidx.appcompat.app.AppCompatActivity import com.github.bijoysingh.starter.util.IntentUtils import com.github.bijoysingh.starter.util.TextUtils import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase +import com.maubis.scarlet.base.config.ApplicationBase.Companion.folderSync +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppImageStorage import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb -import com.maubis.scarlet.base.database.room.note.Note import com.maubis.scarlet.base.core.format.FormatBuilder +import com.maubis.scarlet.base.database.room.note.Note import com.maubis.scarlet.base.export.data.ExportableNote import com.maubis.scarlet.base.main.activity.WidgetConfigureActivity -import com.maubis.scarlet.base.note.* +import com.maubis.scarlet.base.note.deleteToSync +import com.maubis.scarlet.base.note.getFullText +import com.maubis.scarlet.base.note.getTitleForSharing +import com.maubis.scarlet.base.note.mark +import com.maubis.scarlet.base.note.save +import com.maubis.scarlet.base.note.saveWithoutSync import com.maubis.scarlet.base.notification.NotificationConfig import com.maubis.scarlet.base.notification.NotificationHandler -import com.maubis.scarlet.base.widget.AllNotesWidgetProvider.Companion.notifyAllChanged import com.maubis.scarlet.base.service.FloatingNoteService -import com.maubis.scarlet.base.support.utils.ImageCache +import com.maubis.scarlet.base.support.utils.OsVersionUtils +import com.maubis.scarlet.base.widget.AllNotesWidgetProvider.Companion.notifyAllChanged import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import java.util.* @@ -31,10 +37,10 @@ open class MaterialNoteActor(val note: Note) : INoteActor { override fun share(context: Context) { IntentUtils.ShareBuilder(context) - .setSubject(note.getTitle()) - .setText(note.getText()) - .setChooserText(context.getString(R.string.share_using)) - .share() + .setSubject(note.getTitleForSharing()) + .setText(note.getFullText()) + .setChooserText(context.getString(R.string.share_using)) + .share() } override fun popup(activity: AppCompatActivity) { @@ -51,7 +57,7 @@ open class MaterialNoteActor(val note: Note) : INoteActor { } override fun onlineSave(context: Context) { - CoreConfig.instance.externalFolderSync().insert(ExportableNote(note)) + folderSync?.insert(ExportableNote(note)) } override fun save(context: Context) { @@ -68,7 +74,7 @@ open class MaterialNoteActor(val note: Note) : INoteActor { } override fun offlineDelete(context: Context) { - NoteImage(context).deleteAllFiles(note) + sAppImageStorage.deleteAllFiles(note) if (note.isUnsaved()) { return } @@ -92,9 +98,8 @@ open class MaterialNoteActor(val note: Note) : INoteActor { note.save(activity) } - override fun onlineDelete(context: Context) { - CoreConfig.instance.externalFolderSync().remove(ExportableNote(note)) + folderSync?.remove(ExportableNote(note)) } override fun delete(context: Context) { @@ -107,14 +112,14 @@ open class MaterialNoteActor(val note: Note) : INoteActor { notifyAllChanged(context) val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager? notificationManager?.cancel(note.uid) - CoreConfig.instance.imageCache().deleteNote(note.uuid) + ApplicationBase.sAppImageCache.deleteNote(note.uuid) } protected fun onNoteUpdated(context: Context) { WidgetConfigureActivity.notifyNoteChange(context, note) notifyAllChanged(context) val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager? - if (Build.VERSION.SDK_INT >= 23 && notificationManager != null) { + if (OsVersionUtils.canExtractActiveNotifications() && notificationManager != null) { for (notification in notificationManager.activeNotifications) { if (notification.id == note.uid) { val handler = NotificationHandler(context) diff --git a/base/src/main/java/com/maubis/scarlet/base/core/note/NoteBuilder.kt b/base/src/main/java/com/maubis/scarlet/base/core/note/NoteBuilder.kt index b0d8d563..8f152e70 100644 --- a/base/src/main/java/com/maubis/scarlet/base/core/note/NoteBuilder.kt +++ b/base/src/main/java/com/maubis/scarlet/base/core/note/NoteBuilder.kt @@ -3,10 +3,10 @@ package com.maubis.scarlet.base.core.note import com.github.bijoysingh.starter.util.RandomHelper import com.github.bijoysingh.starter.util.TextUtils import com.google.gson.Gson -import com.maubis.scarlet.base.database.room.note.Note import com.maubis.scarlet.base.core.format.Format import com.maubis.scarlet.base.core.format.FormatBuilder import com.maubis.scarlet.base.core.format.FormatType +import com.maubis.scarlet.base.database.room.note.Note import java.util.* fun generateUUID() = UUID.randomUUID().toString() @@ -23,6 +23,7 @@ class NoteBuilder { note.updateTimestamp = note.timestamp note.color = -0xff8695 note.folder = "" + note.description = FormatBuilder().getDescription(emptyList()) return note } diff --git a/base/src/main/java/com/maubis/scarlet/base/core/note/NoteExtensions.kt b/base/src/main/java/com/maubis/scarlet/base/core/note/NoteExtensions.kt index bc706808..ec58e522 100644 --- a/base/src/main/java/com/maubis/scarlet/base/core/note/NoteExtensions.kt +++ b/base/src/main/java/com/maubis/scarlet/base/core/note/NoteExtensions.kt @@ -2,11 +2,10 @@ package com.maubis.scarlet.base.core.note import com.github.bijoysingh.starter.util.TextUtils import com.google.gson.Gson -import com.maubis.scarlet.base.database.room.note.Note import com.maubis.scarlet.base.core.format.Format import com.maubis.scarlet.base.core.format.FormatBuilder -import com.maubis.scarlet.base.note.saveWithoutSync -import java.util.* +import com.maubis.scarlet.base.database.room.note.Note +import com.maubis.scarlet.base.support.utils.throwOrReturn fun Note.isUnsaved(): Boolean { return this.uid === null || this.uid == 0 @@ -14,13 +13,14 @@ fun Note.isUnsaved(): Boolean { fun Note.isEqual(note: Note): Boolean { return TextUtils.areEqualNullIsEmpty(this.state, note.state) - && TextUtils.areEqualNullIsEmpty(this.description, note.description) - && TextUtils.areEqualNullIsEmpty(this.uuid, note.uuid) - && TextUtils.areEqualNullIsEmpty(this.tags, note.tags) - && this.timestamp.toLong() == note.timestamp.toLong() - && this.color.toInt() == note.color.toInt() - && this.locked == note.locked - && this.pinned == note.pinned + && TextUtils.areEqualNullIsEmpty(this.description, note.description) + && TextUtils.areEqualNullIsEmpty(this.uuid, note.uuid) + && TextUtils.areEqualNullIsEmpty(this.tags, note.tags) + && this.timestamp.toLong() == note.timestamp.toLong() + && this.color.toInt() == note.color.toInt() + && this.locked == note.locked + && this.pinned == note.pinned + && this.folder == note.folder } /************************************************************************************** @@ -35,15 +35,15 @@ fun Note.getNoteState(): NoteState { try { return NoteState.valueOf(this.state) } catch (exception: Exception) { - return NoteState.DEFAULT + return throwOrReturn(exception, NoteState.DEFAULT) } } fun Note.getMeta(): NoteMeta { try { return Gson().fromJson(this.meta, NoteMeta::class.java) ?: NoteMeta() - } catch (e: Exception) { - return NoteMeta() + } catch (exception: Exception) { + return throwOrReturn(exception, NoteMeta()) } } @@ -63,6 +63,5 @@ fun Note.setReminderV2(reminder: Reminder) { fun Note.getTagUUIDs(): MutableSet { val tags = if (this.tags == null) "" else this.tags - val split = tags.split(",") - return HashSet(split) + return tags.split(",").filter { it.isNotBlank() }.toMutableSet() } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/core/note/NoteImage.kt b/base/src/main/java/com/maubis/scarlet/base/core/note/NoteImage.kt index 6bf080e7..5cb70670 100644 --- a/base/src/main/java/com/maubis/scarlet/base/core/note/NoteImage.kt +++ b/base/src/main/java/com/maubis/scarlet/base/core/note/NoteImage.kt @@ -4,11 +4,12 @@ import android.content.Context import android.view.View import android.widget.ImageView import com.github.bijoysingh.starter.util.RandomHelper -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase import com.maubis.scarlet.base.core.format.Format import com.maubis.scarlet.base.core.format.FormatBuilder import com.maubis.scarlet.base.core.format.FormatType import com.maubis.scarlet.base.database.room.note.Note +import com.maubis.scarlet.base.support.utils.maybeThrow import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @@ -38,7 +39,7 @@ class NoteImage(context: Context) { fun getFile(noteUUID: String, imageFormat: Format): File { if (imageFormat.formatType != FormatType.IMAGE) { - throw IllegalArgumentException("Format should be an Image") + maybeThrow("Format should be an Image") } return getFile(noteUUID, imageFormat.text) } @@ -66,7 +67,7 @@ class NoteImage(context: Context) { return@launch } - val bitmap = CoreConfig.instance.imageCache().loadFromCache(file) + val bitmap = ApplicationBase.sAppImageCache.loadFromCache(file) if (bitmap === null) { deleteIfExist(file) GlobalScope.launch(Dispatchers.Main) { @@ -83,12 +84,13 @@ class NoteImage(context: Context) { } } - fun loadThumbnailFileToImageView(noteUUID: String, imageUuid: String, - image: ImageView, - callback: ImageLoadCallback? = null) { + fun loadThumbnailFileToImageView( + noteUUID: String, imageUuid: String, + image: ImageView, + callback: ImageLoadCallback? = null) { GlobalScope.launch { - val thumbnailFile = CoreConfig.instance.imageCache().thumbnailFile(noteUUID, imageUuid) - val persistentFile = CoreConfig.instance.imageCache().persistentFile(noteUUID, imageUuid) + val thumbnailFile = ApplicationBase.sAppImageCache.thumbnailFile(noteUUID, imageUuid) + val persistentFile = ApplicationBase.sAppImageCache.persistentFile(noteUUID, imageUuid) if (!persistentFile.exists()) { GlobalScope.launch(Dispatchers.Main) { @@ -99,7 +101,7 @@ class NoteImage(context: Context) { } if (thumbnailFile.exists()) { - val bitmap = CoreConfig.instance.imageCache().loadFromCache(thumbnailFile) + val bitmap = ApplicationBase.sAppImageCache.loadFromCache(thumbnailFile) if (bitmap === null) { deleteIfExist(thumbnailFile) GlobalScope.launch(Dispatchers.Main) { @@ -116,7 +118,7 @@ class NoteImage(context: Context) { return@launch } - val persistentBitmap = CoreConfig.instance.imageCache().loadFromCache(persistentFile) + val persistentBitmap = ApplicationBase.sAppImageCache.loadFromCache(persistentFile) if (persistentBitmap === null) { deleteIfExist(persistentFile) GlobalScope.launch(Dispatchers.Main) { @@ -126,7 +128,7 @@ class NoteImage(context: Context) { return@launch } - val compressedBitmap = CoreConfig.instance.imageCache().saveThumbnail(thumbnailFile, persistentBitmap) + val compressedBitmap = ApplicationBase.sAppImageCache.saveThumbnail(thumbnailFile, persistentBitmap) GlobalScope.launch(Dispatchers.Main) { image.visibility = View.VISIBLE image.setImageBitmap(compressedBitmap) diff --git a/base/src/main/java/com/maubis/scarlet/base/core/note/NoteReminder.kt b/base/src/main/java/com/maubis/scarlet/base/core/note/NoteReminder.kt index 8a86b188..9dcfec2d 100644 --- a/base/src/main/java/com/maubis/scarlet/base/core/note/NoteReminder.kt +++ b/base/src/main/java/com/maubis/scarlet/base/core/note/NoteReminder.kt @@ -12,11 +12,10 @@ class NoteReminder() { var interval: ReminderInterval = ReminderInterval.ONCE var daysOfWeek: IntArray = intArrayOf() - constructor( - alarmTimestamp: Long, - interval: ReminderInterval, - daysOfWeek: IntArray) : this() { + alarmTimestamp: Long, + interval: ReminderInterval, + daysOfWeek: IntArray) : this() { this.alarmTimestamp = alarmTimestamp this.interval = interval this.daysOfWeek = daysOfWeek @@ -50,9 +49,10 @@ class NoteReminder() { } } -class Reminder(var uid: Int = 0, - var timestamp: Long = 0, - var interval: ReminderInterval = ReminderInterval.ONCE) { +class Reminder( + var uid: Int = 0, + var timestamp: Long = 0, + var interval: ReminderInterval = ReminderInterval.ONCE) { fun toCalendar(): Calendar { val calendar = Calendar.getInstance() diff --git a/base/src/main/java/com/maubis/scarlet/base/core/note/NoteSortingUtils.kt b/base/src/main/java/com/maubis/scarlet/base/core/note/NoteSortingUtils.kt index 1113cc22..cfe48f16 100644 --- a/base/src/main/java/com/maubis/scarlet/base/core/note/NoteSortingUtils.kt +++ b/base/src/main/java/com/maubis/scarlet/base/core/note/NoteSortingUtils.kt @@ -1,15 +1,28 @@ package com.maubis.scarlet.base.core.note import com.maubis.scarlet.base.database.room.note.Note -import com.maubis.scarlet.base.note.getAlphabets import com.maubis.scarlet.base.note.getFullText -import com.maubis.scarlet.base.note.getText enum class SortingTechnique() { LAST_MODIFIED, NEWEST_FIRST, OLDEST_FIRST, ALPHABETICAL, + NOTE_COLOR, + NOTE_TAGS, +} + +/** + * Helper class which allow comparison of a pair of objects + */ +class ComparablePair, U : Comparable>(val first: T, val second: U) : Comparable> { + override fun compareTo(other: ComparablePair): Int { + val firstComparison = first.compareTo(other.first) + return when { + firstComparison == 0 -> second.compareTo(other.second) + else -> firstComparison + } + } } fun sort(notes: List, sortingTechnique: SortingTechnique): List { @@ -24,13 +37,36 @@ fun sort(notes: List, sortingTechnique: SortingTechnique): List { else note.timestamp } SortingTechnique.ALPHABETICAL -> notes.sortedBy { note -> - val content = note.getAlphabets() - if (note.pinned || content.isBlank()) 0 - else content[0].toUpperCase().toInt() + val content = note.getFullText().trim().filter { + ((it in 'a'..'z') || (it in 'A'..'Z')) + } + + val sortValue = when { + (note.pinned || content.isBlank()) -> 0 + else -> content[0].toUpperCase().toInt() + } + ComparablePair(sortValue, note.updateTimestamp) + } + SortingTechnique.NOTE_COLOR -> notes.sortedBy { note -> + ComparablePair(note.color, note.updateTimestamp) } - else -> notes.sortedByDescending { note -> + SortingTechnique.NOTE_TAGS -> { + val tagCounterMap = HashMap() + notes.map { it.getTagUUIDs() }.forEach { tags -> + tags.forEach { tag -> + tagCounterMap[tag] = (tagCounterMap[tag] ?: 0) + 1 + } + } + notes.sortedByDescending { + val noteTagScore = it.getTagUUIDs().sumBy { tag -> + tagCounterMap[tag] ?: 0 + } + ComparablePair(ComparablePair(noteTagScore, it.tags ?: ""), it.updateTimestamp) + } + } + SortingTechnique.NEWEST_FIRST -> notes.sortedByDescending { note -> if (note.pinned) Long.MAX_VALUE - else note.timestamp + else note.timestamp ?: note.updateTimestamp } } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/core/tag/MaterialTagActor.kt b/base/src/main/java/com/maubis/scarlet/base/core/tag/MaterialTagActor.kt index c078e8e8..3d80d88a 100644 --- a/base/src/main/java/com/maubis/scarlet/base/core/tag/MaterialTagActor.kt +++ b/base/src/main/java/com/maubis/scarlet/base/core/tag/MaterialTagActor.kt @@ -1,18 +1,18 @@ package com.maubis.scarlet.base.core.tag -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase import com.maubis.scarlet.base.database.room.tag.Tag import com.maubis.scarlet.base.export.data.ExportableTag open class MaterialTagActor(val tag: Tag) : ITagActor { override fun offlineSave() { - val id = CoreConfig.instance.tagsDatabase().database().insertTag(tag) + val id = ApplicationBase.instance.tagsDatabase().database().insertTag(tag) tag.uid = if (tag.isUnsaved()) id.toInt() else tag.uid - CoreConfig.instance.tagsDatabase().notifyInsertTag(tag) + ApplicationBase.instance.tagsDatabase().notifyInsertTag(tag) } override fun onlineSave() { - CoreConfig.instance.externalFolderSync().insert(ExportableTag(tag)) + ApplicationBase.folderSync?.insert(ExportableTag(tag)) } override fun save() { @@ -24,14 +24,14 @@ open class MaterialTagActor(val tag: Tag) : ITagActor { if (tag.isUnsaved()) { return } - CoreConfig.instance.tagsDatabase().database().delete(tag) - CoreConfig.instance.tagsDatabase().notifyDelete(tag) + ApplicationBase.instance.tagsDatabase().database().delete(tag) + ApplicationBase.instance.tagsDatabase().notifyDelete(tag) tag.uid = 0 } override fun delete() { offlineDelete() - CoreConfig.instance.externalFolderSync().remove(ExportableTag(tag)) + ApplicationBase.folderSync?.remove(ExportableTag(tag)) } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/database/FoldersProvider.kt b/base/src/main/java/com/maubis/scarlet/base/database/FoldersProvider.kt index ca9cf894..79393ddb 100644 --- a/base/src/main/java/com/maubis/scarlet/base/database/FoldersProvider.kt +++ b/base/src/main/java/com/maubis/scarlet/base/database/FoldersProvider.kt @@ -1,10 +1,8 @@ package com.maubis.scarlet.base.database -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase import com.maubis.scarlet.base.database.room.folder.Folder import com.maubis.scarlet.base.database.room.folder.FolderDao -import com.maubis.scarlet.base.database.room.tag.Tag -import com.maubis.scarlet.base.database.room.tag.TagDao import java.util.concurrent.ConcurrentHashMap class FoldersProvider { @@ -26,6 +24,11 @@ class FoldersProvider { return folders.size } + fun getUUIDs(): List { + maybeLoadFromDB() + return folders.values.map { it.uuid } + } + fun getAll(): List { maybeLoadFromDB() return folders.values.toList() @@ -49,7 +52,7 @@ class FoldersProvider { fun search(string: String): List { maybeLoadFromDB() return folders.values - .filter { string.isBlank() || it.title.contains(string, true) } + .filter { string.isBlank() || it.title.contains(string, true) } } @Synchronized @@ -67,6 +70,6 @@ class FoldersProvider { } fun database(): FolderDao { - return CoreConfig.instance.database().folders() + return ApplicationBase.instance.database().folders() } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/database/NotesProvider.kt b/base/src/main/java/com/maubis/scarlet/base/database/NotesProvider.kt index 3857de91..459f1af8 100644 --- a/base/src/main/java/com/maubis/scarlet/base/database/NotesProvider.kt +++ b/base/src/main/java/com/maubis/scarlet/base/database/NotesProvider.kt @@ -1,8 +1,7 @@ package com.maubis.scarlet.base.database -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase import com.maubis.scarlet.base.core.note.INoteContainer -import com.maubis.scarlet.base.database.room.folder.Folder import com.maubis.scarlet.base.database.room.note.Note import com.maubis.scarlet.base.database.room.note.NoteDao import com.maubis.scarlet.base.note.applySanityChecks @@ -27,6 +26,11 @@ class NotesProvider { return notes.size } + fun getUUIDs(): List { + maybeLoadFromDB() + return notes.values.map { it.uuid } + } + fun getAll(): List { maybeLoadFromDB() return notes.values.toList() @@ -107,6 +111,6 @@ class NotesProvider { } fun database(): NoteDao { - return CoreConfig.instance.database().notes() + return ApplicationBase.instance.database().notes() } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/database/TagsProvider.kt b/base/src/main/java/com/maubis/scarlet/base/database/TagsProvider.kt index d0bd5abf..ca7ac14f 100644 --- a/base/src/main/java/com/maubis/scarlet/base/database/TagsProvider.kt +++ b/base/src/main/java/com/maubis/scarlet/base/database/TagsProvider.kt @@ -1,6 +1,6 @@ package com.maubis.scarlet.base.database -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase import com.maubis.scarlet.base.database.room.tag.Tag import com.maubis.scarlet.base.database.room.tag.TagDao import java.util.concurrent.ConcurrentHashMap @@ -24,6 +24,11 @@ class TagsProvider { return tags.size } + fun getUUIDs(): List { + maybeLoadFromDB() + return tags.values.map { it.uuid } + } + fun getAll(): List { maybeLoadFromDB() return tags.values.toList() @@ -47,7 +52,7 @@ class TagsProvider { fun search(string: String): List { maybeLoadFromDB() return tags.values - .filter { string.isBlank() || it.title.contains(string, true) } + .filter { string.isBlank() || it.title.contains(string, true) } } @Synchronized @@ -65,6 +70,6 @@ class TagsProvider { } fun database(): TagDao { - return CoreConfig.instance.database().tags() + return ApplicationBase.instance.database().tags() } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/database/remote/IRemoteDatabaseState.kt b/base/src/main/java/com/maubis/scarlet/base/database/remote/IRemoteDatabaseState.kt new file mode 100644 index 00000000..4b66085b --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/database/remote/IRemoteDatabaseState.kt @@ -0,0 +1,6 @@ +package com.maubis.scarlet.base.database.remote + +interface IRemoteDatabaseState { + fun notifyInsert(data: Any, onExecution: () -> Unit) + fun notifyRemove(data: Any, onExecution: () -> Unit) +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/database/remote/IRemoteDatabaseUtils.kt b/base/src/main/java/com/maubis/scarlet/base/database/remote/IRemoteDatabaseUtils.kt index c1c66c74..3915c55a 100644 --- a/base/src/main/java/com/maubis/scarlet/base/database/remote/IRemoteDatabaseUtils.kt +++ b/base/src/main/java/com/maubis/scarlet/base/database/remote/IRemoteDatabaseUtils.kt @@ -44,7 +44,7 @@ object IRemoteDatabaseUtils { val notifiedTag = TagBuilder().copy(tag) val existingTag = CoreConfig.tagsDb.getByUUID(tag.uuid()) var isSameAsExisting = existingTag !== null - && TextUtils.areEqualNullIsEmpty(notifiedTag.title, existingTag.title) + && TextUtils.areEqualNullIsEmpty(notifiedTag.title, existingTag.title) if (existingTag === null) { notifiedTag.saveWithoutSync() @@ -62,10 +62,10 @@ object IRemoteDatabaseUtils { val notifiedFolder = FolderBuilder().copy(folder) val existingFolder = CoreConfig.foldersDb.getByUUID(folder.uuid()) var isSameAsExisting = existingFolder !== null - && TextUtils.areEqualNullIsEmpty(notifiedFolder.title, existingFolder.title) - && (notifiedFolder.color == existingFolder.color) - && (notifiedFolder.timestamp == existingFolder.timestamp) - && (notifiedFolder.updateTimestamp == existingFolder.updateTimestamp) + && TextUtils.areEqualNullIsEmpty(notifiedFolder.title, existingFolder.title) + && (notifiedFolder.color == existingFolder.color) + && (notifiedFolder.timestamp == existingFolder.timestamp) + && (notifiedFolder.updateTimestamp == existingFolder.updateTimestamp) if (existingFolder === null) { notifiedFolder.saveWithoutSync() @@ -90,8 +90,20 @@ object IRemoteDatabaseUtils { } } + fun onRemoteRemoveNote(context: Context, noteUUID: String) { + val existingNote = CoreConfig.notesDb.getByUUID(noteUUID) + if (existingNote !== null && !existingNote.disableBackup) { + existingNote.deleteWithoutSync(context) + sendNoteBroadcast(context, NoteBroadcast.NOTE_DELETED, existingNote.uuid) + } + } + fun onRemoteRemove(context: Context, tag: ITagContainer) { - val existingTag = CoreConfig.tagsDb.getByUUID(tag.uuid()) + onRemoteRemoveTag(context, tag.uuid()) + } + + fun onRemoteRemoveTag(context: Context, tagUUID: String) { + val existingTag = CoreConfig.tagsDb.getByUUID(tagUUID) if (existingTag !== null) { existingTag.deleteWithoutSync() sendNoteBroadcast(context, NoteBroadcast.TAG_DELETED, existingTag.uuid) @@ -99,7 +111,11 @@ object IRemoteDatabaseUtils { } fun onRemoteRemove(context: Context, folder: IFolderContainer) { - val existingFolder = CoreConfig.foldersDb.getByUUID(folder.uuid()) + onRemoteRemoveFolder(context, folder.uuid()) + } + + fun onRemoteRemoveFolder(context: Context, folderUUID: String) { + val existingFolder = CoreConfig.foldersDb.getByUUID(folderUUID) if (existingFolder !== null) { existingFolder.deleteWithoutSync() CoreConfig.notesDb.getAll().filter { it.folder == existingFolder.uuid }.forEach { diff --git a/base/src/main/java/com/maubis/scarlet/base/database/room/AppDatabase.java b/base/src/main/java/com/maubis/scarlet/base/database/room/AppDatabase.java index feb44cd3..2ca937ff 100644 --- a/base/src/main/java/com/maubis/scarlet/base/database/room/AppDatabase.java +++ b/base/src/main/java/com/maubis/scarlet/base/database/room/AppDatabase.java @@ -1,12 +1,13 @@ package com.maubis.scarlet.base.database.room; -import android.arch.persistence.db.SupportSQLiteDatabase; -import android.arch.persistence.room.Database; -import android.arch.persistence.room.Room; -import android.arch.persistence.room.RoomDatabase; -import android.arch.persistence.room.migration.Migration; import android.content.Context; +import androidx.room.Database; +import androidx.room.Room; +import androidx.room.RoomDatabase; +import androidx.room.migration.Migration; +import androidx.sqlite.db.SupportSQLiteDatabase; + import com.maubis.scarlet.base.database.room.folder.Folder; import com.maubis.scarlet.base.database.room.folder.FolderDao; import com.maubis.scarlet.base.database.room.note.Note; @@ -16,7 +17,7 @@ import com.maubis.scarlet.base.database.room.widget.Widget; import com.maubis.scarlet.base.database.room.widget.WidgetDao; -@Database(entities = {Note.class, Tag.class, Widget.class, Folder.class}, version = 13) +@Database(entities = {Note.class, Tag.class, Widget.class, Folder.class}, version = 14) public abstract class AppDatabase extends RoomDatabase { public static final Migration MIGRATION_1_2 = new Migration(1, 2) { @@ -91,7 +92,7 @@ public void migrate(SupportSQLiteDatabase database) { @Override public void migrate(SupportSQLiteDatabase database) { database.execSQL("CREATE TABLE IF NOT EXISTS folder (`uid` INTEGER PRIMARY KEY " + - "AUTOINCREMENT NOT NULL, `title` TEXT, `timestamp` INTEGER, " + + "AUTOINCREMENT, `title` TEXT, `timestamp` INTEGER, " + "`updateTimestamp` INTEGER NOT NULL, `color` INTEGER, `uuid` TEXT)"); database.execSQL("CREATE INDEX `index_folder_uid` ON `folder` (`uid`)"); } @@ -99,15 +100,36 @@ public void migrate(SupportSQLiteDatabase database) { public static final Migration MIGRATION_12_13 = new Migration(12, 13) { @Override public void migrate(SupportSQLiteDatabase database) { + database.beginTransaction(); + database.execSQL("CREATE TEMPORARY TABLE folder_backup(`title` TEXT, `timestamp` INTEGER, " + + "`updateTimestamp` INTEGER NOT NULL, `color` INTEGER, `uuid` TEXT)"); + database.execSQL("INSERT INTO folder_backup SELECT title, timestamp, updateTimestamp, color, uuid FROM folder"); + database.execSQL("DROP TABLE folder"); + database.execSQL("CREATE TABLE folder(`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," + + " `title` TEXT, `timestamp` INTEGER, " + + "`updateTimestamp` INTEGER NOT NULL, `color` INTEGER, `uuid` TEXT)"); + database.execSQL("CREATE INDEX IF NOT EXISTS `index_folder_uid` ON `folder` (`uid`)"); + database.execSQL("INSERT INTO folder SELECT NULL, title, timestamp, updateTimestamp, color, uuid FROM folder_backup"); + database.execSQL("DROP TABLE folder_backup"); database.execSQL("ALTER TABLE note ADD COLUMN folder TEXT DEFAULT ''"); + database.setTransactionSuccessful(); + database.endTransaction(); + } + }; + public static final Migration MIGRATION_13_14 = new Migration(13, 14) { + @Override + public void migrate(SupportSQLiteDatabase database) { } }; public static AppDatabase createDatabase(Context context) { return Room.databaseBuilder(context, AppDatabase.class, "note-database") .allowMainThreadQueries() - .addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6, MIGRATION_6_7, MIGRATION_7_8, MIGRATION_8_9, MIGRATION_9_10, MIGRATION_10_11, MIGRATION_11_12, MIGRATION_12_13) - .build(); + .addMigrations( + MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6, + MIGRATION_6_7, MIGRATION_7_8, MIGRATION_8_9, MIGRATION_9_10, MIGRATION_10_11, + MIGRATION_11_12, MIGRATION_12_13, MIGRATION_13_14 + ).build(); } public abstract NoteDao notes(); diff --git a/base/src/main/java/com/maubis/scarlet/base/database/room/folder/Folder.java b/base/src/main/java/com/maubis/scarlet/base/database/room/folder/Folder.java index 16e58666..c3f3a064 100644 --- a/base/src/main/java/com/maubis/scarlet/base/database/room/folder/Folder.java +++ b/base/src/main/java/com/maubis/scarlet/base/database/room/folder/Folder.java @@ -1,8 +1,8 @@ package com.maubis.scarlet.base.database.room.folder; -import android.arch.persistence.room.Entity; -import android.arch.persistence.room.Index; -import android.arch.persistence.room.PrimaryKey; +import androidx.room.Entity; +import androidx.room.Index; +import androidx.room.PrimaryKey; /** * Underlying Database, difficult to migrate to Kotlin without breaking the Database. diff --git a/base/src/main/java/com/maubis/scarlet/base/database/room/folder/FolderDao.java b/base/src/main/java/com/maubis/scarlet/base/database/room/folder/FolderDao.java index 0052c6d6..5b0b29e0 100644 --- a/base/src/main/java/com/maubis/scarlet/base/database/room/folder/FolderDao.java +++ b/base/src/main/java/com/maubis/scarlet/base/database/room/folder/FolderDao.java @@ -1,12 +1,10 @@ package com.maubis.scarlet.base.database.room.folder; -import android.arch.persistence.room.Dao; -import android.arch.persistence.room.Delete; -import android.arch.persistence.room.Insert; -import android.arch.persistence.room.OnConflictStrategy; -import android.arch.persistence.room.Query; - -import com.maubis.scarlet.base.database.room.note.Note; +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Query; import java.util.List; diff --git a/base/src/main/java/com/maubis/scarlet/base/database/room/note/Note.java b/base/src/main/java/com/maubis/scarlet/base/database/room/note/Note.java index 70ed043c..92595d22 100644 --- a/base/src/main/java/com/maubis/scarlet/base/database/room/note/Note.java +++ b/base/src/main/java/com/maubis/scarlet/base/database/room/note/Note.java @@ -1,8 +1,8 @@ package com.maubis.scarlet.base.database.room.note; -import android.arch.persistence.room.Entity; -import android.arch.persistence.room.Index; -import android.arch.persistence.room.PrimaryKey; +import androidx.room.Entity; +import androidx.room.Index; +import androidx.room.PrimaryKey; /** * Underlying Database, difficult to migrate to Kotlin without breaking the Database. @@ -29,7 +29,7 @@ public class Note { public boolean locked; - public String tags; + public String tags = ""; public long updateTimestamp; diff --git a/base/src/main/java/com/maubis/scarlet/base/database/room/note/NoteDao.java b/base/src/main/java/com/maubis/scarlet/base/database/room/note/NoteDao.java index a0f776a4..024b7022 100644 --- a/base/src/main/java/com/maubis/scarlet/base/database/room/note/NoteDao.java +++ b/base/src/main/java/com/maubis/scarlet/base/database/room/note/NoteDao.java @@ -1,10 +1,10 @@ package com.maubis.scarlet.base.database.room.note; -import android.arch.persistence.room.Dao; -import android.arch.persistence.room.Delete; -import android.arch.persistence.room.Insert; -import android.arch.persistence.room.OnConflictStrategy; -import android.arch.persistence.room.Query; +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Query; import java.util.List; @@ -38,8 +38,7 @@ public interface NoteDao { @Query("SELECT * FROM note WHERE tags LIKE :uuidRegex ORDER BY pinned DESC, timestamp DESC") List getNoteByTag(String uuidRegex); - @Query("SELECT COUNT(*) FROM note WHERE tags LIKE :uuidRegex ORDER BY pinned DESC, timestamp " - + "DESC") + @Query("SELECT COUNT(*) FROM note WHERE tags LIKE :uuidRegex ORDER BY pinned DESC, timestamp " + "DESC") int getNoteCountByTag(String uuidRegex); @Query("SELECT * FROM note WHERE uid = :uid LIMIT 1") diff --git a/base/src/main/java/com/maubis/scarlet/base/database/room/tag/Tag.java b/base/src/main/java/com/maubis/scarlet/base/database/room/tag/Tag.java index 3bb2d189..f60a1a97 100644 --- a/base/src/main/java/com/maubis/scarlet/base/database/room/tag/Tag.java +++ b/base/src/main/java/com/maubis/scarlet/base/database/room/tag/Tag.java @@ -1,8 +1,8 @@ package com.maubis.scarlet.base.database.room.tag; -import android.arch.persistence.room.Entity; -import android.arch.persistence.room.Index; -import android.arch.persistence.room.PrimaryKey; +import androidx.room.Entity; +import androidx.room.Index; +import androidx.room.PrimaryKey; @Entity(tableName = "tag", indices = {@Index("uid")}) public class Tag { diff --git a/base/src/main/java/com/maubis/scarlet/base/database/room/tag/TagDao.java b/base/src/main/java/com/maubis/scarlet/base/database/room/tag/TagDao.java index a0e56c05..26099a9c 100644 --- a/base/src/main/java/com/maubis/scarlet/base/database/room/tag/TagDao.java +++ b/base/src/main/java/com/maubis/scarlet/base/database/room/tag/TagDao.java @@ -1,10 +1,10 @@ package com.maubis.scarlet.base.database.room.tag; -import android.arch.persistence.room.Dao; -import android.arch.persistence.room.Delete; -import android.arch.persistence.room.Insert; -import android.arch.persistence.room.OnConflictStrategy; -import android.arch.persistence.room.Query; +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Query; import java.util.List; diff --git a/base/src/main/java/com/maubis/scarlet/base/database/room/widget/Widget.java b/base/src/main/java/com/maubis/scarlet/base/database/room/widget/Widget.java index 7d0b301a..3eea9aad 100644 --- a/base/src/main/java/com/maubis/scarlet/base/database/room/widget/Widget.java +++ b/base/src/main/java/com/maubis/scarlet/base/database/room/widget/Widget.java @@ -1,8 +1,8 @@ package com.maubis.scarlet.base.database.room.widget; -import android.arch.persistence.room.Entity; -import android.arch.persistence.room.Index; -import android.arch.persistence.room.PrimaryKey; +import androidx.room.Entity; +import androidx.room.Index; +import androidx.room.PrimaryKey; @Entity(tableName = "widget", indices = {@Index("widgetId")}) public class Widget { diff --git a/base/src/main/java/com/maubis/scarlet/base/database/room/widget/WidgetDao.java b/base/src/main/java/com/maubis/scarlet/base/database/room/widget/WidgetDao.java index 9b868efb..005e16c1 100644 --- a/base/src/main/java/com/maubis/scarlet/base/database/room/widget/WidgetDao.java +++ b/base/src/main/java/com/maubis/scarlet/base/database/room/widget/WidgetDao.java @@ -1,10 +1,10 @@ package com.maubis.scarlet.base.database.room.widget; -import android.arch.persistence.room.Dao; -import android.arch.persistence.room.Delete; -import android.arch.persistence.room.Insert; -import android.arch.persistence.room.OnConflictStrategy; -import android.arch.persistence.room.Query; +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Query; import java.util.List; diff --git a/base/src/main/java/com/maubis/scarlet/base/export/activity/ImportNoteActivity.kt b/base/src/main/java/com/maubis/scarlet/base/export/activity/ImportNoteActivity.kt index 00fc8f9b..fcd9e70f 100644 --- a/base/src/main/java/com/maubis/scarlet/base/export/activity/ImportNoteActivity.kt +++ b/base/src/main/java/com/maubis/scarlet/base/export/activity/ImportNoteActivity.kt @@ -9,19 +9,18 @@ import android.widget.TextView import com.github.bijoysingh.starter.async.MultiAsyncTask import com.github.bijoysingh.starter.recyclerview.RecyclerViewBuilder import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme import com.maubis.scarlet.base.export.recycler.FileRecyclerItem import com.maubis.scarlet.base.export.support.NoteImporter import com.maubis.scarlet.base.note.recycler.NoteAppAdapter -import com.maubis.scarlet.base.support.utils.bind import com.maubis.scarlet.base.support.recycler.RecyclerItem +import com.maubis.scarlet.base.support.ui.SecuredActivity import com.maubis.scarlet.base.support.ui.ThemeColorType -import com.maubis.scarlet.base.support.ui.ThemedActivity +import com.maubis.scarlet.base.support.utils.bind import java.io.File import java.io.FileReader - -class ImportNoteActivity : ThemedActivity() { +class ImportNoteActivity : SecuredActivity() { val adapter = NoteAppAdapter(this) var currentlySelectedFile: File? = null @@ -35,9 +34,9 @@ class ImportNoteActivity : ThemedActivity() { setContentView(R.layout.activity_import_note_from_file) RecyclerViewBuilder(this) - .setView(this, R.id.recycler_view) - .setAdapter(adapter) - .build() + .setView(this, R.id.recycler_view) + .setAdapter(adapter) + .build() val activity = this backButton.setOnClickListener { onBackPressed() } @@ -67,8 +66,8 @@ class ImportNoteActivity : ThemedActivity() { MultiAsyncTask.execute(object : MultiAsyncTask.Task> { override fun run(): List { return NoteImporter().getImportableFiles() - .map { FileRecyclerItem(it.name, it.lastModified(), it.absolutePath, it) } - .sorted() + .map { FileRecyclerItem(it.name, it.lastModified(), it.absolutePath, it) } + .sorted() } override fun handle(result: List) { @@ -95,13 +94,12 @@ class ImportNoteActivity : ThemedActivity() { } override fun notifyThemeChange() { - val theme = CoreConfig.instance.themeController() - background.setBackgroundColor(theme.get(ThemeColorType.BACKGROUND)) - backButton.setColorFilter(theme.get(ThemeColorType.TOOLBAR_ICON)) - pageTitle.setTextColor(theme.get(ThemeColorType.TERTIARY_TEXT)) - importFile.setTextColor(theme.get(ThemeColorType.TERTIARY_TEXT)) + background.setBackgroundColor(sAppTheme.get(ThemeColorType.BACKGROUND)) + backButton.setColorFilter(sAppTheme.get(ThemeColorType.TOOLBAR_ICON)) + pageTitle.setTextColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT)) + importFile.setTextColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT)) importFile.setBackgroundResource( - if (CoreConfig.instance.themeController().isNightTheme()) R.drawable.light_circular_border_bg - else R.drawable.dark_circular_border_bg) + if (sAppTheme.isNightTheme()) R.drawable.light_circular_border_bg + else R.drawable.dark_circular_border_bg) } } diff --git a/base/src/main/java/com/maubis/scarlet/base/export/data/ExportableData.kt b/base/src/main/java/com/maubis/scarlet/base/export/data/ExportableData.kt new file mode 100644 index 00000000..ad17e1b4 --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/export/data/ExportableData.kt @@ -0,0 +1,126 @@ +package com.maubis.scarlet.base.export.data + +import com.maubis.scarlet.base.core.folder.IFolderContainer +import com.maubis.scarlet.base.core.note.NoteState +import com.maubis.scarlet.base.core.note.generateUUID +import com.maubis.scarlet.base.core.tag.ITagContainer +import com.maubis.scarlet.base.core.tag.TagBuilder +import com.maubis.scarlet.base.database.room.folder.Folder +import com.maubis.scarlet.base.database.room.tag.Tag +import org.json.JSONObject +import java.io.Serializable +import java.util.* + +/** + * Data class containing the note as a string of the content which can be stored in user + * readable format (markdown) and meta data object + */ +class ExportableSplitNote( + val content: String, + val meta: ExportableNoteMeta) { + + // Default failsafe constructor for Gson to use + constructor() : this( + "", + ExportableNoteMeta()) +} + +/** + * Data class containing only the meta data for the note which makes it unique to Scarlet + */ +class ExportableNoteMeta( + val uuid: String, + val timestamp: Long, + val updateTimestamp: Long, + val color: Int, + val state: String, + val tags: String, + val locked: Boolean, + val pinned: Boolean, + val folder: String) { + + // Default failsafe constructor for Gson to use + constructor() : this( + "invalid", + Calendar.getInstance().timeInMillis, + Calendar.getInstance().timeInMillis, + -0xff8695, + NoteState.DEFAULT.name, + "", + false, + false, + "") +} + +/** + * Data class for the exportability of tags + */ +class ExportableTag( + var uuid: String, + var title: String +) : Serializable, ITagContainer { + + override fun title(): String = title + + override fun uuid(): String = uuid + + // Default failsafe constructor for Gson to use + constructor() : this("invalid", "") + + constructor(tag: Tag) : this( + tag.uuid, + tag.title + ) + + companion object { + fun fromJSON(json: JSONObject): ExportableTag { + val version = if (json.has("version")) json.getInt("version") else 1 + return when (version) { + 1 -> fromJSONObjectV1(json) + else -> fromJSONObjectV1(json) + } + } + + fun fromJSONObjectV1(json: JSONObject): ExportableTag { + return ExportableTag( + generateUUID(), + json["title"] as String) + } + + fun getBestPossibleTagObject(json: JSONObject): Tag { + return TagBuilder().copy(fromJSON(json)) + } + } +} + +/** + * Data class for the exportability of folder + */ +class ExportableFolder( + val uuid: String, + val title: String, + val timestamp: Long, + val updateTimestamp: Long, + val color: Int +) : Serializable, IFolderContainer { + override fun timestamp(): Long = timestamp + override fun updateTimestamp(): Long = updateTimestamp + override fun color(): Int = color + override fun title(): String = title + override fun uuid(): String = uuid + + constructor(folder: Folder) : this( + folder.uuid ?: "", + folder.title ?: "", + folder.timestamp ?: 0, + folder.updateTimestamp, + folder.color ?: 0) + + // Default failsafe constructor for Gson to use + constructor() : this( + "invalid", + "", + Calendar.getInstance().timeInMillis, + Calendar.getInstance().timeInMillis, + -0xff8695) +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/export/data/ExportableExtensions.kt b/base/src/main/java/com/maubis/scarlet/base/export/data/ExportableExtensions.kt new file mode 100644 index 00000000..a65f67dd --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/export/data/ExportableExtensions.kt @@ -0,0 +1,96 @@ +package com.maubis.scarlet.base.export.data + +import com.maubis.scarlet.base.core.format.FormatBuilder +import com.maubis.scarlet.base.core.format.FormatType +import com.maubis.scarlet.base.core.note.getFormats +import com.maubis.scarlet.base.database.room.folder.Folder +import com.maubis.scarlet.base.database.room.note.Note +import com.maubis.scarlet.base.database.room.tag.Tag +import com.maubis.scarlet.base.note.toInternalFormats + +/** + * Converts the note which is markdown into internal format + */ +fun fromExportedMarkdown(content: String): String { + val formats = content.toInternalFormats() + return FormatBuilder().getDescription(formats) +} + +/** + * Converts the note's internal description format into markdown which can be used to export. + */ +fun Note.toExportedMarkdown(): String { + val markdownBuilder = StringBuilder() + getFormats().forEach { format -> + val text = format.text + val formatMarkdown = when (format.formatType) { + FormatType.NUMBERED_LIST -> "- $text" + FormatType.HEADING -> "# $text" + FormatType.HEADING_3 -> "### $text" + FormatType.BULLET_1 -> "- $text" + FormatType.BULLET_2 -> " - $text" + FormatType.BULLET_3 -> " - $text" + FormatType.CHECKLIST_CHECKED -> "[x] $text" + FormatType.CHECKLIST_UNCHECKED -> "[ ] $text" + FormatType.SUB_HEADING -> "## $text" + FormatType.CODE -> "```\n$text\n```" + FormatType.QUOTE -> "> $text" + // TODO: Fix the fact that markdown parsing wont parse this correctly + FormatType.IMAGE -> "$text" + FormatType.SEPARATOR -> "\n---\n" + FormatType.TEXT -> text + + // NOTE: All the following states should never happen at this place + + FormatType.TAG -> "" + FormatType.EMPTY -> "" + } + markdownBuilder.append(formatMarkdown) + markdownBuilder.append("\n") + } + return markdownBuilder.toString().trim() +} + +fun Note.getExportableSplitNote(): ExportableSplitNote { + return ExportableSplitNote( + toExportedMarkdown(), + getExportableNoteMeta()) +} + +fun Note.getExportableNoteMeta(): ExportableNoteMeta { + return ExportableNoteMeta( + uuid, + timestamp, + updateTimestamp, + color, + state, + if (tags == null) "" else tags, + locked, + pinned, + folder + ) +} + +fun Note.mergeMetas(meta: ExportableNoteMeta) { + uuid = meta.uuid + state = meta.state + timestamp = meta.timestamp + updateTimestamp = meta.updateTimestamp + color = meta.color + tags = meta.tags + pinned = meta.pinned + locked = meta.locked + folder = meta.folder +} + +fun Folder.getExportableFolder(): ExportableFolder { + return ExportableFolder( + uuid, + title, + timestamp, + updateTimestamp, + color + ) +} + +fun Tag.getExportableTag(): ExportableTag = ExportableTag(uuid, title) \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/export/data/ExportableFileFormat.kt b/base/src/main/java/com/maubis/scarlet/base/export/data/ExportableFileFormat.kt index fbfdd65e..49a92b6a 100644 --- a/base/src/main/java/com/maubis/scarlet/base/export/data/ExportableFileFormat.kt +++ b/base/src/main/java/com/maubis/scarlet/base/export/data/ExportableFileFormat.kt @@ -1,7 +1,7 @@ package com.maubis.scarlet.base.export.data class ExportableFileFormat( - val version: Int, - val notes: List, - val tags: List, - val folders: List?) \ No newline at end of file + val version: Int, + val notes: List, + val tags: List, + val folders: List?) \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/export/data/ExportableFolder.kt b/base/src/main/java/com/maubis/scarlet/base/export/data/ExportableFolder.kt deleted file mode 100644 index 006e2233..00000000 --- a/base/src/main/java/com/maubis/scarlet/base/export/data/ExportableFolder.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.maubis.scarlet.base.export.data - -import com.maubis.scarlet.base.core.folder.IFolderContainer -import com.maubis.scarlet.base.database.room.folder.Folder -import java.io.Serializable - -class ExportableFolder( - val uuid: String, - val title: String, - val timestamp: Long, - val updateTimestamp: Long, - val color: Int -) : Serializable, IFolderContainer { - override fun timestamp(): Long = timestamp - override fun updateTimestamp(): Long = updateTimestamp - override fun color(): Int = color - override fun title(): String = title - override fun uuid(): String = uuid - - constructor(folder: Folder) : this( - folder.uuid ?: "", - folder.title ?: "", - folder.timestamp ?: 0, - folder.updateTimestamp, - folder.color ?: 0) -} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/export/data/ExportableNote.kt b/base/src/main/java/com/maubis/scarlet/base/export/data/ExportableNote.kt index 08acf717..20d4406d 100644 --- a/base/src/main/java/com/maubis/scarlet/base/export/data/ExportableNote.kt +++ b/base/src/main/java/com/maubis/scarlet/base/export/data/ExportableNote.kt @@ -1,28 +1,28 @@ package com.maubis.scarlet.base.export.data import android.content.Context -import com.maubis.scarlet.base.database.room.note.Note -import com.maubis.scarlet.base.database.room.tag.Tag +import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb import com.maubis.scarlet.base.core.note.INoteContainer import com.maubis.scarlet.base.core.note.NoteBuilder import com.maubis.scarlet.base.core.note.generateUUID +import com.maubis.scarlet.base.database.room.note.Note +import com.maubis.scarlet.base.database.room.tag.Tag import com.maubis.scarlet.base.note.save import com.maubis.scarlet.base.note.tag.save -import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb import org.json.JSONArray import org.json.JSONObject import java.io.Serializable class ExportableNote( - var uuid: String, - var description: String, - var timestamp: Long, - var updateTimestamp: Long, - var color: Int, - var state: String, - var tags: String, - var meta: Map, - var folder: String + var uuid: String, + var description: String, + var timestamp: Long, + var updateTimestamp: Long, + var color: Int, + var state: String, + var tags: String, + var meta: Map, + var folder: String ) : Serializable, INoteContainer { override fun uuid(): String = uuid @@ -48,15 +48,15 @@ class ExportableNote( override fun folder(): String = folder constructor(note: Note) : this( - note.uuid, - note.description, - note.timestamp, - note.updateTimestamp, - note.color, - note.state, - note.tags ?: "", - emptyMap(), - note.folder + note.uuid, + note.description, + note.timestamp, + note.updateTimestamp, + note.color, + note.state, + note.tags ?: "", + emptyMap(), + note.folder ) fun saveIfNeeded(context: Context) { @@ -75,41 +75,41 @@ class ExportableNote( fun fromJSONObjectV2(json: JSONObject): ExportableNote { return ExportableNote( - generateUUID(), - json["description"] as String, - json["timestamp"] as Long, - json["timestamp"] as Long, - json["color"] as Int, - "", - "", - emptyMap(), - "") + generateUUID(), + json["description"] as String, + json["timestamp"] as Long, + json["timestamp"] as Long, + json["color"] as Int, + "", + "", + emptyMap(), + "") } fun fromJSONObjectV3(json: JSONObject): ExportableNote { return ExportableNote( - generateUUID(), - json["description"] as String, - json["timestamp"] as Long, - json["timestamp"] as Long, - json["color"] as Int, - json["state"] as String, - convertTagsJSONArrayToString(json["tags"] as JSONArray), - emptyMap(), - "") + generateUUID(), + json["description"] as String, + json["timestamp"] as Long, + json["timestamp"] as Long, + json["color"] as Int, + json["state"] as String, + convertTagsJSONArrayToString(json["tags"] as JSONArray), + emptyMap(), + "") } fun fromJSONObjectV4(json: JSONObject): ExportableNote { return ExportableNote( - json["uuid"] as String, - json["description"] as String, - json["timestamp"] as Long, - json["timestamp"] as Long, - json["color"] as Int, - json["state"] as String, - convertTagsJSONArrayToString(json["tags"] as JSONArray), - emptyMap(), - "") + json["uuid"] as String, + json["description"] as String, + json["timestamp"] as Long, + json["timestamp"] as Long, + json["color"] as Int, + json["state"] as String, + convertTagsJSONArrayToString(json["tags"] as JSONArray), + emptyMap(), + "") } private fun convertTagsJSONArrayToString(tags: JSONArray): String { diff --git a/base/src/main/java/com/maubis/scarlet/base/export/data/ExportableTag.kt b/base/src/main/java/com/maubis/scarlet/base/export/data/ExportableTag.kt deleted file mode 100644 index 6e0ad4fe..00000000 --- a/base/src/main/java/com/maubis/scarlet/base/export/data/ExportableTag.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.maubis.scarlet.base.export.data - -import com.maubis.scarlet.base.database.room.tag.Tag -import com.maubis.scarlet.base.core.note.generateUUID -import com.maubis.scarlet.base.core.tag.ITagContainer -import com.maubis.scarlet.base.core.tag.TagBuilder -import org.json.JSONObject -import java.io.Serializable - -class ExportableTag( - var uuid: String, - var title: String -) : Serializable, ITagContainer { - - override fun title(): String = title - - override fun uuid(): String = uuid - - constructor(tag: Tag) : this( - tag.uuid, - tag.title - ) - - companion object { - fun fromJSON(json: JSONObject): ExportableTag { - val version = if (json.has("version")) json.getInt("version") else 1 - return when (version) { - 1 -> fromJSONObjectV1(json) - else -> fromJSONObjectV1(json) - } - } - - fun fromJSONObjectV1(json: JSONObject): ExportableTag { - return ExportableTag( - generateUUID(), - json["title"] as String) - } - - fun getBestPossibleTagObject(json: JSONObject): Tag { - return TagBuilder().copy(fromJSON(json)) - } - } -} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/export/recycler/FileImportViewHolder.kt b/base/src/main/java/com/maubis/scarlet/base/export/recycler/FileImportViewHolder.kt index b0398925..1f85aeb1 100644 --- a/base/src/main/java/com/maubis/scarlet/base/export/recycler/FileImportViewHolder.kt +++ b/base/src/main/java/com/maubis/scarlet/base/export/recycler/FileImportViewHolder.kt @@ -7,13 +7,14 @@ import android.os.Environment import android.view.View import android.widget.TextView import com.github.bijoysingh.starter.recyclerview.RecyclerViewHolder -import com.github.bijoysingh.starter.util.DateFormatter import com.github.bijoysingh.starter.util.LocaleManager import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme import com.maubis.scarlet.base.export.activity.ImportNoteActivity import com.maubis.scarlet.base.support.recycler.RecyclerItem import com.maubis.scarlet.base.support.ui.ThemeColorType +import com.maubis.scarlet.base.support.utils.sDateFormat import java.io.File class FileImportViewHolder(context: Context, root: View) @@ -25,26 +26,32 @@ class FileImportViewHolder(context: Context, root: View) private val fileSize: TextView = findViewById(R.id.file_size) init { - val theme = CoreConfig.instance.themeController() - fileName.setTextColor(theme.get(ThemeColorType.SECONDARY_TEXT)) - filePath.setTextColor(theme.get(ThemeColorType.HINT_TEXT)) - fileDate.setTextColor(theme.get(ThemeColorType.TERTIARY_TEXT)) - fileSize.setTextColor(theme.get(ThemeColorType.TERTIARY_TEXT)) + fileName.setTextColor(sAppTheme.get(ThemeColorType.SECONDARY_TEXT)) + filePath.setTextColor(sAppTheme.get(ThemeColorType.HINT_TEXT)) + fileDate.setTextColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT)) + fileSize.setTextColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT)) } override fun populate(data: RecyclerItem, extra: Bundle?) { val item = data as FileRecyclerItem fileName.text = item.name + fileName.typeface = ApplicationBase.sAppTypeface.title() + filePath.text = getPath(item) + filePath.typeface = ApplicationBase.sAppTypeface.text() + fileDate.text = getSubtitleText(item.file) + fileDate.typeface = ApplicationBase.sAppTypeface.text() + fileSize.text = getMetaText(item.file) + fileSize.typeface = ApplicationBase.sAppTypeface.text() root.setOnClickListener { (context as ImportNoteActivity).select(item) } root.setBackgroundColor( - if (item.selected) CoreConfig.instance.themeController().get( - context, R.color.material_grey_100, R.color.dark_hint_text) else Color.TRANSPARENT) + if (item.selected) sAppTheme.get( + context, R.color.material_grey_100, R.color.dark_hint_text) else Color.TRANSPARENT) } private fun getPath(item: FileRecyclerItem): String { @@ -54,7 +61,7 @@ class FileImportViewHolder(context: Context, root: View) } private fun getSubtitleText(file: File): String { - return DateFormatter.getDate("dd MMM yy \u00B7 hh:mm a", file.lastModified()) + return sDateFormat.readableFullTime(file.lastModified()) } private fun getMetaText(file: File): String { diff --git a/base/src/main/java/com/maubis/scarlet/base/export/recycler/FileRecyclerItem.kt b/base/src/main/java/com/maubis/scarlet/base/export/recycler/FileRecyclerItem.kt index e095d898..c9670b44 100644 --- a/base/src/main/java/com/maubis/scarlet/base/export/recycler/FileRecyclerItem.kt +++ b/base/src/main/java/com/maubis/scarlet/base/export/recycler/FileRecyclerItem.kt @@ -5,10 +5,11 @@ import com.maubis.scarlet.base.export.support.AUTO_BACKUP_FILENAME import com.maubis.scarlet.base.support.recycler.RecyclerItem import java.io.File -class FileRecyclerItem(val name: String, - val date: Long, - val path: String, - val file: File) : RecyclerItem(), Comparable { +class FileRecyclerItem( + val name: String, + val date: Long, + val path: String, + val file: File) : RecyclerItem(), Comparable { var selected = false override val type = Type.FILE diff --git a/base/src/main/java/com/maubis/scarlet/base/export/remote/FolderRemoteDatabase.kt b/base/src/main/java/com/maubis/scarlet/base/export/remote/FolderRemoteDatabase.kt index b6f4c8fe..19534139 100644 --- a/base/src/main/java/com/maubis/scarlet/base/export/remote/FolderRemoteDatabase.kt +++ b/base/src/main/java/com/maubis/scarlet/base/export/remote/FolderRemoteDatabase.kt @@ -33,23 +33,23 @@ class FolderRemoteDatabase(val weakContext: WeakReference) : IRemoteDat rootFolder = File(Environment.getExternalStorageDirectory(), sFolderSyncPath) val notesFolder = File(rootFolder, "notes") notesRemoteFolder = RemoteFolder( - notesFolder, - ExportableNote::class.java, - { it -> onRemoteInsert(it) }, - { it -> onRemoteRemove(ExportableNote(it, "", 0L, 0L, 0, NoteState.DEFAULT.name, "", emptyMap(), "")) }, - onNotesInit) + notesFolder, + ExportableNote::class.java, + { it -> onRemoteInsert(it) }, + { it -> onRemoteRemove(ExportableNote(it, "", 0L, 0L, 0, NoteState.DEFAULT.name, "", emptyMap(), "")) }, + onNotesInit) tagsRemoteFolder = RemoteFolder( - File(rootFolder, "tags"), - ExportableTag::class.java, - { it -> onRemoteInsert(it) }, - { it -> onRemoteRemove(ExportableTag(it, "")) }, - onTagsInit) + File(rootFolder, "tags"), + ExportableTag::class.java, + { it -> onRemoteInsert(it) }, + { it -> onRemoteRemove(ExportableTag(it, "")) }, + onTagsInit) foldersRemoteFolder = RemoteFolder( - File(rootFolder, "folders"), - ExportableFolder::class.java, - { it -> onRemoteInsert(it) }, - { it -> onRemoteRemove(ExportableFolder(it, "", 0L, 0L, 0)) }, - onFoldersInit) + File(rootFolder, "folders"), + ExportableFolder::class.java, + { it -> onRemoteInsert(it) }, + { it -> onRemoteRemove(ExportableFolder(it, "", 0L, 0L, 0)) }, + onFoldersInit) val context = weakContext.get() if (context !== null) { diff --git a/base/src/main/java/com/maubis/scarlet/base/export/remote/RemoteFolder.kt b/base/src/main/java/com/maubis/scarlet/base/export/remote/RemoteFolder.kt index 29cd1ceb..ddda8cba 100644 --- a/base/src/main/java/com/maubis/scarlet/base/export/remote/RemoteFolder.kt +++ b/base/src/main/java/com/maubis/scarlet/base/export/remote/RemoteFolder.kt @@ -2,8 +2,9 @@ package com.maubis.scarlet.base.export.remote import com.github.bijoysingh.starter.util.FileManager import com.google.gson.Gson -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences import com.maubis.scarlet.base.export.support.KEY_EXTERNAL_FOLDER_SYNC_LAST_SCAN +import com.maubis.scarlet.base.support.utils.maybeThrow import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @@ -11,18 +12,19 @@ import java.io.File const val LAST_MODIFIED_ERROR_MARGIN = 7 * 1000 * 60 * 60 * 24L -class RemoteFolder(val folder: File, - val klass: Class, - val onRemoteInsert: (T) -> Unit, - val onRemoteDelete: (String) -> Unit, - val onInitComplete: () -> Unit) { +class RemoteFolder( + val folder: File, + val klass: Class, + val onRemoteInsert: (T) -> Unit, + val onRemoteDelete: (String) -> Unit, + val onInitComplete: () -> Unit) { val deletedFolder = File(folder, "deleted") val uuids = HashSet() val deletedUuids = HashSet() val lastScanKey = "${KEY_EXTERNAL_FOLDER_SYNC_LAST_SCAN}_${folder.name}" - var lastScan = CoreConfig.instance.store().get(lastScanKey, 0L) + var lastScan = sAppPreferences.get(lastScanKey, 0L) init { GlobalScope.launch(Dispatchers.IO) { @@ -37,6 +39,7 @@ class RemoteFolder(val folder: File, onRemoteInsert(item) } } catch (exception: Exception) { + maybeThrow(exception) } } } @@ -50,7 +53,7 @@ class RemoteFolder(val folder: File, } onInitComplete() - CoreConfig.instance.store().put(lastScanKey, System.currentTimeMillis()) + sAppPreferences.put(lastScanKey, System.currentTimeMillis()) } } @@ -64,6 +67,7 @@ class RemoteFolder(val folder: File, val file = file(uuid) FileManager.writeToFile(file, data) } catch (exception: Exception) { + maybeThrow(exception) } } diff --git a/base/src/main/java/com/maubis/scarlet/base/export/remote/RemoteImagesFolder.kt b/base/src/main/java/com/maubis/scarlet/base/export/remote/RemoteImagesFolder.kt index d1828ac4..62a2aa4d 100644 --- a/base/src/main/java/com/maubis/scarlet/base/export/remote/RemoteImagesFolder.kt +++ b/base/src/main/java/com/maubis/scarlet/base/export/remote/RemoteImagesFolder.kt @@ -5,6 +5,7 @@ import com.maubis.scarlet.base.core.format.FormatBuilder import com.maubis.scarlet.base.core.format.FormatType import com.maubis.scarlet.base.export.data.ExportableNote import com.maubis.scarlet.base.support.utils.ImageCache +import com.maubis.scarlet.base.support.utils.maybeThrow import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import java.io.File @@ -75,7 +76,6 @@ class RemoteImagesFolder(context: Context, val folder: File) { val imageFiles = noteFolder.listFiles() ?: emptyArray() imageFiles.filter { it.isFile } - val imagesKnown = internalCache.imagesForNote(note.uuid()).map { it.name } imageFiles.forEach { if (!imagesKnown.contains(it.name)) { @@ -107,6 +107,7 @@ class RemoteImagesFolder(context: Context, val folder: File) { inStream.close() outStream.close() } catch (exception: Exception) { + maybeThrow(exception) } } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/export/sheet/BackupSettingsOptionsBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/export/sheet/BackupSettingsOptionsBottomSheet.kt index ad39a96d..0896c071 100644 --- a/base/src/main/java/com/maubis/scarlet/base/export/sheet/BackupSettingsOptionsBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/export/sheet/BackupSettingsOptionsBottomSheet.kt @@ -5,16 +5,16 @@ import com.facebook.litho.ComponentContext import com.github.bijoysingh.starter.util.IntentUtils import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig import com.maubis.scarlet.base.export.activity.ImportNoteActivity import com.maubis.scarlet.base.export.support.PermissionUtils -import com.maubis.scarlet.base.main.sheets.EnterPincodeBottomSheet -import com.maubis.scarlet.base.settings.sheet.SecurityOptionsBottomSheet +import com.maubis.scarlet.base.security.controller.PinLockController.isPinCodeEnabled +import com.maubis.scarlet.base.security.sheets.openUnlockSheet +import com.maubis.scarlet.base.security.sheets.openVerifySheet import com.maubis.scarlet.base.support.sheets.LithoOptionBottomSheet import com.maubis.scarlet.base.support.sheets.LithoOptionsItem import com.maubis.scarlet.base.support.sheets.openSheet import com.maubis.scarlet.base.support.ui.ThemedActivity -import com.maubis.scarlet.base.support.utils.Flavor +import com.maubis.scarlet.base.support.utils.FlavorUtils class BackupSettingsOptionsBottomSheet : LithoOptionBottomSheet() { override fun title(): Int = R.string.home_option_backup_options @@ -22,7 +22,8 @@ class BackupSettingsOptionsBottomSheet : LithoOptionBottomSheet() { override fun getOptions(componentContext: ComponentContext, dialog: Dialog): List { val activity = context as MainActivity val options = ArrayList() - options.add(LithoOptionsItem( + options.add( + LithoOptionsItem( title = R.string.home_option_install_from_store, subtitle = R.string.home_option_install_from_store_subtitle, icon = R.drawable.ic_action_play, @@ -30,77 +31,71 @@ class BackupSettingsOptionsBottomSheet : LithoOptionBottomSheet() { IntentUtils.openAppPlayStore(context) dismiss() }, - visible = CoreConfig.instance.appFlavor() == Flavor.NONE - )) + visible = FlavorUtils.isOpenSource() + )) options.add(LithoOptionsItem( - title = R.string.home_option_export, - subtitle = R.string.home_option_export_subtitle, - icon = R.drawable.ic_export, - listener = { - val manager = PermissionUtils().getStoragePermissionManager(activity) - val hasAllPermissions = manager.hasAllPermissions() - when (hasAllPermissions) { - true -> { - openExportSheet(activity) - dismiss() - } - false -> { - openSheet(activity, PermissionBottomSheet()) - } + title = R.string.home_option_export, + subtitle = R.string.home_option_export_subtitle, + icon = R.drawable.ic_export, + listener = { + val manager = PermissionUtils().getStoragePermissionManager(activity) + val hasAllPermissions = manager.hasAllPermissions() + when (hasAllPermissions) { + true -> { + openExportSheet(activity) + dismiss() + } + false -> { + openSheet(activity, PermissionBottomSheet()) } } + } )) options.add(LithoOptionsItem( - title = R.string.home_option_import, - subtitle = R.string.home_option_import_subtitle, - icon = R.drawable.ic_import, - listener = { - val manager = PermissionUtils().getStoragePermissionManager(activity) - val hasAllPermissions = manager.hasAllPermissions() - when (hasAllPermissions) { - true -> { - IntentUtils.startActivity(activity, ImportNoteActivity::class.java) - dismiss() - } - false -> { - openSheet(activity, PermissionBottomSheet()) - } + title = R.string.home_option_import, + subtitle = R.string.home_option_import_subtitle, + icon = R.drawable.ic_import, + listener = { + val manager = PermissionUtils().getStoragePermissionManager(activity) + val hasAllPermissions = manager.hasAllPermissions() + when (hasAllPermissions) { + true -> { + IntentUtils.startActivity(activity, ImportNoteActivity::class.java) + dismiss() + } + false -> { + openSheet(activity, PermissionBottomSheet()) } } + } )) options.add(LithoOptionsItem( - title = R.string.import_export_layout_folder_sync, - subtitle = R.string.import_export_layout_folder_sync_details, - icon = R.drawable.icon_folder_sync, - listener = { - val manager = PermissionUtils().getStoragePermissionManager(activity) - val hasAllPermissions = manager.hasAllPermissions() - when (hasAllPermissions) { - true -> { - openSheet(activity, ExternalFolderSyncBottomSheet()) - } - false -> openSheet(activity, PermissionBottomSheet()) + title = R.string.import_export_layout_folder_sync, + subtitle = R.string.import_export_layout_folder_sync_details, + icon = R.drawable.icon_folder_sync, + listener = { + val manager = PermissionUtils().getStoragePermissionManager(activity) + val hasAllPermissions = manager.hasAllPermissions() + when (hasAllPermissions) { + true -> { + openSheet(activity, ExternalFolderSyncBottomSheet()) } + false -> openSheet(activity, PermissionBottomSheet()) } + } )) return options } private fun openExportSheet(activity: MainActivity) { - if (!SecurityOptionsBottomSheet.hasPinCodeEnabled()) { + if (!isPinCodeEnabled()) { openSheet(activity, ExportNotesBottomSheet()) return } - EnterPincodeBottomSheet.openUnlockSheet( - activity as ThemedActivity, - object : EnterPincodeBottomSheet.PincodeSuccessListener { - override fun onFailure() { - openExportSheet(activity) - } - override fun onSuccess() { - openSheet(activity, ExportNotesBottomSheet()) - } - }) + openUnlockSheet( + activity = activity as ThemedActivity, + onUnlockSuccess = { openSheet(activity, ExportNotesBottomSheet()) }, + onUnlockFailure = { openExportSheet(activity) }) } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/export/sheet/ExportNotesBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/export/sheet/ExportNotesBottomSheet.kt index 45b69abb..d5d2ce06 100644 --- a/base/src/main/java/com/maubis/scarlet/base/export/sheet/ExportNotesBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/export/sheet/ExportNotesBottomSheet.kt @@ -3,7 +3,7 @@ package com.maubis.scarlet.base.export.sheet import android.app.Dialog import android.content.Intent import android.graphics.Typeface -import android.support.v4.content.FileProvider +import androidx.core.content.FileProvider import com.facebook.litho.Column import com.facebook.litho.Component import com.facebook.litho.ComponentContext @@ -12,9 +12,19 @@ import com.facebook.yoga.YogaEdge import com.github.bijoysingh.starter.util.ToastHelper import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig -import com.maubis.scarlet.base.export.support.* -import com.maubis.scarlet.base.support.sheets.* +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppFlavor +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.export.support.GenericFileProvider +import com.maubis.scarlet.base.export.support.NoteExporter +import com.maubis.scarlet.base.export.support.PermissionUtils +import com.maubis.scarlet.base.export.support.sAutoBackupMode +import com.maubis.scarlet.base.export.support.sBackupLockedNotes +import com.maubis.scarlet.base.export.support.sBackupMarkdown +import com.maubis.scarlet.base.support.sheets.LithoBottomSheet +import com.maubis.scarlet.base.support.sheets.LithoOptionsItem +import com.maubis.scarlet.base.support.sheets.OptionItemLayout +import com.maubis.scarlet.base.support.sheets.getLithoBottomSheetTitle +import com.maubis.scarlet.base.support.sheets.openSheet import com.maubis.scarlet.base.support.specs.BottomSheetBar import com.maubis.scarlet.base.support.specs.separatorSpec import com.maubis.scarlet.base.support.ui.ThemeColorType @@ -25,7 +35,7 @@ import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch val NOTES_EXPORT_FOLDER - get() = when (CoreConfig.instance.appFlavor()) { + get() = when (sAppFlavor) { Flavor.NONE -> "MaterialNotes" Flavor.LITE -> "Scarlet" Flavor.PRO -> "ScarletPro" @@ -41,90 +51,96 @@ class ExportNotesBottomSheet : LithoBottomSheet() { val filenameRender = "${file?.parentFile?.name}/${file?.name}" val component = Column.create(componentContext) - .widthPercent(100f) - .paddingDip(YogaEdge.VERTICAL, 8f) - .child(getLithoBottomSheetTitle(componentContext) - .textRes(R.string.import_export_layout_exporting) - .paddingDip(YogaEdge.HORIZONTAL, 20f) - .marginDip(YogaEdge.HORIZONTAL, 0f)) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_large) - .text(filenameRender) - .typeface(Typeface.MONOSPACE) - .paddingDip(YogaEdge.HORIZONTAL, 20f) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.TERTIARY_TEXT))) - .child(separatorSpec(componentContext).alpha(0.5f)) + .widthPercent(100f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .child( + getLithoBottomSheetTitle(componentContext) + .textRes(R.string.import_export_layout_exporting) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .marginDip(YogaEdge.HORIZONTAL, 0f)) + .child( + Text.create(componentContext) + .textSizeRes(R.dimen.font_size_large) + .text(filenameRender) + .typeface(Typeface.MONOSPACE) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .textColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT))) + .child(separatorSpec(componentContext).alpha(0.5f)) getOptions(componentContext).forEach { if (it.visible) { component.child(OptionItemLayout.create(componentContext) - .option(it) - .onClick { - it.listener() - reset(componentContext.androidContext, dialog) - }) + .option(it) + .onClick { + it.listener() + reset(componentContext.androidContext, dialog) + }) } } component.child(BottomSheetBar.create(componentContext) - .primaryActionRes(R.string.import_export_layout_exporting_done) - .onPrimaryClick { - GlobalScope.launch { - val notes = NoteExporter().getExportContent() - val success = NoteExporter().saveToManualExportFile(notes) - GlobalScope.launch(Dispatchers.Main) { - ToastHelper.show(activity, if (success) R.string.import_export_layout_exported else R.string.import_export_layout_export_failed) - dismiss() - } - } - } - .secondaryActionRes(R.string.import_export_layout_exporting_share) - .onSecondaryClick { - GlobalScope.launch { - val notes = NoteExporter().getExportContent() - NoteExporter().saveToManualExportFile(notes) + .primaryActionRes(R.string.import_export_layout_exporting_done) + .onPrimaryClick { + GlobalScope.launch { + val notes = NoteExporter().getExportContent() + val success = NoteExporter().saveToManualExportFile(notes) + GlobalScope.launch(Dispatchers.Main) { + ToastHelper.show( + activity, if (success) R.string.import_export_layout_exported else R.string.import_export_layout_export_failed) + dismiss() + } + } + } + .secondaryActionRes(R.string.import_export_layout_exporting_share) + .onSecondaryClick { + GlobalScope.launch { + val notes = NoteExporter().getExportContent() + NoteExporter().saveToManualExportFile(notes) - if (file == null || !file.exists()) { - return@launch - } + if (file == null || !file.exists()) { + return@launch + } - val uri = FileProvider.getUriForFile(activity, GenericFileProvider.PROVIDER, file) + val uri = FileProvider.getUriForFile(activity, GenericFileProvider.PROVIDER, file) - val intent = Intent(Intent.ACTION_SEND) - intent.type = "text/plain" - intent.putExtra(Intent.EXTRA_STREAM, uri) - startActivity(Intent.createChooser(intent, getString(R.string.share_using))) + val intent = Intent(Intent.ACTION_SEND) + intent.type = "text/plain" + intent.putExtra(Intent.EXTRA_STREAM, uri) + startActivity(Intent.createChooser(intent, getString(R.string.share_using))) - GlobalScope.launch(Dispatchers.Main) { - dismiss() - } - } - } - .paddingDip(YogaEdge.HORIZONTAL, 20f) - .paddingDip(YogaEdge.VERTICAL, 8f)) + GlobalScope.launch(Dispatchers.Main) { + dismiss() + } + } + } + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .paddingDip(YogaEdge.VERTICAL, 8f)) return component.build() } fun getOptions(componentContext: ComponentContext): List { val activity = componentContext.androidContext as MainActivity val options = ArrayList() - options.add(LithoOptionsItem( + options.add( + LithoOptionsItem( title = R.string.home_option_export_markdown, subtitle = R.string.home_option_export_markdown_subtitle, icon = R.drawable.ic_markdown_logo, listener = { sBackupMarkdown = !sBackupMarkdown }, isSelectable = true, selected = sBackupMarkdown - )) - options.add(LithoOptionsItem( + )) + options.add( + LithoOptionsItem( title = R.string.import_export_locked, subtitle = R.string.import_export_locked_details, icon = R.drawable.ic_action_lock, listener = { sBackupLockedNotes = !sBackupLockedNotes }, isSelectable = true, selected = sBackupLockedNotes - )) - options.add(LithoOptionsItem( + )) + options.add( + LithoOptionsItem( title = R.string.home_option_auto_export, subtitle = R.string.home_option_auto_export_subtitle, icon = R.drawable.ic_time, @@ -143,7 +159,7 @@ class ExportNotesBottomSheet : LithoBottomSheet() { }, isSelectable = true, selected = sAutoBackupMode - )) + )) return options } diff --git a/base/src/main/java/com/maubis/scarlet/base/export/sheet/ExternalFolderSyncBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/export/sheet/ExternalFolderSyncBottomSheet.kt index 0bb3651e..30d364c2 100644 --- a/base/src/main/java/com/maubis/scarlet/base/export/sheet/ExternalFolderSyncBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/export/sheet/ExternalFolderSyncBottomSheet.kt @@ -7,10 +7,10 @@ import com.facebook.litho.Component import com.facebook.litho.ComponentContext import com.facebook.litho.widget.Text import com.facebook.yoga.YogaEdge -import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig -import com.maubis.scarlet.base.config.CoreConfig.Companion.FONT_MONSERRAT +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface +import com.maubis.scarlet.base.export.support.ExternalFolderSync import com.maubis.scarlet.base.export.support.sExternalFolderSync import com.maubis.scarlet.base.export.support.sFolderSyncBackupLocked import com.maubis.scarlet.base.export.support.sFolderSyncPath @@ -21,76 +21,79 @@ import com.maubis.scarlet.base.support.sheets.getLithoBottomSheetTitle import com.maubis.scarlet.base.support.specs.BottomSheetBar import com.maubis.scarlet.base.support.specs.separatorSpec import com.maubis.scarlet.base.support.ui.ThemeColorType -import com.maubis.scarlet.base.support.ui.ThemedActivity - class ExternalFolderSyncBottomSheet : LithoBottomSheet() { override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { - val activity = componentContext.androidContext as ThemedActivity - val component = Column.create(componentContext) - .widthPercent(100f) - .paddingDip(YogaEdge.VERTICAL, 8f) - .child(getLithoBottomSheetTitle(componentContext) - .textRes(R.string.import_export_layout_folder_sync_title) - .paddingDip(YogaEdge.HORIZONTAL, 20f) - .marginDip(YogaEdge.HORIZONTAL, 0f)) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_large) - .textRes(R.string.import_export_layout_folder_sync_description) - .paddingDip(YogaEdge.HORIZONTAL, 20f) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.TERTIARY_TEXT))) - .child(separatorSpec(componentContext).alpha(0.5f)) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_xlarge) - .typeface(FONT_MONSERRAT) - .textRes(R.string.import_export_layout_folder_sync_folder) - .paddingDip(YogaEdge.HORIZONTAL, 20f) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.SECTION_HEADER))) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_large) - .text(sFolderSyncPath) - .typeface(Typeface.MONOSPACE) - .paddingDip(YogaEdge.HORIZONTAL, 20f) - .paddingDip(YogaEdge.VERTICAL, 8f) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.TERTIARY_TEXT))) - .child(separatorSpec(componentContext).alpha(0.5f)) + .widthPercent(100f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .child( + getLithoBottomSheetTitle(componentContext) + .textRes(R.string.import_export_layout_folder_sync_title) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .marginDip(YogaEdge.HORIZONTAL, 0f)) + .child( + Text.create(componentContext) + .textSizeRes(R.dimen.font_size_large) + .typeface(sAppTypeface.text()) + .textRes(R.string.import_export_layout_folder_sync_description) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .textColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT))) + .child(separatorSpec(componentContext).alpha(0.5f)) + .child( + Text.create(componentContext) + .textSizeRes(R.dimen.font_size_xlarge) + .typeface(sAppTypeface.title()) + .textRes(R.string.import_export_layout_folder_sync_folder) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .textColor(sAppTheme.get(ThemeColorType.SECTION_HEADER))) + .child( + Text.create(componentContext) + .textSizeRes(R.dimen.font_size_large) + .text(sFolderSyncPath) + .typeface(Typeface.MONOSPACE) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .textColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT))) + .child(separatorSpec(componentContext).alpha(0.5f)) - getOptions(componentContext).forEach { + getOptions().forEach { if (it.visible) { component.child(OptionItemLayout.create(componentContext) - .option(it) - .onClick { - it.listener() - reset(componentContext.androidContext, dialog) - }) + .option(it) + .onClick { + it.listener() + reset(componentContext.androidContext, dialog) + }) } } component.child(BottomSheetBar.create(componentContext) - .primaryActionRes(if (sExternalFolderSync) R.string.import_export_layout_folder_sync_disable else R.string.import_export_layout_folder_sync_enable) - .isActionNegative(sExternalFolderSync) - .onPrimaryClick { - sExternalFolderSync = !sExternalFolderSync - reset(componentContext.androidContext, dialog) - } - .paddingDip(YogaEdge.HORIZONTAL, 20f) - .paddingDip(YogaEdge.VERTICAL, 8f)) + .primaryActionRes( + if (sExternalFolderSync) R.string.import_export_layout_folder_sync_disable else R.string.import_export_layout_folder_sync_enable) + .isActionNegative(sExternalFolderSync) + .onPrimaryClick { + sExternalFolderSync = !sExternalFolderSync + ExternalFolderSync.enable(componentContext.androidContext, sExternalFolderSync) + reset(componentContext.androidContext, dialog) + } + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .paddingDip(YogaEdge.VERTICAL, 8f)) return component.build() } - fun getOptions(componentContext: ComponentContext): List { - val activity = componentContext.androidContext as MainActivity + fun getOptions(): List { val options = ArrayList() - options.add(LithoOptionsItem( + options.add( + LithoOptionsItem( title = R.string.import_export_locked, subtitle = R.string.import_export_locked_details, icon = R.drawable.ic_action_lock, listener = { sFolderSyncBackupLocked = !sFolderSyncBackupLocked }, isSelectable = true, selected = sFolderSyncBackupLocked - )) + )) return options } diff --git a/base/src/main/java/com/maubis/scarlet/base/export/sheet/PermissionBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/export/sheet/PermissionBottomSheet.kt index 23da9de3..f3c09393 100644 --- a/base/src/main/java/com/maubis/scarlet/base/export/sheet/PermissionBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/export/sheet/PermissionBottomSheet.kt @@ -7,7 +7,8 @@ import com.facebook.litho.ComponentContext import com.facebook.litho.widget.Text import com.facebook.yoga.YogaEdge import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface import com.maubis.scarlet.base.export.support.PermissionUtils import com.maubis.scarlet.base.support.sheets.LithoBottomSheet import com.maubis.scarlet.base.support.sheets.getLithoBottomSheetTitle @@ -19,27 +20,30 @@ class PermissionBottomSheet : LithoBottomSheet() { override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { val activity = context as ThemedActivity val component = Column.create(componentContext) - .widthPercent(100f) - .paddingDip(YogaEdge.VERTICAL, 8f) - .paddingDip(YogaEdge.HORIZONTAL, 20f) - .child(getLithoBottomSheetTitle(componentContext) - .textRes(R.string.permission_layout_give_permission) - .marginDip(YogaEdge.HORIZONTAL, 0f)) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_large) - .marginDip(YogaEdge.BOTTOM, 16f) - .textRes(R.string.permission_layout_give_permission_details) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.TERTIARY_TEXT))) - .child(BottomSheetBar.create(componentContext) - .primaryActionRes(R.string.permission_layout_give_permission_ok) - .onPrimaryClick { - val manager = PermissionUtils().getStoragePermissionManager(activity) - manager.requestPermissions() - dismiss() - }.secondaryActionRes(R.string.delete_sheet_delete_trash_no) - .onSecondaryClick { - dismiss() - }.paddingDip(YogaEdge.VERTICAL, 8f)) + .widthPercent(100f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .child( + getLithoBottomSheetTitle(componentContext) + .textRes(R.string.permission_layout_give_permission) + .marginDip(YogaEdge.HORIZONTAL, 0f)) + .child( + Text.create(componentContext) + .typeface(sAppTypeface.text()) + .textSizeRes(R.dimen.font_size_large) + .marginDip(YogaEdge.BOTTOM, 16f) + .textRes(R.string.permission_layout_give_permission_details) + .textColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT))) + .child(BottomSheetBar.create(componentContext) + .primaryActionRes(R.string.permission_layout_give_permission_ok) + .onPrimaryClick { + val manager = PermissionUtils().getStoragePermissionManager(activity) + manager.requestPermissions() + dismiss() + }.secondaryActionRes(R.string.delete_sheet_delete_trash_no) + .onSecondaryClick { + dismiss() + }.paddingDip(YogaEdge.VERTICAL, 8f)) return component.build() } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/export/support/ExternalFolderSync.kt b/base/src/main/java/com/maubis/scarlet/base/export/support/ExternalFolderSync.kt index d7acb3e5..f31dc604 100644 --- a/base/src/main/java/com/maubis/scarlet/base/export/support/ExternalFolderSync.kt +++ b/base/src/main/java/com/maubis/scarlet/base/export/support/ExternalFolderSync.kt @@ -3,19 +3,22 @@ package com.maubis.scarlet.base.export.support import android.Manifest import android.content.Context import android.content.pm.PackageManager -import android.os.Build -import android.support.v4.content.ContextCompat +import androidx.core.content.ContextCompat import com.github.bijoysingh.starter.util.ToastHelper import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase +import com.maubis.scarlet.base.config.ApplicationBase.Companion.folderSync +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences import com.maubis.scarlet.base.export.data.ExportableFolder import com.maubis.scarlet.base.export.data.ExportableNote import com.maubis.scarlet.base.export.data.ExportableTag +import com.maubis.scarlet.base.export.remote.FolderRemoteDatabase import com.maubis.scarlet.base.export.sheet.NOTES_EXPORT_FOLDER +import com.maubis.scarlet.base.support.utils.OsVersionUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch - +import java.lang.ref.WeakReference const val KEY_EXTERNAL_FOLDER_SYNC_ENABLED = "external_folder_sync_enabled" const val KEY_EXTERNAL_FOLDER_SYNC_LAST_SCAN = "external_folder_sync_last_sync" @@ -23,21 +26,22 @@ const val KEY_EXTERNAL_FOLDER_SYNC_BACKUP_LOCKED = "external_folder_sync_backup_ const val KEY_EXTERNAL_FOLDER_SYNC_PATH = "external_folder_sync_path" var sExternalFolderSync: Boolean - get() = CoreConfig.instance.store().get(KEY_EXTERNAL_FOLDER_SYNC_ENABLED, false) - set(value) = CoreConfig.instance.store().put(KEY_EXTERNAL_FOLDER_SYNC_ENABLED, value) + get() = sAppPreferences.get(KEY_EXTERNAL_FOLDER_SYNC_ENABLED, false) + set(value) = sAppPreferences.put(KEY_EXTERNAL_FOLDER_SYNC_ENABLED, value) var sFolderSyncPath: String - get() = CoreConfig.instance.store().get(KEY_EXTERNAL_FOLDER_SYNC_PATH, "$NOTES_EXPORT_FOLDER/Sync/") - set(value) = CoreConfig.instance.store().put(KEY_EXTERNAL_FOLDER_SYNC_PATH, value) + get() = sAppPreferences.get(KEY_EXTERNAL_FOLDER_SYNC_PATH, "$NOTES_EXPORT_FOLDER/Sync/") + set(value) = sAppPreferences.put(KEY_EXTERNAL_FOLDER_SYNC_PATH, value) var sFolderSyncBackupLocked: Boolean - get() = CoreConfig.instance.store().get(KEY_EXTERNAL_FOLDER_SYNC_BACKUP_LOCKED, true) - set(value) = CoreConfig.instance.store().put(KEY_EXTERNAL_FOLDER_SYNC_BACKUP_LOCKED, value) + get() = sAppPreferences.get(KEY_EXTERNAL_FOLDER_SYNC_BACKUP_LOCKED, true) + set(value) = sAppPreferences.put(KEY_EXTERNAL_FOLDER_SYNC_BACKUP_LOCKED, value) object ExternalFolderSync { fun hasPermission(context: Context): Boolean { - return !(Build.VERSION.SDK_INT >= 23 && ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) + return !(OsVersionUtils.requiresPermissions() + && ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) } fun enable(context: Context, enabled: Boolean) { @@ -45,7 +49,7 @@ object ExternalFolderSync { if (!hasPermission(context)) { GlobalScope.launch(Dispatchers.Main) { ToastHelper.show(context, R.string.permission_layout_give_permission_details) - CoreConfig.instance.externalFolderSync().reset() + folderSync?.reset() } return } @@ -53,27 +57,27 @@ object ExternalFolderSync { loadFirstTime() } else { sExternalFolderSync = false - CoreConfig.instance.externalFolderSync().reset() + folderSync?.reset() } } fun loadFirstTime() { - CoreConfig.instance.externalFolderSync().init( - { - CoreConfig.instance.notesDatabase().getAll().forEach { - CoreConfig.instance.externalFolderSync().insert(ExportableNote(it)) - } - }, - { - CoreConfig.instance.tagsDatabase().getAll().forEach { - CoreConfig.instance.externalFolderSync().insert(ExportableTag(it)) - } - }, - { - CoreConfig.instance.foldersDatabase().getAll().forEach { - CoreConfig.instance.externalFolderSync().insert(ExportableFolder(it)) - } - }) + folderSync?.init( + { + ApplicationBase.instance.notesDatabase().getAll().forEach { + folderSync?.insert(ExportableNote(it)) + } + }, + { + ApplicationBase.instance.tagsDatabase().getAll().forEach { + folderSync?.insert(ExportableTag(it)) + } + }, + { + ApplicationBase.instance.foldersDatabase().getAll().forEach { + folderSync?.insert(ExportableFolder(it)) + } + }) } fun setup(context: Context) { @@ -85,6 +89,7 @@ object ExternalFolderSync { sExternalFolderSync = false return } - CoreConfig.instance.externalFolderSync().init() + folderSync = FolderRemoteDatabase(WeakReference(context)) + folderSync?.init() } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/export/support/GenericFileProvider.kt b/base/src/main/java/com/maubis/scarlet/base/export/support/GenericFileProvider.kt index 428e369e..60e813d9 100644 --- a/base/src/main/java/com/maubis/scarlet/base/export/support/GenericFileProvider.kt +++ b/base/src/main/java/com/maubis/scarlet/base/export/support/GenericFileProvider.kt @@ -1,6 +1,6 @@ package com.maubis.scarlet.base.export.support -import android.support.v4.content.FileProvider +import androidx.core.content.FileProvider class GenericFileProvider : FileProvider() { companion object { diff --git a/base/src/main/java/com/maubis/scarlet/base/export/support/NoteExporter.kt b/base/src/main/java/com/maubis/scarlet/base/export/support/NoteExporter.kt index c548cbaa..8c9c8e83 100644 --- a/base/src/main/java/com/maubis/scarlet/base/export/support/NoteExporter.kt +++ b/base/src/main/java/com/maubis/scarlet/base/export/support/NoteExporter.kt @@ -2,10 +2,9 @@ package com.maubis.scarlet.base.export.support import android.os.AsyncTask import android.os.Environment -import com.github.bijoysingh.starter.util.DateFormatter import com.github.bijoysingh.starter.util.FileManager import com.google.gson.Gson -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences import com.maubis.scarlet.base.config.CoreConfig.Companion.foldersDb import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb import com.maubis.scarlet.base.config.CoreConfig.Companion.tagsDb @@ -13,11 +12,11 @@ import com.maubis.scarlet.base.export.data.ExportableFileFormat import com.maubis.scarlet.base.export.data.ExportableFolder import com.maubis.scarlet.base.export.data.ExportableNote import com.maubis.scarlet.base.export.data.ExportableTag +import com.maubis.scarlet.base.export.data.toExportedMarkdown import com.maubis.scarlet.base.export.sheet.NOTES_EXPORT_FILENAME import com.maubis.scarlet.base.export.sheet.NOTES_EXPORT_FOLDER -import com.maubis.scarlet.base.note.getFullText +import com.maubis.scarlet.base.support.utils.sDateFormat import java.io.File -import java.util.* const val KEY_NOTE_VERSION = "KEY_NOTE_VERSION" const val KEY_BACKUP_LOCATION = "KEY_BACKUP_LOCATION" @@ -31,18 +30,18 @@ const val AUTO_BACKUP_INTERVAL_MS = 1000 * 60 * 60 * 6 // 6 hours update const val STORE_KEY_BACKUP_MARKDOWN = "KEY_BACKUP_MARKDOWN" var sBackupMarkdown: Boolean - get() = CoreConfig.instance.store().get(STORE_KEY_BACKUP_MARKDOWN, false) - set(value) = CoreConfig.instance.store().put(STORE_KEY_BACKUP_MARKDOWN, value) + get() = sAppPreferences.get(STORE_KEY_BACKUP_MARKDOWN, false) + set(value) = sAppPreferences.put(STORE_KEY_BACKUP_MARKDOWN, value) const val STORE_KEY_BACKUP_LOCKED = "KEY_BACKUP_LOCKED" var sBackupLockedNotes: Boolean - get() = CoreConfig.instance.store().get(STORE_KEY_BACKUP_LOCKED, true) - set(value) = CoreConfig.instance.store().put(STORE_KEY_BACKUP_LOCKED, value) + get() = sAppPreferences.get(STORE_KEY_BACKUP_LOCKED, true) + set(value) = sAppPreferences.put(STORE_KEY_BACKUP_LOCKED, value) const val STORE_KEY_AUTO_BACKUP_MODE = "KEY_AUTO_BACKUP_MODE" var sAutoBackupMode: Boolean - get() = CoreConfig.instance.store().get(STORE_KEY_AUTO_BACKUP_MODE, false) - set(value) = CoreConfig.instance.store().put(STORE_KEY_AUTO_BACKUP_MODE, value) + get() = sAppPreferences.get(STORE_KEY_AUTO_BACKUP_MODE, false) + set(value) = sAppPreferences.put(STORE_KEY_AUTO_BACKUP_MODE, value) class NoteExporter() { @@ -52,9 +51,9 @@ class NoteExporter() { } val notes = notesDb - .getAll() - .filter { sBackupLockedNotes || !it.locked } - .map { ExportableNote(it) } + .getAll() + .filter { sBackupLockedNotes || !it.locked } + .map { ExportableNote(it) } val tags = tagsDb.getAll().map { ExportableTag(it) } val folders = foldersDb.getAll().map { ExportableFolder(it) } val fileContent = ExportableFileFormat(EXPORT_VERSION, notes, tags, folders) @@ -64,11 +63,11 @@ class NoteExporter() { private fun getMarkdownExportContent(): String { var totalText = "$EXPORT_NOTE_SEPARATOR\n\n" notesDb.getAll() - .map { it.getFullText() } - .forEach { - totalText += it - totalText += "\n\n$EXPORT_NOTE_SEPARATOR\n\n" - } + .map { it.toExportedMarkdown() } + .forEach { + totalText += it + totalText += "\n\n$EXPORT_NOTE_SEPARATOR\n\n" + } return totalText } @@ -77,23 +76,26 @@ class NoteExporter() { if (!sAutoBackupMode) { return@execute } - val lastBackup = CoreConfig.instance.store().get(KEY_AUTO_BACKUP_LAST_TIMESTAMP, 0L) + val lastBackup = sAppPreferences.get(KEY_AUTO_BACKUP_LAST_TIMESTAMP, 0L) val lastTimestamp = notesDb.getLastTimestamp() if (lastBackup + AUTO_BACKUP_INTERVAL_MS >= lastTimestamp) { return@execute } - val exportFile = getOrCreateFileForExport(AUTO_BACKUP_FILENAME + " " + DateFormatter.getDate("dd_MMM_yyyy", Calendar.getInstance())) + val exportFile = getOrCreateFileForExport( + "$AUTO_BACKUP_FILENAME ${sDateFormat.getDateForBackup()}") if (exportFile === null) { return@execute } saveToFile(exportFile, getExportContent()) - CoreConfig.instance.store().put(KEY_AUTO_BACKUP_LAST_TIMESTAMP, System.currentTimeMillis()) + sAppPreferences + .put(KEY_AUTO_BACKUP_LAST_TIMESTAMP, System.currentTimeMillis()) } } fun getOrCreateManualExportFile(): File? { - return getOrCreateFileForExport(NOTES_EXPORT_FILENAME + " " + DateFormatter.getDate("dd_MMM_yyyy HH_mm", Calendar.getInstance())) + return getOrCreateFileForExport( + "$NOTES_EXPORT_FILENAME ${sDateFormat.getTimestampForBackup()}") } fun getOrCreateFileForExport(filename: String): File? { diff --git a/base/src/main/java/com/maubis/scarlet/base/export/support/NoteImporter.kt b/base/src/main/java/com/maubis/scarlet/base/export/support/NoteImporter.kt index f9823b68..f897e83f 100644 --- a/base/src/main/java/com/maubis/scarlet/base/export/support/NoteImporter.kt +++ b/base/src/main/java/com/maubis/scarlet/base/export/support/NoteImporter.kt @@ -13,6 +13,8 @@ import com.maubis.scarlet.base.export.data.ExportableNote import com.maubis.scarlet.base.note.folder.saveIfUnique import com.maubis.scarlet.base.note.save import com.maubis.scarlet.base.note.tag.saveIfUnique +import com.maubis.scarlet.base.support.utils.maybeThrow +import com.maubis.scarlet.base.support.utils.throwOrReturn import org.json.JSONArray import java.io.BufferedReader import java.io.File @@ -58,19 +60,20 @@ class NoteImporter() { } } catch (exception: Exception) { importNoteFallback(content, context) + maybeThrow(exception) } } private fun importNoteFallback(content: String, context: Context) { content - .split(EXPORT_NOTE_SEPARATOR) - .map { - it.trim() - } - .filter { it.isNotBlank() } - .forEach { - NoteBuilder().gen("", it).save(context) - } + .split(EXPORT_NOTE_SEPARATOR) + .map { + it.trim() + } + .filter { it.isNotBlank() } + .forEach { + NoteBuilder().gen("", it).save(context) + } } fun getImportableFiles(): List { @@ -100,13 +103,12 @@ class NoteImporter() { files.addAll(childFile) } } catch (exception: Exception) { - // Failed + maybeThrow(exception) } return files } - fun readFileInputStream(inputStreamReader: InputStreamReader): String { lateinit var reader: BufferedReader try { @@ -120,7 +122,7 @@ class NoteImporter() { return fileContents.toString() } catch (exception: IOException) { reader.close() - return "" + return throwOrReturn(exception, "") } } @@ -131,7 +133,7 @@ class NoteImporter() { private fun isValidFile(filePath: String, validExtension: String): Boolean { return filePath.endsWith("." + validExtension) - || filePath.endsWith("." + validExtension.toUpperCase()) + || filePath.endsWith("." + validExtension.toUpperCase()) } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/export/support/PermissionUtils.kt b/base/src/main/java/com/maubis/scarlet/base/export/support/PermissionUtils.kt index 214f21f5..b2272db7 100644 --- a/base/src/main/java/com/maubis/scarlet/base/export/support/PermissionUtils.kt +++ b/base/src/main/java/com/maubis/scarlet/base/export/support/PermissionUtils.kt @@ -1,13 +1,14 @@ package com.maubis.scarlet.base.export.support import android.Manifest -import android.support.v7.app.AppCompatActivity +import androidx.appcompat.app.AppCompatActivity import com.github.bijoysingh.starter.util.PermissionManager class PermissionUtils() { fun getStoragePermissionManager(activity: AppCompatActivity): PermissionManager { val manager = PermissionManager(activity) - manager.setPermissions(arrayOf( + manager.setPermissions( + arrayOf( Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)) return manager diff --git a/base/src/main/java/com/maubis/scarlet/base/main/HomeNavigationState.kt b/base/src/main/java/com/maubis/scarlet/base/main/HomeNavigationMode.kt similarity index 80% rename from base/src/main/java/com/maubis/scarlet/base/main/HomeNavigationState.kt rename to base/src/main/java/com/maubis/scarlet/base/main/HomeNavigationMode.kt index 032301e7..61b3e972 100644 --- a/base/src/main/java/com/maubis/scarlet/base/main/HomeNavigationState.kt +++ b/base/src/main/java/com/maubis/scarlet/base/main/HomeNavigationMode.kt @@ -3,7 +3,7 @@ package com.maubis.scarlet.base.main /** * Superset of the Note State class */ -enum class HomeNavigationState { +enum class HomeNavigationMode { DEFAULT, TRASH, FAVOURITE, diff --git a/base/src/main/java/com/maubis/scarlet/base/main/SearchState.kt b/base/src/main/java/com/maubis/scarlet/base/main/SearchState.kt new file mode 100644 index 00000000..b32e57d9 --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/main/SearchState.kt @@ -0,0 +1,113 @@ +package com.maubis.scarlet.base.main + +import com.maubis.scarlet.base.config.ApplicationBase +import com.maubis.scarlet.base.config.CoreConfig.Companion.foldersDb +import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb +import com.maubis.scarlet.base.core.note.NoteState +import com.maubis.scarlet.base.core.note.sort +import com.maubis.scarlet.base.database.room.folder.Folder +import com.maubis.scarlet.base.database.room.note.Note +import com.maubis.scarlet.base.database.room.tag.Tag +import com.maubis.scarlet.base.note.getFullText +import com.maubis.scarlet.base.note.isNoteLockedButAppUnlocked +import com.maubis.scarlet.base.settings.sheet.SortingOptionsBottomSheet + +class SearchState( + var text: String = "", + var mode: HomeNavigationMode = HomeNavigationMode.DEFAULT, + var currentFolder: Folder? = null, + var colors: MutableList = emptyList().toMutableList(), + var tags: MutableList = emptyList().toMutableList()) { + + fun hasFilter(): Boolean { + return currentFolder != null + || tags.isNotEmpty() + || colors.isNotEmpty() + || text.isNotBlank() + || mode !== HomeNavigationMode.DEFAULT + } + + fun clear(): SearchState { + mode = HomeNavigationMode.DEFAULT + text = "" + colors.clear() + tags.clear() + currentFolder = null + return this + } + + fun clearSearchBar(): SearchState { + text = "" + colors.clear() + tags.clear() + return this + } + + fun copy(): SearchState { + return SearchState( + text, + mode, + currentFolder, + colors.filter { true }.toMutableList(), + tags.filter { true }.toMutableList()) + } +} + +fun unifiedSearchSynchronous(state: SearchState): List { + val sorting = SortingOptionsBottomSheet.getSortingState() + val notes = unifiedSearchWithoutFolder(state) + .filter { + val currentFolder = state.currentFolder + if (currentFolder == null) + it.folder.isBlank() + else + currentFolder.uuid == it.folder + } + return sort(notes, sorting) +} + +fun filterFolder(notes: List, folder: Folder): List { + val sorting = SortingOptionsBottomSheet.getSortingState() + val filteredNotes = notes.filter { it.folder == folder.uuid } + return sort(filteredNotes, sorting) +} + +fun filterOutFolders(notes: List): List { + val allFoldersUUIDs = ApplicationBase.instance.foldersDatabase().getAll().map { it.uuid } + val sorting = SortingOptionsBottomSheet.getSortingState() + val filteredNotes = notes.filter { !allFoldersUUIDs.contains(it.folder) } + return sort(filteredNotes, sorting) +} + +fun unifiedSearchWithoutFolder(state: SearchState): List { + return getNotesForMode(state) + .filter { state.colors.isEmpty() || state.colors.contains(it.color) } + .filter { note -> state.tags.isEmpty() || state.tags.filter { note.tags !== null && note.tags.contains(it.uuid) }.isNotEmpty() } + .filter { + when { + state.text.isBlank() -> true + it.locked && !it.isNoteLockedButAppUnlocked() -> false + else -> it.getFullText().contains(state.text, true) + } + } +} + +fun filterDirectlyValidFolders(state: SearchState): List { + if (state.currentFolder != null) { + return emptyList() + } + + return foldersDb.getAll() + .filter { state.colors.isEmpty() || state.colors.contains(it.color) } + .filter { it.title.contains(state.text, true) } +} + +fun getNotesForMode(state: SearchState): List { + return when (state.mode) { + HomeNavigationMode.FAVOURITE -> notesDb.getByNoteState(arrayOf(NoteState.FAVOURITE.name)) + HomeNavigationMode.ARCHIVED -> notesDb.getByNoteState(arrayOf(NoteState.ARCHIVED.name)) + HomeNavigationMode.TRASH -> notesDb.getByNoteState(arrayOf(NoteState.TRASH.name)) + HomeNavigationMode.DEFAULT -> notesDb.getByNoteState(arrayOf(NoteState.DEFAULT.name, NoteState.FAVOURITE.name)) + HomeNavigationMode.LOCKED -> notesDb.getNoteByLocked(true) + } +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/main/activity/OpenTextIntentOrFileActivity.kt b/base/src/main/java/com/maubis/scarlet/base/main/activity/OpenTextIntentOrFileActivity.kt index 17f3940d..453b808b 100644 --- a/base/src/main/java/com/maubis/scarlet/base/main/activity/OpenTextIntentOrFileActivity.kt +++ b/base/src/main/java/com/maubis/scarlet/base/main/activity/OpenTextIntentOrFileActivity.kt @@ -2,7 +2,6 @@ package com.maubis.scarlet.base.main.activity import android.content.Context import android.content.Intent -import android.os.Build import android.os.Bundle import android.text.Editable import android.text.SpannableString @@ -14,27 +13,25 @@ import com.github.bijoysingh.starter.async.MultiAsyncTask import com.github.bijoysingh.starter.util.TextUtils import com.github.bijoysingh.uibasics.views.UITextView import com.maubis.markdown.Markdown +import com.maubis.markdown.spannable.clearMarkdownSpans import com.maubis.markdown.spannable.setFormats import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig -import com.maubis.scarlet.base.database.room.note.Note +import com.maubis.scarlet.base.config.ApplicationBase +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme import com.maubis.scarlet.base.core.note.NoteBuilder +import com.maubis.scarlet.base.database.room.note.Note import com.maubis.scarlet.base.export.support.NoteImporter import com.maubis.scarlet.base.note.creation.activity.ViewAdvancedNoteActivity import com.maubis.scarlet.base.note.save -import com.maubis.scarlet.base.support.utils.bind +import com.maubis.scarlet.base.support.ui.SecuredActivity import com.maubis.scarlet.base.support.ui.ThemeColorType -import com.maubis.scarlet.base.support.ui.ThemedActivity +import com.maubis.scarlet.base.support.utils.bind import java.io.InputStreamReader -import android.support.annotation.NonNull -import android.text.style.* -import com.maubis.markdown.spannable.clearMarkdownSpans - const val KEEP_PACKAGE = "com.google.android.keep" const val INTENT_KEY_DIRECT_NOTES_TRANSFER = "direct_notes_transfer" -class OpenTextIntentOrFileActivity : ThemedActivity() { +class OpenTextIntentOrFileActivity : SecuredActivity() { lateinit var context: Context @@ -61,7 +58,6 @@ class OpenTextIntentOrFileActivity : ThemedActivity() { setView() notifyThemeChange() - val spannable = SpannableString(contentText) spannable.setFormats(Markdown.getSpanInfo(contentText).spans) content.setText(spannable, TextView.BufferType.SPANNABLE) @@ -85,13 +81,12 @@ class OpenTextIntentOrFileActivity : ThemedActivity() { override fun afterTextChanged(text: Editable) { } - }) } override fun onResume() { super.onResume() - CoreConfig.instance.startListener(this) + ApplicationBase.instance.startListener(this) } private fun setView() { @@ -115,21 +110,6 @@ class OpenTextIntentOrFileActivity : ThemedActivity() { } fun handleIntent(): Boolean { - val hasDirectIntent = handleDirectSendText(intent) - if (hasDirectIntent) { - return false - } - - val hasSendIntent = handleSendText(intent) - if (hasSendIntent) { - val note = when (isCallerKeep()) { - true -> NoteBuilder().gen(titleText, NoteBuilder().genFromKeep(contentText)) - false -> NoteBuilder().gen(titleText, contentText) - } - note.save(this) - startActivity(ViewAdvancedNoteActivity.getIntent(this, note)) - return false - } val hasFileIntent = handleFileIntent(intent) if (hasFileIntent) { return true @@ -137,62 +117,39 @@ class OpenTextIntentOrFileActivity : ThemedActivity() { return false } - fun handleSendText(intent: Intent): Boolean { - val sharedText = intent.getStringExtra(Intent.EXTRA_TEXT) - val sharedTitle = intent.getStringExtra(Intent.EXTRA_TITLE) - val sharedSubject = intent.getStringExtra(Intent.EXTRA_SUBJECT) - - titleText = sharedSubject ?: sharedTitle ?: "" - contentText = sharedText ?: "" - return sharedText != null - } - - fun handleDirectSendText(intent: Intent): Boolean { - val sharedText = intent.getStringExtra(INTENT_KEY_DIRECT_NOTES_TRANSFER) - if (sharedText === null || sharedText.isBlank()) { + fun handleFileIntent(intent: Intent): Boolean { + val data = intent.data + val lastPathSegment = data?.lastPathSegment + if (data === null || lastPathSegment === null) { return false } - NoteImporter().gen(this, sharedText) - return true - } - fun handleFileIntent(intent: Intent): Boolean { - val data = intent.data try { val inputStream = contentResolver.openInputStream(data) contentText = NoteImporter().readFileInputStream(InputStreamReader(inputStream)) - filenameText = data.lastPathSegment - inputStream.close() + filenameText = lastPathSegment + inputStream?.close() return true } catch (exception: Exception) { return false } } - fun isCallerKeep(): Boolean { - return when { - Build.VERSION.SDK_INT >= 22 && (referrer?.toString() ?: "").contains(KEEP_PACKAGE) -> true - callingPackage?.contains(KEEP_PACKAGE) ?: false -> true - (intent?.`package` ?: "").contains(KEEP_PACKAGE) -> true - else -> false - } - } - override fun notifyThemeChange() { setSystemTheme(); val containerLayout = findViewById(R.id.container_layout); containerLayout.setBackgroundColor(getThemeColor()); - val toolbarIconColor = CoreConfig.instance.themeController().get(ThemeColorType.TOOLBAR_ICON); + val toolbarIconColor = sAppTheme.get(ThemeColorType.TOOLBAR_ICON); backButton.setColorFilter(toolbarIconColor) - val textColor = CoreConfig.instance.themeController().get(ThemeColorType.SECONDARY_TEXT) + val textColor = sAppTheme.get(ThemeColorType.SECONDARY_TEXT) filename.setTextColor(textColor) title.setTextColor(textColor) content.setTextColor(textColor) - val actionColor = CoreConfig.instance.themeController().get(ThemeColorType.TOOLBAR_ICON) + val actionColor = sAppTheme.get(ThemeColorType.TOOLBAR_ICON) actionDone.setImageTint(actionColor) actionDone.setTextColor(actionColor) } diff --git a/base/src/main/java/com/maubis/scarlet/base/main/activity/WidgetConfigureActivity.kt b/base/src/main/java/com/maubis/scarlet/base/main/activity/WidgetConfigureActivity.kt index 91da6a31..5d2d1bdb 100644 --- a/base/src/main/java/com/maubis/scarlet/base/main/activity/WidgetConfigureActivity.kt +++ b/base/src/main/java/com/maubis/scarlet/base/main/activity/WidgetConfigureActivity.kt @@ -2,18 +2,16 @@ package com.maubis.scarlet.base.main.activity import android.app.Activity import android.app.Application -import android.app.PendingIntent import android.appwidget.AppWidgetManager import android.content.ComponentName import android.content.Context import android.content.Intent import android.os.Bundle -import android.support.v4.content.ContextCompat import android.widget.RemoteViews +import androidx.core.content.ContextCompat import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb -import com.maubis.scarlet.base.core.note.NoteState import com.maubis.scarlet.base.database.room.note.Note import com.maubis.scarlet.base.database.room.widget.Widget import com.maubis.scarlet.base.note.creation.activity.ViewAdvancedNoteActivity @@ -37,8 +35,8 @@ class WidgetConfigureActivity : SelectableNotesActivityBase(), INoteSelectorActi val extras = intent.extras if (extras != null) { appWidgetId = extras.getInt( - AppWidgetManager.EXTRA_APPWIDGET_ID, - AppWidgetManager.INVALID_APPWIDGET_ID) + AppWidgetManager.EXTRA_APPWIDGET_ID, + AppWidgetManager.INVALID_APPWIDGET_ID) } if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) { @@ -55,7 +53,7 @@ class WidgetConfigureActivity : SelectableNotesActivityBase(), INoteSelectorActi override fun onNoteClicked(note: Note) { val widget = Widget(appWidgetId, note.uuid) - CoreConfig.instance.database().widgets().insert(widget) + ApplicationBase.instance.database().widgets().insert(widget) createWidget(widget) } @@ -82,8 +80,7 @@ class WidgetConfigureActivity : SelectableNotesActivityBase(), INoteSelectorActi return } - val intent = ViewAdvancedNoteActivity.getIntent(context, note) - val pendingIntent = PendingIntent.getActivity(context, 5000 + note.uid, intent, 0) + val pendingIntent = ViewAdvancedNoteActivity.getIntentWithStack(context, note) val views = RemoteViews(context.getPackageName(), R.layout.widget_layout) views.setTextViewText(R.id.description, getWidgetNoteText(note)) @@ -103,8 +100,8 @@ class WidgetConfigureActivity : SelectableNotesActivityBase(), INoteSelectorActi private fun notifyNoteChangeBroadcast(context: Context, note: Note): Intent? { val application: Application = context.applicationContext as Application val ids = AppWidgetManager.getInstance(application).getAppWidgetIds( - ComponentName(application, NoteWidgetProvider::class.java)) - val widgets = CoreConfig.instance.database().widgets().getByNote(note.uuid) + ComponentName(application, NoteWidgetProvider::class.java)) + val widgets = ApplicationBase.instance.database().widgets().getByNote(note.uuid) val widgetIds = ArrayList() for (widget in widgets) { diff --git a/base/src/main/java/com/maubis/scarlet/base/main/recycler/EmptyRecyclerHolder.kt b/base/src/main/java/com/maubis/scarlet/base/main/recycler/EmptyRecyclerHolder.kt index 9f43e917..122347e2 100644 --- a/base/src/main/java/com/maubis/scarlet/base/main/recycler/EmptyRecyclerHolder.kt +++ b/base/src/main/java/com/maubis/scarlet/base/main/recycler/EmptyRecyclerHolder.kt @@ -4,7 +4,7 @@ import android.content.Context import android.os.Bundle import android.view.View import com.github.bijoysingh.starter.recyclerview.RecyclerViewHolder -import com.github.bijoysingh.starter.util.IntentUtils +import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.note.creation.activity.CreateNoteActivity import com.maubis.scarlet.base.support.recycler.RecyclerItem @@ -13,7 +13,11 @@ class EmptyRecyclerHolder(context: Context, itemView: View) : RecyclerViewHolder override fun populate(data: RecyclerItem, extra: Bundle) { setFullSpan() itemView.setOnClickListener { - IntentUtils.startActivity(context, CreateNoteActivity::class.java) + val newNoteIntent = CreateNoteActivity.getNewNoteIntent( + context, + folder = (context as MainActivity).state.currentFolder?.uuid ?: "" + ) + context.startActivity(newNoteIntent) } } } diff --git a/base/src/main/java/com/maubis/scarlet/base/main/recycler/InformationRecyclerHolder.kt b/base/src/main/java/com/maubis/scarlet/base/main/recycler/InformationRecyclerHolder.kt index ef32b299..04a16741 100644 --- a/base/src/main/java/com/maubis/scarlet/base/main/recycler/InformationRecyclerHolder.kt +++ b/base/src/main/java/com/maubis/scarlet/base/main/recycler/InformationRecyclerHolder.kt @@ -7,6 +7,7 @@ import android.widget.TextView import com.github.bijoysingh.starter.recyclerview.RecyclerViewHolder import com.github.bijoysingh.uibasics.views.UITextView import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface import com.maubis.scarlet.base.support.recycler.RecyclerItem class InformationRecyclerHolder(context: Context, itemView: View) : RecyclerViewHolder(context, itemView) { @@ -19,8 +20,12 @@ class InformationRecyclerHolder(context: Context, itemView: View) : RecyclerView return } title.setText(data.title) + title.label.typeface = sAppTypeface.title() title.setImageResource(data.icon) + text.setText(data.source) + text.typeface = sAppTypeface.text() + itemView.setOnClickListener { data.function() } diff --git a/base/src/main/java/com/maubis/scarlet/base/main/recycler/InformationRecyclerItem.kt b/base/src/main/java/com/maubis/scarlet/base/main/recycler/InformationRecyclerItem.kt index 70f912c4..52428f9f 100644 --- a/base/src/main/java/com/maubis/scarlet/base/main/recycler/InformationRecyclerItem.kt +++ b/base/src/main/java/com/maubis/scarlet/base/main/recycler/InformationRecyclerItem.kt @@ -6,15 +6,16 @@ import com.github.bijoysingh.starter.util.IntentUtils import com.github.bijoysingh.starter.util.ToastHelper import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences import com.maubis.scarlet.base.export.sheet.BackupSettingsOptionsBottomSheet import com.maubis.scarlet.base.export.support.NoteExporter import com.maubis.scarlet.base.main.activity.INTENT_KEY_DIRECT_NOTES_TRANSFER import com.maubis.scarlet.base.settings.sheet.UISettingsOptionsBottomSheet import com.maubis.scarlet.base.support.recycler.RecyclerItem import com.maubis.scarlet.base.support.sheets.openSheet -import com.maubis.scarlet.base.support.utils.Flavor -import com.maubis.scarlet.base.support.utils.FlavourUtils +import com.maubis.scarlet.base.support.utils.FlavorUtils +import com.maubis.scarlet.base.support.utils.maybeThrow import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.async @@ -38,136 +39,134 @@ class InformationRecyclerItem(val icon: Int, val title: Int, val source: Int, va fun probability(probability: Float): Boolean = Random().nextFloat() <= probability fun shouldShowAppUpdateInformationItem(): Boolean { - return !CoreConfig.instance.remoteConfigFetcher().isLatestVersion() + return !ApplicationBase.instance.remoteConfigFetcher().isLatestVersion() } fun getAppUpdateInformationItem(context: Context): InformationRecyclerItem { return InformationRecyclerItem( - R.drawable.ic_info, - R.string.information_card_title, - R.string.information_new_app_update + R.drawable.ic_info, + R.string.information_card_title, + R.string.information_new_app_update ) { IntentUtils.openAppPlayStore(context) } } fun shouldShowReviewInformationItem(): Boolean { return probability(0.01f) - && !CoreConfig.instance.store().get(KEY_INFO_RATE_AND_REVIEW, false) + && !sAppPreferences.get(KEY_INFO_RATE_AND_REVIEW, false) } fun getReviewInformationItem(context: Context): InformationRecyclerItem { return InformationRecyclerItem( - R.drawable.ic_rating, - R.string.home_option_rate_and_review, - R.string.home_option_rate_and_review_subtitle + R.drawable.ic_rating, + R.string.home_option_rate_and_review, + R.string.home_option_rate_and_review_subtitle ) { - CoreConfig.instance.store().put(KEY_INFO_RATE_AND_REVIEW, true) + sAppPreferences.put(KEY_INFO_RATE_AND_REVIEW, true) IntentUtils.openAppPlayStore(context) } } fun shouldShowThemeInformationItem(): Boolean { return probability(0.01f) - && !CoreConfig.instance.store().get(KEY_THEME_OPTIONS, false) + && !sAppPreferences.get(KEY_THEME_OPTIONS, false) } fun getThemeInformationItem(activity: MainActivity): InformationRecyclerItem { return InformationRecyclerItem( - R.drawable.ic_action_grid, - R.string.home_option_ui_experience, - R.string.home_option_ui_experience_subtitle + R.drawable.ic_action_grid, + R.string.home_option_ui_experience, + R.string.home_option_ui_experience_subtitle ) { - CoreConfig.instance.store().put(KEY_THEME_OPTIONS, true) - UISettingsOptionsBottomSheet.openSheet(activity) + sAppPreferences.put(KEY_THEME_OPTIONS, true) + openSheet(activity, UISettingsOptionsBottomSheet()) } } fun shouldShowBackupInformationItem(): Boolean { return probability(0.01f) - && !CoreConfig.instance.store().get(KEY_BACKUP_OPTIONS, false) + && !sAppPreferences.get(KEY_BACKUP_OPTIONS, false) } fun getBackupInformationItem(activity: MainActivity): InformationRecyclerItem { return InformationRecyclerItem( - R.drawable.ic_export, - R.string.home_option_backup_options, - R.string.home_option_backup_options_subtitle + R.drawable.ic_export, + R.string.home_option_backup_options, + R.string.home_option_backup_options_subtitle ) { - CoreConfig.instance.store().put(KEY_BACKUP_OPTIONS, true) + sAppPreferences.put(KEY_BACKUP_OPTIONS, true) openSheet(activity, BackupSettingsOptionsBottomSheet()) } } - fun shouldShowInstallProInformationItem(): Boolean { return probability(0.01f) - && CoreConfig.instance.store().get(KEY_INFO_INSTALL_PRO_v2, 0) < KEY_INFO_INSTALL_PRO_MAX_COUNT - && CoreConfig.instance.appFlavor() != Flavor.PRO + && sAppPreferences.get(KEY_INFO_INSTALL_PRO_v2, 0) < KEY_INFO_INSTALL_PRO_MAX_COUNT + && !FlavorUtils.isPro() } fun getInstallProInformationItem(context: Context): InformationRecyclerItem { return InformationRecyclerItem( - R.drawable.ic_favorite_white_48dp, - R.string.install_pro_app, - R.string.information_install_pro + R.drawable.ic_favorite_white_48dp, + R.string.install_pro_app, + R.string.information_install_pro ) { notifyProUpsellShown() IntentUtils.openAppPlayStore(context, "com.bijoysingh.quicknote.pro") } } -fun shouldShowSignInformationItem(): Boolean { - if (CoreConfig.instance.authenticator().isLoggedIn() - || CoreConfig.instance.appFlavor() == Flavor.NONE) { +fun shouldShowSignInformationItem(context: Context): Boolean { + if (ApplicationBase.instance.authenticator().isLoggedIn(context) || FlavorUtils.isOpenSource()) { return false } - if (CoreConfig.instance.store().get(KEY_FORCE_SHOW_SIGN_IN, false)) { - CoreConfig.instance.store().put(KEY_FORCE_SHOW_SIGN_IN, false) + if (sAppPreferences.get(KEY_FORCE_SHOW_SIGN_IN, false)) { + sAppPreferences.put(KEY_FORCE_SHOW_SIGN_IN, false) return true } return probability(0.01f) - && !CoreConfig.instance.store().get(KEY_INFO_SIGN_IN, false) + && !sAppPreferences.get(KEY_INFO_SIGN_IN, false) } fun getSignInInformationItem(context: Context): InformationRecyclerItem { return InformationRecyclerItem( - R.drawable.ic_sign_in_options, - R.string.home_option_login_with_app, - R.string.home_option_login_with_app_subtitle + R.drawable.ic_sign_in_options, + R.string.home_option_login_with_app, + R.string.home_option_login_with_app_subtitle ) { - CoreConfig.instance.authenticator().openLoginActivity(context)?.run() + ApplicationBase.instance.authenticator().openLoginActivity(context)?.run() notifyProUpsellShown() } } fun notifyProUpsellShown() { - val proUpsellCount = CoreConfig.instance.store().get(KEY_INFO_INSTALL_PRO_v2, 0) - CoreConfig.instance.store().put(KEY_INFO_INSTALL_PRO_v2, proUpsellCount + 1) + val proUpsellCount = sAppPreferences.get(KEY_INFO_INSTALL_PRO_v2, 0) + sAppPreferences.put(KEY_INFO_INSTALL_PRO_v2, proUpsellCount + 1) } - fun shouldShowMigrateToProAppInformationItem(context: Context): Boolean { - return CoreConfig.instance.appFlavor() == Flavor.LITE - && FlavourUtils.hasProAppInstalled(context) - && !CoreConfig.instance.store().get(KEY_MIGRATE_TO_PRO_SUCCESS, false) + return FlavorUtils.isLite() + && FlavorUtils.hasProAppInstalled(context) + && !sAppPreferences.get(KEY_MIGRATE_TO_PRO_SUCCESS, false) } fun getMigrateToProAppInformationItem(context: Context): InformationRecyclerItem { return InformationRecyclerItem( - R.drawable.ic_import, - R.string.home_option_migrate_to_pro, - R.string.home_option_migrate_to_pro_details + R.drawable.ic_import, + R.string.home_option_migrate_to_pro, + R.string.home_option_migrate_to_pro_details ) { GlobalScope.launch(Dispatchers.Main) { val notes = GlobalScope.async(Dispatchers.IO) { NoteExporter().getExportContent() } val intent = Intent(Intent.ACTION_SEND) - .putExtra(INTENT_KEY_DIRECT_NOTES_TRANSFER, notes.await()) - .setType("text/plain") - .setPackage(FlavourUtils.PRO_APP_PACKAGE_NAME) + .putExtra(INTENT_KEY_DIRECT_NOTES_TRANSFER, notes.await()) + .setType("text/plain") + .setPackage(FlavorUtils.PRO_APP_PACKAGE_NAME) try { context.startActivity(intent) - CoreConfig.instance.store().put(KEY_MIGRATE_TO_PRO_SUCCESS, true) - } catch (e: Exception) { + sAppPreferences.put(KEY_MIGRATE_TO_PRO_SUCCESS, true) + } catch (exception: Exception) { ToastHelper.show(context, "Failed transferring notes to Scarlet Pro") + maybeThrow(exception) } } } diff --git a/base/src/main/java/com/maubis/scarlet/base/main/recycler/ToolbarMainRecyclerHolder.kt b/base/src/main/java/com/maubis/scarlet/base/main/recycler/ToolbarMainRecyclerHolder.kt index a506c13c..90a9dc24 100644 --- a/base/src/main/java/com/maubis/scarlet/base/main/recycler/ToolbarMainRecyclerHolder.kt +++ b/base/src/main/java/com/maubis/scarlet/base/main/recycler/ToolbarMainRecyclerHolder.kt @@ -2,22 +2,24 @@ package com.maubis.scarlet.base.main.recycler import android.content.Context import android.os.Bundle -import android.support.v7.widget.StaggeredGridLayoutManager import android.view.View import android.widget.ImageView import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import androidx.recyclerview.widget.StaggeredGridLayoutManager import com.github.bijoysingh.starter.recyclerview.RecyclerViewHolder import com.maubis.scarlet.base.BuildConfig import com.maubis.scarlet.base.MainActivity +import com.maubis.scarlet.base.MainActivityActions import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig -import com.maubis.scarlet.base.export.sheet.BackupSettingsOptionsBottomSheet -import com.maubis.scarlet.base.settings.sheet.DeleteAndMoreOptionsBottomSheet +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface +import com.maubis.scarlet.base.performAction import com.maubis.scarlet.base.settings.sheet.SettingsOptionsBottomSheet import com.maubis.scarlet.base.support.recycler.RecyclerItem -import com.maubis.scarlet.base.support.sheets.openSheet import com.maubis.scarlet.base.support.ui.ThemeColorType import com.maubis.scarlet.base.support.ui.visibility +import com.maubis.scarlet.base.support.utils.maybeThrow class ToolbarMainRecyclerHolder(context: Context, itemView: View) : RecyclerViewHolder(context, itemView) { @@ -29,24 +31,25 @@ class ToolbarMainRecyclerHolder(context: Context, itemView: View) : RecyclerView override fun populate(data: RecyclerItem, extra: Bundle) { setFullSpan() toolbarIconSearch.setOnClickListener { - (context as MainActivity).setSearchMode(true) + (context as MainActivity).enterSearchMode() } toolbarIconSettings.setOnClickListener { SettingsOptionsBottomSheet.openSheet((context as MainActivity)) } - val titleColor = CoreConfig.instance.themeController().get(ThemeColorType.SECONDARY_TEXT) + val titleColor = sAppTheme.get(ThemeColorType.SECONDARY_TEXT) toolbarTitle.setTextColor(titleColor) + toolbarTitle.typeface = sAppTypeface.heading() - val toolbarIconColor = CoreConfig.instance.themeController().get(ThemeColorType.SECONDARY_TEXT) + val toolbarIconColor = sAppTheme.get(ThemeColorType.SECONDARY_TEXT) toolbarIconSearch.setColorFilter(toolbarIconColor) toolbarIconSettings.setColorFilter(toolbarIconColor) toolbarIconDebug.visibility = visibility(BuildConfig.DEBUG) toolbarIconDebug.setColorFilter(toolbarIconColor) toolbarIconDebug.setOnClickListener { - openSheet((context as MainActivity), DeleteAndMoreOptionsBottomSheet()) + (context as MainActivity).performAction(MainActivityActions.TYPEFACE_PICKER) } } } @@ -55,6 +58,7 @@ fun RecyclerViewHolder.setFullSpan() { try { val layoutParams = itemView.getLayoutParams() as StaggeredGridLayoutManager.LayoutParams layoutParams.isFullSpan = true - } catch (e: Exception) { + } catch (exception: Exception) { + maybeThrow(itemView.context as AppCompatActivity, exception) } } diff --git a/base/src/main/java/com/maubis/scarlet/base/main/sheets/AlertBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/main/sheets/AlertBottomSheet.kt index c8414d27..8d038e1f 100644 --- a/base/src/main/java/com/maubis/scarlet/base/main/sheets/AlertBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/main/sheets/AlertBottomSheet.kt @@ -8,6 +8,8 @@ import com.facebook.litho.widget.Text import com.facebook.yoga.YogaEdge import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme import com.maubis.scarlet.base.config.CoreConfig import com.maubis.scarlet.base.core.format.Format import com.maubis.scarlet.base.core.note.NoteState @@ -22,25 +24,25 @@ import com.maubis.scarlet.base.support.ui.ThemeColorType import com.maubis.scarlet.base.support.ui.ThemedActivity data class AlertSheetConfig( - val title: Int = R.string.delete_sheet_are_you_sure, - val description: Int = R.string.delete_sheet_delete_note_permanently, - val positiveText: Int = R.string.delete_sheet_delete_trash_yes, - val negativeText: Int = R.string.delete_sheet_delete_trash_no, - val onPositiveClick: () -> Unit = {}, - val onNegativeClick: () -> Unit = {}) + val title: Int = R.string.delete_sheet_are_you_sure, + val description: Int = R.string.delete_sheet_delete_note_permanently, + val positiveText: Int = R.string.delete_sheet_delete_trash_yes, + val negativeText: Int = R.string.delete_sheet_delete_trash_no, + val onPositiveClick: () -> Unit = {}, + val onNegativeClick: () -> Unit = {}) fun openDeleteNotePermanentlySheet(activity: ThemedActivity, note: Note, onDelete: () -> Unit) { openSheet(activity, AlertBottomSheet().apply { this.config = AlertSheetConfig( - title = R.string.delete_sheet_are_you_sure, - description = R.string.delete_sheet_delete_note_permanently, - positiveText = R.string.delete_sheet_delete_trash_yes, - negativeText = R.string.delete_sheet_delete_trash_no, - onPositiveClick = { - note.delete(activity) - onDelete() - }, - onNegativeClick = {}) + title = R.string.delete_sheet_are_you_sure, + description = R.string.delete_sheet_delete_note_permanently, + positiveText = R.string.delete_sheet_delete_trash_yes, + negativeText = R.string.delete_sheet_delete_trash_no, + onPositiveClick = { + note.delete(activity) + onDelete() + }, + onNegativeClick = {}) }) } @@ -48,29 +50,30 @@ class AlertBottomSheet : LithoBottomSheet() { var config: AlertSheetConfig = AlertSheetConfig() override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { - val activity = context as ThemedActivity val component = Column.create(componentContext) - .widthPercent(100f) - .paddingDip(YogaEdge.VERTICAL, 8f) - .paddingDip(YogaEdge.HORIZONTAL, 20f) - .child(getLithoBottomSheetTitle(componentContext) - .textRes(config.title) - .marginDip(YogaEdge.HORIZONTAL, 0f)) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_large) - .textRes(config.description) - .marginDip(YogaEdge.BOTTOM, 16f) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.TERTIARY_TEXT))) - .child(BottomSheetBar.create(componentContext) - .primaryActionRes(config.positiveText) - .onPrimaryClick { - config.onPositiveClick() - dismiss() - }.secondaryActionRes(config.negativeText) - .onSecondaryClick { - config.onNegativeClick() - dismiss() - }.paddingDip(YogaEdge.VERTICAL, 8f)) + .widthPercent(100f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .child( + getLithoBottomSheetTitle(componentContext) + .textRes(config.title) + .marginDip(YogaEdge.HORIZONTAL, 0f)) + .child( + Text.create(componentContext) + .textSizeRes(R.dimen.font_size_large) + .textRes(config.description) + .marginDip(YogaEdge.BOTTOM, 16f) + .textColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT))) + .child(BottomSheetBar.create(componentContext) + .primaryActionRes(config.positiveText) + .onPrimaryClick { + config.onPositiveClick() + dismiss() + }.secondaryActionRes(config.negativeText) + .onSecondaryClick { + config.onNegativeClick() + dismiss() + }.paddingDip(YogaEdge.VERTICAL, 8f)) return component.build() } } @@ -78,63 +81,62 @@ class AlertBottomSheet : LithoBottomSheet() { fun openDeleteAllXSheet(activity: MainActivity, subtitle: Int, onSuccess: () -> Unit) { openSheet(activity, AlertBottomSheet().apply { this.config = AlertSheetConfig( - title = R.string.delete_sheet_are_you_sure, - description = subtitle, - positiveText = R.string.delete_sheet_delete_trash_yes, - negativeText = R.string.delete_sheet_delete_trash_no, - onPositiveClick = { - onSuccess() - }, - onNegativeClick = {}) + title = R.string.delete_sheet_are_you_sure, + description = subtitle, + positiveText = R.string.delete_sheet_delete_trash_yes, + negativeText = R.string.delete_sheet_delete_trash_no, + onPositiveClick = { + onSuccess() + }, + onNegativeClick = {}) }) } fun openDeleteFormatDialog(activity: ViewAdvancedNoteActivity, format: Format) { openSheet(activity, AlertBottomSheet().apply { this.config = AlertSheetConfig( - title = R.string.delete_sheet_are_you_sure, - description = R.string.image_delete_all_devices, - positiveText = R.string.delete_sheet_delete_trash_yes, - negativeText = R.string.delete_sheet_delete_trash_no, - onPositiveClick = { - activity.deleteFormat(format) - }, - onNegativeClick = {}) + title = R.string.delete_sheet_are_you_sure, + description = R.string.image_delete_all_devices, + positiveText = R.string.delete_sheet_delete_trash_yes, + negativeText = R.string.delete_sheet_delete_trash_no, + onPositiveClick = { + activity.deleteFormat(format) + }, + onNegativeClick = {}) }) } const val STORE_KEY_IMAGE_SYNC_NOTICE = "IMAGE_SYNC_NOTICE" var sImageSyncNoticeShown: Int - get() = CoreConfig.instance.store().get(STORE_KEY_IMAGE_SYNC_NOTICE, 0) - set(value) = CoreConfig.instance.store().put(STORE_KEY_IMAGE_SYNC_NOTICE, value) - + get() = sAppPreferences.get(STORE_KEY_IMAGE_SYNC_NOTICE, 0) + set(value) = sAppPreferences.put(STORE_KEY_IMAGE_SYNC_NOTICE, value) fun openImageNotSynced(activity: ThemedActivity) { openSheet(activity, AlertBottomSheet().apply { this.config = AlertSheetConfig( - title = R.string.image_not_uploaded, - description = R.string.image_not_uploaded_details, - positiveText = R.string.image_not_uploaded_i_understand, - negativeText = R.string.delete_sheet_delete_trash_no, - onPositiveClick = { sImageSyncNoticeShown = 1 }, - onNegativeClick = {}) + title = R.string.image_not_uploaded, + description = R.string.image_not_uploaded_details, + positiveText = R.string.image_not_uploaded_i_understand, + negativeText = R.string.delete_sheet_delete_trash_no, + onPositiveClick = { sImageSyncNoticeShown = 1 }, + onNegativeClick = {}) }) } fun openDeleteTrashSheet(activity: MainActivity) { openSheet(activity, AlertBottomSheet().apply { this.config = AlertSheetConfig( - title = R.string.delete_sheet_are_you_sure, - description = R.string.delete_sheet_delete_trash, - positiveText = R.string.delete_sheet_delete_trash_yes, - negativeText = R.string.delete_sheet_delete_trash_no, - onPositiveClick = { - val notes = CoreConfig.notesDb.getByNoteState(arrayOf(NoteState.TRASH.name)) - for (note in notes) { - note.delete(activity) - } - activity.setupData() - }, - onNegativeClick = {}) + title = R.string.delete_sheet_are_you_sure, + description = R.string.delete_sheet_delete_trash, + positiveText = R.string.delete_sheet_delete_trash_yes, + negativeText = R.string.delete_sheet_delete_trash_no, + onPositiveClick = { + val notes = CoreConfig.notesDb.getByNoteState(arrayOf(NoteState.TRASH.name)) + for (note in notes) { + note.delete(activity) + } + activity.loadData() + }, + onNegativeClick = {}) }) } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/main/sheets/EnterPincodeBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/main/sheets/EnterPincodeBottomSheet.kt deleted file mode 100644 index cb6dee59..00000000 --- a/base/src/main/java/com/maubis/scarlet/base/main/sheets/EnterPincodeBottomSheet.kt +++ /dev/null @@ -1,288 +0,0 @@ -package com.maubis.scarlet.base.main.sheets - -import android.app.Dialog -import android.content.DialogInterface -import android.text.Editable -import android.text.TextWatcher -import android.view.KeyEvent -import android.view.View -import android.view.inputmethod.EditorInfo -import android.widget.EditText -import android.widget.ImageView -import android.widget.TextView -import com.github.ajalt.reprint.core.AuthenticationFailureReason -import com.github.ajalt.reprint.core.AuthenticationListener -import com.github.ajalt.reprint.core.Reprint -import com.github.bijoysingh.starter.util.LocaleManager -import com.maubis.scarlet.base.MainActivity -import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig -import com.maubis.scarlet.base.settings.sheet.SecurityOptionsBottomSheet -import com.maubis.scarlet.base.settings.sheet.SecurityOptionsBottomSheet.Companion.hasPinCodeEnabled -import com.maubis.scarlet.base.support.ui.ThemeColorType -import com.maubis.scarlet.base.support.ui.ThemedActivity -import com.maubis.scarlet.base.support.ui.ThemedBottomSheetFragment - - -class EnterPincodeBottomSheet : ThemedBottomSheetFragment() { - - var listener: PincodeListener? = null - - override fun getBackgroundView(): Int { - return R.id.container_layout - } - - override fun setupView(dialog: Dialog?) { - super.setupView(dialog) - if (dialog == null) { - return - } - - if (listener == null) { - dismiss() - } - - val title = dialog.findViewById(R.id.options_title) - val action = dialog.findViewById(R.id.action_button) - val enterPin = dialog.findViewById(R.id.enter_pin) - val pinLength = dialog.findViewById(R.id.pin_length) - val fingerprint = dialog.findViewById(R.id.fingerprint) - val removeBtn = dialog.findViewById(R.id.action_remove_button) - - title.setTextColor(CoreConfig.instance.themeController().get(ThemeColorType.SECONDARY_TEXT)) - enterPin.setTextColor(CoreConfig.instance.themeController().get(ThemeColorType.SECONDARY_TEXT)) - - val hintColor = CoreConfig.instance.themeController().get(ThemeColorType.HINT_TEXT) - enterPin.setHintTextColor(hintColor) - pinLength.setTextColor(hintColor) - - title.setText(listener!!.getTitle()) - action.setText(listener!!.getActionTitle()) - fingerprint.visibility = if (listener!!.isFingerprintEnabled()) View.VISIBLE else View.INVISIBLE - enterPin.addTextChangedListener(object : TextWatcher { - override fun afterTextChanged(p0: Editable?) { - // Ignore - } - - override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { - // Ignore - } - - override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { - if (p0 == null) { - return - } - if (p0.length > 4) { - enterPin.setText(p0.substring(0, 4)) - return - } - val text = LocaleManager.toString(p0.length) + " / " + LocaleManager.toString(PIN_LENGTH) - pinLength.text = text - } - }) - removeBtn.setOnClickListener { - listener!!.onRemoveButtonClick() - dismiss() - } - removeBtn.visibility = if (listener!!.isRemoveButtonEnabled()) View.VISIBLE else View.GONE - - enterPin.setOnEditorActionListener { _, actionId, event -> - if (event == null) { - if (actionId != EditorInfo.IME_ACTION_DONE && actionId != EditorInfo.IME_ACTION_NEXT) { - return@setOnEditorActionListener false - } - } else if (actionId == EditorInfo.IME_NULL || actionId == KeyEvent.KEYCODE_ENTER) { - if (event.getAction() != KeyEvent.ACTION_DOWN) { - return@setOnEditorActionListener true - } - } else { - return@setOnEditorActionListener false - } - - if (enterPin.length() != PIN_LENGTH) { - return@setOnEditorActionListener false - } - - listener!!.onPasswordRequested(enterPin.text.toString()) - dismiss() - return@setOnEditorActionListener true - } - - action.setOnClickListener { - val pinCode = enterPin.text.toString() - if (enterPin.length() != PIN_LENGTH) { - return@setOnClickListener - } - - listener!!.onPasswordRequested(pinCode) - dismiss() - } - - if (listener!!.isFingerprintEnabled()) { - Reprint.authenticate(object : AuthenticationListener { - override fun onSuccess(moduleTag: Int) { - listener!!.onSuccess() - dismiss() - } - - override fun onFailure( - failureReason: AuthenticationFailureReason?, - fatal: Boolean, - errorMessage: CharSequence?, - moduleTag: Int, - errorCode: Int) { - // Ignore - } - }) - } - makeBackgroundTransparent(dialog, R.id.root_layout) - } - - override fun onDismiss(dialog: DialogInterface?) { - super.onDismiss(dialog) - Reprint.cancelAuthentication() - } - - override fun onCancel(dialog: DialogInterface?) { - super.onCancel(dialog) - Reprint.cancelAuthentication() - } - - override fun getLayout(): Int = R.layout.bottom_sheet_pin_code - - override fun getBackgroundCardViewIds(): Array = arrayOf(R.id.enter_code_card) - - companion object { - - const val PIN_LENGTH = 4 - - fun openSheet(activity: ThemedActivity, listener: PincodeListener) { - val sheet = EnterPincodeBottomSheet() - - sheet.listener = listener - sheet.show(activity.supportFragmentManager, sheet.tag) - } - - fun openCreateSheet( - activity: ThemedActivity, - listener: PincodeSuccessOnlyListener) { - openSheet(activity, object : PincodeListener { - override fun getTitle(): Int = R.string.security_sheet_enter_new_pin_title - - override fun getActionTitle(): Int = R.string.security_sheet_button_set - - override fun isFingerprintEnabled(): Boolean = false - - override fun isRemoveButtonEnabled(): Boolean = true - - override fun onRemoveButtonClick() { - CoreConfig.instance.store().put(SecurityOptionsBottomSheet.KEY_SECURITY_CODE, "") - sNoPinSetupNoticeShown = false - listener.onSuccess() - - if (activity is MainActivity) - activity.setupData() - } - - override fun onPasswordRequested(password: String) { - CoreConfig.instance.store().put(SecurityOptionsBottomSheet.KEY_SECURITY_CODE, password) - listener.onSuccess() - } - - override fun onSuccess() { - } - }) - } - - fun openVerifySheet( - activity: ThemedActivity, - listener: PincodeSuccessListener) { - openUnlockSheetBase( - activity, - listener, - R.string.security_sheet_enter_current_pin_title, - R.string.security_sheet_button_verify - ) - } - - fun openUnlockSheet( - activity: ThemedActivity, - listener: PincodeSuccessOnlyListener) { - if (!hasPinCodeEnabled()) { - if (sNoPinSetupNoticeShown) { - listener.onSuccess() - return - } - com.maubis.scarlet.base.support.sheets.openSheet(activity, NoPincodeBottomSheet().apply { - this.onSuccess = { listener.onSuccess() } - }) - return - } - - openUnlockSheetBase( - activity, - listener, - R.string.security_sheet_enter_pin_to_unlock_title, - R.string.security_sheet_button_unlock - ) - } - - private fun openUnlockSheetBase( - activity: ThemedActivity, - listener: PincodeSuccessOnlyListener, - title: Int, - actionTitle: Int) { - openSheet(activity, object : PincodeListener { - override fun getTitle(): Int = title - - override fun getActionTitle(): Int = actionTitle - - override fun isFingerprintEnabled(): Boolean { - return Reprint.hasFingerprintRegistered() && - CoreConfig.instance.store().get(SecurityOptionsBottomSheet.KEY_FINGERPRINT_ENABLED, true) - } - - override fun onPasswordRequested(password: String) { - val currentPassword = CoreConfig.instance.store().get(SecurityOptionsBottomSheet.KEY_SECURITY_CODE, "") - if (currentPassword != "" && currentPassword == password) { - listener.onSuccess() - } else if (listener is PincodeSuccessListener) { - listener.onFailure() - } - } - - override fun isRemoveButtonEnabled(): Boolean = false - - override fun onRemoveButtonClick() { - } - - override fun onSuccess() { - listener.onSuccess() - } - }) - } - } - - interface PincodeSuccessOnlyListener { - fun onSuccess() - } - - interface PincodeSuccessListener : PincodeSuccessOnlyListener { - - fun onFailure() - } - - interface PincodeListener : PincodeSuccessOnlyListener { - fun getTitle(): Int - - fun getActionTitle(): Int - - fun isFingerprintEnabled(): Boolean - - fun isRemoveButtonEnabled(): Boolean - - fun onPasswordRequested(password: String): Unit - - fun onRemoveButtonClick(): Unit - } -} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/main/sheets/ExceptionBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/main/sheets/ExceptionBottomSheet.kt new file mode 100644 index 00000000..12ebf806 --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/main/sheets/ExceptionBottomSheet.kt @@ -0,0 +1,58 @@ +package com.maubis.scarlet.base.main.sheets + +import android.app.Dialog +import android.content.Intent +import android.net.Uri +import android.util.Log +import com.facebook.litho.Column +import com.facebook.litho.Component +import com.facebook.litho.ComponentContext +import com.facebook.litho.widget.Text +import com.facebook.yoga.YogaEdge +import com.maubis.markdown.Markdown +import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface +import com.maubis.scarlet.base.support.sheets.LithoBottomSheet +import com.maubis.scarlet.base.support.sheets.getLithoBottomSheetTitle +import com.maubis.scarlet.base.support.specs.BottomSheetBar +import com.maubis.scarlet.base.support.ui.ThemeColorType + +class ExceptionBottomSheet : LithoBottomSheet() { + var exception: Exception = RuntimeException() + + override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { + val component = Column.create(componentContext) + .widthPercent(100f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .child( + getLithoBottomSheetTitle(componentContext) + .textRes(R.string.exception_sheet_title) + .marginDip(YogaEdge.HORIZONTAL, 0f)) + .child( + Text.create(componentContext) + .typeface(sAppTypeface.code()) + .textSizeRes(R.dimen.font_size_small) + .text(Markdown.render("```\n${Log.getStackTraceString(exception)}\n```", true)) + .marginDip(YogaEdge.BOTTOM, 16f) + .textColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT))) + .child(BottomSheetBar.create(componentContext) + .primaryActionRes(R.string.exception_sheet_crash_app) + .onPrimaryClick { + throw exception + }.secondaryActionRes(R.string.exception_sheet_mail) + .onSecondaryClick { + try { + val intent = Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:team.thecodershub@gmail.com")) + intent.putExtra(Intent.EXTRA_SUBJECT, "[Exception] The application threw an exception") + intent.putExtra(Intent.EXTRA_TEXT, "Hi, my app threw this exception\n${Log.getStackTraceString(exception)}") + startActivity(Intent.createChooser(intent, "Send email to developer...")) + } catch (exception: Exception) { + // Ignore this one ;) + } + dismiss() + }.paddingDip(YogaEdge.VERTICAL, 8f)) + return component.build() + } +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/main/sheets/HomeNavigationBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/main/sheets/HomeNavigationBottomSheet.kt deleted file mode 100644 index 37bd8fb5..00000000 --- a/base/src/main/java/com/maubis/scarlet/base/main/sheets/HomeNavigationBottomSheet.kt +++ /dev/null @@ -1,207 +0,0 @@ -package com.maubis.scarlet.base.main.sheets - -import android.app.Dialog -import android.support.v4.content.ContextCompat -import android.view.View -import android.widget.LinearLayout -import android.widget.TextView -import com.github.bijoysingh.starter.util.LocaleManager -import com.github.bijoysingh.uibasics.views.UITextView -import com.maubis.scarlet.base.MainActivity -import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig -import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb -import com.maubis.scarlet.base.config.CoreConfig.Companion.tagsDb -import com.maubis.scarlet.base.core.tag.TagBuilder -import com.maubis.scarlet.base.main.HomeNavigationState -import com.maubis.scarlet.base.note.tag.TagOptionsItem -import com.maubis.scarlet.base.note.tag.sheet.CreateOrEditTagBottomSheet -import com.maubis.scarlet.base.note.tag.view.HomeTagView -import com.maubis.scarlet.base.settings.sheet.SettingsOptionsBottomSheet -import com.maubis.scarlet.base.support.SearchConfig -import com.maubis.scarlet.base.support.option.OptionsItem -import com.maubis.scarlet.base.support.sheets.GridBottomSheetBase -import com.maubis.scarlet.base.support.ui.Theme -import com.maubis.scarlet.base.support.ui.ThemeColorType -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.async -import kotlinx.coroutines.launch - -class HomeNavigationBottomSheet : GridBottomSheetBase() { - - override fun setupViewWithDialog(dialog: Dialog) { - resetOptions(dialog) - resetTags(dialog) - setAddTagOption(dialog) - makeBackgroundTransparent(dialog, R.id.root_layout) - } - - private fun getOptions(): List { - val activity = context as MainActivity - val options = ArrayList() - options.add(OptionsItem( - title = R.string.nav_home, - subtitle = R.string.nav_home_details, - icon = R.drawable.ic_home_white_48dp, - selected = activity.config.mode == HomeNavigationState.DEFAULT, - listener = View.OnClickListener { - activity.onHomeClick(); - dismiss(); - } - )) - options.add(OptionsItem( - title = R.string.nav_favourites, - subtitle = R.string.nav_favourites_details, - icon = R.drawable.ic_favorite_white_48dp, - selected = activity.config.mode == HomeNavigationState.FAVOURITE, - listener = View.OnClickListener { - activity.onFavouritesClick(); - dismiss(); - } - )) - options.add(OptionsItem( - title = R.string.nav_archived, - subtitle = R.string.nav_archived_details, - icon = R.drawable.ic_archive_white_48dp, - selected = activity.config.mode == HomeNavigationState.ARCHIVED, - listener = View.OnClickListener { - activity.onArchivedClick(); - dismiss(); - } - )) - options.add(OptionsItem( - title = R.string.nav_locked, - subtitle = R.string.nav_locked_details, - icon = R.drawable.ic_action_lock, - selected = activity.config.mode == HomeNavigationState.LOCKED, - listener = View.OnClickListener { - activity.onLockedClick(); - dismiss(); - } - )) - options.add(OptionsItem( - title = R.string.nav_trash, - subtitle = R.string.nav_trash_details, - icon = R.drawable.ic_delete_white_48dp, - selected = activity.config.mode == HomeNavigationState.TRASH, - listener = View.OnClickListener { - activity.onTrashClick(); - dismiss(); - } - )) - options.add(OptionsItem( - title = R.string.nav_settings, - subtitle = R.string.nav_settings, - icon = R.drawable.ic_action_settings, - listener = View.OnClickListener { - SettingsOptionsBottomSheet.openSheet(activity) - dismiss(); - } - )) - return options - } - - fun resetOptions(dialog: Dialog) { - GlobalScope.launch(Dispatchers.Main) { - val items = GlobalScope.async(Dispatchers.IO) { getOptions() } - setOptions(dialog, items.await()) - } - } - - fun resetTags(dialog: Dialog) { - GlobalScope.launch(Dispatchers.Main) { - val tags = GlobalScope.async(Dispatchers.IO) { getTagOptions() } - - val titleView = dialog.findViewById(R.id.tag_options_title) - titleView.setTextColor( - CoreConfig.instance.themeController().get(themedContext(), - Theme.DARK, ThemeColorType.SECONDARY_TEXT)) - - val layout = dialog.findViewById(R.id.options_container) - layout.removeAllViews() - setTagOptions(dialog, tags.await()) - } - } - - private fun setTagOptions(dialog: Dialog, options: List) { - val layout = dialog.findViewById(R.id.options_container); - for (option in options.sorted()) { - val contentView = HomeTagView(View.inflate(context, R.layout.layout_home_tag_item, null)) - contentView.title.setText(option.tag.title) - contentView.rootView.setOnClickListener(option.listener) - contentView.subtitle.visibility = View.GONE - contentView.icon.setImageResource(option.getIcon()) - - contentView.action.setImageResource(option.getEditIcon()); - contentView.action.setColorFilter(CoreConfig.instance.themeController().get(themedContext(), Theme.DARK, ThemeColorType.HINT_TEXT)); - contentView.action.setOnClickListener(option.editListener) - - if (option.usages > 0) { - contentView.subtitle.setText(LocaleManager.toString(option.usages)) - contentView.subtitle.visibility = View.VISIBLE - } - - contentView.title.setTextColor(getOptionsTitleColor(option.selected)) - contentView.subtitle.setTextColor(getOptionsSubtitleColor(option.selected)) - contentView.icon.setColorFilter(getOptionsTitleColor(option.selected)) - - layout.addView(contentView.rootView) - } - } - - private fun getTagOptions(): List { - val activity = context as MainActivity - val options = ArrayList() - for (tag in tagsDb.getAll()) { - options.add(TagOptionsItem( - tag = tag, - usages = notesDb.getNoteCountByTag(tag.uuid), - listener = View.OnClickListener { - activity.config = SearchConfig(mode = HomeNavigationState.DEFAULT) - activity.openTag(tag) - dismiss() - }, - editable = true, - editListener = View.OnClickListener { - CreateOrEditTagBottomSheet.openSheet(activity, tag, { _, _ -> resetTags(dialog) }) - } - )) - } - return options - } - - private fun setAddTagOption(dialog: Dialog) { - val hintTextColor = CoreConfig.instance.themeController().get(themedContext(), Theme.DARK, ThemeColorType.HINT_TEXT) - val newTagButton = dialog.findViewById(R.id.new_tag_button) - newTagButton.setTextColor(hintTextColor) - newTagButton.setImageTint(hintTextColor) - newTagButton.setOnClickListener { onNewTagClick() } - newTagButton.icon.alpha = 0.6f - } - - private fun onNewTagClick() { - val activity = context as MainActivity - CreateOrEditTagBottomSheet.openSheet(activity, TagBuilder().emptyTag(), { _, _ -> resetTags(dialog) }) - } - - override fun getOptionsTitleColor(selected: Boolean): Int { - return ContextCompat.getColor(themedContext(), R.color.light_primary_text) - } - - override fun getOptionsSubtitleColor(selected: Boolean): Int { - return ContextCompat.getColor(themedContext(), R.color.light_secondary_text) - } - - override fun getBackgroundCardViewIds(): Array = emptyArray() - - override fun getLayout(): Int = R.layout.bottom_sheet_home_navigation - - companion object { - fun openSheet(activity: MainActivity) { - val sheet = HomeNavigationBottomSheet() - - sheet.show(activity.supportFragmentManager, sheet.tag) - } - } -} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/main/sheets/HomeOptionsBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/main/sheets/HomeOptionsBottomSheet.kt new file mode 100644 index 00000000..d679691f --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/main/sheets/HomeOptionsBottomSheet.kt @@ -0,0 +1,263 @@ +package com.maubis.scarlet.base.main.sheets + +import android.app.Dialog +import android.graphics.Typeface +import com.facebook.litho.ClickEvent +import com.facebook.litho.Column +import com.facebook.litho.Component +import com.facebook.litho.ComponentContext +import com.facebook.litho.Row +import com.facebook.litho.annotations.LayoutSpec +import com.facebook.litho.annotations.OnCreateLayout +import com.facebook.litho.annotations.OnEvent +import com.facebook.litho.annotations.Prop +import com.facebook.litho.widget.Text +import com.facebook.yoga.YogaAlign +import com.facebook.yoga.YogaEdge +import com.maubis.scarlet.base.MainActivity +import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface +import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.core.tag.TagBuilder +import com.maubis.scarlet.base.database.room.tag.Tag +import com.maubis.scarlet.base.main.HomeNavigationMode +import com.maubis.scarlet.base.note.tag.sheet.CreateOrEditTagBottomSheet +import com.maubis.scarlet.base.settings.sheet.SettingsOptionsBottomSheet +import com.maubis.scarlet.base.support.sheets.LithoBottomSheet +import com.maubis.scarlet.base.support.sheets.LithoLabelOptionsItem +import com.maubis.scarlet.base.support.sheets.LithoOptionsItem +import com.maubis.scarlet.base.support.sheets.OptionItemLayout +import com.maubis.scarlet.base.support.sheets.OptionLabelItemLayout +import com.maubis.scarlet.base.support.sheets.getLithoBottomSheetTitle +import com.maubis.scarlet.base.support.specs.RoundIcon +import com.maubis.scarlet.base.support.ui.ThemeColorType + +class LithoTagOptionsItem( + val tag: Tag, + val usages: Int = 0, + val isSelected: Boolean = false, + val isEditable: Boolean = false, + val editListener: () -> Unit = {}, + val listener: () -> Unit = {}) { +} + +@LayoutSpec +object TagItemLayoutSpec { + @OnCreateLayout + fun onCreate(context: ComponentContext, @Prop option: LithoTagOptionsItem): Component { + val titleColor = sAppTheme.get(ThemeColorType.SECONDARY_TEXT) + val selectedColor = when (sAppTheme.isNightTheme()) { + true -> context.getColor(R.color.material_blue_400) + false -> context.getColor(R.color.material_blue_700) + } + + val icon: Int + val bgColor: Int + val bgAlpha: Int + val textColor: Int + val typeface: Typeface + when (option.isSelected) { + true -> { + icon = R.drawable.ic_action_label + bgColor = selectedColor + bgAlpha = 200 + textColor = selectedColor + typeface = sAppTypeface.subHeading() + } + false -> { + icon = R.drawable.ic_action_label_unselected + bgColor = titleColor + bgAlpha = 15 + textColor = titleColor + typeface = sAppTypeface.title() + } + } + + val row = Row.create(context) + .widthPercent(100f) + .alignItems(YogaAlign.CENTER) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .paddingDip(YogaEdge.VERTICAL, 12f) + .child( + RoundIcon.create(context) + .iconRes(icon) + .bgColor(bgColor) + .iconColor(titleColor) + .iconSizeRes(R.dimen.toolbar_round_icon_size) + .iconPaddingRes(R.dimen.toolbar_round_icon_padding) + .bgAlpha(bgAlpha) + .onClick { } + .isClickDisabled(true) + .marginDip(YogaEdge.END, 16f)) + .child( + Text.create(context) + .flexGrow(1f) + .text(option.tag.title) + .textSizeRes(R.dimen.font_size_normal) + .typeface(typeface) + .textStyle(Typeface.BOLD) + .textColor(textColor)) + + if (option.usages > 0) { + row.child( + Text.create(context) + .text("${option.usages}") + .textSizeRes(R.dimen.font_size_normal) + .textColor(titleColor) + .marginDip(YogaEdge.HORIZONTAL, 8f)) + } + + if (option.isEditable) { + row.child(RoundIcon.create(context) + .iconRes(R.drawable.ic_edit_white_48dp) + .bgColor(titleColor) + .bgAlpha(15) + .iconAlpha(0.9f) + .iconColor(titleColor) + .iconSizeRes(R.dimen.toolbar_round_icon_size) + .iconPaddingRes(R.dimen.toolbar_round_icon_padding) + .onClick { option.editListener() } + .isClickDisabled(false) + .marginDip(YogaEdge.START, 12f)) + } + + row.clickHandler(OptionItemLayout.onItemClick(context)) + return row.build() + } + + @OnEvent(ClickEvent::class) + fun onItemClick(context: ComponentContext, @Prop option: LithoTagOptionsItem) { + option.listener() + } +} + +class HomeOptionsBottomSheet : LithoBottomSheet() { + + override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { + val activity = context as MainActivity + val options = getOptions() + val component = Column.create(componentContext) + .widthPercent(100f) + .child( + Column.create(componentContext) + .paddingDip(YogaEdge.TOP, 20f) + .paddingDip(YogaEdge.BOTTOM, 20f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .child( + Row.create(componentContext) + .child(OptionLabelItemLayout.create(componentContext).option(options[0]).onClick { options[0].listener() }) + .child(OptionLabelItemLayout.create(componentContext).option(options[1]).onClick { options[1].listener() }) + .child(OptionLabelItemLayout.create(componentContext).option(options[2]).onClick { options[2].listener() }) + ) + .child( + Row.create(componentContext) + .child(OptionLabelItemLayout.create(componentContext).option(options[3]).onClick { options[3].listener() }) + .child(OptionLabelItemLayout.create(componentContext).option(options[4]).onClick { options[4].listener() }) + .child(OptionLabelItemLayout.create(componentContext).option(options[5]).onClick { options[5].listener() }) + )) + + val tagsComponent = Column.create(componentContext) + .paddingDip(YogaEdge.TOP, 8f) + .paddingDip(YogaEdge.BOTTOM, 20f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .backgroundRes(R.color.dark_hint_text) + .child( + getLithoBottomSheetTitle(componentContext) + .textRes(R.string.tag_sheet_choose_tag) + .marginDip(YogaEdge.BOTTOM, 12f)) + getTagOptions().forEach { + tagsComponent.child(TagItemLayout.create(componentContext).option(it)) + } + + val addTag = LithoOptionsItem( + title = R.string.tag_sheet_new_tag_button, + subtitle = 0, + icon = R.drawable.icon_add_note, + listener = { CreateOrEditTagBottomSheet.openSheet(activity, TagBuilder().emptyTag()) { _, _ -> reset(activity, dialog) } }) + tagsComponent.child(OptionItemLayout.create(componentContext).option(addTag).onClick { addTag.listener() }) + + component.child(tagsComponent) + return component.build() + } + + override fun bottomMargin(): Float = 0f + + private fun getOptions(): List { + val activity = context as MainActivity + val options = ArrayList() + options.add(LithoLabelOptionsItem( + title = R.string.nav_home, + icon = R.drawable.ic_home_white_48dp, + listener = { + activity.onModeChange(HomeNavigationMode.DEFAULT) + dismiss() + } + )) + options.add(LithoLabelOptionsItem( + title = R.string.nav_favourites, + icon = R.drawable.ic_favorite_white_48dp, + listener = { + activity.onModeChange(HomeNavigationMode.FAVOURITE) + dismiss() + } + )) + options.add(LithoLabelOptionsItem( + title = R.string.nav_archived, + icon = R.drawable.ic_archive_white_48dp, + listener = { + activity.onModeChange(HomeNavigationMode.ARCHIVED) + dismiss() + } + )) + options.add(LithoLabelOptionsItem( + title = R.string.nav_locked, + icon = R.drawable.ic_action_lock, + listener = { + activity.onModeChange(HomeNavigationMode.LOCKED) + dismiss() + } + )) + options.add(LithoLabelOptionsItem( + title = R.string.nav_trash, + icon = R.drawable.ic_delete_white_48dp, + listener = { + activity.onModeChange(HomeNavigationMode.TRASH) + dismiss() + } + )) + options.add(LithoLabelOptionsItem( + title = R.string.nav_settings, + icon = R.drawable.ic_action_settings, + listener = { + SettingsOptionsBottomSheet.openSheet(activity) + dismiss() + } + )) + return options + } + + private fun getTagOptions(): List { + val activity = context as MainActivity + val options = ArrayList() + for (tag in CoreConfig.tagsDb.getAll()) { + options.add(LithoTagOptionsItem( + tag = tag, + usages = CoreConfig.notesDb.getNoteCountByTag(tag.uuid), + listener = { + activity.openTag(tag) + dismiss() + }, + isEditable = true, + isSelected = false, + editListener = { + CreateOrEditTagBottomSheet.openSheet(activity, tag) { _, _ -> + reset(activity, dialog) + } + } + )) + } + options.sortByDescending { it.usages } + return options + } +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/main/sheets/InstallProUpsellBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/main/sheets/InstallProUpsellBottomSheet.kt index 3d3f4c0f..b84ae1b2 100644 --- a/base/src/main/java/com/maubis/scarlet/base/main/sheets/InstallProUpsellBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/main/sheets/InstallProUpsellBottomSheet.kt @@ -8,41 +8,58 @@ import com.facebook.litho.widget.Text import com.facebook.yoga.YogaEdge import com.github.bijoysingh.starter.util.IntentUtils import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig -import com.maubis.scarlet.base.config.CoreConfig.Companion.FONT_MONSERRAT +import com.maubis.scarlet.base.config.ApplicationBase +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme import com.maubis.scarlet.base.support.sheets.LithoBottomSheet import com.maubis.scarlet.base.support.sheets.getLithoBottomSheetTitle import com.maubis.scarlet.base.support.specs.BottomSheetBar +import com.maubis.scarlet.base.support.specs.GridSectionItem +import com.maubis.scarlet.base.support.specs.GridSectionOptionItem +import com.maubis.scarlet.base.support.specs.GridSectionView import com.maubis.scarlet.base.support.ui.ThemeColorType -import com.maubis.scarlet.base.support.ui.ThemedActivity class InstallProUpsellBottomSheet : LithoBottomSheet() { override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { - val activity = context as ThemedActivity + val options = listOf( + GridSectionOptionItem(R.drawable.ic_whats_new, R.string.install_pro_sheet_latest_updates, {}), + GridSectionOptionItem(R.drawable.ic_action_lock, R.string.install_pro_sheet_app_lock, {}), + GridSectionOptionItem(R.drawable.ic_action_day_mode, R.string.install_pro_sheet_app_themes, + {}), + GridSectionOptionItem(R.drawable.ic_title_white_48dp, R.string.install_pro_sheet_font_size, {}), + GridSectionOptionItem(R.drawable.ic_note_white_48dp, R.string.install_pro_sheet_note_options, {}), + GridSectionOptionItem(R.drawable.ic_action_color, R.string.install_pro_sheet_viewer_bg, {}), + GridSectionOptionItem(R.drawable.icon_typeface, R.string.home_option_typeface, {}), + GridSectionOptionItem(R.drawable.icon_widget, R.string.install_pro_sheet_widget_options, {})) + val component = Column.create(componentContext) - .widthPercent(100f) - .paddingDip(YogaEdge.VERTICAL, 8f) - .paddingDip(YogaEdge.HORIZONTAL, 20f) - .child(getLithoBottomSheetTitle(componentContext) - .textRes(R.string.available_in_pro_only) - .marginDip(YogaEdge.HORIZONTAL, 0f)) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_large) - .marginDip(YogaEdge.BOTTOM, 4f) - .textRes(R.string.why_install_pro) - .typeface(FONT_MONSERRAT) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.SECTION_HEADER))) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_large) - .marginDip(YogaEdge.BOTTOM, 16f) - .textRes(R.string.why_install_pro_details) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.TERTIARY_TEXT))) - .child(BottomSheetBar.create(componentContext) - .primaryActionRes(R.string.install_pro_app) - .onPrimaryClick { - IntentUtils.openAppPlayStore(activity, "com.bijoysingh.quicknote.pro") - dismiss() - }.paddingDip(YogaEdge.VERTICAL, 8f)) + .widthPercent(100f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .child( + getLithoBottomSheetTitle(componentContext) + .textRes(R.string.available_in_pro_only) + .marginDip(YogaEdge.HORIZONTAL, 0f)) + .child( + Text.create(componentContext) + .textSizeRes(R.dimen.font_size_large) + .marginDip(YogaEdge.BOTTOM, 16f) + .textRes(R.string.why_install_pro) + .typeface(ApplicationBase.sAppTypeface.title()) + .textColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT))) + .child( + GridSectionView.create(componentContext) + .maxLines(3) + .numColumns(2) + .iconSizeRes(R.dimen.primary_round_icon_size) + .section(GridSectionItem(options = options)) + .showSeparator(false)) + .child(BottomSheetBar.create(componentContext) + .primaryActionRes(R.string.install_pro_app) + .onPrimaryClick { + IntentUtils.openAppPlayStore(activity, "com.bijoysingh.quicknote.pro") + dismiss() + } + .paddingDip(YogaEdge.VERTICAL, 8f)) return component.build() } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/main/sheets/NoPincodeBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/main/sheets/NoPincodeBottomSheet.kt deleted file mode 100644 index 0a0d34c1..00000000 --- a/base/src/main/java/com/maubis/scarlet/base/main/sheets/NoPincodeBottomSheet.kt +++ /dev/null @@ -1,63 +0,0 @@ -package com.maubis.scarlet.base.main.sheets - -import android.app.Dialog -import com.facebook.litho.Column -import com.facebook.litho.Component -import com.facebook.litho.ComponentContext -import com.facebook.litho.widget.Text -import com.facebook.yoga.YogaEdge -import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig -import com.maubis.scarlet.base.support.sheets.LithoBottomSheet -import com.maubis.scarlet.base.support.sheets.getLithoBottomSheetTitle -import com.maubis.scarlet.base.support.specs.BottomSheetBar -import com.maubis.scarlet.base.support.ui.ThemeColorType -import com.maubis.scarlet.base.support.ui.ThemedActivity - - -const val STORE_KEY_NO_PIN_ASK = "KEY_NO_PIN_ASK" -var sNoPinSetupNoticeShown: Boolean - get() = CoreConfig.instance.store().get(STORE_KEY_NO_PIN_ASK, false) - set(value) = CoreConfig.instance.store().put(STORE_KEY_NO_PIN_ASK, value) - -class NoPincodeBottomSheet : LithoBottomSheet() { - var onSuccess: () -> Unit = {} - - override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { - val activity = context as ThemedActivity - val component = Column.create(componentContext) - .widthPercent(100f) - .paddingDip(YogaEdge.VERTICAL, 8f) - .paddingDip(YogaEdge.HORIZONTAL, 20f) - .child(getLithoBottomSheetTitle(componentContext) - .textRes(R.string.no_pincode_sheet_title) - .marginDip(YogaEdge.HORIZONTAL, 0f)) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_large) - .textRes(R.string.no_pincode_sheet_details) - .marginDip(YogaEdge.BOTTOM, 16f) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.TERTIARY_TEXT))) - .child(BottomSheetBar.create(componentContext) - .primaryActionRes(R.string.no_pincode_sheet_set_up) - .onPrimaryClick { - EnterPincodeBottomSheet.openCreateSheet(activity, object : EnterPincodeBottomSheet.PincodeSuccessOnlyListener { - override fun onSuccess() { - // Ignore this - } - }) - dismiss() - } - .secondaryActionRes(R.string.no_pincode_sheet_dont_ask) - .onSecondaryClick { - onSuccess() - dismiss() - } - .tertiaryActionRes(R.string.no_pincode_sheet_not_now) - .onTertiaryClick { - onSuccess() - dismiss() - } - .paddingDip(YogaEdge.VERTICAL, 8f)) - return component.build() - } -} diff --git a/base/src/main/java/com/maubis/scarlet/base/main/sheets/WhatsNewBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/main/sheets/WhatsNewBottomSheet.kt index 0d3c5c82..a999df3c 100644 --- a/base/src/main/java/com/maubis/scarlet/base/main/sheets/WhatsNewBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/main/sheets/WhatsNewBottomSheet.kt @@ -1,95 +1,69 @@ package com.maubis.scarlet.base.main.sheets import android.app.Dialog -import android.content.Intent -import android.net.Uri import com.facebook.litho.Column import com.facebook.litho.Component import com.facebook.litho.ComponentContext import com.facebook.litho.widget.Text import com.facebook.yoga.YogaEdge -import com.maubis.markdown.Markdown import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig -import com.maubis.scarlet.base.config.CoreConfig.Companion.FONT_MONSERRAT +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface import com.maubis.scarlet.base.support.sheets.LithoBottomSheet import com.maubis.scarlet.base.support.sheets.getLithoBottomSheetTitle import com.maubis.scarlet.base.support.specs.BottomSheetBar +import com.maubis.scarlet.base.support.specs.GridSectionItem +import com.maubis.scarlet.base.support.specs.GridSectionOptionItem +import com.maubis.scarlet.base.support.specs.GridSectionView import com.maubis.scarlet.base.support.ui.ThemeColorType +import com.maubis.scarlet.base.support.utils.FlavorUtils +import com.maubis.scarlet.base.support.utils.OsVersionUtils + +const val WHATS_NEW_SHEET_INDEX = 11 class WhatsNewBottomSheet : LithoBottomSheet() { override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { + val options = listOf( + if (FlavorUtils.isOpenSource()) null else GridSectionOptionItem(R.drawable.gdrive_icon, R.string.whats_new_sheet_google_drive, {}), + GridSectionOptionItem(R.drawable.icon_share_image, R.string.whats_new_sheet_photo_share, {}), + GridSectionOptionItem(R.drawable.ic_action_color, R.string.whats_new_sheet_note_color, {}), + GridSectionOptionItem(R.drawable.icon_typeface, R.string.whats_new_sheet_choose_fonts, {}), + GridSectionOptionItem(R.drawable.icon_languages, R.string.whats_new_sheet_more_languages, {}), + if (!OsVersionUtils.canAddLauncherShortcuts()) null else GridSectionOptionItem( + R.drawable.icon_shortcut, R.string.whats_new_sheet_launcher_shortcuts, {}), + GridSectionOptionItem(R.drawable.ic_option_fingerprint, R.string.whats_new_sheet_biometric_improvements, {}), + GridSectionOptionItem(R.drawable.ic_markdown_logo, R.string.whats_new_sheet_markdown_improvements, {}), + GridSectionOptionItem(R.drawable.icon_widget, R.string.whats_new_sheet_ui_improvements, {})) + val component = Column.create(componentContext) - .widthPercent(100f) - .paddingDip(YogaEdge.VERTICAL, 8f) - .paddingDip(YogaEdge.HORIZONTAL, 20f) - .child(getLithoBottomSheetTitle(componentContext) - .textRes(R.string.whats_new_title) - .marginDip(YogaEdge.HORIZONTAL, 0f)) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_large) - .marginDip(YogaEdge.BOTTOM, 16f) - .text(WHATS_NEW_DETAILS_SUBTITLE) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.TERTIARY_TEXT))) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_xlarge) - .marginDip(YogaEdge.BOTTOM, 4f) - .text(WHATS_NEW_DETAILS_NEW_FEATURES_TITLE) - .typeface(FONT_MONSERRAT) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.SECTION_HEADER))) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_large) - .marginDip(YogaEdge.BOTTOM, 16f) - .text(Markdown.render(WHATS_NEW_DETAILS_NEW_FEATURES_MD, true)) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.TERTIARY_TEXT))) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_xlarge) - .marginDip(YogaEdge.BOTTOM, 4f) - .text(WHATS_NEW_DETAILS_LAST_RELEASE_TITLE) - .typeface(FONT_MONSERRAT) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.SECTION_HEADER))) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_large) - .marginDip(YogaEdge.BOTTOM, 16f) - .text(Markdown.render(WHATS_NEW_DETAILS_LAST_RELEASE_MD, true)) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.TERTIARY_TEXT))) - .child(BottomSheetBar.create(componentContext) - .primaryActionRes(R.string.import_export_layout_exporting_done) - .onPrimaryClick { - dismiss() - } - .onSecondaryClick { - val url = GOOGLE_TRANSLATE_URL + "en/" + Uri.encode(WHATS_NEW_DETAILS_NEW_FEATURES_MD) - startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url))) - dismiss() - } - .secondaryActionRes(R.string.whats_new_translate) - .paddingDip(YogaEdge.VERTICAL, 8f)) + .widthPercent(100f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .child( + getLithoBottomSheetTitle(componentContext) + .textRes(R.string.whats_new_title) + .marginDip(YogaEdge.HORIZONTAL, 0f)) + .child( + Text.create(componentContext) + .textSizeRes(R.dimen.font_size_large) + .marginDip(YogaEdge.BOTTOM, 16f) + .textRes(R.string.whats_new_sheet_subtitle) + .typeface(sAppTypeface.title()) + .textColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT))) + .child( + GridSectionView.create(componentContext) + .maxLines(3) + .numColumns(2) + .iconSizeRes(R.dimen.ultra_large_round_icon_size) + .section(GridSectionItem(options = options.filterNotNull())) + .showSeparator(false)) + .child(BottomSheetBar.create(componentContext) + .primaryActionRes(R.string.import_export_layout_exporting_done) + .onPrimaryClick { + dismiss() + } + .paddingDip(YogaEdge.VERTICAL, 8f)) return component.build() } - - companion object { - val WHATS_NEW_UID = 9 - val GOOGLE_TRANSLATE_URL = "https://translate.google.com/#auto/" - - val WHATS_NEW_DETAILS_SUBTITLE = "A lot has changed in this update, here is a summary of those changes." - val WHATS_NEW_DETAILS_NEW_FEATURES_TITLE = "New Features" - val WHATS_NEW_DETAILS_LAST_RELEASE_TITLE = "Last Release" - val WHATS_NEW_DETAILS_NEW_FEATURES_MD = - "- **All New UI:** New Note and Settings UI. Cleaner, faster and built for easy use.\n\n" + - "- **Easier Editor:** Easier and faster ways to get markdown, and section options.\n\n" + - "- **Realtime Markdown:** When you type in markdown you get real time conversion and formatting.\n\n" + - "- **More Editor Options:** Head over to settings to get more control on the editor experience.\n\n" + - "- **More Themes:** Pro Users get more themes for the app, and the default dark theme is even darker now.\n\n" + - "- **Folder Sync:** Sync all your notes to an external folder live along with images.\n\n" + - "- **Widget Options:** Widgets now show formatted text! You can also configure what notes to see in the widget.\n\n" + - "Even more little things which help you enjoy using this app everyday" - val WHATS_NEW_DETAILS_LAST_RELEASE_MD = - "- **New UI and Icon:** New Search and Top Actionbar UI and icon\n\n" + - "- **Widgets:** Added a new list of notes widget. Also fixed widget not updating bug.\n\n" + - "- **Reminder:** Improved reminders to be more reliable." - - - } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/main/specs/MainActivityBottomBarSpec.kt b/base/src/main/java/com/maubis/scarlet/base/main/specs/MainActivityBottomBarSpec.kt index 4f51b36f..a37defb4 100644 --- a/base/src/main/java/com/maubis/scarlet/base/main/specs/MainActivityBottomBarSpec.kt +++ b/base/src/main/java/com/maubis/scarlet/base/main/specs/MainActivityBottomBarSpec.kt @@ -1,30 +1,44 @@ package com.maubis.scarlet.base.main.specs +import android.content.pm.ShortcutInfo import android.graphics.Color +import android.graphics.drawable.Icon import android.text.Layout +import com.facebook.litho.ClickEvent +import com.facebook.litho.Column import com.facebook.litho.Component import com.facebook.litho.ComponentContext +import com.facebook.litho.LongClickEvent import com.facebook.litho.Row import com.facebook.litho.annotations.LayoutSpec import com.facebook.litho.annotations.OnCreateLayout +import com.facebook.litho.annotations.OnEvent import com.facebook.litho.annotations.Prop +import com.facebook.litho.widget.Image +import com.facebook.litho.widget.Progress import com.facebook.litho.widget.Text import com.facebook.yoga.YogaAlign import com.facebook.yoga.YogaEdge import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig.Companion.FONT_MONSERRAT +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface import com.maubis.scarlet.base.core.folder.FolderBuilder import com.maubis.scarlet.base.database.room.folder.Folder -import com.maubis.scarlet.base.main.sheets.HomeNavigationBottomSheet +import com.maubis.scarlet.base.main.sheets.HomeOptionsBottomSheet import com.maubis.scarlet.base.note.creation.activity.CreateNoteActivity +import com.maubis.scarlet.base.note.creation.activity.NoteIntentRouterActivity +import com.maubis.scarlet.base.note.creation.sheet.sNoteDefaultColor import com.maubis.scarlet.base.note.folder.sheet.CreateOrEditFolderBottomSheet -import com.maubis.scarlet.base.settings.sheet.sNoteDefaultColor +import com.maubis.scarlet.base.support.addShortcut +import com.maubis.scarlet.base.support.sheets.openSheet import com.maubis.scarlet.base.support.specs.EmptySpec import com.maubis.scarlet.base.support.specs.ToolbarColorConfig import com.maubis.scarlet.base.support.specs.bottomBarCard import com.maubis.scarlet.base.support.specs.bottomBarRoundIcon import com.maubis.scarlet.base.support.ui.ColorUtil +import com.maubis.scarlet.base.support.ui.ThemeColorType +import com.maubis.scarlet.base.support.utils.OsVersionUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @@ -32,45 +46,60 @@ import kotlinx.coroutines.launch @LayoutSpec object MainActivityBottomBarSpec { @OnCreateLayout - fun onCreate(context: ComponentContext, - @Prop colorConfig: ToolbarColorConfig): Component { + fun onCreate( + context: ComponentContext, + @Prop colorConfig: ToolbarColorConfig): Component { val activity = context.androidContext as MainActivity val row = Row.create(context) - .widthPercent(100f) - .alignItems(YogaAlign.CENTER) - .paddingDip(YogaEdge.HORIZONTAL, 4f) + .widthPercent(100f) + .alignItems(YogaAlign.CENTER) + .paddingDip(YogaEdge.HORIZONTAL, 4f) row.child(bottomBarRoundIcon(context, colorConfig) - .bgColor(Color.TRANSPARENT) - .iconRes(R.drawable.ic_apps_white_48dp) - .onClick { - HomeNavigationBottomSheet.openSheet(activity) - }) + .bgColor(Color.TRANSPARENT) + .iconRes(R.drawable.ic_apps_white_48dp) + .onClick { + openSheet(activity, HomeOptionsBottomSheet()) + }) row.child(EmptySpec.create(context).heightDip(1f).flexGrow(1f)) row.child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.icon_add_notebook) - .onClick { - CreateOrEditFolderBottomSheet.openSheet( - activity, - FolderBuilder().emptyFolder(sNoteDefaultColor), - { _, _ -> activity.setupData() }) - }) + .iconRes(R.drawable.icon_add_notebook) + .onClick { + CreateOrEditFolderBottomSheet.openSheet( + activity, + FolderBuilder().emptyFolder(sNoteDefaultColor), + { _, _ -> activity.loadData() }) + }) row.child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.icon_add_list) - .onClick { - val intent = CreateNoteActivity.getNewChecklistNoteIntent( - activity, - activity.config.folders.firstOrNull()?.uuid ?: "") - activity.startActivity(intent) - }) + .iconRes(R.drawable.icon_add_list) + .onClick { + val intent = CreateNoteActivity.getNewChecklistNoteIntent( + activity, + activity.state.currentFolder?.uuid ?: "") + activity.startActivity(intent) + }) row.child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.icon_add_note) - .onClick { - val intent = CreateNoteActivity.getNewNoteIntent( - activity, - activity.config.folders.firstOrNull()?.uuid ?: "") - activity.startActivity(intent) - }) + .iconRes(R.drawable.icon_add_note) + .isLongClickEnabled(true) + .onLongClick { + if (!OsVersionUtils.canAddLauncherShortcuts()) { + return@onLongClick + } + + val shortcut = ShortcutInfo.Builder(activity, "scarlet_notes___create_note") + .setShortLabel(activity.getString(R.string.shortcut_add_note)) + .setLongLabel(activity.getString(R.string.shortcut_add_note)) + .setIcon(Icon.createWithResource(activity, R.mipmap.create_launcher)) + .setIntent(NoteIntentRouterActivity.create()) + .build() + addShortcut(activity, shortcut) + } + .onClick { + val intent = CreateNoteActivity.getNewNoteIntent( + activity, + activity.state.currentFolder?.uuid ?: "") + activity.startActivity(intent) + }) return bottomBarCard(context, row.build(), colorConfig).build() } } @@ -80,44 +109,153 @@ object MainActivityFolderBottomBarSpec { @OnCreateLayout fun onCreate(context: ComponentContext, @Prop folder: Folder): Component { val colorConfig = ToolbarColorConfig( - toolbarBackgroundColor = folder.color, - toolbarIconColor = when (ColorUtil.isLightColored(folder.color)) { - true -> context.getColor(R.color.dark_tertiary_text) - false -> context.getColor(R.color.light_secondary_text) - } + toolbarBackgroundColor = folder.color, + toolbarIconColor = when (ColorUtil.isLightColored(folder.color)) { + true -> context.getColor(R.color.dark_tertiary_text) + false -> context.getColor(R.color.light_secondary_text) + } ) val activity = context.androidContext as MainActivity val row = Row.create(context) - .widthPercent(100f) - .alignItems(YogaAlign.CENTER) - .paddingDip(YogaEdge.HORIZONTAL, 4f) + .widthPercent(100f) + .alignItems(YogaAlign.CENTER) + .paddingDip(YogaEdge.HORIZONTAL, 4f) row.child(bottomBarRoundIcon(context, colorConfig) - .bgColor(Color.TRANSPARENT) - .iconRes(R.drawable.ic_close_white_48dp) - .onClick { - GlobalScope.launch { - activity.config.folders.clear() - activity.unifiedSearch() - GlobalScope.launch(Dispatchers.Main) { - activity.notifyFolderChange() - } - } - }) - row.child(Text.create(context) - .typeface(FONT_MONSERRAT) + .bgColor(Color.TRANSPARENT) + .iconRes(R.drawable.ic_close_white_48dp) + .onClick { activity.onFolderChange(null) }) + row.child( + Text.create(context) + .typeface(sAppTypeface.title()) .textAlignment(Layout.Alignment.ALIGN_CENTER) .flexGrow(1f) .text(folder.title) .textSizeRes(R.dimen.font_size_normal) - .textColor(colorConfig.toolbarIconColor)) + .textColor(colorConfig.toolbarIconColor) + .clickHandler(MainActivityFolderBottomBar.onClickEvent(context))) + row.child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_more_options) + .isClickDisabled(true) + .clickHandler(MainActivityFolderBottomBar.onClickEvent(context)) + .onClick {}) + return bottomBarCard(context, row.build(), colorConfig).build() + } + + @OnEvent(ClickEvent::class) + fun onClickEvent(context: ComponentContext, @Prop folder: Folder) { + val activity = context.androidContext as MainActivity + if (activity.state.currentFolder != null) { + CreateOrEditFolderBottomSheet.openSheet(activity, folder) { _, _ -> activity.loadData() } + } + } +} + +@LayoutSpec +object MainActivityDisabledSyncSpec { + @OnCreateLayout + fun onCreate(context: ComponentContext): Component { + val colorConfig = ToolbarColorConfig( + toolbarBackgroundColor = context.getColor(R.color.material_blue_grey_800), + toolbarIconColor = context.getColor(R.color.light_secondary_text) + ) + val row = Row.create(context) + .widthPercent(100f) + .alignItems(YogaAlign.CENTER) + .paddingDip(YogaEdge.HORIZONTAL, 4f) row.child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_more_options) - .onClick { - if (activity.config.folders.isEmpty()) { - return@onClick - } - CreateOrEditFolderBottomSheet.openSheet(activity, folder, { _, _ -> activity.setupData() }) - }) + .bgColor(Color.TRANSPARENT) + .iconRes(R.drawable.ic_info) + .onClick { + GlobalScope.launch { + + } + }) + row.child( + Column.create(context) + .flexGrow(1f) + .paddingDip(YogaEdge.ALL, 8f) + .child( + Text.create(context) + .typeface(sAppTypeface.subHeading()) + .textRes(R.string.firebase_no_sync_warning) + .textSizeRes(R.dimen.font_size_normal) + .textColor(colorConfig.toolbarIconColor)) + .child( + Text.create(context) + .typeface(sAppTypeface.title()) + .textRes(R.string.firebase_no_sync_warning_details) + .textSizeRes(R.dimen.font_size_small) + .textColor(colorConfig.toolbarIconColor))) + row.clickHandler(MainActivityDisabledSync.onClickEvent(context)) return bottomBarCard(context, row.build(), colorConfig).build() } + + @OnEvent(ClickEvent::class) + fun onClickEvent(context: ComponentContext, @Prop onClick: () -> Unit) { + onClick() + } +} + +@LayoutSpec +object MainActivitySyncingNowSpec { + @OnCreateLayout + fun onCreate(context: ComponentContext, @Prop isSyncHappening: Boolean): Component { + val colorConfig = ToolbarColorConfig( + toolbarBackgroundColor = sAppTheme.get(ThemeColorType.TOOLBAR_BACKGROUND), + toolbarIconColor = sAppTheme.get(ThemeColorType.TOOLBAR_ICON) + ) + val syncText = when (isSyncHappening) { + true -> R.string.home_syncing_top_layout + false -> R.string.home_pending_backup_top_layout + } + val syncIcon = when (isSyncHappening) { + true -> Progress.create(context) + .widthDip(24f) + .alpha(0.8f) + .marginDip(YogaEdge.END, 8f) + .color(colorConfig.toolbarIconColor) + false -> Image.create(context) + .heightDip(24f) + .widthDip(24f) + .marginDip(YogaEdge.END, 8f) + .alpha(0.8f) + .drawableRes(R.drawable.icon_folder_sync) + } + + val row = Row.create(context) + .widthPercent(100f) + .alignItems(YogaAlign.CENTER) + .paddingDip(YogaEdge.HORIZONTAL, 8f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .alpha(0.8f) + .child(EmptySpec.create(context).flexGrow(1f)) + .child( + Row.create(context) + .alignItems(YogaAlign.CENTER) + .alignContent(YogaAlign.CENTER) + .paddingDip(YogaEdge.VERTICAL, 8f) + .paddingDip(YogaEdge.HORIZONTAL, 12f) + .backgroundRes(R.drawable.pending_sync_capsule) + .clickHandler(MainActivitySyncingNow.onClickEvent(context)) + .longClickHandler(MainActivitySyncingNow.onLongClickEvent(context)) + .child(syncIcon) + .child( + Text.create(context) + .typeface(sAppTypeface.title()) + .textRes(syncText) + .textSizeRes(R.dimen.font_size_normal) + .textColorRes(R.color.light_secondary_text))) + return row.build() + } + + @OnEvent(ClickEvent::class) + fun onClickEvent(context: ComponentContext, @Prop onClick: () -> Unit) { + onClick() + } + + @OnEvent(LongClickEvent::class) + fun onLongClickEvent(context: ComponentContext, @Prop onLongClick: () -> Unit): Boolean { + onLongClick() + return true + } } diff --git a/base/src/main/java/com/maubis/scarlet/base/main/utils/MainSnackbar.kt b/base/src/main/java/com/maubis/scarlet/base/main/utils/MainSnackbar.kt index dd72dd54..27143d35 100644 --- a/base/src/main/java/com/maubis/scarlet/base/main/utils/MainSnackbar.kt +++ b/base/src/main/java/com/maubis/scarlet/base/main/utils/MainSnackbar.kt @@ -7,10 +7,10 @@ import android.view.View.VISIBLE import android.widget.LinearLayout import android.widget.TextView import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.database.room.note.Note import com.maubis.scarlet.base.core.note.NoteBuilder import com.maubis.scarlet.base.core.note.NoteState import com.maubis.scarlet.base.core.note.getNoteState +import com.maubis.scarlet.base.database.room.note.Note import com.maubis.scarlet.base.note.save class MainSnackbar(val layout: LinearLayout, val alwaysRunnable: () -> Unit) { diff --git a/base/src/main/java/com/maubis/scarlet/base/note/MarkdownExtensions.kt b/base/src/main/java/com/maubis/scarlet/base/note/MarkdownExtensions.kt index 5789689b..f35140bf 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/MarkdownExtensions.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/MarkdownExtensions.kt @@ -1,32 +1,79 @@ package com.maubis.scarlet.base.note -import com.maubis.markdown.segmenter.MarkdownSegment import com.maubis.markdown.segmenter.MarkdownSegmentType +import com.maubis.markdown.segmenter.TextSegmenter import com.maubis.scarlet.base.core.format.Format import com.maubis.scarlet.base.core.format.FormatType -fun MarkdownSegment.toFormat(): Format { - return Format(type().toFormatType(), strip()) +fun String.toInternalFormats(): List { + return toInternalFormats( + arrayOf( + MarkdownSegmentType.HEADING_1, + MarkdownSegmentType.HEADING_2, + MarkdownSegmentType.HEADING_3, + MarkdownSegmentType.BULLET_1, + MarkdownSegmentType.BULLET_2, + MarkdownSegmentType.BULLET_3, + MarkdownSegmentType.CODE, + MarkdownSegmentType.QUOTE, + MarkdownSegmentType.CHECKLIST_UNCHECKED, + MarkdownSegmentType.CHECKLIST_CHECKED, + MarkdownSegmentType.SEPARATOR, + MarkdownSegmentType.IMAGE)) } -fun MarkdownSegment.toRawFormat(): Format { - return Format(type().toFormatType(), text()) -} +/** + * Converts a string to the internal format types using the Markdown Segmentation Library. + * It's possible to pass specific formats which will be preserved in the formats + */ +fun String.toInternalFormats(whitelistedSegments: Array): List { + val extractedFormats = emptyList().toMutableList() + val segments = TextSegmenter(this).get() + + var lastFormat: Format? = null + segments.forEach { segment -> + val isSegmentWhitelisted = whitelistedSegments.contains(segment.type()) + val newFormat = when { + !isSegmentWhitelisted -> null + segment.type() == MarkdownSegmentType.HEADING_1 -> Format(FormatType.HEADING, segment.strip()) + segment.type() == MarkdownSegmentType.HEADING_2 -> Format(FormatType.SUB_HEADING, segment.strip()) + segment.type() == MarkdownSegmentType.HEADING_3 -> Format(FormatType.HEADING_3, segment.strip()) + segment.type() == MarkdownSegmentType.BULLET_1 -> Format(FormatType.BULLET_1, segment.strip()) + segment.type() == MarkdownSegmentType.BULLET_2 -> Format(FormatType.BULLET_2, segment.strip()) + segment.type() == MarkdownSegmentType.BULLET_3 -> Format(FormatType.BULLET_3, segment.strip()) + segment.type() == MarkdownSegmentType.CODE -> Format(FormatType.CODE, segment.strip()) + segment.type() == MarkdownSegmentType.QUOTE -> Format(FormatType.QUOTE, segment.strip()) + segment.type() == MarkdownSegmentType.CHECKLIST_UNCHECKED -> Format(FormatType.CHECKLIST_UNCHECKED, segment.strip()) + segment.type() == MarkdownSegmentType.CHECKLIST_CHECKED -> Format(FormatType.CHECKLIST_CHECKED, segment.strip()) + segment.type() == MarkdownSegmentType.SEPARATOR -> Format(FormatType.SEPARATOR) + segment.type() == MarkdownSegmentType.IMAGE -> Format(FormatType.IMAGE, segment.strip().trim()) + else -> null + } + + val tempLastFormat = lastFormat + when { + tempLastFormat !== null && newFormat !== null -> { + extractedFormats.add(tempLastFormat) + extractedFormats.add(newFormat) + lastFormat = null + } + tempLastFormat === null && newFormat !== null -> { + extractedFormats.add(newFormat) + } + tempLastFormat !== null && newFormat === null -> { + tempLastFormat.text += "\n" + tempLastFormat.text += segment.text() + lastFormat = tempLastFormat + } + tempLastFormat == null && newFormat === null -> { + lastFormat = Format(FormatType.TEXT, segment.text()) + } + } + } -fun MarkdownSegmentType.toFormatType(): FormatType { - return when (this) { - MarkdownSegmentType.INVALID -> FormatType.EMPTY - MarkdownSegmentType.HEADING_1 -> FormatType.HEADING - MarkdownSegmentType.HEADING_2 -> FormatType.SUB_HEADING - MarkdownSegmentType.HEADING_3 -> FormatType.HEADING_3 - MarkdownSegmentType.NORMAL -> FormatType.TEXT - MarkdownSegmentType.CODE -> FormatType.CODE - MarkdownSegmentType.BULLET_1 -> FormatType.TEXT - MarkdownSegmentType.BULLET_2 -> FormatType.TEXT - MarkdownSegmentType.BULLET_3 -> FormatType.TEXT - MarkdownSegmentType.QUOTE -> FormatType.QUOTE - MarkdownSegmentType.SEPARATOR -> FormatType.SEPARATOR - MarkdownSegmentType.CHECKLIST_UNCHECKED -> FormatType.CHECKLIST_UNCHECKED - MarkdownSegmentType.CHECKLIST_CHECKED -> FormatType.CHECKLIST_CHECKED + val tempLastFormat = lastFormat + if (tempLastFormat !== null) { + extractedFormats.add(tempLastFormat) } + return extractedFormats } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/note/NoteExtensions.kt b/base/src/main/java/com/maubis/scarlet/base/note/NoteExtensions.kt index f5ca2348..19eb49e2 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/NoteExtensions.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/NoteExtensions.kt @@ -1,12 +1,15 @@ package com.maubis.scarlet.base.note import android.content.Context -import android.content.Intent -import android.util.Log -import com.github.bijoysingh.starter.util.DateFormatter import com.google.gson.Gson import com.maubis.markdown.Markdown -import com.maubis.markdown.segmenter.TextSegmenter +import com.maubis.markdown.MarkdownConfig +import com.maubis.markdown.spannable.MarkdownType +import com.maubis.markdown.spannable.bold +import com.maubis.markdown.spannable.font +import com.maubis.markdown.spannable.relativeSize +import com.maubis.markdown.spannable.strike +import com.maubis.scarlet.base.config.ApplicationBase import com.maubis.scarlet.base.config.CoreConfig import com.maubis.scarlet.base.config.CoreConfig.Companion.tagsDb import com.maubis.scarlet.base.core.format.Format @@ -15,41 +18,32 @@ import com.maubis.scarlet.base.core.note.NoteState import com.maubis.scarlet.base.core.note.generateUUID import com.maubis.scarlet.base.core.note.getFormats import com.maubis.scarlet.base.core.note.getTagUUIDs +import com.maubis.scarlet.base.core.note.isUnsaved import com.maubis.scarlet.base.database.room.note.Note import com.maubis.scarlet.base.database.room.tag.Tag -import com.maubis.scarlet.base.main.sheets.EnterPincodeBottomSheet -import com.maubis.scarlet.base.note.creation.activity.CreateNoteActivity -import com.maubis.scarlet.base.note.creation.activity.INTENT_KEY_DISTRACTION_FREE -import com.maubis.scarlet.base.note.creation.activity.INTENT_KEY_NOTE_ID -import com.maubis.scarlet.base.note.creation.activity.ViewAdvancedNoteActivity -import com.maubis.scarlet.base.settings.sheet.sNoteDefaultColor +import com.maubis.scarlet.base.note.creation.activity.NoteIntentRouterActivity +import com.maubis.scarlet.base.note.creation.sheet.sNoteDefaultColor +import com.maubis.scarlet.base.security.controller.PinLockController.needsLockCheck +import com.maubis.scarlet.base.security.sheets.openUnlockSheet +import com.maubis.scarlet.base.settings.sheet.sInternalShowUUID +import com.maubis.scarlet.base.settings.sheet.sSecurityAppLockEnabled +import com.maubis.scarlet.base.settings.sheet.sUIMarkdownEnabledOnHome +import com.maubis.scarlet.base.support.BitmapHelper +import com.maubis.scarlet.base.support.ui.ColorUtil import com.maubis.scarlet.base.support.ui.ThemedActivity -import com.maubis.scarlet.base.support.utils.removeMarkdownHeaders +import com.maubis.scarlet.base.support.ui.sThemeDarkenNoteColor +import com.maubis.scarlet.base.support.utils.sDateFormat import java.util.* import kotlin.collections.ArrayList -fun Note.log(context: Context): String { - val log = HashMap() - log["note"] = this - log["_title"] = getTitle() - log["_text"] = getText() - log["_image"] = getImageFile() - log["_locked"] = getLockedText(false) - log["_fullText"] = getFullText() - log["_displayTime"] = getDisplayTime() - log["_tag"] = getTagString() - log["_formats"] = getFormats() - return Gson().toJson(log) -} - fun Note.log(): String { val log = HashMap() log["note"] = this - log["_title"] = getTitle() - log["_text"] = getText() + log["_text"] = getFullText() log["_image"] = getImageFile() log["_fullText"] = getFullText() log["_displayTime"] = getDisplayTime() + log["_tag"] = getTagString() log["_formats"] = getFormats() return Gson().toJson(log) } @@ -57,20 +51,69 @@ fun Note.log(): String { /************************************************************************************** ************* Content and Display Information Functions Functions ******************** **************************************************************************************/ -fun Note.getTitle(): String { + +fun Note.getFullTextForDirectMarkdownRender(): String { + var text = getFullText() + text = text.replace("\n[x] ", "\n\u2611 ") + text = text.replace("\n[ ] ", "\n\u2610 ") + text = text.replace("\n- ", "\n\u2022 ") + return text +} + +fun Note.getMarkdownForListView(): CharSequence { + var text = getFullTextForDirectMarkdownRender() + if (sUIMarkdownEnabledOnHome) { + return markdownFormatForList(text) + } + return text +} + +internal fun markdownFormatForList(text: String): CharSequence { + return Markdown.renderWithCustomFormatting(text, true) { spannable, spanInfo -> + val s = spanInfo.start + val e = spanInfo.end + when (spanInfo.markdownType) { + MarkdownType.HEADING_1 -> { + spannable.relativeSize(1.2f, s, e) + .font(MarkdownConfig.config.spanConfig.headingTypeface, s, e) + .bold(s, e) + true + } + MarkdownType.HEADING_2 -> { + spannable.relativeSize(1.1f, s, e) + .font(MarkdownConfig.config.spanConfig.headingTypeface, s, e) + .bold(s, e) + true + } + MarkdownType.HEADING_3 -> { + spannable.relativeSize(1.0f, s, e) + .font(MarkdownConfig.config.spanConfig.headingTypeface, s, e) + .bold(s, e) + true + } + MarkdownType.CHECKLIST_CHECKED -> { + spannable.strike(s, e) + true + } + else -> false + } + } +} + +fun Note.getTitleForSharing(): String { val formats = getFormats() if (formats.isEmpty()) { return "" } val format = formats.first() + val headingFormats = listOf(FormatType.HEADING, FormatType.SUB_HEADING, FormatType.HEADING_3) return when { - format.formatType === FormatType.HEADING -> format.text - format.formatType === FormatType.SUB_HEADING -> format.text + headingFormats.contains(format.formatType) -> format.text else -> "" } } -fun Note.getText(): String { +fun Note.getTextForSharing(): String { val formats = getFormats().toMutableList() if (formats.isEmpty()) { return "" @@ -89,7 +132,12 @@ fun Note.getText(): String { stringBuilder.append("\n") } } - return stringBuilder.toString().trim() + + val text = stringBuilder.toString().trim() + if (sInternalShowUUID) { + return "`$uuid`\n\n$text" + } + return text } fun Note.getSmartFormats(): List { @@ -98,7 +146,7 @@ fun Note.getSmartFormats(): List { val smartFormats = ArrayList() formats.forEach { if (it.formatType == FormatType.TEXT) { - val moreFormats = TextSegmenter(it.text).get().map { it.toFormat() } + val moreFormats = it.text.toInternalFormats() moreFormats.forEach { format -> format.uid = maxIndex smartFormats.add(format) @@ -117,45 +165,24 @@ fun Note.getImageFile(): String { return format?.text ?: "" } -fun Note.getMarkdownTitle(isMarkdownEnabled: Boolean): CharSequence { - val titleString = getTitle() - return when { - titleString.isBlank() -> "" - !isMarkdownEnabled -> Markdown.render(removeMarkdownHeaders(titleString), true) - else -> titleString - } -} - -fun Note.getMarkdownText(isMarkdownEnabled: Boolean): CharSequence { - return when { - isMarkdownEnabled -> Markdown.render(removeMarkdownHeaders(getText()), true) - else -> getText() - } -} - fun Note.getFullText(): String { - val formats = getFormats() - return formats.map { it -> it.markdownText }.joinToString(separator = "\n").trim() -} - -fun Note.getAlphabets(): String { - val formats = getFormats() - return formats.map { it -> it.markdownText }.joinToString(separator = "\n").trim().filter { - ((it in 'a'..'z') || (it in 'A'..'Z')) + val fullText = getFormats().map { it -> it.markdownText }.joinToString(separator = "\n").trim() + if (sInternalShowUUID) { + return "`$uuid`\n$fullText" } + return fullText } -fun Note.getUnreliablyStrippedText(context: Context): String { - val builder = StringBuilder() - builder.append(Markdown.render(removeMarkdownHeaders(getTitle())), true) - builder.append(Markdown.render(removeMarkdownHeaders(getText())), true) - return builder.toString().trim { it <= ' ' } +fun Note.isNoteLockedButAppUnlocked(): Boolean { + return this.locked && !needsLockCheck() && sSecurityAppLockEnabled } -fun Note.getLockedText(isMarkdownEnabled: Boolean): CharSequence { +fun Note.getLockedAwareTextForHomeList(): CharSequence { + val lockedText = "******************\n***********\n****************" return when { - this.locked -> "******************\n***********\n****************" - else -> getMarkdownText(isMarkdownEnabled) + isNoteLockedButAppUnlocked() || !this.locked -> getMarkdownForListView() + !sUIMarkdownEnabledOnHome -> "${getTitleForSharing()}\n$lockedText" + else -> markdownFormatForList("# ${getTitleForSharing()}\n\n```\n$lockedText\n```") } } @@ -170,12 +197,12 @@ fun Note.getDisplayTime(): String { Calendar.getInstance().timeInMillis - time < 1000 * 60 * 60 * 2 -> "hh:mm aa" else -> "dd MMMM" } - return DateFormatter.getDate(format, time) + return sDateFormat.readableTime(format, time) } fun Note.getTagString(): String { val tags = getTags() - return tags.map { it -> '`' + it.title + '`' }.joinToString(separator = " ") + return tags.map { it -> "` ${it.title} `" }.joinToString(separator = " ") } fun Note.getTags(): Set { @@ -216,6 +243,13 @@ fun Note.removeTag(tag: Tag) { this.tags = tags.joinToString(separator = ",") } +fun Note.adjustedColor(): Int { + return when (sThemeDarkenNoteColor) { + true -> ColorUtil.darkOrDarkerColor(color ?: sNoteDefaultColor) + false -> color ?: sNoteDefaultColor + } +} + /************************************************************************************** ******************************* Note Action Functions ******************************** **************************************************************************************/ @@ -229,47 +263,40 @@ fun Note.mark(context: Context, noteState: NoteState) { fun Note.edit(context: Context) { if (this.locked) { if (context is ThemedActivity) { - EnterPincodeBottomSheet.openUnlockSheet(context, object : EnterPincodeBottomSheet.PincodeSuccessListener { - override fun onFailure() { - edit(context) - } - - override fun onSuccess() { - openEdit(context) - } - }) + openUnlockSheet( + activity = context, + onUnlockSuccess = { context.startActivity(NoteIntentRouterActivity.edit(context, this)) }, + onUnlockFailure = { edit(context) }) } return } - openEdit(context) -} - -fun Note.view(context: Context) { - val intent = Intent(context, ViewAdvancedNoteActivity::class.java) - intent.putExtra(INTENT_KEY_NOTE_ID, this.uid) - context.startActivity(intent) + context.startActivity(NoteIntentRouterActivity.edit(context, this)) } -fun Note.viewDistractionFree(context: Context) { - val intent = Intent(context, ViewAdvancedNoteActivity::class.java) - intent.putExtra(INTENT_KEY_NOTE_ID, this.uid) - intent.putExtra(INTENT_KEY_DISTRACTION_FREE, true) - context.startActivity(intent) +fun Note.share(context: Context) { + ApplicationBase.instance.noteActions(this).share(context) } -fun Note.openEdit(context: Context) { - val intent = Intent(context, CreateNoteActivity::class.java) - intent.putExtra(INTENT_KEY_NOTE_ID, this.uid) - context.startActivity(intent) +fun Note.hasImages(): Boolean { + val imageFormats = getFormats().filter { it.formatType == FormatType.IMAGE } + return imageFormats.isNotEmpty() } - -fun Note.share(context: Context) { - CoreConfig.instance.noteActions(this).share(context) +fun Note.shareImages(context: Context) { + val imageFormats = getFormats().filter { it.formatType == FormatType.IMAGE } + val bitmaps = imageFormats + .map { ApplicationBase.sAppImageStorage.getFile(uuid, it.text) } + .filter { it.exists() } + .map { BitmapHelper.loadFromFile(it) } + .filterNotNull() + when { + bitmaps.size == 1 -> BitmapHelper.send(context, bitmaps.first()) + bitmaps.size > 1 -> BitmapHelper.send(context, bitmaps) + } } fun Note.copy(context: Context) { - CoreConfig.instance.noteActions(this).copy(context) + ApplicationBase.instance.noteActions(this).copy(context) } /************************************************************************************** @@ -292,15 +319,23 @@ fun Note.save(context: Context) { saveWithoutSync(context) return } - CoreConfig.instance.noteActions(this).save(context) + ApplicationBase.instance.noteActions(this).save(context) +} + +fun Note.unsafeSave_INTERNAL_USE_ONLY() { + applySanityChecks() + + val id = CoreConfig.notesDb.database().insertNote(this) + uid = if (isUnsaved()) id.toInt() else uid + CoreConfig.notesDb.notifyInsertNote(this) } fun Note.saveWithoutSync(context: Context) { - CoreConfig.instance.noteActions(this).offlineSave(context) + ApplicationBase.instance.noteActions(this).offlineSave(context) } fun Note.saveToSync(context: Context) { - CoreConfig.instance.noteActions(this).onlineSave(context) + ApplicationBase.instance.noteActions(this).onlineSave(context) } fun Note.delete(context: Context) { @@ -308,17 +343,17 @@ fun Note.delete(context: Context) { deleteWithoutSync(context) return } - CoreConfig.instance.noteActions(this).delete(context) + ApplicationBase.instance.noteActions(this).delete(context) } fun Note.deleteWithoutSync(context: Context) { - CoreConfig.instance.noteActions(this).offlineDelete(context) + ApplicationBase.instance.noteActions(this).offlineDelete(context) } fun Note.deleteToSync(context: Context) { - CoreConfig.instance.noteActions(this).onlineDelete(context) + ApplicationBase.instance.noteActions(this).onlineDelete(context) } fun Note.softDelete(context: Context) { - CoreConfig.instance.noteActions(this).softDelete(context) + ApplicationBase.instance.noteActions(this).softDelete(context) } diff --git a/base/src/main/java/com/maubis/scarlet/base/note/actions/NoteOptionsBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/note/actions/NoteOptionsBottomSheet.kt index f6549acc..0fc534da 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/actions/NoteOptionsBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/actions/NoteOptionsBottomSheet.kt @@ -2,37 +2,54 @@ package com.maubis.scarlet.base.note.actions import android.app.Dialog import android.content.Intent -import android.support.v4.content.ContextCompat +import android.content.pm.ShortcutInfo +import android.graphics.drawable.Icon import android.view.View import android.widget.GridLayout +import android.widget.LinearLayout +import android.widget.LinearLayout.VERTICAL import android.widget.TextView +import androidx.core.content.ContextCompat import com.github.bijoysingh.starter.util.RandomHelper import com.maubis.markdown.Markdown import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface import com.maubis.scarlet.base.core.note.NoteBuilder import com.maubis.scarlet.base.core.note.NoteState import com.maubis.scarlet.base.core.note.getNoteState import com.maubis.scarlet.base.database.room.note.Note -import com.maubis.scarlet.base.main.sheets.EnterPincodeBottomSheet import com.maubis.scarlet.base.main.sheets.InstallProUpsellBottomSheet import com.maubis.scarlet.base.main.sheets.openDeleteNotePermanentlySheet -import com.maubis.scarlet.base.note.* import com.maubis.scarlet.base.note.activity.INoteOptionSheetActivity -import com.maubis.scarlet.base.note.folder.sheet.FolderChooseOptionsBottomSheet +import com.maubis.scarlet.base.note.copy +import com.maubis.scarlet.base.note.creation.activity.NoteIntentRouterActivity +import com.maubis.scarlet.base.note.edit +import com.maubis.scarlet.base.note.folder.sheet.FolderChooserBottomSheet +import com.maubis.scarlet.base.note.getFullText +import com.maubis.scarlet.base.note.getTagString +import com.maubis.scarlet.base.note.getTitleForSharing +import com.maubis.scarlet.base.note.hasImages import com.maubis.scarlet.base.note.reminders.sheet.ReminderBottomSheet +import com.maubis.scarlet.base.note.save import com.maubis.scarlet.base.note.selection.activity.KEY_SELECT_EXTRA_MODE import com.maubis.scarlet.base.note.selection.activity.KEY_SELECT_EXTRA_NOTE_ID import com.maubis.scarlet.base.note.selection.activity.SelectNotesActivity -import com.maubis.scarlet.base.note.tag.sheet.TagChooseOptionsBottomSheet +import com.maubis.scarlet.base.note.share +import com.maubis.scarlet.base.note.shareImages +import com.maubis.scarlet.base.note.tag.sheet.TagChooserBottomSheet import com.maubis.scarlet.base.notification.NotificationConfig import com.maubis.scarlet.base.notification.NotificationHandler +import com.maubis.scarlet.base.security.sheets.openUnlockSheet import com.maubis.scarlet.base.settings.sheet.ColorPickerBottomSheet import com.maubis.scarlet.base.settings.sheet.ColorPickerDefaultController +import com.maubis.scarlet.base.support.addShortcut import com.maubis.scarlet.base.support.option.OptionsItem import com.maubis.scarlet.base.support.sheets.GridBottomSheetBase +import com.maubis.scarlet.base.support.sheets.openSheet import com.maubis.scarlet.base.support.ui.ThemedActivity -import com.maubis.scarlet.base.support.utils.Flavor +import com.maubis.scarlet.base.support.utils.FlavorUtils +import com.maubis.scarlet.base.support.utils.OsVersionUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.async @@ -57,14 +74,14 @@ class NoteOptionsBottomSheet() : GridBottomSheetBase() { private fun setupGrid(dialog: Dialog, note: Note) { val gridLayoutIds = arrayOf( - R.id.quick_actions_properties, - R.id.note_properties, - R.id.grid_layout) + R.id.quick_actions_properties, + R.id.note_properties, + R.id.grid_layout) val gridOptionFunctions = arrayOf( - { noteForAction: Note -> getQuickActions(noteForAction) }, - { noteForAction: Note -> getNotePropertyOptions(noteForAction) }, - { noteForAction: Note -> getOptions(noteForAction) }) + { noteForAction: Note -> getQuickActions(noteForAction) }, + { noteForAction: Note -> getNotePropertyOptions(noteForAction) }, + { noteForAction: Note -> getOptions(noteForAction) }) gridOptionFunctions.forEachIndexed { index, function -> GlobalScope.launch(Dispatchers.Main) { val items = GlobalScope.async(Dispatchers.IO) { function(note) } @@ -75,31 +92,51 @@ class NoteOptionsBottomSheet() : GridBottomSheetBase() { private fun setupCardViews(note: Note) { val activity = context as ThemedActivity - if (activity !is INoteOptionSheetActivity) { + val dlg = dialog + if (activity !is INoteOptionSheetActivity || dlg === null) { return } - val tagCardLayout = dialog.findViewById(R.id.tag_card_layout) + val groupCardLayout = dlg.findViewById(R.id.group_card_layout) + val tagCardLayout = dlg.findViewById(R.id.tag_card_layout) + val selectCardLayout = dlg.findViewById(R.id.select_notes_layout) + + val selectCardTitle = dlg.findViewById(R.id.select_notes_title) + selectCardTitle.typeface = sAppTypeface.title() + val selectCardSubtitle = dlg.findViewById(R.id.select_notes_subtitle) + selectCardSubtitle.typeface = sAppTypeface.title() + val tags = tagCardLayout.findViewById(R.id.tags_content) - val tagsTitle = tagCardLayout.findViewById(R.id.tags_title) + tags.typeface = sAppTypeface.title() + val tagSubtitle = tagCardLayout.findViewById(R.id.tags_subtitle) + tagSubtitle.typeface = sAppTypeface.title() + val tagContent = note.getTagString() if (tagContent.isNotBlank()) { GlobalScope.launch(Dispatchers.Main) { val text = GlobalScope.async(Dispatchers.IO) { Markdown.renderSegment(tagContent, true) } tags.visibility = View.VISIBLE - tagsTitle.visibility = View.GONE + tagSubtitle.visibility = View.GONE tags.text = text.await() + + groupCardLayout.orientation = VERTICAL + + val params = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) + val margin = activity.resources.getDimension(R.dimen.spacing_xxsmall).toInt() + params.setMargins(margin, margin, margin, margin) + tagCardLayout.layoutParams = params + + selectCardLayout.layoutParams = params } } tagCardLayout.setOnClickListener { - TagChooseOptionsBottomSheet.openSheet( - activity, - note - ) { activity.notifyTagsChanged(note) } + openSheet(activity, TagChooserBottomSheet().apply { + this.note = note + dismissListener = { activity.notifyTagsChanged(note) } + }) dismiss() } - val selectCardLayout = dialog.findViewById(R.id.select_notes_layout) selectCardLayout.setOnClickListener { val intent = Intent(context, SelectNotesActivity::class.java) intent.putExtra(KEY_SELECT_EXTRA_MODE, activity.getSelectMode(note)) @@ -117,7 +154,8 @@ class NoteOptionsBottomSheet() : GridBottomSheetBase() { } val options = ArrayList() - options.add(OptionsItem( + options.add( + OptionsItem( title = R.string.restore_note, subtitle = R.string.tap_for_action_not_trash, icon = R.drawable.ic_restore, @@ -126,17 +164,18 @@ class NoteOptionsBottomSheet() : GridBottomSheetBase() { dismiss() }, visible = note.getNoteState() == NoteState.TRASH - )) + )) options.add(OptionsItem( - title = R.string.edit_note, - subtitle = R.string.tap_for_action_edit, - icon = R.drawable.ic_edit_white_48dp, - listener = View.OnClickListener { - note.edit(activity) - dismiss() - } + title = R.string.edit_note, + subtitle = R.string.tap_for_action_edit, + icon = R.drawable.ic_edit_white_48dp, + listener = View.OnClickListener { + note.edit(activity) + dismiss() + } )) - options.add(OptionsItem( + options.add( + OptionsItem( title = R.string.not_favourite_note, subtitle = R.string.tap_for_action_not_favourite, icon = R.drawable.ic_favorite_white_48dp, @@ -145,8 +184,9 @@ class NoteOptionsBottomSheet() : GridBottomSheetBase() { dismiss() }, visible = note.getNoteState() == NoteState.FAVOURITE - )) - options.add(OptionsItem( + )) + options.add( + OptionsItem( title = R.string.favourite_note, subtitle = R.string.tap_for_action_favourite, icon = R.drawable.ic_favorite_border_white_48dp, @@ -155,8 +195,9 @@ class NoteOptionsBottomSheet() : GridBottomSheetBase() { dismiss() }, visible = note.getNoteState() != NoteState.FAVOURITE - )) - options.add(OptionsItem( + )) + options.add( + OptionsItem( title = R.string.unarchive_note, subtitle = R.string.tap_for_action_not_archive, icon = R.drawable.ic_archive_white_48dp, @@ -165,8 +206,9 @@ class NoteOptionsBottomSheet() : GridBottomSheetBase() { dismiss() }, visible = note.getNoteState() == NoteState.ARCHIVED - )) - options.add(OptionsItem( + )) + options.add( + OptionsItem( title = R.string.archive_note, subtitle = R.string.tap_for_action_archive, icon = R.drawable.ic_archive_white_48dp, @@ -175,8 +217,9 @@ class NoteOptionsBottomSheet() : GridBottomSheetBase() { dismiss() }, visible = note.getNoteState() != NoteState.ARCHIVED - )) - options.add(OptionsItem( + )) + options.add( + OptionsItem( title = R.string.send_note, subtitle = R.string.tap_for_action_share, icon = R.drawable.ic_share_white_48dp, @@ -185,8 +228,9 @@ class NoteOptionsBottomSheet() : GridBottomSheetBase() { dismiss() }, invalid = activity.lockedContentIsHidden() && note.locked - )) - options.add(OptionsItem( + )) + options.add( + OptionsItem( title = R.string.copy_note, subtitle = R.string.tap_for_action_copy, icon = R.drawable.ic_content_copy_white_48dp, @@ -195,8 +239,9 @@ class NoteOptionsBottomSheet() : GridBottomSheetBase() { dismiss() }, invalid = activity.lockedContentIsHidden() && note.locked - )) - options.add(OptionsItem( + )) + options.add( + OptionsItem( title = R.string.delete_note_permanently, subtitle = R.string.tap_for_action_delete, icon = R.drawable.ic_delete_permanently, @@ -206,8 +251,9 @@ class NoteOptionsBottomSheet() : GridBottomSheetBase() { }, visible = note.getNoteState() == NoteState.TRASH, invalid = activity.lockedContentIsHidden() && note.locked - )) - options.add(OptionsItem( + )) + options.add( + OptionsItem( title = R.string.trash_note, subtitle = R.string.tap_for_action_trash, icon = R.drawable.ic_delete_white_48dp, @@ -217,7 +263,7 @@ class NoteOptionsBottomSheet() : GridBottomSheetBase() { }, visible = note.getNoteState() != NoteState.TRASH, invalid = activity.lockedContentIsHidden() && note.locked - )) + )) return options } @@ -229,34 +275,40 @@ class NoteOptionsBottomSheet() : GridBottomSheetBase() { val options = ArrayList() options.add(OptionsItem( - title = R.string.choose_note_color, - subtitle = R.string.tap_for_action_color, - icon = R.drawable.ic_action_color, - listener = View.OnClickListener { - val config = ColorPickerDefaultController( - title = R.string.choose_note_color, - colors = listOf(activity.resources.getIntArray(R.array.bright_colors), activity.resources.getIntArray(R.array.bright_colors_accent)), - selectedColor = note.color, - onColorSelected = { color -> - note.color = color - activity.updateNote(note) - } - ) - com.maubis.scarlet.base.support.sheets.openSheet(activity, ColorPickerBottomSheet().apply { this.config = config }) - dismiss() - } + title = R.string.choose_note_color, + subtitle = R.string.tap_for_action_color, + icon = R.drawable.ic_action_color, + listener = View.OnClickListener { + val config = ColorPickerDefaultController( + title = R.string.choose_note_color, + colors = listOf( + activity.resources.getIntArray(R.array.bright_colors), activity.resources.getIntArray(R.array.bright_colors_accent)), + selectedColor = note.color, + onColorSelected = { color -> + note.color = color + activity.updateNote(note) + } + ) + com.maubis.scarlet.base.support.sheets.openSheet(activity, ColorPickerBottomSheet().apply { this.config = config }) + dismiss() + } )) options.add(OptionsItem( - title = if (note.pinned) R.string.unpin_note else R.string.pin_note, - subtitle = if (note.pinned) R.string.unpin_note else R.string.pin_note, - icon = R.drawable.ic_pin, - listener = View.OnClickListener { - note.pinned = !note.pinned - activity.updateNote(note) - dismiss() - } + title = if (note.folder.isBlank()) R.string.folder_option_add_to_notebook else R.string.folder_option_change_notebook, + subtitle = R.string.folder_option_add_to_notebook, + icon = R.drawable.ic_folder, + listener = View.OnClickListener { + com.maubis.scarlet.base.support.sheets.openSheet(activity, FolderChooserBottomSheet().apply { + this.note = note + this.dismissListener = { + activity.notifyResetOrDismiss() + } + }) + dismiss() + } )) - options.add(OptionsItem( + options.add( + OptionsItem( title = R.string.lock_note, subtitle = R.string.lock_note, icon = R.drawable.ic_action_lock, @@ -266,24 +318,24 @@ class NoteOptionsBottomSheet() : GridBottomSheetBase() { dismiss() }, visible = !note.locked - )) - options.add(OptionsItem( + )) + options.add( + OptionsItem( title = R.string.unlock_note, subtitle = R.string.unlock_note, icon = R.drawable.ic_action_unlock, listener = View.OnClickListener { - EnterPincodeBottomSheet.openUnlockSheet( - activity, - object : EnterPincodeBottomSheet.PincodeSuccessOnlyListener { - override fun onSuccess() { - note.locked = false - activity.updateNote(note) - dismiss() - } - }) + openUnlockSheet( + activity = activity, + onUnlockSuccess = { + note.locked = false + activity.updateNote(note) + dismiss() + }, + onUnlockFailure = { }) }, visible = note.locked - )) + )) return options } @@ -295,17 +347,29 @@ class NoteOptionsBottomSheet() : GridBottomSheetBase() { val options = ArrayList() options.add(OptionsItem( - title = if (note.folder.isBlank()) R.string.folder_option_add_to_notebook else R.string.folder_option_change_notebook, - subtitle = R.string.folder_option_add_to_notebook, - icon = R.drawable.ic_folder, + title = if (note.pinned) R.string.unpin_note else R.string.pin_note, + subtitle = if (note.pinned) R.string.unpin_note else R.string.pin_note, + icon = R.drawable.ic_pin, + listener = View.OnClickListener { + note.pinned = !note.pinned + activity.updateNote(note) + dismiss() + } + )) + options.add( + OptionsItem( + title = R.string.share_images, + subtitle = R.string.share_images, + icon = R.drawable.icon_share_image, listener = View.OnClickListener { - FolderChooseOptionsBottomSheet.openSheet(activity, note, { - activity.notifyResetOrDismiss() - }) + note.shareImages(activity) dismiss() - } - )) - options.add(OptionsItem( + }, + visible = note.hasImages(), + invalid = activity.lockedContentIsHidden() && note.locked + )) + options.add( + OptionsItem( title = R.string.open_in_notification, subtitle = R.string.open_in_notification, icon = R.drawable.ic_action_notification, @@ -315,8 +379,9 @@ class NoteOptionsBottomSheet() : GridBottomSheetBase() { dismiss() }, invalid = activity.lockedContentIsHidden() && note.locked - )) - options.add(OptionsItem( + )) + options.add( + OptionsItem( title = R.string.delete_note_permanently, subtitle = R.string.delete_note_permanently, icon = R.drawable.ic_delete_permanently, @@ -326,8 +391,36 @@ class NoteOptionsBottomSheet() : GridBottomSheetBase() { }, visible = note.getNoteState() !== NoteState.TRASH, invalid = activity.lockedContentIsHidden() && note.locked - )) - options.add(OptionsItem( + )) + + options.add( + OptionsItem( + title = R.string.pin_to_launcher, + subtitle = R.string.pin_to_launcher, + icon = R.drawable.icon_shortcut, + listener = View.OnClickListener { + if (!FlavorUtils.isLite() && OsVersionUtils.canAddLauncherShortcuts()) { + var title = note.getTitleForSharing() + if (title.isBlank()) { + title = note.getFullText().split("\n").firstOrNull() ?: "Note" + } + + val shortcut = ShortcutInfo.Builder(activity, "scarlet_notes___${note.uuid}") + .setShortLabel(title) + .setLongLabel(title) + .setIcon(Icon.createWithResource(activity, R.mipmap.open_note_launcher)) + .setIntent(NoteIntentRouterActivity.view(note)) + .build() + addShortcut(activity, shortcut) + return@OnClickListener + } + openSheet(activity, InstallProUpsellBottomSheet()) + }, + visible = OsVersionUtils.canAddLauncherShortcuts(), + invalid = activity.lockedContentIsHidden() && note.locked + )) + options.add( + OptionsItem( title = R.string.reminder, subtitle = R.string.reminder, icon = R.drawable.ic_action_reminder_icon, @@ -336,8 +429,9 @@ class NoteOptionsBottomSheet() : GridBottomSheetBase() { dismiss() }, invalid = activity.lockedContentIsHidden() && note.locked - )) - options.add(OptionsItem( + )) + options.add( + OptionsItem( title = R.string.duplicate, subtitle = R.string.duplicate, icon = R.drawable.ic_duplicate, @@ -350,8 +444,9 @@ class NoteOptionsBottomSheet() : GridBottomSheetBase() { dismiss() }, invalid = activity.lockedContentIsHidden() && note.locked - )) - options.add(OptionsItem( + )) + options.add( + OptionsItem( title = R.string.voice_action_title, subtitle = R.string.voice_action_title, icon = R.drawable.ic_action_speak_aloud, @@ -360,55 +455,58 @@ class NoteOptionsBottomSheet() : GridBottomSheetBase() { dismiss() }, invalid = activity.lockedContentIsHidden() && note.locked - )) - options.add(OptionsItem( + )) + options.add( + OptionsItem( title = R.string.view_distraction_free, subtitle = R.string.view_distraction_free, icon = R.drawable.ic_action_distraction_free, listener = View.OnClickListener { - if (CoreConfig.instance.appFlavor() == Flavor.PRO) { - note.viewDistractionFree(activity) + if (!FlavorUtils.isLite()) { + activity.startActivity(NoteIntentRouterActivity.view(activity, note, isDistractionFree = true)) return@OnClickListener } - com.maubis.scarlet.base.support.sheets.openSheet(activity, InstallProUpsellBottomSheet()) + openSheet(activity, InstallProUpsellBottomSheet()) }, - visible = CoreConfig.instance.appFlavor() != Flavor.NONE, invalid = activity.lockedContentIsHidden() && note.locked - )) - options.add(OptionsItem( + )) + options.add( + OptionsItem( title = R.string.open_in_popup, subtitle = R.string.tap_for_action_popup, icon = R.drawable.ic_bubble_chart_white_48dp, listener = View.OnClickListener { - CoreConfig.instance.noteActions(note).popup(activity) + ApplicationBase.instance.noteActions(note).popup(activity) dismiss() }, invalid = activity.lockedContentIsHidden() && note.locked - )) - options.add(OptionsItem( + )) + options.add( + OptionsItem( title = R.string.backup_note_enable, subtitle = R.string.backup_note_enable, icon = R.drawable.ic_action_backup, listener = View.OnClickListener { - CoreConfig.instance.noteActions(note).enableBackup(activity) + ApplicationBase.instance.noteActions(note).enableBackup(activity) activity.updateNote(note) dismiss() }, - visible = note.disableBackup && CoreConfig.instance.appFlavor() != Flavor.NONE, + visible = note.disableBackup && FlavorUtils.isPlayStore(), invalid = activity.lockedContentIsHidden() && note.locked - )) - options.add(OptionsItem( + )) + options.add( + OptionsItem( title = R.string.backup_note_disable, subtitle = R.string.backup_note_disable, icon = R.drawable.ic_action_backup_no, listener = View.OnClickListener { - CoreConfig.instance.noteActions(note).disableBackup(activity) + ApplicationBase.instance.noteActions(note).disableBackup(activity) activity.updateNote(note) dismiss() }, - visible = !note.disableBackup && CoreConfig.instance.appFlavor() != Flavor.NONE, + visible = !note.disableBackup && FlavorUtils.isPlayStore(), invalid = activity.lockedContentIsHidden() && note.locked - )) + )) return options } diff --git a/base/src/main/java/com/maubis/scarlet/base/note/actions/TextToSpeechBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/note/actions/TextToSpeechBottomSheet.kt index 5cee9161..bbcefa44 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/actions/TextToSpeechBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/actions/TextToSpeechBottomSheet.kt @@ -1,17 +1,24 @@ package com.maubis.scarlet.base.note.actions import android.app.Dialog -import android.os.Build import android.speech.tts.TextToSpeech import android.widget.ImageView import android.widget.TextView +import com.maubis.markdown.Markdown import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme import com.maubis.scarlet.base.database.room.note.Note -import com.maubis.scarlet.base.note.getUnreliablyStrippedText +import com.maubis.scarlet.base.note.getFullText import com.maubis.scarlet.base.support.ui.ThemeColorType import com.maubis.scarlet.base.support.ui.ThemedActivity import com.maubis.scarlet.base.support.ui.ThemedBottomSheetFragment +import com.maubis.scarlet.base.support.utils.removeMarkdownHeaders + +fun Note.getTextToSpeechText(): String { + val builder = StringBuilder() + builder.append(Markdown.render(removeMarkdownHeaders(getFullText())), true) + return builder.toString().trim { it <= ' ' } +} class TextToSpeechBottomSheet : ThemedBottomSheetFragment() { @@ -26,10 +33,10 @@ class TextToSpeechBottomSheet : ThemedBottomSheetFragment() { val nonNullNote = note!! val title = dialog.findViewById(R.id.options_title) - title.setTextColor(CoreConfig.instance.themeController().get(ThemeColorType.SECONDARY_TEXT)) + title.setTextColor(sAppTheme.get(ThemeColorType.SECONDARY_TEXT)) val speakPlayPause = dialog.findViewById(R.id.speak_play_pause) - speakPlayPause.setColorFilter(CoreConfig.instance.themeController().get(ThemeColorType.TOOLBAR_ICON)) + speakPlayPause.setColorFilter(sAppTheme.get(ThemeColorType.TOOLBAR_ICON)) speakPlayPause.setOnClickListener { val tts = textToSpeech if (tts === null) { @@ -55,12 +62,8 @@ class TextToSpeechBottomSheet : ThemedBottomSheetFragment() { makeBackgroundTransparent(dialog, R.id.root_layout) } - fun speak(note: Note) { - if (Build.VERSION.SDK_INT >= 21) { - textToSpeech?.speak(note.getUnreliablyStrippedText(themedContext()), TextToSpeech.QUEUE_FLUSH, null, "NOTE") - } else { - textToSpeech?.speak(note.getUnreliablyStrippedText(themedContext()), TextToSpeech.QUEUE_FLUSH, null) - } + private fun speak(note: Note) { + textToSpeech?.speak(note.getTextToSpeechText(), TextToSpeech.QUEUE_FLUSH, null, "NOTE") } override fun getBackgroundView(): Int = R.id.container_layout diff --git a/base/src/main/java/com/maubis/scarlet/base/note/activity/INoteOptionSheetActivity.kt b/base/src/main/java/com/maubis/scarlet/base/note/activity/INoteOptionSheetActivity.kt index a231887b..648772f8 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/activity/INoteOptionSheetActivity.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/activity/INoteOptionSheetActivity.kt @@ -1,7 +1,7 @@ package com.maubis.scarlet.base.note.activity -import com.maubis.scarlet.base.database.room.note.Note import com.maubis.scarlet.base.core.note.NoteState +import com.maubis.scarlet.base.database.room.note.Note interface INoteOptionSheetActivity { fun updateNote(note: Note) diff --git a/base/src/main/java/com/maubis/scarlet/base/note/creation/activity/CreateNoteActivity.kt b/base/src/main/java/com/maubis/scarlet/base/note/creation/activity/CreateNoteActivity.kt index e0045986..aba6d134 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/creation/activity/CreateNoteActivity.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/creation/activity/CreateNoteActivity.kt @@ -4,18 +4,22 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.os.Handler -import android.support.v7.widget.RecyclerView -import android.support.v7.widget.helper.ItemTouchHelper +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView import com.facebook.litho.ComponentContext import com.facebook.litho.LithoView import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppImageStorage import com.maubis.scarlet.base.config.CoreConfig.Companion.foldersDb import com.maubis.scarlet.base.core.format.Format import com.maubis.scarlet.base.core.format.FormatBuilder import com.maubis.scarlet.base.core.format.FormatType import com.maubis.scarlet.base.core.format.MarkdownType -import com.maubis.scarlet.base.core.note.* +import com.maubis.scarlet.base.core.note.NoteBuilder import com.maubis.scarlet.base.core.note.NoteImage.Companion.deleteIfExist +import com.maubis.scarlet.base.core.note.getFormats +import com.maubis.scarlet.base.core.note.isEqual +import com.maubis.scarlet.base.core.note.isUnsaved import com.maubis.scarlet.base.database.room.note.Note import com.maubis.scarlet.base.note.creation.specs.NoteCreationBottomBar import com.maubis.scarlet.base.note.creation.specs.NoteCreationTopBar @@ -27,6 +31,7 @@ import com.maubis.scarlet.base.settings.sheet.ColorPickerBottomSheet import com.maubis.scarlet.base.settings.sheet.ColorPickerDefaultController import com.maubis.scarlet.base.support.recycler.SimpleItemTouchHelper import com.maubis.scarlet.base.support.specs.ToolbarColorConfig +import com.maubis.scarlet.base.support.utils.maybeThrow import kotlinx.android.synthetic.main.activity_advanced_note.* import pl.aprilapps.easyphotopicker.DefaultCallback import pl.aprilapps.easyphotopicker.EasyImage @@ -40,8 +45,8 @@ open class CreateNoteActivity : ViewAdvancedNoteActivity() { private var historyIndex = 0 private var historySize = 0L - - val history: MutableList = emptyList().toMutableList() + private var historyModified = false + private val history: MutableList = emptyList().toMutableList() override val editModeValue: Boolean get() = true @@ -50,7 +55,7 @@ open class CreateNoteActivity : ViewAdvancedNoteActivity() { setTouchListener() startHandler() } - + override fun onCreationFinished() { super.onCreationFinished() history.add(NoteBuilder().copy(note!!)) @@ -89,11 +94,12 @@ open class CreateNoteActivity : ViewAdvancedNoteActivity() { addDefaultItem() } !formats[0].text.startsWith("# ") && - formats[0].formatType !== FormatType.HEADING - && formats[0].formatType !== FormatType.IMAGE -> { + formats[0].formatType !== FormatType.HEADING + && formats[0].formatType !== FormatType.IMAGE -> { addEmptyItem(0, FormatType.HEADING) } } + focus(0) } protected open fun addDefaultItem() { @@ -109,19 +115,20 @@ open class CreateNoteActivity : ViewAdvancedNoteActivity() { lithoTopToolbar.removeAllViews() val componentContext = ComponentContext(this) lithoTopToolbar.addView( - LithoView.create(componentContext, - NoteCreationTopBar.create(componentContext).build())) + LithoView.create( + componentContext, + NoteCreationTopBar.create(componentContext).build())) } override fun setBottomToolbar() { val componentContext = ComponentContext(this) lithoBottomToolbar.removeAllViews() lithoBottomToolbar.addView( - LithoView.create( - componentContext, - NoteCreationBottomBar.create(componentContext) - .colorConfig(ToolbarColorConfig(colorConfig.toolbarBackgroundColor, colorConfig.toolbarIconColor)) - .build())) + LithoView.create( + componentContext, + NoteCreationBottomBar.create(componentContext) + .colorConfig(ToolbarColorConfig(colorConfig.toolbarBackgroundColor, colorConfig.toolbarIconColor)) + .build())) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { @@ -132,13 +139,13 @@ open class CreateNoteActivity : ViewAdvancedNoteActivity() { return } - val targetFile = NoteImage(context).renameOrCopy(note!!, imageFile) + val targetFile = sAppImageStorage.renameOrCopy(note!!, imageFile) val index = getFormatIndex(type) triggerImageLoaded(index, targetFile) } - override fun onImagePickerError(e: Exception, source: EasyImage.ImageSource, type: Int) { - //Some error handling + override fun onImagePickerError(exception: Exception, source: EasyImage.ImageSource, type: Int) { + maybeThrow(this@CreateNoteActivity, exception) } }) } @@ -180,7 +187,7 @@ open class CreateNoteActivity : ViewAdvancedNoteActivity() { protected fun maybeUpdateNoteWithoutSync() { val currentNote = note - if (currentNote === null) { + if (currentNote === null || !formatsInitialised.get()) { return } @@ -188,11 +195,11 @@ open class CreateNoteActivity : ViewAdvancedNoteActivity() { currentNote.description = FormatBuilder().getSmarterDescription(formats) // Ignore update if nothing changed. It allows for one undo per few seconds - if (currentNote.isEqual(vLastNoteInstance)) { - return + when { + !historyModified && currentNote.isEqual(vLastNoteInstance) -> return + !historyModified -> addNoteToHistory(NoteBuilder().copy(currentNote)) + else -> historyModified = false } - - addNoteToHistory(NoteBuilder().copy(currentNote)) currentNote.updateTimestamp = Calendar.getInstance().timeInMillis maybeSaveNote(false) } @@ -215,13 +222,13 @@ open class CreateNoteActivity : ViewAdvancedNoteActivity() { } } - private fun startHandler() { val handler = Handler() handler.postDelayed(object : Runnable { override fun run() { if (active) { maybeUpdateNoteWithoutSync() + fullScreenView() handler.postDelayed(this, HANDLER_UPDATE_TIME.toLong()) } } @@ -294,7 +301,7 @@ open class CreateNoteActivity : ViewAdvancedNoteActivity() { val formatToChange = formats[position] if (!formatToChange.text.isBlank()) { - val noteImage = NoteImage(context) + val noteImage = sAppImageStorage deleteIfExist(noteImage.getFile(note!!.uuid, formatToChange.text)) } formatToChange.text = file.name @@ -307,24 +314,26 @@ open class CreateNoteActivity : ViewAdvancedNoteActivity() { historyIndex = if (historyIndex == 0) 0 else (historyIndex - 1) note = NoteBuilder().copy(history.get(historyIndex)) setNote() + historyModified = true } false -> { val maxHistoryIndex = history.size - 1 historyIndex = if (historyIndex == maxHistoryIndex) maxHistoryIndex else (historyIndex + 1) note = NoteBuilder().copy(history.get(historyIndex)) setNote() + historyModified = true } } } fun onColorChangeClick() { val config = ColorPickerDefaultController( - title = R.string.choose_note_color, - colors = listOf(resources.getIntArray(R.array.bright_colors), resources.getIntArray(R.array.bright_colors_accent)), - selectedColor = note!!.color, - onColorSelected = { color -> - setNoteColor(color) - } + title = R.string.choose_note_color, + colors = listOf(resources.getIntArray(R.array.bright_colors), resources.getIntArray(R.array.bright_colors_accent)), + selectedColor = note!!.color, + onColorSelected = { color -> + setNoteColor(color) + } ) com.maubis.scarlet.base.support.sheets.openSheet(this, ColorPickerBottomSheet().apply { this.config = config }) } @@ -391,10 +400,6 @@ open class CreateNoteActivity : ViewAdvancedNoteActivity() { maybeUpdateNoteWithoutSync() } - override fun setFormatChecked(format: Format, checked: Boolean) { - // do nothing - } - override fun createOrChangeToNextFormat(format: Format) { val position = getFormatIndex(format) if (position == -1) { @@ -402,8 +407,8 @@ open class CreateNoteActivity : ViewAdvancedNoteActivity() { } val isCheckList = - (format.formatType === FormatType.CHECKLIST_UNCHECKED - || format.formatType === FormatType.CHECKLIST_CHECKED) + (format.formatType === FormatType.CHECKLIST_UNCHECKED + || format.formatType === FormatType.CHECKLIST_CHECKED) val newPosition = position + 1 when { isCheckList -> addEmptyItemAtFocused(FormatBuilder().getNextFormatType(FormatType.CHECKLIST_UNCHECKED)) @@ -413,19 +418,19 @@ open class CreateNoteActivity : ViewAdvancedNoteActivity() { } companion object { - private const val INTENT_KEY_FOLDER = "key_folder" + const val INTENT_KEY_FOLDER = "key_folder" fun getNewNoteIntent( - context: Context, - folder: String = ""): Intent { + context: Context, + folder: String = ""): Intent { val intent = Intent(context, CreateNoteActivity::class.java) intent.putExtra(INTENT_KEY_FOLDER, folder) return intent } fun getNewChecklistNoteIntent( - context: Context, - folder: String = ""): Intent { + context: Context, + folder: String = ""): Intent { val intent = Intent(context, CreateListNoteActivity::class.java) intent.putExtra(INTENT_KEY_FOLDER, folder) return intent diff --git a/base/src/main/java/com/maubis/scarlet/base/note/creation/activity/NoteIntentRouterActivity.kt b/base/src/main/java/com/maubis/scarlet/base/note/creation/activity/NoteIntentRouterActivity.kt new file mode 100644 index 00000000..1b680e22 --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/note/creation/activity/NoteIntentRouterActivity.kt @@ -0,0 +1,123 @@ +package com.maubis.scarlet.base.note.creation.activity + +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import com.maubis.scarlet.base.config.ApplicationBase.Companion.instance +import com.maubis.scarlet.base.database.room.note.Note +import com.maubis.scarlet.base.note.creation.sheet.sEditorSkipNoteViewer + +class NoteIntentRouterActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val data: Uri? = intent?.data + if (data === null) { + finish() + return + } + + handleOpenNote(data) + handleCreateNote(data) + } + + fun handleOpenNote(data: Uri): Boolean { + if (data.host != "open_note") { + return false + } + + val noteUUID = data.getQueryParameter("uuid") + if (noteUUID === null) { + return false + } + + val note = instance.notesDatabase().getByUUID(noteUUID) + if (note === null) { + return false + } + + val intent = when (data.getQueryParameter("is_edit", false)) { + true -> edit(this, note) + false -> view(this, note, data.getQueryParameter("is_distraction_free", false)) + } + startActivity(intent) + return true + } + + fun handleCreateNote(data: Uri): Boolean { + if (data.host != "create_note") { + return false + } + + startActivity(create(this)) + return true + } + + companion object { + + private fun Boolean.toInt(): Int { + return when (this) { + true -> 1 + else -> 0 + } + } + + private fun Uri.getQueryParameter(key: String, defaultValue: Boolean): Boolean { + val param = getQueryParameter(key) + if (param === null) { + return defaultValue + } + return param == "1" + } + + fun view(context: Context, note: Note, isDistractionFree: Boolean = false): Intent { + if (sEditorSkipNoteViewer) { + return edit(context, note) + } + + return Intent(context, ViewAdvancedNoteActivity::class.java) + .putExtra(INTENT_KEY_NOTE_ID, note.uid) + .putExtra(INTENT_KEY_DISTRACTION_FREE, isDistractionFree) + } + + fun edit(context: Context, note: Note): Intent { + return Intent(context, CreateNoteActivity::class.java) + .putExtra(INTENT_KEY_NOTE_ID, note.uid) + } + + fun create(context: Context, baseFolder: String = ""): Intent { + return Intent(context, CreateNoteActivity::class.java) + .putExtra(CreateNoteActivity.INTENT_KEY_FOLDER, baseFolder) + } + + fun view(note: Note, isDistractionFree: Boolean = false): Intent { + val uri = Uri.Builder() + .scheme("scarlet") + .authority("open_note") + .appendQueryParameter("uuid", note.uuid) + .appendQueryParameter("is_distraction_free", isDistractionFree.toInt().toString()) + .build() + return Intent(Intent.ACTION_VIEW, uri) + } + + fun edit(note: Note): Intent { + val uri = Uri.Builder() + .scheme("scarlet") + .authority("open_note") + .appendQueryParameter("uuid", note.uuid) + .appendQueryParameter("is_edit", "1") + .build() + return Intent(Intent.ACTION_VIEW, uri) + } + + fun create(): Intent { + val uri = Uri.Builder() + .scheme("scarlet") + .authority("create_note") + .build() + return Intent(Intent.ACTION_VIEW, uri) + } + } +} diff --git a/base/src/main/java/com/maubis/scarlet/base/note/creation/activity/ShareToScarletRouterActivity.kt b/base/src/main/java/com/maubis/scarlet/base/note/creation/activity/ShareToScarletRouterActivity.kt new file mode 100644 index 00000000..99e1a758 --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/note/creation/activity/ShareToScarletRouterActivity.kt @@ -0,0 +1,131 @@ +package com.maubis.scarlet.base.note.creation.activity + +import android.content.Intent +import android.graphics.BitmapFactory +import android.net.Uri +import android.os.Bundle +import android.os.Parcelable +import androidx.appcompat.app.AppCompatActivity +import com.maubis.scarlet.base.MainActivity +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppImageStorage +import com.maubis.scarlet.base.core.format.Format +import com.maubis.scarlet.base.core.format.FormatBuilder +import com.maubis.scarlet.base.core.format.FormatType +import com.maubis.scarlet.base.core.note.NoteBuilder +import com.maubis.scarlet.base.core.note.getFormats +import com.maubis.scarlet.base.database.room.note.Note +import com.maubis.scarlet.base.export.support.NoteImporter +import com.maubis.scarlet.base.main.activity.INTENT_KEY_DIRECT_NOTES_TRANSFER +import com.maubis.scarlet.base.main.activity.KEEP_PACKAGE +import com.maubis.scarlet.base.note.save +import com.maubis.scarlet.base.support.BitmapHelper +import com.maubis.scarlet.base.support.utils.OsVersionUtils +import java.io.File + +class ShareToScarletRouterActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + try { + val hasDirectIntent = handleDirectSendText(intent) + if (hasDirectIntent) { + startActivity(Intent(this, MainActivity::class.java)) + return + } + + val note = handleSendText(intent) + if (note === null) { + return + } + startActivity(ViewAdvancedNoteActivity.getIntent(this, note)) + } finally { + finish() + } + } + + private fun handleSendText(intent: Intent): Note? { + val sharedText = intent.getStringExtra(Intent.EXTRA_TEXT) ?: "" + val sharedSubject = intent.getStringExtra(Intent.EXTRA_SUBJECT) + ?: intent.getStringExtra(Intent.EXTRA_TITLE) ?: "" + val sharedImages = when { + intent.action == Intent.ACTION_SEND -> handleSendImage(intent) + intent.action == Intent.ACTION_SEND_MULTIPLE -> handleSendMultipleImages(intent) + else -> emptyList() + } + if (sharedText.isBlank() && sharedSubject.isBlank() && sharedImages.isEmpty()) { + return null + } + + val note = when (isCallerKeep()) { + true -> NoteBuilder().gen(sharedSubject, NoteBuilder().genFromKeep(sharedText)) + false -> NoteBuilder().gen(sharedSubject, sharedText) + } + note.save(this) + + val images = emptyList().toMutableList() + for (uri in sharedImages) { + try { + val inputStream = this.contentResolver.openInputStream(uri) + val bitmap = BitmapFactory.decodeStream(inputStream) + inputStream?.close() + + val temporaryImage = createTempFile() + BitmapHelper.saveToFile(temporaryImage, bitmap) + + images.add(sAppImageStorage.renameOrCopy(note, temporaryImage)) + temporaryImage.delete() + } catch (exception: Exception) { + } + } + val formats = note.getFormats().toMutableList() + for (image in images.reversed()) { + formats.add(0, Format(FormatType.IMAGE, image.name)) + } + note.description = FormatBuilder().getSmarterDescription(formats) + note.save(this) + return note + } + + private fun handleDirectSendText(intent: Intent): Boolean { + val sharedText = intent.getStringExtra(INTENT_KEY_DIRECT_NOTES_TRANSFER) + if (sharedText === null || sharedText.isBlank()) { + return false + } + NoteImporter().gen(this, sharedText) + return true + } + + private fun handleSendImage(intent: Intent): List { + val images = emptyList().toMutableList() + (intent.getParcelableExtra(Intent.EXTRA_STREAM) as? Uri)?.let { + images.add(it) + } + return images + } + + private fun handleSendMultipleImages(intent: Intent): List { + val images = emptyList().toMutableList() + intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM)?.let { + for (parcelable in it) { + if (parcelable is Uri) { + images.add(parcelable) + } + } + } + return images + } + + private fun isCallerKeep(): Boolean { + return try { + when { + OsVersionUtils.canExtractReferrer() && (referrer?.toString() + ?: "").contains(KEEP_PACKAGE) -> true + callingPackage?.contains(KEEP_PACKAGE) ?: false -> true + (intent?.`package` ?: "").contains(KEEP_PACKAGE) -> true + else -> false + } + } catch (exception: Exception) { + false + } + } +} diff --git a/base/src/main/java/com/maubis/scarlet/base/note/creation/activity/ViewNoteActivity.kt b/base/src/main/java/com/maubis/scarlet/base/note/creation/activity/ViewNoteActivity.kt index 2b803239..948c6f3f 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/creation/activity/ViewNoteActivity.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/creation/activity/ViewNoteActivity.kt @@ -1,28 +1,35 @@ package com.maubis.scarlet.base.note.creation.activity +import android.app.PendingIntent import android.content.Context import android.content.Intent import android.graphics.Color -import android.os.Build import android.os.Bundle -import android.support.v7.widget.RecyclerView import android.view.View +import androidx.recyclerview.widget.RecyclerView import com.facebook.litho.ComponentContext import com.facebook.litho.LithoView import com.github.bijoysingh.starter.recyclerview.MultiRecyclerViewControllerItem import com.github.bijoysingh.starter.recyclerview.RecyclerViewBuilder import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb import com.maubis.scarlet.base.core.format.Format import com.maubis.scarlet.base.core.format.FormatBuilder import com.maubis.scarlet.base.core.format.FormatType import com.maubis.scarlet.base.core.format.sectionPreservingSort -import com.maubis.scarlet.base.core.note.* +import com.maubis.scarlet.base.core.note.NoteBuilder +import com.maubis.scarlet.base.core.note.NoteState +import com.maubis.scarlet.base.core.note.generateUUID +import com.maubis.scarlet.base.core.note.getFormats +import com.maubis.scarlet.base.core.note.isUnsaved import com.maubis.scarlet.base.database.room.note.Note -import com.maubis.scarlet.base.note.* import com.maubis.scarlet.base.note.actions.NoteOptionsBottomSheet import com.maubis.scarlet.base.note.activity.INoteOptionSheetActivity +import com.maubis.scarlet.base.note.adjustedColor +import com.maubis.scarlet.base.note.creation.sheet.sNoteDefaultColor import com.maubis.scarlet.base.note.creation.specs.NoteViewBottomBar import com.maubis.scarlet.base.note.creation.specs.NoteViewTopBar import com.maubis.scarlet.base.note.formats.FormatAdapter @@ -30,13 +37,25 @@ import com.maubis.scarlet.base.note.formats.IFormatRecyclerViewActivity import com.maubis.scarlet.base.note.formats.getFormatControllerItems import com.maubis.scarlet.base.note.formats.recycler.KEY_EDITABLE import com.maubis.scarlet.base.note.formats.recycler.KEY_NOTE_COLOR -import com.maubis.scarlet.base.settings.sheet.* +import com.maubis.scarlet.base.note.getSmartFormats +import com.maubis.scarlet.base.note.getTagString +import com.maubis.scarlet.base.note.mark +import com.maubis.scarlet.base.note.save +import com.maubis.scarlet.base.note.saveWithoutSync +import com.maubis.scarlet.base.note.softDelete +import com.maubis.scarlet.base.settings.sheet.STORE_KEY_TEXT_SIZE import com.maubis.scarlet.base.settings.sheet.SettingsOptionsBottomSheet.Companion.KEY_MARKDOWN_ENABLED -import com.maubis.scarlet.base.settings.sheet.UISettingsOptionsBottomSheet.Companion.useNoteColorAsBackground +import com.maubis.scarlet.base.settings.sheet.sEditorTextSize +import com.maubis.scarlet.base.settings.sheet.sUIUseNoteColorAsBackground import com.maubis.scarlet.base.support.specs.ToolbarColorConfig -import com.maubis.scarlet.base.support.ui.* -import com.maubis.scarlet.base.support.ui.ColorUtil.darkerColor +import com.maubis.scarlet.base.support.ui.ColorUtil +import com.maubis.scarlet.base.support.ui.ColorUtil.darkOrDarkerColor +import com.maubis.scarlet.base.support.ui.KEY_NIGHT_THEME +import com.maubis.scarlet.base.support.ui.SecuredActivity +import com.maubis.scarlet.base.support.ui.Theme +import com.maubis.scarlet.base.support.ui.ThemeColorType import com.maubis.scarlet.base.support.utils.bind +import com.maubis.scarlet.base.widget.getPendingIntentWithStack import kotlinx.android.synthetic.main.activity_advanced_note.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope @@ -44,25 +63,25 @@ import kotlinx.coroutines.launch import java.util.* import java.util.concurrent.atomic.AtomicBoolean - const val INTENT_KEY_NOTE_ID = "NOTE_ID" const val INTENT_KEY_DISTRACTION_FREE = "DISTRACTION_FREE" - data class NoteViewColorConfig( - var backgroundColor: Int = Color.BLACK, - var toolbarBackgroundColor: Int = Color.BLACK, - var toolbarIconColor: Int = Color.BLACK, - var statusBarColor: Int = Color.BLACK) + var backgroundColor: Int = Color.BLACK, + var toolbarBackgroundColor: Int = Color.BLACK, + var toolbarIconColor: Int = Color.BLACK, + var statusBarColor: Int = Color.BLACK) -open class ViewAdvancedNoteActivity : ThemedActivity(), INoteOptionSheetActivity, IFormatRecyclerViewActivity { +open class ViewAdvancedNoteActivity : SecuredActivity(), INoteOptionSheetActivity, IFormatRecyclerViewActivity { var focusedFormat: Format? = null + protected var note: Note? = null + protected lateinit var formats: MutableList + protected val formatsInitialised = AtomicBoolean(false) protected lateinit var context: Context protected lateinit var adapter: FormatAdapter - protected lateinit var formats: MutableList protected lateinit var formatsView: RecyclerView protected var isDistractionFree: Boolean = false @@ -109,7 +128,7 @@ open class ViewAdvancedNoteActivity : ThemedActivity(), INoteOptionSheetActivity override fun onResume() { super.onResume() - CoreConfig.instance.startListener(this) + ApplicationBase.instance.startListener(this) if (!creationFinished.get()) { return @@ -133,14 +152,12 @@ open class ViewAdvancedNoteActivity : ThemedActivity(), INoteOptionSheetActivity } private fun startDistractionFreeMode() { - var uiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE - or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - or View.SYSTEM_UI_FLAG_FULLSCREEN) - if (Build.VERSION.SDK_INT >= 19) { - uiVisibility = (uiVisibility or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) - } + val uiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE + or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + or View.SYSTEM_UI_FLAG_FULLSCREEN + or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) window.decorView.systemUiVisibility = uiVisibility } @@ -148,10 +165,10 @@ open class ViewAdvancedNoteActivity : ThemedActivity(), INoteOptionSheetActivity val currentNote = note val bundle = Bundle() bundle.putBoolean(KEY_EDITABLE, editModeValue) - bundle.putBoolean(KEY_MARKDOWN_ENABLED, CoreConfig.instance.store().get(KEY_MARKDOWN_ENABLED, true)) - bundle.putBoolean(KEY_NIGHT_THEME, CoreConfig.instance.themeController().isNightTheme()) + bundle.putBoolean(KEY_MARKDOWN_ENABLED, sAppPreferences.get(KEY_MARKDOWN_ENABLED, true)) + bundle.putBoolean(KEY_NIGHT_THEME, sAppTheme.isNightTheme()) bundle.putInt(STORE_KEY_TEXT_SIZE, sEditorTextSize) - bundle.putInt(KEY_NOTE_COLOR, currentNote?.color ?: sNoteDefaultColor) + bundle.putInt(KEY_NOTE_COLOR, currentNote?.adjustedColor() ?: sNoteDefaultColor) bundle.putString(INTENT_KEY_NOTE_ID, currentNote?.uuid ?: generateUUID()) adapter.setExtra(bundle) } @@ -174,6 +191,7 @@ open class ViewAdvancedNoteActivity : ThemedActivity(), INoteOptionSheetActivity false -> currentNote.getSmartFormats() }.toMutableList() adapter.addItems(formats) + formatsInitialised.set(true) if (!editModeValue) { maybeAddTags() @@ -203,9 +221,9 @@ open class ViewAdvancedNoteActivity : ThemedActivity(), INoteOptionSheetActivity private fun setRecyclerView() { adapter = FormatAdapter(this) formatsView = RecyclerViewBuilder(this) - .setAdapter(adapter) - .setView(this, R.id.advanced_note_recycler) - .build() + .setAdapter(adapter) + .setView(this, R.id.advanced_note_recycler) + .build() } open fun setFormat(format: Format) { @@ -244,7 +262,7 @@ open class ViewAdvancedNoteActivity : ThemedActivity(), INoteOptionSheetActivity } fun openEditor() { - note!!.openEdit(context) + context.startActivity(NoteIntentRouterActivity.edit(context, note!!)) } protected open fun notifyToolbarColor() { @@ -253,24 +271,24 @@ open class ViewAdvancedNoteActivity : ThemedActivity(), INoteOptionSheetActivity return } - val theme = CoreConfig.instance.themeController() + val noteColor = currentNote.adjustedColor() when { - !useNoteColorAsBackground -> { - colorConfig.backgroundColor = theme.get(ThemeColorType.BACKGROUND) - colorConfig.toolbarIconColor = theme.get(ThemeColorType.TOOLBAR_ICON) + !sUIUseNoteColorAsBackground -> { + colorConfig.backgroundColor = sAppTheme.get(ThemeColorType.BACKGROUND) + colorConfig.toolbarIconColor = sAppTheme.get(ThemeColorType.TOOLBAR_ICON) colorConfig.statusBarColor = colorConfig.backgroundColor - colorConfig.toolbarBackgroundColor = theme.get(ThemeColorType.TOOLBAR_BACKGROUND) + colorConfig.toolbarBackgroundColor = sAppTheme.get(ThemeColorType.TOOLBAR_BACKGROUND) } - ColorUtil.isLightColored(currentNote.color) -> { - colorConfig.backgroundColor = currentNote.color - colorConfig.toolbarIconColor = theme.get(context, Theme.DARK, ThemeColorType.TOOLBAR_ICON) - colorConfig.statusBarColor = darkerColor(currentNote.color) + ColorUtil.isLightColored(noteColor) -> { + colorConfig.backgroundColor = noteColor + colorConfig.toolbarIconColor = sAppTheme.get(context, Theme.DARK, ThemeColorType.TOOLBAR_ICON) + colorConfig.statusBarColor = darkOrDarkerColor(noteColor) colorConfig.toolbarBackgroundColor = colorConfig.statusBarColor } else -> { - colorConfig.backgroundColor = currentNote.color - colorConfig.toolbarIconColor = theme.get(context, Theme.DARK, ThemeColorType.TOOLBAR_ICON) - colorConfig.statusBarColor = darkerColor(currentNote.color) + colorConfig.backgroundColor = noteColor + colorConfig.toolbarIconColor = sAppTheme.get(context, Theme.DARK, ThemeColorType.TOOLBAR_ICON) + colorConfig.statusBarColor = darkOrDarkerColor(noteColor) colorConfig.toolbarBackgroundColor = colorConfig.statusBarColor } } @@ -290,18 +308,20 @@ open class ViewAdvancedNoteActivity : ThemedActivity(), INoteOptionSheetActivity lithoBottomToolbar.removeAllViews() val componentContext = ComponentContext(this) lithoBottomToolbar.addView( - LithoView.create(componentContext, - NoteViewBottomBar.create(componentContext) - .colorConfig(ToolbarColorConfig(colorConfig.toolbarBackgroundColor, colorConfig.toolbarIconColor)) - .build())) + LithoView.create( + componentContext, + NoteViewBottomBar.create(componentContext) + .colorConfig(ToolbarColorConfig(colorConfig.toolbarBackgroundColor, colorConfig.toolbarIconColor)) + .build())) } protected open fun setTopToolbar() { lithoTopToolbar.removeAllViews() val componentContext = ComponentContext(this) lithoTopToolbar.addView( - LithoView.create(componentContext, - NoteViewTopBar.create(componentContext).build())) + LithoView.create( + componentContext, + NoteViewTopBar.create(componentContext).build())) } protected open fun setNoteColor(color: Int) { @@ -340,11 +360,8 @@ open class ViewAdvancedNoteActivity : ThemedActivity(), INoteOptionSheetActivity notifyToolbarColor() } - public override fun onSaveInstanceState(savedInstanceState: Bundle?) { + override fun onSaveInstanceState(savedInstanceState: Bundle) { super.onSaveInstanceState(savedInstanceState) - if (savedInstanceState == null) { - return - } savedInstanceState.putInt(INTENT_KEY_NOTE_ID, if (note == null || note!!.uid == null) 0 else note!!.uid) } @@ -358,6 +375,12 @@ open class ViewAdvancedNoteActivity : ThemedActivity(), INoteOptionSheetActivity intent.putExtra(INTENT_KEY_NOTE_ID, note.uid) return intent } + + fun getIntentWithStack(context: Context, note: Note): PendingIntent? { + val intent = Intent(context, ViewAdvancedNoteActivity::class.java) + intent.putExtra(INTENT_KEY_NOTE_ID, note.uid) + return getPendingIntentWithStack(context, 5000 + note.uid, intent) + } } /** @@ -396,7 +419,6 @@ open class ViewAdvancedNoteActivity : ThemedActivity(), INoteOptionSheetActivity * End : INoteOptionSheetActivity */ - /** * Start : IFormatRecyclerView Functions */ diff --git a/base/src/main/java/com/maubis/scarlet/base/note/creation/sheet/EditorOptionsBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/note/creation/sheet/EditorOptionsBottomSheet.kt index 0133a71b..5d17f82b 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/creation/sheet/EditorOptionsBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/creation/sheet/EditorOptionsBottomSheet.kt @@ -2,31 +2,42 @@ package com.maubis.scarlet.base.note.creation.sheet import android.app.Dialog import com.facebook.litho.ComponentContext +import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences +import com.maubis.scarlet.base.settings.sheet.ColorPickerBottomSheet +import com.maubis.scarlet.base.settings.sheet.ColorPickerDefaultController import com.maubis.scarlet.base.support.sheets.LithoOptionBottomSheet import com.maubis.scarlet.base.support.sheets.LithoOptionsItem - -const val STORE_KEY_EDITOR_OPTIONS_MARKDOWN_ENABLED = "KEY_MARKDOWN_ENABLED" -const val STORE_KEY_EDITOR_OPTIONS_LIVE_MARKDOWN = "editor_live_markdown" -const val STORE_KEY_EDITOR_OPTIONS_MARKDOWN_DEFAULT = "editor_markdown_default" -const val STORE_KEY_EDITOR_OPTIONS_MOVE_HANDLES = "editor_move_handles" +import com.maubis.scarlet.base.support.sheets.openSheet var sEditorLiveMarkdown: Boolean - get() = CoreConfig.instance.store().get(STORE_KEY_EDITOR_OPTIONS_LIVE_MARKDOWN, true) - set(value) = CoreConfig.instance.store().put(STORE_KEY_EDITOR_OPTIONS_LIVE_MARKDOWN, value) + get() = sAppPreferences.get("editor_live_markdown", true) + set(value) = sAppPreferences.put("editor_live_markdown", value) + +var sEditorMoveChecked: Boolean + get() = sAppPreferences.get("editor_move_checked_items", true) + set(value) = sAppPreferences.put("editor_move_checked_items", value) var sEditorMarkdownDefault: Boolean - get() = CoreConfig.instance.store().get(STORE_KEY_EDITOR_OPTIONS_MARKDOWN_DEFAULT, false) - set(value) = CoreConfig.instance.store().put(STORE_KEY_EDITOR_OPTIONS_MARKDOWN_DEFAULT, value) + get() = sAppPreferences.get("editor_markdown_default", false) + set(value) = sAppPreferences.put("editor_markdown_default", value) + +var sEditorSkipNoteViewer: Boolean + get() = sAppPreferences.get("skip_note_viewer", false) + set(value) = sAppPreferences.put("skip_note_viewer", value) var sEditorMoveHandles: Boolean - get() = CoreConfig.instance.store().get(STORE_KEY_EDITOR_OPTIONS_MOVE_HANDLES, true) - set(value) = CoreConfig.instance.store().put(STORE_KEY_EDITOR_OPTIONS_MOVE_HANDLES, value) + get() = sAppPreferences.get("editor_move_handles", true) + set(value) = sAppPreferences.put("editor_move_handles", value) var sEditorMarkdownEnabled: Boolean - get() = CoreConfig.instance.store().get(STORE_KEY_EDITOR_OPTIONS_MARKDOWN_ENABLED, true) - set(value) = CoreConfig.instance.store().put(STORE_KEY_EDITOR_OPTIONS_MARKDOWN_ENABLED, value) + get() = sAppPreferences.get("KEY_MARKDOWN_ENABLED", true) + set(value) = sAppPreferences.put("KEY_MARKDOWN_ENABLED", value) + +var sNoteDefaultColor: Int + get() = sAppPreferences.get("KEY_NOTE_DEFAULT_COLOR", (0xFFD32F2F).toInt()) + set(value) = sAppPreferences.put("KEY_NOTE_DEFAULT_COLOR", value) class EditorOptionsBottomSheet : LithoOptionBottomSheet() { @@ -34,49 +45,90 @@ class EditorOptionsBottomSheet : LithoOptionBottomSheet() { override fun getOptions(componentContext: ComponentContext, dialog: Dialog): List { val items = ArrayList() + val activity = context as MainActivity + items.add(LithoOptionsItem( + title = R.string.note_option_default_color, + subtitle = R.string.note_option_default_color_subtitle, + icon = R.drawable.ic_action_color, + listener = { + val config = ColorPickerDefaultController( + title = R.string.note_option_default_color, + colors = listOf( + activity.resources.getIntArray(R.array.bright_colors), + activity.resources.getIntArray(R.array.bright_colors_accent)), + selectedColor = sNoteDefaultColor, + onColorSelected = { sNoteDefaultColor = it } + ) + openSheet(activity, ColorPickerBottomSheet().apply { this.config = config }) + dismiss() + } + )) items.add(LithoOptionsItem( - title = R.string.markdown_sheet_markdown_support, - subtitle = R.string.markdown_sheet_markdown_support_subtitle, - icon = R.drawable.ic_markdown_logo, - selected = sEditorMarkdownEnabled, - isSelectable = true, - listener = { - sEditorMarkdownEnabled = !sEditorMarkdownEnabled - reset(componentContext.androidContext, dialog) - } + title = R.string.markdown_sheet_markdown_support, + subtitle = R.string.markdown_sheet_markdown_support_subtitle, + icon = R.drawable.ic_markdown_logo, + selected = sEditorMarkdownEnabled, + isSelectable = true, + listener = { + sEditorMarkdownEnabled = !sEditorMarkdownEnabled + reset(componentContext.androidContext, dialog) + } )) items.add(LithoOptionsItem( - title = R.string.editor_option_enable_live_markdown, - subtitle = R.string.editor_option_enable_live_markdown_description, - icon = R.drawable.icon_realtime_markdown, - selected = sEditorLiveMarkdown, - isSelectable = true, - listener = { - sEditorLiveMarkdown = !sEditorLiveMarkdown - reset(componentContext.androidContext, dialog) - } + title = R.string.editor_option_enable_live_markdown, + subtitle = R.string.editor_option_enable_live_markdown_description, + icon = R.drawable.icon_realtime_markdown, + selected = sEditorLiveMarkdown, + isSelectable = true, + listener = { + sEditorLiveMarkdown = !sEditorLiveMarkdown + reset(componentContext.androidContext, dialog) + } + )) + items.add(LithoOptionsItem( + title = R.string.editor_option_enable_markdown_mode_default, + subtitle = R.string.editor_option_enable_markdown_mode_default_details, + icon = R.drawable.ic_formats_logo, + selected = sEditorMarkdownDefault, + isSelectable = true, + listener = { + sEditorMarkdownDefault = !sEditorMarkdownDefault + reset(componentContext.androidContext, dialog) + } + )) + + items.add(LithoOptionsItem( + title = R.string.editor_option_skip_view_note, + subtitle = R.string.editor_option_skip_view_note_details, + icon = R.drawable.ic_redo_history, + selected = sEditorSkipNoteViewer, + isSelectable = true, + listener = { + sEditorSkipNoteViewer = !sEditorSkipNoteViewer + reset(componentContext.androidContext, dialog) + } )) items.add(LithoOptionsItem( - title = R.string.editor_option_enable_markdown_mode_default, - subtitle = R.string.editor_option_enable_markdown_mode_default_details, - icon = R.drawable.ic_formats_logo, - selected = sEditorMarkdownDefault, - isSelectable = true, - listener = { - sEditorMarkdownDefault = !sEditorMarkdownDefault - reset(componentContext.androidContext, dialog) - } + title = R.string.editor_option_move_checked_items, + subtitle = R.string.editor_option_move_checked_items_description, + icon = R.drawable.ic_check_box_white_24dp, + selected = sEditorMoveChecked, + isSelectable = true, + listener = { + sEditorMoveChecked = !sEditorMoveChecked + reset(componentContext.androidContext, dialog) + } )) items.add(LithoOptionsItem( - title = R.string.editor_option_enable_move_handle, - subtitle = R.string.editor_option_enable_move_handle_description, - icon = R.drawable.icon_drag_indicator, - selected = sEditorMoveHandles, - isSelectable = true, - listener = { - sEditorMoveHandles = !sEditorMoveHandles - reset(componentContext.androidContext, dialog) - } + title = R.string.editor_option_enable_move_handle, + subtitle = R.string.editor_option_enable_move_handle_description, + icon = R.drawable.icon_drag_indicator, + selected = sEditorMoveHandles, + isSelectable = true, + listener = { + sEditorMoveHandles = !sEditorMoveHandles + reset(componentContext.androidContext, dialog) + } )) return items } diff --git a/base/src/main/java/com/maubis/scarlet/base/note/creation/sheet/FormatActionBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/note/creation/sheet/FormatActionBottomSheet.kt index a2f88877..ac210e28 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/creation/sheet/FormatActionBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/creation/sheet/FormatActionBottomSheet.kt @@ -1,101 +1,92 @@ package com.maubis.scarlet.base.note.creation.sheet import android.app.Dialog -import android.view.View +import com.facebook.litho.ComponentContext import com.github.bijoysingh.starter.util.IntentUtils import com.github.bijoysingh.starter.util.TextUtils import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppImageStorage import com.maubis.scarlet.base.core.format.Format import com.maubis.scarlet.base.core.format.FormatType -import com.maubis.scarlet.base.core.note.NoteImage import com.maubis.scarlet.base.core.note.NoteImage.Companion.deleteIfExist import com.maubis.scarlet.base.note.creation.activity.ViewAdvancedNoteActivity -import com.maubis.scarlet.base.support.option.OptionsItem -import com.maubis.scarlet.base.support.sheets.GridBottomSheetBase -import com.maubis.scarlet.base.support.ui.ThemedActivity +import com.maubis.scarlet.base.support.sheets.GridOptionBottomSheet +import com.maubis.scarlet.base.support.specs.GridSectionItem +import com.maubis.scarlet.base.support.specs.GridSectionOptionItem import pl.aprilapps.easyphotopicker.EasyImage -class FormatActionBottomSheet : GridBottomSheetBase() { +class FormatActionBottomSheet : GridOptionBottomSheet() { var noteUUID: String = "default" var format: Format? = null - override fun setupViewWithDialog(dialog: Dialog) { - if (format === null) { - return - } + override fun title(): Int = R.string.format_action_title - setOptions(dialog, getOptions(noteUUID, format!!)) - setOptionTitle(dialog, R.string.format_action_title) - } + override fun getOptions(componentContext: ComponentContext, dialog: Dialog): List { + val activity = componentContext.androidContext as ViewAdvancedNoteActivity - private fun getOptions(noteUUID: String, format: Format): List { - val activity = themedActivity() as ViewAdvancedNoteActivity - val options = ArrayList() - options.add(OptionsItem( - title = R.string.import_export_layout_exporting_share, - subtitle = R.string.import_export_layout_exporting_share, + val sections = ArrayList() + val options = ArrayList() + + if (this.format === null) { + return sections + } + + val format: Format = this.format!! + options.add( + GridSectionOptionItem( + label = R.string.import_export_layout_exporting_share, icon = R.drawable.ic_share_white_48dp, - listener = View.OnClickListener { + listener = { IntentUtils.ShareBuilder(activity) - .setChooserText(activity.getString(R.string.share_using)) - .setText(format.text) - .share() + .setChooserText(activity.getString(R.string.share_using)) + .setText(format.text) + .share() dismiss() }, visible = !arrayOf(FormatType.IMAGE, FormatType.SEPARATOR).contains(format.formatType) - )) - options.add(OptionsItem( - title = R.string.format_action_copy, - subtitle = R.string.format_action_copy, + )) + options.add( + GridSectionOptionItem( + label = R.string.format_action_copy, icon = R.drawable.ic_content_copy_white_48dp, - listener = View.OnClickListener { + listener = { TextUtils.copyToClipboard(context, format.text) dismiss() }, visible = !arrayOf(FormatType.IMAGE, FormatType.SEPARATOR).contains(format.formatType) - )) - options.add(OptionsItem( - title = R.string.format_action_camera, - subtitle = R.string.format_action_camera, + )) + options.add( + GridSectionOptionItem( + label = R.string.format_action_camera, icon = R.drawable.ic_image_camera, - listener = View.OnClickListener { + listener = { EasyImage.openCamera(activity, format.uid) }, visible = format.formatType === FormatType.IMAGE - )) - options.add(OptionsItem( - title = R.string.format_action_gallery, - subtitle = R.string.format_action_gallery, + )) + options.add( + GridSectionOptionItem( + label = R.string.format_action_gallery, icon = R.drawable.ic_image_gallery, - listener = View.OnClickListener { + listener = { EasyImage.openGallery(activity, format.uid) }, visible = format.formatType === FormatType.IMAGE - )) - options.add(OptionsItem( - title = R.string.delete_sheet_delete_trash_yes, - subtitle = R.string.delete_sheet_delete_trash_yes, - icon = R.drawable.ic_delete_white_48dp, - listener = View.OnClickListener { - activity.deleteFormat(format) - if (format.formatType === FormatType.IMAGE && !format.text.isBlank()) { - val noteImage = NoteImage(themedContext()) - deleteIfExist(noteImage.getFile(noteUUID, format)) - } - dismiss() + )) + options.add(GridSectionOptionItem( + label = R.string.delete_sheet_delete_trash_yes, + icon = R.drawable.ic_delete_white_48dp, + listener = { + activity.deleteFormat(format) + if (format.formatType === FormatType.IMAGE && !format.text.isBlank()) { + deleteIfExist(sAppImageStorage.getFile(noteUUID, format)) } + dismiss() + } )) - return options - } - - companion object { - fun openSheet(activity: ThemedActivity, noteUUID: String, format: Format) { - val sheet = FormatActionBottomSheet() - sheet.format = format - sheet.noteUUID = noteUUID - sheet.show(activity.supportFragmentManager, sheet.tag) - } + sections.add(GridSectionItem(options = options)) + return sections } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/note/creation/sheet/MarkdownHelpBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/note/creation/sheet/MarkdownHelpBottomSheet.kt index 37413ed0..cae6b72c 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/creation/sheet/MarkdownHelpBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/creation/sheet/MarkdownHelpBottomSheet.kt @@ -8,7 +8,8 @@ import com.facebook.litho.widget.Text import com.facebook.yoga.YogaEdge import com.maubis.markdown.Markdown import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface import com.maubis.scarlet.base.support.sheets.LithoBottomSheet import com.maubis.scarlet.base.support.sheets.getLithoBottomSheetTitle import com.maubis.scarlet.base.support.ui.ThemeColorType @@ -16,19 +17,23 @@ import com.maubis.scarlet.base.support.ui.ThemeColorType class MarkdownHelpBottomSheet : LithoBottomSheet() { override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { val column = Column.create(componentContext) - .widthPercent(100f) - .paddingDip(YogaEdge.VERTICAL, 8f) - .child(getLithoBottomSheetTitle(componentContext).textRes(R.string.markdown_help_sheet_title)) + .widthPercent(100f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .child(getLithoBottomSheetTitle(componentContext).textRes(R.string.markdown_help_sheet_title)) - val examples = arrayOf("# Heading", "## Sub Heading", "```\nblock of code\n```", "> quoted text", "**bold**", "*italics*", "_underline_", "~~strike through~~", "`piece of code`") + val examples = arrayOf( + "# Heading", "## Sub Heading", "```\nblock of code\n```", "> quoted text", "**bold**", "*italics*", "_underline_", "~~strike through~~", + "`piece of code`") examples.forEach { column - .child(Text.create(componentContext) - .text(Markdown.render(it)) - .textSizeRes(R.dimen.font_size_normal) - .marginDip(YogaEdge.HORIZONTAL, 20f) - .paddingDip(YogaEdge.VERTICAL, 4f) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.SECONDARY_TEXT))) + .child( + Text.create(componentContext) + .typeface(sAppTypeface.text()) + .text(Markdown.render(it)) + .textSizeRes(R.dimen.font_size_normal) + .marginDip(YogaEdge.HORIZONTAL, 20f) + .paddingDip(YogaEdge.VERTICAL, 4f) + .textColor(sAppTheme.get(ThemeColorType.SECONDARY_TEXT))) } return column.build() diff --git a/base/src/main/java/com/maubis/scarlet/base/note/creation/specs/NoteViewBottomBarSpec.kt b/base/src/main/java/com/maubis/scarlet/base/note/creation/specs/NoteViewBottomBarSpec.kt index 30b09346..72db70e8 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/creation/specs/NoteViewBottomBarSpec.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/creation/specs/NoteViewBottomBarSpec.kt @@ -1,8 +1,20 @@ package com.maubis.scarlet.base.note.creation.specs import android.graphics.Color -import com.facebook.litho.* -import com.facebook.litho.annotations.* +import com.facebook.litho.ClickEvent +import com.facebook.litho.Component +import com.facebook.litho.ComponentContext +import com.facebook.litho.EventHandler +import com.facebook.litho.Row +import com.facebook.litho.StateValue +import com.facebook.litho.annotations.LayoutSpec +import com.facebook.litho.annotations.OnCreateInitialState +import com.facebook.litho.annotations.OnCreateLayout +import com.facebook.litho.annotations.OnEvent +import com.facebook.litho.annotations.OnUpdateState +import com.facebook.litho.annotations.Param +import com.facebook.litho.annotations.Prop +import com.facebook.litho.annotations.State import com.facebook.litho.widget.EmptyComponent import com.facebook.litho.widget.HorizontalScroll import com.facebook.yoga.YogaAlign @@ -35,62 +47,63 @@ object NoteCreationBottomBarSpec { @OnCreateInitialState fun onCreateInitialState( - context: ComponentContext, - state: StateValue) { + context: ComponentContext, + state: StateValue) { state.set(if (sEditorMarkdownDefault) NoteCreateBottomBarType.DEFAULT_MARKDOWNS else NoteCreateBottomBarType.DEFAULT_SEGMENTS) } @OnCreateLayout - fun onCreate(context: ComponentContext, - @Prop colorConfig: ToolbarColorConfig, - @State state: NoteCreateBottomBarType): Component { + fun onCreate( + context: ComponentContext, + @Prop colorConfig: ToolbarColorConfig, + @State state: NoteCreateBottomBarType): Component { val row = Row.create(context) - .widthPercent(100f) - .paddingDip(YogaEdge.HORIZONTAL, 4f) - .alignItems(YogaAlign.CENTER) + .widthPercent(100f) + .paddingDip(YogaEdge.HORIZONTAL, 4f) + .alignItems(YogaAlign.CENTER) val content = when (state) { NoteCreateBottomBarType.DEFAULT_SEGMENTS -> NoteCreationSegmentsBottomBar.create(context) - .colorConfig(colorConfig) - .flexGrow(1f) - .toggleButtonClick(NoteCreationBottomBar.onStateChangeClick(context, NoteCreateBottomBarType.ALL_SEGMENTS)) - NoteCreateBottomBarType.DEFAULT_MARKDOWNS -> NoteCreationMarkdownsBottomBar.create(context) .colorConfig(colorConfig) .flexGrow(1f) - .toggleButtonClick(NoteCreationBottomBar.onStateChangeClick(context, NoteCreateBottomBarType.ALL_MARKDOWNS)) + .toggleButtonClick(NoteCreationBottomBar.onStateChangeClick(context, NoteCreateBottomBarType.ALL_SEGMENTS)) + NoteCreateBottomBarType.DEFAULT_MARKDOWNS -> NoteCreationMarkdownsBottomBar.create(context) + .colorConfig(colorConfig) + .flexGrow(1f) + .toggleButtonClick(NoteCreationBottomBar.onStateChangeClick(context, NoteCreateBottomBarType.ALL_MARKDOWNS)) NoteCreateBottomBarType.ALL_SEGMENTS -> HorizontalScroll.create(context) - .flexGrow(1f) - .contentProps(NoteCreationAllSegmentsBottomBar.create(context).colorConfig(colorConfig)) + .flexGrow(1f) + .contentProps(NoteCreationAllSegmentsBottomBar.create(context).colorConfig(colorConfig)) NoteCreateBottomBarType.ALL_MARKDOWNS -> HorizontalScroll.create(context) - .flexGrow(1f) - .contentProps(NoteCreationAllMarkdownsBottomBar.create(context).colorConfig(colorConfig)) + .flexGrow(1f) + .contentProps(NoteCreationAllMarkdownsBottomBar.create(context).colorConfig(colorConfig)) NoteCreateBottomBarType.OPTIONS -> NoteCreationOptionsBottomBar.create(context) - .colorConfig(colorConfig) - .flexGrow(1f) + .colorConfig(colorConfig) + .flexGrow(1f) } row.child(content) val extraRoundIcon = bottomBarRoundIcon(context, colorConfig) - .bgColor(Color.TRANSPARENT) - .onClick { } - .isClickDisabled(true) + .bgColor(Color.TRANSPARENT) + .onClick { } + .isClickDisabled(true) val icon = when (state) { NoteCreateBottomBarType.DEFAULT_SEGMENTS -> extraRoundIcon - .iconRes(R.drawable.ic_markdown_logo) - .clickHandler(NoteCreationBottomBar.onStateChangeClick(context, NoteCreateBottomBarType.DEFAULT_MARKDOWNS)) + .iconRes(R.drawable.ic_markdown_logo) + .clickHandler(NoteCreationBottomBar.onStateChangeClick(context, NoteCreateBottomBarType.DEFAULT_MARKDOWNS)) NoteCreateBottomBarType.DEFAULT_MARKDOWNS -> extraRoundIcon - .iconRes(R.drawable.ic_formats_logo) - .clickHandler(NoteCreationBottomBar.onStateChangeClick(context, NoteCreateBottomBarType.DEFAULT_SEGMENTS)) + .iconRes(R.drawable.ic_formats_logo) + .clickHandler(NoteCreationBottomBar.onStateChangeClick(context, NoteCreateBottomBarType.DEFAULT_SEGMENTS)) NoteCreateBottomBarType.ALL_SEGMENTS -> extraRoundIcon - .marginDip(YogaEdge.HORIZONTAL, 4f) - .iconRes(R.drawable.ic_close_white_48dp) - .clickHandler(NoteCreationBottomBar.onStateChangeClick(context, NoteCreateBottomBarType.DEFAULT_SEGMENTS)) + .marginDip(YogaEdge.HORIZONTAL, 4f) + .iconRes(R.drawable.ic_close_white_48dp) + .clickHandler(NoteCreationBottomBar.onStateChangeClick(context, NoteCreateBottomBarType.DEFAULT_SEGMENTS)) NoteCreateBottomBarType.ALL_MARKDOWNS -> extraRoundIcon - .marginDip(YogaEdge.HORIZONTAL, 4f) - .iconRes(R.drawable.ic_close_white_48dp) - .clickHandler(NoteCreationBottomBar.onStateChangeClick(context, NoteCreateBottomBarType.DEFAULT_MARKDOWNS)) + .marginDip(YogaEdge.HORIZONTAL, 4f) + .iconRes(R.drawable.ic_close_white_48dp) + .clickHandler(NoteCreationBottomBar.onStateChangeClick(context, NoteCreateBottomBarType.DEFAULT_MARKDOWNS)) NoteCreateBottomBarType.OPTIONS -> EmptyComponent.create(context) } row.child(icon) @@ -98,11 +111,11 @@ object NoteCreationBottomBarSpec { val moreIcon = when (state) { NoteCreateBottomBarType.DEFAULT_MARKDOWNS, NoteCreateBottomBarType.DEFAULT_SEGMENTS, NoteCreateBottomBarType.OPTIONS -> bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_more_options) - .bgColor(Color.TRANSPARENT) - .onClick { } - .isClickDisabled(true) - .clickHandler(NoteCreationBottomBar.onStateChangeClick(context, NoteCreateBottomBarType.OPTIONS)) + .iconRes(R.drawable.ic_more_options) + .bgColor(Color.TRANSPARENT) + .onClick { } + .isClickDisabled(true) + .clickHandler(NoteCreationBottomBar.onStateChangeClick(context, NoteCreateBottomBarType.OPTIONS)) else -> EmptyComponent.create(context) } row.child(moreIcon) @@ -110,9 +123,10 @@ object NoteCreationBottomBarSpec { } @OnEvent(ClickEvent::class) - fun onStateChangeClick(context: ComponentContext, - @State state: NoteCreateBottomBarType, - @Param nextState: NoteCreateBottomBarType) { + fun onStateChangeClick( + context: ComponentContext, + @State state: NoteCreateBottomBarType, + @Param nextState: NoteCreateBottomBarType) { if (state == NoteCreateBottomBarType.OPTIONS && nextState == NoteCreateBottomBarType.OPTIONS) { NoteCreationBottomBar.onStateChange(context, NoteCreateBottomBarType.DEFAULT_SEGMENTS) return @@ -137,209 +151,214 @@ object NoteCreationBottomBarSpec { @LayoutSpec object NoteCreationOptionsBottomBarSpec { @OnCreateLayout - fun onCreate(context: ComponentContext, - @Prop colorConfig: ToolbarColorConfig): Component { + fun onCreate( + context: ComponentContext, + @Prop colorConfig: ToolbarColorConfig): Component { val activity = context.androidContext as CreateNoteActivity return Row.create(context) - .alignItems(YogaAlign.CENTER) - .child(bottomBarRoundIcon(context, colorConfig) - .bgColor(Color.TRANSPARENT) - .iconRes(R.drawable.icon_markdown_help) - .onClick { openSheet(activity, MarkdownHelpBottomSheet()) }) - .child(EmptySpec.create(context).heightDip(1f).flexGrow(1f)) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_undo_history) - .onClick { activity.onHistoryClick(true) }) - .child(bottomBarRoundIcon(context, colorConfig) - .bgColor(activity.note().color) - .bgAlpha(255) - .iconRes(R.drawable.ic_empty) - .onClick { activity.onColorChangeClick() } - .showBorder(true) - .iconMarginHorizontalRes(R.dimen.toolbar_round_small_icon_margin_horizontal) - .iconSizeRes(R.dimen.toolbar_round_small_icon_size)) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_redo_history) - .onClick { activity.onHistoryClick(false) }) - .child(EmptySpec.create(context).heightDip(1f).flexGrow(1f)) - .build() + .alignItems(YogaAlign.CENTER) + .child(bottomBarRoundIcon(context, colorConfig) + .bgColor(Color.TRANSPARENT) + .iconRes(R.drawable.icon_markdown_help) + .onClick { openSheet(activity, MarkdownHelpBottomSheet()) }) + .child(EmptySpec.create(context).heightDip(1f).flexGrow(1f)) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_undo_history) + .onClick { activity.onHistoryClick(true) }) + .child(bottomBarRoundIcon(context, colorConfig) + .bgColor(activity.note().color) + .bgAlpha(255) + .iconRes(R.drawable.ic_empty) + .onClick { activity.onColorChangeClick() } + .showBorder(true) + .iconMarginHorizontalRes(R.dimen.toolbar_round_small_icon_margin_horizontal) + .iconSizeRes(R.dimen.toolbar_round_small_icon_size)) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_redo_history) + .onClick { activity.onHistoryClick(false) }) + .child(EmptySpec.create(context).heightDip(1f).flexGrow(1f)) + .build() } } @LayoutSpec object NoteCreationSegmentsBottomBarSpec { @OnCreateLayout - fun onCreate(context: ComponentContext, - @Prop colorConfig: ToolbarColorConfig, - @Prop toggleButtonClick: EventHandler): Component { + fun onCreate( + context: ComponentContext, + @Prop colorConfig: ToolbarColorConfig, + @Prop toggleButtonClick: EventHandler): Component { val activity = context.androidContext as CreateNoteActivity return Row.create(context) - .alignItems(YogaAlign.CENTER) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_title_white_48dp) - .onClick { activity.addEmptyItemAtFocused(FormatType.HEADING) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_subject_white_48dp) - .onClick { activity.addEmptyItemAtFocused(FormatType.TEXT) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_check_box_white_24dp) - .onClick { activity.addEmptyItemAtFocused(FormatType.CHECKLIST_UNCHECKED) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_format_quote_white_48dp) - .onClick { activity.addEmptyItemAtFocused(FormatType.QUOTE) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_more_horiz_white_48dp) - .onClick { } - .isClickDisabled(true) - .clickHandler(toggleButtonClick)) - .build() + .alignItems(YogaAlign.CENTER) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_title_white_48dp) + .onClick { activity.addEmptyItemAtFocused(FormatType.HEADING) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_subject_white_48dp) + .onClick { activity.addEmptyItemAtFocused(FormatType.TEXT) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_check_box_white_24dp) + .onClick { activity.addEmptyItemAtFocused(FormatType.CHECKLIST_UNCHECKED) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_format_quote_white_48dp) + .onClick { activity.addEmptyItemAtFocused(FormatType.QUOTE) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_more_horiz_white_48dp) + .onClick { } + .isClickDisabled(true) + .clickHandler(toggleButtonClick)) + .build() } } @LayoutSpec object NoteCreationMarkdownsBottomBarSpec { @OnCreateLayout - fun onCreate(context: ComponentContext, - @Prop colorConfig: ToolbarColorConfig, - @Prop toggleButtonClick: EventHandler): Component { + fun onCreate( + context: ComponentContext, + @Prop colorConfig: ToolbarColorConfig, + @Prop toggleButtonClick: EventHandler): Component { val activity = context.androidContext as CreateNoteActivity return Row.create(context) - .alignItems(YogaAlign.CENTER) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_title_white_48dp) - .onClick { activity.triggerMarkdown(MarkdownType.HEADER) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_markdown_bold) - .onClick { activity.triggerMarkdown(MarkdownType.BOLD) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_markdown_italics) - .onClick { activity.triggerMarkdown(MarkdownType.ITALICS) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_format_list_bulleted_white_48dp) - .onClick { activity.triggerMarkdown(MarkdownType.UNORDERED) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_more_horiz_white_48dp) - .onClick { } - .isClickDisabled(true) - .clickHandler(toggleButtonClick)) - .build() + .alignItems(YogaAlign.CENTER) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_title_white_48dp) + .onClick { activity.triggerMarkdown(MarkdownType.HEADER) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_markdown_bold) + .onClick { activity.triggerMarkdown(MarkdownType.BOLD) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_markdown_italics) + .onClick { activity.triggerMarkdown(MarkdownType.ITALICS) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_format_list_bulleted_white_48dp) + .onClick { activity.triggerMarkdown(MarkdownType.UNORDERED) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_more_horiz_white_48dp) + .onClick { } + .isClickDisabled(true) + .clickHandler(toggleButtonClick)) + .build() } } - @LayoutSpec object NoteCreationAllSegmentsBottomBarSpec { @OnCreateLayout - fun onCreate(context: ComponentContext, - @Prop colorConfig: ToolbarColorConfig): Component { + fun onCreate( + context: ComponentContext, + @Prop colorConfig: ToolbarColorConfig): Component { val activity = context.androidContext as CreateNoteActivity return Row.create(context) - .alignSelf(YogaAlign.CENTER) - .alignItems(YogaAlign.CENTER) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_title_white_48dp) - .onClick { activity.addEmptyItemAtFocused(FormatType.HEADING) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_title_white_48dp) - .iconPaddingRes(R.dimen.toolbar_round_icon_padding_subsize) - .onClick { activity.addEmptyItemAtFocused(FormatType.SUB_HEADING) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_subject_white_48dp) - .onClick { activity.addEmptyItemAtFocused(FormatType.TEXT) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_check_box_white_24dp) - .onClick { activity.addEmptyItemAtFocused(FormatType.CHECKLIST_UNCHECKED) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_format_quote_white_48dp) - .onClick { activity.addEmptyItemAtFocused(FormatType.QUOTE) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_code_white_48dp) - .onClick { activity.addEmptyItemAtFocused(FormatType.CODE) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_image_gallery) - .onClick { activity.addEmptyItemAtFocused(FormatType.IMAGE) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_format_separator) - .onClick { activity.addEmptyItemAtFocused(FormatType.SEPARATOR) }) - .build() + .alignSelf(YogaAlign.CENTER) + .alignItems(YogaAlign.CENTER) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_title_white_48dp) + .onClick { activity.addEmptyItemAtFocused(FormatType.HEADING) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_title_white_48dp) + .iconPaddingRes(R.dimen.toolbar_round_icon_padding_subsize) + .onClick { activity.addEmptyItemAtFocused(FormatType.SUB_HEADING) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_subject_white_48dp) + .onClick { activity.addEmptyItemAtFocused(FormatType.TEXT) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_check_box_white_24dp) + .onClick { activity.addEmptyItemAtFocused(FormatType.CHECKLIST_UNCHECKED) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_format_quote_white_48dp) + .onClick { activity.addEmptyItemAtFocused(FormatType.QUOTE) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_code_white_48dp) + .onClick { activity.addEmptyItemAtFocused(FormatType.CODE) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_image_gallery) + .onClick { activity.addEmptyItemAtFocused(FormatType.IMAGE) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_format_separator) + .onClick { activity.addEmptyItemAtFocused(FormatType.SEPARATOR) }) + .build() } } @LayoutSpec object NoteCreationAllMarkdownsBottomBarSpec { @OnCreateLayout - fun onCreate(context: ComponentContext, - @Prop colorConfig: ToolbarColorConfig): Component { + fun onCreate( + context: ComponentContext, + @Prop colorConfig: ToolbarColorConfig): Component { val activity = context.androidContext as CreateNoteActivity return Row.create(context) - .alignSelf(YogaAlign.CENTER) - .alignItems(YogaAlign.CENTER) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_title_white_48dp) - .onClick { activity.triggerMarkdown(MarkdownType.HEADER) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_title_white_48dp) - .iconPaddingRes(R.dimen.toolbar_round_icon_padding_subsize) - .onClick { activity.triggerMarkdown(MarkdownType.SUB_HEADER) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_markdown_bold) - .onClick { activity.triggerMarkdown(MarkdownType.BOLD) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_markdown_italics) - .onClick { activity.triggerMarkdown(MarkdownType.ITALICS) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_check_box_white_24dp) - .onClick { activity.triggerMarkdown(MarkdownType.CHECKLIST_UNCHECKED) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_format_list_bulleted_white_48dp) - .onClick { activity.triggerMarkdown(MarkdownType.UNORDERED) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_markdown_underline) - .onClick { activity.triggerMarkdown(MarkdownType.UNDERLINE) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_code_white_48dp) - .onClick { activity.triggerMarkdown(MarkdownType.CODE_BLOCK) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.icon_code_block) - .onClick { activity.triggerMarkdown(MarkdownType.CODE) }) - .child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_markdown_strikethrough) - .onClick { activity.triggerMarkdown(MarkdownType.STRIKE_THROUGH) }) - .build() + .alignSelf(YogaAlign.CENTER) + .alignItems(YogaAlign.CENTER) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_title_white_48dp) + .onClick { activity.triggerMarkdown(MarkdownType.HEADER) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_title_white_48dp) + .iconPaddingRes(R.dimen.toolbar_round_icon_padding_subsize) + .onClick { activity.triggerMarkdown(MarkdownType.SUB_HEADER) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_markdown_bold) + .onClick { activity.triggerMarkdown(MarkdownType.BOLD) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_markdown_italics) + .onClick { activity.triggerMarkdown(MarkdownType.ITALICS) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_check_box_white_24dp) + .onClick { activity.triggerMarkdown(MarkdownType.CHECKLIST_UNCHECKED) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_format_list_bulleted_white_48dp) + .onClick { activity.triggerMarkdown(MarkdownType.UNORDERED) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_markdown_underline) + .onClick { activity.triggerMarkdown(MarkdownType.UNDERLINE) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_code_white_48dp) + .onClick { activity.triggerMarkdown(MarkdownType.CODE_BLOCK) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.icon_code_block) + .onClick { activity.triggerMarkdown(MarkdownType.CODE) }) + .child(bottomBarRoundIcon(context, colorConfig) + .iconRes(R.drawable.ic_markdown_strikethrough) + .onClick { activity.triggerMarkdown(MarkdownType.STRIKE_THROUGH) }) + .build() } } @LayoutSpec object NoteViewBottomBarSpec { @OnCreateLayout - fun onCreate(context: ComponentContext, - @Prop colorConfig: ToolbarColorConfig): Component { + fun onCreate( + context: ComponentContext, + @Prop colorConfig: ToolbarColorConfig): Component { val activity = context.androidContext as ViewAdvancedNoteActivity val row = Row.create(context) - .widthPercent(100f) - .alignItems(YogaAlign.CENTER) + .widthPercent(100f) + .alignItems(YogaAlign.CENTER) row.child(bottomBarRoundIcon(context, colorConfig) - .bgColor(Color.TRANSPARENT) - .iconRes(R.drawable.ic_apps_white_48dp) - .onClick { activity.openMoreOptions() }) + .bgColor(Color.TRANSPARENT) + .iconRes(R.drawable.ic_apps_white_48dp) + .onClick { activity.openMoreOptions() }) row.child(EmptySpec.create(context).heightDip(1f).flexGrow(1f)) row.child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.icon_delete) - .onClick { activity.moveItemToTrashOrDelete(activity.note()) }) + .iconRes(R.drawable.icon_delete) + .onClick { activity.moveItemToTrashOrDelete(activity.note()) }) row.child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_content_copy_white_48dp) - .onClick { activity.note().copy(activity) }) + .iconRes(R.drawable.ic_content_copy_white_48dp) + .onClick { activity.note().copy(activity) }) row.child(bottomBarRoundIcon(context, colorConfig) - .iconRes(R.drawable.ic_share_white_48dp) - .onClick { activity.note().share(activity) }) + .iconRes(R.drawable.ic_share_white_48dp) + .onClick { activity.note().share(activity) }) row.child(EmptySpec.create(context).heightDip(1f).flexGrow(1f)) row.child(bottomBarRoundIcon(context, colorConfig) - .bgColor(Color.TRANSPARENT) - .iconRes(R.drawable.ic_edit_white_48dp) - .onClick { activity.openEditor() }) + .bgColor(Color.TRANSPARENT) + .iconRes(R.drawable.ic_edit_white_48dp) + .onClick { activity.openEditor() }) return bottomBarCard(context, row.build(), colorConfig).build() } } diff --git a/base/src/main/java/com/maubis/scarlet/base/note/creation/specs/NoteViewTopBarSpec.kt b/base/src/main/java/com/maubis/scarlet/base/note/creation/specs/NoteViewTopBarSpec.kt index 3252e542..37de919a 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/creation/specs/NoteViewTopBarSpec.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/creation/specs/NoteViewTopBarSpec.kt @@ -5,9 +5,7 @@ import com.facebook.litho.ComponentContext import com.facebook.litho.Row import com.facebook.litho.annotations.LayoutSpec import com.facebook.litho.annotations.OnCreateLayout -import com.facebook.litho.annotations.Prop import com.facebook.yoga.YogaAlign -import com.maubis.scarlet.base.note.creation.activity.NoteViewColorConfig import com.maubis.scarlet.base.support.specs.EmptySpec @LayoutSpec @@ -15,8 +13,8 @@ object NoteViewTopBarSpec { @OnCreateLayout fun onCreate(context: ComponentContext): Component { val row = Row.create(context) - .widthPercent(100f) - .alignItems(YogaAlign.CENTER) + .widthPercent(100f) + .alignItems(YogaAlign.CENTER) row.child(EmptySpec.create(context).heightDip(10f)) return row.build() } @@ -27,8 +25,8 @@ object NoteCreationTopBarSpec { @OnCreateLayout fun onCreate(context: ComponentContext): Component { val row = Row.create(context) - .widthPercent(100f) - .alignItems(YogaAlign.CENTER) + .widthPercent(100f) + .alignItems(YogaAlign.CENTER) row.child(EmptySpec.create(context).heightDip(10f)) return row.build() } diff --git a/base/src/main/java/com/maubis/scarlet/base/note/folder/FolderExtensions.kt b/base/src/main/java/com/maubis/scarlet/base/note/folder/FolderExtensions.kt index e8948504..729684f7 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/folder/FolderExtensions.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/folder/FolderExtensions.kt @@ -1,9 +1,9 @@ package com.maubis.scarlet.base.note.folder -import com.github.bijoysingh.starter.util.DateFormatter -import com.maubis.scarlet.base.config.CoreConfig -import com.maubis.scarlet.base.database.room.folder.Folder +import com.maubis.scarlet.base.config.ApplicationBase import com.maubis.scarlet.base.config.CoreConfig.Companion.foldersDb +import com.maubis.scarlet.base.database.room.folder.Folder +import com.maubis.scarlet.base.support.utils.sDateFormat import java.util.* fun Folder.saveIfUnique() { @@ -34,7 +34,7 @@ fun Folder.getDisplayTime(): String { Calendar.getInstance().timeInMillis - time < 1000 * 60 * 60 * 2 -> "hh:mm aa" else -> "dd MMMM" } - return DateFormatter.getDate(format, time) + return sDateFormat.readableTime(format, time) } /************************************************************************************** @@ -42,21 +42,21 @@ fun Folder.getDisplayTime(): String { **************************************************************************************/ fun Folder.save() { - CoreConfig.instance.folderActions(this).save() + ApplicationBase.instance.folderActions(this).save() } fun Folder.saveWithoutSync() { - CoreConfig.instance.folderActions(this).offlineSave() + ApplicationBase.instance.folderActions(this).offlineSave() } fun Folder.saveToSync() { - CoreConfig.instance.folderActions(this).onlineSave() + ApplicationBase.instance.folderActions(this).onlineSave() } fun Folder.delete() { - CoreConfig.instance.folderActions(this).delete() + ApplicationBase.instance.folderActions(this).delete() } fun Folder.deleteWithoutSync() { - CoreConfig.instance.folderActions(this).offlineDelete() + ApplicationBase.instance.folderActions(this).offlineDelete() } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/note/folder/FolderOptionItem.kt b/base/src/main/java/com/maubis/scarlet/base/note/folder/FolderOptionItem.kt index 7a7c51b8..2844a0f6 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/folder/FolderOptionItem.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/folder/FolderOptionItem.kt @@ -4,12 +4,12 @@ import com.maubis.scarlet.base.R import com.maubis.scarlet.base.database.room.folder.Folder class FolderOptionsItem( - val folder: Folder, - val usages: Int = 0, - val selected: Boolean = false, - val editable: Boolean = false, - val editListener: () -> Unit = {}, - val listener: () -> Unit = {}) { + val folder: Folder, + val usages: Int = 0, + val selected: Boolean = false, + val editable: Boolean = false, + val editListener: () -> Unit = {}, + val listener: () -> Unit = {}) { fun getIcon(): Int = when (selected) { true -> R.drawable.ic_folder diff --git a/base/src/main/java/com/maubis/scarlet/base/note/folder/FolderRecyclerHolder.kt b/base/src/main/java/com/maubis/scarlet/base/note/folder/FolderRecyclerHolder.kt index 3bbc11cc..aadc0ebb 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/folder/FolderRecyclerHolder.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/folder/FolderRecyclerHolder.kt @@ -2,13 +2,16 @@ package com.maubis.scarlet.base.note.folder import android.content.Context import android.os.Bundle -import android.support.v7.widget.CardView import android.view.View import android.widget.TextView +import androidx.cardview.widget.CardView import com.github.bijoysingh.starter.recyclerview.RecyclerViewHolder import com.github.bijoysingh.uibasics.views.UITextView import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface import com.maubis.scarlet.base.support.recycler.RecyclerItem +import com.maubis.scarlet.base.support.ui.ColorUtil.darkOrDarkerColor +import com.maubis.scarlet.base.support.ui.sThemeDarkenNoteColor class FolderRecyclerHolder(context: Context, view: View) : RecyclerViewHolder(context, view) { @@ -28,15 +31,22 @@ class FolderRecyclerHolder(context: Context, view: View) : RecyclerViewHolder darkOrDarkerColor(item.folder.color) + false -> item.folder.color + } + view.setCardBackgroundColor(folderColor) view.setOnClickListener { item.click() } diff --git a/base/src/main/java/com/maubis/scarlet/base/note/folder/FolderRecyclerItem.kt b/base/src/main/java/com/maubis/scarlet/base/note/folder/FolderRecyclerItem.kt index cbcd3789..ede0e4a9 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/folder/FolderRecyclerItem.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/folder/FolderRecyclerItem.kt @@ -1,19 +1,20 @@ package com.maubis.scarlet.base.note.folder import android.content.Context -import android.support.v4.content.ContextCompat +import androidx.core.content.ContextCompat import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.database.room.folder.Folder import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb +import com.maubis.scarlet.base.database.room.folder.Folder import com.maubis.scarlet.base.support.recycler.RecyclerItem import com.maubis.scarlet.base.support.ui.ColorUtil -class FolderRecyclerItem(context: Context, - val folder: Folder, - val click: () -> Unit = {}, - val longClick: () -> Unit = {}, - val selected: Boolean = false, - contents: Int = -1) : RecyclerItem() { +class FolderRecyclerItem( + context: Context, + val folder: Folder, + val click: () -> Unit = {}, + val longClick: () -> Unit = {}, + val selected: Boolean = false, + contents: Int = -1) : RecyclerItem() { val isLightShaded = ColorUtil.isLightColored(folder.color) val title = folder.title @@ -39,6 +40,5 @@ class FolderRecyclerItem(context: Context, false -> ContextCompat.getColor(context, R.color.light_secondary_text) } - override val type = RecyclerItem.Type.FOLDER } diff --git a/base/src/main/java/com/maubis/scarlet/base/note/folder/SelectorFolderRecyclerHolder.kt b/base/src/main/java/com/maubis/scarlet/base/note/folder/SelectorFolderRecyclerHolder.kt new file mode 100644 index 00000000..65e4b2a9 --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/note/folder/SelectorFolderRecyclerHolder.kt @@ -0,0 +1,38 @@ +package com.maubis.scarlet.base.note.folder + +import android.content.Context +import android.os.Bundle +import android.view.View +import android.widget.ImageView +import android.widget.TextView +import com.github.bijoysingh.starter.recyclerview.RecyclerViewHolder +import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface +import com.maubis.scarlet.base.main.recycler.setFullSpan +import com.maubis.scarlet.base.support.recycler.RecyclerItem +import com.maubis.scarlet.base.support.ui.CircleDrawable + +class SelectorFolderRecyclerHolder(context: Context, view: View) : RecyclerViewHolder(context, view) { + + protected val title: TextView + protected val icon: ImageView + + init { + title = view.findViewById(R.id.folder_title) + icon = view.findViewById(R.id.folder_icon) + } + + override fun populate(itemData: RecyclerItem, extra: Bundle?) { + setFullSpan() + + val item = itemData as SelectorFolderRecyclerItem + title.text = item.title + title.setTextColor(item.titleColor) + title.typeface = sAppTypeface.title() + title.alpha = 0.8f + + icon.setColorFilter(item.iconColor) + icon.background = CircleDrawable(item.folderColor, false) + icon.alpha = 0.8f + } +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/note/folder/SelectorFolderRecyclerItem.kt b/base/src/main/java/com/maubis/scarlet/base/note/folder/SelectorFolderRecyclerItem.kt new file mode 100644 index 00000000..5f1c267f --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/note/folder/SelectorFolderRecyclerItem.kt @@ -0,0 +1,24 @@ +package com.maubis.scarlet.base.note.folder + +import android.content.Context +import androidx.core.content.ContextCompat +import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.database.room.folder.Folder +import com.maubis.scarlet.base.support.recycler.RecyclerItem +import com.maubis.scarlet.base.support.ui.ColorUtil +import com.maubis.scarlet.base.support.ui.ThemeColorType + +class SelectorFolderRecyclerItem(context: Context, val folder: Folder) : RecyclerItem() { + + val isLightShaded = ColorUtil.isLightColored(folder.color) + val title = folder.title + val titleColor = sAppTheme.get(ThemeColorType.TERTIARY_TEXT) + + val folderColor = folder.color + val iconColor = when (isLightShaded) { + true -> ContextCompat.getColor(context, R.color.dark_secondary_text) + false -> ContextCompat.getColor(context, R.color.light_primary_text) + } + override val type = Type.FOLDER +} diff --git a/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/CreateOrEditFolderBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/CreateOrEditFolderBottomSheet.kt index 6a3b619b..88101d3e 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/CreateOrEditFolderBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/CreateOrEditFolderBottomSheet.kt @@ -2,27 +2,25 @@ package com.maubis.scarlet.base.note.folder.sheet import android.app.Dialog import android.content.Context -import android.view.View import android.view.View.GONE import android.view.View.VISIBLE import android.widget.EditText import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity import com.google.android.flexbox.FlexboxLayout import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig -import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme import com.maubis.scarlet.base.core.folder.isUnsaved import com.maubis.scarlet.base.database.room.folder.Folder import com.maubis.scarlet.base.note.folder.delete import com.maubis.scarlet.base.note.folder.save -import com.maubis.scarlet.base.note.save import com.maubis.scarlet.base.settings.view.ColorView +import com.maubis.scarlet.base.support.sheets.openSheet import com.maubis.scarlet.base.support.ui.ThemeColorType import com.maubis.scarlet.base.support.ui.ThemedActivity import com.maubis.scarlet.base.support.ui.ThemedBottomSheetFragment import com.maubis.scarlet.base.support.utils.getEditorActionListener - class CreateOrEditFolderBottomSheet : ThemedBottomSheetFragment() { var selectedFolder: Folder? = null @@ -49,11 +47,10 @@ class CreateOrEditFolderBottomSheet : ThemedBottomSheetFragment() { val enterFolder = dialog.findViewById(R.id.enter_folder) val removeBtn = dialog.findViewById(R.id.action_remove_button) val colorFlexbox = dialog.findViewById(R.id.color_flexbox) - val colorCard = dialog.findViewById(R.id.core_color_card) - title.setTextColor(CoreConfig.instance.themeController().get(ThemeColorType.SECONDARY_TEXT)) - enterFolder.setTextColor(CoreConfig.instance.themeController().get(ThemeColorType.SECONDARY_TEXT)) - enterFolder.setHintTextColor(CoreConfig.instance.themeController().get(ThemeColorType.HINT_TEXT)) + title.setTextColor(sAppTheme.get(ThemeColorType.SECONDARY_TEXT)) + enterFolder.setTextColor(sAppTheme.get(ThemeColorType.SECONDARY_TEXT)) + enterFolder.setHintTextColor(sAppTheme.get(ThemeColorType.HINT_TEXT)) title.setText(if (folder.isUnsaved()) R.string.folder_sheet_add_note else R.string.folder_sheet_edit_note) action.setOnClickListener { @@ -61,25 +58,24 @@ class CreateOrEditFolderBottomSheet : ThemedBottomSheetFragment() { sheetOnFolderListener(folder, !updated) dismiss() } + + val folderDeleteListener = sheetOnFolderListener removeBtn.visibility = if (folder.isUnsaved()) GONE else VISIBLE removeBtn.setOnClickListener { - folder.delete() - notesDb.getAll().filter { it.folder == folder.uuid }.forEach { - it.folder = "" - it.save(themedContext()) - } - - sheetOnFolderListener(folder, true) + openSheet(context as AppCompatActivity, DeleteFolderBottomSheet().apply { + selectedFolder = folder + sheetOnFolderListener = folderDeleteListener + }) dismiss() } enterFolder.setText(folder.title) enterFolder.setOnEditorActionListener(getEditorActionListener( - runnable = { - val updated = onActionClick(folder, enterFolder.text.toString()) - sheetOnFolderListener(folder, !updated) - dismiss() - return@getEditorActionListener true - })) + runnable = { + val updated = onActionClick(folder, enterFolder.text.toString()) + sheetOnFolderListener(folder, !updated) + dismiss() + return@getEditorActionListener true + })) setColorsList(dialog.context, folder, colorFlexbox) makeBackgroundTransparent(dialog, R.id.root_layout) diff --git a/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/DeleteFolderBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/DeleteFolderBottomSheet.kt new file mode 100644 index 00000000..e7341282 --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/DeleteFolderBottomSheet.kt @@ -0,0 +1,84 @@ +package com.maubis.scarlet.base.note.folder.sheet + +import android.app.Dialog +import androidx.appcompat.app.AppCompatActivity +import com.facebook.litho.ComponentContext +import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.database.room.folder.Folder +import com.maubis.scarlet.base.database.room.note.Note +import com.maubis.scarlet.base.note.folder.delete +import com.maubis.scarlet.base.note.save +import com.maubis.scarlet.base.note.softDelete +import com.maubis.scarlet.base.support.sheets.LithoOptionBottomSheet +import com.maubis.scarlet.base.support.sheets.LithoOptionsItem + +class DeleteFolderBottomSheet : LithoOptionBottomSheet() { + + var selectedFolder: Folder? = null + var sheetOnFolderListener: (folder: Folder, deleted: Boolean) -> Unit = { _, _ -> } + + override fun title(): Int = R.string.folder_delete_option_sheet_title + + override fun getOptions(componentContext: ComponentContext, dialog: Dialog): List { + val folder = selectedFolder + if (folder === null) { + dismiss() + return emptyList() + } + + val activity = context as AppCompatActivity + val options = ArrayList() + options.add(LithoOptionsItem( + title = R.string.folder_delete_option_sheet_remove_folder, + subtitle = R.string.folder_delete_option_sheet_remove_folder_details, + icon = R.drawable.icon_delete, + listener = { + folder.delete() + executeForFolderContent(folder) { + it.folder = "" + it.save(activity) + } + + sheetOnFolderListener(folder, true) + dismiss() + } + )) + options.add(LithoOptionsItem( + title = R.string.folder_delete_option_sheet_remove_folder_content, + subtitle = R.string.folder_delete_option_sheet_remove_folder_content_details, + icon = R.drawable.icon_delete_content, + listener = { + executeForFolderContent(folder) { + it.folder = "" + it.softDelete(activity) + } + + sheetOnFolderListener(folder, false) + dismiss() + } + )) + options.add(LithoOptionsItem( + title = R.string.folder_delete_option_sheet_remove_folder_and_content, + subtitle = R.string.folder_delete_option_sheet_remove_folder_and_content_details, + icon = R.drawable.ic_delete_permanently, + listener = { + folder.delete() + executeForFolderContent(folder) { + it.folder = "" + it.softDelete(activity) + } + + sheetOnFolderListener(folder, true) + dismiss() + } + )) + return options + } + + private fun executeForFolderContent(folder: Folder, lambda: (Note) -> Unit) { + CoreConfig.notesDb.getAll().filter { it.folder == folder.uuid }.forEach { + lambda(it) + } + } +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/FolderChooseOptionsBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/FolderChooseOptionsBottomSheet.kt deleted file mode 100644 index 728810b0..00000000 --- a/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/FolderChooseOptionsBottomSheet.kt +++ /dev/null @@ -1,86 +0,0 @@ -package com.maubis.scarlet.base.note.folder.sheet - -import android.app.Dialog -import android.content.Context -import android.content.DialogInterface -import android.view.View -import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.database.room.folder.Folder -import com.maubis.scarlet.base.database.room.note.Note -import com.maubis.scarlet.base.core.folder.FolderBuilder -import com.maubis.scarlet.base.note.folder.FolderOptionsItem -import com.maubis.scarlet.base.note.save -import com.maubis.scarlet.base.config.CoreConfig.Companion.foldersDb -import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb -import com.maubis.scarlet.base.support.ui.ThemedActivity -import com.maubis.scarlet.base.support.ui.visibility - -class FolderChooseOptionsBottomSheet : FolderOptionItemBottomSheetBase() { - - var note: Note? = null - var dismissListener: () -> Unit = {} - - override fun setupViewWithDialog(dialog: Dialog) { - if (note === null) { - dismiss() - return - } - - val options = getOptions() - dialog.findViewById(R.id.tag_card_layout).visibility = visibility(options.isNotEmpty()) - setOptions(dialog, getOptions()) - } - - override fun onNewFolderClick() { - val activity = context as ThemedActivity - CreateOrEditFolderBottomSheet.openSheet(activity, FolderBuilder().emptyFolder(), { folder, _ -> - toggleFolder(activity, note, folder) - reset(dialog) - }) - } - - fun toggleFolder(context: Context, note: Note?, folder: Folder) { - val localNote = note - if (localNote === null) { - return - } - localNote.folder = if (localNote.folder === folder.uuid) "" else folder.uuid - localNote.save(context) - } - - override fun onDismiss(dialog: DialogInterface?) { - super.onDismiss(dialog) - dismissListener() - } - - private fun getOptions(): List { - val activity = themedContext() as ThemedActivity - val options = ArrayList() - val selectedFolder = note!!.folder - for (folder in foldersDb.getAll()) { - options.add(FolderOptionsItem( - folder = folder, - usages = notesDb.getNoteCountByFolder(folder.uuid), - listener = { - toggleFolder(activity, note, folder) - reset(dialog) - }, - editListener = { - CreateOrEditFolderBottomSheet.openSheet(activity, folder, {_,_ -> reset(dialog)}) - }, - selected = folder.uuid == selectedFolder - )) - } - return options - } - - companion object { - fun openSheet(activity: ThemedActivity, note: Note, dismissListener: () -> Unit) { - val sheet = FolderChooseOptionsBottomSheet() - - sheet.note = note - sheet.dismissListener = dismissListener - sheet.show(activity.supportFragmentManager, sheet.tag) - } - } -} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/FolderChooserBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/FolderChooserBottomSheet.kt new file mode 100644 index 00000000..5bf40c06 --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/FolderChooserBottomSheet.kt @@ -0,0 +1,27 @@ +package com.maubis.scarlet.base.note.folder.sheet + +import com.facebook.litho.ComponentContext +import com.maubis.scarlet.base.database.room.folder.Folder +import com.maubis.scarlet.base.database.room.note.Note +import com.maubis.scarlet.base.note.save + +class FolderChooserBottomSheet : FolderChooserBottomSheetBase() { + + var note: Note? = null + + override fun preComponentRender(componentContext: ComponentContext) { + + } + + override fun onFolderSelected(folder: Folder) { + note!!.folder = when { + note!!.folder == folder.uuid -> "" + else -> folder.uuid + } + note!!.save(requireContext()) + } + + override fun isFolderSelected(folder: Folder): Boolean { + return note!!.folder == folder.uuid + } +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/FolderChooserBottomSheetBase.kt b/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/FolderChooserBottomSheetBase.kt new file mode 100644 index 00000000..f01bf783 --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/FolderChooserBottomSheetBase.kt @@ -0,0 +1,171 @@ +package com.maubis.scarlet.base.note.folder.sheet + +import android.app.Dialog +import android.content.DialogInterface +import android.graphics.Typeface +import androidx.appcompat.app.AppCompatActivity +import com.facebook.litho.ClickEvent +import com.facebook.litho.Column +import com.facebook.litho.Component +import com.facebook.litho.ComponentContext +import com.facebook.litho.Row +import com.facebook.litho.annotations.LayoutSpec +import com.facebook.litho.annotations.OnCreateLayout +import com.facebook.litho.annotations.OnEvent +import com.facebook.litho.annotations.Prop +import com.facebook.litho.widget.Text +import com.facebook.yoga.YogaAlign +import com.facebook.yoga.YogaEdge +import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface +import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.core.folder.FolderBuilder +import com.maubis.scarlet.base.database.room.folder.Folder +import com.maubis.scarlet.base.support.sheets.LithoBottomSheet +import com.maubis.scarlet.base.support.sheets.LithoOptionsItem +import com.maubis.scarlet.base.support.sheets.OptionItemLayout +import com.maubis.scarlet.base.support.sheets.getLithoBottomSheetTitle +import com.maubis.scarlet.base.support.specs.RoundIcon +import com.maubis.scarlet.base.support.ui.ThemeColorType +import com.maubis.scarlet.base.support.ui.ThemedActivity + +data class FolderOptionsItem( + val folder: Folder, + val isSelected: Boolean = false, + val listener: () -> Unit = {}) + +@LayoutSpec +object FolderItemLayoutSpec { + @OnCreateLayout + fun onCreate(context: ComponentContext, @Prop option: FolderOptionsItem): Component { + val titleColor = sAppTheme.get(ThemeColorType.SECONDARY_TEXT) + val selectedColor = when (sAppTheme.isNightTheme()) { + true -> context.getColor(R.color.material_blue_400) + false -> context.getColor(R.color.material_blue_700) + } + + val icon: Int + val bgColor: Int + val bgAlpha: Int + val textColor: Int + val typeface: Typeface + when (option.isSelected) { + true -> { + icon = R.drawable.ic_folder + bgColor = selectedColor + bgAlpha = 200 + textColor = selectedColor + typeface = sAppTypeface.subHeading() + } + false -> { + icon = R.drawable.ic_folder + bgColor = titleColor + bgAlpha = 15 + textColor = titleColor + typeface = sAppTypeface.title() + } + } + + val row = Row.create(context) + .widthPercent(100f) + .alignItems(YogaAlign.CENTER) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .paddingDip(YogaEdge.VERTICAL, 12f) + .child( + RoundIcon.create(context) + .iconRes(icon) + .bgColor(bgColor) + .iconColor(titleColor) + .iconSizeRes(R.dimen.toolbar_round_icon_size) + .iconPaddingRes(R.dimen.toolbar_round_icon_padding) + .bgAlpha(bgAlpha) + .onClick { } + .isClickDisabled(true) + .marginDip(YogaEdge.END, 16f)) + .child( + Text.create(context) + .flexGrow(1f) + .text(option.folder.title) + .textSizeRes(R.dimen.font_size_normal) + .typeface(typeface) + .textStyle(Typeface.BOLD) + .textColor(textColor)) + row.clickHandler(OptionItemLayout.onItemClick(context)) + return row.build() + } + + @OnEvent(ClickEvent::class) + fun onItemClick(context: ComponentContext, @Prop option: FolderOptionsItem) { + option.listener() + } +} + +abstract class FolderChooserBottomSheetBase : LithoBottomSheet() { + + var dismissListener: () -> Unit = {} + + protected abstract fun preComponentRender(componentContext: ComponentContext) + protected abstract fun onFolderSelected(folder: Folder) + protected abstract fun isFolderSelected(folder: Folder): Boolean + + override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { + preComponentRender(componentContext) + val activity = context as ThemedActivity + val component = Column.create(componentContext) + .widthPercent(100f) + val foldersComponent = Column.create(componentContext) + .paddingDip(YogaEdge.TOP, 8f) + .paddingDip(YogaEdge.BOTTOM, 8f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .child( + getLithoBottomSheetTitle(componentContext) + .textRes(R.string.folder_option_change_notebook) + .marginDip(YogaEdge.BOTTOM, 12f)) + getFolderOptions().forEach { + foldersComponent.child(FolderItemLayout.create(componentContext).option(it)) + } + + val addTag = LithoOptionsItem( + title = R.string.folder_sheet_add_note, + subtitle = 0, + icon = R.drawable.icon_add_notebook, + listener = { + CreateOrEditFolderBottomSheet.openSheet(activity, FolderBuilder().emptyFolder()) { folder, _ -> + onFolderSelected(folder) + reset(activity, dialog) + } + }) + foldersComponent.child(OptionItemLayout.create(componentContext) + .option(addTag) + .backgroundRes(R.drawable.accent_rounded_bg) + .marginDip(YogaEdge.TOP, 16f) + .onClick { addTag.listener() }) + + component.child(foldersComponent) + return component.build() + } + + private fun getFolderOptions(): List { + val activity = context as AppCompatActivity + val options = ArrayList() + for (folder in CoreConfig.foldersDb.getAll()) { + options.add( + FolderOptionsItem( + folder = folder, + listener = { + onFolderSelected(folder) + reset(activity, dialog) + }, + isSelected = isFolderSelected(folder) + )) + } + options.sortByDescending { if (it.isSelected) 1 else 0 } + return options + } + + override fun onDismiss(dialog: DialogInterface) { + super.onDismiss(dialog) + dismissListener() + } +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/FolderOptionItemBottomSheetBase.kt b/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/FolderOptionItemBottomSheetBase.kt deleted file mode 100644 index ee0c966f..00000000 --- a/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/FolderOptionItemBottomSheetBase.kt +++ /dev/null @@ -1,74 +0,0 @@ -package com.maubis.scarlet.base.note.folder.sheet - -import android.app.Dialog -import android.view.View -import android.view.View.GONE -import android.widget.LinearLayout -import com.github.bijoysingh.uibasics.views.UIActionView -import com.github.bijoysingh.uibasics.views.UITextView -import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig -import com.maubis.scarlet.base.note.folder.FolderOptionsItem -import com.maubis.scarlet.base.support.ui.ThemeColorType -import com.maubis.scarlet.base.support.ui.ThemedBottomSheetFragment - -abstract class FolderOptionItemBottomSheetBase : ThemedBottomSheetFragment() { - - override fun setupView(dialog: Dialog?) { - super.setupView(dialog) - if (dialog == null) { - return - } - reset(dialog) - setAddFolderOption(dialog) - makeBackgroundTransparent(dialog, R.id.root_layout) - } - - abstract fun setupViewWithDialog(dialog: Dialog) - - abstract fun onNewFolderClick() - - override fun getBackgroundView(): Int { - return R.id.options_layout - } - - override fun getBackgroundCardViewIds(): Array = arrayOf(R.id.tag_card_layout) - - fun setAddFolderOption(dialog: Dialog) { - val newFolderButton = dialog.findViewById(R.id.new_tag_button); - newFolderButton.setText(R.string.folder_sheet_add_note) - newFolderButton.setOnClickListener { onNewFolderClick() } - newFolderButton.icon.alpha = 0.6f - } - - fun reset(dialog: Dialog) { - val layout = dialog.findViewById(R.id.options_container) - layout.removeAllViews() - setupViewWithDialog(dialog) - } - - fun setOptions(dialog: Dialog, options: List) { - val layout = dialog.findViewById(R.id.options_container) - for (option in options) { - val contentView = View.inflate(context, R.layout.layout_option_sheet_item, null) as UIActionView - contentView.setTitle(option.folder.title) - contentView.setOnClickListener { option.listener() } - contentView.subtitle.visibility = GONE - contentView.setImageResource(option.getIcon()) - - if (option.editable) { - contentView.setActionResource(option.getEditIcon()); - contentView.setActionTint(CoreConfig.instance.themeController().get(ThemeColorType.HINT_TEXT)); - contentView.setActionClickListener { option.editListener() } - } - - contentView.setTitleColor(getOptionsTitleColor(option.selected)) - contentView.setSubtitleColor(getOptionsSubtitleColor(option.selected)) - contentView.setImageTint(getOptionsTitleColor(option.selected)) - - layout.addView(contentView) - } - } - - override fun getLayout(): Int = R.layout.bottom_sheet_tag_options -} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/SelectedFolderChooseOptionBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/SelectedFolderChooseOptionBottomSheet.kt index 99f269b8..8f7aa044 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/SelectedFolderChooseOptionBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/folder/sheet/SelectedFolderChooseOptionBottomSheet.kt @@ -1,71 +1,28 @@ package com.maubis.scarlet.base.note.folder.sheet -import android.app.Dialog -import android.content.Context -import android.content.DialogInterface -import android.view.View -import com.maubis.scarlet.base.R +import com.facebook.litho.ComponentContext import com.maubis.scarlet.base.database.room.folder.Folder -import com.maubis.scarlet.base.database.room.note.Note -import com.maubis.scarlet.base.database.room.tag.Tag -import com.maubis.scarlet.base.core.folder.FolderBuilder -import com.maubis.scarlet.base.note.folder.FolderOptionsItem -import com.maubis.scarlet.base.note.save import com.maubis.scarlet.base.note.selection.activity.SelectNotesActivity -import com.maubis.scarlet.base.config.CoreConfig.Companion.foldersDb -import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb -import com.maubis.scarlet.base.support.ui.ThemedActivity -import com.maubis.scarlet.base.support.ui.visibility -class SelectedFolderChooseOptionsBottomSheet : FolderOptionItemBottomSheetBase() { +class SelectedFolderChooseOptionsBottomSheet : FolderChooserBottomSheetBase() { var onActionListener: (Folder, Boolean) -> Unit = { _, _ -> } - - override fun setupViewWithDialog(dialog: Dialog) { - val options = getOptions() - dialog.findViewById(R.id.tag_card_layout).visibility = visibility(options.isNotEmpty()) - setOptions(dialog, getOptions()) - } - - override fun onNewFolderClick() { - val activity = context as ThemedActivity - CreateOrEditFolderBottomSheet.openSheet(activity, FolderBuilder().emptyFolder(), { folder, _ -> - onActionListener(folder, true) - reset(dialog) - }) + var selectedFolders: MutableList = emptyList().toMutableList() + var selectedFolder: String = "" + + override fun preComponentRender(componentContext: ComponentContext) { + val activity = requireContext() as SelectNotesActivity + selectedFolders.clear() + selectedFolders.addAll(activity.getAllSelectedNotes().map { it.folder }.distinct()) + selectedFolder = selectedFolders.firstOrNull() ?: "" } - private fun getOptions(): List { - val activity = themedContext() as SelectNotesActivity - val options = ArrayList() - - val folders = activity.getAllSelectedNotes().map { it.folder }.distinct() - val selectedFolder = when (folders.size) { - 1 -> folders.first() - else -> "" - } - for (folder in foldersDb.getAll()) { - options.add(FolderOptionsItem( - folder = folder, - usages = notesDb.getNoteCountByFolder(folder.uuid), - listener = { - onActionListener(folder, folder.uuid != selectedFolder) - reset(dialog) - }, - editListener = { - CreateOrEditFolderBottomSheet.openSheet(activity, folder, {_,_ -> reset(dialog)}) - }, - selected = folder.uuid == selectedFolder - )) - } - return options + override fun onFolderSelected(folder: Folder) { + onActionListener(folder, true) + onActionListener(folder, folder.uuid != selectedFolder) } - companion object { - fun openSheet(activity: ThemedActivity, listener: (Folder, Boolean) -> Unit) { - val sheet = SelectedFolderChooseOptionsBottomSheet() - sheet.onActionListener = listener - sheet.show(activity.supportFragmentManager, sheet.tag) - } + override fun isFolderSelected(folder: Folder): Boolean { + return folder.uuid == selectedFolder } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/note/formats/FormatControllerList.kt b/base/src/main/java/com/maubis/scarlet/base/note/formats/FormatControllerList.kt index 1c144cc5..2133998f 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/formats/FormatControllerList.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/formats/FormatControllerList.kt @@ -4,82 +4,106 @@ import com.github.bijoysingh.starter.recyclerview.MultiRecyclerViewControllerIte import com.maubis.scarlet.base.R import com.maubis.scarlet.base.core.format.Format import com.maubis.scarlet.base.core.format.FormatType -import com.maubis.scarlet.base.note.formats.recycler.* +import com.maubis.scarlet.base.note.formats.recycler.FormatBulletViewHolder +import com.maubis.scarlet.base.note.formats.recycler.FormatImageViewHolder +import com.maubis.scarlet.base.note.formats.recycler.FormatListViewHolder +import com.maubis.scarlet.base.note.formats.recycler.FormatQuoteViewHolder +import com.maubis.scarlet.base.note.formats.recycler.FormatSeparatorViewHolder +import com.maubis.scarlet.base.note.formats.recycler.FormatTextViewHolder +import com.maubis.scarlet.base.note.formats.recycler.NullFormatHolder import java.util.* fun getFormatControllerItems(): List> { val list = ArrayList>() list.add( - MultiRecyclerViewControllerItem.Builder() - .viewType(FormatType.TAG.ordinal) - .layoutFile(R.layout.item_format_tag) - .holderClass(FormatTextViewHolder::class.java) - .build()) + MultiRecyclerViewControllerItem.Builder() + .viewType(FormatType.TAG.ordinal) + .layoutFile(R.layout.item_format_tag) + .holderClass(FormatTextViewHolder::class.java) + .build()) list.add( - MultiRecyclerViewControllerItem.Builder() - .viewType(FormatType.TEXT.ordinal) - .layoutFile(R.layout.item_format_text) - .holderClass(FormatTextViewHolder::class.java) - .build()) + MultiRecyclerViewControllerItem.Builder() + .viewType(FormatType.TEXT.ordinal) + .layoutFile(R.layout.item_format_text) + .holderClass(FormatTextViewHolder::class.java) + .build()) list.add( - MultiRecyclerViewControllerItem.Builder() - .viewType(FormatType.HEADING.ordinal) - .layoutFile(R.layout.item_format_heading) - .holderClass(FormatTextViewHolder::class.java) - .build()) + MultiRecyclerViewControllerItem.Builder() + .viewType(FormatType.HEADING.ordinal) + .layoutFile(R.layout.item_format_heading) + .holderClass(FormatTextViewHolder::class.java) + .build()) list.add( - MultiRecyclerViewControllerItem.Builder() - .viewType(FormatType.SUB_HEADING.ordinal) - .layoutFile(R.layout.item_format_heading) - .holderClass(FormatTextViewHolder::class.java) - .build()) + MultiRecyclerViewControllerItem.Builder() + .viewType(FormatType.SUB_HEADING.ordinal) + .layoutFile(R.layout.item_format_heading) + .holderClass(FormatTextViewHolder::class.java) + .build()) list.add( - MultiRecyclerViewControllerItem.Builder() - .viewType(FormatType.HEADING_3.ordinal) - .layoutFile(R.layout.item_format_heading) - .holderClass(FormatTextViewHolder::class.java) - .build()) + MultiRecyclerViewControllerItem.Builder() + .viewType(FormatType.HEADING_3.ordinal) + .layoutFile(R.layout.item_format_heading) + .holderClass(FormatTextViewHolder::class.java) + .build()) list.add( - MultiRecyclerViewControllerItem.Builder() - .viewType(FormatType.QUOTE.ordinal) - .layoutFile(R.layout.item_format_quote) - .holderClass(FormatQuoteViewHolder::class.java) - .build()) + MultiRecyclerViewControllerItem.Builder() + .viewType(FormatType.QUOTE.ordinal) + .layoutFile(R.layout.item_format_quote) + .holderClass(FormatQuoteViewHolder::class.java) + .build()) list.add( - MultiRecyclerViewControllerItem.Builder() - .viewType(FormatType.CODE.ordinal) - .layoutFile(R.layout.item_format_code) - .holderClass(FormatTextViewHolder::class.java) - .build()) + MultiRecyclerViewControllerItem.Builder() + .viewType(FormatType.CODE.ordinal) + .layoutFile(R.layout.item_format_code) + .holderClass(FormatTextViewHolder::class.java) + .build()) list.add( - MultiRecyclerViewControllerItem.Builder() - .viewType(FormatType.CHECKLIST_CHECKED.ordinal) - .layoutFile(R.layout.item_format_list) - .holderClass(FormatListViewHolder::class.java) - .build()) + MultiRecyclerViewControllerItem.Builder() + .viewType(FormatType.BULLET_1.ordinal) + .layoutFile(R.layout.item_format_bullet) + .holderClass(FormatBulletViewHolder::class.java) + .build()) list.add( - MultiRecyclerViewControllerItem.Builder() - .viewType(FormatType.CHECKLIST_UNCHECKED.ordinal) - .layoutFile(R.layout.item_format_list) - .holderClass(FormatListViewHolder::class.java) - .build()) + MultiRecyclerViewControllerItem.Builder() + .viewType(FormatType.BULLET_2.ordinal) + .layoutFile(R.layout.item_format_bullet) + .holderClass(FormatBulletViewHolder::class.java) + .build()) list.add( - MultiRecyclerViewControllerItem.Builder() - .viewType(FormatType.IMAGE.ordinal) - .layoutFile(R.layout.item_format_image) - .holderClass(FormatImageViewHolder::class.java) - .build()) + MultiRecyclerViewControllerItem.Builder() + .viewType(FormatType.BULLET_3.ordinal) + .layoutFile(R.layout.item_format_bullet) + .holderClass(FormatBulletViewHolder::class.java) + .build()) list.add( - MultiRecyclerViewControllerItem.Builder() - .viewType(FormatType.SEPARATOR.ordinal) - .layoutFile(R.layout.item_format_separator) - .holderClass(FormatSeparatorViewHolder::class.java) - .build()) + MultiRecyclerViewControllerItem.Builder() + .viewType(FormatType.CHECKLIST_CHECKED.ordinal) + .layoutFile(R.layout.item_format_list) + .holderClass(FormatListViewHolder::class.java) + .build()) list.add( - MultiRecyclerViewControllerItem.Builder() - .viewType(FormatType.EMPTY.ordinal) - .layoutFile(R.layout.item_format_fab_space) - .holderClass(NullFormatHolder::class.java) - .build()) + MultiRecyclerViewControllerItem.Builder() + .viewType(FormatType.CHECKLIST_UNCHECKED.ordinal) + .layoutFile(R.layout.item_format_list) + .holderClass(FormatListViewHolder::class.java) + .build()) + list.add( + MultiRecyclerViewControllerItem.Builder() + .viewType(FormatType.IMAGE.ordinal) + .layoutFile(R.layout.item_format_image) + .holderClass(FormatImageViewHolder::class.java) + .build()) + list.add( + MultiRecyclerViewControllerItem.Builder() + .viewType(FormatType.SEPARATOR.ordinal) + .layoutFile(R.layout.item_format_separator) + .holderClass(FormatSeparatorViewHolder::class.java) + .build()) + list.add( + MultiRecyclerViewControllerItem.Builder() + .viewType(FormatType.EMPTY.ordinal) + .layoutFile(R.layout.item_format_fab_space) + .holderClass(NullFormatHolder::class.java) + .build()) return list } diff --git a/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatBulletViewHolder.kt b/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatBulletViewHolder.kt new file mode 100644 index 00000000..fd923863 --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatBulletViewHolder.kt @@ -0,0 +1,41 @@ +package com.maubis.scarlet.base.note.formats.recycler + +import android.content.Context +import android.view.View +import android.widget.ImageView +import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.core.format.Format +import com.maubis.scarlet.base.core.format.FormatType +import com.maubis.scarlet.base.support.ui.visibility + +class FormatBulletViewHolder(context: Context, view: View) : FormatTextViewHolder(context, view) { + + private val firstMargin: View = root.findViewById(R.id.first_margin) + private val secondMargin: View = root.findViewById(R.id.second_margin) + private val icon: ImageView = root.findViewById(R.id.icon) + + override fun populate(data: Format, config: FormatViewHolderConfig) { + super.populate(data, config) + icon.setColorFilter(config.iconColor) + + when (data.formatType) { + FormatType.BULLET_1 -> { + icon.setImageResource(R.drawable.icon_bullet_1) + firstMargin.visibility = visibility(false) + secondMargin.visibility = visibility(false) + } + FormatType.BULLET_2 -> { + icon.setImageResource(R.drawable.icon_bullet_2) + firstMargin.visibility = visibility(false) + secondMargin.visibility = visibility(true) + } + FormatType.BULLET_3 -> { + icon.setImageResource(R.drawable.icon_bullet_3) + firstMargin.visibility = visibility(true) + secondMargin.visibility = visibility(true) + } + else -> { + } // Ignore other cases + } + } +} diff --git a/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatImageViewHolder.kt b/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatImageViewHolder.kt index d1957b3c..bd9d39d0 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatImageViewHolder.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatImageViewHolder.kt @@ -1,21 +1,22 @@ package com.maubis.scarlet.base.note.formats.recycler import android.content.Context -import android.support.v7.app.AppCompatActivity import android.util.TypedValue import android.view.View import android.widget.ImageView import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity import com.github.bijoysingh.starter.util.ToastHelper import com.github.bijoysingh.uibasics.views.UITextView import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppImageStorage import com.maubis.scarlet.base.core.format.Format import com.maubis.scarlet.base.core.note.ImageLoadCallback -import com.maubis.scarlet.base.core.note.NoteImage -import com.maubis.scarlet.base.main.sheets.AlertBottomSheet import com.maubis.scarlet.base.main.sheets.openDeleteFormatDialog import com.maubis.scarlet.base.note.creation.sheet.FormatActionBottomSheet +import com.maubis.scarlet.base.support.sheets.openSheet import com.maubis.scarlet.base.support.ui.visibility +import com.maubis.scarlet.base.support.utils.maybeThrow import pl.aprilapps.easyphotopicker.EasyImage import java.io.File @@ -54,20 +55,25 @@ class FormatImageViewHolder(context: Context, view: View) : FormatViewHolderBase actionCamera.setOnClickListener { try { EasyImage.openCamera(context as AppCompatActivity, data.uid) - } catch (e: Exception) { + } catch (exception: Exception) { ToastHelper.show(context, "No camera app installed") + maybeThrow(context as AppCompatActivity, exception) } } actionGallery.setOnClickListener { try { EasyImage.openGallery(context as AppCompatActivity, data.uid) - } catch (e: Exception) { + } catch (exception: Exception) { ToastHelper.show(context, "No photo picker app installed") + maybeThrow(context as AppCompatActivity, exception) } } actionMove.setColorFilter(config.iconColor) actionMove.setOnClickListener { - FormatActionBottomSheet.openSheet(activity, config.noteUUID, data) + openSheet(activity, FormatActionBottomSheet().apply { + noteUUID = config.noteUUID + format = data + }) } imageToolbar.visibility = visibility(config.editable) @@ -76,22 +82,25 @@ class FormatImageViewHolder(context: Context, view: View) : FormatViewHolderBase noImageMessage.setBackgroundColor(imageToolbarBg) val fileName = data.text - if (!fileName.isBlank()) { - val file = NoteImage(context).getFile(config.noteUUID, data) - when (file.exists()) { - true -> populateFile(file) - false -> { - noImageMessage.setText(R.string.image_not_on_current_device) - noImageMessage.visibility = visibility(config.editable) - image.visibility = View.GONE - imageToolbar.visibility = View.GONE + when { + fileName.isBlank() -> image.visibility = View.GONE + else -> { + val file = sAppImageStorage.getFile(config.noteUUID, data) + when (file.exists()) { + true -> populateFile(file) + false -> { + noImageMessage.setText(R.string.image_not_on_current_device) + noImageMessage.visibility = visibility(config.editable) + image.visibility = View.GONE + imageToolbar.visibility = View.GONE + } } } } } fun populateFile(file: File) { - NoteImage(context).loadPersistentFileToImageView(image, file, object : ImageLoadCallback { + sAppImageStorage.loadPersistentFileToImageView(image, file, object : ImageLoadCallback { override fun onSuccess() { noImageMessage.visibility = View.GONE } diff --git a/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatListViewHolder.kt b/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatListViewHolder.kt index e3c1216d..83ee6cea 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatListViewHolder.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatListViewHolder.kt @@ -9,19 +9,21 @@ import android.widget.ImageView import com.maubis.scarlet.base.R import com.maubis.scarlet.base.core.format.Format import com.maubis.scarlet.base.core.format.FormatType +import com.maubis.scarlet.base.support.ui.visibility import com.maubis.scarlet.base.support.utils.getEditorActionListener class FormatListViewHolder(context: Context, view: View) : FormatTextViewHolder(context, view) { private val icon: ImageView = root.findViewById(R.id.icon) + private val close: ImageView = root.findViewById(R.id.close) init { edit.setOnEditorActionListener(getEditorActionListener( - runnable = { - activity.createOrChangeToNextFormat(format!!) - true - }, - preConditions = { format === null || !edit.isFocused } + runnable = { + activity.createOrChangeToNextFormat(format) + true + }, + preConditions = { !edit.isFocused } )) edit.imeOptions = EditorInfo.IME_ACTION_DONE edit.setRawInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES or InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE) @@ -40,16 +42,26 @@ class FormatListViewHolder(context: Context, view: View) : FormatTextViewHolder( FormatType.CHECKLIST_UNCHECKED -> { icon.setImageResource(R.drawable.ic_check_box_outline_blank_white_24dp) text.paintFlags = text.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv() - itemView.alpha = 1f + itemView.alpha = 0.8f } else -> { } // Ignore other cases } + close.visibility = visibility(config.editable) + close.setColorFilter(config.iconColor) + close.alpha = 0.8f + close.setOnClickListener { + activity.deleteFormat(format) + } + itemView.setOnClickListener { if (!config.editable) { activity.setFormatChecked(data, data.formatType != FormatType.CHECKLIST_CHECKED) } } + icon.setOnClickListener { + activity.setFormatChecked(data, data.formatType != FormatType.CHECKLIST_CHECKED) + } } } diff --git a/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatSeparatorViewHolder.kt b/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatSeparatorViewHolder.kt index 709c88ed..a0f6d847 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatSeparatorViewHolder.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatSeparatorViewHolder.kt @@ -7,6 +7,7 @@ import com.maubis.scarlet.base.R import com.maubis.scarlet.base.core.format.Format import com.maubis.scarlet.base.note.creation.sheet.FormatActionBottomSheet import com.maubis.scarlet.base.note.creation.sheet.sEditorMoveHandles +import com.maubis.scarlet.base.support.sheets.openSheet import com.maubis.scarlet.base.support.ui.visibility class FormatSeparatorViewHolder(context: Context, view: View) : FormatViewHolderBase(context, view) { @@ -21,7 +22,10 @@ class FormatSeparatorViewHolder(context: Context, view: View) : FormatViewHolder actionMove.setColorFilter(config.iconColor) actionMove.visibility = visibility(config.editable) actionMove.setOnClickListener { - FormatActionBottomSheet.openSheet(activity, config.noteUUID, data) + openSheet(activity, FormatActionBottomSheet().apply { + noteUUID = config.noteUUID + format = data + }) } if (config.editable && !sEditorMoveHandles) { actionMove.visibility = View.INVISIBLE diff --git a/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatTextViewHolder.kt b/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatTextViewHolder.kt index c9186c74..7c052104 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatTextViewHolder.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatTextViewHolder.kt @@ -9,6 +9,7 @@ import android.view.View import android.widget.EditText import android.widget.ImageView import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity import com.maubis.markdown.Markdown import com.maubis.markdown.spannable.clearMarkdownSpans import com.maubis.markdown.spannable.setFormats @@ -19,7 +20,9 @@ import com.maubis.scarlet.base.core.format.MarkdownType import com.maubis.scarlet.base.note.creation.sheet.FormatActionBottomSheet import com.maubis.scarlet.base.note.creation.sheet.sEditorLiveMarkdown import com.maubis.scarlet.base.note.creation.sheet.sEditorMoveHandles +import com.maubis.scarlet.base.support.sheets.openSheet import com.maubis.scarlet.base.support.ui.visibility +import com.maubis.scarlet.base.support.utils.maybeThrow open class FormatTextViewHolder(context: Context, view: View) : FormatViewHolderBase(context, view), TextWatcher { @@ -27,16 +30,16 @@ open class FormatTextViewHolder(context: Context, view: View) : FormatViewHolder protected val edit: EditText = root.findViewById(R.id.edit) protected val actionMove: ImageView = root.findViewById(R.id.action_move_icon) - protected var format: Format? = null + protected lateinit var format: Format init { edit.addTextChangedListener(this) edit.onFocusChangeListener = View.OnFocusChangeListener { _, _ -> activity.focusedFormat = format } edit.setRawInputType( - InputType.TYPE_TEXT_FLAG_CAP_SENTENCES - or InputType.TYPE_TEXT_FLAG_MULTI_LINE - or InputType.TYPE_CLASS_TEXT - or InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE + InputType.TYPE_TEXT_FLAG_CAP_SENTENCES + or InputType.TYPE_TEXT_FLAG_MULTI_LINE + or InputType.TYPE_CLASS_TEXT + or InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE ) } @@ -55,15 +58,17 @@ open class FormatTextViewHolder(context: Context, view: View) : FormatViewHolder text.setBackgroundColor(config.backgroundColor) text.setLinkTextColor(config.accentColor) text.setTextIsSelectable(true) + text.setTypeface(config.typeface, config.typefaceStyle) text.visibility = visibility(!config.editable) edit.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize) edit.setTextColor(config.secondaryTextColor) edit.setHintTextColor(config.hintTextColor) edit.setBackgroundColor(config.backgroundColor) + edit.setTypeface(config.typeface, config.typefaceStyle) edit.visibility = visibility(config.editable) edit.isEnabled = config.editable - + showHintWhenTextIsEmpty() when { config.editable -> edit.setText(data.text) @@ -74,29 +79,43 @@ open class FormatTextViewHolder(context: Context, view: View) : FormatViewHolder actionMove.setColorFilter(config.iconColor) actionMove.visibility = visibility(config.editable) actionMove.setOnClickListener { - FormatActionBottomSheet.openSheet(activity, config.noteUUID, data) + openSheet(activity, FormatActionBottomSheet().apply { + noteUUID = config.noteUUID + format = data + }) } if (config.editable && !sEditorMoveHandles) { actionMove.visibility = View.INVISIBLE } } - override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { + override fun beforeTextChanged(text: CharSequence, start: Int, count: Int, after: Int) { } - override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { - if (format === null || !edit.isFocused) { + override fun onTextChanged(text: CharSequence, start: Int, before: Int, count: Int) { + if (!edit.isFocused) { return } - format!!.text = s.toString() - activity.setFormat(format!!) + + format.text = text.toString() + activity.setFormat(format) + showHintWhenTextIsEmpty() + } + + // Workaround to avoid this holder being higher than the text contained in it when hint text + // occupies more lines than the text inserted by the user + private fun showHintWhenTextIsEmpty() { + edit.hint = when { + format.text.isEmpty() -> format.getHint() + else -> "" + } } override fun afterTextChanged(text: Editable) { text.clearMarkdownSpans() if (sEditorLiveMarkdown) { - text.setFormats(Markdown.getSpanInfo(format!!.text).spans) + text.setFormats(Markdown.getSpanInfo(format.text).spans) } } @@ -126,8 +145,25 @@ open class FormatTextViewHolder(context: Context, view: View) : FormatViewHolder try { val additionTokenLength = (if (markdownType.requiresNewLine) 1 else 0) + markdownType.startToken.length edit.setSelection(Math.min(startString.length + additionTokenLength, edit.text.length)) - } catch (_: Exception) { - // Ignore the exception + } catch (exception: Exception) { + maybeThrow(context as AppCompatActivity, exception) + } + } + + private fun Format.getHint(): String { + return when (formatType) { + FormatType.TEXT, FormatType.TAG -> context.getString(R.string.format_hint_text) + FormatType.HEADING, + FormatType.SUB_HEADING, + FormatType.HEADING_3 + -> context.getString(R.string.format_hint_heading) + FormatType.NUMBERED_LIST, + FormatType.CHECKLIST_UNCHECKED, + FormatType.CHECKLIST_CHECKED + -> context.getString(R.string.format_hint_list) + FormatType.CODE -> context.getString(R.string.format_hint_code) + FormatType.QUOTE -> context.getString(R.string.format_hint_quote) + else -> "" } } } diff --git a/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatViewHolderBase.kt b/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatViewHolderBase.kt index d6427ef9..794b046c 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatViewHolderBase.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/formats/recycler/FormatViewHolderBase.kt @@ -1,21 +1,23 @@ package com.maubis.scarlet.base.note.formats.recycler import android.content.Context +import android.graphics.Typeface import android.os.Bundle -import android.support.v4.content.ContextCompat import android.view.View +import androidx.core.content.ContextCompat import com.github.bijoysingh.starter.recyclerview.RecyclerViewHolder import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface import com.maubis.scarlet.base.core.format.Format import com.maubis.scarlet.base.core.format.FormatType import com.maubis.scarlet.base.note.creation.activity.INTENT_KEY_NOTE_ID import com.maubis.scarlet.base.note.creation.activity.ViewAdvancedNoteActivity +import com.maubis.scarlet.base.note.creation.sheet.sNoteDefaultColor import com.maubis.scarlet.base.settings.sheet.STORE_KEY_TEXT_SIZE import com.maubis.scarlet.base.settings.sheet.SettingsOptionsBottomSheet import com.maubis.scarlet.base.settings.sheet.TEXT_SIZE_DEFAULT -import com.maubis.scarlet.base.settings.sheet.UISettingsOptionsBottomSheet.Companion.useNoteColorAsBackground -import com.maubis.scarlet.base.settings.sheet.sNoteDefaultColor +import com.maubis.scarlet.base.settings.sheet.sUIUseNoteColorAsBackground import com.maubis.scarlet.base.support.ui.ColorUtil import com.maubis.scarlet.base.support.ui.Theme import com.maubis.scarlet.base.support.ui.ThemeColorType @@ -24,17 +26,18 @@ const val KEY_EDITABLE = "KEY_EDITABLE" const val KEY_NOTE_COLOR = "KEY_NOTE_COLOR" data class FormatViewHolderConfig( - val editable: Boolean, - val isMarkdownEnabled: Boolean, - val fontSize: Float, - val backgroundColor: Int, - val secondaryTextColor: Int, - val tertiaryTextColor: Int, - val iconColor: Int, - val hintTextColor: Int, - val accentColor: Int, - val noteUUID: String) - + val editable: Boolean, + val isMarkdownEnabled: Boolean, + val fontSize: Float, + val backgroundColor: Int, + val secondaryTextColor: Int, + val tertiaryTextColor: Int, + val iconColor: Int, + val hintTextColor: Int, + val accentColor: Int, + val noteUUID: String, + val typeface: Typeface, + val typefaceStyle: Int) abstract class FormatViewHolderBase(context: Context, view: View) : RecyclerViewHolder(context, view) { @@ -46,55 +49,69 @@ abstract class FormatViewHolderBase(context: Context, view: View) : RecyclerView val tertiaryTextColor: Int val iconColor: Int val hintTextColor: Int - val theme = CoreConfig.instance.themeController() val isLightBackground = ColorUtil.isLightColored(noteColor) + val linkColor: Int when { - !useNoteColorAsBackground -> { - secondaryTextColor = theme.get(ThemeColorType.SECONDARY_TEXT) - tertiaryTextColor = theme.get(ThemeColorType.TERTIARY_TEXT) - iconColor = theme.get(ThemeColorType.TOOLBAR_ICON) - hintTextColor = theme.get(ThemeColorType.HINT_TEXT) + !sUIUseNoteColorAsBackground -> { + secondaryTextColor = sAppTheme.get(ThemeColorType.SECONDARY_TEXT) + tertiaryTextColor = sAppTheme.get(ThemeColorType.TERTIARY_TEXT) + iconColor = sAppTheme.get(ThemeColorType.TOOLBAR_ICON) + hintTextColor = sAppTheme.get(ThemeColorType.HINT_TEXT) + linkColor = sAppTheme.get(ThemeColorType.ACCENT_TEXT) } isLightBackground -> { - secondaryTextColor = theme.get(context, Theme.LIGHT, ThemeColorType.SECONDARY_TEXT) - tertiaryTextColor = theme.get(context, Theme.LIGHT, ThemeColorType.TERTIARY_TEXT) - iconColor = theme.get(context, Theme.LIGHT, ThemeColorType.TOOLBAR_ICON) - hintTextColor = theme.get(context, Theme.LIGHT, ThemeColorType.HINT_TEXT) + secondaryTextColor = sAppTheme.get(context, Theme.LIGHT, ThemeColorType.SECONDARY_TEXT) + tertiaryTextColor = sAppTheme.get(context, Theme.LIGHT, ThemeColorType.TERTIARY_TEXT) + iconColor = sAppTheme.get(context, Theme.LIGHT, ThemeColorType.TOOLBAR_ICON) + hintTextColor = sAppTheme.get(context, Theme.LIGHT, ThemeColorType.HINT_TEXT) + linkColor = ContextCompat.getColor(context, R.color.colorAccentYellowLight) } else -> { - secondaryTextColor = theme.get(context, Theme.DARK, ThemeColorType.SECONDARY_TEXT) - tertiaryTextColor = theme.get(context, Theme.DARK, ThemeColorType.TERTIARY_TEXT) - iconColor = theme.get(context, Theme.DARK, ThemeColorType.TOOLBAR_ICON) - hintTextColor = theme.get(context, Theme.DARK, ThemeColorType.HINT_TEXT) + secondaryTextColor = sAppTheme.get(context, Theme.DARK, ThemeColorType.SECONDARY_TEXT) + tertiaryTextColor = sAppTheme.get(context, Theme.DARK, ThemeColorType.TERTIARY_TEXT) + iconColor = sAppTheme.get(context, Theme.DARK, ThemeColorType.TOOLBAR_ICON) + hintTextColor = sAppTheme.get(context, Theme.DARK, ThemeColorType.HINT_TEXT) + linkColor = ContextCompat.getColor(context, R.color.colorAccentYellowDark) } } val - config = FormatViewHolderConfig( - editable = !(extra != null - && extra.containsKey(KEY_EDITABLE) - && !extra.getBoolean(KEY_EDITABLE)), - isMarkdownEnabled = (extra == null - || extra.getBoolean(SettingsOptionsBottomSheet.KEY_MARKDOWN_ENABLED, true) - || data.forcedMarkdown), - fontSize = { - val fontSize = extra?.getInt(STORE_KEY_TEXT_SIZE, TEXT_SIZE_DEFAULT) - ?: TEXT_SIZE_DEFAULT - when (data.formatType) { - FormatType.HEADING -> fontSize.toFloat() + 4 - FormatType.SUB_HEADING -> fontSize.toFloat() + 2 - else -> fontSize.toFloat() - } - }(), - backgroundColor = when (data.formatType) { - FormatType.CODE, FormatType.IMAGE -> CoreConfig.instance.themeController().get(context, R.color.code_light, R.color.code_dark) - else -> ContextCompat.getColor(context, R.color.transparent) - }, - secondaryTextColor = secondaryTextColor, - tertiaryTextColor = tertiaryTextColor, - iconColor = iconColor, - hintTextColor = hintTextColor, - accentColor = theme.get(ThemeColorType.ACCENT_TEXT), - noteUUID = extra?.getString(INTENT_KEY_NOTE_ID) ?: "default") + config = FormatViewHolderConfig( + editable = !(extra != null + && extra.containsKey(KEY_EDITABLE) + && !extra.getBoolean(KEY_EDITABLE)), + isMarkdownEnabled = (extra == null + || extra.getBoolean(SettingsOptionsBottomSheet.KEY_MARKDOWN_ENABLED, true) + || data.forcedMarkdown) && (data.formatType != FormatType.CODE), + fontSize = { + val fontSize = extra?.getInt(STORE_KEY_TEXT_SIZE, TEXT_SIZE_DEFAULT) + ?: TEXT_SIZE_DEFAULT + when (data.formatType) { + FormatType.HEADING -> fontSize.toFloat() + 4 + FormatType.SUB_HEADING -> fontSize.toFloat() + 2 + else -> fontSize.toFloat() + } + }(), + backgroundColor = when (data.formatType) { + FormatType.CODE, FormatType.IMAGE -> sAppTheme.get(context, R.color.code_light, R.color.code_dark) + else -> ContextCompat.getColor(context, R.color.transparent) + }, + secondaryTextColor = secondaryTextColor, + tertiaryTextColor = tertiaryTextColor, + iconColor = iconColor, + hintTextColor = hintTextColor, + accentColor = linkColor, + noteUUID = extra?.getString(INTENT_KEY_NOTE_ID) ?: "default", + typeface = when (data.formatType) { + FormatType.HEADING -> sAppTypeface.subHeading() + FormatType.SUB_HEADING -> sAppTypeface.title() + FormatType.HEADING_3 -> sAppTypeface.title() + FormatType.CODE -> sAppTypeface.code() + else -> sAppTypeface.text() + }, + typefaceStyle = when (data.formatType) { + FormatType.HEADING, FormatType.SUB_HEADING, FormatType.HEADING_3 -> Typeface.BOLD + else -> Typeface.NORMAL + }) populate(data, config) diff --git a/base/src/main/java/com/maubis/scarlet/base/note/recycler/NoteAppAdapter.kt b/base/src/main/java/com/maubis/scarlet/base/note/recycler/NoteAppAdapter.kt index c9a98bae..03e4772f 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/recycler/NoteAppAdapter.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/recycler/NoteAppAdapter.kt @@ -9,13 +9,17 @@ import com.maubis.scarlet.base.main.recycler.EmptyRecyclerHolder import com.maubis.scarlet.base.main.recycler.InformationRecyclerHolder import com.maubis.scarlet.base.main.recycler.ToolbarMainRecyclerHolder import com.maubis.scarlet.base.note.folder.FolderRecyclerHolder +import com.maubis.scarlet.base.note.folder.SelectorFolderRecyclerHolder import com.maubis.scarlet.base.note.selection.recycler.SelectableNoteRecyclerViewHolder import com.maubis.scarlet.base.support.recycler.RecyclerItem import java.util.* class NoteAppAdapter : MultiRecyclerViewAdapter { - @JvmOverloads constructor(context: Context, staggered: Boolean = false, isTablet: Boolean = false) : super(context, getRecyclerItemControllerList(staggered, isTablet)) {} + @JvmOverloads + constructor(context: Context, staggered: Boolean = false, isTablet: Boolean = false) : super( + context, getRecyclerItemControllerList(staggered, isTablet)) { + } constructor(context: Context, list: List>) : super(context, list) {} @@ -25,35 +29,41 @@ class NoteAppAdapter : MultiRecyclerViewAdapter { } fun getRecyclerItemControllerList( - staggered: Boolean, - isTablet: Boolean): List> { + staggered: Boolean, + isTablet: Boolean): List> { val list = ArrayList>() - list.add(MultiRecyclerViewControllerItem.Builder() + list.add( + MultiRecyclerViewControllerItem.Builder() .viewType(RecyclerItem.Type.NOTE.ordinal) .layoutFile(if (staggered && !isTablet) R.layout.item_note_staggered else R.layout.item_note) .holderClass(NoteRecyclerHolder::class.java) .build()) - list.add(MultiRecyclerViewControllerItem.Builder() + list.add( + MultiRecyclerViewControllerItem.Builder() .viewType(RecyclerItem.Type.EMPTY.ordinal) .layoutFile(R.layout.item_no_notes) .holderClass(EmptyRecyclerHolder::class.java) .build()) - list.add(MultiRecyclerViewControllerItem.Builder() + list.add( + MultiRecyclerViewControllerItem.Builder() .viewType(RecyclerItem.Type.INFORMATION.ordinal) .layoutFile(R.layout.item_information) .holderClass(InformationRecyclerHolder::class.java) .build()) - list.add(MultiRecyclerViewControllerItem.Builder() + list.add( + MultiRecyclerViewControllerItem.Builder() .viewType(RecyclerItem.Type.FILE.ordinal) .layoutFile(R.layout.item_import_file) .holderClass(FileImportViewHolder::class.java) .build()) - list.add(MultiRecyclerViewControllerItem.Builder() + list.add( + MultiRecyclerViewControllerItem.Builder() .viewType(RecyclerItem.Type.FOLDER.ordinal) .layoutFile(R.layout.item_folder) .holderClass(FolderRecyclerHolder::class.java) .build()) - list.add(MultiRecyclerViewControllerItem.Builder() + list.add( + MultiRecyclerViewControllerItem.Builder() .viewType(RecyclerItem.Type.TOOLBAR.ordinal) .layoutFile(R.layout.toolbar_main) .holderClass(ToolbarMainRecyclerHolder::class.java) @@ -62,15 +72,23 @@ fun getRecyclerItemControllerList( } fun getSelectableRecyclerItemControllerList( - staggered: Boolean, - isTablet: Boolean): List> { + staggered: Boolean, + isTablet: Boolean): List> { val list = ArrayList>() - list.add(MultiRecyclerViewControllerItem.Builder() + list.add( + MultiRecyclerViewControllerItem.Builder() .viewType(RecyclerItem.Type.NOTE.ordinal) .layoutFile(if (staggered && !isTablet) R.layout.item_note_staggered else R.layout.item_note) .holderClass(SelectableNoteRecyclerViewHolder::class.java) .build()) - list.add(MultiRecyclerViewControllerItem.Builder() + list.add( + MultiRecyclerViewControllerItem.Builder() + .viewType(RecyclerItem.Type.FOLDER.ordinal) + .layoutFile(R.layout.item_selector_folder) + .holderClass(SelectorFolderRecyclerHolder::class.java) + .build()) + list.add( + MultiRecyclerViewControllerItem.Builder() .viewType(RecyclerItem.Type.EMPTY.ordinal) .layoutFile(R.layout.item_no_notes) .holderClass(EmptyRecyclerHolder::class.java) diff --git a/base/src/main/java/com/maubis/scarlet/base/note/recycler/NoteRecyclerHolder.kt b/base/src/main/java/com/maubis/scarlet/base/note/recycler/NoteRecyclerHolder.kt index 862035e6..ee7a8be5 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/recycler/NoteRecyclerHolder.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/recycler/NoteRecyclerHolder.kt @@ -5,12 +5,12 @@ import android.os.Bundle import android.view.View import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.database.room.note.Note -import com.maubis.scarlet.base.main.sheets.EnterPincodeBottomSheet import com.maubis.scarlet.base.note.actions.NoteOptionsBottomSheet import com.maubis.scarlet.base.note.copy +import com.maubis.scarlet.base.note.creation.activity.NoteIntentRouterActivity import com.maubis.scarlet.base.note.edit import com.maubis.scarlet.base.note.share -import com.maubis.scarlet.base.note.view +import com.maubis.scarlet.base.security.sheets.openUnlockSheet import com.maubis.scarlet.base.support.ui.ThemedActivity class NoteRecyclerHolder(context: Context, view: View) : NoteRecyclerViewHolderBase(context, view) { @@ -47,17 +47,10 @@ class NoteRecyclerHolder(context: Context, view: View) : NoteRecyclerViewHolderB private fun actionOrUnlockNote(data: Note, runnable: Runnable) { if (context is ThemedActivity && data.locked) { - EnterPincodeBottomSheet.openUnlockSheet( - context as ThemedActivity, - object : EnterPincodeBottomSheet.PincodeSuccessListener { - override fun onFailure() { - actionOrUnlockNote(data, runnable) - } - - override fun onSuccess() { - runnable.run() - } - }) + openUnlockSheet( + activity = context as ThemedActivity, + onUnlockSuccess = { runnable.run() }, + onUnlockFailure = { actionOrUnlockNote(data, runnable) }) return } else if (data.locked) { return @@ -66,6 +59,6 @@ class NoteRecyclerHolder(context: Context, view: View) : NoteRecyclerViewHolderB } private fun openNote(data: Note) { - data.view(context) + context.startActivity(NoteIntentRouterActivity.view(context, data)) } } diff --git a/base/src/main/java/com/maubis/scarlet/base/note/recycler/NoteRecyclerItem.kt b/base/src/main/java/com/maubis/scarlet/base/note/recycler/NoteRecyclerItem.kt index 960a5af4..8ffee86b 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/recycler/NoteRecyclerItem.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/recycler/NoteRecyclerItem.kt @@ -1,32 +1,28 @@ package com.maubis.scarlet.base.note.recycler import android.content.Context -import android.support.v4.content.ContextCompat +import androidx.core.content.ContextCompat import com.maubis.markdown.Markdown import com.maubis.scarlet.base.R import com.maubis.scarlet.base.core.note.getNoteState import com.maubis.scarlet.base.core.note.getReminderV2 import com.maubis.scarlet.base.database.room.note.Note -import com.maubis.scarlet.base.note.* -import com.maubis.scarlet.base.note.creation.sheet.sEditorMarkdownEnabled -import com.maubis.scarlet.base.settings.sheet.UISettingsOptionsBottomSheet.Companion.sMarkdownEnabledHome +import com.maubis.scarlet.base.note.adjustedColor +import com.maubis.scarlet.base.note.getDisplayTime +import com.maubis.scarlet.base.note.getImageFile +import com.maubis.scarlet.base.note.getLockedAwareTextForHomeList +import com.maubis.scarlet.base.note.getTagString import com.maubis.scarlet.base.settings.sheet.sNoteItemLineCount import com.maubis.scarlet.base.support.recycler.RecyclerItem import com.maubis.scarlet.base.support.ui.ColorUtil class NoteRecyclerItem(context: Context, val note: Note) : RecyclerItem() { - private val isLightShaded = ColorUtil.isLightColored(note.color) - private val isMarkdownEnabled = sEditorMarkdownEnabled && sMarkdownEnabledHome val lineCount = sNoteItemLineCount + val backgroundColor = note.adjustedColor() + val isLightShaded = ColorUtil.isLightColored(backgroundColor) - val title = note.getMarkdownTitle(isMarkdownEnabled) - val titleColor = when (isLightShaded) { - true -> ContextCompat.getColor(context, R.color.dark_tertiary_text) - false -> ContextCompat.getColor(context, R.color.light_primary_text) - } - - val description = note.getLockedText(isMarkdownEnabled) + val description = note.getLockedAwareTextForHomeList() val descriptionColor = when (isLightShaded) { true -> ContextCompat.getColor(context, R.color.dark_tertiary_text) false -> ContextCompat.getColor(context, R.color.light_primary_text) @@ -60,5 +56,5 @@ class NoteRecyclerItem(context: Context, val note: Note) : RecyclerItem() { val imageSource = note.getImageFile() val disableBackup = note.disableBackup - override val type = RecyclerItem.Type.NOTE + override val type = Type.NOTE } diff --git a/base/src/main/java/com/maubis/scarlet/base/note/recycler/NoteRecyclerViewHolderBase.kt b/base/src/main/java/com/maubis/scarlet/base/note/recycler/NoteRecyclerViewHolderBase.kt index 29cb489c..2c00a1fe 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/recycler/NoteRecyclerViewHolderBase.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/recycler/NoteRecyclerViewHolderBase.kt @@ -1,19 +1,22 @@ package com.maubis.scarlet.base.note.recycler import android.content.Context +import android.graphics.Typeface import android.os.Bundle -import android.support.v7.widget.CardView import android.view.View import android.view.View.GONE import android.view.View.VISIBLE import android.widget.ImageView import android.widget.TextView +import androidx.cardview.widget.CardView import com.github.bijoysingh.starter.recyclerview.RecyclerViewHolder import com.github.bijoysingh.starter.util.TextUtils import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.database.room.note.Note -import com.maubis.scarlet.base.core.note.NoteImage +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppImageStorage +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface import com.maubis.scarlet.base.core.note.NoteState +import com.maubis.scarlet.base.database.room.note.Note +import com.maubis.scarlet.base.note.isNoteLockedButAppUnlocked import com.maubis.scarlet.base.support.recycler.RecyclerItem import com.maubis.scarlet.base.support.ui.visibility import com.maubis.scarlet.base.support.utils.trim @@ -23,7 +26,6 @@ open class NoteRecyclerViewHolderBase(context: Context, view: View) : RecyclerVi protected val view: CardView protected val tags: TextView protected val image: ImageView - protected val title: TextView protected val description: TextView protected val edit: ImageView protected val share: ImageView @@ -33,6 +35,7 @@ open class NoteRecyclerViewHolderBase(context: Context, view: View) : RecyclerVi protected val bottomLayout: View protected val pinIndicator: ImageView + protected val unlockIndicator: ImageView protected val reminderIndicator: ImageView protected val stateIndicator: ImageView protected val backupIndicator: ImageView @@ -41,13 +44,13 @@ open class NoteRecyclerViewHolderBase(context: Context, view: View) : RecyclerVi this.view = view as CardView tags = view.findViewById(R.id.tags) image = view.findViewById(R.id.image) - title = view.findViewById(R.id.title) description = view.findViewById(R.id.description) share = view.findViewById(R.id.share_button) delete = view.findViewById(R.id.delete_button) copy = view.findViewById(R.id.copy_button) moreOptions = view.findViewById(R.id.options_button) pinIndicator = view.findViewById(R.id.pin_icon) + unlockIndicator = view.findViewById(R.id.unlock_icon) reminderIndicator = view.findViewById(R.id.reminder_icon) edit = view.findViewById(R.id.edit_button) bottomLayout = view.findViewById(R.id.bottom_toolbar_layout) @@ -57,28 +60,23 @@ open class NoteRecyclerViewHolderBase(context: Context, view: View) : RecyclerVi override fun populate(itemData: RecyclerItem, extra: Bundle?) { val item = itemData as NoteRecyclerItem - setTitle(item) setDescription(item) setImage(item) setIndicators(item) setMetaText(item) + view.alpha = if (item.note.isNoteLockedButAppUnlocked()) 0.7f else 1.0f view.setOnClickListener { viewClick(item.note, extra) } view.setOnLongClickListener { viewLongClick(item.note, extra) false } - view.setCardBackgroundColor(item.note.color) + view.setCardBackgroundColor(item.backgroundColor) setActionBar(item, extra) } - private fun setTitle(note: NoteRecyclerItem) { - title.text = note.title - title.visibility = if (note.title.isEmpty()) View.GONE else View.VISIBLE - title.setTextColor(note.titleColor) - } - private fun setDescription(note: NoteRecyclerItem) { + description.setTypeface(sAppTypeface.text(), Typeface.NORMAL) description.text = note.description description.maxLines = note.lineCount description.setTextColor(note.descriptionColor) @@ -88,7 +86,7 @@ open class NoteRecyclerViewHolderBase(context: Context, view: View) : RecyclerVi val isImageAvailable = !note.imageSource.isBlank() image.visibility = visibility(isImageAvailable) if (isImageAvailable) { - NoteImage(context).loadThumbnailFileToImageView(note.note.uuid, note.imageSource, image) + sAppImageStorage.loadThumbnailFileToImageView(note.note.uuid, note.imageSource, image) } } @@ -111,14 +109,17 @@ open class NoteRecyclerViewHolderBase(context: Context, view: View) : RecyclerVi } NoteState.DEFAULT -> stateIndicator.visibility = GONE } + unlockIndicator.visibility = visibility(note.note.locked) pinIndicator.setColorFilter(note.indicatorColor) stateIndicator.setColorFilter(note.indicatorColor) reminderIndicator.setColorFilter(note.indicatorColor) backupIndicator.setColorFilter(note.indicatorColor) + unlockIndicator.setColorFilter(note.indicatorColor) } private fun setMetaText(note: NoteRecyclerItem) { + tags.typeface = sAppTypeface.text() when { !TextUtils.isNullOrEmpty(note.tagsSource) -> { tags.setTextColor(note.tagsColor) diff --git a/base/src/main/java/com/maubis/scarlet/base/note/reminders/ReminderJob.kt b/base/src/main/java/com/maubis/scarlet/base/note/reminders/ReminderJob.kt index 6435b733..24199ff5 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/reminders/ReminderJob.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/reminders/ReminderJob.kt @@ -4,6 +4,7 @@ import com.evernote.android.job.Job import com.evernote.android.job.JobManager import com.evernote.android.job.JobRequest import com.evernote.android.job.util.support.PersistableBundleCompat +import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb import com.maubis.scarlet.base.core.note.Reminder import com.maubis.scarlet.base.core.note.ReminderInterval import com.maubis.scarlet.base.core.note.getReminderV2 @@ -12,11 +13,10 @@ import com.maubis.scarlet.base.note.saveWithoutSync import com.maubis.scarlet.base.notification.NotificationConfig import com.maubis.scarlet.base.notification.NotificationHandler import com.maubis.scarlet.base.notification.REMINDER_NOTIFICATION_CHANNEL_ID -import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb +import com.maubis.scarlet.base.support.utils.maybeThrow import java.util.* import java.util.concurrent.TimeUnit - class ReminderJob : Job() { override fun onRunJob(params: Params): Job.Result { @@ -33,9 +33,9 @@ class ReminderJob : Job() { val reminder = note.getReminderV2() if (reminder?.interval == ReminderInterval.DAILY) { val reminderV2 = Reminder( - 0, - nextJobTimestamp(reminder.timestamp, System.currentTimeMillis()), - ReminderInterval.DAILY) + 0, + nextJobTimestamp(reminder.timestamp, System.currentTimeMillis()), + ReminderInterval.DAILY) reminderV2.uid = scheduleJob(note.uuid, reminderV2) note.setReminderV2(reminderV2) note.saveWithoutSync(context) @@ -43,7 +43,8 @@ class ReminderJob : Job() { note.meta = "" note.saveWithoutSync(context) } - } catch (e: Exception) { + } catch (exception: Exception) { + maybeThrow(exception) } return Job.Result.SUCCESS @@ -63,10 +64,10 @@ class ReminderJob : Job() { } return JobRequest.Builder(ReminderJob.TAG) - .setExact(deltaTime) - .setExtras(extras) - .build() - .schedule() + .setExact(deltaTime) + .setExtras(extras) + .build() + .schedule() } fun nextJobTimestamp(timestamp: Long, currentTimestamp: Long): Long { diff --git a/base/src/main/java/com/maubis/scarlet/base/note/reminders/ReminderJobCreator.kt b/base/src/main/java/com/maubis/scarlet/base/note/reminders/ReminderJobCreator.kt index 07859f3d..ef055203 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/reminders/ReminderJobCreator.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/reminders/ReminderJobCreator.kt @@ -1,6 +1,6 @@ package com.maubis.scarlet.base.note.reminders -import android.support.annotation.Nullable +import androidx.annotation.Nullable import com.evernote.android.job.Job import com.evernote.android.job.JobCreator diff --git a/base/src/main/java/com/maubis/scarlet/base/note/reminders/sheet/ReminderBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/note/reminders/sheet/ReminderBottomSheet.kt index 73a97869..85150181 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/reminders/sheet/ReminderBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/reminders/sheet/ReminderBottomSheet.kt @@ -8,7 +8,7 @@ import android.widget.TextView import com.github.bijoysingh.starter.util.DateFormatter import com.github.bijoysingh.uibasics.views.UIActionView import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme import com.maubis.scarlet.base.core.note.Reminder import com.maubis.scarlet.base.core.note.ReminderInterval import com.maubis.scarlet.base.core.note.getReminderV2 @@ -21,16 +21,17 @@ import com.maubis.scarlet.base.support.sheets.LithoChooseOptionsItem import com.maubis.scarlet.base.support.ui.ThemeColorType import com.maubis.scarlet.base.support.ui.ThemedActivity import com.maubis.scarlet.base.support.ui.ThemedBottomSheetFragment +import com.maubis.scarlet.base.support.utils.sDateFormat import java.util.* - +// TODO: Upgrade to Litho class ReminderBottomSheet : ThemedBottomSheetFragment() { var selectedNote: Note? = null var reminder: Reminder = Reminder( - 0, - Calendar.getInstance().timeInMillis, - ReminderInterval.ONCE) + 0, + Calendar.getInstance().timeInMillis, + ReminderInterval.ONCE) override fun getBackgroundView(): Int { return R.id.container_layout @@ -49,9 +50,9 @@ class ReminderBottomSheet : ThemedBottomSheetFragment() { val calendar = Calendar.getInstance() reminder = note.getReminderV2() ?: Reminder( - 0, - calendar.timeInMillis, - ReminderInterval.ONCE) + 0, + calendar.timeInMillis, + ReminderInterval.ONCE) val isNewReminder = reminder.uid == 0 if (isNewReminder) { @@ -70,9 +71,14 @@ class ReminderBottomSheet : ThemedBottomSheetFragment() { } fun setListeners(note: Note, isNewReminder: Boolean) { - val reminderDate = dialog.findViewById(R.id.reminder_date) - val reminderTime = dialog.findViewById(R.id.reminder_time) - val reminderRepeat = dialog.findViewById(R.id.reminder_repeat) + val dlg = dialog + if (dlg === null) { + return + } + + val reminderDate = dlg.findViewById(R.id.reminder_date) + val reminderTime = dlg.findViewById(R.id.reminder_time) + val reminderRepeat = dlg.findViewById(R.id.reminder_repeat) reminderDate.setOnClickListener { if (reminder.interval == ReminderInterval.ONCE) { @@ -86,8 +92,8 @@ class ReminderBottomSheet : ThemedBottomSheetFragment() { openFrequencyDialog() } - val removeAlarm = dialog.findViewById(R.id.remove_alarm) - val setAlarm = dialog.findViewById(R.id.set_alarm) + val removeAlarm = dlg.findViewById(R.id.remove_alarm) + val setAlarm = dlg.findViewById(R.id.set_alarm) if (isNewReminder) { removeAlarm.visibility = GONE } @@ -130,87 +136,96 @@ class ReminderBottomSheet : ThemedBottomSheetFragment() { fun openFrequencyDialog() { val isSelected = fun(interval: ReminderInterval): Boolean = interval == reminder.interval com.maubis.scarlet.base.support.sheets.openSheet( - themedActivity() as ThemedActivity, - GenericOptionsBottomSheet().apply { - title = R.string.reminder_sheet_repeat - options = arrayListOf( - LithoChooseOptionsItem( - title = getReminderIntervalLabel(ReminderInterval.ONCE), - listener = { - reminder.interval = ReminderInterval.ONCE - setContent(reminder) - }, - selected = isSelected(ReminderInterval.ONCE) - ), - LithoChooseOptionsItem( - title = getReminderIntervalLabel(ReminderInterval.DAILY), - listener = { - reminder.interval = ReminderInterval.DAILY - setContent(reminder) - }, - selected = isSelected(ReminderInterval.DAILY) - ) + themedActivity() as ThemedActivity, + GenericOptionsBottomSheet().apply { + title = R.string.reminder_sheet_repeat + options = arrayListOf( + LithoChooseOptionsItem( + title = getReminderIntervalLabel(ReminderInterval.ONCE), + listener = { + reminder.interval = ReminderInterval.ONCE + setContent(reminder) + }, + selected = isSelected(ReminderInterval.ONCE) + ), + LithoChooseOptionsItem( + title = getReminderIntervalLabel(ReminderInterval.DAILY), + listener = { + reminder.interval = ReminderInterval.DAILY + setContent(reminder) + }, + selected = isSelected(ReminderInterval.DAILY) ) - } + ) + } ) } fun openDatePickerDialog() { val calendar = reminder.toCalendar() val dialog = DatePickerDialog( - themedContext(), - R.style.DialogTheme, - DatePickerDialog.OnDateSetListener { _, year, month, day -> - calendar.set(Calendar.YEAR, year) - calendar.set(Calendar.MONTH, month) - calendar.set(Calendar.DAY_OF_MONTH, day) - reminder.timestamp = calendar.timeInMillis - setContent(reminder) - }, - calendar.get(Calendar.YEAR), - calendar.get(Calendar.MONTH), - calendar.get(Calendar.DAY_OF_MONTH)) + themedContext(), + R.style.DialogTheme, + DatePickerDialog.OnDateSetListener { _, year, month, day -> + calendar.set(Calendar.YEAR, year) + calendar.set(Calendar.MONTH, month) + calendar.set(Calendar.DAY_OF_MONTH, day) + reminder.timestamp = calendar.timeInMillis + setContent(reminder) + }, + calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH), + calendar.get(Calendar.DAY_OF_MONTH)) dialog.show() } fun openTimePickerDialog() { val calendar = reminder.toCalendar() val dialog = TimePickerDialog( - themedContext(), - R.style.DialogTheme, - TimePickerDialog.OnTimeSetListener { _, hourOfDay, minute -> - calendar.set(Calendar.HOUR_OF_DAY, hourOfDay) - calendar.set(Calendar.MINUTE, minute) - calendar.set(Calendar.SECOND, 0) - reminder.timestamp = calendar.timeInMillis - setContent(reminder) - }, - calendar.get(Calendar.HOUR_OF_DAY), - calendar.get(Calendar.MINUTE), - false) + themedContext(), + R.style.DialogTheme, + TimePickerDialog.OnTimeSetListener { _, hourOfDay, minute -> + calendar.set(Calendar.HOUR_OF_DAY, hourOfDay) + calendar.set(Calendar.MINUTE, minute) + calendar.set(Calendar.SECOND, 0) + reminder.timestamp = calendar.timeInMillis + setContent(reminder) + }, + calendar.get(Calendar.HOUR_OF_DAY), + calendar.get(Calendar.MINUTE), + false) dialog.show() } fun setContent(reminder: Reminder) { - val reminderDate = dialog.findViewById(R.id.reminder_date) - val reminderTime = dialog.findViewById(R.id.reminder_time) - val reminderRepeat = dialog.findViewById(R.id.reminder_repeat) + val dlg = dialog + if (dlg === null) { + return + } + + val reminderDate = dlg.findViewById(R.id.reminder_date) + val reminderTime = dlg.findViewById(R.id.reminder_time) + val reminderRepeat = dlg.findViewById(R.id.reminder_repeat) - val date = Date(reminder.timestamp) reminderRepeat.setSubtitle(getReminderIntervalLabel(reminder.interval)) - reminderTime.setSubtitle(DateFormatter.getDate(DateFormatter.Formats.HH_MM_A.format, date)) - reminderDate.setSubtitle(DateFormatter.getDate(DateFormatter.Formats.DD_MMM_YYYY.format, date)) + reminderTime.setSubtitle(sDateFormat.readableTime(DateFormatter.Formats.HH_MM_A.format, reminder.timestamp)) + reminderDate.setSubtitle(sDateFormat.readableTime(DateFormatter.Formats.DD_MMM_YYYY.format, reminder.timestamp)) reminderDate.alpha = if (reminder.interval == ReminderInterval.ONCE) 1.0f else 0.5f } fun setColors() { - val reminderDate = dialog.findViewById(R.id.reminder_date) - val reminderTime = dialog.findViewById(R.id.reminder_time) - val reminderRepeat = dialog.findViewById(R.id.reminder_repeat) + val dlg = dialog + if (dlg === null) { + return + } + + val reminderDate = dlg.findViewById(R.id.reminder_date) + val reminderTime = dlg.findViewById(R.id.reminder_time) + val reminderRepeat = dlg.findViewById(R.id.reminder_repeat) - val iconColor = CoreConfig.instance.themeController().get(ThemeColorType.TOOLBAR_ICON) - val textColor = CoreConfig.instance.themeController().get(ThemeColorType.TERTIARY_TEXT) - val titleColor = CoreConfig.instance.themeController().get(ThemeColorType.SECTION_HEADER) + val iconColor = sAppTheme.get(ThemeColorType.TOOLBAR_ICON) + val textColor = sAppTheme.get(ThemeColorType.TERTIARY_TEXT) + val titleColor = sAppTheme.get(ThemeColorType.SECTION_HEADER) reminderDate.setTitleColor(titleColor) reminderDate.setSubtitleColor(textColor) diff --git a/base/src/main/java/com/maubis/scarlet/base/note/selection/activity/SelectNotesActivity.kt b/base/src/main/java/com/maubis/scarlet/base/note/selection/activity/SelectNotesActivity.kt index 29af1e5b..83e73139 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/selection/activity/SelectNotesActivity.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/selection/activity/SelectNotesActivity.kt @@ -1,16 +1,17 @@ package com.maubis.scarlet.base.note.selection.activity import android.os.Bundle -import android.support.design.widget.FloatingActionButton -import android.support.v7.widget.RecyclerView +import androidx.recyclerview.widget.RecyclerView import com.github.bijoysingh.starter.util.IntentUtils +import com.google.android.material.floatingactionbutton.FloatingActionButton import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb import com.maubis.scarlet.base.database.room.note.Note -import com.maubis.scarlet.base.main.HomeNavigationState +import com.maubis.scarlet.base.main.HomeNavigationMode import com.maubis.scarlet.base.note.getFullText -import com.maubis.scarlet.base.note.selection.sheet.SelectedNoteOptionsBottomSheet +import com.maubis.scarlet.base.note.selection.sheet.SelectedNotesOptionsBottomSheet +import com.maubis.scarlet.base.support.sheets.openSheet import com.maubis.scarlet.base.support.utils.bind -import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb const val KEY_SELECT_EXTRA_MODE = "KEY_SELECT_EXTRA_MODE" const val KEY_SELECT_EXTRA_NOTE_ID = "KEY_SELECT_EXTRA_NOTE_ID" @@ -48,13 +49,13 @@ class SelectNotesActivity : SelectableNotesActivityBase() { primaryFab.setOnClickListener { runTextFunction { text -> IntentUtils.ShareBuilder(this) - .setChooserText(getString(R.string.share_using)) - .setText(text) - .share() + .setChooserText(getString(R.string.share_using)) + .setText(text) + .share() } } secondaryFab.setOnClickListener { - SelectedNoteOptionsBottomSheet.openSheet(this) + openSheet(this, SelectedNotesOptionsBottomSheet()) } recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { @@ -142,12 +143,12 @@ class SelectNotesActivity : SelectableNotesActivityBase() { return builder.toString() } - fun getMode(navigationState: String): Array { - return when (navigationState) { - HomeNavigationState.FAVOURITE.name -> arrayOf(HomeNavigationState.FAVOURITE.name) - HomeNavigationState.ARCHIVED.name -> arrayOf(HomeNavigationState.ARCHIVED.name) - HomeNavigationState.TRASH.name -> arrayOf(HomeNavigationState.TRASH.name) - else -> arrayOf(HomeNavigationState.DEFAULT.name, HomeNavigationState.FAVOURITE.name) + fun getMode(navigationMode: String): Array { + return when (navigationMode) { + HomeNavigationMode.FAVOURITE.name -> arrayOf(HomeNavigationMode.FAVOURITE.name) + HomeNavigationMode.ARCHIVED.name -> arrayOf(HomeNavigationMode.ARCHIVED.name) + HomeNavigationMode.TRASH.name -> arrayOf(HomeNavigationMode.TRASH.name) + else -> arrayOf(HomeNavigationMode.DEFAULT.name, HomeNavigationMode.FAVOURITE.name) } } } diff --git a/base/src/main/java/com/maubis/scarlet/base/note/selection/activity/SelectableNotesActivityBase.kt b/base/src/main/java/com/maubis/scarlet/base/note/selection/activity/SelectableNotesActivityBase.kt index ea3af1c1..faa3c3fc 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/selection/activity/SelectableNotesActivityBase.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/selection/activity/SelectableNotesActivityBase.kt @@ -1,28 +1,36 @@ package com.maubis.scarlet.base.note.selection.activity import android.os.Bundle -import android.support.v7.widget.LinearLayoutManager -import android.support.v7.widget.RecyclerView -import android.support.v7.widget.StaggeredGridLayoutManager import android.view.View import android.widget.GridLayout import android.widget.ImageView import android.widget.TextView +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.StaggeredGridLayoutManager import com.github.bijoysingh.starter.async.MultiAsyncTask import com.github.bijoysingh.starter.recyclerview.RecyclerViewBuilder import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig -import com.maubis.scarlet.base.database.room.note.Note +import com.maubis.scarlet.base.config.ApplicationBase.Companion.instance +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme import com.maubis.scarlet.base.core.note.sort +import com.maubis.scarlet.base.database.room.note.Note import com.maubis.scarlet.base.main.recycler.EmptyRecyclerItem +import com.maubis.scarlet.base.note.folder.SelectorFolderRecyclerItem import com.maubis.scarlet.base.note.recycler.NoteAppAdapter import com.maubis.scarlet.base.note.recycler.NoteRecyclerItem import com.maubis.scarlet.base.note.recycler.getSelectableRecyclerItemControllerList -import com.maubis.scarlet.base.settings.sheet.* +import com.maubis.scarlet.base.settings.sheet.STORE_KEY_LINE_COUNT +import com.maubis.scarlet.base.settings.sheet.SettingsOptionsBottomSheet +import com.maubis.scarlet.base.settings.sheet.SortingOptionsBottomSheet +import com.maubis.scarlet.base.settings.sheet.sNoteItemLineCount +import com.maubis.scarlet.base.settings.sheet.sUIUseGridView +import com.maubis.scarlet.base.support.recycler.RecyclerItem +import com.maubis.scarlet.base.support.ui.SecuredActivity import com.maubis.scarlet.base.support.ui.ThemeColorType -import com.maubis.scarlet.base.support.ui.ThemedActivity -abstract class SelectableNotesActivityBase : ThemedActivity(), INoteSelectorActivity { +abstract class SelectableNotesActivityBase : SecuredActivity(), INoteSelectorActivity { lateinit var recyclerView: RecyclerView lateinit var adapter: NoteAppAdapter @@ -36,14 +44,34 @@ abstract class SelectableNotesActivityBase : ThemedActivity(), INoteSelectorActi notifyThemeChange() setupRecyclerView() - MultiAsyncTask.execute(object : MultiAsyncTask.Task> { - override fun run(): List { + MultiAsyncTask.execute(object : MultiAsyncTask.Task> { + override fun run(): List { val sorting = SortingOptionsBottomSheet.getSortingState() - return sort(getNotes(), sorting) - .map { NoteRecyclerItem(this@SelectableNotesActivityBase, it) } + val notes = sort(getNotes(), sorting) + .sortedBy { it.folder } + .map { NoteRecyclerItem(this@SelectableNotesActivityBase, it) } + + if (notes.isEmpty()) { + return notes + } + + val items = emptyList().toMutableList() + var lastFolder = "" + notes.forEach { + val noteFolderId = it.note.folder + if (lastFolder != noteFolderId) { + val folder = instance.foldersDatabase().getByUUID(noteFolderId) + if (folder !== null) { + items.add(SelectorFolderRecyclerItem(this@SelectableNotesActivityBase, folder)) + lastFolder = noteFolderId + } + } + items.add(it) + } + return items } - override fun handle(notes: List) { + override fun handle(notes: List) { adapter.clearItems() if (notes.isEmpty()) { @@ -66,22 +94,21 @@ abstract class SelectableNotesActivityBase : ThemedActivity(), INoteSelectorActi open fun getLayoutUI(): Int = R.layout.activity_select_note fun setupRecyclerView() { - val staggeredView = CoreConfig.instance.store().get(UISettingsOptionsBottomSheet.KEY_LIST_VIEW, false) val isTablet = resources.getBoolean(R.bool.is_tablet) - val isMarkdownEnabled = CoreConfig.instance.store().get(SettingsOptionsBottomSheet.KEY_MARKDOWN_ENABLED, true) - val isMarkdownHomeEnabled = CoreConfig.instance.store().get(SettingsOptionsBottomSheet.KEY_MARKDOWN_HOME_ENABLED, true) + val isMarkdownEnabled = sAppPreferences.get(SettingsOptionsBottomSheet.KEY_MARKDOWN_ENABLED, true) + val isMarkdownHomeEnabled = sAppPreferences.get(SettingsOptionsBottomSheet.KEY_MARKDOWN_HOME_ENABLED, true) val adapterExtra = Bundle() adapterExtra.putBoolean(SettingsOptionsBottomSheet.KEY_MARKDOWN_ENABLED, isMarkdownEnabled && isMarkdownHomeEnabled) adapterExtra.putInt(STORE_KEY_LINE_COUNT, sNoteItemLineCount) - adapter = NoteAppAdapter(this, getSelectableRecyclerItemControllerList(staggeredView, isTablet)) + adapter = NoteAppAdapter(this, getSelectableRecyclerItemControllerList(sUIUseGridView, isTablet)) adapter.setExtra(adapterExtra) recyclerView = RecyclerViewBuilder(this) - .setView(this, R.id.recycler_view) - .setAdapter(adapter) - .setLayoutManager(getLayoutManager(staggeredView, isTablet)) - .build() + .setView(this, R.id.recycler_view) + .setAdapter(adapter) + .setLayoutManager(getLayoutManager(sUIUseGridView, isTablet)) + .build() } override fun notifyThemeChange() { @@ -90,7 +117,7 @@ abstract class SelectableNotesActivityBase : ThemedActivity(), INoteSelectorActi val containerLayout = findViewById(R.id.container_layout) containerLayout.setBackgroundColor(getThemeColor()) - val toolbarIconColor = CoreConfig.instance.themeController().get(ThemeColorType.TOOLBAR_ICON); + val toolbarIconColor = sAppTheme.get(ThemeColorType.TOOLBAR_ICON); findViewById(R.id.back_button).setColorFilter(toolbarIconColor) findViewById(R.id.toolbar_title).setTextColor(toolbarIconColor) } diff --git a/base/src/main/java/com/maubis/scarlet/base/note/selection/sheet/SelectedNoteOptionsBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/note/selection/sheet/SelectedNoteOptionsBottomSheet.kt deleted file mode 100644 index a3eff2d1..00000000 --- a/base/src/main/java/com/maubis/scarlet/base/note/selection/sheet/SelectedNoteOptionsBottomSheet.kt +++ /dev/null @@ -1,285 +0,0 @@ -package com.maubis.scarlet.base.note.selection.sheet - -import android.app.Dialog -import android.view.View -import com.github.bijoysingh.starter.util.IntentUtils -import com.github.bijoysingh.starter.util.TextUtils -import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.core.format.FormatBuilder -import com.maubis.scarlet.base.core.format.sectionPreservingSort -import com.maubis.scarlet.base.core.note.NoteState -import com.maubis.scarlet.base.core.note.getFormats -import com.maubis.scarlet.base.main.sheets.EnterPincodeBottomSheet -import com.maubis.scarlet.base.note.* -import com.maubis.scarlet.base.note.folder.sheet.SelectedFolderChooseOptionsBottomSheet -import com.maubis.scarlet.base.note.selection.activity.SelectNotesActivity -import com.maubis.scarlet.base.note.tag.sheet.SelectedTagChooseOptionsBottomSheet -import com.maubis.scarlet.base.support.option.OptionsItem -import com.maubis.scarlet.base.support.sheets.GridBottomSheetBase - -class SelectedNoteOptionsBottomSheet() : GridBottomSheetBase() { - - override fun setupViewWithDialog(dialog: Dialog) { - setOptions(dialog, getOptions()) - setOptionTitle(dialog, R.string.choose_action) - } - - private fun getOptions(): List { - val activity = context as SelectNotesActivity - val options = ArrayList() - - val allItemsInTrash = !activity.getAllSelectedNotes().any { it.state !== NoteState.TRASH.name } - options.add(OptionsItem( - title = R.string.restore_note, - subtitle = R.string.tap_for_action_not_trash, - icon = R.drawable.ic_restore, - listener = lockAwareFunctionRunner(activity, { - activity.runNoteFunction { - it.mark(activity, NoteState.DEFAULT) - } - }), - visible = allItemsInTrash - )) - - val allItemsInFavourite = !activity.getAllSelectedNotes().any { it.state !== NoteState.FAVOURITE.name } - options.add(OptionsItem( - title = R.string.not_favourite_note, - subtitle = R.string.tap_for_action_not_favourite, - icon = R.drawable.ic_favorite_white_48dp, - listener = lockAwareFunctionRunner(activity, { - activity.runNoteFunction { - it.mark(activity, NoteState.DEFAULT) - } - }), - visible = allItemsInFavourite - )) - options.add(OptionsItem( - title = R.string.favourite_note, - subtitle = R.string.tap_for_action_favourite, - icon = R.drawable.ic_favorite_border_white_48dp, - listener = lockAwareFunctionRunner(activity, { - activity.runNoteFunction { - it.mark(activity, NoteState.FAVOURITE) - } - }), - visible = !allItemsInFavourite - )) - - val allItemsInArchived = !activity.getAllSelectedNotes().any { it.state !== NoteState.ARCHIVED.name } - options.add(OptionsItem( - title = R.string.unarchive_note, - subtitle = R.string.tap_for_action_not_archive, - icon = R.drawable.ic_archive_white_48dp, - listener = lockAwareFunctionRunner(activity, { - activity.runNoteFunction { - it.mark(activity, NoteState.DEFAULT) - } - activity.finish() - }), - visible = allItemsInArchived - )) - options.add(OptionsItem( - title = R.string.archive_note, - subtitle = R.string.tap_for_action_archive, - icon = R.drawable.ic_archive_white_48dp, - listener = lockAwareFunctionRunner(activity, { - activity.runNoteFunction { - it.mark(activity, NoteState.ARCHIVED) - } - activity.finish() - }), - visible = !allItemsInArchived - )) - options.add(OptionsItem( - title = R.string.send_note, - subtitle = R.string.tap_for_action_share, - icon = R.drawable.ic_share_white_48dp, - listener = lockAwareFunctionRunner(activity, { - activity.runTextFunction { - IntentUtils.ShareBuilder(activity) - .setChooserText(getString(R.string.share_using)) - .setText(it) - .share() - } - }) - )) - options.add(OptionsItem( - title = R.string.copy_note, - subtitle = R.string.tap_for_action_copy, - icon = R.drawable.ic_content_copy_white_48dp, - listener = lockAwareFunctionRunner(activity, { - activity.runTextFunction { - TextUtils.copyToClipboard(activity, it) - } - activity.finish() - }) - )) - options.add(OptionsItem( - title = R.string.trash_note, - subtitle = R.string.tap_for_action_trash, - icon = R.drawable.ic_delete_white_48dp, - listener = lockAwareFunctionRunner(activity, { - activity.runNoteFunction { - it.mark(activity, NoteState.TRASH) - } - activity.finish() - }), - visible = !allItemsInTrash - )) - options.add(OptionsItem( - title = R.string.delete_note_permanently, - subtitle = R.string.tap_for_action_delete, - icon = R.drawable.ic_delete_permanently, - listener = lockAwareFunctionRunner(activity, { - activity.runNoteFunction { - it.delete(activity) - } - activity.finish() - }) - )) - options.add(OptionsItem( - title = R.string.change_tags, - subtitle = R.string.change_tags, - icon = R.drawable.ic_action_tags, - listener = lockAwareFunctionRunner(activity, { - SelectedTagChooseOptionsBottomSheet.openSheet(activity, { - tag, selectTag -> - activity.runNoteFunction { - when (selectTag) { - true -> it.addTag(tag) - false -> it.removeTag(tag) - } - it.save(activity) - } - }) - }) - )) - options.add(OptionsItem( - title = R.string.folder_option_change_notebook, - subtitle = R.string.folder_option_change_notebook, - icon = R.drawable.ic_folder, - listener = lockAwareFunctionRunner(activity, { - SelectedFolderChooseOptionsBottomSheet.openSheet(activity, { - folder, selectFolder -> - activity.runNoteFunction { - when (selectFolder) { - true -> it.folder = folder.uuid - false -> it.folder = "" - } - it.save(activity) - } - }) - }) - )) - - val allLocked = !activity.getAllSelectedNotes().any { !it.locked } - options.add(OptionsItem( - title = R.string.lock_note, - subtitle = R.string.lock_note, - icon = R.drawable.ic_action_lock, - listener = lockAwareFunctionRunner(activity, { - activity.runNoteFunction { - it.locked = true - it.save(activity) - } - activity.finish() - }), - visible = !allLocked - )) - options.add(OptionsItem( - title = R.string.unlock_note, - subtitle = R.string.unlock_note, - icon = R.drawable.ic_action_unlock, - listener = lockAwareFunctionRunner(activity, { - activity.runNoteFunction { - it.locked = false - it.save(activity) - } - activity.finish() - }), - visible = allLocked - )) - - options.add(OptionsItem( - title = R.string.merge_notes, - subtitle = R.string.merge_notes, - icon = R.drawable.ic_merge_note, - listener = lockAwareFunctionRunner(activity, { - val selectedNotes = activity.getOrderedSelectedNotes().toMutableList() - if (selectedNotes.isEmpty()) { - return@lockAwareFunctionRunner - } - - val note = selectedNotes.firstOrNull() - if (note === null) { - return@lockAwareFunctionRunner - } - - val formats = note.getFormats().toMutableList() - selectedNotes.removeAt(0) - for (noteToAdd in selectedNotes) { - formats.addAll(noteToAdd.getFormats()) - noteToAdd.delete(activity) - } - note.description = FormatBuilder().getDescription(sectionPreservingSort(formats)) - note.save(activity) - activity.finish() - }) - )) - - val allBackupDisabled = !activity.getAllSelectedNotes().any { !it.disableBackup } - options.add(OptionsItem( - title = R.string.backup_note_enable, - subtitle = R.string.backup_note_enable, - icon = R.drawable.ic_action_backup, - listener = lockAwareFunctionRunner(activity, { - activity.runNoteFunction { - it.disableBackup = false - it.save(activity) - } - activity.finish() - }), - visible = allBackupDisabled - )) - options.add(OptionsItem( - title = R.string.backup_note_disable, - subtitle = R.string.backup_note_disable, - icon = R.drawable.ic_action_backup_no, - listener = lockAwareFunctionRunner(activity, { - activity.runNoteFunction { - it.disableBackup = true - it.save(activity) - } - activity.finish() - }), - visible = !allBackupDisabled - )) - return options - } - - private fun lockAwareFunctionRunner( - activity: SelectNotesActivity, - listener: () -> Unit): View.OnClickListener = View.OnClickListener { - val hasLockedNote = activity.getAllSelectedNotes().any { it.locked } - if (!hasLockedNote) { - listener() - dismiss() - return@OnClickListener - } - EnterPincodeBottomSheet.openUnlockSheet( - activity, - object : EnterPincodeBottomSheet.PincodeSuccessOnlyListener { - override fun onSuccess() { - listener() - dismiss() - } - }) - } - - companion object { - fun openSheet(activity: SelectNotesActivity) { - val sheet = SelectedNoteOptionsBottomSheet() - sheet.show(activity.supportFragmentManager, sheet.tag) - } - } -} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/note/selection/sheet/SelectedNotesOptionsBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/note/selection/sheet/SelectedNotesOptionsBottomSheet.kt new file mode 100644 index 00000000..611f8d3b --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/note/selection/sheet/SelectedNotesOptionsBottomSheet.kt @@ -0,0 +1,352 @@ +package com.maubis.scarlet.base.note.selection.sheet + +import android.app.Dialog +import androidx.core.content.ContextCompat +import com.facebook.litho.ComponentContext +import com.github.bijoysingh.starter.util.IntentUtils +import com.github.bijoysingh.starter.util.TextUtils +import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.core.format.FormatBuilder +import com.maubis.scarlet.base.core.format.sectionPreservingSort +import com.maubis.scarlet.base.core.note.NoteState +import com.maubis.scarlet.base.core.note.getFormats +import com.maubis.scarlet.base.main.sheets.AlertBottomSheet +import com.maubis.scarlet.base.main.sheets.AlertSheetConfig +import com.maubis.scarlet.base.note.addTag +import com.maubis.scarlet.base.note.delete +import com.maubis.scarlet.base.note.folder.sheet.SelectedFolderChooseOptionsBottomSheet +import com.maubis.scarlet.base.note.mark +import com.maubis.scarlet.base.note.removeTag +import com.maubis.scarlet.base.note.save +import com.maubis.scarlet.base.note.selection.activity.SelectNotesActivity +import com.maubis.scarlet.base.note.tag.sheet.SelectedTagChooserBottomSheet +import com.maubis.scarlet.base.security.sheets.openUnlockSheet +import com.maubis.scarlet.base.support.sheets.GridOptionBottomSheet +import com.maubis.scarlet.base.support.sheets.openSheet +import com.maubis.scarlet.base.support.specs.GridSectionItem +import com.maubis.scarlet.base.support.specs.GridSectionOptionItem + +class SelectedNotesOptionsBottomSheet : GridOptionBottomSheet() { + override fun title(): Int = R.string.choose_action + + override fun getOptions(componentContext: ComponentContext, dialog: Dialog): List { + val options = ArrayList() + options.add(getQuickActions(componentContext)) + options.add(getSecondaryActions(componentContext, dialog)) + options.add(getTertiaryActions(componentContext, dialog)) + return options + } + + private fun getQuickActions(componentContext: ComponentContext): GridSectionItem { + val activity = componentContext.androidContext as SelectNotesActivity + val options = ArrayList() + + val allItemsInTrash = !activity.getAllSelectedNotes().any { it.state !== NoteState.TRASH.name } + options.add( + GridSectionOptionItem( + label = R.string.restore_note, + icon = R.drawable.ic_restore, + listener = lockAwareFunctionRunner(activity) { + activity.runNoteFunction { + it.mark(activity, NoteState.DEFAULT) + } + activity.finish() + }, + visible = allItemsInTrash + )) + + val allItemsInFavourite = !activity.getAllSelectedNotes().any { it.state !== NoteState.FAVOURITE.name } + options.add( + GridSectionOptionItem( + label = R.string.not_favourite_note, + icon = R.drawable.ic_favorite_white_48dp, + listener = lockAwareFunctionRunner(activity) { + activity.runNoteFunction { + it.mark(activity, NoteState.DEFAULT) + } + activity.finish() + }, + visible = allItemsInFavourite + )) + options.add( + GridSectionOptionItem( + label = R.string.favourite_note, + icon = R.drawable.ic_favorite_border_white_48dp, + listener = lockAwareFunctionRunner(activity) { + activity.runNoteFunction { + it.mark(activity, NoteState.FAVOURITE) + } + activity.finish() + }, + visible = !allItemsInFavourite + )) + + val allItemsInArchived = !activity.getAllSelectedNotes().any { it.state !== NoteState.ARCHIVED.name } + options.add( + GridSectionOptionItem( + label = R.string.unarchive_note, + icon = R.drawable.ic_archive_white_48dp, + listener = lockAwareFunctionRunner(activity) { + activity.runNoteFunction { + it.mark(activity, NoteState.DEFAULT) + } + activity.finish() + }, + visible = allItemsInArchived + )) + options.add( + GridSectionOptionItem( + label = R.string.archive_note, + icon = R.drawable.ic_archive_white_48dp, + listener = lockAwareFunctionRunner(activity) { + activity.runNoteFunction { + it.mark(activity, NoteState.ARCHIVED) + } + activity.finish() + }, + visible = !allItemsInArchived + )) + options.add(GridSectionOptionItem( + label = R.string.send_note, + icon = R.drawable.ic_share_white_48dp, + listener = lockAwareFunctionRunner(activity) { + activity.runTextFunction { + IntentUtils.ShareBuilder(activity) + .setChooserText(getString(R.string.share_using)) + .setText(it) + .share() + } + } + )) + options.add(GridSectionOptionItem( + label = R.string.copy_note, + icon = R.drawable.ic_content_copy_white_48dp, + listener = lockAwareFunctionRunner(activity) { + activity.runTextFunction { + TextUtils.copyToClipboard(activity, it) + } + activity.finish() + } + )) + options.add( + GridSectionOptionItem( + label = R.string.trash_note, + icon = R.drawable.ic_delete_white_48dp, + listener = lockAwareFunctionRunner(activity) { + activity.runNoteFunction { + it.mark(activity, NoteState.TRASH) + } + activity.finish() + }, + visible = !allItemsInTrash + )) + + return GridSectionItem( + options = options, + sectionColor = ContextCompat.getColor(activity, R.color.material_blue_800)) + } + + private fun getSecondaryActions(componentContext: ComponentContext, dialog: Dialog): GridSectionItem { + val activity = componentContext.androidContext as SelectNotesActivity + val options = ArrayList() + + options.add(GridSectionOptionItem( + label = R.string.change_tags, + icon = R.drawable.ic_action_tags, + listener = lockAwareFunctionRunner(activity) { + openSheet(activity, SelectedTagChooserBottomSheet().apply { + onActionListener = { tag, selectTag -> + activity.runNoteFunction { + when (selectTag) { + true -> it.addTag(tag) + false -> it.removeTag(tag) + } + it.save(activity) + } + activity.finish() + } + }) + } + )) + + + options.add(GridSectionOptionItem( + label = R.string.folder_option_change_notebook, + icon = R.drawable.ic_folder, + listener = lockAwareFunctionRunner(activity) { + openSheet(activity, SelectedFolderChooseOptionsBottomSheet().apply { + this.dismissListener = {} + this.onActionListener = { folder, selectFolder -> + activity.runNoteFunction { + when (selectFolder) { + true -> it.folder = folder.uuid + false -> it.folder = "" + } + it.save(activity) + } + activity.finish() + } + }) + } + )) + + val allLocked = !activity.getAllSelectedNotes().any { !it.locked } + options.add( + GridSectionOptionItem( + label = R.string.lock_note, + icon = R.drawable.ic_action_lock, + listener = lockAwareFunctionRunner(activity) { + activity.runNoteFunction { + it.locked = true + it.save(activity) + } + activity.finish() + }, + visible = !allLocked + )) + options.add( + GridSectionOptionItem( + label = R.string.unlock_note, + icon = R.drawable.ic_action_unlock, + listener = lockAwareFunctionRunner(activity) { + activity.runNoteFunction { + it.locked = false + it.save(activity) + } + activity.finish() + }, + visible = allLocked + )) + + return GridSectionItem( + options = options, + sectionColor = ContextCompat.getColor(activity, R.color.material_red_800)) + } + + private fun getTertiaryActions(componentContext: ComponentContext, dialog: Dialog): GridSectionItem { + val activity = componentContext.androidContext as SelectNotesActivity + val options = ArrayList() + + val allItemsPinned = !activity.getAllSelectedNotes().any { !it.pinned } + options.add( + GridSectionOptionItem( + label = R.string.pin_note, + icon = R.drawable.ic_pin, + listener = lockAwareFunctionRunner(activity) { + activity.runNoteFunction { + it.pinned = true + it.save(activity) + } + activity.finish() + }, + visible = !allItemsPinned + )) + options.add( + GridSectionOptionItem( + label = R.string.unpin_note, + icon = R.drawable.ic_pin, + listener = lockAwareFunctionRunner(activity) { + activity.runNoteFunction { + it.pinned = false + it.save(activity) + } + activity.finish() + }, + visible = allItemsPinned + )) + + options.add(GridSectionOptionItem( + label = R.string.merge_notes, + icon = R.drawable.ic_merge_note, + listener = lockAwareFunctionRunner(activity) { + val selectedNotes = activity.getOrderedSelectedNotes().toMutableList() + if (selectedNotes.isEmpty()) { + return@lockAwareFunctionRunner + } + + val note = selectedNotes.firstOrNull() + if (note === null) { + return@lockAwareFunctionRunner + } + + val formats = note.getFormats().toMutableList() + selectedNotes.removeAt(0) + for (noteToAdd in selectedNotes) { + formats.addAll(noteToAdd.getFormats()) + noteToAdd.delete(activity) + } + note.description = FormatBuilder().getDescription(sectionPreservingSort(formats)) + note.save(activity) + activity.finish() + } + )) + + options.add(GridSectionOptionItem( + label = R.string.delete_note_permanently, + icon = R.drawable.ic_delete_permanently, + listener = lockAwareFunctionRunner(activity) { + openSheet(activity, AlertBottomSheet().apply { + config = AlertSheetConfig( + description = R.string.delete_sheet_delete_selected_notes_permanently, + onPositiveClick = { + activity.runNoteFunction { + it.delete(activity) + } + activity.finish() + } + ) + }) + } + )) + + val allBackupDisabled = !activity.getAllSelectedNotes().any { !it.disableBackup } + options.add( + GridSectionOptionItem( + label = R.string.backup_note_enable, + icon = R.drawable.ic_action_backup, + listener = lockAwareFunctionRunner(activity) { + activity.runNoteFunction { + it.disableBackup = false + it.save(activity) + } + activity.finish() + }, + visible = allBackupDisabled + )) + options.add( + GridSectionOptionItem( + label = R.string.backup_note_disable, + icon = R.drawable.ic_action_backup_no, + listener = lockAwareFunctionRunner(activity) { + activity.runNoteFunction { + it.disableBackup = true + it.save(activity) + } + activity.finish() + }, + visible = !allBackupDisabled + )) + return GridSectionItem( + options = options, + sectionColor = ContextCompat.getColor(activity, R.color.material_teal_800)) + } + + private fun lockAwareFunctionRunner( + activity: SelectNotesActivity, + listener: () -> Unit): () -> Unit = { + val hasLockedNote = activity.getAllSelectedNotes().any { it.locked } + when { + hasLockedNote -> openUnlockSheet( + activity = activity, + onUnlockSuccess = { + listener() + dismiss() + }, + onUnlockFailure = {}) + else -> { + listener() + dismiss() + } + } + } +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/note/tag/TagExtensions.kt b/base/src/main/java/com/maubis/scarlet/base/note/tag/TagExtensions.kt index af06ec05..6ac2451b 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/tag/TagExtensions.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/tag/TagExtensions.kt @@ -1,8 +1,8 @@ package com.maubis.scarlet.base.note.tag -import com.maubis.scarlet.base.config.CoreConfig -import com.maubis.scarlet.base.database.room.tag.Tag +import com.maubis.scarlet.base.config.ApplicationBase import com.maubis.scarlet.base.config.CoreConfig.Companion.tagsDb +import com.maubis.scarlet.base.database.room.tag.Tag fun Tag.saveIfUnique() { val existing = tagsDb.getByTitle(title) @@ -26,21 +26,21 @@ fun Tag.saveIfUnique() { **************************************************************************************/ fun Tag.save() { - CoreConfig.instance.tagActions(this).save() + ApplicationBase.instance.tagActions(this).save() } fun Tag.saveWithoutSync() { - CoreConfig.instance.tagActions(this).offlineSave() + ApplicationBase.instance.tagActions(this).offlineSave() } fun Tag.saveToSync() { - CoreConfig.instance.tagActions(this).onlineSave() + ApplicationBase.instance.tagActions(this).onlineSave() } fun Tag.delete() { - CoreConfig.instance.tagActions(this).delete() + ApplicationBase.instance.tagActions(this).delete() } fun Tag.deleteWithoutSync() { - CoreConfig.instance.tagActions(this).offlineDelete() + ApplicationBase.instance.tagActions(this).offlineDelete() } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/note/tag/TagOptionsItem.kt b/base/src/main/java/com/maubis/scarlet/base/note/tag/TagOptionsItem.kt index efcf70f0..6df3bd20 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/tag/TagOptionsItem.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/tag/TagOptionsItem.kt @@ -6,12 +6,12 @@ import com.maubis.scarlet.base.database.room.tag.Tag import com.maubis.scarlet.base.support.option.TagOptionsItemBase class TagOptionsItem( - tag: Tag, - usages: Int = 0, - selected: Boolean = false, - editable: Boolean = false, - editListener: View.OnClickListener? = null, - listener: View.OnClickListener) : TagOptionsItemBase(tag, usages, selected, editable, editListener, listener) { + tag: Tag, + usages: Int = 0, + selected: Boolean = false, + editable: Boolean = false, + editListener: View.OnClickListener? = null, + listener: View.OnClickListener) : TagOptionsItemBase(tag, usages, selected, editable, editListener, listener) { override fun getIcon(): Int = when (selected) { true -> R.drawable.ic_action_label diff --git a/base/src/main/java/com/maubis/scarlet/base/note/tag/sheet/CreateOrEditTagBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/note/tag/sheet/CreateOrEditTagBottomSheet.kt index 8718f9f1..86ec1ace 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/tag/sheet/CreateOrEditTagBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/tag/sheet/CreateOrEditTagBottomSheet.kt @@ -6,7 +6,7 @@ import android.view.View.VISIBLE import android.widget.EditText import android.widget.TextView import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme import com.maubis.scarlet.base.core.tag.isUnsaved import com.maubis.scarlet.base.database.room.tag.Tag import com.maubis.scarlet.base.note.tag.delete @@ -16,7 +16,6 @@ import com.maubis.scarlet.base.support.ui.ThemedActivity import com.maubis.scarlet.base.support.ui.ThemedBottomSheetFragment import com.maubis.scarlet.base.support.utils.getEditorActionListener - class CreateOrEditTagBottomSheet : ThemedBottomSheetFragment() { var selectedTag: Tag? = null @@ -43,9 +42,9 @@ class CreateOrEditTagBottomSheet : ThemedBottomSheetFragment() { val enterTag = dialog.findViewById(R.id.enter_tag) val removeBtn = dialog.findViewById(R.id.action_remove_button) - title.setTextColor(CoreConfig.instance.themeController().get(ThemeColorType.SECONDARY_TEXT)) - enterTag.setTextColor(CoreConfig.instance.themeController().get(ThemeColorType.SECONDARY_TEXT)) - enterTag.setHintTextColor(CoreConfig.instance.themeController().get(ThemeColorType.HINT_TEXT)) + title.setTextColor(sAppTheme.get(ThemeColorType.SECONDARY_TEXT)) + enterTag.setTextColor(sAppTheme.get(ThemeColorType.SECONDARY_TEXT)) + enterTag.setHintTextColor(sAppTheme.get(ThemeColorType.HINT_TEXT)) title.setText(if (tag.isUnsaved()) R.string.tag_sheet_create_title else R.string.tag_sheet_edit_title) action.setOnClickListener { @@ -61,12 +60,12 @@ class CreateOrEditTagBottomSheet : ThemedBottomSheetFragment() { } enterTag.setText(tag.title) enterTag.setOnEditorActionListener(getEditorActionListener( - runnable = { - val updated = onActionClick(tag, enterTag.text.toString()) - sheetOnTagListener(tag, !updated) - dismiss() - return@getEditorActionListener true - })) + runnable = { + val updated = onActionClick(tag, enterTag.text.toString()) + sheetOnTagListener(tag, !updated) + dismiss() + return@getEditorActionListener true + })) makeBackgroundTransparent(dialog, R.id.root_layout) } diff --git a/base/src/main/java/com/maubis/scarlet/base/note/tag/sheet/SelectedTagChooseOptionsBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/note/tag/sheet/SelectedTagChooseOptionsBottomSheet.kt deleted file mode 100644 index 9748c2b4..00000000 --- a/base/src/main/java/com/maubis/scarlet/base/note/tag/sheet/SelectedTagChooseOptionsBottomSheet.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.maubis.scarlet.base.note.tag.sheet - -import android.app.Dialog -import android.view.View -import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.database.room.tag.Tag -import com.maubis.scarlet.base.core.note.getTagUUIDs -import com.maubis.scarlet.base.core.tag.TagBuilder -import com.maubis.scarlet.base.note.selection.activity.SelectNotesActivity -import com.maubis.scarlet.base.note.tag.TagOptionsItem -import com.maubis.scarlet.base.config.CoreConfig.Companion.tagsDb -import com.maubis.scarlet.base.support.ui.ThemedActivity -import com.maubis.scarlet.base.support.ui.visibility - -class SelectedTagChooseOptionsBottomSheet : TagOptionItemBottomSheetBase() { - - var onActionListener: (Tag, Boolean) -> Unit = { _, _ -> } - - override fun setupViewWithDialog(dialog: Dialog) { - val options = getOptions() - dialog.findViewById(R.id.tag_card_layout).visibility = visibility(options.isNotEmpty()) - setOptions(dialog, getOptions()) - } - - override fun onNewTagClick() { - val activity = context as ThemedActivity - CreateOrEditTagBottomSheet.openSheet(activity, TagBuilder().emptyTag(), { tag, _ -> - onActionListener(tag, true) - reset(dialog) - }) - } - - private fun getOptions(): List { - val activity = themedContext() as SelectNotesActivity - val options = ArrayList() - - val tags = HashSet() - tags.addAll(activity.getAllSelectedNotes().firstOrNull()?.getTagUUIDs() ?: emptySet()) - - activity.getAllSelectedNotes().forEach { - val uuids = it.getTagUUIDs().toMutableSet() - val uuidsToRemove = HashSet() - for (tag in tags) { - if (!uuids.contains(tag)) { - uuidsToRemove.add(tag) - } - } - tags.removeAll(uuidsToRemove) - } - for (tag in tagsDb.getAll()) { - options.add(TagOptionsItem( - tag = tag, - listener = View.OnClickListener { - onActionListener(tag, !tags.contains(tag.uuid)) - activity.refreshSelectedNotes() - reset(dialog) - }, - selected = tags.contains(tag.uuid) - )) - } - return options - } - - companion object { - fun openSheet(activity: ThemedActivity, onActionListener: (Tag, Boolean) -> Unit) { - val sheet = SelectedTagChooseOptionsBottomSheet() - sheet.onActionListener = onActionListener - sheet.show(activity.supportFragmentManager, sheet.tag) - } - } -} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/note/tag/sheet/SelectedTagChooserBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/note/tag/sheet/SelectedTagChooserBottomSheet.kt new file mode 100644 index 00000000..68ece29d --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/note/tag/sheet/SelectedTagChooserBottomSheet.kt @@ -0,0 +1,93 @@ +package com.maubis.scarlet.base.note.tag.sheet + +import android.app.Dialog +import com.facebook.litho.Column +import com.facebook.litho.Component +import com.facebook.litho.ComponentContext +import com.facebook.yoga.YogaEdge +import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.core.note.getTagUUIDs +import com.maubis.scarlet.base.core.tag.TagBuilder +import com.maubis.scarlet.base.database.room.tag.Tag +import com.maubis.scarlet.base.main.sheets.LithoTagOptionsItem +import com.maubis.scarlet.base.main.sheets.TagItemLayout +import com.maubis.scarlet.base.note.selection.activity.SelectNotesActivity +import com.maubis.scarlet.base.support.sheets.LithoBottomSheet +import com.maubis.scarlet.base.support.sheets.LithoOptionsItem +import com.maubis.scarlet.base.support.sheets.OptionItemLayout +import com.maubis.scarlet.base.support.sheets.getLithoBottomSheetTitle + +class SelectedTagChooserBottomSheet : LithoBottomSheet() { + + var onActionListener: (Tag, Boolean) -> Unit = { _, _ -> } + + override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { + val activity = context as SelectNotesActivity + val component = Column.create(componentContext) + .widthPercent(100f) + val tagsComponent = Column.create(componentContext) + .paddingDip(YogaEdge.TOP, 8f) + .paddingDip(YogaEdge.BOTTOM, 8f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .child( + getLithoBottomSheetTitle(componentContext) + .textRes(R.string.tag_sheet_choose_tag) + .marginDip(YogaEdge.BOTTOM, 12f)) + getTagOptions().forEach { + tagsComponent.child(TagItemLayout.create(componentContext).option(it)) + } + + val addTag = LithoOptionsItem( + title = R.string.tag_sheet_new_tag_button, + subtitle = 0, + icon = R.drawable.icon_add_note, + listener = { + CreateOrEditTagBottomSheet.openSheet(activity, TagBuilder().emptyTag()) { tag, _ -> + onActionListener(tag, true) + reset(activity, dialog) + } + }) + tagsComponent.child(OptionItemLayout.create(componentContext) + .option(addTag) + .backgroundRes(R.drawable.accent_rounded_bg) + .marginDip(YogaEdge.TOP, 16f) + .onClick { addTag.listener() }) + + component.child(tagsComponent) + return component.build() + } + + private fun getTagOptions(): List { + val activity = context as SelectNotesActivity + val options = ArrayList() + + val tags = HashSet() + tags.addAll(activity.getAllSelectedNotes().firstOrNull()?.getTagUUIDs() ?: emptySet()) + + activity.getAllSelectedNotes().forEach { + val uuids = it.getTagUUIDs().toMutableSet() + val uuidsToRemove = HashSet() + for (tag in tags) { + if (!uuids.contains(tag)) { + uuidsToRemove.add(tag) + } + } + tags.removeAll(uuidsToRemove) + } + for (tag in CoreConfig.tagsDb.getAll()) { + options.add( + LithoTagOptionsItem( + tag = tag, + listener = { + onActionListener(tag, !tags.contains(tag.uuid)) + activity.refreshSelectedNotes() + reset(activity, dialog) + }, + isSelected = tags.contains(tag.uuid) + )) + } + options.sortByDescending { if (it.isSelected) 1 else 0 } + return options + } +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/note/tag/sheet/TagChooseOptionsBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/note/tag/sheet/TagChooseOptionsBottomSheet.kt deleted file mode 100644 index e692582b..00000000 --- a/base/src/main/java/com/maubis/scarlet/base/note/tag/sheet/TagChooseOptionsBottomSheet.kt +++ /dev/null @@ -1,73 +0,0 @@ -package com.maubis.scarlet.base.note.tag.sheet - -import android.app.Dialog -import android.content.DialogInterface -import android.view.View -import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.database.room.note.Note -import com.maubis.scarlet.base.core.note.getTagUUIDs -import com.maubis.scarlet.base.core.tag.TagBuilder -import com.maubis.scarlet.base.note.save -import com.maubis.scarlet.base.note.tag.TagOptionsItem -import com.maubis.scarlet.base.note.toggleTag -import com.maubis.scarlet.base.config.CoreConfig.Companion.tagsDb -import com.maubis.scarlet.base.support.ui.ThemedActivity -import com.maubis.scarlet.base.support.ui.visibility - -class TagChooseOptionsBottomSheet : TagOptionItemBottomSheetBase() { - - var note: Note? = null - var dismissListener: () -> Unit = {} - - override fun setupViewWithDialog(dialog: Dialog) { - if (note === null) { - dismiss() - return - } - - val options = getOptions() - dialog.findViewById(R.id.tag_card_layout).visibility = visibility(options.isNotEmpty()) - setOptions(dialog, getOptions()) - } - - override fun onNewTagClick() { - val activity = context as ThemedActivity - CreateOrEditTagBottomSheet.openSheet(activity, TagBuilder().emptyTag(), { tag, _ -> - note!!.toggleTag(tag) - note!!.save(activity) - reset(dialog) - }) - } - - override fun onDismiss(dialog: DialogInterface?) { - super.onDismiss(dialog) - dismissListener() - } - - private fun getOptions(): List { - val options = ArrayList() - val tags = note!!.getTagUUIDs() - for (tag in tagsDb.getAll()) { - options.add(TagOptionsItem( - tag = tag, - listener = View.OnClickListener { - note!!.toggleTag(tag) - note!!.save(themedContext()) - reset(dialog) - }, - selected = tags.contains(tag.uuid) - )) - } - return options - } - - companion object { - fun openSheet(activity: ThemedActivity, note: Note, dismissListener: () -> Unit) { - val sheet = TagChooseOptionsBottomSheet() - - sheet.note = note - sheet.dismissListener = dismissListener - sheet.show(activity.supportFragmentManager, sheet.tag) - } - } -} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/note/tag/sheet/TagChooserBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/note/tag/sheet/TagChooserBottomSheet.kt new file mode 100644 index 00000000..1835ed2f --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/note/tag/sheet/TagChooserBottomSheet.kt @@ -0,0 +1,90 @@ +package com.maubis.scarlet.base.note.tag.sheet + +import android.app.Dialog +import android.content.DialogInterface +import androidx.appcompat.app.AppCompatActivity +import com.facebook.litho.Column +import com.facebook.litho.Component +import com.facebook.litho.ComponentContext +import com.facebook.yoga.YogaEdge +import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.core.note.getTagUUIDs +import com.maubis.scarlet.base.core.tag.TagBuilder +import com.maubis.scarlet.base.database.room.note.Note +import com.maubis.scarlet.base.main.sheets.LithoTagOptionsItem +import com.maubis.scarlet.base.main.sheets.TagItemLayout +import com.maubis.scarlet.base.note.save +import com.maubis.scarlet.base.note.toggleTag +import com.maubis.scarlet.base.support.sheets.LithoBottomSheet +import com.maubis.scarlet.base.support.sheets.LithoOptionsItem +import com.maubis.scarlet.base.support.sheets.OptionItemLayout +import com.maubis.scarlet.base.support.sheets.getLithoBottomSheetTitle +import com.maubis.scarlet.base.support.ui.ThemedActivity + +class TagChooserBottomSheet : LithoBottomSheet() { + + var note: Note? = null + var dismissListener: () -> Unit = {} + + override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { + if (note === null) { + dismiss() + return Column.create(componentContext).widthPercent(100f).build() + } + + val activity = context as ThemedActivity + val component = Column.create(componentContext) + .widthPercent(100f) + val tagsComponent = Column.create(componentContext) + .paddingDip(YogaEdge.TOP, 8f) + .paddingDip(YogaEdge.BOTTOM, 8f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .child( + getLithoBottomSheetTitle(componentContext) + .textRes(R.string.tag_sheet_choose_tag) + .marginDip(YogaEdge.BOTTOM, 12f)) + getTagOptions().forEach { + tagsComponent.child(TagItemLayout.create(componentContext).option(it)) + } + + val addTag = LithoOptionsItem( + title = R.string.tag_sheet_new_tag_button, + subtitle = 0, + icon = R.drawable.icon_add_note, + listener = { CreateOrEditTagBottomSheet.openSheet(activity, TagBuilder().emptyTag()) { _, _ -> reset(activity, dialog) } }) + tagsComponent.child(OptionItemLayout.create(componentContext) + .option(addTag) + .backgroundRes(R.drawable.accent_rounded_bg) + .marginDip(YogaEdge.TOP, 16f) + .onClick { addTag.listener() }) + + component.child(tagsComponent) + return component.build() + } + + private fun getTagOptions(): List { + val activity = context as AppCompatActivity + val options = ArrayList() + val tags = note!!.getTagUUIDs() + for (tag in CoreConfig.tagsDb.getAll()) { + options.add( + LithoTagOptionsItem( + tag = tag, + listener = { + note!!.toggleTag(tag) + note!!.save(activity) + reset(activity, dialog) + }, + isSelected = tags.contains(tag.uuid) + )) + } + options.sortByDescending { if (it.isSelected) 1 else 0 } + return options + } + + override fun onDismiss(dialog: DialogInterface) { + super.onDismiss(dialog) + dismissListener() + } +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/note/tag/sheet/TagOptionItemBottomSheetBase.kt b/base/src/main/java/com/maubis/scarlet/base/note/tag/sheet/TagOptionItemBottomSheetBase.kt deleted file mode 100644 index fecf5e9b..00000000 --- a/base/src/main/java/com/maubis/scarlet/base/note/tag/sheet/TagOptionItemBottomSheetBase.kt +++ /dev/null @@ -1,72 +0,0 @@ -package com.maubis.scarlet.base.note.tag.sheet - -import android.app.Dialog -import android.view.View -import android.view.View.GONE -import android.widget.LinearLayout -import com.github.bijoysingh.uibasics.views.UIActionView -import com.github.bijoysingh.uibasics.views.UITextView -import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig -import com.maubis.scarlet.base.note.tag.TagOptionsItem -import com.maubis.scarlet.base.support.ui.ThemeColorType -import com.maubis.scarlet.base.support.ui.ThemedBottomSheetFragment - -abstract class TagOptionItemBottomSheetBase : ThemedBottomSheetFragment() { - override fun setupView(dialog: Dialog?) { - super.setupView(dialog) - if (dialog == null) { - return - } - reset(dialog) - setAddTagOption(dialog) - makeBackgroundTransparent(dialog, R.id.root_layout) - } - - abstract fun setupViewWithDialog(dialog: Dialog) - - abstract fun onNewTagClick() - - override fun getBackgroundView(): Int { - return R.id.options_layout - } - - override fun getBackgroundCardViewIds(): Array = arrayOf(R.id.tag_card_layout) - - fun setAddTagOption(dialog: Dialog) { - val newTagButton = dialog.findViewById(R.id.new_tag_button); - newTagButton.setOnClickListener { onNewTagClick() } - newTagButton.icon.alpha = 0.6f - } - - fun reset(dialog: Dialog) { - val layout = dialog.findViewById(R.id.options_container) - layout.removeAllViews() - setupViewWithDialog(dialog) - } - - fun setOptions(dialog: Dialog, options: List) { - val layout = dialog.findViewById(R.id.options_container); - for (option in options) { - val contentView = View.inflate(context, R.layout.layout_option_sheet_item, null) as UIActionView - contentView.setTitle(option.tag.title) - contentView.setOnClickListener(option.listener) - contentView.subtitle.visibility = GONE - contentView.setImageResource(option.getIcon()) - - if (option.editable) { - contentView.setActionResource(option.getEditIcon()); - contentView.setActionTint(CoreConfig.instance.themeController().get(ThemeColorType.HINT_TEXT)); - contentView.setActionClickListener(option.editListener) - } - - contentView.setTitleColor(getOptionsTitleColor(option.selected)) - contentView.setSubtitleColor(getOptionsSubtitleColor(option.selected)) - contentView.setImageTint(getOptionsTitleColor(option.selected)) - - layout.addView(contentView) - } - } - - override fun getLayout(): Int = R.layout.bottom_sheet_tag_options -} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/note/tag/view/HomeTagView.kt b/base/src/main/java/com/maubis/scarlet/base/note/tag/view/HomeTagView.kt index 3fd00e1c..92f4618a 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/tag/view/HomeTagView.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/tag/view/HomeTagView.kt @@ -19,5 +19,4 @@ class HomeTagView(val rootView: View) { action = rootView.findViewById(R.id.action) } - } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/note/tag/view/TagsAndColorPickerViewHolder.kt b/base/src/main/java/com/maubis/scarlet/base/note/tag/view/TagsAndColorPickerViewHolder.kt index 1fc7fd1b..b6e8cd44 100644 --- a/base/src/main/java/com/maubis/scarlet/base/note/tag/view/TagsAndColorPickerViewHolder.kt +++ b/base/src/main/java/com/maubis/scarlet/base/note/tag/view/TagsAndColorPickerViewHolder.kt @@ -1,21 +1,22 @@ package com.maubis.scarlet.base.note.tag.view -import android.support.v4.content.ContextCompat import android.view.View import android.widget.TextView +import androidx.core.content.ContextCompat import com.google.android.flexbox.FlexboxLayout import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.database.room.tag.Tag -import com.maubis.scarlet.base.settings.view.ColorView +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb import com.maubis.scarlet.base.config.CoreConfig.Companion.tagsDb +import com.maubis.scarlet.base.database.room.tag.Tag +import com.maubis.scarlet.base.settings.view.ColorView class TagsAndColorPickerViewHolder( - val activity: MainActivity, - val flexbox: FlexboxLayout, - val onTagClick: (Tag) -> Unit, - val onColorClick: (Int) -> Unit) { + val activity: MainActivity, + val flexbox: FlexboxLayout, + val onTagClick: (Tag) -> Unit, + val onColorClick: (Int) -> Unit) { val tags = emptySet().toMutableSet() val colors = emptySet().toMutableSet() @@ -42,37 +43,38 @@ class TagsAndColorPickerViewHolder( private fun setTags() { val length = tags.size tags.toList() - .subList(0, Math.min(length, 6)) - .forEach { - val tag = it - val tagView = View.inflate(activity, R.layout.layout_flexbox_tag_item, null) as View - val text = tagView.findViewById(R.id.tag_text) + .subList(0, Math.min(length, 6)) + .forEach { + val tag = it + val tagView = View.inflate(activity, R.layout.layout_flexbox_tag_item, null) as View + val text = tagView.findViewById(R.id.tag_text) - if (activity.config.tags.filter { it.uuid == tag.uuid }.isNotEmpty()) { - text.setBackgroundResource(R.drawable.flexbox_selected_tag_item_bg) - text.setTextColor(ContextCompat.getColor(activity, R.color.colorAccent)) - } + if (activity.state.tags.filter { it.uuid == tag.uuid }.isNotEmpty()) { + text.setBackgroundResource(R.drawable.flexbox_selected_tag_item_bg) + text.setTextColor(ContextCompat.getColor(activity, R.color.colorAccent)) + } - text.text = it.title - tagView.setOnClickListener { - onTagClick(tag) - } - flexbox.addView(tagView) + text.text = it.title + text.typeface = sAppTypeface.title() + tagView.setOnClickListener { + onTagClick(tag) } + flexbox.addView(tagView) + } } private fun setColors() { val length = colors.size colors.toList() - .subList(0, Math.min(length, 6)) - .forEach { - val color = it - val colorView = ColorView(activity, R.layout.layout_color_small) - colorView.setColor(color, activity.config.colors.contains(color)) - colorView.setOnClickListener { - onColorClick(color) - } - flexbox.addView(colorView) + .subList(0, Math.min(length, 6)) + .forEach { + val color = it + val colorView = ColorView(activity, R.layout.layout_color_small) + colorView.setColor(color, activity.state.colors.contains(color)) + colorView.setOnClickListener { + onColorClick(color) } + flexbox.addView(colorView) + } } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/notification/NotificationHandler.kt b/base/src/main/java/com/maubis/scarlet/base/notification/NotificationHandler.kt index d1570510..c917b880 100644 --- a/base/src/main/java/com/maubis/scarlet/base/notification/NotificationHandler.kt +++ b/base/src/main/java/com/maubis/scarlet/base/notification/NotificationHandler.kt @@ -1,27 +1,32 @@ package com.maubis.scarlet.base.notification -import android.app.* +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent +import android.app.TaskStackBuilder import android.content.Context import android.content.Context.NOTIFICATION_SERVICE import android.content.Intent -import android.os.Build -import android.support.v4.app.NotificationCompat import android.view.View.GONE import android.view.View.VISIBLE import android.widget.RemoteViews +import androidx.core.app.NotificationCompat import com.github.bijoysingh.starter.util.TextUtils import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme import com.maubis.scarlet.base.database.room.note.Note import com.maubis.scarlet.base.note.creation.activity.CreateNoteActivity import com.maubis.scarlet.base.note.creation.activity.INTENT_KEY_NOTE_ID +import com.maubis.scarlet.base.note.creation.activity.NoteIntentRouterActivity import com.maubis.scarlet.base.note.creation.activity.ViewAdvancedNoteActivity import com.maubis.scarlet.base.note.getDisplayTime -import com.maubis.scarlet.base.note.getText -import com.maubis.scarlet.base.note.getTitle +import com.maubis.scarlet.base.note.getTextForSharing +import com.maubis.scarlet.base.note.getTitleForSharing import com.maubis.scarlet.base.support.INTENT_KEY_ACTION import com.maubis.scarlet.base.support.ui.ThemeColorType +import com.maubis.scarlet.base.support.utils.OsVersionUtils const val REQUEST_CODE_BASE = 3200; const val REQUEST_CODE_MULTIPLIER = 250; @@ -29,8 +34,8 @@ const val NOTE_NOTIFICATION_CHANNEL_ID = "NOTE_NOTIFICATION_CHANNEL"; const val REMINDER_NOTIFICATION_CHANNEL_ID = "REMINDER_NOTIFICATION_CHANNEL"; class NotificationConfig( - val note: Note, - val channel: String = NOTE_NOTIFICATION_CHANNEL_ID + val note: Note, + val channel: String = NOTE_NOTIFICATION_CHANNEL_ID ) class NotificationHandler(val context: Context) { @@ -42,17 +47,17 @@ class NotificationHandler(val context: Context) { } fun openNotification(config: NotificationConfig) { - val pendingIntent = getPendingActivityIntent(config, getNoteOpenIntent(config), 1) - var contentView = getRemoteView(config) + val pendingIntent = getPendingActivityIntent(config, NoteIntentRouterActivity.view(context.applicationContext, config.note), 1) + val contentView = getRemoteView(config) val notificationBuilder = NotificationCompat.Builder(context, config.channel) - .setSmallIcon(R.drawable.ic_format_quote_white_48dp) - .setContentTitle(config.note.getTitle()) - .setColor(config.note.color) - .setCategory(NotificationCompat.CATEGORY_EVENT) - .setContent(contentView) - .setCustomBigContentView(contentView) - .setContentIntent(pendingIntent) - .setAutoCancel(false) + .setSmallIcon(R.drawable.ic_format_quote_white_48dp) + .setContentTitle(config.note.getTitleForSharing()) + .setColor(config.note.color) + .setCategory(NotificationCompat.CATEGORY_EVENT) + .setContent(contentView) + .setCustomBigContentView(contentView) + .setContentIntent(pendingIntent) + .setAutoCancel(false) if (config.channel === REMINDER_NOTIFICATION_CHANNEL_ID) { notificationBuilder.setPriority(NotificationCompat.PRIORITY_HIGH) @@ -65,45 +70,46 @@ class NotificationHandler(val context: Context) { } private fun createNotificationChannel() { - if (Build.VERSION.SDK_INT < 26) { + if (!OsVersionUtils.canAddNotificationChannels()) { return } + val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager? if (manager === null) { return } + val channel = NotificationChannel( - NOTE_NOTIFICATION_CHANNEL_ID, - context.getString(R.string.notification_channel_label), - NotificationManager.IMPORTANCE_MIN) + NOTE_NOTIFICATION_CHANNEL_ID, + context.getString(R.string.notification_channel_label), + NotificationManager.IMPORTANCE_MIN) manager.createNotificationChannel(channel) val channelForReminder = NotificationChannel( - REMINDER_NOTIFICATION_CHANNEL_ID, - context.getString(R.string.notification_reminder_channel_label), - NotificationManager.IMPORTANCE_HIGH) + REMINDER_NOTIFICATION_CHANNEL_ID, + context.getString(R.string.notification_reminder_channel_label), + NotificationManager.IMPORTANCE_HIGH) manager.createNotificationChannel(channelForReminder) } fun getRemoteView(config: NotificationConfig): RemoteViews { val contentView = RemoteViews(context.packageName, R.layout.notification_note_layout) - val hasTitle = !TextUtils.isNullOrEmpty(config.note.getTitle()) + val hasTitle = !TextUtils.isNullOrEmpty(config.note.getTitleForSharing()) contentView.setViewVisibility(R.id.title, if (hasTitle) VISIBLE else GONE) - contentView.setTextViewText(R.id.title, config.note.getTitle()) - contentView.setTextViewText(R.id.description, config.note.getText()) + contentView.setTextViewText(R.id.title, config.note.getTitleForSharing()) + contentView.setTextViewText(R.id.description, config.note.getTextForSharing()) contentView.setTextViewText(R.id.timestamp, config.note.getDisplayTime()) - val theme = CoreConfig.instance.themeController() - val titleColor = theme.get(ThemeColorType.SECONDARY_TEXT) - val descColor = theme.get(ThemeColorType.TERTIARY_TEXT) + val titleColor = sAppTheme.get(ThemeColorType.SECONDARY_TEXT) + val descColor = sAppTheme.get(ThemeColorType.TERTIARY_TEXT) contentView.setTextColor(R.id.title, titleColor) contentView.setTextColor(R.id.description, titleColor) contentView.setTextColor(R.id.timestamp, descColor) - val backgroundColor = theme.get(ThemeColorType.BACKGROUND) + val backgroundColor = sAppTheme.get(ThemeColorType.BACKGROUND) contentView.setInt(R.id.root_layout, "setBackgroundColor", backgroundColor) - val iconColor = theme.get(ThemeColorType.TOOLBAR_ICON) + val iconColor = sAppTheme.get(ThemeColorType.TOOLBAR_ICON) contentView.setInt(R.id.options_button, "setColorFilter", iconColor) contentView.setInt(R.id.copy_button, "setColorFilter", iconColor) contentView.setInt(R.id.share_button, "setColorFilter", iconColor) @@ -111,20 +117,20 @@ class NotificationHandler(val context: Context) { contentView.setInt(R.id.edit_button, "setColorFilter", iconColor) contentView.setOnClickPendingIntent( - R.id.options_button, - getPendingActivityIntent(config, getNoteOpenIntent(config), 2)) + R.id.options_button, + getPendingActivityIntent(config, getNoteOpenIntent(config), 2)) contentView.setOnClickPendingIntent( - R.id.edit_button, - getPendingActivityIntent(config, getNoteEditIntent(config), 3)) + R.id.edit_button, + getPendingActivityIntent(config, getNoteEditIntent(config), 3)) contentView.setOnClickPendingIntent( - R.id.copy_button, - getPendingServiceIntent(config, getNoteActionIntent(config, NotificationIntentService.NoteAction.COPY), 4)) + R.id.copy_button, + getPendingServiceIntent(config, getNoteActionIntent(config, NotificationIntentService.NoteAction.COPY), 4)) contentView.setOnClickPendingIntent( - R.id.share_button, - getPendingServiceIntent(config, getNoteActionIntent(config, NotificationIntentService.NoteAction.SHARE), 5)) + R.id.share_button, + getPendingServiceIntent(config, getNoteActionIntent(config, NotificationIntentService.NoteAction.SHARE), 5)) contentView.setOnClickPendingIntent( - R.id.delete_button, - getPendingServiceIntent(config, getNoteActionIntent(config, NotificationIntentService.NoteAction.DELETE), 6)) + R.id.delete_button, + getPendingServiceIntent(config, getNoteActionIntent(config, NotificationIntentService.NoteAction.DELETE), 6)) return contentView } @@ -142,20 +148,20 @@ class NotificationHandler(val context: Context) { } private fun getPendingActivityIntent( - config: NotificationConfig, - intent: Intent, - requestCode: Int): PendingIntent { + config: NotificationConfig, + intent: Intent, + requestCode: Int): PendingIntent { val stackBuilder = TaskStackBuilder.create(context) stackBuilder.addParentStack(MainActivity::class.java) stackBuilder.addNextIntent(intent) return stackBuilder.getPendingIntent( - REQUEST_CODE_BASE + config.note.uid + requestCode * REQUEST_CODE_MULTIPLIER, - PendingIntent.FLAG_UPDATE_CURRENT) + REQUEST_CODE_BASE + config.note.uid + requestCode * REQUEST_CODE_MULTIPLIER, + PendingIntent.FLAG_UPDATE_CURRENT) } private fun getNoteActionIntent( - config: NotificationConfig, - action: NotificationIntentService.NoteAction): Intent { + config: NotificationConfig, + action: NotificationIntentService.NoteAction): Intent { val intent = Intent(context, NotificationIntentService::class.java) intent.putExtra(INTENT_KEY_NOTE_ID, config.note.uid) intent.putExtra(INTENT_KEY_ACTION, action.name) @@ -163,13 +169,13 @@ class NotificationHandler(val context: Context) { } private fun getPendingServiceIntent( - config: NotificationConfig, - intent: Intent, - requestCode: Int): PendingIntent { + config: NotificationConfig, + intent: Intent, + requestCode: Int): PendingIntent { return PendingIntent.getService( - context, - REQUEST_CODE_BASE + config.note.uid + requestCode * REQUEST_CODE_MULTIPLIER, - intent, - PendingIntent.FLAG_UPDATE_CURRENT) + context, + REQUEST_CODE_BASE + config.note.uid + requestCode * REQUEST_CODE_MULTIPLIER, + intent, + PendingIntent.FLAG_UPDATE_CURRENT) } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/notification/NotificationIntentService.kt b/base/src/main/java/com/maubis/scarlet/base/notification/NotificationIntentService.kt index bf5ed076..c966dae2 100644 --- a/base/src/main/java/com/maubis/scarlet/base/notification/NotificationIntentService.kt +++ b/base/src/main/java/com/maubis/scarlet/base/notification/NotificationIntentService.kt @@ -4,10 +4,11 @@ import android.app.IntentService import android.app.NotificationManager import android.content.Context import android.content.Intent -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb import com.maubis.scarlet.base.support.INTENT_KEY_ACTION import com.maubis.scarlet.base.support.INTENT_KEY_NOTE_ID +import com.maubis.scarlet.base.support.utils.throwOrReturn class NotificationIntentService : IntentService("NotificationIntentService") { @@ -37,10 +38,10 @@ class NotificationIntentService : IntentService("NotificationIntentService") { } when (action) { - NoteAction.COPY -> CoreConfig.instance.noteActions(note).copy(context) - NoteAction.SHARE -> CoreConfig.instance.noteActions(note).share(context) + NoteAction.COPY -> ApplicationBase.instance.noteActions(note).copy(context) + NoteAction.SHARE -> ApplicationBase.instance.noteActions(note).share(context) NoteAction.DELETE -> { - CoreConfig.instance.noteActions(note).softDelete(context) + ApplicationBase.instance.noteActions(note).softDelete(context) val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager notificationManager.cancel(note.uid) } @@ -54,8 +55,8 @@ class NotificationIntentService : IntentService("NotificationIntentService") { try { return NoteAction.valueOf(action) - } catch (_: Exception) { - return null + } catch (exception: Exception) { + return throwOrReturn(exception, null) } } diff --git a/base/src/main/java/com/maubis/scarlet/base/security/activity/AppLockActivity.kt b/base/src/main/java/com/maubis/scarlet/base/security/activity/AppLockActivity.kt new file mode 100644 index 00000000..a9c8864d --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/security/activity/AppLockActivity.kt @@ -0,0 +1,63 @@ +package com.maubis.scarlet.base.security.activity + +import android.content.Context +import android.os.Bundle +import com.facebook.litho.Component +import com.facebook.litho.ComponentContext +import com.facebook.litho.LithoView +import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.security.controller.PinLockController +import com.maubis.scarlet.base.security.controller.isBiometricEnabled +import com.maubis.scarlet.base.security.controller.showBiometricPrompt +import com.maubis.scarlet.base.settings.sheet.sSecurityCode +import com.maubis.scarlet.base.support.ui.ThemedActivity + +class AppLockActivity : ThemedActivity() { + lateinit var context: Context + lateinit var component: Component + lateinit var componentContext: ComponentContext + + private var passCodeEntered: String = "" + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + context = this + componentContext = ComponentContext(context) + + setView() + notifyThemeChange() + } + + private fun setView() { + component = AppLockView.create(componentContext) + .fingerprintEnabled(isBiometricEnabled()) + .onTextChange { text -> + passCodeEntered = text + } + .onClick { + if (passCodeEntered.length == 4 && sSecurityCode == passCodeEntered) { + PinLockController.notifyPinVerified() + finish() + } + } + .build() + setContentView(LithoView.create(componentContext, component)) + } + + override fun onResume() { + super.onResume() + passCodeEntered = "" + + if (isBiometricEnabled()) { + showBiometricPrompt(this, onSuccess = { + PinLockController.notifyPinVerified() + finish() + }, title = R.string.biometric_prompt_unlock_app, subtitle = R.string.biometric_prompt_unlock_app_details) + } + + } + + override fun notifyThemeChange() { + setSystemTheme() + } +} diff --git a/base/src/main/java/com/maubis/scarlet/base/security/activity/AppLockActivitySpecs.kt b/base/src/main/java/com/maubis/scarlet/base/security/activity/AppLockActivitySpecs.kt new file mode 100644 index 00000000..a3df547e --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/security/activity/AppLockActivitySpecs.kt @@ -0,0 +1,143 @@ +package com.maubis.scarlet.base.security.activity + +import android.text.InputType +import android.text.Layout +import android.view.inputmethod.EditorInfo +import com.facebook.litho.ClickEvent +import com.facebook.litho.Column +import com.facebook.litho.Component +import com.facebook.litho.ComponentContext +import com.facebook.litho.Row +import com.facebook.litho.annotations.FromEvent +import com.facebook.litho.annotations.LayoutSpec +import com.facebook.litho.annotations.OnCreateLayout +import com.facebook.litho.annotations.OnEvent +import com.facebook.litho.annotations.Prop +import com.facebook.litho.widget.EditText +import com.facebook.litho.widget.Image +import com.facebook.litho.widget.Text +import com.facebook.litho.widget.TextChangedEvent +import com.facebook.yoga.YogaAlign +import com.facebook.yoga.YogaEdge +import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface +import com.maubis.scarlet.base.support.specs.EmptySpec +import com.maubis.scarlet.base.support.ui.ThemeColorType +import com.maubis.scarlet.base.support.utils.getEditorActionListener + +@LayoutSpec +object AppLockViewSpec { + + @OnCreateLayout + fun onCreate( + context: ComponentContext, + @Prop fingerprintEnabled: Boolean, + @Prop onTextChange: (String) -> Unit, + @Prop onClick: () -> Unit): Component { + return Column.create(context) + .backgroundColor(sAppTheme.get(ThemeColorType.BACKGROUND)) + .child( + AppLockContentView.create(context) + .fingerprintEnabled(fingerprintEnabled) + .onTextChange(onTextChange) + .onClick(onClick) + .flexGrow(1f)) + .child( + Row.create(context) + .alignItems(YogaAlign.CENTER) + .paddingDip(YogaEdge.HORIZONTAL, 12f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .marginDip(YogaEdge.ALL, 16f) + .child( + when { + fingerprintEnabled -> Image.create(context) + .drawableRes(R.drawable.ic_option_fingerprint) + .heightDip(36f) + else -> null + } + ) + .child(EmptySpec.create(context).flexGrow(1f)) + .child( + Text.create(context) + .backgroundRes(R.drawable.accent_rounded_bg) + .textSizeRes(R.dimen.font_size_large) + .textColorRes(R.color.white) + .textRes(R.string.security_sheet_button_unlock) + .textAlignment(Layout.Alignment.ALIGN_CENTER) + .paddingDip(YogaEdge.VERTICAL, 12f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .typeface(sAppTypeface.title()) + .clickHandler(AppLockView.onUnlockClick(context)))) + .build() + } + + @OnEvent(ClickEvent::class) + fun onUnlockClick(context: ComponentContext, @Prop onClick: () -> Unit) { + onClick() + } +} + +@LayoutSpec +object AppLockContentViewSpec { + + @OnCreateLayout + fun onCreate( + context: ComponentContext, + @Prop fingerprintEnabled: Boolean, + @Prop onClick: () -> Unit): Component { + val description = when { + fingerprintEnabled -> R.string.app_lock_details + else -> R.string.app_lock_details_no_fingerprint + } + val editBackground = when { + sAppTheme.isNightTheme() -> R.drawable.light_secondary_rounded_bg + else -> R.drawable.secondary_rounded_bg + } + + return Column.create(context) + .paddingDip(YogaEdge.ALL, 16f) + .backgroundColor(sAppTheme.get(ThemeColorType.BACKGROUND)) + .child( + Text.create(context) + .textSizeRes(R.dimen.font_size_xxlarge) + .textRes(R.string.app_lock_title) + .textColor(sAppTheme.get(ThemeColorType.SECONDARY_TEXT)) + .typeface(sAppTypeface.heading())) + .child( + Text.create(context) + .textSizeRes(R.dimen.font_size_large) + .textColor(sAppTheme.get(ThemeColorType.SECONDARY_TEXT)) + .textRes(description) + .typeface(sAppTypeface.title())) + .child(EmptySpec.create(context).flexGrow(1f)) + .child( + EditText.create(context) + .backgroundRes(editBackground) + .textSizeRes(R.dimen.font_size_xlarge) + .minWidthDip(128f) + .maxLength(4) + .hint("****") + .alignSelf(YogaAlign.CENTER) + .inputType(InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD) + .textAlignment(Layout.Alignment.ALIGN_CENTER) + .typeface(sAppTypeface.text()) + .textColor(sAppTheme.get(ThemeColorType.PRIMARY_TEXT)) + .paddingDip(YogaEdge.HORIZONTAL, 22f) + .paddingDip(YogaEdge.VERTICAL, 6f) + .imeOptions(EditorInfo.IME_ACTION_DONE) + .editorActionListener(getEditorActionListener({ + onClick() + true + })) + .textChangedEventHandler(AppLockContentView.onTextChanged(context))) + .child(EmptySpec.create(context).flexGrow(1f)) + .build() + } + + @OnEvent(TextChangedEvent::class) + fun onTextChanged(context: ComponentContext, @FromEvent text: String, @Prop onTextChange: (String) -> Unit) { + onTextChange(text) + } + +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/security/controller/BiometricUtils.kt b/base/src/main/java/com/maubis/scarlet/base/security/controller/BiometricUtils.kt new file mode 100644 index 00000000..5cf49cfa --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/security/controller/BiometricUtils.kt @@ -0,0 +1,55 @@ +package com.maubis.scarlet.base.security.controller + +import androidx.appcompat.app.AppCompatActivity +import androidx.biometric.BiometricManager +import androidx.biometric.BiometricPrompt +import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment +import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sBiometricManager +import com.maubis.scarlet.base.settings.sheet.sSecurityBiometricEnabled + +fun deviceHasBiometricEnabled(): Boolean { + return sBiometricManager.canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS +} + +fun isBiometricEnabled() = sSecurityBiometricEnabled && deviceHasBiometricEnabled() + +fun showBiometricPrompt( + activity: AppCompatActivity, + fragment: Fragment? = null, + onSuccess: () -> Unit = {}, + onFailure: () -> Unit = {}, + title: Int = R.string.biometric_prompt_unlock_app, + subtitle: Int = R.string.biometric_prompt_unlock_app_details) { + val executor = ContextCompat.getMainExecutor(activity) + + val callback = object : BiometricPrompt.AuthenticationCallback() { + override fun onAuthenticationError(errorCode: Int, errString: CharSequence) { + super.onAuthenticationError(errorCode, errString) + onFailure() + } + + override fun onAuthenticationFailed() { + super.onAuthenticationFailed() + onFailure() + } + + override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) { + super.onAuthenticationSucceeded(result) + onSuccess() + } + } + + val prompt = when { + fragment !== null -> BiometricPrompt(fragment, executor, callback) + else -> BiometricPrompt(activity, executor, callback) + } + val promptInfo = BiometricPrompt.PromptInfo.Builder() + .setTitle(activity.getString(title)) + .setDescription(activity.getString(subtitle)) + .setDeviceCredentialAllowed(false) + .setNegativeButtonText(activity.getString(R.string.delete_sheet_delete_trash_no)) + .build() + prompt.authenticate(promptInfo) +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/security/controller/PinLockController.kt b/base/src/main/java/com/maubis/scarlet/base/security/controller/PinLockController.kt new file mode 100644 index 00000000..64f4ef88 --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/security/controller/PinLockController.kt @@ -0,0 +1,49 @@ +package com.maubis.scarlet.base.security.controller + +import android.os.SystemClock +import com.github.bijoysingh.starter.util.TextUtils +import com.maubis.scarlet.base.settings.sheet.sSecurityAppLockEnabled +import com.maubis.scarlet.base.settings.sheet.sSecurityAskPinAlways +import com.maubis.scarlet.base.settings.sheet.sSecurityCode + +object PinLockController { + private var sLastLoginTimeMs = 0L + + fun isPinCodeEnabled(): Boolean { + return !TextUtils.isNullOrEmpty(sSecurityCode) + } + + fun needsAppLock(): Boolean { + // App lock enabled + if (isPinCodeEnabled() && sSecurityAppLockEnabled) { + return needsLockCheckImpl() + } + return false + } + + fun needsLockCheck(): Boolean { + if (sSecurityAskPinAlways) { + return true + } + + return needsLockCheckImpl() + } + + private fun needsLockCheckImpl(): Boolean { + val deltaSinceLastUnlock = SystemClock.uptimeMillis() - sLastLoginTimeMs + + // unlock stays 10 minutes + if (sLastLoginTimeMs == 0L || deltaSinceLastUnlock > 1000 * 60 * 5) { + return true + } + + // reset lock time + notifyPinVerified() + return false + } + + fun notifyPinVerified() { + sLastLoginTimeMs = SystemClock.uptimeMillis() + } + +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/security/sheets/NoPincodeBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/security/sheets/NoPincodeBottomSheet.kt new file mode 100644 index 00000000..b50460fb --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/security/sheets/NoPincodeBottomSheet.kt @@ -0,0 +1,65 @@ +package com.maubis.scarlet.base.security.sheets + +import android.app.Dialog +import com.facebook.litho.Column +import com.facebook.litho.Component +import com.facebook.litho.ComponentContext +import com.facebook.litho.widget.Text +import com.facebook.yoga.YogaEdge +import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface +import com.maubis.scarlet.base.support.sheets.LithoBottomSheet +import com.maubis.scarlet.base.support.sheets.getLithoBottomSheetTitle +import com.maubis.scarlet.base.support.specs.BottomSheetBar +import com.maubis.scarlet.base.support.ui.ThemeColorType +import com.maubis.scarlet.base.support.ui.ThemedActivity + +const val STORE_KEY_NO_PIN_ASK = "KEY_NO_PIN_ASK" +var sNoPinSetupNoticeShown: Boolean + get() = sAppPreferences.get(STORE_KEY_NO_PIN_ASK, false) + set(value) = sAppPreferences.put(STORE_KEY_NO_PIN_ASK, value) + +class NoPincodeBottomSheet : LithoBottomSheet() { + var onSuccess: () -> Unit = {} + + override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { + val activity = context as ThemedActivity + val component = Column.create(componentContext) + .widthPercent(100f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .child( + getLithoBottomSheetTitle(componentContext) + .textRes(R.string.no_pincode_sheet_title) + .marginDip(YogaEdge.HORIZONTAL, 0f)) + .child( + Text.create(componentContext) + .typeface(sAppTypeface.text()) + .textSizeRes(R.dimen.font_size_large) + .textRes(R.string.no_pincode_sheet_details) + .marginDip(YogaEdge.BOTTOM, 16f) + .textColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT))) + .child(BottomSheetBar.create(componentContext) + .primaryActionRes(R.string.no_pincode_sheet_set_up) + .onPrimaryClick { + openCreateSheet( + activity = activity, + onCreateSuccess = {}) + dismiss() + } + .secondaryActionRes(R.string.no_pincode_sheet_dont_ask) + .onSecondaryClick { + onSuccess() + dismiss() + } + .tertiaryActionRes(R.string.no_pincode_sheet_not_now) + .onTertiaryClick { + onSuccess() + dismiss() + } + .paddingDip(YogaEdge.VERTICAL, 8f)) + return component.build() + } +} diff --git a/base/src/main/java/com/maubis/scarlet/base/security/sheets/PincodeBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/security/sheets/PincodeBottomSheet.kt new file mode 100644 index 00000000..718ec39f --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/security/sheets/PincodeBottomSheet.kt @@ -0,0 +1,284 @@ +package com.maubis.scarlet.base.security.sheets + +import android.app.Dialog +import android.text.InputType +import android.text.Layout +import android.view.inputmethod.EditorInfo +import androidx.appcompat.app.AppCompatActivity +import com.facebook.litho.ClickEvent +import com.facebook.litho.Column +import com.facebook.litho.Component +import com.facebook.litho.ComponentContext +import com.facebook.litho.Row +import com.facebook.litho.annotations.FromEvent +import com.facebook.litho.annotations.LayoutSpec +import com.facebook.litho.annotations.OnCreateLayout +import com.facebook.litho.annotations.OnEvent +import com.facebook.litho.annotations.Prop +import com.facebook.litho.widget.EditText +import com.facebook.litho.widget.Image +import com.facebook.litho.widget.Text +import com.facebook.litho.widget.TextChangedEvent +import com.facebook.yoga.YogaAlign +import com.facebook.yoga.YogaEdge +import com.maubis.scarlet.base.MainActivity +import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface +import com.maubis.scarlet.base.security.controller.PinLockController +import com.maubis.scarlet.base.security.controller.PinLockController.isPinCodeEnabled +import com.maubis.scarlet.base.security.controller.PinLockController.needsLockCheck +import com.maubis.scarlet.base.security.controller.isBiometricEnabled +import com.maubis.scarlet.base.security.controller.showBiometricPrompt +import com.maubis.scarlet.base.settings.sheet.sSecurityAppLockEnabled +import com.maubis.scarlet.base.settings.sheet.sSecurityCode +import com.maubis.scarlet.base.support.sheets.LithoBottomSheet +import com.maubis.scarlet.base.support.sheets.getLithoBottomSheetTitle +import com.maubis.scarlet.base.support.sheets.openSheet +import com.maubis.scarlet.base.support.specs.EmptySpec +import com.maubis.scarlet.base.support.ui.ThemeColorType +import com.maubis.scarlet.base.support.ui.ThemedActivity +import com.maubis.scarlet.base.support.utils.getEditorActionListener + +data class PincodeSheetData( + val title: Int, + val actionTitle: Int, + val onSuccess: () -> Unit, + val onFailure: () -> Unit = {}, + val isFingerprintEnabled: Boolean = false, + val onActionClicked: (String) -> Unit = { password -> + when { + password != "" && password == sSecurityCode -> { + PinLockController.notifyPinVerified() + onSuccess() + } + else -> onFailure() + } + }, + val isRemoveButtonEnabled: Boolean = false, + val onRemoveButtonClick: () -> Unit = {}) + +private var sPincodeSheetPasscodeEntered = "" + +@LayoutSpec +object PincodeSheetViewSpec { + + @OnCreateLayout + fun onCreate( + context: ComponentContext, + @Prop data: PincodeSheetData, + @Prop dismiss: () -> Unit): Component { + val editBackground = when { + sAppTheme.isNightTheme() -> R.drawable.light_secondary_rounded_bg + else -> R.drawable.secondary_rounded_bg + } + + val component = Column.create(context) + .widthPercent(100f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .child( + getLithoBottomSheetTitle(context) + .textRes(data.title) + .marginDip(YogaEdge.HORIZONTAL, 0f)) + .child( + Text.create(context) + .typeface(sAppTypeface.text()) + .textSizeRes(R.dimen.font_size_large) + .textRes(R.string.app_lock_details) + .marginDip(YogaEdge.BOTTOM, 16f) + .textColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT))) + .child( + EditText.create(context) + .backgroundRes(editBackground) + .textSizeRes(R.dimen.font_size_xlarge) + .minWidthDip(128f) + .maxLength(4) + .alignSelf(YogaAlign.CENTER) + .hint("****") + .inputType(InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD) + .textAlignment(Layout.Alignment.ALIGN_CENTER) + .typeface(sAppTypeface.text()) + .textColor(sAppTheme.get(ThemeColorType.PRIMARY_TEXT)) + .paddingDip(YogaEdge.HORIZONTAL, 22f) + .paddingDip(YogaEdge.VERTICAL, 6f) + .marginDip(YogaEdge.VERTICAL, 8f) + .imeOptions(EditorInfo.IME_ACTION_DONE) + .editorActionListener(getEditorActionListener({ + data.onActionClicked(sPincodeSheetPasscodeEntered) + dismiss() + true + })) + .textChangedEventHandler(PincodeSheetView.onTextChangeListener(context))) + .child( + Row.create(context) + .alignItems(YogaAlign.CENTER) + .paddingDip(YogaEdge.HORIZONTAL, 8f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .child( + when { + data.isFingerprintEnabled -> Image.create(context) + .drawableRes(R.drawable.ic_option_fingerprint) + .heightDip(36f) + else -> null + } + ) + .child( + when { + data.isRemoveButtonEnabled -> Text.create(context) + .textSizeRes(R.dimen.font_size_large) + .textColor(sAppTheme.get(ThemeColorType.HINT_TEXT)) + .textRes(R.string.security_sheet_button_remove) + .textAlignment(Layout.Alignment.ALIGN_CENTER) + .paddingDip(YogaEdge.VERTICAL, 12f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .typeface(sAppTypeface.title()) + .clickHandler(PincodeSheetView.onRemoveClick(context)) + else -> null + } + ) + .child(EmptySpec.create(context).flexGrow(1f)) + .child( + Text.create(context) + .backgroundRes(R.drawable.accent_rounded_bg) + .textSizeRes(R.dimen.font_size_large) + .textColorRes(R.color.white) + .textRes(data.actionTitle) + .textAlignment(Layout.Alignment.ALIGN_CENTER) + .paddingDip(YogaEdge.VERTICAL, 12f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .typeface(sAppTypeface.title()) + .clickHandler(PincodeSheetView.onActionClick(context)))) + return component.build() + } + + @OnEvent(TextChangedEvent::class) + fun onTextChangeListener(context: ComponentContext, @FromEvent text: String) { + sPincodeSheetPasscodeEntered = text + } + + @OnEvent(ClickEvent::class) + fun onActionClick( + context: ComponentContext, + @Prop data: PincodeSheetData, + @Prop dismiss: () -> Unit) { + data.onActionClicked(sPincodeSheetPasscodeEntered) + sPincodeSheetPasscodeEntered = "" + dismiss() + } + + @OnEvent(ClickEvent::class) + fun onRemoveClick( + context: ComponentContext, + @Prop data: PincodeSheetData, + @Prop dismiss: () -> Unit) { + data.onRemoveButtonClick() + sPincodeSheetPasscodeEntered = "" + dismiss() + } +} + +class PincodeBottomSheet : LithoBottomSheet() { + var data = PincodeSheetData( + title = R.string.no_pincode_sheet_title, + actionTitle = R.string.no_pincode_sheet_details, + onSuccess = {}) + + override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { + sPincodeSheetPasscodeEntered = "" + return PincodeSheetView.create(componentContext) + .data(data) + .dismiss { dismiss() } + .build() + } + + override fun onResume() { + super.onResume() + val compatActivity = activity + if (compatActivity === null || compatActivity !is AppCompatActivity) { + return + } + + if (data.isFingerprintEnabled) { + showBiometricPrompt(compatActivity, this, { + data.onSuccess() + dismiss() + }) + } + } +} + +fun openCreateSheet( + activity: ThemedActivity, + onCreateSuccess: () -> Unit) { + + openSheet(activity, PincodeBottomSheet().apply { + data = PincodeSheetData( + title = R.string.security_sheet_enter_new_pin_title, + actionTitle = R.string.security_sheet_button_set, + isFingerprintEnabled = false, + isRemoveButtonEnabled = true, + onRemoveButtonClick = { + sSecurityCode = "" + sSecurityAppLockEnabled = false + sNoPinSetupNoticeShown = false + onCreateSuccess() + + if (activity is MainActivity) { + activity.loadData() + } + }, + onActionClicked = { password: String -> + if (password.length == 4 && password.toIntOrNull() !== null) { + sSecurityCode = password + onCreateSuccess() + } + }, + onSuccess = {} + ) + }) +} + +fun openVerifySheet( + activity: ThemedActivity, + onVerifySuccess: () -> Unit, + onVerifyFailure: () -> Unit = {}) { + openSheet(activity, PincodeBottomSheet().apply { + data = PincodeSheetData( + title = R.string.security_sheet_enter_current_pin_title, + actionTitle = R.string.security_sheet_button_verify, + onSuccess = onVerifySuccess, + onFailure = onVerifyFailure, + isFingerprintEnabled = isBiometricEnabled() + ) + }) +} + +fun openUnlockSheet( + activity: ThemedActivity, + onUnlockSuccess: () -> Unit, + onUnlockFailure: () -> Unit) { + if (!isPinCodeEnabled()) { + if (sNoPinSetupNoticeShown) { + onUnlockSuccess() + return + } + openSheet(activity, NoPincodeBottomSheet().apply { + this.onSuccess = onUnlockSuccess + }) + return + } + + if (!needsLockCheck()) { + return onUnlockSuccess() + } + openSheet(activity, PincodeBottomSheet().apply { + data = PincodeSheetData( + title = R.string.security_sheet_enter_pin_to_unlock_title, + actionTitle = R.string.security_sheet_button_unlock, + onSuccess = onUnlockSuccess, + onFailure = onUnlockFailure, + isFingerprintEnabled = isBiometricEnabled() + ) + }) +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/service/FloatingNoteService.kt b/base/src/main/java/com/maubis/scarlet/base/service/FloatingNoteService.kt index ef24d5f4..1c81359c 100644 --- a/base/src/main/java/com/maubis/scarlet/base/service/FloatingNoteService.kt +++ b/base/src/main/java/com/maubis/scarlet/base/service/FloatingNoteService.kt @@ -3,24 +3,29 @@ package com.maubis.scarlet.base.service import android.app.Activity import android.content.Intent import android.content.Intent.FLAG_ACTIVITY_NEW_TASK -import android.support.v4.content.ContextCompat import android.view.Gravity import android.view.View import android.widget.ImageView import android.widget.TextView +import androidx.core.content.ContextCompat import com.bsk.floatingbubblelib.FloatingBubbleConfig import com.bsk.floatingbubblelib.FloatingBubblePermissions import com.bsk.floatingbubblelib.FloatingBubbleService -import com.github.bijoysingh.starter.util.TextUtils +import com.maubis.markdown.Markdown import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb import com.maubis.scarlet.base.core.note.NoteBuilder import com.maubis.scarlet.base.database.room.note.Note -import com.maubis.scarlet.base.note.* +import com.maubis.scarlet.base.note.copy import com.maubis.scarlet.base.note.creation.activity.CreateNoteActivity import com.maubis.scarlet.base.note.creation.activity.INTENT_KEY_NOTE_ID +import com.maubis.scarlet.base.note.getDisplayTime +import com.maubis.scarlet.base.note.getFullTextForDirectMarkdownRender +import com.maubis.scarlet.base.note.getTextForSharing +import com.maubis.scarlet.base.note.getTitleForSharing import com.maubis.scarlet.base.support.ui.ThemeColorType +import com.maubis.scarlet.base.support.utils.maybeThrow /** * The floating not service @@ -30,29 +35,28 @@ import com.maubis.scarlet.base.support.ui.ThemeColorType class FloatingNoteService : FloatingBubbleService() { private var note: Note? = null - private lateinit var title: TextView private lateinit var description: TextView private lateinit var timestamp: TextView private lateinit var panel: View override fun getConfig(): FloatingBubbleConfig { - val theme = CoreConfig.instance.themeController() return FloatingBubbleConfig.Builder() - .bubbleIcon(ContextCompat.getDrawable(context, R.drawable.app_icon)) - .removeBubbleIcon(ContextCompat.getDrawable( - context, - com.bsk.floatingbubblelib.R.drawable.close_default_icon)) - .bubbleIconDp(72) - .removeBubbleIconDp(72) - .paddingDp(8) - .borderRadiusDp(4) - .physicsEnabled(true) - .expandableColor(theme.get(ThemeColorType.BACKGROUND)) - .triangleColor(theme.get(ThemeColorType.BACKGROUND)) - .gravity(Gravity.END) - .expandableView(loadView()) - .removeBubbleAlpha(0.7f) - .build() + .bubbleIcon(ContextCompat.getDrawable(context, R.drawable.app_icon)) + .removeBubbleIcon( + ContextCompat.getDrawable( + context, + com.bsk.floatingbubblelib.R.drawable.close_default_icon)) + .bubbleIconDp(72) + .removeBubbleIconDp(72) + .paddingDp(8) + .borderRadiusDp(4) + .physicsEnabled(true) + .expandableColor(sAppTheme.get(ThemeColorType.BACKGROUND)) + .triangleColor(sAppTheme.get(ThemeColorType.BACKGROUND)) + .gravity(Gravity.END) + .expandableView(loadView()) + .removeBubbleAlpha(0.7f) + .build() } override fun onGetIntent(intent: Intent): Boolean { @@ -69,15 +73,12 @@ class FloatingNoteService : FloatingBubbleService() { stopSelf() } - val theme = CoreConfig.instance.themeController() val rootView = getInflater().inflate(R.layout.layout_add_note_overlay, null) - title = rootView.findViewById(R.id.title) as TextView description = rootView.findViewById(R.id.description) as TextView timestamp = rootView.findViewById(R.id.timestamp) as TextView - title.setTextColor(theme.get(ThemeColorType.SECONDARY_TEXT)) - description.setTextColor(theme.get(ThemeColorType.SECONDARY_TEXT)) + description.setTextColor(sAppTheme.get(ThemeColorType.SECONDARY_TEXT)) val noteItem = note!! @@ -90,7 +91,7 @@ class FloatingNoteService : FloatingBubbleService() { intent.addFlags(FLAG_ACTIVITY_NEW_TASK) context.startActivity(intent) } catch (exception: Exception) { - // Some issue + maybeThrow(exception) } stopSelf() } @@ -110,29 +111,25 @@ class FloatingNoteService : FloatingBubbleService() { } panel = rootView.findViewById(R.id.panel_layout) - panel.setBackgroundColor(theme.get(ThemeColorType.BACKGROUND)) + panel.setBackgroundColor(sAppTheme.get(ThemeColorType.BACKGROUND)) setNote(noteItem) return rootView } fun getShareIntent(note: Note) { - val sharingIntent = Intent(android.content.Intent.ACTION_SEND) + val sharingIntent = Intent(Intent.ACTION_SEND) sharingIntent.type = "text/plain" - sharingIntent.putExtra(Intent.EXTRA_SUBJECT, note.getTitle()) - sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, note.getText()) + sharingIntent.putExtra(Intent.EXTRA_SUBJECT, note.getTitleForSharing()) + sharingIntent.putExtra(Intent.EXTRA_TEXT, note.getTextForSharing()) sharingIntent.addFlags(FLAG_ACTIVITY_NEW_TASK) context.startActivity(sharingIntent) } fun setNote(note: Note) { - val noteTitle = note.getTitle() - val noteDescription = note.getMarkdownText(true) - title.text = noteTitle + val noteDescription = Markdown.render(note.getFullTextForDirectMarkdownRender(), true) description.text = noteDescription timestamp.text = note.getDisplayTime() - - title.visibility = if (TextUtils.isNullOrEmpty(noteTitle)) View.GONE else View.VISIBLE } companion object { diff --git a/base/src/main/java/com/maubis/scarlet/base/service/SyncedNoteBroadcastReceiver.kt b/base/src/main/java/com/maubis/scarlet/base/service/SyncedNoteBroadcastReceiver.kt index 5f9eb21d..94c6589b 100644 --- a/base/src/main/java/com/maubis/scarlet/base/service/SyncedNoteBroadcastReceiver.kt +++ b/base/src/main/java/com/maubis/scarlet/base/service/SyncedNoteBroadcastReceiver.kt @@ -23,13 +23,15 @@ fun getNoteIntentFilter(): IntentFilter { filter.addAction(NoteBroadcast.NOTE_DELETED.name) filter.addAction(NoteBroadcast.TAG_CHANGED.name) filter.addAction(NoteBroadcast.TAG_DELETED.name) + filter.addAction(NoteBroadcast.FOLDER_CHANGED.name) + filter.addAction(NoteBroadcast.FOLDER_DELETED.name) return filter } fun sendNoteBroadcast( - context: Context, - broadcast: NoteBroadcast, - uuid: String) { + context: Context, + broadcast: NoteBroadcast, + uuid: String) { val intent = Intent() intent.action = broadcast.name intent.putExtra(KEY_UUID, uuid) @@ -53,6 +55,8 @@ class SyncedNoteBroadcastReceiver(val listener: () -> Unit) : BroadcastReceiver( NoteBroadcast.NOTE_DELETED.name -> listener() NoteBroadcast.TAG_CHANGED.name -> listener() NoteBroadcast.TAG_DELETED.name -> listener() + NoteBroadcast.FOLDER_CHANGED.name -> listener() + NoteBroadcast.FOLDER_DELETED.name -> listener() } } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/AboutSettingsOptionsBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/AboutSettingsOptionsBottomSheet.kt index d46214f5..972e21f0 100644 --- a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/AboutSettingsOptionsBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/AboutSettingsOptionsBottomSheet.kt @@ -4,15 +4,14 @@ import android.app.Dialog import android.content.Intent import android.net.Uri import com.facebook.litho.ComponentContext -import com.github.bijoysingh.starter.util.IntentUtils import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig import com.maubis.scarlet.base.main.sheets.WhatsNewBottomSheet import com.maubis.scarlet.base.support.sheets.LithoOptionBottomSheet import com.maubis.scarlet.base.support.sheets.LithoOptionsItem import com.maubis.scarlet.base.support.sheets.openSheet -import com.maubis.scarlet.base.support.utils.Flavor +import com.maubis.scarlet.base.support.utils.FlavorUtils +import com.maubis.scarlet.base.support.utils.maybeThrow const val PRIVACY_POLICY_LINK = "https://www.iubenda.com/privacy-policy/8213521" @@ -23,53 +22,68 @@ class AboutSettingsOptionsBottomSheet : LithoOptionBottomSheet() { val activity = context as MainActivity val options = ArrayList() options.add(LithoOptionsItem( - title = R.string.home_option_about_page, - subtitle = R.string.home_option_about_page_subtitle, - icon = R.drawable.ic_info, - listener = { - openSheet(activity, AboutUsBottomSheet()) - dismiss() - } + title = R.string.home_option_about_page, + subtitle = R.string.home_option_about_page_subtitle, + icon = R.drawable.ic_info, + listener = { + openSheet(activity, AboutUsBottomSheet()) + dismiss() + } )) options.add(LithoOptionsItem( - title = R.string.home_option_open_source_page, - subtitle = R.string.home_option_open_source_page_subtitle, - icon = R.drawable.ic_code_white_48dp, - listener = { - openSheet(activity, OpenSourceBottomSheet()) + title = R.string.home_option_open_source_page, + subtitle = R.string.home_option_open_source_page_subtitle, + icon = R.drawable.ic_code_white_48dp, + listener = { + openSheet(activity, OpenSourceBottomSheet()) + dismiss() + } + )) + options.add(LithoOptionsItem( + title = R.string.home_option_faq_title, + subtitle = R.string.home_option_faq_description, + icon = R.drawable.icon_help, + listener = { + try { + activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(SettingsOptionsBottomSheet.GITHUB_FAQ_URL))) dismiss() + } catch (exception: Exception) { + maybeThrow(activity, exception) } + } )) options.add(LithoOptionsItem( + title = R.string.whats_new_title, + subtitle = R.string.whats_new_subtitle, + icon = R.drawable.ic_whats_new, + listener = { + openSheet(activity, WhatsNewBottomSheet()) + dismiss() + } + )) + options.add( + LithoOptionsItem( title = R.string.material_notes_privacy_policy, subtitle = R.string.material_notes_privacy_policy_subtitle, icon = R.drawable.ic_privacy_policy, listener = { - activity.startActivity(Intent( + activity.startActivity( + Intent( Intent.ACTION_VIEW, Uri.parse(PRIVACY_POLICY_LINK))) dismiss() }, - visible = CoreConfig.instance.appFlavor() != Flavor.NONE + visible = FlavorUtils.isPlayStore() - )) + )) options.add(LithoOptionsItem( - title = R.string.home_option_rate_and_review, - subtitle = R.string.home_option_rate_and_review_subtitle, - icon = R.drawable.ic_rating, - listener = { - IntentUtils.openAppPlayStore(activity) - dismiss() - } - )) - options.add(LithoOptionsItem( - title = R.string.whats_new_title, - subtitle = R.string.whats_new_subtitle, - icon = R.drawable.ic_whats_new, - listener = { - com.maubis.scarlet.base.support.sheets.openSheet(activity, WhatsNewBottomSheet()) - dismiss() - } + title = R.string.internal_settings_title, + subtitle = R.string.internal_settings_description, + icon = R.drawable.icon_code_block, + listener = { + openSheet(activity, InternalSettingsOptionsBottomSheet()) + dismiss() + } )) return options } diff --git a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/AboutUsBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/AboutUsBottomSheet.kt index 678d26d8..7f7d4e47 100644 --- a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/AboutUsBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/AboutUsBottomSheet.kt @@ -9,11 +9,13 @@ import com.facebook.yoga.YogaEdge import com.github.bijoysingh.starter.util.IntentUtils import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface import com.maubis.scarlet.base.support.sheets.LithoBottomSheet import com.maubis.scarlet.base.support.sheets.getLithoBottomSheetTitle import com.maubis.scarlet.base.support.specs.BottomSheetBar import com.maubis.scarlet.base.support.ui.ThemeColorType +import com.maubis.scarlet.base.support.utils.maybeThrow class AboutUsBottomSheet : LithoBottomSheet() { @@ -25,6 +27,7 @@ class AboutUsBottomSheet : LithoBottomSheet() { val pInfo = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0) version = pInfo.versionName } catch (exception: Exception) { + maybeThrow(activity, exception) } val appName = getString(R.string.app_name) @@ -32,48 +35,58 @@ class AboutUsBottomSheet : LithoBottomSheet() { val aboutAppDetails = getString(R.string.about_page_description, appName) val component = Column.create(componentContext) - .widthPercent(100f) - .paddingDip(YogaEdge.VERTICAL, 8f) - .paddingDip(YogaEdge.HORIZONTAL, 20f) - .child(getLithoBottomSheetTitle(componentContext) - .textRes(R.string.home_option_about_page) - .marginDip(YogaEdge.HORIZONTAL, 0f)) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_large) - .marginDip(YogaEdge.BOTTOM, 16f) - .text(aboutUsDetails) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.TERTIARY_TEXT))) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_xlarge) - .marginDip(YogaEdge.BOTTOM, 4f) - .textRes(R.string.about_page_about_app) - .typeface(CoreConfig.FONT_MONSERRAT) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.SECTION_HEADER))) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_large) - .marginDip(YogaEdge.BOTTOM, 16f) - .text(aboutAppDetails) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.TERTIARY_TEXT))) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_xlarge) - .marginDip(YogaEdge.BOTTOM, 4f) - .textRes(R.string.about_page_app_version) - .typeface(CoreConfig.FONT_MONSERRAT) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.SECTION_HEADER))) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_large) - .marginDip(YogaEdge.BOTTOM, 16f) - .text(version) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.TERTIARY_TEXT))) - .child(BottomSheetBar.create(componentContext) - .primaryActionRes(R.string.about_page_rate) - .onPrimaryClick { - try { - IntentUtils.openAppPlayStore(activity) - dismiss() - } catch (exception: Exception) { - } - }.paddingDip(YogaEdge.VERTICAL, 8f)) + .widthPercent(100f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .child( + getLithoBottomSheetTitle(componentContext) + .textRes(R.string.home_option_about_page) + .marginDip(YogaEdge.HORIZONTAL, 0f)) + .child( + Text.create(componentContext) + .typeface(sAppTypeface.text()) + .textSizeRes(R.dimen.font_size_large) + .marginDip(YogaEdge.BOTTOM, 16f) + .text(aboutUsDetails) + .textColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT))) + .child( + Text.create(componentContext) + .textSizeRes(R.dimen.font_size_xlarge) + .marginDip(YogaEdge.BOTTOM, 4f) + .textRes(R.string.about_page_about_app) + .typeface(sAppTypeface.title()) + .textColor(sAppTheme.get(ThemeColorType.SECTION_HEADER))) + .child( + Text.create(componentContext) + .typeface(sAppTypeface.text()) + .textSizeRes(R.dimen.font_size_large) + .marginDip(YogaEdge.BOTTOM, 16f) + .text(aboutAppDetails) + .textColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT))) + .child( + Text.create(componentContext) + .textSizeRes(R.dimen.font_size_xlarge) + .marginDip(YogaEdge.BOTTOM, 4f) + .textRes(R.string.about_page_app_version) + .typeface(sAppTypeface.title()) + .textColor(sAppTheme.get(ThemeColorType.SECTION_HEADER))) + .child( + Text.create(componentContext) + .typeface(sAppTypeface.text()) + .textSizeRes(R.dimen.font_size_large) + .marginDip(YogaEdge.BOTTOM, 16f) + .text(version) + .textColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT))) + .child(BottomSheetBar.create(componentContext) + .primaryActionRes(R.string.about_page_rate) + .onPrimaryClick { + try { + IntentUtils.openAppPlayStore(activity) + dismiss() + } catch (exception: Exception) { + maybeThrow(activity, exception) + } + }.paddingDip(YogaEdge.VERTICAL, 8f)) return component.build() } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/ColorPickerBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/ColorPickerBottomSheet.kt index 8721b33d..4891b45b 100644 --- a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/ColorPickerBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/ColorPickerBottomSheet.kt @@ -2,7 +2,11 @@ package com.maubis.scarlet.base.settings.sheet import android.app.Dialog import android.graphics.Color -import com.facebook.litho.* +import com.facebook.litho.ClickEvent +import com.facebook.litho.Column +import com.facebook.litho.Component +import com.facebook.litho.ComponentContext +import com.facebook.litho.Row import com.facebook.litho.annotations.LayoutSpec import com.facebook.litho.annotations.OnCreateLayout import com.facebook.litho.annotations.OnEvent @@ -19,29 +23,35 @@ import com.maubis.scarlet.base.support.specs.separatorSpec import com.maubis.scarlet.base.support.ui.ColorUtil class ColorPickerDefaultController( - val title: Int = R.string.note_option_default_color, - var selectedColor: Int = Color.WHITE, - val colors: List = listOf(intArrayOf(Color.WHITE)), - val onColorSelected: (Int) -> Unit = {}, - val columns: Int = 6) + val title: Int = R.string.note_option_default_color, + var selectedColor: Int = Color.WHITE, + val colors: List = listOf(intArrayOf(Color.WHITE)), + val onColorSelected: (Int) -> Unit = {}, + val columns: Int = 6) @LayoutSpec object ColorPickerItemSpec { @OnCreateLayout - fun onCreate(context: ComponentContext, - @Prop color: Int, - @Prop isSelected: Boolean): Component { + fun onCreate( + context: ComponentContext, + @Prop color: Int, + @Prop isSelected: Boolean): Component { val row = Row.create(context) - .alignItems(YogaAlign.CENTER) - .child(RoundIcon.create(context) - .iconRes(if (isSelected) R.drawable.ic_done_white_48dp else R.drawable.ic_empty) - .bgColor(color) - .showBorder(true) - .iconColorRes(if (ColorUtil.isLightColored(color)) R.color.dark_tertiary_text else R.color.light_secondary_text) - .iconSizeRes(R.dimen.toolbar_round_icon_size) - .iconPaddingRes(R.dimen.toolbar_round_icon_padding) - .onClick { } - .isClickDisabled(true)) + .alignItems(YogaAlign.CENTER) + .child(RoundIcon.create(context) + .iconRes( + when { + isSelected -> R.drawable.ic_done_white_48dp + color == Color.TRANSPARENT -> R.drawable.icon_no_color + else -> R.drawable.ic_empty + }) + .bgColor(color) + .showBorder(true) + .iconColorRes(if (ColorUtil.isLightColored(color)) R.color.dark_tertiary_text else R.color.light_secondary_text) + .iconSizeRes(R.dimen.toolbar_round_icon_size) + .iconPaddingRes(R.dimen.toolbar_round_icon_padding) + .onClick { } + .isClickDisabled(true)) row.clickHandler(ColorPickerItem.onItemClick(context)) return row.build() } @@ -58,12 +68,13 @@ class ColorPickerBottomSheet : LithoBottomSheet() { override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { val column = Column.create(componentContext) - .widthPercent(100f) - .paddingDip(YogaEdge.VERTICAL, 8f) - .paddingDip(YogaEdge.HORIZONTAL, 20f) - .child(getLithoBottomSheetTitle(componentContext) - .textRes(config.title) - .marginDip(YogaEdge.HORIZONTAL, 0f)) + .widthPercent(100f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .child( + getLithoBottomSheetTitle(componentContext) + .textRes(config.title) + .marginDip(YogaEdge.HORIZONTAL, 0f)) config.colors.forEachIndexed { colorArrayIndex, colorArray -> var flex: Row.Builder? = null @@ -71,21 +82,21 @@ class ColorPickerBottomSheet : LithoBottomSheet() { if (index % config.columns == 0) { column.child(flex) flex = Row.create(componentContext) - .widthPercent(100f) - .alignItems(YogaAlign.CENTER) - .paddingDip(YogaEdge.VERTICAL, 8f) + .widthPercent(100f) + .alignItems(YogaAlign.CENTER) + .paddingDip(YogaEdge.VERTICAL, 8f) } flex?.child( - ColorPickerItem.create(componentContext) - .color(color) - .isSelected(color == config.selectedColor) - .onColorSelected { color -> - config.selectedColor = color - config.onColorSelected(color) - reset(componentContext.androidContext, dialog) - } - .flexGrow(1f)) + ColorPickerItem.create(componentContext) + .color(color) + .isSelected(color == config.selectedColor) + .onColorSelected { selectedColor -> + config.selectedColor = selectedColor + config.onColorSelected(selectedColor) + reset(componentContext.androidContext, dialog) + } + .flexGrow(1f)) } column.child(flex) @@ -96,10 +107,10 @@ class ColorPickerBottomSheet : LithoBottomSheet() { } } column.child(BottomSheetBar.create(componentContext) - .primaryActionRes(R.string.import_export_layout_exporting_done) - .onPrimaryClick { - dismiss() - }.paddingDip(YogaEdge.VERTICAL, 8f)) + .primaryActionRes(R.string.import_export_layout_exporting_done) + .onPrimaryClick { + dismiss() + }.paddingDip(YogaEdge.VERTICAL, 8f)) return column.build() } } diff --git a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/DeleteAndMoreOptionsBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/DeleteAndMoreOptionsBottomSheet.kt index 4aff64db..8634a4d5 100644 --- a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/DeleteAndMoreOptionsBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/DeleteAndMoreOptionsBottomSheet.kt @@ -4,7 +4,7 @@ import android.app.Dialog import com.facebook.litho.ComponentContext import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase import com.maubis.scarlet.base.config.CoreConfig.Companion.foldersDb import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb import com.maubis.scarlet.base.config.CoreConfig.Companion.tagsDb @@ -14,7 +14,11 @@ import com.maubis.scarlet.base.note.folder.delete import com.maubis.scarlet.base.note.tag.delete import com.maubis.scarlet.base.support.sheets.LithoOptionBottomSheet import com.maubis.scarlet.base.support.sheets.LithoOptionsItem -import kotlinx.coroutines.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.async +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class DeleteAndMoreOptionsBottomSheet : LithoOptionBottomSheet() { override fun title(): Int = R.string.home_option_delete_notes_and_more @@ -23,71 +27,72 @@ class DeleteAndMoreOptionsBottomSheet : LithoOptionBottomSheet() { val activity = context as MainActivity val options = ArrayList() options.add(LithoOptionsItem( - title = R.string.home_option_delete_all_notes, - subtitle = R.string.home_option_delete_all_notes_details, - icon = R.drawable.ic_note_white_48dp, - listener = { - openDeleteAllXSheet(activity, R.string.home_option_delete_all_notes_details) { - GlobalScope.launch(Dispatchers.Main) { - withContext(Dispatchers.IO) { notesDb.getAll().forEach { it.delete(activity) } } - activity.resetAndSetupData() - dismiss() - } + title = R.string.home_option_delete_all_notes, + subtitle = R.string.home_option_delete_all_notes_details, + icon = R.drawable.ic_note_white_48dp, + listener = { + openDeleteAllXSheet(activity, R.string.home_option_delete_all_notes_details) { + GlobalScope.launch(Dispatchers.Main) { + withContext(Dispatchers.IO) { notesDb.getAll().forEach { it.delete(activity) } } + activity.resetAndLoadData() + dismiss() } } + } )) options.add(LithoOptionsItem( - title = R.string.home_option_delete_all_tags, - subtitle = R.string.home_option_delete_all_tags_details, - icon = R.drawable.ic_action_tags, - listener = { - openDeleteAllXSheet(activity, R.string.home_option_delete_all_tags_details) { - GlobalScope.launch(Dispatchers.Main) { - withContext(Dispatchers.IO) { tagsDb.getAll().forEach { it.delete() } } - activity.resetAndSetupData() - dismiss() - } + title = R.string.home_option_delete_all_tags, + subtitle = R.string.home_option_delete_all_tags_details, + icon = R.drawable.ic_action_tags, + listener = { + openDeleteAllXSheet(activity, R.string.home_option_delete_all_tags_details) { + GlobalScope.launch(Dispatchers.Main) { + withContext(Dispatchers.IO) { tagsDb.getAll().forEach { it.delete() } } + activity.resetAndLoadData() + dismiss() } } + } )) options.add(LithoOptionsItem( - title = R.string.home_option_delete_all_folders, - subtitle = R.string.home_option_delete_all_folders_details, - icon = R.drawable.ic_folder, - listener = { - openDeleteAllXSheet(activity, R.string.home_option_delete_all_folders_details) { - GlobalScope.launch(Dispatchers.Main) { - withContext(Dispatchers.IO) { foldersDb.getAll().forEach { it.delete() } } - activity.resetAndSetupData() - dismiss() - } + title = R.string.home_option_delete_all_folders, + subtitle = R.string.home_option_delete_all_folders_details, + icon = R.drawable.ic_folder, + listener = { + openDeleteAllXSheet(activity, R.string.home_option_delete_all_folders_details) { + GlobalScope.launch(Dispatchers.Main) { + withContext(Dispatchers.IO) { foldersDb.getAll().forEach { it.delete() } } + activity.resetAndLoadData() + dismiss() } } + } )) options.add(LithoOptionsItem( - title = R.string.home_option_delete_everything, - subtitle = R.string.home_option_delete_everything_details, - icon = R.drawable.ic_delete_permanently, - listener = { - openDeleteAllXSheet(activity, R.string.home_option_delete_everything_details) { - GlobalScope.launch(Dispatchers.Main) { - val notes = GlobalScope.async(Dispatchers.IO) { notesDb.getAll().forEach { it.delete(activity) } } - val tags = GlobalScope.async(Dispatchers.IO) { tagsDb.getAll().forEach { it.delete() } } - val folders = GlobalScope.async(Dispatchers.IO) { foldersDb.getAll().forEach { it.delete() } } + title = R.string.home_option_delete_everything, + subtitle = R.string.home_option_delete_everything_details, + icon = R.drawable.ic_delete_permanently, + listener = { + openDeleteAllXSheet(activity, R.string.home_option_delete_everything_details) { + GlobalScope.launch(Dispatchers.Main) { + val notes = GlobalScope.async(Dispatchers.IO) { notesDb.getAll().forEach { it.delete(activity) } } + val tags = GlobalScope.async(Dispatchers.IO) { tagsDb.getAll().forEach { it.delete() } } + val folders = GlobalScope.async(Dispatchers.IO) { foldersDb.getAll().forEach { it.delete() } } - notes.await() - tags.await() - folders.await() + notes.await() + tags.await() + folders.await() - activity.resetAndSetupData() - dismiss() - } + activity.resetAndLoadData() + dismiss() } - } + + } )) - val forgetMeClick = CoreConfig.instance.authenticator().openForgetMeActivity(activity) - options.add(LithoOptionsItem( + val forgetMeClick = ApplicationBase.instance.authenticator().openForgetMeActivity(activity) + options.add( + LithoOptionsItem( title = R.string.forget_me_option_title, subtitle = R.string.forget_me_option_details, icon = R.drawable.ic_action_forget_me, @@ -95,8 +100,8 @@ class DeleteAndMoreOptionsBottomSheet : LithoOptionBottomSheet() { forgetMeClick?.run() dismiss() }, - visible = forgetMeClick !== null && CoreConfig.instance.authenticator().isLoggedIn() - )) + visible = forgetMeClick !== null && ApplicationBase.instance.authenticator().isLegacyLoggedIn() + )) return options } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/FontSizeBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/FontSizeBottomSheet.kt index 03b9f313..b1271814 100644 --- a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/FontSizeBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/FontSizeBottomSheet.kt @@ -8,7 +8,9 @@ import com.facebook.litho.widget.Text import com.facebook.yoga.YogaEdge import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface import com.maubis.scarlet.base.support.sheets.LithoBottomSheet import com.maubis.scarlet.base.support.sheets.getLithoBottomSheetTitle import com.maubis.scarlet.base.support.specs.BottomSheetBar @@ -21,39 +23,42 @@ const val TEXT_SIZE_MIN = 12 const val TEXT_SIZE_MAX = 24 var sEditorTextSize: Int - get() = CoreConfig.instance.store().get(STORE_KEY_TEXT_SIZE, TEXT_SIZE_DEFAULT) - set(value) = CoreConfig.instance.store().put(STORE_KEY_TEXT_SIZE, value) + get() = sAppPreferences.get(STORE_KEY_TEXT_SIZE, TEXT_SIZE_DEFAULT) + set(value) = sAppPreferences.put(STORE_KEY_TEXT_SIZE, value) class FontSizeBottomSheet : LithoBottomSheet() { override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { val activity = context as MainActivity val component = Column.create(componentContext) - .widthPercent(100f) - .paddingDip(YogaEdge.VERTICAL, 8f) - .paddingDip(YogaEdge.HORIZONTAL, 20f) - .child(getLithoBottomSheetTitle(componentContext) - .textRes(R.string.note_option_font_size) - .marginDip(YogaEdge.HORIZONTAL, 0f)) - .child(Text.create(componentContext) - .textSizeDip(sEditorTextSize.toFloat()) - .marginDip(YogaEdge.BOTTOM, 16f) - .textRes(R.string.note_option_font_size_example) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.TERTIARY_TEXT))) - .child(CounterChooser.create(componentContext) - .value(sEditorTextSize) - .minValue(TEXT_SIZE_MIN) - .maxValue(TEXT_SIZE_MAX) - .onValueChange { value -> - sEditorTextSize = value - reset(activity, dialog) - } - .paddingDip(YogaEdge.VERTICAL, 16f)) - .child(BottomSheetBar.create(componentContext) - .primaryActionRes(R.string.import_export_layout_exporting_done) - .onPrimaryClick { - dismiss() - }.paddingDip(YogaEdge.VERTICAL, 8f)) + .widthPercent(100f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .child( + getLithoBottomSheetTitle(componentContext) + .textRes(R.string.note_option_font_size) + .marginDip(YogaEdge.HORIZONTAL, 0f)) + .child( + Text.create(componentContext) + .textSizeDip(sEditorTextSize.toFloat()) + .marginDip(YogaEdge.BOTTOM, 16f) + .typeface(sAppTypeface.text()) + .textRes(R.string.note_option_font_size_example) + .textColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT))) + .child(CounterChooser.create(componentContext) + .value(sEditorTextSize) + .minValue(TEXT_SIZE_MIN) + .maxValue(TEXT_SIZE_MAX) + .onValueChange { value -> + sEditorTextSize = value + reset(activity, dialog) + } + .paddingDip(YogaEdge.VERTICAL, 16f)) + .child(BottomSheetBar.create(componentContext) + .primaryActionRes(R.string.import_export_layout_exporting_done) + .onPrimaryClick { + dismiss() + }.paddingDip(YogaEdge.VERTICAL, 8f)) return component.build() } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/InternalSettingsOptionsBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/InternalSettingsOptionsBottomSheet.kt new file mode 100644 index 00000000..aafc51bf --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/InternalSettingsOptionsBottomSheet.kt @@ -0,0 +1,103 @@ +package com.maubis.scarlet.base.settings.sheet + +import android.app.Dialog +import com.facebook.litho.ComponentContext +import com.maubis.scarlet.base.MainActivity +import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences +import com.maubis.scarlet.base.support.sheets.LithoOptionBottomSheet +import com.maubis.scarlet.base.support.sheets.LithoOptionsItem +import com.maubis.scarlet.base.support.utils.maybeThrow +import com.maubis.scarlet.base.support.utils.sInternalLogTracesToNote +import com.maubis.scarlet.base.support.utils.sInternalShowTracesInSheet +import com.maubis.scarlet.base.support.utils.sInternalThrowOnException +import com.maubis.scarlet.base.support.utils.sInternalThrownExceptionCount + +const val KEY_INTERNAL_ENABLE_FULL_SCREEN = "internal_enable_full_screen" +var sInternalEnableFullScreen: Boolean + get() = sAppPreferences.get(KEY_INTERNAL_ENABLE_FULL_SCREEN, false) + set(value) = sAppPreferences.put(KEY_INTERNAL_ENABLE_FULL_SCREEN, value) + +const val KEY_INTERNAL_SHOW_UUID = "internal_show_uuid" +var sInternalShowUUID: Boolean + get() = sAppPreferences.get(KEY_INTERNAL_SHOW_UUID, false) + set(value) = sAppPreferences.put(KEY_INTERNAL_SHOW_UUID, value) + +class InternalSettingsOptionsBottomSheet : LithoOptionBottomSheet() { + override fun title(): Int = R.string.internal_settings_title + + override fun getOptions(componentContext: ComponentContext, dialog: Dialog): List { + val activity = context as MainActivity + val options = ArrayList() + options.add( + LithoOptionsItem( + title = R.string.internal_settings_enable_fullscreen_title, + subtitle = R.string.internal_settings_enable_fullscreen_description, + icon = R.drawable.ic_action_grid, + listener = { + sInternalEnableFullScreen = !sInternalEnableFullScreen + reset(activity, dialog) + }, + isSelectable = true, + selected = sInternalEnableFullScreen + )) + options.add( + LithoOptionsItem( + title = R.string.internal_settings_show_uuid_title, + subtitle = R.string.internal_settings_show_uuid_description, + icon = R.drawable.ic_code_white_48dp, + listener = { + sInternalShowUUID = !sInternalShowUUID + reset(activity, dialog) + }, + isSelectable = true, + selected = sInternalShowUUID + )) + options.add( + LithoOptionsItem( + title = R.string.internal_settings_enable_log_exceptions_title, + subtitle = R.string.internal_settings_enable_log_exceptions_description, + icon = R.drawable.ic_note_white_48dp, + listener = { + sInternalLogTracesToNote = !sInternalLogTracesToNote + reset(activity, dialog) + }, + isSelectable = true, + selected = sInternalLogTracesToNote + )) + options.add( + LithoOptionsItem( + title = R.string.internal_settings_enable_show_exceptions_title, + subtitle = R.string.internal_settings_enable_show_exceptions_description, + icon = R.drawable.icon_add_list, + listener = { + sInternalShowTracesInSheet = !sInternalShowTracesInSheet + reset(activity, dialog) + }, + isSelectable = true, + selected = sInternalShowTracesInSheet + )) + options.add( + LithoOptionsItem( + title = R.string.internal_settings_enable_throw_exceptions_title, + subtitle = R.string.internal_settings_enable_throw_exceptions_description, + icon = R.drawable.ic_whats_new, + listener = { + sInternalThrowOnException = !sInternalThrowOnException + sInternalThrownExceptionCount = 0 + reset(activity, dialog) + }, + isSelectable = true, + selected = sInternalThrowOnException + )) + options.add(LithoOptionsItem( + title = R.string.internal_settings_fake_exceptions_title, + subtitle = R.string.internal_settings_fake_exceptions_description, + icon = R.drawable.ic_info, + listener = { + maybeThrow(activity, RuntimeException("Fake Exception for Testing")) + } + )) + return options + } +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/LineCountBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/LineCountBottomSheet.kt index f54ca47e..72261eb0 100644 --- a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/LineCountBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/LineCountBottomSheet.kt @@ -7,7 +7,7 @@ import com.facebook.litho.ComponentContext import com.facebook.yoga.YogaEdge import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences import com.maubis.scarlet.base.support.sheets.LithoBottomSheet import com.maubis.scarlet.base.support.sheets.getLithoBottomSheetTitle import com.maubis.scarlet.base.support.specs.BottomSheetBar @@ -22,35 +22,36 @@ const val LINE_COUNT_MIN = 2 const val LINE_COUNT_MAX = 15 var sNoteItemLineCount: Int - get() = CoreConfig.instance.store().get(STORE_KEY_LINE_COUNT, LINE_COUNT_DEFAULT) - set(value) = CoreConfig.instance.store().put(STORE_KEY_LINE_COUNT, value) + get() = sAppPreferences.get(STORE_KEY_LINE_COUNT, LINE_COUNT_DEFAULT) + set(value) = sAppPreferences.put(STORE_KEY_LINE_COUNT, value) class LineCountBottomSheet : LithoBottomSheet() { override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { val activity = context as MainActivity val component = Column.create(componentContext) - .widthPercent(100f) - .paddingDip(YogaEdge.VERTICAL, 8f) - .paddingDip(YogaEdge.HORIZONTAL, 20f) - .child(getLithoBottomSheetTitle(componentContext) - .textRes(R.string.note_option_number_lines) - .marginDip(YogaEdge.HORIZONTAL, 0f)) - .child(CounterChooser.create(componentContext) - .value(sNoteItemLineCount) - .minValue(LINE_COUNT_MIN) - .maxValue(LINE_COUNT_MAX) - .onValueChange { value -> - sNoteItemLineCount = value - GlobalScope.launch(Dispatchers.Main) { reset(activity, dialog) } - GlobalScope.launch(Dispatchers.Main) { activity.notifyAdapterExtraChanged() } - } - .paddingDip(YogaEdge.VERTICAL, 16f)) - .child(BottomSheetBar.create(componentContext) - .primaryActionRes(R.string.import_export_layout_exporting_done) - .onPrimaryClick { - dismiss() - }.paddingDip(YogaEdge.VERTICAL, 8f)) + .widthPercent(100f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .child( + getLithoBottomSheetTitle(componentContext) + .textRes(R.string.note_option_number_lines) + .marginDip(YogaEdge.HORIZONTAL, 0f)) + .child(CounterChooser.create(componentContext) + .value(sNoteItemLineCount) + .minValue(LINE_COUNT_MIN) + .maxValue(LINE_COUNT_MAX) + .onValueChange { value -> + sNoteItemLineCount = value + GlobalScope.launch(Dispatchers.Main) { reset(activity, dialog) } + GlobalScope.launch(Dispatchers.Main) { activity.notifyAdapterExtraChanged() } + } + .paddingDip(YogaEdge.VERTICAL, 16f)) + .child(BottomSheetBar.create(componentContext) + .primaryActionRes(R.string.import_export_layout_exporting_done) + .onPrimaryClick { + dismiss() + }.paddingDip(YogaEdge.VERTICAL, 8f)) return component.build() } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/NoteSettingsOptionsBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/NoteSettingsOptionsBottomSheet.kt deleted file mode 100644 index 4bad7c51..00000000 --- a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/NoteSettingsOptionsBottomSheet.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.maubis.scarlet.base.settings.sheet - -import android.app.Dialog -import com.facebook.litho.ComponentContext -import com.maubis.scarlet.base.MainActivity -import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig -import com.maubis.scarlet.base.support.sheets.LithoOptionBottomSheet -import com.maubis.scarlet.base.support.sheets.LithoOptionsItem -import com.maubis.scarlet.base.support.sheets.openSheet - -const val STORE_KEY_NOTE_DEFAULT_COLOR = "KEY_NOTE_DEFAULT_COLOR" - -var sNoteDefaultColor: Int - get() = CoreConfig.instance.store().get(STORE_KEY_NOTE_DEFAULT_COLOR, (0xFFD32F2F).toInt()) - set(value) = CoreConfig.instance.store().put(STORE_KEY_NOTE_DEFAULT_COLOR, value) - -class NoteSettingsOptionsBottomSheet : LithoOptionBottomSheet() { - override fun title(): Int = R.string.home_option_note_settings - - override fun getOptions(componentContext: ComponentContext, dialog: Dialog): List { - val activity = context as MainActivity - val options = ArrayList() - options.add(LithoOptionsItem( - title = R.string.note_option_default_color, - subtitle = R.string.note_option_default_color_subtitle, - icon = R.drawable.ic_action_color, - listener = { - val config = ColorPickerDefaultController( - title = R.string.note_option_default_color, - colors = listOf(activity.resources.getIntArray(R.array.bright_colors), activity.resources.getIntArray(R.array.bright_colors_accent)), - selectedColor = sNoteDefaultColor, - onColorSelected = { sNoteDefaultColor = it } - ) - openSheet(activity, ColorPickerBottomSheet().apply { this.config = config }) - dismiss() - } - )) - options.add(LithoOptionsItem( - title = R.string.home_option_security, - subtitle = R.string.home_option_security_subtitle, - icon = R.drawable.ic_option_security, - listener = { - SecurityOptionsBottomSheet.openSheet(activity) - dismiss() - } - )) - return options - } -} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/OpenSourceBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/OpenSourceBottomSheet.kt index 8e7dfcd6..872995b3 100644 --- a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/OpenSourceBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/OpenSourceBottomSheet.kt @@ -11,11 +11,13 @@ import com.facebook.yoga.YogaEdge import com.maubis.markdown.Markdown import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface import com.maubis.scarlet.base.support.sheets.LithoBottomSheet import com.maubis.scarlet.base.support.sheets.getLithoBottomSheetTitle import com.maubis.scarlet.base.support.specs.BottomSheetBar import com.maubis.scarlet.base.support.ui.ThemeColorType +import com.maubis.scarlet.base.support.utils.maybeThrow class OpenSourceBottomSheet : LithoBottomSheet() { @@ -25,77 +27,82 @@ class OpenSourceBottomSheet : LithoBottomSheet() { val creatorName = componentContext.getString(R.string.maubis_apps) val openSourceDetails = getString(R.string.about_page_description_os, appName, creatorName) val component = Column.create(componentContext) - .widthPercent(100f) - .paddingDip(YogaEdge.VERTICAL, 8f) - .paddingDip(YogaEdge.HORIZONTAL, 20f) - .child(getLithoBottomSheetTitle(componentContext) - .textRes(R.string.osp_page_about_osp) - .marginDip(YogaEdge.HORIZONTAL, 0f)) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_large) - .marginDip(YogaEdge.BOTTOM, 16f) - .text(openSourceDetails) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.TERTIARY_TEXT))) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_xlarge) - .marginDip(YogaEdge.BOTTOM, 4f) - .textRes(R.string.osp_page_libraries) - .typeface(CoreConfig.FONT_MONSERRAT) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.SECTION_HEADER))) - .child(Text.create(componentContext) - .textSizeRes(R.dimen.font_size_large) - .marginDip(YogaEdge.BOTTOM, 4f) - .text(Markdown.render(LIBRARY_DETAILS_MD, true)) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.TERTIARY_TEXT))) - .child(BottomSheetBar.create(componentContext) - .primaryActionRes(R.string.about_page_contribute) - .onPrimaryClick { - try { - activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(GITHUB_URL))) - dismiss() - } catch (exception: Exception) { - } - } - .paddingDip(YogaEdge.VERTICAL, 8f)) + .widthPercent(100f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .child( + getLithoBottomSheetTitle(componentContext) + .textRes(R.string.osp_page_about_osp) + .marginDip(YogaEdge.HORIZONTAL, 0f)) + .child( + Text.create(componentContext) + .typeface(sAppTypeface.text()) + .textSizeRes(R.dimen.font_size_large) + .marginDip(YogaEdge.BOTTOM, 16f) + .text(openSourceDetails) + .textColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT))) + .child( + Text.create(componentContext) + .textSizeRes(R.dimen.font_size_xlarge) + .marginDip(YogaEdge.BOTTOM, 4f) + .textRes(R.string.osp_page_libraries) + .typeface(sAppTypeface.title()) + .textColor(sAppTheme.get(ThemeColorType.SECTION_HEADER))) + .child( + Text.create(componentContext) + .typeface(sAppTypeface.text()) + .textSizeRes(R.dimen.font_size_large) + .marginDip(YogaEdge.BOTTOM, 4f) + .text(Markdown.render(LIBRARY_DETAILS_MD, true)) + .textColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT))) + .child(BottomSheetBar.create(componentContext) + .primaryActionRes(R.string.about_page_contribute) + .onPrimaryClick { + try { + activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(GITHUB_URL))) + dismiss() + } catch (exception: Exception) { + maybeThrow(activity, exception) + } + } + .paddingDip(YogaEdge.VERTICAL, 8f)) return component.build() } companion object { val GITHUB_URL = "https://github.com/BijoySingh/Material-Notes-Android-App" val LIBRARY_DETAILS_MD = "**Android Support Libraries**\n" + - "- `'com.android.support.appcompat-v7'`\n" + - "- `'com.android.support.recyclerview-v7'`\n" + - "- `'com.android.support.cardview-v7'`\n" + - "- `'com.android.support.support-v4'`\n" + - "- `'com.android.support.design'`\n" + - "- `'com.android.support.constraint'`\n\n" + - "**Android Architecture Room Library**\n" + - "- `'android.arch.persistence.room'`\n\n" + - "**Internal Support Libraries**\n" + - "- `'com.github.bijoysingh.android-basics'`\n" + - "- `'com.github.bijoysingh.ui-basics'`\n" + - "- `'com.github.bijoysingh.floating-bubble'`\n\n" + - "**Kotlin Support**\n" + - "- `'org.jetbrains.kotlin'`\n" + - "- `'org.jetbrains.kotlinx'`\n\n" + - "**Reprint: Fingerprint Library**\n" + - "- `'com.github.ajalt.reprint'`\n\n" + - "**Google Firebase Support Library**\n" + - "- `'com.google.firebase:firebase-auth'`\n" + - "- `'com.google.firebase:firebase-database'`\n\n" + - "**Google Play Services Library**\n" + - "- `'com.google.android.gms:play-services-auth'`\n\n" + - "**Shortcuts Gradle Plugin**\n" + - "- `'com.github.zellius:android-shortcut-gradle-plugin'`\n\n" + - "**Facebook Litho and SoLoader**\n" + - "- `'com.facebook.litho'`\n" + - "- `'com.facebook.soloader:soloader'`\n\n" + - "**Easy Image**\n" + - "- `'com.github.jkwiecien:EasyImage'`\n\n" + - "**Evernote Android Job**\n" + - "- `'com.evernote:android-job'`\n\n" + - "**Google Flexbox Library**\n" + - "- `'com.google.android:flexbox'`\n" + "- `'com.android.support.appcompat-v7'`\n" + + "- `'com.android.support.recyclerview-v7'`\n" + + "- `'com.android.support.cardview-v7'`\n" + + "- `'com.android.support.support-v4'`\n" + + "- `'com.android.support.design'`\n" + + "- `'com.android.support.constraint'`\n\n" + + "**Android Architecture Room Library**\n" + + "- `'android.arch.persistence.room'`\n\n" + + "**Internal Support Libraries**\n" + + "- `'com.github.bijoysingh.android-basics'`\n" + + "- `'com.github.bijoysingh.ui-basics'`\n" + + "- `'com.github.bijoysingh.floating-bubble'`\n\n" + + "**Kotlin Support**\n" + + "- `'org.jetbrains.kotlin'`\n" + + "- `'org.jetbrains.kotlinx'`\n\n" + + "**Google Firebase Support Library**\n" + + "- `'com.google.firebase:firebase-auth'`\n" + + "- `'com.google.firebase:firebase-database'`\n\n" + + "**Google Play Services Library**\n" + + "- `'com.google.android.gms:play-services-auth'`\n\n" + + "**Shortcuts Gradle Plugin**\n" + + "- `'com.github.zellius:android-shortcut-gradle-plugin'`\n\n" + + "**Facebook Litho and SoLoader**\n" + + "- `'com.facebook.litho'`\n" + + "- `'com.facebook.soloader:soloader'`\n\n" + + "**Easy Image**\n" + + "- `'com.github.jkwiecien:EasyImage'`\n\n" + + "**Evernote Android Job**\n" + + "- `'com.evernote:android-job'`\n\n" + + "**Google Flexbox Library**\n" + + "- `'com.google.android:flexbox'`\n" } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/SecurityOptionsBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/SecurityOptionsBottomSheet.kt index dc46385c..8620321c 100644 --- a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/SecurityOptionsBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/SecurityOptionsBottomSheet.kt @@ -2,145 +2,187 @@ package com.maubis.scarlet.base.settings.sheet import android.app.Dialog import com.facebook.litho.ComponentContext -import com.github.ajalt.reprint.core.Reprint -import com.github.bijoysingh.starter.util.TextUtils -import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig -import com.maubis.scarlet.base.main.sheets.EnterPincodeBottomSheet -import com.maubis.scarlet.base.main.sheets.EnterPincodeBottomSheet.Companion.openCreateSheet -import com.maubis.scarlet.base.main.sheets.EnterPincodeBottomSheet.Companion.openVerifySheet +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences +import com.maubis.scarlet.base.main.sheets.InstallProUpsellBottomSheet +import com.maubis.scarlet.base.security.controller.PinLockController.isPinCodeEnabled +import com.maubis.scarlet.base.security.controller.deviceHasBiometricEnabled +import com.maubis.scarlet.base.security.sheets.openCreateSheet +import com.maubis.scarlet.base.security.sheets.openVerifySheet import com.maubis.scarlet.base.support.sheets.LithoOptionBottomSheet import com.maubis.scarlet.base.support.sheets.LithoOptionsItem +import com.maubis.scarlet.base.support.sheets.openSheet import com.maubis.scarlet.base.support.ui.ThemedActivity +import com.maubis.scarlet.base.support.utils.FlavorUtils + +const val KEY_SECURITY_CODE = "KEY_SECURITY_CODE" +const val KEY_FINGERPRINT_ENABLED = "KEY_FINGERPRINT_ENABLED" +const val KEY_APP_LOCK_ENABLED = "app_lock_enabled" +const val KEY_ASK_PIN_ALWAYS = "ask_pin_always" + +var sSecurityCode: String + get() = sAppPreferences.get(KEY_SECURITY_CODE, "") + set(value) = sAppPreferences.put(KEY_SECURITY_CODE, value) +var sSecurityBiometricEnabled: Boolean + get() = sAppPreferences.get(KEY_FINGERPRINT_ENABLED, true) + set(value) = sAppPreferences.put(KEY_FINGERPRINT_ENABLED, value) +var sSecurityAppLockEnabled: Boolean + get() = sAppPreferences.get(KEY_APP_LOCK_ENABLED, false) + set(value) = sAppPreferences.put(KEY_APP_LOCK_ENABLED, value) +var sSecurityAskPinAlways: Boolean + get() = sAppPreferences.get(KEY_ASK_PIN_ALWAYS, true) + set(value) = sAppPreferences.put(KEY_ASK_PIN_ALWAYS, value) class SecurityOptionsBottomSheet : LithoOptionBottomSheet() { override fun title(): Int = R.string.security_option_title override fun getOptions(componentContext: ComponentContext, dialog: Dialog): List { + val activity = context as ThemedActivity val options = ArrayList() - options.add(LithoOptionsItem( + options.add( + LithoOptionsItem( title = R.string.security_option_set_pin_code, subtitle = R.string.security_option_set_pin_code_subtitle, icon = R.drawable.ic_option_security, listener = { - val currentPinCode = CoreConfig.instance.store().get(KEY_SECURITY_CODE, "") - val hasPinCode = !TextUtils.isNullOrEmpty(currentPinCode) - if (hasPinCode) { - openResetPasswordDialog(dialog) - } else { - openCreatePasswordDialog(dialog) + when { + isPinCodeEnabled() -> openResetPasswordDialog(dialog) + else -> openCreatePasswordDialog(dialog) } }, isSelectable = true, - selected = !TextUtils.isNullOrEmpty(CoreConfig.instance.store().get(KEY_SECURITY_CODE, "")) - )) - val hasFingerprint = Reprint.hasFingerprintRegistered() - options.add(LithoOptionsItem( - title = R.string.security_option_fingerprint_enabled, - subtitle = R.string.security_option_fingerprint_enabled_subtitle, + selected = isPinCodeEnabled() + )) + + val isLite = FlavorUtils.isLite() + options.add( + LithoOptionsItem( + title = R.string.security_option_lock_app, + subtitle = R.string.security_option_lock_app_details, + icon = R.drawable.ic_apps_white_48dp, + listener = { + if (isLite && !sSecurityAppLockEnabled) { + openSheet(activity, InstallProUpsellBottomSheet()) + return@LithoOptionsItem + } + + when { + isPinCodeEnabled() -> openVerifySheet( + activity = activity, + onVerifySuccess = { + sSecurityAppLockEnabled = !sSecurityAppLockEnabled + reset(componentContext.androidContext, dialog) + } + ) + else -> openCreatePasswordDialog(dialog) + } + }, + isSelectable = !isLite, + selected = sSecurityAppLockEnabled , + actionIcon = when { + sSecurityAppLockEnabled -> R.drawable.ic_done_white_48dp + isLite -> R.drawable.ic_rating + else -> 0 + } + )) + + options.add( + LithoOptionsItem( + title = R.string.security_option_ask_pin_always, + subtitle = R.string.security_option_ask_pin_always_details, + icon = R.drawable.ic_action_grid, + listener = { + if (isLite) { + openSheet(activity, InstallProUpsellBottomSheet()) + return@LithoOptionsItem + } + + when { + isPinCodeEnabled() -> openVerifySheet( + activity = activity, + onVerifySuccess = { + sSecurityAskPinAlways = !sSecurityAskPinAlways + reset(componentContext.androidContext, dialog) + } + ) + else -> openCreatePasswordDialog(dialog) + } + }, + isSelectable = !isLite, + selected = sSecurityAskPinAlways, + actionIcon = when { + isLite -> R.drawable.ic_rating + sSecurityAskPinAlways -> R.drawable.ic_done_white_48dp + else -> 0 + } + )) + + val hasFingerprint = deviceHasBiometricEnabled() + options.add( + LithoOptionsItem( + title = R.string.security_option_biometrics_enabled, + subtitle = R.string.security_option_biometrics_enabled_subtitle, icon = R.drawable.ic_option_fingerprint, listener = { - val currentPinCode = CoreConfig.instance.store().get(KEY_SECURITY_CODE, "") - val hasPinCode = !TextUtils.isNullOrEmpty(currentPinCode) - if (hasPinCode) { - openVerifyPasswordDialog( - object : EnterPincodeBottomSheet.PincodeSuccessOnlyListener { - override fun onSuccess() { - CoreConfig.instance.store().put(KEY_FINGERPRINT_ENABLED, false) - reset(componentContext.androidContext, dialog) - } - } + when { + isPinCodeEnabled() -> openVerifySheet( + activity = activity, + onVerifySuccess = { + sSecurityBiometricEnabled = false + reset(componentContext.androidContext, dialog) + } ) - } else { - CoreConfig.instance.store().put(KEY_FINGERPRINT_ENABLED, false) - reset(componentContext.androidContext, dialog) + else -> { + sSecurityBiometricEnabled = false + reset(componentContext.androidContext, dialog) + } } }, - visible = CoreConfig.instance.store().get(KEY_FINGERPRINT_ENABLED, true) && hasFingerprint, + visible = sSecurityBiometricEnabled && hasFingerprint, isSelectable = true, selected = true - )) - options.add(LithoOptionsItem( - title = R.string.security_option_fingerprint_disabled, - subtitle = R.string.security_option_fingerprint_disabled_subtitle, + )) + options.add( + LithoOptionsItem( + title = R.string.security_option_biometrics_disabled, + subtitle = R.string.security_option_biometrics_disabled_subtitle, icon = R.drawable.ic_option_fingerprint, listener = { - val currentPinCode = CoreConfig.instance.store().get(KEY_SECURITY_CODE, "") - val hasPinCode = !TextUtils.isNullOrEmpty(currentPinCode) - if (hasPinCode) { - openVerifyPasswordDialog( - object : EnterPincodeBottomSheet.PincodeSuccessOnlyListener { - override fun onSuccess() { - CoreConfig.instance.store().put(KEY_FINGERPRINT_ENABLED, true) - reset(componentContext.androidContext, dialog) - } - } + when { + isPinCodeEnabled() -> openVerifySheet( + activity = activity, + onVerifySuccess = { + sSecurityBiometricEnabled = true + reset(componentContext.androidContext, dialog) + } ) - } else { - CoreConfig.instance.store().put(KEY_FINGERPRINT_ENABLED, true) - reset(componentContext.androidContext, dialog) + else -> { + sSecurityBiometricEnabled = true + reset(componentContext.androidContext, dialog) + } } }, - visible = !CoreConfig.instance.store().get(KEY_FINGERPRINT_ENABLED, true) && hasFingerprint - )) + visible = !sSecurityBiometricEnabled && hasFingerprint + )) return options } fun openCreatePasswordDialog(dialog: Dialog) { val activity = context as ThemedActivity openCreateSheet( - activity, - object : EnterPincodeBottomSheet.PincodeSuccessOnlyListener { - override fun onSuccess() { - reset(dialog.context, dialog) - } - }) + activity = activity, + onCreateSuccess = { reset(dialog.context, dialog) }) } fun openResetPasswordDialog(dialog: Dialog) { val activity = context as ThemedActivity openVerifySheet( - activity, - object : EnterPincodeBottomSheet.PincodeSuccessListener { - override fun onFailure() { - openResetPasswordDialog(dialog) - } - - override fun onSuccess() { - openCreatePasswordDialog(dialog) - } - }) - } - - fun openVerifyPasswordDialog(listener: EnterPincodeBottomSheet.PincodeSuccessOnlyListener) { - val activity = context as ThemedActivity - openVerifySheet( - activity, - object : EnterPincodeBottomSheet.PincodeSuccessListener { - override fun onFailure() { - - } - - override fun onSuccess() { - listener.onSuccess() - } - }) - } - - companion object { - - const val KEY_SECURITY_CODE = "KEY_SECURITY_CODE" - const val KEY_FINGERPRINT_ENABLED = "KEY_FINGERPRINT_ENABLED" - - fun openSheet(activity: MainActivity) { - val sheet = SecurityOptionsBottomSheet() - sheet.show(activity.supportFragmentManager, sheet.tag) - } - - fun hasPinCodeEnabled(): Boolean { - val currentPinCode = CoreConfig.instance.store().get(KEY_SECURITY_CODE, "") - return !TextUtils.isNullOrEmpty(currentPinCode) - } + activity, + onVerifySuccess = { + openCreatePasswordDialog(dialog) + }, + onVerifyFailure = { + openResetPasswordDialog(dialog) + }) } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/SettingsOptionsBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/SettingsOptionsBottomSheet.kt index 6f297b62..b21b0f99 100644 --- a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/SettingsOptionsBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/SettingsOptionsBottomSheet.kt @@ -5,17 +5,15 @@ import com.facebook.litho.ComponentContext import com.github.bijoysingh.starter.util.IntentUtils import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase import com.maubis.scarlet.base.export.sheet.BackupSettingsOptionsBottomSheet import com.maubis.scarlet.base.main.recycler.getMigrateToProAppInformationItem import com.maubis.scarlet.base.note.creation.sheet.EditorOptionsBottomSheet import com.maubis.scarlet.base.support.sheets.LithoOptionBottomSheet import com.maubis.scarlet.base.support.sheets.LithoOptionsItem import com.maubis.scarlet.base.support.sheets.openSheet -import com.maubis.scarlet.base.support.utils.Flavor -import com.maubis.scarlet.base.support.utils.FlavourUtils -import com.maubis.scarlet.base.support.utils.FlavourUtils.PRO_APP_PACKAGE_NAME -import com.maubis.scarlet.base.support.utils.FlavourUtils.hasProAppInstalled +import com.maubis.scarlet.base.support.utils.FlavorUtils +import com.maubis.scarlet.base.support.utils.FlavorUtils.PRO_APP_PACKAGE_NAME import com.maubis.scarlet.base.widget.sheet.WidgetOptionsBottomSheet class SettingsOptionsBottomSheet : LithoOptionBottomSheet() { @@ -25,11 +23,12 @@ class SettingsOptionsBottomSheet : LithoOptionBottomSheet() { val activity = context as MainActivity val options = ArrayList() - val loginClick = CoreConfig.instance.authenticator().openLoginActivity(activity) - val firebaseUser = CoreConfig.instance.authenticator().userId() + val loginClick = ApplicationBase.instance.authenticator().openLoginActivity(activity) + val isLoggedIn = ApplicationBase.instance.authenticator().isLoggedIn(activity) val migrateToPro = getMigrateToProAppInformationItem(activity) - options.add(LithoOptionsItem( + options.add( + LithoOptionsItem( title = migrateToPro.title, subtitle = migrateToPro.source, icon = migrateToPro.icon, @@ -37,10 +36,11 @@ class SettingsOptionsBottomSheet : LithoOptionBottomSheet() { migrateToPro.function() dismiss() }, - visible = CoreConfig.instance.appFlavor() == Flavor.LITE && FlavourUtils.hasProAppInstalled(activity), + visible = FlavorUtils.isLite() && FlavorUtils.hasProAppInstalled(activity), selected = true - )) - options.add(LithoOptionsItem( + )) + options.add( + LithoOptionsItem( title = R.string.home_option_login_with_app, subtitle = R.string.home_option_login_with_app_subtitle, icon = R.drawable.ic_sign_in_options, @@ -48,57 +48,59 @@ class SettingsOptionsBottomSheet : LithoOptionBottomSheet() { loginClick?.run() dismiss() }, - visible = loginClick !== null && firebaseUser === null - )) + visible = loginClick !== null && !isLoggedIn + )) options.add(LithoOptionsItem( - title = R.string.home_option_ui_experience, - subtitle = R.string.home_option_ui_experience_subtitle, - icon = R.drawable.ic_action_grid, - listener = { - UISettingsOptionsBottomSheet.openSheet(activity) - } + title = R.string.home_option_ui_experience, + subtitle = R.string.home_option_ui_experience_subtitle, + icon = R.drawable.ic_action_grid, + listener = { + openSheet(activity, UISettingsOptionsBottomSheet()) + } )) options.add(LithoOptionsItem( - title = R.string.home_option_note_settings, - subtitle = R.string.home_option_note_settings_subtitle, - icon = R.drawable.ic_subject_white_48dp, - listener = { - openSheet(activity, NoteSettingsOptionsBottomSheet()) - } + title = R.string.home_option_editor_options_title, + subtitle = R.string.home_option_editor_options_description, + icon = R.drawable.ic_edit_white_48dp, + listener = { + openSheet(activity, EditorOptionsBottomSheet()) + } )) options.add(LithoOptionsItem( - title = R.string.home_option_editor_options_title, - subtitle = R.string.home_option_editor_options_description, - icon = R.drawable.ic_edit_white_48dp, - listener = { - openSheet(activity, EditorOptionsBottomSheet()) - } + title = R.string.home_option_backup_options, + subtitle = R.string.home_option_backup_options_subtitle, + icon = R.drawable.ic_export, + listener = { + openSheet(activity, BackupSettingsOptionsBottomSheet()) + } )) options.add(LithoOptionsItem( - title = R.string.home_option_backup_options, - subtitle = R.string.home_option_backup_options_subtitle, - icon = R.drawable.ic_export, - listener = { - openSheet(activity, BackupSettingsOptionsBottomSheet()) - } + title = R.string.home_option_security, + subtitle = R.string.home_option_security_subtitle, + icon = R.drawable.ic_option_security, + listener = { + openSheet(activity, SecurityOptionsBottomSheet()) + dismiss() + } )) options.add(LithoOptionsItem( - title = R.string.home_option_widget_options_title, - subtitle = R.string.home_option_widget_options_description, - icon = R.drawable.icon_widget, - listener = { - openSheet(activity, WidgetOptionsBottomSheet()) - } + title = R.string.home_option_widget_options_title, + subtitle = R.string.home_option_widget_options_description, + icon = R.drawable.icon_widget, + listener = { + openSheet(activity, WidgetOptionsBottomSheet()) + } )) options.add(LithoOptionsItem( - title = R.string.home_option_about, - subtitle = R.string.home_option_about_subtitle, - icon = R.drawable.ic_info, - listener = { - openSheet(activity, AboutSettingsOptionsBottomSheet()) - } + title = R.string.home_option_about, + subtitle = R.string.home_option_about_subtitle, + icon = R.drawable.ic_info, + listener = { + openSheet(activity, AboutSettingsOptionsBottomSheet()) + } )) - options.add(LithoOptionsItem( + options.add( + LithoOptionsItem( title = R.string.home_option_install_pro_app, subtitle = R.string.home_option_install_pro_app_details, icon = R.drawable.ic_favorite_white_48dp, @@ -106,40 +108,47 @@ class SettingsOptionsBottomSheet : LithoOptionBottomSheet() { IntentUtils.openAppPlayStore(context, PRO_APP_PACKAGE_NAME) dismiss() }, - visible = CoreConfig.instance.appFlavor() == Flavor.LITE && !hasProAppInstalled(activity) - )) + visible = FlavorUtils.isLite() && !FlavorUtils.hasProAppInstalled(activity) + )) options.add(LithoOptionsItem( - title = R.string.home_option_rate_and_review, - subtitle = R.string.home_option_rate_and_review_subtitle, - icon = R.drawable.ic_rating, - listener = { - IntentUtils.openAppPlayStore(activity) - dismiss() - } + title = R.string.home_option_rate_and_review, + subtitle = R.string.home_option_rate_and_review_subtitle, + icon = R.drawable.ic_rating, + listener = { + IntentUtils.openAppPlayStore(activity) + dismiss() + } )) options.add(LithoOptionsItem( - title = R.string.home_option_delete_notes_and_more, - subtitle = R.string.home_option_delete_notes_and_more_details, - icon = R.drawable.ic_delete_permanently, - listener = { - openSheet(activity, DeleteAndMoreOptionsBottomSheet()) - } + title = R.string.home_option_delete_notes_and_more, + subtitle = R.string.home_option_delete_notes_and_more_details, + icon = R.drawable.ic_delete_permanently, + listener = { + openSheet(activity, DeleteAndMoreOptionsBottomSheet()) + } )) - options.add(LithoOptionsItem( + options.add( + LithoOptionsItem( title = R.string.home_option_logout_of_app, subtitle = R.string.home_option_logout_of_app_subtitle, icon = R.drawable.ic_sign_in_options, listener = { - CoreConfig.instance.authenticator().logout() + if (ApplicationBase.instance.authenticator().isLegacyLoggedIn()) { + ApplicationBase.instance.authenticator().openTransferDataActivity(activity)?.run() + dismiss() + return@LithoOptionsItem + } + + ApplicationBase.instance.authenticator().openLogoutActivity(activity)?.run() dismiss() }, - visible = firebaseUser !== null - )) + visible = isLoggedIn + )) return options } companion object { - + const val GITHUB_FAQ_URL = "http://bijoysingh.github.io/Scarlet-Notes/faq/" const val KEY_MARKDOWN_ENABLED = "KEY_MARKDOWN_ENABLED" const val KEY_MARKDOWN_HOME_ENABLED = "KEY_MARKDOWN_HOME_ENABLED" diff --git a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/SortingOptionsBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/SortingOptionsBottomSheet.kt index 7251ae9a..259f2c50 100644 --- a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/SortingOptionsBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/SortingOptionsBottomSheet.kt @@ -4,7 +4,7 @@ import android.app.Dialog import com.facebook.litho.ComponentContext import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences import com.maubis.scarlet.base.core.note.SortingTechnique import com.maubis.scarlet.base.support.sheets.LithoChooseOptionBottomSheet import com.maubis.scarlet.base.support.sheets.LithoChooseOptionsItem @@ -12,48 +12,24 @@ import com.maubis.scarlet.base.support.sheets.LithoChooseOptionsItem class SortingOptionsBottomSheet : LithoChooseOptionBottomSheet() { var listener: () -> Unit = {} - override fun title(): Int = R.string.sort_sheet_title + override fun title(): Int = R.string.sort_sheet_title override fun getOptions(componentContext: ComponentContext, dialog: Dialog): List { val sorting = getSortingState() val options = ArrayList() - options.add(LithoChooseOptionsItem( - title = getSortingTechniqueLabel(SortingTechnique.LAST_MODIFIED), - listener = { - setSortingState(SortingTechnique.LAST_MODIFIED) - listener() - reset(componentContext.androidContext, dialog) - }, - selected = sorting == SortingTechnique.LAST_MODIFIED - )) - options.add(LithoChooseOptionsItem( - title = getSortingTechniqueLabel(SortingTechnique.NEWEST_FIRST), - listener = { - setSortingState(SortingTechnique.NEWEST_FIRST) - listener() - reset(componentContext.androidContext, dialog) - }, - selected = sorting == SortingTechnique.NEWEST_FIRST - )) - options.add(LithoChooseOptionsItem( - title = getSortingTechniqueLabel(SortingTechnique.OLDEST_FIRST), - listener = { - setSortingState(SortingTechnique.OLDEST_FIRST) - listener() - reset(componentContext.androidContext, dialog) - }, - selected = sorting == SortingTechnique.OLDEST_FIRST - )) - options.add(LithoChooseOptionsItem( - title = getSortingTechniqueLabel(SortingTechnique.ALPHABETICAL), - listener = { - setSortingState(SortingTechnique.ALPHABETICAL) - listener() - reset(componentContext.androidContext, dialog) - }, - selected = sorting == SortingTechnique.ALPHABETICAL - )) + SortingTechnique.values().forEach { technique -> + options.add( + LithoChooseOptionsItem( + title = getSortingTechniqueLabel(technique), + listener = { + setSortingState(technique) + listener() + reset(componentContext.androidContext, dialog) + }, + selected = sorting == technique + )) + } return options } @@ -62,7 +38,7 @@ class SortingOptionsBottomSheet : LithoChooseOptionBottomSheet() { const val KEY_SORTING_TECHNIQUE = "KEY_SORTING_TECHNIQUE" fun getSortingState(): SortingTechnique { - return SortingTechnique.values()[CoreConfig.instance.store().get(KEY_SORTING_TECHNIQUE, SortingTechnique.NEWEST_FIRST.ordinal)] + return SortingTechnique.values()[sAppPreferences.get(KEY_SORTING_TECHNIQUE, SortingTechnique.LAST_MODIFIED.ordinal)] } fun getSortingTechniqueLabel(technique: SortingTechnique): Int { @@ -71,11 +47,13 @@ class SortingOptionsBottomSheet : LithoChooseOptionBottomSheet() { SortingTechnique.NEWEST_FIRST -> R.string.sort_sheet_newest_first SortingTechnique.OLDEST_FIRST -> R.string.sort_sheet_oldest_first SortingTechnique.ALPHABETICAL -> R.string.sort_sheet_alphabetical + SortingTechnique.NOTE_COLOR -> R.string.sort_sheet_note_color + SortingTechnique.NOTE_TAGS -> R.string.sort_sheet_note_tags } } fun setSortingState(sortingTechnique: SortingTechnique) { - CoreConfig.instance.store().put(KEY_SORTING_TECHNIQUE, sortingTechnique.ordinal) + sAppPreferences.put(KEY_SORTING_TECHNIQUE, sortingTechnique.ordinal) } fun openSheet(activity: MainActivity, listener: () -> Unit) { diff --git a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/ThemeColorPickerBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/ThemeColorPickerBottomSheet.kt index fb17fb3a..d4b5abf8 100644 --- a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/ThemeColorPickerBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/ThemeColorPickerBottomSheet.kt @@ -2,17 +2,25 @@ package com.maubis.scarlet.base.settings.sheet import android.app.Dialog import android.graphics.Color -import com.facebook.litho.* +import androidx.appcompat.app.AppCompatActivity +import com.facebook.litho.ClickEvent +import com.facebook.litho.Column +import com.facebook.litho.Component +import com.facebook.litho.ComponentContext +import com.facebook.litho.Row import com.facebook.litho.annotations.LayoutSpec import com.facebook.litho.annotations.OnCreateLayout import com.facebook.litho.annotations.OnEvent import com.facebook.litho.annotations.Prop import com.facebook.yoga.YogaAlign import com.facebook.yoga.YogaEdge +import com.maubis.scarlet.base.MainActivityActions import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme import com.maubis.scarlet.base.main.sheets.InstallProUpsellBottomSheet import com.maubis.scarlet.base.support.sheets.LithoBottomSheet +import com.maubis.scarlet.base.support.sheets.LithoOptionsItem +import com.maubis.scarlet.base.support.sheets.OptionItemLayout import com.maubis.scarlet.base.support.sheets.getLithoBottomSheetTitle import com.maubis.scarlet.base.support.sheets.openSheet import com.maubis.scarlet.base.support.specs.BottomSheetBar @@ -21,45 +29,51 @@ import com.maubis.scarlet.base.support.specs.RoundIcon import com.maubis.scarlet.base.support.ui.Theme import com.maubis.scarlet.base.support.ui.ThemeManager.Companion.getThemeFromStore import com.maubis.scarlet.base.support.ui.ThemedActivity -import com.maubis.scarlet.base.support.utils.Flavor +import com.maubis.scarlet.base.support.ui.sThemeDarkenNoteColor +import com.maubis.scarlet.base.support.ui.sThemeIsAutomatic +import com.maubis.scarlet.base.support.ui.setThemeFromSystem +import com.maubis.scarlet.base.support.utils.FlavorUtils +import com.maubis.scarlet.base.support.utils.OsVersionUtils @LayoutSpec object ThemeColorPickerItemSpec { @OnCreateLayout - fun onCreate(context: ComponentContext, - @Prop theme: Theme, - @Prop isDisabled: Boolean, - @Prop isSelected: Boolean): Component { + fun onCreate( + context: ComponentContext, + @Prop theme: Theme, + @Prop isDisabled: Boolean, + @Prop isSelected: Boolean): Component { - var icon = RoundIcon.create(context) - .showBorder(true) - .iconSizeDip(64f) - .iconPaddingDip(16f) - .onClick { } - .flexGrow(1f) - .isClickDisabled(true) - .alpha(if (isDisabled) 0.3f else 1f) + val icon = RoundIcon.create(context) + .showBorder(true) + .iconSizeDip(64f) + .iconPaddingDip(16f) + .onClick { } + .flexGrow(1f) + .isClickDisabled(true) + .alpha(if (isDisabled) 0.3f else 1f) when (isSelected) { true -> icon.iconRes(R.drawable.ic_done_white_48dp) - .bgColorRes(R.color.colorAccent) - .iconColor(Color.WHITE) + .bgColorRes(R.color.colorAccent) + .iconColor(Color.WHITE) false -> icon.iconRes(R.drawable.icon_realtime_markdown) - .bgColorRes(theme.background) - .iconColorRes(theme.primaryText) + .bgColorRes(theme.background) + .iconColorRes(theme.primaryText) } val row = Row.create(context) - .widthPercent(100f) - .alignItems(YogaAlign.CENTER) - .child(icon) + .widthPercent(100f) + .alignItems(YogaAlign.CENTER) + .child(icon) row.clickHandler(ThemeColorPickerItem.onItemClick(context)) return row.build() } @OnEvent(ClickEvent::class) - fun onItemClick(context: ComponentContext, - @Prop theme: Theme, - @Prop isDisabled: Boolean, - @Prop onThemeSelected: (Theme) -> Unit) { + fun onItemClick( + context: ComponentContext, + @Prop theme: Theme, + @Prop isDisabled: Boolean, + @Prop onThemeSelected: (Theme) -> Unit) { if (isDisabled) { openSheet(context.androidContext as ThemedActivity, InstallProUpsellBottomSheet()) return @@ -74,46 +88,104 @@ class ThemeColorPickerBottomSheet : LithoBottomSheet() { override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { val column = Column.create(componentContext) - .widthPercent(100f) - .paddingDip(YogaEdge.VERTICAL, 8f) - .paddingDip(YogaEdge.HORIZONTAL, 20f) - .child(getLithoBottomSheetTitle(componentContext) - .textRes(R.string.theme_page_title) - .marginDip(YogaEdge.HORIZONTAL, 0f)) + .widthPercent(100f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .child( + getLithoBottomSheetTitle(componentContext) + .textRes(R.string.theme_page_title) + .marginDip(YogaEdge.HORIZONTAL, 0f)) - var flex: Row.Builder? = null - Theme.values().forEachIndexed { index, theme -> - if (index % 4 == 0) { - column.child(flex) - flex = Row.create(componentContext) + if (OsVersionUtils.canUseSystemTheme()) { + column.child( + OptionItemLayout.create(componentContext) + .option( + LithoOptionsItem( + title = R.string.theme_use_system_theme, + subtitle = R.string.theme_use_system_theme_details, + icon = R.drawable.ic_action_color, + listener = {}, + isSelectable = true, + selected = sThemeIsAutomatic, + actionIcon = if (FlavorUtils.isLite()) R.drawable.ic_rating else 0 + )) + .onClick { + val context = componentContext.androidContext as AppCompatActivity + if (FlavorUtils.isLite()) { + openSheet(context, InstallProUpsellBottomSheet()) + return@onClick + } + + sThemeIsAutomatic = !sThemeIsAutomatic + if (sThemeIsAutomatic) { + setThemeFromSystem(context) + onThemeChange(sAppTheme.get()) + } + reset(context, dialog) + }) + } + + if (sAppTheme.isNightTheme()) { + column.child( + OptionItemLayout.create(componentContext) + .option( + LithoOptionsItem( + title = R.string.theme_dark_notes, + subtitle = R.string.theme_dark_notes_details, + icon = R.drawable.night_mode_white_48dp, + listener = {}, + isSelectable = true, + selected = sThemeDarkenNoteColor, + actionIcon = if (FlavorUtils.isLite()) R.drawable.ic_rating else 0 + )) + .onClick { + val context = componentContext.androidContext as AppCompatActivity + if (FlavorUtils.isLite()) { + openSheet(context, InstallProUpsellBottomSheet()) + return@onClick + } + + sThemeDarkenNoteColor = !sThemeDarkenNoteColor + context.startActivity(MainActivityActions.COLOR_PICKER.intent(context)) + context.finish() + }) + } + + if (!sThemeIsAutomatic) { + var flex: Row.Builder? = null + Theme.values().forEachIndexed { index, theme -> + if (index % 4 == 0) { + column.child(flex) + flex = Row.create(componentContext) .widthPercent(100f) .alignItems(YogaAlign.CENTER) .paddingDip(YogaEdge.VERTICAL, 12f) - } + } - val disabled = when { - CoreConfig.instance.appFlavor() == Flavor.PRO -> false - theme == Theme.DARK || theme == Theme.LIGHT -> false - else -> true - } - flex?.child( + val disabled = when { + !FlavorUtils.isLite() -> false + theme == Theme.DARK || theme == Theme.LIGHT -> false + else -> true + } + flex?.child( ThemeColorPickerItem.create(componentContext) - .theme(theme) - .isDisabled(disabled) - .isSelected(theme.name == getThemeFromStore().name) - .onThemeSelected { theme -> - onThemeChange(theme) - reset(componentContext.androidContext, dialog) - } - .flexGrow(1f)) + .theme(theme) + .isDisabled(disabled) + .isSelected(theme.name == getThemeFromStore().name) + .onThemeSelected { newTheme -> + onThemeChange(newTheme) + } + .flexGrow(1f)) + } + column.child(flex) } - column.child(flex) + column.child(EmptySpec.create(componentContext).widthPercent(100f).heightDip(24f)) column.child(BottomSheetBar.create(componentContext) - .primaryActionRes(R.string.import_export_layout_exporting_done) - .onPrimaryClick { - dismiss() - }.paddingDip(YogaEdge.VERTICAL, 8f)) + .primaryActionRes(R.string.import_export_layout_exporting_done) + .onPrimaryClick { + dismiss() + }.paddingDip(YogaEdge.VERTICAL, 8f)) return column.build() } } diff --git a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/TypefacePickerBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/TypefacePickerBottomSheet.kt new file mode 100644 index 00000000..92e92322 --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/TypefacePickerBottomSheet.kt @@ -0,0 +1,157 @@ +package com.maubis.scarlet.base.settings.sheet + +import android.app.Dialog +import com.facebook.litho.ClickEvent +import com.facebook.litho.Column +import com.facebook.litho.Component +import com.facebook.litho.ComponentContext +import com.facebook.litho.Row +import com.facebook.litho.annotations.LayoutSpec +import com.facebook.litho.annotations.OnCreateLayout +import com.facebook.litho.annotations.OnEvent +import com.facebook.litho.annotations.Prop +import com.facebook.litho.widget.Text +import com.facebook.yoga.YogaAlign +import com.facebook.yoga.YogaEdge +import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface +import com.maubis.scarlet.base.main.sheets.InstallProUpsellBottomSheet +import com.maubis.scarlet.base.support.sheets.LithoBottomSheet +import com.maubis.scarlet.base.support.sheets.getLithoBottomSheetTitle +import com.maubis.scarlet.base.support.sheets.openSheet +import com.maubis.scarlet.base.support.specs.BottomSheetBar +import com.maubis.scarlet.base.support.specs.EmptySpec +import com.maubis.scarlet.base.support.ui.LithoCircleDrawable +import com.maubis.scarlet.base.support.ui.ThemeColorType +import com.maubis.scarlet.base.support.ui.ThemedActivity +import com.maubis.scarlet.base.support.ui.font.TypefaceController +import com.maubis.scarlet.base.support.ui.font.sPreferenceTypeface +import com.maubis.scarlet.base.support.utils.FlavorUtils + +@LayoutSpec +object TypefacePickerItemSpec { + @OnCreateLayout + fun onCreate( + context: ComponentContext, + @Prop typeface: TypefaceController.TypefaceType, + @Prop isDisabled: Boolean, + @Prop isSelected: Boolean): Component { + + val typefaceSet = sAppTypeface.getSetForType(context.androidContext, typeface) + val fontColor = when (isSelected) { + true -> sAppTheme.get(ThemeColorType.ACCENT_TEXT) + false -> sAppTheme.get(ThemeColorType.SECONDARY_TEXT) + } + val content = Column.create(context) + .paddingDip(YogaEdge.ALL, 24f) + .child( + Row.create(context) + .child( + Text.create(context) + .text("Abc") + .textSizeRes(R.dimen.font_size_xlarge) + .textColor(fontColor) + .typeface(typefaceSet.heading)) + .child( + Text.create(context) + .text("defg") + .textSizeRes(R.dimen.font_size_xlarge) + .textColor(fontColor) + .typeface(typefaceSet.subHeading))) + .child( + Text.create(context) + .text("hijklmnop") + .textSizeRes(R.dimen.font_size_large) + .textColor(fontColor) + .typeface(typefaceSet.title)) + .child( + Text.create(context) + .text("qrstuvwxyz\n0123456789") + .textSizeRes(R.dimen.font_size_normal) + .textColor(fontColor) + .typeface(typefaceSet.text)) + .background(LithoCircleDrawable(sAppTheme.get(ThemeColorType.BACKGROUND), 255, true)) + + val data = Column.create(context) + .alignSelf(YogaAlign.CENTER) + .alignContent(YogaAlign.CENTER) + .alignItems(YogaAlign.CENTER) + .marginAuto(YogaEdge.HORIZONTAL) + .child(content) + .child( + Text.create(context) + .textRes(typeface.title) + .textSizeRes(R.dimen.font_size_normal) + .textColor(sAppTheme.get(ThemeColorType.PRIMARY_TEXT)) + .typeface(sAppTypeface.title()) + .marginDip(YogaEdge.TOP, 12f)) + if (isDisabled) { + data.alpha(0.4f) + } + + val row = Row.create(context) + .widthPercent(100f) + .alignItems(YogaAlign.CENTER) + .alignContent(YogaAlign.CENTER) + .child(data) + row.clickHandler(ThemeColorPickerItem.onItemClick(context)) + return row.build() + } + + @OnEvent(ClickEvent::class) + fun onItemClick( + context: ComponentContext, + @Prop typeface: TypefaceController.TypefaceType, + @Prop isDisabled: Boolean, + @Prop onTypefaceSelected: (TypefaceController.TypefaceType) -> Unit) { + if (isDisabled) { + openSheet(context.androidContext as ThemedActivity, InstallProUpsellBottomSheet()) + return + } + onTypefaceSelected(typeface) + } +} + +class TypefacePickerBottomSheet : LithoBottomSheet() { + + var onTypefaceChange: (TypefaceController.TypefaceType) -> Unit = {} + + override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { + val column = Column.create(componentContext) + .widthPercent(100f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .child( + getLithoBottomSheetTitle(componentContext) + .textRes(R.string.typeface_page_title) + .marginDip(YogaEdge.HORIZONTAL, 0f)) + + var flex: Row.Builder? = null + TypefaceController.TypefaceType.values().forEachIndexed { index, typeface -> + if (index % 2 == 0) { + column.child(flex) + flex = Row.create(componentContext) + .widthPercent(100f) + .alignItems(YogaAlign.CENTER) + .paddingDip(YogaEdge.VERTICAL, 12f) + } + flex?.child( + TypefacePickerItem.create(componentContext) + .typeface(typeface) + .isDisabled(FlavorUtils.isLite() && !typeface.isLiteEnabled) + .isSelected(sPreferenceTypeface == typeface.name) + .onTypefaceSelected { newTypeface -> onTypefaceChange(newTypeface) } + .flexGrow(1f)) + } + column.child(flex) + + column.child(EmptySpec.create(componentContext).widthPercent(100f).heightDip(24f)) + column.child(BottomSheetBar.create(componentContext) + .primaryActionRes(R.string.import_export_layout_exporting_done) + .onPrimaryClick { + dismiss() + }.paddingDip(YogaEdge.VERTICAL, 8f)) + return column.build() + } +} diff --git a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/UISettingsOptionsBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/UISettingsOptionsBottomSheet.kt index ebff2d37..e5973805 100644 --- a/base/src/main/java/com/maubis/scarlet/base/settings/sheet/UISettingsOptionsBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/settings/sheet/UISettingsOptionsBottomSheet.kt @@ -3,16 +3,30 @@ package com.maubis.scarlet.base.settings.sheet import android.app.Dialog import com.facebook.litho.ComponentContext import com.maubis.scarlet.base.MainActivity +import com.maubis.scarlet.base.MainActivityActions import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme import com.maubis.scarlet.base.main.sheets.InstallProUpsellBottomSheet +import com.maubis.scarlet.base.performAction import com.maubis.scarlet.base.settings.sheet.SortingOptionsBottomSheet.Companion.getSortingState import com.maubis.scarlet.base.settings.sheet.SortingOptionsBottomSheet.Companion.getSortingTechniqueLabel import com.maubis.scarlet.base.support.sheets.LithoOptionBottomSheet import com.maubis.scarlet.base.support.sheets.LithoOptionsItem import com.maubis.scarlet.base.support.sheets.openSheet -import com.maubis.scarlet.base.support.ui.KEY_APP_THEME -import com.maubis.scarlet.base.support.utils.Flavor +import com.maubis.scarlet.base.support.utils.FlavorUtils + +var sUIUseGridView: Boolean + get() = sAppPreferences.get("KEY_LIST_VIEW", true) + set(isGrid) = sAppPreferences.put("KEY_LIST_VIEW", isGrid) + +var sUIUseNoteColorAsBackground: Boolean + get() = sAppPreferences.get("KEY_NOTE_VIEWER_BG_COLOR", false) + set(value) = sAppPreferences.put("KEY_NOTE_VIEWER_BG_COLOR", value) + +var sUIMarkdownEnabledOnHome: Boolean + get() = sAppPreferences.get("KEY_MARKDOWN_HOME_ENABLED", true) + set(value) = sAppPreferences.put("KEY_MARKDOWN_HOME_ENABLED", value) class UISettingsOptionsBottomSheet : LithoOptionBottomSheet() { override fun title(): Int = R.string.home_option_ui_experience @@ -20,133 +34,111 @@ class UISettingsOptionsBottomSheet : LithoOptionBottomSheet() { override fun getOptions(componentContext: ComponentContext, dialog: Dialog): List { val activity = componentContext.androidContext as MainActivity val options = ArrayList() - val flavor = CoreConfig.instance.appFlavor() options.add(LithoOptionsItem( - title = R.string.home_option_theme_color, - subtitle = R.string.home_option_theme_color_subtitle, - icon = if (CoreConfig.instance.themeController().isNightTheme()) R.drawable.night_mode_white_48dp else R.drawable.ic_action_day_mode, - listener = { - com.maubis.scarlet.base.support.sheets.openSheet(activity, ThemeColorPickerBottomSheet().apply { - this.onThemeChange = { theme -> - CoreConfig.instance.store().put(KEY_APP_THEME, theme.name) - CoreConfig.instance.themeController().notifyChange(activity) - activity.notifyThemeChange() - reset(activity, dialog) - } - }) - } + title = R.string.home_option_theme_color, + subtitle = R.string.home_option_theme_color_subtitle, + icon = if (sAppTheme.isNightTheme()) R.drawable.night_mode_white_48dp else R.drawable.ic_action_day_mode, + listener = { + activity.performAction(MainActivityActions.COLOR_PICKER) + } )) - val isTablet = resources.getBoolean(R.bool.is_tablet) options.add(LithoOptionsItem( + title = R.string.home_option_typeface, + subtitle = R.string.home_option_typeface_subtitle, + icon = R.drawable.icon_typeface, + listener = { + activity.performAction(MainActivityActions.TYPEFACE_PICKER) + } + )) + val isTablet = resources.getBoolean(R.bool.is_tablet) + options.add( + LithoOptionsItem( title = R.string.home_option_enable_list_view, subtitle = R.string.home_option_enable_list_view_subtitle, icon = R.drawable.ic_action_list, listener = { - useGridView = false + sUIUseGridView = false activity.notifyAdapterExtraChanged() reset(activity, dialog) }, - visible = !isTablet && useGridView - )) - options.add(LithoOptionsItem( + visible = !isTablet && sUIUseGridView + )) + options.add( + LithoOptionsItem( title = R.string.home_option_enable_grid_view, subtitle = R.string.home_option_enable_grid_view_subtitle, icon = R.drawable.ic_action_grid, listener = { - useGridView = true + sUIUseGridView = true activity.notifyAdapterExtraChanged() reset(activity, dialog) }, - visible = !isTablet && !useGridView - )) + visible = !isTablet && !sUIUseGridView + )) options.add(LithoOptionsItem( - title = R.string.home_option_order_notes, - subtitle = getSortingTechniqueLabel(getSortingState()), - icon = R.drawable.ic_sort, - listener = { - SortingOptionsBottomSheet.openSheet(activity, { activity.setupData() }) - reset(activity, dialog) - } + title = R.string.home_option_order_notes, + subtitle = getSortingTechniqueLabel(getSortingState()), + icon = R.drawable.ic_sort, + listener = { + SortingOptionsBottomSheet.openSheet(activity, { activity.loadData() }) + reset(activity, dialog) + } )) - options.add(LithoOptionsItem( + options.add( + LithoOptionsItem( title = R.string.note_option_font_size, subtitle = 0, content = activity.getString(R.string.note_option_font_size_subtitle, sEditorTextSize), icon = R.drawable.ic_title_white_48dp, listener = { - if (flavor == Flavor.PRO) { - com.maubis.scarlet.base.support.sheets.openSheet(activity, FontSizeBottomSheet()) - } else { - openSheet(activity, InstallProUpsellBottomSheet()) + when { + FlavorUtils.isLite() -> openSheet(activity, InstallProUpsellBottomSheet()) + else -> openSheet(activity, FontSizeBottomSheet()) } reset(activity, dialog) }, - visible = flavor != Flavor.NONE, - actionIcon = if (flavor == Flavor.PRO) 0 else R.drawable.ic_rating - )) + actionIcon = if (FlavorUtils.isLite()) R.drawable.ic_rating else 0 + )) options.add(LithoOptionsItem( - title = R.string.note_option_number_lines, - subtitle = 0, - content = activity.getString(R.string.note_option_number_lines_subtitle, sNoteItemLineCount), - icon = R.drawable.ic_action_list, - listener = { - openSheet(activity, LineCountBottomSheet()) - } + title = R.string.note_option_number_lines, + subtitle = 0, + content = activity.getString(R.string.note_option_number_lines_subtitle, sNoteItemLineCount), + icon = R.drawable.ic_action_list, + listener = { + openSheet(activity, LineCountBottomSheet()) + } )) - options.add(LithoOptionsItem( + options.add( + LithoOptionsItem( title = R.string.ui_options_note_background_color, - subtitle = when (useNoteColorAsBackground) { + subtitle = when (sUIUseNoteColorAsBackground) { true -> R.string.ui_options_note_background_color_settings_note false -> R.string.ui_options_note_background_color_settings_theme }, icon = R.drawable.ic_action_color, listener = { - if (flavor != Flavor.PRO) { + if (FlavorUtils.isLite()) { openSheet(activity, InstallProUpsellBottomSheet()) return@LithoOptionsItem } - useNoteColorAsBackground = !useNoteColorAsBackground + sUIUseNoteColorAsBackground = !sUIUseNoteColorAsBackground reset(activity, dialog) }, - visible = flavor != Flavor.NONE, - actionIcon = if (flavor == Flavor.PRO) 0 else R.drawable.ic_rating - )) - options.add(LithoOptionsItem( + actionIcon = if (FlavorUtils.isLite()) R.drawable.ic_rating else 0 + )) + options.add( + LithoOptionsItem( title = R.string.markdown_sheet_home_markdown_support, subtitle = R.string.markdown_sheet_home_markdown_support_subtitle, icon = R.drawable.ic_markdown_logo, listener = { - sMarkdownEnabledHome = !sMarkdownEnabledHome + sUIMarkdownEnabledOnHome = !sUIMarkdownEnabledOnHome reset(activity, dialog) }, isSelectable = true, - selected = sMarkdownEnabledHome - )) + selected = sUIMarkdownEnabledOnHome + )) return options } - - companion object { - - const val KEY_LIST_VIEW = "KEY_LIST_VIEW" - const val KEY_NOTE_VIEWER_BG_COLOR = "KEY_NOTE_VIEWER_BG_COLOR" - const val KEY_MARKDOWN_HOME_ENABLED = "KEY_MARKDOWN_HOME_ENABLED" - - fun openSheet(activity: MainActivity) { - val sheet = UISettingsOptionsBottomSheet() - sheet.show(activity.supportFragmentManager, sheet.tag) - } - - var useGridView: Boolean - get() = CoreConfig.instance.store().get(KEY_LIST_VIEW, true) - set(isGrid) = CoreConfig.instance.store().put(KEY_LIST_VIEW, isGrid) - - var useNoteColorAsBackground: Boolean - get() = CoreConfig.instance.store().get(KEY_NOTE_VIEWER_BG_COLOR, false) - set(value) = CoreConfig.instance.store().put(KEY_NOTE_VIEWER_BG_COLOR, value) - - var sMarkdownEnabledHome: Boolean - get() = CoreConfig.instance.store().get(KEY_MARKDOWN_HOME_ENABLED, true) - set(value) = CoreConfig.instance.store().put(KEY_MARKDOWN_HOME_ENABLED, value) - } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/settings/view/ColorView.kt b/base/src/main/java/com/maubis/scarlet/base/settings/view/ColorView.kt index 4dc00953..73940a01 100644 --- a/base/src/main/java/com/maubis/scarlet/base/settings/view/ColorView.kt +++ b/base/src/main/java/com/maubis/scarlet/base/settings/view/ColorView.kt @@ -22,7 +22,6 @@ class ColorView : LinearLayout { init(context) } - constructor(context: Context, layout: Int) : super(context) { init(context, layout) } diff --git a/base/src/main/java/com/maubis/scarlet/base/support/BitmapHelper.kt b/base/src/main/java/com/maubis/scarlet/base/support/BitmapHelper.kt new file mode 100644 index 00000000..3951c0b3 --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/support/BitmapHelper.kt @@ -0,0 +1,54 @@ +package com.maubis.scarlet.base.support + +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.net.Uri +import android.provider.MediaStore +import java.io.File +import java.io.FileOutputStream + +object BitmapHelper { + fun send(context: Context, bitmap: Bitmap) { + val path = MediaStore.Images.Media.insertImage( + context.contentResolver, bitmap, "Scarlet Image", "Scarlet Image") + val uri = Uri.parse(path) + + val intent = Intent(Intent.ACTION_SEND) + intent.type = "image/jpeg" + intent.putExtra(Intent.EXTRA_STREAM, uri) + context.startActivity(Intent.createChooser(intent, "Share Image")) + } + + fun send(context: Context, bitmaps: List) { + val fileUris = ArrayList() + bitmaps + .mapIndexed { index, bitmap -> + MediaStore.Images.Media.insertImage( + context.contentResolver, bitmap, "Scarlet Image ($index)", "Scarlet Image ($index)") + }.map { + Uri.parse(it) + }.forEach { fileUris.add(it) } + val intent = Intent(Intent.ACTION_SEND_MULTIPLE) + intent.type = "image/jpeg" + intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, fileUris) + context.startActivity(Intent.createChooser(intent, "Share Images")) + } + + fun loadFromFile(cacheFile: File): Bitmap? { + if (cacheFile.exists()) { + val options = BitmapFactory.Options() + options.inPreferredConfig = Bitmap.Config.ARGB_8888 + return BitmapFactory.decodeFile(cacheFile.absolutePath, options) + } + return null + } + + fun saveToFile(cacheFile: File, bitmap: Bitmap) { + val fOut = FileOutputStream(cacheFile) + bitmap.compress(Bitmap.CompressFormat.PNG, 90, fOut) + fOut.flush() + fOut.close() + } +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/support/SearchConfig.kt b/base/src/main/java/com/maubis/scarlet/base/support/SearchConfig.kt deleted file mode 100644 index 1442fe86..00000000 --- a/base/src/main/java/com/maubis/scarlet/base/support/SearchConfig.kt +++ /dev/null @@ -1,130 +0,0 @@ -package com.maubis.scarlet.base.support - -import com.maubis.scarlet.base.config.CoreConfig.Companion.foldersDb -import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb -import com.maubis.scarlet.base.core.note.NoteState -import com.maubis.scarlet.base.core.note.sort -import com.maubis.scarlet.base.database.room.folder.Folder -import com.maubis.scarlet.base.database.room.note.Note -import com.maubis.scarlet.base.database.room.tag.Tag -import com.maubis.scarlet.base.main.HomeNavigationState -import com.maubis.scarlet.base.note.getFullText -import com.maubis.scarlet.base.settings.sheet.SortingOptionsBottomSheet - -class SearchConfig( - var text: String = "", - var mode: HomeNavigationState = HomeNavigationState.DEFAULT, - var colors: MutableList = emptyList().toMutableList(), - var tags: MutableList = emptyList().toMutableList(), - var folders: MutableList = emptyList().toMutableList()) { - - fun hasFolder(folder: Folder) = folders.firstOrNull { it.uuid == folder.uuid } !== null - - fun hasFilter(): Boolean { - return folders.isNotEmpty() - || tags.isNotEmpty() - || colors.isNotEmpty() - || text.isNotBlank() - || mode !== HomeNavigationState.DEFAULT; - } - - fun clear(): SearchConfig { - mode = HomeNavigationState.DEFAULT - text = "" - colors.clear() - tags.clear() - folders.clear() - return this - } - - fun clearSearchBar(): SearchConfig { - text = "" - colors.clear() - tags.clear() - return this - } - - fun resetMode(state: HomeNavigationState): SearchConfig { - mode = state - return this - } - - fun copy(): SearchConfig { - return SearchConfig( - text, - mode, - colors.filter { true }.toMutableList(), - tags.filter { true }.toMutableList(), - folders.filter { true }.toMutableList()) - } -} - -fun unifiedSearchSynchronous(config: SearchConfig): List { - val sorting = SortingOptionsBottomSheet.getSortingState() - val notes = filterSearchWithoutFolder(config) - .filter { - when (config.folders.isEmpty()) { - true -> it.folder.isBlank() - false -> config.folders.map { it.uuid }.contains(it.folder) - } - } - return sort(notes, sorting) -} - -private fun filterSearchWithoutFolder(config: SearchConfig): List { - return getNotesForMode(config) - .filter { config.colors.isEmpty() || config.colors.contains(it.color) } - .filter { note -> config.tags.isEmpty() || config.tags.filter { note.tags !== null && note.tags.contains(it.uuid) }.isNotEmpty() } - .filter { - when { - config.text.isBlank() -> true - it.locked -> false - else -> it.getFullText().contains(config.text, true) - } - } -} - -fun unifiedFolderSearchSynchronous(config: SearchConfig): List { - if (!config.folders.isEmpty()) { - return emptyList() - } - if (config.text.isNotBlank() || config.tags.isNotEmpty()) { - val folders = HashSet() - if (config.text.isNotBlank()) { - folders.addAll( - foldersDb.getAll() - .filter { config.colors.isEmpty() || config.colors.contains(it.color) } - .filter { it.title.contains(config.text, true) }) - } - folders.addAll( - filterSearchWithoutFolder(config) - .filter { it.folder.isNotBlank() } - .map { it.folder } - .distinct() - .map { foldersDb.getByUUID(it) } - .filterNotNull()) - return folders.toList() - } - return foldersDb.getAll() - .filter { - config.colors.isEmpty() - || config.colors.contains(it.color) - || notesDb.getNotesByFolder(it.uuid).filter { config.colors.contains(it.color) }.isNotEmpty() - } - .filter { - when { - config.text.isBlank() -> true - else -> it.title.contains(config.text, true) - } - } -} - -fun getNotesForMode(config: SearchConfig): List { - return when (config.mode) { - HomeNavigationState.FAVOURITE -> notesDb.getByNoteState(arrayOf(NoteState.FAVOURITE.name)) - HomeNavigationState.ARCHIVED -> notesDb.getByNoteState(arrayOf(NoteState.ARCHIVED.name)) - HomeNavigationState.TRASH -> notesDb.getByNoteState(arrayOf(NoteState.TRASH.name)) - HomeNavigationState.DEFAULT -> notesDb.getByNoteState(arrayOf(NoteState.DEFAULT.name, NoteState.FAVOURITE.name)) - HomeNavigationState.LOCKED -> notesDb.getNoteByLocked(true) - } -} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/support/ShortcutUtils.kt b/base/src/main/java/com/maubis/scarlet/base/support/ShortcutUtils.kt new file mode 100644 index 00000000..f2e4291d --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/support/ShortcutUtils.kt @@ -0,0 +1,29 @@ +package com.maubis.scarlet.base.support + +import android.app.PendingIntent +import android.content.Context +import android.content.pm.ShortcutInfo +import android.content.pm.ShortcutManager +import com.maubis.scarlet.base.support.utils.OsVersionUtils + +fun addShortcut(context: Context, shortcut: ShortcutInfo) { + if (!OsVersionUtils.canAddLauncherShortcuts()) { + return + } + + val shortcutManager = context.getSystemService(ShortcutManager::class.java) + if (shortcutManager === null) { + return + } + + shortcutManager.dynamicShortcuts = listOf(shortcut) + if (shortcutManager.isRequestPinShortcutSupported) { + val pinShortcutInfo = ShortcutInfo.Builder(context, shortcut.id).build() + val pinnedShortcutCallbackIntent = shortcutManager.createShortcutResultIntent(pinShortcutInfo) + + val successCallback = PendingIntent.getBroadcast( + context, 0, + pinnedShortcutCallbackIntent, 0) + shortcutManager.requestPinShortcut(pinShortcutInfo, successCallback.intentSender) + } +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/support/database/HouseKeeper.kt b/base/src/main/java/com/maubis/scarlet/base/support/database/HouseKeeper.kt index ec5a9ac0..00e5deb4 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/database/HouseKeeper.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/database/HouseKeeper.kt @@ -1,7 +1,6 @@ package com.maubis.scarlet.base.support.database import android.content.Context -import com.github.bijoysingh.starter.async.SimpleThreadExecutor import com.maubis.scarlet.base.config.CoreConfig.Companion.foldersDb import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb import com.maubis.scarlet.base.core.note.NoteImage.Companion.deleteIfExist @@ -20,11 +19,11 @@ import java.util.concurrent.TimeUnit class HouseKeeper(val context: Context) { private val houseKeeperTasks: Array<() -> Unit> = arrayOf( - { removeOlderClips() }, - { removeDecoupledFolders() }, - { removeOldReminders() }, - { deleteRedundantImageFiles() }, - { migrateZeroUidNotes() } + { removeOlderClips() }, + { removeDecoupledFolders() }, + { removeOldReminders() }, + { deleteRedundantImageFiles() }, + { migrateZeroUidNotes() } ) fun execute() { @@ -33,10 +32,9 @@ class HouseKeeper(val context: Context) { } } - private fun removeOlderClips() { + fun removeOlderClips(deltaTimeMs: Long = 604800000L) { val notes = notesDb.database() - .getOldTrashedNotes( - Calendar.getInstance().timeInMillis - 1000 * 60 * 60 * 24 * 7) + .getOldTrashedNotes(Calendar.getInstance().timeInMillis - deltaTimeMs) for (note in notes) { note.delete(context) } @@ -45,13 +43,13 @@ class HouseKeeper(val context: Context) { private fun removeDecoupledFolders() { val folders = foldersDb.getAll().map { it.uuid } notesDb.getAll() - .filter { it.folder.isNotBlank() } - .forEach { - if (!folders.contains(it.folder)) { - it.folder = "" - it.save(context) - } + .filter { it.folder.isNotBlank() } + .forEach { + if (!folders.contains(it.folder)) { + it.folder = "" + it.save(context) } + } } private fun removeOldReminders() { diff --git a/base/src/main/java/com/maubis/scarlet/base/support/database/HouseKeeperJob.kt b/base/src/main/java/com/maubis/scarlet/base/support/database/HouseKeeperJob.kt index e0d210b0..7ebfa955 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/database/HouseKeeperJob.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/database/HouseKeeperJob.kt @@ -10,7 +10,7 @@ class HouseKeeperJob : DailyJob() { fun schedule() { val builder = JobRequest.Builder(TAG).setRequiresDeviceIdle(true) - DailyJob.schedule(builder, TimeUnit.HOURS.toMillis(1), TimeUnit.HOURS.toMillis(7)) + schedule(builder, TimeUnit.HOURS.toMillis(1), TimeUnit.HOURS.toMillis(16)) } } diff --git a/base/src/main/java/com/maubis/scarlet/base/support/database/MigrationUtils.kt b/base/src/main/java/com/maubis/scarlet/base/support/database/MigrationUtils.kt index 15b5017e..be12e0c6 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/database/MigrationUtils.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/database/MigrationUtils.kt @@ -2,34 +2,32 @@ package com.maubis.scarlet.base.support.database import android.content.Context import com.google.gson.Gson -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb import com.maubis.scarlet.base.core.note.NoteMeta import com.maubis.scarlet.base.core.note.Reminder import com.maubis.scarlet.base.core.note.getReminder import com.maubis.scarlet.base.note.reminders.ReminderJob import com.maubis.scarlet.base.note.saveWithoutSync -import com.maubis.scarlet.base.settings.sheet.UISettingsOptionsBottomSheet.Companion.KEY_LIST_VIEW -import com.maubis.scarlet.base.support.ui.KEY_APP_THEME -import com.maubis.scarlet.base.support.ui.KEY_NIGHT_THEME +import com.maubis.scarlet.base.settings.sheet.sUIUseGridView import com.maubis.scarlet.base.support.ui.Theme +import com.maubis.scarlet.base.support.ui.sThemeLabel import com.maubis.scarlet.base.support.utils.getLastUsedAppVersionCode +import com.maubis.scarlet.base.support.utils.maybeThrow +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch import java.io.File import java.util.* -const val KEY_MIGRATE_THEME = "KEY_MIGRATE_THEME" const val KEY_MIGRATE_DEFAULT_VALUES = "KEY_MIGRATE_DEFAULT_VALUES" const val KEY_MIGRATE_REMINDERS = "KEY_MIGRATE_REMINDERS" const val KEY_MIGRATE_IMAGES = "KEY_MIGRATE_IMAGES" +const val KEY_MIGRATE_TO_GDRIVE_DATABASE = "KEY_MIGRATE_TO_GDRIVE_DATABASE_v2" class Migrator(val context: Context) { fun start() { - runTask(KEY_MIGRATE_THEME) { - val isNightMode = CoreConfig.instance.store().get(KEY_NIGHT_THEME, true) - CoreConfig.instance.store().put(KEY_APP_THEME, if (isNightMode) Theme.DARK.name else Theme.LIGHT.name) - CoreConfig.instance.themeController().notifyChange(context) - } runTask(key = KEY_MIGRATE_REMINDERS) { val notes = notesDb.getAll() for (note in notes) { @@ -57,23 +55,39 @@ class Migrator(val context: Context) { File(context.cacheDir, "images").renameTo(File(context.filesDir, "images")) } runTaskIf( - getLastUsedAppVersionCode() == 0, - KEY_MIGRATE_DEFAULT_VALUES) { - CoreConfig.instance.store().put(KEY_APP_THEME, Theme.DARK.name) - CoreConfig.instance.store().put(KEY_LIST_VIEW, true) + getLastUsedAppVersionCode() == 0, + KEY_MIGRATE_DEFAULT_VALUES) { + sThemeLabel = Theme.DARK.name + sUIUseGridView = true + } + + runTask(KEY_MIGRATE_TO_GDRIVE_DATABASE) { + GlobalScope.launch { + val remoteDatabaseState = ApplicationBase.instance.remoteDatabaseState() + ApplicationBase.instance.notesDatabase().getAll().forEach { + remoteDatabaseState.notifyInsert(it) {} + } + ApplicationBase.instance.tagsDatabase().getAll().forEach { + remoteDatabaseState.notifyInsert(it) {} + } + ApplicationBase.instance.foldersDatabase().getAll().forEach { + remoteDatabaseState.notifyInsert(it) {} + } + } } } private fun runTask(key: String, task: () -> Unit) { - if (CoreConfig.instance.store().get(key, false)) { + if (sAppPreferences.get(key, false)) { return } try { task() - } catch (_: Exception) { + } catch (exception: Exception) { + maybeThrow(exception) } - CoreConfig.instance.store().put(key, true) + sAppPreferences.put(key, true) } private fun runTaskIf(condition: Boolean, key: String, task: () -> Unit) { diff --git a/base/src/main/java/com/maubis/scarlet/base/support/option/OptionsItem.kt b/base/src/main/java/com/maubis/scarlet/base/support/option/OptionsItem.kt index cb90dc85..97d04699 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/option/OptionsItem.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/option/OptionsItem.kt @@ -3,13 +3,13 @@ package com.maubis.scarlet.base.support.option import android.view.View class OptionsItem( - val title: Int, - val subtitle: Int, - val icon: Int, - val selected: Boolean = false, // indicates its a selected option (blue color) - val visible: Boolean = true, // indicates if the option is visible - val enabled: Boolean = false, // indicates if the option will show a checked on the side - val invalid: Boolean = false, // indicates that the option will be faded and click removed - val content: String = "", // content is an alternative to subtitle when it's 0 - val actionIcon: Int = 0, // icon resource for the action - val listener: View.OnClickListener) \ No newline at end of file + val title: Int, + val subtitle: Int, + val icon: Int, + val selected: Boolean = false, // indicates its a selected option (blue color) + val visible: Boolean = true, // indicates if the option is visible + val enabled: Boolean = false, // indicates if the option will show a checked on the side + val invalid: Boolean = false, // indicates that the option will be faded and click removed + val content: String = "", // content is an alternative to subtitle when it's 0 + val actionIcon: Int = 0, // icon resource for the action + val listener: View.OnClickListener) \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/support/option/TagOptionsItemBase.kt b/base/src/main/java/com/maubis/scarlet/base/support/option/TagOptionsItemBase.kt index 10e0cc34..fc51649a 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/option/TagOptionsItemBase.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/option/TagOptionsItemBase.kt @@ -4,12 +4,12 @@ import android.view.View import com.maubis.scarlet.base.database.room.tag.Tag abstract class TagOptionsItemBase( - val tag: Tag, - val usages: Int, - val selected: Boolean, - val editable: Boolean, - val editListener: View.OnClickListener? = null, - val listener: View.OnClickListener) : Comparable { + val tag: Tag, + val usages: Int, + val selected: Boolean, + val editable: Boolean, + val editListener: View.OnClickListener? = null, + val listener: View.OnClickListener) : Comparable { abstract fun getIcon(): Int diff --git a/base/src/main/java/com/maubis/scarlet/base/support/recycler/SimpleItemTouchHelper.kt b/base/src/main/java/com/maubis/scarlet/base/support/recycler/SimpleItemTouchHelper.kt index eea5a418..4a75cde0 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/recycler/SimpleItemTouchHelper.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/recycler/SimpleItemTouchHelper.kt @@ -1,7 +1,7 @@ package com.maubis.scarlet.base.support.recycler -import android.support.v7.widget.RecyclerView -import android.support.v7.widget.helper.ItemTouchHelper +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView class SimpleItemTouchHelper(private val mAdapter: ItemTouchHelperAdapter) : ItemTouchHelper.Callback() { @@ -9,16 +9,18 @@ class SimpleItemTouchHelper(private val mAdapter: ItemTouchHelperAdapter) : Item override fun isItemViewSwipeEnabled(): Boolean = true - override fun getMovementFlags(recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder): Int { + override fun getMovementFlags( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder): Int { val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN val swipeFlags = 0 //ItemTouchHelper.START | ItemTouchHelper.END; return ItemTouchHelper.Callback.makeMovementFlags(dragFlags, swipeFlags) } - override fun onMove(recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder, - target: RecyclerView.ViewHolder): Boolean { + override fun onMove( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + target: RecyclerView.ViewHolder): Boolean { mAdapter.onItemMove(viewHolder.adapterPosition, target.adapterPosition) return true } diff --git a/base/src/main/java/com/maubis/scarlet/base/support/sheets/GridBottomSheetBase.kt b/base/src/main/java/com/maubis/scarlet/base/support/sheets/GridBottomSheetBase.kt index c19e08c1..c8e168b6 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/sheets/GridBottomSheetBase.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/sheets/GridBottomSheetBase.kt @@ -6,7 +6,8 @@ import android.widget.GridLayout import android.widget.TextView import com.github.bijoysingh.uibasics.views.UILabelView import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface import com.maubis.scarlet.base.support.option.OptionsItem import com.maubis.scarlet.base.support.ui.ThemeColorType import com.maubis.scarlet.base.support.ui.ThemedBottomSheetFragment @@ -36,7 +37,7 @@ abstract class GridBottomSheetBase : ThemedBottomSheetFragment() { fun setOptionTitle(dialog: Dialog, title: Int) { GlobalScope.launch(Dispatchers.Main) { val titleView = dialog.findViewById(R.id.options_title) - titleView.setTextColor(CoreConfig.instance.themeController().get(ThemeColorType.SECONDARY_TEXT)) + titleView.setTextColor(sAppTheme.get(ThemeColorType.SECONDARY_TEXT)) titleView.setText(title) } } @@ -47,13 +48,15 @@ abstract class GridBottomSheetBase : ThemedBottomSheetFragment() { } fun setOptions(layoutGrid: GridLayout, options: List) { - layoutGrid.columnCount = if (resources.getBoolean(R.bool.is_tablet)) 4 else 3 + val context = layoutGrid.context + layoutGrid.columnCount = if (context.resources.getBoolean(R.bool.is_tablet)) 4 else 3 for (option in options) { if (!option.visible) { continue } val contentView = View.inflate(context, R.layout.layout_grid_item, null) as UILabelView + contentView.label.typeface = sAppTypeface.title() contentView.setText(option.title) contentView.setImageResource(option.icon) contentView.setTextColor(getOptionsTitleColor(option.selected)) diff --git a/base/src/main/java/com/maubis/scarlet/base/support/sheets/GridOptionBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/support/sheets/GridOptionBottomSheet.kt new file mode 100644 index 00000000..10e0e5db --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/support/sheets/GridOptionBottomSheet.kt @@ -0,0 +1,38 @@ +package com.maubis.scarlet.base.support.sheets + +import android.app.Dialog +import com.facebook.litho.Column +import com.facebook.litho.Component +import com.facebook.litho.ComponentContext +import com.facebook.yoga.YogaEdge +import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.support.specs.GridSectionItem +import com.maubis.scarlet.base.support.specs.GridSectionView + +abstract class GridOptionBottomSheet : LithoBottomSheet() { + + abstract fun title(): Int + abstract fun getOptions(componentContext: ComponentContext, dialog: Dialog): List + + override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { + val column = Column.create(componentContext) + .widthPercent(100f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .child(getLithoBottomSheetTitle(componentContext).textRes(title())) + + val options = getOptions(componentContext, dialog) + var index = 0 + options.forEach { + index++ + column.child( + GridSectionView.create(componentContext) + .marginDip(YogaEdge.HORIZONTAL, 12f) + .marginDip(YogaEdge.VERTICAL, 8f) + .iconSizeRes(R.dimen.primary_round_icon_size) + .showSeparator(index != options.size) + .section(it)) + } + + return column.build() + } +} diff --git a/base/src/main/java/com/maubis/scarlet/base/support/sheets/LithoBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/support/sheets/LithoBottomSheet.kt index 2b1990bc..a8d4968c 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/sheets/LithoBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/sheets/LithoBottomSheet.kt @@ -4,10 +4,9 @@ import android.app.Dialog import android.content.Context import android.graphics.Color import android.graphics.Typeface -import android.support.design.widget.BottomSheetDialogFragment -import android.support.v7.app.AppCompatActivity +import android.os.Bundle import android.view.View -import android.widget.ScrollView +import androidx.appcompat.app.AppCompatActivity import com.facebook.litho.Column import com.facebook.litho.Component import com.facebook.litho.ComponentContext @@ -17,9 +16,11 @@ import com.facebook.litho.widget.Text import com.facebook.litho.widget.VerticalScroll import com.facebook.yoga.YogaAlign import com.facebook.yoga.YogaEdge +import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig -import com.maubis.scarlet.base.config.CoreConfig.Companion.FONT_MONSERRAT +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface +import com.maubis.scarlet.base.support.ui.BottomSheetTabletDialog import com.maubis.scarlet.base.support.ui.ThemeColorType fun openSheet(activity: AppCompatActivity, sheet: LithoBottomSheet) { @@ -28,26 +29,42 @@ fun openSheet(activity: AppCompatActivity, sheet: LithoBottomSheet) { fun getLithoBottomSheetTitle(context: ComponentContext): Text.Builder { return Text.create(context) - .textSizeRes(R.dimen.font_size_xxxlarge) - .typeface(CoreConfig.FONT_MONSERRAT) - .marginDip(YogaEdge.HORIZONTAL, 20f) - .marginDip(YogaEdge.TOP, 18f) - .marginDip(YogaEdge.BOTTOM, 8f) - .textStyle(Typeface.BOLD) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.PRIMARY_TEXT)) + .textSizeRes(R.dimen.font_size_xxxlarge) + .typeface(sAppTypeface.heading()) + .marginDip(YogaEdge.HORIZONTAL, 20f) + .marginDip(YogaEdge.TOP, 18f) + .marginDip(YogaEdge.BOTTOM, 8f) + .textStyle(Typeface.BOLD) + .textColor(sAppTheme.get(ThemeColorType.PRIMARY_TEXT)) } fun getLithoBottomSheetButton(context: ComponentContext): Text.Builder { return Text.create(context) - .typeface(FONT_MONSERRAT) - .textSizeRes(R.dimen.font_size_large) - .paddingDip(YogaEdge.VERTICAL, 12f) - .paddingDip(YogaEdge.HORIZONTAL, 24f) - .textColorRes(R.color.light_secondary_text) - .backgroundRes(R.drawable.accent_rounded_bg) + .typeface(sAppTypeface.title()) + .textSizeRes(R.dimen.font_size_large) + .paddingDip(YogaEdge.VERTICAL, 12f) + .paddingDip(YogaEdge.HORIZONTAL, 24f) + .textColorRes(R.color.light_secondary_text) + .backgroundRes(R.drawable.accent_rounded_bg) } abstract class LithoBottomSheet : BottomSheetDialogFragment() { + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val ctxt = context ?: activity + if (ctxt === null) { + return super.onCreateDialog(savedInstanceState) + } + + val isTablet = ctxt.resources.getBoolean(R.bool.is_tablet) + val dialog = when { + isTablet -> BottomSheetTabletDialog(ctxt, theme) + else -> super.onCreateDialog(savedInstanceState) + } + retainInstance = true + return dialog + } + override fun setupDialog(dialog: Dialog, style: Int) { val localContext = context if (localContext === null) { @@ -58,35 +75,41 @@ abstract class LithoBottomSheet : BottomSheetDialogFragment() { reset(localContext, dialog) } - fun reset(localContext: Context, dialog: Dialog) { + fun reset(localContext: Context, dialog: Dialog?) { + if (dialog === null) { + return + } + val componentContext = ComponentContext(localContext) getFullComponent(componentContext, dialog, getComponent(componentContext, dialog)) } fun getFullComponent(componentContext: ComponentContext, dialog: Dialog, childComponent: Component) { - val topHandle = when (CoreConfig.instance.themeController().isNightTheme()) { + val topHandle = when (sAppTheme.isNightTheme()) { true -> R.drawable.bottom_sheet_top_handle_dark false -> R.drawable.bottom_sheet_top_handle_light } val baseComponent = Column.create(componentContext) - .paddingDip(YogaEdge.VERTICAL, 16f) - .widthPercent(100f) - .alignItems(YogaAlign.CENTER) - .backgroundColor(CoreConfig.instance.themeController().get(ThemeColorType.BACKGROUND)) - .child( - Image.create(componentContext) - .drawableRes(topHandle) - .widthDip(72f) - .heightDip(6f) - .alpha(0.8f) - .marginDip(YogaEdge.BOTTOM, 8f) - .build() - ) - .child(VerticalScroll.create(componentContext) - .nestedScrollingEnabled(true) - .childComponent(childComponent)) - .build() + .paddingDip(YogaEdge.TOP, topMargin()) + .paddingDip(YogaEdge.BOTTOM, bottomMargin()) + .widthPercent(100f) + .alignItems(YogaAlign.CENTER) + .backgroundColor(backgroundColor(componentContext)) + .child( + Image.create(componentContext) + .drawableRes(topHandle) + .widthDip(72f) + .heightDip(6f) + .alpha(0.8f) + .marginDip(YogaEdge.BOTTOM, 8f) + .build() + ) + .child( + VerticalScroll.create(componentContext) + .nestedScrollingEnabled(true) + .childComponent(childComponent)) + .build() val contentView = LithoView.create(componentContext.androidContext, baseComponent) dialog.setContentView(contentView) @@ -98,4 +121,10 @@ abstract class LithoBottomSheet : BottomSheetDialogFragment() { } abstract fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component + + open fun backgroundColor(componentContext: ComponentContext) = sAppTheme.get(ThemeColorType.BACKGROUND) + + open fun topMargin() = 16f + + open fun bottomMargin() = 16f } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/support/sheets/LithoChooseOptionBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/support/sheets/LithoChooseOptionBottomSheet.kt index 002455a5..e712f66e 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/sheets/LithoChooseOptionBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/sheets/LithoChooseOptionBottomSheet.kt @@ -3,7 +3,11 @@ package com.maubis.scarlet.base.support.sheets import android.app.Dialog import android.graphics.Color import android.graphics.Typeface -import com.facebook.litho.* +import com.facebook.litho.ClickEvent +import com.facebook.litho.Column +import com.facebook.litho.Component +import com.facebook.litho.ComponentContext +import com.facebook.litho.Row import com.facebook.litho.annotations.LayoutSpec import com.facebook.litho.annotations.OnCreateLayout import com.facebook.litho.annotations.OnEvent @@ -12,47 +16,49 @@ import com.facebook.litho.widget.Text import com.facebook.yoga.YogaAlign import com.facebook.yoga.YogaEdge import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface import com.maubis.scarlet.base.support.specs.RoundIcon import com.maubis.scarlet.base.support.ui.ThemeColorType class LithoChooseOptionsItem( - val title: Int, - val selected: Boolean = false, - val listener: () -> Unit) + val title: Int, + val selected: Boolean = false, + val listener: () -> Unit) @LayoutSpec object ChooseOptionItemLayoutSpec { @OnCreateLayout - fun onCreate(context: ComponentContext, - @Prop option: LithoChooseOptionsItem): Component { - val theme = CoreConfig.instance.themeController() - val titleColor = theme.get(ThemeColorType.SECONDARY_TEXT) + fun onCreate( + context: ComponentContext, + @Prop option: LithoChooseOptionsItem): Component { + val titleColor = sAppTheme.get(ThemeColorType.SECONDARY_TEXT) val selectedColor = context.getColor(R.color.colorAccent) val row = Row.create(context) - .widthPercent(100f) - .alignItems(YogaAlign.CENTER) - .paddingDip(YogaEdge.HORIZONTAL, 20f) - .paddingDip(YogaEdge.VERTICAL, 12f) - .child(Text.create(context) - .textRes(option.title) - .textSizeRes(R.dimen.font_size_normal) - .typeface(CoreConfig.FONT_MONSERRAT) - .textStyle(Typeface.BOLD) - .textColor(titleColor) - .flexGrow(1f)) - .child(RoundIcon.create(context) - .iconRes(R.drawable.ic_done_white_48dp) - .bgColor(if (option.selected) selectedColor else titleColor) - .bgAlpha(if (option.selected) 200 else 25) - .iconAlpha(if (option.selected) 1f else 0.6f) - .iconColor(if (option.selected) Color.WHITE else titleColor) - .iconSizeRes(R.dimen.toolbar_round_small_icon_size) - .iconPaddingRes(R.dimen.toolbar_round_small_icon_padding) - .onClick { } - .isClickDisabled(true) - .marginDip(YogaEdge.START, 12f)) + .widthPercent(100f) + .alignItems(YogaAlign.CENTER) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .paddingDip(YogaEdge.VERTICAL, 12f) + .child( + Text.create(context) + .textRes(option.title) + .textSizeRes(R.dimen.font_size_normal) + .typeface(sAppTypeface.title()) + .textStyle(Typeface.BOLD) + .textColor(titleColor) + .flexGrow(1f)) + .child(RoundIcon.create(context) + .iconRes(R.drawable.ic_done_white_48dp) + .bgColor(if (option.selected) selectedColor else titleColor) + .bgAlpha(if (option.selected) 200 else 25) + .iconAlpha(if (option.selected) 1f else 0.6f) + .iconColor(if (option.selected) Color.WHITE else titleColor) + .iconSizeRes(R.dimen.toolbar_round_small_icon_size) + .iconPaddingRes(R.dimen.toolbar_round_small_icon_padding) + .onClick { } + .isClickDisabled(true) + .marginDip(YogaEdge.START, 12f)) row.clickHandler(ChooseOptionItemLayout.onItemClick(context)) return row.build() } @@ -70,16 +76,16 @@ abstract class LithoChooseOptionBottomSheet : LithoBottomSheet() { override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { val column = Column.create(componentContext) - .widthPercent(100f) - .paddingDip(YogaEdge.VERTICAL, 8f) - .child(getLithoBottomSheetTitle(componentContext).textRes(title())) + .widthPercent(100f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .child(getLithoBottomSheetTitle(componentContext).textRes(title())) getOptions(componentContext, dialog).forEach { column.child(ChooseOptionItemLayout.create(componentContext) - .option(it) - .onClick { - it.listener() - reset(componentContext.androidContext, dialog) - }) + .option(it) + .onClick { + it.listener() + reset(componentContext.androidContext, dialog) + }) } return column.build() } diff --git a/base/src/main/java/com/maubis/scarlet/base/support/sheets/LithoOptionBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/support/sheets/LithoOptionBottomSheet.kt index df84e5bc..d089a4ae 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/sheets/LithoOptionBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/sheets/LithoOptionBottomSheet.kt @@ -3,7 +3,11 @@ package com.maubis.scarlet.base.support.sheets import android.app.Dialog import android.graphics.Color import android.graphics.Typeface.BOLD -import com.facebook.litho.* +import com.facebook.litho.ClickEvent +import com.facebook.litho.Column +import com.facebook.litho.Component +import com.facebook.litho.ComponentContext +import com.facebook.litho.Row import com.facebook.litho.annotations.LayoutSpec import com.facebook.litho.annotations.OnCreateLayout import com.facebook.litho.annotations.OnEvent @@ -12,32 +16,31 @@ import com.facebook.litho.widget.Text import com.facebook.yoga.YogaAlign import com.facebook.yoga.YogaEdge import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig -import com.maubis.scarlet.base.config.CoreConfig.Companion.FONT_MONSERRAT -import com.maubis.scarlet.base.config.CoreConfig.Companion.FONT_OPEN_SANS +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface import com.maubis.scarlet.base.support.specs.RoundIcon import com.maubis.scarlet.base.support.ui.ThemeColorType class LithoOptionsItem( - val title: Int, - val subtitle: Int, - val content: String = "", - val icon: Int, - val isSelectable: Boolean = false, - val selected: Boolean = false, - val actionIcon: Int = 0, - val visible: Boolean = true, - val listener: () -> Unit) + val title: Int, + val subtitle: Int, + val content: String = "", + val icon: Int, + val isSelectable: Boolean = false, + val selected: Boolean = false, + val actionIcon: Int = 0, + val visible: Boolean = true, + val listener: () -> Unit) @LayoutSpec object OptionItemLayoutSpec { @OnCreateLayout - fun onCreate(context: ComponentContext, - @Prop option: LithoOptionsItem): Component { - val theme = CoreConfig.instance.themeController() - val titleColor = theme.get(ThemeColorType.SECONDARY_TEXT) - val subtitleColor = theme.get(ThemeColorType.HINT_TEXT) - val selectedColor = theme.get(ThemeColorType.ACCENT_TEXT) + fun onCreate( + context: ComponentContext, + @Prop option: LithoOptionsItem): Component { + val titleColor = sAppTheme.get(ThemeColorType.SECONDARY_TEXT) + val subtitleColor = sAppTheme.get(ThemeColorType.HINT_TEXT) + val selectedColor = sAppTheme.get(ThemeColorType.ACCENT_TEXT) val subtitle = when (option.subtitle) { 0 -> option.content @@ -45,63 +48,110 @@ object OptionItemLayoutSpec { } val row = Row.create(context) - .widthPercent(100f) - .alignItems(YogaAlign.CENTER) - .paddingDip(YogaEdge.HORIZONTAL, 20f) - .paddingDip(YogaEdge.VERTICAL, 12f) - .child( - RoundIcon.create(context) - .iconRes(option.icon) - .bgColor(titleColor) - .iconColor(titleColor) - .iconSizeRes(R.dimen.toolbar_round_icon_size) - .iconPaddingRes(R.dimen.toolbar_round_icon_padding) - .bgAlpha(15) - .onClick { } - .isClickDisabled(true) - .marginDip(YogaEdge.END, 16f)) - .child(Column.create(context) - .flexGrow(1f) - .child( - Text.create(context) - .textRes(option.title) - .textSizeRes(R.dimen.font_size_normal) - .typeface(FONT_MONSERRAT) - .textStyle(BOLD) - .textColor(titleColor)) - .child( - Text.create(context) - .text(subtitle) - .textSizeRes(R.dimen.font_size_small) - .typeface(FONT_OPEN_SANS) - .textColor(subtitleColor))) + .widthPercent(100f) + .alignItems(YogaAlign.CENTER) + .paddingDip(YogaEdge.HORIZONTAL, 20f) + .paddingDip(YogaEdge.VERTICAL, 12f) + .child( + RoundIcon.create(context) + .iconRes(option.icon) + .bgColor(titleColor) + .iconColor(titleColor) + .iconSizeRes(R.dimen.toolbar_round_icon_size) + .iconPaddingRes(R.dimen.toolbar_round_icon_padding) + .bgAlpha(15) + .onClick { } + .isClickDisabled(true) + .marginDip(YogaEdge.END, 16f)) + .child( + Column.create(context) + .flexGrow(1f) + .child( + Text.create(context) + .textRes(option.title) + .textSizeRes(R.dimen.font_size_normal) + .typeface(sAppTypeface.title()) + .textStyle(BOLD) + .textColor(titleColor)) + .child( + Text.create(context) + .text(subtitle) + .textSizeRes(R.dimen.font_size_small) + .typeface(sAppTypeface.title()) + .textColor(subtitleColor))) if (option.isSelectable) { row.child(RoundIcon.create(context) - .iconRes(if (option.actionIcon == 0) R.drawable.ic_done_white_48dp else option.actionIcon) - .bgColor(if (option.selected) selectedColor else titleColor) - .bgAlpha(if (option.selected) 200 else 25) - .iconAlpha(if (option.selected) 1f else 0.6f) - .iconColor(if (option.selected) Color.WHITE else titleColor) - .iconSizeRes(R.dimen.toolbar_round_small_icon_size) - .iconPaddingRes(R.dimen.toolbar_round_small_icon_padding) - .onClick { } - .isClickDisabled(true) - .marginDip(YogaEdge.START, 12f)) + .iconRes(if (option.actionIcon == 0) R.drawable.ic_done_white_48dp else option.actionIcon) + .bgColor(if (option.selected) selectedColor else titleColor) + .bgAlpha(if (option.selected) 200 else 25) + .iconAlpha(if (option.selected) 1f else 0.6f) + .iconColor(if (option.selected) Color.WHITE else titleColor) + .iconSizeRes(R.dimen.toolbar_round_small_icon_size) + .iconPaddingRes(R.dimen.toolbar_round_small_icon_padding) + .onClick { } + .isClickDisabled(true) + .marginDip(YogaEdge.START, 12f)) } else if (!option.isSelectable && option.actionIcon != 0) { row.child(RoundIcon.create(context) - .iconRes(option.actionIcon) + .iconRes(option.actionIcon) + .bgColor(titleColor) + .bgAlpha(25) + .iconAlpha(0.9f) + .iconColor(titleColor) + .iconSizeRes(R.dimen.toolbar_round_small_icon_size) + .iconPaddingRes(R.dimen.toolbar_round_small_icon_padding) + .onClick { } + .isClickDisabled(true) + .marginDip(YogaEdge.START, 12f)) + } + + row.clickHandler(OptionItemLayout.onItemClick(context)) + return row.build() + } + + @OnEvent(ClickEvent::class) + fun onItemClick(context: ComponentContext, @Prop onClick: () -> Unit) { + onClick() + } +} + +class LithoLabelOptionsItem( + val title: Int, + val icon: Int, + val visible: Boolean = true, + val listener: () -> Unit) + +@LayoutSpec +object OptionLabelItemLayoutSpec { + @OnCreateLayout + fun onCreate( + context: ComponentContext, + @Prop option: LithoLabelOptionsItem): Component { + val titleColor = sAppTheme.get(ThemeColorType.SECONDARY_TEXT) + + val row = Column.create(context) + .widthPercent(100f) + .alignItems(YogaAlign.CENTER) + .paddingDip(YogaEdge.VERTICAL, 16f) + .child( + RoundIcon.create(context) + .iconRes(option.icon) .bgColor(titleColor) - .bgAlpha(25) - .iconAlpha(0.9f) .iconColor(titleColor) - .iconSizeRes(R.dimen.toolbar_round_small_icon_size) - .iconPaddingRes(R.dimen.toolbar_round_small_icon_padding) + .iconSizeRes(R.dimen.toolbar_round_icon_size) + .iconPaddingRes(R.dimen.toolbar_round_icon_padding) + .bgAlpha(15) .onClick { } .isClickDisabled(true) - .marginDip(YogaEdge.START, 12f)) - } - + .marginDip(YogaEdge.BOTTOM, 4f)) + .child( + Text.create(context) + .textRes(option.title) + .textSizeRes(R.dimen.font_size_normal) + .typeface(sAppTypeface.title()) + .textStyle(BOLD) + .textColor(titleColor)) row.clickHandler(OptionItemLayout.onItemClick(context)) return row.build() } @@ -119,16 +169,16 @@ abstract class LithoOptionBottomSheet : LithoBottomSheet() { override fun getComponent(componentContext: ComponentContext, dialog: Dialog): Component { val column = Column.create(componentContext) - .widthPercent(100f) - .paddingDip(YogaEdge.VERTICAL, 8f) - .child(getLithoBottomSheetTitle(componentContext).textRes(title())) + .widthPercent(100f) + .paddingDip(YogaEdge.VERTICAL, 8f) + .child(getLithoBottomSheetTitle(componentContext).textRes(title())) getOptions(componentContext, dialog).forEach { if (it.visible) { column.child(OptionItemLayout.create(componentContext) - .option(it) - .onClick { - it.listener() - }) + .option(it) + .onClick { + it.listener() + }) } } return column.build() diff --git a/base/src/main/java/com/maubis/scarlet/base/support/specs/BottomSheetBarSpec.kt b/base/src/main/java/com/maubis/scarlet/base/support/specs/BottomSheetBarSpec.kt index 45c051ca..c9ce93ce 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/specs/BottomSheetBarSpec.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/specs/BottomSheetBarSpec.kt @@ -4,12 +4,17 @@ import com.facebook.litho.ClickEvent import com.facebook.litho.Component import com.facebook.litho.ComponentContext import com.facebook.litho.Row -import com.facebook.litho.annotations.* +import com.facebook.litho.annotations.LayoutSpec +import com.facebook.litho.annotations.OnCreateLayout +import com.facebook.litho.annotations.OnEvent +import com.facebook.litho.annotations.Prop +import com.facebook.litho.annotations.ResType import com.facebook.litho.widget.Text import com.facebook.yoga.YogaAlign import com.facebook.yoga.YogaEdge import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface import com.maubis.scarlet.base.support.sheets.getLithoBottomSheetButton import com.maubis.scarlet.base.support.ui.ThemeColorType @@ -17,41 +22,44 @@ import com.maubis.scarlet.base.support.ui.ThemeColorType object BottomSheetBarSpec { @OnCreateLayout fun onCreate( - context: ComponentContext, - @Prop(resType = ResType.STRING) primaryAction: String, - @Prop(optional = true) isActionNegative: Boolean?, - @Prop(resType = ResType.STRING, optional = true) secondaryAction: String?, - @Prop(resType = ResType.STRING, optional = true) tertiaryAction: String?): Component { + context: ComponentContext, + @Prop(resType = ResType.STRING) primaryAction: String, + @Prop(optional = true) isActionNegative: Boolean?, + @Prop(resType = ResType.STRING, optional = true) secondaryAction: String?, + @Prop(resType = ResType.STRING, optional = true) tertiaryAction: String?): Component { val actionNegative = isActionNegative ?: false val row = Row.create(context) - .alignItems(YogaAlign.CENTER) + .alignItems(YogaAlign.CENTER) if (secondaryAction !== null && secondaryAction.isNotBlank()) { - row.child(Text.create(context) + row.child( + Text.create(context) .text(secondaryAction) - .typeface(CoreConfig.FONT_MONSERRAT) + .typeface(sAppTypeface.title()) .textSizeRes(R.dimen.font_size_large) .paddingDip(YogaEdge.VERTICAL, 6f) .paddingDip(YogaEdge.HORIZONTAL, 16f) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.TERTIARY_TEXT)) + .textColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT)) .clickHandler(BottomSheetBar.onSecondaryClickEvent(context))) } row.child(EmptySpec.create(context).flexGrow(1f)) if (tertiaryAction !== null && tertiaryAction.isNotBlank()) { - row.child(Text.create(context) + row.child( + Text.create(context) .text(tertiaryAction) - .typeface(CoreConfig.FONT_MONSERRAT) + .typeface(sAppTypeface.title()) .textSizeRes(R.dimen.font_size_large) .paddingDip(YogaEdge.VERTICAL, 6f) .paddingDip(YogaEdge.HORIZONTAL, 16f) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.TERTIARY_TEXT)) + .textColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT)) .clickHandler(BottomSheetBar.onTertiaryClickEvent(context))) } - row.child(getLithoBottomSheetButton(context) + row.child( + getLithoBottomSheetButton(context) .text(primaryAction) .backgroundRes(if (actionNegative) R.drawable.disabled_rounded_bg else R.drawable.accent_rounded_bg) .clickHandler(BottomSheetBar.onPrimaryClickEvent(context))) diff --git a/base/src/main/java/com/maubis/scarlet/base/support/specs/CounterChooserSpec.kt b/base/src/main/java/com/maubis/scarlet/base/support/specs/CounterChooserSpec.kt index 8605272a..07633e90 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/specs/CounterChooserSpec.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/specs/CounterChooserSpec.kt @@ -10,34 +10,36 @@ import com.facebook.litho.widget.Text import com.facebook.yoga.YogaAlign import com.facebook.yoga.YogaEdge import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface import com.maubis.scarlet.base.support.ui.ThemeColorType @LayoutSpec object CounterChooserSpec { @OnCreateLayout fun onCreate( - context: ComponentContext, - @Prop value: Int, - @Prop minValue: Int, - @Prop maxValue: Int, - @Prop onValueChange: (Int) -> Unit): Component { + context: ComponentContext, + @Prop value: Int, + @Prop minValue: Int, + @Prop maxValue: Int, + @Prop onValueChange: (Int) -> Unit): Component { val row = Row.create(context) - .alignItems(YogaAlign.CENTER) - .child(EmptySpec.create(context).flexGrow(1f)) - .child(bottomBarRoundIcon(context, ToolbarColorConfig()) - .iconRes(R.drawable.icon_less_counter) - .onClick { onValueChange(Math.max(value - 1, minValue)) }) - .child(Text.create(context) - .text(value.toString()) - .typeface(CoreConfig.FONT_MONSERRAT) - .textSizeRes(R.dimen.font_size_xxxlarge) - .paddingDip(YogaEdge.HORIZONTAL, 12f) - .textColor(CoreConfig.instance.themeController().get(ThemeColorType.TERTIARY_TEXT))) - .child(bottomBarRoundIcon(context, ToolbarColorConfig()) - .iconRes(R.drawable.icon_more_counter) - .onClick { onValueChange(Math.min(value + 1, maxValue)) }) - .child(EmptySpec.create(context).flexGrow(1f)) + .alignItems(YogaAlign.CENTER) + .child(EmptySpec.create(context).flexGrow(1f)) + .child(bottomBarRoundIcon(context, ToolbarColorConfig()) + .iconRes(R.drawable.icon_less_counter) + .onClick { onValueChange(Math.max(value - 1, minValue)) }) + .child( + Text.create(context) + .text(value.toString()) + .typeface(sAppTypeface.title()) + .textSizeRes(R.dimen.font_size_xxxlarge) + .paddingDip(YogaEdge.HORIZONTAL, 12f) + .textColor(sAppTheme.get(ThemeColorType.TERTIARY_TEXT))) + .child(bottomBarRoundIcon(context, ToolbarColorConfig()) + .iconRes(R.drawable.icon_more_counter) + .onClick { onValueChange(Math.min(value + 1, maxValue)) }) + .child(EmptySpec.create(context).flexGrow(1f)) return row.build() } } diff --git a/base/src/main/java/com/maubis/scarlet/base/support/specs/GridSectionViewSpec.kt b/base/src/main/java/com/maubis/scarlet/base/support/specs/GridSectionViewSpec.kt new file mode 100644 index 00000000..d5dfe7d0 --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/support/specs/GridSectionViewSpec.kt @@ -0,0 +1,160 @@ +package com.maubis.scarlet.base.support.specs + +import android.graphics.Color +import android.text.Layout +import android.text.TextUtils +import com.facebook.litho.ClickEvent +import com.facebook.litho.Column +import com.facebook.litho.Component +import com.facebook.litho.ComponentContext +import com.facebook.litho.Row +import com.facebook.litho.annotations.LayoutSpec +import com.facebook.litho.annotations.OnCreateLayout +import com.facebook.litho.annotations.OnEvent +import com.facebook.litho.annotations.Prop +import com.facebook.litho.annotations.ResType +import com.facebook.litho.widget.SolidColor +import com.facebook.litho.widget.Text +import com.facebook.yoga.YogaAlign +import com.facebook.yoga.YogaEdge +import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTypeface +import com.maubis.scarlet.base.support.ui.ThemeColorType + +data class GridSectionItem( + val title: Int = 0, + val sectionColor: Int = 0, + val options: List) + +data class GridSectionOptionItem( + val icon: Int, + val label: Int, + val listener: () -> Unit, + val visible: Boolean = true) + +@LayoutSpec +object GridOptionSpec { + @OnCreateLayout + fun onCreate( + context: ComponentContext, + @Prop option: GridSectionOptionItem, + @Prop solidSectionColor: Boolean, + @Prop(resType = ResType.COLOR) labelColor: Int, + @Prop(resType = ResType.COLOR) iconColor: Int, + @Prop(resType = ResType.DIMEN_SIZE) iconSize: Int, + @Prop(resType = ResType.COLOR) maxLines: Int, + @Prop(resType = ResType.COLOR) sectionColor: Int): Component { + return Column.create(context) + .alignItems(YogaAlign.CENTER) + .alignContent(YogaAlign.CENTER) + .paddingDip(YogaEdge.VERTICAL, 8f) + .paddingDip(YogaEdge.HORIZONTAL, 4f) + .child( + RoundIcon.create(context) + .bgColor(sectionColor) + .iconColor(iconColor) + .iconRes(option.icon) + .iconSizePx(iconSize) + .iconPaddingRes(R.dimen.primary_round_icon_padding) + .iconMarginVerticalRes(R.dimen.toolbar_round_icon_margin_vertical) + .iconMarginHorizontalRes(R.dimen.toolbar_round_icon_margin_horizontal) + .isClickDisabled(true) + .bgAlpha(if (solidSectionColor) 255 else 15) + ) + .child( + Text.create(context) + .textRes(option.label) + .textAlignment(Layout.Alignment.ALIGN_CENTER) + .typeface(sAppTypeface.title()) + .textSizeRes(R.dimen.font_size_small) + .paddingDip(YogaEdge.VERTICAL, 8f) + .paddingDip(YogaEdge.HORIZONTAL, 16f) + .minLines(maxLines) + .maxLines(maxLines) + .ellipsize(TextUtils.TruncateAt.END) + .textColor(labelColor)) + .clickHandler(GridOption.onClick(context)) + .build() + } + + @OnEvent(ClickEvent::class) + fun onClick(context: ComponentContext, @Prop option: GridSectionOptionItem) { + option.listener() + } +} + +@LayoutSpec +object GridSectionViewSpec { + @OnCreateLayout + fun onCreate( + context: ComponentContext, + @Prop section: GridSectionItem, + @Prop(resType = ResType.DIMEN_SIZE) iconSize: Int, + @Prop(optional = true) numColumns: Int?, + @Prop(optional = true) maxLines: Int?, + @Prop(optional = true) showSeparator: Boolean?): Component { + val column = Column.create(context) + val primaryColor = sAppTheme.get(ThemeColorType.SECONDARY_TEXT) + + if (section.title != 0) { + column.child( + Text.create(context) + .textRes(section.title) + .typeface(sAppTypeface.title()) + .textSizeRes(R.dimen.font_size_normal) + .maxLines(1) + .ellipsize(TextUtils.TruncateAt.END) + .textColor(primaryColor)) + } + + val visibleOptions = section.options.filter { it.visible } + val getComponentAtIndex: (Int) -> Component = { index -> + when { + index >= visibleOptions.size -> EmptySpec.create(context) + .flexGrow(1f) + .flexBasisDip(1f) + .build() + else -> GridOption.create(context) + .flexGrow(1f) + .flexBasisDip(1f) + .solidSectionColor(section.sectionColor != 0) + .labelColor(primaryColor) + .maxLines(maxLines ?: 2) + .iconSizePx(iconSize) + .iconColor(if (section.sectionColor == 0) primaryColor else Color.WHITE) + .sectionColor(if (section.sectionColor == 0) primaryColor else section.sectionColor) + .option(visibleOptions[index]) + .build() + } + } + + val numberOfColumns = numColumns ?: 3 + var index = 0 + while (true) { + val row = Row.create(context) + .widthPercent(100f) + if (index >= visibleOptions.size) { + break + } + + for (delta in 0..(numberOfColumns - 1)) { + row.child(getComponentAtIndex(index)) + index += 1 + } + column.child(row) + } + + if (showSeparator == true) { + column.child( + SolidColor.create(context) + .color(sAppTheme.get(ThemeColorType.PRIMARY_TEXT)) + .heightDip(1.5f) + .widthDip(196f) + .alignSelf(YogaAlign.CENTER) + .marginDip(YogaEdge.VERTICAL, 16f) + .alpha(0.1f)) + } + return column.build() + } +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/support/specs/RoundIconSpec.kt b/base/src/main/java/com/maubis/scarlet/base/support/specs/RoundIconSpec.kt index bf2533c5..2f3a6445 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/specs/RoundIconSpec.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/specs/RoundIconSpec.kt @@ -6,7 +6,12 @@ import com.facebook.litho.ClickEvent import com.facebook.litho.Column import com.facebook.litho.Component import com.facebook.litho.ComponentContext -import com.facebook.litho.annotations.* +import com.facebook.litho.LongClickEvent +import com.facebook.litho.annotations.LayoutSpec +import com.facebook.litho.annotations.OnCreateLayout +import com.facebook.litho.annotations.OnEvent +import com.facebook.litho.annotations.Prop +import com.facebook.litho.annotations.ResType import com.facebook.litho.widget.Image import com.facebook.yoga.YogaAlign import com.facebook.yoga.YogaEdge @@ -16,38 +21,51 @@ import com.maubis.scarlet.base.support.ui.LithoCircleDrawable object RoundIconSpec { @OnCreateLayout fun onCreate( - context: ComponentContext, - @Prop(resType = ResType.DRAWABLE) icon: Drawable, - @Prop(resType = ResType.COLOR) iconColor: Int, - @Prop(resType = ResType.COLOR) bgColor: Int, - @Prop(resType = ResType.DIMEN_SIZE) iconSize: Int, - @Prop(resType = ResType.DIMEN_SIZE, optional = true) iconPadding: Int?, - @Prop(resType = ResType.DIMEN_OFFSET, optional = true) iconMarginVertical: Int?, - @Prop(resType = ResType.DIMEN_OFFSET, optional = true) iconMarginHorizontal: Int?, - @Prop(optional = true) iconAlpha: Float?, - @Prop(optional = true) bgAlpha: Int?, - @Prop(optional = true) isClickDisabled: Boolean?, - @Prop(optional = true) showBorder: Boolean?): Component { + context: ComponentContext, + @Prop(resType = ResType.DRAWABLE) icon: Drawable, + @Prop(resType = ResType.COLOR) iconColor: Int, + @Prop(resType = ResType.COLOR) bgColor: Int, + @Prop(resType = ResType.DIMEN_SIZE) iconSize: Int, + @Prop(resType = ResType.DIMEN_SIZE, optional = true) iconPadding: Int?, + @Prop(resType = ResType.DIMEN_OFFSET, optional = true) iconMarginVertical: Int?, + @Prop(resType = ResType.DIMEN_OFFSET, optional = true) iconMarginHorizontal: Int?, + @Prop(optional = true) iconAlpha: Float?, + @Prop(optional = true) bgAlpha: Int?, + @Prop(optional = true) isClickDisabled: Boolean?, + @Prop(optional = true) isLongClickEnabled: Boolean?, + @Prop(optional = true) showBorder: Boolean?): Component { val image = Image.create(context) - .heightPx(iconSize) - .widthPx(iconSize) - .paddingPx(YogaEdge.ALL, iconPadding ?: 0) - .marginPx(YogaEdge.VERTICAL, iconMarginVertical ?: 0) - .marginPx(YogaEdge.HORIZONTAL, iconMarginHorizontal ?: 0) - .drawable(icon.color(iconColor)) - .alpha(iconAlpha ?: 1f) - .background(LithoCircleDrawable(bgColor, bgAlpha ?: 255, showBorder ?: false)) + .heightPx(iconSize) + .widthPx(iconSize) + .paddingPx(YogaEdge.ALL, iconPadding ?: 0) + .marginPx(YogaEdge.VERTICAL, iconMarginVertical ?: 0) + .marginPx(YogaEdge.HORIZONTAL, iconMarginHorizontal ?: 0) + .drawable(icon.color(iconColor)) + .alpha(iconAlpha ?: 1f) + .background( + LithoCircleDrawable( + bgColor, bgAlpha ?: Color.alpha(bgColor), showBorder + ?: false)) if (isClickDisabled === null || !isClickDisabled) { image.clickHandler(RoundIcon.onClickEvent(context)) } + if (isLongClickEnabled !== null && isLongClickEnabled) { + image.longClickHandler(RoundIcon.onLongClickEvent(context)) + } return Column.create(context) - .alignItems(YogaAlign.CENTER) - .child(image) - .build() + .alignItems(YogaAlign.CENTER) + .child(image) + .build() } @OnEvent(ClickEvent::class) fun onClickEvent(context: ComponentContext, @Prop(optional = true) onClick: () -> Unit) { onClick() } + + @OnEvent(LongClickEvent::class) + fun onLongClickEvent(context: ComponentContext, @Prop(optional = true) onLongClick: () -> Unit): Boolean { + onLongClick() + return true + } } diff --git a/base/src/main/java/com/maubis/scarlet/base/support/specs/SpecUtils.kt b/base/src/main/java/com/maubis/scarlet/base/support/specs/SpecUtils.kt index 5d4771a2..28ea0f68 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/specs/SpecUtils.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/specs/SpecUtils.kt @@ -12,13 +12,13 @@ import com.facebook.litho.widget.SolidColor import com.facebook.yoga.YogaAlign import com.facebook.yoga.YogaEdge import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme import com.maubis.scarlet.base.support.ui.ThemeColorType object EmptySpec { fun create(context: ComponentContext): SolidColor.Builder { return SolidColor.create(context) - .color(Color.TRANSPARENT) + .color(Color.TRANSPARENT) } } @@ -30,44 +30,42 @@ fun Drawable.color(tint: Int): Drawable { fun separatorSpec(context: ComponentContext): Component.Builder<*> { return SolidColor.create(context) - .alignSelf(YogaAlign.CENTER) - .colorRes(R.color.material_grey_200) - .heightDip(1f) - .widthDip(164f) - .marginDip(YogaEdge.HORIZONTAL, 32f) - .marginDip(YogaEdge.TOP, 16f) - .marginDip(YogaEdge.BOTTOM, 16f) + .alignSelf(YogaAlign.CENTER) + .colorRes(R.color.material_grey_200) + .heightDip(1f) + .widthDip(164f) + .marginDip(YogaEdge.HORIZONTAL, 32f) + .marginDip(YogaEdge.TOP, 16f) + .marginDip(YogaEdge.BOTTOM, 16f) } - data class ToolbarColorConfig( - var toolbarBackgroundColor: Int = CoreConfig.instance.themeController().get(ThemeColorType.TOOLBAR_BACKGROUND), - var toolbarIconColor: Int = CoreConfig.instance.themeController().get(ThemeColorType.TOOLBAR_ICON)) - + var toolbarBackgroundColor: Int = sAppTheme.get(ThemeColorType.TOOLBAR_BACKGROUND), + var toolbarIconColor: Int = sAppTheme.get(ThemeColorType.TOOLBAR_ICON)) fun bottomBarRoundIcon(context: ComponentContext, colorConfig: ToolbarColorConfig): RoundIcon.Builder { return RoundIcon.create(context) - .bgColor(colorConfig.toolbarIconColor) - .iconColor(colorConfig.toolbarIconColor) - .iconSizeRes(R.dimen.toolbar_round_icon_size) - .iconPaddingRes(R.dimen.toolbar_round_icon_padding) - .iconMarginVerticalRes(R.dimen.toolbar_round_icon_margin_vertical) - .iconMarginHorizontalRes(R.dimen.toolbar_round_icon_margin_horizontal) - .bgAlpha(15) + .bgColor(colorConfig.toolbarIconColor) + .iconColor(colorConfig.toolbarIconColor) + .iconSizeRes(R.dimen.toolbar_round_icon_size) + .iconPaddingRes(R.dimen.toolbar_round_icon_padding) + .iconMarginVerticalRes(R.dimen.toolbar_round_icon_margin_vertical) + .iconMarginHorizontalRes(R.dimen.toolbar_round_icon_margin_horizontal) + .bgAlpha(15) } fun bottomBarCard(context: ComponentContext, child: Component, colorConfig: ToolbarColorConfig): Column.Builder { return Column.create(context) - .widthPercent(100f) - .paddingDip(YogaEdge.ALL, 0f) - .backgroundColor(Color.TRANSPARENT) - .child( - Card.create(context) - .widthPercent(100f) - .backgroundColor(Color.TRANSPARENT) - .clippingColor(Color.TRANSPARENT) - .cardBackgroundColor(colorConfig.toolbarBackgroundColor) - .cornerRadiusDip(0f) - .elevationDip(0f) - .content(child)) + .widthPercent(100f) + .paddingDip(YogaEdge.ALL, 0f) + .backgroundColor(Color.TRANSPARENT) + .child( + Card.create(context) + .widthPercent(100f) + .backgroundColor(Color.TRANSPARENT) + .clippingColor(Color.TRANSPARENT) + .cardBackgroundColor(colorConfig.toolbarBackgroundColor) + .cornerRadiusDip(0f) + .elevationDip(0f) + .content(child)) } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/support/ui/BottomSheetTabletDialog.kt b/base/src/main/java/com/maubis/scarlet/base/support/ui/BottomSheetTabletDialog.kt index aef207a9..8a3ca69a 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/ui/BottomSheetTabletDialog.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/ui/BottomSheetTabletDialog.kt @@ -2,16 +2,16 @@ package com.maubis.scarlet.base.support.ui import android.content.Context import android.os.Bundle -import android.support.design.widget.BottomSheetDialog import android.view.ViewGroup +import com.google.android.material.bottomsheet.BottomSheetDialog import com.maubis.scarlet.base.R class BottomSheetTabletDialog(context: Context, theme: Int) : BottomSheetDialog(context, theme) { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState); - val width = context.resources.getDimensionPixelSize(R.dimen.bottom_sheet_width_for_tablets); - getWindow().setLayout( - if (width > 0) width else ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT); + val width = context.resources.getDimensionPixelSize(R.dimen.bottom_sheet_width_for_tablets) + window?.setLayout( + if (width > 0) width else ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/support/ui/CircleDrawable.kt b/base/src/main/java/com/maubis/scarlet/base/support/ui/CircleDrawable.kt index e1e9aa81..5e0348cd 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/ui/CircleDrawable.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/ui/CircleDrawable.kt @@ -1,8 +1,13 @@ package com.maubis.scarlet.base.support.ui -import android.graphics.* +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.ColorFilter +import android.graphics.Paint +import android.graphics.PixelFormat +import android.graphics.Rect import android.graphics.drawable.Drawable -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme class CircleDrawable(color: Int, showBorder: Boolean = true) : Drawable() { private val paint: Paint @@ -13,7 +18,7 @@ class CircleDrawable(color: Int, showBorder: Boolean = true) : Drawable() { this.paint = Paint(Paint.ANTI_ALIAS_FLAG) this.paint.color = color - val isNightTheme = CoreConfig.instance.themeController().isNightTheme() + val isNightTheme = sAppTheme.isNightTheme() this.borderPaint = Paint(Paint.ANTI_ALIAS_FLAG) this.borderPaint.color = when { !showBorder -> Color.TRANSPARENT diff --git a/base/src/main/java/com/maubis/scarlet/base/support/ui/ColorUtil.kt b/base/src/main/java/com/maubis/scarlet/base/support/ui/ColorUtil.kt index 3f1855b8..2aea0233 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/ui/ColorUtil.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/ui/ColorUtil.kt @@ -1,25 +1,24 @@ package com.maubis.scarlet.base.support.ui import android.graphics.Color -import android.support.v4.graphics.ColorUtils +import androidx.core.graphics.ColorUtils object ColorUtil { fun isLightColored(color: Int): Boolean { + if (Color.alpha(color) < 100) { + return true + } return ColorUtils.calculateLuminance(color) > 0.4 } - fun darkerColor(color: Int): Int { - return luminantColor(color, 0.2f) - } - - fun darkerOrSlightlyDarkerColor(color: Int): Int { + fun darkOrDarkerColor(color: Int): Int { val hsl = floatArrayOf(0.0f, 0.0f, 0.0f) ColorUtils.RGBToHSL(Color.red(color), Color.green(color), Color.blue(color), hsl) val luminance = hsl[2] - if (luminance > 0.2) { - return luminantColor(color, 0.2f) + if (luminance > 0.25) { + return luminantColor(color, 0.25f) } return luminantColor(color, luminance * 0.8f) } diff --git a/base/src/main/java/com/maubis/scarlet/base/support/ui/IThemeChangeListener.kt b/base/src/main/java/com/maubis/scarlet/base/support/ui/IThemeChangeListener.kt new file mode 100644 index 00000000..02c62701 --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/support/ui/IThemeChangeListener.kt @@ -0,0 +1,5 @@ +package com.maubis.scarlet.base.support.ui + +interface IThemeChangeListener { + fun onChange(theme: Theme) +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/support/ui/IThemeManager.kt b/base/src/main/java/com/maubis/scarlet/base/support/ui/IThemeManager.kt index b24a0c8f..191c1fd7 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/ui/IThemeManager.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/ui/IThemeManager.kt @@ -10,9 +10,13 @@ interface IThemeManager { fun isNightTheme(): Boolean + fun get(): Theme + fun get(type: ThemeColorType): Int fun get(context: Context, theme: Theme, type: ThemeColorType): Int fun get(context: Context, lightColor: Int, darkColor: Int): Int + + fun register(listener: IThemeChangeListener) } diff --git a/base/src/main/java/com/maubis/scarlet/base/support/ui/LithoCircleDrawable.kt b/base/src/main/java/com/maubis/scarlet/base/support/ui/LithoCircleDrawable.kt index 1823192b..dbe18e11 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/ui/LithoCircleDrawable.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/ui/LithoCircleDrawable.kt @@ -1,8 +1,13 @@ package com.maubis.scarlet.base.support.ui -import android.graphics.* +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.ColorFilter +import android.graphics.Paint +import android.graphics.PixelFormat +import android.graphics.Rect import com.facebook.litho.drawable.ComparableDrawable -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme class LithoCircleDrawable(color: Int, alpha: Int = 255, val showBorder: Boolean = false) : ComparableDrawable() { private val mPaint: Paint @@ -14,7 +19,7 @@ class LithoCircleDrawable(color: Int, alpha: Int = 255, val showBorder: Boolean this.mPaint.color = color this.mPaint.alpha = alpha - val isNightTheme = CoreConfig.instance.themeController().isNightTheme() + val isNightTheme = sAppTheme.isNightTheme() this.mBorderPaint = Paint(Paint.ANTI_ALIAS_FLAG) this.mBorderPaint.color = when { !showBorder -> Color.TRANSPARENT @@ -27,10 +32,10 @@ class LithoCircleDrawable(color: Int, alpha: Int = 255, val showBorder: Boolean val bounds = bounds canvas.drawCircle(bounds.centerX().toFloat(), bounds.centerY().toFloat(), mRadius.toFloat(), mBorderPaint) canvas.drawCircle( - bounds.centerX().toFloat(), - bounds.centerY().toFloat(), - mRadius.toFloat() - (if (showBorder) 2 else 0), - mPaint) + bounds.centerX().toFloat(), + bounds.centerY().toFloat(), + mRadius.toFloat() - (if (showBorder) 2 else 0), + mPaint) } override fun setAlpha(alpha: Int) { @@ -52,8 +57,8 @@ class LithoCircleDrawable(color: Int, alpha: Int = 255, val showBorder: Boolean override fun isEquivalentTo(other: ComparableDrawable?): Boolean { return other is LithoCircleDrawable - && other.mRadius == mRadius - && other.mPaint.color == mPaint.color + && other.mRadius == mRadius + && other.mPaint.color == mPaint.color } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/support/ui/SecuredActivity.kt b/base/src/main/java/com/maubis/scarlet/base/support/ui/SecuredActivity.kt new file mode 100644 index 00000000..2ab15160 --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/support/ui/SecuredActivity.kt @@ -0,0 +1,14 @@ +package com.maubis.scarlet.base.support.ui + +import android.content.Intent +import com.maubis.scarlet.base.security.activity.AppLockActivity +import com.maubis.scarlet.base.security.controller.PinLockController + +abstract class SecuredActivity : ThemedActivity() { + override fun onResume() { + super.onResume() + if (PinLockController.needsAppLock()) { + startActivity(Intent(this, AppLockActivity::class.java)) + } + } +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/support/ui/ThemeColorType.kt b/base/src/main/java/com/maubis/scarlet/base/support/ui/ThemeColorType.kt index 106813c9..e4961046 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/ui/ThemeColorType.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/ui/ThemeColorType.kt @@ -1,6 +1,5 @@ package com.maubis.scarlet.base.support.ui - enum class ThemeColorType { BACKGROUND, STATUS_BAR, diff --git a/base/src/main/java/com/maubis/scarlet/base/support/ui/ThemeManager.kt b/base/src/main/java/com/maubis/scarlet/base/support/ui/ThemeManager.kt index 2809cb41..28200dd1 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/ui/ThemeManager.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/ui/ThemeManager.kt @@ -1,28 +1,63 @@ package com.maubis.scarlet.base.support.ui import android.content.Context +import android.content.res.Configuration import android.graphics.Color -import android.os.Build -import android.support.v4.content.ContextCompat +import androidx.core.content.ContextCompat import com.github.bijoysingh.starter.util.DimensionManager import com.maubis.markdown.MarkdownConfig import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences +import com.maubis.scarlet.base.support.utils.OsVersionUtils +import com.maubis.scarlet.base.support.utils.throwOrReturn +import java.lang.ref.WeakReference -const val KEY_APP_THEME = "KEY_APP_THEME" +var sThemeLabel: String + get() = sAppPreferences.get("KEY_APP_THEME", Theme.DARK.name) + set(value) = sAppPreferences.put("KEY_APP_THEME", value) + +var sThemeIsAutomatic: Boolean + get() = sAppPreferences.get("automatic_theme", false) + set(value) = sAppPreferences.put("automatic_theme", value) + +var sThemeDarkenNoteColor: Boolean + get() = sAppPreferences.get("darken_note_color", false) + set(value) = sAppPreferences.put("darken_note_color", value) + +fun setThemeFromSystem(context: Context) { + val configuration = context.resources.configuration + val systemBasedTheme = when (configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) { + Configuration.UI_MODE_NIGHT_NO -> Theme.LIGHT.name + Configuration.UI_MODE_NIGHT_YES -> Theme.VERY_DARK.name + else -> Theme.VERY_DARK.name + } + if (systemBasedTheme === sThemeLabel) { + return + } + sThemeLabel = systemBasedTheme +} // Old Theme Key, remove in future once theme is properly handled const val KEY_NIGHT_THEME: String = "KEY_NIGHT_THEME" -class ThemeManager() : IThemeManager { +class ThemeManager : IThemeManager { lateinit var theme: Theme + var listeners = HashSet>() var map = HashMap() override fun setup(context: Context) { theme = getThemeFromStore() notifyChange(context) } + override fun get(): Theme { + return theme + } + + override fun register(listener: IThemeChangeListener) { + listeners.add(WeakReference(listener)) + } + override fun isNightTheme() = theme.isNightTheme override fun get(type: ThemeColorType): Int = map[type] ?: Color.WHITE @@ -42,10 +77,18 @@ class ThemeManager() : IThemeManager { } if (map[ThemeColorType.TOOLBAR_BACKGROUND] == map[ThemeColorType.BACKGROUND]) { - map[ThemeColorType.TOOLBAR_BACKGROUND] = ColorUtil.darkerOrSlightlyDarkerColor(map[ThemeColorType.TOOLBAR_BACKGROUND] ?: 0) + map[ThemeColorType.TOOLBAR_BACKGROUND] = ColorUtil.darkOrDarkerColor( + map[ThemeColorType.TOOLBAR_BACKGROUND] + ?: 0) } setMarkdownConfig(context) + for (reference in listeners) { + val listener = reference.get() + if (listener !== null) { + listener.onChange(theme) + } + } } private fun setMarkdownConfig(context: Context) { @@ -67,7 +110,7 @@ class ThemeManager() : IThemeManager { val colorResource = when (type) { ThemeColorType.BACKGROUND -> theme.background ThemeColorType.STATUS_BAR -> { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) theme.background + if (OsVersionUtils.canSetStatusBarTheme()) theme.background else theme.statusBarColorFallback ?: theme.background } ThemeColorType.PRIMARY_TEXT -> theme.primaryText @@ -94,11 +137,10 @@ class ThemeManager() : IThemeManager { } fun getThemeFromStore(): Theme { - val theme = CoreConfig.instance.store().get(KEY_APP_THEME, Theme.DARK.name) - try { - return Theme.valueOf(theme) - } catch (_: Exception) { - return Theme.DARK + return try { + Theme.valueOf(sThemeLabel) + } catch (exception: Exception) { + throwOrReturn(exception, Theme.DARK) } } } @@ -106,164 +148,164 @@ class ThemeManager() : IThemeManager { // NOTE: These names cannot be changed enum class Theme( - val isNightTheme: Boolean, - val background: Int, - val primaryText: Int, - val secondaryText: Int, - val tertiaryText: Int, - val hintText: Int, - val disabledText: Int, - val accentText: Int, - val sectionHeader: Int, - val toolbarBackground: Int, - val toolbarIcon: Int, - val statusBarColorFallback: Int? = null) { + val isNightTheme: Boolean, + val background: Int, + val primaryText: Int, + val secondaryText: Int, + val tertiaryText: Int, + val hintText: Int, + val disabledText: Int, + val accentText: Int, + val sectionHeader: Int, + val toolbarBackground: Int, + val toolbarIcon: Int, + val statusBarColorFallback: Int? = null) { LIGHT( - isNightTheme = false, - background = R.color.white, - primaryText = R.color.dark_primary_text, - secondaryText = R.color.dark_secondary_text, - tertiaryText = R.color.dark_tertiary_text, - hintText = R.color.dark_hint_text, - disabledText = R.color.material_grey_600, - accentText = R.color.colorAccent, - sectionHeader = R.color.material_blue_grey_600, - toolbarBackground = R.color.material_grey_50, - toolbarIcon = R.color.dark_secondary_text, - statusBarColorFallback = R.color.material_grey_500), + isNightTheme = false, + background = R.color.white, + primaryText = R.color.dark_primary_text, + secondaryText = R.color.dark_secondary_text, + tertiaryText = R.color.dark_tertiary_text, + hintText = R.color.dark_hint_text, + disabledText = R.color.material_grey_600, + accentText = R.color.colorAccent, + sectionHeader = R.color.material_blue_grey_600, + toolbarBackground = R.color.material_grey_50, + toolbarIcon = R.color.dark_secondary_text, + statusBarColorFallback = R.color.material_grey_500), OFF_WHITE( - isNightTheme = false, - background = R.color.bg_off_white, - primaryText = R.color.dark_primary_text, - secondaryText = R.color.dark_secondary_text, - tertiaryText = R.color.dark_tertiary_text, - hintText = R.color.dark_hint_text, - disabledText = R.color.material_grey_600, - accentText = R.color.colorAccent, - sectionHeader = R.color.material_blue_grey_700, - toolbarBackground = R.color.bg_off_white_dark, - toolbarIcon = R.color.dark_secondary_text, - statusBarColorFallback = R.color.bg_off_white_darkest), + isNightTheme = false, + background = R.color.bg_off_white, + primaryText = R.color.dark_primary_text, + secondaryText = R.color.dark_secondary_text, + tertiaryText = R.color.dark_tertiary_text, + hintText = R.color.dark_hint_text, + disabledText = R.color.material_grey_600, + accentText = R.color.colorAccent, + sectionHeader = R.color.material_blue_grey_700, + toolbarBackground = R.color.bg_off_white_dark, + toolbarIcon = R.color.dark_secondary_text, + statusBarColorFallback = R.color.bg_off_white_darkest), PEACH( - isNightTheme = false, - background = R.color.bg_peach, - primaryText = R.color.dark_primary_text, - secondaryText = R.color.dark_secondary_text, - tertiaryText = R.color.dark_tertiary_text, - hintText = R.color.dark_hint_text, - disabledText = R.color.material_grey_600, - accentText = R.color.colorAccent, - sectionHeader = R.color.material_blue_grey_700, - toolbarBackground = R.color.bg_peach_dark, - toolbarIcon = R.color.dark_secondary_text, - statusBarColorFallback = R.color.bg_peach_darkest), + isNightTheme = false, + background = R.color.bg_peach, + primaryText = R.color.dark_primary_text, + secondaryText = R.color.dark_secondary_text, + tertiaryText = R.color.dark_tertiary_text, + hintText = R.color.dark_hint_text, + disabledText = R.color.material_grey_600, + accentText = R.color.colorAccent, + sectionHeader = R.color.material_blue_grey_700, + toolbarBackground = R.color.bg_peach_dark, + toolbarIcon = R.color.dark_secondary_text, + statusBarColorFallback = R.color.bg_peach_darkest), ROSE( - isNightTheme = false, - background = R.color.app_theme_rose, - primaryText = R.color.dark_primary_text, - secondaryText = R.color.dark_secondary_text, - tertiaryText = R.color.dark_tertiary_text, - hintText = R.color.dark_hint_text, - disabledText = R.color.material_grey_600, - accentText = R.color.colorAccent, - sectionHeader = R.color.material_blue_grey_700, - toolbarBackground = R.color.app_theme_rose_dark, - toolbarIcon = R.color.dark_secondary_text, - statusBarColorFallback = R.color.app_theme_rose_dark), + isNightTheme = false, + background = R.color.app_theme_rose, + primaryText = R.color.dark_primary_text, + secondaryText = R.color.dark_secondary_text, + tertiaryText = R.color.dark_tertiary_text, + hintText = R.color.dark_hint_text, + disabledText = R.color.material_grey_600, + accentText = R.color.colorAccent, + sectionHeader = R.color.material_blue_grey_700, + toolbarBackground = R.color.app_theme_rose_dark, + toolbarIcon = R.color.dark_secondary_text, + statusBarColorFallback = R.color.app_theme_rose_dark), TEAL( - isNightTheme = true, - background = R.color.app_theme_oceanic, - primaryText = R.color.light_primary_text, - secondaryText = R.color.light_primary_text, - tertiaryText = R.color.light_secondary_text, - hintText = R.color.light_hint_text, - disabledText = R.color.material_grey_200, - accentText = R.color.colorAccentDark, - sectionHeader = R.color.material_blue_grey_200, - toolbarBackground = R.color.app_theme_oceanic, - toolbarIcon = R.color.white), + isNightTheme = true, + background = R.color.app_theme_oceanic, + primaryText = R.color.light_primary_text, + secondaryText = R.color.light_primary_text, + tertiaryText = R.color.light_secondary_text, + hintText = R.color.light_hint_text, + disabledText = R.color.material_grey_200, + accentText = R.color.material_pink_accent_100, + sectionHeader = R.color.material_blue_grey_200, + toolbarBackground = R.color.app_theme_oceanic, + toolbarIcon = R.color.white), VIOLET( - isNightTheme = true, - background = R.color.app_theme_violet, - primaryText = R.color.light_primary_text, - secondaryText = R.color.light_primary_text, - tertiaryText = R.color.light_secondary_text, - hintText = R.color.light_hint_text, - disabledText = R.color.material_grey_200, - accentText = R.color.colorAccentDark, - sectionHeader = R.color.material_blue_grey_200, - toolbarBackground = R.color.app_theme_violet, - toolbarIcon = R.color.white), + isNightTheme = true, + background = R.color.app_theme_violet, + primaryText = R.color.light_primary_text, + secondaryText = R.color.light_primary_text, + tertiaryText = R.color.light_secondary_text, + hintText = R.color.light_hint_text, + disabledText = R.color.material_grey_200, + accentText = R.color.material_pink_accent_100, + sectionHeader = R.color.material_blue_grey_200, + toolbarBackground = R.color.app_theme_violet, + toolbarIcon = R.color.white), HONEYSUCKLE( - isNightTheme = true, - background = R.color.app_theme_honeysuckle, - primaryText = R.color.light_primary_text, - secondaryText = R.color.light_primary_text, - tertiaryText = R.color.light_secondary_text, - hintText = R.color.light_hint_text, - disabledText = R.color.material_grey_200, - accentText = R.color.colorAccentDark, - sectionHeader = R.color.material_blue_grey_200, - toolbarBackground = R.color.app_theme_honeysuckle, - toolbarIcon = R.color.white), + isNightTheme = true, + background = R.color.app_theme_honeysuckle, + primaryText = R.color.light_primary_text, + secondaryText = R.color.light_primary_text, + tertiaryText = R.color.light_secondary_text, + hintText = R.color.light_hint_text, + disabledText = R.color.material_grey_200, + accentText = R.color.material_yellow_accent_100, + sectionHeader = R.color.material_blue_grey_200, + toolbarBackground = R.color.app_theme_honeysuckle, + toolbarIcon = R.color.white), BROWN( - isNightTheme = true, - background = R.color.material_brown_800, - primaryText = R.color.light_primary_text, - secondaryText = R.color.light_primary_text, - tertiaryText = R.color.light_secondary_text, - hintText = R.color.light_hint_text, - disabledText = R.color.material_grey_200, - accentText = R.color.colorAccentDark, - sectionHeader = R.color.material_blue_grey_200, - toolbarBackground = R.color.material_brown_900, - toolbarIcon = R.color.white), + isNightTheme = true, + background = R.color.material_brown_800, + primaryText = R.color.light_primary_text, + secondaryText = R.color.light_primary_text, + tertiaryText = R.color.light_secondary_text, + hintText = R.color.light_hint_text, + disabledText = R.color.material_grey_200, + accentText = R.color.material_pink_accent_100, + sectionHeader = R.color.material_blue_grey_200, + toolbarBackground = R.color.material_brown_900, + toolbarIcon = R.color.white), BLUE_GRAY( - isNightTheme = true, - background = R.color.material_blue_grey_900, - primaryText = R.color.light_primary_text, - secondaryText = R.color.light_primary_text, - tertiaryText = R.color.light_secondary_text, - hintText = R.color.light_hint_text, - disabledText = R.color.material_grey_200, - accentText = R.color.colorAccentDark, - sectionHeader = R.color.material_blue_grey_200, - toolbarBackground = R.color.material_blue_grey_900, - toolbarIcon = R.color.white), + isNightTheme = true, + background = R.color.material_blue_grey_900, + primaryText = R.color.light_primary_text, + secondaryText = R.color.light_primary_text, + tertiaryText = R.color.light_secondary_text, + hintText = R.color.light_hint_text, + disabledText = R.color.material_grey_200, + accentText = R.color.material_pink_accent_100, + sectionHeader = R.color.material_blue_grey_200, + toolbarBackground = R.color.material_blue_grey_900, + toolbarIcon = R.color.white), DARK( - isNightTheme = true, - background = R.color.material_grey_850, - primaryText = R.color.light_primary_text, - secondaryText = R.color.light_primary_text, - tertiaryText = R.color.light_secondary_text, - hintText = R.color.light_hint_text, - disabledText = R.color.material_grey_200, - accentText = R.color.colorAccentDark, - sectionHeader = R.color.material_blue_grey_200, - toolbarBackground = R.color.material_grey_900, - toolbarIcon = R.color.white), + isNightTheme = true, + background = R.color.material_grey_850, + primaryText = R.color.light_primary_text, + secondaryText = R.color.light_primary_text, + tertiaryText = R.color.light_secondary_text, + hintText = R.color.light_hint_text, + disabledText = R.color.material_grey_200, + accentText = R.color.material_pink_accent_100, + sectionHeader = R.color.material_blue_grey_200, + toolbarBackground = R.color.material_grey_900, + toolbarIcon = R.color.white), VERY_DARK( - isNightTheme = true, - background = R.color.material_grey_900, - primaryText = R.color.light_primary_text, - secondaryText = R.color.light_primary_text, - tertiaryText = R.color.light_secondary_text, - hintText = R.color.light_hint_text, - disabledText = R.color.material_grey_200, - accentText = R.color.colorAccentDark, - sectionHeader = R.color.material_blue_grey_200, - toolbarBackground = R.color.material_grey_900, - toolbarIcon = R.color.white), + isNightTheme = true, + background = R.color.material_grey_900, + primaryText = R.color.light_primary_text, + secondaryText = R.color.light_primary_text, + tertiaryText = R.color.light_secondary_text, + hintText = R.color.light_hint_text, + disabledText = R.color.material_grey_200, + accentText = R.color.material_pink_accent_100, + sectionHeader = R.color.material_blue_grey_200, + toolbarBackground = R.color.material_grey_900, + toolbarIcon = R.color.white), BLACK( - isNightTheme = true, - background = R.color.black, - primaryText = R.color.light_primary_text, - secondaryText = R.color.light_primary_text, - tertiaryText = R.color.light_secondary_text, - hintText = R.color.light_hint_text, - disabledText = R.color.material_grey_200, - accentText = R.color.colorAccentDark, - sectionHeader = R.color.material_blue_grey_200, - toolbarBackground = R.color.black, - toolbarIcon = R.color.white), + isNightTheme = true, + background = R.color.black, + primaryText = R.color.light_primary_text, + secondaryText = R.color.light_primary_text, + tertiaryText = R.color.light_secondary_text, + hintText = R.color.light_hint_text, + disabledText = R.color.material_grey_200, + accentText = R.color.material_pink_accent_100, + sectionHeader = R.color.material_blue_grey_200, + toolbarBackground = R.color.black, + toolbarIcon = R.color.white), } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/support/ui/ThemedActivity.kt b/base/src/main/java/com/maubis/scarlet/base/support/ui/ThemedActivity.kt index 03530e9d..6c772ed0 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/ui/ThemedActivity.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/ui/ThemedActivity.kt @@ -1,32 +1,74 @@ package com.maubis.scarlet.base.support.ui import android.content.Context -import android.os.Build -import android.support.v7.app.AppCompatActivity +import android.content.res.Configuration +import android.os.Bundle import android.view.View import android.view.inputmethod.InputMethodManager -import com.maubis.scarlet.base.config.CoreConfig +import androidx.appcompat.app.AppCompatActivity +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme +import com.maubis.scarlet.base.settings.sheet.sInternalEnableFullScreen +import com.maubis.scarlet.base.support.utils.OsVersionUtils +import com.maubis.scarlet.base.support.utils.maybeThrow -abstract class ThemedActivity : AppCompatActivity() { +abstract class ThemedActivity : AppCompatActivity(), IThemeChangeListener { abstract fun notifyThemeChange() + override fun onChange(theme: Theme) { + notifyThemeChange() + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + sAppTheme.register(this) + } + fun setSystemTheme(color: Int = getStatusBarColor()) { setStatusBarColor(color) setStatusBarTextColor() } - fun setStatusBarColor(color: Int) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - window.statusBarColor = color + override fun onResume() { + super.onResume() + fullScreenView() + } + + override fun onConfigurationChanged(configuration: Configuration) { + super.onConfigurationChanged(configuration) + if (!sThemeIsAutomatic) { + return } + setThemeFromSystem(this) + sAppTheme.notifyChange(this) + } + + fun fullScreenView() { + if (!sInternalEnableFullScreen) { + return + } + + window.decorView.systemUiVisibility = ( + View.SYSTEM_UI_FLAG_IMMERSIVE + // Set the content to appear under the system bars so that the + // content doesn't resize when the system bars hide and show. + or View.SYSTEM_UI_FLAG_LAYOUT_STABLE + or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + // Hide the nav bar and status bar + or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + or View.SYSTEM_UI_FLAG_FULLSCREEN) + } + + fun setStatusBarColor(color: Int) { + window.statusBarColor = color } fun setStatusBarTextColor() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (OsVersionUtils.canSetStatusBarTheme()) { val view = window.decorView var flags = view.systemUiVisibility - flags = when (CoreConfig.instance.themeController().isNightTheme()) { + flags = when (sAppTheme.isNightTheme()) { true -> flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv() false -> flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR } @@ -34,16 +76,16 @@ abstract class ThemedActivity : AppCompatActivity() { } } - fun getThemeColor(): Int = CoreConfig.instance.themeController().get(ThemeColorType.BACKGROUND) + fun getThemeColor(): Int = sAppTheme.get(ThemeColorType.BACKGROUND) - fun getStatusBarColor(): Int = CoreConfig.instance.themeController().get(ThemeColorType.STATUS_BAR) + fun getStatusBarColor(): Int = sAppTheme.get(ThemeColorType.STATUS_BAR) fun tryClosingTheKeyboard() { try { val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager inputMethodManager.hideSoftInputFromWindow(currentFocus!!.windowToken, 0) } catch (exception: Exception) { - // Do nothing + maybeThrow(this, exception) } } @@ -52,7 +94,7 @@ abstract class ThemedActivity : AppCompatActivity() { val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0) } catch (exception: Exception) { - // Do nothing + maybeThrow(this, exception) } } } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/support/ui/ThemedBottomSheetFragment.kt b/base/src/main/java/com/maubis/scarlet/base/support/ui/ThemedBottomSheetFragment.kt index 0c8dcda1..e5423b89 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/ui/ThemedBottomSheetFragment.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/ui/ThemedBottomSheetFragment.kt @@ -5,18 +5,19 @@ import android.app.Dialog import android.content.Context import android.graphics.Color import android.os.Bundle -import android.support.v4.content.ContextCompat -import android.support.v7.app.AppCompatActivity -import android.support.v7.widget.CardView import android.view.View +import androidx.appcompat.app.AppCompatActivity +import androidx.cardview.widget.CardView +import androidx.core.content.ContextCompat import com.github.bijoysingh.starter.fragments.SimpleBottomSheetFragment import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.R -import com.maubis.scarlet.base.config.CoreConfig -import com.maubis.scarlet.base.export.sheet.BackupSettingsOptionsBottomSheet +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppTheme abstract class ThemedBottomSheetFragment : SimpleBottomSheetFragment() { + var appContext: Context? = null + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val isTablet = maybeContext()?.resources?.getBoolean(R.bool.is_tablet) ?: false val dialog = when { @@ -31,19 +32,20 @@ abstract class ThemedBottomSheetFragment : SimpleBottomSheetFragment() { if (dialog == null) { return } + appContext = dialog.context.applicationContext resetBackground(dialog) } fun themedActivity(): Activity = activity ?: context as AppCompatActivity - fun themedContext(): Context = context ?: activity!! + fun themedContext(): Context = maybeContext()!! - fun maybeContext(): Context? = context ?: activity + fun maybeContext(): Context? = context ?: activity ?: appContext abstract fun getBackgroundView(): Int fun resetBackground(dialog: Dialog) { - val backgroundColor = CoreConfig.instance.themeController().get(ThemeColorType.BACKGROUND) + val backgroundColor = sAppTheme.get(ThemeColorType.BACKGROUND) val containerLayout = dialog.findViewById(getBackgroundView()) containerLayout.setBackgroundColor(backgroundColor) for (viewId in getBackgroundCardViewIds()) { @@ -54,8 +56,8 @@ abstract class ThemedBottomSheetFragment : SimpleBottomSheetFragment() { open fun getOptionsTitleColor(selected: Boolean): Int { val colorResource = when { - CoreConfig.instance.themeController().isNightTheme() && selected -> R.color.material_blue_300 - CoreConfig.instance.themeController().isNightTheme() -> R.color.light_secondary_text + sAppTheme.isNightTheme() && selected -> R.color.material_blue_300 + sAppTheme.isNightTheme() -> R.color.light_secondary_text selected -> R.color.material_blue_700 else -> R.color.dark_secondary_text } @@ -64,8 +66,8 @@ abstract class ThemedBottomSheetFragment : SimpleBottomSheetFragment() { open fun getOptionsSubtitleColor(selected: Boolean): Int { val colorResource = when { - CoreConfig.instance.themeController().isNightTheme() && selected -> R.color.material_blue_200 - CoreConfig.instance.themeController().isNightTheme() -> R.color.light_tertiary_text + sAppTheme.isNightTheme() && selected -> R.color.material_blue_200 + sAppTheme.isNightTheme() -> R.color.light_tertiary_text selected -> R.color.material_blue_500 else -> R.color.dark_tertiary_text } diff --git a/base/src/main/java/com/maubis/scarlet/base/support/ui/font/TypefaceController.kt b/base/src/main/java/com/maubis/scarlet/base/support/ui/font/TypefaceController.kt new file mode 100644 index 00000000..168618af --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/support/ui/font/TypefaceController.kt @@ -0,0 +1,91 @@ +package com.maubis.scarlet.base.support.ui.font + +import android.content.Context +import android.graphics.Typeface +import androidx.core.content.res.ResourcesCompat +import com.maubis.markdown.MarkdownConfig +import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.ApplicationBase + +const val KEY_PREFERENCE_TYPEFACE = "typeface_setting" +var sPreferenceTypeface: String + get() = ApplicationBase.sAppPreferences.get(KEY_PREFERENCE_TYPEFACE, TypefaceController.TypefaceType.APP_DEFAULT.name) + set(value) = ApplicationBase.sAppPreferences.put(KEY_PREFERENCE_TYPEFACE, value) + +class TypefaceController(context: Context) { + enum class TypefaceType(val title: Int, val isLiteEnabled: Boolean) { + APP_DEFAULT(R.string.typeface_title_app_default, true), + OS_DEFAULT(R.string.typeface_title_os_default, true), + MONOSPACE(R.string.typeface_title_monospace, false), + SERIF_TITLE(R.string.typeface_title_serif, false), + } + + data class TypefaceSet( + val heading: Typeface = Typeface.DEFAULT, + val subHeading: Typeface = Typeface.DEFAULT, + val title: Typeface = Typeface.DEFAULT, + val text: Typeface = Typeface.DEFAULT, + val code: Typeface = Typeface.MONOSPACE + ) + + private var mTypefaceSet: TypefaceSet = TypefaceSet() + + init { + notifyChange(context) + } + + fun notifyChange(context: Context) { + mTypefaceSet = getSetForType(context, getTypefaceSetting()) + setMarkdownConfig() + } + + fun getSetForType(context: Context, typefaceType: TypefaceType): TypefaceSet { + return when (typefaceType) { + TypefaceType.APP_DEFAULT -> TypefaceSet( + heading = ResourcesCompat.getFont(context, R.font.monserrat_bold) ?: Typeface.DEFAULT, + subHeading = ResourcesCompat.getFont(context, R.font.monserrat_medium) ?: Typeface.DEFAULT, + title = ResourcesCompat.getFont(context, R.font.monserrat) ?: Typeface.DEFAULT, + text = ResourcesCompat.getFont(context, R.font.open_sans) ?: Typeface.DEFAULT, + code = Typeface.MONOSPACE) + TypefaceType.OS_DEFAULT -> TypefaceSet() + TypefaceType.MONOSPACE -> TypefaceSet( + heading = ResourcesCompat.getFont(context, R.font.mono_bold_xml) ?: Typeface.MONOSPACE, + subHeading = ResourcesCompat.getFont(context, R.font.mono_medium_xml) ?: Typeface.MONOSPACE, + title = ResourcesCompat.getFont(context, R.font.mono_regular_xml) ?: Typeface.MONOSPACE, + text = ResourcesCompat.getFont(context, R.font.mono_regular_xml) ?: Typeface.MONOSPACE, + code = Typeface.MONOSPACE) + TypefaceType.SERIF_TITLE -> TypefaceSet( + heading = ResourcesCompat.getFont(context, R.font.serif_bold_xml) ?: Typeface.SERIF, + subHeading = ResourcesCompat.getFont(context, R.font.serif_bold_xml) ?: Typeface.SERIF, + title = ResourcesCompat.getFont(context, R.font.serif_regular_xml) ?: Typeface.SERIF, + text = ResourcesCompat.getFont(context, R.font.open_sans) ?: Typeface.DEFAULT, + code = Typeface.MONOSPACE) + } + } + + private fun setMarkdownConfig() { + MarkdownConfig.config.spanConfig.headingTypeface = subHeading() + MarkdownConfig.config.spanConfig.heading2Typeface = title() + MarkdownConfig.config.spanConfig.heading3Typeface = title() + MarkdownConfig.config.spanConfig.textTypeface = text() + MarkdownConfig.config.spanConfig.codeTypeface = code() + } + + private fun getTypefaceSetting(): TypefaceType { + return try { + TypefaceType.valueOf(sPreferenceTypeface) + } catch (exception: Exception) { + TypefaceType.APP_DEFAULT + } + } + + fun heading(): Typeface = mTypefaceSet.heading + + fun subHeading(): Typeface = mTypefaceSet.subHeading + + fun title(): Typeface = mTypefaceSet.title + + fun text(): Typeface = mTypefaceSet.text + + fun code(): Typeface = mTypefaceSet.code +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/support/utils/AppVersionUtils.kt b/base/src/main/java/com/maubis/scarlet/base/support/utils/AppVersionUtils.kt index 9a63ffe5..efac3363 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/utils/AppVersionUtils.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/utils/AppVersionUtils.kt @@ -1,9 +1,9 @@ package com.maubis.scarlet.base.support.utils import com.maubis.scarlet.base.BuildConfig -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences import com.maubis.scarlet.base.config.CoreConfig.Companion.notesDb -import com.maubis.scarlet.base.main.sheets.WhatsNewBottomSheet.Companion.WHATS_NEW_UID +import com.maubis.scarlet.base.main.sheets.WHATS_NEW_SHEET_INDEX import java.util.* const val KEY_LAST_KNOWN_APP_VERSION = "KEY_LAST_KNOWN_APP_VERSION" @@ -20,7 +20,7 @@ fun getCurrentVersionCode(): Int { * If nothing can be concluded it's 0 (assumes new user) */ fun getLastUsedAppVersionCode(): Int { - val appVersion = CoreConfig.instance.store().get(KEY_LAST_KNOWN_APP_VERSION, 0) + val appVersion = sAppPreferences.get(KEY_LAST_KNOWN_APP_VERSION, 0) return when { appVersion > 0 -> appVersion notesDb.getCount() > 0 -> -1 @@ -29,8 +29,8 @@ fun getLastUsedAppVersionCode(): Int { } fun shouldShowWhatsNewSheet(): Boolean { - val lastShownWhatsNew = CoreConfig.instance.store().get(KEY_LAST_SHOWN_WHATS_NEW, 0) - if (lastShownWhatsNew >= WHATS_NEW_UID) { + val lastShownWhatsNew = sAppPreferences.get(KEY_LAST_SHOWN_WHATS_NEW, 0) + if (lastShownWhatsNew >= WHATS_NEW_SHEET_INDEX) { // Already shown the latest return false } @@ -38,18 +38,18 @@ fun shouldShowWhatsNewSheet(): Boolean { val lastUsedAppVersion = getLastUsedAppVersionCode() // Update the values independent of the decision - CoreConfig.instance.store().put(KEY_LAST_SHOWN_WHATS_NEW, WHATS_NEW_UID) - CoreConfig.instance.store().put(KEY_LAST_KNOWN_APP_VERSION, getCurrentVersionCode()) + sAppPreferences.put(KEY_LAST_SHOWN_WHATS_NEW, WHATS_NEW_SHEET_INDEX) + sAppPreferences.put(KEY_LAST_KNOWN_APP_VERSION, getCurrentVersionCode()) // New users don't need to see the whats new screen return lastUsedAppVersion != 0 } fun getInstanceID(): String { - val deviceId = CoreConfig.instance.store().get(KEY_INSTANCE_ID, "") + val deviceId = sAppPreferences.get(KEY_INSTANCE_ID, "") if (deviceId.isBlank()) { val newDeviceId = UUID.randomUUID().toString() - CoreConfig.instance.store().put(KEY_INSTANCE_ID, newDeviceId) + sAppPreferences.put(KEY_INSTANCE_ID, newDeviceId) return newDeviceId } return deviceId diff --git a/base/src/main/java/com/maubis/scarlet/base/support/utils/BindSupport.kt b/base/src/main/java/com/maubis/scarlet/base/support/utils/BindSupport.kt index 74355816..d6a26177 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/utils/BindSupport.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/utils/BindSupport.kt @@ -1,8 +1,8 @@ package com.maubis.scarlet.base.support.utils import android.app.Activity -import android.support.annotation.IdRes import android.view.View +import androidx.annotation.IdRes fun Activity.bind(@IdRes idRes: Int): Lazy { @Suppress("UNCHECKED_CAST") diff --git a/base/src/main/java/com/maubis/scarlet/base/support/utils/DateFormatUtils.kt b/base/src/main/java/com/maubis/scarlet/base/support/utils/DateFormatUtils.kt new file mode 100644 index 00000000..61a1be46 --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/support/utils/DateFormatUtils.kt @@ -0,0 +1,31 @@ +package com.maubis.scarlet.base.support.utils + +import android.content.Context +import android.text.format.DateFormat +import com.github.bijoysingh.starter.util.DateFormatter +import java.util.* + +lateinit var sDateFormat: DateFormatUtils + +class DateFormatUtils(context: Context) { + private val is24HourFormat = DateFormat.is24HourFormat(context) + + fun readableFullTime(timestamp: Long): String = readableTime( + DateFormatter.Formats.HH_MM_A_DD_MMM_YYYY.format, + timestamp) + + fun readableTime(format: String, timestamp: Long): String { + val hourFormatSafe = when { + is24HourFormat -> format + .replace("a", "") + .replace("h", "H") + else -> format + } + return DateFormatter.getDate( + DateFormat.getBestDateTimePattern(Locale.getDefault(), hourFormatSafe), + timestamp) + } + + fun getDateForBackup(): String = DateFormatter.getDate("dd_MMM_yyyy", Calendar.getInstance()) + fun getTimestampForBackup(): String = DateFormatter.getDate("dd_MMM_yyyy HH_mm", Calendar.getInstance()) +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/support/utils/ExceptionUtils.kt b/base/src/main/java/com/maubis/scarlet/base/support/utils/ExceptionUtils.kt new file mode 100644 index 00000000..abcf8432 --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/support/utils/ExceptionUtils.kt @@ -0,0 +1,145 @@ +package com.maubis.scarlet.base.support.utils + +import android.os.SystemClock +import android.util.Log +import androidx.appcompat.app.AppCompatActivity +import com.github.bijoysingh.starter.util.DateFormatter +import com.maubis.scarlet.base.BuildConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.instance +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences +import com.maubis.scarlet.base.core.format.Format +import com.maubis.scarlet.base.core.format.FormatBuilder +import com.maubis.scarlet.base.core.format.FormatType +import com.maubis.scarlet.base.core.note.NoteBuilder +import com.maubis.scarlet.base.core.note.getFormats +import com.maubis.scarlet.base.core.note.isUnsaved +import com.maubis.scarlet.base.main.sheets.ExceptionBottomSheet +import com.maubis.scarlet.base.note.unsafeSave_INTERNAL_USE_ONLY +import com.maubis.scarlet.base.support.sheets.openSheet +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch + +const val KEY_INTERNAL_LOG_TRACES_TO_NOTE = "internal_log_traces_to_note" +var sInternalLogTracesToNote: Boolean + get() = sAppPreferences.get(KEY_INTERNAL_LOG_TRACES_TO_NOTE, false) + set(value) = sAppPreferences.put(KEY_INTERNAL_LOG_TRACES_TO_NOTE, value) + +const val KEY_INTERNAL_SHOW_TRACES_IN_SHEET = "internal_show_traces_in_sheet" +var sInternalShowTracesInSheet: Boolean + get() = sAppPreferences.get(KEY_INTERNAL_SHOW_TRACES_IN_SHEET, false) + set(value) = sAppPreferences.put(KEY_INTERNAL_SHOW_TRACES_IN_SHEET, value) + +const val KEY_INTERNAL_THROW_ON_EXCEPTION = "internal_throw_on_exception" +var sInternalThrowOnException: Boolean + get() = sAppPreferences.get(KEY_INTERNAL_THROW_ON_EXCEPTION, false) + set(value) = sAppPreferences.put(KEY_INTERNAL_THROW_ON_EXCEPTION, value) + +const val KEY_INTERNAL_THROWN_EXCEPTION_COUNT = "internal_thrown_exception_count" +var sInternalThrownExceptionCount: Int + get() = sAppPreferences.get(KEY_INTERNAL_THROWN_EXCEPTION_COUNT, 0) + set(value) = sAppPreferences.put(KEY_INTERNAL_THROWN_EXCEPTION_COUNT, value) + +/** + * Throws in debug builds and stores the log trace to a fixed note in case of 'internal debug mode'. + */ +fun maybeThrow(activity: AppCompatActivity, thrownException: Exception) { + if (sInternalShowTracesInSheet) { + openSheet(activity, ExceptionBottomSheet().apply { this.exception = thrownException }) + } + maybeThrow(thrownException) +} + +/** + * Throws in debug builds and stores the log trace to a fixed note in case of 'internal debug mode'. + */ +fun maybeThrow(exception: Exception) { + if (sInternalLogTracesToNote) { + storeToDebugNote(Log.getStackTraceString(exception)) + } + + if (sInternalThrowOnException) { + sInternalThrownExceptionCount += 1 + if (sInternalThrownExceptionCount <= 5) { + GlobalScope.launch { + SystemClock.sleep(1000) + throw exception + } + } + + sInternalThrownExceptionCount = 0 + sInternalThrowOnException = false + } + + if (BuildConfig.DEBUG) { + Log.e("Scarlet", "Exception Thrown and Recovered", exception) + } +} + +/** + * Throws in debug builds and stores the log trace to a fixed note in case of 'internal debug mode'. + */ +fun maybeThrow(message: String) { + maybeThrow(IllegalStateException(message)) +} + +/** + * Throws in debug builds and stores the log trace to a fixed note in case of 'internal debug mode'. + * Else returns the provided value + */ +fun throwOrReturn(message: String, result: DataType): DataType { + return throwOrReturn(IllegalStateException(message), result) +} + +/** + * Throws in debug builds and stores the log trace to a fixed note in case of 'internal debug mode'. + * Else returns the provided value + */ +fun throwOrReturn(exception: Exception, result: DataType): DataType { + maybeThrow(exception) + return result +} + +private fun storeToDebugNote(trace: String) { + GlobalScope.launch { + storeToDebugNoteSync(trace) + } +} + +const val EXCEPTION_NOTE_KEY = "debug-note" +const val EXCEPTION_NOTE_NUM_DATA_PER_EXCEPTION = 4 +const val EXCEPTION_NOTE_MAX_EXCEPTIONS = 20 + +@Synchronized +private fun storeToDebugNoteSync(trace: String) { + val note = instance.notesDatabase().getByUUID(EXCEPTION_NOTE_KEY) + ?: NoteBuilder().emptyNote().apply { + uuid = EXCEPTION_NOTE_KEY + disableBackup = true + } + + val initialFormats = note.getFormats().toMutableList() + if (note.isUnsaved() || initialFormats.isEmpty()) { + initialFormats.add(Format(FormatType.HEADING, "Note Exceptions")) + } + + val additionalFormats = emptyList().toMutableList() + additionalFormats.add(Format(FormatType.SUB_HEADING, "Exception")) + additionalFormats.add( + Format( + FormatType.QUOTE, + "Throw at ${DateFormatter.getDate(System.currentTimeMillis())}")) + additionalFormats.add( + Format( + FormatType.CODE, + trace)) + additionalFormats.add(Format(FormatType.SEPARATOR)) + + val maxFormatCount = 1 + EXCEPTION_NOTE_MAX_EXCEPTIONS * EXCEPTION_NOTE_NUM_DATA_PER_EXCEPTION + if (initialFormats.size > maxFormatCount) { + initialFormats.subList(0, maxFormatCount) + } + + initialFormats.addAll(1, additionalFormats) + note.description = FormatBuilder().getDescription(initialFormats) + note.unsafeSave_INTERNAL_USE_ONLY() +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/support/utils/FlavourUtils.kt b/base/src/main/java/com/maubis/scarlet/base/support/utils/FlavorUtils.kt similarity index 51% rename from base/src/main/java/com/maubis/scarlet/base/support/utils/FlavourUtils.kt rename to base/src/main/java/com/maubis/scarlet/base/support/utils/FlavorUtils.kt index 74c1da8e..e9b22229 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/utils/FlavourUtils.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/utils/FlavorUtils.kt @@ -1,33 +1,37 @@ package com.maubis.scarlet.base.support.utils import android.content.Context -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppFlavor +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import java.lang.ref.WeakReference - enum class Flavor { NONE, // FDroid, Master Builds LITE, // Play Store Version PRO, // Play Store Pro Version } -object FlavourUtils { +object FlavorUtils { const val PRO_APP_PACKAGE_NAME = "com.bijoysingh.quicknote.pro" const val KEY_PRO_APP_INSTALLED = "pro_app_installed" fun hasProAppInstalled(context: Context): Boolean { val reference = WeakReference(context) GlobalScope.launch(Dispatchers.IO) { - var found = false - try { - found = reference.get()?.packageManager?.getPackageInfo(PRO_APP_PACKAGE_NAME, 0) != null + val found = try { + reference.get()?.packageManager?.getPackageInfo(PRO_APP_PACKAGE_NAME, 0) != null } catch (e: Exception) { - found = false + throwOrReturn(e, false) } - CoreConfig.instance.store().put(KEY_PRO_APP_INSTALLED, found) + sAppPreferences.put(KEY_PRO_APP_INSTALLED, found) } - return CoreConfig.instance.store().get(KEY_PRO_APP_INSTALLED, false) + return sAppPreferences.get(KEY_PRO_APP_INSTALLED, false) } + + fun isPro() = sAppFlavor == Flavor.PRO + fun isLite() = sAppFlavor == Flavor.LITE + fun isPlayStore() = sAppFlavor != Flavor.NONE + fun isOpenSource() = sAppFlavor == Flavor.NONE } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/support/utils/ImageCache.kt b/base/src/main/java/com/maubis/scarlet/base/support/utils/ImageCache.kt index 2a6ec502..8ba8d59c 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/utils/ImageCache.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/utils/ImageCache.kt @@ -29,7 +29,6 @@ class ImageCache(context: Context) { } } - fun imagesForNote(noteUUID: String): Array { val folder = File(persistentFolder, noteUUID) return folder.listFiles() ?: emptyArray() @@ -75,12 +74,18 @@ class ImageCache(context: Context) { thumbnailCacheSize.addAndGet(-cacheFile.length()) } - val fOut = FileOutputStream(cacheFile) - val compressedBitmap = sampleBitmap(bitmap) - compressedBitmap.compress(Bitmap.CompressFormat.PNG, 75, fOut) - fOut.flush() - fOut.close() + val compressedBitmap: Bitmap = sampleBitmap(bitmap) + + try { + val fOut = FileOutputStream(cacheFile) + compressedBitmap.compress(Bitmap.CompressFormat.PNG, 75, fOut) + fOut.flush() + fOut.close() + } catch (exception: Exception) { + return throwOrReturn(exception, compressedBitmap) + } + thumbnailCacheSize.addAndGet(cacheFile.length()) performEviction() return compressedBitmap } diff --git a/base/src/main/java/com/maubis/scarlet/base/support/utils/LogUtils.kt b/base/src/main/java/com/maubis/scarlet/base/support/utils/LogUtils.kt new file mode 100644 index 00000000..bf514fba --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/support/utils/LogUtils.kt @@ -0,0 +1,14 @@ +package com.maubis.scarlet.base.support.utils + +import android.util.Log +import com.maubis.scarlet.base.BuildConfig + +fun log(message: String) { + log("Scarlet", message) +} + +fun log(tag: String, description: String) { + if (BuildConfig.DEBUG) { + Log.d(tag, description) + } +} \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/support/utils/OsVersionUtils.kt b/base/src/main/java/com/maubis/scarlet/base/support/utils/OsVersionUtils.kt new file mode 100644 index 00000000..e8a14961 --- /dev/null +++ b/base/src/main/java/com/maubis/scarlet/base/support/utils/OsVersionUtils.kt @@ -0,0 +1,19 @@ +package com.maubis.scarlet.base.support.utils + +import android.os.Build + +object OsVersionUtils { + fun canExtractReferrer() = Build.VERSION.SDK_INT >= 22 + + fun requiresPermissions() = Build.VERSION.SDK_INT >= 23 + + fun canSetStatusBarTheme() = Build.VERSION.SDK_INT >= 23 + + fun canExtractActiveNotifications() = Build.VERSION.SDK_INT >= 23 + + fun canAddLauncherShortcuts() = Build.VERSION.SDK_INT >= 26 + + fun canAddNotificationChannels() = Build.VERSION.SDK_INT >= 26 + + fun canUseSystemTheme() = Build.VERSION.SDK_INT >= 29 +} diff --git a/base/src/main/java/com/maubis/scarlet/base/support/utils/TextInputUtils.kt b/base/src/main/java/com/maubis/scarlet/base/support/utils/TextInputUtils.kt index 9e130012..40984622 100644 --- a/base/src/main/java/com/maubis/scarlet/base/support/utils/TextInputUtils.kt +++ b/base/src/main/java/com/maubis/scarlet/base/support/utils/TextInputUtils.kt @@ -5,8 +5,8 @@ import android.view.inputmethod.EditorInfo import android.widget.TextView fun getEditorActionListener( - runnable: () -> Boolean, - preConditions: () -> Boolean = { false }): TextView.OnEditorActionListener { + runnable: () -> Boolean, + preConditions: () -> Boolean = { false }): TextView.OnEditorActionListener { return TextView.OnEditorActionListener { _: TextView, actionId: Int, event: KeyEvent? -> if (preConditions()) { return@OnEditorActionListener false diff --git a/base/src/main/java/com/maubis/scarlet/base/widget/AllNotesWidgetProvider.kt b/base/src/main/java/com/maubis/scarlet/base/widget/AllNotesWidgetProvider.kt index 29acfe31..6bea70f6 100644 --- a/base/src/main/java/com/maubis/scarlet/base/widget/AllNotesWidgetProvider.kt +++ b/base/src/main/java/com/maubis/scarlet/base/widget/AllNotesWidgetProvider.kt @@ -1,22 +1,22 @@ package com.maubis.scarlet.base.widget import android.app.Application +import android.app.PendingIntent import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetProvider +import android.content.ComponentName import android.content.Context import android.content.Intent import android.net.Uri import android.widget.RemoteViews -import com.maubis.scarlet.base.R -import android.app.PendingIntent -import android.content.ComponentName import com.maubis.scarlet.base.MainActivity +import com.maubis.scarlet.base.R import com.maubis.scarlet.base.note.creation.activity.CreateListNoteActivity import com.maubis.scarlet.base.note.creation.activity.CreateNoteActivity import com.maubis.scarlet.base.note.creation.activity.ViewAdvancedNoteActivity - - -const val STORE_KEY_ALL_NOTE_WIDGET = "all_note_widget" +import com.maubis.scarlet.base.support.ui.visibility +import com.maubis.scarlet.base.widget.sheet.sWidgetBackgroundColor +import com.maubis.scarlet.base.widget.sheet.sWidgetShowToolbar class AllNotesWidgetProvider : AppWidgetProvider() { @@ -26,25 +26,28 @@ class AllNotesWidgetProvider : AppWidgetProvider() { val appWidgetId = appWidgetIds[i] val views = RemoteViews( - context.packageName, - R.layout.widget_layout_all_notes + context.packageName, + R.layout.widget_layout_all_notes ) val intent = Intent(context, AllNotesWidgetService::class.java) intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]) intent.data = Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)) views.setRemoteAdapter(R.id.list, intent) + views.setInt(R.id.widget_background, "setBackgroundColor", sWidgetBackgroundColor) + views.setViewVisibility(R.id.toolbar, visibility(sWidgetShowToolbar)) + val noteIntent = Intent(context, ViewAdvancedNoteActivity::class.java) noteIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]) - val notePendingIntent = PendingIntent.getActivity(context, 0, noteIntent, PendingIntent.FLAG_UPDATE_CURRENT) + val notePendingIntent = getPendingIntentWithStack(context, 0, noteIntent) views.setPendingIntentTemplate(R.id.list, notePendingIntent) val createNoteIntent = Intent(context, CreateNoteActivity::class.java) - val createNotePendingIntent = PendingIntent.getActivity(context, 23214, createNoteIntent, PendingIntent.FLAG_UPDATE_CURRENT) + val createNotePendingIntent = getPendingIntentWithStack(context, 23214, createNoteIntent) views.setOnClickPendingIntent(R.id.add_note, createNotePendingIntent) val createListNoteIntent = Intent(context, CreateListNoteActivity::class.java) - val createListNotePendingIntent = PendingIntent.getActivity(context, 13123, createListNoteIntent, PendingIntent.FLAG_UPDATE_CURRENT) + val createListNotePendingIntent = getPendingIntentWithStack(context, 13123, createListNoteIntent) views.setOnClickPendingIntent(R.id.add_list, createListNotePendingIntent) val mainIntent = Intent(context, MainActivity::class.java) @@ -59,7 +62,7 @@ class AllNotesWidgetProvider : AppWidgetProvider() { fun notifyAllChanged(context: Context) { val application: Application = context.applicationContext as Application val ids = AppWidgetManager.getInstance(application).getAppWidgetIds( - ComponentName(application, AllNotesWidgetProvider::class.java)) + ComponentName(application, AllNotesWidgetProvider::class.java)) if (ids.isEmpty()) { return } diff --git a/base/src/main/java/com/maubis/scarlet/base/widget/AllNotesWidgetService.kt b/base/src/main/java/com/maubis/scarlet/base/widget/AllNotesWidgetService.kt index c91d41b0..860defcf 100644 --- a/base/src/main/java/com/maubis/scarlet/base/widget/AllNotesWidgetService.kt +++ b/base/src/main/java/com/maubis/scarlet/base/widget/AllNotesWidgetService.kt @@ -3,19 +3,17 @@ package com.maubis.scarlet.base.widget import android.content.Context import android.content.Intent import android.os.Bundle -import android.support.v4.content.ContextCompat import android.widget.AdapterView import android.widget.RemoteViews import android.widget.RemoteViewsService +import androidx.core.content.ContextCompat import com.maubis.scarlet.base.R import com.maubis.scarlet.base.database.room.note.Note import com.maubis.scarlet.base.note.creation.activity.INTENT_KEY_NOTE_ID -import com.maubis.scarlet.base.note.creation.activity.ViewAdvancedNoteActivity import com.maubis.scarlet.base.support.ui.ColorUtil import com.maubis.scarlet.base.widget.sheet.getWidgetNoteText import com.maubis.scarlet.base.widget.sheet.getWidgetNotes - class AllNotesWidgetService : RemoteViewsService() { override fun onGetViewFactory(intent: Intent?): RemoteViewsFactory { return AllNotesRemoteViewsFactory(applicationContext) @@ -34,7 +32,7 @@ class AllNotesRemoteViewsFactory(val context: Context) : RemoteViewsService.Remo } override fun getItemId(position: Int): Long { - return notes[position].uid.toLong() + return if (position < notes.size) notes[position].uid.toLong() else 0 } override fun onDataSetChanged() { @@ -46,13 +44,12 @@ class AllNotesRemoteViewsFactory(val context: Context) : RemoteViewsService.Remo } override fun getViewAt(position: Int): RemoteViews? { - if (position == AdapterView.INVALID_POSITION) { + if (position == AdapterView.INVALID_POSITION || position >= notes.size) { return null } val note = notes[position] - val intent = ViewAdvancedNoteActivity.getIntent(context, note) val views = RemoteViews(context.getPackageName(), R.layout.item_widget_note) views.setTextViewText(R.id.description, getWidgetNoteText(note)) diff --git a/base/src/main/java/com/maubis/scarlet/base/widget/CreateNoteWidgetProvider.kt b/base/src/main/java/com/maubis/scarlet/base/widget/CreateNoteWidgetProvider.kt index d6439e8b..2ba91d61 100644 --- a/base/src/main/java/com/maubis/scarlet/base/widget/CreateNoteWidgetProvider.kt +++ b/base/src/main/java/com/maubis/scarlet/base/widget/CreateNoteWidgetProvider.kt @@ -6,12 +6,12 @@ import android.appwidget.AppWidgetProvider import android.content.Context import android.content.Intent import android.widget.RemoteViews +import androidx.core.app.TaskStackBuilder import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.R import com.maubis.scarlet.base.note.creation.activity.CreateListNoteActivity import com.maubis.scarlet.base.note.creation.activity.CreateNoteActivity - class CreateNoteWidgetProvider : AppWidgetProvider() { override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) { @@ -19,24 +19,30 @@ class CreateNoteWidgetProvider : AppWidgetProvider() { for (i in 0 until N) { val appWidgetId = appWidgetIds[i] - val intent = Intent(context, CreateNoteActivity::class.java) - val pendingIntent = PendingIntent.getActivity(context, 23100, intent, 0) - - val views = RemoteViews(context.packageName, R.layout.add_note_widget_layout) - views.setOnClickPendingIntent(R.id.add_note, pendingIntent) + views.setOnClickPendingIntent(R.id.add_note, getPendingIntent(context, CreateNoteActivity::class.java, 23100)) - val intentList = Intent(context, CreateListNoteActivity::class.java) - val pendingIntentList = PendingIntent.getActivity(context, 23101, intentList, 0) + val pendingIntentList = getPendingIntent(context, CreateListNoteActivity::class.java, 23101) views.setOnClickPendingIntent(R.id.add_list, pendingIntentList) - val intentApp = Intent(context, MainActivity::class.java) val pendingIntentApp = PendingIntent.getActivity(context, 23102, intentApp, 0) views.setOnClickPendingIntent(R.id.open_app, pendingIntentApp) - appWidgetManager.updateAppWidget(appWidgetId, views); - + appWidgetManager.updateAppWidget(appWidgetId, views) } } + + private fun getPendingIntent(context: Context, activityClass: Class, requestCode: Int): PendingIntent { + return getPendingIntentWithStack(context, requestCode, Intent(context, activityClass)) + } +} + +fun getPendingIntentWithStack( + context: Context, requestCode: Int, resultIntent: Intent, flags: Int = PendingIntent.FLAG_UPDATE_CURRENT): PendingIntent { + return TaskStackBuilder.create(context) + .addNextIntentWithParentStack(Intent(context, MainActivity::class.java)) + .addNextIntent(resultIntent) + .getPendingIntent(requestCode, flags) + ?: PendingIntent.getActivity(context, requestCode, resultIntent, 0) } \ No newline at end of file diff --git a/base/src/main/java/com/maubis/scarlet/base/widget/NoteWidgetProvider.kt b/base/src/main/java/com/maubis/scarlet/base/widget/NoteWidgetProvider.kt index 3db4b7a7..1c4ef3ab 100644 --- a/base/src/main/java/com/maubis/scarlet/base/widget/NoteWidgetProvider.kt +++ b/base/src/main/java/com/maubis/scarlet/base/widget/NoteWidgetProvider.kt @@ -3,7 +3,7 @@ package com.maubis.scarlet.base.widget import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetProvider import android.content.Context -import com.maubis.scarlet.base.config.CoreConfig +import com.maubis.scarlet.base.config.ApplicationBase import com.maubis.scarlet.base.main.activity.WidgetConfigureActivity class NoteWidgetProvider : AppWidgetProvider() { @@ -12,7 +12,7 @@ class NoteWidgetProvider : AppWidgetProvider() { val N = appWidgetIds.size for (i in 0 until N) { val appWidgetId = appWidgetIds[i] - val widget = CoreConfig.instance.database().widgets().getByID(appWidgetId) + val widget = ApplicationBase.instance.database().widgets().getByID(appWidgetId) if (widget === null) { continue } @@ -30,11 +30,11 @@ class NoteWidgetProvider : AppWidgetProvider() { val N = appWidgetIds.size for (i in 0 until N) { val appWidgetId = appWidgetIds[i] - val widget = CoreConfig.instance.database().widgets().getByID(appWidgetId) + val widget = ApplicationBase.instance.database().widgets().getByID(appWidgetId) if (widget === null) { continue } - CoreConfig.instance.database().widgets().delete(widget) + ApplicationBase.instance.database().widgets().delete(widget) } } diff --git a/base/src/main/java/com/maubis/scarlet/base/widget/sheet/WidgetOptionsBottomSheet.kt b/base/src/main/java/com/maubis/scarlet/base/widget/sheet/WidgetOptionsBottomSheet.kt index ec1baa0f..35005351 100644 --- a/base/src/main/java/com/maubis/scarlet/base/widget/sheet/WidgetOptionsBottomSheet.kt +++ b/base/src/main/java/com/maubis/scarlet/base/widget/sheet/WidgetOptionsBottomSheet.kt @@ -5,18 +5,25 @@ import android.app.Dialog import android.appwidget.AppWidgetManager import android.content.ComponentName import android.content.Intent +import android.graphics.Color import com.facebook.litho.ComponentContext import com.maubis.markdown.Markdown import com.maubis.scarlet.base.MainActivity import com.maubis.scarlet.base.R +import com.maubis.scarlet.base.config.ApplicationBase.Companion.sAppPreferences import com.maubis.scarlet.base.config.CoreConfig import com.maubis.scarlet.base.core.note.NoteState import com.maubis.scarlet.base.core.note.sort import com.maubis.scarlet.base.database.room.note.Note -import com.maubis.scarlet.base.note.getFullText +import com.maubis.scarlet.base.main.sheets.InstallProUpsellBottomSheet +import com.maubis.scarlet.base.note.getFullTextForDirectMarkdownRender +import com.maubis.scarlet.base.settings.sheet.ColorPickerBottomSheet +import com.maubis.scarlet.base.settings.sheet.ColorPickerDefaultController import com.maubis.scarlet.base.settings.sheet.SortingOptionsBottomSheet import com.maubis.scarlet.base.support.sheets.LithoOptionBottomSheet import com.maubis.scarlet.base.support.sheets.LithoOptionsItem +import com.maubis.scarlet.base.support.sheets.openSheet +import com.maubis.scarlet.base.support.utils.FlavorUtils import com.maubis.scarlet.base.widget.AllNotesWidgetProvider import com.maubis.scarlet.base.widget.NoteWidgetProvider import kotlinx.coroutines.GlobalScope @@ -25,30 +32,40 @@ import kotlinx.coroutines.launch const val STORE_KEY_WIDGET_ENABLE_FORMATTING = "widget_enable_formatting" var sWidgetEnableFormatting: Boolean - get() = CoreConfig.instance.store().get(STORE_KEY_WIDGET_ENABLE_FORMATTING, true) - set(value) = CoreConfig.instance.store().put(STORE_KEY_WIDGET_ENABLE_FORMATTING, value) + get() = sAppPreferences.get(STORE_KEY_WIDGET_ENABLE_FORMATTING, true) + set(value) = sAppPreferences.put(STORE_KEY_WIDGET_ENABLE_FORMATTING, value) const val STORE_KEY_WIDGET_SHOW_LOCKED_NOTES = "widget_show_locked_notes" var sWidgetShowLockedNotes: Boolean - get() = CoreConfig.instance.store().get(STORE_KEY_WIDGET_SHOW_LOCKED_NOTES, false) - set(value) = CoreConfig.instance.store().put(STORE_KEY_WIDGET_SHOW_LOCKED_NOTES, value) + get() = sAppPreferences.get(STORE_KEY_WIDGET_SHOW_LOCKED_NOTES, false) + set(value) = sAppPreferences.put(STORE_KEY_WIDGET_SHOW_LOCKED_NOTES, value) const val STORE_KEY_WIDGET_SHOW_ARCHIVED_NOTES = "widget_show_archived_notes" var sWidgetShowArchivedNotes: Boolean - get() = CoreConfig.instance.store().get(STORE_KEY_WIDGET_SHOW_ARCHIVED_NOTES, true) - set(value) = CoreConfig.instance.store().put(STORE_KEY_WIDGET_SHOW_ARCHIVED_NOTES, value) + get() = sAppPreferences.get(STORE_KEY_WIDGET_SHOW_ARCHIVED_NOTES, true) + set(value) = sAppPreferences.put(STORE_KEY_WIDGET_SHOW_ARCHIVED_NOTES, value) const val STORE_KEY_WIDGET_SHOW_TRASH_NOTES = "widget_show_trash_notes" var sWidgetShowDeletedNotes: Boolean - get() = CoreConfig.instance.store().get(STORE_KEY_WIDGET_SHOW_TRASH_NOTES, false) - set(value) = CoreConfig.instance.store().put(STORE_KEY_WIDGET_SHOW_TRASH_NOTES, value) + get() = sAppPreferences.get(STORE_KEY_WIDGET_SHOW_TRASH_NOTES, false) + set(value) = sAppPreferences.put(STORE_KEY_WIDGET_SHOW_TRASH_NOTES, value) + +const val STORE_KEY_WIDGET_BACKGROUND_COLOR = "widget_background_color_v1" +var sWidgetBackgroundColor: Int + get() = sAppPreferences.get(STORE_KEY_WIDGET_BACKGROUND_COLOR, 0x65000000) + set(value) = sAppPreferences.put(STORE_KEY_WIDGET_BACKGROUND_COLOR, value) + +const val STORE_KEY_WIDGET_SHOW_TOOLBAR = "widget_show_toolbar" +var sWidgetShowToolbar: Boolean + get() = sAppPreferences.get(STORE_KEY_WIDGET_SHOW_TOOLBAR, true) + set(value) = sAppPreferences.put(STORE_KEY_WIDGET_SHOW_TOOLBAR, value) fun getWidgetNoteText(note: Note): CharSequence { if (note.locked && !sWidgetShowLockedNotes) { return "******************\n***********\n****************" } - val text = note.getFullText() + val text = note.getFullTextForDirectMarkdownRender() return when (sWidgetEnableFormatting) { true -> Markdown.render(text, true) false -> text @@ -66,7 +83,7 @@ fun getWidgetNotes(): List { val sorting = SortingOptionsBottomSheet.getSortingState() return sort(CoreConfig.notesDb.getByNoteState(state.toTypedArray()) - .filter { note -> (!note.locked || sWidgetShowLockedNotes) }, sorting) + .filter { note -> (!note.locked || sWidgetShowLockedNotes) }, sorting) } class WidgetOptionsBottomSheet : LithoOptionBottomSheet() { @@ -75,7 +92,8 @@ class WidgetOptionsBottomSheet : LithoOptionBottomSheet() { override fun getOptions(componentContext: ComponentContext, dialog: Dialog): List { val activity = context as MainActivity val options = ArrayList() - options.add(LithoOptionsItem( + options.add( + LithoOptionsItem( title = R.string.widget_option_enable_formatting, subtitle = R.string.widget_option_enable_formatting_details, icon = R.drawable.ic_markdown_logo, @@ -86,8 +104,9 @@ class WidgetOptionsBottomSheet : LithoOptionBottomSheet() { }, isSelectable = true, selected = sWidgetEnableFormatting - )) - options.add(LithoOptionsItem( + )) + options.add( + LithoOptionsItem( title = R.string.widget_option_show_locked_notes, subtitle = R.string.widget_option_show_locked_notes_details, icon = R.drawable.ic_action_lock, @@ -98,8 +117,9 @@ class WidgetOptionsBottomSheet : LithoOptionBottomSheet() { }, isSelectable = true, selected = sWidgetShowLockedNotes - )) - options.add(LithoOptionsItem( + )) + options.add( + LithoOptionsItem( title = R.string.widget_option_show_archived_notes, subtitle = R.string.widget_option_show_archived_notes_details, icon = R.drawable.ic_archive_white_48dp, @@ -110,8 +130,9 @@ class WidgetOptionsBottomSheet : LithoOptionBottomSheet() { }, isSelectable = true, selected = sWidgetShowArchivedNotes - )) - options.add(LithoOptionsItem( + )) + options.add( + LithoOptionsItem( title = R.string.widget_option_show_trash_notes, subtitle = R.string.widget_option_show_trash_notes_details, icon = R.drawable.icon_delete, @@ -122,16 +143,56 @@ class WidgetOptionsBottomSheet : LithoOptionBottomSheet() { }, isSelectable = true, selected = sWidgetShowDeletedNotes - )) + )) + options.add( + LithoOptionsItem( + title = R.string.widget_option_show_toolbar, + subtitle = R.string.widget_option_show_toolbar_details, + icon = R.drawable.ic_action_grid, + listener = { + sWidgetShowToolbar = !sWidgetShowToolbar + notifyAllNotesConfigChanged(activity) + reset(activity, dialog) + }, + isSelectable = true, + selected = sWidgetShowToolbar + )) + + val isLite = FlavorUtils.isLite() + options.add( + LithoOptionsItem( + title = R.string.widget_option_background_color, + subtitle = R.string.widget_option_background_color_details, + icon = R.drawable.ic_action_color, + listener = { + if (isLite) { + openSheet(activity, InstallProUpsellBottomSheet()) + return@LithoOptionsItem + } + + openSheet(activity, ColorPickerBottomSheet().apply { + config = ColorPickerDefaultController( + title = R.string.widget_option_background_color, + selectedColor = sWidgetBackgroundColor, + colors = listOf(intArrayOf(Color.TRANSPARENT, Color.WHITE, Color.LTGRAY, 0x65000000, Color.DKGRAY, Color.BLACK)), + onColorSelected = { + sWidgetBackgroundColor = it + notifyAllNotesConfigChanged(activity) + }, + columns = 6) + }) + }, + actionIcon = if (!isLite) 0 else R.drawable.ic_rating + )) return options } fun notifyWidgetConfigChanged(activity: MainActivity) { GlobalScope.launch { - val broadcastIntent = GlobalScope.async { + val singleNoteBroadcastIntent = GlobalScope.async { val application: Application = activity.applicationContext as Application val ids = AppWidgetManager.getInstance(application).getAppWidgetIds( - ComponentName(application, NoteWidgetProvider::class.java)) + ComponentName(application, NoteWidgetProvider::class.java)) val intent = Intent(application, NoteWidgetProvider::class.java) intent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE @@ -140,7 +201,24 @@ class WidgetOptionsBottomSheet : LithoOptionBottomSheet() { } AllNotesWidgetProvider.notifyAllChanged(activity) - activity.sendBroadcast(broadcastIntent.await()) + activity.sendBroadcast(singleNoteBroadcastIntent.await()) + } + } + + fun notifyAllNotesConfigChanged(activity: MainActivity) { + GlobalScope.launch { + val allNotesBroadcastIntent = GlobalScope.async { + val application: Application = activity.applicationContext as Application + val ids = AppWidgetManager.getInstance(application).getAppWidgetIds( + ComponentName(application, AllNotesWidgetProvider::class.java)) + + val intent = Intent(application, AllNotesWidgetProvider::class.java) + intent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE + intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids) + intent + } + + activity.sendBroadcast(allNotesBroadcastIntent.await()) } } } \ No newline at end of file diff --git a/base/src/main/res/drawable-hdpi/ic_action_enabled.png b/base/src/main/res/drawable-hdpi/ic_action_enabled.png deleted file mode 100644 index 53923459..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_action_enabled.png and /dev/null differ diff --git a/base/src/main/res/drawable-hdpi/ic_action_reminder.png b/base/src/main/res/drawable-hdpi/ic_action_reminder.png deleted file mode 100644 index bc6f1841..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_action_reminder.png and /dev/null differ diff --git a/base/src/main/res/drawable-hdpi/ic_action_search.png b/base/src/main/res/drawable-hdpi/ic_action_search.png deleted file mode 100644 index 407fb1be..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_action_search.png and /dev/null differ diff --git a/base/src/main/res/drawable-hdpi/ic_add_folder.png b/base/src/main/res/drawable-hdpi/ic_add_folder.png deleted file mode 100644 index 129a25da..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_add_folder.png and /dev/null differ diff --git a/base/src/main/res/drawable-hdpi/ic_add_search.png b/base/src/main/res/drawable-hdpi/ic_add_search.png deleted file mode 100644 index 0fb3a1cb..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_add_search.png and /dev/null differ diff --git a/base/src/main/res/drawable-hdpi/ic_add_white_48dp.png b/base/src/main/res/drawable-hdpi/ic_add_white_48dp.png deleted file mode 100644 index 0fdced8f..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_add_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-hdpi/ic_arrow_upward_white_48dp.png b/base/src/main/res/drawable-hdpi/ic_arrow_upward_white_48dp.png deleted file mode 100644 index d7b27da8..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_arrow_upward_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-hdpi/ic_border_color_white_24dp.png b/base/src/main/res/drawable-hdpi/ic_border_color_white_24dp.png deleted file mode 100644 index 79aa203d..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_border_color_white_24dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-hdpi/ic_chevron_left.png b/base/src/main/res/drawable-hdpi/ic_chevron_left.png deleted file mode 100644 index fb87e635..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_chevron_left.png and /dev/null differ diff --git a/base/src/main/res/drawable-hdpi/ic_chevron_right.png b/base/src/main/res/drawable-hdpi/ic_chevron_right.png deleted file mode 100644 index eb17f2bb..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_chevron_right.png and /dev/null differ diff --git a/base/src/main/res/drawable-hdpi/ic_drag_handle_white_48dp.png b/base/src/main/res/drawable-hdpi/ic_drag_handle_white_48dp.png deleted file mode 100644 index e91ef07e..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_drag_handle_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-hdpi/ic_fiber_smart_record_white_24dp.png b/base/src/main/res/drawable-hdpi/ic_fiber_smart_record_white_24dp.png deleted file mode 100644 index 8506b36a..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_fiber_smart_record_white_24dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-hdpi/ic_fiber_smart_record_white_48dp.png b/base/src/main/res/drawable-hdpi/ic_fiber_smart_record_white_48dp.png deleted file mode 100644 index 5466fe63..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_fiber_smart_record_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-hdpi/ic_format_list_numbered_white_48dp.png b/base/src/main/res/drawable-hdpi/ic_format_list_numbered_white_48dp.png deleted file mode 100644 index acd1249f..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_format_list_numbered_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-hdpi/ic_keyboard_arrow_down_white_48dp.png b/base/src/main/res/drawable-hdpi/ic_keyboard_arrow_down_white_48dp.png deleted file mode 100644 index f9622b7b..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_keyboard_arrow_down_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-hdpi/ic_keyboard_arrow_up_white_48dp.png b/base/src/main/res/drawable-hdpi/ic_keyboard_arrow_up_white_48dp.png deleted file mode 100644 index ce4aa560..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_keyboard_arrow_up_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-hdpi/ic_more_vert_white_48dp.png b/base/src/main/res/drawable-hdpi/ic_more_vert_white_48dp.png deleted file mode 100644 index d3228130..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_more_vert_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-hdpi/ic_playlist_add_check_white_48dp.png b/base/src/main/res/drawable-hdpi/ic_playlist_add_check_white_48dp.png deleted file mode 100644 index 29008871..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_playlist_add_check_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-hdpi/ic_refresh.png b/base/src/main/res/drawable-hdpi/ic_refresh.png deleted file mode 100644 index d0355836..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_refresh.png and /dev/null differ diff --git a/base/src/main/res/drawable-hdpi/ic_reorder_white_48dp.png b/base/src/main/res/drawable-hdpi/ic_reorder_white_48dp.png deleted file mode 100644 index a0d2543f..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_reorder_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-hdpi/ic_settings_white_48dp.png b/base/src/main/res/drawable-hdpi/ic_settings_white_48dp.png deleted file mode 100644 index eabb0a2b..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_settings_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-hdpi/ic_text_fields_white_48dp.png b/base/src/main/res/drawable-hdpi/ic_text_fields_white_48dp.png deleted file mode 100644 index 2d76a1da..00000000 Binary files a/base/src/main/res/drawable-hdpi/ic_text_fields_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_action_enabled.png b/base/src/main/res/drawable-mdpi/ic_action_enabled.png deleted file mode 100644 index d5b3406a..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_action_enabled.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_action_reminder.png b/base/src/main/res/drawable-mdpi/ic_action_reminder.png deleted file mode 100644 index 95e7cf87..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_action_reminder.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_action_search.png b/base/src/main/res/drawable-mdpi/ic_action_search.png deleted file mode 100644 index 55c36f9c..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_action_search.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_add_folder.png b/base/src/main/res/drawable-mdpi/ic_add_folder.png deleted file mode 100644 index 7cd7a48c..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_add_folder.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_add_search.png b/base/src/main/res/drawable-mdpi/ic_add_search.png deleted file mode 100644 index 386397d3..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_add_search.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_add_white_48dp.png b/base/src/main/res/drawable-mdpi/ic_add_white_48dp.png deleted file mode 100644 index 67bb598e..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_add_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_arrow_upward_white_48dp.png b/base/src/main/res/drawable-mdpi/ic_arrow_upward_white_48dp.png deleted file mode 100644 index edd9b1dd..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_arrow_upward_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_border_color_white_24dp.png b/base/src/main/res/drawable-mdpi/ic_border_color_white_24dp.png deleted file mode 100644 index 2840abb8..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_border_color_white_24dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_chevron_left.png b/base/src/main/res/drawable-mdpi/ic_chevron_left.png deleted file mode 100644 index e301accb..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_chevron_left.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_chevron_right.png b/base/src/main/res/drawable-mdpi/ic_chevron_right.png deleted file mode 100644 index 9bf60655..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_chevron_right.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_drag_handle_white_48dp.png b/base/src/main/res/drawable-mdpi/ic_drag_handle_white_48dp.png deleted file mode 100644 index aa1547b0..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_drag_handle_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_fiber_smart_record_white_24dp.png b/base/src/main/res/drawable-mdpi/ic_fiber_smart_record_white_24dp.png deleted file mode 100644 index 7d5473cf..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_fiber_smart_record_white_24dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_fiber_smart_record_white_48dp.png b/base/src/main/res/drawable-mdpi/ic_fiber_smart_record_white_48dp.png deleted file mode 100644 index ba3256d8..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_fiber_smart_record_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_format_list_numbered_white_48dp.png b/base/src/main/res/drawable-mdpi/ic_format_list_numbered_white_48dp.png deleted file mode 100644 index fcb7575e..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_format_list_numbered_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_keyboard_arrow_down_white_48dp.png b/base/src/main/res/drawable-mdpi/ic_keyboard_arrow_down_white_48dp.png deleted file mode 100644 index 058cebb7..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_keyboard_arrow_down_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_keyboard_arrow_up_white_48dp.png b/base/src/main/res/drawable-mdpi/ic_keyboard_arrow_up_white_48dp.png deleted file mode 100644 index ae36d91e..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_keyboard_arrow_up_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_more_vert_white_48dp.png b/base/src/main/res/drawable-mdpi/ic_more_vert_white_48dp.png deleted file mode 100644 index efab8a74..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_more_vert_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_playlist_add_check_white_48dp.png b/base/src/main/res/drawable-mdpi/ic_playlist_add_check_white_48dp.png deleted file mode 100644 index a94c5d03..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_playlist_add_check_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_refresh.png b/base/src/main/res/drawable-mdpi/ic_refresh.png deleted file mode 100644 index 32022dc9..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_refresh.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_reorder_white_48dp.png b/base/src/main/res/drawable-mdpi/ic_reorder_white_48dp.png deleted file mode 100644 index 6b4c5286..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_reorder_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_settings_white_48dp.png b/base/src/main/res/drawable-mdpi/ic_settings_white_48dp.png deleted file mode 100644 index 5caedc8e..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_settings_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-mdpi/ic_text_fields_white_48dp.png b/base/src/main/res/drawable-mdpi/ic_text_fields_white_48dp.png deleted file mode 100644 index 612d1438..00000000 Binary files a/base/src/main/res/drawable-mdpi/ic_text_fields_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_action_enabled.png b/base/src/main/res/drawable-xhdpi/ic_action_enabled.png deleted file mode 100644 index f88c7828..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_action_enabled.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_action_reminder.png b/base/src/main/res/drawable-xhdpi/ic_action_reminder.png deleted file mode 100644 index 43d354be..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_action_reminder.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_action_search.png b/base/src/main/res/drawable-xhdpi/ic_action_search.png deleted file mode 100644 index 2d270ff6..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_action_search.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_add_folder.png b/base/src/main/res/drawable-xhdpi/ic_add_folder.png deleted file mode 100644 index bc0edf68..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_add_folder.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_add_search.png b/base/src/main/res/drawable-xhdpi/ic_add_search.png deleted file mode 100644 index 0484d65f..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_add_search.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_add_white_48dp.png b/base/src/main/res/drawable-xhdpi/ic_add_white_48dp.png deleted file mode 100644 index d64c22e9..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_add_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_arrow_upward_white_48dp.png b/base/src/main/res/drawable-xhdpi/ic_arrow_upward_white_48dp.png deleted file mode 100644 index 8ac0552c..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_arrow_upward_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_border_color_white_24dp.png b/base/src/main/res/drawable-xhdpi/ic_border_color_white_24dp.png deleted file mode 100644 index de9e5093..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_border_color_white_24dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_chevron_left.png b/base/src/main/res/drawable-xhdpi/ic_chevron_left.png deleted file mode 100644 index 764df638..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_chevron_left.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_chevron_right.png b/base/src/main/res/drawable-xhdpi/ic_chevron_right.png deleted file mode 100644 index d752e034..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_chevron_right.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_drag_handle_white_48dp.png b/base/src/main/res/drawable-xhdpi/ic_drag_handle_white_48dp.png deleted file mode 100644 index 12269073..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_drag_handle_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_fiber_smart_record_white_24dp.png b/base/src/main/res/drawable-xhdpi/ic_fiber_smart_record_white_24dp.png deleted file mode 100644 index ba3256d8..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_fiber_smart_record_white_24dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_fiber_smart_record_white_48dp.png b/base/src/main/res/drawable-xhdpi/ic_fiber_smart_record_white_48dp.png deleted file mode 100644 index 9f2861fb..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_fiber_smart_record_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_format_list_numbered_white_48dp.png b/base/src/main/res/drawable-xhdpi/ic_format_list_numbered_white_48dp.png deleted file mode 100644 index e4a79b2c..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_format_list_numbered_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_keyboard_arrow_down_white_48dp.png b/base/src/main/res/drawable-xhdpi/ic_keyboard_arrow_down_white_48dp.png deleted file mode 100644 index 30948d98..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_keyboard_arrow_down_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_keyboard_arrow_up_white_48dp.png b/base/src/main/res/drawable-xhdpi/ic_keyboard_arrow_up_white_48dp.png deleted file mode 100644 index 42615516..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_keyboard_arrow_up_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_more_vert_white_48dp.png b/base/src/main/res/drawable-xhdpi/ic_more_vert_white_48dp.png deleted file mode 100644 index 2f2cb3d0..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_more_vert_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_playlist_add_check_white_48dp.png b/base/src/main/res/drawable-xhdpi/ic_playlist_add_check_white_48dp.png deleted file mode 100644 index 767d066d..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_playlist_add_check_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_refresh.png b/base/src/main/res/drawable-xhdpi/ic_refresh.png deleted file mode 100644 index 01376be9..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_refresh.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_reorder_white_48dp.png b/base/src/main/res/drawable-xhdpi/ic_reorder_white_48dp.png deleted file mode 100644 index bc4fde51..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_reorder_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_settings_white_48dp.png b/base/src/main/res/drawable-xhdpi/ic_settings_white_48dp.png deleted file mode 100644 index 507c5edd..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_settings_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xhdpi/ic_text_fields_white_48dp.png b/base/src/main/res/drawable-xhdpi/ic_text_fields_white_48dp.png deleted file mode 100644 index f4e597a8..00000000 Binary files a/base/src/main/res/drawable-xhdpi/ic_text_fields_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_action_enabled.png b/base/src/main/res/drawable-xxhdpi/ic_action_enabled.png deleted file mode 100644 index 7cbf796e..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_action_enabled.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_action_reminder.png b/base/src/main/res/drawable-xxhdpi/ic_action_reminder.png deleted file mode 100644 index 69cf883f..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_action_reminder.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_action_search.png b/base/src/main/res/drawable-xxhdpi/ic_action_search.png deleted file mode 100644 index d0d4d59e..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_action_search.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_add_folder.png b/base/src/main/res/drawable-xxhdpi/ic_add_folder.png deleted file mode 100644 index fa9fe1de..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_add_folder.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_add_search.png b/base/src/main/res/drawable-xxhdpi/ic_add_search.png deleted file mode 100644 index 88ece0fd..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_add_search.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_add_white_48dp.png b/base/src/main/res/drawable-xxhdpi/ic_add_white_48dp.png deleted file mode 100644 index 7e699137..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_add_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_arrow_upward_white_48dp.png b/base/src/main/res/drawable-xxhdpi/ic_arrow_upward_white_48dp.png deleted file mode 100644 index 5e61c3d1..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_arrow_upward_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_border_color_white_24dp.png b/base/src/main/res/drawable-xxhdpi/ic_border_color_white_24dp.png deleted file mode 100644 index 43bd9729..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_border_color_white_24dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_chevron_left.png b/base/src/main/res/drawable-xxhdpi/ic_chevron_left.png deleted file mode 100644 index e5f8c0db..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_chevron_left.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_chevron_right.png b/base/src/main/res/drawable-xxhdpi/ic_chevron_right.png deleted file mode 100644 index 0e7016e1..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_chevron_right.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_drag_handle_white_48dp.png b/base/src/main/res/drawable-xxhdpi/ic_drag_handle_white_48dp.png deleted file mode 100644 index dafaeeca..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_drag_handle_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_fiber_smart_record_white_24dp.png b/base/src/main/res/drawable-xxhdpi/ic_fiber_smart_record_white_24dp.png deleted file mode 100644 index 5466fe63..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_fiber_smart_record_white_24dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_fiber_smart_record_white_48dp.png b/base/src/main/res/drawable-xxhdpi/ic_fiber_smart_record_white_48dp.png deleted file mode 100644 index 18b04c0a..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_fiber_smart_record_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_format_list_numbered_white_48dp.png b/base/src/main/res/drawable-xxhdpi/ic_format_list_numbered_white_48dp.png deleted file mode 100644 index ddddeda0..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_format_list_numbered_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_keyboard_arrow_down_white_48dp.png b/base/src/main/res/drawable-xxhdpi/ic_keyboard_arrow_down_white_48dp.png deleted file mode 100644 index 18e31e94..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_keyboard_arrow_down_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_keyboard_arrow_up_white_48dp.png b/base/src/main/res/drawable-xxhdpi/ic_keyboard_arrow_up_white_48dp.png deleted file mode 100644 index 62467ced..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_keyboard_arrow_up_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_more_vert_white_48dp.png b/base/src/main/res/drawable-xxhdpi/ic_more_vert_white_48dp.png deleted file mode 100644 index b37b96fe..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_more_vert_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_playlist_add_check_white_48dp.png b/base/src/main/res/drawable-xxhdpi/ic_playlist_add_check_white_48dp.png deleted file mode 100644 index 04f7aa76..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_playlist_add_check_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_refresh.png b/base/src/main/res/drawable-xxhdpi/ic_refresh.png deleted file mode 100644 index ae805a5c..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_refresh.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_reorder_white_48dp.png b/base/src/main/res/drawable-xxhdpi/ic_reorder_white_48dp.png deleted file mode 100644 index 86241027..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_reorder_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_settings_white_48dp.png b/base/src/main/res/drawable-xxhdpi/ic_settings_white_48dp.png deleted file mode 100644 index 55492f6c..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_settings_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxhdpi/ic_text_fields_white_48dp.png b/base/src/main/res/drawable-xxhdpi/ic_text_fields_white_48dp.png deleted file mode 100644 index ba38086a..00000000 Binary files a/base/src/main/res/drawable-xxhdpi/ic_text_fields_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxxhdpi/ic_add_white_48dp.png b/base/src/main/res/drawable-xxxhdpi/ic_add_white_48dp.png deleted file mode 100644 index 165c907d..00000000 Binary files a/base/src/main/res/drawable-xxxhdpi/ic_add_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxxhdpi/ic_arrow_upward_white_48dp.png b/base/src/main/res/drawable-xxxhdpi/ic_arrow_upward_white_48dp.png deleted file mode 100644 index 3e23887a..00000000 Binary files a/base/src/main/res/drawable-xxxhdpi/ic_arrow_upward_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxxhdpi/ic_border_color_white_24dp.png b/base/src/main/res/drawable-xxxhdpi/ic_border_color_white_24dp.png deleted file mode 100644 index dd541e33..00000000 Binary files a/base/src/main/res/drawable-xxxhdpi/ic_border_color_white_24dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxxhdpi/ic_drag_handle_white_48dp.png b/base/src/main/res/drawable-xxxhdpi/ic_drag_handle_white_48dp.png deleted file mode 100644 index 84164aaf..00000000 Binary files a/base/src/main/res/drawable-xxxhdpi/ic_drag_handle_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxxhdpi/ic_fiber_smart_record_white_24dp.png b/base/src/main/res/drawable-xxxhdpi/ic_fiber_smart_record_white_24dp.png deleted file mode 100644 index 9f2861fb..00000000 Binary files a/base/src/main/res/drawable-xxxhdpi/ic_fiber_smart_record_white_24dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxxhdpi/ic_fiber_smart_record_white_48dp.png b/base/src/main/res/drawable-xxxhdpi/ic_fiber_smart_record_white_48dp.png deleted file mode 100644 index c08b3ca4..00000000 Binary files a/base/src/main/res/drawable-xxxhdpi/ic_fiber_smart_record_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxxhdpi/ic_format_list_numbered_white_48dp.png b/base/src/main/res/drawable-xxxhdpi/ic_format_list_numbered_white_48dp.png deleted file mode 100644 index 5eb047e8..00000000 Binary files a/base/src/main/res/drawable-xxxhdpi/ic_format_list_numbered_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxxhdpi/ic_keyboard_arrow_down_white_48dp.png b/base/src/main/res/drawable-xxxhdpi/ic_keyboard_arrow_down_white_48dp.png deleted file mode 100644 index 6cd2a11e..00000000 Binary files a/base/src/main/res/drawable-xxxhdpi/ic_keyboard_arrow_down_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxxhdpi/ic_keyboard_arrow_up_white_48dp.png b/base/src/main/res/drawable-xxxhdpi/ic_keyboard_arrow_up_white_48dp.png deleted file mode 100644 index 5cd5f669..00000000 Binary files a/base/src/main/res/drawable-xxxhdpi/ic_keyboard_arrow_up_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxxhdpi/ic_more_vert_white_48dp.png b/base/src/main/res/drawable-xxxhdpi/ic_more_vert_white_48dp.png deleted file mode 100644 index df34cfd4..00000000 Binary files a/base/src/main/res/drawable-xxxhdpi/ic_more_vert_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxxhdpi/ic_playlist_add_check_white_48dp.png b/base/src/main/res/drawable-xxxhdpi/ic_playlist_add_check_white_48dp.png deleted file mode 100644 index acf7865e..00000000 Binary files a/base/src/main/res/drawable-xxxhdpi/ic_playlist_add_check_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxxhdpi/ic_reorder_white_48dp.png b/base/src/main/res/drawable-xxxhdpi/ic_reorder_white_48dp.png deleted file mode 100644 index 11edfa31..00000000 Binary files a/base/src/main/res/drawable-xxxhdpi/ic_reorder_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxxhdpi/ic_settings_white_48dp.png b/base/src/main/res/drawable-xxxhdpi/ic_settings_white_48dp.png deleted file mode 100644 index 9e242e77..00000000 Binary files a/base/src/main/res/drawable-xxxhdpi/ic_settings_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable-xxxhdpi/ic_text_fields_white_48dp.png b/base/src/main/res/drawable-xxxhdpi/ic_text_fields_white_48dp.png deleted file mode 100644 index 97965997..00000000 Binary files a/base/src/main/res/drawable-xxxhdpi/ic_text_fields_white_48dp.png and /dev/null differ diff --git a/base/src/main/res/drawable/bullet_1.png b/base/src/main/res/drawable/bullet_1.png deleted file mode 100644 index 0d989f9e..00000000 Binary files a/base/src/main/res/drawable/bullet_1.png and /dev/null differ diff --git a/base/src/main/res/drawable/bullet_2.png b/base/src/main/res/drawable/bullet_2.png deleted file mode 100644 index 558fa6cd..00000000 Binary files a/base/src/main/res/drawable/bullet_2.png and /dev/null differ diff --git a/base/src/main/res/drawable/bullet_3.png b/base/src/main/res/drawable/bullet_3.png deleted file mode 100644 index f9331e90..00000000 Binary files a/base/src/main/res/drawable/bullet_3.png and /dev/null differ diff --git a/base/src/main/res/drawable/gdrive_icon.png b/base/src/main/res/drawable/gdrive_icon.png new file mode 100644 index 00000000..d0ea1e50 Binary files /dev/null and b/base/src/main/res/drawable/gdrive_icon.png differ diff --git a/base/src/main/res/drawable/get_started_background.xml b/base/src/main/res/drawable/get_started_background.xml deleted file mode 100644 index 0e0311f4..00000000 --- a/base/src/main/res/drawable/get_started_background.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - diff --git a/base/src/main/res/drawable/ic_scarlet_logo.png b/base/src/main/res/drawable/ic_scarlet_logo.png deleted file mode 100644 index c2010875..00000000 Binary files a/base/src/main/res/drawable/ic_scarlet_logo.png and /dev/null differ diff --git a/base/src/main/res/drawable/icon_bullet_1.png b/base/src/main/res/drawable/icon_bullet_1.png new file mode 100644 index 00000000..3b47c15c Binary files /dev/null and b/base/src/main/res/drawable/icon_bullet_1.png differ diff --git a/base/src/main/res/drawable/icon_bullet_2.png b/base/src/main/res/drawable/icon_bullet_2.png new file mode 100644 index 00000000..9f1c87e5 Binary files /dev/null and b/base/src/main/res/drawable/icon_bullet_2.png differ diff --git a/base/src/main/res/drawable/icon_bullet_3.png b/base/src/main/res/drawable/icon_bullet_3.png new file mode 100644 index 00000000..00313445 Binary files /dev/null and b/base/src/main/res/drawable/icon_bullet_3.png differ diff --git a/base/src/main/res/drawable/icon_delete_content.png b/base/src/main/res/drawable/icon_delete_content.png new file mode 100644 index 00000000..ad9a87db Binary files /dev/null and b/base/src/main/res/drawable/icon_delete_content.png differ diff --git a/base/src/main/res/drawable/icon_help.png b/base/src/main/res/drawable/icon_help.png new file mode 100644 index 00000000..b6cb9b23 Binary files /dev/null and b/base/src/main/res/drawable/icon_help.png differ diff --git a/base/src/main/res/drawable/icon_languages.png b/base/src/main/res/drawable/icon_languages.png new file mode 100644 index 00000000..f825ccad Binary files /dev/null and b/base/src/main/res/drawable/icon_languages.png differ diff --git a/base/src/main/res/drawable/icon_no_color.png b/base/src/main/res/drawable/icon_no_color.png new file mode 100644 index 00000000..39345156 Binary files /dev/null and b/base/src/main/res/drawable/icon_no_color.png differ diff --git a/base/src/main/res/drawable/icon_share_image.png b/base/src/main/res/drawable/icon_share_image.png new file mode 100644 index 00000000..69acba26 Binary files /dev/null and b/base/src/main/res/drawable/icon_share_image.png differ diff --git a/base/src/main/res/drawable/icon_shortcut.png b/base/src/main/res/drawable/icon_shortcut.png new file mode 100644 index 00000000..5753ef16 Binary files /dev/null and b/base/src/main/res/drawable/icon_shortcut.png differ diff --git a/base/src/main/res/drawable/icon_sync_disabled.png b/base/src/main/res/drawable/icon_sync_disabled.png new file mode 100644 index 00000000..915d999e Binary files /dev/null and b/base/src/main/res/drawable/icon_sync_disabled.png differ diff --git a/base/src/main/res/drawable/icon_typeface.png b/base/src/main/res/drawable/icon_typeface.png new file mode 100644 index 00000000..0bf19d5a Binary files /dev/null and b/base/src/main/res/drawable/icon_typeface.png differ diff --git a/base/src/main/res/drawable/image_placeholder.jpg b/base/src/main/res/drawable/image_placeholder.jpg deleted file mode 100644 index 5dae74b2..00000000 Binary files a/base/src/main/res/drawable/image_placeholder.jpg and /dev/null differ diff --git a/base/src/main/res/drawable/install_pro_background.xml b/base/src/main/res/drawable/install_pro_background.xml deleted file mode 100644 index 9146e154..00000000 --- a/base/src/main/res/drawable/install_pro_background.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - diff --git a/base/src/main/res/drawable/light_secondary_rounded_bg.xml b/base/src/main/res/drawable/light_secondary_rounded_bg.xml new file mode 100644 index 00000000..1d0f36e7 --- /dev/null +++ b/base/src/main/res/drawable/light_secondary_rounded_bg.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/base/src/main/res/drawable/login_button_active.xml b/base/src/main/res/drawable/login_button_active.xml index 9faa8c0d..b595d339 100644 --- a/base/src/main/res/drawable/login_button_active.xml +++ b/base/src/main/res/drawable/login_button_active.xml @@ -6,7 +6,7 @@ android:shape="rectangle" > - + diff --git a/base/src/main/res/drawable/login_button_disabled.xml b/base/src/main/res/drawable/login_button_disabled.xml index 8c904c9a..553e2314 100644 --- a/base/src/main/res/drawable/login_button_disabled.xml +++ b/base/src/main/res/drawable/login_button_disabled.xml @@ -5,11 +5,11 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > - - + + + android:color="@color/material_grey_800"/> diff --git a/base/src/main/res/drawable/pending_note_background.xml b/base/src/main/res/drawable/pending_note_background.xml new file mode 100644 index 00000000..6f09de78 --- /dev/null +++ b/base/src/main/res/drawable/pending_note_background.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/base/src/main/res/drawable/pending_sync_capsule.xml b/base/src/main/res/drawable/pending_sync_capsule.xml new file mode 100644 index 00000000..3e84cd03 --- /dev/null +++ b/base/src/main/res/drawable/pending_sync_capsule.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/base/src/main/res/drawable/quote_end.png b/base/src/main/res/drawable/quote_end.png deleted file mode 100644 index dc8d7405..00000000 Binary files a/base/src/main/res/drawable/quote_end.png and /dev/null differ diff --git a/base/src/main/res/drawable/quote_start.png b/base/src/main/res/drawable/quote_start.png deleted file mode 100644 index 2de49cef..00000000 Binary files a/base/src/main/res/drawable/quote_start.png and /dev/null differ diff --git a/base/src/main/res/drawable/secondary_rounded_bg.xml b/base/src/main/res/drawable/secondary_rounded_bg.xml new file mode 100644 index 00000000..91b91dc6 --- /dev/null +++ b/base/src/main/res/drawable/secondary_rounded_bg.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/base/src/main/res/font/mono_bold.ttf b/base/src/main/res/font/mono_bold.ttf new file mode 100644 index 00000000..482f028a Binary files /dev/null and b/base/src/main/res/font/mono_bold.ttf differ diff --git a/base/src/main/res/font/mono_bold_xml.xml b/base/src/main/res/font/mono_bold_xml.xml new file mode 100644 index 00000000..7758021d --- /dev/null +++ b/base/src/main/res/font/mono_bold_xml.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/base/src/main/res/font/mono_medium.ttf b/base/src/main/res/font/mono_medium.ttf new file mode 100644 index 00000000..c496725e Binary files /dev/null and b/base/src/main/res/font/mono_medium.ttf differ diff --git a/base/src/main/res/font/mono_medium_xml.xml b/base/src/main/res/font/mono_medium_xml.xml new file mode 100644 index 00000000..73d536be --- /dev/null +++ b/base/src/main/res/font/mono_medium_xml.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/base/src/main/res/font/mono_regular.ttf b/base/src/main/res/font/mono_regular.ttf new file mode 100644 index 00000000..5919b5d1 Binary files /dev/null and b/base/src/main/res/font/mono_regular.ttf differ diff --git a/base/src/main/res/font/mono_regular_xml.xml b/base/src/main/res/font/mono_regular_xml.xml new file mode 100644 index 00000000..4eb647d8 --- /dev/null +++ b/base/src/main/res/font/mono_regular_xml.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/base/src/main/res/font/monserrat_bold.xml b/base/src/main/res/font/monserrat_bold.xml new file mode 100644 index 00000000..4c3dbb84 --- /dev/null +++ b/base/src/main/res/font/monserrat_bold.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/base/src/main/res/font/monserrat_medium.xml b/base/src/main/res/font/monserrat_medium.xml new file mode 100644 index 00000000..151838c5 --- /dev/null +++ b/base/src/main/res/font/monserrat_medium.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/base/src/main/res/font/montserrat_extrabold.ttf b/base/src/main/res/font/montserrat_extrabold.ttf new file mode 100644 index 00000000..6725d537 Binary files /dev/null and b/base/src/main/res/font/montserrat_extrabold.ttf differ diff --git a/base/src/main/res/font/montserrat_medium.ttf b/base/src/main/res/font/montserrat_medium.ttf new file mode 100644 index 00000000..db5b1af8 Binary files /dev/null and b/base/src/main/res/font/montserrat_medium.ttf differ diff --git a/base/src/main/res/font/serif_bold.ttf b/base/src/main/res/font/serif_bold.ttf new file mode 100644 index 00000000..2726b0a0 Binary files /dev/null and b/base/src/main/res/font/serif_bold.ttf differ diff --git a/base/src/main/res/font/serif_bold_xml.xml b/base/src/main/res/font/serif_bold_xml.xml new file mode 100644 index 00000000..0e821b07 --- /dev/null +++ b/base/src/main/res/font/serif_bold_xml.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/base/src/main/res/font/serif_regular.ttf b/base/src/main/res/font/serif_regular.ttf new file mode 100644 index 00000000..0e875241 Binary files /dev/null and b/base/src/main/res/font/serif_regular.ttf differ diff --git a/base/src/main/res/font/serif_regular_xml.xml b/base/src/main/res/font/serif_regular_xml.xml new file mode 100644 index 00000000..cd65d570 --- /dev/null +++ b/base/src/main/res/font/serif_regular_xml.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/base/src/main/res/layout/activity_advanced_note.xml b/base/src/main/res/layout/activity_advanced_note.xml index 28503825..4eb6ca7d 100644 --- a/base/src/main/res/layout/activity_advanced_note.xml +++ b/base/src/main/res/layout/activity_advanced_note.xml @@ -16,7 +16,7 @@ android:layout_height="0dp" android:layout_weight="1"> - diff --git a/base/src/main/res/layout/activity_import_note_from_file.xml b/base/src/main/res/layout/activity_import_note_from_file.xml index 66ba5372..92b2b3da 100644 --- a/base/src/main/res/layout/activity_import_note_from_file.xml +++ b/base/src/main/res/layout/activity_import_note_from_file.xml @@ -47,7 +47,7 @@ android:layout_gravity="center" android:indeterminate="true" /> - - @@ -20,11 +20,17 @@ android:layout_marginBottom="@dimen/spacing_xxsmall" android:visibility="gone" /> - + android:layout_weight="1"> + + + + + - + diff --git a/base/src/main/res/layout/activity_select_note.xml b/base/src/main/res/layout/activity_select_note.xml index a8b89994..06a4b57f 100644 --- a/base/src/main/res/layout/activity_select_note.xml +++ b/base/src/main/res/layout/activity_select_note.xml @@ -33,7 +33,7 @@ android:textSize="@dimen/font_size_large" /> - - - - - - + diff --git a/base/src/main/res/layout/bottom_sheet_create_folder.xml b/base/src/main/res/layout/bottom_sheet_create_folder.xml index 32e09b15..f68ed745 100644 --- a/base/src/main/res/layout/bottom_sheet_create_folder.xml +++ b/base/src/main/res/layout/bottom_sheet_create_folder.xml @@ -1,5 +1,5 @@ - - @@ -46,9 +46,9 @@ android:textSize="24sp" /> - + - @@ -61,9 +61,9 @@ ui:alignItems="stretch" ui:flexWrap="wrap" ui:justifyContent="center" /> - + - @@ -98,6 +98,6 @@ - + - \ No newline at end of file + \ No newline at end of file diff --git a/base/src/main/res/layout/bottom_sheet_create_or_edit_tag.xml b/base/src/main/res/layout/bottom_sheet_create_or_edit_tag.xml index 647c4332..c1a1be87 100644 --- a/base/src/main/res/layout/bottom_sheet_create_or_edit_tag.xml +++ b/base/src/main/res/layout/bottom_sheet_create_or_edit_tag.xml @@ -1,5 +1,5 @@ - - @@ -46,9 +46,9 @@ android:textSize="24sp" /> - + - @@ -83,6 +83,6 @@ - + - \ No newline at end of file + \ No newline at end of file diff --git a/base/src/main/res/layout/bottom_sheet_grid_layout.xml b/base/src/main/res/layout/bottom_sheet_grid_layout.xml index 3f4b56d3..50f4f493 100644 --- a/base/src/main/res/layout/bottom_sheet_grid_layout.xml +++ b/base/src/main/res/layout/bottom_sheet_grid_layout.xml @@ -1,11 +1,11 @@ - - @@ -37,5 +37,5 @@ - - \ No newline at end of file + + \ No newline at end of file diff --git a/base/src/main/res/layout/bottom_sheet_home_navigation.xml b/base/src/main/res/layout/bottom_sheet_home_navigation.xml deleted file mode 100644 index 4bf6fb3a..00000000 --- a/base/src/main/res/layout/bottom_sheet_home_navigation.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/base/src/main/res/layout/bottom_sheet_note_options.xml b/base/src/main/res/layout/bottom_sheet_note_options.xml index 256053f9..169255f4 100644 --- a/base/src/main/res/layout/bottom_sheet_note_options.xml +++ b/base/src/main/res/layout/bottom_sheet_note_options.xml @@ -1,5 +1,5 @@ - + android:orientation="vertical"> - @@ -33,66 +33,125 @@ android:padding="@dimen/spacing_small"> - + - + - - - - - - - + + - - + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + @@ -100,53 +159,9 @@ android:id="@+id/note_properties" style="@style/NoteOptionGridLayout" android:padding="@dimen/spacing_small" /> - + - - - - - - - - - - - - - - @@ -165,6 +180,6 @@ - + - \ No newline at end of file + \ No newline at end of file diff --git a/base/src/main/res/layout/bottom_sheet_options.xml b/base/src/main/res/layout/bottom_sheet_options.xml deleted file mode 100644 index 96ce478f..00000000 --- a/base/src/main/res/layout/bottom_sheet_options.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/base/src/main/res/layout/bottom_sheet_pin_code.xml b/base/src/main/res/layout/bottom_sheet_pin_code.xml deleted file mode 100644 index f1e05a48..00000000 --- a/base/src/main/res/layout/bottom_sheet_pin_code.xml +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/base/src/main/res/layout/bottom_sheet_reminder.xml b/base/src/main/res/layout/bottom_sheet_reminder.xml index 057905ad..8398d6d3 100644 --- a/base/src/main/res/layout/bottom_sheet_reminder.xml +++ b/base/src/main/res/layout/bottom_sheet_reminder.xml @@ -1,5 +1,5 @@ - - @@ -84,9 +84,9 @@ app:titleSize="@dimen/font_size_xsmall" /> - + - @@ -125,6 +125,6 @@ android:textSize="@dimen/font_size_small" /> - + - \ No newline at end of file + \ No newline at end of file diff --git a/base/src/main/res/layout/bottom_sheet_speak_note.xml b/base/src/main/res/layout/bottom_sheet_speak_note.xml index a6f24af1..2ce176f0 100644 --- a/base/src/main/res/layout/bottom_sheet_speak_note.xml +++ b/base/src/main/res/layout/bottom_sheet_speak_note.xml @@ -1,11 +1,11 @@ - - @@ -37,5 +37,5 @@ android:tint="@color/dark_tertiary_text" /> - - \ No newline at end of file + + \ No newline at end of file diff --git a/base/src/main/res/layout/bottom_sheet_tag_options.xml b/base/src/main/res/layout/bottom_sheet_tag_options.xml deleted file mode 100644 index bc7dac9e..00000000 --- a/base/src/main/res/layout/bottom_sheet_tag_options.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/base/src/main/res/layout/item_folder.xml b/base/src/main/res/layout/item_folder.xml index e30b1c6c..30e2083a 100644 --- a/base/src/main/res/layout/item_folder.xml +++ b/base/src/main/res/layout/item_folder.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/base/src/main/res/layout/item_format_bullet.xml b/base/src/main/res/layout/item_format_bullet.xml new file mode 100644 index 00000000..6497cf43 --- /dev/null +++ b/base/src/main/res/layout/item_format_bullet.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/base/src/main/res/layout/item_format_code.xml b/base/src/main/res/layout/item_format_code.xml index d178b6f1..8add1520 100644 --- a/base/src/main/res/layout/item_format_code.xml +++ b/base/src/main/res/layout/item_format_code.xml @@ -7,18 +7,14 @@ \ No newline at end of file diff --git a/base/src/main/res/layout/item_format_heading.xml b/base/src/main/res/layout/item_format_heading.xml index 4556138e..d4336d4a 100644 --- a/base/src/main/res/layout/item_format_heading.xml +++ b/base/src/main/res/layout/item_format_heading.xml @@ -7,14 +7,10 @@ \ No newline at end of file diff --git a/base/src/main/res/layout/item_format_list.xml b/base/src/main/res/layout/item_format_list.xml index b56983e3..eb2b1c65 100644 --- a/base/src/main/res/layout/item_format_list.xml +++ b/base/src/main/res/layout/item_format_list.xml @@ -8,8 +8,8 @@ android:id="@+id/icon" android:layout_width="@dimen/icon_size_normal" android:layout_height="@dimen/icon_size_normal" - android:layout_marginStart="@dimen/spacing_large" android:layout_gravity="center_vertical" + android:layout_marginStart="@dimen/spacing_large" android:src="@drawable/ic_check_box_outline_blank_white_24dp" android:tint="@color/material_blue_grey_500" /> @@ -17,11 +17,21 @@ android:id="@+id/text" style="@style/FormatEdit" android:autoLink="web" - android:hint="@string/format_hint_list" android:linksClickable="true" /> + style="@style/FormatText" /> + + + \ No newline at end of file diff --git a/base/src/main/res/layout/item_format_quote.xml b/base/src/main/res/layout/item_format_quote.xml index df54c4f0..60575e67 100644 --- a/base/src/main/res/layout/item_format_quote.xml +++ b/base/src/main/res/layout/item_format_quote.xml @@ -17,7 +17,6 @@ android:id="@+id/text" style="@style/FormatText" android:autoLink="web" - android:hint="@string/format_hint_quote" android:linksClickable="true" android:paddingStart="@dimen/spacing_xxsmall" android:paddingBottom="@dimen/spacing_small" @@ -26,7 +25,6 @@ \ No newline at end of file diff --git a/base/src/main/res/layout/item_format_tag.xml b/base/src/main/res/layout/item_format_tag.xml index 02add132..464cd86c 100644 --- a/base/src/main/res/layout/item_format_tag.xml +++ b/base/src/main/res/layout/item_format_tag.xml @@ -9,13 +9,11 @@ android:id="@+id/text" style="@style/FormatText" android:autoLink="web" - android:hint="@string/format_hint_text" android:linksClickable="true" /> \ No newline at end of file diff --git a/base/src/main/res/layout/item_format_text.xml b/base/src/main/res/layout/item_format_text.xml index 3a8f666f..adc0db0e 100644 --- a/base/src/main/res/layout/item_format_text.xml +++ b/base/src/main/res/layout/item_format_text.xml @@ -9,12 +9,10 @@ android:id="@+id/text" style="@style/FormatText" android:autoLink="web" - android:hint="@string/format_hint_text" android:linksClickable="true" /> \ No newline at end of file diff --git a/base/src/main/res/layout/item_import_file.xml b/base/src/main/res/layout/item_import_file.xml index 3bb00990..014f8e2e 100644 --- a/base/src/main/res/layout/item_import_file.xml +++ b/base/src/main/res/layout/item_import_file.xml @@ -52,7 +52,6 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:fontFamily="@style/FontText" android:text="12 Aug 2017, 11:00 PM" android:textColor="@color/dark_hint_text" android:textSize="@dimen/font_size_small" /> @@ -61,7 +60,6 @@ android:id="@+id/file_size" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:fontFamily="@style/FontText" android:text="2.0MB" android:textColor="@color/dark_hint_text" android:textSize="@dimen/font_size_small" /> diff --git a/base/src/main/res/layout/item_information.xml b/base/src/main/res/layout/item_information.xml index 5b9f22e2..ccf9cd96 100644 --- a/base/src/main/res/layout/item_information.xml +++ b/base/src/main/res/layout/item_information.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/base/src/main/res/layout/item_no_notes.xml b/base/src/main/res/layout/item_no_notes.xml index 574e99fc..63a225b8 100644 --- a/base/src/main/res/layout/item_no_notes.xml +++ b/base/src/main/res/layout/item_no_notes.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/base/src/main/res/layout/item_note.xml b/base/src/main/res/layout/item_note.xml index 9fb9ac9e..8568586b 100644 --- a/base/src/main/res/layout/item_note.xml +++ b/base/src/main/res/layout/item_note.xml @@ -1,5 +1,5 @@ - - - + + - \ No newline at end of file + \ No newline at end of file diff --git a/base/src/main/res/layout/item_note_staggered.xml b/base/src/main/res/layout/item_note_staggered.xml index bd25504f..36301b6b 100644 --- a/base/src/main/res/layout/item_note_staggered.xml +++ b/base/src/main/res/layout/item_note_staggered.xml @@ -1,5 +1,5 @@ - - - + + - \ No newline at end of file + \ No newline at end of file diff --git a/base/src/main/res/layout/item_selector_folder.xml b/base/src/main/res/layout/item_selector_folder.xml new file mode 100644 index 00000000..dce1771f --- /dev/null +++ b/base/src/main/res/layout/item_selector_folder.xml @@ -0,0 +1,33 @@ + + + + + + + \ No newline at end of file diff --git a/base/src/main/res/layout/layout_add_note_overlay.xml b/base/src/main/res/layout/layout_add_note_overlay.xml index 1b9e033a..3b47ee57 100644 --- a/base/src/main/res/layout/layout_add_note_overlay.xml +++ b/base/src/main/res/layout/layout_add_note_overlay.xml @@ -5,20 +5,6 @@ android:layout_height="match_parent" android:orientation="vertical"> - - \ No newline at end of file + ui:textSize="@dimen/font_size_normal"/> \ No newline at end of file diff --git a/base/src/main/res/layout/layout_home_tag_item.xml b/base/src/main/res/layout/layout_home_tag_item.xml index 14709a8f..57b58961 100644 --- a/base/src/main/res/layout/layout_home_tag_item.xml +++ b/base/src/main/res/layout/layout_home_tag_item.xml @@ -20,7 +20,6 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - style="@style/FontText" android:textColor="@color/dark_secondary_text" android:textSize="@dimen/font_size_normal" /> diff --git a/base/src/main/res/layout/layout_option_sheet_item.xml b/base/src/main/res/layout/layout_option_sheet_item.xml index 79821784..dba77624 100644 --- a/base/src/main/res/layout/layout_option_sheet_item.xml +++ b/base/src/main/res/layout/layout_option_sheet_item.xml @@ -12,9 +12,7 @@ ui:iconTint="@color/dark_tertiary_text" ui:subtitleColor="@color/dark_tertiary_text" ui:subtitleSize="@dimen/font_size_small" - ui:subtitleStyle="@style/FontText" ui:titleColor="@color/dark_secondary_text" ui:titleSize="@dimen/font_size_normal" - ui:titleStyle="@style/FontText" ui:actionSize="@dimen/icon_size_normal" ui:actionTint="@color/material_blue_400"/> \ No newline at end of file diff --git a/base/src/main/res/layout/search_toolbar_main.xml b/base/src/main/res/layout/search_toolbar_main.xml index 9d96b5ab..295f0239 100644 --- a/base/src/main/res/layout/search_toolbar_main.xml +++ b/base/src/main/res/layout/search_toolbar_main.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/base/src/main/res/layout/toolbar_folder_bottom.xml b/base/src/main/res/layout/toolbar_folder_bottom.xml index 7074e808..bcfd6f2f 100644 --- a/base/src/main/res/layout/toolbar_folder_bottom.xml +++ b/base/src/main/res/layout/toolbar_folder_bottom.xml @@ -20,7 +20,6 @@ + android:background="@color/transparent" + android:orientation="vertical"> - - - - - - - - - + android:layout_height="match_parent" + android:background="@color/transparent" + android:orientation="vertical" + android:paddingTop="2dp" + android:paddingBottom="2dp"> - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/base/src/main/res/mipmap-hdpi/create_launcher.png b/base/src/main/res/mipmap-hdpi/create_launcher.png new file mode 100644 index 00000000..9d329a83 Binary files /dev/null and b/base/src/main/res/mipmap-hdpi/create_launcher.png differ diff --git a/base/src/main/res/mipmap-hdpi/open_note_launcher.png b/base/src/main/res/mipmap-hdpi/open_note_launcher.png new file mode 100644 index 00000000..b45793ea Binary files /dev/null and b/base/src/main/res/mipmap-hdpi/open_note_launcher.png differ diff --git a/base/src/main/res/mipmap-mdpi/create_launcher.png b/base/src/main/res/mipmap-mdpi/create_launcher.png new file mode 100644 index 00000000..4d5ce6db Binary files /dev/null and b/base/src/main/res/mipmap-mdpi/create_launcher.png differ diff --git a/base/src/main/res/mipmap-mdpi/open_note_launcher.png b/base/src/main/res/mipmap-mdpi/open_note_launcher.png new file mode 100644 index 00000000..f07e82fb Binary files /dev/null and b/base/src/main/res/mipmap-mdpi/open_note_launcher.png differ diff --git a/base/src/main/res/mipmap-xhdpi/create_launcher.png b/base/src/main/res/mipmap-xhdpi/create_launcher.png new file mode 100644 index 00000000..060f8d37 Binary files /dev/null and b/base/src/main/res/mipmap-xhdpi/create_launcher.png differ diff --git a/base/src/main/res/mipmap-xhdpi/open_note_launcher.png b/base/src/main/res/mipmap-xhdpi/open_note_launcher.png new file mode 100644 index 00000000..f18f3f6a Binary files /dev/null and b/base/src/main/res/mipmap-xhdpi/open_note_launcher.png differ diff --git a/base/src/main/res/mipmap-xxhdpi/create_launcher.png b/base/src/main/res/mipmap-xxhdpi/create_launcher.png new file mode 100644 index 00000000..76963a06 Binary files /dev/null and b/base/src/main/res/mipmap-xxhdpi/create_launcher.png differ diff --git a/base/src/main/res/mipmap-xxhdpi/open_note_launcher.png b/base/src/main/res/mipmap-xxhdpi/open_note_launcher.png new file mode 100644 index 00000000..f487ed23 Binary files /dev/null and b/base/src/main/res/mipmap-xxhdpi/open_note_launcher.png differ diff --git a/base/src/main/res/mipmap-xxxhdpi/create_launcher.png b/base/src/main/res/mipmap-xxxhdpi/create_launcher.png new file mode 100644 index 00000000..ac1eaf7d Binary files /dev/null and b/base/src/main/res/mipmap-xxxhdpi/create_launcher.png differ diff --git a/base/src/main/res/mipmap-xxxhdpi/open_note_launcher.png b/base/src/main/res/mipmap-xxxhdpi/open_note_launcher.png new file mode 100644 index 00000000..7fdb9173 Binary files /dev/null and b/base/src/main/res/mipmap-xxxhdpi/open_note_launcher.png differ diff --git a/base/src/main/res/values-ar/strings.xml b/base/src/main/res/values-ar/strings.xml index d43f57c2..eb78a211 100644 --- a/base/src/main/res/values-ar/strings.xml +++ b/base/src/main/res/values-ar/strings.xml @@ -4,24 +4,17 @@ حفظ استيراد بحث ملاحظات | | - البحث %s… جار المشاركة باستخدام … لا ملاحظات يبدو أنك لم تضف أي ملاحظات. انقر لإضافة ملاحظة. - إضافة ملاحظة … - إضافة ملاحظة سريعة … - اضف ملاحظة إضافة قائمة التحقق - الوضع الليلي - وضع اليوم تحرير مذكرة إنشاء إعلام فتح في نافذة منبثقة - حذف ملاحظة الحذف بشكل نهائي نسخ ملاحظة إرسال ملاحظة @@ -43,8 +36,6 @@ الهاء الحرة اختر الإجراء… - انقر لعرض الملاحظة في الوضع الليلي - انقر لعرض الملاحظة في وضع اليوم انقر لفتح ملاحظة للتحرير انقر لنسخ محتوى الملاحظة إلى الحافظة انقر لمشاركة محتوى المذكرة مع تطبيقات أخرى @@ -58,60 +49,26 @@ انقر لتغيير لون خلفية الملاحظة انقر على إلغاء أرشفة الملاحظة - ملاحظاتك | | الصفحة الرئيسية - كل من الملاحظات العادية والمفضلة لديك المفضلة - جميع الملاحظات المفضلة لديك أرشفة - جميع الملاحظات المؤرشفة مقفل - كل من الملاحظات الخاصة بك مؤمن - الكلمات - كل علامات الملاحظة الخاصة بك قمامة، يدمر، يهدم - جميع الملاحظات في المهملات إضافة محتوى… إضافة العنوان … - إضافة عنوان فرعي … إضافة نص مقتبس … اضافة عنصر… إضافة شفرة … انقر لإضافة صورة أو تغييرها - كتلة التنسيق - عنوان - عنوان فرعي - نص - اقتبس - الشفرة - قائمة تدقيق - صورة - الفاصل - - تنسيق تحديد السعر - بالخط العريض - المائل - أكد - إضراب - قائمة - خيارات والإعدادات واجهة والخبرة اختيار كيف يبدو التطبيق ويشعر. - ملاحظة التفضيلات - اختر ملاحظة وإعدادات أخرى. حول معرفة المزيد عنا والتطبيق. الأمان تأمين الملاحظات وخيارات الأمان - تمكين الوضع الليلي - تمكين المظهر المظلم كخيار افتراضي - تمكين وضع اليوم - تمكين موضوع الضوء بشكل افتراضي - إعدادات تخفيض السعر - اطلع على كيفية استخدام تخفيض السعر في الملاحظات تمكين تخطيط القائمة إظهار الملاحظات في عمود واحد تمكين تخطيط الشبكة @@ -131,8 +88,6 @@ معرفة المزيد عن مشروع مفتوح المصدر معدل ومراجعة أخبرنا أعرف كم كنت أحب التطبيق - ملء المسح - مساعدتنا على تحسين التطبيق من خلال إخبارنا ما تريد تثبيت برو التطبيق ثبِّت Pro Pro لإلغاء قفل الميزات ومطور الدعم تهاجر ملاحظات على القرمزي برو @@ -153,15 +108,10 @@ خيارات الأمان رمز عبور تعيين رقم التعريف الشخصي المكون من 4 أرقام لقفل الملاحظات - فتح مع بصمات الأصابع - سيتم فتح الملاحظات مع بصمات الأصابع - تم تعطيل بصمة الإصبع - لن تستخدم الملاحظات بصمة الإصبع أدخل رقم تعريف شخصي جديد أدخل رقم التعريف الشخصي لإلغاء التأمين أدخل رقم التعريف الشخصي الحالي - ادخل الرمز التحقق فتح جلس @@ -176,7 +126,6 @@ السماح بتنسيق التضمين المنسق تخفيض السعر في قائمة الملاحظات تمكين تنسيق علامة التبويب في قائمة الملاحظات - أمثلة إعطاء الأذونات استيراد وتصدير تتطلب أذونات التخزين. يرجى إعطاء الإذن عند الطلب. @@ -191,7 +140,6 @@ شارك - معلومات عنا وأكثر معدل على اللعب المتجر تساهم نسخة التطبيق @@ -199,16 +147,12 @@ المكتبات مشروع المصدر المفتوح - حول مشروع المصدر المفتوح - ملاحظة تذكير تاريخ التذكير تذكير الوقت تكرار تكرار مرة واحدة فقط اليومي - العادة - بيتا ملاحظة الإخطارات تذكير وإنذارات @@ -241,10 +185,6 @@ تعرف ما هو الجديد في التحديثات الأخيرة من التطبيق ترجمه - انقر لإضافة ملاحظة جديدة - انقر لرؤية خيارات المنزل - القائمة الرئيسية لديها الملاحظات المفضلة لديك والأرشيف، وكذلك إعدادات التطبيق. يمكنك العثور على العلامات هنا أيضا. - نسخ حظر الإجراءات النصية صالة عرض @@ -299,9 +239,6 @@ تسجيل الدخول للحصول على النسخ الاحتياطي سحابة والمزامنة خروج تسجيل الخروج لإيقاف النسخ الاحتياطي سحابة - الدخول مع جوجل - تسجيل الدخول | - لقد سجلت الدخول فشل تسجيل الدخول إلى غوغل سياسة الخصوصية @@ -315,19 +252,10 @@ احصل على أحدث الميزات أولا \n \n ستتوفر بعض الميزات الإضافية فقط لمستخدمي برو - سبب تمكين مزامنة السحاب - التحميل والنسخ الاحتياطي من تغييرات الجهاز \n - \n - المزامنة بين أجهزة متعددة، والحصول على تحديثات سريعة \n - \n - حفظها بشكل آمن على خوادم غوغل فيريباس - مرحبا، - ملاحظات المادة الآن القرمزي! - البدء @@ -338,7 +266,6 @@ انقر لإضافة أو تغيير العلامات - عرض المزيد من الإجراءات حدد ملاحظات حدد إجراءات وتنفيذها على ملاحظات متعددة في وقت واحد @@ -361,4 +288,155 @@ ملاحظات حديثة + + دمج الملاحظات + تصدير كما تخفيض السعر + تصدير الملاحظات في شكل تخفيض السعر. (لا يمكنك استيراد هذه العودة إلى التطبيق) + استخدام لون موضوع للخلفية + استخدام لون المذكرة للخلفية + مكن + تعطيل + تمكين مزامنة المجلد + مجلد مزامنة + مزامنة جميع الملاحظات والعلامات والمجلدات الخاصة بك إلى مجلد خارجي. يساعدك هذا في مزامنة استخدام تطبيقات أخرى بين الأجهزة ، وكذلك الحصول على نسخة في حال كنت بحاجة إلى حذف التطبيق. + تصدير إلى مجلد + مزامنة جميع الملاحظات والعلامات وغيرها إلى مجلد خارجي + تصدير الملاحظات المقفلة + مرتب حسب الحروف الأبجدية + متوفر على Scarlet Pro + النسخ الاحتياطي أيضا الملاحظات التي يتم تأمين + خيارات المحرر + تغيير الإعدادات والاستخدام لمحرر الملاحظات + خيارات تخفيض السعر الافتراضية + أظهر الأزرار السريعة للتخفيض على شريط الأدوات كإعداد افتراضي + تخفيض السعر الفعلي + اختر ما إذا كنت تريد أن يكون تخفيض السعر مرئيًا كنوعك. التمكين يمكن أن يؤثر على الأداء على الملاحظات الكبيرة. + نقل العناصر المحددة + تنتقل العناصر المحددة إلى أسفل القائمة. إلغاء تحديد لا إعادة تعيين الموقف. + إظهار مقابض الحركة + أظهر المقبض لتحريك العناصر لأعلى أو لأسفل. لا يزال بإمكانك تحريك الأشياء عن طريق لمس الزاوية. + أمثلة تخفيض السعر + إعدادات القطعة + تغيير الإعدادات لعناصر واجهة مستخدم الشاشة الرئيسية + تمكين التنسيق + يتم تقديم الملاحظات مع التنسيق في عناصر واجهة تعامل الشاشة الرئيسية + إظهار الملاحظات المقفلة + السماح بإظهار الملاحظات المقفلة في عناصر واجهة تعامل الشاشة الرئيسية + إظهار الملاحظات المؤرشفة + السماح بعرض الملاحظات المؤرشفة في عناصر واجهة تعامل الشاشة الرئيسية + إظهار الملاحظات في المهملات + السماح بإظهار الملاحظات في المهملات في عناصر واجهة تعامل الشاشة الرئيسية + مساعدة والأسئلة الشائعة + ابحث عن مساعدة حول كيفية استخدام الميزات الموجودة في التطبيق + المزامنة + في انتظار النسخ الاحتياطي + خيارات للمطور + تغيير الإعدادات الداخلية إلى التطبيق المستخدم للتصحيح + استثناءات السجل + سجل اشتعلت استثناءات إلى ملاحظة ثابتة ، للسماح لإعادة توجيه إلى المطور + إظهار ورقة الاستثناء + إظهار الاستثناءات التي تم اكتشافها على ورقة إن أمكن ، للسماح بإعادة التوجيه إلى Developer + رمي على استثناءات + رمي وتعطل التطبيق على استثناءات. سيتم إعادة تعيين بعد 5 حوادث + تمكين ملء الشاشة + اجعل التطبيق بملء الشاشة للسماح بلقطات وتسجيلات + إظهار ملاحظة UUIDs + عرض معرفات فريدة من الملاحظات في عرض الشاشة الرئيسية + استثناءات وهمية + رمي استثناء وهمية لاختبار ميزات الاستثناء + استثناء الرمية + تحطم التطبيقات + بريد + فشل الاتصال + المزامنة على Google Drive + يتيح لك Google Drive مزامنة ملاحظاتك بين الأجهزة باستخدام حساب Google Drive الخاص بك. + تسجيل الدخول إلى جوجل Firebase من قبل؟ + تسجيل الدخول إلى Google Drive + تسجيل الدخول + تسجيل الخروج من القرمزي + توقف عن مزامنة الملاحظات والعلامات والمجلدات. + توقف عن مزامنة الملاحظات والعلامات والمجلدات مع Google Drive. + ستظل بياناتك على التطبيق وعلى Google Drive موجودة. + تسجيل الخروج من Drive + تسجيل الخروج + يتم تخزين الملاحظات والعلامات والمجلدات على Google Drive ، بحيث يمكنك التحكم في الوصول إليها فقط. + يتم تحميل صورك ومزامنتها عبر الأجهزة أيضًا. + استعادة البيانات من Firebase + الدخول مع جوجل + تسجيل الدخول + اعتدنا على تخزين معلوماتك على Google Firebase. بعد تسجيل الدخول سنقوم باسترداد هذه إلى جهازك + لن تتم مزامنة الملاحظات والتغييرات الجديدة مع Google Firebase ، وستحتاج إلى تسجيل الدخول إلى Google Drive + بمجرد استرداد ملاحظاتك ، يمكنك حذفها من Google Firebase ، ثم التبديل + لا تتم مزامنة بياناتك! + تم تعطيل مزامنة البيانات استنادًا إلى تسجيل الدخول القديم ، فكّر في التبديل إلى المزامنة القائمة على Google Drive. + نقل البيانات من Firebase إلى Drive + مسح البيانات وتسجيل الخروج + المقاصة وتسجيل الخروج + اعتدنا على تخزين معلوماتك على Google Firebase. نحن ننتقل إلى تخزين ملاحظاتك في Google Drive. + مزيد من الخصوصية. + مزامنة الصور. + الخطوات التالية + سنقوم أولاً بحذف الملاحظات الخاصة بك من Firebase وتسجيل الخروج. + يمكنك بعد ذلك تسجيل الدخول إلى Google Drive ، وسنقوم بتحميل بياناتك مع الصور. + + + إزالة الخيارات + إزالة دفتر الملاحظات + فقط إزالة دفتر الملاحظات. نقل الملاحظات خارج المجلد. + إزالة دفتر الملاحظات والملاحظات + إزالة دفتر الملاحظات. جميع الملاحظات تتحرك إلى سلة المهملات أو يتم حذفها. + إزالة الملاحظات + حافظ على دفتر الملاحظات ولكن جميع الملاحظات تنتقل إلى المهملات أو يتم حذفها. + تخصيص الخطوط + حدد التطبيق ولاحظ الخطوط + حدد مجموعة الخط + ملاحظة: قد لا تعمل الخطوط بشكل صحيح مع جميع اللغات + التطبيق الافتراضي + الجهاز الافتراضي + مونو + شريف + فتح التطبيق + أدخل رقم التعريف الشخصي المكون من 4 أرقام أو استخدم القياسات الحيوية لإلغاء القفل + أدخل رقم التعريف الشخصي المكون من 4 أرقام لإلغاء القفل + استخدام سمة النظام + استخدم النسق الخفيف أو المظلم من النظام + ملاحظات الظلام + تغميق تلقائيا ملاحظة وألوان المجلد + محلي + التحكم عن بعد + غير متوفره + خلقت + تم الحذف + محدث + خلفية القطعة + اختر لون الخلفية لعنصر واجهة تعامل الملاحظات المتعددة + إظهار شريط أدوات العمل + القطعة متعددة الملاحظات يظهر شريط الأدوات + تخطي ملاحظة العارض + تخطي عارض الملاحظة والانتقال إلى محرر الملاحظات مباشرة + هل ترغب في حذف هذه الملاحظات نهائيًا؟ + أسرع التحديثات والطلبات. + قفل التطبيق وفتح واحد. + المزيد من سمات التطبيق. + ملاحظة الخطوط وأحجام الخطوط. + لون خلفية المشاهد. + المزيد من خيارات القطعة. + المزيد من الإجراءات ملاحظة. + ملاحظة اللون + ملاحظة العلامات + تمكين قفل التطبيق + استخدم رقم التعريف الشخصي لإلغاء قفل التطبيق بالكامل + اسأل دائمًا عن رقم التعريف الشخصي + أدخل رقم التعريف الشخصي لجميع الملاحظات ، حتى إذا تم إدخالها مسبقًا + فتح مع القياسات الحيوية + السماح بفتح مع بصمة أو القياسات الحيوية الأخرى + القياسات الحيوية معطلة + لا تسمح بفتح مع بصمة أو القياسات الحيوية الأخرى + فتح ملاحظة + استخدم بصمة الجهاز أو القياسات الحيوية لفتح الملاحظة والوصول إليها. + فتح التطبيق + استخدم بصمة الجهاز أو القياسات الحيوية لإلغاء قفل التطبيق والوصول إلى جميع الملاحظات. + قاذفة اختصار + مشاركة الصور + diff --git a/base/src/main/res/values-bn/strings.xml b/base/src/main/res/values-bn/strings.xml index 1920a896..5b7ef762 100644 --- a/base/src/main/res/values-bn/strings.xml +++ b/base/src/main/res/values-bn/strings.xml @@ -6,17 +6,13 @@ ব্যবহার করে ভাগ করুন … কোন নোট নেই মনে হচ্ছে আপনি কোন নোট যোগ না করেছেন। একটি নোট যোগ করতে ক্লিক করুন - একটি নোট যোগ করো… - একটি দ্রুত নোট যোগ করুন … নোট সম্পাদনা করুন পপআপ খুলুন - নোট মুছুন অনুলিপি নোট নোট পাঠান নির্বাচন করুন… সামগ্রী যোগ করুন … শিরোলেখ জুড়ুন … - উপ শিরোনাম যোগ করুন … উদ্ধৃত পাঠ্য যোগ করুন … আইটেম যোগ করুন… কোড যুক্ত করুন … @@ -26,9 +22,6 @@ একটি স্তব্ধ গ্রিডে নোট দেখান মার্কড্ডন সহায়তা মাপদণ্ড সমর্থিত ফরম্যাটিং মঞ্জুরি দিন - উদাহরণ - মার্কডাউন সেটিংস - নোটগুলিতে মার্কাডাউন কিভাবে ব্যবহার করা যায় তা দেখুন লক নোট নোট আনলক করুন নিরাপত্তা @@ -36,14 +29,9 @@ নিরাপত্তা অপশন পাস কোড নোট লক করার জন্য একটি 4 ডিজিটের PIN সেট করুন - আঙুলের ছাপ দিয়ে আনলক করুন - নোটগুলি আঙ্গুলের ছাপ দিয়ে আনলক হবে - ফিঙ্গারপ্রিন্ট অক্ষম হয়েছে - নোটগুলি একটি আঙ্গুলের ছাপ ব্যবহার করবে না নতুন PIN লিখুন আনলক করতে পিন লিখুন বর্তমান PIN লিখুন - কোড লিখুন যাচাই করুন আনলক করুন সেট @@ -68,7 +56,6 @@ ফাইলের জন্য এক্সপোর্ট করা হচ্ছে | সম্পন্ন ভাগ - আমাদের সম্পর্কে এবং আরও প্লে স্টোরে রেট দিন অবদান অনুসন্ধান নোটগুলি | @@ -76,16 +63,9 @@ অ্যাপ সংস্করণ অ্যাপ সম্পর্কে - দিন মোড রঙ পরিবর্তন করুন - দিন মোডে নোট দেখতে ট্যাপ করুন নোটের পটভূমির রং পরিবর্তন করতে আলতো চাপুন - নাইট মোড সক্ষম করুন - ডিফল্ট হিসাবে অন্ধকার থিমটি সক্ষম করুন - ডে মোড সক্ষম করুন - ডিফল্ট হিসাবে হালকা থিমটি সক্ষম করুন - রাত মোড চিরতরে মুছে দাও অব্যবহৃত নোট আর্কাইভ নোট @@ -93,7 +73,6 @@ চিহ্নিত করুন প্রিয় নোট পুনরুদ্ধার করুন আবর্জনা সরান - রাতের মোডে নোট দেখতে ট্যাপ করুন সম্পাদনা করার জন্য নোটটি খুলতে ট্যাপ করুন ক্লিপবোর্ডে নোট সামগ্রী কপি করতে আলতো চাপুন অন্যান্য অ্যাপ্লিকেশনে নোট সামগ্রী ভাগ করতে আলতো চাপুন @@ -105,21 +84,13 @@ নোট হিসাবে প্রিয় হিসাবে চিহ্নিত করতে আলতো চাপুন নোট আর্কাইভ করতে আলতো চাপুন নোট অযাচাই করার জন্য আলতো চাপুন - আপনার নোটস | বাড়ি - আপনার সব স্বাভাবিক এবং প্রিয় নোট প্রিয় - আপনার প্রিয় নোট সব আর্কাইভ করা - আপনার সংরক্ষণাগারভুক্ত সমস্ত নোট আবর্জনা - ট্র্যাশ আপনার সমস্ত নোট বিজ্ঞপ্তি তৈরি করুন নোট বিজ্ঞপ্তিগুলি লক - আপনার লক নোট সব - ট্যাগ - আপনার সমস্ত নোট ট্যাগ নতুন ট্যাগ যোগ করুন | ট্যাগ করা সম্পাদনা করুন | ট্যাগ লিখুন @@ -130,8 +101,6 @@ আমদানি নোট তালিকাতে মার্কডাউন নোটগুলির তালিকাতে মার্কড্ডা ফর্ম্যাটিং সক্ষম করুন - সার্ভে পূরণ - আপনার পছন্দ কি আমাদের বলার মাধ্যমে অ্যাপ্লিকেশন উন্নত করতে আমাদের সাহায্য করুন ট্যাগ পরিবর্তন করুন @@ -140,8 +109,6 @@ ওপেন সোর্স প্রকল্প সম্পর্কে আরও জানুন লাইব্রেরি ওপেন সোর্স প্রকল্প - ওপেন সোর্স প্রকল্প সম্পর্কে - নোট অনুস্মারক অনুস্মারক তারিখ অনুস্মারক সময় পুনরাবৃত্তি ফ্রিকোয়েন্সি @@ -156,8 +123,6 @@ ইন্টারফেস এবং অভিজ্ঞতা অ্যাপ্লিকেশন কেমন দেখায় এবং অনুভব করে তা চয়ন করুন। - নোট পছন্দসমূহ - নোট এবং অন্যান্য সেটিংস চয়ন করুন। সম্পর্কিত আমাদের এবং অ্যাপ সম্পর্কে আরও জানুন ডিফল্ট নোট রঙ @@ -192,19 +157,6 @@ নোট যোগ করুন চেকলিস্ট যোগ করুন - ফরম্যাটিং ব্লক করুন - শিরোনাম - উপ শিরোনাম - পাঠ - উদ্ধৃতি - কোড - চেকলিস্ট - মার্কডাউন ফরম্যাটিং - সাহসী - ইটালিক - আনডারলাইন করা - ধর্মঘট - তালিকা একটি নোট নির্বাচন করুন নোট নির্বাচন করুন সেটিংস @@ -218,29 +170,18 @@ কি নতুন অ্যাপ্লিকেশনের সাম্প্রতিক আপডেটে নতুন কি আছে তা জানুন অনুবাদ - একটি নতুন নোট যোগ করতে ক্লিক করুন - হোম বিকল্প দেখতে ক্লিক করুন - হোম মেনু আপনার প্রিয় এবং আর্কাইভ নোট, পাশাপাশি অ্যাপ্লিকেশন সেটিংস আছে। আপনি এখানে আপনার ট্যাগ খুঁজে পেতে পারেন। অ্যাপে সাইন ইন করুন ক্লাউড ব্যাকআপ এবং সিঙ্ক্রোনাইজেশনের জন্য সাইন ইন করুন সাইন আউট ক্লাউড ব্যাকআপ বন্ধ করতে সাইন আউট করুন - Google এর সাথে সাইন ইন করুন - সাইন ইন ইন … - আপনি সংযুক্ত আছেন Google লগইন ব্যর্থ গোপনীয়তা নীতি কন্টেন্ট জন্য অ্যাপ্লিকেশন গোপনীয়তা নীতি প্রো অ্যাপ ইনস্টল করুন কেন প্রো ইনস্টল ক্লাউড সিঙ্ক চালানোর জন্য ব্যাপক সার্ভারের খরচ সাপোর্ট ডেভেলপার, \n\n প্রথমে সর্বশেষ বৈশিষ্ট্যগুলি পান \n\n কিছু অতিরিক্ত বৈশিষ্ট্যগুলি শুধুমাত্র প্রো ব্যবহারকারীদের জন্য উপলব্ধ হবে - কেন মেঘ সমন্বয় সক্ষম - ডিভাইসের পরিবর্তনগুলির বিরুদ্ধে আপলোড এবং ব্যাকআপ করুন \n\n একাধিক ডিভাইসের মধ্যে সমন্বয় করুন, এবং দ্রুত আপডেট পান করুন \n\n Google Firebase সার্ভারে নিরাপদে সংরক্ষিত - হ্যালো, - উপাদান টীকা এখন স্কারলেট! - এবার শুরু করা যাক কপি @@ -257,30 +198,24 @@ আমি বুঝেছি স্বয়ংক্রিয়ভাবে রপ্তানি করুন ব্যাকআপ হিসাবে বহিরাগত ফাইল ঘন ঘন রপ্তানি নোট - ভাবমূর্তি ইমেজ যোগ বা পরিবর্তন করতে ক্লিক করুন শুধুমাত্র একবার দৈনন্দিন - প্রথা - বিটা অনুস্মারক এবং এলার্ম %s ওপেন সোর্স এবং কেউ এটি আরও ভালো করার জন্য অবদান রাখার জন্য উন্মুক্ত। এটি বর্তমানে %s দ্বারা নির্মিত এবং রক্ষণাবেক্ষণ করা হয়। %s একটি সহজ নোট গ্রহণের অ্যাপ্লিকেশন। এটি ব্যবহার করা খুব কঠিন অভিজ্ঞতা ছাড়া দ্রুত রিচ টেক্সট ইনপুট অনুমতি দেয়। এটি বহু টাস্কিং একটি বাতাস তোলে। হাই, আমরা ডিজাইনার এবং প্রোগ্রামারের একটি জোড়া, যিনি %s তৈরি করেছেন। আমরা সুন্দর, সাবধানে ডিজাইন ফ্রি, বিজ্ঞাপন-মুক্ত বা ন্যূনতম বিজ্ঞাপন অ্যাপ্লিকেশন তৈরি করতে চেষ্টা করি যা সকলের জন্য দুর্দান্ত ইউটিলিটি প্রদান করে! %d হোম স্ক্রিনে লাইন - অনুসন্ধান %s… বিতর্ক মুক্ত - বিভাজক অ্যাপ থিম থিম জন্য পটভূমি রঙ নির্বাচন করুন অ্যাপ থিম নির্বাচন করুন ট্যাগ যোগ বা পরিবর্তন করতে ক্লিক করুন - আরো কর্ম দেখান নোট নির্বাচন করুন নির্বাচন করুন এবং একযোগে একাধিক নোট কর্ম সঞ্চালন নোট ট্র্যাশে সরানো হয় @@ -316,4 +251,155 @@ অ্যাপ্লিকেশন নোট, ট্যাগ এবং ফোল্ডার মুছে দিন নোট ভিউয়ার ব্যাকগ্রাউন্ড + + নোট মার্জ করুন + মার্কডাউন হিসাবে রপ্তানি করুন + মার্কডাউন বিন্যাসে নোট রপ্তানি করুন। (আপনি এই অ্যাপ্লিকেশন ফিরে এই আমদানি করতে পারবেন না) + পটভূমি জন্য থিম রঙ ব্যবহার করুন + পটভূমি জন্য নোট রঙ ব্যবহার করুন + সক্ষম করা + অক্ষম + ফোল্ডার সিঙ্ক সক্ষম করুন + ফোল্ডার সিঙ্ক + একটি বহিরাগত ফোল্ডারে আপনার সমস্ত নোট, ট্যাগ এবং ফোল্ডার সিঙ্ক করুন। এটি আপনাকে ডিভাইসগুলির মধ্যে অন্য অ্যাপ্লিকেশানগুলি ব্যবহার করে সিঙ্ক করতে সহায়তা করে এবং সেই অ্যাপ্লিকেশানটি মুছে ফেলার ক্ষেত্রে একটি অনুলিপি রয়েছে। + ফোল্ডারে এক্সপোর্ট করা হচ্ছে + একটি বহিরাগত ফোল্ডারে সব নোট, ট্যাগ ইত্যাদি সিঙ্ক করুন + রপ্তানি লক নোট + বর্ণানুক্রমিক + Scarlet প্রো পাওয়া যায় + সম্পাদক অপশন + নোট সম্পাদকের জন্য সেটিংস এবং ব্যবহার পরিবর্তন করুন + ডিফল্ট হিসাবে চিহ্নিত বিকল্প + ডিফল্ট হিসাবে সরঞ্জামদণ্ডে মার্কডাউন দ্রুত বোতামগুলি দেখান + রিয়েলটাইম Markdown + আপনি আপনার টাইপ হিসাবে চিহ্নিত হতে চান চিহ্নিত করুন। সক্রিয় বড় নোট কর্মক্ষমতা প্রভাবিত করতে পারেন। + চেক করা আইটেম সরান + চেক আইটেম তালিকা নীচে সরানো। আনচেক অবস্থান পুনরায় সেট না। + আন্দোলন হ্যান্ডলগুলি দেখান + আইটেম উপরে বা নিচে সরানোর জন্য হ্যান্ডেল দেখান। আপনি এখনও কোণার স্পর্শ দ্বারা চারপাশে জিনিস সরাতে পারেন। + মার্কডাউন উদাহরণ + উইজেট সেটিংস + হোম স্ক্রিন উইজেট জন্য সেটিংস পরিবর্তন করুন + ফরম্যাটিং সক্রিয় করুন + নোট হোম স্ক্রিন উইজেটে বিন্যাস সহ রেন্ডার করা হয় + লক নোট দেখান + লক করা নোটগুলি হোম স্ক্রীন উইজেটগুলিতে দেখানোর অনুমতি দিন + সংরক্ষণাগারভুক্ত নোট প্রদর্শন করুন + আর্কাইভ নোটগুলি হোম স্ক্রীন উইজেটগুলিতে দেখানোর অনুমতি দিন + ট্র্যাশে নোট দেখান + ট্র্যাশে নোটগুলি হোম স্ক্রীন উইজেটগুলিতে দেখানোর অনুমতি দিন + সাহায্য এবং সাধারণ প্রশ্ন + অ্যাপ্লিকেশন বৈশিষ্ট্য ব্যবহার করার জন্য সাহায্য খুঁজুন + সিঙ্ক করা হচ্ছে + মুলতুবি ব্যাকআপ + বিকাশকারী বিকল্প + ডিবাগিংয়ের জন্য ব্যবহৃত অ্যাপ্লিকেশনে অভ্যন্তরীণ সেটিংস পরিবর্তন করুন + লগ ব্যতিক্রম + ডেভেলপারকে ফরোয়ার্ড করার জন্য একটি নির্দিষ্ট নোটে লগগুলি ব্যতিক্রমগুলি ধরা হয়েছে + ব্যতিক্রম পত্রক দেখান + বিকাশকারীকে ফরোয়ার্ড করার জন্য, সম্ভব হলে একটি শীটে ধরা ব্যতিক্রমগুলি দেখান + ব্যতিক্রম উপর নিক্ষেপ + থ্রেড এবং ব্যতিক্রম ব্যতিক্রম অ্যাপ্লিকেশন। 5 ক্র্যাশ পরে রিসেট করা হবে + পূর্ণস্ক্রীন সক্রিয় করুন + স্ক্রিনশট এবং রেকর্ডিং অনুমতি দিতে পূর্ণস্ক্রীন অ্যাপ্লিকেশন করুন + নোট UUID দেখান + হোম স্ক্রীন ভিউতে নোটগুলির অনন্য আইড দেখান + জাল আপত্তি + ব্যতিক্রম বৈশিষ্ট্য পরীক্ষা করার জন্য একটি জাল ব্যতিক্রম নিক্ষেপ + ব্যতিক্রম নিক্ষিপ্ত + ক্র্যাশ অ্যাপ্লিকেশন + মেল + সংযোগ ব্যর্থ হয়েছে + Google ড্রাইভে সিঙ্ক করুন + Google ড্রাইভ আপনাকে আপনার নিজের Google ড্রাইভ অ্যাকাউন্ট ব্যবহার করে ডিভাইসগুলির মধ্যে আপনার নোটগুলি সিঙ্ক করতে দেয়। + আগে গুগল ফায়ারবসে লগ ইন? + গুগল ড্রাইভে সাইন ইন করুন + সাইন ইন করুন | + স্কারলেট সাইন আউট + নোট, ট্যাগ এবং ফোল্ডার সিঙ্ক করা বন্ধ করুন। + আপনার Google ড্রাইভে আপনার নোট, ট্যাগ এবং ফোল্ডার সিঙ্ক করা বন্ধ করুন। + অ্যাপ্লিকেশন এবং Google ড্রাইভে আপনার ডেটা এখনও থাকবে। + ড্রাইভ থেকে সাইন আউট + সাইন আউট + নোট, ট্যাগ এবং ফোল্ডার আপনার নিজের Google ড্রাইভে সংরক্ষণ করা হয়, তাই শুধুমাত্র আপনি তাদের অ্যাক্সেস নিয়ন্ত্রণ করতে পারেন। + আপনার ফটো আপলোড এবং ডিভাইস জুড়ে সিঙ্ক করা হয়। + Firebase থেকে তথ্য পুনরুদ্ধার করুন + গুগলের সাথে সাইন ইন করুন + সাইন ইন করুন | + আমরা গুগল ফায়ারবসে আপনার তথ্য সংরক্ষণ করতে ব্যবহার করতাম। লগ ইন করার পরে আমরা আপনার ডিভাইসে এই পুনরুদ্ধার করা হবে + নতুন নোট এবং পরিবর্তনগুলি Google Firebase এ সিঙ্ক করা হবে না এবং আপনাকে Google ড্রাইভে লগইন করতে হবে + একবার আপনার নোট পুনরুদ্ধার হয়ে গেলে, আপনি তাদের Google ফায়ারবেস থেকে মুছতে পারেন এবং তারপরে স্যুইচ করতে পারেন + আপনার তথ্য সিঙ্ক হচ্ছে না! + লিগ্যাসি লগইন ভিত্তিক ডেটা সিঙ্ক অক্ষম করা হয়েছে, Google ড্রাইভ ভিত্তিক সিঙ্কে স্যুইচ করার কথা বিবেচনা করুন। + ফায়ারবেস থেকে ড্রাইভে ডেটা স্থানান্তর করুন + সাফ ডেটা এবং সাইন আউট + ক্লিয়ারিং এবং সাইন আউট + আমরা গুগল ফায়ারবসে আপনার তথ্য সংরক্ষণ করতে ব্যবহার করতাম। আমরা আপনার Google ড্রাইভে আপনার নোট সংরক্ষণ করতে চলে যাচ্ছি। + আরো গোপনীয়তা। + ছবি সিঙ্ক। + পরবর্তী পদক্ষেপ + আমরা প্রথমে ফায়ারबेस থেকে আপনার নোট মুছে ফেলব এবং আপনাকে লগ আউট করব। + তারপর আপনি Google ড্রাইভে লগ ইন করতে পারেন এবং আমরা আপনার ডেটা চিত্র সহ আপলোড করব। + + + বিকল্পগুলি সরান + নোটবুক সরান + কেবল নোটবুক সরান। নোটগুলি ফোল্ডারের বাইরে চলে যায়। + নোটবুক এবং নোটগুলি সরান + নোটবুক সরান। সমস্ত নোট ট্র্যাশে সরানো হয় বা মুছে ফেলা হয়। + নোটগুলি সরান + নোটবুক রাখুন তবে সমস্ত নোট ট্র্যাশে চলে যায় বা মুছে ফেলা হয়। + হরফ কাস্টমাইজ করুন + অ্যাপ এবং নোট ফন্ট নির্বাচন করুন + একটি ফন্ট সেট নির্বাচন করুন + দ্রষ্টব্য: ফন্টগুলি সমস্ত ভাষার সাথে সঠিকভাবে কাজ করতে পারে না + অ্যাপ ডিফল্ট + ডিভাইস ডিফল্ট + মনো + সেরিফ + আনলক অ্যাপ্লিকেশন + 4 ডিজিটের পিন প্রবেশ করুন বা আনলক করতে বায়োমেট্রিক ব্যবহার করুন + আনলক করতে 4 ডিজিটের পিন প্রবেশ করুন + সিস্টেম থিম ব্যবহার করুন + সিস্টেম থেকে হালকা বা গা dark় থিম ব্যবহার করুন + গাark় নোট + স্বয়ংক্রিয়ভাবে নোট এবং ফোল্ডারের রঙগুলি গাen় করে তুলুন + স্থানীয় + দূরবর্তী + অপ্রাপ্য + নির্মিত + মুছে ফেলা + আপডেট করা হয়েছে + উইজেটের পটভূমি + মাল্টি-নোট উইজেটের জন্য পটভূমি রঙ চয়ন করুন + অ্যাকশন সরঞ্জামদণ্ড প্রদর্শন করুন + মাল্টি-নোট উইজেট টুলবারটি দেখায় + নোট দর্শককে এড়িয়ে যান + নোট দর্শককে এড়িয়ে সরাসরি নোট সম্পাদকটিতে ঝাঁপুন + আপনি কি এই নোটগুলি স্থায়ীভাবে মুছতে চান? + দ্রুত আপডেট এবং অনুরোধগুলি। + অ্যাপ লক এবং একক আনলক। + আরও অ্যাপ থিমস। + ফন্ট এবং হরফ আকার নোট করুন। + দর্শকের পটভূমির রঙ। + আরও উইজেট বিকল্প। + আরও নোট ক্রিয়া। + নোট রঙ + নোট ট্যাগ + লক থাকা নোটগুলিও ব্যাকআপ করুন + অ্যাপ লক সক্ষম করুন + পুরো অ্যাপ্লিকেশনটি আনলক করতে পিন ব্যবহার করুন + সর্বদা পিনের জন্য জিজ্ঞাসা করুন + সমস্ত নোটের জন্য পিন প্রবেশ করুন, এমনকি আগে প্রবেশ করানো হয়েছে + বায়োমেট্রিক্স দিয়ে আনলক করুন + ফিঙ্গারপ্রিন্ট বা অন্যান্য বায়োমেট্রিক্স দিয়ে আনলক করার অনুমতি দিন + বায়োমেট্রিক্স অক্ষম + ফিঙ্গারপ্রিন্ট বা অন্যান্য বায়োমেট্রিক্স দিয়ে আনলক করার অনুমতি দেবেন না + আনলক নোট + নোটটি আনলক করতে এবং অ্যাক্সেস করতে ডিভাইস ফিঙ্গারপ্রিন্ট বা বায়োমেট্রিক ব্যবহার করুন। + আনলক অ্যাপ্লিকেশন + অ্যাপ্লিকেশনটি আনলক করতে এবং সমস্ত নোট অ্যাক্সেস করতে ডিভাইস ফিঙ্গারপ্রিন্ট বা বায়োমেট্রিক ব্যবহার করুন। + লঞ্চার শর্টকাট + ফটো ভাগ করুন + \ No newline at end of file diff --git a/base/src/main/res/values-de/strings.xml b/base/src/main/res/values-de/strings.xml index 06e67ed3..7d9eeff8 100644 --- a/base/src/main/res/values-de/strings.xml +++ b/base/src/main/res/values-de/strings.xml @@ -6,17 +6,13 @@ Teilen über… Keine Notizen Es scheint, dass Sie keine Notizen hinzugefügt haben. Klicken Sie, um eine Notiz hinzuzufügen. - Notiz hinzufügen… - Schnellnotiz hinzufügen… Bearbeiten Im Popup öffnen - Notiz löschen Kopieren Notiz senden… Aktion wählen… Inhalt hinzufügen… Überschrift hinzufügen… - Unterüberschrift hinzufügen… Zitat hinzufügen… Artikel hinzufügen… Code hinzufügen … @@ -27,14 +23,9 @@ Sicherheitsoptionen Code eingeben Stellen Sie eine vierstellige PIN ein, um Notizen zu sperren - Entsperren mit Fingerabdruck - Die Notizen werden mit dem Fingerabdruck entsperrt - Fingerabdruck deaktiviert - Die Notizen verwenden keinen Fingerabdruck Geben Sie eine neue PIN ein Geben Sie zum Entsperren die PIN ein Geben Sie die aktuelle PIN ein - Code eingeben Überprüfen Entsperren Einstellen @@ -45,9 +36,6 @@ Notizen in einem gestaffelten Raster anzeigen Markdown-Unterstützung Erlaube Markdown-Formatierung - Beispiele - Markdown-Einstellungen - Sehen Sie, wie man Markdown in Notizen verwendet Optionen und Einstellungen Notizen exportieren @@ -69,22 +57,14 @@ In Datei exportieren… Erledigt Teilen - Über uns und mehr Im Play Store bewerten Beitragen App-Version Über die App - Tagmodus Farbe ändern - Tippen Sie hier, um die Notiz im Tagmodus anzuzeigen Tippen, um die Hintergrundfarbe der Notiz zu ändern - Nachtmodus aktivieren - Aktiviere dunkles Design als Standard - Tagmodus aktivieren - Tagmodus als Standard aktivieren - Nachtmodus Dauerhaft löschen Notiz dearchivieren Notiz archivieren @@ -92,7 +72,6 @@ Als Favorit markieren Notiz wiederherstellen Ab in den Müll - Tippen, um die Notiz im Nachtmodus anzuzeigen. Zum Öffnen der Notiz antippen Tippen, um den Notizinhalt in die Zwischenablage zu kopieren Tippen, um Notizinhalte an andere Apps weiterzugeben @@ -104,21 +83,13 @@ Tippen, um die Markierung als Favorit zu entfernen Zum Archivieren der Notiz antippen Tippen Sie auf, um die Notiz zu dearchivieren - Deine Notizen… Hauptseite - Alle Ihre normalen und Lieblingsnotizen Favoriten - Alle deine Lieblingsnotizen Archiviert - Alle archivierten Notizen Papierkorb - Alle Ihre Notizen im Papierkorb Benachrichtigung erstellen Hinweis Benachrichtigungen Verschlossen - Alle Ihre gesperrten Notizen - Stichworte - Alle Ihre Notiz-Tags Neuen Tag hinzufügen … Tag bearbeiten … Tag eingeben @@ -129,8 +100,6 @@ Einführen Abschrift in der Notizliste Aktivieren Sie Markdown-Formatierung in der Liste der Notizen - Umfrage ausfüllen - Hilf uns, die App zu verbessern, indem du uns sagst, was dir gefällt Tags ändern @@ -139,8 +108,6 @@ Erfahren Sie mehr über das Open-Source-Projekt Bibliotheken Open-Source-Projekt - Über das Open-Source-Projekt - Hinweis Erinnerung Erinnerungsdatum Erinnerungszeit Häufigkeit wiederholen @@ -155,8 +122,6 @@ Schnittstelle und Erfahrung Wählen Sie, wie die App aussieht und sich anfühlt. - Hinweis Einstellungen - Wählen Sie Notiz und andere Einstellungen. Über Erfahren Sie mehr über uns und die App. Standard Hinweisfarbe @@ -191,19 +156,6 @@ Notiz hinzufügen Prüfliste hinzufügen - Blockformatierung - Überschrift - Unter Überschrift - Text - Zitat - Code - Checkliste - Abzeichnungsformatierung - Fett gedruckt - Kursivschrift - Unterstreichen - Streik - Liste Wählen Sie eine Notiz Wählen Sie Notizen die Einstellungen @@ -216,29 +168,18 @@ Was gibt\'s Neues Erfahren Sie, was in den letzten Updates der App neu ist Übersetzen - Klicken Sie auf, um eine neue Notiz hinzuzufügen - Klicken Sie hier, um die Startseite anzuzeigen - Das Home-Menü enthält Ihre Favoriten- und Archivnotizen sowie die Anwendungseinstellungen. Sie können Ihre Tags auch hier finden. In der App anmelden Melden Sie sich für Cloud-Backup und -Synchronisierung an Ausloggen Melden Sie sich ab, um die Cloud-Sicherung zu stoppen - Anmeldung mit Google - Anmelden … - Du bist eingeloggt Google-Anmeldung fehlgeschlagen Datenschutz-Bestimmungen App-Datenschutzrichtlinie für den Inhalt Installieren Sie die Pro App Warum Pro installieren? Unterstütze den Entwickler für die enormen Serverkosten, um die Cloud-Synchronisierung auszuführen \n\n Hol dir die neuesten Funktionen zuerst \n\n Einige zusätzliche Funktionen sind nur für Pro-Benutzer verfügbar - Warum sollte Cloud Sync aktiviert sein? - Hochladen und Sichern gegen Geräteänderungen \n\n Synchronisieren Sie mehrere Geräte und erhalten Sie schnelle Updates \n\n Sicher auf den Google Firebase Servern gespeichert - Hallo, - Material Notes ist jetzt Scarlet! - Loslegen Kopieren @@ -255,30 +196,24 @@ Ich verstehe Automatisch exportieren Exportiert häufig Notizen in eine externe Datei als Backup - Bild Klicken Sie hier, um ein Bild hinzuzufügen oder zu ändern Nur einmal Täglich - Brauch - Beta Erinnerungen und Alarme %s ist Open Source und jeder ist offen, um dazu beizutragen, dass es besser wird. Es wird derzeit von %s gebaut und gewartet. %s ist eine einfache Notiz App. Es ermöglicht eine schnelle Rich-Text-Eingabe, ohne dass die Bedienung sehr schwierig wird. Es macht Multitasking zum Kinderspiel. Hallo, wir sind ein Paar Designer und Programmierer, die %s erstellt haben. Wir sind bestrebt, schöne, sorgfältig gestaltete kostenlose, werbefreie oder minimale Anzeigen-Apps zu entwickeln, die allen Nutzern großen Nutzen bieten! %d Zeilen auf dem Startbildschirm - Suche %s … Ablenkung frei - Separator App-Thema Wählen Sie die Hintergrundfarbe für das Thema Wählen Sie App Theme Klicken Sie hier, um Tags hinzuzufügen oder zu ändern - Mehr Aktionen anzeigen Wählen Sie Notizen aus Wählen Sie mehrere Notizen gleichzeitig aus und führen Sie sie aus Die Notiz wurde in den Papierkorb verschoben @@ -314,4 +249,155 @@ Löschen Sie Notizen, Tags und Ordner in der App Hinweis Viewer-Hintergrund + + Notizen zusammenführen + Als Abschrift exportieren + Notizen im Abschriftenformat exportieren. (Sie können diese nicht zurück in die App importieren.) + Verwenden Sie die Themenfarbe für den Hintergrund + Verwenden Sie die Notenfarbe für den Hintergrund + Aktivieren + Deaktivieren + Aktivieren Sie die Ordnersynchronisierung + Ordnersynchronisation + Synchronisieren Sie alle Ihre Notizen, Tags und Ordner mit einem externen Ordner. Auf diese Weise können Sie mit anderen Apps zwischen Geräten synchronisieren und eine Kopie haben, falls Sie die App löschen müssen. + In Ordner exportieren + Synchronisieren Sie alle Notizen, Tags usw. mit einem externen Ordner + Gesperrte Notizen exportieren + Alphabetisch + Verfügbar für Scarlet Pro + Sichern Sie auch die gesperrten Notizen + Editoroptionen + Ändern Sie die Einstellungen und die Verwendung für den Notizeditor + Abschriftenoptionen als Standard + Standardmäßig werden die Abschriftenschaltflächen in der Symbolleiste angezeigt + Echtzeit Markdown + Wählen Sie aus, ob Markdown als Typ angezeigt werden soll. Das Aktivieren kann sich auf die Leistung großer Noten auswirken. + Markierte Objekte verschieben + Markierte Elemente werden an das Ende der Liste verschoben. Deaktivieren setzt die Position nicht zurück. + Bewegungsgriffe anzeigen + Zeigen Sie auf den Griff, um Elemente nach oben oder unten zu verschieben. Sie können immer noch Dinge bewegen, indem Sie die Ecke berühren. + Abschriftenbeispiele + Widget-Einstellungen + Ändern Sie die Einstellungen für die Widgets des Startbildschirms + Formatierung aktivieren + Notizen werden mit der Formatierung in Widgets des Startbildschirms gerendert + Gesperrte Notizen anzeigen + Zulassen, dass gesperrte Notizen in Widgets auf dem Startbildschirm angezeigt werden + Archivierte Notizen anzeigen + Ermöglichen, dass archivierte Notizen in Widgets auf dem Startbildschirm angezeigt werden + Notizen im Papierkorb anzeigen + Zulassen, dass Notizen im Papierkorb in Widgets auf dem Startbildschirm angezeigt werden + Hilfe und häufig gestellte Fragen + Hier finden Sie Hilfe zur Verwendung der Funktionen in der App + Synchronisierung + Ausstehende Sicherung + Entwickleroptionen + Ändern Sie die internen Einstellungen in der Anwendung, die zum Debuggen verwendet wird + Ausnahmen protokollieren + Erfasste Ausnahmen in einer festen Notiz protokollieren, um die Weiterleitung an Developer zu ermöglichen + Ausnahmeblatt anzeigen + Zeigen Sie gefangene Ausnahmen nach Möglichkeit auf einem Blatt an, um die Weiterleitung an Developer zu ermöglichen + Ausnahmen auslösen + Wirf und stürze die Anwendung in Ausnahmefällen ab. Wird nach 5 Abstürzen zurückgesetzt + Vollbild aktivieren + Erstellen Sie die App im Vollbildmodus, um Screenshots und Aufzeichnungen zuzulassen + Hinweis-UUIDs anzeigen + Zeigen Sie die eindeutigen IDs der Notizen in der Startbildschirmansicht an + Gefälschte Ausnahmen + Wirf eine gefälschte Ausnahme aus, um die Ausnahmefunktionen zu testen + Ausnahme ausgelöst + Crash App + Mail + Verbindung fehlgeschlagen + Synchronisieren Sie auf Google Drive + Mit Google Drive können Sie Ihre Notizen mit Ihrem eigenen Google Drive-Konto zwischen Geräten synchronisieren. + Bei Google Firebase angemeldet? + Melden Sie sich bei Google Drive an + Anmelden … + Melden Sie sich von Scarlet ab + Stoppen Sie die Synchronisierung von Notizen, Tags und Ordnern. + Synchronisieren Sie Ihre Notizen, Tags und Ordner nicht mehr mit Google Drive. + Ihre Daten in der App und auf Google Drive bleiben erhalten. + Vom Laufwerk abmelden + Abmelden … + Notizen, Tags und Ordner werden auf Ihrem eigenen Google Drive gespeichert, sodass nur Sie den Zugriff darauf steuern können. + Ihre Fotos werden auch geräteübergreifend hochgeladen und synchronisiert. + Daten aus Firebase wiederherstellen + Anmeldung mit Google + Anmelden … + Wir haben Ihre Daten in Google Firebase gespeichert. Nach dem Einloggen stellen wir diese auf Ihrem Gerät wieder her + Neue Notizen und Änderungen werden NICHT mit Google Firebase synchronisiert, und Sie müssen sich bei Google Drive anmelden + Sobald Ihre Notizen wiederhergestellt sind, können Sie sie aus Google Firebase löschen und dann umschalten + Ihre Daten werden nicht synchronisiert! + Die Datensynchronisierung basierend auf der alten Anmeldung ist deaktiviert. Überlegen Sie, ob Sie auf die Google Drive-basierte Synchronisierung umsteigen möchten. + Übertragen Sie Daten von Firebase auf das Laufwerk + Daten löschen und abmelden + Löschen und Abmelden + Wir haben Ihre Daten in Google Firebase gespeichert. Wir werden Ihre Notizen in Ihrem Google Drive speichern. + Mehr Privatsphäre. + Foto-Synchronisierung. + Nächste Schritte + Wir werden zuerst Ihre Notizen aus Firebase löschen und Sie abmelden. + Sie können sich dann bei Google Drive anmelden. Wir laden Ihre Daten zusammen mit Bildern hoch. + + + Optionen entfernen + Notebook entfernen + Nur Notebook entfernen. Notizen außerhalb des Ordners verschieben. + Notizbuch und Notizen entfernen + Notebook entfernen. Alle Notizen werden in den Papierkorb verschoben oder gelöscht. + Notizen entfernen + Notebook behalten, aber alle Notizen werden in den Papierkorb verschoben oder gelöscht. + Schriftarten anpassen + Wählen Sie die App und die Notizschriftarten aus + Wählen Sie einen Zeichensatz + Hinweis: Schriftarten funktionieren möglicherweise nicht in allen Sprachen + App-Standard + Gerätestandard + Mono + Serif + App freischalten + Geben Sie die 4-stellige PIN ein oder verwenden Sie Biometrie zum Entsperren + Geben Sie die 4-stellige PIN zum Entsperren ein + Verwenden Sie das Systemdesign + Verwenden Sie das helle oder dunkle Thema aus dem System + Dunkle Noten + Noten- und Ordnerfarben automatisch abdunkeln + Lokal + Fernbedienung + Nicht verfügbar + Erstellt + Gelöscht + Aktualisiert + Widget Hintergrund + Wählen Sie die Hintergrundfarbe für das Widget für mehrere Notizen + Aktionssymbolleiste anzeigen + Multi-Notizen-Widget zeigt die Symbolleiste + Note Viewer überspringen + Überspringen Sie den Notizen-Viewer und springen Sie direkt zum Notizen-Editor + Möchten Sie diese Notizen dauerhaft löschen? + Schnellere Updates und Anfragen. + App Lock und Single Unlock. + Weitere App-Themen. + Beachten Sie Schriftarten und Schriftgrößen. + Viewer-Hintergrundfarbe. + Weitere Widget-Optionen. + Weitere Hinweisaktionen. + Beachten Sie Farbe + Hinweis Tags + App-Sperre aktivieren + Verwenden Sie die PIN, um die gesamte Anwendung zu entsperren + Immer nach PIN fragen + Geben Sie die PIN für alle Notizen ein, auch wenn diese zuvor eingegeben wurden + Mit Biometrics entsperren + Erlaube das Entsperren mit einem Fingerabdruck oder anderen biometrischen Daten + Biometrie deaktiviert + Lassen Sie das Entsperren nicht mit einem Fingerabdruck oder anderen biometrischen Daten zu + Hinweis entsperren + Verwenden Sie Gerätefingerabdrücke oder biometrische Daten, um die Notiz und den Zugriff zu entsperren. + App freischalten + Verwenden Sie Gerätefingerabdruck oder Biometrie, um die App zu entsperren und auf alle Notizen zuzugreifen. + Launcher-Verknüpfung + Teile Fotos + diff --git a/base/src/main/res/values-es/strings.xml b/base/src/main/res/values-es/strings.xml index 9018008e..d8f7c514 100644 --- a/base/src/main/res/values-es/strings.xml +++ b/base/src/main/res/values-es/strings.xml @@ -6,17 +6,13 @@ Compartir usando … No Notas Parece que no has añadido ninguna nota. Haga clic para agregar una nota. - Agrega una nota… - Añadir una nota rápida … Editar nota Abrir en Popup - Eliminar nota Copiar nota Enviar nota Elige Acción… Agregar contenido… Añadir encabezado … - Add Sub Heading … Añadir texto citado … Añadir artículo… Añadir código … @@ -26,9 +22,6 @@ Mostrar notas en una grilla escalonada Apoyo Markdown Permitir formato compatible con markdown - Ejemplos - Configuración de reducción - Vea cómo usar el descuento en notas Nota de bloqueo Desbloquear nota @@ -37,14 +30,9 @@ Opciones de seguridad Código de Pase Establecer un PIN de 4 dígitos para bloquear notas - Desbloquear con huella digital - Las notas se desbloquearán con la huella digital - Huella digital deshabilitada - Las notas no usarán una huella digital Ingrese un nuevo PIN Ingresa el PIN para desbloquear Ingrese el PIN actual - introduzca el código Verificar desbloquear Conjunto @@ -69,22 +57,14 @@ Exportar a archivo … Hecho Compartir - Sobre nosotros y más Valorar en Play Store Contribuir Version de aplicacion Acerca de la aplicación - Modo día Notas de búsqueda … Cambiar el color - Toca para ver la nota en modo día Toca para cambiar el color de fondo de la nota - Habilitar modo nocturno - Habilitar el tema oscuro como predeterminado - Habilitar modo día - Habilitar el tema claro como predeterminado - Modo nocturno borrar permanentemente Nota de desarchivo Nota de archivo @@ -92,7 +72,6 @@ Marcar favorito Restaurar nota Mover a la papelera - Toca para ver la nota en modo nocturno Toca para abrir una nota para editar Toca para copiar el contenido de la nota en el portapapeles Toca para compartir contenido de notas en otras aplicaciones @@ -104,21 +83,13 @@ Toca para marcar la nota no como favorita Toca para archivar la nota Toca para desarchivar la nota - Sus notas … Casa - Todas sus notas normales y favoritas Favoritos - Todas tus notas favoritas Archivado - Todas tus notas archivadas Basura - Todas tus notas en la basura Crear notificación Nota Notificaciones Bloqueado - Todas tus notas bloqueadas - Etiquetas - Todas las etiquetas de tus notas Agregar nueva etiqueta … Editar etiqueta … enter tag @@ -129,8 +100,6 @@ Importar Retraso en la lista de notas Habilitar el formateo Markdown en la lista de notas - Completar encuesta - Ayúdenos a mejorar la aplicación diciéndonos lo que le gusta Cambiar etiquetas @@ -139,8 +108,6 @@ Sepa más sobre el proyecto de código abierto Bibliotecas Proyecto de código abierto - Acerca del Proyecto de Código Abierto - Recordatorio de nota Fecha de recordatorio Tiempo de Recordatorio Repetir frecuencia @@ -155,8 +122,6 @@ Interfaz y experiencia Elija cómo se ve y se siente la aplicación. - Preferencias de notas - Elija nota y otras configuraciones. Acerca de Conozca más sobre nosotros y la aplicación. Color predeterminado de la nota @@ -191,19 +156,6 @@ Añadir la nota Agregar lista de verificación - Formateo de bloque - Título - Sub encabezado - Texto - Citar - Código - Checklist - Formato de marcado - Negrita - Cursiva - Subrayar - Huelga - Lista Seleccione una nota Seleccionar notas Configuraciones @@ -217,29 +169,18 @@ Qué hay de nuevo Saber qué hay de nuevo en las actualizaciones recientes de la aplicación Traducir - Haga clic para agregar una nueva nota - Haga clic para ver las opciones de inicio - El menú de inicio tiene sus notas favoritas y de archivo, así como la configuración de la aplicación. Usted puede encontrar sus etiquetas aquí también. Iniciar sesión en la aplicación Iniciar sesión para copia de seguridad y sincronización en la nube Desconectar Cerrar sesión para detener la copia de seguridad en la nube - Inicia sesión con Google - Firmando … - Usted ha iniciado sesión Error de inicio de sesión de Google Política de privacidad Política de privacidad de la aplicación para el contenido Instalar la aplicación Pro Por qué instalar Pro Soporte al desarrollador para los costos masivos del servidor, para ejecutar la sincronización en la nube \n\n Obtenga las características más recientes primero \n\n Algunas características adicionales estarán disponibles solo para usuarios Pro - Por qué habilitar Cloud Sync - Cargar y realizar copias de seguridad de los cambios en el dispositivo \n\n Sincronizar entre varios dispositivos y obtener actualizaciones rápidas \n\n Guardado de forma segura en los servidores de Google Firebase - Hola, - Material Notes ahora es Scarlet! - Empezar Dupdo @@ -256,30 +197,24 @@ Entiendo Exportar Automáticamente Exportar notas con frecuencia a un archivo externo como respaldo - Imagen Haga clic para agregar o cambiar la imagen Sólo una vez Diario - Personalizado - Beta Recordatorios y alarmas %s es de código abierto y cualquiera está dispuesto a contribuir para mejorarlo. Actualmente está construido y mantenido por %s. %s es una aplicación para tomar notas. Permite la entrada rápida de texto enriquecido sin hacer que la experiencia sea muy difícil de usar. Hace multitarea en un abrir y cerrar de ojos. Hola, somos un par de diseñador y programador, que creó %s. ¡Nos esforzamos por crear aplicaciones publicitarias hermosas, cuidadosamente diseñadas, gratuitas, sin publicidad o mínimas que sean de gran utilidad para todos! %d líneas en la pantalla de inicio - Buscar %s… Distracción gratis - Separador Tema de la aplicación Seleccione el color de fondo para el tema Seleccione el tema de la aplicación Haga clic para agregar o cambiar etiquetas - Mostrar más acciones Seleccione notas Selecciona y realiza acciones en múltiples notas a la vez. La nota fue movida a la basura. @@ -315,4 +250,156 @@ Eliminar notas, etiquetas y carpetas en la aplicación Fondo del visor de notas + + + Notas de fusión + Exportar como Markdown + Exportar notas en formato markdown. (No puede importar estos de nuevo a la aplicación) + Utilice el color del tema para el fondo + Usa el color de la nota para el fondo. + Habilitar + Inhabilitar + Habilitar sincronización de carpetas + Sincronización de carpetas + Sincronice todas sus notas, etiquetas y carpetas en una carpeta externa. Esto le ayuda a sincronizar usando otras aplicaciones entre dispositivos, así como tener una copia en caso de que necesite eliminar la aplicación. + Exportando a la carpeta + Sincroniza todas las notas, etiquetas, etc. a una carpeta externa. + Exportar notas bloqueadas + Alfabético + Disponible en Scarlet Pro + También copia de seguridad de las notas que están bloqueadas + Opciones del editor + Cambiar la configuración y el uso del editor de notas. + Opciones de Markdown como predeterminadas + Mostrar los botones rápidos de reducción en la barra de herramientas por defecto + Markdown en tiempo real + Elija si desea que la reducción sea visible como su tipo. Habilitar puede afectar el rendimiento en grandes notas. + Mover elementos marcados + Los elementos marcados se mueven al final de la lista. Desmarcar no restablece la posición. + Mostrar manijas de movimiento + Mostrar el controlador para mover elementos hacia arriba o hacia abajo. Todavía puedes mover cosas tocando la esquina. + Ejemplos de rebajas + Configuracion de Widget + Cambiar la configuración de los widgets de la pantalla de inicio. + Habilitar formato + Las notas se procesan con formato en los widgets de la pantalla de inicio + Mostrar notas bloqueadas + Permitir que las notas bloqueadas se muestren en los widgets de la pantalla de inicio + Mostrar notas archivadas + Permitir que las notas archivadas se muestren en los widgets de la pantalla de inicio + Mostrar notas en la basura + Permitir que las notas en la papelera se muestren en los widgets de la pantalla de inicio + Ayuda y preguntas comunes + Encuentre ayuda sobre cómo usar las funciones en la aplicación + Sincronizando + Copia de seguridad pendiente + Opciones de desarrollador + Cambiar la configuración interna de la aplicación utilizada para la depuración. + Excepciones de registro + Registre las excepciones detectadas en una nota fija, para permitir el reenvío al desarrollador + Mostrar hoja de excepciones + Mostrar excepciones capturadas en una hoja si es posible, para permitir el reenvío al Desarrollador + Lanzar en excepciones + Lanzar y bloquear la aplicación en excepciones. Se reiniciará después de 5 choques. + Habilitar pantalla completa + Haga la aplicación en pantalla completa para permitir capturas de pantalla y grabaciones. + Mostrar notas UUIDs + Muestra los ID únicos de las notas en la vista de la pantalla de inicio + Falsas excepciones + Lanzar una excepción falsa para probar las características de excepción + Excepción lanzada + Aplicación Crash + Correo + La conexión falló + Sincronizar en Google Drive + Google Drive le permite sincronizar sus notas entre dispositivos usando su propia cuenta de Google Drive. + ¿Has iniciado sesión en Google Firebase antes? + Inicia sesión en Google Drive + Ingresando enâ € ¦ + Cerrar sesión de Scarlet + Deja de sincronizar notas, etiquetas y carpetas. + Deje de sincronizar sus notas, etiquetas y carpetas a su Google Drive. + Sus datos en la aplicación y en Google Drive todavía estarán allí. + Cerrar sesión de Drive + Cerrar sesión … + Las notas, etiquetas y carpetas se almacenan en su propio Google Drive, de modo que solo usted puede controlar el acceso a ellas. + Sus fotos también se cargan y sincronizan en todos los dispositivos. + Restaurar datos desde Firebase + Inicia sesión con Google + Ingresando enâ € ¦ + Solíamos almacenar su información en Google Firebase. Después de iniciar sesión los recuperaremos en su dispositivo. + Las nuevas notas y los cambios NO se sincronizarán con Google Firebase, y debe iniciar sesión en Google Drive + Una vez que se recuperan sus notas, puede eliminarlas de Google Firebase y luego cambiar + Sus datos no se están sincronizando! + La sincronización de datos basada en el inicio de sesión heredado está deshabilitada, considere cambiar a la sincronización basada en Google Drive. + Transfiere datos de Firebase a Drive + Borrar datos y cerrar sesión + Borrado y cierre de sesión + Solíamos almacenar su información en Google Firebase. Nos estamos moviendo para almacenar sus notas en su Google Drive. + Más privacidad. + Sincronización de fotos + Próximos pasos + Primero eliminaremos sus notas de Firebase y cerraremos sesión. + Luego, puede iniciar sesión en Google Drive y cargaremos sus datos junto con las imágenes. + + + Eliminar opciones + Eliminar cuaderno + Solo quitar cuaderno. Las notas se mueven fuera de la carpeta. + Eliminar cuaderno y notas + Quitar cuaderno. Todas las notas se mueven a la papelera o se eliminan. + Eliminar notas + Mantenga Notebook pero todas las notas se mueven a la papelera o se eliminan. + Personalizar fuentes + Seleccione la aplicación y observe las fuentes + Seleccione un conjunto de fuentes + Nota: las fuentes pueden no funcionar correctamente con todos los idiomas + Aplicación predeterminada + Dispositivo predeterminado + Mono + Serif + Desbloquear aplicación + Ingrese un PIN de 4 dígitos o use datos biométricos para desbloquear + Ingrese un PIN de 4 dígitos para desbloquear + Usar tema del sistema + Usa el tema claro u oscuro del sistema + Notas oscuras + Oscurece automáticamente la nota y los colores de la carpeta + Local + Remoto + Indisponible + Creado + Eliminado + Actualizado + Fondo de widget + Elija el color de fondo para el widget de notas múltiples + Mostrar barra de herramientas de acción + El widget de notas múltiples muestra la barra de herramientas + Saltar visor de notas + Omita el visor de notas y vaya directamente al editor de notas. + ¿Desea eliminar permanentemente estas notas? + Actualizaciones y solicitudes más rápidas. + App Lock y Single Unlock. + Más temas de aplicaciones. + Fuentes de nota y tamaños de fuente. + Color de fondo del visor. + Más opciones de widgets. + Más acciones de notas. + Color de la nota + Etiquetas de nota + Habilitar bloqueo de aplicaciones + Use el PIN para desbloquear toda la aplicación + Siempre solicite PIN + Ingrese el PIN para todas las notas, incluso si se ingresó previamente + Desbloquear con biometría + Permitir desbloqueo con una huella digital u otra biometría + Biometría deshabilitada + No permita el desbloqueo con una huella digital u otros datos biométricos. + Desbloquear nota + Use la huella digital del dispositivo o datos biométricos para desbloquear la nota y acceder. + Desbloquear aplicación + Use la huella digital del dispositivo o datos biométricos para desbloquear la aplicación y acceder a todas las notas. + Lanzador de acceso directo + Compartir fotos + \ No newline at end of file diff --git a/base/src/main/res/values-fr/strings.xml b/base/src/main/res/values-fr/strings.xml index 24b7e6d0..cfb23f10 100644 --- a/base/src/main/res/values-fr/strings.xml +++ b/base/src/main/res/values-fr/strings.xml @@ -6,17 +6,13 @@ Partager avec … Pas de notes Il semble que vous n\'ayez pas ajouté de notes. Cliquez pour ajouter une note. - Ajouter une note… - Ajouter une note rapide … Modifier Ouvrir comme pop-up - Supprimer Copier Partager Choisir une action… Ajouter du contenu… Ajouter un titre … - Ajouter un sous-titre … Ajouter une citation … Ajouter un item… Ajouter du code … @@ -27,14 +23,9 @@ Options de sécurité Code PIN Définir un code PIN à 4 chiffres pour verrouiller les notes - Débloquer avec une empreinte digitale - Les notes se déverrouilleront avec l\'empreinte digitale - Empreinte digitale désactivée - Les notes n\'utiliseront pas d\'empreinte digitale Entrer le nouveau code PIN Entrer le code PIN pour déverrouiller Entrer le code PIN actuel - Entrer le code Vérifier Ouvrir Activer @@ -45,9 +36,6 @@ Afficher les notes dans une grille décalée Prise en charge du formatage Autoriser le formatage pris en charge - Exemples - Paramètres de formatage - Voir comment utiliser le formatage dans les notes Options et paramètres Exporter des notes Exporter des notes vers le stockage de l\'appareil @@ -67,23 +55,15 @@ Exportation vers un fichier … Terminé Partager - À propos de nous et plus Noter sur le Play Store Contribuer Version de l\'application À propos de l\'application Rechercher des notes … - Mode jour Changer de couleur - Appuyer pour afficher la note en mode jour Appuyer pour modifier la couleur d\'arrière-plan de la note - Activer le mode nuit - Activer le thème sombre par défaut - Activer le mode jour - Activer le thème lumineux par défaut - Mode nuit Supprimer définitivement Retirer des archives Archiver @@ -91,7 +71,6 @@ Marquer comme favori Restaurer Mettre à la corbeille - Appuyer pour afficher la note en mode nuit Appuyer pour éditer la note Appuyer pour copier le contenu de la note dans le presse-papiers Appuyer pour partager le contenu de la note avec d\'autres applications @@ -103,21 +82,13 @@ Appuyer pour retirer la note des favoris Appuyer pour archiver la note Appuyer pour retirer la note des archives - Vos notes … Accueil - Toutes vos notes normales et préférées Favoris - Toutes vos notes préférées Archives - Toutes vos notes archivées Corbeille - Toutes vos notes à la corbeille Créer une notification Notifications Verrouillé - Toutes vos notes verrouillées - Tags - Toutes vos tags Ajouter un nouveau tag Modifier le tag … entrer le tag @@ -128,8 +99,6 @@ Importer Markdown dans la liste des notes Activer le formatage Markdown dans la liste des notes - Remplir l\'enquête - Aidez-nous à améliorer l\'application en nous disant ce que vous aimez Modifier les tags @@ -138,8 +107,6 @@ En savoir plus sur le projet open source Bibliothèques Projet Open Source - À propos du projet Open Source - Rappel Date du rappel Heure du rappel Fréquence du rappel @@ -154,8 +121,6 @@ Interface Définir l\'apparence de l\'application. - Préférences des notes - Définir les paramètres des notes. À propos En savoir plus sur nous et sur l\'application. Couleur des notes par défaut @@ -190,19 +155,6 @@ Ajouter une note Ajouter une liste - Formatage du texte - Titre - Sous-titre - Texte - Citation - Code - Liste - Formatage Markdown - Gras - Italique - Souligner - Barrer - Liste Sélectionner une note Sélectionner des notes Paramètres @@ -216,29 +168,18 @@ Quoi de neuf Voir les nouveautés dans les mises à jour récentes de l\'application Traduire - Cliquer pour ajouter une nouvelle note - Cliquer pour voir les options de l\'accueil - Le menu de l\'accueil montre vos notes préférées et archivées, ainsi que les paramètres de l\'application. Vous pouvez trouver vos tags ici aussi. Connectez-vous à l\'application Connexion pour la sauvegarde et la synchronisation dans le cloud Déconnexion Se déconnecter pour arrêter la sauvegarde dans le cloud - Connectez-vous avec Google - Connexion … - Vous êtes authentifié Échec de la connexion à Google Politique de confidentialité Politique de confidentialité de l\'application pour le contenu Installer l\'application Pro Pourquoi installer Pro Supporter le développeur pour les coûts massifs du serveur, pour exécuter la synchronisation du cloud \n\n Récupérer les dernières fonctionnalités en premier \n\n Certaines fonctionnalités supplémentaires ne seront disponibles que pour les utilisateurs Pro - Pourquoi activer Cloud Sync - Téléchargement et sauvegarde des modifications de l\'appareil \n\n Synchronisation entre plusieurs appareils et mise à jour rapide \n\n Enregistrement sécurisé sur les serveurs Google Firebase - Bonjour, - Notes de matériaux est maintenant Scarlet! - Commencer Copie @@ -255,30 +196,24 @@ Je comprends Exporter automatiquement Exporter des notes fréquemment vers un fichier externe en tant que sauvegarde - Image Cliquez pour ajouter ou modifier l\'image Juste une fois du quotidien - Douane - Bêta Rappels et alarmes %s est open source et tout le monde est ouvert pour contribuer à l\'améliorer. Il est actuellement construit et maintenu par %s. %s est une application de prise de notes simple. Il permet une saisie rapide en texte enrichi sans rendre l\'expérience très difficile à utiliser. Cela rend le multitâche facile. Salut, nous sommes une paire de concepteur et programmeur, qui a créé %s. Nous nous efforçons de créer de superbes applications gratuites, sans annonces ou minimes qui soient utiles à tous! %d lignes sur l\'écran d\'accueil - Rechercher %s… Distraction Gratuit - Séparateur Thème de l\'application Sélectionnez la couleur de fond pour le thème Sélectionnez le thème de l\'application Cliquez pour ajouter ou modifier des tags - Afficher plus d\'actions Sélectionnez des notes Sélectionner et effectuer des actions sur plusieurs notes à la fois La note a été déplacée à la corbeille @@ -314,4 +249,155 @@ Supprimer des notes, des balises et des dossiers dans l\'application Note Viewer Background + + Fusionner les notes + Exporter comme démarque + Exporter des notes au format markdown. (Vous ne pouvez pas les importer dans l\'application) + Utiliser la couleur du thème pour le fond + Utiliser la couleur de note pour le fond + Activer + Désactiver + Activer la synchronisation des dossiers + Synchronisation des dossiers + Synchronisez toutes vos notes, balises et dossiers dans un dossier externe. Cela vous aide à synchroniser en utilisant d\'autres applications entre appareils, ainsi qu\'à en avoir une copie au cas où vous auriez besoin de supprimer l\'application. + Exporter vers un dossier + Synchronisez toutes les notes, balises, etc. dans un dossier externe. + Exporter les notes verrouillées + Alphabétique + Disponible sur Scarlet Pro + Sauvegardez également les notes qui sont verrouillées + Options de l\'éditeur + Modifier les paramètres et l\'utilisation de l\'éditeur de notes + Options de démarquage par défaut + Afficher les boutons rapides de démarquage dans la barre d’outils par défaut + Markdown en temps réel + Choisissez si vous voulez que le démarquage soit visible en tant que votre type. L\'activation peut affecter les performances sur les notes volumineuses. + Déplacer les éléments cochés + Les éléments cochés sont déplacés au bas de la liste. Décocher ne réinitialise pas la position. + Afficher les poignées de mouvement + Afficher la poignée pour déplacer les éléments vers le haut ou le bas. Vous pouvez toujours déplacer des objets en touchant le coin. + Exemples de démarques + Paramètres du widget + Modifier les paramètres des widgets de l\'écran d\'accueil + Activer le formatage + Les notes sont rendues avec le formatage dans les widgets de l\'écran d\'accueil. + Afficher les notes verrouillées + Autoriser l\'affichage des notes verrouillées dans les widgets de l\'écran d\'accueil + Afficher les notes archivées + Autoriser l\'affichage des notes archivées dans les widgets de l\'écran d\'accueil + Afficher les notes dans la corbeille + Autoriser l\'affichage des notes dans la corbeille dans les widgets de l\'écran d\'accueil + Aide et questions communes + Trouver de l\'aide sur l\'utilisation des fonctionnalités de l\'application + Synchronisation + Sauvegarde en attente + Options de développeur + Modifier les paramètres internes de l\'application utilisée pour le débogage + Enregistrer les exceptions + Journalise les exceptions interceptées dans une note fixe, pour permettre le transfert vers le développeur + Afficher la feuille d\'exception + Afficher les exceptions interceptées sur une feuille, si possible, pour permettre le transfert au développeur + Lancer sur les exceptions + Lancer et planter l\'application sur les exceptions. Sera réinitialisé après 5 accidents + Activer le plein écran + Créez l\'application en plein écran pour autoriser les captures d\'écran et les enregistrements + Afficher les UUID de note + Afficher les identifiants uniques des notes dans la vue de l\'écran d\'accueil + Fausses exceptions + Lancer une fausse exception pour tester les fonctionnalités de l\'exception + Exception levée + Crash App + Courrier + La connexion a échoué + Synchroniser sur Google Drive + Google Drive vous permet de synchroniser vos notes entre appareils en utilisant votre propre compte Google Drive. + Connecté à Google Firebase avant? + Connectez-vous à Google Drive. + Ouverture de session… + Déconnexion de Scarlet + Arrêtez la synchronisation des notes, des balises et des dossiers. + Arrêtez de synchroniser vos notes, tags et dossiers sur votre Google Drive. + Vos données sur l\'application et sur Google Drive seront toujours là. + Déconnexion de Drive + Se déconnecter… + Les notes, les balises et les dossiers sont stockés sur votre propre Google Drive. Vous êtes donc le seul à pouvoir en contrôler l\'accès. + Vos photos sont également téléchargées et synchronisées sur plusieurs appareils. + Restaurer les données de Firebase + Connectez-vous avec Google + Ouverture de session… + Nous avions l\'habitude de stocker vos informations sur Google Firebase. Après la connexion, nous les récupérerons sur votre appareil. + Les nouvelles notes et modifications NE seront PAS synchronisées sur Google Firebase et vous devez vous connecter à Google Drive. + Une fois vos notes récupérées, vous pouvez les supprimer de Google Firebase, puis basculer + Vos données ne sont pas synchronisées! + La synchronisation des données basée sur la connexion héritée est désactivée, envisagez de passer à la synchronisation basée sur Google Drive. + Transférer des données de Firebase à Drive + Effacer les données et se déconnecter + Dégagement et déconnexion + Nous avions l\'habitude de stocker vos informations sur Google Firebase. Nous allons maintenant stocker vos notes dans votre Google Drive. + Plus d\'intimité. + Sync Photo + Prochaines étapes + Nous allons d\'abord supprimer vos notes de Firebase et vous déconnecter. + Vous pouvez ensuite vous connecter à Google Drive et nous téléchargerons vos données avec les images. + + + Supprimer les options + Supprimer le carnet + Supprimer uniquement le carnet. Les notes se déplacent hors du dossier. + Supprimer le carnet et les notes + Supprimer le cahier. Toutes les notes sont déplacées ou supprimées. + Supprimer les notes + Conservez Notebook, mais toutes les notes sont déplacées ou supprimées. + Personnaliser les polices + Sélectionnez les polices de l\'application et de la note + Sélectionnez un jeu de polices + Remarque: les polices peuvent ne pas fonctionner correctement avec toutes les langues. + App par défaut + Par défaut de l\'appareil + Mono + Serif + Déverrouiller l\'application + Entrez un code PIN à 4 chiffres ou utilisez la biométrie pour déverrouiller + Entrez un code PIN à 4 chiffres pour déverrouiller + Utiliser le thème du système + Utilisez le thème clair ou sombre du système + Notes sombres + Assombrir automatiquement les couleurs des notes et des dossiers + Local + Éloigné + Indisponible + Établi + Supprimé + Mis à jour + Contexte du widget + Choisissez la couleur de fond pour le widget multi-notes + Afficher la barre d\'outils d\'action + Le widget multi-notes affiche la barre d\'outils + Ignorer la visionneuse de notes + Ignorer la visionneuse de notes et accéder directement à l\'éditeur de notes + Souhaitez-vous supprimer définitivement ces notes? + Mises à jour et demandes plus rapides. + App Lock et Single Unlock. + Plus de thèmes d\'application. + Remarque Polices et tailles de police. + Couleur de fond de la visionneuse. + Plus d\'options de widget. + Plus d\'actions de note. + Note couleur + Étiquettes de note + Activer le verrouillage de l\'application + Utiliser un code PIN pour déverrouiller toute l\'application + Toujours demander le code PIN + Entrer le code PIN pour toutes les notes, même si elles avaient déjà été entrées + Déverrouiller avec la biométrie + Autoriser le déverrouillage avec une empreinte digitale ou autre biométrie + Biométrie désactivée + Ne pas autoriser le déverrouillage avec une empreinte digitale ou d\'autres données biométriques + Déverrouiller la note + Utilisez les empreintes digitales ou biométriques du périphérique pour déverrouiller la note et y accéder. + Déverrouiller l\'application + Utilisez les empreintes digitales ou biométriques du périphérique pour déverrouiller l\'application et accéder à toutes les notes. + Raccourci du lanceur + Partager des photos + diff --git a/base/src/main/res/values-hi/strings.xml b/base/src/main/res/values-hi/strings.xml index 3e0fefaa..b0fd6ed9 100644 --- a/base/src/main/res/values-hi/strings.xml +++ b/base/src/main/res/values-hi/strings.xml @@ -6,17 +6,13 @@ का उपयोग साझा करें … नोट्स नहीं ऐसा लगता है कि आपने कोई नोट नहीं जोड़ा है नोट जोड़ने के लिए क्लिक करें - टिप्पणी जोड़ें… - त्वरित नोट जोड़ें … नोट संपादित करें पॉपअप में खोलें - नोट हटाएं प्रतिलिपि नोट नोट भेजें विकल्प चुने… सामग्री जोड़ें… शीर्षक जोड़ें … - उप शीर्षक जोड़ें … उद्धरित पाठ जोड़ें … सामान जोडें… कोड जोड़ें … @@ -27,14 +23,9 @@ सुरक्षा विकल्प पास कोड नोट लॉक करने के लिए एक 4 अंकों का पिन सेट करें - फ़िंगरप्रिंट से अनलॉक करें - नोट फिंगरप्रिंट से अनलॉक होगा - फ़िंगरप्रिंट अक्षम - नोट्स फिंगरप्रिंट का उपयोग नहीं करेंगे नया पिन दर्ज करें अनलॉक करने के लिए पिन दर्ज करें वर्तमान पिन दर्ज करें - कोड दर्ज करें सत्यापित करें अनलॉक सेट @@ -45,9 +36,6 @@ एक कंपित ग्रिड में नोट्स दिखाएं मार्कडाउन समर्थन मार्कडाउन समर्थित स्वरूपण की अनुमति दें - उदाहरण - मार्कडाउन सेटिंग्स - नोट्स में मार्कडाउन का उपयोग कैसे करें विकल्प और सेटिंग्स निर्यात नोट्स साझा करने के लिए डिवाइस संग्रहण में नोट निर्यात करें @@ -67,23 +55,15 @@ फाइल करने के लिए निर्यात | किया हुआ शेयर - हमारे बारे में और अधिक प्ले स्टोर पर रेट करें योगदान एप्लिकेशन वेरीज़न ऐप के बारे में नोट्स खोजें … | - दिन मोड रंग बदलना - दिन मोड में नोट देखने के लिए टैप करें नोट के पृष्ठभूमि का रंग बदलने के लिए टैप करें - नाइट मोड सक्षम करें - डिफ़ॉल्ट के रूप में गहरा विषय सक्षम करें - डे मोड सक्षम करें - प्रकाश विषय को डिफ़ॉल्ट के रूप में सक्षम करें - रात्री स्वरुप स्थायी रूप से मिटाएं अनचाही नोट पुरालेख नोट @@ -91,7 +71,6 @@ मार्क पसंदीदा नोट पुनर्स्थापित करें रद्दी में डालें - रात मोड में नोट देखने के लिए टैप करें संपादन के लिए नोट खोलने के लिए टैप करें क्लिपबोर्ड पर नोट सामग्री कॉपी करने के लिए टैप करें अन्य ऐप्स पर नोट सामग्री साझा करने के लिए टैप करें @@ -103,21 +82,13 @@ नोट को पसंदीदा के रूप में चिह्नित करने के लिए टैप करें नोट संग्रह करने के लिए टैप करें ध्यान हटाने के लिए टैप करें - आपका नोट्स … | होम - आपके सभी सामान्य और पसंदीदा नोट्स पसंदीदा - आपके सभी पसंदीदा नोट्स संग्रहीत - आपके सभी संग्रहीत नोट कचरा - कचरा में आपके सभी नोट्स अधिसूचना बनाएं नोट नोटिफिकेशन बंद - आपके सभी लॉक नोट्स - टैग - आपके सभी नोट टैग नई टैग जोड़ें | | टैग करें संपादित करें | टैग दर्ज करें @@ -128,8 +99,6 @@ आयात नोट सूची में मार्कडाउन नोट्स की सूची में मार्कटाउन स्वरूपण सक्षम करें - सर्वेक्षण भरें - हमें बताएं कि आप क्या पसंद करते हैं टैग बदलें @@ -138,8 +107,6 @@ ओपन सोर्स परियोजना के बारे में अधिक जानें पुस्तकालय ओपन सोर्स प्रोजेक्ट - ओपन सोर्स प्रोजेक्ट के बारे में - नोट अनुस्मारक अनुस्मारक तिथि अनुस्मारक समय आवृत्ति दोहराएं @@ -154,8 +121,6 @@ इंटरफ़ेस और अनुभव चुनें कि ऐप कैसा दिखता है और कैसे लगता है। - नोट प्राथमिकताएं - नोट और अन्य सेटिंग्स चुनें के बारे में हमारे और ऐप के बारे में अधिक जानें डिफ़ॉल्ट नोट रंग @@ -190,19 +155,6 @@ नोट जोड़े चेकलिस्ट जोड़ें - ब्लॉक फ़ॉर्मेटिंग - शीर्षक - उप शीर्षक - टेक्स्ट - उद्धरण - कोड - चेकलिस्ट - मार्कडाउन फ़ॉर्मेटिंग - साहसिक - इटैलिक - रेखांकित करना - धरना - सूची एक नोट चुनें नोट्स का चयन करें सेटिंग्स @@ -216,29 +168,18 @@ नया क्या है एप के हालिया अपडेट में नया क्या है, पता करें अनुवाद करना - कोई नया नोट जोड़ने के लिए क्लिक करें - होम विकल्प देखने के लिए क्लिक करें - होम मेनू में आपके पसंदीदा और संग्रह नोट्स, साथ ही एप्लिकेशन सेटिंग्स हैं। आप यहां अपने टैग भी पा सकते हैं। ऐप में साइन इन करें क्लाउड बैकअप और सिंक्रनाइज़ेशन के लिए साइन इन करें साइन आउट क्लाउड बैकअप को रोकने के लिए साइन आउट करें - Google के साथ साइन इन करें - साइनिंग इन … | - आप लोग्ड इन हो चुके हैं Google लॉगिन विफल गोपनीयता नीति सामग्री के लिए ऐप गोपनीयता नीति प्रो ऐप इंस्टॉल करें क्यों प्रो स्थापित करें क्लाउड सिंक चलाने के लिए बड़े सर्वर लागतों के लिए समर्थन डेवलपर का समर्थन करें \n\n नवीनतम सुविधाओं को पहले प्राप्त करें \n\n कुछ अतिरिक्त सुविधाएं केवल प्रो उपयोगकर्ता के लिए उपलब्ध होंगी - क्लाउड सिंक क्यों सक्षम करें - डिवाइस के बदलावों के विरुद्ध अपलोड करें और बैकअप लें \n\n एकाधिक उपकरणों के बीच समन्वय करें, और त्वरित अपडेट प्राप्त करें \n\n Google Firebase सर्वर पर सुरक्षित रूप से सहेजा गया - नमस्ते, - सामग्री नोट्स अब लाल रंग है! - शुरू हो जाओ प्रतिलिपि @@ -255,30 +196,24 @@ मै समझता हुँ स्वचालित रूप से निर्यात करें बाह्य फ़ाइल में बार-बार बैकअप के रूप में निर्यात करें - छवि चित्र जोड़ने या बदलने के लिए क्लिक करें सिर्फ एक बार रोज - रिवाज - बीटा अनुस्मारक और अलार्म %s ओपन सोर्स है और कोई इसे बेहतर बनाने के लिए योगदान करने के लिए खुला है। यह वर्तमान में %s द्वारा बनाया और रखरखाव किया गया है। %s एक साधारण नोट लेने वाला ऐप है यह प्रयोग करने में बहुत मुश्किल अनुभव किए बिना त्वरित रिच टेक्स्ट इनपुट की अनुमति देता है यह बहु-कार्य करने वाला हवा बनाता है नमस्ते, हम डिजाइनर और प्रोग्रामर की एक जोड़ी हैं, जिन्होंने %s बनाया है हम सुन्दर, सावधानीपूर्वक डिज़ाइन किए गए मुक्त, विज्ञापन-मुक्त या न्यूनतम विज्ञापन एप्लिकेशन बनाने की कोशिश करते हैं जो हर किसी के लिए महान उपयोगिता प्रदान करते हैं! %d होम स्क्रीन पर लाइनें - खोज %s … व्याकुलता मुक्त - सेपरेटर ऐप थीम विषय के लिए पृष्ठभूमि रंग का चयन करें ऐप थीम का चयन करें टैग जोड़ने या बदलने के लिए क्लिक करें - अधिक क्रियाएं दिखाएं नोट्स का चयन करें एक साथ कई नोट्स पर क्रियाएं चुनें और निष्पादित करें नोट ट्रैश में ले जाया गया था @@ -314,4 +249,155 @@ ऐप में नोट्स, टैग और फ़ोल्डर्स हटाएं नोट दर्शक पृष्ठभूमि + + नोट्स मिलाएं + मार्कडाउन के रूप में निर्यात करें + मार्कडाउन प्रारूप में नोट्स निर्यात करें। (आप इन एप्लिकेशन को वापस आयात नहीं कर सकते) + पृष्ठभूमि के लिए थीम रंग का उपयोग करें + पृष्ठभूमि के लिए नोट रंग का उपयोग करें + सक्षम करें + अक्षम + फ़ोल्डर सिंक सक्षम करें + फ़ोल्डर सिंक + अपने सभी नोट्स, टैग और फ़ोल्डर्स को बाहरी फ़ोल्डर में सिंक करें। यह आपको डिवाइस के बीच अन्य एप्लिकेशन का उपयोग करके सिंक करने में मदद करता है, साथ ही आपको एप्लिकेशन को हटाने की आवश्यकता होने की स्थिति में एक कॉपी भी है। + फ़ोल्डर में निर्यात कर रहा है + सभी नोट्स, टैग आदि को किसी बाहरी फ़ोल्डर में सिंक करें + बंद नोट निर्यात करें + वर्णमाला + स्कारलेट प्रो पर उपलब्ध है + जो नोट बंद हैं उनका भी बैकअप लें + संपादक विकल्प + नोट संपादक के लिए सेटिंग्स और उपयोग बदलें + डिफ़ॉल्ट के रूप में मार्कडाउन विकल्प + डिफ़ॉल्ट रूप में टूलबार पर मार्कडाउन क्विक बटन दिखाएं + रियलटाइम मार्कडाउन + चुनें कि क्या आप मार्कडाउन को अपने प्रकार के रूप में देखना चाहते हैं। सक्षम करना बड़े नोटों पर प्रदर्शन को प्रभावित कर सकता है। + चेक किए गए आइटम ले जाएं + चेक किए गए आइटम सूची के निचले भाग में जाते हैं। अनचेक स्थिति को रीसेट नहीं करता है। + मूवमेंट हैंडल दिखाएं + आइटम को ऊपर या नीचे ले जाने के लिए हैंडल दिखाएं। आप अभी भी कोने को छूकर चीजों को घुमा सकते हैं। + मार्कडाउन उदाहरण + विजेट सेटिंग्स + होम स्क्रीन विजेट के लिए सेटिंग्स बदलें + स्वरूपण सक्षम करें + नोट्स होम स्क्रीन विजेट में प्रारूपण के साथ प्रदान किए जाते हैं + बंद नोट दिखाएं + बंद नोटों को होम स्क्रीन विजेट में दिखाने की अनुमति दें + संग्रहीत नोट दिखाएं + संग्रहीत नोटों को होम स्क्रीन विजेट में दिखाने की अनुमति दें + ट्रैश में नोट दिखाएं + होम स्क्रीन विजेट में दिखाए जाने वाले ट्रैश में नोट्स दें + सहायता और सामान्य प्रश्न + एप्लिकेशन में सुविधाओं का उपयोग करने के बारे में मदद प्राप्त करें + सिंक कर रहा है + लंबित बैकअप + डेवलपर विकल्प + डिबगिंग के लिए उपयोग किए जाने वाले एप्लिकेशन में आंतरिक सेटिंग्स बदलें + अपवाद लॉग करें + डेवलपर को अग्रेषित करने की अनुमति देने के लिए, एक निश्चित नोट के अपवादों को पकड़ लें + अपवाद शीट दिखाएं + डेवलपर को अग्रेषित करने की अनुमति देने के लिए यदि संभव हो तो एक शीट पर अपवादों को दिखाएं + अपवाद पर फेंक दो + अपवादों पर एप्लिकेशन को फेंकें और क्रैश करें। 5 क्रैश के बाद रीसेट हो जाएगा + पूर्णस्क्रीन सक्षम करें + स्क्रीनशॉट और रिकॉर्डिंग की अनुमति देने के लिए फुलस्क्रीन में ऐप बनाएं + नोट UUIDs दिखाएं + होम स्क्रीन दृश्य में नोटों की अद्वितीय आईडी दिखाएं + नकली अपवाद + अपवाद सुविधाओं का परीक्षण करने के लिए एक नकली अपवाद फेंक दें + अपवाद फेंकना + क्रैश ऐप + मेल + कनेक्शन विफल + Google डिस्क पर सिंक करें + Google ड्राइव आपको अपने स्वयं के Google ड्राइव खाते का उपयोग करके उपकरणों के बीच अपने नोट्स को सिंक करने की अनुमति देता है। + पहले Google Firebase में लॉग इन किया है? + Google ड्राइव में साइन इन करें + साइन इन करें € ¦ ¦ + स्कारलेट से साइन आउट करें + नोट्स, टैग और फ़ोल्डरों को सिंक करना बंद करें। + अपने नोट्स, टैग और फ़ोल्डरों को अपने Google ड्राइव में सिंक करना बंद करें। + ऐप और Google ड्राइव पर आपका डेटा अभी भी रहेगा। + ड्राइव से साइन आउट करें + साइन आउट करना € ¦ + नोट्स, टैग और फ़ोल्डर आपके स्वयं के Google ड्राइव पर संग्रहीत किए जाते हैं, इसलिए केवल आप उन तक पहुंच को नियंत्रित कर सकते हैं। + आपके फ़ोटो अपलोड किए गए हैं और साथ ही उपकरणों में भी सिंक किए गए हैं। + Firebase से डेटा को पुनर्स्थापित करें + Google के साथ साइन इन करें + साइन इन करें € ¦ ¦ + हम आपकी जानकारी Google Firebase पर संग्रहीत करते थे। लॉग इन करने के बाद हम इन्हें आपके डिवाइस पर रिकवर कर लेंगे + नए नोट और परिवर्तन Google Firebase पर सिंक नहीं होंगे, और आपको Google ड्राइव पर लॉगिन करना होगा + एक बार जब आपके नोट बरामद हो जाते हैं, तो आप उन्हें Google Firebase से हटा सकते हैं और फिर स्विच कर सकते हैं + आपका डेटा सिंक नहीं किया जा रहा है! + विरासत लॉगिन पर आधारित डेटा सिंक अक्षम है, Google ड्राइव आधारित सिंक पर स्विच करने पर विचार करें। + फायरबेस से ड्राइव में डेटा ट्रांसफर करें + डेटा साफ़ करें और साइन आउट करें + समाशोधन और हस्ताक्षर करना + हम आपकी जानकारी Google Firebase पर संग्रहीत करते थे। हम आपके नोट्स को आपके Google ड्राइव में संग्रहीत करने के लिए आगे बढ़ रहे हैं। + अधिक गोपनीयता। + फोटो सिंक। + अगला कदम + हम पहले आपके नोट्स को Firebase से हटाकर आपको लॉग आउट करेंगे। + फिर आप Google ड्राइव में लॉग इन कर सकते हैं, और हम आपके डेटा को छवियों के साथ अपलोड करेंगे। + + + विकल्प निकालें + नोटबुक निकालें + केवल नोटबुक निकालें। नोट फ़ोल्डर के बाहर चले जाते हैं। + नोटबुक और नोट्स निकालें + नोटबुक निकालें। सभी नोट ट्रैश में चले जाते हैं या हटा दिए जाते हैं। + नोट निकालें + नोटबुक रखें लेकिन सभी नोट्स ट्रैश में चले जाते हैं या हटा दिए जाते हैं। + फ़ॉन्ट्स अनुकूलित करें + एप्लिकेशन का चयन करें और फोंट नोट करें + एक फ़ॉन्ट सेट का चयन करें + नोट: फ़ॉन्ट्स सभी भाषाओं के साथ ठीक से काम नहीं कर सकते हैं + ऐप डिफ़ॉल्ट + डिवाइस डिफ़ॉल्ट + मोनो + सेरिफ़ + ऐप अनलॉक करें + अनलॉक करने के लिए 4 अंकों का पिन दर्ज करें या बायोमेट्रिक्स का उपयोग करें + अनलॉक करने के लिए 4 अंकों का पिन डालें + सिस्टम थीम का उपयोग करें + सिस्टम से लाइट या डार्क थीम का उपयोग करें + डार्क नोट्स + स्वचालित रूप से नोट और फ़ोल्डर रंगों को गहरा करें + स्थानीय + रिमोट + अनुपलब्ध + बनाया था + हटाए गए + अपडेट किया गया + विजेट पृष्ठभूमि + मल्टी-नोट्स विजेट के लिए पृष्ठभूमि का रंग चुनें + एक्शन टूलबार दिखाएं + मल्टी-नोट्स विजेट टूलबार दिखाता है + नोट व्यूअर को छोड़ें + नोट व्यूअर को छोड़ें और सीधे नोट एडिटर पर जाएं + क्या आप इन नोटों को स्थायी रूप से हटाना चाहेंगे? + तेज़ अद्यतन और अनुरोध। + ऐप लॉक और सिंगल अनलॉक। + अधिक ऐप थीम्स। + नोट फ़ॉन्ट और फ़ॉन्ट आकार। + दर्शक पृष्ठभूमि का रंग। + अधिक विजेट विकल्प। + अधिक नोट क्रियाएँ। + नोट का रंग + नोट टैग + ऐप लॉक सक्षम करें + पूरे एप्लिकेशन को अनलॉक करने के लिए पिन का उपयोग करें + हमेशा पिन मांगते हैं + सभी नोटों के लिए पिन दर्ज करें, भले ही पहले दर्ज किया गया हो + बायोमेट्रिक्स के साथ अनलॉक + एक फिंगरप्रिंट या अन्य बायोमेट्रिक्स के साथ अनलॉक करने की अनुमति दें + बॉयोमीट्रिक्स अक्षम + फिंगरप्रिंट या अन्य बायोमेट्रिक्स के साथ अनलॉक करने की अनुमति न दें + नोट को अनलॉक करें + नोट और पहुंच को अनलॉक करने के लिए डिवाइस फिंगरप्रिंट या बायोमेट्रिक्स का उपयोग करें। + ऐप अनलॉक करें + एप्लिकेशन को अनलॉक करने और सभी नोटों तक पहुंचने के लिए डिवाइस फिंगरप्रिंट या बायोमेट्रिक्स का उपयोग करें। + लॉन्चर शॉर्टकट + फोटो सांझा करें + \ No newline at end of file diff --git a/base/src/main/res/values-hu/strings.xml b/base/src/main/res/values-hu/strings.xml new file mode 100644 index 00000000..c90b7ac9 --- /dev/null +++ b/base/src/main/res/values-hu/strings.xml @@ -0,0 +1,472 @@ + + Cím + Tartalom + Mentés + Importálás + Jegyzetek keresése… + Keresés ezzel… + + Nincsenek jegyzetek + Úgy néz ki, hogy még nem adott hozzá jegyzeteket. Koppintson egy jegyzet hozzáadásához. + + Jegyzet hozzáadása + Ellenőrzőlista hozzáadása + + Jegyzet szerkesztése + Értesítés létrehozása + Megnyitás felugró ablakban + Végleges törlés + Jegyzet másolása + Jegyzet küldése + Jegyzet archiválásának visszavonása + Jegyzet archiválása + Kedvencnek jelölés visszavonása + Kedvencnek jelölés + Jegyzet visszaállítása + Kukába helyezés + Szín módosítása + Jegyzet zárolása + Címkék módosítása + Jegyzet zárolása + Emlékeztető + Kiválasztás + Kétszerezés + Jegyzet rögzítése + Jegyzet rögzítésének feloldása + Zavarásmentés + Jegyzetek egyesítése + Művelet kiválasztása… + + Koppintson a jegyzet szerkesztésre megnyitásához + Koppintson a jegyzet tartalmának vágólapra másolásához + Koppintson a jegyzet tartalmának más alkalmazásokkal megosztásához + Koppintson a jegyzet felugró ablakban megnyitásához + Koppintson a jegyzet törléséhez + Koppintson a jegyzet kukába dobásához + Koppintson a jegyzet helyreállításához a kukából + Koppintson a jegyzet kedvencként megjelöléséhez + Koppintson a jegyzet eltávolításához a kedvencekből + Koppintson a jegyzet archiválásához + Koppintson a jegyzet háttérszínének módosításához + Koppintson a jegyzet helyreállításához az archívumból + + Kezdőlap + Kedvencek + Archivált + Zárolt + Kuka + + Tartalom hozzáadása… + Címsor hozzáadása… + Idézett szöveg hozzáadása… + Elem hozzáadása… + Kód hozzáadása… + Koppintson egy kép hozzáadásához vagy cseréjéhez + + Beállítások + Felület és felhasználói élmény + Válassza ki, hogyan működjön az alkalmazás. + Névjegy + Tudjon meg többet rólunk és az alkalmazásról. + Biztonság + Jegyzetek zárolása és biztonsági beállítások + Listaelrendezés engedélyezése + Jegyzetek megjelenítése egyetlen oszlopban + Rácsnézet engedélyezése + Jegyzetek megjelenítése lépcsőzetes rácsként + Jegyzetek rendezése + Biztonsági mentés és importálás + Biztonsági mentési, importálási és exportálási beállítások + Jegyzetek exportálása + Jegyzetek exportálása az eszköz tárhelyére megosztás céljából + Jegyzetek importálása + Jegyzetek importálása az eszköz tárhelyéről + Exportálás markdownként + Jegyzetek exportálása markdown formátumban. (Ezeket nem importálhatja vissza az alkalmazásba) + Automatikus exportálás + Jegyzetek gyakori exportálása egy külső fájlba biztonsági mentésként + Rólunk + Tudjon meg többet az alkalmazásról és a fejlesztőkről + Nyílt forráskódú projekt + Tudjon meg többet a nyílt forráskódú projektről + Értékelés + Mondja el, mennyire tetszett az alkalmazás + Pro alkalmazás telepítése + A Pro alkalmazás telepítése funkciók feloldásához és a fejlesztő támogatásához + Jegyzetek migrálása a Scarlet Próba + Migrálja az összes jegyzetét a pro alkalmazásba + Jegyzetek törlése és egyebek + Jegyzetek, címkék és egyéb adatok törlése az alkalmazásból + Minden jegyzet törlése + Az összes jegyzet törlése az alkalmazásból + Minden mappa törlése + Az összes mappa törlése az alkalmazásból + Minden címke törlése + Az összes címke törlése az alkalmazásból + Minden törlése + Az összes jegyzet, címke és mappa törlése az alkalmazásból + + Jegyzetmegjelenítő háttere + Témaszín használata a háttérhez + Jegyzetszín használata a háttérhez + + Biztonsági beállítások + Jelkód + Állítson be egy 4 számjegyes PIN-kódot a jegyzetek zárolásához + + Adja meg a PIN-kódot + A feloldáshoz adja meg a PIN-kódot + Adja meg a jelenlegi PIN-kódot + Ellenőrzés + Zárolás + Beállítás + Eltávolítás + + Alapértelmezett jegyzetszín + Válassza ki a jegyzetek alapértelmezett színét + Jegyzetek sorainak számának korlátja + %d sor a kezdőképernyőn + + Markdown támogatás + Markdown támogatott formázás engedélyezése + Markdown a jegyzetlistában + Markdown formázás engedélyezése a jegyzetek listájában + + Engedélyek megadása + Az importálás és exportálás tároló engedélyt igényel. Adja meg az engedélyt, ha kérésre kerül. + Engedélyezés + + Biztonsági mentés importálása fájlból + Fájl importálása + Fájlba exportálva + Exportálás sikertelen + Fájlba exportálás… + Kész + Megosztás + Engedélyezés + Letiltás + Mappaszinkronizálás engedélyezése + Mappaszinkronizálás + Szinkronizálja az összes jegyzetét, címkéjét és mappáját egy külső mappába. Ez segít, ha más alkalmazásokkal szinkronizál az eszközei közt, valamint másolatot készít, ha törölnie kell az alkalmazást. + Mappába exportálás + Az összes jegyzet, címke és egyebek szinkronizálása egy külső mappába + Zárolt jegyzetek exportálása + + Értékelés a Play Áruházban + Közreműködés + Alkalmazásverzió + Az alkalmazás névjegye + + Programkönyvtárak + Nyílt forráskódú projekt + + Emlékeztető dátuma + Emlékeztető ideje + Ismétlési gyakoriság + Csak egyszer + Naponta + + Jegyzetértesítések + Értesítések és riasztások + + + A %s nyílt forráskódú, és bárki közreműködhet a jobbá tételében. Jelenleg %s készíti és tartja karban. + + + A %s egy egyszerű jegyzetkészítő alkalmazás. Gyors gazdag szöveges bemenetet tesz lehetővé, anélkül hogy nehezen használható volna. Gyerekjátékká teszi a párhuzamos munkavégzést. + + Üdv, egy dizájner és programozó páros vagyunk, akik a %s alkalmazást készítették. + Arra vállalkoztunk, hogy szép, gondosan tervezett, reklámmentes vagy csak minimális reklámokat tartalmazó alkalmazásokat készítsünk, amelyek mindenki számára hasznosak. + + Új címke hozzáadása… + Címke szerkesztése… + címke megadása + + Új címke létrehozása + Címke kiválasztása… + + Jegyzetek rendezése + Legújabb elől + Legrégebbi elől + Legutóbb módosítva + Betűrendben + + + Jegyzet kiválasztása + Jegyzetek kiválasztása + Beállítások + A jegyzet törölt vagy zárolt + + + + Újdonságok + Tudja meg, hogy mik az újdonságok az alkalmazás legújabb frissítéseiben + Fordítás + Másolás + Szövegblokk műveletek + Galéria + Kamera + + Jegyzet felolvasása hangosan + Jegyzet felolvasása + Az elem törlése az összes eszközről törli a képet. + A kép nincs ezen az eszközön + A kép nem tölthető be + A képek nincsenek szinkronizálva + A képek nincsenek szinkronizálva az eszközök között. A képek nem fognak megjelenni a többi eszközön, amikor megnézni a jegyzetet. + Megértettem + + + + Jegyzetek betűmérete + A betűméret módosítása a jegyzetek lapon. Az előnézetben láthatja, hogyan nézne ki. + %d képpontos betűk a jegyzetmegjelenítőben + + + + Telepítés az Áruházból + Alkalmazás telepítése a Google áruházból a felhős szinkronizáció miatt + + + + Nincs PIN-kód megadva + Nem állított be PIN-kódot. Szeretné most beállítani? + Később + Ne kérdezze többet + Beállítás + + + + Biztos benne? + Véglegesen törli a jegyzeteket a kuka mappából? + Véglegesen törli ezt a jegyzetet? + Törlés + Mégse + A jegyzetek 7 nap után véglegesen törlésre kerülnek + + + + Információk + Koppintson a legfrissebb alkalmazásverzió telepítéséhez + Koppintson a Scarlet Próra történő frissítéshez + + + + Bejelentkezés az alkalmazásba + Jelentkezzen be felhős biztonsági mentéshez és szinkronizáláshoz + Kijelentkezés + Kijelentkezés a felhős biztonsági mentés leállításához + Google bejelentkezés sikertelen + + Adatvédelmi irányelvek + Az alkalmazás adatvédelmi irányelvei a tartalomhoz + + Pro alkalmazás telepítése + A Scarlet Próban elérhető + + Miért telepítse a Pro verziót + + ✔ Támogassa a fejlesztőt a felhős szinkronizálás jelentős kiszolgálóköltségeiben \n\n✔ Kapja meg először a legfrissebb funkciókat \n\n✔ Egyes további funkciók csak a Pro felhasználók számára lesz elérhetők + + + + + Alkalmazástéma + Válassza ki a téma háttérszínét + Alkalmazástéma kiválasztása + + + Koppintson a címkék hozzáadásához vagy módosításához + + Jegyzetek kiválasztása + Választáson ki több jegyzetet egyszerre, és végezzen rajtuk műveletet + + A jegyzet át lett helyezve a kukába + A jegyzet törlésre került + Visszavonás + + Biztonsági mentés kikapcsolása + Biztonsági mentés bekapcsolása + + Üres jegyzetfüzet + 1 jegyzet + %d jegyzet + Új jegyzetfüzet hozzáadása + Jegyzetfüzet szerkesztése + Jegyzetfüzet hozzáadása + + Jegyzetfüzet hozzáadása + Jegyzetfőzet módosítása + + Friss jegyzetek + + + Szerkesztőbeállítások + A jegyzetszerkesztőt beállításainak és használatának módosítása + + Markdown lehetőséget alapértelmezetten + A markdown gyorsgombok megjelenítése az eszköztáron alapértelmezetten + + Valós idejű markdown + Akkor válassza, ha gépelés közben szeretné látni a markdownt. Bekapcsolása befolyásolhatja a teljesítményt a nagy jegyzeteknél. + + Bejelölt elem áthelyezése + A bejelölt elemek a lista végére kerülnek. A jelölés eltávolítása nem állítja vissza a pozíciót. + + Mozgatási kezelőszervek megjelenítése + Fogantyú megjelenítése az elemek fel és le mozgatásához. A sarkoknál megérintéssel továbbra is átrendezheti a dolgokat. + + Markdown példák + + + + Felületi elem beállítások + A kezdőképernyő felületi elemeinek beállításainak módosítása + + Formázás engedélyezése + A jegyzetek formázva jelennek meg a kezdőképernyőn + + Zárolt jegyzetek megjelenítése + A zárolt jegyzetek megjelenhetnek a kezdőképernyőn + + Archivált jegyzetek megjelenítése + Az archivált jegyzetek megjelenhetnek a kezdőképernyőn + + Kukában lévő jegyzetek megjelenítése + A kukában lévő jegyzetek megjelenhetnek a kezdőképernyőn + + + Súgó és gyakori kérdések + Kapjon segítséget az alkalmazás funkcióinak használatához + + Szinkronizálás + Biztonsági mentés folyamatban + + + Fejlesztői beállítások + Az alkalmazás belső beállításainak módosítása hibakeresés céljából + + Kivételek naplózása + Elkapott kivételek naplózása egy rögzített bejegyzésbe, hogy továbbküldhesse a fejlesztőnek + + Kivételek megjelenítése egy lapon + Elkapott kivételek megjelenítése egy lapon, ha az lehetséges, hogy továbbküldhesse a fejlesztőnek + + Kivételek továbbdobása + Kivételek továbbdobása és az alkalmazás összeomlasztása. 5 összeomlás után vissza lesz állítva + + Teljes képernyő engedélyezése + Az alkalmazás teljes képernyősre állítása, hogy képernyőképeket és -felvételeket készíthessen + + Jegyzetek UUID azonosítójának megjelenítése + A jegyzetek egyedi azonosítójának megjelenítése a kezdőképernyőn + + Hamis kivételek + Hamis kivétel dobása a kivételfunkciók teszteléséhez + + Kivétel dobva + Alkalmazás összeomlasztása + E-mail + + + Kapcsolódás sikertelen + Szinkronizálás a Google Drive-on + A Google Drive-val szinkronizálhatja a jegyzeteit az eszközei között a saját Google Drive fiókjával. + Már bejelentkezett a Google Firebase-be? + Bejelentkezés a Google Drive-ba + Bejelentkezés… + + Kijelentkezés a Scarletből + Jegyzetek, címkék és mappák szinkronizálásának leállítása. + Jegyzetek, címkék és mappák Google Drive szinkronizálásának leállítása. + Az adatai megmaradnak az alkalmazásban és a Google Drive-on. + Kijelentkezés a Drive-ból + Kijelentkezés… + + A jegyzetei, címkéi és mappái a saját Google Drive-jában lesznek tárolva, így a hozzáférésük felett Ön rendelkezik. + A fényképei is fel lesznek töltve, és szinkronizálásra kerülnek a többi eszközével. + + + Adatok visszaállítása a Firebase-ből + Google bejelentkezés + Bejelentkezés… + + Az adatait a Google Firebase-ben tároltuk. Bejelentkezés után visszaállítjuk ezeket az eszközére + Az új jegyzetek NEM lesznek szinkronizálva a Google Firebase-be, és be kell jelentkeznie a Google Drive-ba + Ha helyreállításra kerültek a jegyzetei, törölheti azokat a Google Firebase-ből, és átválthat + + Az adatai nem szinkronizáltak. + A régi bejelentkezésre épülő adatszinkronizálás letiltásra került, fontolja meg, hogy a Google Drive-alapú szinkronizálásra vált. + + Adatok átvitele a Firebase-ből a Drive-ba + Adatok törlése és kijelentkezés + Törlés és kijelentkezés + Az adatait eddig a Google Firebase-ben tároltuk. A jegyzetei tárolását átvisszük a Google Drive-jába. + Több adatvédelem. + Fénykép-szinkronizálás + Következő lépések + Először töröljük a jegyzeteit a Firebase-ből és kijelentkeztetjük. + Aztán bejelentkezhet a Google Drive-ba, és feltöltjük az adatait a képeivel együtt. + + + Távolítsa el az Opciókat + Távolítsa el a Notebookot + Csak a Notebook-ot távolítsa el. A jegyzetek a mappán kívülre kerülnek. + Távolítsa el a Notebookot és a Jegyzeteket + Távolítsa el a Notebookot. Minden jegyzet a kukába kerül vagy törlődik. + Távolítsa el a megjegyzéseket + Tartsa a Notebookot, de az összes jegyzet a kukába kerül, vagy törlődik. + Testreszabhatja a betűkészleteket + Válassza ki az alkalmazást és a jegyzet betűkészleteit + Válasszon egy betűkészletet + Megjegyzés: Lehet, hogy a betűtípusok nem működnek megfelelően minden nyelven + Alapértelmezett alkalmazás + Device Default + Monó + betűtalp + Unlock App + Írja be a 4 számjegyű PIN kódot, vagy használja a biometrikus adatokat a feloldáshoz + Írja be a 4 számjegyű PIN kódot a feloldáshoz + Használja a Rendszer témát + Használja a rendszer világos vagy sötét témáját + Sötét jegyzetek + A jegyzet és a mappa színei automatikusan elsötétülnek + Helyi + Távoli + Nem érhető el + Alkotó + törölve + korszerűsített + Widget háttér + Válassza ki a multi-notes widget háttérszínét + Mutassa a Művelet eszköztárat + A többjegyű widget az eszköztárat mutatja + A Megjegyzés néző átugrása + Átugorja a jegyzetnézegetőt, és ugorjon közvetlenül a jegyzetszerkesztőre + Véglegesen törli ezeket a megjegyzéseket? + Gyorsabb frissítések és kérések. + App Lock és Single Unlock. + Több App témák. + Megjegyzés: Betűtípusok és betűméret. + Viewer háttér színét. + További widget-beállítások. + További megjegyzésműveletek. + Megjegyzés színe + Megjegyzés címkék + A lezárt jegyzeteket is készítsen biztonsági másolatot + Engedélyezze az alkalmazászárat + Használja a PIN-kódot a teljes alkalmazás feloldásához + Mindig kérjen PIN-kódot + Írja be az összes jegyzet PIN-kódját, még akkor is, ha korábban megadta + Nyisd ki a biometrikus adatokkal + Engedélyezze az ujjlenyomat vagy más biometrikus elem feloldását + A biometria le van tiltva + Ne engedje meg ujjlenyomat vagy más biometrikus elem feloldását + Megjegyzés feloldása + Használja az eszköz ujjlenyomatát vagy biometrikus adatait a jegyzet feloldásához és a hozzáféréshez. + Unlock App + Használjon eszköz ujjlenyomatát vagy biometrikus adatait az alkalmazás feloldásához és az összes jegyzet eléréséhez. + Launcher parancsikon + Fotók megosztása + + diff --git a/base/src/main/res/values-it/strings.xml b/base/src/main/res/values-it/strings.xml index 84518527..26d4a783 100644 --- a/base/src/main/res/values-it/strings.xml +++ b/base/src/main/res/values-it/strings.xml @@ -6,25 +6,18 @@ Condividi con… Nessuna nota Sembra che non hai aggiunto alcuna nota. Fai clic per aggiungere una nota. - Aggiungi una nota… - Aggiungi nota veloce… Modifica nota - Apri in popup - Elimina nota + Apri in pop-up Copia nota Invia nota Scegli un\'azione… Aggiungi contenuto… Aggiungi intestazione… - Aggiungi sottotitolo… Aggiungi testo citato… Aggiungi elemento… Aggiungi codice… - Markdown Support - Consenti la formattazione markdown - Esempi - Impostazioni Markdown - Scopri come utilizzare il markdown nelle note + Supporto Markdown + Consenti la formattazione Markdown Opzioni e impostazioni Esporta note Esporta le note nella memoria del dispositivo @@ -34,17 +27,16 @@ Scopri di più sull\'app e sugli sviluppatori Valuta e recensisci Facci sapere quanto ti è piaciuta l\'app - Dai i permessi - L\'importazione e l\'esportazione richiedono il permesso di archiviazione. Si prega di dare il permesso quando richiesto. - Permetti + Concedi permessi + L\'importazione e l\'esportazione richiedono il permesso di archiviazione. Si prega di concedere il permesso quando richiesto. + Concedi Importa backup da file Importa file Esportato nel file Esportazione fallita - Esportazione nel file… + Esportazione su file… Ok Condividi - Informazioni Vota su Play Store Contribuisci Versione dell\'app @@ -53,18 +45,13 @@ Proteggi nota Sblocca nota Sicurezza - Opzioni di sicurezza e di blocco + Blocco delle note e opzioni di sicurezza Opzioni di sicurezza Codice di accesso Imposta un PIN di 4 cifre per proteggere le note - Sblocca con Fingerprint - Le note verranno sbloccate con l\'impronta digitale - Impronta digitale disabilitata - Le note non utilizzeranno un\'impronta digitale Inserisci il nuovo PIN Inserisci il PIN per sbloccare Inserisci il PIN corrente - Inserisci il PIN Verifica Sblocca Imposta @@ -74,16 +61,9 @@ Abilita layout a griglia Mostra le note in una griglia sfalsata - Modalità giorno Cambia colore - Tocca per visualizzare la nota nella modalità giorno Tocca per cambiare il colore di sfondo della nota - Abilita modalità notte - Abilita il tema scuro come predefinito - Abilita modalità giorno - Abilita il tema chiaro come predefinito - Modalità notturna Elimina definitivamente Rimuovi nota dall\'archivio Archivia nota @@ -91,7 +71,6 @@ Aggiungi ai preferiti Ripristina nota Sposta nel cestino - Tocca per visualizzare la nota nella modalità notte Tocca per modificare la nota Tocca per copiare il contenuto della nota negli appunti Tocca per condividere il contenuto della nota con altre app @@ -103,43 +82,31 @@ Tocca per contrassegnare la nota come non preferita Tocca per archiviare la nota Tocca per annullare l\'archiviazione della nota - I tuoi appunti… Home - Tutte le tue note normali e preferite Preferiti - Tutte le tue note preferite Archivio - Tutte le tue note archiviate Cestino - Tutte le tue note nel cestino Crea notifica - Note in notifica + Note nell\'area di notifica Protetti - Tutte le tue note protette - Tag - Tutti i tuoi tag Aggiungi nuovo tag… Modifica tag… - inserisci il tag + Inserisci il tag Crea un nuovo tag Scegli un tag… Importa - Markdown in Elenco note + Markdown nell\'elenco delle note Abilita la formattazione Markdown nell\'elenco delle note - Rispondi al sondaggio - Aiutaci a migliorare l\'app dicendoci cosa ti piace Cambia tag Ordine note - Progetto Open Source + Progetto open source Scopri di più sul progetto open source Librerie - Progetto Open Source - Informazioni sul progetto Open Source - Aggiungi promemoria + Progetto open source Data del promemoria Ora del promemoria Frequenza ripetizione @@ -152,27 +119,25 @@ Sblocca nota - Interfaccia ed esperienza - Scegli l\'aspetto dell\'app. - Preferenze nota - Scegli preferenze e altre impostazioni. - Chi siamo - Scopri di più su di noi e sull\'app. + Interfaccia ed esperienza utente + Modifica l\'aspetto dell\'app + Informazioni sull\'app + Scopri di più su di noi e sull\'app Colore nota predefinita Scegli il colore predefinito delle note - Limite lunghezza note + Lunghezza anteprima note Backup e importazione Backup, importazione ed esportazione delle note Installa dallo store - Installa app da Google Store per Cloud Sync + Installa l\'app dallo store di Google per effettuare la sincronizzazione con il cloud Nessun PIN impostato Non hai impostato il PIN. Vuoi impostarlo ora? - Dopo + Più tardi Non chiedere mai Imposta @@ -184,124 +149,93 @@ Vuoi eliminare definitivamente questa nota? Elimina Annulla - Le note vengono cancellate per sempre dopo 7 giorni + Le note vengono cancellate definitivamente dopo 7 giorni Aggiungi nota - Aggiungi lista di controllo - Formattazione - Intestazione - Sottotitolo - Testo - Citazione - Codice - Lista di controllo - Formattazione Markdown - Grassetto - Corsivo - Sottolinea - Barrato - Elenco + Aggiungi nota con elenco Seleziona una nota - Seleziona Note + Seleziona note Impostazioni Nota cancellata o protetta Dimensione carattere - Regola le dimensioni del carattere del testo nella pagina delle note. Puoi vedere come sarebbe in questa anteprima. - %d dimensioni del testo nel visualizzatore note + Regola le dimensioni del carattere del testo delle note. Puoi vedere come apparirà in questa anteprima. + Dimensione del testo nel visualizzatore note: %d Cosa c\'è di nuovo - Scopri cosa c\'è di nuovo nei recenti aggiornamenti dell\'app + Scopri cosa c\'è di nuovo negli ultimi aggiornamenti dell\'app Traduci - Fai clic per aggiungere una nuova nota - Clicca per vedere le opzioni della home - Il menu principale contiene le note preferite e archiviate, nonché le impostazioni dell\'applicazione. Puoi trovare anche i tuoi tag. Accedi all\'app - Accedi per il backup e la sincronizzazione del cloud + Accedi per il backup e la sincronizzazione con il cloud Disconnessione - Esci per interrompere il backup del cloud - Accedi con Google - Accesso in € | - Ti sei autenticato - Accesso Google non riuscito - politica sulla riservatezza - Politica sulla privacy dell\'app per il contenuto - Installa l\'app Pro - Perché installare Pro - Supporta lo sviluppatore per i massivi costi del server, per eseguire la sincronizzazione del cloud \n\n Prima le funzionalità più recenti \n\n Alcune funzioni aggiuntive saranno disponibili solo per gli utenti Pro - Perché abilitare Cloud Sync - Carica e fai il backup delle modifiche del dispositivo \n\n Sincronizza tra più dispositivi e ottieni aggiornamenti rapidi \n\n Salvataggio sicuro sui server Firebase di Google - Ciao, - Le note materiali sono ora scarlatte! - Iniziare + Esci per interrompere il backup sul cloud + Accesso a Google non riuscito + Privacy policy + Privacy policy dell\'app per il contenuto + Installa la versione Pro + Perché installare la versione Pro + Supporta lo sviluppatore per i costi del server necessari ad eseguire la sincronizzazione con il cloud \n\n Ottieni prima le ultime funzionalità \n\n Alcune funzioni aggiuntive saranno disponibili solo per gli utenti Pro - copia - Blocca azioni di testo + Copia + Azioni blocco di testo Galleria - telecamera - Parla ad alta voce - Parlare a voce alta - L\'eliminazione di questo elemento eliminerà l\'immagine da tutti i dispositivi. - Immagine non su questo dispositivo + Fotocamera + Leggi ad alta voce + Leggi ad alta voce + La cancellazione di questo elemento eliminerà l\'immagine da tutti i dispositivi. + Immagine non presente su questo dispositivo L\'immagine non può essere caricata Le immagini non sono sincronizzate - Le immagini non sono sincronizzate su tutti i dispositivi. Le tue immagini non verranno visualizzate su altri dispositivi durante la visualizzazione della nota! + Le immagini non sono sincronizzate su tutti i dispositivi. Le tue immagini non verranno visualizzate sugli altri dispositivi! Capisco Esporta automaticamente Esporta frequentemente le note in un file esterno come backup - Immagine Clicca per aggiungere o cambiare immagine Solo una volta Quotidiano - costume - Beta - Promemoria e allarmi - %s è open source e chiunque è aperto a contribuire a migliorarlo. Attualmente è costruito e gestito da %s. - %s è una semplice app per prendere appunti. Permette di inserire rapidamente Rich Text senza rendere l\'esperienza molto difficile da usare. Rende il multi-tasking un gioco da ragazzi. - Ciao, siamo una coppia di designer e programmatori, che ha creato %s. - Ci sforziamo di creare app pubblicitarie gratuite, pubblicitarie o minime, progettate con cura, che siano di grande utilità per tutti! - %d linee sulla schermata iniziale - Cerca %s … - Distrazione gratuita - Separatore + Promemoria e sveglie + %s è open source e chiunque è libero di contribuire per migliorarla. Attualmente è sviluppata e gestita da %s. + %s è una semplice app per prendere appunti. Permette di inserire rapidamente testo formattato senza rendere complicata l\'esperienza utente. Rende il multi-tasking un gioco da ragazzi. + Ciao, siamo una coppia di designer e programmatori che ha creato %s. Ci sforziamo di creare app progettate con cura, senza o con poca pubblicità, che siano di grande utilità per tutti! + %d linee sulla schermata principale + Senza distrazioni Tema dell\'app Seleziona il colore di sfondo per il tema - Seleziona tema app + Seleziona il tema dell\'app Fai clic per aggiungere o modificare i tag - Mostra più azioni - Seleziona Note + Seleziona note Seleziona ed esegui azioni su più note contemporaneamente La nota è stata spostata nel cestino La nota è stata cancellata - Disfare - Disabilita backup - Abilita backup + Annulla + Escludi dal backup + Includi nel backup Notebook vuoto 1 nota - %d Note - Crea nuovo taccuino + %d note + Crea nuovo blocco note Modifica blocco note - Aggiungi notebook + Aggiungi blocco note Aggiungi al blocco note - Modifica notebook + Modifica blocco note Note recenti Informazione Tocca per installare la versione più recente dell\'app - Toccare per aggiornare a Scarlet Pro - Installa l\'app Pro - Installa l\'app Pro per sbloccare funzionalità e supportare lo sviluppatore - Migrazione di Notes a Scarlet Pro - Migra tutte le tue note all\'app pro + Tocca per passare a Scarlet Pro + Installa la versione Pro + Installa la versione Pro per sbloccare funzionalità e supportare lo sviluppatore + Migra le note su Scarlet Pro + Migra tutte le tue note sulla versione Pro Elimina note e altro Elimina note, tag e altri dati nell\'app Elimina tutte le note @@ -312,6 +246,159 @@ Elimina tutti i tag nell\'app Elimina tutto Elimina note, tag e cartelle nell\'app - Note sullo sfondo del visualizzatore + Sfondo visualizzatore note + + + Unisci note + Esporta come Markdown + Esporta le note in formato Markdown (non è possibile importarle nuovamente nell\'app) + Usa il colore del tema per lo sfondo + Usa il colore della nota per lo sfondo + Abilita + Disabilita + Abilita sincronizzazione cartella + Sincronizzazione cartella + Sincronizza tutte le note, i tag e le cartelle in una cartella esterna. Questo ti aiuta a sincronizzare i dati utilizzando altre app su più dispositivi, oltre ad averne una copia nel caso in cui tu decida di eliminare l\'app. + Esportazione nella cartella + Sincronizza tutte le note, i tag, ecc. in una cartella esterna + Esporta note protette + Alfabetico + Disponibile su Scarlet Pro + Effettua anche il backup delle note che sono protette + Opzioni dell\'editor + Modifica le impostazioni dell\'editor delle note + Mostra opzioni Markdown come predefinite + Mostra i pulsanti rapidi per la formattazione Markdown sulla barra degli strumenti come impostazione predefinita + Formattazione Markdown in tempo reale + La formattazione Markdown verrà applicata mentre scrivi. Può influire sulle prestazioni su note di grandi dimensioni. + Riordina elementi selezionati + Gli elementi selezionati verranno spostati in fondo all\'elenco + Mostra maniglie di movimento + Mostra la maniglia per spostare gli elementi. Se l\'opzione è disabilitata, potrai comunque spostarli toccando l\'angolo. + Esempi di formattazione Markdown + Impostazioni dei widget + Modifica le impostazioni per i widget della schermata principale + Abilita formattazione + Le note vengono visualizzate con formattazione nei widget della schermata principale + Mostra note protette + Consenti alle note protette di essere visualizzate nei widget della schermata principale + Mostra note archiviate + Consenti alle note archiviate di essere visualizzate nei widget della schermata principale + Mostra note nel cestino + Consenti alle note nel cestino di essere visualizzate nei widget della schermata principale + Aiuto e domande comuni + Trova assistenza su come utilizzare le funzionalità dell\'app + Sincronizzazione + Backup in sospeso + Opzioni sviluppatore + Modifica le impostazioni interne utilizzate per il debug + Registra eccezioni + Registra le eccezioni rilevate su una nota fissata per consentirne l\'inoltro allo sviluppatore + Mostra eccezioni + Mostra le eccezioni rilevate, se possibile, per consentirne l\'inoltro allo sviluppatore + Propaga eccezioni + Fa crashare l\'applicazione in caso di eccezioni. L\'opzione verrà ripristinata dopo 5 arresti anomali + Abilita modalità schermo intero + Rendi l\'app a schermo intero per consentire screenshot e registrazioni + Mostra UUID note + Mostra gli ID univoci delle note nella schermata principale + Eccezioni fasulle + Lancia un\'eccezione fasulla per testare le funzionalità relative alle eccezioni + Eccezione generata + Fai crashare l\'app + Invia email + Connessione fallita + Sincronizza su Google Drive + Google Drive ti consente di sincronizzare le tue note tra i dispositivi utilizzando il tuo account Google. + Hai effettuato l\'accesso a Google Firebase in precedenza? + Accedi a Google Drive + Accesso in corso… + Esci da Scarlet + Smetti di sincronizzare note, tag e cartelle. + Interrompi la sincronizzazione di note, tag e cartelle su Google Drive. + I tuoi dati sull\'app e su Google Drive rimarranno al loro posto. + Esci da Drive + Disconnessione in corso… + Note, tag e cartelle sono memorizzati sul tuo Google Drive, quindi solo tu puoi controllarne l\'accesso. + Le tue foto vengono caricate e sincronizzate anche su tutti i dispositivi. + Ripristina dati da Firebase + Accedi con Google + Accesso in corso… + Conservavamo i tuoi dati su Google Firebase. Dopo aver effettuato l\'accesso, li ripristineremo sul tuo dispositivo + Le tue note NON verranno più sincronizzate con Google Firebase e dovrai accedere a Google Drive + Una volta recuperate le note, è possibile eliminarle da Google Firebase ed effettuare la migrazione + I tuoi dati non vengono sincronizzati! + La sincronizzazione dei dati basata sull\'accesso legacy è disabilitata, considera la possibilità di passare alla sincronizzazione basata su Google Drive. + Trasferisci dati da Firebase a Drive + Cancella dati ed esci + Cancellazione e disconnessione + Conservavamo le tue informazioni su Google Firebase. Stiamo passando alla memorizzazione delle note nel tuo Google Drive. + Più privacy. + Sincronizzazione foto. + Prossimi passi + Prima elimineremo le tue note da Firebase e ti disconnetteremo. + Puoi quindi accedere a Google Drive e noi caricheremo i tuoi dati insieme alle immagini. + Vuoi eliminare definitivamente queste note? + Sblocca l\'app + Inserisci il PIN di 4 cifre per effettuare lo sblocco + Inserisci il PIN di 4 cifre o usa l\'impronta per effettuare lo sblocco + Dimenticami + Disconnettimi e rimuovi tutti i dati memorizzati online + Blocco dell\'app e sblocco singolo delle note. + Più temi. + Selezione della dimensione del carattere. + Aggiornamenti e richieste più veloci. + Più opzioni per i widget. + Colore di sfondo dinamico del visualizzatore note. + Locale + Remoto + Creato + Eliminato + Non disponibile + Aggiornato + Richiedi sempre il PIN + Richiedi il PIN per ciascuna nota protetta, anche se è stato già inserito + Abilita blocco dell\'applicazione + Usa il PIN per sbloccare l\'applicazione + Colore delle note + Tag delle note + Sfondo del widget + Scegli il colore di sfondo per il widget multi-nota + Mostra barra delle azioni + Mostra la barra delle azioni nel widget multi-nota + + + Opzioni di rimozione + Rimuovi il blocco note + Rimuovi solo il blocco note. Le note al suo interno verranno spostate al di fuori di esso. + Rimuovi blocco note e contenuto + Rimuovi il blocco note. Tutte le note al suo interno verranno eliminate. + Rimuovi note + Mantieni il blocco note, ma elimina tutte le note al suo interno. + Personalizza il tipo di carattere + Seleziona il tipo di carattere utilizzato nell\'applicazione + Seleziona un tipo di carattere + Nota: i caratteri potrebbero non funzionare correttamente con tutte le lingue + Predefinito + Dispositivo + Monospaziato + Serif + Usa tema di sistema + Usa il tema chiaro o scuro impostato dal sistema + Note scure + Rende automaticamente più scuri i colori delle note e delle cartelle + Salta visualizzatore note + Salta il visualizzatore delle note e passa direttamente all\'editor + Più azioni per le note. + Sblocca con autenticazione biometrica + Consenti lo sblocco con un\'impronta digitale o altri identificatori biometrici + Autenticazione biometrica disabilitata + Non consentire lo sblocco con impronta digitale o altri identificatori biometrici + Sblocca nota + Usa l\'impronta digitale o l\'identificatore biometrico configurato per sbloccare la nota e accedervi. + Sblocca app + Usa l\'impronta digitale o l\'identificatore biometrico configurato per sbloccare l\'app e accedere a tutte le note. + Scorciatoia nel launcher + Condividi foto diff --git a/base/src/main/res/values-iw/strings.xml b/base/src/main/res/values-iw/strings.xml index b29ecf1f..aff1ffa1 100644 --- a/base/src/main/res/values-iw/strings.xml +++ b/base/src/main/res/values-iw/strings.xml @@ -6,39 +6,26 @@ שתף באמצעות … אין הערות נראה שלא הוספת הערות. לחץ כדי להוסיף הערה. - הוסף הערה… - הוסף הערה מהירה … ערוך הערה פתח ב- Popup - מחק הערה העתק הערה שלח הערה בחר פעולה… הוסף תוכן … הוסף כותרת … - הוסף כותרת משנה … הוסף טקסט מצוטט … הוסף פריט… הוסף קוד … חפש הערות - מצב יום שינוי צבע - הקש כדי להציג את ההערה במצב יום הקש כדי לשנות את צבע הרקע של ההערה - הפעל מצב לילה - אפשר עיצוב כהה כברירת מחדל - הפעל מצב יום - אפשר עיצוב אור כברירת מחדל הפעל פריסת רשימה הצג הערות בעמודה אחת הפעל פריסת רשת הצג הערות ברשת מטושטשת תמיכה Markdown אפשר עיצוב נתמך של סימון - דוגמאות - הגדרות Markdown - ראה כיצד להשתמש ב- markdown בהערות הערה נעל נעילת הערה בִּטָחוֹן @@ -46,14 +33,9 @@ אפשרויות אבטחה מעבר קוד הגדר PIN 4 ספרות כדי לנעול הערות - נעילת עם טביעת אצבע - פתקים יפתח עם טביעת האצבע - טביעת אצבע מושבתת - ההערות לא ישתמשו בטביעת אצבע הזן קוד PIN חדש הזן PIN כדי לבטל את הנעילה הזן את קוד ה- PIN הנוכחי - להזין את הקוד לְאַמֵת לבטל נעילה מַעֲרֶכֶת @@ -78,13 +60,11 @@ ייצוא ל- fileâ € בוצע לַחֲלוֹק - אודותינו ועוד שיעור על חנות Play לתרום גרסת האפליקציה על האפליקציה - מצב לילה מחק לצמיתות Unarchive הערה הערה בארכיון @@ -92,7 +72,6 @@ סמן מועדף שחזור הערה העבר לאשפה - הקש כדי להציג את ההערה במצב לילה הקש כדי לפתוח פתק לעריכה הקש כדי להעתיק תוכן הערה ללוח הקש כדי לשתף תוכן הערה ביישומים אחרים @@ -104,21 +83,13 @@ הקש כדי לסמן הערה לא כאתר מועדף הקש כדי להעביר לארכיון את ההערה הקש כדי לשחרר את ההערה מהארכיון - ההערות שלך בית - כל ההערות הרגילות והמועדפות שלך מועדפים - כל ההערות המועדפות עליך בארכיון - כל ההערות שלך בארכיון אַשׁפָּה - כל ההערות שלך באשפה צור הודעה הערה הודעות נָעוּל - כל ההערות הנעולות שלך - תגים - כל תגי ההערות שלך הוסף תג חדש ערוך Taga הזן תג @@ -129,8 +100,6 @@ יְבוּא Markdown ברשימת ההערות הפעל עיצוב Markdown ברשימת ההערות - מילוי סקר - עזור לנו לשפר את האפליקציה על ידי כך שתספר לנו מה אתה אוהב שנה תגים @@ -139,8 +108,6 @@ לדעת יותר על פרוייקט קוד פתוח ספריות פרוייקט קוד פתוח - על פרוייקט קוד פתוח - הערה תזכורת תאריך תזכורת זמן תזכורת חזור על תדר @@ -155,8 +122,6 @@ ממשק וניסיון בחר כיצד האפליקציה נראית ומרגישה. - הערה העדפות - בחר הערה והגדרות אחרות. על אודות למידע נוסף עלינו ועל האפליקציה. ברירת מחדל הערה צבע @@ -191,19 +156,6 @@ להוסיף הערה הוסף רשימת בדיקה - חסום עיצוב - כּוֹתֶרֶת - כותרת משנה - טֶקסט - ציטוט - קוד - צ\'ק ליסט - עיצוב סמן - נוֹעָז - אוֹתִיוֹת מוּטוֹת - לָשִׂים דָגֵשׁ - לְהַכּוֹת - רשימה בחר הערה בחר הערות הגדרות @@ -217,29 +169,18 @@ מה חדש דע מה חדש בעדכונים האחרונים של האפליקציה לתרגם - לחץ כדי להוסיף הערה חדשה - לחץ כדי לראות את אפשרויות הבית - בתפריט הבית יש הערות מועדפות וארכיוניות, כמו גם הגדרות יישום. תוכל למצוא את התגים שלך גם כאן. היכנס לאפליקציה היכנס לגיבוי ענן ולסינכרון התנתק צא כדי לעצור את גיבוי הענן - היכנס באמצעות Google - כניסה - אתה מחובר הכניסה של Google נכשלה מדיניות פרטיות מדיניות הפרטיות של האפליקציה עבור התוכן התקן Pro App למה להתקין Pro תמיכה מפתח עבור עלויות השרת מסיבית, כדי להפעיל את סנכרון ענן \n\n קבל את התכונות החדשות הראשון \n\n כמה תכונות נוספות יהיה זמין רק למשתמשים Pro - מדוע להפעיל את Cloud Sync - טען וגבה מפני שינויי מכשירים \n\n סנכרון בין מכשירים מרובים, וקבל עדכונים מהירים \n\n נשמר באופן מאובטח בשרתי Google Firebase - שלום, - הערות החומר הוא עכשיו סקרלט! - להתחיל עותק @@ -256,30 +197,24 @@ אני מבין ייצוא אוטומטי ייצוא הערות לעתים קרובות לקובץ חיצוני כגיבוי - תמונה לחץ כדי להוסיף או לשנות את התמונה רק פעם אחת יום יומי - המותאם אישית - בטא תזכורות ו אזעקות %s הוא קוד פתוח וכל אחד פתוח לתרום כדי לעשות את זה טוב יותר. הוא נבנה כעת ומתוחזק על ידי %s. %s הוא פתק פשוט לוקח יישום. זה מאפשר קלט טקסט עשיר עשיר מבלי להפוך את החוויה קשה מאוד לשימוש. זה עושה multi-tasking משב רוח. היי, אנחנו זוג מעצב ומתכנת, שיצר %s. אנו משתדלים לבנות יפה, תוכנן בקפידה ללא תשלום, מודעות חינם או מודעות מינימלי אשר משרתים כלי נהדר לכולם! %d שורות במסך הבית - חיפוש %s … הסחת דעת חינם - מפריד נושא בחר את צבע הרקע עבור ערכת הנושא בחר ערכת נושא של אפליקציות לחץ כדי להוסיף או לשנות תגים - הצג פעולות נוספות בחר הערות בחר וביצע פעולות במספר הערות בבת אחת הפתק הועבר לאשפה @@ -315,4 +250,155 @@ מחק הערות, תגים ותיקיות באפליקציה הערה מציג רקע + + מיזוג הערות + ייצא כסימון + ייצא הערות בפורמט סימון. (אינך יכול לייבא אותם בחזרה לאפליקציה) + השתמש בצבע הנושא לרקע + השתמש בצבע הערה לרקע + אפשר + השבת + הפעל סנכרון תיקיות + סינכרון תיקיות + סנכרן את כל ההערות, התגים והתיקיות שלך לתיקיה חיצונית. זה עוזר לך לסנכרן שימוש באפליקציות אחרות בין מכשירים, וכן לקבל עותק למקרה שתצטרך למחוק את האפליקציה. + מייצא לתיקיה + סנכרן את כל ההערות, התגים וכו \'לתיקיה חיצונית + ייצא פתקים נעולים + אלפביתי + זמין ב- Scarlet Pro + גבה גם את הפתקים הנעולים + אפשרויות עורך + שנה את ההגדרות והשימוש עבור עורך ההערות + אפשרויות סימון כברירת מחדל + הצג את לחצני המהירות לסימון בסרגל הכלים כברירת מחדל + Markdown בזמן אמת + בחר אם ברצונך שהסימון יהיה גלוי כסוג. הפעלה יכולה להשפיע על הביצועים על תווים גדולים. + העבר פריטים מסומנים + פריטים מסומנים עוברים לתחתית הרשימה. ביטול הסימון אינו מאפס את המיקום. + הצג ידיות תנועה + הצג את הידית כדי להזיז פריטים למעלה או למטה. אתה עדיין יכול להזיז דברים על ידי נגיעה בפינה. + דוגמאות לסריקה + הגדרות יישומון + שנה את ההגדרות עבור יישומוני מסך הבית + אפשר עיצוב + הערות ניתנות באמצעות עיצוב בווידג\'טים של מסך הבית + הצג פתקים נעולים + אפשר להציג הערות נעולות בווידג\'טים של מסך הבית + הצג הערות בארכיון + אפשר להצגת הערות בארכיון בווידג\'טים של מסך הבית + הצג הערות באשפה + אפשר להצגת ההערות באשפה בווידג\'טים של מסך הבית + עזרה ושאלות נפוצות + מצא עזרה כיצד להשתמש בתכונות באפליקציה + מסנכרן + ממתין לגיבוי + אפשרויות למפתחים + שנה הגדרות פנימיות ליישום המשמש לניפוי באגים + חריגים ביומן + יומן חריגים שנתפסו לפתק קבוע, כדי לאפשר העברה למפתח + הצג גיליון חריג + הצג חריגים שנתפסו על גיליון במידת האפשר, כדי לאפשר העברה למפתח + זרוק על חריגים + זרוק את האפליקציה והתרסק אותה על חריגים. יתאפס לאחר 5 קריסות + אפשר מסך מלא + הפוך את האפליקציה למסך מלא כדי לאפשר צילומי מסך והקלטות + הצג UUIDs הערה + הצג את המזהים הייחודיים של ההערות בתצוגת מסך הבית + חריגים מזויפים + זרוק חריג מזויף לבדיקת תכונות החריגה + חריגה נזרקת + אפליקציית התרסקות + דואר + חיבור נכשל + סנכרן בכונן Google + כונן Google מאפשר לך לסנכרן את ההערות שלך בין מכשירים באמצעות חשבון Google Drive שלך. + התחברת ל- Firebase של גוגל לפני? + היכנס ל- Google Drive + חתימה על פנימה + יציאה מסקרלט + הפסק לסנכרן הערות, תגיות ותיקיות. + הפסק לסנכרן את ההערות, התגיות והתיקיות שלך לכונן Google שלך. + הנתונים שלך באפליקציה וב- Google Drive עדיין יהיו שם. + צא מכונן + יציאה החוצה … + הערות, תגים ותיקיות מאוחסנים בכונן Google שלך, כך שרק אתה יכול לשלוט על הגישה אליהם. + גם התמונות שלך מועלות ומסונכרנות בין מכשירים. + שחזר נתונים מבסיס האש + היכנס באמצעות Google + חתימה על פנימה + נהגנו לאחסן את המידע שלך ב- Google Firebase. לאחר הכניסה נשחזר אותם למכשיר שלך + הערות ושינויים חדשים לא יסונכרנו עם Google Firebase, ועליך להיכנס ל- Google Drive + לאחר שההערות שלך יתאוששו, אתה יכול למחוק אותן מ- Google Firebase ואז לעבור + הנתונים שלך לא מסונכרנים! + סנכרון נתונים המבוסס על כניסה מדור קודם אינו זמין, שקול לעבור לסנכרון מבוסס Google Drive. + העבר נתונים מכונן האש לכונן + נקה נתונים ויצא + ניקוי ויציאה + נהגנו לאחסן את המידע שלך ב- Google Firebase. אנו עוברים לאחסון הערות בכונן Google שלך. + פרטיות רבה יותר. + סינכרון תמונות. + הצעדים הבאים + אנו נמחק תחילה את ההערות שלך מ- Firebase ונצא אותך. + לאחר מכן תוכל להיכנס ל- Google Drive ונעלה את הנתונים שלך יחד עם תמונות. + + + הסר אפשרויות + הסר את המחברת + הסר רק את המחברת. הערות נעות מחוץ לתיקיה. + הסר את המחברת והערות + הסר את המחברת. כל ההערות עוברות לאשפה או נמחקות. + הסר הערות + שמור את המחברת אך כל ההערות עוברות לאשפה או נמחקות. + התאם אישית גופנים + בחר את גופני היישום והערות + בחר ערכת גופנים + הערה: ייתכן שגופנים לא עובדים כמו שצריך עם כל השפות + ברירת מחדל ליישום + ברירת מחדל של המכשיר + מונו + Serif + בטל את נעילת האפליקציה + הזן מספר PIN בן 4 ספרות או השתמש בביומטריה כדי לבטל את הנעילה + הזן מספר PIN בן 4 ספרות כדי לבטל את הנעילה + השתמש בערכת הנושא של המערכת + השתמש בערכת הנושא האור או הכהה מהמערכת + הערות כהות + מחשיך אוטומטית את צבעי ההערות והתיקיות + מקומי + מרחוק + אינו זמין + נוצר + נמחק + עודכן + רקע יישומון + בחר את צבע הרקע עבור יישומון רב הערות + הצג סרגל כלים של פעולה + רכיב widget עם ריבוי הערות מציג את סרגל הכלים + דלג על מציג הערות + דלג על מציג ההערות וקפץ ישירות לעורך ההערות + האם תרצה למחוק פתקים אלה לצמיתות? + עדכונים ובקשות מהירים יותר. + נעילת אפליקציה ונעילת יחיד. + ערכות נושא נוספות לאפליקציות. + הערה גופנים וגדלי גופנים. + צבע רקע של הצופה. + אפשרויות יישומון נוספות. + פעולות הערה נוספות. + הערה צבע + הערה תגיות + אפשר נעילת אפליקציה + השתמש ב- PIN כדי לבטל את נעילת היישום כולו + בקש תמיד PIN + הזן קוד PIN לכל ההערות, גם אם הוזן קודם לכן + בטל נעילה עם ביומטריה + אפשר ביטול נעילה באמצעות טביעת אצבע או ביומטריה אחרת + ביומטריה מושבתת + אל תאפשר ביטול נעילה עם טביעת אצבע או ביומטריה אחרת + בטל נעילת הערה + השתמש בטביעת אצבע של המכשיר או בביומטריה כדי לבטל את נעילת הפתק והגישה אליו. + בטל את נעילת האפליקציה + השתמש בטביעת אצבע או ביומטריה של המכשיר כדי לבטל את נעילת האפליקציה ולגשת לכל ההערות. + קיצור דרך משגר + שתף תמונות + \ No newline at end of file diff --git a/base/src/main/res/values-ja/strings.xml b/base/src/main/res/values-ja/strings.xml index 7c782580..3a6816ec 100644 --- a/base/src/main/res/values-ja/strings.xml +++ b/base/src/main/res/values-ja/strings.xml @@ -8,16 +8,11 @@ 共有を使用して| | ノートなし メモを追加していないようです。メモを追加する場合にクリックします。 - ノートを追加する| - 簡単なメモを追加する| メモを追加 チェックリストを追加 - ナイトモード - デイモード メモを編集する 通知の作成 ポップアップで開く - メモを削除 永久に削除 コピーノート ノートを送る @@ -37,8 +32,6 @@ ピンノート ノートを固定解除する アクションを選択する| - タップしてナイトモードでノートを表示する - タップしてメモを日中のモードで表示する タップして編集用のメモを開きます ノートのコンテンツをクリップボードにコピーするにはタップしてください タップしてメモコンテンツを他のアプリと共有する @@ -51,54 +44,24 @@ タップしてメモをアーカイブする タップしてメモの背景色を変更する メモを保存するにはタップしてください - あなたのメモやその他| ホーム - あなたの普通のノートとお気に入りのノート お気に入り - お気に入りのメモすべて アーカイブ済み - すべてのアーカイブされたメモ ロックされた - すべてのロックされたメモ - タグ - すべてのノートタグ ごみ - ごみの中のあなたのメモ コンテンツを追加する| 見出しを追加する| - サブ見出しを追加する| 引用符で囲まれたテキストを追加する| アイテムを追加する| コードを追加する| - ブロック書式設定 - 見出し - 副見出し - テキスト - 見積もり - コード - チェックリスト - マークダウンの書式設定 - 大胆な - イタリック体 - アンダーライン - ストライク - リスト オプションと設定 インターフェースと経験 アプリの見た目と感じ方を選択します。 - ノート設定 - メモやその他の設定を選択します。 私たちとアプリについてもっと知ってください。 セキュリティ ロックノートとセキュリティオプション - ナイトモードを有効にする - 暗いテーマをデフォルトとして有効にする - デイモードを有効にする - デフォルトとしてライトテーマを有効にする - マークダウン設定 - メモにmarkdownを使用する方法を参照してください リストレイアウトを有効にする ノートを1つの列に表示する グリッドレイアウトを有効にする @@ -116,19 +79,12 @@ オープンソースプロジェクトの詳細を知る 評価と批評 あなたがアプリをどれだけ好きだったか教えてください - 調査を記入する - あなたの好きなことを教えてアプリを改善してください セキュリティオプション パスコード ノートをロックする4桁のPINを設定する - フィンガープリントでロック解除 - ノートは指紋でロック解除されます - 指紋を無効にする - ノートは指紋を使用しません 新しいPINを入力してください PINを入力してロックを解除する 現在のPINを入力 - コードを入力する 確認 ロックを解除する セット @@ -141,7 +97,6 @@ マークダウンがサポートされているフォーマットを許可する ノートリストのマークダウン ノートのリストでマークダウンの書式設定を有効にする - 許可を与える インポートとエクスポートにはストレージ権限が必要です。要請された場合は許可を与えてください。 許可する @@ -152,15 +107,12 @@ ファイルにエクスポートする| 完了 シェア - 私たちについて Playストアでのレート 寄稿 アプリのバージョン アプリについて 図書館 オープンソースプロジェクト - オープンソースプロジェクトについて - メモの通知 リマインダの日付 リマインダー時間 繰り返し周波数 @@ -181,9 +133,6 @@ 新着情報 最近のアプリのアップデートで何が新しくなったのかを知る 翻訳 - クリックして新しいメモを追加する - クリックしてホームオプションを表示する - ホームメニューには、お気に入りのメモやアーカイブのメモ、アプリケーションの設定があります。ここでもあなたのタグを見つけることができます。 メモフォントサイズ メモページのテキストのフォントサイズを調整します。このプレビューでどのように見えるかを見ることができます。 ノートビューア内のテキストの%dサイズ @@ -205,20 +154,12 @@ クラウドバックアップと同期のためのサインイン サインアウト ログアウトしてクラウドバックアップを停止する - Googleでログイン - サインイン| - あなたはログインしています Googleログインに失敗しました 個人情報保護方針 コンテンツのアプリプライバシーポリシー プロアプリのインストール プロをインストールする理由 クラウド同期を実行するために大規模なサーバーコストの開発者をサポートする \n\n 最新の機能を最初に入手する \n\n いくつかの追加機能はProユーザーだけが利用できます - クラウド同期を有効にする理由 - †"デバイスの変更に対するアップロードとバックアップ \n\n 複数のデバイス間の同期とクイックアップデートの取得 \n\n Google Firebaseサーバーへの安全な保存 - こんにちは、 - マテリアルノートはスカーレットになりました! - 開始する コピー @@ -235,30 +176,24 @@ わかりました 自動的にエクスポート メモを頻繁にバックアップとして外部ファイルにエクスポートする - 画像 クリックして画像を追加または変更する 1回だけ 毎日 - カスタム - ベータ リマインダーとアラーム %s はオープンソースで誰でもオープンになっています。 現在、%sによって構築され維持されています。 %sはアプリを撮るシンプルなメモです。 体験を非常に難しくすることなく、リッチテキスト入力を素早く行うことができます。 それはマルチタスクを簡単にします。 こんにちは、私たちは%sを創造したデザイナーとプログラマーのペアです。 私たちは美しくて慎重に設計された無償、無償、または最小限の広告アプリケーションを構築して、誰にとっても大きな有用性を提供するよう努めています。 ホーム画面の%d行 - 検索%s … 気を散らさない - セパレータ アプリのテーマ テーマの背景色を選択する アプリケーションテーマを選択 クリックしてタグを追加または変更する - その他のアクションを表示 ノートを選択 一度に複数のノートでアクションを選択して実行する メモはゴミ箱に移動されました @@ -294,4 +229,155 @@ アプリ内のメモ、タグ、フォルダを削除する ビューアの背景 + + メモをマージ + 値下げとしてエクスポート + ノートをマークダウン形式でエクスポートします。 (これらをアプリにインポートすることはできません) + 背景色にテーマカラーを使用 + 背景にメモの色を使用 + 有効にする + 無効にする + フォルダ同期を有効にする + フォルダ同期 + すべてのメモ、タグ、およびフォルダを外部フォルダに同期します。これにより、デバイス間で他のアプリを使用して同期したり、アプリを削除する必要がある場合に備えてコピーを作成したりできます。 + フォルダにエクスポート + すべてのメモ、タグなどを外部フォルダに同期する + ロックされたメモをエクスポートする + アルファベット順 + Scarlet Proで利用可能 + ロックされているメモもバックアップする + エディタオプション + ノートエディタの設定と使い方を変更する + デフォルトとしてのマークダウンオプション + デフォルトでマークダウンクイックボタンをツールバーに表示する + リアルタイムマークダウン + マークダウンを自分のタイプとして表示するかどうかを選択してください。有効にすると、大きな音符のパフォーマンスに影響が出る可能性があります。 + チェックしたアイテムを移動する + チェックされた項目はリストの一番下に移動します。チェックを外すと位置はリセットされません。 + 移動ハンドルを表示 + アイテムを上下に移動するためのハンドルを表示します。あなたはまだコーナーに触れることによって物事を動かすことができます。 + マークダウンの例 + ウィジェット設定 + ホーム画面ウィジェットの設定を変更する + フォーマットを有効にする + ノートはホームスクリーンウィジェットのフォーマットでレンダリングされる + ロックされたメモを表示 + ロックされたメモをホーム画面のウィジェットに表示することを許可する + アーカイブノートを表示 + アーカイブされたメモをホーム画面のウィジェットに表示することを許可する + ゴミ箱にメモを表示 + ゴミ箱のメモをホーム画面のウィジェットに表示することを許可する + ヘルプとよくある質問 + アプリの機能を使用する方法についてのヘルプを探す + 同期中 + バックアップ保留 + 開発者向けオプション + デバッグに使用するアプリケーションに内部設定を変更する + 例外ログ + 検出された例外を修正されたメモに記録して、開発者に転送できるようにします。 + 例外シートを表示 + 可能であれば、キャッチされた例外をシートに表示して、Developerに転送できるようにする + 例外を投げる + 例外が発生した場合はアプリケーションをスローしてクラッシュさせます。 5回のクラッシュ後にリセットされます + フルスクリーンを有効にする + スクリーンショットと録画を許可するようにフルスクリーンでアプリを作る + メモUUIDを表示 + ホームスクリーンビューでメモの一意のIDを表示する + 偽の例外 + 例外機能をテストするために偽の例外を投げる + スローされた例外 + クラッシュアプ​​リ + 郵便物 + 接続に失敗しました + Googleドライブで同期 + Googleドライブでは、自分のGoogleドライブアカウントを使用してデバイス間でメモを同期できます。 + 以前にGoogle Firebaseにログインしましたか? + Googleドライブにサインインする + サインイン + スカーレットからサインアウト + メモ、タグ、フォルダの同期を停止します。 + メモ、タグ、フォルダをGoogleドライブに同期しないでください。 + アプリとGoogleドライブのデータはそのまま残ります。 + ドライブからサインアウトする + ログアウトする + メモ、タグ、フォルダは自分のGoogleドライブに保存されているため、それらへのアクセスを制御できるのはあなただけです。 + あなたの写真はアップロードされ、デバイス間でも同期されます。 + Firebaseからデータを復元する + Googleでサインイン + サインイン + Google Firebaseにあなたの情報を保存していました。ログインした後、私たちはあなたのデバイスにこれらを回復します + 新しいメモや変更はGoogle Firebaseに同期されません。Googleドライブにログインする必要があります。 + メモが復元されたら、Google Firebaseからそれらを削除してから切り替えることができます。 + あなたのデータは同期されていません! + 従来のログインに基づくデータ同期は無効になっています。Googleドライブベースの同期への切り替えを検討してください。 + Firebaseからドライブへのデータ転送 + データを消去してサインアウトする + クリアとサインアウト + Google Firebaseにあなたの情報を保存していました。 Googleドライブへのメモの保存に移行しています。 + より多くのプライバシー。 + 写真の同期 + 次のステップ + まずFirebaseからあなたのメモを削除してログアウトします。 + Googleドライブにログインすると、データと共に画像がアップロードされます。 + + + 削除オプション + ノートブックを削除 + ノートブックのみを削除します。メモはフォルダ外に移動します。 + ノートブックとノートを削除する + ノートブックを削除します。すべてのメモがゴミ箱に移動するか、削除されます。 + メモを削除 + ノートブックを保持しますが、すべてのノートはゴミ箱に移動するか、削除されます。 + フォントをカスタマイズする + アプリを選択し、フォントをメモします + フォントセットを選択 + 注:すべての言語でフォントが正しく機能しない場合があります + アプリのデフォルト + デバイスのデフォルト + モノ + セリフ + アプリのロックを解除 + 4桁のPINを入力するか、生体認証を使用してロックを解除します + ロック解除するには4桁のPINを入力してください + システムテーマを使用する + システムから明るいテーマまたは暗いテーマを使用する + ダークノート + メモとフォルダーの色を自動的に暗くする + 地元 + リモート + 利用できません + 作成した + 削除しました + 更新しました + ウィジェットの背景 + マルチノートウィジェットの背景色を選択する + アクションツールバーを表示 + マルチノートウィジェットはツールバーを表示します + ノートビューアーをスキップ + ノートビューアーをスキップして、ノートエディターに直接ジャンプする + これらのメモを完全に削除しますか? + より高速な更新とリクエスト。 + アプリロックとシングルロック解除。 + その他のアプリテーマ。 + フォントとフォントサイズに注意してください。 + ビューアーの背景色。 + その他のウィジェットオプション。 + その他のメモアクション。 + ノートの色 + ノートタグ + アプリロックを有効にする + PINを使用してアプリケーション全体のロックを解除します + 常にPINを要求する + 以前に入力した場合でも、すべてのメモにPINを入力します + 生体認証でロック解除 + 指紋またはその他の生体認証によるロック解除を許可する + 生体認証が無効です + 指紋またはその他の生体認証によるロック解除を許可しない + メモのロックを解除 + デバイスの指紋または生体認証を使用して、メモとアクセスのロックを解除します。 + アプリのロックを解除 + デバイスの指紋または生体認証を使用して、アプリのロックを解除し、すべてのメモにアクセスします。 + ランチャーショートカット + 写真を共有する + \ No newline at end of file diff --git a/base/src/main/res/values-ko/strings.xml b/base/src/main/res/values-ko/strings.xml index ddcd89b3..6d1dabaf 100644 --- a/base/src/main/res/values-ko/strings.xml +++ b/base/src/main/res/values-ko/strings.xml @@ -8,16 +8,11 @@ 사용하여 공유 | 메모 없음 메모를 추가하지 않은 것 같습니다. 메모를 추가하려면 클릭하십시오. - 메모 추가하기 | - 빠른 메모 추가하기 | 메모를 추가 체크리스트 추가 - 야간 모드 - 주간 모드 메모 편집 알림 만들기 팝업에서 열기 - 메모 삭제 영구적으로 삭제 메모 복사 메모 보내기 @@ -37,8 +32,6 @@ 핀 메모 메모 고정 해제 액션 선택 | - 밤 모드에서 메모를 보려면 탭하세요. - 요일 모드에서 메모를 보려면 살짝 누르십시오. 편집하기 위해 메모를 열려면 살짝 누르십시오. 메모 내용을 클립 보드에 복사하려면 누르십시오. 메모 콘텐츠를 다른 앱과 공유하려면 탭하세요. @@ -51,54 +44,24 @@ 메모를 보관하려면 탭하세요. 메모의 배경색을 변경하려면 누르십시오. 메모를 보관 취소하려면 탭하세요. - 귀하의 메모 및 기타 … | - 당신의 평소와 좋아하는 모든 메모 즐겨 찾기 - 좋아하는 모든 메모 보관 됨 - 보관 처리 된 모든 메모 잠김 - 모든 잠긴 메모 - 태그 - 모든 메모 태그 폐물 - 휴지통에있는 모든 메모 컨텐츠 추가 | 헤딩 추가하기 | - 하위 제목 추가 … | 따옴표 붙은 텍스트 추가하기 | 항목 추가하기 | 코드 추가 | - 블록 서식 지정 - 표제 - 하위 제목 - 본문 - 인용문 - 암호 - 체크리스트 - 마크 다운 형식 - 대담한 - 이탤릭체 - 밑줄 - 스트라이크 - 명부 옵션 및 설정 인터페이스와 경험 앱의 모양과 느낌을 선택합니다. - 메모 환경 설정 - 메모 및 기타 설정을 선택하십시오. 우리와 앱에 대해 더 많이 알기. 보안 잠금 메모 및 보안 옵션 - 야간 모드 사용 - 어두운 테마를 기본값으로 사용 - 주간 모드 사용 - 조명 테마를 기본값으로 사용 - 마크 다운 설정 - 메모에서 마크 다운 사용 방법보기 목록 레이아웃 사용 단일 열에 노트 표시 그리드 레이아웃 활성화 @@ -116,19 +79,12 @@ 오픈 소스 프로젝트에 대해 더 많이 알기 별점과 리뷰 앱을 얼마나 좋아하는지 알려주세요. - 설문 조사 작성 - 내가 좋아하는 것을 말하면서 앱을 개선 할 수 있도록 도와주세요. 보안 옵션 패스 코드 메모를 잠 그려면 4 자리 PIN을 설정하십시오. - 지문 잠금 해제 - 메모는 지문으로 잠금 해제됩니다. - 지문 사용 중지됨 - 메모에는 지문이 사용되지 않습니다. 새 PIN 입력 잠금 해제 할 PIN 입력 현재 PIN 입력 - 코드를 입력 검증 터놓다 세트 @@ -141,7 +97,6 @@ 마크 다운 지원 서식 지정 허용 노트 목록의 마크 다운 메모 목록에서 마크 다운 서식 사용 - 예제들 권한 부여 가져 오기 및 내보내기에는 저장 영역 권한이 필요합니다. 요청시 허가를하십시오. 허용 @@ -152,15 +107,12 @@ 파일로 내보내기 … | 끝난 - 회사 소개 Play 스토어에서 평가하기 기부 앱 버전 앱 정보 도서관 오픈 소스 프로젝트 - 오픈 소스 프로젝트 정보 - 메모 알림 알림 날짜 미리 알림 시간 반복 주파수 @@ -181,9 +133,6 @@ What \'s New 앱의 최근 업데이트에서 새로운 점을 파악합니다. 옮기다 - 새 메모를 추가하려면 클릭하십시오. - 홈 옵션을 보려면 클릭하십시오. - 홈 메뉴에는 응용 프로그램 설정뿐만 아니라 좋아하는 노트와 아카이브 노트가 있습니다. 여기에서도 태그를 찾을 수 있습니다. 참고 글꼴 크기 메모 페이지에서 텍스트의 글꼴 크기를 조정하십시오. 미리보기에서 어떻게 보이는지 알 수 있습니다. 노트 뷰어의 텍스트 크기 %d @@ -205,20 +154,12 @@ 클라우드 백업 및 동기화를위한 로그인 로그 아웃 클라우드 백업을 중지하려면 로그 아웃하십시오. - Google로 로그인 - 로그인 | - 로그인하셨습니다. Google 로그인 실패 개인 정보 정책 콘텐츠에 대한 앱 개인 정보 취급 방침 프로 앱 설치 Pro를 설치해야하는 이유 대규모의 서버 비용, 클라우드 동기화 실행을위한 개발자 지원 \n\n 최신 기능 먼저 가져 오기 \n\n 일부 추가 기능은 Pro 사용자 만 사용할 수 있습니다 - 클라우드 동기화를 사용 설정해야하는 이유 - 장치 변경에 대한 업로드 및 백업 \n\n 여러 장치 간 동기화 및 빠른 업데이트 받기 \n\n Google Firebase 서버에 안전하게 저장 - 여보세요, - 소재 노트는 스칼렛입니다! - 시작하다 @@ -235,30 +176,24 @@ 이해 했어 자동으로 내보내기 메모를 외부 파일로 자주 내보내 백업으로 보내기 - 영상 이미지를 추가하거나 변경하려면 클릭하십시오. 한 번만 매일 - 관습 - 베타 미리 알림 및 경보 %s는 오픈 소스이며 누구나 오픈 소스를 통해 더 잘 만들 수 있습니다. 그것은 현재 %s에 의해 만들어지고 관리되고 있습니다. %s는 앱을 복용하는 간단한 메모입니다. 경험을 사용하기가 매우 어렵지 않으면 서 빠른 서식있는 텍스트 입력이 가능합니다. 그것은 멀티 태스킹 바람을 만듭니다. 안녕하세요, 우리는 %s 를 만든 디자이너와 프로그래머입니다. 우리는 아름답고 신중하게 디자인 된 무료, 광고없는 또는 최소한의 광고 응용 프로그램을 만들어 모든 사람에게 유용한 유틸리티를 제공하기 위해 노력합니다. 홈 스크린의 %d 라인 - %s 검색 … 산만 무료 - 분리 기호 앱 테마 테마의 배경색 선택 앱 테마 선택 태그를 추가하거나 변경하려면 클릭하십시오. - 추가 작업 표시 메모 선택 한 번에 여러 음표에 대한 작업 선택 및 수행 메모가 휴지통으로 이동되었습니다. @@ -294,4 +229,155 @@ 앱의 메모, 태그 및 폴더 삭제 뷰어 배경 참고 + + 메모 병합 + 마크 다운으로 내보내기 + 메모를 축소 형으로 내 보냅니다. (다시 앱으로 가져올 수는 없습니다.) + 배경에 테마 색상 사용 + 배경에 노트 색상 사용 + 사용 + 사용 안함 + 폴더 동기화 사용 + 폴더 동기화 + 모든 노트, 태그 및 폴더를 외부 폴더와 동기화하십시오. 이렇게하면 기기간에 다른 앱을 사용하여 동기화하는 데 도움이되며 앱을 삭제해야하는 경우를 대비하여 사본을 얻을 수 있습니다. + 폴더로 내보내기 + 모든 노트, 태그 등을 외부 폴더와 동기화하십시오. + 잠긴 메모 내보내기 + 알파벳순 + 스칼렛 프로에서 사용 가능 + 또한 잠긴 메모를 백업하십시오. + 편집기 옵션 + 노트 편집기의 설정 및 사용법 변경 + 기본값으로 표시 옵션 + 툴바에 마크 다운 단축 버튼 표시 (기본값) + 실시간 마카오 + 유형으로 표시 할 수있는 가격 표시를 선택하십시오. 큰 노트에 대해 효과를 적용 할 수 있습니다. + 선택한 항목 이동 + 선택된 항목은 목록의 맨 아래로 이동합니다. 선택을 취소해도 위치가 재설정되지 않습니다. + 이동 핸들 표시 + 항목을 위 또는 아래로 움직이려면 핸들을 표시하십시오. 모서리를 만져도 주변을 움직일 수 있습니다. + 마크 다운 예 + 위젯 설정 + 홈 화면 위젯의 설정 변경 + 서식 사용 + 메모는 홈 스크린 위젯에서 포맷으로 렌더링됩니다. + 잠긴 메모 표시 + 잠긴 메모를 홈 화면 위젯에 표시하도록 허용 + 보관 된 메모 표시 + 보관 된 메모를 홈 화면 위젯에 표시하도록 허용 + 메모를 휴지통에 표시 + 휴지통에있는 메모를 홈 화면 위젯에 표시하도록 허용 + 도움말 및 일반적인 질문 + 앱에서 기능을 사용하는 방법에 대한 도움말을 찾아보십시오. + 동기화 중 + 보류중인 백업 + 개발자 옵션 + 디버깅에 사용되는 응용 프로그램의 내부 설정 변경 + 예외 로그 + 고정 메모에 catch 된 예외를 기록하여 개발자에게 전달할 수 있도록합니다. + 예외 시트 표시 + 가능한 경우 시트에 예외를 표시하여 개발자에게 전달할 수 있도록합니다. + 예외에 던지기 + 응용 프로그램을 예외에 대해 던집니다. 5 번의 충돌 후 재설정됩니다. + 전체 화면 사용 + 전체 화면으로 앱을 만들어 스크린 샷과 녹음을 허용합니다. + 메모 UUID 표시 + 홈 화면보기에서 노트의 고유 ID 표시 + 가짜 예외 + 가짜 예외를 던져 예외 기능을 테스트하십시오. + Throw 된 Exception + 앱 다운 + 우편 + 연결에 실패 + Google 드라이브에서 동기화 + Google 드라이브를 사용하면 자신의 Google 드라이브 계정을 사용하여 기기간에 메모를 동기화 할 수 있습니다. + 이전에 Google Firebase에 로그인하셨습니까? + Google 드라이브에 로그인 + 서명하는 중 | + 스칼렛 사인 + 메모, 태그 및 폴더 동기화를 중지합니다. + 메모, 태그 및 폴더를 Google 드라이브와 동기화하지 않습니다. + 앱 및 Google 드라이브의 데이터는 그대로 유지됩니다. + 드라이브에서 로그 아웃 + 서명 아웃 | + 메모, 태그 및 폴더는 나만의 Google 드라이브에 저장되므로 액세스 권한 만 제어 할 수 있습니다. + 사진은 기기간에 업로드되고 동기화됩니다. + Firebase에서 데이터 복원 + Google로 로그인 + 서명하는 중 | + Google은 귀하의 정보를 Google Firebase에 저장하곤했습니다. 로그인 한 후 장치로 복구합니다. + 새로운 메모와 변경 사항은 Google Firebase에 동기화되지 않으며 Google 드라이브에 로그인해야합니다. + 메모가 복구되면 Google Firebase에서 메모를 삭제 한 다음 전환 할 수 있습니다. + 데이터가 동기화되지 않습니다. + 기존 로그인을 기반으로 한 데이터 동기화가 사용 중지되었습니다. Google 드라이브 기반 동기화로 전환하는 것이 좋습니다. + Firebase에서 드라이브로 데이터 전송 + 데이터 지우기 및 로그 아웃 + 삭제 및 로그 아웃 + Google은 귀하의 정보를 Google Firebase에 저장하곤했습니다. Google은 메모를 Google 드라이브에 저장하는 작업으로 이전하고 있습니다. + 더 많은 개인 정보. + 사진 동기화. + 다음 단계 + 먼저 Firebase에서 노트를 삭제하고 로그 아웃합니다. + 그런 다음 Google 드라이브에 로그인하면 이미지와 함께 데이터가 업로드됩니다. + + + 옵션 제거 + 노트북 제거 + 노트북 만 제거하십시오. 메모가 폴더 밖으로 이동합니다. + 노트 및 메모 제거 + 노트북을 제거하십시오. 모든 메모가 휴지통으로 이동되거나 삭제됩니다. + 메모 제거 + 전자 필기장을 유지하지만 모든 메모는 휴지통으로 이동되거나 삭제됩니다. + 글꼴 사용자 정의 + 앱과 메모 글꼴을 선택하십시오 + 글꼴 세트를 선택하십시오 + 참고 : 모든 언어에서 글꼴이 제대로 작동하지 않을 수 있습니다 + 앱 기본값 + 장치 기본값 + 모노 + 가는 장식 선 + 앱 잠금 해제 + 4 자리 PIN을 입력하거나 생체 인식을 사용하여 잠금 해제 + 잠금을 해제하려면 4 자리 PIN을 입력하십시오 + 시스템 테마 사용 + 시스템에서 밝거나 어두운 테마를 사용하십시오. + 다크 노트 + 메모 및 폴더 색상을 자동으로 어둡게합니다 + 노동 조합 지부 + + 없는 + 만들어진 + 삭제 + 업데이트 + 위젯 배경 + 다중 노트 위젯의 배경색을 선택하십시오. + 작업 도구 모음 표시 + 다중 노트 위젯에 도구 모음이 표시됩니다 + 노트 뷰어 건너 뛰기 + 노트 뷰어를 건너 뛰고 노트 편집기로 바로 이동 + 이 메모를 완전히 삭제 하시겠습니까? + 빠른 업데이트 및 요청. + 앱 잠금 및 단일 잠금 해제. + 더 많은 앱 테마. + 글꼴 및 글꼴 크기를 참고하십시오. + 뷰어 배경색. + 더 많은 위젯 옵션. + 추가 참고 조치. + 참고 색상 + 노트 태그 + 앱 잠금 사용 + PIN을 사용하여 전체 응용 프로그램의 잠금을 해제하십시오 + 항상 PIN을 요청하십시오 + 이전에 입력 한 경우에도 모든 메모에 PIN을 입력하십시오. + 생체 인식으로 잠금 해제 + 지문 또는 다른 생체 인식으로 잠금 해제 허용 + 생체 인식 비활성화 + 지문 또는 기타 생체 인식으로 잠금 해제하지 마십시오 + 노트 잠금 해제 + 메모 및 액세스 잠금을 해제하려면 장치 지문 또는 생체 인식을 사용하십시오. + 앱 잠금 해제 + 장치 지문 또는 생체 인식을 사용하여 앱을 잠금 해제하고 모든 메모에 액세스하십시오. + 실행기 바로 가기 + 사진 공유 + \ No newline at end of file diff --git a/base/src/main/res/values-mr/strings.xml b/base/src/main/res/values-mr/strings.xml index 7d59b4a0..9882ee18 100644 --- a/base/src/main/res/values-mr/strings.xml +++ b/base/src/main/res/values-mr/strings.xml @@ -6,17 +6,13 @@ वापरून सामायिक करा … कोणत्याही टिपा नाहीत आपण कोणत्याही नोट्स जोडले नाहीत असे दिसते एक टीप जोडण्यासाठी क्लिक करा - एक टीप जोडा … - एक द्रुत टीप जोडा … टीप संपादित करा पॉपअपमध्ये उघडा - टीप हटवा कॉपी टीप टीप पाठवा क्रिया निवडा … सामग्री जोडा … मथळा जोडा … - उप शीर्षलेख जोडा … कोट केलेला मजकूर जोडा … आयटम जोडा … कोड जोडा … @@ -43,7 +39,6 @@ फाईलवर निर्यात करत आहे … | झाले सामायिक करा - आमच्याबद्दल आणि बरेच काही प्ले स्टोअरवर रेट करा योगदान द्या अॅप आवृत्ती @@ -53,36 +48,21 @@ टीप अनलॉक करा चिन्हांकित आधार मार्कडाउन समर्थित स्वरूपण ला अनुमती द्या - उदाहरणे - चिन्हांकित करा सेटिंग्ज - नोट्समध्ये चिन्हांकित कसे वापरावे ते पहा सुरक्षा लॉकिंग नोट्स आणि सुरक्षा पर्याय सुरक्षा पर्याय पास कोड टिपा लॉक करण्यासाठी 4 अंकी पिन सेट करा - फिंगरप्रिंटसह अनलॉक करा - नोट्स फिंगरप्रिंटसह अनलॉक होतील - फिंगरप्रिंट अक्षम केले - टिपा फिंगरप्रिंट वापरणार नाही नवीन पिन प्रविष्ट करा अनलॉक करण्यासाठी पिन प्रविष्ट करा वर्तमान PIN प्रविष्ट करा - कोड टाका सत्यापित करा अनलॉक करा सेट करा काढा - दिवस मोड रंग बदला - दिवस मोडमध्ये टीप पाहण्यासाठी टॅप करा टीपचा पार्श्वभूमी रंग बदलण्यासाठी टॅप करा - रात्री मोड सक्षम करा - डीफॉल्ट म्हणून गडद थीम सक्षम करा - दिवस मोड सक्षम करा - मुलभूत म्हणून प्रकाश थीम सक्षम करा - रात्र मोड कायमचे हटवा टीप संग्रहण रद्द करा संग्रहण टीप @@ -90,7 +70,6 @@ मार्क पसंतीचा टीप पुनर्संचयित करा कचरा मध्ये हलवा - रात्रीच्या मोडमध्ये टीप पाहण्यासाठी टॅप करा संपादनासाठी टिप उघडण्यासाठी टॅप करा टीप सामग्री क्लिपबोर्डवर कॉपी करण्यासाठी टॅप करा अन्य अॅप्सवर टीप सामग्री सामायिक करण्यासाठी टॅप करा @@ -102,21 +81,13 @@ टीप आवडलेली म्हणून चिन्हांकित करण्यासाठी टॅप करा टीप संग्रहित करण्यासाठी टॅप करा टीप संग्रहित करणे अनइझम करण्यासाठी टॅप करा - आपले नोट्स … | घर - आपल्या सर्व सामान्य आणि आवडत्या नोट्स आवडते - आपल्या सर्व आवडत्या टिपा संग्रहित - आपल्या सर्व संग्रहित टिपा कचरा - कचरा मधील आपल्या सर्व नोट्स सूचना तयार करा टीप सूचना लॉक केलेले - आपली सर्व लॉक केलेली टिपा - टॅग्ज - आपले सर्व नोट टॅग्ज नवीन टॅग जोडा | टॅगचे संपादन करा | टॅग प्रविष्ट करा @@ -127,8 +98,6 @@ आयात करा नोट लिस्ट मध्ये चिन्हांकित करा नोट्सच्या सूचीमध्ये चिन्हांकित स्वरूपन सक्षम करा - सर्वेक्षण भरा - आपल्याला काय आवडते ते आम्हाला सांगून अनुप्रयोग सुधारण्यात आम्हाला मदत करा टॅग्ज बदला @@ -137,8 +106,6 @@ मुक्त स्त्रोत प्रकल्पाबद्दल अधिक जाणून घ्या ग्रंथालये मुक्त स्रोत प्रकल्प - मुक्त स्त्रोत प्रकल्पाबद्दल - टीप स्मरणपत्र स्मरणपत्र तारीख स्मरणपत्र वेळ वारंवारिता पुनरावृत्ती करा @@ -153,8 +120,6 @@ इंटरफेस आणि अनुभव अॅप कसे दिसते आणि कसे वाटते ते निवडा - टीप प्राधान्ये - टीप आणि अन्य सेटिंग्ज निवडा विषयी आमच्याबद्दल आणि अॅपबद्दल अधिक जाणून घ्या डीफॉल्ट टीप रंग @@ -189,19 +154,6 @@ नोंदी जोडा चेकलिस्ट जोडा - ब्लॉक फॉरमॅटिंग - मथळा - उप शीर्षलेख - मजकूर - कोट - कोड - चेकलिस्ट - चिन्हांकित स्वरूपन - धीट - तिर्यक - अधोरेखित करा - स्ट्राइक - यादी एक टीप निवडा टिपा निवडा सेटिंग्ज @@ -215,29 +167,18 @@ काय नवीन आहे अॅपच्या अलीकडील अद्यतनांमध्ये नवीन काय आहे ते जाणून घ्या भाषांतर करा - एक नवीन टीप जोडण्यासाठी क्लिक करा - मुख्यपृष्ठ पर्याय पाहण्यासाठी क्लिक करा - होम मेनूमध्ये आपल्या पसंतीचे आणि संग्रहित नोट्स तसेच अनुप्रयोग सेटिंग्ज असतात. आपण येथे आपले टॅगदेखील शोधू शकता. अॅपमध्ये साइन इन करा मेघ बॅकअप आणि समक्रमण साठी साइन इन करा साइन आऊट करा मेघ बॅकअप थांबविण्यासाठी साइन आउट करा - Google सह साइन इन करा - साइन इन करत आहे … | - आपण लॉग इन केले आहे Google लॉगिन अयशस्वी गोपनीयता धोरण सामग्रीसाठी अॅप्स गोपनीयता धोरण प्रो अॅप स्थापित करा का प्रो स्थापित क्लाऊड सिंक चालविण्याकरिता मोठ्या सर्व्हरच्या खर्चासाठी समर्थन विकसक \n\n प्रथम नवीनतम वैशिष्ट्ये मिळवा \n\n काही अतिरिक्त वैशिष्ट्ये केवळ प्रो वापरकर्त्यांसाठी उपलब्ध असतील - मेघ समक्रमण सक्षम का - डिव्हाइस बदलांविषयी अपलोड आणि बॅकअप \n\n एकाधिक डिव्हाइसेस दरम्यान समक्रमण करा, आणि द्रुत अद्यतने मिळवा \n\n Google Firebase सर्व्हरवर सुरक्षितपणे जतन केले - हॅलो, - सामग्री टिपा आता कमी दर्जाची आहे! - सुरु करूया कॉपी करा @@ -254,30 +195,24 @@ मी समजून घ्या स्वयंचलितरित्या निर्यात करा बॅकअप म्हणून बाह्य फायलीमध्ये वारंवार नोट्स निर्यात करा - प्रतिमा प्रतिमा जोडण्यासाठी किंवा बदलण्यासाठी क्लिक करा फक्त एकदाच दैनिक - सानुकूल - बीटा स्मरणपत्रे आणि अलार्म %s मुक्त स्त्रोत आहे आणि कोणीही ते अधिक चांगले बनवण्यासाठी योगदान देण्यास तयार आहे. हे सध्या %s द्वारे बांधले आणि ठेवली जाते. %s ही एक सोपी टीप ठेवण्याचे अनुप्रयोग आहे. तो वापरण्यासाठी अतिशय कठीण अनुभव न जलद रिच मजकूर इनपुट परवानगी देते. हे बहु- tasking एक ब्रीझ करते हाय, आम्ही डिझायनर आणि प्रोग्रामरचा जोडीदार आहे, ज्याने %s तयार केले आहे. आम्ही सुरेख, काळजीपूर्वक डिझाइन केलेले विनामूल्य, जाहिरात-मुक्त किंवा कमीत कमी जाहिरातीचे अॅप्स तयार करण्याचा प्रयत्न करतो जे प्रत्येकाला उत्कृष्ट उपयुक्तता देतात! %d होम स्क्रीनवरील ओळी - %s शोधा … Distraction विनामूल्य - सेपरेटर अॅप थीम थीमसाठी पार्श्वभूमी रंग निवडा अॅप थीम निवडा टॅग जोडण्यासाठी किंवा बदलण्यासाठी क्लिक करा - अधिक क्रिया दर्शवा नोट्स निवडा एकाच वेळी एकाधिक नोट्सवर क्रिया निवडा आणि करा टीप कचर्यात हलविली गेली @@ -313,4 +248,155 @@ अॅप मधील नोट्स, टॅग आणि फोल्डर हटवा नोट दर्शक पहा + + नोट्स विलीन करा + मार्कडाउन म्हणून निर्यात करा + मार्कडाउन स्वरूपनात नोट्स निर्यात करा. (आपण हे अॅपवर परत आयात करू शकत नाही) + पार्श्वभूमीसाठी थीम रंग वापरा + पार्श्वभूमीसाठी नोट रंग वापरा + सक्षम करा + अक्षम करा + फोल्डर सिंक सक्षम करा + फोल्डर समक्रमण + आपल्या सर्व नोट्स, टॅग आणि फोल्डर्स एका बाह्य फोल्डरमध्ये समक्रमित करा. हे आपल्याला डिव्हाइसेस दरम्यान इतर अॅप्स वापरुन समक्रमित करण्यात मदत करते आणि आपल्याला अॅप हटविण्याची आवश्यकता असल्यास कॉपी देखील आहे. + फोल्डरमध्ये निर्यात करीत आहे + सर्व नोट्स, टॅग्ज इ. बाह्य फोल्डरमध्ये समक्रमित करा + बंद लॉक नोट्स + वर्णानुक्रम + स्कार्लेट प्रो वर उपलब्ध + लॉक केलेल्या नोट्सचा बॅक अप देखील घ्या + संपादक पर्याय + नोट संपादकासाठी सेटिंग्ज आणि वापर बदला + डीफॉल्ट म्हणून मार्कडाउन पर्याय + टूलबारवरील मार्कडाउन त्वरित बटणे डीफॉल्ट म्हणून दर्शवा + रिअलटाइम मार्कडाउन + आपल्या प्रकारानुसार मार्कडाउन दृश्यमान होऊ इच्छित असल्यास निवडा. सक्षम करणे मोठ्या नोट्सवरील कार्यप्रदर्शन प्रभावित करू शकते. + चेक केलेले आयटम हलवा + चेक केलेले आयटम सूचीच्या तळाशी फिरतात. अनचेक स्थिती रीसेट करत नाही. + हालचाल हाताळताना दर्शवा + आयटम वर किंवा खाली हलविण्यासाठी हँडल दर्शवा. कोपऱ्याला स्पर्श करून आपण अद्याप गोष्टी हलवू शकता. + मार्कडाउन उदाहरणे + विजेट सेटिंग्ज + होम स्क्रीन विजेटसाठी सेटिंग्ज बदला + स्वरूपन सक्षम करा + होम स्क्रीन विजेटमध्ये स्वरूपनासह नोट्स प्रस्तुत केली जातात + लॉक केलेले नोट्स दर्शवा + होम स्क्रीन विजेटमध्ये लॉक केलेल्या नोट्स दर्शविण्याची परवानगी द्या + संग्रहित नोट्स दर्शवा + संग्रहित टिपा होम स्क्रीन विजेटमध्ये दर्शविण्याची परवानगी द्या + कचर्यातील नोट्स दर्शवा + होम स्क्रीन विजेटमध्ये कचर्यातील नोट्स दर्शविण्याची परवानगी द्या + मदत आणि सामान्य प्रश्न + अॅपमधील वैशिष्ट्यांचा वापर कसा करावा याबद्दल मदत शोधा + संकालन + प्रलंबित बॅकअप + विकसक पर्याय + डीबगिंगसाठी वापरल्या जाणार्या अनुप्रयोगास अंतर्गत सेटिंग्ज बदला + लॉग अपवाद + विकसकांना अग्रेषित करण्याची अनुमती देण्यासाठी लॉगने एका निश्चित टीपमध्ये अपवाद पकडले + अपवाद पत्रक दर्शवा + विकसकांना अग्रेषित करण्याची परवानगी देण्यासाठी शक्य असल्यास शीटवर पकडलेले अपवाद दर्शवा + अपवादांवर थ्रो + अपवादांवर अनुप्रयोग थ्रो आणि क्रॅश करा. 5 क्रॅश नंतर रीसेट केले जाईल + पूर्णस्क्रीन सक्षम करा + स्क्रीनशॉट आणि रेकॉर्डिंग्जना अनुमती देण्यासाठी अॅपला पूर्णस्क्रीनमध्ये बनवा + नोट यूयूआयडी दर्शवा + मुख्यपृष्ठ स्क्रीन दृश्यात नोट्सचे अनन्य id दर्शवा + खोटे अपवाद + अपवाद वैशिष्ट्यांचे परीक्षण करण्यासाठी बनावट अपवाद थ्रो + अपवाद फेकले + क्रॅश अॅप + मेल + संपर्क खंडित + Google ड्राइव्ह वर समक्रमित करा + Google ड्राइव्ह आपल्याला आपले स्वत: चे Google ड्राइव्ह खाते वापरून डिव्हाइसेस दरम्यान आपली टिपा संकालित करण्याची परवानगी देते. + आधी Google फायरबेस मध्ये लॉग इन केले? + Google ड्राइव्ह मध्ये साइन इन करा + साइन इन करत आहे + स्कार्लेट बाहेर साइन आउट करा + नोट्स, टॅग आणि फोल्डर समक्रमित करणे थांबवा. + आपल्या Google ड्राइव्हवर आपले नोट्स, टॅग आणि फोल्डर समक्रमित करणे थांबवा. + आपला अॅप आणि Google ड्राइव्हवरील डेटा अद्याप तेथेच आहे. + ड्राइव्हमधून साइन आउट करा + साइन आउट करत आहे + नोट्स, टॅग्ज आणि फोल्डर्स आपल्या स्वत: च्या Google ड्राइव्हवर संग्रहित केले जातात, म्हणूनच आपण त्यांच्यामध्ये प्रवेश नियंत्रित करू शकता. + आपले फोटो देखील डिव्हाइसेसवर अपलोड आणि समक्रमित केले जातात. + फायरबेस पासून डेटा पुनर्संचयित करा + Google सह साइन इन करा + साइन इन करत आहे + आम्ही आपली माहिती Google फायरबेसवर संग्रहित करतो. लॉग इन केल्यानंतर आम्ही ते आपल्या डिव्हाइसवर पुनर्प्राप्त करू + नवीन नोट्स आणि बदल Google फायरबेसवर समक्रमित केले जाणार नाहीत आणि आपल्याला Google ड्राइव्ह वर लॉग इन करणे आवश्यक आहे + एकदा आपली नोट्स पुनर्प्राप्त झाल्यानंतर, आपण त्यांना Google फायरबेसमधून हटवू शकता आणि नंतर स्विच करू शकता + आपला डेटा समक्रमित केला जात नाही! + लीगेसी लॉगिनवर आधारित डेटा सिंक अक्षम केला आहे, Google ड्राइव्ह आधारित सिंकवर स्विच करणे विचारात घ्या. + फायरबेस पासून ड्राइव्हवर डेटा स्थानांतरित करा + डेटा साफ करा आणि साइन आउट करा + क्लिअरिंग आणि साइनिंग आउट + आम्ही आपली माहिती Google फायरबेसवर संग्रहित करतो. आम्ही आपल्या Google ड्राइव्हमध्ये आपले नोट्स संचयित करण्यासाठी पुढे जात आहोत. + अधिक गोपनीयता + फोटो समक्रमण + पुढची पायरी + आम्ही प्रथम आपल्या नोट्स फायरबेसमधून हटवू आणि आपल्याला लॉग आउट करू. + आपण नंतर Google ड्राइव्हमध्ये लॉग इन करू शकता आणि आम्ही आपला डेटा प्रतिमांसह अपलोड करू. + + + पर्याय काढा + नोटबुक काढा + केवळ नोटबुक काढा. नोट्स फोल्डरच्या बाहेर हलतात. + नोटबुक आणि नोट्स काढा + नोटबुक काढा. सर्व नोट्स कचर्‍यामध्ये हलविल्या आहेत किंवा हटविल्या गेल्या आहेत. + टिपा काढा + नोटबुक ठेवा परंतु सर्व नोट्स कचर्‍यात हलविल्या आहेत किंवा हटविल्या गेल्या आहेत. + फॉन्ट सानुकूलित करा + अ‍ॅप आणि नोट फॉन्ट निवडा + एक फॉन्ट सेट निवडा + टीप: सर्व भाषांसह फॉन्ट योग्य प्रकारे कार्य करू शकत नाहीत + अ‍ॅप डीफॉल्ट + डिव्हाइस डीफॉल्ट + मोनो + सेरिफ + अ‍ॅप अनलॉक करा + 4 अंकी पिन प्रविष्ट करा किंवा अनलॉक करण्यासाठी बायोमेट्रिक्स वापरा + अनलॉक करण्यासाठी 4 अंकी पिन प्रविष्ट करा + सिस्टम थीम वापरा + सिस्टमवरील प्रकाश किंवा गडद थीम वापरा + गडद नोट्स + टीप आणि फोल्डर रंग स्वयंचलितपणे गडद करा + स्थानिक + रिमोट + अनुपलब्ध + तयार केले + हटविले + अद्यतनित + विजेट पार्श्वभूमी + एकाधिक नोट्स विजेटसाठी पार्श्वभूमी रंग निवडा + अ‍ॅक्शन टूलबार दर्शवा + मल्टी-नोट्स विजेट टूलबार दर्शवितो + टीप दर्शक वगळा + टीप दर्शक वगळा आणि थेट टीप संपादकावर जा + आपण या नोट्स कायमचे हटवू इच्छिता? + वेगवान अद्यतने आणि विनंत्या. + अ‍ॅप लॉक आणि सिंगल अनलॉक. + अधिक अ‍ॅप थीम. + फॉन्ट आणि फॉन्ट आकार लक्षात ठेवा. + दर्शक पार्श्वभूमी रंग. + अधिक विजेट पर्याय. + अधिक टीप क्रिया. + टीप रंग + टीप टॅग्ज + अ‍ॅप लॉक सक्षम करा + संपूर्ण अनुप्रयोग अनलॉक करण्यासाठी पिन वापरा + नेहमी पिन विचारा + सर्व नोट्ससाठी पिन प्रविष्ट करा, जरी आधी प्रविष्ट केली असेल + बायोमेट्रिक्ससह अनलॉक करा + फिंगरप्रिंट किंवा इतर बायोमेट्रिक्ससह अनलॉकला अनुमती द्या + बायोमेट्रिक्स अक्षम केले + फिंगरप्रिंट किंवा इतर बायोमेट्रिक्ससह अनलॉक करण्यास अनुमती देऊ नका + अनलॉक टीप + टीप आणि प्रवेश अनलॉक करण्यासाठी डिव्हाइस फिंगरप्रिंट किंवा बायोमेट्रिक्स वापरा. + अ‍ॅप अनलॉक करा + अ‍ॅप अनलॉक करण्यासाठी आणि सर्व टिपांवर प्रवेश करण्यासाठी डिव्हाइस फिंगरप्रिंट किंवा बायोमेट्रिक्स वापरा. + लाँचर शॉर्टकट + फोटो सामायिक करा + \ No newline at end of file diff --git a/base/src/main/res/values-ms/strings.xml b/base/src/main/res/values-ms/strings.xml index b62e372a..6c272aca 100644 --- a/base/src/main/res/values-ms/strings.xml +++ b/base/src/main/res/values-ms/strings.xml @@ -6,17 +6,13 @@ Kongsi menggunakan … Tiada Nota Nampaknya anda belum menambahkan sebarang nota. Klik untuk menambah nota. - Tambah nota … - Tambah nota cepat … Edit Nota Buka Dalam Popup - Padam Nota Salin Nota Hantar Nota Pilih Tindakan … Tambah Kandungan … Tambah Tajuk … - Tambah Sub Tajuk … Tambahkan Teks Kutipan … Tambah Item … Tambah Kod … @@ -27,21 +23,13 @@ Pilihan Keselamatan Kod Pas Tetapkan PIN 4 digit untuk mengunci nota - Buka kunci dengan cap jari - Nota-nota akan dibuka dengan cap jari - Cap jari dilumpuhkan - Nota tidak akan menggunakan cap jari Masukkan PIN baru Masukkan PIN untuk membuka kunci Masukkan PIN semasa - masukkan kod Sahkan Buka kunci Sokongan Markdown Benarkan markup disokong pemformatan - Contoh - Tetapan Tamat Penamatan - Lihat cara menggunakan markdown dalam nota Tetapkan Dayakan Layout Senarai Tunjukkan nota dalam satu lajur @@ -67,23 +55,15 @@ Mengeksport ke failâ € | Selesai Kongsi - Mengenai Kami dan Lebih Banyak Rate pada Play Store Sumbang Versi App Nota Pencari Mengenai App - Mod Hari Tukar Warna - Ketik untuk melihat nota dalam mod hari Ketik untuk menukar warna latar belakang nota - Dayakan Mod Malam - Dayakan tema gelap sebagai lalai - Dayakan Mod Hari - Dayakan tema cahaya sebagai lalai - Mod malam Padamkan secara kekal Nota Unarkif Nota Arkib @@ -91,7 +71,6 @@ Tandakan Kegemaran Pulihkan Nota Pindah ke tong sampah - Ketik untuk melihat nota dalam mod malam Ketik untuk membuka nota untuk mengedit Ketik untuk menyalin kandungan nota ke papan keratan Ketik untuk berkongsi kandungan nota ke apl lain @@ -103,21 +82,13 @@ Ketik untuk menandakan nota sebagai kegemaran Ketik untuk mengarkibkan nota tersebut Ketik untuk menyusun notarkar nota - Nota andaâ € | Rumah - Semua nota biasa dan kegemaran anda Kegemaran - Semua nota kegemaran anda Diarkibkan - Semua nota arkib anda Sampah - Semua nota anda di dalam tong sampah Buat Pemberitahuan Pemberitahuan Nota Terkunci - Semua nota terkunci anda - Tags - Semua tanda nota anda Tambah Tag Baru Edit Tag … masukkan tag @@ -128,8 +99,6 @@ Import Senarai penurunan nilai dalam Senarai Nota Dayakan pemformatan keterlihatan dalam senarai nota - Isi kajian - Bantu kami meningkatkan aplikasi dengan memberitahu kami apa yang anda suka Tukar Tag @@ -138,8 +107,6 @@ Ketahui lebih lanjut mengenai projek sumber terbuka Perpustakaan Projek Sumber Terbuka - Mengenai Projek Sumber Terbuka - Peringatan Peringatan Tarikh Peringatan Masa Peringatan Kekerapan Ulang @@ -154,8 +121,6 @@ Antara Muka dan Pengalaman Pilih bagaimana aplikasinya kelihatan dan dirasakan. - Nota Pilihan - Pilih nota dan tetapan lain. Mengenai Ketahui lebih lanjut mengenai kami dan aplikasinya. Warna Nota Default @@ -190,19 +155,6 @@ Tambah Nota Tambah Senarai Semak - Blok Pemformatan - Tajuk - Sub Tajuk - Teks - Quote - Kod - Senarai Semak - Pemformatan Markdown - Bold - Italik - Garis bawah - Mogok - Senarai Pilih Nota Pilih Nota Tetapan @@ -216,29 +168,18 @@ Apa yang Baru Ketahui apa yang baru dalam kemas kini aplikasi baru-baru ini Terjemah - Klik untuk menambah nota baharu - Klik untuk melihat pilihan rumah - Menu rumah mempunyai nota kegemaran dan arkib anda, serta tetapan aplikasi. Anda boleh mencari tag anda di sini juga. Masuk ke App Masuk untuk sandaran dan penyegerakan awan Keluar Log keluar untuk menghentikan sandaran awan - Masuk dengan Google - Menandatangani dalam € | - Anda log masuk Masuk Google Gagal Dasar Privasi Dasar privasi apl untuk kandungan Pasang Pro App Mengapa Memasang Pro Pemaju sokongan untuk kos pelayan besar, untuk menjalankan penyegerakan awan \n\n Dapatkan ciri-ciri terkini terlebih dahulu \n\n Sesetengah ciri tambahan akan tersedia hanya untuk pengguna Pro - Kenapa membolehkan Cloud Sync - Muat naik dan sandaran terhadap perubahan peranti \n\n Segerakkan antara berbilang peranti, dan dapatkan kemas kini pantas \n\n Secepat disimpan di pelayan Google Firebase - Halo, - Nota Bahan kini Scarlet! - Bermula Salinan @@ -255,30 +196,24 @@ Saya faham Eksport Secara Automatik Nota eksport sering ke fail luaran sebagai sandaran - Gambar Klik untuk menambah atau menukar imej Hanya sekali Harian - Custom - Beta Peringatan dan Penggera %s adalah sumber terbuka dan sesiapa sahaja terbuka untuk menyumbang untuk menjadikannya lebih baik. Ia kini dibina dan diselenggarakan oleh %s. %s adalah aplikasi mengambil nota ringkas. Ia membolehkan input teks kaya cepat tanpa membuat pengalaman yang sangat sukar untuk digunakan. Ia membuat pelbagai tugas dengan mudah. Hai, kami sepasang pereka dan pengaturcara, yang mencipta %s. Kami berusaha untuk membina aplikasi iklan bebas, bebas iklan atau minimum yang direka dengan cermat, yang berfungsi dengan baik untuk semua orang! garis %d pada skrin utama - Cari %s … Penglibatan Percuma - Pemisah Tema App Pilih warna latar belakang untuk tema Pilih Tema App Klik untuk menambah atau tukar tag - Tunjukkan Lagi Tindakan Pilih Nota Pilih dan lakukan tindakan pada beberapa nota serentak Nota itu dipindahkan ke sampah @@ -314,4 +249,155 @@ Padamkan nota, teg dan folder dalam aplikasi Latar Belakang Pencari Nota + + Merge Notes + Eksport Sebagai Penurunan Nilai + Nota eksport dalam format markdown. (Anda tidak boleh mengimport kembali ini ke aplikasi) + Gunakan warna tema untuk latar belakang + Gunakan warna nota untuk latar belakang + Dayakan + Lumpuhkan + Dayakan Penyegerakan Folder + Penyegerakan Folder + Segerakkan semua nota, teg dan folder anda ke folder luaran. Ini membantu anda menyelaraskan menggunakan aplikasi lain antara peranti, dan juga mempunyai salinan sekiranya anda perlu memadamkan aplikasi. + Mengeksport ke Folder + Segerakkan semua nota, teg, dan lain-lain ke folder luaran + Nota terkunci eksport + Abjad + Boleh didapati di Scarlet Pro + Juga sandarkan nota yang terkunci + Pilihan Editor + Tukar tetapan dan penggunaan untuk editor nota + Pilihan Kemaskini sebagai Default + Tunjukkan butang cepat keluar pada bar alat sebagai lalai + Pengendalian Masa Nyata + Pilih jika anda mahu markdown dapat dilihat sebagai jenis anda. Mendayakan boleh memberi kesan pada nota besar. + Pindah Item Diperiksa + Item yang diperiksa bergerak ke bahagian bawah senarai. Nyahtanda tidak menetapkan semula kedudukan. + Tunjukkan Pergerakan Gerakan + Tunjukkan pemegang untuk memindahkan item ke atas atau ke bawah. Anda masih boleh memindahkan perkara dengan menyentuh sudut. + Contoh Markdown + Tetapan Widget + Tukar tetapan untuk widget skrin utama + Dayakan Pemformatan + Nota diberikan dengan memformat dalam widget skrin utama + Tunjukkan Nota Dikunci + Benarkan nota terkunci untuk ditunjukkan dalam widget skrin utama + Tunjukkan Nota Terarkib + Benarkan nota arkib akan ditunjukkan dalam widget skrin utama + Tunjukkan Nota dalam Sampah + Benarkan nota dalam sampah untuk ditunjukkan dalam widget skrin utama + Soalan Bantuan dan Biasa + Cari bantuan tentang cara menggunakan ciri dalam aplikasinya + Penyelarasan + Menunggu Cadangan + Pilihan Pemaju + Tukar tetapan dalaman ke aplikasi yang digunakan untuk penyahpepijatan + Pengecualian Log + Log tertangkap pengecualian ke nota tetap, untuk membenarkan penghantaran ke Pemaju + Paparkan Helaian Pengecualian + Tunjukkan pengecualian yang terperangkap pada lembaran jika boleh, untuk membenarkan penghantaran ke Pemaju + Buang pada Pengecualian + Buang dan kemalangan aplikasi pada pengecualian. Akan ditetapkan semula selepas 5 kemalangan + Dayakan Fullscreen + Jadikan aplikasinya di skrin penuh untuk membenarkan tangkapan skrin dan rakaman + Tunjukkan Nota UUIDs + Tunjukkan id unik nota dalam paparan skrin utama + Pengecualian Palsu + Buang pengecualian palsu untuk menguji ciri pengecualian + Pengecualian Dibuang + Crash App + Mel + Sambungan gagal + Segerakkan di Google Drive + Google Drive membolehkan anda menyegerakkan nota anda antara peranti menggunakan akaun Google Drive anda sendiri. + Log masuk ke Google Firebase sebelum ini? + Masuk ke Google Drive + Menandatangani Inâ € | + Keluar dari Scarlet + Berhenti menyegerakkan nota, teg dan folder. + Berhenti menyegerakkan nota, teg dan folder anda ke Google Drive anda. + Data anda di apl dan di Google Drive masih di sana. + Log keluar dari Drive + Menandatangani Outâ € | + Nota, Teg dan Folder disimpan di Google Drive anda sendiri, jadi hanya anda yang boleh mengawal akses kepada mereka. + Foto anda dimuat naik dan disegerakkan merentasi peranti juga. + Pulihkan Data daripada Firebase + Masuk dengan Google + Menandatangani Inâ € | + Kami digunakan untuk menyimpan maklumat anda di Google Firebase. Selepas log masuk, kami akan memulihkannya ke peranti anda + Nota dan perubahan baru TIDAK akan diselaraskan ke Google Firebase, dan anda perlu log masuk ke Google Drive + Apabila nota anda pulih, anda boleh memadamkannya dari Google Firebase, dan kemudian beralih + Data anda tidak disegerakkan! + Penyegerakan Data berdasarkan log masuk lama dilumpuhkan, pertimbangkan untuk bertukar ke penyegerakan berasaskan Google Drive. + Memindahkan Data dari Firebase ke Drive + Kosongkan Data dan Log Keluar + Penjelasan dan Keluar + Kami digunakan untuk menyimpan maklumat anda di Google Firebase. Kami sedang bergerak untuk menyimpan nota anda di Google Drive anda. + Privasi lebih lanjut. + Penyegerakan Foto. + Langkah seterusnya + Kami akan memadamkan nota anda dari Firebase dan log keluar anda terlebih dahulu. + Anda kemudiannya boleh log masuk ke Google Drive, dan kami akan memuat naik data anda bersama-sama dengan imej. + + + Buang Pilihan + Keluarkan Notebook + Hanya Keluarkan Notebook. Nota bergerak di luar folder. + Keluarkan Notebook dan Nota + Keluarkan Notebook. Semua nota bergerak ke sampah atau dipadamkan. + Alih Keluar Nota + Simpan Notebook tetapi semua nota bergerak ke sampah atau dipadam. + Sesuaikan Font + Pilih aplikasi dan fon nota + Pilih Set Font + Nota: Font mungkin tidak berfungsi dengan baik dengan semua bahasa + Default Apl + Default peranti + Mono + Serif + Buka kunci aplikasinya + Masukkan PIN digit 4 atau gunakan biometrik untuk membuka kunci + Masukkan PIN digit 4 untuk membuka kunci + Gunakan Tema Sistem + Gunakan tema cahaya atau gelap dari sistem + Nota gelap + Catat warna nota dan folder secara automatik + Tempatan + Jauh + Tidak tersedia + Dibuat + Dihapuskan + Dikemaskini + Latar Belakang Widget + Pilih warna latar belakang untuk widget berbilang nota + Tunjukkan Toolbar Tindakan + Widget berbilang nota menunjukkan bar alat + Skip Note Viewer + Langkau penonton nota dan terus ke editor nota + Adakah anda mahu menghapuskan nota ini secara kekal? + Pembaharuan dan Permintaan yang lebih cepat. + Lock App dan Unlock Single. + Lagi Tema Apl. + Nota Font dan Saiz Fon. + Warna Latar Belakang Penonton. + Lebih Pilihan Widget. + Tindakan Catatan Lebih Lanjut. + Nota Warna + Nota Tags + Dayakan Kunci Apl + Gunakan PIN untuk membuka kunci keseluruhan aplikasi + Sentiasa meminta PIN + Masukkan PIN untuk semua nota, walaupun sebelum dimasukkan + Buka kunci dengan Biometrik + Benarkan buka kunci dengan cap jari atau biometrik lain + Biometrik dilumpuhkan + Jangan benarkan buka kunci dengan cap jari atau biometrik lain + Buka kunci Nota + Gunakan cap jari peranti atau biometrik untuk membuka kunci nota dan akses. + Buka kunci aplikasinya + Gunakan cap jari peranti atau biometrik untuk membuka kunci aplikasi dan mengakses semua nota. + Pintasan Pelancar + Kongsi Foto + \ No newline at end of file diff --git a/base/src/main/res/values-pa/strings.xml b/base/src/main/res/values-pa/strings.xml index 0d472825..8d11d6d1 100644 --- a/base/src/main/res/values-pa/strings.xml +++ b/base/src/main/res/values-pa/strings.xml @@ -6,17 +6,13 @@ ਵਰਤਦੇ ਹੋਏ ਸ਼ੇਅਰ ਕਰੋ … ਕੋਈ ਨੋਟਸ ਨਹੀਂ ਇੰਜ ਜਾਪਦਾ ਹੈ ਕਿ ਤੁਸੀਂ ਕੋਈ ਨੋਟ ਨਹੀਂ ਜੋੜਿਆ ਹੈ ਕੋਈ ਨੋਟ ਜੋੜਨ ਲਈ ਕਲਿੱਕ ਕਰੋ - ਕੋਈ ਨੋਟ ਜੋੜੋ … - ਇੱਕ ਤੁਰੰਤ ਸੂਚਨਾ ਜੋੜੋ … ਨੋਟ ਸੰਪਾਦਿਤ ਕਰੋ ਪੋਪਅੱਪ ਵਿੱਚ ਖੋਲ੍ਹੋ - ਨੋਟ ਮਿਟਾਓ ਨੋਟ ਕਾਪੀ ਕਰੋ ਸੂਚਨਾ ਭੇਜੋ ਕਾਰਵਾਈ ਚੁਣੋ … ਸਮੱਗਰੀ ਜੋੜੋ … ਸਿਰਲੇਖ ਸ਼ਾਮਲ ਕਰੋ … - ਸਬ ਸਿਰਲੇਖ ਸ਼ਾਮਲ ਕਰੋ … ਹਵਾਲੇ ਪਾਓ … ਆਈਟਮ ਸ਼ਾਮਲ ਕਰੋ … ਕੋਡ ਜੋੜੋ … @@ -28,14 +24,9 @@ ਸੁਰੱਖਿਆ ਵਿਕਲਪ ਪਾਸ ਕੋਡ ਨੋਟਸ ਨੂੰ ਲਾਕ ਕਰਨ ਲਈ ਇੱਕ 4 ਅੰਕ ਦਾ PIN ਸੈਟ ਕਰੋ - ਫਿੰਗਰਪ੍ਰਿੰਟ ਨਾਲ ਅਨਲੌਕ ਕਰੋ - ਨੋਟਸ ਫਿੰਗਰਪ੍ਰਿੰਟ ਨਾਲ ਅਨਲੌਕ ਹੋ ਜਾਣਗੇ - ਫਿੰਗਰਪ੍ਰਿੰਟ ਅਸਮਰਥਿਤ - ਨੋਟਸ ਫਿੰਗਰਪ੍ਰਿੰਟ ਦੀ ਵਰਤੋਂ ਨਹੀਂ ਕਰਨਗੇ ਨਵਾਂ PIN ਦਰਜ ਕਰੋ ਅਨਲੌਕ ਕਰਨ ਲਈ PIN ਦਰਜ ਕਰੋ ਮੌਜੂਦਾ PIN ਦਰਜ ਕਰੋ - ਕੋਡ ਦਰਜ ਕਰੋ ਜਾਂਚ ਕਰੋ ਅਨਲੌਕ ਸੈੱਟ ਕਰੋ @@ -46,9 +37,6 @@ ਥੋੜ੍ਹੇ ਸਮੇਂ ਵਿਚ ਗਰਿੱਡ ਵਿਚ ਨੋਟ ਦਿਖਾਓ ਮਾਰਕਡਾਉਨ ਸਹਿਯੋਗ ਮਾਰਕਡਾਊਨ ਸਮਰਥਿਤ ਫੌਰਮੈਟਿੰਗ ਨੂੰ ਅਨੁਮਤੀ ਦਿਓ - ਉਦਾਹਰਨਾਂ - ਮਾਰਕੇਡਾਊਨ ਸੈਟਿੰਗਜ਼ - ਸੂਚਨਾਵਾਂ ਵਿੱਚ ਮਾਰਕਡਾਊਨ ਨੂੰ ਕਿਵੇਂ ਵਰਤਿਆ ਜਾਵੇ ਵੇਖੋ ਚੋਣਾਂ ਅਤੇ ਸੈਟਿੰਗਾਂ ਨੋਟ ਐਕਸਪੋਰਟ ਸਾਂਝੇ ਕਰਨ ਲਈ ਡਿਵਾਈਸ ਸਟੋਰੇਜ ਨੂੰ ਨੋਟ ਐਕਸਪੋਰਟ ਕਰੋ @@ -68,22 +56,14 @@ ਫਾਈਲ ਨੂੰ ਐਕਸਪੋਰਟ ਕਰ ਰਿਹਾ ਹੈ | ਹੋ ਗਿਆ ਸਾਂਝਾ ਕਰੋ - ਸਾਡੇ ਬਾਰੇ ਅਤੇ ਹੋਰ ਪਲੇ ਸਟੋਰ ਤੇ ਰੇਟ ਯੋਗਦਾਨ ਐਪ ਵਰਜ਼ਨ ਐਪ ਬਾਰੇ - ਦਿਵਸ ਮੋਡ ਰੰਗ ਬਦਲੋ - ਦਿਨ ਦੇ ਮੋਡ ਵਿੱਚ ਨੋਟ ਦੇਖਣ ਲਈ ਟੈਪ ਕਰੋ ਨੋਟ ਦੇ ਪਿਛੋਕੜ ਰੰਗ ਨੂੰ ਬਦਲਣ ਲਈ ਟੈਪ ਕਰੋ - ਰਾਤ ਮੋਡ ਸਮਰੱਥ ਬਣਾਓ - ਡਿਫੌਲਟ ਦੇ ਤੌਰ ਤੇ ਡੌਕ ਥੀਮ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ - ਦਿਨ ਮੋਡ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ - ਡਿਫਾਲਟ ਤੌਰ ਤੇ ਲਾਈਟ ਥੀਮ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ - ਨਾਈਟ ਮੋਡ ਹਮੇਸ਼ਾ ਲਈ ਹਟਾਓ ਅਨਾਰਚਾਇਜ਼ ਨੋਟ ਆਰਕਾਈਵ ਸੂਚਨਾ @@ -91,7 +71,6 @@ ਮਰਕੁਸ ਪਸੰਦੀਦਾ ਨੋਟ ਰੀਸਟੋਰ ਕਰੋ ਰੱਦੀ \'ਚ ਭੇਜੋ - ਰਾਤ ਨੂੰ ਮੋਡ ਵਿੱਚ ਨੋਟ ਦੇਖਣ ਲਈ ਟੈਪ ਕਰੋ ਸੰਪਾਦਨ ਲਈ ਨੋਟ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ ਸੂਚਨਾ ਸਮੱਗਰੀ ਦੀ ਕਲਿਪਬੋਰਡ ਤੇ ਕਾਪੀ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ ਹੋਰ ਐਪਸ ਤੇ ਨੋਟ ਸਮੱਗਰੀ ਨੂੰ ਸਾਂਝਾ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ @@ -103,21 +82,13 @@ ਨੋਟ ਨੂੰ ਮਨਪਸੰਦ ਨਾ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ ਨੋਟ ਨੂੰ ਅਕਾਇਵ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ ਨੋਟ ਨੂੰ ਅਨਾਰਿਚ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ - ਤੁਹਾਡੇ ਨੋਟਸ | ਘਰ - ਤੁਹਾਡੇ ਸਾਰੇ ਆਮ ਅਤੇ ਮਨਪਸੰਦ ਨੋਟਸ ਮਨਪਸੰਦ - ਤੁਹਾਡੇ ਸਾਰੇ ਪਸੰਦੀਦਾ ਨੋਟਸ ਆਰਕਾਈਵਡ - ਤੁਹਾਡੇ ਸਾਰੇ ਸੰਗ੍ਰਹਿਤ ਨੋਟਸ ਟ੍ਰੈਸ਼ - ਰੱਦੀ ਵਿੱਚ ਤੁਹਾਡੇ ਸਾਰੇ ਨੋਟਸ ਸੂਚਨਾ ਬਣਾਓ ਸੂਚਨਾ ਨੋਟਿਸ ਬੰਦ - ਤੁਹਾਡੇ ਸਾਰੇ ਲਾਕ ਨੋਟਸ - ਟੈਗਸ - ਤੁਹਾਡੇ ਸਾਰੇ ਨੋਟ ਟੈਗਸ ਨਿਊ ਟੈਗ ਸ਼ਾਮਲ ਕਰੋ | ਟੈਗ ਸੰਪਾਦਨ ਕਰੋ | ਟੈਗ ਦਿਓ @@ -128,8 +99,6 @@ ਆਯਾਤ ਕਰੋ ਨੋਟ ਸੂਚੀ ਵਿੱਚ ਮਾਰਕੇਡਾਊਨ ਨੋਟਸ ਦੀ ਸੂਚੀ ਵਿੱਚ ਮਾਰਕੱਡਾਡ ਫਾਰਮੈਟਿੰਗ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ - ਸਰਵੇਖਣ ਭਰੋ - ਸਾਨੂੰ ਦੱਸੋ ਕਿ ਤੁਸੀਂ ਕੀ ਪਸੰਦ ਕਰਦੇ ਹੋ, ਐਪ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਵਿੱਚ ਸਾਡੀ ਸਹਾਇਤਾ ਕਰੋ ਟੈਗ ਬਦਲੋ @@ -138,8 +107,6 @@ ਓਪਨ ਸੋਰਸ ਪ੍ਰੋਜੈਕਟ ਬਾਰੇ ਹੋਰ ਜਾਣੋ ਲਾਇਬ੍ਰੇਰੀਆਂ ਓਪਨ ਸੋਰਸ ਪ੍ਰੋਜੈਕਟ - ਓਪਨ ਸੋਰਸ ਪ੍ਰੋਜੈਕਟ ਬਾਰੇ - ਨੋਟ ਰੀਮਾਈਂਡਰ ਰੀਮਾਈਂਡਰ ਤਾਰੀਖ ਰੀਮਾਈਂਡਰ ਟਾਈਮ ਬਾਰ ਬਾਰ ਦੁਹਰਾਓ @@ -154,8 +121,6 @@ ਇੰਟਰਫੇਸ ਅਤੇ ਅਨੁਭਵ ਚੁਣੋ ਕਿ ਐਪ ਕਿਵੇਂ ਵੇਖਦਾ ਹੈ ਅਤੇ ਕਿਵੇਂ ਮਹਿਸੂਸ ਕਰਦਾ ਹੈ - ਨੋਟ ਪਸੰਦ - ਨੋਟ ਅਤੇ ਹੋਰ ਸੈਟਿੰਗਜ਼ ਚੁਣੋ. ਇਸ ਬਾਰੇ ਸਾਡੇ ਅਤੇ ਐਪ ਬਾਰੇ ਹੋਰ ਜਾਣੋ ਡਿਫੌਲਟ ਨੋਟ ਰੰਗ @@ -190,19 +155,6 @@ ਨੋਟ ਜੋੜੋ ਚੈੱਕਲਿਸਟ ਸ਼ਾਮਲ ਕਰੋ - ਬਲਾਕ ਫਾਰਮੈਟਿੰਗ - ਸਿਰਲੇਖ - ਉਪ ਸਿਰਲੇਖ - ਟੈਕਸਟ - ਹਵਾਲਾ - ਕੋਡ - ਚੈੱਕਲਿਸਟ - ਮਾਰਕੇਡੋਂ ਫਾਰਮੈਟਿੰਗ - ਬੋਲਡ - ਇਟਾਲਿਕ - ਹੇਠਾਂ ਰੇਖਾ ਖਿੱਚੋ - ਹੜਤਾਲ - ਸੂਚੀ ਇੱਕ ਨੋਟ ਚੁਣੋ ਨੋਟਸ ਚੁਣੋ ਸੈਟਿੰਗਾਂ @@ -216,9 +168,6 @@ ਨਵਾਂ ਕੀ ਹੈ ਐਪ ਦੇ ਹਾਲ ਹੀ ਦੇ ਅਪਡੇਟਸ ਵਿੱਚ ਨਵਾਂ ਕੀ ਹੈ ਪਤਾ ਕਰੋ ਅਨੁਵਾਦ - ਇੱਕ ਨਵਾਂ ਨੋਟ ਜੋੜਨ ਲਈ ਕਲਿੱਕ ਕਰੋ - ਘਰ ਦੀਆਂ ਚੋਣਾਂ ਦੇਖਣ ਲਈ ਕਲਿੱਕ ਕਰੋ - ਹੋਮ ਮੀਨੂ ਵਿੱਚ ਤੁਹਾਡੀ ਮਨਪਸੰਦ ਅਤੇ ਅਕਾਇਵ ਨੋਟਸ ਦੇ ਨਾਲ ਨਾਲ ਐਪਲੀਕੇਸ਼ਨ ਸੈਟਿੰਗਜ਼ ਵੀ ਹਨ. ਤੁਸੀਂ ਇੱਥੇ ਆਪਣੇ ਟੈਗ ਵੀ ਲੱਭ ਸਕਦੇ ਹੋ @@ -236,51 +185,37 @@ ਮੈਂ ਸੱਮਝਦਾ ਹਾਂ ਆਟੋਮੈਟਿਕ ਤੌਰ ਤੇ ਨਿਰਯਾਤ ਕਰੋ ਬੈਕਅਪ ਦੇ ਤੌਰ ਤੇ ਬਾਹਰੀ ਫਾਈਲਾਂ ਤੇ ਅਕਸਰ ਨੋਟ ਐਕਸਪੋਰਟ ਕਰੋ - ਚਿੱਤਰ ਚਿੱਤਰ ਨੂੰ ਜੋੜਨ ਜਾਂ ਬਦਲਣ ਲਈ ਕਲਿੱਕ ਕਰੋ ਸਿਰਫ਼ ਇੱਕ ਵਾਰ ਰੋਜ਼ਾਨਾ - ਕਸਟਮ - ਬੀਟਾ ਰੀਮਾਈਂਡਰਸ ਅਤੇ ਅਲਾਰਮ %s ਓਪਨ ਸੋਰਸ ਹੈ ਅਤੇ ਕੋਈ ਵੀ ਇਸ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ ਯੋਗਦਾਨ ਪਾਉਣ ਲਈ ਖੁੱਲ੍ਹਾ ਹੈ. ਇਹ ਵਰਤਮਾਨ ਵਿੱਚ %s ਦੁਆਰਾ ਬਣਾਇਆ ਅਤੇ ਪਰਬੰਧਨ ਕੀਤਾ ਗਿਆ ਹੈ. %s ਇੱਕ ਸਧਾਰਨ ਨੋਟ ਲੈਣਾ ਐਪ ਹੈ. ਇਹ ਤਜ਼ਰਬੇ ਨੂੰ ਬਹੁਤ ਮੁਸ਼ਕਲ ਬਣਾਉਣ ਦੇ ਬਿਨਾਂ ਤੁਰੰਤ ਰਿਚ ਟੈਕਸਟ ਇੰਪੁੱਟ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ. ਇਹ ਬਹੁਤਾ ਨਾਲ ਕੰਮ ਕਰਨ ਵਾਲੀ ਇੱਕ ਹਵਾ ਬਣਾਉਂਦਾ ਹੈ ਹੈਲੋ, ਅਸੀਂ ਡਿਜ਼ਾਇਨਰ ਅਤੇ ਪ੍ਰੋਗਰਾਮਰ ਦਾ ਇੱਕ ਜੋੜਾ ਹਾਂ, ਜਿਸਨੇ %s ਬਣਾਇਆ ਹੈ ਅਸੀਂ ਸੁੰਦਰ, ਧਿਆਨ ਨਾਲ ਡਿਜ਼ਾਈਨ ਕੀਤੇ ਗਏ ਮੁਫ਼ਤ, ਵਿਗਿਆਪਨ-ਮੁਕਤ ਜਾਂ ਘੱਟੋ ਘੱਟ ਇਸ਼ਤਿਹਾਰਾਂ ਵਾਲੇ ਐਪਸ ਬਣਾਉਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਹਾਂ ਜੋ ਹਰ ਕਿਸੇ ਲਈ ਮਹਾਨ ਉਪਯੋਗਤਾ ਦੀ ਸੇਵਾ ਕਰਦੇ ਹਨ! %d ਹੋਮ ਸਕ੍ਰੀਨ ਤੇ ਲਾਈਨਾਂ - %s ਖੋਜ ਕਰੋ … ਵਿਵਹਾਰ ਮੁਫ਼ਤ - ਵਿਭਾਜਕ ਐਪ ਵਿੱਚ ਸਾਈਨ ਇਨ ਕਰੋ ਕਲਾਉਡ ਬੈਕਅਪ ਅਤੇ ਸਮਕਾਲੀਕਰਨ ਲਈ ਸਾਈਨ ਇਨ ਕਰੋ ਸਾਇਨ ਆਉਟ ਕਲਾਉਡ ਬੈਕਅਪ ਨੂੰ ਰੋਕਣ ਲਈ ਸਾਈਨ ਆਉਟ ਕਰੋ - Google ਦੇ ਨਾਲ ਸਾਈਨ ਇਨ ਕਰੋ - ਸਾਈਨ ਇੰਨ ਕਰੋ | - ਤੁਸੀਂ ਲੌਗਇਨ ਹੋ ਗੂਗਲ ਲਾਗਇਨ ਫੇਲ੍ਹ ਪਰਾਈਵੇਟ ਨੀਤੀ ਸਮਗਰੀ ਲਈ ਐਪ ਗੋਪਨੀਯਤਾ ਨੀਤੀ ਪ੍ਰੋ ਐੱਸ ਇੰਸਟਾਲ ਕਰੋ ਪ੍ਰੋ ਇੰਸਟਾਲ ਕਿਉਂ ਕਰੋ ਕਲਾਉਡ ਸੰਕੁਚਨ ਨੂੰ ਚਲਾਉਣ ਲਈ ਵੱਡੇ ਸਰਵਰ ਲਾਗਤਾਂ ਲਈ ਸਹਿਯੋਗ ਡਿਵੈਲਪਰ \n\n ਪਹਿਲਾਂ ਸਭ ਤੋਂ ਨਵੀਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਪ੍ਰਾਪਤ ਕਰੋ \n\n ਕੁਝ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਕੇਵਲ ਪ੍ਰੋ ਯੂਜ਼ਰਸ ਲਈ ਉਪਲਬਧ ਹੋਣਗੀਆਂ - ਕਿਉਂ Cloud Sync ਸਮਰਥਿਤ ਕਰੋ - ਡਿਵਾਈਸ ਬਦਲਾਅ ਦੇ ਵਿਰੁੱਧ ਅਪਲੋਡ ਅਤੇ ਬੈਕਅੱਪ ਕਰੋ \n\n ਬਹੁਤੇ ਡਿਵਾਈਸਾਂ ਵਿਚਕਾਰ ਸਿੰਕ ਕਰੋ, ਅਤੇ ਤੁਰੰਤ ਅਪਡੇਟਾਂ ਪ੍ਰਾਪਤ ਕਰੋ \n\n Google Firebase ਸਰਵਰਾਂ ਤੇ ਸੁਰੱਖਿਅਤ ਰੂਪ ਵਿੱਚ ਸੁਰੱਖਿਅਤ ਕੀਤਾ ਗਿਆ - ਸਤ ਸ੍ਰੀ ਅਕਾਲ, - ਮੈਟੀਰੀਅਲ ਨੋਟਸ ਹੁਣ ਸਵਾਨੇ ਹਨ! - ਸ਼ੁਰੂਆਤ ਕਰੋ ਐਪ ਥੀਮ ਥੀਮ ਲਈ ਬੈਕਗਰਾਊਂਡ ਰੰਗ ਚੁਣੋ ਐਪ ਥੀਮ ਚੁਣੋ ਟੈਗਸ ਨੂੰ ਜੋੜਨ ਜਾਂ ਬਦਲਣ ਲਈ ਕਲਿਕ ਕਰੋ - ਹੋਰ ਕਾਰਵਾਈਆਂ ਦਿਖਾਓ ਨੋਟਸ ਚੁਣੋ ਇੱਕ ਵਾਰ ਵਿੱਚ ਕਈ ਨੋਟਿਸਾਂ ਉੱਤੇ ਕਾਰਵਾਈ ਚੁਣੋ ਅਤੇ ਕਾਰਵਾਈ ਕਰੋ ਨੋਟ ਨੂੰ ਰੱਦੀ \'ਚ ਭੇਜਿਆ ਗਿਆ ਸੀ @@ -316,4 +251,155 @@ ਐਪ ਵਿੱਚ ਨੋਟਸ, ਟੈਗਸ ਅਤੇ ਫੋਲਡਰ ਮਿਟਾਓ ਨੋਟ ਵਿਊਅਰ ਬੈਕਗਰਾਊਂਡ + + ਨੋਟਸ ਮਿਲਾਓ + ਮਾਰਕਡਾਉਨ ਦੇ ਤੌਰ ਤੇ ਨਿਰਯਾਤ ਕਰੋ + ਮਾਰਕੇਡਾਊਨ ਫਾਰਮੈਟ ਵਿੱਚ ਨੋਟ ਨਿਰਯਾਤ ਕਰੋ. (ਤੁਸੀਂ ਇਹ ਵਾਪਸ ਐਪ ਤੇ ਆਯਾਤ ਨਹੀਂ ਕਰ ਸਕਦੇ) + ਪਿਛੋਕੜ ਲਈ ਥੀਮ ਕਲੰਡ ਵਰਤੋਂ + ਪਿਛੋਕੜ ਲਈ ਨੋਟ ਰੰਗ ਦੀ ਵਰਤੋਂ ਕਰੋ + ਸਮਰੱਥ ਬਣਾਓ + ਅਸਮਰੱਥ ਕਰੋ + ਫੋਲਡਰ ਸਿੰਕ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ + ਫੋਲਡਰ ਸਿੰਕ ਕਰੋ + ਆਪਣੇ ਸਾਰੇ ਨੋਟਸ, ਟੈਗਸ ਅਤੇ ਫੋਲਡਰ ਨੂੰ ਇੱਕ ਬਾਹਰੀ ਫੋਲਡਰ ਵਿੱਚ ਸਿੰਕ ਕਰੋ. ਇਹ ਡਿਵਾਈਸਾਂ ਦੇ ਵਿੱਚਕਾਰ ਦੂਜੀਆਂ ਐਪਲੀਕੇਸ਼ਾਂ ਦਾ ਉਪਯੋਗ ਕਰਕੇ ਸਿੰਕ ਕਰਨ ਵਿੱਚ ਤੁਹਾਡੀ ਸਹਾਇਤਾ ਕਰਦਾ ਹੈ, ਨਾਲ ਹੀ ਤੁਹਾਡੇ ਕੋਲ ਐਪ ਨੂੰ ਮਿਟਾਉਣ ਦੀ ਜ਼ਰੂਰਤ ਦੇ ਨਾਲ ਇੱਕ ਕਾਪੀ ਹੈ + ਫੋਲਡਰ ਵਿੱਚ ਐਕਸਪੋਰਟ ਕਰ ਰਿਹਾ ਹੈ + ਸਾਰੇ ਨੋਟਸ, ਟੈਗਾਂ ਆਦਿ ਨੂੰ ਇੱਕ ਬਾਹਰੀ ਫੋਲਡਰ ਵਿੱਚ ਸਿੰਕ ਕਰੋ + ਤਾਲਾਬੰਦ ਨੋਟ ਐਕਸਪੋਰਟ + ਵਰਣਮਾਲਾ ਦੇ ਅਨੁਸਾਰ + ਸਕਾਰਲੈਟ ਪ੍ਰੋ ਤੇ ਉਪਲਬਧ + ਲੌਕ ਹੋਏ ਨੋਟਸ ਨੂੰ ਵੀ ਬੈਕਅਪ ਕਰੋ + ਸੰਪਾਦਕ ਵਿਕਲਪ + ਨੋਟ ਸੰਪਾਦਕ ਲਈ ਸੈਟਿੰਗਾਂ ਅਤੇ ਵਰਤੋਂ ਬਦਲੋ + Markdown ਚੋਣਾਂ ਨੂੰ ਡਿਫਾਲਟ ਦੇ ਤੌਰ ਤੇ + ਡਿਫੌਲਟ ਵਜੋਂ ਟੂਲਬਾਰ ਤੇ ਮਾਰਕਡਾਊਨ ਤੇਜ਼ ਬਟਨ ਦਿਖਾਓ + ਰੀਅਲਟਾਈਮ ਮਾਰਕਾਡਾਊਨ + ਚੁਣੋ ਕਿ ਕੀ ਤੁਸੀਂ ਚਾਹੁੰਦੇ ਹੋ ਕਿ ਮਾਰਕਡਾਊਨ ਤੁਹਾਡੀ ਕਿਸਮ ਦੇ ਤੌਰ ਤੇ ਦਿਖਾਈ ਦੇਵੇ ਯੋਗ ਕਰਨਾ ਵੱਡੇ ਨੋਟਸ ਤੇ ਪ੍ਰਦਰਸ਼ਨ ਨੂੰ ਪ੍ਰਭਾਵਤ ਕਰ ਸਕਦਾ ਹੈ. + ਚੈਕਡ ਆਈਟਮਾਂ ਨੂੰ ਮੂਵ ਕਰੋ + ਚੈੱਕ ਕੀਤੀਆਂ ਆਈਟਮਾਂ ਸੂਚੀ ਦੇ ਹੇਠਾਂ ਚਲੀਆਂ ਗਈਆਂ ਹਨ ਅਨਚੈਕ ਪੁਜ਼ੀਸ਼ਨ ਨੂੰ ਰੀਸੈਟ ਨਹੀਂ ਕਰਦਾ. + ਅੰਦੋਲਨ ਹੈਂਡਲ ਵੇਖੋ + ਆਈਟਮਾਂ ਨੂੰ ਉੱਪਰ ਜਾਂ ਹੇਠਾਂ ਵੱਲ ਹਿਲਾਉਣ ਲਈ ਹੈਂਡਲ ਦਿਖਾਓ ਤੁਸੀਂ ਅਜੇ ਵੀ ਕੋਨੇ ਨੂੰ ਛੂਹ ਕੇ ਆਲੇ ਦੁਆਲੇ ਦੀਆਂ ਚੀਜਾਂ ਨੂੰ ਪ੍ਰਭਾਵਿਤ ਕਰ ਸਕਦੇ ਹੋ + ਮਾਰਕੇਡਾਉਨ ਦੀਆਂ ਉਦਾਹਰਨਾਂ + ਵਿਜੇਟ ਸੈਟਿੰਗਜ਼ + ਹੋਮ ਸਕ੍ਰੀਨ ਵਿਜੇਟਸ ਲਈ ਸੈਟਿੰਗਾਂ ਬਦਲੋ + ਫਾਰਮੈਟਿੰਗ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ + ਹੋਮ ਸਕ੍ਰੀਨ ਵਿਡਜਿਟ ਵਿੱਚ ਫੌਰਮੈਟਿੰਗ ਦੇ ਨਾਲ ਨੋਟਸ ਰੈਂਡਰ ਕੀਤੇ ਜਾਂਦੇ ਹਨ + ਲੌਕਡ ਨੋਟਸ ਦਿਖਾਓ + ਲੌਕ ਕੀਤੀਆਂ ਨੋਟਾਂ ਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ ਵਿਜੇਟਾਂ ਵਿੱਚ ਦਿਖਾਉਣ ਦੀ ਆਗਿਆ ਦਿਓ + ਆਰਕਾਈਵਡ ਨੋਟਸ ਵੇਖੋ + ਆਰਕਾਈਵ ਕੀਤੀਆਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ ਵਿਜੇਟਾਂ ਵਿੱਚ ਦਿਖਾਉਣ ਦੀ ਆਗਿਆ ਦਿਓ + ਰੱਦੀ ਵਿੱਚ ਨੋਟ ਵੇਖੋ + ਘਰਾਂ ਦੀਆਂ ਸਕ੍ਰੀਨ ਵਿਜੇਟਾਂ ਵਿੱਚ ਰੱਦੀ ਵਿੱਚ ਨੋਟਸ ਦਿਖਾਉਣ ਦੀ ਆਗਿਆ ਦਿਓ + ਮਦਦ ਅਤੇ ਆਮ ਸਵਾਲ + ਐਪ ਵਿੱਚ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦਾ ਉਪਯੋਗ ਕਿਵੇਂ ਕਰਨਾ ਹੈ ਬਾਰੇ ਮਦਦ ਲੱਭੋ + ਸਿੰਕ ਕਰਨਾ + ਬਕਾਇਆ ਬੈਕਅਪ + ਵਿਕਾਸਕਾਰ ਵਿਕਲਪ + ਡੀਬੱਗਿੰਗ ਲਈ ਵਰਤੀ ਜਾਂਦੀ ਐਪਲੀਕੇਸ਼ਨ ਵਿੱਚ ਅੰਦਰੂਨੀ ਸੈਟਿੰਗ ਬਦਲੋ + ਲਾਗ ਅਪਵਾਦ + ਡਿਵੈਲਪਰ ਨੂੰ ਫਾਰਵਰਡਿੰਗ ਦੀ ਆਗਿਆ ਦੇਣ ਲਈ ਇੱਕ ਨਿਸ਼ਚਿਤ ਨੋਟ ਦੇ ਫਰਕ ਅਪਵਾਦ + ਅਪਵਾਦ ਸ਼ੀਟ ਦਿਖਾਓ + ਜੇ ਹੋ ਸਕੇ ਤਾਂ ਇੱਕ ਸ਼ੀਟ \'ਤੇ ਫੜੇ ਅਪਵਾਦ ਦਿਖਾਓ, ਤਾਂ ਕਿ ਡਿਵੈਲਪਰ ਨੂੰ ਫਾਰਵਰਡਿੰਗ ਦੀ ਆਗਿਆ ਦਿੱਤੀ ਜਾ ਸਕੇ + ਅਪਵਾਦ ਤੇ ਸੁੱਟੋ + ਅਪਵਾਦ ਤੇ ਅਰਜ਼ੀ ਨੂੰ ਸੁੱਟ ਅਤੇ ਕਰੈਸ਼ ਕਰੋ. 5 ਕ੍ਰੈਸ਼ਾਂ ਦੇ ਬਾਅਦ ਰੀਸੈਟ ਕੀਤਾ ਜਾਏਗਾ + ਫੁਲਸਕ੍ਰੀਨ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ + ਸਕ੍ਰੀਨਸ਼ਾਟ ਅਤੇ ਰਿਕਾਰਡਿੰਗਾਂ ਦੀ ਆਗਿਆ ਦੇਣ ਲਈ ਐਪ ਨੂੰ ਫੁਲਸਕ੍ਰੀਨ ਬਣਾਉ + ਨੋਟ ਵੇਖੋ UUID + ਹੋਮ ਸਕ੍ਰੀਨ ਵਿਯੂ ਵਿੱਚ ਨੋਟਸ ਦੀਆਂ ਵਿਲੱਖਣ ਆਈਡੀਆਂ ਦਿਖਾਓ + ਨਕਲੀ ਅਪਵਾਦ + ਅਪਵਾਦ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦੀ ਜਾਂਚ ਕਰਨ ਲਈ ਇੱਕ ਨਕਲੀ ਅਪਵਾਦ ਨੂੰ ਸੁੱਟੋ + ਅਪਵਾਦ ਸੁੱਟਿਆ + ਕ੍ਰੈਸ਼ ਐਪ + ਮੇਲ + ਕੁਨੈਕਸ਼ਨ ਫੇਲ੍ਹ ਹੈ + Google Drive ਤੇ ਸਿੰਕ ਕਰੋ + Google ਡ੍ਰਾਇਵ ਤੁਹਾਨੂੰ ਤੁਹਾਡੀਆਂ ਖੁਦ ਦੀ Google ਡ੍ਰਾਈਵ ਖਾਤੇ ਦੀ ਵਰਤੋਂ ਕਰਦੇ ਹੋਏ ਡਿਵਾਈਸਾਂ ਦੇ ਵਿਚਕਾਰ ਆਪਣੇ ਨੋਟਸ ਨੂੰ ਸਿੰਕ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ. + Google Firebase ਵਿੱਚ ਪਹਿਲਾਂ ਲੌਗਇਨ ਕੀਤਾ? + Google Drive ਵਿੱਚ ਸਾਈਨ ਇਨ ਕਰੋ + ਸਾਈਨ ਇਨ ਕਰੋ | + ਸਕਾਰਲੇਟ ਦੇ ਸਾਈਨ ਆਊਟ + ਨੋਟਸ, ਟੈਗਸ ਅਤੇ ਫੋਲਡਰਸਿੰਗ ਸਿੰਕਿੰਗ ਬੰਦ ਕਰੋ + ਆਪਣੇ Google Drive ਤੇ ਤੁਹਾਡੇ ਨੋਟਸ, ਟੈਗਸ ਅਤੇ ਫੋਲਡਰਸ ਨੂੰ ਸਿੰਕ ਕਰਨਾ ਬੰਦ ਕਰੋ + ਐਪ ਅਤੇ Google ਡਰਾਇਵ \'ਤੇ ਤੁਹਾਡਾ ਡੇਟਾ ਅਜੇ ਵੀ ਉੱਥੇ ਹੋਵੇਗਾ + ਡ੍ਰਾਈਵ ਤੋਂ ਸਾਈਨ ਆਉਟ ਕਰੋ + ਸਾਈਨ ਆਉਟ \'| + ਨੋਟਸ, ਟੈਗਸ ਅਤੇ ਫੋਲਡਰ ਤੁਹਾਡੀ ਆਪਣੀ ਗੂਗਲ ਡ੍ਰਾਇਵ ਉੱਤੇ ਸਟੋਰ ਕੀਤੇ ਜਾਂਦੇ ਹਨ, ਇਸ ਲਈ ਸਿਰਫ ਤੁਸੀਂ ਉਹਨਾਂ ਤੱਕ ਪਹੁੰਚ ਨੂੰ ਕੰਟਰੋਲ ਕਰ ਸਕਦੇ ਹੋ. + ਤੁਹਾਡੀਆਂ ਫੋਟੋਆਂ ਨੂੰ ਵੀ ਡਿਵਾਈਸ ਉੱਤੇ ਅਪਲੋਡ ਅਤੇ ਸਿੰਕ ਕੀਤਾ ਗਿਆ ਹੈ + ਫਾਇਰਬੇਸ ਤੋਂ ਡਾਟਾ ਰੀਸਟੋਰ ਕਰੋ + Google ਦੇ ਨਾਲ ਸਾਈਨ ਇਨ ਕਰੋ + ਸਾਈਨ ਇਨ ਕਰੋ | + ਅਸੀਂ ਤੁਹਾਡੀ ਜਾਣਕਾਰੀ ਨੂੰ Google Firebase ਤੇ ਸਟੋਰ ਕਰਨ ਲਈ ਵਰਤਿਆ ਸੀ ਲੌਗਇਨ ਕਰਨ ਦੇ ਬਾਅਦ ਅਸੀਂ ਇਸਨੂੰ ਤੁਹਾਡੀ ਡਿਵਾਈਸ ਤੇ ਵਾਪਸ ਪ੍ਰਾਪਤ ਕਰਾਂਗੇ + ਨਵੇਂ ਨੋਟਸ ਅਤੇ ਬਦਲਾਵ Google Firebase ਤੇ ਸਿੰਕ ਨਹੀਂ ਕੀਤੇ ਜਾਣਗੇ, ਅਤੇ ਤੁਹਾਨੂੰ Google Drive ਤੇ ਲਾਗਇਨ ਕਰਨ ਦੀ ਲੋੜ ਹੈ + ਇੱਕ ਵਾਰ ਜਦੋਂ ਤੁਹਾਡੇ ਨੋਟਸ ਰਿਕਵਰ ਕੀਤੇ ਜਾਂਦੇ ਹਨ, ਤੁਸੀਂ ਉਹਨਾਂ ਨੂੰ Google Firebase ਤੋਂ ਮਿਟਾ ਸਕਦੇ ਹੋ, ਅਤੇ ਫਿਰ ਇਸਦੇ ਬਦਲੀ ਕਰ ਸਕਦੇ ਹੋ + ਤੁਹਾਡੇ ਡੇਟਾ ਨੂੰ ਸਿੰਕ ਨਹੀਂ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ! + ਲੇਗਸੀ ਲੌਗਿਨ ਦੇ ਅਧਾਰ \'ਤੇ ਡੇਟਾ ਸਿੰਕ ਅਸਮਰੱਥ ਹੈ, Google ਡ੍ਰਾਇਵ ਆਧਾਰਿਤ ਸਿੰਕ ਤੇ ਸਵਿਚ ਕਰਨ ਦਾ ਵਿਚਾਰ ਕਰੋ. + ਫਾਇਰਬੇਸ ਤੋਂ ਡਰਾਇਵ ਤੱਕ ਡੇਟਾ ਟ੍ਰਾਂਸਫਰ ਕਰੋ + ਡਾਟਾ ਸਾਫ਼ ਕਰੋ ਅਤੇ ਸਾਈਨ ਆਉਟ ਕਰੋ + ਕਲੀਅਰਿੰਗ ਅਤੇ ਸਾਈਨ ਆਉਟ + ਅਸੀਂ ਤੁਹਾਡੀ ਜਾਣਕਾਰੀ ਨੂੰ Google Firebase ਤੇ ਸਟੋਰ ਕਰਨ ਲਈ ਵਰਤਿਆ ਸੀ ਅਸੀਂ ਤੁਹਾਡੇ Google ਡਰਾਈਵ ਵਿੱਚ ਆਪਣੇ ਨੋਟਸ ਨੂੰ ਸਟੋਰ ਕਰਨ ਲਈ ਅੱਗੇ ਵਧ ਰਹੇ ਹਾਂ. + ਹੋਰ ਗੋਪਨੀਯਤਾ + ਫੋਟੋ ਸਮਕਾਲੀ + ਅਗਲਾ ਕਦਮ + ਅਸੀਂ ਪਹਿਲਾਂ ਫਾਇਰਬੇਜ ਤੋਂ ਤੁਹਾਡੇ ਨੋਟਸ ਮਿਟਾ ਸਕਦੇ ਹਾਂ ਅਤੇ ਤੁਹਾਨੂੰ ਆਉਟ ਕਰ ਸਕਦੇ ਹਾਂ. + ਤੁਸੀਂ ਫਿਰ Google Drive ਤੇ ਲੌਗ ਇਨ ਕਰ ਸਕਦੇ ਹੋ, ਅਤੇ ਅਸੀਂ ਚਿੱਤਰਾਂ ਦੇ ਨਾਲ ਤੁਹਾਡੇ ਡੇਟਾ ਨੂੰ ਅਪਲੋਡ ਕਰਾਂਗੇ. + + + ਵਿਕਲਪ ਹਟਾਓ + ਨੋਟਬੁੱਕ ਹਟਾਓ + ਸਿਰਫ ਨੋਟਬੁੱਕ ਹਟਾਓ. ਨੋਟ ਫੋਲਡਰ ਦੇ ਬਾਹਰ ਚਲੇ ਜਾਂਦੇ ਹਨ. + ਨੋਟਬੁੱਕ ਅਤੇ ਨੋਟ ਹਟਾਓ + ਨੋਟਬੁੱਕ ਹਟਾਓ. ਸਾਰੇ ਨੋਟ ਰੱਦੀ ਵਿੱਚ ਚਲੇ ਜਾਂਦੇ ਹਨ ਜਾਂ ਮਿਟਾ ਦਿੱਤੇ ਗਏ ਹਨ. + ਨੋਟ ਹਟਾਓ + ਨੋਟਬੁੱਕ ਰੱਖੋ ਪਰ ਸਾਰੇ ਨੋਟ ਰੱਦੀ ਵਿੱਚ ਭੇਜਦੇ ਹਨ ਜਾਂ ਮਿਟਾ ਦਿੱਤੇ ਜਾਂਦੇ ਹਨ. + ਫੋਂਟ ਅਨੁਕੂਲਿਤ ਕਰੋ + ਐਪ ਅਤੇ ਨੋਟ ਫੋਂਟ ਦੀ ਚੋਣ ਕਰੋ + ਇੱਕ ਫੋਂਟ ਸੈਟ ਚੁਣੋ + ਨੋਟ: ਫੋਂਟ ਸਾਰੀਆਂ ਭਾਸ਼ਾਵਾਂ ਦੇ ਨਾਲ ਕੰਮ ਨਹੀਂ ਕਰ ਸਕਦੇ + ਐਪ ਡਿਫੌਲਟ + ਡਿਵਾਈਸ ਡਿਫੌਲਟ + ਮੋਨੋ + ਸੀਰੀਫ + ਅਨਲੌਕ ਐਪ + 4 ਅੰਕਾਂ ਦਾ ਪਿੰਨ ਦਰਜ ਕਰੋ ਜਾਂ ਅਨਲੌਕ ਕਰਨ ਲਈ ਬਾਇਓਮੈਟ੍ਰਿਕਸ ਦੀ ਵਰਤੋਂ ਕਰੋ + ਅਨਲੌਕ ਕਰਨ ਲਈ 4 ਅੰਕਾਂ ਦਾ ਪਿੰਨ ਦਰਜ ਕਰੋ + ਸਿਸਟਮ ਥੀਮ ਵਰਤੋਂ + ਸਿਸਟਮ ਤੋਂ ਲਾਈਟ ਜਾਂ ਡਾਰਕ ਥੀਮ ਦੀ ਵਰਤੋਂ ਕਰੋ + ਗੂੜ੍ਹੇ ਨੋਟ + ਨੋਟ ਅਤੇ ਫੋਲਡਰ ਦੇ ਰੰਗ ਆਪਣੇ ਆਪ ਗੂੜ੍ਹੇ ਕਰੋ + ਸਥਾਨਕ + ਰਿਮੋਟ + ਅਣਉਪਲਬਧ + ਬਣਾਇਆ + ਮਿਟਾਇਆ ਗਿਆ + ਅੱਪਡੇਟ ਕੀਤਾ + ਵਿਜੇਟ ਪਿਛੋਕੜ + ਮਲਟੀ-ਨੋਟ ਵਿਜੇਟ ਲਈ ਪਿਛੋਕੜ ਦਾ ਰੰਗ ਚੁਣੋ + ਐਕਸ਼ਨ ਟੂਲਬਾਰ ਵੇਖੋ + ਮਲਟੀ-ਨੋਟ ਵਿਡਜਿਟ ਟੂਲਬਾਰ ਦਿਖਾਉਂਦਾ ਹੈ + ਨੋਟ ਦਰਸ਼ਕ ਛੱਡੋ + ਨੋਟ ਦੇਖਣ ਵਾਲੇ ਨੂੰ ਛੱਡੋ ਅਤੇ ਸਿੱਧੇ ਤੌਰ \'ਤੇ ਨੋਟ ਐਡੀਟਰ\' ਤੇ ਜਾਓ + ਕੀ ਤੁਸੀਂ ਇਹਨਾਂ ਨੋਟਾਂ ਨੂੰ ਪੱਕੇ ਤੌਰ \'ਤੇ ਮਿਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ? + ਤੇਜ਼ ਅਪਡੇਟਾਂ ਅਤੇ ਬੇਨਤੀਆਂ. + ਐਪ ਲੌਕ ਅਤੇ ਸਿੰਗਲ ਅਨਲੌਕ. + ਵਧੇਰੇ ਐਪ ਥੀਮ. + ਨੋਟ ਫੋਂਟ ਅਤੇ ਫੋਂਟ ਅਕਾਰ. + ਦਰਸ਼ਕ ਪਿਛੋਕੜ ਦਾ ਰੰਗ. + ਹੋਰ ਵਿਜੇਟ ਵਿਕਲਪ. + ਵਧੇਰੇ ਨੋਟਿਸ ਕਾਰਵਾਈਆਂ. + ਨੋਟ ਰੰਗ + ਨੋਟ ਟੈਗਸ + ਐਪ ਲੌਕ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ + ਪੂਰੀ ਐਪਲੀਕੇਸ਼ਨ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਲਈ ਪਿੰਨ ਦੀ ਵਰਤੋਂ ਕਰੋ + ਹਮੇਸ਼ਾਂ ਪਿੰਨ ਪੁੱਛੋ + ਸਾਰੇ ਨੋਟਸ ਲਈ ਪਿੰਨ ਦਰਜ ਕਰੋ, ਭਾਵੇਂ ਪਹਿਲਾਂ ਦਰਜ ਕੀਤਾ ਗਿਆ ਹੋਵੇ + ਬਾਇਓਮੈਟ੍ਰਿਕਸ ਨਾਲ ਅਨਲੌਕ ਕਰੋ + ਫਿੰਗਰਪ੍ਰਿੰਟ ਜਾਂ ਹੋਰ ਬਾਇਓਮੈਟ੍ਰਿਕਸ ਨਾਲ ਅਨਲੌਕ ਦੀ ਆਗਿਆ ਦਿਓ + ਬਾਇਓਮੈਟ੍ਰਿਕਸ ਅਸਮਰਥਿਤ + ਫਿੰਗਰਪ੍ਰਿੰਟ ਜਾਂ ਹੋਰ ਬਾਇਓਮੈਟ੍ਰਿਕਸ ਨਾਲ ਅਨਲੌਕ ਦੀ ਆਗਿਆ ਨਾ ਦਿਓ + ਅਨਲੌਕ ਨੋਟ + ਨੋਟ ਅਤੇ ਐਕਸੈਸ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਲਈ ਡਿਵਾਈਸ ਫਿੰਗਰਪ੍ਰਿੰਟ ਜਾਂ ਬਾਇਓਮੈਟ੍ਰਿਕਸ ਦੀ ਵਰਤੋਂ ਕਰੋ. + ਅਨਲੌਕ ਐਪ + ਐਪ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਅਤੇ ਸਾਰੇ ਨੋਟਸ ਨੂੰ ਐਕਸੈਸ ਕਰਨ ਲਈ ਡਿਵਾਈਸ ਫਿੰਗਰਪ੍ਰਿੰਟ ਜਾਂ ਬਾਇਓਮੈਟ੍ਰਿਕਸ ਦੀ ਵਰਤੋਂ ਕਰੋ. + ਲਾਂਚਰ ਸ਼ੌਰਟਕਟ + ਫੋਟੋਆਂ ਸਾਂਝੀਆਂ ਕਰੋ + \ No newline at end of file diff --git a/base/src/main/res/values-pl/strings.xml b/base/src/main/res/values-pl/strings.xml new file mode 100644 index 00000000..d3ee09ff --- /dev/null +++ b/base/src/main/res/values-pl/strings.xml @@ -0,0 +1,383 @@ + + + + Tytuł + Zawartość + Zapisać + Import + Szukaj w notatkach… + Udostępnij za pomocą… + Brak notatek + Wygląda na to, że nie dodałeś żadnych notatek. Kliknij, aby dodać notatkę. + Dodaj notatkę + Dodaj listę kontrolną + Edytuj notatkę + Utwórz powiadomienie + Otwórz w Popup + Usuń trwale + Kopiuj notatkę + Wyślij notatkę + Unarchive Note + Notatka archiwalna + Oznacz jako ulubione + Oznacz Ulubione + Przywróć notatkę + Przenieść do kosza + Zmień kolor + Uwaga blokady + Zmień tagi + Odblokuj notatkę + Przypomnienie + Wybierz + Duplikować + Przypnij notatkę + Odepnij notatkę + Distraction Free + Scal notatki + Wybierz działanie… + Dotknij, aby otworzyć notatkę do edycji + Dotknij, aby skopiować zawartość notatki do schowka + Dotknij, aby udostępnić treść notatki innym aplikacjom + Dotknij, aby otworzyć notatkę w wyskakującym okienku + Dotknij, aby usunąć notatkę + Dotknij, aby przenieść notatkę do kosza + Dotknij, aby przenieść notatkę z kosza + Dotknij, aby zaznaczyć notatkę jako ulubioną + Dotknij, aby zaznaczyć notatkę nie jako ulubioną + Wybierz, aby zarchiwizować notatkę + Dotknij, aby zmienić kolor tła notatki + Dotknij, aby rozpakować notatkę + Dom + Ulubione + Zarchiwizowane + Zablokowany + Śmieci + Dodaj treść… + Dodaj nagłówek… + Dodaj cytowany tekst… + Dodaj element… + Dodaj kod… + Kliknij, aby dodać lub zmienić obraz + + + Opcje i ustawienia + Interfejs i doświadczenie + Wybierz sposób, w jaki aplikacja wygląda i czuje się. + O + Dowiedz się więcej o nas i aplikacji. + Bezpieczeństwo + Blokowanie notatek i opcji zabezpieczeń + Włącz układ listy + Pokaż notatki w jednej kolumnie + Włącz układ siatki + Pokaż notatki w rozłożonej siatce + Uwagi dotyczące zamówień + Kopia zapasowa i import + Opcje tworzenia kopii zapasowych, importowania i eksportowania notatek + Eksportuj notatki + Eksportuj notatki do pamięci urządzenia, aby udostępnić + Importuj notatki + Importuj notatki z pamięci urządzenia + Eksportuj jako Markdown + Eksportuj notatki w formacie przeceny. (Nie możesz zaimportować ich z powrotem do aplikacji) + Eksportuj automatycznie + Często eksportuj notatki do pliku zewnętrznego jako kopię zapasową + O nas + Dowiedz się więcej o aplikacji i programistach + Projekt Open Source + Dowiedz się więcej o projekcie open source + Oceń i zrecenzuj + Powiedz nam, ile podobała ci się aplikacja + Zainstaluj Pro App + Zainstaluj Pro App, aby odblokować funkcje i wsparcie programisty + Migracja notatek do Scarlet Pro + Przeprowadź migrację wszystkich notatek do aplikacji pro + Usuń notatki i więcej + Usuń notatki, tagi i inne dane w aplikacji + Usuń wszystkie notatki + Usuń wszystkie notatki z aplikacji + Usuń wszystkie foldery + Usuń wszystkie foldery w aplikacji + Usuń wszystkie tagi + Usuń wszystkie tagi w aplikacji + Usuń wszystko + Usuń notatki, tagi i foldery w aplikacji + Tło podglądu notatki + Użyj koloru motywu dla tła + Użyj koloru notatki dla tła + + + Opcje ochrony + Kod dostępu + Ustaw 4-cyfrowy kod PIN, aby zablokować notatki + Wprowadź nowy kod PIN + Wprowadź kod PIN, aby odblokować + Wprowadź bieżący kod PIN + Zweryfikować + Odblokować + Zestaw + Usunąć + Domyślny kolor notatki + Wybierz domyślny kolor nut + Limit linii uwagi + %d linie na ekranie głównym + Wsparcie w przypadku obniżki cen + Zezwalaj na formatowanie obsługiwane przez przecenę + Markdown in Note List + Włącz formatowanie Markdown na liście notatek + Daj uprawnienia + Importowanie i eksportowanie wymaga uprawnień do przechowywania. Proszę o wyrażenie zgody na żądanie. + Dopuszczać + Importuj kopię zapasową z pliku + Importować plik + Eksportowane do pliku + Eksport nie powiódł się + Eksportowanie do pliku… + Gotowe + Dzielić + Włączyć + Wyłączyć + Włącz synchronizację folderów + Synchronizacja folderów + Synchronizuj wszystkie swoje notatki, tagi i foldery z folderem zewnętrznym. Pomaga to synchronizować za pomocą innych aplikacji między urządzeniami, a także mieć kopię na wypadek konieczności usunięcia aplikacji. + Eksportowanie do folderu + Zsynchronizuj wszystkie notatki, tagi itp. Z folderem zewnętrznym + Eksportuj zablokowane notatki + Wykonaj również kopię zapasową zablokowanych notatek + Oceń na Play Store + Przyczynić się + Wersja aplikacji + O aplikacji + Biblioteki + Projekt Open Source + Data przypomnienia + Czas przypomnienia + Powtórz częstotliwość + Tylko raz + Codziennie + Uwaga Powiadomienia + Przypomnienia i alarmy + %s jest open source i każdy jest otwarty, aby przyczynić się do jego ulepszenia. Jest obecnie budowany i utrzymywany przez %s. + %s to prosta aplikacja do robienia notatek. Pozwala na szybkie wprowadzanie tekstu sformatowanego, nie czyniąc tego bardzo trudnym w użyciu. Sprawia, że ​​wielozadaniowość jest prosta. + Cześć, jesteśmy parą projektantów i programistów, którzy stworzyli %s. + Staramy się budować piękne, starannie zaprojektowane darmowe, wolne od reklam lub minimalne aplikacje reklamowe, które są przydatne dla wszystkich! + Dodaj nowy tag… + Edytuj znacznik… + wprowadź tag + + + Utwórz nowy tag + Wybierz tag… + Sortuj notatki według + Najpierw najnowsze + Najpierw najstarsi + Ostatnio zmodyfikowane + Alfabetyczny + Wybierz notatkę + Wybierz Notatki + Ustawienia + Uwaga usunięta lub zablokowana + Co nowego + Dowiedz się, co nowego w najnowszych aktualizacjach aplikacji + Tłumaczyć + Kopiuj + Blokuj akcje tekstowe + Galeria + Aparat fotograficzny + Mów głośno na głos + Mówić na głos + Usunięcie tego elementu spowoduje usunięcie obrazu ze wszystkich urządzeń. + Obraz nie jest na tym urządzeniu + Nie można załadować obrazu + Obrazy nie są synchronizowane + Obrazy nie są synchronizowane między urządzeniami. Twoje obrazy nie będą wyświetlane na innych urządzeniach podczas wyświetlania notatki! + Rozumiem + Uwaga Rozmiar czcionki + Dostosuj rozmiar czcionki tekstu na stronie notatek. Możesz zobaczyć, jak będzie wyglądać w tym podglądzie. + %d rozmiar tekstu w przeglądarce notatek + Zainstaluj ze sklepu + Zainstaluj aplikację z Google Store dla Cloud Sync + Brak kodu PIN + Nie skonfigurowałeś kodu PIN. Czy chcesz to teraz skonfigurować? + Później + Nigdy nie pytaj + Ustawiać + Jesteś pewny? + Czy chcesz trwale usunąć notatki z folderu kosza? + Czy chcesz trwale usunąć tę notatkę? + Kasować + Anuluj + Notatki są usuwane na zawsze po 7 dniach + Informacja + Wybierz, aby zainstalować najnowszą wersję aplikacji + Wybierz, aby uaktualnić do Scarlet Pro + Zaloguj się do aplikacji + Zaloguj się, aby wykonać kopię zapasową w chmurze i synchronizację + Wyloguj się + Wyloguj się, aby zatrzymać tworzenie kopii zapasowej w chmurze + Logowanie Google nie powiodło się + Polityka prywatności + Polityka prywatności aplikacji dla treści + Zainstaluj Pro App + Dostępne na Scarlet Pro + Dlaczego warto zainstalować Pro? + ✔ Wspieraj programistę w zakresie ogromnych kosztów serwera, aby uruchomić synchronizację w chmurze \n\n✔ Najpierw zdobądź najnowsze funkcje\n\n✔ Niektóre dodatkowe funkcje będą dostępne tylko dla użytkowników Pro + + + Motyw aplikacji + Wybierz kolor tła dla motywu + Wybierz motyw aplikacji + Kliknij, aby dodać lub zmienić tagi + Wybierz Notatki + Wybierz i wykonaj czynności na wielu notatkach jednocześnie + Notatka została przeniesiona do kosza + Notatka została usunięta + Cofnij + Wyłącz kopię zapasową + Włącz kopię zapasową + Pusty notatnik + 1 Uwaga + %d Notatki + Utwórz nowy notatnik + Edytuj notatnik + Dodaj notatnik + Dodaj do Notatnika + Zmień notatnik + Ostatnie notatki + Opcje edytora + Zmień ustawienia i użycie edytora notatek + Opcje wyboru jako domyślne + Pokaż domyślne przyciski szybkiego wybierania na pasku narzędzi + Markdown w czasie rzeczywistym + Wybierz, czy chcesz, aby przecena była widoczna jako twój typ. Włączenie może wpływać na wydajność dużych nut. + Przenieś zaznaczone przedmioty + Zaznaczone elementy przechodzą na dół listy. Usuń zaznaczenie nie resetuje pozycji. + Pokaż uchwyty ruchu + Pokaż uchwyt, aby przesunąć elementy w górę lub w dół. Nadal możesz przemieszczać rzeczy, dotykając rogu. + Przykłady obniżek + Ustawienia widżetu + Zmień ustawienia widżetów ekranu głównego + Włącz formatowanie + Notatki są renderowane z formatowaniem w widżetach ekranu głównego + Pokaż zablokowane notatki + Zezwalaj na wyświetlanie zablokowanych notatek w widżetach ekranu głównego + Pokaż zarchiwizowane notatki + Pozwól, aby zarchiwizowane notatki były wyświetlane w widżetach ekranu głównego + Pokaż notatki w koszu + Pozwól na wyświetlanie notatek w koszu na widżetach ekranu głównego + Pomoc i często zadawane pytania + Znajdź pomoc dotyczącą korzystania z funkcji w aplikacji + Synchronizacja + Oczekiwanie na kopię zapasową + Opcje programistyczne + Zmień ustawienia wewnętrzne na aplikację używaną do debugowania + Wyjątki dziennika + Zarejestruj wychwycone wyjątki w ustalonej notatce, aby umożliwić przekazywanie do programisty + + + Pokaż arkusz wyjątków + Pokaż wychwycone wyjątki na arkuszu, jeśli to możliwe, aby umożliwić przekazanie do programisty + Wyrzuć wyjątki + Rzucaj i zawieszaj aplikację na wyjątkach. Zostanie zresetowany po 5 awariach + Włącz pełny ekran + Ustaw aplikację na pełnym ekranie, aby umożliwić zrzuty ekranu i nagrania + Pokaż identyfikatory UUID + Pokaż unikalne identyfikatory notatek w widoku ekranu głównego + Fałszywe wyjątki + Wyrzuć fałszywy wyjątek, aby przetestować funkcje wyjątku + Wyjątek rzucony + Crash App + Poczta + Połączenie nieudane + Synchronizuj na Dysku Google + Dysk Google umożliwia synchronizację notatek między urządzeniami za pomocą własnego konta Dysku Google. + Zalogowałeś się wcześniej do Google Firebase? + Zaloguj się na Dysk Google + Podpisywanie… + Wyloguj się z Scarlet + Przestań synchronizować notatki, tagi i foldery. + Przestań synchronizować swoje notatki, tagi i foldery z Dyskiem Google. + Twoje dane w aplikacji i na Dysku Google nadal tam będą. + Wyloguj się z dysku + Wylogowanie… + Notatki, tagi i foldery są przechowywane na własnym Dysku Google, więc tylko Ty możesz kontrolować dostęp do nich. + Twoje zdjęcia są przesyłane i synchronizowane również na różnych urządzeniach. + Przywróć dane z Firebase + Zaloguj się za pomocą Google + Podpisywanie… + Używaliśmy do przechowywania twoich informacji w Google Firebase. Po zalogowaniu odzyskamy je na Twoim urządzeniu + Nowe notatki i zmiany NIE zostaną zsynchronizowane z Google Firebase i musisz zalogować się na Dysk Google + Po odzyskaniu notatek możesz je usunąć z Google Firebase, a następnie przełączyć + Twoje dane nie są synchronizowane! + Synchronizacja danych oparta na starszym logowaniu jest wyłączona, należy rozważyć przejście na synchronizację opartą na Dysku Google. + Przenieś dane z Firebase do napędu + Wyczyść dane i wyloguj się + Czyszczenie i wylogowywanie + Używaliśmy do przechowywania twoich informacji w Google Firebase. Przechodzimy do przechowywania notatek na Twoim Dysku Google. + Więcej prywatności. + Synchronizacja zdjęć. + Następne kroki + Najpierw usuniemy notatki z Firebase i wylogujemy się. + Następnie możesz zalogować się na Dysk Google, a my prześlemy Twoje dane wraz z obrazami. + + + Usuń opcje + Usuń notatnik + Usuń tylko notatnik. Notatki przenoszą się poza folder. + Usuń notatnik i notatki + Usuń notatnik. Wszystkie notatki są przenoszone do kosza lub są usuwane. + Usuń notatki + Zachowaj Notatnik, ale wszystkie notatki zostaną przeniesione do kosza lub zostaną usunięte. + Dostosuj czcionki + Wybierz aplikację i czcionki notatek + Wybierz zestaw czcionek + Uwaga: Czcionki mogą nie działać poprawnie we wszystkich językach + Domyślna aplikacja + Domyślne urządzenie + Mono + Szeryfowy + Odblokuj aplikację + Wprowadź 4-cyfrowy kod PIN lub użyj danych biometrycznych, aby odblokować + Wprowadź 4-cyfrowy kod PIN, aby odblokować + Użyj motywu systemu + Użyj jasnego lub ciemnego motywu z systemu + Ciemne nuty + Automatycznie przyciemnij kolory notatek i folderów + Lokalny + Zdalny + Niedostępne + Stworzony + Usunięte + Zaktualizowano + Tło widżetu + Wybierz kolor tła dla widżetu z wieloma notatkami + Pokaż pasek narzędzi działania + Widżet Multi-notes pokazuje pasek narzędzi + Pomiń przeglądarkę notatek + Pomiń przeglądarkę notatek i przejdź bezpośrednio do edytora notatek + Czy chcesz trwale usunąć te notatki? + Szybsze aktualizacje i żądania. + Blokada aplikacji i pojedyncze odblokowanie. + Więcej motywów aplikacji. + Uwaga Czcionki i rozmiary czcionek. + Kolor tła przeglądarki. + Więcej opcji widżetów. + Więcej uwag Akcje. + Kolor notatki + Uwaga Tagi + Włącz blokadę aplikacji + Użyj kodu PIN, aby odblokować całą aplikację + Zawsze pytaj o PIN + Wprowadź PIN dla wszystkich notatek, nawet jeśli zostały wcześniej wprowadzone + Odblokuj za pomocą biometrii + Zezwól na odblokowanie za pomocą odcisku palca lub innej biometrii + Dane biometryczne wyłączone + Nie zezwalaj na odblokowanie za pomocą odcisku palca lub innej biometrii + Odblokuj notatkę + Użyj odcisku palca urządzenia lub danych biometrycznych, aby odblokować notatkę i uzyskać do niej dostęp. + Odblokuj aplikację + Użyj odcisku palca urządzenia lub danych biometrycznych, aby odblokować aplikację i uzyskać dostęp do wszystkich notatek. + Skrót programu uruchamiającego + Dzielić się zdjęciami + + \ No newline at end of file diff --git a/base/src/main/res/values-pt/strings.xml b/base/src/main/res/values-pt/strings.xml index 9e0fb215..c08aad8a 100644 --- a/base/src/main/res/values-pt/strings.xml +++ b/base/src/main/res/values-pt/strings.xml @@ -6,25 +6,18 @@ Compartilhe usando … Sem notas Parece que você não adicionou nenhuma nota. Clique para adicionar uma nota. - Adicione uma anotação… - Adicione uma nota rápida … Editar nota Abrir em pop-up - Excluir nota Copiar nota Enviar nota Escolher ação… Adicionar conteúdo… Adicionar cabeçalho … - Adicionar sub encabeçamento … Adicionar texto citado … Adicionar Item… Adicionar código … Suporte Markdown Permitir formatação suportada pelo markdown - Exemplos - Configurações de Markdown - Veja como usar markdown em notas Opções e Configurações Exportar notas Exportar notas para o armazenamento do dispositivo para compartilhar @@ -44,7 +37,6 @@ Exportando para arquivo … Feito Compartilhar - Sobre nós e mais Avalie na Play Store Contribuir Versão da aplicação @@ -62,29 +54,17 @@ Opções de segurança Código de passagem Defina um PIN de 4 dígitos para bloquear notas - Desbloquear com impressão digital - As notas serão desbloqueadas com a impressão digital - Fingerprint desativado - As notas não usarão uma impressão digital Digite o novo PIN Digite PIN para desbloquear Digite o PIN atual - Coloque o código Verificar Desbloquear Conjunto Remover - Modo dia Mudar cor - Toque para visualizar a nota no modo dia Toque para alterar a cor de fundo da nota - Ativar modo noturno - Ativar tema escuro como padrão - Ativar modo dia - Ative o tema da luz como padrão - Modo noturno Apagar permanentemente Unarchive Note Nota de arquivo @@ -92,7 +72,6 @@ Marcar Favorito Nota de restauração Mover para lixeira - Toque para ver a nota no modo noturno Toque para abrir a nota para edição Toque para copiar o conteúdo da nota para a área de transferência Toque para compartilhar conteúdo de notas em outras aplicações @@ -104,21 +83,13 @@ Toque para marcar a nota não como favorito Toque para arquivar a nota Toque para desarchivar a nota - Suas notas … Casa - Todas as suas notas normais e favoritas Favoritos - Todas as suas notas favoritas Arquivado - Todas as suas anotações arquivadas Lixo - Todas as suas notas no lixo Criar Notificação Notificações de nota Bloqueado - Todas as suas notas bloqueadas - Tag - Todas as suas notas Adicionar nova etiqueta … Editar Tag … digite tag @@ -129,8 +100,6 @@ Importar Marcação na lista de notas Habilite a formatação do Markdown na lista de notas - Enquete de preenchimento - Ajude-nos a melhorar o aplicativo, dizendo-nos o que você gosta Alterar Tags @@ -139,8 +108,6 @@ Saiba mais sobre o projeto de código aberto Bibliotecas Projeto de código aberto - Sobre o Projeto Open Source - Lembrete de nota Data de Lembrete Tempo de lembrete Frequência repetida @@ -155,8 +122,6 @@ Interface e Experiência Escolha como o aplicativo parece e se sente. - Preferências de nota - Escolha a nota e outras configurações. Sobre Saiba mais sobre nós e o aplicativo. Cor da nota padrão @@ -191,19 +156,6 @@ Adicionar nota Adicionar lista de verificação - Formatação de blocos - Título - Título secundário - Texto - Citar - Código - Lista de controle - Formatação de Markdown - Negrito - Itálico - Sublinhado - Greve - Lista Selecione uma nota Selecione notas Configurações @@ -217,9 +169,6 @@ O que há de novo Saiba o que há de novo nas atualizações recentes do aplicativo Traduzir - Clique para adicionar uma nova nota - Clique para ver as opções de casa - O menu inicial tem suas notas favoritas e de arquivo, bem como as configurações da aplicação. Você também pode encontrar suas tags aqui. @@ -237,51 +186,37 @@ Compreendo Exportar automaticamente Exportar notas com freqüência para arquivos externos como backup - Imagem Clique para adicionar ou alterar a imagem Apenas uma vez Diariamente - personalizadas - Beta Lembretes e alarmes %s é de código aberto e qualquer pessoa está aberta para contribuir para torná-lo melhor. Atualmente, ele é construído e mantido por %s. %s é um simples aplicativo de tomada de notas. Ele permite uma entrada rápida de Rich Text sem tornar a experiência muito difícil de usar. Isso torna a multitarefa uma brisa. Oi, somos um par de designers e programadores, que criaram %s. Nós nos esforçamos para criar aplicativos de anúncios bonitos, cuidadosamente projetados, gratuitos, gratuitos ou mínimos, que servem uma ótima utilidade para todos! %d linhas na tela inicial - Pesquisar %s … Distração grátis - Separador Iniciar sessão na aplicação Faça login para o backup e sincronização da nuvem Sair Sair para parar o backup da nuvem - Faça login no Google - Assinando em … - Você está logado Falha no Login do Google Política de Privacidade Política de privacidade da aplicação para o conteúdo Instale a aplicação Pro Por que instalar o Pro Desenvolvedor de suporte para os custos maciços do servidor, para executar a sincronização da nuvem \n\n Obtenha os recursos mais recentes primeiro \n\n Alguns recursos extras estarão disponíveis apenas para usuários do Pro - Por que ativar o Cloud Sync - Carregar e fazer backup de mudanças no dispositivo \n\n Sincronizar entre vários dispositivos e obter atualizações rápidas \n\n Salvaguardado de forma segura em servidores do Google Firebase - Olá, - Notas de material agora é escarlate! - Iniciar App Theme Selecione a cor de fundo para o tema Selecione o tema da aplicação Clique para adicionar ou alterar tags - Mostrar mais ações Selecione Notas Selecione e execute ações em várias notas de uma só vez A nota foi movida para o lixo @@ -317,4 +252,155 @@ Excluir notas, tags e pastas no aplicativo Fundo do visualizador de nota + + Mesclar anotações + Exportar como Markdown + Exportar notas no formato de marcação. (Você não pode importar de volta para o aplicativo) + Use a cor do tema para o fundo + Use a cor da nota para o fundo + Habilitar + Desabilitar + Ativar sincronização de pastas + Sincronização de pastas + Sincronize todas as suas anotações, tags e pastas em uma pasta externa. Isso ajuda você a sincronizar usando outros aplicativos entre dispositivos, além de ter uma cópia no caso de precisar excluir o aplicativo. + Exportando para pasta + Sincronize todas as notas, tags, etc para uma pasta externa + Exportar notas bloqueadas + Alfabético + Disponível no Scarlet Pro + Também faça backup das notas bloqueadas + Opções do editor + Alterar as configurações e uso para o editor de notas + Opções de marcação como padrão + Mostrar os botões rápidos de markdown na barra de ferramentas como padrão + Markdown em tempo real + Escolha se você deseja que o markdown seja visível como seu tipo. A ativação pode afetar o desempenho em notas grandes. + Mover itens marcados + Os itens marcados passam para o final da lista. Desmarque não redefine a posição. + Mostrar alças de movimento + Mostrar a alça para mover itens para cima ou para baixo. Você ainda pode mover as coisas tocando no canto. + Exemplos de remarcação + Configurações de Widget + Alterar as configurações dos widgets da tela principal + Ativar formatação + As notas são renderizadas com formatação nos widgets da tela inicial + Mostrar notas bloqueadas + Permitir que notas bloqueadas sejam exibidas em widgets da tela inicial + Mostrar notas arquivadas + Permitir que anotações arquivadas sejam mostradas em widgets da tela inicial + Mostrar notas no lixo + Permitir que notas na lixeira sejam exibidas em widgets da tela inicial + Ajuda e Perguntas Comuns + Encontre ajuda sobre como usar os recursos no aplicativo + Sincronizando + Backup pendente + Opções de desenvolvedor + Alterar configurações internas para o aplicativo usado para depuração + Exceções de log + Registrar exceções capturadas em uma nota fixa, para permitir o encaminhamento para o desenvolvedor + Mostrar folha de exceção + Mostrar exceções capturadas em uma planilha, se possível, para permitir o encaminhamento para o desenvolvedor + Lançar exceções + Jogue e trave o aplicativo em exceções. Será reposto após 5 falhas + Ativar tela inteira + Torne o aplicativo em tela cheia para permitir capturas de tela e gravações + Mostrar UUIDs de notas + Mostrar os IDs exclusivos das notas na exibição da tela inicial + Exceções falsas + Lance uma exceção falsa para testar os recursos de exceção + Exceção lançada + Bater App + Enviar + Conexão falhada + Sincronizar no Google Drive + O Google Drive permite sincronizar suas notas entre dispositivos usando sua própria conta do Google Drive. + Já fez login no Google Firebase? + Faça login no Google Drive + Assinando em … + Sair do Escarlate + Pare de sincronizar notas, tags e pastas. + Pare de sincronizar suas notas, tags e pastas com seu Google Drive. + Seus dados no aplicativo e no Google Drive ainda estarão lá. + Sair do Drive + Sair … + Notas, etiquetas e pastas são armazenados no seu próprio Google Drive, pelo que apenas pode controlar o acesso a eles. + Suas fotos também são carregadas e sincronizadas em todos os dispositivos. + Restaurar dados do Firebase + Faça login no Google + Assinando em … + Nós armazenamos suas informações no Google Firebase. Após o login, nós os recuperaremos no seu dispositivo + Novas notas e alterações NÃO serão sincronizadas no Google Firebase e você precisará fazer login no Google Drive + Depois que suas anotações forem recuperadas, você poderá excluí-las do Google Firebase e, em seguida, alternar + Seus dados não estão sendo sincronizados! + A Sincronização de dados com base no login herdado está desativada. Considere a possibilidade de alternar para a sincronização baseada no Google Drive. + Transferir dados do Firebase para o Drive + Limpar dados e sair + Limpar e sair + Nós armazenamos suas informações no Google Firebase. Estamos mudando para armazenar suas anotações no seu Google Drive. + Mais privacidade. + Sincronização de fotos. + Próximos passos + Primeiramente, excluiremos suas anotações do Firebase e faremos seu logout. + Você pode fazer login no Google Drive e enviaremos seus dados junto com as imagens. + + + Remover opções + Remover Notebook + Remova apenas o notebook. As anotações são movidas para fora da pasta. + Remover bloco de anotações e anotações + Remova o notebook. Todas as notas passam para o lixo ou são excluídas. + Remover anotações + Mantenha o Bloco de anotações, mas todas as anotações passam para a lixeira ou são excluídas. + Personalizar fontes + Selecione o aplicativo e observe as fontes + Selecione um conjunto de fontes + Nota: As fontes podem não funcionar corretamente em todos os idiomas + Padrão do aplicativo + Padrão do dispositivo + Mono + Serif + Desbloquear aplicativo + Digite o PIN de 4 dígitos ou use a biometria para desbloquear + Digite o PIN de 4 dígitos para desbloquear + Usar tema do sistema + Use o tema claro ou escuro do sistema + Notas Sombrias + Escurecer automaticamente as cores das notas e pastas + Local + Controlo remoto + Indisponível + Criado + Excluído + Atualizada + Fundo do widget + Escolha a cor de fundo para o widget de várias notas + Mostrar barra de ferramentas de ação + O widget de várias notas mostra a barra de ferramentas + Ignorar visualizador de notas + Pule o visualizador de notas e vá diretamente para o editor de notas + Deseja excluir permanentemente essas notas? + Atualizações e solicitações mais rápidas. + Bloqueio de aplicativo e desbloqueio único. + Mais temas de aplicativos. + Observe fontes e tamanhos de fonte. + Cor de fundo do visualizador. + Mais opções de widget. + Mais ações de anotação. + Nota Cor + Tags de nota + Ativar bloqueio de aplicativo + Use o PIN para desbloquear o aplicativo inteiro + Sempre solicite o PIN + Digite o PIN para todas as notas, mesmo se inserido anteriormente + Desbloquear com biometria + Permitir desbloqueio com uma impressão digital ou outros dados biométricos + Biometria desativada + Não permita o desbloqueio com uma impressão digital ou outra biometria + Nota de desbloqueio + Use a impressão digital do dispositivo ou a biometria para desbloquear a nota e o acesso. + Desbloquear aplicativo + Use a impressão digital ou a biometria do dispositivo para desbloquear o aplicativo e acessar todas as notas. + Atalho do iniciador + Compartilhar fotos + \ No newline at end of file diff --git a/base/src/main/res/values-ru/strings.xml b/base/src/main/res/values-ru/strings.xml index b86f9709..ef3eb4c5 100644 --- a/base/src/main/res/values-ru/strings.xml +++ b/base/src/main/res/values-ru/strings.xml @@ -4,24 +4,17 @@ Сохранить Импортировать Поиск заметок - Поиск %s … Отправить через … Нет заметок Похоже, у вас нет ни одной заметки. Нажмите, чтобы добавить. - Добавить заметку… - Добавить быструю заметку… - Добавить заметку Добавить контрольный список - Ночной режим - Дневной режим Редактировать Создать уведомление Открыть всплывающее окно - Удалить Удалить совсем Копировать Поделиться @@ -43,8 +36,6 @@ Отвлечение бесплатно Выберите действие… - Нажмите, чтобы просмотреть заметку в ночном режиме - Нажмите, чтобы просмотреть заметку в дневном режиме Нажмите, чтобы открыть заметку для редактирования Нажмите, чтобы скопировать содержимое заметки в буфер обмена Нажмите, чтобы поделиться содержимым заметки с другим приложением @@ -58,60 +49,26 @@ Нажмите, чтобы сменить цвет фона заметки Нажмите, чтобы разархивировать заметку - Ваши заметки… Главное - Все ваши обычные и избранные заметки Избранное - Все ваши избранные заметки Архив - Все ваши архивные заметки Заблокированные - Все ваши заблокированные заметки - Теги - Все ваши заметки Корзина - Все ваши удалённые заметки Добавить содержимое… Добавить заголовок… - Добавить подзаголовок… Добавить цитируемый текст… Добавить пункт… Добавить код… Нажмите, чтобы добавить или изменить изображение - Блокирование форматирования - заголовок - Sub Heading - Текст - котировка - Код - контрольный список - Образ - Разделитель - - Форматирование Markdown - Жирный - Курсив - подчеркивание - удар - Список - Параметры и настройки Интерфейс и опыт Выберите, как приложение выглядит и чувствует. - Примечание. - Выберите примечание и другие настройки. О программе Узнайте больше о нас и приложении. Безопасность Блокировка заметок и параметров безопасности - Ночной режим - Включить темную тему по умолчанию - Дневной режим - Включить светлую тему по умолчанию - Настройки разметки - Посмотрите, как использовать уценку в заметках Включить макет списка Показывать заметки в одном столбце Включить компоновку сетки @@ -131,8 +88,6 @@ Узнайте больше о проекте с открытым исходным кодом Оценка и отзыв Расскажите нам насколько вам нравится приложение - Заполнение опроса - Помогите нам улучшить приложение, сообщив нам, что вам нравится Установить Pro App Установите приложение Pro для разблокировки функций и поддержки разработчика Перенос заметок в Scarlet Pro @@ -153,15 +108,10 @@ Параметры безопасности Код прохода Установите 4-значный PIN-код для блокировки заметок - Разблокировка с помощью отпечатка пальца - Заметки будут разблокированы с помощью отпечатка пальца - Отключить отпечаток пальца - Примечания не будут использовать отпечаток Введите новый PIN-код Введите PIN-код для разблокировки Введите текущий PIN-код - введите код проверить отпереть Задавать @@ -176,7 +126,6 @@ Разрешить форматирование поддерживаемых меток Отметка в списке заметок Включить форматирование Markdown в списке заметок - Примеры Дать разрешение Импорт и экспорт требуют разрешения на доступ к файловой системе. Пожалуйста, дайте разрешение по запросу. @@ -191,7 +140,6 @@ Поделиться - О нас и многое другое Оценить в Play Маркет Сделать вклад Версия приложения @@ -199,16 +147,12 @@ Библиотеки Проект с открытым исходным кодом - О проекте с открытым исходным кодом - Примечание Напоминание Дата напоминания Время напоминания Частота повторения Только один раз Ежедневно - изготовленный на заказ - Бета Уведомления об уведомлениях Напоминания и сигналы тревоги @@ -241,10 +185,6 @@ Узнайте, что нового в последних обновлениях приложения Переведите - Нажмите, чтобы добавить новую заметку - Нажмите, чтобы увидеть домашние параметры - В главном меню есть ваши любимые и архивные заметки, а также настройки приложения. Здесь вы можете найти свои теги. - копия Блокировать текстовые действия Галерея @@ -299,9 +239,6 @@ Вход для резервного копирования и синхронизации облаков Выход Выйти, чтобы остановить резервное копирование облаков - Войти с помощью Google - Вход в систему | - Вы вошли в систему Ошибка входа в Google политика конфиденциальности @@ -315,19 +252,10 @@ Сначала получить самые последние функции \n \n Некоторые дополнительные функции будут доступны только пользователям Pro - Зачем использовать Cloud Sync - Загрузка и резервное копирование от изменений устройства \n - \n - Синхронизация между несколькими устройствами и быстрое обновление \n - \n - Безопасное сохранение на серверах Google Firebase - Здравствуйте, - Материал Notes теперь Scarlet! - Начать @@ -338,7 +266,6 @@ Нажмите, чтобы добавить или изменить теги - Показать другие действия Выберите заметки Выбирайте и выполняйте действия сразу по нескольким нотам @@ -361,4 +288,156 @@ Последние примечания + + Объединить заметки + Экспортировать как уценку + Экспорт заметок в формате уценки. (Вы не можете импортировать их обратно в приложение) + Используйте цвет темы для фона + Используйте цвет заметки для фона + включить + запрещать + Включить синхронизацию папок + Синхронизация папок + Синхронизируйте все свои заметки, теги и папки с внешней папкой. Это поможет вам синхронизировать использование других приложений между устройствами, а также иметь копию на случай, если вам нужно удалить приложение. + Экспорт в папку + Синхронизировать все заметки, теги и т. Д. Во внешней папке + Экспорт заблокированных заметок + По алфавиту + Доступно на Скарлет Про + Также сделайте резервную копию заметок, которые заблокированы + Параметры редактора + Изменить настройки и использование для редактора заметок + Параметры уценки по умолчанию + Показывать быстрые кнопки уценки на панели инструментов по умолчанию + Уценка в реальном времени + Выберите, если вы хотите, чтобы уценка была видна как ваш тип. Включение может повлиять на производительность на больших заметках. + Переместить отмеченные элементы + Проверенные элементы перемещаются в конец списка. Снять отметку не сбрасывает положение. + Показать ручки движения + Показать ручку для перемещения предметов вверх или вниз. Вы все еще можете перемещать вещи, касаясь угла. + Примеры уценок + Настройки виджета + Изменить настройки виджетов на главном экране + Включить форматирование + Заметки отображаются с форматированием в виджетах главного экрана + Показать заблокированные заметки + Разрешить показ заблокированных заметок в виджетах главного экрана + Показать архивные заметки + Разрешить отображение архивных заметок в виджетах главного экрана + Показать заметки в корзине + Разрешить отображение заметок в корзине на виджетах главного экрана + Помощь и общие вопросы + Найти справку о том, как использовать функции в приложении + Синхронизации + Ожидание резервного копирования + Параметры разработчика + Изменить внутренние настройки для приложения, используемого для отладки + Исключения журнала + Записывать перехваченные исключения в фиксированную заметку, чтобы разрешить пересылку разработчику + Показать лист исключений + По возможности отображать перехваченные исключения на листе, чтобы разрешить пересылку разработчику + Бросить на исключения + Выкинь и вылети приложение на исключения. Будет сброшен после 5 сбоев + Включить полноэкранный режим + Сделайте приложение в полноэкранном режиме, чтобы разрешить скриншоты и записи + Показать примечания UUID + Показать уникальные идентификаторы заметок на главном экране + Поддельные исключения + Создайте ложное исключение, чтобы проверить возможности исключения + Исключение брошено + Crash App + почта + Ошибка подключения + Синхронизация на Google Диске + Google Диск позволяет синхронизировать ваши заметки между устройствами, используя вашу собственную учетную запись Google Drive. + Входили в Google Firebase раньше? + Войдите в Google Drive + Вход в систему… + Выйти из Алого ордена + Прекратите синхронизировать заметки, теги и папки. + Прекратите синхронизировать свои заметки, теги и папки с вашим Google Диском. + Ваши данные в приложении и на Google Диске все еще будут там. + Выйти из Drive + Выход … + Заметки, теги и папки хранятся на вашем собственном Google Диске, поэтому только вы можете контролировать доступ к ним. + Ваши фотографии также загружаются и синхронизируются между устройствами. + Восстановить данные из Firebase + Войти через Google + Вход в систему… + Мы использовали для хранения вашей информации в Google Firebase. После входа мы восстановим их на вашем устройстве. + Новые заметки и изменения НЕ будут синхронизироваться с Google Firebase, и вам необходимо войти на Google Диск + Как только ваши заметки будут восстановлены, вы можете удалить их из Google Firebase, а затем переключиться + Ваши данные не синхронизируются! + Синхронизация данных на основе устаревшего входа отключена, рассмотрите возможность перехода на синхронизацию на Google Диске. + Перенос данных с Firebase на диск + Очистить данные и выйти + Очистка и выход + Мы использовали для хранения вашей информации в Google Firebase. Мы переходим к хранению ваших заметок на вашем Google Диске. + Больше конфиденциальности. + Синхронизация фотографий. + Следующие шаги + Сначала мы удалим ваши заметки из Firebase и выйдем из системы. + Затем вы можете войти в Google Drive, и мы загрузим ваши данные вместе с изображениями. + + + + Удалить параметры + Удалить блокнот + Только удалить ноутбук. Заметки перемещаются за пределы папки. + Удалить блокнот и заметки + Удалить блокнот. Все заметки перемещаются в корзину или удаляются. + Удалить заметки + Сохраните записную книжку, но все заметки перемещаются в корзину или удаляются. + Настроить шрифты + Выберите приложение и отметьте шрифты + Выберите набор шрифтов + Примечание. Шрифты могут работать некорректно со всеми языками. + Приложение по умолчанию + Устройство по умолчанию + Моно + засечка + Разблокировать приложение + Введите 4-значный PIN-код или используйте биометрические данные, чтобы разблокировать + Введите 4-значный PIN-код, чтобы разблокировать + Использовать тему системы + Используйте светлую или темную тему из системы + Темные ноты + Автоматически затемнять цвета заметок и папок + Местный + Удаленный + Недоступен + созданный + Исключен + обновленный + Фон виджета + Выберите цвет фона для виджета с несколькими заметками + Показать панель действий + Мульти-заметка виджет показывает панель инструментов + Skip Note Viewer + Пропустить средство просмотра заметок и перейти непосредственно к редактору заметок + Вы хотите навсегда удалить эти заметки? + Более быстрые обновления и запросы. + Блокировка приложений и одиночная разблокировка. + Больше тем приложения. + Обратите внимание, шрифты и размеры шрифтов. + Цвет фона просмотра. + Дополнительные параметры виджета. + Больше действий Примечание. + Примечание цвет + Примечание теги + Включить блокировку приложения + Используйте PIN-код, чтобы разблокировать все приложение + Всегда спрашивай ПИН + Введите PIN-код для всех заметок, даже если они были введены ранее + Разблокировать с помощью биометрии + Разрешить разблокировку с помощью отпечатка пальца или другой биометрии + Биометрия отключена + Не позволяйте разблокировать с помощью отпечатка пальца или других биометрических данных + Разблокировать примечание + Используйте отпечаток пальца устройства или биометрические данные, чтобы разблокировать заметку и получить доступ. + Разблокировать приложение + Используйте отпечаток пальца устройства или биометрические данные, чтобы разблокировать приложение и получить доступ ко всем заметкам. + Ярлык запуска + Обмениваться фотографиями + diff --git a/base/src/main/res/values-tr/strings.xml b/base/src/main/res/values-tr/strings.xml index f77bd832..d8e3bd04 100644 --- a/base/src/main/res/values-tr/strings.xml +++ b/base/src/main/res/values-tr/strings.xml @@ -6,17 +6,13 @@ Kullanarak paylaş … Not Yok Hiçbir not eklememişsiniz gibi görünüyor. Not eklemek için tıklayın. - Bir not ekle… - Hızlı not ekle … Notu Düzenle Açılır Pencerede Aç - Not Sil Notu Kopyala Not gönder Eylem seçin… İçerik Ekle … Başlık Ekle … - Alt Başlık Ekle … Alıntı Metni Ekle … Öğe eklemek… Kod Ekle … @@ -27,14 +23,9 @@ Güvenlik seçenekleri Şifreyi Gir Notları kilitlemek için 4 basamaklı bir PIN belirleyin - Parmak izi ile kilidini aç - Notlar parmak iziyle açılacaktır - Parmak izi devre dışı - Notlar bir parmak izi kullanmaz Yeni PIN girin Kilidi açmak için PIN girin Geçerli PIN\'i gir - Kodu girin DOĞRULAYIN Kilidini aç Set @@ -63,23 +54,15 @@ Dosyaya dışa aktarma | tamam Pay - Hakkımızda ve Daha Fazlası Play Store\'da Ücretlendirme Katkıda bulunmak Uygulama sürümü App Hakkında - Gün Modu Notları Ara … Rengi değiştir - Notu gündüz modunda görüntülemek için dokunun Notun arka plan rengini değiştirmek için dokunun - Gece Modunu Etkinleştir - Koyu temayı varsayılan olarak etkinleştir - Gün Modunu Etkinleştir - Hafif temayı varsayılan olarak etkinleştir - Gece modu kalıcı olarak sil Unarchive Not Arşiv Notu @@ -87,7 +70,6 @@ Favoriyi işaretle Notu Geri Yükle Çöp kutusuna taşıyın - Notu gece modunda görüntülemek için dokunun Düzenlemek için notu açmak için dokunun Not içeriğini panoya kopyalamak için dokunun Not içeriğini diğer uygulamalara paylaşmak için dokunun @@ -99,26 +81,15 @@ Notu favori olarak işaretlemek için dokunun Notu arşivlemek için hafifçe dokunun Notu arşivden kaldırmak için hafifçe dokunun - Notlarınız | Ev - Normal ve favori notlarınızın tümü Favoriler - En sevdiğiniz notların tümü Arşivlenen - Arşivlenen notlarınızın tamamı Çöp - Çöplerdeki notların tümü Markdown Destek Markdown destekli formatlamaya izin ver - Örnekler - İşaretleme Ayarları - Notlarda markdown\'u nasıl kullanacağınızı öğrenin Bildirim Oluştur Not Bildirimleri Kilitli - Kilitli notların tümü - Etiketler - Tüm not etiketleriniz Yeni Etiket Ekle | Etiketi Düzenle | etiketi gir @@ -129,8 +100,6 @@ İthalat Not Listesindeki İşaretleme Not listesinde Markdown biçimlendirmeyi etkinleştirin - Dolgu Anketi - Neye benzediğinizi söyleyerek uygulamayı geliştirmemize yardımcı olun Etiketleri Değiştir @@ -139,8 +108,6 @@ Açık kaynak projesi hakkında daha fazla şey öğrenin Kütüphaneler Açık Kaynak Projesi - Açık Kaynak Projesi Hakkında - Not Hatırlatma Hatırlatma Tarihi Hatırlatıcı Saati Sıklığı Tekrarla @@ -155,8 +122,6 @@ Arayüz ve Deneyim Uygulamanın nasıl göründüğünü ve neler hissettiğini seçin. - Not Tercihleri - Not ve diğer ayarları seçin. hakkında Bizimle uygulama hakkında daha fazla bilgi edinin. Varsayılan Not Renk @@ -190,19 +155,6 @@ Not ekle Kontrol Listesi Ekle - Blok Formatlama - başlık - Alt Başlık - Metin - Alıntı - kod - Kontrol Listesi - İşaretleme Biçimlendirme - cesur - italik yazı - Altını çizmek - Vuruş - Liste Not Seç Notlar\'ı seçin Ayarlar @@ -216,9 +168,6 @@ Ne var ne yok Uygulamanın son güncellemelerindeki yenilikleri bilin Çevirmek - Yeni bir not eklemek için tıklayın - Ev seçeneklerini görmek için tıklayın - Ana menü, favori ve arşiv notların yanı sıra uygulama ayarlarına sahiptir. Etiketlerinizi de burada bulabilirsiniz. @@ -236,25 +185,19 @@ Anlıyorum Otomatik Olarak Dışa Aktar Notları sık sık dış dosyaya yedekleme olarak dışa aktarın - görüntü Resmi eklemek veya değiştirmek için tıklayın Sadece bir kere Günlük - görenek - Beta Hatırlatıcılar ve Alarmlar %s açık kaynaklıdır ve herkes daha iyi hale getirmeye katkıda bulunmaya açıktır. Şu anda %s tarafından oluşturulmakta ve sürdürülmektedir. %s, uygulamayı çeken basit bir nottur. Kullanımı çok zor hale getirmeden hızlı Zengin Metin girişi sağlar. Çok görevli bir esinti yapar. Merhaba, biz %s \'ı yaratan bir çift tasarımcı ve programcıyız. Herkese harika bir hizmet sunan güzel, dikkatlice tasarlanmış ücretsiz, reklamsız veya minimum reklam uygulamaları oluşturmaya çalışıyoruz! %d ana ekranda çizgiler - %s ara … Distraksiyon Ücretsiz - Ayırıcı - @@ -262,27 +205,18 @@ Bulut yedekleme ve senkronizasyon için oturum açın Oturumu Kapat Bulut yedeklemeyi durdurmak için çıkış yapın - Google ile giriş yap - Oturum açma | - Oturum açtınız Google Giriş Başarısız Oldu Gizlilik Politikası İçerik için uygulama gizlilik politikası Pro Uygulamasını Yükle Neden Pro Install Bulut senkronizasyonunu çalıştırmak için büyük sunucu maliyetleri için geliştiriciyi destekleyin \n\n En yeni özellikleri edinin \n\n Bazı ekstra özellikler yalnızca Pro kullanıcıları tarafından kullanılabilir olacak - Cloud Sync\'i neden etkinleştirebilirim? - Cihaz değişikliklerine karşı yükle ve yedekle \n\n Birden fazla cihaz arasında senkronize edin ve hızlı güncellemeler yapın \n\n Güvenli bir şekilde Google Firebase sunucularına kaydedin - Merhaba, - Malzeme Notları artık Scarlet! - Başlamak Uygulama Teması Temanın arka plan rengini seçin Uygulama Temasını Seç Etiket eklemek veya değiştirmek için tıklayın - Diğer İşlemleri Göster Notlar Seç Tek seferde birden fazla notta eylemleri seçip gerçekleştirin Not çöp kutusuna taşındı @@ -318,4 +252,155 @@ Uygulamadaki notları, etiketleri ve klasörleri silin Not Görüntüleyici Arka Planı + + Notları Birleştirme + Markdown Olarak Dışa Aktar + Notları işaretleme biçiminde dışa aktarın. (Bunları uygulamaya geri alamazsınız) + Arka plan için tema rengini kullan + Arka plan için not rengini kullan + etkinleştirme + Devre dışı + Klasör Eşitlemesini Etkinleştir + Folder Sync + Tüm notlarınızı, etiketlerinizi ve klasörlerinizi harici bir klasöre senkronize edin. Bu, diğer uygulamaları kullanarak cihazları senkronize etmenize yardımcı olur, ayrıca uygulamayı silmeniz gerekebilecek bir kopyası da vardır. + Klasöre Verme + Tüm notları, etiketleri vb. Harici bir klasöre senkronize edin. + Kilitli notları dışa aktar + Alfabetik + Scarlet Pro\'da mevcut + Ayrıca kilitlenmiş notları yedekle + Editör Seçenekleri + Not düzenleyicinin ayarlarını ve kullanımını değiştirin + Varsayılan Olarak İşaretleme Seçenekleri + Araç çubuğundaki markdown hızlı düğmelerini varsayılan olarak göster + Gerçek Zamanlı İşaretleme + İşaretlemenin türünüz olarak görünmesini isteyip istemediğinizi seçin. Etkinleştirme, büyük notalarda performansı etkileyebilir. + İşaretli Öğeleri Taşı + Kontrol edilen öğeler listenin en altına taşınır. Seçimi kaldır konumu sıfırlamaz. + Hareket Kollarını Göster + Öğeleri yukarı veya aşağı taşımak için tutamacı gösterin. Köşeye dokunarak şeyleri hareket ettirebilirsiniz. + Markdown Örnekleri + Widget Ayarları + Ana ekran widget\'larının ayarlarını değiştirin + Biçimlendirmeyi Etkinleştir + Notlar, ana ekran widget\'larında biçimlendirme ile işlenir + Kilitli Notları Göster + Kilitli notların ana ekran widget\'larında gösterilmesine izin ver + Arşivlenmiş Notları Göster + Arşivlenmiş notların ana ekran widget\'larında gösterilmesine izin ver + Notları Çöp Kutusunda Göster + Çöp kutusundaki notların ana ekran widget\'larında gösterilmesine izin ver + Yardım ve Sıkça Sorulan Sorular + Uygulamadaki özellikleri nasıl kullanacağınız konusunda yardım bulun + Senkronizasyon + Bekleyen Yedekleme + Geliştirici Seçenekleri + Dahili ayarları hata ayıklama için kullanılan uygulamaya değiştirin + Günlük İstisnaları + Geliştirici\'ye iletime izin vermek için, özel durumları sabit bir nota yakalanan özel durumlar + İstisna Sayfasını Göster + Geliştirici\'ye iletime izin vermek için mümkünse bir sayfada yakalanan istisnaları gösterin + İstisnaları At + İstisnalar üzerine uygulamayı at ve çök. 5 çökmeden sonra sıfırlanacak + Tam Ekranı Etkinleştir + Ekran görüntülerine ve kayıtlara izin vermek için uygulamayı tam ekran yapın + Not UUID\'lerini Göster + Notların benzersiz kimliklerini giriş ekranı görünümünde gösterme + Sahte İstisnalar + İstisna özelliklerini test etmek için sahte bir istisna atın + İstisna Fırlatıldı + Crash Uygulaması + Posta + Bağlantı Başarısız + Google Drive\'da senkronize et + Google Drive, notlarınızı kendi Google Drive hesabınızı kullanarak cihazlar arasında senkronize etmenize olanak sağlar. + Daha önce Google Firebase’e giriş yaptınız mı? + Google Drive\'da Oturum Açın + Oturum Açma… + Scarlet Çıkış + Notları, etiketleri ve klasörleri senkronize etmeyi durdurun. + Notlarınızı, etiketlerinizi ve klasörlerinizi Google Drive\'ınızla senkronize etmeyi bırakın. + Uygulamadaki ve Google Drive\'daki verileriniz hala orada olacak. + Drive\'dan Çıkış Yapın + Çıkış Yapılıyor + Notlar, Etiketler ve Klasörler kendi Google Drive\'ınızda saklanır, böylece bunlara yalnızca siz erişebilirsiniz. + Fotoğraflarınız cihazlar arasında da yüklenir ve senkronize edilir. + Firebase\'den Veri Geri Yükleme + Google ile giriş yap + Oturum Açma… + Bilgilerinizi Google Firebase’de depolardık. Giriş yaptıktan sonra bunları cihazınıza geri yükleyeceğiz. + Yeni notlar ve değişiklikler Google Firebase ile senkronize edilmeyecek ve Google Drive\'da oturum açmanız gerekecek + Notlarınız kurtarıldıktan sonra, Google Firebase\'den silebilir ve ardından geçiş yapabilirsiniz. + Verileriniz senkronize edilmiyor! + Eski oturuma dayalı Veri Senkronizasyonu devre dışı bırakıldı, Google Drive tabanlı senkronizasyona geçmeyi düşünün. + Firebase\'den Drive\'a Veri Aktarma + Verileri Temizle ve Çıkış Yap + Temizleme ve Çıkış Yapma + Bilgilerinizi Google Firebase’de depolardık. Notlarınızı Google Drive\'ınıza kaydetmeye geçiyoruz. + Daha fazla gizlilik. + Fotoğraf Senk. + Sonraki adımlar + İlk önce notlarınızı Firebase\'den silip oturumunuzu kapatırız. + Daha sonra Google Drive’a giriş yapabilirsiniz; verilerinizi resimlerle birlikte yükleriz. + + + Seçenekleri Kaldır + Not defterini kaldır + Sadece Not Defterini Çıkarın. Notlar dış klasöre taşınır. + Not Defterini ve Notları Kaldır + Not defterini çıkarın. Tüm notlar çöp kutusuna taşınır veya silinir. + Notları Kaldır + Not Defteri\'ni saklayın, ancak tüm notlar çöp kutusuna taşınır veya silinir. + Yazı Tiplerini Özelleştir + Uygulamayı seçin ve yazı tiplerini not edin + Bir Yazı Tipi Kümesi Seç + Not: Yazı tipleri tüm dillerle düzgün çalışmayabilir + Uygulama Varsayılanı + Aygıt Varsayılanı + Mono + Serif + Uygulamanın kilidini aç + Kilidi açmak için 4 basamaklı PIN kodunu girin veya biyometrik kullanın + Kilidi açmak için 4 basamaklı PIN kodunu girin + Sistem Temasını Kullan + Sistemdeki açık veya koyu temayı kullanın + Karanlık Notlar + Not ve klasör renklerini otomatik olarak karart + Yerel + uzak + Kullanım dışı + düzenlendi + silindi + Güncellenmiş + Widget Arka Planı + Çoklu notlar widget\'ı için arka plan rengini seçin + Eylem Araç Çubuğunu Göster + Çoklu not widget\'ı araç çubuğunu gösterir + Not Görüntüleyiciyi Atla + Not görüntüleyiciyi atla ve doğrudan not düzenleyicisine atla + Bu notları kalıcı olarak silmek ister misiniz? + Daha Hızlı Güncellemeler ve İstekler. + Uygulama Kilidi ve Tek Kilidi Açma. + Diğer Uygulama Temaları. + Yazı Tipleri ve Yazı Tipi Boyutları. + Görüntüleyici Arkaplan Rengi. + Daha fazla Widget Seçenekleri. + Diğer Not İşlemleri. + Not Rengi + Not Etiketleri + Uygulama Kilidi\'ni etkinleştir + Tüm uygulamanın kilidini açmak için PIN kullanın + Her zaman PIN sor + Daha önce girmiş olsanız bile, tüm notlar için PIN kodunu girin. + Biyometri ile aç + Parmak izi veya başka bir biyometri ile kilidi açmaya izin ver + Biyometri devre dışı + Parmak izi veya başka bir biyometri ile kilidi açmaya izin verme + Notun kilidini aç + Notun kilidini açmak ve erişmek için cihaz parmak izi veya biyometri kullanın. + Uygulamanın kilidini aç + Uygulamanın kilidini açmak ve tüm notlara erişmek için cihaz parmak izini veya biyometriyi kullanın. + Başlatıcı Kısayolu + Fotoğrafları paylaş + \ No newline at end of file diff --git a/base/src/main/res/values-v23/styles.xml b/base/src/main/res/values-v23/styles.xml index f7558e72..d9435a01 100644 --- a/base/src/main/res/values-v23/styles.xml +++ b/base/src/main/res/values-v23/styles.xml @@ -9,7 +9,6 @@ @style/RobotoTextViewStyle @style/RobotoButtonStyle @style/RobotoEditTextStyle - monospace @color/white true diff --git a/base/src/main/res/values-zh-rCN/strings.xml b/base/src/main/res/values-zh-rCN/strings.xml index a81af2af..438ca677 100644 --- a/base/src/main/res/values-zh-rCN/strings.xml +++ b/base/src/main/res/values-zh-rCN/strings.xml @@ -9,18 +9,12 @@ 没有笔记 您尚未添加笔记。点击以添加一条笔记。 - 添加笔记… - 添加快速笔记… - 添加笔记 添加清单项 - 夜间模式 - 日间模式 编辑笔记 创建通知 在弹出窗口中打开 - 删除笔记 永久删除 复制笔记 发送笔记 @@ -41,8 +35,6 @@ 取消固定笔记 选择操作… - 轻触以在夜间模式下查看该笔记 - 轻触以在日间模式下查看该笔记 轻触以打开并编辑该笔记 轻触以将该笔记的内容复制到剪贴板 轻触以将该笔记的内容分享到其他应用 @@ -56,57 +48,25 @@ 轻触以更改该笔记的背景色 轻触以取消归档 - 您的笔记和其他 主页 - 您所有的普通笔记和已收藏的笔记 收藏夹 - 您所有已收藏的笔记 归档 - 您所有已归档的笔记 已锁定 - 您所有已锁定的笔记 - 标签 - 您所有的笔记标签 回收站 - 您所有在回收站中的笔记 添加内容… 添加标题… - 添加副标题… 添加引用文本… 添加列表项… 添加代码… - 块排版 - 标题 - 副标题 - 文本 - 引用 - 代码 - 清单 - - Markdown 排版 - 加粗 - 倾斜 - 下划线 - 删除线 - 列表 - 选项和设置 界面和体验 选择本应用的观感 - 笔记首选项 - 选择笔记和其他的设置 关于 了解更多关于我们和本应用的信息 安全 锁定笔记和安全方面的选项 - 启用夜间模式 - 将暗色主题设为默认主题 - 启用日间模式 - 将亮色主题设为默认主题 - Markdown 设置 - 看看如何在笔记中使用 markdown 列表视图 将笔记显示为一列 网格视图 @@ -124,21 +84,14 @@ 了解更多关于开源项目的信息 Rate and Review 告诉我们您有多喜欢本应用 - 参与调查 - 说说您喜欢什么,以帮助我们改善本应用 安全选项 密码 设置一个 4 位的 PIN 码来锁定笔记 - 指纹解锁 - 笔记可通过指纹解锁 - 指纹解锁已禁用 - 笔记不能通过指纹解锁 输入新的 PIN 码 输入 PIN 码解锁 输入当前的 PIN 码 - 输入密码 验证 解锁 设置 @@ -152,7 +105,6 @@ 允许 markdown 支持的排版 笔记列表中的 Markdown 在笔记列表中使用 Markdown 排版 - 示例 授权 导入和导出功能需要存储权限。请在收到请求后授权。 @@ -173,7 +125,6 @@ 导出已锁定的笔记 同样备份已锁定的笔记 - 关于我们和其他 在 Play 商店上评分 贡献 应用版本 @@ -181,9 +132,7 @@ 开源项目 - 关于开源项目 - 笔记提醒 提醒日期 提醒时间 重复频率 @@ -214,9 +163,6 @@ 了解本应用最近更新的内容 翻译 - 点击新建一条笔记 - 点击查看主页选项 - 主页菜单中有您已收藏和归档的笔记,以及应用设置。您还可以在此找到您的标签。 @@ -263,51 +209,37 @@ 我明白 自动导出 频繁导出笔记到外部文件作为备份 - 图片 点击添加或更改图像 只有一次 日常 - 习惯 - Beta版 提醒和警报 %s是开源的,任何人都可以为改善它做出贡献。 它目前由%s构建和维护。 %s是一个简单的笔记应用程序。 它允许快速富文本输入,而不会让使用体验变得非常困难。 它使得多任务轻而易举。 嗨,我们是一对设计师和程序员,他们创造了%s。 我们致力于打造漂亮,精心设计的免费,无广告或最低限度的广告应用程序,这些应用程序对每个人都非常实用! 主屏幕上的%d行 - 搜索%s … 分心免费 - 分隔器 登录到应用程序 登录云备份和同步 登出 注销以停止云备份 - 用Google登录 - 登录… - 您已经登录 Google登录失败 隐私政策 应用程序隐私政策的内容 安装Pro App 为什么安装Pro 支持大规模服务器成本的开发人员,运行云同步 \n\n 首先获取最新功能 \n\n 一些额外功能仅适用于专业用户 - 为什么启用云端同步 - 根据设备更改进行上传和备份 \n\n 在多个设备之间进行同步,并获得快速更新 \n\n 安全地保存在Google Firebase服务器上 - 你好, - 材料的笔记现在是猩红色! - 开始使用 应用主题 选择主题的背景颜色 选择应用主题 单击以添加或更改标签 - 显示更多操作 选择备注 一次选择并对多个音符执行操作 这张纸条被移到了垃圾桶里 @@ -376,5 +308,130 @@ 显示回收站中的笔记 允许回收站中的笔记出现在主屏幕小部件中 - + + + 合并备注 + 出口为降价 + 以降价格式导出备注。 (你不能将这些导回到应用程序) + 使用主题颜色为背景 + 使用备注颜色作为背景 + 启用 + 禁用 + 按英文字母顺序 + 可在Scarlet Pro上使用 + 移动选中的项目 + 选中的项目移动到列表的底部。取消选中不会重置位置。 + 帮助和常见问题 + 查找有关如何使用应用程序中的功能的帮助 + 同步 + 待备份 + 开发者选项 + 将内部设置更改为用于调试的应用程序 + 记录例外 + 记录固定注释的异常,以允许转发给Developer + 显示例外表 + 如果可能,在工作表上显示捕获的异常,以允许转发到Developer + 抛弃异常 + 在异常上抛出并崩溃应用程序。 5次崩溃后将重置 + 启用全屏 + 全屏显示应用程序以允许截屏和录制 + 显示注释UUID + 在主屏幕视图中显示备注的唯一ID + 假例外 + 抛出一个假异常来测试异常功能 + 抛出异常 + 崩溃应用程序 + 邮件 + 连接失败 + 在Google云端硬盘上同步 + Google云端硬盘可让您使用自己的Google云端硬盘帐户在设备之间同步笔记。 + 之前登录过Google Firebase? + 登录Google云端硬盘 + 签约 + 退出血色 + 停止同步笔记,标签和文件夹。 + 停止将您的笔记,标签和文件夹同步到Google云端硬盘。 + 您在应用和Google云端硬盘上的数据仍然存在。 + 从云端硬盘退出 + 签出 - + 备注,标签和文件夹存储在您自己的Google云端硬盘中,因此只有您可以控制对它们的访问权限。 + 您的照片也会上传并在设备间同步。 + 从Firebase还原数据 + 与谷歌签约 + 签约 + 我们过去常常将您的信息存储在Google Firebase上。登录后,我们会将这些恢复到您的设备 + 新笔记和更改不会同步到Google Firebase,您需要登录Google云端硬盘 + 恢复笔记后,您可以将其从Google Firebase中删除,然后进行切换 + 您的数据未同步! + 基于旧版登录的数据同步已停用,请考虑切换到基于Google云端硬盘的同步。 + 将数据从Firebase传输到云端硬盘 + 清除数据并注销 + 清除和签出 + 我们过去常常将您的信息存储在Google Firebase上。我们正在将您的笔记存储到您的Google云端硬盘中。 + 更多隐私。 + 照片同步。 + 下一步 + 我们会先从Firebase中删除您的备注并注销。 + 然后,您可以登录Google云端硬盘,我们会将您的数据与图片一起上传。 + + + 删除选项 + 移除笔记本 + 仅删除笔记本。便笺移到文件夹之外。 + 删除笔记本和笔记 + 删除笔记本。所有笔记都会移至回收站或被删除。 + 删除笔记 + 保留笔记本,但所有笔记都移至废纸or或被删除。 + 自定义字体 + 选择应用程序并记下字体 + 选择字体集 + 注意:字体可能不适用于所有语言 + 应用默认 + 设备默认 + 单声道 + 衬线 + 解锁应用 + 输入4位数的PIN或使用生物识别技术解锁 + 输入4位数PIN码以解锁 + 使用系统主题 + 使用系统中的浅色或深色主题 + 黑暗笔记 + 自动使笔记和文件夹的颜色变暗 + 本地 + 远程 + 不可用 + 已建立 + 已删除 + 更新 + 小部件背景 + 选择多笔记小部件的背景颜色 + 显示动作工具栏 + 多笔记小部件显示工具栏 + 跳过笔记查看器 + 跳过便笺查看器,直接跳至便笺编辑器 + 您要永久删除这些注释吗? + 更快的更新和请求。 + 应用锁定和单次解锁。 + 更多应用主题。 + 注意字体和字体大小。 + 查看器背景色。 + 更多小部件选项。 + 更多注释动作。 + 音符颜色 + 注意标签 + 启用应用锁定 + 使用PIN解锁整个应用程序 + 总是要求输入PIN + 输入所有便笺的PIN码,即使之前已输入 + 用生物识别技术解锁 + 允许使用指纹或其他生物特征进行解锁 + 生物识别功能已禁用 + 禁止使用指纹或其他生物特征进行解锁 + 解锁笔记 + 使用设备的指纹或生物识别技术来解锁笔记和访问权限。 + 解锁应用 + 使用设备指纹或生物识别技术解锁应用程序并访问所有笔记。 + 启动器快捷方式 + 分享照片 + diff --git a/base/src/main/res/values-zh-rHK/strings.xml b/base/src/main/res/values-zh-rHK/strings.xml index 3a1b788b..848cbba5 100644 --- a/base/src/main/res/values-zh-rHK/strings.xml +++ b/base/src/main/res/values-zh-rHK/strings.xml @@ -6,29 +6,20 @@ 分享使用… 沒有筆記 看來你還沒有添加任何筆記。 點擊添加備註。 - 添加備註… - 添加快速筆記… 編輯註釋 在彈出窗口中打開 - 刪除註釋 複製說明 發送注意事項 選擇動作… 添加內容… 添加標題… - 添加子標題… 添加引號文本… 新增項目… 添加代碼… 選項和設置 導出註釋 - 日間模式 換顏色 - 點按即可在日間模式下查看筆記 點擊改變音符的背景顏色 - 啟用夜間模式 - 默認啟用黑色主題 - 啟用日間模式 搜索筆記… 鎖定注意 解鎖注意 @@ -37,14 +28,9 @@ 安全選項 密碼 設置一個4位數字的PIN碼來鎖定音符 - 用指紋解鎖 - 筆記將用指紋解鎖 - 指紋被禁用 - 筆記不會使用指紋 輸入新的PIN碼 輸入PIN碼即可解鎖 輸入當前的PIN碼 - 輸入代碼 校驗 開鎖 @@ -54,7 +40,6 @@ 啟用網格佈局 以交錯格子顯示筆記 - 默認啟用輕量級主題 將筆記導出到設備存儲以進行共享 導入註釋 從設備存儲導入筆記 @@ -72,12 +57,10 @@ 導出到文件… 完成 分享 - 關於我們和更多 Play商店的價格 有助於 應用程式版本 關於應用 - 夜間模式 永久刪除 解除注意 存檔注意 @@ -85,7 +68,6 @@ 標記收藏 還原註意 移到廢紙簍 - 點按即可在夜間模式下查看筆記 點擊以打開註釋進行編輯 點擊將音符內容複製到剪貼板 點按即可將筆記內容分享到其他應用 @@ -97,26 +79,15 @@ 點擊標記註意不是最喜歡的 點擊歸檔筆記 點擊以取消存檔 - 你的筆記… - 所有正常和最喜歡的筆記 最愛 - 所有你最喜歡的筆記 存檔 - 所有的歸檔筆記 垃圾 - 你在垃圾桶裡的所有筆記 減價支持 允許降價支持格式 - 例子 - 減價設置 - 看看如何在筆記中使用降價 創建通知 注意通知 鎖定 - 所有鎖定的筆記 - 標籤 - 所有的筆記標籤 添加新標籤… 編輯標籤… 輸入標籤 @@ -127,8 +98,6 @@ 進口 註釋列表中的降價 在筆記列表中啟用Markdown格式 - 填寫調查 - 通過告訴我們你喜歡什麼來幫助我們改進應用程序 更改標籤 @@ -137,8 +106,6 @@ 了解更多關於開源項目 圖書館 開源項目 - 關於開源項目 - 注意提醒 提醒日期 提醒時間 重複頻率 @@ -153,8 +120,6 @@ 界面和經驗 選擇應用程序的外觀和感覺。 - 注意首選項 - 選擇筆記和其他設置。 關於 了解更多關於我們和應用程序。 默認的注意顏色 @@ -189,19 +154,6 @@ 添加註釋 添加清單 - 塊格式化 - 標題 - 小標題 - 文本 - 引用 - - 清單 - 降價格式 - 膽大 - 斜體 - 強調 - 罷工 - 名單 選擇一個註釋 選擇註釋 設置 @@ -215,9 +167,6 @@ 什麼是新的 了解最近更新的應用程序中的新功能 翻譯 - 點擊添加一個新的筆記 - 點擊查看家庭選項 - 主菜單有您最喜歡的和存檔的筆記,以及應用程序設置。 你也可以在這裡找到你的標籤。 @@ -235,51 +184,37 @@ 我明白 自動導出 頻繁導出筆記到外部文件作為備份 - 圖片 點擊添加或更改圖像 只有一次 日常 - 習慣 - Beta版 提醒和警報 %s是開源的,任何人都可以為改善它做出貢獻。 它目前由%s構建和維護。 %s是一個簡單的筆記應用程序。 它允許快速富文本輸入,而不會讓使用體驗變得非常困難。 它使得多任務輕而易舉。 嗨,我們是一對設計師和程序員,他們創造了%s。 我們致力於打造漂亮,精心設計的免費,無廣告或最低限度的廣告應用程序,這些應用程序對每個人都非常實用! 主屏幕上的%d行 - 搜索%s … 分心免費 - 分隔器 登錄到應用程序 登錄雲備份和同步 登出 註銷以停止雲備份 - 用Google登錄 - 登錄… - 您已經登錄 Google登錄失敗 隱私政策 應用程序隱私政策的內容 安裝Pro App 為什麼安裝Pro 支持大規模服務器成本的開發人員,運行云同步 \n\n 首先獲取最新功能 \n\n 一些額外功能僅適用於專業用戶 - 為什麼啟用雲端同步 - 根據設備更改進行上傳和備份 \n\n 在多個設備之間進行同步,並獲得快速更新 \n\n 安全地保存在Google Firebase服務器上 - 你好, - 材料的筆記現在是猩紅色! - 開始使用 應用主題 選擇主題的背景顏色 選擇應用主題 單擊以添加或更改標籤 - 顯示更多操作 選擇備註 一次選擇並對多個音符執行操作 這張紙條被移到了垃圾桶裡 @@ -315,4 +250,155 @@ 刪除應用中的註釋,標籤和文件夾 注意查看器背景 + + 合併備註 + 出口為降價 + 以降價格式導出備註。 (你不能將這些導回到應用程序) + 使用主題顏色為背景 + 使用備註顏色作為背景 + 啟用 + 禁用 + 啟用文件夾同步 + 文件夾同步 + 將所有筆記,標籤和文件夾同步到外部文件夾。這有助於您在設備之間使用其他應用進行同步,並且可以在您需要刪除應用時獲得副本。 + 導出到文件夾 + 將所有筆記,標籤等同步到外部文件夾 + 導出鎖定的筆記 + 按英文字母順序 + 可在Scarlet Pro上使用 + 還備份已鎖定的備註 + 編輯器選項 + 更改註釋編輯器的設置和用法 + Markdown選項為默認值 + 默認情況下顯示工具欄上的降價快速按鈕 + 實時降價 + 選擇是否要將標記顯示為類型。啟用可以影響大筆記的性能。 + 移動選中的項目 + 選中的項目移動到列表的底部。取消選中不會重置位置。 + 顯示運動手柄 + 顯示向上或向下移動項目的句柄。你仍然可以通過觸摸角落來移動東西。 + 降價示例 + 小部件設置 + 更改主屏幕小組件的設置 + 啟用格式化 + 在主屏幕小部件中使用格式呈現註釋 + 顯示鎖定的筆記 + 允許鎖定的註釋顯示在主屏幕小部件中 + 顯示存檔的筆記 + 允許存檔的註釋顯示在主屏幕小部件中 + 在廢紙簍中顯示備註 + 允許垃圾中的註釋顯示在主屏幕小部件中 + 幫助和常見問題 + 查找有關如何使用應用程序中的功能的幫助 + 同步 + 待備份 + 開發者選項 + 將內部設置更改為用於調試的應用程序 + 記錄例外 + 記錄固定註釋的異常,以允許轉發給Developer + 顯示例外表 + 如果可能,在工作表上顯示捕獲的異常,以允許轉發到Developer + 拋棄異常 + 在異常上拋出並崩潰應用程序。 5次崩潰後將重置 + 啟用全屏 + 全屏顯示應用程序以允許截屏和錄製 + 顯示註釋UUID + 在主屏幕視圖中顯示備註的唯一ID + 假例外 + 拋出一個假異常來測試異常功能 + 拋出異常 + 崩潰應用程序 + 郵件 + 連接失敗 + 在Google雲端硬盤上同步 + Google雲端硬盤可讓您使用自己的Google雲端硬盤帳戶在設備之間同步筆記。 + 之前登錄過Google Firebase? + 登錄Google雲端硬盤 + 簽約 + 退出血色 + 停止同步筆記,標籤和文件夾。 + 停止將您的筆記,標籤和文件夾同步到Google雲端硬盤。 + 您在應用和Google雲端硬盤上的數據仍然存在。 + 從雲端硬盤退出 + 簽出 - + 備註,標籤和文件夾存儲在您自己的Google雲端硬盤中,因此只有您可以控制對它們的訪問權限。 + 您的照片也會上傳並在設備間同步。 + 從Firebase還原數據 + 與穀歌簽約 + 簽約 + 我們過去常常將您的信息存儲在Google Firebase上。登錄後,我們會將這些恢復到您的設備 + 新筆記和更改不會同步到Google Firebase,您需要登錄Google雲端硬盤 + 恢復筆記後,您可以將其從Google Firebase中刪除,然後進行切換 + 您的數據未同步! + 基於舊版登錄的數據同步已停用,請考慮切換到基於Google雲端硬盤的同步。 + 將數據從Firebase傳輸到雲端硬盤 + 清除數據並註銷 + 清除和簽出 + 我們過去常常將您的信息存儲在Google Firebase上。我們正在將您的筆記存儲到您的Google雲端硬盤中。 + 更多隱私。 + 照片同步。 + 下一步 + 我們會先從Firebase中刪除您的備註並註銷。 + 然後,您可以登錄Google雲端硬盤,我們會將您的數據與圖片一起上傳。 + + + 刪除選項 + 移除筆記本 + 僅刪除筆記本。便箋移到文件夾之外。 + 刪除筆記本和筆記 + 刪除筆記本。所有筆記都會移至回收站或被刪除。 + 刪除筆記 + 保留筆記本,但所有筆記都移至廢紙or或被刪除。 + 自定義字體 + 選擇應用程序並記下字體 + 選擇字體集 + 注意:字體可能不適用於所有語言 + 應用默認 + 設備默認 + 單聲道 + 襯線 + 解鎖應用 + 輸入4位數的PIN或使用生物識別技術解鎖 + 輸入4位數PIN碼以解鎖 + 使用系統主題 + 使用系統中的淺色或深色主題 + 黑暗筆記 + 自動使筆記和文件夾的顏色變暗 + 本地 + 遠程 + 不可用 + 已建立 + 已刪除 + 更新 + 小部件背景 + 選擇多筆記小部件的背景顏色 + 顯示動作工具欄 + 多筆記小部件顯示工具欄 + 跳過筆記查看器 + 跳過便箋查看器,直接跳至便箋編輯器 + 您要永久刪除這些註釋嗎? + 更快的更新和請求。 + 應用鎖定和單次解鎖。 + 更多應用主題。 + 注意字體和字體大小。 + 查看器背景色。 + 更多小部件選項。 + 更多註釋動作。 + 音符顏色 + 注意標籤 + 啟用應用鎖定 + 使用PIN解鎖整個應用程序 + 總是要求輸入PIN + 輸入所有便箋的PIN碼,即使之前已輸入 + 用生物識別技術解鎖 + 允許使用指紋或其他生物特徵進行解鎖 + 生物識別功能已禁用 + 禁止使用指紋或其他生物特徵進行解鎖 + 解鎖筆記 + 使用設備的指紋或生物識別技術來解鎖筆記和訪問權限。 + 解鎖應用 + 使用設備指紋或生物識別技術解鎖應用程序並訪問所有筆記。 + 啟動器快捷方式 + 分享照片 + \ No newline at end of file diff --git a/base/src/main/res/values-zh-rMO/strings.xml b/base/src/main/res/values-zh-rMO/strings.xml index 3a1b788b..848cbba5 100644 --- a/base/src/main/res/values-zh-rMO/strings.xml +++ b/base/src/main/res/values-zh-rMO/strings.xml @@ -6,29 +6,20 @@ 分享使用… 沒有筆記 看來你還沒有添加任何筆記。 點擊添加備註。 - 添加備註… - 添加快速筆記… 編輯註釋 在彈出窗口中打開 - 刪除註釋 複製說明 發送注意事項 選擇動作… 添加內容… 添加標題… - 添加子標題… 添加引號文本… 新增項目… 添加代碼… 選項和設置 導出註釋 - 日間模式 換顏色 - 點按即可在日間模式下查看筆記 點擊改變音符的背景顏色 - 啟用夜間模式 - 默認啟用黑色主題 - 啟用日間模式 搜索筆記… 鎖定注意 解鎖注意 @@ -37,14 +28,9 @@ 安全選項 密碼 設置一個4位數字的PIN碼來鎖定音符 - 用指紋解鎖 - 筆記將用指紋解鎖 - 指紋被禁用 - 筆記不會使用指紋 輸入新的PIN碼 輸入PIN碼即可解鎖 輸入當前的PIN碼 - 輸入代碼 校驗 開鎖 @@ -54,7 +40,6 @@ 啟用網格佈局 以交錯格子顯示筆記 - 默認啟用輕量級主題 將筆記導出到設備存儲以進行共享 導入註釋 從設備存儲導入筆記 @@ -72,12 +57,10 @@ 導出到文件… 完成 分享 - 關於我們和更多 Play商店的價格 有助於 應用程式版本 關於應用 - 夜間模式 永久刪除 解除注意 存檔注意 @@ -85,7 +68,6 @@ 標記收藏 還原註意 移到廢紙簍 - 點按即可在夜間模式下查看筆記 點擊以打開註釋進行編輯 點擊將音符內容複製到剪貼板 點按即可將筆記內容分享到其他應用 @@ -97,26 +79,15 @@ 點擊標記註意不是最喜歡的 點擊歸檔筆記 點擊以取消存檔 - 你的筆記… - 所有正常和最喜歡的筆記 最愛 - 所有你最喜歡的筆記 存檔 - 所有的歸檔筆記 垃圾 - 你在垃圾桶裡的所有筆記 減價支持 允許降價支持格式 - 例子 - 減價設置 - 看看如何在筆記中使用降價 創建通知 注意通知 鎖定 - 所有鎖定的筆記 - 標籤 - 所有的筆記標籤 添加新標籤… 編輯標籤… 輸入標籤 @@ -127,8 +98,6 @@ 進口 註釋列表中的降價 在筆記列表中啟用Markdown格式 - 填寫調查 - 通過告訴我們你喜歡什麼來幫助我們改進應用程序 更改標籤 @@ -137,8 +106,6 @@ 了解更多關於開源項目 圖書館 開源項目 - 關於開源項目 - 注意提醒 提醒日期 提醒時間 重複頻率 @@ -153,8 +120,6 @@ 界面和經驗 選擇應用程序的外觀和感覺。 - 注意首選項 - 選擇筆記和其他設置。 關於 了解更多關於我們和應用程序。 默認的注意顏色 @@ -189,19 +154,6 @@ 添加註釋 添加清單 - 塊格式化 - 標題 - 小標題 - 文本 - 引用 - - 清單 - 降價格式 - 膽大 - 斜體 - 強調 - 罷工 - 名單 選擇一個註釋 選擇註釋 設置 @@ -215,9 +167,6 @@ 什麼是新的 了解最近更新的應用程序中的新功能 翻譯 - 點擊添加一個新的筆記 - 點擊查看家庭選項 - 主菜單有您最喜歡的和存檔的筆記,以及應用程序設置。 你也可以在這裡找到你的標籤。 @@ -235,51 +184,37 @@ 我明白 自動導出 頻繁導出筆記到外部文件作為備份 - 圖片 點擊添加或更改圖像 只有一次 日常 - 習慣 - Beta版 提醒和警報 %s是開源的,任何人都可以為改善它做出貢獻。 它目前由%s構建和維護。 %s是一個簡單的筆記應用程序。 它允許快速富文本輸入,而不會讓使用體驗變得非常困難。 它使得多任務輕而易舉。 嗨,我們是一對設計師和程序員,他們創造了%s。 我們致力於打造漂亮,精心設計的免費,無廣告或最低限度的廣告應用程序,這些應用程序對每個人都非常實用! 主屏幕上的%d行 - 搜索%s … 分心免費 - 分隔器 登錄到應用程序 登錄雲備份和同步 登出 註銷以停止雲備份 - 用Google登錄 - 登錄… - 您已經登錄 Google登錄失敗 隱私政策 應用程序隱私政策的內容 安裝Pro App 為什麼安裝Pro 支持大規模服務器成本的開發人員,運行云同步 \n\n 首先獲取最新功能 \n\n 一些額外功能僅適用於專業用戶 - 為什麼啟用雲端同步 - 根據設備更改進行上傳和備份 \n\n 在多個設備之間進行同步,並獲得快速更新 \n\n 安全地保存在Google Firebase服務器上 - 你好, - 材料的筆記現在是猩紅色! - 開始使用 應用主題 選擇主題的背景顏色 選擇應用主題 單擊以添加或更改標籤 - 顯示更多操作 選擇備註 一次選擇並對多個音符執行操作 這張紙條被移到了垃圾桶裡 @@ -315,4 +250,155 @@ 刪除應用中的註釋,標籤和文件夾 注意查看器背景 + + 合併備註 + 出口為降價 + 以降價格式導出備註。 (你不能將這些導回到應用程序) + 使用主題顏色為背景 + 使用備註顏色作為背景 + 啟用 + 禁用 + 啟用文件夾同步 + 文件夾同步 + 將所有筆記,標籤和文件夾同步到外部文件夾。這有助於您在設備之間使用其他應用進行同步,並且可以在您需要刪除應用時獲得副本。 + 導出到文件夾 + 將所有筆記,標籤等同步到外部文件夾 + 導出鎖定的筆記 + 按英文字母順序 + 可在Scarlet Pro上使用 + 還備份已鎖定的備註 + 編輯器選項 + 更改註釋編輯器的設置和用法 + Markdown選項為默認值 + 默認情況下顯示工具欄上的降價快速按鈕 + 實時降價 + 選擇是否要將標記顯示為類型。啟用可以影響大筆記的性能。 + 移動選中的項目 + 選中的項目移動到列表的底部。取消選中不會重置位置。 + 顯示運動手柄 + 顯示向上或向下移動項目的句柄。你仍然可以通過觸摸角落來移動東西。 + 降價示例 + 小部件設置 + 更改主屏幕小組件的設置 + 啟用格式化 + 在主屏幕小部件中使用格式呈現註釋 + 顯示鎖定的筆記 + 允許鎖定的註釋顯示在主屏幕小部件中 + 顯示存檔的筆記 + 允許存檔的註釋顯示在主屏幕小部件中 + 在廢紙簍中顯示備註 + 允許垃圾中的註釋顯示在主屏幕小部件中 + 幫助和常見問題 + 查找有關如何使用應用程序中的功能的幫助 + 同步 + 待備份 + 開發者選項 + 將內部設置更改為用於調試的應用程序 + 記錄例外 + 記錄固定註釋的異常,以允許轉發給Developer + 顯示例外表 + 如果可能,在工作表上顯示捕獲的異常,以允許轉發到Developer + 拋棄異常 + 在異常上拋出並崩潰應用程序。 5次崩潰後將重置 + 啟用全屏 + 全屏顯示應用程序以允許截屏和錄製 + 顯示註釋UUID + 在主屏幕視圖中顯示備註的唯一ID + 假例外 + 拋出一個假異常來測試異常功能 + 拋出異常 + 崩潰應用程序 + 郵件 + 連接失敗 + 在Google雲端硬盤上同步 + Google雲端硬盤可讓您使用自己的Google雲端硬盤帳戶在設備之間同步筆記。 + 之前登錄過Google Firebase? + 登錄Google雲端硬盤 + 簽約 + 退出血色 + 停止同步筆記,標籤和文件夾。 + 停止將您的筆記,標籤和文件夾同步到Google雲端硬盤。 + 您在應用和Google雲端硬盤上的數據仍然存在。 + 從雲端硬盤退出 + 簽出 - + 備註,標籤和文件夾存儲在您自己的Google雲端硬盤中,因此只有您可以控制對它們的訪問權限。 + 您的照片也會上傳並在設備間同步。 + 從Firebase還原數據 + 與穀歌簽約 + 簽約 + 我們過去常常將您的信息存儲在Google Firebase上。登錄後,我們會將這些恢復到您的設備 + 新筆記和更改不會同步到Google Firebase,您需要登錄Google雲端硬盤 + 恢復筆記後,您可以將其從Google Firebase中刪除,然後進行切換 + 您的數據未同步! + 基於舊版登錄的數據同步已停用,請考慮切換到基於Google雲端硬盤的同步。 + 將數據從Firebase傳輸到雲端硬盤 + 清除數據並註銷 + 清除和簽出 + 我們過去常常將您的信息存儲在Google Firebase上。我們正在將您的筆記存儲到您的Google雲端硬盤中。 + 更多隱私。 + 照片同步。 + 下一步 + 我們會先從Firebase中刪除您的備註並註銷。 + 然後,您可以登錄Google雲端硬盤,我們會將您的數據與圖片一起上傳。 + + + 刪除選項 + 移除筆記本 + 僅刪除筆記本。便箋移到文件夾之外。 + 刪除筆記本和筆記 + 刪除筆記本。所有筆記都會移至回收站或被刪除。 + 刪除筆記 + 保留筆記本,但所有筆記都移至廢紙or或被刪除。 + 自定義字體 + 選擇應用程序並記下字體 + 選擇字體集 + 注意:字體可能不適用於所有語言 + 應用默認 + 設備默認 + 單聲道 + 襯線 + 解鎖應用 + 輸入4位數的PIN或使用生物識別技術解鎖 + 輸入4位數PIN碼以解鎖 + 使用系統主題 + 使用系統中的淺色或深色主題 + 黑暗筆記 + 自動使筆記和文件夾的顏色變暗 + 本地 + 遠程 + 不可用 + 已建立 + 已刪除 + 更新 + 小部件背景 + 選擇多筆記小部件的背景顏色 + 顯示動作工具欄 + 多筆記小部件顯示工具欄 + 跳過筆記查看器 + 跳過便箋查看器,直接跳至便箋編輯器 + 您要永久刪除這些註釋嗎? + 更快的更新和請求。 + 應用鎖定和單次解鎖。 + 更多應用主題。 + 注意字體和字體大小。 + 查看器背景色。 + 更多小部件選項。 + 更多註釋動作。 + 音符顏色 + 注意標籤 + 啟用應用鎖定 + 使用PIN解鎖整個應用程序 + 總是要求輸入PIN + 輸入所有便箋的PIN碼,即使之前已輸入 + 用生物識別技術解鎖 + 允許使用指紋或其他生物特徵進行解鎖 + 生物識別功能已禁用 + 禁止使用指紋或其他生物特徵進行解鎖 + 解鎖筆記 + 使用設備的指紋或生物識別技術來解鎖筆記和訪問權限。 + 解鎖應用 + 使用設備指紋或生物識別技術解鎖應用程序並訪問所有筆記。 + 啟動器快捷方式 + 分享照片 + \ No newline at end of file diff --git a/base/src/main/res/values-zh-rTW/strings.xml b/base/src/main/res/values-zh-rTW/strings.xml index 3a1b788b..848cbba5 100644 --- a/base/src/main/res/values-zh-rTW/strings.xml +++ b/base/src/main/res/values-zh-rTW/strings.xml @@ -6,29 +6,20 @@ 分享使用… 沒有筆記 看來你還沒有添加任何筆記。 點擊添加備註。 - 添加備註… - 添加快速筆記… 編輯註釋 在彈出窗口中打開 - 刪除註釋 複製說明 發送注意事項 選擇動作… 添加內容… 添加標題… - 添加子標題… 添加引號文本… 新增項目… 添加代碼… 選項和設置 導出註釋 - 日間模式 換顏色 - 點按即可在日間模式下查看筆記 點擊改變音符的背景顏色 - 啟用夜間模式 - 默認啟用黑色主題 - 啟用日間模式 搜索筆記… 鎖定注意 解鎖注意 @@ -37,14 +28,9 @@ 安全選項 密碼 設置一個4位數字的PIN碼來鎖定音符 - 用指紋解鎖 - 筆記將用指紋解鎖 - 指紋被禁用 - 筆記不會使用指紋 輸入新的PIN碼 輸入PIN碼即可解鎖 輸入當前的PIN碼 - 輸入代碼 校驗 開鎖 @@ -54,7 +40,6 @@ 啟用網格佈局 以交錯格子顯示筆記 - 默認啟用輕量級主題 將筆記導出到設備存儲以進行共享 導入註釋 從設備存儲導入筆記 @@ -72,12 +57,10 @@ 導出到文件… 完成 分享 - 關於我們和更多 Play商店的價格 有助於 應用程式版本 關於應用 - 夜間模式 永久刪除 解除注意 存檔注意 @@ -85,7 +68,6 @@ 標記收藏 還原註意 移到廢紙簍 - 點按即可在夜間模式下查看筆記 點擊以打開註釋進行編輯 點擊將音符內容複製到剪貼板 點按即可將筆記內容分享到其他應用 @@ -97,26 +79,15 @@ 點擊標記註意不是最喜歡的 點擊歸檔筆記 點擊以取消存檔 - 你的筆記… - 所有正常和最喜歡的筆記 最愛 - 所有你最喜歡的筆記 存檔 - 所有的歸檔筆記 垃圾 - 你在垃圾桶裡的所有筆記 減價支持 允許降價支持格式 - 例子 - 減價設置 - 看看如何在筆記中使用降價 創建通知 注意通知 鎖定 - 所有鎖定的筆記 - 標籤 - 所有的筆記標籤 添加新標籤… 編輯標籤… 輸入標籤 @@ -127,8 +98,6 @@ 進口 註釋列表中的降價 在筆記列表中啟用Markdown格式 - 填寫調查 - 通過告訴我們你喜歡什麼來幫助我們改進應用程序 更改標籤 @@ -137,8 +106,6 @@ 了解更多關於開源項目 圖書館 開源項目 - 關於開源項目 - 注意提醒 提醒日期 提醒時間 重複頻率 @@ -153,8 +120,6 @@ 界面和經驗 選擇應用程序的外觀和感覺。 - 注意首選項 - 選擇筆記和其他設置。 關於 了解更多關於我們和應用程序。 默認的注意顏色 @@ -189,19 +154,6 @@ 添加註釋 添加清單 - 塊格式化 - 標題 - 小標題 - 文本 - 引用 - - 清單 - 降價格式 - 膽大 - 斜體 - 強調 - 罷工 - 名單 選擇一個註釋 選擇註釋 設置 @@ -215,9 +167,6 @@ 什麼是新的 了解最近更新的應用程序中的新功能 翻譯 - 點擊添加一個新的筆記 - 點擊查看家庭選項 - 主菜單有您最喜歡的和存檔的筆記,以及應用程序設置。 你也可以在這裡找到你的標籤。 @@ -235,51 +184,37 @@ 我明白 自動導出 頻繁導出筆記到外部文件作為備份 - 圖片 點擊添加或更改圖像 只有一次 日常 - 習慣 - Beta版 提醒和警報 %s是開源的,任何人都可以為改善它做出貢獻。 它目前由%s構建和維護。 %s是一個簡單的筆記應用程序。 它允許快速富文本輸入,而不會讓使用體驗變得非常困難。 它使得多任務輕而易舉。 嗨,我們是一對設計師和程序員,他們創造了%s。 我們致力於打造漂亮,精心設計的免費,無廣告或最低限度的廣告應用程序,這些應用程序對每個人都非常實用! 主屏幕上的%d行 - 搜索%s … 分心免費 - 分隔器 登錄到應用程序 登錄雲備份和同步 登出 註銷以停止雲備份 - 用Google登錄 - 登錄… - 您已經登錄 Google登錄失敗 隱私政策 應用程序隱私政策的內容 安裝Pro App 為什麼安裝Pro 支持大規模服務器成本的開發人員,運行云同步 \n\n 首先獲取最新功能 \n\n 一些額外功能僅適用於專業用戶 - 為什麼啟用雲端同步 - 根據設備更改進行上傳和備份 \n\n 在多個設備之間進行同步,並獲得快速更新 \n\n 安全地保存在Google Firebase服務器上 - 你好, - 材料的筆記現在是猩紅色! - 開始使用 應用主題 選擇主題的背景顏色 選擇應用主題 單擊以添加或更改標籤 - 顯示更多操作 選擇備註 一次選擇並對多個音符執行操作 這張紙條被移到了垃圾桶裡 @@ -315,4 +250,155 @@ 刪除應用中的註釋,標籤和文件夾 注意查看器背景 + + 合併備註 + 出口為降價 + 以降價格式導出備註。 (你不能將這些導回到應用程序) + 使用主題顏色為背景 + 使用備註顏色作為背景 + 啟用 + 禁用 + 啟用文件夾同步 + 文件夾同步 + 將所有筆記,標籤和文件夾同步到外部文件夾。這有助於您在設備之間使用其他應用進行同步,並且可以在您需要刪除應用時獲得副本。 + 導出到文件夾 + 將所有筆記,標籤等同步到外部文件夾 + 導出鎖定的筆記 + 按英文字母順序 + 可在Scarlet Pro上使用 + 還備份已鎖定的備註 + 編輯器選項 + 更改註釋編輯器的設置和用法 + Markdown選項為默認值 + 默認情況下顯示工具欄上的降價快速按鈕 + 實時降價 + 選擇是否要將標記顯示為類型。啟用可以影響大筆記的性能。 + 移動選中的項目 + 選中的項目移動到列表的底部。取消選中不會重置位置。 + 顯示運動手柄 + 顯示向上或向下移動項目的句柄。你仍然可以通過觸摸角落來移動東西。 + 降價示例 + 小部件設置 + 更改主屏幕小組件的設置 + 啟用格式化 + 在主屏幕小部件中使用格式呈現註釋 + 顯示鎖定的筆記 + 允許鎖定的註釋顯示在主屏幕小部件中 + 顯示存檔的筆記 + 允許存檔的註釋顯示在主屏幕小部件中 + 在廢紙簍中顯示備註 + 允許垃圾中的註釋顯示在主屏幕小部件中 + 幫助和常見問題 + 查找有關如何使用應用程序中的功能的幫助 + 同步 + 待備份 + 開發者選項 + 將內部設置更改為用於調試的應用程序 + 記錄例外 + 記錄固定註釋的異常,以允許轉發給Developer + 顯示例外表 + 如果可能,在工作表上顯示捕獲的異常,以允許轉發到Developer + 拋棄異常 + 在異常上拋出並崩潰應用程序。 5次崩潰後將重置 + 啟用全屏 + 全屏顯示應用程序以允許截屏和錄製 + 顯示註釋UUID + 在主屏幕視圖中顯示備註的唯一ID + 假例外 + 拋出一個假異常來測試異常功能 + 拋出異常 + 崩潰應用程序 + 郵件 + 連接失敗 + 在Google雲端硬盤上同步 + Google雲端硬盤可讓您使用自己的Google雲端硬盤帳戶在設備之間同步筆記。 + 之前登錄過Google Firebase? + 登錄Google雲端硬盤 + 簽約 + 退出血色 + 停止同步筆記,標籤和文件夾。 + 停止將您的筆記,標籤和文件夾同步到Google雲端硬盤。 + 您在應用和Google雲端硬盤上的數據仍然存在。 + 從雲端硬盤退出 + 簽出 - + 備註,標籤和文件夾存儲在您自己的Google雲端硬盤中,因此只有您可以控制對它們的訪問權限。 + 您的照片也會上傳並在設備間同步。 + 從Firebase還原數據 + 與穀歌簽約 + 簽約 + 我們過去常常將您的信息存儲在Google Firebase上。登錄後,我們會將這些恢復到您的設備 + 新筆記和更改不會同步到Google Firebase,您需要登錄Google雲端硬盤 + 恢復筆記後,您可以將其從Google Firebase中刪除,然後進行切換 + 您的數據未同步! + 基於舊版登錄的數據同步已停用,請考慮切換到基於Google雲端硬盤的同步。 + 將數據從Firebase傳輸到雲端硬盤 + 清除數據並註銷 + 清除和簽出 + 我們過去常常將您的信息存儲在Google Firebase上。我們正在將您的筆記存儲到您的Google雲端硬盤中。 + 更多隱私。 + 照片同步。 + 下一步 + 我們會先從Firebase中刪除您的備註並註銷。 + 然後,您可以登錄Google雲端硬盤,我們會將您的數據與圖片一起上傳。 + + + 刪除選項 + 移除筆記本 + 僅刪除筆記本。便箋移到文件夾之外。 + 刪除筆記本和筆記 + 刪除筆記本。所有筆記都會移至回收站或被刪除。 + 刪除筆記 + 保留筆記本,但所有筆記都移至廢紙or或被刪除。 + 自定義字體 + 選擇應用程序並記下字體 + 選擇字體集 + 注意:字體可能不適用於所有語言 + 應用默認 + 設備默認 + 單聲道 + 襯線 + 解鎖應用 + 輸入4位數的PIN或使用生物識別技術解鎖 + 輸入4位數PIN碼以解鎖 + 使用系統主題 + 使用系統中的淺色或深色主題 + 黑暗筆記 + 自動使筆記和文件夾的顏色變暗 + 本地 + 遠程 + 不可用 + 已建立 + 已刪除 + 更新 + 小部件背景 + 選擇多筆記小部件的背景顏色 + 顯示動作工具欄 + 多筆記小部件顯示工具欄 + 跳過筆記查看器 + 跳過便箋查看器,直接跳至便箋編輯器 + 您要永久刪除這些註釋嗎? + 更快的更新和請求。 + 應用鎖定和單次解鎖。 + 更多應用主題。 + 注意字體和字體大小。 + 查看器背景色。 + 更多小部件選項。 + 更多註釋動作。 + 音符顏色 + 注意標籤 + 啟用應用鎖定 + 使用PIN解鎖整個應用程序 + 總是要求輸入PIN + 輸入所有便箋的PIN碼,即使之前已輸入 + 用生物識別技術解鎖 + 允許使用指紋或其他生物特徵進行解鎖 + 生物識別功能已禁用 + 禁止使用指紋或其他生物特徵進行解鎖 + 解鎖筆記 + 使用設備的指紋或生物識別技術來解鎖筆記和訪問權限。 + 解鎖應用 + 使用設備指紋或生物識別技術解鎖應用程序並訪問所有筆記。 + 啟動器快捷方式 + 分享照片 + \ No newline at end of file diff --git a/base/src/main/res/values-zh/strings.xml b/base/src/main/res/values-zh/strings.xml index 3a1b788b..848cbba5 100644 --- a/base/src/main/res/values-zh/strings.xml +++ b/base/src/main/res/values-zh/strings.xml @@ -6,29 +6,20 @@ 分享使用… 沒有筆記 看來你還沒有添加任何筆記。 點擊添加備註。 - 添加備註… - 添加快速筆記… 編輯註釋 在彈出窗口中打開 - 刪除註釋 複製說明 發送注意事項 選擇動作… 添加內容… 添加標題… - 添加子標題… 添加引號文本… 新增項目… 添加代碼… 選項和設置 導出註釋 - 日間模式 換顏色 - 點按即可在日間模式下查看筆記 點擊改變音符的背景顏色 - 啟用夜間模式 - 默認啟用黑色主題 - 啟用日間模式 搜索筆記… 鎖定注意 解鎖注意 @@ -37,14 +28,9 @@ 安全選項 密碼 設置一個4位數字的PIN碼來鎖定音符 - 用指紋解鎖 - 筆記將用指紋解鎖 - 指紋被禁用 - 筆記不會使用指紋 輸入新的PIN碼 輸入PIN碼即可解鎖 輸入當前的PIN碼 - 輸入代碼 校驗 開鎖 @@ -54,7 +40,6 @@ 啟用網格佈局 以交錯格子顯示筆記 - 默認啟用輕量級主題 將筆記導出到設備存儲以進行共享 導入註釋 從設備存儲導入筆記 @@ -72,12 +57,10 @@ 導出到文件… 完成 分享 - 關於我們和更多 Play商店的價格 有助於 應用程式版本 關於應用 - 夜間模式 永久刪除 解除注意 存檔注意 @@ -85,7 +68,6 @@ 標記收藏 還原註意 移到廢紙簍 - 點按即可在夜間模式下查看筆記 點擊以打開註釋進行編輯 點擊將音符內容複製到剪貼板 點按即可將筆記內容分享到其他應用 @@ -97,26 +79,15 @@ 點擊標記註意不是最喜歡的 點擊歸檔筆記 點擊以取消存檔 - 你的筆記… - 所有正常和最喜歡的筆記 最愛 - 所有你最喜歡的筆記 存檔 - 所有的歸檔筆記 垃圾 - 你在垃圾桶裡的所有筆記 減價支持 允許降價支持格式 - 例子 - 減價設置 - 看看如何在筆記中使用降價 創建通知 注意通知 鎖定 - 所有鎖定的筆記 - 標籤 - 所有的筆記標籤 添加新標籤… 編輯標籤… 輸入標籤 @@ -127,8 +98,6 @@ 進口 註釋列表中的降價 在筆記列表中啟用Markdown格式 - 填寫調查 - 通過告訴我們你喜歡什麼來幫助我們改進應用程序 更改標籤 @@ -137,8 +106,6 @@ 了解更多關於開源項目 圖書館 開源項目 - 關於開源項目 - 注意提醒 提醒日期 提醒時間 重複頻率 @@ -153,8 +120,6 @@ 界面和經驗 選擇應用程序的外觀和感覺。 - 注意首選項 - 選擇筆記和其他設置。 關於 了解更多關於我們和應用程序。 默認的注意顏色 @@ -189,19 +154,6 @@ 添加註釋 添加清單 - 塊格式化 - 標題 - 小標題 - 文本 - 引用 - - 清單 - 降價格式 - 膽大 - 斜體 - 強調 - 罷工 - 名單 選擇一個註釋 選擇註釋 設置 @@ -215,9 +167,6 @@ 什麼是新的 了解最近更新的應用程序中的新功能 翻譯 - 點擊添加一個新的筆記 - 點擊查看家庭選項 - 主菜單有您最喜歡的和存檔的筆記,以及應用程序設置。 你也可以在這裡找到你的標籤。 @@ -235,51 +184,37 @@ 我明白 自動導出 頻繁導出筆記到外部文件作為備份 - 圖片 點擊添加或更改圖像 只有一次 日常 - 習慣 - Beta版 提醒和警報 %s是開源的,任何人都可以為改善它做出貢獻。 它目前由%s構建和維護。 %s是一個簡單的筆記應用程序。 它允許快速富文本輸入,而不會讓使用體驗變得非常困難。 它使得多任務輕而易舉。 嗨,我們是一對設計師和程序員,他們創造了%s。 我們致力於打造漂亮,精心設計的免費,無廣告或最低限度的廣告應用程序,這些應用程序對每個人都非常實用! 主屏幕上的%d行 - 搜索%s … 分心免費 - 分隔器 登錄到應用程序 登錄雲備份和同步 登出 註銷以停止雲備份 - 用Google登錄 - 登錄… - 您已經登錄 Google登錄失敗 隱私政策 應用程序隱私政策的內容 安裝Pro App 為什麼安裝Pro 支持大規模服務器成本的開發人員,運行云同步 \n\n 首先獲取最新功能 \n\n 一些額外功能僅適用於專業用戶 - 為什麼啟用雲端同步 - 根據設備更改進行上傳和備份 \n\n 在多個設備之間進行同步,並獲得快速更新 \n\n 安全地保存在Google Firebase服務器上 - 你好, - 材料的筆記現在是猩紅色! - 開始使用 應用主題 選擇主題的背景顏色 選擇應用主題 單擊以添加或更改標籤 - 顯示更多操作 選擇備註 一次選擇並對多個音符執行操作 這張紙條被移到了垃圾桶裡 @@ -315,4 +250,155 @@ 刪除應用中的註釋,標籤和文件夾 注意查看器背景 + + 合併備註 + 出口為降價 + 以降價格式導出備註。 (你不能將這些導回到應用程序) + 使用主題顏色為背景 + 使用備註顏色作為背景 + 啟用 + 禁用 + 啟用文件夾同步 + 文件夾同步 + 將所有筆記,標籤和文件夾同步到外部文件夾。這有助於您在設備之間使用其他應用進行同步,並且可以在您需要刪除應用時獲得副本。 + 導出到文件夾 + 將所有筆記,標籤等同步到外部文件夾 + 導出鎖定的筆記 + 按英文字母順序 + 可在Scarlet Pro上使用 + 還備份已鎖定的備註 + 編輯器選項 + 更改註釋編輯器的設置和用法 + Markdown選項為默認值 + 默認情況下顯示工具欄上的降價快速按鈕 + 實時降價 + 選擇是否要將標記顯示為類型。啟用可以影響大筆記的性能。 + 移動選中的項目 + 選中的項目移動到列表的底部。取消選中不會重置位置。 + 顯示運動手柄 + 顯示向上或向下移動項目的句柄。你仍然可以通過觸摸角落來移動東西。 + 降價示例 + 小部件設置 + 更改主屏幕小組件的設置 + 啟用格式化 + 在主屏幕小部件中使用格式呈現註釋 + 顯示鎖定的筆記 + 允許鎖定的註釋顯示在主屏幕小部件中 + 顯示存檔的筆記 + 允許存檔的註釋顯示在主屏幕小部件中 + 在廢紙簍中顯示備註 + 允許垃圾中的註釋顯示在主屏幕小部件中 + 幫助和常見問題 + 查找有關如何使用應用程序中的功能的幫助 + 同步 + 待備份 + 開發者選項 + 將內部設置更改為用於調試的應用程序 + 記錄例外 + 記錄固定註釋的異常,以允許轉發給Developer + 顯示例外表 + 如果可能,在工作表上顯示捕獲的異常,以允許轉發到Developer + 拋棄異常 + 在異常上拋出並崩潰應用程序。 5次崩潰後將重置 + 啟用全屏 + 全屏顯示應用程序以允許截屏和錄製 + 顯示註釋UUID + 在主屏幕視圖中顯示備註的唯一ID + 假例外 + 拋出一個假異常來測試異常功能 + 拋出異常 + 崩潰應用程序 + 郵件 + 連接失敗 + 在Google雲端硬盤上同步 + Google雲端硬盤可讓您使用自己的Google雲端硬盤帳戶在設備之間同步筆記。 + 之前登錄過Google Firebase? + 登錄Google雲端硬盤 + 簽約 + 退出血色 + 停止同步筆記,標籤和文件夾。 + 停止將您的筆記,標籤和文件夾同步到Google雲端硬盤。 + 您在應用和Google雲端硬盤上的數據仍然存在。 + 從雲端硬盤退出 + 簽出 - + 備註,標籤和文件夾存儲在您自己的Google雲端硬盤中,因此只有您可以控制對它們的訪問權限。 + 您的照片也會上傳並在設備間同步。 + 從Firebase還原數據 + 與穀歌簽約 + 簽約 + 我們過去常常將您的信息存儲在Google Firebase上。登錄後,我們會將這些恢復到您的設備 + 新筆記和更改不會同步到Google Firebase,您需要登錄Google雲端硬盤 + 恢復筆記後,您可以將其從Google Firebase中刪除,然後進行切換 + 您的數據未同步! + 基於舊版登錄的數據同步已停用,請考慮切換到基於Google雲端硬盤的同步。 + 將數據從Firebase傳輸到雲端硬盤 + 清除數據並註銷 + 清除和簽出 + 我們過去常常將您的信息存儲在Google Firebase上。我們正在將您的筆記存儲到您的Google雲端硬盤中。 + 更多隱私。 + 照片同步。 + 下一步 + 我們會先從Firebase中刪除您的備註並註銷。 + 然後,您可以登錄Google雲端硬盤,我們會將您的數據與圖片一起上傳。 + + + 刪除選項 + 移除筆記本 + 僅刪除筆記本。便箋移到文件夾之外。 + 刪除筆記本和筆記 + 刪除筆記本。所有筆記都會移至回收站或被刪除。 + 刪除筆記 + 保留筆記本,但所有筆記都移至廢紙or或被刪除。 + 自定義字體 + 選擇應用程序並記下字體 + 選擇字體集 + 注意:字體可能不適用於所有語言 + 應用默認 + 設備默認 + 單聲道 + 襯線 + 解鎖應用 + 輸入4位數的PIN或使用生物識別技術解鎖 + 輸入4位數PIN碼以解鎖 + 使用系統主題 + 使用系統中的淺色或深色主題 + 黑暗筆記 + 自動使筆記和文件夾的顏色變暗 + 本地 + 遠程 + 不可用 + 已建立 + 已刪除 + 更新 + 小部件背景 + 選擇多筆記小部件的背景顏色 + 顯示動作工具欄 + 多筆記小部件顯示工具欄 + 跳過筆記查看器 + 跳過便箋查看器,直接跳至便箋編輯器 + 您要永久刪除這些註釋嗎? + 更快的更新和請求。 + 應用鎖定和單次解鎖。 + 更多應用主題。 + 注意字體和字體大小。 + 查看器背景色。 + 更多小部件選項。 + 更多註釋動作。 + 音符顏色 + 注意標籤 + 啟用應用鎖定 + 使用PIN解鎖整個應用程序 + 總是要求輸入PIN + 輸入所有便箋的PIN碼,即使之前已輸入 + 用生物識別技術解鎖 + 允許使用指紋或其他生物特徵進行解鎖 + 生物識別功能已禁用 + 禁止使用指紋或其他生物特徵進行解鎖 + 解鎖筆記 + 使用設備的指紋或生物識別技術來解鎖筆記和訪問權限。 + 解鎖應用 + 使用設備指紋或生物識別技術解鎖應用程序並訪問所有筆記。 + 啟動器快捷方式 + 分享照片 + \ No newline at end of file diff --git a/base/src/main/res/values/colors.xml b/base/src/main/res/values/colors.xml index 06eb9ac4..58d425bd 100644 --- a/base/src/main/res/values/colors.xml +++ b/base/src/main/res/values/colors.xml @@ -6,8 +6,11 @@ #07575B #003B46 + #F52549 @color/material_pink_accent_200 + #FFFFCD + #505000 #C62828 @@ -30,6 +33,9 @@ #22000000 #22FFFFFF + #16000000 + #16FFFFFF + #FFEBEE #e8ccd0 #d8a9af @@ -43,14 +49,18 @@ #99907d + @color/black @color/material_grey_850 @color/material_blue_grey_800 + @color/material_blue_grey_700 @color/material_purple_700 @color/material_deep_purple_700 @color/material_indigo_700 + @color/material_blue_900 @color/material_blue_700 @color/material_light_blue_700 @color/material_cyan_700 + @color/material_cyan_800 @color/material_teal_700 @color/material_green_700 @color/material_light_green_700 @@ -61,6 +71,8 @@ @color/material_deep_orange_700 @color/material_pink_700 @color/material_red_700 + @color/material_red_900 + @color/material_brown_700 diff --git a/base/src/main/res/values/dimens.xml b/base/src/main/res/values/dimens.xml index a05cd116..ad1d1dd0 100644 --- a/base/src/main/res/values/dimens.xml +++ b/base/src/main/res/values/dimens.xml @@ -18,6 +18,10 @@ 6dp 36dp + 64dp + 48dp + 12dp + 36dp 32dp 32dp diff --git a/base/src/main/res/values/strings.xml b/base/src/main/res/values/strings.xml index 3895083c..04cc040f 100644 --- a/base/src/main/res/values/strings.xml +++ b/base/src/main/res/values/strings.xml @@ -6,24 +6,18 @@ Save Import Search Notes… - Search %s… Share using… No Notes It seems you have not added any notes. Click to add a note. - Add a note… - Add a quick note… - Add Note Add Checklist - Night Mode - Day Mode Edit Note Create Notification + Share Photos Open In Popup - Delete Note Delete Permanently Copy Note Send Note @@ -38,16 +32,15 @@ Change Tags Unlock Note Reminder + Launcher Shortcut Select Duplicate Pin Note Unpin Note Distraction Free - Merge Notes + Merge Notes Choose Action… - Tap to view the note in night mode - Tap to view the note in day mode Tap to open note for editing Tap to copy note content to clipboard Tap to share note content to other apps @@ -61,60 +54,26 @@ Tap to change the background colour of the note Tap to unarchive the note - Your Notes and More… Home - All of your normal and favourite notes Favourites - All of your favourite notes Archived - All of your archived notes Locked - All of your locked notes - Tags - All your note tags Trash - All of your notes in the trash Add Content… Add Heading… - Add Sub Heading… Add Quoted Text… Add Item… Add Code… Click to add or change image - Block Formatting - Heading - Sub Heading - Text - Quote - Code - Checklist - Image - Separator - - Markdown Formatting - Bold - Italics - Underline - Strike - List - Options and Settings Interface and Experience Choose how the app looks and feels. - Note Preferences - Choose note and other settings. About Know more about us and the app. Security Locking notes and security options - Enable Night Mode - Enable dark theme as default - Enable Day Mode - Enable light theme as default - Markdown Settings - See how to use markdown in notes Enable List Layout Show notes in a single column Enable Grid Layout @@ -126,10 +85,8 @@ Export notes to device storage to share Import Notes Import notes from the device storage - Export As Markdown - Export notes in markdown format. (You cannot import these back to the app) - Export Folder - Choose where all exports are stored + Export As Markdown + Export notes in markdown format. (You cannot import these back to the app) Export Automatically Export notes frequently to external file as backup About Us @@ -138,8 +95,6 @@ Know more about the open source project Rate and Review Tell us how much you liked the app - Fill Survey - Help us improve the app by telling us what you like Install Pro App Install the Pro App to unlock features and support developer Migrate Notes to Scarlet Pro @@ -156,21 +111,30 @@ Delete notes, tags and folders in the app Note Viewer Background - Use theme color for background - Use note color for background + Use theme color for background + Use note color for background Security Options Pass Code Set a 4 digit PIN to lock notes - Unlock with Fingerprint - The notes will unlock with the fingerprint - Fingerprint disabled - The notes will not use a fingerprint + Enable App Lock + Use PIN to unlock the whole application + Always ask for PIN + Enter PIN for all notes, even if previously entered + Unlock with Biometrics + Allow unlock with a fingerprint or other biometrics + Biometrics disabled + Do not allow unlock with a fingerprint or other biometrics + + Unlock Note + Use device fingerprint or biometrics to unlock the note and access. + + Unlock App + Use device fingerprint or biometrics to unlock the app and access all notes. Enter new PIN Enter PIN to unlock Enter current PIN - enter code Verify Unlock Set @@ -185,7 +149,6 @@ Allow markdown supported formatting Markdown in Note List Enable Markdown formatting in the list of notes - Examples # Heading \n## Subheading \n\n```\nblock of code\n```\n\n> quote\n\n- **bold**\n- *italics*\n- _underline_\n- ~~strike~~\n- `code`\n Give Permissions @@ -199,22 +162,21 @@ Exporting to file… Done Share - Enable - Disable - Enable Folder Sync - Folder Sync - Sync all your notes, tags and folders to an external folder. This helps you sync using other apps between devices, as well have a copy in case you need to delete the app. - Exporting to Folder - Sync all the notes, tags, etc to an external folder + Enable + Disable + Enable Folder Sync + Folder Sync + Sync all your notes, tags and folders to an external folder. This helps you sync using other apps between devices, as well have a copy in case you need to delete the app. + Exporting to Folder + Sync all the notes, tags, etc to an external folder MaterialNotes/BACKUP.txt - Export locked notes - Also backup the notes which are locked + Export locked notes + Also backup the notes which are locked %s KB %s MB %s GB - About Us and More Rate on Play Store Contribute App Version @@ -222,16 +184,12 @@ Libraries Open Source Project - About Open Source Project - Note Reminder Reminder Date Reminder Time Repeat Frequency Only Once Daily - Custom - Beta Note Notifications Reminders and Alarms @@ -254,9 +212,11 @@ Sort Notes By Newest First + Note Color + Note Tags Oldest First Most Recently Modified - Alphabetical + Alphabetical Select a Note @@ -270,9 +230,24 @@ Know what is new in the recent updates of the app Translate - Click to add a new note - Click to see home options - The home menu has your favourite and archive notes, as well as application settings. You can find your tags here too. + A lot has changed in this update, here is a summary of those changes. + Sign In with Drive. More Privacy. + Share Photos. To and From. + More Note Colors. + Customise Fonts. + Launcher Shortcuts. + More Languages Supported. + H3 and Bullet Support. + More Biometric Support. + UI Improvements. + + Faster Updates and Requests. + App Lock and Single Unlock. + More App Themes. + Note Fonts and Font Sizes. + Viewer Background Color. + More Widget Options. + More Note Actions. Copy Block Text Actions @@ -312,6 +287,7 @@ Are you sure? Would you like to permanently delete the notes in the trash folder? Would you like to permanently delete this note? + Would you like to permanently delete these notes? Delete Cancel Notes are deleted forever after 7 days @@ -328,35 +304,25 @@ Sign In for cloud backup and synchronisation Sign Out Sign Out to stop cloud backup - Sign In with Google - Signing in… - You are logged in Google Login Failed Privacy Policy App privacy policy for the content Install Pro App - Available on Scarlet Pro + Available on Scarlet Pro Why Install Pro ✔ Support developer for the massive server costs, to run the cloud sync \n\n✔ Get the latest features first \n\n✔ Some extra features will be available only to Pro users - Why enable Cloud Sync - - ✔ Upload and backup against device changes \n\n✔ Sync between multiple devices, and get quick updates \n\n✔ Securely saved on Google Firebase servers - Forget Me Logout and remove all online data - Hello, Scarlet - Material Notes is now Scarlet! - Get Started @@ -367,7 +333,6 @@ Click to add or change tags - Show More Actions Select Notes Select and perform actions on multiple notes at once @@ -392,36 +357,164 @@ - Editor Options - Change the settings and usage for the note editor + Editor Options + Change the settings and usage for the note editor + + Markdown Options as Default + Show the markdown quick buttons on the toolbar as default - Markdown Options as Default - Show the markdown quick buttons on the toolbar as default + Skip Note Viewer + Skip the note viewer and jump to the note editor directly - Realtime Markdown - Choose if you want markdown to be visible as your type. Enabling can effect performance on large notes. + Realtime Markdown + Choose if you want markdown to be visible as your type. Enabling can effect performance on large notes. - Show Movement Handles - Show the handle to move items up or down. You can still move things around by touching the corner. + Move Checked Items + Checked items move to the bottom of the list. Uncheck does not reset position. - Markdown Examples + Show Movement Handles + Show the handle to move items up or down. You can still move things around by touching the corner. + + Markdown Examples - Widget Settings - Change the settings for the home screen widgets + Widget Settings + Change the settings for the home screen widgets + + Enable Formatting + Notes are rendered with formatting in home screen widgets + + Show Locked Notes + Allow locked notes to be shown in home screen widgets - Enable Formatting - Notes are rendered with formatting in home screen widgets + Show Archived Notes + Allow archived notes to be shown in home screen widgets - Show Locked Notes - Allow locked notes to be shown in home screen widgets + Show Notes in Trash + Allow notes in trash to be shown in home screen widgets + + Widget Background + Choose the background color for the multi-notes widget + + Show Action Toolbar + Multi-notes widget shows the toolbar - Show Archived Notes - Allow archived notes to be shown in home screen widgets - Show Notes in Trash - Allow notes in trash to be shown in home screen widgets + Help and Common Questions + Find help on how to use the features in the app + + Syncing + Pending Backup + Local + Remote + + Unavailable + Created + Deleted + Updated + + + Developer Options + Change internal settings to the application used for debugging + + Log Exceptions + Log caught exceptions to a fixed note, to allow forwarding to Developer + + Show Exception Sheet + Show caught exceptions on a sheet if possible, to allow forwarding to Developer + + Throw on Exceptions + Throw and crash the application on exceptions. Will be reset after 5 crashes + + Enable Fullscreen + Make the app in fullscreen to allow screenshots and recordings + + Show Note UUIDs + Show the unique ids of the notes in the home screen view + + Fake Exceptions + Throw a fake exception to test the exception features + + Exception Thrown + Crash App + Mail + + + Connection Failed + Sync on Google Drive + Google Drive allows you to sync your notes between devices using your own Google Drive account. + Logged into Google Firebase before? + Sign In to Google Drive + Signing In… + + Sign Out of Scarlet + Stop syncing notes, tags and folders. + Stop syncing your notes, tags and folders to your Google Drive. + Your data on the app and on Google Drive will still be there. + Sign Out from Drive + Signing Out… + + Notes, Tags and Folders are stored on your own Google Drive, so only you can control access to them. + Your photos are uploaded and synced across devices as well. + + + Restore Data from Firebase + Sign In with Google + Signing In… + + We used to store your information on Google Firebase. After logging in we will recover these to your device + New notes and changes will NOT be synced over to Google Firebase, and you need to login on to Google Drive + Once your notes are recovered, you can delete them from Google Firebase, and then switch over + + Your data is not being synced! + Data Sync based on legacy login is disabled, consider switching over to Google Drive based sync. + + Transfer Data from Firebase to Drive + Clear Data and Sign Out + Clearing and Signing Out + We used to store your information on Google Firebase. We are moving over to storing your notes in your Google Drive. + More Privacy. + Photo Sync. + Next Steps + We will first delete your notes from Firebase and log you out. + You can then log into Google Drive, and we will upload your data along with images. + + + + Unlock App + Enter 4 digit PIN or use biometrics to unlock + Enter 4 digit PIN to unlock + + + + Use System Theme + Use the light or dark theme from the system + + Dark Notes + Automatically darken note and folder colors + + + Remove Options + Remove Notebook + Only Remove Notebook. Notes move outside folder. + Remove Notebook and Notes + Remove Notebook. All notes move to trash or are deleted. + Remove Notes + Keep Notebook but all notes move to trash or are deleted. + + + Customise Fonts + Select the app and note fonts + Select a Font Set + Note: Fonts might not work properly with all languages + + App Default + Device Default + Mono + Serif + + diff --git a/base/src/main/res/values/styles.xml b/base/src/main/res/values/styles.xml index 09ae99f8..3db738cf 100644 --- a/base/src/main/res/values/styles.xml +++ b/base/src/main/res/values/styles.xml @@ -8,7 +8,6 @@ @style/RobotoTextViewStyle @style/RobotoButtonStyle @style/RobotoEditTextStyle - @font/open_sans - - - - - - -