diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml
new file mode 100644
index 00000000..e442406a
--- /dev/null
+++ b/.idea/deploymentTargetDropDown.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index a0de2a15..0dbe464b 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -7,10 +7,11 @@
-
+
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index db4810bd..48a98ed0 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -2,6 +2,7 @@
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 1cf01017..924048d1 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -94,7 +94,7 @@
-
+
diff --git a/.idea/render.experimental.xml b/.idea/render.experimental.xml
new file mode 100644
index 00000000..8ec256a5
--- /dev/null
+++ b/.idea/render.experimental.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api/.gitignore b/api/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/api/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/api/build.gradle b/api/build.gradle
new file mode 100644
index 00000000..650ba93b
--- /dev/null
+++ b/api/build.gradle
@@ -0,0 +1,12 @@
+plugins {
+ id 'java-library'
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+}
+
+dependencies {
+ implementation 'org.jetbrains:annotations:15.0'
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/fazziclay/opentoday/api/Event.java b/api/src/main/java/com/fazziclay/opentoday/api/Event.java
new file mode 100644
index 00000000..656b194e
--- /dev/null
+++ b/api/src/main/java/com/fazziclay/opentoday/api/Event.java
@@ -0,0 +1,4 @@
+package com.fazziclay.opentoday.api;
+
+public interface Event {
+}
diff --git a/api/src/main/java/com/fazziclay/opentoday/api/EventExceptionEvent.java b/api/src/main/java/com/fazziclay/opentoday/api/EventExceptionEvent.java
new file mode 100644
index 00000000..f3362bd4
--- /dev/null
+++ b/api/src/main/java/com/fazziclay/opentoday/api/EventExceptionEvent.java
@@ -0,0 +1,19 @@
+package com.fazziclay.opentoday.api;
+
+public class EventExceptionEvent implements Event {
+ private final Event event;
+ private final Exception exception;
+
+ public EventExceptionEvent(Event event, Exception e) {
+ this.event = event;
+ this.exception = e;
+ }
+
+ public Event getEvent() {
+ return event;
+ }
+
+ public Exception getException() {
+ return exception;
+ }
+}
diff --git a/api/src/main/java/com/fazziclay/opentoday/api/EventHandler.java b/api/src/main/java/com/fazziclay/opentoday/api/EventHandler.java
new file mode 100644
index 00000000..b695fa6e
--- /dev/null
+++ b/api/src/main/java/com/fazziclay/opentoday/api/EventHandler.java
@@ -0,0 +1,15 @@
+package com.fazziclay.opentoday.api;
+
+public class EventHandler {
+ public static void call(Event event) {
+ try {
+ PluginManager.callEvent(event);
+ } catch (Exception e) {
+ PluginManager.callEvent(new EventExceptionEvent(event, e));
+ }
+ }
+
+ public void handle(Event event) {
+
+ }
+}
diff --git a/api/src/main/java/com/fazziclay/opentoday/api/OpenTodayPlugin.java b/api/src/main/java/com/fazziclay/opentoday/api/OpenTodayPlugin.java
new file mode 100644
index 00000000..c14db17f
--- /dev/null
+++ b/api/src/main/java/com/fazziclay/opentoday/api/OpenTodayPlugin.java
@@ -0,0 +1,10 @@
+package com.fazziclay.opentoday.api;
+
+public abstract class OpenTodayPlugin {
+ public void onEnable() {}
+ public void onDisable() {}
+
+ public EventHandler[] getEventHandlers() {
+ return new EventHandler[0];
+ }
+}
diff --git a/api/src/main/java/com/fazziclay/opentoday/api/PluginException.java b/api/src/main/java/com/fazziclay/opentoday/api/PluginException.java
new file mode 100644
index 00000000..afd0fbe5
--- /dev/null
+++ b/api/src/main/java/com/fazziclay/opentoday/api/PluginException.java
@@ -0,0 +1,33 @@
+package com.fazziclay.opentoday.api;
+
+public class PluginException extends RuntimeException {
+ private final OpenTodayPlugin plugin;
+
+ public PluginException(OpenTodayPlugin plugin) {
+ this.plugin = plugin;
+ }
+
+ public PluginException(String message, OpenTodayPlugin plugin) {
+ super(message);
+ this.plugin = plugin;
+ }
+
+ public PluginException(String message, Throwable cause, OpenTodayPlugin plugin) {
+ super(message, cause);
+ this.plugin = plugin;
+ }
+
+ public PluginException(Throwable cause, OpenTodayPlugin plugin) {
+ super(cause);
+ this.plugin = plugin;
+ }
+
+ public PluginException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, OpenTodayPlugin plugin) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ this.plugin = plugin;
+ }
+
+ public OpenTodayPlugin getPlugin() {
+ return plugin;
+ }
+}
diff --git a/api/src/main/java/com/fazziclay/opentoday/api/PluginManager.java b/api/src/main/java/com/fazziclay/opentoday/api/PluginManager.java
new file mode 100644
index 00000000..2a8887db
--- /dev/null
+++ b/api/src/main/java/com/fazziclay/opentoday/api/PluginManager.java
@@ -0,0 +1,57 @@
+package com.fazziclay.opentoday.api;
+
+import java.util.HashMap;
+
+public class PluginManager {
+ private static final HashMap activePlugins = new HashMap<>();
+
+ public static void loadPlugin(String packageId, OpenTodayPlugin plugin) {
+ disablePlugin(packageId);
+ activePlugins.put(packageId, plugin);
+ plugin.onEnable();
+ }
+
+ public static void disablePlugin(String packageId) {
+ OpenTodayPlugin openTodayPlugin = activePlugins.get(packageId);
+ if (openTodayPlugin != null) {
+ openTodayPlugin.onDisable();
+ activePlugins.remove(packageId);
+ }
+ }
+
+ public static void disableAllPlugins() {
+ if (activePlugins.isEmpty()) return;
+ for (String s : activePlugins.keySet()) {
+ disablePlugin(s);
+ }
+ }
+
+ public static void callEvent(Event event) {
+ activePlugins.forEach((s, plugin) -> {
+ try {
+ for (EventHandler eventHandler : plugin.getEventHandlers()) {
+ eventHandler.handle(event);
+ }
+ } catch (Exception e) {
+ throw new PluginException("Exception while process eventHandlers in \"" + s + "\"(" + plugin + ") plugin", e, plugin);
+ }
+ });
+ }
+
+ public static OpenTodayPlugin getActivePlugin(String key) {
+ return activePlugins.get(key);
+ }
+
+ public static T getActivePlugin(Class clazz) {
+ for (OpenTodayPlugin value : activePlugins.values()) {
+ if (value.getClass() == clazz) {
+ return (T) value;
+ }
+ }
+ return null;
+ }
+
+ public static boolean isPluginActive(String key) {
+ return getActivePlugin(key) != null;
+ }
+}
diff --git a/app/build.gradle b/app/build.gradle
index 1aa18c03..f51128e1 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -4,20 +4,20 @@ plugins {
}
// =====
-var isDev = true
-var beta = false
-var appIdSuffix = "" // EMPTY FOR RELEASES!!!!
-var verBuild = 140
-var verName = "1.2+[patches:[fix-tick] + [special_widget] + [fixes-itemstorageviewer] + [item-sleepTime] + [notification-manager]"
-var verBranch = "fixes-itemstorageviewer + special_widget + item-sleepTime + notification-manager (currently main)" // use "RELEASE" for releases versions
-var verReleaseTime = 1689778441 // in seconds
+var isDev = false // add .dev to applicationId
+var beta = false // add .beta to applicationId
+var appIdSuffix = "" // add this to applicationId (E M P T Y F O R R E L E A S E S)
+var verBuild = 160 // versionCode
+var verName = "1.3" // versionName...
+var verBranch = "main" // branch
+var verReleaseTime = 1699198506 // releaseTime
android {
- compileSdk 33
+ compileSdk 34
defaultConfig {
applicationId "com.fazziclay.opentoday" + (isDev ? ".dev" : "") + (beta ? ".beta" : "") + appIdSuffix
minSdk 26
- targetSdk 33
+ targetSdk 34
versionCode verBuild
versionName verName + " (build " + verBuild + (isDev ? " dev" : "") + ")"
@@ -51,24 +51,27 @@ android {
testOptions {
unitTests.returnDefaultValues = true
}
+ packagingOptions {
+ resources.excludes.add("META-INF/*") // fix build errors
+ }
namespace 'com.fazziclay.opentoday'
}
dependencies {
// Application
- implementation files("./libs/OpenTodayTelemetry-v2-v11.jar")
- implementation files("./libs/NeoSocket-1.0.jar")
- implementation files("./libs/JavaNeoUtil-1.1.jar")
- implementation files("./libs/WarningRose-v0.4.1.jar")
- implementation 'com.github.martin-stone:hsv-alpha-color-picker-android:3.0.1'
+ implementation files("./libs/OpenTodayTelemetry-v2-v11.jar") // telemetry library for OpenToday SourceCode: https://github.com/FazziCLAY/OpenTodayTelemetry
+ implementation files("./libs/NeoSocket-1.0.jar") // for network (bad library...) uses by OpenTodayTelemetry SourceCode: https://github.com/FazziCLAY/NeoSocket
+ implementation files("./libs/JavaNeoUtil-1.1.jar") // java utils by FazziCLAY (uses FileUtil) SourceCode: https://github.com/FazziCLAY/JavaNeoUtil
+ implementation files("./libs/WarningRose-v0.4.1.jar") // for DebugTickCounter debug rose (only for developer) SourceCode: https://github.com/FazziCLAY/WarningRose
+ implementation 'com.github.leondzn:simple-analog-clock:1.0.1' // analog clock
+ implementation 'com.github.martin-stone:hsv-alpha-color-picker-android:3.0.1' // color picker
implementation 'androidx.appcompat:appcompat:1.6.1'
- implementation 'com.google.android.material:material:1.9.0'
- implementation 'com.google.code.gson:gson:2.8.9'
- implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
- implementation 'androidx.navigation:navigation-fragment:2.5.3'
- implementation 'androidx.navigation:navigation-ui:2.5.3'
+ implementation 'com.google.android.material:material:1.10.0'
+ implementation 'androidx.navigation:navigation-fragment-ktx:2.7.4'
+ implementation 'androidx.navigation:navigation-ui-ktx:2.7.4'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
- implementation 'androidx.core:core-ktx:1.10.1'
+ implementation 'androidx.core:core-ktx:1.12.0'
+ implementation project(path: ':api') // api
// Tests
androidTestImplementation 'org.junit.jupiter:junit-jupiter:5.9.3'
diff --git a/app/src/debug/res/values/strings.xml b/app/src/debug/res/values/strings.xml
index e652d944..1415dbd3 100644
--- a/app/src/debug/res/values/strings.xml
+++ b/app/src/debug/res/values/strings.xml
@@ -1,4 +1,4 @@
- OpenToday (Debug)
+ OpenToday
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ed473a47..efae0b04 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -40,6 +40,7 @@
android:name="com.fazziclay.opentoday.gui.activity.AlarmActivity"
android:showWhenLocked="true"
android:showOnLockScreen="true"
+ android:excludeFromRecents="true"
android:turnScreenOn="true"
android:exported="true"
tools:targetApi="o_mr1">
diff --git a/app/src/main/assets/CHANGELOG b/app/src/main/assets/CHANGELOG
index ebdabfc4..b9185384 100644
--- a/app/src/main/assets/CHANGELOG
+++ b/app/src/main/assets/CHANGELOG
@@ -1,17 +1,55 @@
-TODO: changelog
-== branch: item-sleepTime
-* Added new item: SleepTimeItem - automatically calculate sleep time
-* DATA_VERSIONS now is 11
-
-== branch: fixes-itemstoragedrawer
-* Keyboard now shows automatically in ItemTextEditorFragment
-* Fixes memory-leaks in ItemsEditorFragment if item instance of FilterItemGroup (related with edit-filter buttons)
-* Fixes memory-leaks in CycleListItem while rendering
-* ItemsStorage: added "getItemAt(int)" method.
-* Basic logic of "ItemsStorageDrawer" moved to new parent "AbstractItemsStorageDrawer"
-* Drag&Drop re-order now not resets while item updated.
-* Drag&Drop re-order(and maybe swipes...) now available in child items
-* Fixed DeleteItemsFragment: now all items un-minimized
+$[@bold;-#00FF00;S25]# Changelog v160 1.3 (2023.11.05)$[||]
+$[@bold;-#44dd44]Innovation:$[@reset;-reset]
+ * Notification can now come as an alarm clock (full screen)
+ * When creating an item, its default background color is random (configurable)
+ * The analog clock can be enabled in the settings
+ * Tags have been added to items, now you can label them! (not used anywhere yet)
+ * To date&time format added NO_TIME presets
+ * The text editor can now edit bold, italic, strikeout and font size
+ * Added icons
+ * If the item has notifications, it will have the corresponding icon on it
+
+$[@bold]Gui Improvements:$[@reset]
+ * Animations added
+ * Item text editor now automatically show keyboard
+ * After closing the toolbar, the focus is set to QuickNote
+ * When deleting, child elements are now counted
+ * An (+) button has been added to the list of tabs
+ * Item margins increased
+ * When the item is clamped inside the group, a specific item is now moved, and not the whole group
+ * Inside DeleteItemsFragment, now all items are rendered not minimized
+ * More material style
+ * Uses new icons
+ * The color selection button has been changed
+
+$[@bold]Code Improvements:$[@reset]
+ * SettingsManager rewritten
+ * Startup performance improved: uses multi-threaded loading (BackendInitializer.java)
+ * Added minimal plugins support
+ * Basic logic of "ItemsStorageDrawer" moved to new parent "AbstractItemsStorageDrawer"
+ * Drag&Drop re-order(and maybe swipes...) now available in child items
+ * Notifications can now have a custom icon and color
+ * ColorUtil.colorize now fast if received plain text
+
+$[@bold]Fixes:$[@reset]
+ * Fixes memory-leaks in ItemsEditorFragment if item instance of FilterItemGroup (related with edit-filter buttons)
+ * Fixes memory-leaks in CycleListItem while rendering
+ * [GUI] Drag&Drop re-order now not reset while item updated.
+ * [GUI] With a large update of Items Storage, ItemsStorageDrawer did not have time to process it and caused a crash.
+
+$[@bold]Other:$[@reset]
+ * DATA_VERSION is 12
+ * DataFixer 10->11: nothing; 11->12: fix settings
+ * Target to android 34
+ * Secret item: SleepTime - automatically counts sleep time (still in development)
+ * Secret item: MissingNo - it turns into an item, the import of which failed, it still contains the parent's information, and when re-importing the error will try to be eliminated.
+ * ItemsStorage: added "getItemAt(int)" method.
+ * ItemsStorage: added "totalCount()" method.
+ * [GUI] "main" instead of "RELEASE" is now default branch in AboutFragment
+ * Added profiler: in releases it disabled.
+
+
+
$[@bold;-#00FF00;S25]# Changelog v134 1.2 (2023.06.18)$[||]
Correct release for 1.1.4
diff --git a/app/src/main/assets/beautify_colors.txt b/app/src/main/assets/beautify_colors.txt
new file mode 100644
index 00000000..07afd1d4
--- /dev/null
+++ b/app/src/main/assets/beautify_colors.txt
@@ -0,0 +1,14 @@
+// default colors for OpenToday
+#ff0000;fully red
+#d19b29;оранжевый
+#808000;тёмно-ораньжевый
+#2adc0e;хакерский-зелёный
+#008000;тёмнозелёный
+#6bc6d1;голубой
+#008080;цвет блока гвардианов
+#e02271;малиновая лада
+#0c7a89;цвел блока гвардианов
+#6338d3;цвет фиолетово-курсовый
+#a290f7;светло фиолетовый-курсовый
+#7801d9;цвет курсы-фиолетово
+#ff00f0;sorry brother
\ No newline at end of file
diff --git a/app/src/main/assets/LICENSE_JavaNeoUtil b/app/src/main/assets/licenses/LICENSE_JavaNeoUtil
similarity index 100%
rename from app/src/main/assets/LICENSE_JavaNeoUtil
rename to app/src/main/assets/licenses/LICENSE_JavaNeoUtil
diff --git a/app/src/main/assets/LICENSE_NeoSocket b/app/src/main/assets/licenses/LICENSE_NeoSocket
similarity index 100%
rename from app/src/main/assets/LICENSE_NeoSocket
rename to app/src/main/assets/licenses/LICENSE_NeoSocket
diff --git a/app/src/main/assets/LICENSE_OpenToday b/app/src/main/assets/licenses/LICENSE_OpenToday
similarity index 100%
rename from app/src/main/assets/LICENSE_OpenToday
rename to app/src/main/assets/licenses/LICENSE_OpenToday
diff --git a/app/src/main/assets/LICENSE_OpenTodayTelemetry b/app/src/main/assets/licenses/LICENSE_OpenTodayTelemetry
similarity index 100%
rename from app/src/main/assets/LICENSE_OpenTodayTelemetry
rename to app/src/main/assets/licenses/LICENSE_OpenTodayTelemetry
diff --git a/app/src/main/assets/LICENSE_hsv-alpha-color-picker-android b/app/src/main/assets/licenses/LICENSE_hsv-alpha-color-picker-android
similarity index 100%
rename from app/src/main/assets/LICENSE_hsv-alpha-color-picker-android
rename to app/src/main/assets/licenses/LICENSE_hsv-alpha-color-picker-android
diff --git a/app/src/main/assets/licenses/LICENSE_simple-analog-clock b/app/src/main/assets/licenses/LICENSE_simple-analog-clock
new file mode 100644
index 00000000..7a4a3ea2
--- /dev/null
+++ b/app/src/main/assets/licenses/LICENSE_simple-analog-clock
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
\ No newline at end of file
diff --git a/app/src/main/java/com/fazziclay/opentoday/Build.java b/app/src/main/java/com/fazziclay/opentoday/Build.java
new file mode 100644
index 00000000..7b126214
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/Build.java
@@ -0,0 +1,72 @@
+package com.fazziclay.opentoday;
+
+import androidx.annotation.NonNull;
+
+import com.fazziclay.opentoday.app.CustomBuildConfig;
+import com.fazziclay.opentoday.app.FeatureFlag;
+
+import java.util.Arrays;
+
+// I im happy!
+public class Build {
+ // Setting this :)
+ public static final BuildDebugStatus DEBUG_STATUS = BuildDebugStatus.AUTOMATIC;
+ public static final BuildLogsStatus LOGS_STATUS = BuildLogsStatus.OFF;
+ public static final boolean IS_SECRET_SETTINGS_AVAILABLE = true;
+ public static final boolean IS_SHADOW_CUSTOM_BUILD_CONFIG = false; // normally is FALSE
+ public static final FeatureFlag[] INITIAL_FEATURE_FLAGS = {
+ //FeatureFlag.TOOLBAR_DEBUG,
+ //FeatureFlag.ITEM_SLEEP_TIME,
+ //FeatureFlag.ITEM_DEBUG_TICK_COUNTER,
+ //FeatureFlag.DISABLE_DEBUG_MODE_NOTIFICATION,
+ };
+ public static final boolean PROFILERS = false; // normally is FALSE (long uses profilers causes crashes)
+
+
+ // work code
+ public static boolean isDebug() {
+ return switch (DEBUG_STATUS) {
+ case TRUE -> true;
+ case FALSE -> false;
+ case AUTOMATIC -> CustomBuildConfig.DEBUG;
+ };
+ }
+
+ public static boolean isLogs() {
+ return LOGS_STATUS != BuildLogsStatus.OFF;
+ }
+
+ public static boolean isLogsSave() {
+ return LOGS_STATUS == BuildLogsStatus.ON_WITH_FILE;
+ }
+
+ public static boolean isSecretSettingAvailable() {
+ return IS_SECRET_SETTINGS_AVAILABLE;
+ }
+
+ @NonNull
+ public static String getBuildDebugReport() {
+ return "DebugStatus=" + DEBUG_STATUS +
+ "; LogsStatus=" + LOGS_STATUS +
+ "; SecretSettings=" + IS_SECRET_SETTINGS_AVAILABLE +
+ "; ShadowCustomBuildConfig=" + IS_SHADOW_CUSTOM_BUILD_CONFIG +
+ "; InitialFeatureFlags=" + Arrays.toString(INITIAL_FEATURE_FLAGS) +
+ "; Profilers=" + PROFILERS;
+ }
+
+ public static boolean isProfilersEnabled() {
+ return PROFILERS;
+ }
+
+ public enum BuildDebugStatus {
+ TRUE,
+ FALSE,
+ AUTOMATIC
+ }
+
+ public enum BuildLogsStatus {
+ OFF,
+ ON,
+ ON_WITH_FILE
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/Debug.java b/app/src/main/java/com/fazziclay/opentoday/Debug.java
index 5029b087..afdcd6b2 100644
--- a/app/src/main/java/com/fazziclay/opentoday/Debug.java
+++ b/app/src/main/java/com/fazziclay/opentoday/Debug.java
@@ -1,21 +1,34 @@
package com.fazziclay.opentoday;
+import android.app.Activity;
import android.os.Build;
import androidx.annotation.NonNull;
import com.fazziclay.opentoday.app.App;
+import com.fazziclay.opentoday.debug.TestItemViewGenerator;
/**
* Collect debug info and other debug constants
*/
public class Debug {
+ public static final boolean DEBUG_TICK_NOTIFICATION = App.debug(false);
+ public static final int DEBUG_MAIN_ACTIVITY_START_SLEEP = App.debug(false) ? 6000 : 0;
+ public static final int DEBUG_APP_START_SLEEP = App.debug(false) ? 8000 : 0;
+ public static Class extends Activity> DEBUG_MAIN_ACTIVITY = App.debug(false) ? TestItemViewGenerator.class : null;
+ public static final boolean DEBUG_TEST_EXCEPTION_ON_LAUNCH = false;
+ public static final boolean DEBUG_IMPORTANT_NOTIFICATIONS = App.debug(false);
+ public static final boolean DEBUG_ALWAYS_SHOW_UI_NOTIFICATIONS = App.debug(false);
+ public static final boolean DEBUG_LOG_ALL_IN_MAINACTIVITY = App.debug(false);
+ public static final boolean DEBUG_NETWORK_UTIL_SHADOWCONTENT = App.debug(false);
+
public static final boolean CUSTOM_ITEMSTABINCLUDE_BACKGROUND = App.debug(false);
public static final boolean CUSTOM_MAINACTIVITY_BACKGROUND = App.debug(false);
public static final boolean SHOW_PATH_TO_ITEM_ON_ITEMTEXT = App.debug(false);
public static final boolean SHOW_ID_ON_ITEMTEXT = App.debug(false);
public static final boolean SHOW_GEN_ID_ON_ITEMTEXT = App.debug(false);
- public static final boolean DESTROY_ANY_TEXTITEM_CHILD = App.debug(true);
+ public static final boolean DESTROY_ANY_TEXTITEM_CHILD = App.debug(false);
+ public static final boolean SHOW_DEBUG_MESSAGE_TOAST_IN_ITEMSTICKRECEIVER = App.debug(false);
public static final int DEF = -1;
@@ -42,13 +55,13 @@ public static String getDebugInfoText() {
androidReleaseOrCodename = "sdk DEBUG_MAIN_ACTIVITY = debug(false) ? TestItemViewGenerator.class : null;
- public static final boolean DEBUG_TEST_EXCEPTION_ON_LAUNCH = false;
- public static final boolean DEBUG_IMPORTANT_NOTIFICATIONS = debug(false);
- public static final boolean DEBUG_ALWAYS_SHOW_UI_NOTIFICATIONS = debug(false);
- public static final boolean DEBUG_LOG_ALL_IN_MAINACTIVITY = debug(false);
- public static final boolean DEBUG_NETWORK_UTIL_SHADOWCONTENT = debug(false);
+ public static final boolean DEBUG = com.fazziclay.opentoday.Build.isDebug();
+ public static final boolean LOG = com.fazziclay.opentoday.Build.isLogs();
+ public static final boolean LOGS_SAVE = com.fazziclay.opentoday.Build.isLogsSave();
+ public static final boolean SECRET_SETTINGS_AVAILABLE = com.fazziclay.opentoday.Build.isSecretSettingAvailable();
public static boolean debug(boolean b) {
return (DEBUG && b);
@@ -115,18 +110,15 @@ public static App get() {
private final OptionalField colorHistoryManager = new OptionalField<>(() -> new ColorHistoryManager(new File(getExternalFilesDir(""), "color_history.json"), 10));
private final OptionalField pinCodeManager = new OptionalField<>(() -> new PinCodeManager(this));
private final OptionalField selectionManager = new OptionalField<>(SelectionManager::new);
- private final OptionalField telemetry = new OptionalField<>(() -> new Telemetry(this, getSettingsManager().isTelemetry()));
+ private final OptionalField telemetry = new OptionalField<>(() -> new Telemetry(this, SettingsManager.IS_TELEMETRY.get(getSettingsManager())));
private final OptionalField tickThread = new OptionalField<>(this::preCheckTickThread, TickThread::requestTerminate, this::validateTickThread);
private final OptionalField translation = new OptionalField<>(() -> new TranslationImpl(this::getString));
private final OptionalField> importantDebugCallbacks = new OptionalField<>(CallbackStorage::new);
- private final List featureFlags = new ArrayList<>(App.DEBUG ? Arrays.asList(
- FeatureFlag.ITEM_DEBUG_TICK_COUNTER,
- //FeatureFlag.ALWAYS_SHOW_SAVE_STATUS,
- //FeatureFlag.DISABLE_AUTOMATIC_TICK,
- FeatureFlag.DISABLE_DEBUG_MODE_NOTIFICATION,
- FeatureFlag.TOOLBAR_DEBUG
- ) : Collections.emptyList());
+ private final OptionalField beautifyColorManager = new OptionalField<>(() -> new BeautifyColorManager(this));
+ private final OptionalField itemNotificationHandler = new OptionalField<>(() -> new ItemNotificationHandler(this, this));
+ private final List featureFlags = new ArrayList<>(Arrays.asList(com.fazziclay.opentoday.Build.INITIAL_FEATURE_FLAGS));
private long appStartupTime = 0;
+ private boolean pluginsInitialized = false;
/**
* OPENTODAY APPLICATION INITIALIZE
@@ -144,8 +136,11 @@ public void onCreate() {
super.onCreate();
instance = this;
setupCrashReporter();
- DebugUtil.sleep(DEBUG_APP_START_SLEEP);
+ DebugUtil.sleep(Debug.DEBUG_APP_START_SLEEP);
CrashReportContext.BACK.push("App onCreate");
+ if (DEBUG) {
+ StrictMode.enableDefaults();
+ }
logsFile = new File(getExternalCacheDir(), "latest.log");
final FixResult fixResult = Logger.dur("App", "[DataFixer] fixToCurrentVersion", () -> getDataFixer().fixToCurrentVersion());
@@ -169,13 +164,7 @@ public void onLowMemory() {
Logger.i("App", "onLowMemory.");
openSourceLicenses.free();
dataFixer.free();
- tabsManager.free();
- settingsManager.free();
- colorHistoryManager.free();
pinCodeManager.free();
- selectionManager.free();
- telemetry.free();
- tickThread.free();
Debug.free();
TimeUtil.free();
@@ -196,15 +185,27 @@ public void onTrimMemory(int level) {
if (level >= TRIM_MEMORY_RUNNING_LOW) {
openSourceLicenses.free();
dataFixer.free();
- colorHistoryManager.free();
- //telemetry.free();
pinCodeManager.free();
Debug.free();
- TimeUtil.free();
- RandomUtil.free();
}
}
+ public static Profiler createProfiler(@NotNull String name) {
+ return com.fazziclay.opentoday.Build.isProfilersEnabled() ? addProfiler(new ProfilerImpl(name)) : Profiler.EMPTY;
+ }
+
+ public static ProfilerImpl addProfiler(ProfilerImpl profiler) {
+ if (ProfilerImpl.PROFILERS == null) {
+ ProfilerImpl.PROFILERS = new ArrayList<>();
+ }
+ ProfilerImpl.PROFILERS.add(profiler);
+ return profiler;
+ }
+
+ public List getProfilers() {
+ return ProfilerImpl.PROFILERS;
+ }
+
public boolean isPinCodeNeed() {
return this.getPinCodeManager().isPinCodeSet();
}
@@ -229,7 +230,60 @@ public int getPinCodeLength() {
private void registryNotificationsChannels() {
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(new NotificationChannel(NOTIFICATION_QUCIKNOTE_CHANNEL, getString(R.string.notificationChannel_quickNote_title), NotificationManager.IMPORTANCE_HIGH));
- notificationManager.createNotificationChannel(new NotificationChannel(NOTIFICATION_ITEMS_CHANNEL, getString(R.string.notificationChannel_items_title), NotificationManager.IMPORTANCE_HIGH));
+ notificationManager.createNotificationChannel(new NotificationChannel(NOTIFICATION_ITEMS_CHANNEL, getString(R.string.notificationChannel_items_title), NotificationManager.IMPORTANCE_MAX));
+ }
+
+ public void tryInitPlugins() {
+ IPROF.push("reinitPlugins");
+ CrashReportContext.BACK.push("App::reinitPlugins");
+ if (!pluginsInitialized) {
+ CrashReportContext.BACK.push("disabling all...");
+ PluginManager.disableAllPlugins();
+ for (final String shortName : getSettingsManager().getPlugins().split(",")) {
+ CrashReportContext.BACK.swap("plugin: " + shortName.trim());
+
+ PluginsRegistry.PluginInfo pluginInfo = PluginsRegistry.REGISTRY.getByShortName(shortName);
+ try {
+ initPlugin(pluginInfo, 0);
+
+ } catch (Exception e) {
+ Logger.e("App", "failed init plugin: " + shortName, e);
+ }
+ }
+ pluginsInitialized = true;
+ CrashReportContext.BACK.pop();
+ }
+ CrashReportContext.BACK.pop();
+ IPROF.pop();
+ }
+
+ public void initPlugin(PluginsRegistry.PluginInfo pluginInfo, int i) throws Exception {
+ if (pluginInfo == null) {
+ throw new NullPointerException("pluginInfo is null");
+ }
+
+ if (PluginManager.isPluginActive(pluginInfo.getPackageId())) {
+ Logger.w("App:initPlugins", "plugin " + pluginInfo.getShortName() + " already active...");
+ return;
+ }
+
+ if (i > 10) {
+ Logger.w("App:initPlugins", "i > 10...");
+ return;
+ }
+
+ for (final String depend : pluginInfo.getDepends()) {
+ initPlugin(PluginsRegistry.REGISTRY.getByShortName(depend), i + 1);
+ }
+
+ PluginManager.loadPlugin(
+ pluginInfo.getPackageId(),
+ pluginInfo.getClazz().getConstructor().newInstance());
+ }
+
+ public void initPlugins() {
+ pluginsInitialized = false;
+ tryInitPlugins();
}
/**
@@ -291,11 +345,12 @@ private void updateVersionFile() {
private License[] createOpenSourceLicensesArray() {
// TODO: 19.10.2022 add v prefix to version to telemetry
return new License[]{
- new License("LICENSE_OpenToday", "OpenToday (this app)", "fazziclay@gmail.com\nhttps://fazziclay.github.io/opentoday"),
- new License("LICENSE_hsv-alpha-color-picker-android", "hsv-alpha-color-picker-android", "https://github.com/martin-stone/hsv-alpha-color-picker-android"),
- new License("LICENSE_JavaNeoUtil", "JavaNeoUtil v" + JavaNeoUtil.VERSION_NAME, "https://github.com/fazziclay/javaneoutil"),
- new License("LICENSE_NeoSocket", "NeoSocket v" + NeoSocket.VERSION_NAME, "https://github.com/fazziclay/neosocket"),
- new License("LICENSE_OpenTodayTelemetry", "OpenTodayTelemetry " + OpenTodayTelemetry.VERSION_NAME, getString(R.string.openSourceLicenses_telemetry_warn) + "\nhttps://github.com/fazziclay/opentodaytelemetry"),
+ new License("licenses/LICENSE_OpenToday", "OpenToday (this app)", "fazziclay@gmail.com\nhttps://fazziclay.github.io/opentoday"),
+ new License("licenses/LICENSE_hsv-alpha-color-picker-android", "hsv-alpha-color-picker-android", "https://github.com/martin-stone/hsv-alpha-color-picker-android"),
+ new License("licenses/LICENSE_JavaNeoUtil", "JavaNeoUtil v" + JavaNeoUtil.VERSION_NAME, "https://github.com/fazziclay/javaneoutil"),
+ new License("licenses/LICENSE_NeoSocket", "NeoSocket v" + NeoSocket.VERSION_NAME, "https://github.com/fazziclay/neosocket"),
+ new License("licenses/LICENSE_OpenTodayTelemetry", "OpenTodayTelemetry " + OpenTodayTelemetry.VERSION_NAME, getString(R.string.openSourceLicenses_telemetry_warn) + "\nhttps://github.com/fazziclay/opentodaytelemetry"),
+ new License("licenses/LICENSE_simple-analog-clock", "simple-analog-clock", "Analog clock\nhttps://github.com/leondzn/simple-analog-clock")
};
}
@@ -313,7 +368,7 @@ public static void exception(Context context, Exception exception) {
App.crash(context, CrashReport.create(exception), false);
}
- private static void crash(@Nullable Context context, @NotNull final CrashReport crashReport, boolean fatal) {
+ public static void crash(@Nullable Context context, @NotNull final CrashReport crashReport, boolean fatal) {
if (context == null) context = App.get();
crashReport.setFatal(CrashReport.FatalEnum.fromBoolean(fatal));
@@ -494,7 +549,15 @@ public ItemsRoot getItemsRoot() {
return getTabsManager();
}
+ public BeautifyColorManager getBeautifyColorManager() {
+ return beautifyColorManager.get();
+ }
+
public StringBuilder getLogs() {
return logs;
}
+
+ public ItemNotificationHandler getItemNotificationHandler() {
+ return itemNotificationHandler.get();
+ }
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/BeautifyColorManager.java b/app/src/main/java/com/fazziclay/opentoday/app/BeautifyColorManager.java
new file mode 100644
index 00000000..13b2dcac
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/BeautifyColorManager.java
@@ -0,0 +1,48 @@
+package com.fazziclay.opentoday.app;
+
+import android.content.Context;
+import android.graphics.Color;
+
+import com.fazziclay.opentoday.util.RandomUtil;
+import com.fazziclay.opentoday.util.StreamUtil;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class BeautifyColorManager {
+ private final Context context;
+ private final List colors = new ArrayList<>();
+
+ public BeautifyColorManager(Context context) {
+ this.context = context;
+ load();
+ }
+
+ public static int randomBackgroundColor(Context context) {
+ return App.get(context).getBeautifyColorManager().randomBackgroundColor();
+ }
+
+ public int randomBackgroundColor() {
+ if (colors.isEmpty()) {
+ return RandomUtil.nextInt();
+ }
+
+ int i = RandomUtil.nextInt(colors.size());
+ return colors.get(i);
+ }
+
+ private void load() {
+ try {
+ for (String s : StreamUtil.read(context.getAssets().open("beautify_colors.txt")).split("\n")) {
+ if (s.startsWith("//")) continue;
+ s = s.split(";")[0];
+ try {
+ colors.add(Color.parseColor(s));
+ } catch (Exception ignored) {}
+ }
+ } catch (IOException e) {
+ App.exception(App.get(), e);
+ }
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/CrashReport.java b/app/src/main/java/com/fazziclay/opentoday/app/CrashReport.java
index 0a720110..4c145280 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/CrashReport.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/CrashReport.java
@@ -74,7 +74,7 @@ public String convertToText() {
* DATA_VERSION: %_APPLICATION_DATA_VERSION_%
* RELEASE_TIME: %_APPLICATION_VERSION_RELEASE_TIME_%
* version-data: %_VERSION_DATA_%
- * SHADOW_RELEASE: %_SHADOW_RELEASE_%
+ * build-report: %_BUILD_REPORT_%
* DEBUG: %_APPLICATION_DEBUG_%
* DEBUG_TICK_NOTIFICATION: %_APPLICATION_DEBUG_TICK_NOTIFICATION_%
* DEBUG_MAIN_ACTIVITY_START_SLEEP: %_APPLICATION_DEBUG_MAIN_ACTIVITY_START_SLEEP_%
@@ -156,11 +156,11 @@ public String convertToText() {
text = text.replace("%_APPLICATION_DATA_VERSION_%", getText(App.APPLICATION_DATA_VERSION));
text = text.replace("%_VERSION_DATA_%", getText(() -> App.get().versionDataPutLatestStart(App.get().getVersionData()).toString()));
text = text.replace("%_APPLICATION_DEBUG_%", getText(App.DEBUG));
- text = text.replace("%_APPLICATION_DEBUG_TICK_NOTIFICATION_%", getText(App.DEBUG_TICK_NOTIFICATION));
- text = text.replace("%_APPLICATION_DEBUG_MAIN_ACTIVITY_START_SLEEP_%", getText(App.DEBUG_MAIN_ACTIVITY_START_SLEEP));
- text = text.replace("%_APPLICATION_DEBUG_APP_START_SLEEP_%", getText(App.DEBUG_APP_START_SLEEP));
- text = text.replace("%_APPLICATION_DEBUG_MAIN_ACTIVITY_%", getText(App.DEBUG_MAIN_ACTIVITY));
- text = text.replace("%_DEBUG_TEST_EXCEPTION_ON_LAUNCH_%", getText(App.DEBUG_TEST_EXCEPTION_ON_LAUNCH));
+ text = text.replace("%_APPLICATION_DEBUG_TICK_NOTIFICATION_%", getText(Debug.DEBUG_TICK_NOTIFICATION));
+ text = text.replace("%_APPLICATION_DEBUG_MAIN_ACTIVITY_START_SLEEP_%", getText(Debug.DEBUG_MAIN_ACTIVITY_START_SLEEP));
+ text = text.replace("%_APPLICATION_DEBUG_APP_START_SLEEP_%", getText(Debug.DEBUG_APP_START_SLEEP));
+ text = text.replace("%_APPLICATION_DEBUG_MAIN_ACTIVITY_%", getText(Debug.DEBUG_MAIN_ACTIVITY));
+ text = text.replace("%_DEBUG_TEST_EXCEPTION_ON_LAUNCH_%", getText(Debug.DEBUG_TEST_EXCEPTION_ON_LAUNCH));
text = text.replace("%_TIME_FORMATTED_%", getText(() -> {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss SSS", Locale.ENGLISH);
return dateFormat.format(new Date(this.crashTimeMillis));
@@ -188,7 +188,7 @@ public String convertToText() {
text = text.replace("%_DEVICE_DISPLAY_%", getText(Build.DISPLAY));
text = text.replace("%_DEVICE_BOOTLOADER_%", getText(() -> Build.BOOTLOADER));
text = text.replace("%_L_LOGS_%", getText(() -> startAllLines("| ", App.get().getLogs().toString())));
- text = text.replace("%_SHADOW_RELEASE_%", getText(() -> !App.SHADOW_RELEASE ? "false" : "WARNING! SHADOW RELEASE IS TRUE (ENABLED)"));
+ text = text.replace("%_BUILD_REPORT_%", getText(com.fazziclay.opentoday.Build::getBuildDebugReport));
return text;
}
@@ -277,7 +277,16 @@ private String generateRandomComment() {
"MathGame added in 1.1.4",
"CrashReportContext added in 1.1.4",
"Summer love OpenToday developing.. :cry:",
- "Stretchly, thanks!"
+ "Stretchly, thanks!",
+
+ // 2023.10.22 (15:33 UTC)
+ "{no-fun}Celeste - Lena Raine",
+ "{no-fun}but, C418 - Excursions",
+ "{no-fun}r2I4I",
+ "{no-fun}r5T",
+ "{no-fun}r1N",
+ "{no-fun}r7[SPACE]",
+ "This is only tags hehe",
};
Random random = new Random();
int max = comments.length;
@@ -298,6 +307,13 @@ private String generateRandomComment() {
}
}
+ if (result.startsWith("{no-fun}")) {
+ return (random.nextInt(1000) == 753 ? "oOOoOOoOOoOOo 1000 == 753, AND " : "")+result
+ .replace("{no-fun}", "")
+ .replace(":)", ":(")
+ .replace(":/", ":(");
+ }
+
if (random.nextInt(1000) == 753) {
return "OooOOooOOOOOooo 1000 == 753";
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/CrashReportContext.java b/app/src/main/java/com/fazziclay/opentoday/app/CrashReportContext.java
index 9f27b99e..73c6f41a 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/CrashReportContext.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/CrashReportContext.java
@@ -76,5 +76,10 @@ public void push(String s) {
public void pop() {
stack.pop();
}
+
+ public void swap(String s) {
+ pop();
+ push(s);
+ }
}
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/CustomBuildConfig.java b/app/src/main/java/com/fazziclay/opentoday/app/CustomBuildConfig.java
index af3505e5..a3361e4c 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/CustomBuildConfig.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/CustomBuildConfig.java
@@ -1,9 +1,10 @@
package com.fazziclay.opentoday.app;
+import com.fazziclay.opentoday.Build;
import com.fazziclay.opentoday.BuildConfig;
public class CustomBuildConfig {
- public static final boolean SHADOW_BUILD_CONFIG = false;
+ public static final boolean SHADOW_BUILD_CONFIG = Build.IS_SHADOW_CUSTOM_BUILD_CONFIG;
public static final String VERSION_NAME;
public static final int VERSION_CODE;
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/ItemNotificationHandler.java b/app/src/main/java/com/fazziclay/opentoday/app/ItemNotificationHandler.java
new file mode 100644
index 00000000..215ff313
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/ItemNotificationHandler.java
@@ -0,0 +1,129 @@
+package com.fazziclay.opentoday.app;
+
+import android.app.AlarmManager;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.os.Build;
+
+import androidx.core.app.NotificationCompat;
+
+import com.fazziclay.opentoday.app.items.item.Item;
+import com.fazziclay.opentoday.app.items.notification.DayItemNotification;
+import com.fazziclay.opentoday.app.items.notification.ItemNotification;
+import com.fazziclay.opentoday.app.items.tick.ItemsTickReceiver;
+import com.fazziclay.opentoday.gui.activity.AlarmActivity;
+import com.fazziclay.opentoday.util.ColorUtil;
+import com.fazziclay.opentoday.util.Logger;
+import com.fazziclay.opentoday.util.RandomUtil;
+import com.fazziclay.opentoday.util.time.TimeUtil;
+
+import java.util.HashMap;
+
+public class ItemNotificationHandler {
+ private static final String TAG = "ItemNotificationHandler";
+ private static boolean exceptionOnce = true;
+
+ private final Context context;
+ private final App app;
+
+ private final HashMap cachedAlarms = new HashMap<>();
+
+ public ItemNotificationHandler(Context context, App app) {
+ this.context = context;
+ this.app = app;
+ }
+
+ public void setAlarm(ItemNotification itemNotification, long triggerAtMs) {
+ if (!itemNotification.isAttached()) {
+ throw new IllegalArgumentException("setAlarm required attached ItemNotification for working...");
+ }
+ int requestId = itemNotification.getId().hashCode();
+
+ boolean isCached = isCachedAlarm(requestId, triggerAtMs);
+ if (isCached) {
+ return;
+ }
+
+ int flags = PendingIntent.FLAG_UPDATE_CURRENT;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ flags = flags | PendingIntent.FLAG_IMMUTABLE;
+ }
+
+ try {
+ var intent = ItemsTickReceiver.createNotificationTriggerIntent(context, itemNotification);
+ var pendingIntent = PendingIntent.getBroadcast(context,
+ requestId,
+ intent,
+ flags);
+
+ final AlarmManager alarmManager = context.getSystemService(AlarmManager.class);
+ // owoo
+ {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ if (alarmManager.canScheduleExactAlarms()) {
+ alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMs, pendingIntent);
+
+ } else {
+ Logger.w(TAG, "alarm canScheduleExactAlarms=false. for " + itemNotification + " to " + triggerAtMs + "unix-ms: " + TimeUtil.getDebugDate(triggerAtMs));
+ return;
+ }
+ } else {
+ alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMs, pendingIntent);
+ }
+ }
+ cachedAlarms.put(requestId, triggerAtMs);
+ Logger.d(TAG, "alarm set for " + itemNotification + " to " + triggerAtMs + "unix-ms: " + TimeUtil.getDebugDate(triggerAtMs));
+
+ } catch (Exception e) {
+ if (exceptionOnce) {
+ App.exception(null, e);
+ exceptionOnce = false;
+ }
+ }
+ }
+
+ private boolean isCachedAlarm(int requestId, long triggerAtMs) {
+ if (cachedAlarms.containsKey(requestId)) {
+ return cachedAlarms.get(requestId) == triggerAtMs;
+ }
+ return false;
+ }
+
+ public void handle(Item item, ItemNotification notification) {
+ if (notification instanceof DayItemNotification dayItemNotification) {
+ final String nTitle = dayItemNotification.isNotifyTitleFromItemText() ? (item.isParagraphColorize() ? ColorUtil.colorizeToPlain(item.getText()) : item.getText()) : dayItemNotification.getNotifyTitle();
+ final String nText = dayItemNotification.isNotifyTextFromItemText() ? (item.isParagraphColorize() ? ColorUtil.colorizeToPlain(item.getText()) : item.getText()) : dayItemNotification.getNotifyText();
+
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(context, App.NOTIFICATION_ITEMS_CHANNEL)
+ .setSmallIcon(dayItemNotification.getIcon().getResId())
+ .setContentTitle(nTitle)
+ .setContentText(nText)
+ .setSubText(dayItemNotification.getNotifySubText())
+ .setPriority(NotificationCompat.PRIORITY_MAX);
+
+ if (notification.getColor() != ItemNotification.DEFAULT_COLOR) {
+ builder.setColor(notification.getColor());
+ }
+
+ if (dayItemNotification.isFullScreen()) {
+ PendingIntent pending = PendingIntent.getActivity(context,
+ RandomUtil.nextInt(),
+ AlarmActivity.createIntent(context,
+ item.getId(),
+ dayItemNotification.isPreRenderPreviewMode(),
+ nTitle,
+ dayItemNotification.isSound(),
+ dayItemNotification.getNotificationId()),
+ PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
+ builder.setFullScreenIntent(pending, true);
+ builder.setCategory(NotificationCompat.CATEGORY_ALARM);
+ }
+ builder.setUsesChronometer(true);
+ NotificationManager systemService = context.getSystemService(NotificationManager.class);
+ if (systemService.areNotificationsEnabled()) {
+ systemService.notify(dayItemNotification.getNotificationId(), builder.build());
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/OptionalField.java b/app/src/main/java/com/fazziclay/opentoday/app/OptionalField.java
index d165851e..72c081a9 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/OptionalField.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/OptionalField.java
@@ -2,9 +2,13 @@
import androidx.annotation.NonNull;
+import com.fazziclay.opentoday.util.profiler.Profiler;
+
import org.jetbrains.annotations.NotNull;
public class OptionalField {
+ private static final Profiler PROFILER = App.createProfiler("OptionalField");
+
private final InitSupplier supplier;
private final FreeRunnable freeRunnable;
private final Validator validator;
@@ -38,12 +42,18 @@ public OptionalField(final InitSupplier supplier, final FreeRunnable freeR
@NonNull
@NotNull
public T get() {
+ PROFILER.push("get");
if (value == null) {
+ PROFILER.push("supplier");
value = supplier.supplier();
+ PROFILER.pop();
}
if (validator != null) {
+ PROFILER.push("validate");
value = validator.validate(value);
+ PROFILER.pop();
}
+ PROFILER.pop();
return value;
}
@@ -52,10 +62,12 @@ public boolean isSet() {
}
public void free() {
+ PROFILER.push("free");
if (isSet()) {
if (freeRunnable != null) freeRunnable.preFree(value);
}
value = null;
+ PROFILER.pop();
}
public interface InitSupplier {
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/Registry.kt b/app/src/main/java/com/fazziclay/opentoday/app/Registry.kt
index 99f04ce7..15da5fd0 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/Registry.kt
+++ b/app/src/main/java/com/fazziclay/opentoday/app/Registry.kt
@@ -1,6 +1,7 @@
package com.fazziclay.opentoday.app
import com.fazziclay.neosocket.packet.PacketsRegistry
+import com.fazziclay.opentoday.app.icons.IconsRegistry
import com.fazziclay.opentoday.app.items.item.ItemsRegistry
import com.fazziclay.opentoday.app.items.item.filter.FiltersRegistry
import com.fazziclay.opentoday.app.items.notification.ItemNotificationsRegistry
@@ -12,4 +13,5 @@ val TABS: TabsRegistry = TabsRegistry.REGISTRY
val ITEM_NOTIFICATIONS: ItemNotificationsRegistry = ItemNotificationsRegistry.REGISTRY
val TELEMETRY_PACKETS: PacketsRegistry = Telemetry.REGISTRY
val FILTERS: FiltersRegistry = FiltersRegistry.REGISTRY
-val ENUMS : EnumsRegistry = EnumsRegistry
\ No newline at end of file
+val ENUMS: EnumsRegistry = EnumsRegistry
+val ICONS: IconsRegistry = IconsRegistry.REGISTRY
\ No newline at end of file
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/SettingsManager.java b/app/src/main/java/com/fazziclay/opentoday/app/SettingsManager.java
deleted file mode 100644
index eb69539d..00000000
--- a/app/src/main/java/com/fazziclay/opentoday/app/SettingsManager.java
+++ /dev/null
@@ -1,285 +0,0 @@
-package com.fazziclay.opentoday.app;
-
-import androidx.appcompat.app.AppCompatDelegate;
-
-import com.fazziclay.javaneoutil.FileUtil;
-import com.fazziclay.opentoday.app.items.item.ItemsRegistry;
-import com.fazziclay.opentoday.app.items.item.TextItem;
-import com.fazziclay.opentoday.util.Logger;
-import com.fazziclay.opentoday.util.annotation.Getter;
-import com.fazziclay.opentoday.util.annotation.Setter;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.io.File;
-import java.util.Calendar;
-import java.util.UUID;
-
-public class SettingsManager {
- private static final String TAG = "SettingsManager";
- // Theme
- private static final String KEY_THEME = "theme";
- private static final String THEME_SYSTEM = "system";
- private static final String THEME_NIGHT = "night";
- private static final String THEME_LIGHT = "light";
-
- // First day of week
- private static final String KEY_FIRST_DAY_OF_WEEK = "firstDayOfWeek";
- private static final String FIRST_DAY_OF_WEEK_SATURDAY = "saturday";
- private static final String FIRST_DAY_OF_WEEK_MONDAY = "monday";
-
- private static final String KEY_QUICK_NOTE_NOTIFICATION = "quickNote"; // TODO: 14.10.2022 rename & add to DataFixer
- private static final String KEY_PARSETIMEFROMQUICKNOTE = "parseTimeFromQuickNote"; // TODO: 14.10.2022 add to datafixer
- private static final String KEY_ISMINIMIZEGRAYCOLOR = "isMinimizeGrayColor"; // TODO: 14.10.2022 add to datafixer
- private static final String KEY_TRIMITEMNAMESONEDIT = "trimItemNamesOnEdit";
-
- // local
- private final File saveFile;
-
- private int firstDayOfWeek = Calendar.SUNDAY;
- private int theme = AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM;
- private boolean quickNoteNotification = true;
- private boolean parseTimeFromQuickNote = true;
- private boolean isMinimizeGrayColor = false;
- private boolean trimItemNamesOnEdit = true;
- private ItemAction itemOnClickAction = ItemAction.OPEN_EDITOR;
- private ItemAction itemOnLeftAction = ItemAction.MINIMIZE_REVERT;
- private UUID quickNoteNotificationItemsStorageId = null;
- private boolean isTelemetry = true;
- private ItemsRegistry.ItemInfo defaultQuickNoteType = ItemsRegistry.REGISTRY.get(TextItem.class);
- private FirstTab firstTab = FirstTab.TAB_ON_CLOSING;
- private String datePattern = "yyyy.MM.dd EE";
- private String timePattern = "HH:mm:ss";
- private ItemAddPosition itemAddPosition = ItemAddPosition.BOTTOM;
- private boolean confirmFastChanges = true;
- private boolean isAutoCloseToolbar = true;
- private boolean isScrollToAddedItem = true;
- private boolean isItemEditorBackgroundFromItem = false;
-
-
- public SettingsManager(File saveFile) {
- this.saveFile = saveFile;
- load();
- }
-
- @Getter public int getFirstDayOfWeek() { return firstDayOfWeek; }
- @Setter public void setFirstDayOfWeek(int firstDayOfWeek) { this.firstDayOfWeek = firstDayOfWeek; }
- @Getter public int getTheme() { return theme; }
- @Setter public void setTheme(int theme) { this.theme = theme; }
- @Getter public boolean isQuickNoteNotification() { return quickNoteNotification; }
- @Setter public void setQuickNoteNotification(boolean quickNoteNotification) { this.quickNoteNotification = quickNoteNotification; }
- @Getter public boolean isMinimizeGrayColor() { return isMinimizeGrayColor; }
- @Setter public void setMinimizeGrayColor(boolean minimizeGrayColor) {isMinimizeGrayColor = minimizeGrayColor;}
- @Getter public boolean isParseTimeFromQuickNote() { return parseTimeFromQuickNote; }
- @Setter public void setParseTimeFromQuickNote(boolean parseTimeFromQuickNote) {this.parseTimeFromQuickNote = parseTimeFromQuickNote;}
- @Getter public boolean isTrimItemNamesOnEdit() {return trimItemNamesOnEdit;}
- @Setter public void setTrimItemNamesOnEdit(boolean trimItemNamesOnEdit) {this.trimItemNamesOnEdit = trimItemNamesOnEdit;}
- @Getter public ItemAction getItemOnClickAction() {return itemOnClickAction;}
- @Setter public void setItemOnClickAction(ItemAction itemOnClickAction) {this.itemOnClickAction = itemOnClickAction;}
- @Getter public ItemAction getItemOnLeftAction() {return itemOnLeftAction;}
- @Setter public void setItemOnLeftAction(ItemAction itemOnLeftAction) {this.itemOnLeftAction = itemOnLeftAction;}
- @Getter public UUID getQuickNoteNotificationItemsStorageId() {return quickNoteNotificationItemsStorageId;}
- @Setter public void setQuickNoteNotificationItemsStorageId(UUID quickNoteNotificationItemsStorageId) {this.quickNoteNotificationItemsStorageId = quickNoteNotificationItemsStorageId;}
- @Getter public boolean isTelemetry() {return isTelemetry;}
- @Setter public void setTelemetry(boolean b) {this.isTelemetry = b;}
- @Getter public ItemsRegistry.ItemInfo getDefaultQuickNoteType() {return defaultQuickNoteType;}
- @Setter public void setDefaultQuickNoteType(ItemsRegistry.ItemInfo defaultQuickNoteType) {this.defaultQuickNoteType = defaultQuickNoteType;}
- @Getter public FirstTab getFirstTab() {return firstTab;}
- @Setter public void setFirstTab(FirstTab firstTab) {this.firstTab = firstTab;}
- @Getter public String getDatePattern() {return datePattern;}
- @Setter public void setDatePattern(String datePattern) {this.datePattern = datePattern;}
- @Getter public String getTimePattern() {return timePattern;}
- @Setter public void setTimePattern(String timePattern) {this.timePattern = timePattern;}
- public void applyDateAndTimePreset(DateAndTimePreset p) {
- setDatePattern(p.getDate());
- setTimePattern(p.getTime());
- }
- @Setter public void setItemAddPosition(ItemAddPosition e) {this.itemAddPosition = e;}
- @Getter public ItemAddPosition getItemAddPosition() {return itemAddPosition;}
-
- @Getter public boolean isConfirmFastChanges() {return confirmFastChanges;}
- @Setter public void setConfirmFastChanges(boolean confirmFastChanges) {this.confirmFastChanges = confirmFastChanges;}
-
-
-
- public boolean isItemEditorBackgroundFromItem() {
- return isItemEditorBackgroundFromItem;
- }
-
- public boolean isScrollToAddedItem() {
- return isScrollToAddedItem;
- }
-
- public boolean isAutoCloseToolbar() {
- return isAutoCloseToolbar;
- }
-
- public void setAutoCloseToolbar(boolean autoCloseToolbar) {
- isAutoCloseToolbar = autoCloseToolbar;
- }
-
- public void setItemEditorBackgroundFromItem(boolean itemEditorBackgroundFromItem) {
- isItemEditorBackgroundFromItem = itemEditorBackgroundFromItem;
- }
-
- public void setScrollToAddedItem(boolean scrollToAddedItem) {
- isScrollToAddedItem = scrollToAddedItem;
- }
-
- private void load() {
- if (!FileUtil.isExist(saveFile)) {
- return;
- }
- try {
- JSONObject j = new JSONObject(FileUtil.getText(saveFile, "{}"));
- // first day of week
- String dayOfWeek = j.optString(KEY_FIRST_DAY_OF_WEEK, FIRST_DAY_OF_WEEK_SATURDAY);
- if (dayOfWeek.equalsIgnoreCase(FIRST_DAY_OF_WEEK_MONDAY)) {
- this.firstDayOfWeek = Calendar.MONDAY;
- } else {
- this.firstDayOfWeek = Calendar.SATURDAY;
- }
-
- // theme
- String them = j.optString(KEY_THEME, THEME_SYSTEM);
- if (them.equalsIgnoreCase(THEME_LIGHT)) {
- this.theme = AppCompatDelegate.MODE_NIGHT_NO;
- } else if (them.equalsIgnoreCase(THEME_NIGHT)) {
- this.theme = AppCompatDelegate.MODE_NIGHT_YES;
- } else {
- this.theme = AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM;
- }
-
- // Quick note and etc...
- this.quickNoteNotification = j.optBoolean(KEY_QUICK_NOTE_NOTIFICATION, this.quickNoteNotification);
- this.parseTimeFromQuickNote = j.optBoolean(KEY_PARSETIMEFROMQUICKNOTE, this.parseTimeFromQuickNote);
- this.isMinimizeGrayColor = j.optBoolean(KEY_ISMINIMIZEGRAYCOLOR, this.isMinimizeGrayColor);
- this.trimItemNamesOnEdit = j.optBoolean(KEY_TRIMITEMNAMESONEDIT, this.trimItemNamesOnEdit);
- try {
- this.itemOnClickAction = ItemAction.valueOf(j.optString("itemOnClickAction"));
- } catch (Exception ignored) {}
- try {
- this.itemOnLeftAction = ItemAction.valueOf(j.optString("itemOnLeftAction"));
- } catch (Exception ignored) {}
- try {
- this.quickNoteNotificationItemsStorageId = UUID.fromString(j.optString("quickNoteNotificationItemsStorageId"));
- } catch (Exception ignored) {}
- this.isTelemetry = j.optBoolean("isTelemetry", isTelemetry);
- try {
- this.defaultQuickNoteType = ItemsRegistry.REGISTRY.get(j.getString("defaultQuickNoteType"));
- } catch (Exception ignored) {}
-
- try {
- this.firstTab = FirstTab.valueOf(j.getString("firstTab"));
- } catch (Exception ignored) {}
- datePattern = j.optString("datePattern", datePattern);
- timePattern = j.optString("timePattern", timePattern);
-
- try {
- this.itemAddPosition = ItemAddPosition.valueOf(j.getString("itemAddPosition"));
- } catch (Exception ignored) {}
- this.confirmFastChanges = j.optBoolean("confirmFastChanges", this.confirmFastChanges);
- this.isAutoCloseToolbar = j.optBoolean("isAutoCloseToolbar", this.isAutoCloseToolbar);
- this.isScrollToAddedItem = j.optBoolean("isScrollToAddedItem", this.isScrollToAddedItem);
- this.isItemEditorBackgroundFromItem = j.optBoolean("isItemEditorBackgroundFromItem", this.isItemEditorBackgroundFromItem);
-
- } catch (Exception e) {
- Logger.e(TAG, "load", e);
- App.exception(null, e);
- }
- }
-
- public void save() {
- try {
- JSONObject j = exportJSONSettings();
- FileUtil.setText(saveFile, j.toString());
- } catch (Exception e) {
- Logger.e(TAG, "save", e);
- App.exception(null, e);
- }
- }
-
- public JSONObject exportJSONSettings() throws JSONException {
- JSONObject j = new JSONObject();
-
- String temp_firstDayOfWeek = this.firstDayOfWeek == Calendar.MONDAY ? FIRST_DAY_OF_WEEK_MONDAY : FIRST_DAY_OF_WEEK_SATURDAY;
- String temp_theme = THEME_SYSTEM;
- if (this.theme == AppCompatDelegate.MODE_NIGHT_YES) temp_theme = THEME_NIGHT;
- if (this.theme == AppCompatDelegate.MODE_NIGHT_NO) temp_theme = THEME_LIGHT;
-
- j.put(KEY_THEME, temp_theme);
- j.put(KEY_FIRST_DAY_OF_WEEK, temp_firstDayOfWeek);
- j.put(KEY_QUICK_NOTE_NOTIFICATION, this.quickNoteNotification);
- j.put(KEY_PARSETIMEFROMQUICKNOTE, this.parseTimeFromQuickNote);
- j.put(KEY_ISMINIMIZEGRAYCOLOR, this.isMinimizeGrayColor);
- j.put(KEY_TRIMITEMNAMESONEDIT, this.trimItemNamesOnEdit);
- j.put("itemOnClickAction", itemOnClickAction.name());
- j.put("itemOnLeftAction", itemOnLeftAction.name());
- j.put("quickNoteNotificationItemsStorageId", quickNoteNotificationItemsStorageId != null ? quickNoteNotificationItemsStorageId.toString() : null);
- j.put("isTelemetry", this.isTelemetry);
- j.put("defaultQuickNoteType", this.defaultQuickNoteType.getStringType());
- j.put("firstTab", this.firstTab.name());
- j.put("datePattern", this.datePattern);
- j.put("timePattern", this.timePattern);
- j.put("itemAddPosition", this.itemAddPosition.name());
- j.put("confirmFastChanges", this.confirmFastChanges);
- j.put("isAutoCloseToolbar", this.isAutoCloseToolbar);
- j.put("isScrollToAddedItem", this.isScrollToAddedItem);
- j.put("isItemEditorBackgroundFromItem", this.isItemEditorBackgroundFromItem);
- return j;
- }
-
- public void importData(JSONObject settings) {
- FileUtil.setText(saveFile, settings.toString());
- load();
- }
-
- public enum ItemAction {
- OPEN_EDITOR,
- OPEN_TEXT_EDITOR,
- SELECT_REVERT,
- SELECT_ON,
- SELECT_OFF,
- DELETE_REQUEST,
- MINIMIZE_REVERT,
- MINIMIZE_ON,
- MINIMIZE_OFF
- }
-
- public enum FirstTab {
- FIRST,
- TAB_ON_CLOSING
- }
-
- public enum DateAndTimePreset {
- DEFAULT("HH:mm:ss", "yyyy.MM.dd EE"),
- DEFAULT_FULLY_WEEKDAY("HH:mm:ss", "yyyy.MM.dd EEEE"),
- NO_SECONDS("HH:mm", "yyyy.MM.dd EE"),
- NO_SECONDS_FULLY_WEEKDAY("HH:mm", "yyyy.MM.dd EEEE"),
- INVERT_DATE("HH:mm:ss", "dd.MM.yyyy EE"),
- INVERT_DATE_FULLY_WEEKDAY("HH:mm:ss", "dd.MM.yyyy EEEE"),
- ;
-
- private final String time;
- private final String date;
-
- DateAndTimePreset(String time, String date) {
- this.time = time;
- this.date = date;
- }
-
- public String getTime() {
- return time;
- }
-
- public String getDate() {
- return date;
- }
- }
-
- public enum ItemAddPosition {
- TOP,
- BOTTOM
- }
-}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/Telemetry.java b/app/src/main/java/com/fazziclay/opentoday/app/Telemetry.java
index 3fb64247..6624a098 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/Telemetry.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/Telemetry.java
@@ -1,5 +1,7 @@
package com.fazziclay.opentoday.app;
+import static com.fazziclay.opentoday.util.InlineUtil.IPROF;
+
import androidx.annotation.NonNull;
import com.fazziclay.javaneoutil.FileUtil;
@@ -77,7 +79,11 @@ public void queryTelemetryStatus() {
}
public void send(LPacket lPacket) {
- if (!isEnabled) return;
+ IPROF.push("Telemetry:send");
+ if (!isEnabled) {
+ IPROF.pop();
+ return;
+ }
Logger.d(TAG, "send(): " + lPacket);
if (lPacket.isDelay() && !NO_DELAY) {
long last = getLastSend(lPacket.getClass().getName());
@@ -93,6 +99,7 @@ public void send(LPacket lPacket) {
int d2 = g.get(Calendar.DAY_OF_MONTH);
Logger.d(TAG, "send() d1=", d1, "d2=", d2 + " sanding-canceled: " + (d1 == d2));
if (d1 == d2) {
+ IPROF.pop();
return;
}
}
@@ -106,6 +113,7 @@ public void send(LPacket lPacket) {
}
Logger.d(TAG, "send(): wait: done");
setLastSend(lPacket.getClass().getName());
+ IPROF.pop();
}
@NonNull
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/UpdateChecker.java b/app/src/main/java/com/fazziclay/opentoday/app/UpdateChecker.java
index f2796679..0f02b27a 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/UpdateChecker.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/UpdateChecker.java
@@ -14,7 +14,7 @@ public class UpdateChecker {
private static final String V2_URL_LATEST_BUILD = "https://fazziclay.github.io/api/project_3/v2/latest_build";
private static final String V2_URL_LATEST = "https://fazziclay.github.io/api/project_3/v2/latest.json";
- private static final long CACHE_TIMEOUT_MILLIS = 5 * 60 * 60 * 1000; // 5 hours
+ private static final long CACHE_TIMEOUT_MILLIS = 48 * 60 * 60 * 1000; // 48 hours
private static final String TAG = "UpdateChecker";
public static void check(Context context, Result result) {
@@ -31,6 +31,7 @@ private static class UpdateCheckedThread extends Thread {
private final File cacheFile;
public UpdateCheckedThread(Context context, Result result) {
+ setName("UpdateCheckerThread");
this.result = result;
this.cacheFile = new File(context.getExternalCacheDir(), "latest_update_check");
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/data/Cherry.java b/app/src/main/java/com/fazziclay/opentoday/app/data/Cherry.java
index da615ce2..590d03f9 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/data/Cherry.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/data/Cherry.java
@@ -1,6 +1,7 @@
package com.fazziclay.opentoday.app.data;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import org.json.JSONArray;
import org.json.JSONObject;
@@ -202,6 +203,7 @@ public String toString() {
return "Cherry"+json.toString();
}
+ @Nullable
public String getString(String key) {
if (!has(key)) return null;
try {
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/data/CherryOrchard.java b/app/src/main/java/com/fazziclay/opentoday/app/data/CherryOrchard.java
index 0892ea7a..d9617c7a 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/data/CherryOrchard.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/data/CherryOrchard.java
@@ -131,6 +131,12 @@ public void forEachCherry(CherryProvider provider) {
}
}
+ public Cherry createAndAdd() {
+ Cherry cherry = new Cherry();
+ put(cherry);
+ return cherry;
+ }
+
public interface CherryProvider {
void provide(int index, Cherry cherry);
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/datafixer/DataFixer.java b/app/src/main/java/com/fazziclay/opentoday/app/datafixer/DataFixer.java
index dd61619b..edd43e7d 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/datafixer/DataFixer.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/datafixer/DataFixer.java
@@ -155,9 +155,116 @@ private int tryFix(int dataVersion) {
isUpdated = true;
}
+ if (dataVersion == 11) {
+ log("v11 -> v12", "Fixing settings");
+ fix11versionTo12();
+ dataVersion = 12;
+ isUpdated = true;
+ }
+
return dataVersion;
}
+ private void fix11versionTo12() {
+ final String TAG = "v11 -> v12";
+ // DO NOT EDIT
+ try {
+ File file = new File(context.getExternalFilesDir(""), "settings.json");
+ JSONObject old = new JSONObject(FileUtil.getText(file));
+ JSONObject nev = new JSONObject();
+
+ if (old.has("theme")) {
+ String val = old.getString("theme");
+ if (val.equals("night")) {
+ nev.put("theme", "NIGHT");
+ } else if (val.equals("light")) {
+ nev.put("theme", "LIGHT");
+ } else {
+ nev.put("theme", "AUTO");
+ }
+ }
+
+ if (old.has("firstDayOfWeek")) {
+ String val = old.getString("firstDayOfWeek");
+ if (val.equals("saturday")) {
+ nev.put("first_day_of_week", "SATURDAY");
+ } else if (val.equals("monday")) {
+ nev.put("first_day_of_week", "MONDAY");
+ }
+ }
+
+ if (old.has("quickNote")) {
+ nev.put("quick_note.notification.enable", old.getBoolean("quickNote"));
+ }
+
+ if (old.has("parseTimeFromQuickNote")) {
+ nev.put("quick_note.parse_time_from_item", old.getBoolean("parseTimeFromQuickNote"));
+ }
+
+ if (old.has("isMinimizeGrayColor")) {
+ nev.put("item.minimize.gray_color", old.getBoolean("isMinimizeGrayColor"));
+ }
+
+ if (old.has("trimItemNamesOnEdit")) {
+ nev.put("item.editor.trim_names", old.getBoolean("trimItemNamesOnEdit"));
+ }
+
+ if (old.has("itemOnClickAction")) {
+ nev.put("item.action.click", old.getString("itemOnClickAction"));
+ }
+
+ if (old.has("itemOnLeftAction")) {
+ nev.put("item.action.left_swipe", old.getString("itemOnLeftAction"));
+ }
+
+ if (old.has("isTelemetry")) {
+ nev.put("telemetry.enable", old.getBoolean("isTelemetry"));
+ }
+
+ if (old.has("defaultQuickNoteType")) {
+ String defaultQuickNoteType = old.getString("defaultQuickNoteType");
+ String c = switch (defaultQuickNoteType) {
+ case "CheckboxItem" -> "CHECKBOX";
+ case "GroupItem" -> "GROUP";
+ case "FilterGroupItem" -> "FILTER_GROUP";
+ case "LongTextItem" -> "LONG_TEXT";
+ case "DayRepeatableCheckboxItem" -> "CHECKBOX_DAY_REPEATABLE";
+ default -> "TEXT";
+ };
+ nev.put("quick_note.item_type", c);
+ }
+
+ if (old.has("firstTab")) {
+ nev.put("first_tab", old.getString("firstTab"));
+ }
+
+ if (old.has("itemAddPosition")) {
+ nev.put("item.add_position", old.getString("itemAddPosition"));
+ }
+
+ if (old.has("confirmFastChanges")) {
+ nev.put("fast_changes.confirm", old.getBoolean("confirmFastChanges"));
+ }
+
+ if (old.has("isAutoCloseToolbar")) {
+ nev.put("toolbar.auto_close", old.getBoolean("isAutoCloseToolbar"));
+ }
+
+ if (old.has("isScrollToAddedItem")) {
+ nev.put("item.is_scroll_to_added", old.getBoolean("isScrollToAddedItem"));
+ }
+
+ if (old.has("isItemEditorBackgroundFromItem")) {
+ nev.put("item.use_container_editor_background_from_item", old.getBoolean("isItemEditorBackgroundFromItem"));
+ }
+
+
+ FileUtil.setText(file, nev.toString());
+ } catch (Exception e) {
+ log(TAG, "exception: " + e);
+ }
+ }
+
private void fix8versionTo9() {
final String TAG = "v8 -> v9";
log(TAG, "FIX START");
@@ -378,6 +485,11 @@ public JSONArray fixItems(int from, JSONArray items) throws Exception {
from = 11;
}
+ if (from == 11) {
+ // nothing to fix
+ from = 12;
+ }
+
return result;
}
@@ -400,6 +512,11 @@ public JSONArray fixTabs(int from, JSONArray tabs) throws Exception {
// nothing to fix
from = 11;
}
+
+ if (from == 11) {
+ // nothing to fix
+ from = 12;
+ }
return result;
}
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/events/gui/CurrentItemsStorageContextChanged.java b/app/src/main/java/com/fazziclay/opentoday/app/events/gui/CurrentItemsStorageContextChanged.java
new file mode 100644
index 00000000..44e95954
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/events/gui/CurrentItemsStorageContextChanged.java
@@ -0,0 +1,16 @@
+package com.fazziclay.opentoday.app.events.gui;
+
+import com.fazziclay.opentoday.api.Event;
+import com.fazziclay.opentoday.app.items.ItemsStorage;
+
+public class CurrentItemsStorageContextChanged implements Event {
+ private final ItemsStorage currentItemsStorage;
+
+ public CurrentItemsStorageContextChanged(ItemsStorage currentItemsStorage) {
+ this.currentItemsStorage = currentItemsStorage;
+ }
+
+ public ItemsStorage getCurrentItemsStorage() {
+ return currentItemsStorage;
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/events/gui/toolbar/AppToolbarSelectionClickEvent.java b/app/src/main/java/com/fazziclay/opentoday/app/events/gui/toolbar/AppToolbarSelectionClickEvent.java
new file mode 100644
index 00000000..7f1f2c85
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/events/gui/toolbar/AppToolbarSelectionClickEvent.java
@@ -0,0 +1,31 @@
+package com.fazziclay.opentoday.app.events.gui.toolbar;
+
+import android.app.Activity;
+
+import com.fazziclay.opentoday.api.Event;
+import com.fazziclay.opentoday.app.items.selection.SelectionManager;
+import com.fazziclay.opentoday.databinding.ToolbarMoreSelectionBinding;
+
+public class AppToolbarSelectionClickEvent implements Event {
+ private final Activity activity;
+ private final com.fazziclay.opentoday.databinding.ToolbarMoreSelectionBinding localBinding;
+ private final SelectionManager selectionManager;
+
+ public AppToolbarSelectionClickEvent(Activity activity, ToolbarMoreSelectionBinding localBinding, SelectionManager selectionManager) {
+ this.activity = activity;
+ this.localBinding = localBinding;
+ this.selectionManager = selectionManager;
+ }
+
+ public Activity getActivity() {
+ return activity;
+ }
+
+ public SelectionManager getSelectionManager() {
+ return selectionManager;
+ }
+
+ public ToolbarMoreSelectionBinding getLocalBinding() {
+ return localBinding;
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/events/items/ItemsRootDestroyedEvent.java b/app/src/main/java/com/fazziclay/opentoday/app/events/items/ItemsRootDestroyedEvent.java
new file mode 100644
index 00000000..1bd147bd
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/events/items/ItemsRootDestroyedEvent.java
@@ -0,0 +1,16 @@
+package com.fazziclay.opentoday.app.events.items;
+
+import com.fazziclay.opentoday.api.Event;
+import com.fazziclay.opentoday.app.items.ItemsRoot;
+
+public class ItemsRootDestroyedEvent implements Event {
+ private final ItemsRoot itemsRoot;
+
+ public ItemsRootDestroyedEvent(ItemsRoot itemsRoot) {
+ this.itemsRoot = itemsRoot;
+ }
+
+ public ItemsRoot getItemsRoot() {
+ return itemsRoot;
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/events/items/ItemsRootInitializedEvent.java b/app/src/main/java/com/fazziclay/opentoday/app/events/items/ItemsRootInitializedEvent.java
new file mode 100644
index 00000000..48a255f1
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/events/items/ItemsRootInitializedEvent.java
@@ -0,0 +1,16 @@
+package com.fazziclay.opentoday.app.events.items;
+
+import com.fazziclay.opentoday.api.Event;
+import com.fazziclay.opentoday.app.items.ItemsRoot;
+
+public class ItemsRootInitializedEvent implements Event {
+ private final ItemsRoot itemsRoot;
+
+ public ItemsRootInitializedEvent(ItemsRoot itemsRoot) {
+ this.itemsRoot = itemsRoot;
+ }
+
+ public ItemsRoot getItemsRoot() {
+ return itemsRoot;
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/icons/IconsRegistry.java b/app/src/main/java/com/fazziclay/opentoday/app/icons/IconsRegistry.java
new file mode 100644
index 00000000..9ae71f4f
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/icons/IconsRegistry.java
@@ -0,0 +1,137 @@
+package com.fazziclay.opentoday.app.icons;
+
+import androidx.annotation.DrawableRes;
+
+import com.fazziclay.opentoday.R;
+import com.fazziclay.opentoday.util.Logger;
+import com.fazziclay.opentoday.util.RandomUtil;
+
+import java.util.Arrays;
+
+public class IconsRegistry {
+ private static final String TAG = "IconsRegistry";
+ public static final IconsRegistry REGISTRY = new IconsRegistry();
+
+ private final Icon[] ICONS = new Icon[]{
+ new Icon("opentoday", R.mipmap.ic_launcher),
+ new Icon("opentoday_beta", R.mipmap.ic_launcher_beta),
+ new Icon("none", R.drawable.close_24px), // special icon
+
+
+
+ new Icon("add", R.drawable.add_24px),
+ new Icon("aspect_ratio", R.drawable.aspect_ratio_24px),
+ new Icon("background_replace", R.drawable.background_replace_24px),
+ new Icon("barefoot", R.drawable.barefoot_24px),
+ new Icon("baseline_account_tree", R.drawable.baseline_account_tree_24),
+ new Icon("baseline_add_alert", R.drawable.baseline_add_alert_24),
+ new Icon("baseline_celebration", R.drawable.baseline_celebration_24),
+ new Icon("baseline_thumb_up", R.drawable.baseline_thumb_up_24),
+ new Icon("baseline_upcoming", R.drawable.baseline_upcoming_24),
+ new Icon("baseline_waves", R.drawable.baseline_waves_24),
+ new Icon("baseline_weekend", R.drawable.baseline_weekend_24),
+ new Icon("baseline_window", R.drawable.baseline_window_24),
+ new Icon("baseline_yard", R.drawable.baseline_yard_24),
+ new Icon("bed", R.drawable.bed_24px),
+ new Icon("bedtime", R.drawable.bedtime_24px),
+ new Icon("calendar_clock", R.drawable.calendar_clock_24px),
+ new Icon("calendar_today", R.drawable.calendar_today_24px),
+ new Icon("check_box_outline_blank", R.drawable.check_box_outline_blank_24px),
+ new Icon("close", R.drawable.close_24px),
+ new Icon("cloudy_snowing", R.drawable.cloudy_snowing_24px),
+ new Icon("content_copy", R.drawable.content_copy_24px),
+ new Icon("delete", R.drawable.delete_24px),
+ new Icon("edit", R.drawable.edit_24px),
+ new Icon("edit_note", R.drawable.edit_note_24px),
+ new Icon("emoji_flags", R.drawable.emoji_flags_24px),
+ new Icon("emoji_food_beverage", R.drawable.emoji_food_beverage_24px),
+ new Icon("emoji_objects", R.drawable.emoji_objects_24px),
+ new Icon("export_notes", R.drawable.export_notes_24px),
+ new Icon("face_2", R.drawable.face_2_24px),
+ new Icon("fluid", R.drawable.fluid_24px),
+ new Icon("format_bold", R.drawable.format_bold_24px),
+ new Icon("format_italic", R.drawable.format_italic_24px),
+ new Icon("format_size", R.drawable.format_size_24px),
+ new Icon("format_strikethrough", R.drawable.format_strikethrough_24px),
+ new Icon("gastroenterology", R.drawable.gastroenterology_24px),
+ new Icon("handyman", R.drawable.handyman_24px),
+ new Icon("home_health", R.drawable.home_health_24px),
+ new Icon("home_work", R.drawable.home_work_24px),
+ new Icon("info_i", R.drawable.info_i_24px),
+ new Icon("minimize", R.drawable.minimize_24px),
+ new Icon("new_label", R.drawable.new_label_24px),
+ new Icon("notifications", R.drawable.notifications_24px),
+ new Icon("opacity", R.drawable.opacity_24px),
+ new Icon("palette", R.drawable.palette_24px),
+ new Icon("pause_presentation", R.drawable.pause_presentation_24px),
+ new Icon("pill", R.drawable.pill_24px),
+ new Icon("procedure", R.drawable.procedure_24px),
+ new Icon("psychiatry", R.drawable.psychiatry_24px),
+ new Icon("recommend", R.drawable.recommend_24px),
+ new Icon("redeem", R.drawable.redeem_24px),
+ new Icon("repeat", R.drawable.repeat_24px),
+ new Icon("rocket", R.drawable.rocket_24px),
+ new Icon("rocket_launch", R.drawable.rocket_launch_24px),
+ new Icon("save", R.drawable.save_24px),
+ new Icon("select", R.drawable.select_24px),
+ new Icon("sentiment_stressed", R.drawable.sentiment_stressed_24px),
+ new Icon("sentiment_very_dissatisfied", R.drawable.sentiment_very_dissatisfied_24px),
+ new Icon("sentiment_worried", R.drawable.sentiment_worried_24px),
+ new Icon("shopping_basket", R.drawable.shopping_basket_24px),
+ new Icon("shopping_cart", R.drawable.shopping_cart_24px),
+ new Icon("store", R.drawable.store_24px),
+ new Icon("surgical", R.drawable.surgical_24px),
+ new Icon("swipe_left", R.drawable.swipe_left_24px),
+ new Icon("syringe", R.drawable.syringe_24px),
+ new Icon("taunt", R.drawable.taunt_24px),
+ new Icon("touch_app", R.drawable.touch_app_24px),
+ new Icon("tune", R.drawable.tune_24px),
+
+ };
+ public final Icon OPENTODAY = getById("opentoday");
+ public final Icon NONE = getById("none");
+
+ private IconsRegistry() {
+ }
+
+ public Icon randomIcon() {
+ return getIconsList()[RandomUtil.bounds(0, getIconsList().length)];
+ }
+
+
+ public class Icon {
+ private final String id;
+ private final int resId;
+
+ public Icon(String id, @DrawableRes int resId) {
+ this.id = id;
+ this.resId = resId;
+ }
+
+ @DrawableRes
+ public int getResId() {
+ return resId;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public boolean isNone() {
+ return this == NONE;
+ }
+ }
+
+ public Icon[] getIconsList() {
+ return ICONS.clone();
+ }
+
+ public Icon getById(String id) {
+ for (Icon icon : ICONS) {
+ if (icon.id.equalsIgnoreCase(id)) {
+ return icon;
+ }
+ }
+ return OPENTODAY;
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/ItemsStorage.java b/app/src/main/java/com/fazziclay/opentoday/app/items/ItemsStorage.java
index 2eeecfe8..7ae46eab 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/ItemsStorage.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/ItemsStorage.java
@@ -108,6 +108,12 @@ public interface ItemsStorage extends Tickable {
*/
int size();
+ /**
+ * get items count include children item
+ * @return count of total items
+ */
+ int totalSize();
+
/**
* Get OnItemStorageUpdate CallbackStorage
* @return callbackStorage
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/QuickNoteReceiver.java b/app/src/main/java/com/fazziclay/opentoday/app/items/QuickNoteReceiver.java
index 25d86b5c..746c1fac 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/QuickNoteReceiver.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/QuickNoteReceiver.java
@@ -12,10 +12,11 @@
import com.fazziclay.opentoday.R;
import com.fazziclay.opentoday.app.App;
-import com.fazziclay.opentoday.app.SettingsManager;
-import com.fazziclay.opentoday.app.items.item.TextItem;
+import com.fazziclay.opentoday.app.items.item.Item;
+import com.fazziclay.opentoday.app.settings.SettingsManager;
import com.fazziclay.opentoday.app.items.tab.TabsManager;
-import com.fazziclay.opentoday.gui.fragment.ItemsTabIncludeFragment;
+import com.fazziclay.opentoday.gui.GuiItemsHelper;
+import com.fazziclay.opentoday.gui.fragment.item.ItemsTabIncludeFragment;
import com.fazziclay.opentoday.util.RandomUtil;
import java.util.UUID;
@@ -73,8 +74,10 @@ public void onReceive(final Context context, final Intent intent) {
}
}
if (rawText != null) {
- final TextItem item = new TextItem(context.getString(R.string.quickNote_notificationPattern, rawText));
- if (settingsManager.isParseTimeFromQuickNote()) item.getNotifications().addAll(ItemsTabIncludeFragment.QUICK_NOTE_NOTIFICATIONS_PARSE.run(rawText));
+ final Item item = GuiItemsHelper.createItem(context, settingsManager.getDefaultQuickNoteType(), context.getString(R.string.quickNote_notificationPattern, rawText), settingsManager);
+ if (settingsManager.isParseTimeFromQuickNote()) {
+ item.addNotifications(ItemsTabIncludeFragment.QUICK_NOTE_NOTIFICATIONS_PARSE.run(rawText));
+ }
UUID itemsStorageIdForQuickNote = settingsManager.getQuickNoteNotificationItemsStorageId();
ItemsStorage itemsStorage;
if (itemsStorageIdForQuickNote == null) {
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/callback/ItemCallback.java b/app/src/main/java/com/fazziclay/opentoday/app/items/callback/ItemCallback.java
index e42416ad..c0e6c22a 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/callback/ItemCallback.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/callback/ItemCallback.java
@@ -28,4 +28,13 @@ public Status detached(Item item) {
public Status tick(Item item) {
return Status.NONE;
}
+
+ // debug function...
+ public Status click(Item item) {
+ return Status.NONE;
+ }
+
+ public Status cachedNotificationStatusChanged(Item item, boolean isUpdateNotifications) {
+ return Status.NONE;
+ }
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/callback/OnTabsChanged.java b/app/src/main/java/com/fazziclay/opentoday/app/items/callback/OnTabsChanged.java
index 13c5c2cb..28616933 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/callback/OnTabsChanged.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/callback/OnTabsChanged.java
@@ -35,4 +35,8 @@ public Status onTabMoved(Tab tab, int fromPos, int toPos) {
public Status onTabRenamed(Tab tab, int position) {
return Status.NONE;
}
+
+ public Status onTabIconChanged(Tab tab, int position) {
+ return Status.NONE;
+ }
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/item/CheckboxItem.java b/app/src/main/java/com/fazziclay/opentoday/app/items/item/CheckboxItem.java
index 46425187..88be9d12 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/item/CheckboxItem.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/item/CheckboxItem.java
@@ -62,6 +62,11 @@ public CheckboxItem(CheckboxItem copy) {
this.checked = copy.checked;
}
+ @Override
+ public ItemType getItemType() {
+ return ItemType.CHECKBOX;
+ }
+
@Override
protected void updateStat() {
super.updateStat();
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/item/CounterItem.java b/app/src/main/java/com/fazziclay/opentoday/app/items/item/CounterItem.java
index 585091a6..1118929a 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/item/CounterItem.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/item/CounterItem.java
@@ -58,6 +58,11 @@ public CounterItem(CounterItem copy) {
this.step = copy.step;
}
+ @Override
+ public ItemType getItemType() {
+ return ItemType.COUNTER;
+ }
+
public void up() {
counter = counter + step;
visibleChanged();
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/item/CycleListItem.java b/app/src/main/java/com/fazziclay/opentoday/app/items/item/CycleListItem.java
index 8c9f419e..22248a3a 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/item/CycleListItem.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/item/CycleListItem.java
@@ -17,6 +17,9 @@
import com.fazziclay.opentoday.util.callback.CallbackStorage;
import com.fazziclay.opentoday.util.callback.Status;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import java.util.UUID;
public class CycleListItem extends TextItem implements ContainerItem, ItemsStorage, CurrentItemStorage {
@@ -81,6 +84,11 @@ public CycleListItem(CycleListItem copy) {
}
}
+ @Override
+ public ItemType getItemType() {
+ return ItemType.CYCLE_LIST;
+ }
+
@Override
public Item getCurrentItem() {
if (size() == 0) {
@@ -128,18 +136,31 @@ public void previous() {
public void tick(TickSession tickSession) {
if (!tickSession.isAllowed(this)) return;
super.tick(tickSession);
- if (tickBehavior != TickBehavior.ALL) ItemUtil.tickOnlyImportantTargets(tickSession, getAllItems());
+ final List- planned = new ArrayList<>();
if (tickBehavior == TickBehavior.ALL) {
- itemsCycleStorage.tick(tickSession);
+ planned.addAll(Arrays.asList(getAllItems()));
+
} else if (tickBehavior == TickBehavior.CURRENT) {
Item c = getCurrentItem();
- if (c != null && tickSession.isAllowed(c)) c.tick(tickSession);
+ if (c != null && tickSession.isAllowed(c)) {
+ planned.add(c);
+ }
} else if (tickBehavior == TickBehavior.NOT_CURRENT) {
Item c = getCurrentItem();
for (Item item : getAllItems()) {
- if (item != c && tickSession.isAllowed(item)) item.tick(tickSession);
+ if (item != c && tickSession.isAllowed(item)) {
+ planned.add(item);
+ }
}
}
+
+ if (tickBehavior != TickBehavior.ALL) {
+ tickSession.runWithPlannedNormalTick(planned, null, () -> ItemUtil.tickOnlyImportantTargets(tickSession, getAllItems()));
+ }
+
+ for (Item item : planned) {
+ item.tick(tickSession);
+ }
}
@Override
@@ -192,6 +213,11 @@ public int size() {
return itemsCycleStorage.size();
}
+ @Override
+ public int totalSize() {
+ return itemsCycleStorage.totalSize();
+ }
+
@Override
public void addItem(Item item) {
Item p = getCurrentItem();
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/item/DayRepeatableCheckboxItem.java b/app/src/main/java/com/fazziclay/opentoday/app/items/item/DayRepeatableCheckboxItem.java
index bf2b22ab..a9c734c8 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/item/DayRepeatableCheckboxItem.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/item/DayRepeatableCheckboxItem.java
@@ -74,6 +74,11 @@ public DayRepeatableCheckboxItem(DayRepeatableCheckboxItem copy) {
this.latestDayOfYear = copy.latestDayOfYear;
}
+ @Override
+ public ItemType getItemType() {
+ return ItemType.CHECKBOX_DAY_REPEATABLE;
+ }
+
@Override
public void setChecked(boolean s) {
latestDayOfYear = new GregorianCalendar().get(Calendar.DAY_OF_YEAR);
@@ -86,6 +91,7 @@ public void tick(TickSession tickSession) {
super.tick(tickSession);
if (tickSession.isTickTargetAllowed(TickTarget.ITEM_DAY_REPEATABLE_CHECKBOX_UPDATE)) {
+ profPush(tickSession, "checkbox_day_repeatable_update");
int dayOfYear = tickSession.getGregorianCalendar().get(Calendar.DAY_OF_YEAR);
if (dayOfYear != latestDayOfYear) {
latestDayOfYear = dayOfYear;
@@ -103,6 +109,7 @@ public void tick(TickSession tickSession) {
tickSession.saveNeeded();
}
}
+ profPop(tickSession);
}
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/item/DebugTickCounterItem.java b/app/src/main/java/com/fazziclay/opentoday/app/items/item/DebugTickCounterItem.java
index 4bc13beb..f1f11155 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/item/DebugTickCounterItem.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/item/DebugTickCounterItem.java
@@ -49,6 +49,7 @@ public static DebugTickCounterItem createEmpty() {
}
@SaveKey(key = "counter") @RequireSave private int counter;
+ private long plannedCounter;
private String debugStat = "";
private Rose rose;
@@ -75,6 +76,11 @@ public DebugTickCounterItem(DebugTickCounterItem copy) {
this.rose = copy.rose; // warning!
}
+ @Override
+ public ItemType getItemType() {
+ return ItemType.DEBUG_TICK_COUNTER;
+ }
+
@Override
public void tick(TickSession tickSession) {
if (!tickSession.isAllowed(this)) {
@@ -89,6 +95,9 @@ public void tick(TickSession tickSession) {
} else {
counter++;
+ if (tickSession.isPlannedTick(this)) {
+ plannedCounter++;
+ }
final List targets = new ArrayList<>();
for (TickTarget value : TickTarget.values()) {
boolean allow = tickSession.isTickTargetAllowed(value);
@@ -103,10 +112,11 @@ public void tick(TickSession tickSession) {
=== Debug tick counter ===
ID: %s
$[-#ffff00;S16]Counter: $[-#00aaff] %s$[||]
+ $[-#ffff00;S14]PlannedCounter: $[-#00aaff] %s$[||]
$[-#f0f0f0]Allowed targets: %s$[||]
$[-#00ffff]Whitelist(%s): %s$[||]
$[-$fff00f]PathToMe: %s$[||]
- """, getId(), counter, targets, tickSession._isWhitelist(), tickSession._getWhitelist(),
+ """, getId(), counter, plannedCounter, targets, tickSession._isWhitelist(), tickSession._getWhitelist(),
Arrays.toString(ItemUtil.getPathToItem(this)));
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/item/FilterGroupItem.java b/app/src/main/java/com/fazziclay/opentoday/app/items/item/FilterGroupItem.java
index 968e622b..f11daef6 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/item/FilterGroupItem.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/item/FilterGroupItem.java
@@ -30,6 +30,7 @@
import java.util.List;
import java.util.Set;
import java.util.UUID;
+import java.util.function.Function;
public class FilterGroupItem extends TextItem implements ContainerItem, ItemsStorage {
// START - Save
@@ -130,6 +131,11 @@ public FilterGroupItem(FilterGroupItem copy) {
}
}
+ @Override
+ public ItemType getItemType() {
+ return ItemType.FILTER_GROUP;
+ }
+
@Setter public void setTickBehavior(@NonNull TickBehavior o) {this.tickBehavior = o;}
@Getter @NonNull public TickBehavior getTickBehavior() {
return tickBehavior;
@@ -200,6 +206,16 @@ public int size() {
return items.size();
}
+ @Override
+ public int totalSize() {
+ int c = 0;
+ for (ItemFilterWrapper item : items) {
+ c++;
+ c+= item.item.getChildrenItemCount();
+ }
+ return c;
+ }
+
private void addItem(ItemFilterWrapper item) {
addItem(item, items.size());
}
@@ -314,8 +330,8 @@ public void tick(TickSession tickSession) {
if (!tickSession.isAllowed(this)) return;
super.tick(tickSession);
- if (tickBehavior != TickBehavior.ALL) ItemUtil.tickOnlyImportantTargets(tickSession, getAllItems());
if (tickSession.isTickTargetAllowed(TickTarget.ITEM_FILTER_GROUP_TICK)) {
+ profPush(tickSession, "filter_group_tick");
recalculate(tickSession.getGregorianCalendar());
updateStat();
@@ -333,6 +349,10 @@ public void tick(TickSession tickSession) {
default -> throw new RuntimeException(TAG + ": Unexpected tickBehavior: " + tickBehavior);
}
+ profPop(tickSession);
+ if (tickBehavior != TickBehavior.ALL) {
+ tickSession.runWithPlannedNormalTick(tickList, (Function) itemFilterWrapper -> itemFilterWrapper.item, () -> ItemUtil.tickOnlyImportantTargets(tickSession, getAllItems()));
+ }
// NOTE: No use 'for-loop' (self-delete item in tick => ConcurrentModificationException)
int i = tickList.size() - 1;
while (i >= 0) {
@@ -342,9 +362,11 @@ public void tick(TickSession tickSession) {
}
i--;
}
+ profPush(tickSession, "filter_group_tick");
recalculate(tickSession.getGregorianCalendar());
updateStat();
+ profPop(tickSession);
}
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/item/GroupItem.java b/app/src/main/java/com/fazziclay/opentoday/app/items/item/GroupItem.java
index 3b298315..e62c977a 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/item/GroupItem.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/item/GroupItem.java
@@ -68,6 +68,11 @@ public GroupItem(GroupItem copy) {
if (copy != null) this.itemsStorage.copyData(copy.getAllItems());
}
+ @Override
+ public ItemType getItemType() {
+ return ItemType.GROUP;
+ }
+
@Override
public void tick(TickSession tickSession) {
if (!tickSession.isAllowed(this)) return;
@@ -121,6 +126,11 @@ public int size() {
return itemsStorage.size();
}
+ @Override
+ public int totalSize() {
+ return itemsStorage.totalSize();
+ }
+
@Override
public void addItem(Item item) {
itemsStorage.addItem(item);
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/item/Item.java b/app/src/main/java/com/fazziclay/opentoday/app/items/item/Item.java
index c57396a8..0190d8ce 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/item/Item.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/item/Item.java
@@ -11,9 +11,14 @@
import com.fazziclay.opentoday.app.items.ItemsStorage;
import com.fazziclay.opentoday.app.items.Unique;
import com.fazziclay.opentoday.app.items.callback.ItemCallback;
+import com.fazziclay.opentoday.app.items.notification.DayItemNotification;
import com.fazziclay.opentoday.app.items.notification.ItemNotification;
import com.fazziclay.opentoday.app.items.notification.ItemNotificationCodecUtil;
import com.fazziclay.opentoday.app.items.notification.ItemNotificationUtil;
+import com.fazziclay.opentoday.app.items.notification.NotificationController;
+import com.fazziclay.opentoday.app.items.tag.ItemTag;
+import com.fazziclay.opentoday.app.items.tag.TagsCodecUtil;
+import com.fazziclay.opentoday.app.items.tag.TagsUtil;
import com.fazziclay.opentoday.app.items.tick.TickSession;
import com.fazziclay.opentoday.app.items.tick.TickTarget;
import com.fazziclay.opentoday.app.items.tick.Tickable;
@@ -22,6 +27,7 @@
import com.fazziclay.opentoday.util.annotation.SaveKey;
import com.fazziclay.opentoday.util.annotation.Setter;
import com.fazziclay.opentoday.util.callback.CallbackStorage;
+import com.fazziclay.opentoday.util.callback.Status;
import org.jetbrains.annotations.NotNull;
@@ -51,6 +57,8 @@ public static class ItemCodec extends AbstractItemCodec {
private static final String KEY_VIEW_CUSTOM_BACKGROUND_COLOR = "viewCustomBackgroundColor";
private static final String KEY_NOTIFICATIONS = "notifications";
private static final String KEY_MINIMIZE = "minimize";
+ private static final String KEY_TAGS = "tags";
+
@NonNull
@Override
public Cherry exportItem(@NonNull Item item) {
@@ -60,10 +68,16 @@ public Cherry exportItem(@NonNull Item item) {
.put(KEY_VIEW_BACKGROUND_COLOR, item.viewBackgroundColor)
.put(KEY_VIEW_CUSTOM_BACKGROUND_COLOR, item.viewCustomBackgroundColor)
.put(KEY_MINIMIZE, item.minimize)
- .put(KEY_NOTIFICATIONS, ItemNotificationCodecUtil.exportNotificationList(item.notifications));
+ .put(KEY_NOTIFICATIONS, ItemNotificationCodecUtil.exportNotificationList(item.notifications))
+ .put(KEY_TAGS, TagsCodecUtil.exportTagsList(item.tags));
}
- private final Item defaultValues = new Item(){};
+ private final Item defaultValues = new Item(){
+ @Override
+ public ItemType getItemType() {
+ throw new UnsupportedOperationException("This method of this instance never executed!");
+ }
+ };
@NonNull
@Override
public Item importItem(@NonNull Cherry cherry, Item item) {
@@ -74,6 +88,14 @@ public Item importItem(@NonNull Cherry cherry, Item item) {
item.viewCustomBackgroundColor = cherry.optBoolean(KEY_VIEW_CUSTOM_BACKGROUND_COLOR, defaultValues.viewCustomBackgroundColor);
item.minimize = cherry.optBoolean(KEY_MINIMIZE, defaultValues.minimize);
item.notifications = ItemNotificationCodecUtil.importNotificationList(cherry.optOrchard(KEY_NOTIFICATIONS));
+ for (ItemNotification notification : item.notifications) {
+ if (notification.getId() == null) {
+ notification.attach(item.notificationController);
+ } else {
+ notification.setController(item.notificationController);
+ }
+ }
+ item.tags = TagsCodecUtil.importTagsList(cherry.optOrchard(KEY_TAGS));
return item;
}
@@ -103,12 +125,16 @@ private void applyId(Item item, Cherry cherry) {
@SaveKey(key = "viewCustomBackgroundColor") @RequireSave private boolean viewCustomBackgroundColor = false; // юзаем ли фоновый цвет
@SaveKey(key = "minimize") @RequireSave private boolean minimize = false;
@NonNull @SaveKey(key = "notifications") @RequireSave private List notifications = new ArrayList<>();
+ @NonNull @SaveKey(key = "tags") @RequireSave private List tags = new ArrayList<>();
+ @NonNull private final NotificationController notificationController = new ItemNotificationController();
+ private boolean cachedNotificationStatus;
// Copy constructor
- public Item(@Nullable Item copy) {
+ protected Item(@Nullable Item copy) {
// unattached
this.id = null;
this.controller = null;
+ this.cachedNotificationStatus = true;
// copy
if (copy != null) {
@@ -117,13 +143,19 @@ public Item(@Nullable Item copy) {
this.viewCustomBackgroundColor = copy.viewCustomBackgroundColor;
this.minimize = copy.minimize;
this.notifications = ItemNotificationUtil.copy(copy.notifications);
+ for (ItemNotification notification : this.notifications) {
+ notification.attach(notificationController);
+ }
+ this.tags = TagsUtil.copy(copy.tags);
}
}
- public Item() {
+ protected Item() {
this(null);
}
+ public abstract ItemType getItemType();
+
// For fast get text (method overrides by TextItem)
public String getText() {
return "[Item not have text. Ops...]";
@@ -177,8 +209,36 @@ protected void detach() {
public void tick(TickSession tickSession) {
if (!tickSession.isAllowed(this)) return;
Debug.tickedItems++;
- if (tickSession.isTickTargetAllowed(TickTarget.ITEM_NOTIFICATIONS)) ItemNotificationUtil.tick(tickSession, notifications, this);
- if (tickSession.isTickTargetAllowed(TickTarget.ITEM_CALLBACKS)) itemCallbacks.run((callbackStorage, callback) -> callback.tick(Item.this));
+ if (tickSession.isTickTargetAllowed(TickTarget.ITEM_NOTIFICATIONS)) {
+ profPush(tickSession, "item_notifications_tick");
+ ItemNotificationUtil.tick(tickSession, notifications);
+ profPop(tickSession);
+ }
+ if (tickSession.isTickTargetAllowed(TickTarget.ITEM_CALLBACKS)) {
+ profPush(tickSession, "callbacks");
+ itemCallbacks.run((callbackStorage, callback) -> callback.tick(Item.this));
+ profPop(tickSession);
+ }
+
+ profPush(tickSession, "cachedNotificationStatus");
+ boolean isUpdateNotifications = tickSession.isTickTargetAllowed(TickTarget.ITEM_NOTIFICATION_UPDATE);
+ if (isUpdateNotifications != cachedNotificationStatus && !tickSession.isPlannedTick(this)) {
+ cachedNotificationStatus = isUpdateNotifications;
+ itemCallbacks.run((callbackStorage, callback) -> callback.cachedNotificationStatusChanged(Item.this, isUpdateNotifications));
+ }
+ profPop(tickSession);
+ }
+
+ protected void profPush(TickSession t, String s) {
+ t.getProfiler().push(s);
+ }
+
+ protected void profSwap(TickSession t, String s) {
+ t.getProfiler().swap(s);
+ }
+
+ protected void profPop(TickSession t) {
+ t.getProfiler().pop();
}
protected void regenerateId() {
@@ -197,6 +257,7 @@ public int getChildrenItemCount() {
}
protected void updateStat() {
+ stat.setNotifications(notifications.size());
stat.tick();
}
@@ -204,6 +265,10 @@ public CallbackStorage getItemCallbacks() {
return itemCallbacks;
}
+ public void dispatchClick() {
+ itemCallbacks.run((callbackStorage, callback) -> callback.click(Item.this));
+ }
+
// Getters & Setters
@Nullable @Override @Getter public UUID getId() { return id; }
@@ -224,7 +289,53 @@ public CallbackStorage getItemCallbacks() {
@Getter public boolean isMinimize() { return minimize; }
@Setter public void setMinimize(boolean minimize) { this.minimize = minimize; }
- @Getter @NonNull public List getNotifications() { return notifications; }
+ @Getter @NonNull public ItemNotification[] getNotifications() { return notifications.toArray(new ItemNotification[0]); }
+
+ public void addNotifications(ItemNotification... notifications) {
+ for (ItemNotification notification : notifications) {
+ notification.attach(notificationController);
+ this.notifications.add(notification);
+ }
+ updateStat();
+ visibleChanged();
+ }
+
+ public void removeNotifications(ItemNotification... notifications) {
+ for (ItemNotification notification : notifications) {
+ notification.detach();
+ this.notifications.remove(notification);
+ }
+ updateStat();
+ visibleChanged();
+ }
+
+ public ItemNotification getNotificationById(UUID notifyId) {
+ for (ItemNotification notification : notifications) {
+ if (notifyId.equals(notification.getId())) return notification;
+ }
+ return null;
+ }
+
+ public void moveNotifications(int positionFrom, int positionTo) {
+ if (!(positionFrom >= 0 && positionTo >= 0 && positionFrom < notifications.size() && positionTo < notifications.size())) {
+ throw new IndexOutOfBoundsException("failed move notifications... from=" + positionFrom + "; to=" + positionTo);
+ }
+ ItemNotification itemNotification = notifications.get(positionFrom);
+ notifications.remove(itemNotification);
+ notifications.add(positionTo, itemNotification);
+ }
+
+ public void removeAllNotifications() {
+ removeNotifications(getNotifications());
+ }
+
+ public boolean isNotifications() {
+ return !notifications.isEmpty();
+ }
+
+ public boolean getCachedNotificationStatus() {
+ return cachedNotificationStatus;
+ }
@Getter @NonNull public ItemStat getStat() {
return stat;
@@ -237,6 +348,20 @@ public CallbackStorage getItemCallbacks() {
return null;
}
+ @NonNull
+ public ItemTag[] getTags() {
+ return tags.toArray(new ItemTag[0]);
+ }
+
+ public void removeTag(ItemTag t) {
+ tags.remove(t);
+ }
+
+ public void addTag(ItemTag t) {
+ t.bind();
+ tags.add(t);
+ }
+
@NotNull
@Override
public String toString() {
@@ -245,4 +370,16 @@ public String toString() {
text = text.substring(0, max);
return getClass().getSimpleName()+"@[ID:"+getId()+" HASH:"+hashCode() +" TEXT:'"+text+"']";
}
+
+ private class ItemNotificationController implements NotificationController {
+ @Override
+ public UUID generateId(ItemNotification notification) {
+ return UUID.randomUUID();
+ }
+
+ @Override
+ public Item getParentItem(ItemNotification itemNotification) {
+ return Item.this;
+ }
+ }
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/item/ItemCodecUtil.java b/app/src/main/java/com/fazziclay/opentoday/app/items/item/ItemCodecUtil.java
index f9fff796..40a2e57f 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/item/ItemCodecUtil.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/item/ItemCodecUtil.java
@@ -50,13 +50,18 @@ public static Item importItem(Cherry cherry) {
// export item (Item -> JSON)
public static Cherry exportItem(Item item) {
- /*IETool from itemClass*/
- AbstractItemCodec codec = ItemsRegistry.REGISTRY.get(item.getClass()).getCodec();
- /*Export from IETool*/Cherry cherry = codec.exportItem(item);
- /*Put itemType to json*/
- if (!(item instanceof MissingNoItem)) {
- cherry.put(KEY_ITEMTYPE, ItemsRegistry.REGISTRY.get(item.getClass()).getStringType());
+ try {
+ /*IETool from itemClass*/
+ AbstractItemCodec codec = ItemsRegistry.REGISTRY.get(item.getClass()).getCodec();
+ /*Export from IETool*/
+ Cherry cherry = codec.exportItem(item);
+ /*Put itemType to json*/
+ if (!(item instanceof MissingNoItem)) {
+ cherry.put(KEY_ITEMTYPE, ItemsRegistry.REGISTRY.get(item.getClass()).getStringType());
+ }
+ return cherry;
+ } catch (Exception e) {
+ throw new RuntimeException("Exception while export item " + item, e);
}
- return cherry;
}
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/item/ItemStat.java b/app/src/main/java/com/fazziclay/opentoday/app/items/item/ItemStat.java
index fe8b19dc..a91f0736 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/item/ItemStat.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/item/ItemStat.java
@@ -4,6 +4,7 @@ public class ItemStat {
private int totalTicks = 0;
private int containerItems;
private int activeItems;
+ private int notifications;
private boolean isChecked;
public int getContainerItems() {
@@ -34,6 +35,14 @@ public int getTotalTicks() {
return totalTicks;
}
+ public void setNotifications(int notifications) {
+ this.notifications = notifications;
+ }
+
+ public int getNotifications() {
+ return notifications;
+ }
+
public void tick() {
totalTicks++;
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/item/LongTextItem.java b/app/src/main/java/com/fazziclay/opentoday/app/items/item/LongTextItem.java
index 068c9041..ac83ec39 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/item/LongTextItem.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/item/LongTextItem.java
@@ -86,6 +86,11 @@ public LongTextItem(LongTextItem copy) {
this.isCustomLongTextSize = copy.isCustomLongTextSize;
}
+ @Override
+ public ItemType getItemType() {
+ return ItemType.LONG_TEXT;
+ }
+
@Setter
public void setLongTextColor(int longTextColor) {this.longTextColor = longTextColor;}
@Getter
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/item/MathGameItem.java b/app/src/main/java/com/fazziclay/opentoday/app/items/item/MathGameItem.java
index 7c5dd0dd..376c279e 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/item/MathGameItem.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/item/MathGameItem.java
@@ -89,6 +89,11 @@ public MathGameItem(TextItem append) {
this.primitiveAllowedOperations.add("+");
}
+ @Override
+ public ItemType getItemType() {
+ return ItemType.MATH_GAME;
+ }
+
@Override
public void tick(TickSession tickSession) {
if (!tickSession.isAllowed(this)) return;
@@ -96,10 +101,12 @@ public void tick(TickSession tickSession) {
super.tick(tickSession);
if (tickSession.isTickTargetAllowed(TickTarget.ITEM_MATH_GAME_UPDATE)) {
+ profPush(tickSession, "math_game_update");
if (!quest.isInitialize()) {
generateQuest();
visibleChanged();
}
+ profPop(tickSession);
}
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/item/MissingNoItem.java b/app/src/main/java/com/fazziclay/opentoday/app/items/item/MissingNoItem.java
index a81c3ce9..4b587f41 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/item/MissingNoItem.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/item/MissingNoItem.java
@@ -8,6 +8,7 @@
import java.util.ArrayList;
import java.util.List;
+// un-imported item :(
public class MissingNoItem extends Item {
public static final MissingNoItemCodec CODEC = new MissingNoItemCodec();
private static class MissingNoItemCodec extends AbstractItemCodec {
@@ -33,6 +34,11 @@ public MissingNoItem(Cherry cherry) {
this.cherry = cherry;
}
+ @Override
+ public ItemType getItemType() {
+ return ItemType.MISSING_NO;
+ }
+
public MissingNoItem putException(Exception e) {
exceptionList.add(e);
return this;
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/item/SimpleItemsStorage.java b/app/src/main/java/com/fazziclay/opentoday/app/items/item/SimpleItemsStorage.java
index e0b8ef54..90df17b1 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/item/SimpleItemsStorage.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/item/SimpleItemsStorage.java
@@ -40,6 +40,16 @@ public int size() {
return items.size();
}
+ @Override
+ public int totalSize() {
+ int c = 0;
+ for (Item item : items) {
+ c++;
+ c+= item.getChildrenItemCount();
+ }
+ return c;
+ }
+
@Override
public Item getItemAt(int position) {
return items.get(position);
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/item/SleepTimeItem.java b/app/src/main/java/com/fazziclay/opentoday/app/items/item/SleepTimeItem.java
index 6624585d..280a0f99 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/item/SleepTimeItem.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/item/SleepTimeItem.java
@@ -2,6 +2,7 @@
import androidx.annotation.NonNull;
+import com.fazziclay.opentoday.app.App;
import com.fazziclay.opentoday.app.Translation;
import com.fazziclay.opentoday.app.data.Cherry;
import com.fazziclay.opentoday.app.items.tick.TickSession;
@@ -39,6 +40,7 @@ public Item importItem(@NonNull Cherry cherry, Item item) {
private int elapsedTime; // cached
private int wakeUpForRequiredAtCurr; // cached
+ private int elapsedToStartSleep; // cached
private long tick; // cached
@NonNull
@@ -47,12 +49,19 @@ public static SleepTimeItem createEmpty() {
}
+ public SleepTimeItem(TextItem append) {
+ super(append);
+ tick = 0;
+ elapsedTime = 0;
+ wakeUpForRequiredAtCurr = 0;
+ }
public SleepTimeItem(SleepTimeItem copy) {
super(copy);
tick = 0;
elapsedTime = 0;
wakeUpForRequiredAtCurr = 0;
+ elapsedToStartSleep = 0;
if (copy != null) {
this.wakeUpTime = copy.wakeUpTime;
@@ -65,11 +74,16 @@ private SleepTimeItem() {
this(null);
}
+ @Override
+ public ItemType getItemType() {
+ return ItemType.SLEEP_TIME;
+ }
+
@Override
protected void regenerateId() {
super.regenerateId();
if (sleepTextPattern == null) {
- sleepTextPattern = getRoot().getTranslation().get(Translation.KEY_SLEEP_TIME_ITEM_PATTERN);
+ sleepTextPattern = App.get().getTranslation().get(Translation.KEY_SLEEP_TIME_ITEM_PATTERN); // TODO: 08.10.2023 uses static App.get() is bad...
save();
}
}
@@ -77,6 +91,7 @@ protected void regenerateId() {
@Override
public void tick(TickSession tickSession) {
super.tick(tickSession);
+ profPush(tickSession, "sleep_time_update");
elapsedTime = wakeUpTime - TimeUtil.getDaySeconds();
if (elapsedTime <= 0) {
elapsedTime = TimeUtil.SECONDS_IN_DAY + elapsedTime;
@@ -87,16 +102,31 @@ public void tick(TickSession tickSession) {
wakeUpForRequiredAtCurr-=TimeUtil.SECONDS_IN_DAY;
}
+ elapsedToStartSleep = wakeUpTime - requiredSleepTime - TimeUtil.getDaySeconds();
+ if (elapsedToStartSleep < 0) {
+ elapsedToStartSleep += TimeUtil.SECONDS_IN_DAY;
+ }
+ if (elapsedToStartSleep < 0) {
+ elapsedToStartSleep += TimeUtil.SECONDS_IN_DAY;
+ }
+
if (tick % 5 == 0) {
visibleChanged();
}
tick++;
+ profPop(tickSession);
}
public int getElapsedTime() {
return elapsedTime;
}
+
+ public int getElapsedTimeToStartSleep() {
+ return elapsedToStartSleep;
+ }
+
+
public void setWakeUpTime(int wakeUpTime) {
this.wakeUpTime = wakeUpTime;
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/item/TextItem.java b/app/src/main/java/com/fazziclay/opentoday/app/items/item/TextItem.java
index f3af832b..0ee6ee42 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/item/TextItem.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/item/TextItem.java
@@ -83,6 +83,11 @@ public TextItem(TextItem copy) {
}
}
+ @Override
+ public ItemType getItemType() {
+ return ItemType.TEXT;
+ }
+
@Override @Getter @NonNull public String getText() { return text; }
@Setter public void setText(@NonNull String v) { this.text = v; }
@Getter public int getTextColor() { return textColor; }
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/item/Transform.java b/app/src/main/java/com/fazziclay/opentoday/app/items/item/Transform.java
index c93b4876..2ee32bf7 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/item/Transform.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/item/Transform.java
@@ -29,9 +29,18 @@ public class Transform {
public static Result transform(Item item, ItemType to) {
ItemType from = ItemUtil.getItemType(item);
+ if (to == ItemType.SLEEP_TIME) {
+ return Result.allow(() -> new SleepTimeItem((TextItem) item));
+ }
+
+ if (to == ItemType.TEXT) {
+ if (item instanceof TextItem textItem) {
+ return Result.allow(() -> new TextItem(textItem));
+ }
+ }
+
if (to == ItemType.COUNTER) {
- if (from == ItemType.TEXT) {
- TextItem textItem = (TextItem) item;
+ if (item instanceof TextItem textItem) {
return Result.allow(() -> new CounterItem(textItem));
}
}
@@ -40,19 +49,34 @@ public static Result transform(Item item, ItemType to) {
if (from == ItemType.CHECKBOX) {
return Result.allow(() -> new DayRepeatableCheckboxItem((CheckboxItem) item, false, 0));
- } else if (from == ItemType.TEXT) {
+ } else if (item instanceof TextItem) {
return Result.allow(() -> new DayRepeatableCheckboxItem(new CheckboxItem((TextItem) item, false), false, 0));
}
}
if (to == ItemType.CHECKBOX) {
- if (from == ItemType.TEXT) {
+ if (item instanceof CheckboxItem) {
+ return Result.allow(() -> new CheckboxItem((CheckboxItem) item));
+ }
+
+ if (item instanceof TextItem) {
return Result.allow(() -> new CheckboxItem((TextItem) item, false));
}
}
if (to == ItemType.LONG_TEXT) {
- if (from == ItemType.TEXT) {
+ if (item instanceof ContainerItem containerItem) {
+ return Result.allow(() -> {
+ String text = "";
+ for (Item intItem : containerItem.getAllItems()) {
+ String t = ((intItem instanceof CheckboxItem checkboxItem) ? (checkboxItem.isChecked() ? "[*]" : "[ ]") : "") + intItem.getText();
+ text += t + "\n\n";
+ }
+ return new LongTextItem((TextItem) item, text);
+ });
+ }
+
+ if (item instanceof TextItem) {
return Result.allow(() -> new LongTextItem((TextItem) item, item.getText()));
}
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotificationCodec.java b/app/src/main/java/com/fazziclay/opentoday/app/items/notification/AbstractItemNotificationCodec.java
similarity index 73%
rename from app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotificationCodec.java
rename to app/src/main/java/com/fazziclay/opentoday/app/items/notification/AbstractItemNotificationCodec.java
index 24a75902..16f43405 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotificationCodec.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/notification/AbstractItemNotificationCodec.java
@@ -2,7 +2,7 @@
import com.fazziclay.opentoday.app.data.Cherry;
-public abstract class ItemNotificationCodec {
+public abstract class AbstractItemNotificationCodec {
public abstract Cherry exportNotification(ItemNotification itemNotification);
- public abstract ItemNotification importNotification(Cherry cherry);
+ public abstract ItemNotification importNotification(Cherry cherry, ItemNotification notification);
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/notification/DayItemNotification.java b/app/src/main/java/com/fazziclay/opentoday/app/items/notification/DayItemNotification.java
index 3aa6d8d7..31d311d0 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/notification/DayItemNotification.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/notification/DayItemNotification.java
@@ -1,31 +1,22 @@
package com.fazziclay.opentoday.app.items.notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.Context;
-
import androidx.annotation.NonNull;
-import androidx.core.app.NotificationCompat;
-import com.fazziclay.opentoday.R;
-import com.fazziclay.opentoday.app.App;
+import com.fazziclay.opentoday.app.ItemNotificationHandler;
import com.fazziclay.opentoday.app.data.Cherry;
-import com.fazziclay.opentoday.app.items.item.Item;
import com.fazziclay.opentoday.app.items.tick.TickSession;
import com.fazziclay.opentoday.app.items.tick.TickTarget;
-import com.fazziclay.opentoday.gui.activity.AlarmActivity;
-import com.fazziclay.opentoday.util.ColorUtil;
-import com.fazziclay.opentoday.util.RandomUtil;
+import com.fazziclay.opentoday.util.time.TimeUtil;
import java.util.Calendar;
-public class DayItemNotification implements ItemNotification {
- public static final ItemNotificationCodec CODEC = new Codec();
- private static class Codec extends ItemNotificationCodec {
+public class DayItemNotification extends ItemNotification {
+ public static final DayItemNotificationCodec CODEC = new DayItemNotificationCodec();
+ private static class DayItemNotificationCodec extends ItemNotification.ItemNotificationCodec {
@Override
public Cherry exportNotification(ItemNotification itemNotification) {
DayItemNotification d = (DayItemNotification) itemNotification;
- return new Cherry()
+ return super.exportNotification(itemNotification)
.put("notificationId", d.notificationId)
.put("notifyTitle", d.notifyTitle)
.put("notifyTitleFromItemText", d.notifyTitleFromItemText)
@@ -44,8 +35,10 @@ public Cherry exportNotification(ItemNotification itemNotification) {
}
@Override
- public ItemNotification importNotification(Cherry cherry) {
- DayItemNotification o = new DayItemNotification();
+ public ItemNotification importNotification(Cherry cherry, ItemNotification notification) {
+ DayItemNotification o = notification == null ? new DayItemNotification() : (DayItemNotification) notification;
+ super.importNotification(cherry, o);
+
o.notificationId = cherry.optInt("notificationId", 543);
o.notifyTitle = cherry.optString("notifyTitle", "");
o.notifyTitleFromItemText = cherry.optBoolean("notifyTitleFromItemText", true);
@@ -61,6 +54,7 @@ public ItemNotification importNotification(Cherry cherry) {
}
}
+
private int notificationId = 0;
private String notifyTitle;
private boolean notifyTitleFromItemText = false;
@@ -75,27 +69,25 @@ public ItemNotification importNotification(Cherry cherry) {
private boolean sound = true;
public DayItemNotification() {
-
- }
-
- public DayItemNotification(int notificationId, String notifyTitle, String notifyText, String notifySubText, int time) {
- this.notificationId = notificationId;
- this.notifyTitle = notifyTitle;
- this.notifyText = notifyText;
- this.notifySubText = notifySubText;
- this.time = time;
+ // do nothing
}
@Override
- public boolean tick(TickSession tickSession, Item item) {
- if (tickSession.isTickTargetAllowed(TickTarget.ITEM_NOTIFICATION_SCHEDULE)) tickSession.setAlarmDayOfTimeInSeconds(time, item);
+ public boolean tick(TickSession tickSession) {
+ boolean isTimeToSend = tickSession.getDayTime() >= time;
+
+ if (tickSession.isTickTargetAllowed(TickTarget.ITEM_NOTIFICATION_SCHEDULE)) {
+ final long shift = isTimeToSend ? TimeUtil.SECONDS_IN_DAY : 0;
+ final long baseDayMs = tickSession.getNoTimeCalendar().getTimeInMillis() + (shift * 1000L);
+ long triggerAtMs = baseDayMs + (time * 1000L) + 599;
+ tickSession.getItemNotificationHandler().setAlarm(this, triggerAtMs);
+ }
+
if (tickSession.isTickTargetAllowed(TickTarget.ITEM_NOTIFICATION_UPDATE)) {
int dayOfYear = tickSession.getGregorianCalendar().get(Calendar.DAY_OF_YEAR);
if (dayOfYear != latestDayOfYear) {
- boolean isTimeToSend = tickSession.getDayTime() >= time;
-
if (isTimeToSend) {
- sendNotify(tickSession.getContext(), item);
+ sendNotify(tickSession.getItemNotificationHandler());
latestDayOfYear = dayOfYear;
tickSession.saveNeeded();
tickSession.importantSaveNeeded();
@@ -109,30 +101,11 @@ public boolean tick(TickSession tickSession, Item item) {
@NonNull
@Override
public DayItemNotification clone() {
- try {
- return (DayItemNotification) super.clone();
- } catch (CloneNotSupportedException e) {
- throw new RuntimeException("Clone exception", e);
- }
+ return (DayItemNotification) super.clone();
}
- public void sendNotify(Context context, Item item) {
- final String nTitle = notifyTitleFromItemText ? (item.isParagraphColorize() ? ColorUtil.colorizeToPlain(item.getText()) : item.getText()) : notifyTitle;
- final String nText = notifyTextFromItemText ? (item.isParagraphColorize() ? ColorUtil.colorizeToPlain(item.getText()) : item.getText()) : notifyText;
-
- NotificationCompat.Builder builder = new NotificationCompat.Builder(context, App.NOTIFICATION_ITEMS_CHANNEL)
- .setSmallIcon(R.mipmap.ic_launcher)
- .setContentTitle(nTitle)
- .setContentText(nText)
- .setSubText(notifySubText)
- .setPriority(NotificationCompat.PRIORITY_MAX);
-
- if (fullScreen) {
- PendingIntent pending = PendingIntent.getActivity(context, RandomUtil.nextInt(), AlarmActivity.createIntent(context, item.getId(), isPreRenderPreviewMode, nTitle, sound), PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
- builder.setFullScreenIntent(pending, true);
- }
-
- context.getSystemService(NotificationManager.class).notify(this.notificationId, builder.build());
+ public void sendNotify(ItemNotificationHandler itemNotificationHandler) {
+ itemNotificationHandler.handle(getParentItem(), this);
}
public int getLatestDayOfYear() {
@@ -222,4 +195,22 @@ public boolean isFullScreen() {
public void setFullScreen(boolean fullScreen) {
this.fullScreen = fullScreen;
}
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "DayItemNotification{" +
+ "notificationId=" + notificationId +
+ ", notifyTitle='" + notifyTitle + '\'' +
+ ", notifyTitleFromItemText=" + notifyTitleFromItemText +
+ ", notifyText='" + notifyText + '\'' +
+ ", notifyTextFromItemText=" + notifyTextFromItemText +
+ ", notifySubText='" + notifySubText + '\'' +
+ ", latestDayOfYear=" + latestDayOfYear +
+ ", time=" + time +
+ ", fullScreen=" + fullScreen +
+ ", isPreRenderPreviewMode=" + isPreRenderPreviewMode +
+ ", sound=" + sound +
+ "} " + super.toString();
+ }
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotification.java b/app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotification.java
index a448a6d8..d2de00c2 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotification.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotification.java
@@ -2,11 +2,121 @@
import androidx.annotation.NonNull;
+import com.fazziclay.opentoday.app.data.Cherry;
+import com.fazziclay.opentoday.app.icons.IconsRegistry;
import com.fazziclay.opentoday.app.items.item.Item;
import com.fazziclay.opentoday.app.items.tick.TickSession;
-public interface ItemNotification extends Cloneable {
- boolean tick(TickSession tickSession, Item item);
+import org.jetbrains.annotations.NotNull;
+
+import java.util.UUID;
+
+public abstract class ItemNotification implements Cloneable {
+ public static final int DEFAULT_COLOR = 0; // this is magic number
+
+
+ public static class ItemNotificationCodec extends AbstractItemNotificationCodec {
+ @Override
+ public Cherry exportNotification(ItemNotification itemNotification) {
+ return new Cherry()
+ .put("id", itemNotification.id == null ? null : itemNotification.id.toString())
+ .put("icon", itemNotification.icon.getId())
+ .put("color", itemNotification.color);
+ }
+
+ @Override
+ public ItemNotification importNotification(Cherry cherry, ItemNotification notification) {
+ if (cherry.has("id")) {
+ try {
+ notification.id = UUID.fromString(cherry.getString("id"));
+ } catch (Exception ignored) {}
+ }
+ notification.icon = IconsRegistry.REGISTRY.getById(cherry.optString("icon", "opentoday"));
+ notification.color = cherry.optInt("color", DEFAULT_COLOR);
+ return notification;
+ }
+ }
+
+
+ private UUID id;
+ private NotificationController controller;
+ @NotNull private IconsRegistry.Icon icon = IconsRegistry.REGISTRY.OPENTODAY;
+ private int color;
+
+ public abstract boolean tick(TickSession tickSession);
+
+ @NonNull
+ public ItemNotification clone() {
+ ItemNotification clone;
+ try {
+ clone = (ItemNotification) super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new RuntimeException("Clone exception", e);
+ }
+ clone.controller = null;
+ clone.id = null;
+ return clone;
+ }
+
+ public void attach(@NotNull NotificationController controller) {
+ if (controller == null) {
+ throw new IllegalArgumentException("controller is null :(");
+ }
+ this.controller = controller;
+ this.id = controller.generateId(this);
+ }
+
+ public void detach() {
+ this.controller = null;
+ this.id = null;
+ }
+
+ public boolean isAttached() {
+ return controller != null;
+ }
+
+ public UUID getId() {
+ return id;
+ }
+
+ public NotificationController getController() {
+ return controller;
+ }
+
+ public Item getParentItem() {
+ if (!isAttached()) return null;
+ return controller.getParentItem(this);
+ }
+
+ // DO NOT USE THIS!!!!!! (used only for importing)
+ public void setController(NotificationController controller) {
+ this.controller = controller;
+ }
+
+
+ public void setIcon(@NonNull IconsRegistry.Icon icon) {
+ this.icon = icon;
+ }
+
+ @NonNull
+ public IconsRegistry.Icon getIcon() {
+ return icon;
+ }
+
+ public int getColor() {
+ return color;
+ }
+
+ public void setColor(int c) {
+ this.color = c;
+ }
+
@NonNull
- ItemNotification clone();
+ @Override
+ public String toString() {
+ return "ItemNotification{" +
+ "id=" + id +
+ ", controller=" + controller +
+ '}';
+ }
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotificationCodecUtil.java b/app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotificationCodecUtil.java
index 556b55c7..eb4f8094 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotificationCodecUtil.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotificationCodecUtil.java
@@ -6,15 +6,16 @@
import java.util.List;
public class ItemNotificationCodecUtil {
- private static final String KEY_TYPE = "type";
+ private static final String KEY_TYPE = "type"; // TODO: 22.10.2023 maybe rename to "notificationType"? (it need write fixes in DataFaxer....)
+ // must return mutable list (arraylist!)
public static List importNotificationList(CherryOrchard orchard) {
final List result = new ArrayList<>();
orchard.forEachCherry((_ignore, cherry) -> {
final String type = cherry.getString(KEY_TYPE);
- final ItemNotificationCodec codec = ItemNotificationsRegistry.REGISTRY.getByStringType(type).getCodec();
- result.add(codec.importNotification(cherry));
+ final AbstractItemNotificationCodec codec = ItemNotificationsRegistry.REGISTRY.getByStringType(type).getCodec();
+ result.add(codec.importNotification(cherry, null));
});
return result;
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotificationType.java b/app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotificationType.java
new file mode 100644
index 00000000..b3a21e28
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotificationType.java
@@ -0,0 +1,5 @@
+package com.fazziclay.opentoday.app.items.notification;
+
+public enum ItemNotificationType {
+ DAY
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotificationUtil.java b/app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotificationUtil.java
index 866d0946..eb0c84f0 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotificationUtil.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotificationUtil.java
@@ -21,9 +21,9 @@ public static List copy(List notifications)
return result;
}
- public static void tick(TickSession tickSession, List notifications, Item item) {
+ public static void tick(TickSession tickSession, List notifications) {
for (ItemNotification notification : notifications) {
- notification.tick(tickSession, item);
+ notification.tick(tickSession);
}
}
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotificationsRegistry.java b/app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotificationsRegistry.java
index 9242cfa1..85a55bc5 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotificationsRegistry.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/notification/ItemNotificationsRegistry.java
@@ -4,7 +4,7 @@ public class ItemNotificationsRegistry {
public static final ItemNotificationsRegistry REGISTRY = new ItemNotificationsRegistry();
private static final ItemNotificationInfo[] NOTIFICATIONS = new ItemNotificationInfo[] {
- new ItemNotificationInfo(DayItemNotification.class, "DayItemNotification", DayItemNotification.CODEC)
+ new ItemNotificationInfo(DayItemNotification.class, "DayItemNotification", DayItemNotification.CODEC, ItemNotificationType.DAY)
};
public ItemNotificationInfo[] getAllNotifications() {
@@ -14,12 +14,14 @@ public ItemNotificationInfo[] getAllNotifications() {
public static class ItemNotificationInfo {
private final Class extends ItemNotification> clazz;
private final String stringType;
- private final ItemNotificationCodec codec;
+ private final AbstractItemNotificationCodec codec;
+ private final ItemNotificationType type;
- public ItemNotificationInfo(Class extends ItemNotification> clazz, String v, ItemNotificationCodec codec) {
+ public ItemNotificationInfo(Class extends ItemNotification> clazz, String v, AbstractItemNotificationCodec codec, ItemNotificationType type) {
this.clazz = clazz;
this.stringType = v;
this.codec = codec;
+ this.type = type;
}
public Class extends ItemNotification> getClazz() {
@@ -30,9 +32,13 @@ public String getStringType() {
return stringType;
}
- public ItemNotificationCodec getCodec() {
+ public AbstractItemNotificationCodec getCodec() {
return codec;
}
+
+ public ItemNotificationType getType() {
+ return type;
+ }
}
public ItemNotificationInfo getByStringType(String v) {
@@ -52,4 +58,13 @@ public ItemNotificationInfo getByClass(Class extends ItemNotification> v) {
}
return null;
}
+
+ public ItemNotificationInfo getByType(ItemNotificationType type) {
+ for (ItemNotificationInfo info : NOTIFICATIONS) {
+ if (info.type == type) {
+ return info;
+ }
+ }
+ return null;
+ }
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/notification/NotificationController.java b/app/src/main/java/com/fazziclay/opentoday/app/items/notification/NotificationController.java
new file mode 100644
index 00000000..9adf478f
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/notification/NotificationController.java
@@ -0,0 +1,11 @@
+package com.fazziclay.opentoday.app.items.notification;
+
+import com.fazziclay.opentoday.app.items.item.Item;
+
+import java.util.UUID;
+
+public interface NotificationController {
+ UUID generateId(ItemNotification notification);
+
+ Item getParentItem(ItemNotification itemNotification);
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/tab/Debug202305RandomTab.java b/app/src/main/java/com/fazziclay/opentoday/app/items/tab/Debug202305RandomTab.java
index 9bcaaa15..af774297 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/tab/Debug202305RandomTab.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/tab/Debug202305RandomTab.java
@@ -1,11 +1,17 @@
package com.fazziclay.opentoday.app.items.tab;
+import android.graphics.Color;
+
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.fazziclay.javaneoutil.FileUtil;
+import com.fazziclay.opentoday.app.App;
import com.fazziclay.opentoday.app.data.Cherry;
+import com.fazziclay.opentoday.app.items.ItemsRoot;
import com.fazziclay.opentoday.app.items.ItemsStorage;
import com.fazziclay.opentoday.app.items.Readonly;
+import com.fazziclay.opentoday.app.items.callback.ItemCallback;
import com.fazziclay.opentoday.app.items.callback.OnItemsStorageUpdate;
import com.fazziclay.opentoday.app.items.item.CheckboxItem;
import com.fazziclay.opentoday.app.items.item.CounterItem;
@@ -17,10 +23,19 @@
import com.fazziclay.opentoday.app.items.item.TextItem;
import com.fazziclay.opentoday.app.items.tick.TickSession;
import com.fazziclay.opentoday.app.items.tick.Tickable;
+import com.fazziclay.opentoday.util.ColorUtil;
import com.fazziclay.opentoday.util.RandomUtil;
+import com.fazziclay.opentoday.util.StreamUtil;
+import com.fazziclay.opentoday.util.callback.CallbackImportance;
import com.fazziclay.opentoday.util.callback.CallbackStorage;
+import com.fazziclay.opentoday.util.callback.Status;
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Comparator;
import java.util.UUID;
+import java.util.function.ToIntFunction;
public class Debug202305RandomTab extends Tab implements Tickable, Readonly {
public static final TabCodec CODEC = new TabCodec() {
@@ -38,16 +53,53 @@ public Tab importTab(@NonNull Cherry cherry, @Nullable Tab tab) {
return t;
}
};
+ private static final boolean GEN_COLORS = true;
+ private static final boolean DISABLE_TAB = true; // yes, disable this tab in releases. (this tab causes crashes...)
- private final SimpleItemsStorage itemsStorage = new SimpleItemsStorage(getRoot()) {
+ private final SimpleItemsStorage itemsStorage = new SimpleItemsStorage((ItemsRoot) null) {
@Override
public void save() {
// do nothing in Debug tab
}
};
+ double DistanceSquared(int a, int b)
+ {
+ int deltaR = Color.red(a) - Color.red(b);
+ int deltaG = Color.green(a) - Color.green(b);
+ int deltaB = Color.blue(a) - Color.blue(b);
+ int deltaAlpha = Color.alpha(a) - Color.alpha(b);
+ double rgbDistanceSquared = (deltaR * deltaR + deltaG * deltaG + deltaB * deltaB) / 3.0;
+ return deltaAlpha * deltaAlpha / 2.0 + rgbDistanceSquared * Color.alpha(a) * Color.alpha(b) / (255 * 255);
+ }
+
public Debug202305RandomTab() {
super("Debug202305RandomTab");
+
+ String[] s = new String[0];
+ try {
+ s = StreamUtil.read(App.get().getAssets().open("beautify_colors.txt")).split("\n");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+// Arrays.parallelSort(s, Comparator.comparingInt(s12 -> {
+// return (int) DistanceSquared(Color.WHITE, Color.parseColor(s12));
+// }));
+ for (String s1 : s) {
+ if (s1.startsWith("//")) continue;
+ s1 = s1.split(";")[0];
+ TextItem item = (TextItem) ItemsRegistry.REGISTRY.get(ItemType.TEXT).create();
+ try {
+ int c = Color.parseColor(s1);
+ item.setViewCustomBackgroundColor(true);
+ item.setViewBackgroundColor(c);
+ item.setText("Всем привет, это тестовый текстик <3");
+ } catch (Exception e) {
+ item.setText("Exception: " + e);
+ }
+ itemsStorage.addItem(item);
+ }
+
}
@Override
@@ -97,7 +149,16 @@ public Item[] getAllItems() {
@Override
public void tick(TickSession tickSession) {
if (!tickSession.isAllowed(this)) return;
+ if (DISABLE_TAB) {
+ return;
+ }
+ if (GEN_COLORS) {
+ for (int i = 0; i < 2; i++) {
+ tick_genColors(tickSession);
+ }
+ return;
+ }
tick111(itemsStorage);
for (Item item : getAllItems()) {
if (item instanceof ItemsStorage) {
@@ -106,6 +167,47 @@ public void tick(TickSession tickSession) {
}
}
+ boolean flag = true;
+ int color;
+ ItemCallback itemCallback = new ItemCallback() {
+ @Override
+ public Status click(Item item) {
+ String color = ColorUtil.colorToHex(item.getViewBackgroundColor());
+ FileUtil.addText(new File(App.get().getExternalCacheDir(), "beautify_colors.txt"), color + "\n");
+ item.setMinimize(true);
+ if (item instanceof TextItem t) {
+ t.setText("[YES] " + t.getText());
+ }
+ item.visibleChanged();
+ return super.click(item);
+ }
+ };
+ private void tick_genColors(TickSession tickSession) {
+ if (flag) {
+ color = RandomUtil.nextInt() | 0xFF000000;
+ Item item = ItemsRegistry.REGISTRY.get(ItemType.values()[RandomUtil.nextInt(ItemType.values().length)]).create();
+ if (item instanceof TextItem textItem) {
+ textItem.setViewCustomBackgroundColor(true);
+ textItem.setViewBackgroundColor(color);
+ textItem.setText("Hello everybody!");
+ }
+ item.getItemCallbacks().addCallback(CallbackImportance.DEFAULT, itemCallback);
+ itemsStorage.addItem(item);
+ }
+ if (!flag) {
+ Item item = ItemsRegistry.REGISTRY.get(ItemType.values()[RandomUtil.nextInt(ItemType.values().length)]).create();
+ if (item instanceof TextItem textItem) {
+ textItem.setViewCustomBackgroundColor(true);
+ textItem.setViewBackgroundColor(color);
+ textItem.setParagraphColorize(true);
+ textItem.setText("$[-#ffffff]White text! $[-#000000] Black text $[-#ff00ff]" + ColorUtil.colorToHex(color));
+ }
+ item.getItemCallbacks().addCallback(CallbackImportance.DEFAULT, itemCallback);
+ itemsStorage.addItem(item);
+ }
+ flag = !flag;
+ }
+
public void tick111(ItemsStorage itemsStorage) {
byte mode = (byte) (RandomUtil.nextBoolean() ? 0 : 1); // 0 remove; 1 add
if (itemsStorage.isEmpty()) mode = 1;
@@ -138,6 +240,11 @@ public int size() {
return itemsStorage.size();
}
+ @Override
+ public int totalSize() {
+ return itemsStorage.totalSize();
+ }
+
@NonNull
@Override
public CallbackStorage getOnItemsStorageCallbacks() {
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/tab/LocalItemsTab.java b/app/src/main/java/com/fazziclay/opentoday/app/items/tab/LocalItemsTab.java
index e2c1f649..5ba02b2b 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/tab/LocalItemsTab.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/tab/LocalItemsTab.java
@@ -116,6 +116,11 @@ public int size() {
return itemsStorage.size();
}
+ @Override
+ public int totalSize() {
+ return itemsStorage.totalSize();
+ }
+
@NonNull
@Override
public CallbackStorage getOnItemsStorageCallbacks() {
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/tab/Tab.java b/app/src/main/java/com/fazziclay/opentoday/app/items/tab/Tab.java
index 1fd28e8d..ac7042f5 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/tab/Tab.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/tab/Tab.java
@@ -4,6 +4,7 @@
import androidx.annotation.Nullable;
import com.fazziclay.opentoday.app.data.Cherry;
+import com.fazziclay.opentoday.app.icons.IconsRegistry;
import com.fazziclay.opentoday.app.items.ItemsRoot;
import com.fazziclay.opentoday.app.items.ItemsStorage;
import com.fazziclay.opentoday.app.items.Unique;
@@ -22,6 +23,7 @@ protected static class TabCodec extends AbstractTabCodec {
private static final String KEY_ID = "id";
private static final String KEY_NAME = "name";
private static final String KEY_DISABLE_TICK = "disableTick";
+ private static final String KEY_ICON = "icon";
@NonNull
@Override
@@ -29,7 +31,9 @@ public Cherry exportTab(@NonNull Tab tab) {
return new Cherry()
.put(KEY_NAME, tab.name)
.put(KEY_ID, tab.id == null ? null : tab.id.toString())
- .put(KEY_DISABLE_TICK, tab.disableTick);
+ .put(KEY_DISABLE_TICK, tab.disableTick)
+ .put(KEY_ICON, tab.icon.getId());
+
}
@NonNull
@@ -38,7 +42,7 @@ public Tab importTab(@NonNull Cherry cherry, @Nullable Tab tab) {
if (cherry.has(KEY_ID)) tab.id = UUID.fromString(cherry.getString(KEY_ID));
tab.name = cherry.optString(KEY_NAME, "");
tab.disableTick = cherry.optBoolean(KEY_DISABLE_TICK, false);
-
+ tab.icon = IconsRegistry.REGISTRY.getById(cherry.optString(KEY_ICON, IconsRegistry.REGISTRY.NONE.getId()));
if (tab.id == null) Logger.w("Tab", "id is null while importing...");
return tab;
}
@@ -47,6 +51,7 @@ public Tab importTab(@NonNull Cherry cherry, @Nullable Tab tab) {
@RequireSave @SaveKey(key = "id") private UUID id = null;
@RequireSave @SaveKey(key = "name") private String name = "";
@RequireSave @SaveKey(key = "disableTick") private boolean disableTick = false;
+ @RequireSave @SaveKey(key = "icon") private IconsRegistry.Icon icon = IconsRegistry.REGISTRY.NONE;
private TabController controller;
public Tab(String name) {
@@ -113,6 +118,15 @@ public void setName(String text) {
if (controller != null) controller.nameChanged(this);
}
+ public IconsRegistry.Icon getIcon() {
+ return icon;
+ }
+
+ public void setIcon(IconsRegistry.Icon icon) {
+ this.icon = icon;
+ if (controller != null) controller.iconChanged(this);
+ }
+
@Override
public void save() {
if (controller != null) {
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/tab/TabController.java b/app/src/main/java/com/fazziclay/opentoday/app/items/tab/TabController.java
index eca200bc..ac080bb3 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/tab/TabController.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/tab/TabController.java
@@ -14,4 +14,5 @@ public interface TabController {
void nameChanged(@NonNull final Tab tab);
UUID generateId();
ItemsRoot getRoot();
+ void iconChanged(Tab tab);
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/tab/TabsManager.java b/app/src/main/java/com/fazziclay/opentoday/app/items/tab/TabsManager.java
index 08356ebc..39d252a2 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/tab/TabsManager.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/tab/TabsManager.java
@@ -7,11 +7,14 @@
import com.fazziclay.javaneoutil.FileUtil;
import com.fazziclay.opentoday.Debug;
+import com.fazziclay.opentoday.api.EventHandler;
import com.fazziclay.opentoday.app.App;
import com.fazziclay.opentoday.app.CrashReportContext;
import com.fazziclay.opentoday.app.ImportantDebugCallback;
import com.fazziclay.opentoday.app.Translation;
import com.fazziclay.opentoday.app.data.CherryOrchard;
+import com.fazziclay.opentoday.app.events.items.ItemsRootDestroyedEvent;
+import com.fazziclay.opentoday.app.events.items.ItemsRootInitializedEvent;
import com.fazziclay.opentoday.app.items.ItemPath;
import com.fazziclay.opentoday.app.items.ItemsRoot;
import com.fazziclay.opentoday.app.items.ItemsStorage;
@@ -49,7 +52,7 @@
public class TabsManager implements ItemsRoot, Tickable {
public static final int TAB_NAME_MAX_LENGTH = 35;
- private static final boolean DEBUG_ITEMS_SET = false;
+ private static final boolean DEBUG_ITEMS_SET = false; // Default value is FALSE!!!!!!!!!
private static final String TAG = "TabsManager";
private boolean destroyed;
@@ -71,6 +74,7 @@ public TabsManager(@NotNull final File dataOriginalFile, @NotNull final File dat
this.dataCompressFile = dataCompressFile;
this.translation = translation;
load();
+ EventHandler.call(new ItemsRootInitializedEvent(this));
}
@Nullable
@@ -285,6 +289,7 @@ public void destroy() {
}
destroyed = true;
+ EventHandler.call(new ItemsRootDestroyedEvent(this));
}
private void checkDestroy() {
@@ -322,6 +327,13 @@ public UUID generateId() {
public ItemsRoot getRoot() {
return TabsManager.this;
}
+
+ @Override
+ public void iconChanged(Tab tab) {
+ onTabsChangedCallbacks.run((callbackStorage, callback) -> callback.onTabIconChanged(tab, getTabPosition(tab)));
+ TabsManager.this.internalOnTabChanged();
+ TabsManager.this.queueSave(SaveInitiator.USER);
+ }
}
// ==== Tick ====
@@ -504,6 +516,7 @@ public boolean saveAllDirect() {
writer.write(originalData);
writer.flush();
writer.close();
+ gz.close();
}
if (debugPrintSaveStatusAlways) {
@@ -539,7 +552,7 @@ public SaveThread() {
public void run() {
while (!isInterrupted() && enabled) {
if (request && (requestImportance > 0 || ((System.currentTimeMillis() - firstRequestTime) > 1000 * 10))) {
- if (App.LOG) Logger.i(TAG, String.format("SaveThread: requestCount=%s\nfirstTime=%s\nlatestTime=%s", requestsCount, TimeUtil.getDebugDate(firstRequestTime), TimeUtil.getDebugDate(latestRequestTime)));
+ Logger.i(TAG, String.format("SaveThread: requestCount=%s\nfirstTime=%s\nlatestTime=%s", requestsCount, TimeUtil.getDebugDate(firstRequestTime), TimeUtil.getDebugDate(latestRequestTime)));
request = false;
requestsCount = Debug.latestSaveRequestsCount = 0;
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/tag/ItemTag.java b/app/src/main/java/com/fazziclay/opentoday/app/items/tag/ItemTag.java
new file mode 100644
index 00000000..27dc91fe
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/tag/ItemTag.java
@@ -0,0 +1,73 @@
+package com.fazziclay.opentoday.app.items.tag;
+
+import androidx.annotation.NonNull;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class ItemTag {
+ private @NotNull String name;
+ private @Nullable String value;
+ private @NotNull ValueType valueType = ValueType.NULL;
+ private boolean bind = false;
+
+ public ItemTag(@NonNull String name, @Nullable String value) {
+ this.name = name;
+ this.value = value;
+ recalcValueType();
+ }
+
+ private void recalcValueType() {
+ if (value == null) {
+ valueType = ValueType.NULL;
+ } else {
+ try {
+ Double.valueOf(value);
+ valueType = ValueType.NUMBER;
+ } catch (Exception e) {
+ valueType = ValueType.STRING;
+ }
+ }
+ }
+
+ public void setName(@NotNull String name) {
+ this.name = name;
+ }
+
+ public void setValue(@Nullable String value) {
+ this.value = value;
+ recalcValueType();
+ }
+
+ @NotNull
+ public ValueType getValueType() {
+ return valueType;
+ }
+
+ @NotNull
+ public String getName() {
+ return name;
+ }
+
+ @Nullable
+ public String getValue() {
+ return value;
+ }
+
+ protected ItemTag copy() {
+ return new ItemTag(name, value);
+ }
+
+ public void bind() {
+ if (bind) {
+ throw new RuntimeException("This ItemTag already bind.");
+ }
+ bind = true;
+ }
+
+ public enum ValueType {
+ NULL,
+ NUMBER,
+ STRING
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/tag/ItemTagsRegistry.java b/app/src/main/java/com/fazziclay/opentoday/app/items/tag/ItemTagsRegistry.java
new file mode 100644
index 00000000..d98b8891
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/tag/ItemTagsRegistry.java
@@ -0,0 +1,16 @@
+package com.fazziclay.opentoday.app.items.tag;
+
+// currently unused ()
+public class ItemTagsRegistry {
+ public static final ItemTagsRegistry REGISTRY = new ItemTagsRegistry();
+
+ private static final TagInfo[] INFOS = new TagInfo[]{
+
+ };
+
+ private ItemTagsRegistry() {}
+
+ public static class TagInfo {
+
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/tag/TagsCodecUtil.java b/app/src/main/java/com/fazziclay/opentoday/app/items/tag/TagsCodecUtil.java
new file mode 100644
index 00000000..bde1bbfb
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/tag/TagsCodecUtil.java
@@ -0,0 +1,32 @@
+package com.fazziclay.opentoday.app.items.tag;
+
+import com.fazziclay.opentoday.app.data.Cherry;
+import com.fazziclay.opentoday.app.data.CherryOrchard;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TagsCodecUtil {
+ public static List importTagsList(final CherryOrchard orchard) {
+ final List ret = new ArrayList<>();
+
+ orchard.forEachCherry((index, cherry) -> {
+ var tag = new ItemTag(cherry.getString("name"), cherry.getString("value"));
+ ret.add(tag);
+ });
+
+ return ret;
+ }
+
+ public static CherryOrchard exportTagsList(final List tags) {
+ final CherryOrchard orchard = new CherryOrchard();
+ for (final ItemTag tag : tags) {
+ final Cherry cherry = orchard.createAndAdd();
+ cherry.put("tagType", "pre_registry_generic_tag");
+ cherry.put("name", tag.getName());
+ cherry.put("value", tag.getValue());
+ }
+
+ return orchard;
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/tag/TagsUtil.java b/app/src/main/java/com/fazziclay/opentoday/app/items/tag/TagsUtil.java
new file mode 100644
index 00000000..ed5ad649
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/tag/TagsUtil.java
@@ -0,0 +1,20 @@
+package com.fazziclay.opentoday.app.items.tag;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TagsUtil {
+ public static List copy(final List tags) {
+ final List ret = new ArrayList<>();
+
+ for (final ItemTag tag : tags) {
+ ret.add(copy(tag));
+ }
+
+ return ret;
+ }
+
+ public static ItemTag copy(final ItemTag itemTag) {
+ return itemTag.copy();
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/tick/ItemsTickReceiver.java b/app/src/main/java/com/fazziclay/opentoday/app/items/tick/ItemsTickReceiver.java
index f01f0861..426de087 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/tick/ItemsTickReceiver.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/tick/ItemsTickReceiver.java
@@ -4,11 +4,15 @@
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.widget.Toast;
import androidx.core.app.NotificationCompat;
+import com.fazziclay.opentoday.Debug;
import com.fazziclay.opentoday.R;
import com.fazziclay.opentoday.app.App;
+import com.fazziclay.opentoday.app.items.item.Item;
+import com.fazziclay.opentoday.app.items.notification.ItemNotification;
import com.fazziclay.opentoday.util.Logger;
import java.util.ArrayList;
@@ -35,6 +39,12 @@ public static Intent createIntent(Context context, String[] array, boolean usePa
.putExtra(EXTRA_PERSONAL_TICK_MODE, (usePaths ? PersonalTickMode.PERSONAL_AND_PATH : PersonalTickMode.PERSONAL_ONLY).name());
}
+ public static Intent createNotificationTriggerIntent(Context context, ItemNotification itemNotification) {
+ final Item item = itemNotification.getParentItem();
+ return createIntent(context, item.getId(), true);
+ // TODO: 22.10.2023 currently while item tick ticked all item notifications! maybe need specify by notify id?
+ }
+
@Override
public void onReceive(Context context, Intent intent) {
Logger.d(TAG, "onReceive(...)");
@@ -45,7 +55,9 @@ public void onReceive(Context context, Intent intent) {
if (intent != null && intent.getExtras() != null && intent.getExtras().containsKey("debugMessage")) {
String s = intent.getExtras().getString("debugMessage", "none");
- //Toast.makeText(context, "ItemsTickReceive: " + s, Toast.LENGTH_SHORT).show();
+ if (Debug.SHOW_DEBUG_MESSAGE_TOAST_IN_ITEMSTICKRECEIVER) {
+ Toast.makeText(context, "ItemsTickReceive: " + s, Toast.LENGTH_SHORT).show();
+ }
Logger.d("ItemsTickReceiver", "DebugMessage! " + s);
}
@@ -72,7 +84,7 @@ public void onReceive(Context context, Intent intent) {
}
private void debugNotification(Context context) {
- if (App.DEBUG_TICK_NOTIFICATION) {
+ if (Debug.DEBUG_TICK_NOTIFICATION) {
context.getSystemService(NotificationManager.class).notify(321, new NotificationCompat.Builder(context, App.NOTIFICATION_ITEMS_CHANNEL)
.setSmallIcon(R.mipmap.ic_launcher)
.setSilent(true)
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/tick/TickSession.java b/app/src/main/java/com/fazziclay/opentoday/app/items/tick/TickSession.java
index 6d83e388..888b2597 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/tick/TickSession.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/tick/TickSession.java
@@ -1,14 +1,11 @@
package com.fazziclay.opentoday.app.items.tick;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.os.Build;
-
import com.fazziclay.opentoday.app.App;
+import com.fazziclay.opentoday.app.ItemNotificationHandler;
import com.fazziclay.opentoday.app.items.Unique;
import com.fazziclay.opentoday.app.items.item.Item;
import com.fazziclay.opentoday.util.Logger;
+import com.fazziclay.opentoday.util.profiler.Profiler;
import org.jetbrains.annotations.NotNull;
@@ -17,9 +14,9 @@
import java.util.List;
import java.util.Stack;
import java.util.UUID;
+import java.util.function.Function;
public class TickSession {
- private static boolean exceptionOnce = true;
private static final String TAG = "TickSession";
private static final boolean LOG_ISALLOWED = App.debug(false);
@@ -33,23 +30,30 @@ public static GregorianCalendar getLatestGregorianCalendar() {
return gregorianCalendar1;
}
- private final Context context;
+ private final ItemNotificationHandler itemNotificationHandler;
private GregorianCalendar gregorianCalendar;
private GregorianCalendar noTimeCalendar;
private int dayTime;
private boolean isPersonalTick;
+ private Profiler profiler;
private boolean saveNeeded = false;
private boolean importantSaveNeeded = false;
private final Stack
> specifiedTickTarget = new Stack<>();
+ private final Stack> plannedTick = new Stack<>();
private final List whitelist = new ArrayList<>();
private boolean isWhitelist = false;
- public TickSession(Context context, GregorianCalendar gregorianCalendar, GregorianCalendar noTimeCalendar, int dayTime, boolean isPersonalTick) {
- this.context = context;
+ public TickSession(ItemNotificationHandler itemNotificationHandler, GregorianCalendar gregorianCalendar, GregorianCalendar noTimeCalendar, int dayTime, boolean isPersonalTick, Profiler profiler) {
+ this.itemNotificationHandler = itemNotificationHandler;
this.gregorianCalendar = gregorianCalendar;
this.noTimeCalendar = noTimeCalendar;
this.dayTime = dayTime;
this.isPersonalTick = isPersonalTick;
+ this.profiler = profiler;
+ }
+
+ public Profiler getProfiler() {
+ return profiler;
}
public boolean isAllowed(Unique unique) {
@@ -70,12 +74,21 @@ public boolean isTickTargetAllowed(TickTarget tickTarget) {
return specifiedTickTarget.lastElement().contains(tickTarget);
}
+ public boolean isPlannedTick(Item item) {
+ if (plannedTick.isEmpty()) return false;
+ return plannedTick.lastElement().contains(item);
+ }
+
public void runWithSpecifiedTickTargets(List targets, Runnable r) {
specifiedTickTarget.push(targets);
r.run();
specifiedTickTarget.pop();
}
+ public boolean isTickedWithSpecifiedTickTarget() {
+ return !specifiedTickTarget.isEmpty();
+ }
+
public GregorianCalendar getGregorianCalendar() {
return gregorianCalendar;
}
@@ -88,10 +101,6 @@ public int getDayTime() {
return dayTime;
}
- public Context getContext() {
- return context;
- }
-
public boolean isPersonalTick() {
return isPersonalTick;
}
@@ -108,26 +117,6 @@ public boolean isImportantSaveNeeded() {
return importantSaveNeeded;
}
- public void setAlarmDayOfTimeInSeconds(int time, Item item) {
- final long shift = getDayTime() >= time ? (24*60*60*1000L) : 0; // IN MILLIS!!
- final AlarmManager alarmManager = getContext().getSystemService(AlarmManager.class);
- final int flags;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- flags = PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE;
- } else {
- flags = PendingIntent.FLAG_UPDATE_CURRENT;
- }
- long triggerAtMs = getNoTimeCalendar().getTimeInMillis() + shift + (time * 1000L) + 599;
- try {
- alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMs, PendingIntent.getBroadcast(getContext(), item.getId().hashCode() + time, ItemsTickReceiver.createIntent(context, item.getId(), true).putExtra("debugMessage", "DayItemNotification is work :)\nItem:\n * id-hashCode: " + item.getId().hashCode() + "\n * Item: " + item + " time: " + time), flags));
- } catch (Exception e) {
- if (exceptionOnce) {
- App.exception(null, e);
- exceptionOnce = false;
- }
- }
- }
-
public void recyclePersonal(boolean b) {
this.isPersonalTick = b;
}
@@ -180,6 +169,10 @@ public void importantSaveNeeded() {
this.importantSaveNeeded = true;
}
+ public ItemNotificationHandler getItemNotificationHandler() {
+ return itemNotificationHandler;
+ }
+
@NotNull
@Override
public String toString() {
@@ -189,4 +182,19 @@ public String toString() {
", whitelist=" + whitelist +
'}';
}
+
+ public void runWithPlannedNormalTick(List list, Function f, Runnable o) {
+ final List- i;
+ if (f == null) {
+ i = (List
- ) new ArrayList<>(list);
+ } else {
+ i = new ArrayList<>();
+ for (final T t : list) {
+ i.add(f.apply(t));
+ }
+ }
+ plannedTick.push(i);
+ o.run();
+ plannedTick.pop();
+ }
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/items/tick/TickThread.java b/app/src/main/java/com/fazziclay/opentoday/app/items/tick/TickThread.java
index 8c461e37..a84b9999 100644
--- a/app/src/main/java/com/fazziclay/opentoday/app/items/tick/TickThread.java
+++ b/app/src/main/java/com/fazziclay/opentoday/app/items/tick/TickThread.java
@@ -12,6 +12,7 @@
import com.fazziclay.opentoday.app.items.item.ItemUtil;
import com.fazziclay.opentoday.app.items.tab.TabsManager;
import com.fazziclay.opentoday.util.Logger;
+import com.fazziclay.opentoday.util.profiler.Profiler;
import com.fazziclay.opentoday.util.time.TimeUtil;
import java.util.ArrayList;
@@ -21,6 +22,7 @@
public class TickThread extends Thread {
private static final String TAG = "TickThread";
+ private static final Profiler PROFILER = App.createProfiler("TickThread");
private static boolean exceptionOnceDebugFlag = true; // for once call App.exception(...)
private static final boolean LOG = App.debug(true);
private static final boolean LOG_ONLY_PERSONAL = true;
@@ -55,7 +57,7 @@ public TickThread(Context context, TabsManager tabsManager) {
}
private void log(String s) {
- if (App.LOG && LOG) {
+ if (LOG) {
if (LOG_ONLY_PERSONAL) {
if (currentlyExecutingTickPersonal) {
Logger.d(TAG, s);
@@ -68,23 +70,28 @@ private void log(String s) {
@Override
public void run() {
+ PROFILER.push("run");
enabled = true;
while (!isInterrupted() && enabled) {
+ PROFILER.push("tick");
long tickStart = System.currentTimeMillis();
if (requested) {
try {
log("Processing requests: " + requests + "; all: "+requestedAll+"; personal: " + requestedPersonal);
+ PROFILER.push("all");
if (requestedAll) {
recycle(false);
tickAll();
}
+ PROFILER.swap("personal");
if (requestedPersonal) {
recycle(true);
tickPersonal();
}
+ PROFILER.swap("save");
if (defaultTickSession.isSaveNeeded()) {
if (defaultTickSession.isImportantSaveNeeded()) {
tabsManager.queueSave(SaveInitiator.USER);
@@ -92,15 +99,19 @@ public void run() {
tabsManager.queueSave(requestedPersonal ? SaveInitiator.TICK_PERSONAL : SaveInitiator.TICK);
}
}
+ PROFILER.pop();
} catch (Exception e) {
+ PROFILER.push("exceptions");
Logger.e(TAG, "EXCEPTION IN TICK!!!!!!!", e);
if (exceptionOnceDebugFlag) {
App.exception(null, e);
exceptionOnceDebugFlag = false;
}
+ PROFILER.pop2();
}
// reset requests
+ PROFILER.push("resets");
personalsNoPaths.clear();
personalsPaths.clear();
requested = false;
@@ -109,9 +120,11 @@ public void run() {
firstRequestTime = 0;
lastRequestTime = 0;
requests = 0;
+ PROFILER.pop();
}
long tickEnd = System.currentTimeMillis();
+ PROFILER.swap("sleep");
try {
int sleep = (int) (1000 - (tickEnd - tickStart));
if (sleep <= 0) sleep = 1;
@@ -120,18 +133,23 @@ public void run() {
} catch (Exception e) {
throw new RuntimeException(e);
}
+ PROFILER.pop();
}
log("Thread done.");
interrupt();
enabled = false;
+ PROFILER.pop();
}
private void tickAll() {
+ PROFILER.push("tickAll");
tabsManager.tick(defaultTickSession);
log("Tick all");
+ PROFILER.pop();
}
private void tickPersonal() {
+ PROFILER.push("tickPersonal");
currentlyExecutingTickPersonal = true;
if (!this.personalsNoPaths.isEmpty()) {
List personalsNoPaths = new ArrayList<>(this.personalsNoPaths);
@@ -163,9 +181,11 @@ private void tickPersonal() {
currentlyExecutingTickPersonal = false;
+ PROFILER.pop();
}
private void recycle(boolean personal) {
+ PROFILER.push("recycle");
log("recycle. personal="+personal);
GregorianCalendar gregorianCalendar = new GregorianCalendar();
GregorianCalendar noTimeCalendar = TimeUtil.noTimeCalendar(gregorianCalendar);
@@ -179,6 +199,7 @@ private void recycle(boolean personal) {
defaultTickSession.recycleSaveNeeded();
defaultTickSession.recycleWhitelist(false);
defaultTickSession.recycleSpecifiedTickTarget();
+ PROFILER.pop();
}
@@ -238,7 +259,7 @@ private TickSession createTickSession(Context context) {
int daySeconds = (int) ((gregorianCalendar.getTimeInMillis() - noTimeCalendar.getTimeInMillis()) / 1000);
- return new TickSession(context, gregorianCalendar, noTimeCalendar, daySeconds, false);
+ return new TickSession(App.get(context).getItemNotificationHandler(), gregorianCalendar, noTimeCalendar, daySeconds, false, PROFILER);
}
public void requestTerminate() {
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/settings/ActionBarPosition.java b/app/src/main/java/com/fazziclay/opentoday/app/settings/ActionBarPosition.java
new file mode 100644
index 00000000..02b5b255
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/settings/ActionBarPosition.java
@@ -0,0 +1,6 @@
+package com.fazziclay.opentoday.app.settings;
+
+public enum ActionBarPosition {
+ TOP,
+ BOTTOM
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/settings/BooleanOption.java b/app/src/main/java/com/fazziclay/opentoday/app/settings/BooleanOption.java
new file mode 100644
index 00000000..24d4fa0e
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/settings/BooleanOption.java
@@ -0,0 +1,29 @@
+package com.fazziclay.opentoday.app.settings;
+
+public class BooleanOption extends Option {
+ public BooleanOption(String saveKey, boolean maybeUndefined, boolean defVal) {
+ super(saveKey, maybeUndefined, defVal);
+ }
+
+ public void set(SettingsManager sm, boolean val) {
+ _set(sm, val);
+ }
+
+ public boolean get(SettingsManager sm) {
+ Object o = _get(sm);
+ if (o instanceof Boolean bool) {
+ return bool;
+ }
+ throw new RuntimeException("SettingsManager.BooleanOption can't be get because internal error :(");
+ }
+
+ @Override
+ public Object parseValue(Object o) {
+ return (Boolean) o;
+ }
+
+ @Override
+ public Object writeValue(Object o) {
+ return (Boolean) o;
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/settings/ColorOption.java b/app/src/main/java/com/fazziclay/opentoday/app/settings/ColorOption.java
new file mode 100644
index 00000000..1ab717d9
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/settings/ColorOption.java
@@ -0,0 +1,7 @@
+package com.fazziclay.opentoday.app.settings;
+
+public class ColorOption extends IntegerOption {
+ public ColorOption(String saveKey, boolean maybeUndefined, int defVal) {
+ super(saveKey, maybeUndefined, defVal);
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/settings/EnumOption.java b/app/src/main/java/com/fazziclay/opentoday/app/settings/EnumOption.java
new file mode 100644
index 00000000..013cdd5a
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/settings/EnumOption.java
@@ -0,0 +1,34 @@
+package com.fazziclay.opentoday.app.settings;
+
+public class EnumOption> extends Option {
+ private final Class clazz;
+
+ public EnumOption(String saveKey, boolean maybeUndefined, T defVal) {
+ super(saveKey, maybeUndefined, defVal);
+ this.clazz = (Class) defVal.getClass();
+ }
+
+ public T get(SettingsManager sm) {
+ Object o = _get(sm);
+ if (o instanceof Enum> anEnum) {
+ return (T) anEnum;
+ }
+ throw new RuntimeException("SettingsManager unknown value in EnumOption");
+ }
+
+ public void set(SettingsManager sm, T t) {
+ _set(sm, t);
+ }
+
+ @Override
+ public Object parseValue(Object o) {
+ String s = (String) o;
+ return Enum.valueOf(clazz, s);
+ }
+
+ @Override
+ public Object writeValue(Object o) {
+ T anEnum = (T) o;
+ return anEnum.name();
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/settings/IntegerOption.java b/app/src/main/java/com/fazziclay/opentoday/app/settings/IntegerOption.java
new file mode 100644
index 00000000..408bdc0b
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/settings/IntegerOption.java
@@ -0,0 +1,25 @@
+package com.fazziclay.opentoday.app.settings;
+
+public class IntegerOption extends Option {
+ public IntegerOption(String saveKey, boolean maybeUndefined, int defVal) {
+ super(saveKey, maybeUndefined, defVal);
+ }
+
+ public void set(SettingsManager sm, int s) {
+ _set(sm, s);
+ }
+
+ public int get(SettingsManager sm) {
+ return (int) _get(sm);
+ }
+
+ @Override
+ public Object parseValue(Object o) {
+ return (int) o;
+ }
+
+ @Override
+ public Object writeValue(Object o) {
+ return (int) o;
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/settings/Option.java b/app/src/main/java/com/fazziclay/opentoday/app/settings/Option.java
new file mode 100644
index 00000000..00b4aa49
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/settings/Option.java
@@ -0,0 +1,52 @@
+package com.fazziclay.opentoday.app.settings;
+
+public class Option {
+ protected String saveKey;
+ protected boolean maybeUndefined;
+ protected Object defVal;
+
+ public Option(String saveKey, boolean maybeUndefined, Object defVal) {
+ this.saveKey = saveKey;
+ this.maybeUndefined = maybeUndefined;
+ this.defVal = defVal;
+ }
+
+ public String getSaveKey() {
+ return saveKey;
+ }
+
+ protected Object _get(SettingsManager sm) {
+ Object o = sm.getOption(this);
+ if (o == null) {
+ if (!maybeUndefined) {
+ _set(sm, defVal);
+ }
+ return defVal;
+ }
+ return o;
+ }
+
+ public Object getObject(SettingsManager sm) {
+ return _get(sm);
+ }
+
+ protected void _set(SettingsManager sm, Object o) {
+ sm.setOption(this, o);
+ }
+
+ public void def(SettingsManager sm) {
+ if (maybeUndefined) {
+ sm.clearOption(this);
+ } else {
+ throw new UnsupportedOperationException("This option can't be undefined");
+ }
+ }
+
+ public Object parseValue(Object o) {
+ return o;
+ }
+
+ public Object writeValue(Object o) {
+ return o;
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/settings/SettingsManager.java b/app/src/main/java/com/fazziclay/opentoday/app/settings/SettingsManager.java
new file mode 100644
index 00000000..6301d3b3
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/settings/SettingsManager.java
@@ -0,0 +1,407 @@
+package com.fazziclay.opentoday.app.settings;
+
+import static com.fazziclay.opentoday.util.InlineUtil.IPROF;
+
+import android.graphics.Color;
+import android.util.ArraySet;
+
+import com.fazziclay.javaneoutil.FileUtil;
+import com.fazziclay.opentoday.app.App;
+import com.fazziclay.opentoday.app.items.item.ItemType;
+import com.fazziclay.opentoday.app.items.item.ItemsRegistry;
+import com.fazziclay.opentoday.app.settings.enums.DateAndTimePreset;
+import com.fazziclay.opentoday.app.settings.enums.FirstDayOfWeek;
+import com.fazziclay.opentoday.app.settings.enums.FirstTab;
+import com.fazziclay.opentoday.app.settings.enums.ItemAction;
+import com.fazziclay.opentoday.app.settings.enums.ItemAddPosition;
+import com.fazziclay.opentoday.app.settings.enums.ThemeEnum;
+import com.fazziclay.opentoday.util.Logger;
+import com.fazziclay.opentoday.util.annotation.Getter;
+import com.fazziclay.opentoday.util.annotation.Setter;
+import com.fazziclay.opentoday.util.callback.Callback;
+import com.fazziclay.opentoday.util.callback.CallbackStorage;
+import com.fazziclay.opentoday.util.callback.Status;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.UUID;
+
+public class SettingsManager {
+ // static
+ private static final String TAG = "SettingsManager";
+ private static final Set REGISTERED_OPTIONS = new ArraySet<>();
+
+ public static final EnumOption THEME = registerOption(new EnumOption<>("theme", false, ThemeEnum.AUTO));
+ public static final EnumOption FIRST_DAY_OF_WEEK = registerOption(new EnumOption<>("first_day_of_week", false, FirstDayOfWeek.SATURDAY));
+ public static final BooleanOption ANALOG_CLOCK_ENABLE = registerOption(new BooleanOption("analog_clock.enable", false, false));
+ public static final IntegerOption ANALOG_CLOCK_SIZE = registerOption(new IntegerOption("analog_clock.size", true, 90));
+ public static final IntegerOption ANALOG_CLOCK_TRANSPARENCY = registerOption(new IntegerOption("analog_clock.transparency", true, 65));
+ public static final ColorOption ANALOG_CLOCK_COLOR_SECONDS = registerOption(new ColorOption("analog_clock.color.second", true, Color.BLACK));
+ public static final ColorOption ANALOG_CLOCK_COLOR_MINUTE = registerOption(new ColorOption("analog_clock.color.minute", true, Color.BLACK));
+ public static final ColorOption ANALOG_CLOCK_COLOR_HOUR = registerOption(new ColorOption("analog_clock.color.hour", true, Color.BLACK));
+ public static final BooleanOption QUICK_NOTE_NOTIFICATION_ENABLE = registerOption(new BooleanOption("quick_note.notification.enable", false, true));
+ public static final BooleanOption QUICK_NOTE_PARSE_TIME_FROM_ITEM = registerOption(new BooleanOption("quick_note.parse_time_from_item", false, true));
+ public static final EnumOption QUICK_NOTE_ITEM_TYPE = registerOption(new EnumOption<>("quick_note.item_type", false, ItemType.CHECKBOX));
+ public static final BooleanOption ITEM_MINIMIZE_GRAY_COLOR = registerOption(new BooleanOption("item.minimize.gray_color", false, true));
+ public static final BooleanOption ITEM_TRIM_NAMES_IN_EDITOR = registerOption(new BooleanOption("item.editor.trim_names", false, true));
+ public static final BooleanOption ITEM_RANDOM_BACKGROUND = registerOption(new BooleanOption("item.random_background_on_create", false, true));
+ public static final BooleanOption ITEM_EDITOR_BACKGROUND_AS_ITEM = registerOption(new BooleanOption("item.use_container_editor_background_from_item", false, false));
+ public static final BooleanOption ITEM_IS_SCROLL_TO_ADDED = registerOption(new BooleanOption("item.is_scroll_to_added", false, true));
+ public static final EnumOption ITEM_ACTION_CLICK = registerOption(new EnumOption<>("item.action.click", false, ItemAction.OPEN_EDITOR));
+ public static final EnumOption ITEM_ACTION_LEFT_SWIPE = registerOption(new EnumOption<>("item.action.left_swipe", false, ItemAction.MINIMIZE_REVERT));
+ public static final EnumOption ITEM_ADD_POSITION = registerOption(new EnumOption<>("item.add_position", false, ItemAddPosition.BOTTOM));
+ public static final BooleanOption ITEM_PATH_VISIBLE = registerOption(new BooleanOption("item.path_visible", false, true));
+ public static final BooleanOption IS_TELEMETRY = registerOption(new BooleanOption("telemetry.enable", false, true));
+ public static final EnumOption DEFAULT_FIRST_TAB = registerOption(new EnumOption<>("first_tab", false, FirstTab.TAB_ON_CLOSING));
+ public static final EnumOption DATE_TIME_FORMAT = registerOption(new EnumOption<>("date_time_format", false, DateAndTimePreset.DEFAULT));
+ public static final BooleanOption FAST_CHANGES_CONFIRM = registerOption(new BooleanOption("fast_changes.confirm", false, true));
+ public static final BooleanOption IS_FIRST_LAUNCH = registerOption(new BooleanOption("is_first_launch", false, true));
+ public static final StringOption PLUGINS = registerOption(new StringOption("plugins", true, "")); // empty string is default
+ public static final BooleanOption TOOLBAR_AUTOMATICALLY_CLOSE = registerOption(new BooleanOption("toolbar.auto_close", false, true));
+ public static final EnumOption ACTIONBAR_POSITION = registerOption(new EnumOption<>("actionbar.position", false, ActionBarPosition.TOP));
+ public static final BooleanOption COLOR_HISTORY_ENABLED = registerOption(new BooleanOption("color_history.enabled", false, true));
+
+
+ // object
+ private final HashMap optionsValue = new HashMap<>();
+ private final File saveFile;
+ private final SaveThread saveThread;
+ public final CallbackStorage callbacks = new CallbackStorage<>();
+
+ protected void setOption(Option option, Object value) {
+ optionsValue.put(option, value);
+ callbacks.run((callbackStorage, callback) -> callback.run(option, value));
+ }
+
+ protected Object getOption(Option option) {
+ return optionsValue.get(option);
+ }
+
+ protected void clearOption(Option option) {
+ optionsValue.remove(option);
+ callbacks.run((callbackStorage, callback) -> callback.run(option, option.defVal));
+ }
+
+ private static T registerOption(T option) {
+ REGISTERED_OPTIONS.add(option);
+ return option;
+ }
+
+
+ public SettingsManager(File saveFile) {
+ this.saveFile = saveFile;
+ this.saveThread = new SaveThread();
+ load();
+ saveThread.start();
+ }
+
+ private void load() {
+ IPROF.push("SettingsManager:load");
+ try {
+ String text = FileUtil.getText(saveFile, "{}");
+ JSONObject json = new JSONObject(text);
+
+ for (Option option : REGISTERED_OPTIONS) {
+ String key = option.saveKey;
+ if (json.has(key)) {
+ setOption(option, option.parseValue(json.get(key)));
+ } else if (!option.maybeUndefined) {
+ setOption(option, option.defVal);
+ }
+ }
+
+ } catch (Exception e) {
+ Logger.e(TAG, "load", e);
+ App.exception(null, e);
+ }
+ IPROF.pop();
+ }
+
+ private class SaveThread extends Thread {
+ boolean requested = false;
+
+ public SaveThread() {
+ setName("SettingsManager.SaveThread");
+ }
+
+ @Override
+ public void run() {
+ while (true) {
+ if (requested) {
+ requested = false;
+ directSave();
+ }
+ try {
+ Thread.sleep(1500);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ public void request() {
+ this.requested = true;
+ }
+ }
+
+ public void directSave() {
+ try {
+ JSONObject j = exportJSONSettings();
+ FileUtil.setText(saveFile, j.toString());
+ } catch (Exception e) {
+ Logger.e(TAG, "save", e);
+ App.exception(null, e);
+ }
+ }
+
+ public void save() {
+ IPROF.push("SettingsManager:save");
+ saveThread.request();
+ IPROF.pop();
+ }
+
+ public JSONObject exportJSONSettings() throws JSONException {
+ JSONObject j = new JSONObject();
+
+ for (Option option : optionsValue.keySet()) {
+ Object value = optionsValue.get(option);
+ j.put(option.saveKey, option.writeValue(value));
+ }
+
+ return j;
+ }
+
+ public void importData(JSONObject settings) {
+ FileUtil.setText(saveFile, settings.toString());
+ load();
+ }
+
+ public boolean isChangeDefaultQuickNoteInLongSendClick() {
+ return false; // TODO: 22.10.2023 make editable
+ }
+
+
+
+
+
+
+ @Getter
+ public int getFirstDayOfWeek() {
+ return FIRST_DAY_OF_WEEK.get(this).id();
+ }
+
+ @Setter
+ public void setFirstDayOfWeek(int firstDayOfWeek) {
+ FIRST_DAY_OF_WEEK.set(this, FirstDayOfWeek.of(firstDayOfWeek));
+ }
+
+
+
+
+ public int getTheme() {
+ return THEME.get(this).id();
+ }
+
+ @Setter
+ public void setTheme(int theme) {
+ THEME.set(this, ThemeEnum.ofId(theme));
+ }
+
+
+
+
+
+ @Getter
+ public boolean isQuickNoteNotification() {
+ return QUICK_NOTE_NOTIFICATION_ENABLE.get(this);
+ }
+
+ @Setter
+ public void setQuickNoteNotification(boolean quickNoteNotification) {
+ QUICK_NOTE_NOTIFICATION_ENABLE.set(this, quickNoteNotification);
+ }
+
+ @Getter
+ public boolean isMinimizeGrayColor() {
+ return ITEM_MINIMIZE_GRAY_COLOR.get(this);
+ }
+
+ @Setter
+ public void setMinimizeGrayColor(boolean ff) {
+ ITEM_MINIMIZE_GRAY_COLOR.set(this, ff);
+ }
+
+ @Getter
+ public boolean isParseTimeFromQuickNote() {
+ return QUICK_NOTE_PARSE_TIME_FROM_ITEM.get(this);
+ }
+
+ @Setter
+ public void setParseTimeFromQuickNote(boolean parseTimeFromQuickNote) {
+ QUICK_NOTE_PARSE_TIME_FROM_ITEM.set(this, parseTimeFromQuickNote);
+ }
+
+ @Getter
+ public boolean isTrimItemNamesOnEdit() {
+ return ITEM_TRIM_NAMES_IN_EDITOR.get(this);
+ }
+
+ @Setter
+ public void setTrimItemNamesOnEdit(boolean trimItemNamesOnEdit) {
+ ITEM_TRIM_NAMES_IN_EDITOR.set(this, isTrimItemNamesOnEdit());
+ }
+
+ @Getter
+ public ItemAction getItemOnClickAction() {
+ return ITEM_ACTION_CLICK.get(this);
+ }
+
+ @Setter
+ public void setItemOnClickAction(ItemAction itemOnClickAction) {
+ ITEM_ACTION_CLICK.set(this, itemOnClickAction);
+ }
+
+ @Getter
+ public ItemAction getItemOnLeftAction() {
+ return ITEM_ACTION_LEFT_SWIPE.get(this);
+ }
+
+ @Setter
+ public void setItemOnLeftAction(ItemAction itemOnLeftAction) {
+ ITEM_ACTION_LEFT_SWIPE.set(this, itemOnLeftAction);
+ }
+
+ @Getter
+ public UUID getQuickNoteNotificationItemsStorageId() {
+ return null; // TODO: 30.10.2023 uuid not supported currently
+ }
+
+ @Setter
+ public void setQuickNoteNotificationItemsStorageId(UUID quickNoteNotificationItemsStorageId) {
+ // TODO: 30.10.2023 uuid not supported currently
+ }
+
+
+ @Getter
+ public ItemsRegistry.ItemInfo getDefaultQuickNoteType() {
+ return ItemsRegistry.REGISTRY.get(QUICK_NOTE_ITEM_TYPE.get(this));
+ }
+
+ @Setter
+ public void setDefaultQuickNoteType(ItemsRegistry.ItemInfo defaultQuickNoteType) {
+ QUICK_NOTE_ITEM_TYPE.set(this, defaultQuickNoteType.getItemType());
+ }
+
+ @Getter
+ public FirstTab getFirstTab() {
+ return DEFAULT_FIRST_TAB.get(this);
+ }
+
+ @Setter
+ public void setFirstTab(FirstTab firstTab) {
+ DEFAULT_FIRST_TAB.set(this, firstTab);
+ }
+
+ @Getter
+ public String getDatePattern() {
+ return DATE_TIME_FORMAT.get(this).getDate();
+ }
+
+ @Getter
+ public String getTimePattern() {
+ return DATE_TIME_FORMAT.get(this).getTime();
+ }
+
+
+ public void applyDateAndTimePreset(DateAndTimePreset p) {
+ DATE_TIME_FORMAT.set(this, p);
+ }
+
+ @Setter
+ public void setItemAddPosition(ItemAddPosition e) {
+ ITEM_ADD_POSITION.set(this, e);
+ }
+
+ @Getter
+ public ItemAddPosition getItemAddPosition() {
+ return ITEM_ADD_POSITION.get(this);
+ }
+
+ @Getter
+ public boolean isConfirmFastChanges() {
+ return FAST_CHANGES_CONFIRM.get(this);
+ }
+
+ @Setter
+ public void setConfirmFastChanges(boolean b) {
+ FAST_CHANGES_CONFIRM.set(this, b);
+ }
+
+ @Getter
+ public boolean isItemEditorBackgroundFromItem() {
+ return ITEM_EDITOR_BACKGROUND_AS_ITEM.get(this);
+ }
+
+ @Setter
+ public void setItemEditorBackgroundFromItem(boolean b) {
+ ITEM_EDITOR_BACKGROUND_AS_ITEM.set(this, b);
+ }
+
+ @Getter
+ public boolean isScrollToAddedItem() {
+ return ITEM_IS_SCROLL_TO_ADDED.get(this);
+ }
+
+ @Setter
+ public void setScrollToAddedItem(boolean b) {
+ ITEM_IS_SCROLL_TO_ADDED.set(this, b);
+ }
+
+ @Getter
+ public boolean isAutoCloseToolbar() {
+ return TOOLBAR_AUTOMATICALLY_CLOSE.get(this);
+ }
+
+ @Setter
+ public void setAutoCloseToolbar(boolean b) {
+ TOOLBAR_AUTOMATICALLY_CLOSE.set(this, b);
+ }
+
+ @Getter
+ public boolean isRandomItemBackground() {
+ return ITEM_RANDOM_BACKGROUND.get(this);
+ }
+
+ @Setter
+ public void setRandomItemBackground(boolean b) {
+ ITEM_RANDOM_BACKGROUND.set(this, b);
+ }
+
+ @Getter
+ public String getPlugins() {
+ return PLUGINS.get(this);
+ }
+
+ @Setter
+ public void setPlugins(String plugins) {
+ PLUGINS.set(this, plugins);
+ }
+
+
+ public boolean isSetupDone() {
+ return IS_FIRST_LAUNCH.get(this);
+ }
+
+ public void setIsFirstLaunch(boolean b) {
+ IS_FIRST_LAUNCH.set(this, b);
+ }
+
+
+ public interface OptionChangedCallback extends Callback {
+ Status run(Option option, Object value);
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/settings/StringOption.java b/app/src/main/java/com/fazziclay/opentoday/app/settings/StringOption.java
new file mode 100644
index 00000000..ab952d37
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/settings/StringOption.java
@@ -0,0 +1,25 @@
+package com.fazziclay.opentoday.app.settings;
+
+public class StringOption extends Option {
+ public StringOption(String saveKey, boolean maybeUndefined, String defVal) {
+ super(saveKey, maybeUndefined, defVal);
+ }
+
+ public void set(SettingsManager sm, String s) {
+ _set(sm, s);
+ }
+
+ public String get(SettingsManager sm) {
+ return (String) _get(sm);
+ }
+
+ @Override
+ public Object parseValue(Object o) {
+ return (String) o;
+ }
+
+ @Override
+ public Object writeValue(Object o) {
+ return (String) o;
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/settings/enums/DateAndTimePreset.java b/app/src/main/java/com/fazziclay/opentoday/app/settings/enums/DateAndTimePreset.java
new file mode 100644
index 00000000..16132066
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/settings/enums/DateAndTimePreset.java
@@ -0,0 +1,31 @@
+package com.fazziclay.opentoday.app.settings.enums;
+
+public enum DateAndTimePreset {
+ DEFAULT("HH:mm:ss", "yyyy.MM.dd EE"),
+ DEFAULT_FULLY_WEEKDAY("HH:mm:ss", "yyyy.MM.dd EEEE"),
+ NO_SECONDS("HH:mm", "yyyy.MM.dd EE"),
+ NO_SECONDS_FULLY_WEEKDAY("HH:mm", "yyyy.MM.dd EEEE"),
+ NO_TIME("", "yyyy.MM.dd EE"),
+ NO_TIME_INVERT("", "dd.MM.yyyy EE"),
+ NO_TIME_FULLY_WEEKDAY("", "yyyy.MM.dd EEEE"),
+ NO_TIME_FULLY_WEEKDAY_INVERT("", "dd.MM.yyyy EEEE"),
+ INVERT_DATE("HH:mm:ss", "dd.MM.yyyy EE"),
+ INVERT_DATE_FULLY_WEEKDAY("HH:mm:ss", "dd.MM.yyyy EEEE"),
+ ;
+
+ private final String time;
+ private final String date;
+
+ DateAndTimePreset(String time, String date) {
+ this.time = time;
+ this.date = date;
+ }
+
+ public String getTime() {
+ return time;
+ }
+
+ public String getDate() {
+ return date;
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/settings/enums/FirstDayOfWeek.java b/app/src/main/java/com/fazziclay/opentoday/app/settings/enums/FirstDayOfWeek.java
new file mode 100644
index 00000000..b658e63f
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/settings/enums/FirstDayOfWeek.java
@@ -0,0 +1,18 @@
+package com.fazziclay.opentoday.app.settings.enums;
+
+import java.util.Calendar;
+
+public enum FirstDayOfWeek {
+ MONDAY,
+ SATURDAY;
+
+ public static FirstDayOfWeek of(int i) {
+ if (i == Calendar.SATURDAY) return SATURDAY;
+ return MONDAY;
+ }
+
+ public int id() {
+ if (this == SATURDAY) return Calendar.SATURDAY;
+ return Calendar.MONDAY;
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/settings/enums/FirstTab.java b/app/src/main/java/com/fazziclay/opentoday/app/settings/enums/FirstTab.java
new file mode 100644
index 00000000..8015d78e
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/settings/enums/FirstTab.java
@@ -0,0 +1,6 @@
+package com.fazziclay.opentoday.app.settings.enums;
+
+public enum FirstTab {
+ FIRST,
+ TAB_ON_CLOSING
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/settings/enums/ItemAction.java b/app/src/main/java/com/fazziclay/opentoday/app/settings/enums/ItemAction.java
new file mode 100644
index 00000000..80322628
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/settings/enums/ItemAction.java
@@ -0,0 +1,15 @@
+package com.fazziclay.opentoday.app.settings.enums;
+
+// ==== ENUMS
+public enum ItemAction {
+ OPEN_EDITOR,
+ OPEN_TEXT_EDITOR,
+ SELECT_REVERT,
+ SELECT_ON,
+ SELECT_OFF,
+ DELETE_REQUEST,
+ MINIMIZE_REVERT,
+ MINIMIZE_ON,
+ MINIMIZE_OFF,
+ SHOW_ACTION_DIALOG
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/settings/enums/ItemAddPosition.java b/app/src/main/java/com/fazziclay/opentoday/app/settings/enums/ItemAddPosition.java
new file mode 100644
index 00000000..7f19f0f7
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/settings/enums/ItemAddPosition.java
@@ -0,0 +1,6 @@
+package com.fazziclay.opentoday.app.settings.enums;
+
+public enum ItemAddPosition {
+ TOP,
+ BOTTOM
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/app/settings/enums/ThemeEnum.java b/app/src/main/java/com/fazziclay/opentoday/app/settings/enums/ThemeEnum.java
new file mode 100644
index 00000000..3ab96f4c
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/app/settings/enums/ThemeEnum.java
@@ -0,0 +1,35 @@
+package com.fazziclay.opentoday.app.settings.enums;
+
+import android.graphics.Color;
+
+import androidx.appcompat.app.AppCompatDelegate;
+
+public enum ThemeEnum {
+ AUTO,
+ NIGHT,
+ LIGHT;
+
+ public static ThemeEnum ofId(int theme) {
+ return switch (theme) {
+ case AppCompatDelegate.MODE_NIGHT_NO -> LIGHT;
+ case AppCompatDelegate.MODE_NIGHT_YES -> NIGHT;
+ default -> AUTO;
+ };
+ }
+
+ public int id() {
+ return switch (this) {
+ case AUTO -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM;
+ case NIGHT -> AppCompatDelegate.MODE_NIGHT_YES;
+ case LIGHT -> AppCompatDelegate.MODE_NIGHT_NO;
+ };
+ }
+
+ public int getRawForegroundColor() {
+ return switch (this) {
+ case AUTO -> Color.GREEN;
+ case NIGHT -> Color.WHITE;
+ case LIGHT -> Color.BLACK;
+ };
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/ActivitySettings.java b/app/src/main/java/com/fazziclay/opentoday/gui/ActivitySettings.java
index 1406d363..37a59108 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/ActivitySettings.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/ActivitySettings.java
@@ -6,11 +6,30 @@
public class ActivitySettings implements Cloneable {
private boolean clockVisible = true;
+ private boolean analogClockForceVisible = false;
+ private boolean analogClockForceHidden = false;
private boolean notificationsVisible = true;
private boolean dateClickCalendar = true;
+ private boolean showCanonicalClock = false; // show clock if ACTIONBAR_POSITION in bottom and not show analog clock
private ToolbarSettings toolbarSettings = null;
+ public void analogClockForceVisible(boolean b) {
+ this.analogClockForceVisible = b;
+ }
+
+ public void analogClockForceHidden(boolean b) {
+ this.analogClockForceHidden = b;
+ }
+
+ public boolean isShowCanonicalClock() {
+ return showCanonicalClock;
+ }
+
+ public void setShowCanonicalClock(boolean showCanonicalClock) {
+ this.showCanonicalClock = showCanonicalClock;
+ }
+
public ActivitySettings setClockVisible(boolean clockVisible) {
this.clockVisible = clockVisible;
return this;
@@ -35,6 +54,14 @@ public boolean isClockVisible() {
return clockVisible;
}
+ public boolean isAnalogClockForceVisible() {
+ return analogClockForceVisible;
+ }
+
+ public boolean isAnalogClockForceHidden() {
+ return analogClockForceHidden;
+ }
+
public boolean isNotificationsVisible() {
return notificationsVisible;
}
@@ -67,6 +94,7 @@ public void setToolbarSettings(ToolbarSettings toolbarSettings) {
this.toolbarSettings = toolbarSettings;
}
+ @NotNull
@Override
public String toString() {
return "ActivitySettings{" +
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/BackendInitializer.java b/app/src/main/java/com/fazziclay/opentoday/gui/BackendInitializer.java
new file mode 100644
index 00000000..e7b8f882
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/BackendInitializer.java
@@ -0,0 +1,89 @@
+package com.fazziclay.opentoday.gui;
+
+import android.util.ArraySet;
+
+import androidx.annotation.NonNull;
+
+import com.fazziclay.opentoday.app.App;
+import com.fazziclay.opentoday.app.CrashReport;
+import com.fazziclay.opentoday.util.profiler.Profiler;
+
+import java.util.Set;
+
+public class BackendInitializer {
+ private static boolean backInitialized = false;
+ private static boolean backInitializeInProcess = false;
+ private static final Set modulesInitialized = new ArraySet<>();
+
+ public static boolean isWaitGuiForBack() {
+ return !backInitialized && backInitializeInProcess; // if not initializED and initializING
+ }
+
+ public static boolean isWaitForModule(Module module) {
+ return isWaitGuiForBack() && !modulesInitialized.contains(module);
+ }
+
+ public static void startBackInitializerThread() {
+ if (!backInitialized && !backInitializeInProcess) {
+ backInitializeInProcess = true;
+ new BackInitializerThread().start();
+ }
+ }
+
+ private static class BackInitializerThread extends Thread {
+ private static final Profiler PROFILER = App.createProfiler("GUILauncher:BackInitializerThread");
+
+ public BackInitializerThread() {
+ setName("BackInitializerThread");
+ setDefaultUncaughtExceptionHandler((thread, throwable) -> {
+ App.crash(null, CrashReport.create(thread, throwable), false);
+ backInitializeInProcess = false;
+ });
+ }
+
+ public void init(@NonNull Module m, @NonNull Runnable r) {
+ try {
+ PROFILER.push(m.name());
+ r.run();
+ PROFILER.swap("update_modules_set");
+ modulesInitialized.add(m);
+ PROFILER.pop();
+ } catch (Exception e) {
+ throw new RuntimeException("Exception while init module " + m, e);
+ }
+ }
+
+ @Override
+ public void run() {
+ PROFILER.push("run");
+ PROFILER.push("app.get");
+ App app = App.get();
+ PROFILER.pop();
+
+ init(Module.SETTINGS_MANAGER, app::getSettingsManager);
+ init(Module.PLUGINS, app::initPlugins);
+ init(Module.TABS_MANAGER, app::getTabsManager);
+ init(Module.ITEM_NOTIFICATION_HANDLER, app::getItemNotificationHandler);
+ init(Module.IMPORTANT_DEBUG_CALLBACKS, app::getImportantDebugCallbacks);
+ init(Module.SELECTION_MANAGER, app::getSelectionManager);
+ init(Module.BEATIFY_COLOR_MANAGER, app::getBeautifyColorManager);
+ init(Module.COLOR_HISTORY_MANAGER, app::getColorHistoryManager);
+
+ backInitialized = true;
+ backInitializeInProcess = false;
+ PROFILER.pop();
+ }
+ }
+
+ public enum Module {
+ PLUGINS,
+ TABS_MANAGER,
+ SETTINGS_MANAGER,
+ COLOR_HISTORY_MANAGER,
+ BEATIFY_COLOR_MANAGER,
+ ITEM_NOTIFICATION_HANDLER,
+ IMPORTANT_DEBUG_CALLBACKS,
+ PIN_CODE_MANAGER,
+ SELECTION_MANAGER;
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/ColorPicker.java b/app/src/main/java/com/fazziclay/opentoday/gui/ColorPicker.java
index 8c5eaa0d..1a96834c 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/ColorPicker.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/ColorPicker.java
@@ -7,14 +7,18 @@
import androidx.appcompat.app.AlertDialog;
+import com.fazziclay.opentoday.app.App;
import com.fazziclay.opentoday.app.ColorHistoryManager;
+import com.fazziclay.opentoday.app.settings.SettingsManager;
import com.google.android.material.chip.Chip;
import com.google.android.material.chip.ChipGroup;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.rarepebble.colorpicker.ColorPickerView;
public class ColorPicker {
private final Context context;
private int startColor;
+ private SettingsManager settingsManager;
private ColorHistoryManager colorHistoryManager;
private int colorHistoryMax = 5;
private boolean showHex;
@@ -30,6 +34,7 @@ public ColorPicker(Context context) {
public ColorPicker(Context context, int startColor) {
this.context = context;
this.startColor = startColor;
+ this.settingsManager = App.get(context).getSettingsManager();
}
public ColorPicker setting(boolean showHex, boolean showPreview, boolean showAlpha) {
@@ -71,7 +76,7 @@ public void showDialog(String title, String negative, String positive, ColorPick
dialogLayout.addView(historyHorizontal);
}
- AlertDialog.Builder builder = new AlertDialog.Builder(context)
+ AlertDialog.Builder builder = (colorHistoryManager == null ? new MaterialAlertDialogBuilder(context) : new AlertDialog.Builder(context))
.setTitle(title)
.setView(dialogLayout)
.setNegativeButton(negative, null)
@@ -94,7 +99,9 @@ public ColorPicker setStartColor(int color) {
}
public ColorPicker setColorHistoryManager(ColorHistoryManager colorHistoryManager) {
- this.colorHistoryManager = colorHistoryManager;
+ if (SettingsManager.COLOR_HISTORY_ENABLED.get(settingsManager)) {
+ this.colorHistoryManager = colorHistoryManager;
+ }
return this;
}
@@ -109,6 +116,12 @@ public ColorPicker setNeutralDialogButton(String text, Runnable runnable) {
return this;
}
+ public ColorPicker setNeutralDialogButton(int resId, Runnable runnable) {
+ this.neutralDialogButtonText = context.getString(resId);
+ this.neutralDialogButtonRunnable = runnable;
+ return this;
+ }
+
public interface ColorPickerInterface {
void selected(int color);
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/EnumsRegistry.kt b/app/src/main/java/com/fazziclay/opentoday/gui/EnumsRegistry.kt
index 9f1e98b6..7ab10df2 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/EnumsRegistry.kt
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/EnumsRegistry.kt
@@ -4,29 +4,33 @@ import android.content.Context
import androidx.annotation.StringRes
import com.fazziclay.opentoday.R
import com.fazziclay.opentoday.app.ImportWrapper
-import com.fazziclay.opentoday.app.SettingsManager
import com.fazziclay.opentoday.app.items.item.CycleListItem
import com.fazziclay.opentoday.app.items.item.FilterGroupItem
import com.fazziclay.opentoday.app.items.item.ItemType
import com.fazziclay.opentoday.app.items.item.filter.FiltersRegistry
import com.fazziclay.opentoday.app.items.item.filter.LogicContainerItemFilter
+import com.fazziclay.opentoday.app.settings.enums.FirstTab
+import com.fazziclay.opentoday.app.settings.enums.ItemAction
+import com.fazziclay.opentoday.app.settings.enums.ItemAddPosition
+import com.fazziclay.opentoday.util.InlineUtil.IPROF
// GUI-only
object EnumsRegistry {
private val ENUMS = arrayOf(
EnumInfo(LogicContainerItemFilter.LogicMode.AND, R.string.logic_container_logicMode_AND),
EnumInfo(LogicContainerItemFilter.LogicMode.OR, R.string.logic_container_logicMode_OR),
- EnumInfo(SettingsManager.FirstTab.FIRST, R.string.settings_firstTab_first),
- EnumInfo(SettingsManager.FirstTab.TAB_ON_CLOSING, R.string.settings_firstTab_onClosed),
- EnumInfo(SettingsManager.ItemAction.OPEN_EDITOR, R.string.itemAction_OPEN_EDITOR),
- EnumInfo(SettingsManager.ItemAction.OPEN_TEXT_EDITOR, R.string.itemAction_OPEN_TEXT_EDITOR),
- EnumInfo(SettingsManager.ItemAction.SELECT_REVERT, R.string.itemAction_SELECT_REVERT),
- EnumInfo(SettingsManager.ItemAction.SELECT_ON, R.string.itemAction_SELECT_ON),
- EnumInfo(SettingsManager.ItemAction.SELECT_OFF, R.string.itemAction_SELECT_OFF),
- EnumInfo(SettingsManager.ItemAction.DELETE_REQUEST, R.string.itemAction_DELETE_REQUEST),
- EnumInfo(SettingsManager.ItemAction.MINIMIZE_REVERT, R.string.itemAction_MINIMIZE_REVERT),
- EnumInfo(SettingsManager.ItemAction.MINIMIZE_ON, R.string.itemAction_MINIMIZE_ON),
- EnumInfo(SettingsManager.ItemAction.MINIMIZE_OFF, R.string.itemAction_MINIMIZE_OFF),
+ EnumInfo(FirstTab.FIRST, R.string.settings_firstTab_first),
+ EnumInfo(FirstTab.TAB_ON_CLOSING, R.string.settings_firstTab_onClosed),
+ EnumInfo(ItemAction.OPEN_EDITOR, R.string.itemAction_OPEN_EDITOR),
+ EnumInfo(ItemAction.OPEN_TEXT_EDITOR, R.string.itemAction_OPEN_TEXT_EDITOR),
+ EnumInfo(ItemAction.SELECT_REVERT, R.string.itemAction_SELECT_REVERT),
+ EnumInfo(ItemAction.SELECT_ON, R.string.itemAction_SELECT_ON),
+ EnumInfo(ItemAction.SELECT_OFF, R.string.itemAction_SELECT_OFF),
+ EnumInfo(ItemAction.DELETE_REQUEST, R.string.itemAction_DELETE_REQUEST),
+ EnumInfo(ItemAction.MINIMIZE_REVERT, R.string.itemAction_MINIMIZE_REVERT),
+ EnumInfo(ItemAction.MINIMIZE_ON, R.string.itemAction_MINIMIZE_ON),
+ EnumInfo(ItemAction.MINIMIZE_OFF, R.string.itemAction_MINIMIZE_OFF),
+ EnumInfo(ItemAction.SHOW_ACTION_DIALOG, R.string.itemAction_SHOW_ACTION_DIALOG),
EnumInfo(ImportWrapper.ErrorCode.NOT_IMPORT_TEXT, R.string.importWrapper_errorCode_NOT_IMPORT_TEXT),
EnumInfo(ImportWrapper.ErrorCode.VERSION_NOT_COMPATIBLE, R.string.importWrapper_errorCode_VERSION_NOT_COMPATIBLE),
EnumInfo(FiltersRegistry.FilterType.DATE, R.string.filterRegistry_filterType_DATE),
@@ -56,21 +60,23 @@ object EnumsRegistry {
EnumInfo(CycleListItem.TickBehavior.CURRENT, R.string.item_cycleList_tickBehavior_current),
EnumInfo(CycleListItem.TickBehavior.NOT_CURRENT, R.string.item_cycleList_tickBehavior_notCurrent),
- EnumInfo(SettingsManager.ItemAddPosition.TOP, R.string.settings_itemAddPosition_TOP),
- EnumInfo(SettingsManager.ItemAddPosition.BOTTOM, R.string.settings_itemAddPosition_BOTTOM),
+ EnumInfo(ItemAddPosition.TOP, R.string.settings_itemAddPosition_TOP),
+ EnumInfo(ItemAddPosition.BOTTOM, R.string.settings_itemAddPosition_BOTTOM),
)
fun missingChecks() {
+ IPROF.push("EnumsRegistry:missingChecks")
missingCheck(LogicContainerItemFilter.LogicMode.values().toList())
- missingCheck(SettingsManager.FirstTab.values().toList())
- missingCheck(SettingsManager.ItemAction.values().toList())
+ missingCheck(FirstTab.values().toList())
+ missingCheck(ItemAction.values().toList())
missingCheck(ImportWrapper.ErrorCode.values().toList())
missingCheck(FiltersRegistry.FilterType.values().toList())
missingCheck(ItemType.values().toList())
missingCheck(FilterGroupItem.TickBehavior.values().toList())
missingCheck(CycleListItem.TickBehavior.values().toList())
- missingCheck(SettingsManager.ItemAddPosition.values().toList())
+ missingCheck(ItemAddPosition.values().toList())
+ IPROF.pop()
}
private fun missingCheck(values: List>) {
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/GuiItemsHelper.java b/app/src/main/java/com/fazziclay/opentoday/gui/GuiItemsHelper.java
new file mode 100644
index 00000000..a74ad920
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/GuiItemsHelper.java
@@ -0,0 +1,55 @@
+package com.fazziclay.opentoday.gui;
+
+import android.content.Context;
+
+import com.fazziclay.opentoday.app.BeautifyColorManager;
+import com.fazziclay.opentoday.app.settings.SettingsManager;
+import com.fazziclay.opentoday.app.items.ItemsStorage;
+import com.fazziclay.opentoday.app.items.item.Item;
+import com.fazziclay.opentoday.app.items.item.ItemType;
+import com.fazziclay.opentoday.app.items.item.ItemsRegistry;
+import com.fazziclay.opentoday.app.items.item.TextItem;
+
+public class GuiItemsHelper {
+ /**
+ * Create item include settings {@link SettingsManager#isRandomItemBackground()} and set text
+ */
+ public static Item createItem(Context context, ItemType itemType, String text, SettingsManager settingsManager) {
+ final ItemsRegistry.ItemInfo registryItem = ItemsRegistry.REGISTRY.get(itemType);
+ return createItem(context, registryItem, text, settingsManager);
+ }
+
+
+ /**
+ * Create item include settings {@link SettingsManager#isRandomItemBackground()} and set text
+ */
+ public static Item createItem(Context context, ItemsRegistry.ItemInfo registryItem, String text, SettingsManager settingsManager) {
+ final Item item = registryItem.create();
+ applyInitRandomColorIfNeeded(context, item, settingsManager);
+ if (item instanceof TextItem textItem) {
+ textItem.setText(text);
+ }
+
+ return item;
+ }
+
+ /**
+ * Add items to itemsStorage include logic of settings options
+ */
+ public static void addItem(Item item, ItemsStorage itemsStorage, SettingsManager settingsManager) {
+ switch (settingsManager.getItemAddPosition()) {
+ case TOP -> itemsStorage.addItem(item, 0);
+ case BOTTOM -> itemsStorage.addItem(item);
+ }
+ }
+
+ /**
+ * Set random background color if SettingsManager.ITEM_RANDOM_BACKGROUND enabled
+ */
+ public static void applyInitRandomColorIfNeeded(Context context, Item item, SettingsManager sm) {
+ if (sm.isRandomItemBackground()) {
+ item.setViewCustomBackgroundColor(true);
+ item.setViewBackgroundColor(BeautifyColorManager.randomBackgroundColor(context));
+ }
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/ItemTagGui.java b/app/src/main/java/com/fazziclay/opentoday/gui/ItemTagGui.java
new file mode 100644
index 00000000..2c7bbb02
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/ItemTagGui.java
@@ -0,0 +1,12 @@
+package com.fazziclay.opentoday.gui;
+
+import com.fazziclay.opentoday.app.items.tag.ItemTag;
+
+public class ItemTagGui {
+ public static String textInChip(ItemTag tag) {
+ if (tag.getValue() == null) {
+ return tag.getName();
+ }
+ return tag.getName() + ": " + tag.getValue();
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/UI.kt b/app/src/main/java/com/fazziclay/opentoday/gui/UI.kt
index 6ef4dd4f..f494d07b 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/UI.kt
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/UI.kt
@@ -8,6 +8,7 @@ import android.content.Context
import android.content.DialogInterface
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
+import android.os.Handler
import android.widget.CheckBox
import android.widget.EditText
import android.widget.LinearLayout
@@ -22,16 +23,20 @@ import com.fazziclay.opentoday.app.FeatureFlag
import com.fazziclay.opentoday.app.items.item.Item
import com.fazziclay.opentoday.app.items.selection.SelectionManager
import com.fazziclay.opentoday.app.items.tick.ItemsTickReceiver
+import com.fazziclay.opentoday.app.settings.enums.ThemeEnum
import com.fazziclay.opentoday.gui.callbacks.UIDebugCallback
import com.fazziclay.opentoday.gui.fragment.MainRootFragment
import com.fazziclay.opentoday.gui.interfaces.NavigationHost
import com.fazziclay.opentoday.util.InlineUtil
+import com.fazziclay.opentoday.util.InlineUtil.IPROF
+import com.fazziclay.opentoday.util.Logger
import com.fazziclay.opentoday.util.ResUtil
import com.fazziclay.opentoday.util.callback.CallbackStorage
import com.fazziclay.opentoday.util.callback.Status
import java.util.UUID
object UI {
+ private const val TAG: String = "UI"
private val debugCallbacks: CallbackStorage = CallbackStorage()
@JvmStatic
@@ -67,8 +72,12 @@ object UI {
@JvmStatic
fun rootBack(fragment: Fragment) {
- val host = findFragmentInParents(fragment, MainRootFragment::class.java) ?: throw RuntimeException("Fragment is not contains MainRootFragment in parents!")
- host.popBackStack()
+ val host = findFragmentInParents(fragment, MainRootFragment::class.java)
+ if (host != null) {
+ host.popBackStack()
+ } else {
+ Logger.e(TAG, "rootBack can't be run", RuntimeException("Fragment is not contains MainRootFragment in parents!"))
+ }
}
@JvmStatic
@@ -83,7 +92,21 @@ object UI {
@JvmStatic
fun setTheme(i: Int) {
+ IPROF.push("UI:setTheme")
AppCompatDelegate.setDefaultNightMode(i)
+ IPROF.pop();
+ }
+
+ @JvmStatic
+ fun setTheme(i: ThemeEnum) {
+ IPROF.push("UI:setTheme")
+ AppCompatDelegate.setDefaultNightMode(i.id())
+ IPROF.pop();
+ }
+
+ @JvmStatic
+ fun getTheme(): ThemeEnum {
+ return ThemeEnum.ofId(AppCompatDelegate.getDefaultNightMode())
}
@JvmStatic
@@ -102,6 +125,11 @@ object UI {
}
}
+ @JvmStatic
+ fun postDelayed(runnable: Runnable, long: Long): Unit {
+ Handler().postDelayed(runnable, long)
+ }
+
object Debug {
@SuppressLint("SetTextI18n")
@JvmStatic
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/activity/AlarmActivity.java b/app/src/main/java/com/fazziclay/opentoday/gui/activity/AlarmActivity.java
index 3e1c00e1..351dddab 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/activity/AlarmActivity.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/activity/AlarmActivity.java
@@ -1,8 +1,11 @@
package com.fazziclay.opentoday.gui.activity;
+import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Bundle;
@@ -14,7 +17,7 @@
import androidx.appcompat.app.AppCompatActivity;
import com.fazziclay.opentoday.app.App;
-import com.fazziclay.opentoday.app.SettingsManager;
+import com.fazziclay.opentoday.app.settings.enums.ItemAction;
import com.fazziclay.opentoday.app.items.ItemsRoot;
import com.fazziclay.opentoday.app.items.item.CycleListItem;
import com.fazziclay.opentoday.app.items.item.FilterGroupItem;
@@ -22,13 +25,14 @@
import com.fazziclay.opentoday.app.items.item.Item;
import com.fazziclay.opentoday.databinding.ActivityAlarmBinding;
import com.fazziclay.opentoday.gui.interfaces.ItemInterface;
-import com.fazziclay.opentoday.gui.item.HolderDestroyer;
+import com.fazziclay.opentoday.gui.item.Destroyer;
import com.fazziclay.opentoday.gui.item.ItemViewGenerator;
import com.fazziclay.opentoday.gui.item.ItemViewGeneratorBehavior;
import com.fazziclay.opentoday.gui.item.ItemsStorageDrawerBehavior;
import org.jetbrains.annotations.NotNull;
+import java.io.IOException;
import java.util.Objects;
import java.util.UUID;
@@ -36,16 +40,20 @@ public class AlarmActivity extends AppCompatActivity {
private App app;
private ActivityAlarmBinding binding;
+ private int cancelNotifyId;
private MediaPlayer mediaPlayer;
- private final HolderDestroyer holderDestroy = new HolderDestroyer();
+ private final Destroyer holderDestroy = new Destroyer();
@NotNull
- public static Intent createIntent(@NotNull Context context, @Nullable UUID previewItem, boolean isPreviewMode, @NotNull String title, boolean sound) {
- return new Intent(context, AlarmActivity.class)
+ public static Intent createIntent(@NotNull Context context, @Nullable UUID previewItem, boolean isPreviewMode, @NotNull String title, boolean sound, int cancelNotifyId) {
+ Intent intent = new Intent(context, AlarmActivity.class)
.putExtra("previewItemId", Objects.toString(previewItem, null))
.putExtra("previewItemIsPreviewMode", isPreviewMode)
.putExtra("title", title)
- .putExtra("sound", sound);
+ .putExtra("sound", sound)
+ .putExtra("cancelNotifyId", cancelNotifyId);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return intent;
}
@Override
@@ -61,12 +69,15 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
String title = getIntent().getStringExtra("title");
boolean sound = getIntent().getBooleanExtra("sound", true);
+ cancelNotifyId = getIntent().getIntExtra("cancelNotifyId", 0);
+
app = App.get(this);
binding = ActivityAlarmBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
binding.title.setText(title);
binding.okButton.setOnClickListener(view -> {
+ getSystemService(NotificationManager.class).cancel(cancelNotifyId);
finish();
});
@@ -76,9 +87,21 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
}
if (sound) {
- mediaPlayer = MediaPlayer.create(this, Settings.System.DEFAULT_ALARM_ALERT_URI);
- mediaPlayer.setLooping(true);
- mediaPlayer.start();
+ setVolumeControlStream(AudioManager.STREAM_ALARM);
+ try {
+ mediaPlayer = new MediaPlayer();
+ mediaPlayer.setDataSource(this, Settings.System.DEFAULT_ALARM_ALERT_URI);
+ mediaPlayer.setAudioAttributes(new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .build());
+ mediaPlayer.setVolume(1.0f, 1.0f);
+ mediaPlayer.setLooping(true);
+ mediaPlayer.prepare();
+ mediaPlayer.start();
+ } catch (IOException e) {
+ App.exception(this, e); // no crash
+ }
}
new Handler(Looper.getMainLooper()).postDelayed(this::finish, 1000*60*2);
@@ -123,8 +146,8 @@ public void onFilterGroupEdit(FilterGroupItem filterGroupItem) {
public ItemsStorageDrawerBehavior getItemsStorageDrawerBehavior(Item item) {
return new ItemsStorageDrawerBehavior() {
@Override
- public SettingsManager.ItemAction getItemOnClickAction() {
- return SettingsManager.ItemAction.OPEN_EDITOR;
+ public ItemAction getItemOnClickAction() {
+ return ItemAction.OPEN_EDITOR;
}
@Override
@@ -133,8 +156,8 @@ public boolean isScrollToAddedItem() {
}
@Override
- public SettingsManager.ItemAction getItemOnLeftAction() {
- return SettingsManager.ItemAction.OPEN_EDITOR;
+ public ItemAction getItemOnLeftAction() {
+ return ItemAction.OPEN_EDITOR;
}
@Override
@@ -163,6 +186,11 @@ public void onItemDeleteRequest(Item item) {
public boolean isRenderMinimized(Item item) {
return item.isMinimize();
}
+
+ @Override
+ public boolean isRenderNotificationIndicator(Item item) {
+ return item.isNotifications();
+ }
};
ItemInterface onItemClick = new ItemInterface() {
@Override
@@ -181,4 +209,20 @@ protected void onDestroy() {
}
holderDestroy.destroy();
}
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (mediaPlayer != null) {
+ mediaPlayer.pause();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if (mediaPlayer != null) {
+ mediaPlayer.start();
+ }
+ }
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/activity/CrashReportActivity.java b/app/src/main/java/com/fazziclay/opentoday/gui/activity/CrashReportActivity.java
index 56508e84..f27097d4 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/activity/CrashReportActivity.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/activity/CrashReportActivity.java
@@ -20,7 +20,10 @@
import com.fazziclay.javaneoutil.FileUtil;
import com.fazziclay.opentoday.R;
import com.fazziclay.opentoday.app.App;
+import com.fazziclay.opentoday.app.settings.SettingsManager;
import com.fazziclay.opentoday.app.Telemetry;
+import com.fazziclay.opentoday.app.UpdateChecker;
+import com.fazziclay.opentoday.util.NetworkUtil;
import java.io.File;
import java.util.UUID;
@@ -42,6 +45,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crash_report);
Button sendToDeveloper = findViewById(R.id.sendToDeveloper);
+ Button updateAvailable = findViewById(R.id.update_available);
TextView crashReportText = findViewById(R.id.crashReportText);
if (sendToDeveloper == null || crashReportText == null) {
@@ -54,6 +58,25 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
return;
}
+ if (updateAvailable != null) {
+ try {
+ UpdateChecker.check(this, (available, url, name) -> runOnUiThread(() -> {
+ if (available) {
+ updateAvailable.setVisibility(View.VISIBLE);
+ updateAvailable.setOnClickListener(view -> {
+ try {
+ NetworkUtil.openBrowser(this, url);
+ } catch (Exception e) {
+ Toast.makeText(this, "Error: " + e, Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+ }));
+ } catch (Exception e) {
+ Toast.makeText(this, "Check update exception: " + e, Toast.LENGTH_SHORT).show();
+ }
+ }
+
File file = new File(getIntent().getExtras().getString(EXTRA_PATH));
String crashString = FileUtil.getText(file);
UUID crashId = UUID.fromString(getIntent().getExtras().getString(EXTRA_ID));
@@ -69,7 +92,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
boolean visibleSendToDeveloper = true;
try {
- visibleSendToDeveloper = !App.get(this).getSettingsManager().isTelemetry();
+ visibleSendToDeveloper = !SettingsManager.IS_TELEMETRY.get(App.get(this).getSettingsManager());
} catch (Exception ignored) {}
crashReportText.setText(crashString);
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/activity/LauncherActivity.kt b/app/src/main/java/com/fazziclay/opentoday/gui/activity/LauncherActivity.kt
index 65b496c5..a8820f17 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/activity/LauncherActivity.kt
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/activity/LauncherActivity.kt
@@ -3,40 +3,89 @@ package com.fazziclay.opentoday.gui.activity
import android.app.Activity
import android.content.Intent
import android.os.Bundle
+import android.widget.Toast
+import com.fazziclay.opentoday.Debug
import com.fazziclay.opentoday.app.App
+import com.fazziclay.opentoday.app.settings.SettingsManager
+import com.fazziclay.opentoday.gui.BackendInitializer
+import com.fazziclay.opentoday.gui.EnumsRegistry
import com.fazziclay.opentoday.gui.UI
import com.fazziclay.opentoday.util.DebugUtil
+import com.fazziclay.opentoday.util.InlineUtil.IPROF
+import com.fazziclay.opentoday.util.profiler.Profiler
class LauncherActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
+ PROFILER.push("LauncherActivity:onCreate")
+
+ PROFILER.push("backend_initializer_start_thread")
+ BackendInitializer.startBackInitializerThread()
+
+ PROFILER.swap("super.onCreate")
super.onCreate(savedInstanceState)
+
+ PROFILER.swap("run")
run()
+
+ PROFILER.swap("finish")
finish()
+
+ PROFILER.pop()
+ PROFILER.pop()
}
private fun run() {
if (App.DEBUG) {
- DebugUtil.sleep(App.DEBUG_MAIN_ACTIVITY_START_SLEEP)
- if (App.DEBUG_TEST_EXCEPTION_ON_LAUNCH) {
+ PROFILER.push("debugs")
+ DebugUtil.sleep(Debug.DEBUG_MAIN_ACTIVITY_START_SLEEP)
+ if (Debug.DEBUG_TEST_EXCEPTION_ON_LAUNCH) {
throw RuntimeException(
"This is cute Runtime Exception in LauncherActivity (debug)",
RuntimeException("DEBUG_TEST_EXCEPTION_ON_LAUNCH is enabled :)")
)
}
- if (App.DEBUG_MAIN_ACTIVITY != null) {
- startActivity(Intent(this, App.DEBUG_MAIN_ACTIVITY))
+ if (Debug.DEBUG_MAIN_ACTIVITY != null) {
+ startActivity(Intent(this, Debug.DEBUG_MAIN_ACTIVITY))
return
}
+
+ EnumsRegistry.missingChecks()
+ PROFILER.pop()
}
+
+ PROFILER.push("app.get")
val app = App.get(this)
- UI.setTheme(app.settingsManager.theme)
- val sharedPreferences = getSharedPreferences(App.SHARED_NAME, MODE_PRIVATE)
- val isSetupDone = sharedPreferences.getBoolean(App.SHARED_KEY_IS_SETUP_DONE, false)
+
+ PROFILER.swap("settings")
+
+ PROFILER.push("wait_settings_init")
+ val startWait = System.currentTimeMillis()
+ while (BackendInitializer.isWaitForModule(BackendInitializer.Module.SETTINGS_MANAGER)) {
+ // waiting init settings
+ if (System.currentTimeMillis() - startWait > 1000 * 10) {
+ Toast.makeText(this, "Long...", Toast.LENGTH_SHORT).show()
+ break
+ }
+ }
+ PROFILER.pop()
+
+ val isSetupDone = !SettingsManager.IS_FIRST_LAUNCH.get(app.settingsManager)
+ val theme = SettingsManager.THEME.get(app.settingsManager)
+
+ PROFILER.swap("theme")
+ UI.setTheme(theme)
+
+ PROFILER.swap("launches_activities")
if (isSetupDone) {
startActivity(Intent(this, MainActivity::class.java))
} else {
startActivity(Intent(this, SetupActivity::class.java))
}
+ PROFILER.pop()
+ }
+
+ companion object {
+ private val PROFILER: Profiler = IPROF
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/activity/MainActivity.kt b/app/src/main/java/com/fazziclay/opentoday/gui/activity/MainActivity.kt
index efc25a80..6272a06c 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/activity/MainActivity.kt
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/activity/MainActivity.kt
@@ -1,18 +1,26 @@
package com.fazziclay.opentoday.gui.activity
import android.annotation.SuppressLint
+import android.app.AlarmManager
import android.app.DatePickerDialog
+import android.app.NotificationManager
+import android.content.Intent
import android.graphics.Color
import android.graphics.Typeface
+import android.net.Uri
+import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
+import android.provider.Settings
import android.view.Menu
import android.view.View
import android.widget.LinearLayout
+import android.widget.RelativeLayout
import android.widget.TextView
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
+import androidx.activity.result.contract.ActivityResultContracts.*
import androidx.appcompat.app.AppCompatActivity
import com.fazziclay.opentoday.Debug
import com.fazziclay.opentoday.R
@@ -20,16 +28,18 @@ import com.fazziclay.opentoday.app.App
import com.fazziclay.opentoday.app.CrashReportContext
import com.fazziclay.opentoday.app.FeatureFlag
import com.fazziclay.opentoday.app.ImportantDebugCallback
-import com.fazziclay.opentoday.app.SettingsManager
+import com.fazziclay.opentoday.app.Telemetry
import com.fazziclay.opentoday.app.Telemetry.UiClosedLPacket
-import com.fazziclay.opentoday.app.Telemetry.UiOpenLPacket
import com.fazziclay.opentoday.app.UpdateChecker
import com.fazziclay.opentoday.app.items.QuickNoteReceiver
+import com.fazziclay.opentoday.app.settings.ActionBarPosition
+import com.fazziclay.opentoday.app.settings.Option
+import com.fazziclay.opentoday.app.settings.SettingsManager
import com.fazziclay.opentoday.databinding.ActivityMainBinding
import com.fazziclay.opentoday.databinding.NotificationDebugappBinding
import com.fazziclay.opentoday.databinding.NotificationUpdateAvailableBinding
import com.fazziclay.opentoday.gui.ActivitySettings
-import com.fazziclay.opentoday.gui.EnumsRegistry
+import com.fazziclay.opentoday.gui.BackendInitializer
import com.fazziclay.opentoday.gui.UI
import com.fazziclay.opentoday.gui.UINotification
import com.fazziclay.opentoday.gui.UIRoot
@@ -45,16 +55,21 @@ import com.fazziclay.opentoday.util.StreamUtil
import com.fazziclay.opentoday.util.callback.CallbackImportance
import com.fazziclay.opentoday.util.callback.Status
import java.text.SimpleDateFormat
+import java.util.Calendar
import java.util.GregorianCalendar
import java.util.Locale
import java.util.Stack
+
+
+
@SuppressLint("NonConstantResourceId")
class MainActivity : AppCompatActivity(), UIRoot {
companion object {
private const val TAG = "MainActivity"
private const val CONTAINER_ID = R.id.mainActivity_rootFragmentContainer
private val DEFAULT_ACTIVITY_SETTINGS: ActivitySettings = ActivitySettings()
+ private val PROFILER = App.createProfiler("MainActivity")
}
private lateinit var binding: ActivityMainBinding
private lateinit var app: App
@@ -65,15 +80,17 @@ class MainActivity : AppCompatActivity(), UIRoot {
private lateinit var currentDateHandler: Handler
private lateinit var currentDateRunnable: Runnable
private lateinit var currentDateCalendar: GregorianCalendar
+ private lateinit var settingsAnalogClockCallback: SettingsManager.OptionChangedCallback
+ private lateinit var settingsActionbarCallback: SettingsManager.OptionChangedCallback
private var activitySettingsStack: Stack = Stack()
private var debugView = false
private var debugHandler: Handler? = null
private lateinit var debugRunnable: Runnable
private var debugViewSize = 13
- private var debugViewBackground: Int = 0x33000000
+ private var debugViewBackground: Int = Color.BLACK
@SuppressLint("SetTextI18n")
private var importantDebugCallback = ImportantDebugCallback { m ->
- if (!App.DEBUG_IMPORTANT_NOTIFICATIONS) return@ImportantDebugCallback Status.Builder()
+ if (!Debug.DEBUG_IMPORTANT_NOTIFICATIONS) return@ImportantDebugCallback Status.Builder()
.setRemoveCallback(true)
.build()
val text = TextView(this@MainActivity)
@@ -91,46 +108,149 @@ class MainActivity : AppCompatActivity(), UIRoot {
// Activity overrides
override fun onCreate(savedInstanceState: Bundle?) {
+ PROFILER.push("MainActivity:onCreate")
+
+ PROFILER.push("phase0")
+ BackendInitializer.startBackInitializerThread()
val startTime = System.currentTimeMillis()
CrashReportContext.mainActivityCreate()
CrashReportContext.FRONT.push("MainActivity")
Logger.d(TAG, "onCreate", nullStat(savedInstanceState))
- if (App.DEBUG) EnumsRegistry.missingChecks()
+
+ PROFILER.swap("phase1")
app = App.get(this)
+ while (BackendInitializer.isWaitForModule(BackendInitializer.Module.SETTINGS_MANAGER)) {
+ // do nothing
+ }
settingsManager = app.settingsManager
- UI.setTheme(settingsManager.theme)
- app.telemetry.send(UiOpenLPacket())
+ app.tryInitPlugins()
+
+ PROFILER.swap("inflate&set")
+
+ PROFILER.push("inflate")
binding = ActivityMainBinding.inflate(layoutInflater)
+
+ PROFILER.swap("set")
setContentView(binding.root)
+ PROFILER.pop()
+
+ PROFILER.swap("super.onCreate")
super.onCreate(savedInstanceState)
+ PROFILER.swap("phase2")
+ val theme = SettingsManager.THEME.get(settingsManager)
+ UI.setTheme(theme)
+
setSupportActionBar(binding.toolbar)
supportActionBar?.hide()
+ settingsActionbarCallback = SettingsManager.OptionChangedCallback { option, value ->
+ if (option == SettingsManager.ACTIONBAR_POSITION) {
+ val actionParams = (binding.toolbar.layoutParams as RelativeLayout.LayoutParams)
+ val dateParams = (binding.currentDateDate.layoutParams as RelativeLayout.LayoutParams)
+ val timeParams = (binding.currentDateTime.layoutParams as RelativeLayout.LayoutParams)
+ val containerParams = (binding.mainActivityRootFragmentContainer.layoutParams as RelativeLayout.LayoutParams)
+ val pos = value as ActionBarPosition
+ if (pos == ActionBarPosition.TOP) {
+ actionParams.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM)
+ dateParams.addRule(RelativeLayout.BELOW, binding.toolbar.id)
+ timeParams.addRule(RelativeLayout.BELOW, binding.toolbar.id)
+ containerParams.removeRule(RelativeLayout.ABOVE)
+ } else {
+ actionParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM)
+ dateParams.removeRule(RelativeLayout.BELOW)
+ timeParams.removeRule(RelativeLayout.BELOW)
+ containerParams.addRule(RelativeLayout.ABOVE, binding.toolbar.id)
+ }
+ }
+ return@OptionChangedCallback Status.NONE
+ }
+ settingsActionbarCallback.run(SettingsManager.ACTIONBAR_POSITION, SettingsManager.ACTIONBAR_POSITION.get(settingsManager))
+ settingsManager.callbacks.addCallback(CallbackImportance.DEFAULT, settingsActionbarCallback)
+
+
debugRunnable = Runnable {
- binding.debugInfo.text = ColorUtil.colorize(Debug.getDebugInfoText(), Color.WHITE, Color.TRANSPARENT, Typeface.NORMAL)
+ binding.debugInfo.text = ColorUtil.colorize(
+ Debug.getDebugInfoText(),
+ Color.WHITE,
+ Color.TRANSPARENT,
+ Typeface.NORMAL
+ )
if (debugView && debugHandler != null) {
- debugHandler!!.postDelayed(this.debugRunnable, 99)
+ debugHandler!!.postDelayed(this.debugRunnable, 50)
}
}
if (Debug.CUSTOM_MAINACTIVITY_BACKGROUND) binding.root.setBackgroundColor(Color.parseColor("#00ffff"))
+
+ if (settingsManager.isQuickNoteNotification) {
+ PROFILER.push("send_quick_note")
+ QuickNoteReceiver.sendQuickNoteNotification(this)
+ PROFILER.pop()
+ }
+
+ PROFILER.swap("wait_gui_for_back")
+ while (BackendInitializer.isWaitGuiForBack()) {
+ // waiting back initialize
+ }
+ PROFILER.swap("telemetry")
+ app.telemetry.send(Telemetry.UiOpenLPacket())
+
+ PROFILER.swap("savedInstanceState==null actions")
if (savedInstanceState == null) {
+ PROFILER.push("fragment begin")
+
supportFragmentManager.beginTransaction()
- .replace(CONTAINER_ID, MainRootFragment.create(), "MainRootFragment")
- .commit()
+ .replace(CONTAINER_ID, MainRootFragment.create(), "MainRootFragment")
+ .commit()
+
+ PROFILER.pop()
+ }
+
+ PROFILER.swap("phase3")
+ settingsAnalogClockCallback = SettingsManager.OptionChangedCallback { option, value ->
+ if (option == SettingsManager.ANALOG_CLOCK_ENABLE) {
+ val visible: Boolean = value as Boolean
+ if (visible) {
+ if (getCurrentActivitySettings().isClockVisible) {
+ viewVisible(binding.analogClock, true, View.GONE)
+ }
+ } else {
+ viewVisible(binding.analogClock, false, View.GONE)
+ }
+
+ } else if (option == SettingsManager.ANALOG_CLOCK_SIZE) {
+ val size: Int = (value as Int).coerceAtMost(500)
+ val layoutParams = RelativeLayout.LayoutParams(size, size)
+ layoutParams.addRule(RelativeLayout.ALIGN_PARENT_END)
+ binding.analogClock.layoutParams = layoutParams
+
+ } else if (option == SettingsManager.ANALOG_CLOCK_TRANSPARENCY) {
+ val alpha: Float = ((value as Int) / 100f)
+ binding.analogClock.alpha = alpha
+
+ } else if (option == SettingsManager.ANALOG_CLOCK_COLOR_SECONDS) {
+ binding.analogClock.setSecondTint(value as Int)
+ } else if (option == SettingsManager.ANALOG_CLOCK_COLOR_MINUTE) {
+ binding.analogClock.setMinuteTint(value as Int)
+ } else if (option == SettingsManager.ANALOG_CLOCK_COLOR_HOUR) {
+ binding.analogClock.setHourTint(value as Int)
+ }
+
+ return@OptionChangedCallback Status.NONE
}
setupNotifications()
setupCurrentDate()
- if (settingsManager.isQuickNoteNotification) {
- QuickNoteReceiver.sendQuickNoteNotification(this)
- }
updateDebugView()
- onBackPressedDispatcher.addCallback(object: OnBackPressedCallback(true) {
+ onBackPressedDispatcher.addCallback(object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
val exit = Runnable { this@MainActivity.finish() }
val def = Runnable {
if (System.currentTimeMillis() - lastExitClick > 2000) {
- Toast.makeText(this@MainActivity, R.string.abc_pressAgainForExitWarning, Toast.LENGTH_SHORT).show()
+ Toast.makeText(
+ this@MainActivity,
+ R.string.abc_pressAgainForExitWarning,
+ Toast.LENGTH_SHORT
+ ).show()
lastExitClick = System.currentTimeMillis()
} else {
exit.run()
@@ -146,27 +266,93 @@ class MainActivity : AppCompatActivity(), UIRoot {
}
}
})
+
+ PROFILER.swap("phase4")
updateByActivitySettings()
Debug.mainActivityStartupTime = System.currentTimeMillis() - startTime
app.importantDebugCallbacks.addCallback(CallbackImportance.DEFAULT, importantDebugCallback)
- if (App.DEBUG_LOG_ALL_IN_MAINACTIVITY) {
+ if (Debug.DEBUG_LOG_ALL_IN_MAINACTIVITY) {
Logger.i(TAG, "------------------")
- Logger.d(TAG, "Example debug message", 10, 20, 30, Exception("Exception in debug logging"))
+ Logger.d(
+ TAG,
+ "Example debug message",
+ 10,
+ 20,
+ 30,
+ Exception("Exception in debug logging")
+ )
Logger.w(TAG, "Example warning message")
Logger.e(TAG, "Example error message", Exception("Example exception for logger"))
Logger.i(TAG, "------------------")
}
val HIDE_IMPORTANT_TODOS = true
- if (App.DEBUG || App.SHADOW_RELEASE) {
+ if (App.DEBUG) {
try {
val todo = StreamUtil.read(assets.open("IMPORTANT_TODO"))
if (todo.isNotEmpty() && !HIDE_IMPORTANT_TODOS) {
binding.importantTodo.visibility = View.VISIBLE
binding.importantTodo.text = todo
}
- } catch (ignored: Exception) {}
+ } catch (ignored: Exception) {
+ }
+ }
+
+ PROFILER.pop()
+ PROFILER.pop()
+
+ val requestPermissionLauncher = registerForActivityResult(
+ RequestPermission()
+ ) { isGranted: Boolean ->
+ if (isGranted) {
+ Toast.makeText(this, R.string.abc_success, Toast.LENGTH_LONG).show();
+ } else {
+ Toast.makeText(this, R.string.abc_not_success, Toast.LENGTH_LONG).show();
+ }
+ tryCheckPermissions()
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ requestPermissionLauncher.launch(
+ android.Manifest.permission.POST_NOTIFICATIONS
+ )
+ } else {
+ tryCheckPermissions()
+ }
+ }
+
+ private fun tryCheckPermissions() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ val alarmManager: AlarmManager = getSystemService(AlarmManager::class.java)
+ if (!alarmManager.canScheduleExactAlarms()) {
+ Toast.makeText(this, R.string.main_activity_allowExactAlarms, Toast.LENGTH_LONG)
+ .show()
+ startActivity(Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM))
+ return
+ }
}
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+ val notificationManager: NotificationManager =
+ getSystemService(NotificationManager::class.java)
+ if (!notificationManager.canUseFullScreenIntent()) {
+ Toast.makeText(
+ this,
+ R.string.main_activity_allowFullScreenIntent,
+ Toast.LENGTH_LONG
+ ).show()
+ val intent = Intent(Settings.ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT)
+ intent.data = Uri.parse("package:${applicationInfo.packageName}")
+ startActivity(intent)
+ return
+ }
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ Logger.i(TAG, "onResume")
+ tryCheckPermissions()
}
override fun onPause() {
@@ -204,12 +390,16 @@ class MainActivity : AppCompatActivity(), UIRoot {
app.telemetry.send(UiClosedLPacket())
currentDateHandler.removeCallbacks(currentDateRunnable)
app.importantDebugCallbacks.removeCallback(importantDebugCallback)
+ settingsManager.callbacks.removeCallback(settingsAnalogClockCallback)
+ settingsManager.callbacks.removeCallback(settingsActionbarCallback)
+
CrashReportContext.mainActivityDestroy()
CrashReportContext.FRONT.pop()
}
// Current Date
private fun setupCurrentDate() {
+ PROFILER.push("setupCurrentDate")
currentDateCalendar = GregorianCalendar()
setCurrentDate()
currentDateHandler = Handler(mainLooper)
@@ -231,6 +421,18 @@ class MainActivity : AppCompatActivity(), UIRoot {
dialog.datePicker.firstDayOfWeek = app.settingsManager.firstDayOfWeek
dialog.show()
})
+ settingsManager.callbacks.addCallback(CallbackImportance.DEFAULT, settingsAnalogClockCallback)
+ manualCallSettingAnalog(SettingsManager.ANALOG_CLOCK_ENABLE)
+ manualCallSettingAnalog(SettingsManager.ANALOG_CLOCK_TRANSPARENCY)
+ manualCallSettingAnalog(SettingsManager.ANALOG_CLOCK_SIZE)
+ manualCallSettingAnalog(SettingsManager.ANALOG_CLOCK_COLOR_SECONDS)
+ manualCallSettingAnalog(SettingsManager.ANALOG_CLOCK_COLOR_MINUTE)
+ manualCallSettingAnalog(SettingsManager.ANALOG_CLOCK_COLOR_HOUR)
+ PROFILER.pop()
+ }
+
+ private fun manualCallSettingAnalog(option: Option) {
+ settingsAnalogClockCallback.run(option, option.getObject(settingsManager))
}
private fun internalItemsTick() {
@@ -240,6 +442,7 @@ class MainActivity : AppCompatActivity(), UIRoot {
}
private fun setCurrentDate() {
+ PROFILER.push("setCurrentDate")
currentDateCalendar.timeInMillis = System.currentTimeMillis()
val time = currentDateCalendar.time
@@ -250,10 +453,24 @@ class MainActivity : AppCompatActivity(), UIRoot {
// Time
dateFormat = SimpleDateFormat(settingsManager.timePattern, Locale.getDefault())
binding.currentDateTime.text = dateFormat.format(time)
+
+ // Analog
+ if (SettingsManager.ANALOG_CLOCK_ENABLE.get(settingsManager) || getCurrentActivitySettings().isAnalogClockForceVisible) {
+ if (getCurrentActivitySettings().isAnalogClockForceHidden) {
+ return
+ }
+ val hour = currentDateCalendar.get(Calendar.HOUR)
+ val minute = currentDateCalendar.get(Calendar.MINUTE)
+ val second = currentDateCalendar.get(Calendar.SECOND)
+ val millis = currentDateCalendar.get(Calendar.MILLISECOND)
+ binding.analogClock.setTime(hour, minute, second, millis)
+ }
+ PROFILER.pop()
}
// Update checker
private fun setupUpdateAvailableNotify() {
+ PROFILER.push("setupUpdateAvailableNotify")
UpdateChecker.check(app) { available: Boolean, url: String?, name: String? ->
runOnUiThread {
if (available) {
@@ -270,6 +487,7 @@ class MainActivity : AppCompatActivity(), UIRoot {
}
}
}
+ PROFILER.pop()
}
// App is DEBUG warning notify
@@ -309,8 +527,18 @@ class MainActivity : AppCompatActivity(), UIRoot {
binding.debugLogsSizeDown.visibility = View.VISIBLE
binding.debugLogsSwitch.visibility = View.VISIBLE
binding.debugLogsSwitch.setOnClickListener {
+ val IS_PROFILERS = com.fazziclay.opentoday.Build.isProfilersEnabled()
+ var text = app.logs.toString()
+ if (IS_PROFILERS) {
+ text = ""
+ App.get().profilers.forEach {
+ text += "\n\n" + it.getResult(-1)
+ }
+ }
+
+
viewVisible(binding.debugLogsScroll, binding.debugLogsSwitch.isChecked, View.GONE)
- binding.debugLogsText.text = ColorUtil.colorize("\n\n\n\n\n\n"+app.logs.toString(), Color.BLUE, Color.TRANSPARENT, 0, false)
+ binding.debugLogsText.text = ColorUtil.colorize("\n\n\n\n\n\n\n\n\n\n\n\n\n"+text, Color.YELLOW, Color.TRANSPARENT, 0, false)
}
binding.debugLogsSwitch.setOnLongClickListener {
toggleLogsOverlay()
@@ -326,6 +554,7 @@ class MainActivity : AppCompatActivity(), UIRoot {
binding.debugLogsText.textSize = debugViewSize.toFloat()
}
+ binding.debugLogsScroll.setBackgroundColor(debugViewBackground)
binding.debugLogsSizeUp.setOnLongClickListener {
debugViewBackground+=0x21000000
binding.debugLogsScroll.setBackgroundColor(debugViewBackground)
@@ -383,15 +612,22 @@ class MainActivity : AppCompatActivity(), UIRoot {
Logger.i(TAG, "update activity settings: $settings")
- viewVisible(binding.currentDateDate, settings.isClockVisible, View.GONE)
- viewVisible(binding.currentDateTime, settings.isClockVisible, View.GONE)
+ val canon = settings.isShowCanonicalClock && SettingsManager.ACTIONBAR_POSITION[settingsManager] == ActionBarPosition.BOTTOM;
+ val clockVisible = settings.isClockVisible || (canon)
+ var analogClockVisible = (settings.isClockVisible && SettingsManager.ANALOG_CLOCK_ENABLE.get(settingsManager)) || settings.isAnalogClockForceVisible
+ if (settings.isAnalogClockForceHidden || canon) analogClockVisible = false
+
+ viewVisible(binding.currentDateDate, clockVisible, View.GONE)
+ viewVisible(binding.currentDateTime, clockVisible, View.GONE)
+ viewVisible(binding.analogClock, analogClockVisible, View.GONE)
binding.currentDateDate.isEnabled = settings.isDateClickCalendar
binding.currentDateTime.isEnabled = settings.isDateClickCalendar
- viewVisible(binding.notifications, settings.isNotificationsVisible || App.DEBUG_ALWAYS_SHOW_UI_NOTIFICATIONS, View.GONE)
+ viewVisible(binding.notifications, settings.isNotificationsVisible || Debug.DEBUG_ALWAYS_SHOW_UI_NOTIFICATIONS, View.GONE)
val toolbarSettings = settings.toolbarSettings
if (toolbarSettings == null) {
supportActionBar?.hide()
+
} else {
supportActionBar?.show()
if (toolbarSettings.title != null) {
@@ -411,6 +647,7 @@ class MainActivity : AppCompatActivity(), UIRoot {
}, 25)
} else if (binding.toolbar.menu != null) {
+ binding.toolbar.menu.clear()
binding.toolbar.menu.close()
Logger.d(TAG, "toolbar closed...")
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/activity/SetupActivity.kt b/app/src/main/java/com/fazziclay/opentoday/gui/activity/SetupActivity.kt
index 0582e42a..6e198053 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/activity/SetupActivity.kt
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/activity/SetupActivity.kt
@@ -8,8 +8,8 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import com.fazziclay.opentoday.R
import com.fazziclay.opentoday.app.App
-import com.fazziclay.opentoday.app.SettingsManager
import com.fazziclay.opentoday.app.Telemetry
+import com.fazziclay.opentoday.app.settings.SettingsManager
import com.fazziclay.opentoday.databinding.ActivitySetupBinding
import com.fazziclay.opentoday.gui.UI
import com.fazziclay.opentoday.util.InlineUtil.viewClick
@@ -54,15 +54,16 @@ class SetupActivity : AppCompatActivity() {
private fun done() {
val isTelemetry = binding.setupTelemetry.isChecked
- settingsManager.isTelemetry = isTelemetry
+ SettingsManager.IS_TELEMETRY.set(settingsManager, isTelemetry)
settingsManager.save()
- telemetry.setEnabled(isTelemetry)
+ telemetry.isEnabled = isTelemetry
setupDone()
startMain()
}
private fun setupDone() {
- getSharedPreferences(App.SHARED_NAME, MODE_PRIVATE).edit().putBoolean(App.SHARED_KEY_IS_SETUP_DONE, true).apply()
+ SettingsManager.IS_FIRST_LAUNCH[settingsManager] = false
+ settingsManager.save()
}
private fun startMain() {
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/dialog/DialogItemNotificationsEditor.java b/app/src/main/java/com/fazziclay/opentoday/gui/dialog/DialogItemNotificationsEditor.java
deleted file mode 100644
index d4568775..00000000
--- a/app/src/main/java/com/fazziclay/opentoday/gui/dialog/DialogItemNotificationsEditor.java
+++ /dev/null
@@ -1,177 +0,0 @@
-package com.fazziclay.opentoday.gui.dialog;
-
-import static com.fazziclay.opentoday.util.InlineUtil.viewClick;
-import static com.fazziclay.opentoday.util.InlineUtil.viewVisible;
-
-import android.app.Activity;
-import android.app.Dialog;
-import android.app.TimePickerDialog;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-
-import androidx.appcompat.app.AlertDialog;
-
-import com.fazziclay.opentoday.R;
-import com.fazziclay.opentoday.app.items.item.Item;
-import com.fazziclay.opentoday.app.items.notification.DayItemNotification;
-import com.fazziclay.opentoday.app.items.notification.ItemNotification;
-import com.fazziclay.opentoday.databinding.DialogItemNotificationBinding;
-import com.fazziclay.opentoday.databinding.DialogItemNotificationsEditorBinding;
-import com.fazziclay.opentoday.databinding.ItemNotificationBinding;
-import com.fazziclay.opentoday.util.MinBaseAdapter;
-import com.fazziclay.opentoday.util.MinTextWatcher;
-import com.fazziclay.opentoday.util.RandomUtil;
-import com.fazziclay.opentoday.util.time.ConvertMode;
-import com.fazziclay.opentoday.util.time.HumanTimeType;
-import com.fazziclay.opentoday.util.time.TimeUtil;
-
-public class DialogItemNotificationsEditor {
- private final Activity activity;
- private final Item item;
- private final Runnable onApply;
- private final Dialog dialog;
- private final DialogItemNotificationsEditorBinding binding;
- private final View view;
-
- // TODO: 07.06.2023 fix all
- public DialogItemNotificationsEditor(Activity activity, Item item, Runnable o) {
-
- this.activity = activity;
- this.item = item;
- this.onApply = o;
-
- dialog = new Dialog(activity, android.R.style.ThemeOverlay_Material_ActionBar);
- dialog.setOnCancelListener(dialog -> onApply.run());
-
- binding = DialogItemNotificationsEditorBinding.inflate(activity.getLayoutInflater());
- view = binding.getRoot();
-
- viewClick(binding.cancelButton, dialog::cancel);
- updateEmptyView(item.getNotifications().isEmpty());
- binding.list.setAdapter(new MinBaseAdapter() {
- @Override
- public int getCount() {
- return item.getNotifications().size();
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- ItemNotification itemNotification = item.getNotifications().get(position);
-
- ItemNotificationBinding b = ItemNotificationBinding.inflate(activity.getLayoutInflater(), parent, false);
-
- if (itemNotification instanceof DayItemNotification d) {
- b.text.setText(String.format("#%s - %s - %s", d.getNotificationId(), activity.getString(R.string.itemNotification_day), TimeUtil.convertToHumanTime(d.getTime(), ConvertMode.HHMM)));
- }
-
- b.delete.setOnClickListener(v -> {
- new AlertDialog.Builder(activity)
- .setTitle(R.string.fragment_itemEditor_delete_title)
- .setPositiveButton(R.string.fragment_itemEditor_delete_apply, (ee, eee) -> {
- item.getNotifications().remove(itemNotification);
- item.save();
- notifyDataSetChanged();
- updateEmptyView(item.getNotifications().isEmpty());
- })
- .setNegativeButton(R.string.fragment_itemEditor_delete_cancel, null)
- .show();
- });
-
-
- b.getRoot().setOnClickListener(v -> {
- DialogItemNotificationBinding l = DialogItemNotificationBinding.inflate(activity.getLayoutInflater());
-
- DayItemNotification d = (DayItemNotification) itemNotification;
-
- l.notificationId.setText(String.valueOf(d.getNotificationId()));
- MinTextWatcher.after(l.notificationId, () -> {
- try {
- int i = Integer.parseInt(l.notificationId.getText().toString());
- d.setNotificationId(i);
- } catch (Exception ignored) {
- d.setNotificationId(0);
- l.notificationId.setText("0");
- }
- });
- l.text.setText(d.getNotifyText());
- l.textFromItem.setChecked(d.isNotifyTextFromItemText());
- l.textFromItem.setOnClickListener(vvv -> {
- l.text.setEnabled(!l.textFromItem.isChecked());
- d.setNotifyTextFromItemText(l.textFromItem.isChecked());
- });
- l.text.setEnabled(!l.textFromItem.isChecked());
- MinTextWatcher.after(l.text, () -> d.setNotifyText(l.text.getText().toString()));
- l.title.setText(d.getNotifyTitle());
- l.titleFromItem.setChecked(d.isNotifyTitleFromItemText());
- l.titleFromItem.setOnClickListener(vvv -> {
- l.title.setEnabled(!l.titleFromItem.isChecked());
- d.setNotifyTitleFromItemText(l.titleFromItem.isChecked());
- });
- l.title.setEnabled(!l.titleFromItem.isChecked());
- MinTextWatcher.after(l.title, () -> d.setNotifyTitle(l.title.getText().toString()));
-
- l.notifySubText.setText(d.getNotifySubText());
- MinTextWatcher.after(l.notifySubText, () -> d.setNotifySubText(l.notifySubText.getText().toString()));
-
- l.test.setOnClickListener(v2132321 -> {
- d.sendNotify(activity, item);
- });
- l.time.setText(activity.getString(R.string.dialog_itemNotification_time, TimeUtil.convertToHumanTime(d.getTime(), ConvertMode.HHMM)));
- l.time.setOnClickListener(_ignore -> new TimePickerDialog(activity, (view, hourOfDay, minute) -> {
- d.setTime((hourOfDay * 60 * 60) + (minute * 60));
- d.setLatestDayOfYear(0);
- item.save();
- l.time.setText(activity.getString(R.string.dialog_itemNotification_time, TimeUtil.convertToHumanTime(d.getTime(), ConvertMode.HHMM)));
- }, TimeUtil.getHumanValue(d.getTime(), HumanTimeType.HOUR), TimeUtil.getHumanValue(d.getTime(), HumanTimeType.MINUTE_OF_HOUR), true).show());
-
-
- l.fullScreen.setOnCheckedChangeListener((compoundButton, b1) -> {
- l.previewViewOnly.setEnabled(b1);
- l.sound.setEnabled(b1);
- });
- l.fullScreen.setOnClickListener(i____ -> d.setFullScreen(l.fullScreen.isChecked()));
- l.fullScreen.setChecked(d.isFullScreen());
- l.previewViewOnly.setEnabled(d.isFullScreen());
- l.sound.setEnabled(d.isFullScreen());
-
- l.previewViewOnly.setChecked(d.isPreRenderPreviewMode());
- l.previewViewOnly.setOnClickListener(i___ -> d.setPreRenderPreviewMode(l.previewViewOnly.isChecked()));
-
- l.sound.setChecked(d.isSound());
- l.sound.setOnClickListener(i____ -> d.setSound(l.sound.isChecked()));
-
- new AlertDialog.Builder(activity)
- .setView(l.getRoot())
- .setPositiveButton(R.string.dialog_itemNotification_apply, (_refre, _werwer) -> {
- if (d.getTime() > TimeUtil.getDaySeconds()) d.setLatestDayOfYear(0);
- notifyDataSetChanged();
- item.save();
- })
- .setNegativeButton(R.string.dialog_itemNotification_cancel, null)
- .show();
- });
-
- return b.getRoot();
- }
- });
-
- binding.add.setOnClickListener(v -> {
- DayItemNotification dayItemNotification = new DayItemNotification();
- dayItemNotification.setNotificationId(RandomUtil.nextIntPositive());
- item.getNotifications().add(dayItemNotification);
- item.save();
- updateEmptyView(item.getNotifications().isEmpty());
- ((BaseAdapter) binding.list.getAdapter()).notifyDataSetChanged();
- });
- }
-
- private void updateEmptyView(boolean empty) {
- viewVisible(binding.empty, empty, View.GONE);
- }
-
- public void show() {
- dialog.setContentView(view);
- dialog.show();
- }
-}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/dialog/DialogSelectItemAction.java b/app/src/main/java/com/fazziclay/opentoday/gui/dialog/DialogSelectItemAction.java
index c98fc767..040ae971 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/dialog/DialogSelectItemAction.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/dialog/DialogSelectItemAction.java
@@ -6,30 +6,37 @@
import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
-import androidx.appcompat.app.AlertDialog;
+import androidx.annotation.Nullable;
import com.fazziclay.opentoday.R;
-import com.fazziclay.opentoday.app.SettingsManager;
+import com.fazziclay.opentoday.app.settings.enums.ItemAction;
import com.fazziclay.opentoday.gui.EnumsRegistry;
import com.fazziclay.opentoday.util.MinBaseAdapter;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
public class DialogSelectItemAction {
private final Activity activity;
- private final SettingsManager.ItemAction selected;
+ @Nullable private final ItemAction selected;
private final OnSelected onSelected;
private final String message;
private Dialog dialog;
private final View view;
+ private List excludeList = new ArrayList<>();
- public DialogSelectItemAction(Activity activity, SettingsManager.ItemAction selected, OnSelected onSelected) {
+ public DialogSelectItemAction(Activity activity, @Nullable ItemAction selected, OnSelected onSelected) {
this(activity, selected, onSelected, null);
}
- public DialogSelectItemAction(Activity activity, SettingsManager.ItemAction selected, OnSelected onSelected, String message) {
+ public DialogSelectItemAction(Activity activity, ItemAction selected, OnSelected onSelected, String message) {
this.activity = activity;
this.selected = selected;
this.onSelected = onSelected;
@@ -43,7 +50,7 @@ public DialogSelectItemAction(Activity activity, SettingsManager.ItemAction sele
listView.setPadding(10, 10, 10, 10);
this.view = listView;
- dialog = new AlertDialog.Builder(activity)
+ dialog = new MaterialAlertDialogBuilder(activity)
.setTitle(R.string.dialog_selectItemAction_title)
.setMessage(message)
.setPositiveButton(R.string.dialog_selectItemAction_cancel, null)
@@ -53,13 +60,16 @@ public DialogSelectItemAction(Activity activity, SettingsManager.ItemAction sele
listView.setAdapter(new MinBaseAdapter() {
@Override
public int getCount() {
- return SettingsManager.ItemAction.values().length;
+ return ItemAction.values().length;
}
@SuppressLint("SetTextI18n")
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- SettingsManager.ItemAction itemAction = SettingsManager.ItemAction.values()[position];
+ ItemAction itemAction = ItemAction.values()[position];
+ if (excludeList.contains(itemAction)) {
+ return new FrameLayout(activity);
+ }
TextView textView = new TextView(DialogSelectItemAction.this.activity);
textView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
@@ -70,17 +80,22 @@ public View getView(int position, View convertView, ViewGroup parent) {
}
});
listView.setOnItemClickListener((parent, view, position, id) -> {
- SettingsManager.ItemAction itemAction = SettingsManager.ItemAction.values()[position];
+ ItemAction itemAction = ItemAction.values()[position];
DialogSelectItemAction.this.onSelected.run(itemAction);
dialog.cancel();
});
}
+ public DialogSelectItemAction excludeFromList(ItemAction... actions) {
+ excludeList.addAll(Arrays.asList(actions));
+ return this;
+ }
+
public void show() {
dialog.show();
}
public interface OnSelected {
- void run(SettingsManager.ItemAction itemAction);
+ void run(ItemAction itemAction);
}
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/dialog/DialogSelectItemType.java b/app/src/main/java/com/fazziclay/opentoday/gui/dialog/DialogSelectItemType.java
index c6d9e61d..cb019bf1 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/dialog/DialogSelectItemType.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/dialog/DialogSelectItemType.java
@@ -1,97 +1,67 @@
package com.fazziclay.opentoday.gui.dialog;
-import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
-import android.view.View;
-import android.widget.ListView;
-import android.widget.Spinner;
import com.fazziclay.opentoday.R;
import com.fazziclay.opentoday.app.App;
import com.fazziclay.opentoday.app.items.item.ItemType;
import com.fazziclay.opentoday.app.items.item.ItemsRegistry;
-import com.fazziclay.opentoday.util.EnumUtil;
-import com.fazziclay.opentoday.util.SimpleSpinnerAdapter;
+import com.fazziclay.opentoday.gui.EnumsRegistry;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+
+import java.util.ArrayList;
+import java.util.List;
public class DialogSelectItemType {
+ private final CharSequence[] itemsNames;
+ private final ItemsRegistry.ItemInfo[] itemsInfos;
+
private final Context context;
private final App app;
- private final String selectButtonText;
private String title;
private String message;
private final OnSelected onSelected;
- private View view;
- private final SimpleSpinnerAdapter simpleSpinnerAdapter;
- private final Dialog dialog;
+ private Dialog dialog;
private final ItemTypeValidator itemTypeValidator;
+ private int selectedItem = -1;
public DialogSelectItemType(Context context, OnSelected onSelected) {
- this(context, null, onSelected);
- }
-
- public DialogSelectItemType(Context context, OnSelected onSelected, ItemTypeValidator itemTypeValidator) {
- this(context, null, onSelected, itemTypeValidator);
+ this(context, onSelected, (ItemType) null);
}
- public DialogSelectItemType(Context context, int resId, OnSelected onSelected) {
- this(context, context.getString(resId), onSelected);
+ public DialogSelectItemType(Context context, OnSelected onSelected, ItemType selectedItem) {
+ this(context, onSelected, type -> ItemsRegistry.REGISTRY.get(type).isCompatibility(App.get(context).getFeatureFlags()), selectedItem);
}
- public DialogSelectItemType(Context context, String selectButtonText, OnSelected onSelected) {
- this(context, selectButtonText, onSelected, type -> ItemsRegistry.REGISTRY.get(type).isCompatibility(App.get(context).getFeatureFlags()));
+ public DialogSelectItemType(Context context, OnSelected onSelected, ItemTypeValidator itemTypeValidator) {
+ this(context, onSelected, itemTypeValidator, null);
}
-
- public DialogSelectItemType(Context context, String selectButtonText, OnSelected onSelected, ItemTypeValidator itemTypeValidator) {
+ public DialogSelectItemType(Context context, OnSelected onSelected, ItemTypeValidator itemTypeValidator, ItemType selectedItem) {
this.context = context;
this.app = App.get(context);
this.itemTypeValidator = itemTypeValidator;
- if (selectButtonText == null) {
- this.selectButtonText = context.getString(R.string.dialog_selectItemType_select);
- } else {
- this.selectButtonText = selectButtonText;
- }
this.onSelected = onSelected;
- this.simpleSpinnerAdapter = new SimpleSpinnerAdapter<>(context);
- for (ItemType value : ItemType.values()) {
- if (this.itemTypeValidator.validate(value)) {
- EnumUtil.addToSimpleSpinnerAdapter(context, simpleSpinnerAdapter, value);
+ final List tempInfos = new ArrayList<>();
+ final List tempNames = new ArrayList<>();
+
+ int i = 0;
+ for (final ItemsRegistry.ItemInfo item : ItemsRegistry.REGISTRY.getAllItems()) {
+ boolean validate = itemTypeValidator.validate(item.getItemType());
+ if (validate) {
+ tempInfos.add(item);
+ tempNames.add(EnumsRegistry.INSTANCE.name(item.getItemType(), context));
+ if (item.getItemType() == selectedItem) {
+ this.selectedItem = i;
+ }
+ i++;
}
}
- final byte MODE = 2; // 1 - spinner; 2 - list
- // TODO: 2023.05.25 Add MODE selecting in constructor
- // TODO: 2023.05.25 add StartValue to constructor
- if (MODE == 1) {
- Spinner spinner = new Spinner(context);
- this.view = spinner;
- spinner.setAdapter(simpleSpinnerAdapter);
- }
- if (MODE == 2) {
- ListView listView = new ListView(context);
- this.view = listView;
- listView.setAdapter(simpleSpinnerAdapter);
- listView.setOnItemClickListener((parent, ignoreView, position, id) -> {
- ItemType itemType = simpleSpinnerAdapter.getItem(position);
- onSelected.onSelected(itemType);
- cancel();
- });
- }
-
- this.dialog = new AlertDialog.Builder(context)
- .setTitle(this.title)
- .setMessage(this.message)
- .setView(this.view)
- .setNegativeButton(context.getString(R.string.dialog_selectItemAction_cancel), null)
- .setPositiveButton(this.selectButtonText, (i2, i1) -> {
- if (MODE == 1) {
- ItemType itemType = simpleSpinnerAdapter.getItem(((Spinner) view).getSelectedItemPosition());
- onSelected.onSelected(itemType);
- }
- })
- .create();
+ itemsInfos = tempInfos.toArray(new ItemsRegistry.ItemInfo[0]);
+ itemsNames = tempNames.toArray(new CharSequence[0]);
}
public DialogSelectItemType setTitle(String m) {
@@ -106,6 +76,16 @@ public DialogSelectItemType setMessage(String m) {
}
public void show() {
+ this.dialog = new MaterialAlertDialogBuilder(context)
+ .setTitle(this.title)
+ .setMessage(this.message)
+ .setSingleChoiceItems(itemsNames, selectedItem, (dialogInterface, i) -> {
+ if (i < 0) return;
+ onSelected.onSelected(itemsInfos[i].getItemType());
+ cancel();
+ })
+ .setPositiveButton(context.getString(R.string.dialog_selectItemAction_cancel), null)
+ .create();
dialog.show();
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/dialog/IconSelectorDialog.java b/app/src/main/java/com/fazziclay/opentoday/gui/dialog/IconSelectorDialog.java
new file mode 100644
index 00000000..5cad7d8d
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/dialog/IconSelectorDialog.java
@@ -0,0 +1,95 @@
+package com.fazziclay.opentoday.gui.dialog;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.view.Gravity;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.content.res.AppCompatResources;
+
+import com.fazziclay.opentoday.R;
+import com.fazziclay.opentoday.app.icons.IconsRegistry;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+
+import java.util.function.Consumer;
+
+public class IconSelectorDialog {
+
+ private final Context context;
+ private final Consumer iconConsumer;
+ private AlertDialog dialog;
+ private boolean noneIsAvailable;
+
+ public IconSelectorDialog(Context context, Consumer iconConsumer) {
+ this.context = context;
+ this.iconConsumer = iconConsumer;
+ }
+
+ public void show() {
+ var view = new LinearLayout(context);
+ view.setOrientation(LinearLayout.VERTICAL);
+ view.setPadding(20, 10, 10, 10);
+
+ for (IconsRegistry.Icon icon : IconsRegistry.REGISTRY.getIconsList()) {
+ if (icon == IconsRegistry.REGISTRY.NONE) {
+ continue;
+ }
+ LinearLayout l = new LinearLayout(context);
+ l.setOrientation(LinearLayout.HORIZONTAL);
+
+ ImageView i = new ImageView(context);
+ i.setLayoutParams(new LinearLayout.LayoutParams(70, 70));
+ i.setScaleType(ImageView.ScaleType.FIT_XY);
+ Drawable d = AppCompatResources.getDrawable(context, icon.getResId());
+ i.setImageDrawable(d);
+ l.addView(i);
+
+ TextView t = new TextView(context);
+ LinearLayout.LayoutParams tl = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ tl.setMarginStart(7);
+ tl.gravity = Gravity.CENTER;
+ t.setTextSize(17);
+ t.setLayoutParams(tl);
+ t.setText(icon.getId());
+ l.addView(t);
+
+ l.setOnClickListener(v -> {
+ iconConsumer.accept(icon);
+ cancel();
+ });
+ view.addView(l);
+ }
+
+ var scroll = new ScrollView(context);
+ scroll.addView(view);
+
+ final var builder = new MaterialAlertDialogBuilder(context)
+ .setTitle(R.string.dialog_iconSelector_title)
+ .setView(scroll)
+ .setNegativeButton(R.string.abc_cancel, null);
+
+ if (noneIsAvailable) {
+ builder.setNeutralButton(R.string.dialog_iconSelector_none, (dialogInterface, i) -> iconConsumer.accept(IconsRegistry.REGISTRY.NONE));
+ }
+
+ dialog = builder.show();
+
+
+ }
+
+ private void cancel() {
+ if (dialog != null) {
+ dialog.cancel();
+ }
+ }
+
+ public IconSelectorDialog noneIsAvailable(boolean b) {
+ this.noneIsAvailable = b;
+ return this;
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/AboutFragment.kt b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/AboutFragment.kt
index 6ad3f536..fad0ad3e 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/AboutFragment.kt
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/AboutFragment.kt
@@ -14,13 +14,14 @@ import com.fazziclay.opentoday.databinding.FragmentAboutBinding
import com.fazziclay.opentoday.gui.ActivitySettings
import com.fazziclay.opentoday.gui.UI
import com.fazziclay.opentoday.gui.activity.OpenSourceLicensesActivity
+import com.fazziclay.opentoday.gui.interfaces.ActivitySettingsMember
import com.fazziclay.opentoday.util.InlineUtil.viewClick
import com.fazziclay.opentoday.util.NetworkUtil
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
-class AboutFragment : Fragment() {
+class AboutFragment : Fragment(), ActivitySettingsMember {
companion object {
private const val LINK_OPENSOURCE = "https://github.com/fazziclay/opentoday"
private const val LINK_ISSUES = "https://github.com/fazziclay/opentoday/issues"
@@ -38,16 +39,11 @@ class AboutFragment : Fragment() {
super.onCreate(savedInstanceState)
UI.getUIRoot(this).pushActivitySettings { a ->
a.isClockVisible = false
- a.isNotificationsVisible = false
+ a.isNotificationsVisible = true
a.toolbarSettings = ActivitySettings.ToolbarSettings.createBack(R.string.aboutapp_title) { UI.rootBack(this) }
}
}
- override fun onDestroy() {
- super.onDestroy()
- UI.getUIRoot(this).popActivitySettings()
- }
-
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
binding = FragmentAboutBinding.inflate(inflater)
@@ -61,9 +57,9 @@ class AboutFragment : Fragment() {
binding.textVersion.text = App.VERSION_NAME
binding.textReleaseTime.text = getReleaseTime()
binding.textBranch.text = App.VERSION_BRANCH
- if (!App.VERSION_BRANCH.equals("RELEASE", ignoreCase = true)) binding.textBranch.setTextColor(Color.RED)
+ if (!App.VERSION_BRANCH.equals("main", ignoreCase = true)) binding.textBranch.setTextColor(Color.RED)
binding.textPackage.text = App.APPLICATION_ID
- viewClick(binding.aboutText, this::manuallyCrashInteract)
+ viewClick(binding.aboutText, this::manuallySecretSettingsInteract)
viewClick(binding.sourceCode, Runnable { NetworkUtil.openBrowser(requireActivity(), LINK_OPENSOURCE) })
viewClick(binding.issues, Runnable { NetworkUtil.openBrowser(requireActivity(), LINK_ISSUES) })
viewClick(binding.licenses, Runnable { requireActivity().startActivity(OpenSourceLicensesActivity.createLaunchIntent(requireContext())) })
@@ -75,15 +71,19 @@ class AboutFragment : Fragment() {
return SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault()).format(Date(App.VERSION_RELEASE_TIME * 1000))
}
- private fun manuallyCrashInteract() {
+ private fun manuallySecretSettingsInteract() {
+ if (!App.SECRET_SETTINGS_AVAILABLE) {
+ return
+ }
+
if (System.currentTimeMillis() - easterEggLastClick < 1000) {
easterEggCounter++
if (easterEggCounter == 3) {
- Toast.makeText(requireContext(), R.string.manuallyCrash_7tap, Toast.LENGTH_SHORT).show()
+ Toast.makeText(requireContext(), R.string.fragment_about_secretSettingsWarning, Toast.LENGTH_SHORT).show()
}
if (easterEggCounter >= 10) {
easterEggCounter = 0
- UI.Debug.showCrashWithMessageDialog(requireContext(), "Crash by AboutFragment easterEgg :) %s")
+ UI.findFragmentInParents(this, MainRootFragment::class.java)?.navigate(DeveloperFragment(), true)
}
} else {
easterEggCounter = 0
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ChangelogFragment.kt b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ChangelogFragment.kt
index b8ec6957..5ff192db 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ChangelogFragment.kt
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ChangelogFragment.kt
@@ -12,12 +12,13 @@ import com.fazziclay.opentoday.R
import com.fazziclay.opentoday.databinding.FragmentChangelogBinding
import com.fazziclay.opentoday.gui.ActivitySettings
import com.fazziclay.opentoday.gui.UI
+import com.fazziclay.opentoday.gui.interfaces.ActivitySettingsMember
import com.fazziclay.opentoday.util.ColorUtil
import com.fazziclay.opentoday.util.Logger
import com.fazziclay.opentoday.util.ResUtil
import com.fazziclay.opentoday.util.StreamUtil
-class ChangelogFragment : Fragment() {
+class ChangelogFragment : Fragment(), ActivitySettingsMember {
companion object {
fun create(): Fragment {
return ChangelogFragment()
@@ -40,11 +41,6 @@ class ChangelogFragment : Fragment() {
}
}
- override fun onDestroy() {
- super.onDestroy()
- UI.getUIRoot(this).popActivitySettings()
- }
-
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/DeleteItemsFragment.java b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/DeleteItemsFragment.java
index fbad159d..146fb5ae 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/DeleteItemsFragment.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/DeleteItemsFragment.java
@@ -9,13 +9,15 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatDelegate;
+import androidx.appcompat.content.res.AppCompatResources;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.fazziclay.opentoday.R;
import com.fazziclay.opentoday.app.App;
-import com.fazziclay.opentoday.app.SettingsManager;
+import com.fazziclay.opentoday.app.settings.enums.ItemAction;
import com.fazziclay.opentoday.app.items.ItemsRoot;
import com.fazziclay.opentoday.app.items.item.CycleListItem;
import com.fazziclay.opentoday.app.items.item.FilterGroupItem;
@@ -24,16 +26,18 @@
import com.fazziclay.opentoday.databinding.FragmentDeleteItemsBinding;
import com.fazziclay.opentoday.gui.ActivitySettings;
import com.fazziclay.opentoday.gui.UI;
+import com.fazziclay.opentoday.gui.interfaces.ActivitySettingsMember;
import com.fazziclay.opentoday.gui.item.ItemViewGenerator;
import com.fazziclay.opentoday.gui.item.ItemViewGeneratorBehavior;
import com.fazziclay.opentoday.gui.item.ItemViewHolder;
import com.fazziclay.opentoday.gui.item.ItemsStorageDrawerBehavior;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
-public class DeleteItemsFragment extends Fragment {
+public class DeleteItemsFragment extends Fragment implements ActivitySettingsMember {
private static final String KEY_ITEMS_TO_DELETE = "itemsToDelete";
private static final ItemViewGeneratorBehavior ITEM_VIEW_GENERATOR_BEHAVIOR = new DeleteViewGeneratorBehavior();
@@ -66,6 +70,7 @@ public static DeleteItemsFragment create(UUID[] items) {
private ItemsRoot itemsRoot;
private ItemViewGenerator itemViewGenerator;
private Item[] itemsToDelete;
+ private int totalToDelete;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -80,24 +85,20 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
u.add(itemsRoot.getItemById(UUID.fromString(s)));
}
itemsToDelete = u.toArray(new Item[0]);
+ totalToDelete = 0;
+ for (Item item : itemsToDelete) {
+ totalToDelete += item.getChildrenItemCount() + 1;
+ }
// parse END
- itemViewGenerator = ItemViewGenerator.builder(requireActivity())
- .setPreviewMode(true)
- .build();
+ itemViewGenerator = new ItemViewGenerator(requireActivity(), true);
UI.getUIRoot(this).pushActivitySettings(a -> {
a.setNotificationsVisible(false);
- a.setToolbarSettings(ActivitySettings.ToolbarSettings.createBack(requireActivity().getString(R.string.fragment_deleteItems_delete_title, String.valueOf(itemsToDelete.length)), () -> UI.rootBack(DeleteItemsFragment.this)));
+ a.setToolbarSettings(ActivitySettings.ToolbarSettings.createBack(requireActivity().getString(R.string.fragment_deleteItems_delete_title, String.valueOf(itemsToDelete.length), String.valueOf(totalToDelete)), () -> UI.rootBack(DeleteItemsFragment.this)));
});
}
- @Override
- public void onDestroy() {
- super.onDestroy();
- UI.getUIRoot(this).popActivitySettings();
- }
-
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
@@ -131,16 +132,19 @@ public int getItemCount() {
}
});
- binding.deleteButton.setOnClickListener(v -> new AlertDialog.Builder(requireContext())
- .setTitle(requireActivity().getString(R.string.fragment_deleteItems_delete_title, String.valueOf(itemsToDelete.length)))
- .setNegativeButton(R.string.fragment_deleteItems_delete_cancel, null)
- .setPositiveButton(R.string.fragment_deleteItems_delete_apply, ((_dialog1, _which) -> {
- for (Item item : itemsToDelete) {
- item.delete();
- }
- UI.rootBack(this);
- }))
- .show());
+ binding.deleteButton.setOnClickListener(v -> {
+ AlertDialog show = new MaterialAlertDialogBuilder(requireContext())
+ .setTitle(requireActivity().getString(R.string.fragment_deleteItems_delete_title, String.valueOf(itemsToDelete.length), String.valueOf(totalToDelete)))
+ .setNegativeButton(R.string.fragment_deleteItems_delete_cancel, null)
+ .setPositiveButton(R.string.fragment_deleteItems_delete_apply, ((_dialog1, _which) -> {
+ for (Item item : itemsToDelete) {
+ item.delete();
+ }
+ UI.rootBack(this);
+ }))
+ .show();
+ show.setIcon(R.drawable.delete_24px);
+ });
binding.cancelButton.setOnClickListener(v -> UI.rootBack(this));
return binding.getRoot();
@@ -153,7 +157,7 @@ private static class DeleteViewGeneratorBehavior implements ItemViewGeneratorBeh
private static final ItemsStorageDrawerBehavior ITEM_STORAGE_DRAWER_BEHAVIOR = new ItemsStorageDrawerBehavior() {
@Override
- public SettingsManager.ItemAction getItemOnClickAction() {
+ public ItemAction getItemOnClickAction() {
return null;
}
@@ -163,7 +167,7 @@ public boolean isScrollToAddedItem() {
}
@Override
- public SettingsManager.ItemAction getItemOnLeftAction() {
+ public ItemAction getItemOnLeftAction() {
return null;
}
@@ -186,6 +190,7 @@ public boolean ignoreFilterGroup() {
public void onItemDeleteRequest(Item item) {
// do nothing
}
+
};
@Override
@@ -223,5 +228,10 @@ public ItemsStorageDrawerBehavior getItemsStorageDrawerBehavior(Item item) {
public boolean isRenderMinimized(Item item) {
return false;
}
+
+ @Override
+ public boolean isRenderNotificationIndicator(Item item) {
+ return item.isNotifications();
+ }
}
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/DeveloperFragment.java b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/DeveloperFragment.java
new file mode 100644
index 00000000..a0d4d99c
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/DeveloperFragment.java
@@ -0,0 +1,128 @@
+package com.fazziclay.opentoday.gui.fragment;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.Fragment;
+
+import com.fazziclay.javaneoutil.FileUtil;
+import com.fazziclay.opentoday.Debug;
+import com.fazziclay.opentoday.R;
+import com.fazziclay.opentoday.app.App;
+import com.fazziclay.opentoday.databinding.FragmentDeveloperBinding;
+import com.fazziclay.opentoday.gui.ActivitySettings;
+import com.fazziclay.opentoday.gui.UI;
+import com.fazziclay.opentoday.gui.UINotification;
+import com.fazziclay.opentoday.gui.activity.MainActivity;
+import com.fazziclay.opentoday.gui.dialog.IconSelectorDialog;
+import com.fazziclay.opentoday.gui.interfaces.ActivitySettingsMember;
+import com.fazziclay.opentoday.gui.interfaces.NavigationHost;
+import com.fazziclay.opentoday.util.ColorUtil;
+
+import java.io.File;
+
+public class DeveloperFragment extends Fragment implements NavigationHost, ActivitySettingsMember {
+
+ private Context context;
+ private FragmentDeveloperBinding binding;
+ private App app;
+ private boolean popBackStackFlag = true;
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ this.context = requireContext();
+ this.app = App.get(context);
+ UI.getUIRoot(this).pushActivitySettings(a -> {
+ a.setClockVisible(true);
+ a.setDateClickCalendar(true);
+ a.setNotificationsVisible(true);
+ a.setToolbarSettings(ActivitySettings.ToolbarSettings.createBack("OwO!~", () -> {
+ Toast.makeText(context, "back in toolbar clicked! (1000ms delay)", Toast.LENGTH_SHORT).show();
+ UI.postDelayed(() -> {
+ popBackStackFlag = false;
+ UI.rootBack(this);
+ }, 1000);
+ }));
+ });
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ binding = FragmentDeveloperBinding.inflate(inflater);
+ setupView();
+ return binding.getRoot();
+ }
+
+ private void setupView() {
+ binding.plugins.setOnClickListener(_ignore -> showPluginsDialog());
+ binding.crash.setOnClickListener(_ignore -> UI.Debug.showCrashWithMessageDialog(context, "DeveloperFragment love you <3"));
+ binding.featureFlags.setOnClickListener(_ignore -> UI.Debug.showFeatureFlagsDialog(app, context));
+ binding.debugText.setText(ColorUtil.colorize(Debug.getDebugInfoText(), Color.WHITE, Color.BLACK, Typeface.NORMAL));
+ binding.icons.setOnClickListener(_ignore -> new IconSelectorDialog(context, icon -> {
+ Toast.makeText(context, "icon = " + icon.getId(), Toast.LENGTH_SHORT).show();
+ }).show());
+ binding.profiler.setOnClickListener((v) -> {
+ binding.debugText.setText(ColorUtil.PROFILER.getResult(-1));
+ });
+ binding.resetUpdateCheckerTimeout.setOnClickListener(fhsfs -> {
+ File cacheFile = new File(context.getExternalCacheDir(), "latest_update_check");
+ FileUtil.delete(cacheFile);
+ Toast.makeText(context, R.string.abc_success, Toast.LENGTH_SHORT).show();
+ });
+ }
+
+ private void showPluginsDialog() {
+ var view = new EditText(context);
+ view.setText(app.getSettingsManager().getPlugins());
+ new AlertDialog.Builder(context)
+ .setTitle(R.string.fragment_developer_plugins_title)
+ .setMessage(R.string.fragment_developer_plugins_message)
+ .setView(view)
+ .setPositiveButton("Set+Restart", (dialogInterface, i) -> {
+ app.getSettingsManager().setPlugins(view.getText().toString());
+ app.getSettingsManager().save();
+ app.initPlugins();
+ var notify = new TextView(context);
+ notify.setText(R.string.fragment_developer_plugins_reloadedNotification);
+ notify.setTextSize(20);
+ notify.setBackgroundColor(Color.DKGRAY);
+ UI.getUIRoot(this).addNotification(new UINotification(notify, 5000));
+ UI.postDelayed(() -> {
+ getActivity().finish();
+ startActivity(new Intent(context, MainActivity.class));
+ }, 1500);
+ })
+ .setNegativeButton(R.string.abc_cancel, null)
+ .show();
+ }
+
+ @Override
+ public boolean popBackStack() {
+ if (!popBackStackFlag) return false;
+ Toast.makeText(context, "Attempt to popBackStack! (1000ms delayed)", Toast.LENGTH_SHORT).show();
+ UI.postDelayed(() -> {
+ popBackStackFlag = false;
+ UI.rootBack(this);
+ }, 1000);
+ return popBackStackFlag;
+ }
+
+ @Override
+ public void navigate(@NonNull Fragment fragment, boolean addToBackStack) {
+ Toast.makeText(context, "Attempt to navigate in developer fragment lol", Toast.LENGTH_SHORT).show();
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/EnterPinCodeFragment.kt b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/EnterPinCodeFragment.kt
index 74ec0313..28b33e27 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/EnterPinCodeFragment.kt
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/EnterPinCodeFragment.kt
@@ -11,10 +11,13 @@ import com.fazziclay.opentoday.databinding.FragmentEnterPincodeBinding
import com.fazziclay.opentoday.databinding.NotificationTooLongPincodeBinding
import com.fazziclay.opentoday.gui.UI
import com.fazziclay.opentoday.gui.UINotification
+import com.fazziclay.opentoday.gui.fragment.item.ItemsTabIncludeFragment
+import com.fazziclay.opentoday.gui.fragment.settings.SettingsFragment
+import com.fazziclay.opentoday.gui.interfaces.ActivitySettingsMember
import com.fazziclay.opentoday.gui.interfaces.NavigationHost
import com.fazziclay.opentoday.util.InlineUtil.viewClick
-class EnterPinCodeFragment : Fragment() {
+class EnterPinCodeFragment : Fragment(), ActivitySettingsMember {
companion object {
fun create(): EnterPinCodeFragment {
return EnterPinCodeFragment()
@@ -41,11 +44,6 @@ class EnterPinCodeFragment : Fragment() {
}
}
- override fun onDestroy() {
- super.onDestroy()
- UI.getUIRoot(this).popActivitySettings()
- }
-
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
binding = FragmentEnterPincodeBinding.inflate(layoutInflater)
setupKeyboardEmulator()
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/FilterGroupItemFilterEditorFragment.kt b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/FilterGroupItemFilterEditorFragment.kt
index 5f502827..c0f899a5 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/FilterGroupItemFilterEditorFragment.kt
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/FilterGroupItemFilterEditorFragment.kt
@@ -21,6 +21,7 @@ import com.fazziclay.opentoday.app.items.item.filter.LogicContainerItemFilter
import com.fazziclay.opentoday.databinding.FragmentFilterGroupItemFilterEditorBinding
import com.fazziclay.opentoday.gui.ActivitySettings
import com.fazziclay.opentoday.gui.UI
+import com.fazziclay.opentoday.gui.interfaces.ActivitySettingsMember
import com.fazziclay.opentoday.gui.interfaces.Destroy
import com.fazziclay.opentoday.gui.part.DateItemFilterPartEditor
import com.fazziclay.opentoday.gui.part.ItemStatFilterPartEditor
@@ -28,7 +29,7 @@ import com.fazziclay.opentoday.gui.part.LogicContainerItemFilterPartEditor
import kotlinx.coroutines.Runnable
import java.util.UUID
-class FilterGroupItemFilterEditorFragment : Fragment() {
+class FilterGroupItemFilterEditorFragment : Fragment(), ActivitySettingsMember {
companion object {
private const val KEY_FILTER_GROUP = "filterGroupItemFilterEditorFragment:filterGroupId"
private const val KEY_ITEM = "filterGroupItemFilterEditorFragment:itemId"
@@ -122,7 +123,6 @@ class FilterGroupItemFilterEditorFragment : Fragment() {
override fun onDestroy() {
super.onDestroy()
part?.destroy()
- UI.getUIRoot(this).popActivitySettings()
}
private fun setupView() {
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ImportFragment.java b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ImportFragment.java
index 08e12fb3..425dd769 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ImportFragment.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ImportFragment.java
@@ -22,7 +22,7 @@
import com.fazziclay.opentoday.app.App;
import com.fazziclay.opentoday.app.ColorHistoryManager;
import com.fazziclay.opentoday.app.ImportWrapper;
-import com.fazziclay.opentoday.app.SettingsManager;
+import com.fazziclay.opentoday.app.settings.SettingsManager;
import com.fazziclay.opentoday.app.items.ItemsStorage;
import com.fazziclay.opentoday.app.items.item.Item;
import com.fazziclay.opentoday.app.items.selection.SelectionManager;
@@ -32,11 +32,12 @@
import com.fazziclay.opentoday.gui.ActivitySettings;
import com.fazziclay.opentoday.gui.EnumsRegistry;
import com.fazziclay.opentoday.gui.UI;
+import com.fazziclay.opentoday.gui.interfaces.ActivitySettingsMember;
import com.fazziclay.opentoday.util.NetworkUtil;
import java.util.UUID;
-public class ImportFragment extends Fragment {
+public class ImportFragment extends Fragment implements ActivitySettingsMember {
private static final String KEY_ITEMS_STORAGE = "importFragment:itemsStorageId";
private static final String KEY_START_TEXT = "importFragment:startImportText";
private static final String KEY_AUTORUN = "importFragment:autoRun";
@@ -96,12 +97,6 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
});
}
- @Override
- public void onDestroy() {
- super.onDestroy();
- UI.getUIRoot(this).popActivitySettings();
- }
-
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ItemEditorFragment.java b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ItemEditorFragment.java
index b07cb3f6..1b82c116 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ItemEditorFragment.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ItemEditorFragment.java
@@ -14,27 +14,32 @@
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
+import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
-import android.widget.EditText;
-import android.widget.TimePicker;
import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
+import android.widget.TimePicker;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.ItemTouchHelper;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
import com.fazziclay.opentoday.R;
import com.fazziclay.opentoday.app.App;
+import com.fazziclay.opentoday.app.BeautifyColorManager;
import com.fazziclay.opentoday.app.ColorHistoryManager;
import com.fazziclay.opentoday.app.CrashReportContext;
import com.fazziclay.opentoday.app.ImportWrapper;
-import com.fazziclay.opentoday.app.SettingsManager;
import com.fazziclay.opentoday.app.items.ItemsRoot;
import com.fazziclay.opentoday.app.items.ItemsStorage;
import com.fazziclay.opentoday.app.items.item.CheckboxItem;
@@ -47,13 +52,15 @@
import com.fazziclay.opentoday.app.items.item.ItemsRegistry;
import com.fazziclay.opentoday.app.items.item.LongTextItem;
import com.fazziclay.opentoday.app.items.item.MathGameItem;
-import com.fazziclay.opentoday.app.items.item.SleepTimeItem;
import com.fazziclay.opentoday.app.items.item.MissingNoItem;
+import com.fazziclay.opentoday.app.items.item.SleepTimeItem;
import com.fazziclay.opentoday.app.items.item.TextItem;
import com.fazziclay.opentoday.app.items.notification.DayItemNotification;
import com.fazziclay.opentoday.app.items.notification.ItemNotification;
import com.fazziclay.opentoday.app.items.selection.SelectionManager;
import com.fazziclay.opentoday.app.items.tab.Tab;
+import com.fazziclay.opentoday.app.items.tag.ItemTag;
+import com.fazziclay.opentoday.app.settings.SettingsManager;
import com.fazziclay.opentoday.databinding.FragmentItemEditorBinding;
import com.fazziclay.opentoday.databinding.FragmentItemEditorModuleCheckboxBinding;
import com.fazziclay.opentoday.databinding.FragmentItemEditorModuleCounterBinding;
@@ -64,11 +71,13 @@
import com.fazziclay.opentoday.databinding.FragmentItemEditorModuleLongtextBinding;
import com.fazziclay.opentoday.databinding.FragmentItemEditorModuleMathgameBinding;
import com.fazziclay.opentoday.databinding.FragmentItemEditorModuleTextBinding;
+import com.fazziclay.opentoday.databinding.ItemEditorFragmentModuleItemNotificationBinding;
import com.fazziclay.opentoday.gui.ActivitySettings;
import com.fazziclay.opentoday.gui.ColorPicker;
import com.fazziclay.opentoday.gui.EnumsRegistry;
+import com.fazziclay.opentoday.gui.ItemTagGui;
import com.fazziclay.opentoday.gui.UI;
-import com.fazziclay.opentoday.gui.dialog.DialogItemNotificationsEditor;
+import com.fazziclay.opentoday.gui.interfaces.ActivitySettingsMember;
import com.fazziclay.opentoday.gui.interfaces.BackStackMember;
import com.fazziclay.opentoday.gui.interfaces.NavigationHost;
import com.fazziclay.opentoday.util.ClipboardUtil;
@@ -76,11 +85,14 @@
import com.fazziclay.opentoday.util.EnumUtil;
import com.fazziclay.opentoday.util.Logger;
import com.fazziclay.opentoday.util.MinTextWatcher;
+import com.fazziclay.opentoday.util.RandomUtil;
import com.fazziclay.opentoday.util.ResUtil;
import com.fazziclay.opentoday.util.SimpleSpinnerAdapter;
import com.fazziclay.opentoday.util.time.ConvertMode;
import com.fazziclay.opentoday.util.time.HumanTimeType;
import com.fazziclay.opentoday.util.time.TimeUtil;
+import com.google.android.material.chip.Chip;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -89,8 +101,9 @@
import java.util.List;
import java.util.Locale;
import java.util.UUID;
+import java.util.function.Consumer;
-public class ItemEditorFragment extends Fragment implements BackStackMember {
+public class ItemEditorFragment extends Fragment implements BackStackMember, ActivitySettingsMember {
private static final int MODE_UNKNOWN = 0x00;
private static final int MODE_CREATE = 0x02;
private static final int MODE_EDIT = 0x04;
@@ -141,6 +154,8 @@ public static ItemEditorFragment edit(UUID itemId) {
}
+
+
private FragmentItemEditorBinding binding;
private App app;
private ItemsRoot itemsRoot;
@@ -156,6 +171,7 @@ public static ItemEditorFragment edit(UUID itemId) {
// Edit
// Create
private ItemsStorage itemsStorage; // for create
+ private int initBackgroundColor; // for create
// Internal
private final List editModules = new ArrayList<>();
@@ -192,7 +208,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
colorHistoryManager = app.getColorHistoryManager();
selectionManager = app.getSelectionManager();
mode = getArguments().getInt(KEY_MODE, MODE_UNKNOWN);
-
+
if (mode == MODE_EDIT) {
if (getArguments().containsKey(KEY_EDIT_TAB_ID)) {
Tab tab = itemsRoot.getTabById(getArgTabId());
@@ -206,6 +222,9 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
addItemPosition = getArgAddItemPosition();
ItemsRegistry.ItemInfo itemInfo = ItemsRegistry.REGISTRY.get(getArgItemType());
item = itemInfo.create();
+ if (settingsManager.isRandomItemBackground()) {
+ initBackgroundColor = BeautifyColorManager.randomBackgroundColor(app);
+ }
} else {
throw new RuntimeException("Unknown mode: " + mode);
@@ -264,6 +283,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
UI.getUIRoot(this).pushActivitySettings(a -> {
a.setNotificationsVisible(false);
a.setClockVisible(false);
+ a.setShowCanonicalClock(true);
a.setToolbarSettings(ActivitySettings.ToolbarSettings.createBack(EnumsRegistry.INSTANCE.nameResId(ItemsRegistry.REGISTRY.get(item.getClass()).getItemType()), this::cancelRequest)
.setMenu(R.menu.menu_item_editor, menu -> {
menu.findItem(R.id.exportItem)
@@ -288,6 +308,20 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
return true;
})
.setVisible(mode == MODE_EDIT);
+
+
+ MenuItem menuItem = menu.findItem(R.id.deleteItem);
+ menuItem.setVisible(item.isAttached());
+ menuItem.setOnMenuItemClickListener(menuItem1 -> {
+ deleteRequest();
+ return true;
+ });
+
+ menuItem = menu.findItem(R.id.saveItem);
+ menuItem.setOnMenuItemClickListener(menuItem1 -> {
+ applyRequest();
+ return true;
+ });
}));
});
}
@@ -295,18 +329,12 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
@Override
public void onDestroy() {
super.onDestroy();
- UI.getUIRoot(this).popActivitySettings();
CrashReportContext.FRONT.pop();
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
- viewClick(binding.applyButton, this::applyRequest);
- viewClick(binding.cancelButton, this::cancelRequest);
- viewClick(binding.deleteButton, this::deleteRequest);
- viewVisible(binding.deleteButton, item.isAttached(), View.GONE);
-
return binding.getRoot();
}
@@ -334,7 +362,6 @@ public UUID getArgItemStorageId() {
public String getArgItemType() {
return getArguments().getString(KEY_CREATE_ITEM_TYPE);
}
-
public int getArgAddItemPosition() {
return getArguments().getInt(KEY_ADD_ITEM_POSITION);
}
@@ -404,7 +431,7 @@ private void cancelRequest() {
cancel();
return;
}
- new AlertDialog.Builder(requireContext())
+ new MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.fragment_itemEditor_cancel_unsaved_title)
.setNegativeButton(R.string.fragment_itemEditor_cancel_unsaved_continue, null)
.setPositiveButton(R.string.fragment_itemEditor_cancel_unsaved_discard, ((dialog1, which) -> cancel()))
@@ -416,7 +443,7 @@ private void deleteRequest() {
}
public static void deleteRequest(Context context, Item item, Runnable onDelete) {
- new AlertDialog.Builder(context)
+ AlertDialog show = new MaterialAlertDialogBuilder(context)
.setTitle(R.string.fragment_itemEditor_delete_title)
.setMessage(context.getString(R.string.fragment_itemEditor_delete_message, item.getChildrenItemCount()))
.setNegativeButton(R.string.fragment_itemEditor_delete_cancel, null)
@@ -425,6 +452,8 @@ public static void deleteRequest(Context context, Item item, Runnable onDelete)
if (onDelete != null) onDelete.run();
}))
.show();
+
+ show.setIcon(R.drawable.delete_24px);
}
private void cancel() {
@@ -449,18 +478,11 @@ public UserException(String m) {
public abstract static class BaseEditUiModule {
public abstract View getView();
-
public abstract void setup(Item item, Activity activity, View view);
-
public abstract void commit(Item item) throws Exception;
-
public abstract void setOnStartEditListener(Runnable o);
-
- public void notifyCreateMode() {
- }
-
- public void onResume() {
- }
+ public void notifyCreateMode() {}
+ public void onResume() {}
}
public class ItemEditModule extends BaseEditUiModule {
@@ -468,6 +490,7 @@ public class ItemEditModule extends BaseEditUiModule {
private Runnable onEditStart;
private int temp_backgroundColor;
+ private boolean isDefaultBackColor;
@Override
public View getView() {
@@ -482,23 +505,50 @@ public void setup(Item item, Activity activity, View view) {
binding.selected.setChecked(selectionManager.isSelected(item));
viewVisible(binding.selected, mode == MODE_EDIT, View.GONE);
+
+
+ // chip tags START
+ binding.addTag.setOnClickListener(view1 -> showEditTagDialog(new ItemTag("", ""), (itemTag) -> {
+ item.addTag(itemTag);
+ updateTags();
+ }));
+ updateTags();
+ // chip tags END
+
+
+
binding.viewMinHeight.setText(String.valueOf(item.getViewMinHeight()));
- binding.defaultBackgroundColor.setChecked(!item.isViewCustomBackgroundColor());
temp_backgroundColor = item.getViewBackgroundColor();
+ isDefaultBackColor = !item.isViewCustomBackgroundColor();
+ if (mode == MODE_CREATE && settingsManager.isRandomItemBackground()) {
+ temp_backgroundColor = initBackgroundColor;
+ isDefaultBackColor = false;
+ }
updateTextColorIndicator(activity);
- viewClick(binding.viewBackgroundColorEdit, () -> new ColorPicker(activity, temp_backgroundColor)
+ viewClick(binding.itemBackgroundColor, () -> new ColorPicker(activity, temp_backgroundColor)
.setting(true, true, true)
.setColorHistoryManager(colorHistoryManager)
+ .setNeutralDialogButton(R.string.fragment_itemEditor_module_item_backgroundColor_dialog_reset, () -> {
+ isDefaultBackColor = true;
+ updateTextColorIndicator(activity);
+ onEditStart.run();
+ })
.showDialog(R.string.fragment_itemEditor_module_item_backgroundColor_dialog_title,
R.string.fragment_itemEditor_module_item_backgroundColor_dialog_cancel,
- R.string.fragment_itemEditor_module_item_backgroundColor_dialog_apply,
+ R.string.fragment_itemEditor_module_item_backgroundColor_dialog_ok,
(color) -> {
temp_backgroundColor = color;
- binding.defaultBackgroundColor.setChecked(false);
+ isDefaultBackColor = false;
updateTextColorIndicator(activity);
onEditStart.run();
}));
binding.minimize.setChecked(item.isMinimize());
+ viewLong(binding.itemBackgroundColor, () -> {
+ temp_backgroundColor = BeautifyColorManager.randomBackgroundColor(app);
+ isDefaultBackColor = false;
+ updateTextColorIndicator(activity);
+ onEditStart.run();
+ });
// On edit start
binding.viewMinHeight.addTextChangedListener(new MinTextWatcher() {
@@ -511,32 +561,124 @@ public void onTextChanged(CharSequence s, int start, int before, int count) {
onEditStart.run();
}
});
- viewClick(binding.defaultBackgroundColor, () -> {
- updateTextColorIndicator(activity);
- onEditStart.run();
- });
viewClick(binding.minimize, onEditStart);
//
- viewClick(binding.editNotifications, () -> new DialogItemNotificationsEditor(activity, item, () -> updateNotificationPreview(item, activity)).show());
- updateNotificationPreview(item, activity);
+ viewClick(binding.addNotification, () -> {
+
+ DayItemNotification dayItemNotification = new DayItemNotification();
+ dayItemNotification.setNotificationId(RandomUtil.nextIntPositive());
+ dayItemNotification.setLatestDayOfYear(new GregorianCalendar().get(Calendar.DAY_OF_YEAR));
+ item.addNotifications(dayItemNotification);
+ item.save();
+
+ binding.notifications.getAdapter().notifyItemInserted(item.getNotifications().length);
+ updateNotificationNotFoundText();
+ });
+
+ binding.notifications.setAdapter(new RecyclerView.Adapter() {
+ @NonNull
+ @Override
+ public NotificationHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ return new NotificationHolder(parent);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull NotificationHolder holder, int position) {
+ holder.bind(item.getNotifications()[position]);
+ }
+
+ @Override
+ public int getItemCount() {
+ return item.getNotifications().length;
+ }
+ });
+ binding.notifications.setLayoutManager(new LinearLayoutManager(requireContext()));
+ new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.DOWN | ItemTouchHelper.UP, ItemTouchHelper.LEFT) {
+ @Override
+ public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
+ int positionFrom = viewHolder.getAdapterPosition();
+ int positionTo = target.getAdapterPosition();
+
+ item.moveNotifications(positionFrom, positionTo);
+ item.save();
+ binding.notifications.getAdapter().notifyItemMoved(positionFrom, positionTo);
+ return true;
+ }
+
+ @Override
+ public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
+ int pos = viewHolder.getAdapterPosition();
+ ItemNotificationFragment.showDeleteNotificationDialog(requireContext(), () -> {
+ ItemNotification notification = item.getNotifications()[pos];
+ item.removeNotifications(notification);
+ item.save();
+ binding.notifications.getAdapter().notifyItemRemoved(pos);
+ updateNotificationNotFoundText();
+ });
+ binding.notifications.getAdapter().notifyItemChanged(pos);
+ }
+ }).attachToRecyclerView(binding.notifications);
+ updateNotificationNotFoundText();
}
- private void updateNotificationPreview(Item item, Activity activity) {
- StringBuilder text = new StringBuilder();
- for (ItemNotification notification : item.getNotifications()) {
+ @Override
+ public void onResume() {
+ binding.notifications.getAdapter().notifyDataSetChanged();
+ updateNotificationNotFoundText();
+ }
+
+ class NotificationHolder extends RecyclerView.ViewHolder {
+ private final FrameLayout frameLayout;
+ private final ItemEditorFragmentModuleItemNotificationBinding b;
+
+ public NotificationHolder(ViewGroup parent) {
+ super(new FrameLayout(parent.getContext()));
+ frameLayout = ((FrameLayout) itemView);
+ frameLayout.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+ b = ItemEditorFragmentModuleItemNotificationBinding.inflate(getActivity().getLayoutInflater());
+ var params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ params.setMargins(3, 5, 3, 5);
+ b.getRoot().setLayoutParams(params);
+ frameLayout.addView(b.getRoot());
+ }
+
+ public void bind(ItemNotification notification) {
if (notification instanceof DayItemNotification d) {
- text.append(String.format("#%s - %s - %s", d.getNotificationId(), activity.getString(R.string.itemNotification_day), TimeUtil.convertToHumanTime(d.getTime(), ConvertMode.HHMM))).append("\n");
+ b.time.setText(TimeUtil.convertToHumanTime(d.getTime(), ConvertMode.HHMM));
+ b.notificationId.setText("#" + d.getNotificationId());
+ b.getRoot().setOnClickListener(view -> {
+ if (mode == MODE_EDIT) {
+ disableStateRestoreOnEdits();
+ navigationHost.navigate(ItemNotificationFragment.create(getArgItemId(), notification.getId()), true);
+ } else {
+ Toast.makeText(requireContext(), R.string.fragment_itemEditor_module_item_notifications_cantOpenWhileCreate, Toast.LENGTH_SHORT).show();
+ }
+ });
}
}
- binding.notificationsPreview.setText(text.toString());
+ }
+
+ private void updateNotificationNotFoundText() {
+ viewVisible(binding.notificationsNotFounded, !item.isNotifications(), View.GONE);
+ }
+
+ private void updateTags() {
+ binding.itemTagsGroup.removeAllViews();
+ for (final ItemTag tag : item.getTags()) {
+ var view = new Chip(getActivity());
+ view.setText(ItemTagGui.textInChip(tag));
+ viewClick(view, () -> showEditTagDialog(tag, (editedTag) -> view.setText(ItemTagGui.textInChip(editedTag))));
+ binding.itemTagsGroup.addView(view);
+ }
+ binding.itemTagsGroup.addView(binding.addTag);
}
private void updateTextColorIndicator(Activity activity) {
- if (binding.defaultBackgroundColor.isChecked()) {
- binding.viewBackgroundColorIndicator.setBackgroundTintList(ColorStateList.valueOf(ResUtil.getAttrColor(activity, R.attr.item_backgroundColor)));
+ if (isDefaultBackColor) {
+ binding.itemBackgroundColor.setColor(ResUtil.getAttrColor(activity, R.attr.item_backgroundColor));
} else {
- binding.viewBackgroundColorIndicator.setBackgroundTintList(ColorStateList.valueOf(temp_backgroundColor));
+ binding.itemBackgroundColor.setColor(temp_backgroundColor);
}
}
@@ -548,7 +690,7 @@ public void commit(Item item) {
item.setViewMinHeight(Integer.parseInt(binding.viewMinHeight.getText().toString()));
item.setViewBackgroundColor(temp_backgroundColor);
- item.setViewCustomBackgroundColor(!binding.defaultBackgroundColor.isChecked());
+ item.setViewCustomBackgroundColor(!isDefaultBackColor);
item.setMinimize(binding.minimize.isChecked());
if (binding.selected.isChecked()) {
if (!selectionManager.isSelected(item)) {
@@ -569,6 +711,54 @@ public int getTempBackgroundColor() {
public void setOnStartEditListener(Runnable o) {
onEditStart = o;
}
+
+ private void showEditTagDialog(ItemTag tag, Consumer afterEdit) {
+ var view = new LinearLayout(getContext());
+ view.setOrientation(LinearLayout.VERTICAL);
+
+ var title = new EditText(getContext());
+ title.setHint(R.string.dialog_itemTag_title_hint);
+ title.setText(tag.getName());
+ view.addView(title);
+
+
+ var text = new EditText(getContext());
+ text.setHint(R.string.dialog_itemTag_value_hint);
+ text.setText(tag.getValue());
+ view.addView(text);
+
+
+ MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity())
+ .setTitle(R.string.dialog_itemTag_title)
+ .setMessage(R.string.dialog_itemTag_message)
+ .setView(view)
+ .setNegativeButton(R.string.abc_cancel, null);
+
+
+ var ref = new Object() {
+ AlertDialog alertDialog = null;
+ };
+ builder.setPositiveButton(R.string.dialog_itemTag_apply, (_fdfd, _tbnhgfhj) -> {
+ String titleText = title.getText().toString().trim();
+ if (titleText.isEmpty()) {
+ Toast.makeText(getContext(), R.string.dialog_itemTag_titleNotMayEmpty, Toast.LENGTH_SHORT).show();
+ UI.postDelayed(ref.alertDialog::show, 200);
+ return;
+ }
+ tag.setName(titleText);
+ String value = text.getText().toString().trim();
+ if (value.isEmpty()) {
+ value = null;
+ }
+ tag.setValue(value);
+ afterEdit.accept(tag);
+ });
+
+
+ ref.alertDialog = builder.create();
+ ref.alertDialog.show();
+
+ }
}
public class TextItemEditModule extends BaseEditUiModule {
@@ -577,6 +767,7 @@ public class TextItemEditModule extends BaseEditUiModule {
private int temp_textColor;
private MinTextWatcher textWatcher;
+ private boolean isDefaultTextColor;
@Override
public View getView() {
@@ -595,18 +786,22 @@ public void setup(Item item, Activity activity, View view) {
Toast.makeText(activity, R.string.abc_coped, Toast.LENGTH_SHORT).show();
});
binding.text.setText(textItem.getText());
- binding.defaultTextColor.setChecked(!textItem.isCustomTextColor());
+ isDefaultTextColor = !textItem.isCustomTextColor();
temp_textColor = textItem.getTextColor();
updateTextColorIndicator(activity);
- binding.textColorEdit.setOnClickListener(v -> new ColorPicker(activity, temp_textColor)
+ binding.textColor.setOnClickListener(v -> new ColorPicker(activity, temp_textColor)
.setting(true, true, true)
.setColorHistoryManager(colorHistoryManager)
+ .setNeutralDialogButton(R.string.fragment_itemEditor_module_text_textColor_dialog_reset, () -> {
+ isDefaultTextColor = true;
+ updateTextColorIndicator(activity);
+ })
.showDialog(R.string.fragment_itemEditor_module_text_textColor_dialog_title,
R.string.fragment_itemEditor_module_text_textColor_dialog_cancel,
- R.string.fragment_itemEditor_module_text_textColor_dialog_apply,
+ R.string.fragment_itemEditor_module_text_textColor_dialog_ok,
(color) -> {
temp_textColor = color;
- binding.defaultTextColor.setChecked(false);
+ isDefaultTextColor = false;
updateTextColorIndicator(activity);
onEditStart.run();
}));
@@ -626,10 +821,6 @@ public void onTextChanged(CharSequence s, int start, int before, int count) {
viewVisible(binding.openTextEditor, false, View.INVISIBLE);
}
});
- binding.defaultTextColor.setOnClickListener(v -> {
- updateTextColorIndicator(activity);
- onEditStart.run();
- });
binding.clickableUrls.setChecked(textItem.isClickableUrls());
binding.clickableUrls.setOnClickListener(v -> onEditStart.run());
//
@@ -651,10 +842,10 @@ public void onResume() {
}
private void updateTextColorIndicator(Activity activity) {
- if (binding.defaultTextColor.isChecked()) {
- binding.textColorIndicator.setBackgroundTintList(ColorStateList.valueOf(ResUtil.getAttrColor(activity, R.attr.item_textColor)));
+ if (isDefaultTextColor) {
+ binding.textColor.setColor(ResUtil.getAttrColor(activity, R.attr.item_textColor));
} else {
- binding.textColorIndicator.setBackgroundTintList(ColorStateList.valueOf(temp_textColor));
+ binding.textColor.setColor(temp_textColor);
}
}
@@ -668,7 +859,7 @@ public void commit(Item item) {
}
textItem.setText(userInput);
textItem.setTextColor(temp_textColor);
- textItem.setCustomTextColor(!binding.defaultTextColor.isChecked());
+ textItem.setCustomTextColor(!isDefaultTextColor);
textItem.setClickableUrls(binding.clickableUrls.isChecked());
textItem.setParagraphColorize(binding.paragraphColorize.isChecked());
}
@@ -890,8 +1081,7 @@ public void onItemSelected(AdapterView> parent, View view, int position, long
}
@Override
- public void onNothingSelected(AdapterView> parent) {
- }
+ public void onNothingSelected(AdapterView> parent) {}
});
}
@@ -963,12 +1153,10 @@ public void setup(Item item, Activity activity, View view) {
}
@Override
- public void commit(Item item) {
- }
+ public void commit(Item item) {}
@Override
- public void setOnStartEditListener(Runnable o) {
- }
+ public void setOnStartEditListener(Runnable o) { }
}
private static class FilterGroupItemEditModule extends BaseEditUiModule {
@@ -992,7 +1180,6 @@ public void setup(Item item, Activity activity, View view) {
binding.tickBehavior.setSelection(simpleSpinnerAdapter.getValuePosition(filterGroupItem.getTickBehavior()));
binding.tickBehavior.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
int counter = 0;
-
@Override
public void onItemSelected(AdapterView> adapterView, View view, int i, long l) {
if (counter > 0) {
@@ -1002,8 +1189,7 @@ public void onItemSelected(AdapterView> adapterView, View view, int i, long l)
}
@Override
- public void onNothingSelected(AdapterView> adapterView) {
- }
+ public void onNothingSelected(AdapterView> adapterView) {}
});
}
@@ -1055,11 +1241,10 @@ public void setup(Item item, Activity activity, View view) {
// 4 EditText call this function at the same time when onStateRestored
int boundsDisableCounter = 0;
-
private void boundsChanged() {
if (disableMathGameBoundsEdits) {
boundsDisableCounter++;
- if (boundsDisableCounter >= 4) disableMathGameBoundsEdits = false;
+ if (boundsDisableCounter >= 4)disableMathGameBoundsEdits = false;
return;
}
boundsDisableCounter = 0;
@@ -1089,20 +1274,16 @@ public void commit(Item item) {
operationChange(MathGameItem.Operation.DIVIDE, binding.primitiveDivide.isChecked());
try {
this.item.setPrimitiveNumber1Min(Integer.parseInt(binding.n1min.getText().toString()));
- } catch (Exception ignored) {
- }
+ } catch (Exception ignored) {}
try {
this.item.setPrimitiveNumber1Max(Integer.parseInt(binding.n1max.getText().toString()));
- } catch (Exception ignored) {
- }
+ } catch (Exception ignored) {}
try {
this.item.setPrimitiveNumber2Min(Integer.parseInt(binding.n2min.getText().toString()));
- } catch (Exception ignored) {
- }
+ } catch (Exception ignored) {}
try {
this.item.setPrimitiveNumber2Max(Integer.parseInt(binding.n2max.getText().toString()));
- } catch (Exception ignored) {
- }
+ } catch (Exception ignored) {}
if (mode == MODE_EDIT) this.item.generateQuest();
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ItemNotificationFragment.java b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ItemNotificationFragment.java
new file mode 100644
index 00000000..290906e0
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ItemNotificationFragment.java
@@ -0,0 +1,224 @@
+package com.fazziclay.opentoday.gui.fragment;
+
+import android.app.AlertDialog;
+import android.app.TimePickerDialog;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.content.res.AppCompatResources;
+import androidx.fragment.app.Fragment;
+
+import com.fazziclay.opentoday.R;
+import com.fazziclay.opentoday.app.App;
+import com.fazziclay.opentoday.app.items.ItemsRoot;
+import com.fazziclay.opentoday.app.items.item.Item;
+import com.fazziclay.opentoday.app.items.notification.DayItemNotification;
+import com.fazziclay.opentoday.app.items.notification.ItemNotification;
+import com.fazziclay.opentoday.databinding.DialogItemNotificationBinding;
+import com.fazziclay.opentoday.gui.ActivitySettings;
+import com.fazziclay.opentoday.gui.ColorPicker;
+import com.fazziclay.opentoday.gui.UI;
+import com.fazziclay.opentoday.gui.dialog.IconSelectorDialog;
+import com.fazziclay.opentoday.gui.interfaces.ActivitySettingsMember;
+import com.fazziclay.opentoday.util.MinTextWatcher;
+import com.fazziclay.opentoday.util.time.ConvertMode;
+import com.fazziclay.opentoday.util.time.HumanTimeType;
+import com.fazziclay.opentoday.util.time.TimeUtil;
+
+import java.util.UUID;
+
+public class ItemNotificationFragment extends Fragment implements ActivitySettingsMember {
+ private static final String KEY_ITEM_ID = "itemId";
+ private static final String KEY_NOTIFY_ID = "notifyId";
+
+ public static ItemNotificationFragment create(UUID itemId, UUID notificationId) {
+ Bundle b = new Bundle();
+ b.putString(KEY_ITEM_ID, itemId.toString());
+ b.putString(KEY_NOTIFY_ID, notificationId.toString());
+
+ ItemNotificationFragment f = new ItemNotificationFragment();
+ f.setArguments(b);
+ return f;
+ }
+
+ private Context context;
+ private App app;
+ private ItemsRoot itemsRoot;
+ private Item item;
+ private DayItemNotification notification;
+
+
+ private DialogItemNotificationBinding binding;
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ this.context = requireContext();
+ this.app = App.get(context);
+ this.itemsRoot = app.getItemsRoot();
+
+ Bundle args = getArguments();
+ UUID itemId = UUID.fromString(args.getString(KEY_ITEM_ID));
+ UUID notifyId = UUID.fromString(args.getString(KEY_NOTIFY_ID));
+
+ this.item = itemsRoot.getItemById(itemId);
+ this.notification = (DayItemNotification) item.getNotificationById(notifyId);
+
+
+ setupActivitySettings();
+ }
+
+ private void setupActivitySettings() {
+ UI.getUIRoot(this).pushActivitySettings(a -> {
+ a.setToolbarSettings(ActivitySettings.ToolbarSettings.createBack(R.string.fragment_itemNotification_title, () -> UI.rootBack(this)).setMenu(R.menu.menu_notification, new ActivitySettings.ToolbarSettings.MenuInterface() {
+ @Override
+ public void run(Menu menu) {
+ MenuItem item1 = menu.findItem(R.id.notificationDelete);
+ item1.setOnMenuItemClickListener(menuItem -> {
+ deleteRequest();
+ return true;
+ });
+ }
+ }));
+ a.setClockVisible(true);
+ a.setDateClickCalendar(true);
+ a.analogClockForceHidden(true);
+ });
+ }
+
+ private void deleteRequest() {
+ showDeleteNotificationDialog(context, () -> {
+ item.removeNotifications(notification);
+ item.save();
+ UI.rootBack(this);
+ });
+ }
+
+ public static void showDeleteNotificationDialog(Context context, Runnable onDelete) {
+ new AlertDialog.Builder(context)
+ .setIcon(R.drawable.delete_24px)
+ .setTitle(R.string.fragment_itemNotification_delete_title)
+ .setNegativeButton(R.string.abc_cancel, null)
+ .setPositiveButton(R.string.fragment_itemNotification_delete_apply, (ign1, ign2) -> onDelete.run())
+ .show();
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ binding = DialogItemNotificationBinding.inflate(inflater, container, false);
+ setupView();
+ return binding.getRoot();
+ }
+
+ private void setupView() {
+ // icon
+ Drawable drawable = AppCompatResources.getDrawable(context, notification.getIcon().getResId());
+ binding.icon.setImageDrawable(drawable);
+ binding.icon.setScaleType(ImageView.ScaleType.FIT_XY);
+ binding.icon.setOnClickListener(ignore -> new IconSelectorDialog(context, icon -> {
+ notification.setIcon(icon);
+ Drawable drawable1 = AppCompatResources.getDrawable(context, notification.getIcon().getResId());
+ binding.icon.setImageDrawable(drawable1);
+ }).show());
+
+ // id
+ binding.notificationId.setText(String.valueOf(notification.getNotificationId()));
+ MinTextWatcher.after(binding.notificationId, () -> {
+ try {
+ int i = Integer.parseInt(binding.notificationId.getText().toString());
+ notification.setNotificationId(i);
+ } catch (Exception ignored) {
+ notification.setNotificationId(0);
+ binding.notificationId.setText("0");
+ binding.notificationId.setSelection(1);
+ }
+ });
+
+ // text
+ binding.text.setText(notification.getNotifyText());
+ binding.textFromItem.setChecked(notification.isNotifyTextFromItemText());
+ binding.textFromItem.setOnClickListener(vvv -> {
+ binding.text.setEnabled(!binding.textFromItem.isChecked());
+ notification.setNotifyTextFromItemText(binding.textFromItem.isChecked());
+ });
+ binding.text.setEnabled(!binding.textFromItem.isChecked());
+ MinTextWatcher.after(binding.text, () -> notification.setNotifyText(binding.text.getText().toString()));
+
+
+ // title
+ binding.title.setText(notification.getNotifyTitle());
+ binding.titleFromItem.setChecked(notification.isNotifyTitleFromItemText());
+ binding.titleFromItem.setOnClickListener(vvv -> {
+ binding.title.setEnabled(!binding.titleFromItem.isChecked());
+ notification.setNotifyTitleFromItemText(binding.titleFromItem.isChecked());
+ });
+ binding.title.setEnabled(!binding.titleFromItem.isChecked());
+ MinTextWatcher.after(binding.title, () -> notification.setNotifyTitle(binding.title.getText().toString()));
+
+ // sub text
+ binding.notifySubText.setText(notification.getNotifySubText());
+ MinTextWatcher.after(binding.notifySubText, () -> notification.setNotifySubText(binding.notifySubText.getText().toString()));
+
+ // send test notify
+ binding.test.setOnClickListener(v2132321 -> {
+ notification.sendNotify(App.get(context).getItemNotificationHandler());
+ });
+
+ // time
+ binding.time.setText(context.getString(R.string.dialog_itemNotification_time, TimeUtil.convertToHumanTime(notification.getTime(), ConvertMode.HHMM)));
+ binding.time.setOnClickListener(_ignore -> new TimePickerDialog(context, (view, hourOfDay, minute) -> {
+ notification.setTime((hourOfDay * 60 * 60) + (minute * 60));
+ notification.setLatestDayOfYear(0);
+ item.save();
+ binding.time.setText(context.getString(R.string.dialog_itemNotification_time, TimeUtil.convertToHumanTime(notification.getTime(), ConvertMode.HHMM)));
+ }, TimeUtil.getHumanValue(notification.getTime(), HumanTimeType.HOUR), TimeUtil.getHumanValue(notification.getTime(), HumanTimeType.MINUTE_OF_HOUR), true).show());
+
+ // fullscreen
+ binding.fullScreen.setOnCheckedChangeListener((compoundButton, b1) -> {
+ binding.previewViewOnly.setEnabled(b1);
+ binding.sound.setEnabled(b1);
+ });
+ binding.fullScreen.setOnClickListener(i____ -> notification.setFullScreen(binding.fullScreen.isChecked()));
+ binding.fullScreen.setChecked(notification.isFullScreen());
+ binding.previewViewOnly.setEnabled(notification.isFullScreen());
+ binding.sound.setEnabled(notification.isFullScreen());
+
+ binding.previewViewOnly.setChecked(notification.isPreRenderPreviewMode());
+ binding.previewViewOnly.setOnClickListener(i___ -> notification.setPreRenderPreviewMode(binding.previewViewOnly.isChecked()));
+
+ binding.sound.setChecked(notification.isSound());
+ binding.sound.setOnClickListener(i____ -> notification.setSound(binding.sound.isChecked()));
+
+ // color
+ if (notification.getColor() == ItemNotification.DEFAULT_COLOR) {
+ binding.notificationColor.setColorSet(false);
+ } else {
+ binding.notificationColor.setColor(notification.getColor());
+ }
+ binding.notificationColor.setOnClickListener(vvvvv123daqb -> {
+ new ColorPicker(context)
+ .setting(true, true, true)
+ .setStartColor(notification.getColor())
+ .setColorHistoryManager(App.get().getColorHistoryManager())
+ .setNeutralDialogButton(R.string.dialog_itemNotification_defaultColor, () -> {
+ binding.notificationColor.setColorSet(false);
+ notification.setColor(ItemNotification.DEFAULT_COLOR);
+ })
+ .showDialog(R.string.dialog_itemNotification_notificationColor, R.string.abc_cancel, R.string.abc_ok, color -> {
+ binding.notificationColor.setColor(color);
+ notification.setColor(color);
+ });
+ });
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ItemTextEditorFragment.java b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ItemTextEditorFragment.java
index e4c93455..60b6ac2e 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ItemTextEditorFragment.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ItemTextEditorFragment.java
@@ -1,6 +1,7 @@
package com.fazziclay.opentoday.gui.fragment;
import static com.fazziclay.opentoday.util.InlineUtil.viewClick;
+import static com.fazziclay.opentoday.util.InlineUtil.viewLong;
import static com.fazziclay.opentoday.util.InlineUtil.viewVisible;
import android.content.res.ColorStateList;
@@ -28,33 +29,48 @@
import com.fazziclay.opentoday.app.items.ItemsRoot;
import com.fazziclay.opentoday.app.items.item.LongTextItem;
import com.fazziclay.opentoday.app.items.item.TextItem;
+import com.fazziclay.opentoday.app.settings.SettingsManager;
import com.fazziclay.opentoday.databinding.FragmentItemTextEditorBinding;
import com.fazziclay.opentoday.gui.ActivitySettings;
import com.fazziclay.opentoday.gui.ColorPicker;
import com.fazziclay.opentoday.gui.UI;
+import com.fazziclay.opentoday.gui.interfaces.ActivitySettingsMember;
import com.fazziclay.opentoday.gui.interfaces.BackStackMember;
import com.fazziclay.opentoday.util.ColorUtil;
import com.fazziclay.opentoday.util.MinTextWatcher;
import com.fazziclay.opentoday.util.ResUtil;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+import org.intellij.lang.annotations.MagicConstant;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Objects;
import java.util.UUID;
+import java.util.function.Consumer;
-public class ItemTextEditorFragment extends Fragment implements BackStackMember {
+public class ItemTextEditorFragment extends Fragment implements BackStackMember, ActivitySettingsMember {
public static final int EDITABLE_TYPE_TEXT = 0;
public static final int EDITABLE_TYPE_LONG_TEXT = 1;
public static final int EDITABLE_TYPE_AUTO = 2;
+ private static final CharSequence[] AVAILABLE_TEXT_SIZES = new CharSequence[]{
+ "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16",
+ "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30"
+ };
private static final String KEY_ID = "ItemTextEditorFragment_itemId";
private static final String KEY_EDITABLE_TYPE = "ItemTextEditorFragment_editableType";
private static final String KEY_OVERRIDE_PREVIEW_BACKGROUND = "ItemTextEditorFragment_overridePreviewBackground";
private static final String TAG = "ItemTextEditorFragment";
+ private int themeForeColor;
public static ItemTextEditorFragment create(UUID id) {
return create(id, EDITABLE_TYPE_AUTO, null);
}
- public static ItemTextEditorFragment create(UUID id, int editableType, @Nullable String overridePreviewBackground) {
+ public static ItemTextEditorFragment create(@NotNull UUID id,
+ @MagicConstant(intValues = {EDITABLE_TYPE_AUTO, EDITABLE_TYPE_TEXT, EDITABLE_TYPE_LONG_TEXT}) int editableType,
+ @Nullable String overridePreviewBackground) {
ItemTextEditorFragment f = new ItemTextEditorFragment();
Bundle args = new Bundle();
@@ -82,73 +98,101 @@ public static ItemTextEditorFragment create(UUID id, int editableType, @Nullable
private String system;
// CURRENT SYSTEM (END)
+
+ private ItemTextEditorFragment() {
+ }
+
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- App app = App.get(requireContext());
- colorHistoryManager = app.getColorHistoryManager();
- ItemsRoot itemsRoot = app.getItemsRoot();
-
- binding = FragmentItemTextEditorBinding.inflate(getLayoutInflater());
- if (getArguments().containsKey(KEY_OVERRIDE_PREVIEW_BACKGROUND)) {
- overridePreviewBackground = getArguments().getString(KEY_OVERRIDE_PREVIEW_BACKGROUND);
+ final App app = App.get(requireContext());
+ final ItemsRoot itemsRoot = app.getItemsRoot();
+ final Bundle args = getArguments();
+ this.colorHistoryManager = app.getColorHistoryManager();
+ final SettingsManager settingsManager = app.getSettingsManager();
+
+ if (args.containsKey(KEY_OVERRIDE_PREVIEW_BACKGROUND)) {
+ overridePreviewBackground = args.getString(KEY_OVERRIDE_PREVIEW_BACKGROUND);
}
- UUID id = UUID.fromString(getArguments().getString(KEY_ID));
- int editableType = getArguments().getInt(KEY_EDITABLE_TYPE);
+ final UUID id = UUID.fromString(args.getString(KEY_ID));
+ final int editableType = args.getInt(KEY_EDITABLE_TYPE);
+
var _item = itemsRoot.getItemById(id);
if (!(_item instanceof TextItem)) {
- Toast.makeText(requireContext(), R.string.abc_unknown, Toast.LENGTH_SHORT).show();
+ Toast.makeText(requireContext(), R.string.abc_unknown, Toast.LENGTH_LONG).show();
UI.rootBack(this);
return;
}
item = (TextItem) _item;
- if (item == null) throw new RuntimeException("Item not found in ItemsRoot by provided UUID");
+ if (item == null) {
+ throw new RuntimeException("Item not found in ItemsRoot by provided UUID");
+ }
if (editableType == EDITABLE_TYPE_AUTO || editableType == EDITABLE_TYPE_LONG_TEXT) {
isLongText = true;
} else if (editableType == EDITABLE_TYPE_TEXT) {
isLongText = false;
}
if (!(item instanceof LongTextItem)) isLongText = false;
- setupView();
- UI.getUIRoot(this).pushActivitySettings(a -> {
- a.setNotificationsVisible(false);
- a.setClockVisible(false);
- a.setToolbarSettings(
- ActivitySettings.ToolbarSettings.createBack(isLongText ? R.string.fragment_itemTextEditor_toolbar_title_longTextItem : R.string.fragment_itemTextEditor_toolbar_title_textItem, this::cancelRequest)
- .setMenu(R.menu.menu_item_text_editor, menu -> {
- MenuItem preview = previewMenuItem = menu.findItem(R.id.previewFormatting);
- preview.setChecked(showPreview);
- preview.setOnMenuItemClickListener(menuItem -> {
- menuItem.setChecked(!showPreview);
- setShowPreview(!showPreview);
- return true;
- });
-
- MenuItem formattingHelp = menu.findItem(R.id.helpFormatting);
- formattingHelp.setOnMenuItemClickListener(menuItem -> {
- openFormattingHelp();
- return true;
- });
- })
- );
- });
+
+ themeForeColor = UI.getTheme().getRawForegroundColor();
+ if (savedInstanceState == null) {
+ setupActivitySettings();
+ }
+ }
+
+ private void setupActivitySettings() {
+ UI.getUIRoot(this)
+ .pushActivitySettings(a -> {
+ a.setNotificationsVisible(false);
+ a.setClockVisible(false);
+ a.setToolbarSettings(
+ ActivitySettings.ToolbarSettings.createBack(isLongText ? R.string.fragment_itemTextEditor_toolbar_title_longTextItem : R.string.fragment_itemTextEditor_toolbar_title_textItem, this::cancelRequest)
+ .setMenu(R.menu.menu_item_text_editor, menu -> {
+ MenuItem preview = previewMenuItem = menu.findItem(R.id.previewFormatting);
+ preview.setChecked(showPreview);
+ preview.setOnMenuItemClickListener(menuItem -> {
+ menuItem.setChecked(!showPreview);
+ setShowPreview(!showPreview);
+ return true;
+ });
+
+ MenuItem formattingHelp = menu.findItem(R.id.helpFormatting);
+ formattingHelp.setOnMenuItemClickListener(menuItem -> {
+ openFormattingHelp();
+ return true;
+ });
+
+ MenuItem saveText = menu.findItem(R.id.saveText);
+ saveText.setOnMenuItemClickListener(menuItem -> {
+ applyAndClose();
+ return true;
+ });
+ })
+ );
+ });
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ binding = FragmentItemTextEditorBinding.inflate(inflater);
+ setupView();
return binding.getRoot();
}
@Override
public void onDestroy() {
super.onDestroy();
- UI.getUIRoot(this).popActivitySettings();
Debug.itemTextEditor = null;
}
+ private void applyAndClose() {
+ setEditableText(binding.editText.getText().toString());
+ UI.rootBack(this);
+ }
+
// return true if block
@Override
public boolean popBackStack() {
@@ -177,7 +221,7 @@ private void cancelRequest() {
private void openFormattingHelp() {
TextView text = new TextView(requireContext());
- text.setPadding(3, 2, 3, 2);
+ text.setPadding(10, 10, 10, 10);
ScrollView scrollView = new ScrollView(requireContext());
scrollView.addView(text);
@@ -188,7 +232,7 @@ private void openFormattingHelp() {
Typeface.NORMAL,
false));
- new AlertDialog.Builder(requireContext())
+ new MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.fragment_itemTextEditor_formattingHelp_title)
.setView(scrollView)
.setPositiveButton(R.string.abc_ok, null)
@@ -228,10 +272,6 @@ private void setEditableText(String s) {
}
private void setupView() {
- viewClick(binding.apply, () -> {
- setEditableText(binding.editText.getText().toString());
- UI.rootBack(this);
- });
binding.editText.setText(getEditableText());
binding.editText.requestFocus();
@@ -251,7 +291,12 @@ private void setupView() {
binding.formattingPreview.setBackgroundColor(item.getViewBackgroundColor());
}
- viewClick(binding.addSystem, () -> putText(binding.editText.getSelectionStart(), "$[]"));
+ viewClick(binding.addSystem, () -> {
+ putText(binding.editText.getSelectionStart(), "$[]");
+ if (!isShowPreview()) {
+ setShowPreview(true);
+ }
+ });
viewClick(binding.deleteSystem, this::clearCurrentSystem);
viewClick(binding.foregroundColor, () -> new ColorPicker(requireContext(), getSystemColorValue("-"))
@@ -260,6 +305,8 @@ private void setupView() {
.setColorHistoryMax(20)
.setNeutralDialogButton(getString(R.string.fragment_itemTextEditor_foregroundColor_reset), () -> resetSystem("-"))
.showDialog(R.string.fragment_itemTextEditor_foregroundColor_title, R.string.fragment_itemTextEditor_foregroundColor_cancel, R.string.fragment_itemTextEditor_foregroundColor_apply, (color) -> setSystemValue("-", ColorUtil.colorToHex(color))));
+ viewLong(binding.foregroundColor, () -> setSystemValue("-", "reset"));
+
viewClick(binding.backgroundSystem, () -> new ColorPicker(requireContext(), getSystemColorValue("="))
.setting(true, true, true)
@@ -267,6 +314,61 @@ private void setupView() {
.setColorHistoryMax(20)
.setNeutralDialogButton(getString(R.string.fragment_itemTextEditor_backgroundColor_reset), () -> resetSystem("="))
.showDialog(R.string.fragment_itemTextEditor_backgroundColor_title, R.string.fragment_itemTextEditor_backgroundColor_cancel, R.string.fragment_itemTextEditor_backgroundColor_apply, (color) -> setSystemValue("=", ColorUtil.colorToHex(color))));
+ viewLong(binding.backgroundSystem, () -> setSystemValue("=", "reset"));
+
+ viewClick(binding.isBold, () -> {
+ String atContent = getSystemStringValue("@", "");
+ boolean bold = atContent.contains("bold");
+ boolean italic = atContent.contains("italic");
+ boolean strikeOut = atContent.contains("~");
+ setSystemValue("@", getStyleContent(!bold, italic, strikeOut));
+ });
+
+ viewClick(binding.isItalic, () -> {
+ String atContent = getSystemStringValue("@", "");
+ boolean bold = atContent.contains("bold");
+ boolean italic = atContent.contains("italic");
+ boolean strikeOut = atContent.contains("~");
+ setSystemValue("@", getStyleContent(bold, !italic, strikeOut));
+ });
+
+ viewClick(binding.isStrikeOut, () -> {
+ String atContent = getSystemStringValue("@", "");
+ boolean bold = atContent.contains("bold");
+ boolean italic = atContent.contains("italic");
+ boolean strikeOut = atContent.contains("~");
+ setSystemValue("@", getStyleContent(bold, italic, !strikeOut));
+ });
+
+ for (View view : new View[]{binding.isItalic, binding.isStrikeOut, binding.isBold}) {
+ viewLong(view, () -> setSystemValue("@", "reset"));
+ }
+
+ viewClick(binding.formatTextSize, () -> {
+ int size;
+ try {
+ size = Integer.parseInt(getSystemStringValue("S", "-1"));
+ } catch (Exception e) {
+ size = -1;
+ }
+ new TextSizeDialog()
+ .setReset(() -> resetSystem("S"))
+ .setSelectedSize(size)
+ .show((s) -> setSystemValue("S", String.valueOf(s)));
+ });
+ viewLong(binding.formatTextSize, () -> setSystemValue("S", "reset"));
+ }
+
+ private String getStyleContent(boolean bold, boolean italic, boolean strikeOut) {
+ if (bold && italic) {
+ return "bolditalic" + (strikeOut ? "~" : "");
+ } else if (bold) {
+ return "bold" + (strikeOut ? "~" : "");
+ } else if (italic) {
+ return "italic" + (strikeOut ? "~" : "");
+ } else {
+ return "" + (strikeOut ? "~" : "");
+ }
}
private void updateCurrentSystem(int start) {
@@ -308,25 +410,62 @@ private void updateCurrentSystem(int start) {
viewVisible(binding.addSystem, !isSystem(), View.GONE);
viewVisible(binding.deleteSystem, isSystem(), View.GONE);
- binding.foregroundColor.setBackgroundTintList(ColorStateList.valueOf(getSystemColorValue("-")));
+ binding.foregroundColor.setImageTintList(ColorStateList.valueOf(getSystemColorValue("-")));
viewVisible(binding.foregroundColor, isSystem(), View.GONE);
- binding.backgroundSystem.setBackgroundTintList(ColorStateList.valueOf(getSystemColorValue("=")));
+
+ binding.backgroundSystem.setImageTintList(ColorStateList.valueOf(getSystemColorValue("=")));
viewVisible(binding.backgroundSystem, isSystem(), View.GONE);
+
+
+ viewVisible(binding.isBold, isSystem(), View.GONE);
+ binding.isBold.setBackgroundTintList(ColorStateList.valueOf(getStyleTintColor("bold")));
+
+
+ viewVisible(binding.isItalic, isSystem(), View.GONE);
+ binding.isItalic.setBackgroundTintList(ColorStateList.valueOf(getStyleTintColor("italic")));
+
+ viewVisible(binding.isStrikeOut, isSystem(), View.GONE);
+ binding.isStrikeOut.setBackgroundTintList(ColorStateList.valueOf(getStyleTintColor("~")));
+
+ viewVisible(binding.formatTextSize, isSystem(), View.GONE);
+ }
+
+ private int getStyleTintColor(String type) {
+ var colorStyleReset = ResUtil.getAttrColor(requireContext(), R.attr.itemTextEditor_style_reset);
+ if (system != null && system.equals("||")) return colorStyleReset;
+
+ String styleValue = getSystemStringValue("@", "");
+ if (styleValue.equals("reset")) return colorStyleReset;
+
+ var colorStyleTrue = ResUtil.getAttrColor(requireContext(), R.attr.itemTextEditor_style_true);
+ var colorStyleFalse = ResUtil.getAttrColor(requireContext(), R.attr.itemTextEditor_style_false);
+
+ return styleValue.contains(type) ? colorStyleTrue : colorStyleFalse;
}
private int getSystemColorValue(String chas) {
- if (system == null) return Color.TRANSPARENT;
+ if (system == null) return themeForeColor;
for (String s : system.split(";")) {
if (s.startsWith(chas) && s.length() > 1) {
String colorValue = s.substring(1);
try {
return Color.parseColor(colorValue);
} catch (Exception e) {
- return 0xFFFF00FF;
+ return themeForeColor;
}
}
}
- return Color.TRANSPARENT;
+ return themeForeColor;
+ }
+
+ private String getSystemStringValue(String chas, String def) {
+ if (system == null) return def;
+ for (String s : system.split(";")) {
+ if (s.startsWith(chas) && s.length() > 1) {
+ return s.substring(1);
+ }
+ }
+ return def;
}
private void setSystemValue(String c, String val) {
@@ -387,6 +526,10 @@ private void setShowPreview(boolean b) {
if (previewMenuItem != null) previewMenuItem.setChecked(b);
}
+ public boolean isShowPreview() {
+ return showPreview;
+ }
+
private boolean isSystemXExist(String anChar) {
if (system == null) return false;
for (String s : system.split(";")) {
@@ -447,4 +590,42 @@ private String concatLines(String... lines) {
public boolean isSystem() {
return system != null;
}
+
+ private class TextSizeDialog {
+ private Runnable resetRunnable;
+ private int selectedSize = -1;
+
+ public TextSizeDialog setReset(Runnable s) {
+ this.resetRunnable = s;
+ return this;
+ }
+
+ public TextSizeDialog setSelectedSize(int selectedSize) {
+ this.selectedSize = selectedSize;
+ return this;
+ }
+
+ public void show(Consumer applyConsumer) {
+ new MaterialAlertDialogBuilder(requireContext())
+ .setTitle(R.string.fragment_itemTextEditor_size_title)
+ .setSingleChoiceItems(AVAILABLE_TEXT_SIZES, Math.max(0, findElementPositionInArray(AVAILABLE_TEXT_SIZES, String.valueOf(selectedSize))), (dialogInterface, i) -> {
+ if (i < 0) return;
+ int selectedSize = Integer.parseInt(String.valueOf(AVAILABLE_TEXT_SIZES[i]));
+ applyConsumer.accept(selectedSize);
+ dialogInterface.cancel();
+ })
+ .setPositiveButton(R.string.abc_cancel, null)
+ .setNegativeButton(R.string.fragment_itemTextEditor_size_reset, (dialogInterface, i) -> resetRunnable.run())
+ .show();
+ }
+ }
+
+ private int findElementPositionInArray(Object[] array, Object element) {
+ int i = 0;
+ for (Object o : array) {
+ if (o.equals(element)) return i;
+ i++;
+ }
+ return -1;
+ }
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/MainRootFragment.kt b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/MainRootFragment.kt
index 641331f9..bbcd5e43 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/MainRootFragment.kt
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/MainRootFragment.kt
@@ -9,6 +9,9 @@ import androidx.fragment.app.Fragment
import com.fazziclay.opentoday.R
import com.fazziclay.opentoday.app.App
import com.fazziclay.opentoday.app.CrashReportContext
+import com.fazziclay.opentoday.gui.UI.getUIRoot
+import com.fazziclay.opentoday.gui.fragment.item.ItemsTabIncludeFragment
+import com.fazziclay.opentoday.gui.interfaces.ActivitySettingsMember
import com.fazziclay.opentoday.gui.interfaces.BackStackMember
import com.fazziclay.opentoday.gui.interfaces.NavigationHost
import com.fazziclay.opentoday.util.InlineUtil.nullStat
@@ -73,6 +76,9 @@ class MainRootFragment : Fragment(), NavigationHost {
CrashReportContext.setMainRootFragment("popBackStack")
Logger.d(TAG, "popBackStack", "pop internal")
if (childFragmentManager.backStackEntryCount > 0) {
+ if (currentFragment is ActivitySettingsMember) {
+ getUIRoot(this).popActivitySettings()
+ }
childFragmentManager.popBackStack()
return true
}
@@ -83,7 +89,13 @@ class MainRootFragment : Fragment(), NavigationHost {
CrashReportContext.setMainRootFragment("navigate addToBack=$addToBackStack fragment=$fragment")
Logger.d(TAG, "navigate to=$fragment addToBack=$addToBackStack")
val transaction = childFragmentManager.beginTransaction()
- .replace(CONTAINER_ID, fragment)
+ .setCustomAnimations(
+ R.anim.slide_in, // enter
+ R.anim.fade_out, // exit
+ R.anim.fade_in, // popEnter
+ R.anim.slide_out // popExit
+ )
+ .replace(CONTAINER_ID, fragment)
if (addToBackStack) transaction.addToBackStack(null)
transaction.commit()
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ItemsEditorFragment.java b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/item/ItemsEditorFragment.java
similarity index 92%
rename from app/src/main/java/com/fazziclay/opentoday/gui/fragment/ItemsEditorFragment.java
rename to app/src/main/java/com/fazziclay/opentoday/gui/fragment/item/ItemsEditorFragment.java
index fff42faf..c05d29c4 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ItemsEditorFragment.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/item/ItemsEditorFragment.java
@@ -1,8 +1,10 @@
-package com.fazziclay.opentoday.gui.fragment;
+package com.fazziclay.opentoday.gui.fragment.item;
import static com.fazziclay.opentoday.util.InlineUtil.nullStat;
import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
@@ -21,7 +23,7 @@
import com.fazziclay.opentoday.R;
import com.fazziclay.opentoday.app.App;
-import com.fazziclay.opentoday.app.SettingsManager;
+import com.fazziclay.opentoday.app.settings.SettingsManager;
import com.fazziclay.opentoday.app.items.ItemsStorage;
import com.fazziclay.opentoday.app.items.Readonly;
import com.fazziclay.opentoday.app.items.callback.OnItemsStorageUpdate;
@@ -35,11 +37,17 @@
import com.fazziclay.opentoday.databinding.ItemsStorageEmptyBinding;
import com.fazziclay.opentoday.gui.UI;
import com.fazziclay.opentoday.gui.activity.MainActivity;
+import com.fazziclay.opentoday.gui.fragment.DeleteItemsFragment;
+import com.fazziclay.opentoday.gui.fragment.FilterGroupItemFilterEditorFragment;
+import com.fazziclay.opentoday.gui.fragment.ItemEditorFragment;
+import com.fazziclay.opentoday.gui.fragment.ItemTextEditorFragment;
+import com.fazziclay.opentoday.gui.fragment.MainRootFragment;
import com.fazziclay.opentoday.gui.interfaces.NavigationHost;
import com.fazziclay.opentoday.gui.item.ItemViewGeneratorBehavior;
import com.fazziclay.opentoday.gui.item.ItemsStorageDrawer;
import com.fazziclay.opentoday.gui.item.ItemsStorageDrawerBehavior;
import com.fazziclay.opentoday.gui.item.SettingsItemsStorageDrawerBehavior;
+import com.fazziclay.opentoday.util.ColorUtil;
import com.fazziclay.opentoday.util.Logger;
import com.fazziclay.opentoday.util.ResUtil;
import com.fazziclay.opentoday.util.callback.CallbackImportance;
@@ -49,7 +57,7 @@
import java.util.UUID;
public class ItemsEditorFragment extends Fragment {
- private static final int RES_FILTER_BUTTON_IMAGE = android.R.drawable.ic_menu_manage;
+ private static final int RES_FILTER_BUTTON_IMAGE = R.drawable.filter_alt_24px;
private static final String EXTRA_TAB_ID = "items_editor_fragment_tabId";
private static final String EXTRA_ITEM_ID = "items_editor_fragment_itemId";
private static final String EXTRA_PREVIEW_MODE = "items_editor_fragment_previewMode";
@@ -209,6 +217,11 @@ public ItemsStorageDrawerBehavior getItemsStorageDrawerBehavior(Item item) {
public boolean isRenderMinimized(Item item) {
return item.isMinimize();
}
+
+ @Override
+ public boolean isRenderNotificationIndicator(Item item) {
+ return item.isNotifications();
+ }
};
@@ -259,6 +272,7 @@ private void updateNotFoundState(boolean ignoreCache, boolean none) {
if (none) {
ItemsStorageEmptyBinding b = ItemsStorageEmptyBinding.inflate(getLayoutInflater());
b.getRoot().setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+ b.itemsStorageEmptyDescription.setText(ColorUtil.colorize(getString(R.string.itemsStorageEmpty_details), ResUtil.getAttrColor(requireContext(), R.attr.item_text_textColor), Color.TRANSPARENT, Typeface.NORMAL));
layout.addView(b.getRoot());
} else {
layout.addView(itemsStorageDrawer.getView());
@@ -341,13 +355,14 @@ private void applyFilterGroupViewPatch(FilterGroupItem filterGroupItem) {
ImageButton filter = new ImageButton(view.getContext());
filter.setImageResource(RES_FILTER_BUTTON_IMAGE);
+ filter.setImageTintList(ColorStateList.valueOf(ResUtil.getAttrColor(requireContext(), R.attr.itemFilterState_iconColor)));
filterGroup_setEditButtonBackground(filter, item);
filter.setOnClickListener(v -> editFilterGroupItemFilter(filterGroupItem, item));
layout.addView(filter);
filter.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 70, 0));
buttons.put(item, filter);
- destroyer.addDestroyListener(() -> buttons.remove(item));
+ destroyer.add(() -> buttons.remove(item));
return layout;
});
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ItemsEditorRootFragment.java b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/item/ItemsEditorRootFragment.java
similarity index 82%
rename from app/src/main/java/com/fazziclay/opentoday/gui/fragment/ItemsEditorRootFragment.java
rename to app/src/main/java/com/fazziclay/opentoday/gui/fragment/item/ItemsEditorRootFragment.java
index 1b30b269..1d2b0096 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ItemsEditorRootFragment.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/item/ItemsEditorRootFragment.java
@@ -1,7 +1,9 @@
-package com.fazziclay.opentoday.gui.fragment;
+package com.fazziclay.opentoday.gui.fragment.item;
import static com.fazziclay.opentoday.util.InlineUtil.nullStat;
+import static com.fazziclay.opentoday.util.InlineUtil.viewVisible;
+import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.LayoutInflater;
@@ -27,9 +29,13 @@
import com.fazziclay.opentoday.app.items.item.ItemsRegistry;
import com.fazziclay.opentoday.app.items.tab.Tab;
import com.fazziclay.opentoday.app.items.tab.TabsManager;
+import com.fazziclay.opentoday.app.settings.Option;
+import com.fazziclay.opentoday.app.settings.SettingsManager;
import com.fazziclay.opentoday.gui.EnumsRegistry;
import com.fazziclay.opentoday.gui.interfaces.NavigationHost;
import com.fazziclay.opentoday.util.Logger;
+import com.fazziclay.opentoday.util.callback.CallbackImportance;
+import com.fazziclay.opentoday.util.callback.Status;
import java.util.UUID;
@@ -37,8 +43,20 @@ public class ItemsEditorRootFragment extends Fragment implements NavigationHost
private static final int ROOT_CONTAINER_ID = R.id.changeOnLeftSwipe;
private static final String EXTRA_TAB_ID = "items_editor_root_fragment_tabId";
private static final String TAG = "ItemsEditorRootFragment";
+
+
+ private Context context;
private TextView path;
private Item current;
+ private final SettingsManager.OptionChangedCallback optionChangedCallback = new SettingsManager.OptionChangedCallback() {
+ @Override
+ public Status run(Option option, Object value) {
+ if (option == SettingsManager.ITEM_PATH_VISIBLE) {
+ viewVisible(path, (Boolean) value, View.GONE);
+ }
+ return Status.NONE;
+ }
+ };
@NonNull
public static ItemsEditorRootFragment create(@NonNull UUID tabId) {
@@ -50,16 +68,20 @@ public static ItemsEditorRootFragment create(@NonNull UUID tabId) {
}
private TabsManager tabsManager;
+ private SettingsManager sm;
private UUID tabId;
private Tab tab;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ this.context = requireContext();
Logger.d(TAG, "onCreate", nullStat(savedInstanceState));
Bundle args = getArguments();
- this.tabsManager = App.get(requireContext()).getTabsManager();
+ final App app = App.get(context);
+ this.tabsManager = app.getTabsManager();
+ this.sm = app.getSettingsManager();
tabId = UUID.fromString(args.getString(EXTRA_TAB_ID));
tab = tabsManager.getTabById(tabId);
@@ -83,14 +105,17 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Logger.d(TAG, "onCreateView", nullStat(savedInstanceState));
- path = new TextView(requireContext());
+ path = new TextView(context);
+ optionChangedCallback.run(SettingsManager.ITEM_PATH_VISIBLE, SettingsManager.ITEM_PATH_VISIBLE.get(sm));
+ sm.callbacks.addCallback(CallbackImportance.DEFAULT, optionChangedCallback);
updatePath();
- FrameLayout frameLayout = new FrameLayout(requireContext());
+ FrameLayout frameLayout = new FrameLayout(context);
+ frameLayout.setPadding(0, 5, 0, 0);
frameLayout.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
frameLayout.setId(ROOT_CONTAINER_ID);
- LinearLayout l = new LinearLayout(requireContext());
+ LinearLayout l = new LinearLayout(context);
l.setOrientation(LinearLayout.VERTICAL);
l.addView(path);
l.addView(frameLayout);
@@ -99,6 +124,12 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
return l;
}
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ sm.callbacks.removeCallback(optionChangedCallback);
+ }
+
private Drawable getBackgroundDrawable() {
// TODO: 2023.05.22 Add tab background
return tab.getName().equalsIgnoreCase("FAZZICLAY TAB") ? AppCompatResources.getDrawable(requireContext(), R.mipmap.ic_launcher) : null;
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ItemsTabIncludeFragment.java b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/item/ItemsTabIncludeFragment.java
similarity index 83%
rename from app/src/main/java/com/fazziclay/opentoday/gui/fragment/ItemsTabIncludeFragment.java
rename to app/src/main/java/com/fazziclay/opentoday/gui/fragment/item/ItemsTabIncludeFragment.java
index 6cdd679a..4d58a925 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/ItemsTabIncludeFragment.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/item/ItemsTabIncludeFragment.java
@@ -1,6 +1,7 @@
-package com.fazziclay.opentoday.gui.fragment;
+package com.fazziclay.opentoday.gui.fragment.item;
import static com.fazziclay.opentoday.util.InlineUtil.nullStat;
+import static com.fazziclay.opentoday.util.InlineUtil.viewClick;
import android.content.Context;
import android.graphics.Color;
@@ -8,6 +9,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;
import androidx.annotation.NonNull;
@@ -18,22 +20,27 @@
import com.fazziclay.opentoday.Debug;
import com.fazziclay.opentoday.R;
+import com.fazziclay.opentoday.api.EventHandler;
import com.fazziclay.opentoday.app.App;
import com.fazziclay.opentoday.app.ImportWrapper;
-import com.fazziclay.opentoday.app.SettingsManager;
+import com.fazziclay.opentoday.app.events.gui.CurrentItemsStorageContextChanged;
+import com.fazziclay.opentoday.app.icons.IconsRegistry;
import com.fazziclay.opentoday.app.items.ItemsStorage;
import com.fazziclay.opentoday.app.items.Unique;
import com.fazziclay.opentoday.app.items.callback.OnTabsChanged;
import com.fazziclay.opentoday.app.items.item.Item;
import com.fazziclay.opentoday.app.items.item.ItemsRegistry;
-import com.fazziclay.opentoday.app.items.item.TextItem;
-import com.fazziclay.opentoday.app.items.notification.ItemNotification;
import com.fazziclay.opentoday.app.items.selection.SelectionManager;
import com.fazziclay.opentoday.app.items.tab.Tab;
import com.fazziclay.opentoday.app.items.tab.TabsManager;
+import com.fazziclay.opentoday.app.settings.SettingsManager;
+import com.fazziclay.opentoday.app.settings.enums.FirstTab;
import com.fazziclay.opentoday.databinding.FragmentItemsTabIncludeBinding;
+import com.fazziclay.opentoday.gui.GuiItemsHelper;
import com.fazziclay.opentoday.gui.UI;
import com.fazziclay.opentoday.gui.dialog.DialogSelectItemType;
+import com.fazziclay.opentoday.gui.fragment.ImportFragment;
+import com.fazziclay.opentoday.gui.fragment.MainRootFragment;
import com.fazziclay.opentoday.gui.interfaces.CurrentItemsTab;
import com.fazziclay.opentoday.gui.interfaces.NavigationHost;
import com.fazziclay.opentoday.gui.toolbar.AppToolbar;
@@ -43,13 +50,12 @@
import com.fazziclay.opentoday.util.callback.Status;
import com.google.android.material.tabs.TabLayout;
-import java.util.List;
import java.util.UUID;
public class ItemsTabIncludeFragment extends Fragment implements CurrentItemsTab, NavigationHost {
private static final String TAG = "ItemsTabIncludeFragment";
- public static final ItemsTabIncludeFragment.QuickNoteInterface QUICK_NOTE_NOTIFICATIONS_PARSE = QuickNote.QUICK_NOTE_NOTIFICATIONS_PARSE;
+ public static final QuickNote.QuickNoteInterface QUICK_NOTE_NOTIFICATIONS_PARSE = QuickNote.QUICK_NOTE_NOTIFICATIONS_PARSE;
public static ItemsTabIncludeFragment create() {
return new ItemsTabIncludeFragment();
}
@@ -83,7 +89,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
this.rootNavigationHost = UI.findFragmentInParents(this, MainRootFragment.class);
binding = FragmentItemsTabIncludeBinding.inflate(getLayoutInflater());
- if (settingsManager.getFirstTab() == SettingsManager.FirstTab.TAB_ON_CLOSING) {
+ if (settingsManager.getFirstTab() == FirstTab.TAB_ON_CLOSING) {
currentTab = getLastTabId();
if (currentTab == null || tabsManager.getTabById(currentTab) == null) {
currentTab = tabsManager.getFirstTab().getId();
@@ -91,12 +97,13 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
} else {
currentItemsStorage = tabsManager.getTabById(currentTab);
}
- } else if (settingsManager.getFirstTab() == SettingsManager.FirstTab.FIRST) {
+ } else if (settingsManager.getFirstTab() == FirstTab.FIRST) {
currentTab = tabsManager.getFirstTab().getId();
currentItemsStorage = tabsManager.getFirstTab();
} else {
throw new RuntimeException("Unknown firstTab settings!");
}
+ EventHandler.call(new CurrentItemsStorageContextChanged(currentItemsStorage));
this.toolbar = new AppToolbar(requireActivity(), tabsManager, settingsManager, selectionManager, currentItemsStorage, rootNavigationHost, binding.toolbar, binding.toolbarMore);
@@ -119,9 +126,18 @@ public void onPageSelected(int position) {
reloadTabs();
updateViewPager(false);
+ viewClick(binding.addTabInlineButton, () -> {
+ AppToolbar.showAddTabDialog(requireContext(), tabsManager);
+ });
- this.toolbar.setOnMoreVisibleChangedListener(visible -> binding.quickNote.setVisibility(!visible ? View.VISIBLE : View.INVISIBLE));
+ this.toolbar.setOnMoreVisibleChangedListener(visible -> {
+ binding.quickNote.setVisibility(!visible ? View.VISIBLE : View.INVISIBLE);
+ final InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
+ if (imm.isActive()) {
+ binding.quickNote.requestFocus();
+ }
+ });
this.toolbar.create();
setupQuickNote();
@@ -174,6 +190,7 @@ public void onDestroy() {
Logger.d(TAG, "onDestroy");
tabsManager.getOnTabsChangedCallbacks().removeCallback(localOnTabChanged);
if (toolbar != null) toolbar.destroy();
+ EventHandler.call(new CurrentItemsStorageContextChanged(null));
}
@Override
@@ -205,32 +222,27 @@ private void setupQuickNote() {
Toast.makeText(requireContext(), R.string.toolbar_more_file_import_unsupported, Toast.LENGTH_SHORT).show();
}
} else {
- Item item = settingsManager.getDefaultQuickNoteType().create();
- if (item instanceof TextItem) ((TextItem) item).setText(text);
- if (app.getSettingsManager().isParseTimeFromQuickNote()) item.getNotifications().addAll(QUICK_NOTE_NOTIFICATIONS_PARSE.run(text));
- switch (settingsManager.getItemAddPosition()) {
- case TOP -> currentItemsStorage.addItem(item, 0);
- case BOTTOM -> currentItemsStorage.addItem(item);
- }
+ Item item = GuiItemsHelper.createItem(requireContext(), settingsManager.getDefaultQuickNoteType(), text, settingsManager);
+ if (settingsManager.isParseTimeFromQuickNote()) item.addNotifications(QUICK_NOTE_NOTIFICATIONS_PARSE.run(text));
+ GuiItemsHelper.addItem(item, currentItemsStorage, settingsManager);
}
});
binding.quickNoteAdd.setOnLongClickListener(v -> {
new DialogSelectItemType(requireContext(), (type) -> {
- ItemsRegistry.ItemInfo registryItem = ItemsRegistry.REGISTRY.get(type);
- settingsManager.setDefaultQuickNoteType(registryItem);
- settingsManager.save();
+ final ItemsRegistry.ItemInfo registryItem = ItemsRegistry.REGISTRY.get(type);
+ if (settingsManager.isChangeDefaultQuickNoteInLongSendClick()) {
+ settingsManager.setDefaultQuickNoteType(registryItem);
+ settingsManager.save();
+ }
String text = binding.quickNoteText.getText().toString();
- Item item = registryItem.create();
binding.quickNoteText.setText("");
- if (item instanceof TextItem) ((TextItem) item).setText(text);
- if (settingsManager.isParseTimeFromQuickNote()) item.getNotifications().addAll(QUICK_NOTE_NOTIFICATIONS_PARSE.run(text));
- switch (settingsManager.getItemAddPosition()) {
- case TOP -> currentItemsStorage.addItem(item, 0);
- case BOTTOM -> currentItemsStorage.addItem(item);
- }
+ Item item = GuiItemsHelper.createItem(requireContext(), registryItem, text, settingsManager);
+ if (settingsManager.isParseTimeFromQuickNote()) item.addNotifications(QUICK_NOTE_NOTIFICATIONS_PARSE.run(text));
+
+ GuiItemsHelper.addItem(item, currentItemsStorage, settingsManager);
}).show();
return true;
});
@@ -240,6 +252,7 @@ public void setItemStorageInContext(ItemsStorage itemsStorage) {
Logger.d(TAG, "setItemStorageInContext", itemsStorage);
this.currentItemsStorage = itemsStorage;
this.toolbar.setItemStorage(itemsStorage);
+ EventHandler.call(new CurrentItemsStorageContextChanged(currentItemsStorage));
}
private void updateViewPager(boolean smoothScroll) {
@@ -252,10 +265,14 @@ private void updateViewPager(boolean smoothScroll) {
private void setupTabs() {
binding.tabs.removeAllTabs();
- for (Tab tab : tabsManager.getAllTabs()) {
+ for (final Tab tab : tabsManager.getAllTabs()) {
TabLayout.Tab tabView = binding.tabs.newTab();
tabView.setTag(tab.getId().toString());
tabView.setText(tab.getName());
+ IconsRegistry.Icon icon = tab.getIcon();
+ if (icon != IconsRegistry.REGISTRY.NONE) {
+ tabView.setIcon(icon.getResId());
+ }
binding.tabs.addTab(tabView);
}
}
@@ -272,7 +289,7 @@ private void reloadTabs() {
i++;
}
- binding.tabs.setVisibility(binding.tabs.getTabCount() == 1 ? View.GONE : View.VISIBLE);
+ binding.tabsScrollView.setVisibility(binding.tabs.getTabCount() == 1 ? View.GONE : View.VISIBLE);
binding.tabs.addOnTabSelectedListener(uiOnTabSelectedListener);
}
@@ -327,9 +344,7 @@ private ItemsEditorRootFragment getCurrentViewPagerFragment() {
return (ItemsEditorRootFragment) getChildFragmentManager().findFragmentByTag("f" + binding.viewPager.getCurrentItem());
}
- public interface QuickNoteInterface {
- List run(String text);
- }
+
// On UI tab selected
private class UIOnTabSelectedListener implements TabLayout.OnTabSelectedListener {
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/settings/AnalogClockSettingsFragment.java b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/settings/AnalogClockSettingsFragment.java
new file mode 100644
index 00000000..52191ea3
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/settings/AnalogClockSettingsFragment.java
@@ -0,0 +1,130 @@
+package com.fazziclay.opentoday.gui.fragment.settings;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.SeekBar;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+import androidx.fragment.app.Fragment;
+
+import com.fazziclay.opentoday.R;
+import com.fazziclay.opentoday.app.App;
+import com.fazziclay.opentoday.app.ColorHistoryManager;
+import com.fazziclay.opentoday.app.settings.ColorOption;
+import com.fazziclay.opentoday.app.settings.SettingsManager;
+import com.fazziclay.opentoday.databinding.FragmentSettingsAnalogClockBinding;
+import com.fazziclay.opentoday.gui.ActivitySettings;
+import com.fazziclay.opentoday.gui.ColorPicker;
+import com.fazziclay.opentoday.gui.UI;
+import com.fazziclay.opentoday.gui.interfaces.ActivitySettingsMember;
+import com.fazziclay.opentoday.util.opentodaybutton.MaterialButtonWithColorIndicator;
+
+public class AnalogClockSettingsFragment extends Fragment implements ActivitySettingsMember {
+ private FragmentSettingsAnalogClockBinding binding;
+ private Context context;
+ private App app;
+ private SettingsManager sm;
+ private ColorHistoryManager colorHistoryManager;
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ this.context = requireContext();
+ this.app = App.get(context);
+ this.sm = app.getSettingsManager();
+ this.colorHistoryManager = app.getColorHistoryManager();
+
+ if (savedInstanceState == null) {
+ setupActivitySettings();
+ }
+ }
+
+ private void setupActivitySettings() {
+ UI.getUIRoot(this).pushActivitySettings(a -> {
+ a.setClockVisible(true);
+ a.analogClockForceVisible(true);
+ a.setToolbarSettings(ActivitySettings.ToolbarSettings.createBack(R.string.settings_analogClock_title, () -> UI.rootBack(this)));
+ });
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ binding = FragmentSettingsAnalogClockBinding.inflate(inflater, container, false);
+ setupView();
+ return binding.getRoot();
+ }
+
+ private void setupView() {
+ binding.alpha.setProgress(SettingsManager.ANALOG_CLOCK_TRANSPARENCY.get(sm));
+ binding.alpha.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
+ SettingsManager.ANALOG_CLOCK_TRANSPARENCY.set(sm, i);
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ sm.save();
+ }
+ });
+
+
+ binding.size.setProgress(SettingsManager.ANALOG_CLOCK_SIZE.get(sm));
+ binding.size.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
+ SettingsManager.ANALOG_CLOCK_SIZE.set(sm, i);
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ sm.save();
+ }
+ });
+ updateButtonsColorIndicator();
+ setupButtonHand(binding.secondHandColor, R.string.fragment_settings_analogClockSettings_handColor_second, SettingsManager.ANALOG_CLOCK_COLOR_SECONDS);
+ setupButtonHand(binding.minuteHandColor, R.string.fragment_settings_analogClockSettings_handColor_minute, SettingsManager.ANALOG_CLOCK_COLOR_MINUTE);
+ setupButtonHand(binding.hourHandColor, R.string.fragment_settings_analogClockSettings_handColor_hour, SettingsManager.ANALOG_CLOCK_COLOR_HOUR);
+ }
+
+ public void setupButtonHand(MaterialButtonWithColorIndicator view, @StringRes int title, ColorOption option) {
+ view.setOnClickListener(v -> {
+ int initColor = option.get(sm);
+ new ColorPicker(context, initColor)
+ .setColorHistoryManager(colorHistoryManager)
+ .setting(true, true, true)
+ .setNeutralDialogButton(R.string.fragment_settings_analogClockSettings_handColor_reset, () -> {
+ option.def(sm);
+ updateButtonsColorIndicator();
+ sm.save();
+ })
+ .showDialog(title, R.string.abc_cancel, R.string.abc_ok, color -> {
+ option.set(sm, color);
+ updateButtonsColorIndicator();
+ sm.save();
+ });
+ });
+ }
+
+ public void updateButtonsColorIndicator() {
+ binding.secondHandColor.setColor(SettingsManager.ANALOG_CLOCK_COLOR_SECONDS.get(sm));
+ binding.minuteHandColor.setColor(SettingsManager.ANALOG_CLOCK_COLOR_MINUTE.get(sm));
+ binding.hourHandColor.setColor(SettingsManager.ANALOG_CLOCK_COLOR_HOUR.get(sm));
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/SettingsFragment.kt b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/settings/SettingsFragment.kt
similarity index 78%
rename from app/src/main/java/com/fazziclay/opentoday/gui/fragment/SettingsFragment.kt
rename to app/src/main/java/com/fazziclay/opentoday/gui/fragment/settings/SettingsFragment.kt
index 7c2103af..0a2950b4 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/fragment/SettingsFragment.kt
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/fragment/settings/SettingsFragment.kt
@@ -1,4 +1,4 @@
-package com.fazziclay.opentoday.gui.fragment
+package com.fazziclay.opentoday.gui.fragment.settings
import android.app.Activity
import android.app.AlertDialog
@@ -13,6 +13,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.AdapterView.OnItemSelectedListener
+import android.widget.CompoundButton
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.Spinner
@@ -28,17 +29,22 @@ import com.fazziclay.opentoday.app.ImportWrapper
import com.fazziclay.opentoday.app.PinCodeManager
import com.fazziclay.opentoday.app.PinCodeManager.PinCodeNotValidateException
import com.fazziclay.opentoday.app.PinCodeManager.ValidationException
-import com.fazziclay.opentoday.app.SettingsManager
-import com.fazziclay.opentoday.app.SettingsManager.FirstTab
import com.fazziclay.opentoday.app.items.QuickNoteReceiver
import com.fazziclay.opentoday.app.items.item.ItemType
import com.fazziclay.opentoday.app.items.item.ItemsRegistry
+import com.fazziclay.opentoday.app.settings.ActionBarPosition
+import com.fazziclay.opentoday.app.settings.BooleanOption
+import com.fazziclay.opentoday.app.settings.SettingsManager
+import com.fazziclay.opentoday.app.settings.enums.DateAndTimePreset
+import com.fazziclay.opentoday.app.settings.enums.FirstTab
+import com.fazziclay.opentoday.app.settings.enums.ItemAddPosition
import com.fazziclay.opentoday.databinding.ExportBinding
import com.fazziclay.opentoday.databinding.FragmentSettingsBinding
import com.fazziclay.opentoday.gui.ActivitySettings
import com.fazziclay.opentoday.gui.EnumsRegistry
import com.fazziclay.opentoday.gui.UI
import com.fazziclay.opentoday.gui.dialog.DialogSelectItemType
+import com.fazziclay.opentoday.gui.fragment.MainRootFragment
import com.fazziclay.opentoday.util.EnumUtil
import com.fazziclay.opentoday.util.InlineUtil.viewClick
import com.fazziclay.opentoday.util.Logger
@@ -62,7 +68,7 @@ class SettingsFragment : Fragment() {
private lateinit var binding: FragmentSettingsBinding
private lateinit var app: App
- private lateinit var settingsManager: SettingsManager
+ private lateinit var sm: SettingsManager
private lateinit var colorHistoryManager: ColorHistoryManager
private lateinit var pinCodeManager: PinCodeManager
private var pinCodeCallback = Runnable {}
@@ -75,7 +81,7 @@ class SettingsFragment : Fragment() {
CrashReportContext.FRONT.push("SettingsFragment")
Logger.d(TAG, "onCreate")
app = App.get(requireContext())
- settingsManager = app.settingsManager
+ sm = app.settingsManager
colorHistoryManager = app.colorHistoryManager
pinCodeManager = app.pinCodeManager
UI.getUIRoot(this).pushActivitySettings { a ->
@@ -105,20 +111,20 @@ class SettingsFragment : Fragment() {
viewClick(binding.dateAndTimeFormat, Runnable {
val preview = TextView(requireContext())
val spinner = Spinner(requireContext())
- val adapter = SimpleSpinnerAdapter(requireContext())
+ val adapter = SimpleSpinnerAdapter(requireContext())
spinner.adapter = adapter
- for (value in SettingsManager.DateAndTimePreset.values()) {
+ for (value in DateAndTimePreset.values()) {
adapter.add(value.name, value)
}
spinner.onItemSelectedListener = object : OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view123: View?, position: Int, id: Long) {
val t = adapter.getItem(position)
- settingsManager.applyDateAndTimePreset(t)
- settingsManager.save()
+ sm.applyDateAndTimePreset(t)
+ sm.save()
val current = GregorianCalendar().time
- val dateFormat = SimpleDateFormat(settingsManager.datePattern, Locale.getDefault())
- val timeFormat = SimpleDateFormat(settingsManager.timePattern, Locale.getDefault())
+ val dateFormat = SimpleDateFormat(sm.datePattern, Locale.getDefault())
+ val timeFormat = SimpleDateFormat(sm.timePattern, Locale.getDefault())
val previewText = dateFormat.format(current) + " " + timeFormat.format(current)
@@ -142,53 +148,42 @@ class SettingsFragment : Fragment() {
viewClick(binding.themeTitle, Runnable { experimentalFeaturesInteract() })
// QuickNote
- binding.quickNoteCheckbox.isChecked = settingsManager.isQuickNoteNotification
+ binding.quickNoteCheckbox.isChecked = sm.isQuickNoteNotification
viewClick(binding.quickNoteCheckbox, Runnable {
- settingsManager.isQuickNoteNotification = binding.quickNoteCheckbox.isChecked
- if (settingsManager.isQuickNoteNotification) {
+ sm.isQuickNoteNotification = binding.quickNoteCheckbox.isChecked
+ if (sm.isQuickNoteNotification) {
QuickNoteReceiver.sendQuickNoteNotification(requireContext())
} else {
QuickNoteReceiver.cancelQuickNoteNotification(requireContext())
}
- settingsManager.save()
+ sm.save()
})
- // Parse time from quick note
- binding.parseTimeFromQuickNote.isChecked = settingsManager.isParseTimeFromQuickNote
- viewClick(binding.parseTimeFromQuickNote, Runnable {
- settingsManager.isParseTimeFromQuickNote = binding.parseTimeFromQuickNote.isChecked
- settingsManager.save()
- })
- // Minimize gray color
- binding.minimizeGrayColor.isChecked = settingsManager.isMinimizeGrayColor
- viewClick(binding.minimizeGrayColor, Runnable {
- settingsManager.isMinimizeGrayColor = binding.minimizeGrayColor.isChecked
- settingsManager.save()
- })
- // Trim item names in Editor
- binding.trimItemNamesOnEdit.isChecked = settingsManager.isTrimItemNamesOnEdit
- viewClick(binding.trimItemNamesOnEdit, Runnable {
- settingsManager.isTrimItemNamesOnEdit = binding.trimItemNamesOnEdit.isChecked
- settingsManager.save()
+ // Lock color history
+ binding.colorHistoryEnabled.isChecked = SettingsManager.COLOR_HISTORY_ENABLED[sm]
+ viewClick(binding.colorHistoryEnabled, Runnable {
+ binding.colorHistoryLocked.isEnabled = binding.colorHistoryEnabled.isChecked
+ SettingsManager.COLOR_HISTORY_ENABLED[sm] = binding.colorHistoryEnabled.isChecked
+ sm.save()
})
- // Lock color history
binding.colorHistoryLocked.isChecked = colorHistoryManager.isLocked
+ binding.colorHistoryLocked.isEnabled = binding.colorHistoryEnabled.isChecked
viewClick(binding.colorHistoryLocked, Runnable {
colorHistoryManager.isLocked = binding.colorHistoryLocked.isChecked
})
// Export
- viewClick(binding.export, Runnable { showExportDialog(requireActivity(), settingsManager, colorHistoryManager) })
+ viewClick(binding.export, Runnable { showExportDialog(requireActivity(), sm, colorHistoryManager) })
// Is telemetry
- binding.isTelemetry.isChecked = settingsManager.isTelemetry
+ binding.isTelemetry.isChecked = SettingsManager.IS_TELEMETRY.get(sm)
viewClick(binding.isTelemetry, Runnable {
val isTelemetry = binding.isTelemetry.isChecked
- settingsManager.isTelemetry = isTelemetry
- settingsManager.save()
+ SettingsManager.IS_TELEMETRY.set(sm, isTelemetry)
+ sm.save()
app.telemetry.setEnabled(isTelemetry)
if (isTelemetry) AlertDialog.Builder(requireContext())
.setTitle(R.string.setup_telemetry)
@@ -196,48 +191,53 @@ class SettingsFragment : Fragment() {
.setPositiveButton(R.string.abc_ok, null)
.show()
})
- binding.defaultQuickNoteType.text = getString(R.string.settings_defaultQuickNoteType, getString(EnumsRegistry.nameResId(settingsManager.defaultQuickNoteType.itemType)))
+ binding.defaultQuickNoteType.text = getString(R.string.settings_defaultQuickNoteType, getString(EnumsRegistry.nameResId(sm.defaultQuickNoteType.itemType)))
viewClick(binding.defaultQuickNoteType, Runnable {
- DialogSelectItemType(context) { type: ItemType ->
- settingsManager.defaultQuickNoteType = ItemsRegistry.REGISTRY.get(type)
- binding.defaultQuickNoteType.text = getString(R.string.settings_defaultQuickNoteType, getString(EnumsRegistry.nameResId(settingsManager.defaultQuickNoteType.itemType)))
- settingsManager.save()
- }.show()
+ DialogSelectItemType(context, { type: ItemType ->
+ sm.defaultQuickNoteType = ItemsRegistry.REGISTRY.get(type)
+ binding.defaultQuickNoteType.text = getString(R.string.settings_defaultQuickNoteType, getString(EnumsRegistry.nameResId(sm.defaultQuickNoteType.itemType)))
+ sm.save()
+ }, sm.defaultQuickNoteType.itemType).setTitle(getString(R.string.dialog_selectItemType_generic_title)).show()
})
pinCodeCallback = Runnable { binding.pincode.text = getString(R.string.settings_pincode, if (pinCodeManager.isPinCodeSet) getString(R.string.settings_pincode_on) else getString(R.string.settings_pincode_off)) }
pinCodeCallback.run()
viewClick(binding.pincode, Runnable { showPinCodeDialog() })
// add item to top
- binding.addItemsToTop.isChecked = settingsManager.itemAddPosition == SettingsManager.ItemAddPosition.TOP
+ binding.addItemsToTop.isChecked = sm.itemAddPosition == ItemAddPosition.TOP
viewClick(binding.addItemsToTop, Runnable {
- settingsManager.itemAddPosition = if (binding.addItemsToTop.isChecked) SettingsManager.ItemAddPosition.TOP else SettingsManager.ItemAddPosition.BOTTOM
- settingsManager.save()
- })
-
- // confirm easy-to-make changes
- binding.confirmFastChanges.isChecked = settingsManager.isConfirmFastChanges
- viewClick(binding.confirmFastChanges, Runnable {
- settingsManager.isConfirmFastChanges = binding.confirmFastChanges.isChecked
- settingsManager.save()
+ sm.itemAddPosition = if (binding.addItemsToTop.isChecked) ItemAddPosition.TOP else ItemAddPosition.BOTTOM
+ sm.save()
})
- binding.autoCloseToolbar.isChecked = settingsManager.isAutoCloseToolbar
- viewClick(binding.autoCloseToolbar, Runnable {
- settingsManager.isAutoCloseToolbar = binding.autoCloseToolbar.isChecked
- settingsManager.save()
+ // action bar position
+ binding.actionbarInBottom.isChecked = SettingsManager.ACTIONBAR_POSITION[sm] == ActionBarPosition.BOTTOM
+ viewClick(binding.actionbarInBottom, Runnable {
+ SettingsManager.ACTIONBAR_POSITION[sm] = if (binding.actionbarInBottom.isChecked) ActionBarPosition.BOTTOM else ActionBarPosition.TOP
+ sm.save()
+ UI.rootBack(this)
})
- binding.scrollToAddedItem.isChecked = settingsManager.isScrollToAddedItem
- viewClick(binding.scrollToAddedItem, Runnable {
- settingsManager.isScrollToAddedItem = binding.scrollToAddedItem.isChecked
- settingsManager.save()
- })
+ attachCheckBox(binding.parseTimeFromQuickNote, SettingsManager.QUICK_NOTE_PARSE_TIME_FROM_ITEM)
+ attachCheckBox(binding.minimizeGrayColor, SettingsManager.ITEM_MINIMIZE_GRAY_COLOR)
+ attachCheckBox(binding.trimItemNamesOnEdit, SettingsManager.ITEM_TRIM_NAMES_IN_EDITOR)
+ attachCheckBox(binding.confirmFastChanges, SettingsManager.FAST_CHANGES_CONFIRM)
+ attachCheckBox(binding.autoCloseToolbar, SettingsManager.TOOLBAR_AUTOMATICALLY_CLOSE)
+ attachCheckBox(binding.scrollToAddedItem, SettingsManager.ITEM_IS_SCROLL_TO_ADDED)
+ attachCheckBox(binding.itemInternalBackgroundFromItem, SettingsManager.ITEM_EDITOR_BACKGROUND_AS_ITEM)
+ attachCheckBox(binding.isItemBackgroundRandom, SettingsManager.ITEM_RANDOM_BACKGROUND)
+ attachCheckBox(binding.isAnalogClock, SettingsManager.ANALOG_CLOCK_ENABLE)
+ attachCheckBox(binding.showItemPath, SettingsManager.ITEM_PATH_VISIBLE)
+ binding.analogClockOptions.setOnClickListener {
+ UI.findFragmentInParents(this, MainRootFragment::class.java)?.navigate(AnalogClockSettingsFragment(), true)
+ }
+ }
- binding.itemInternalBackgroundFromItem.isChecked = settingsManager.isItemEditorBackgroundFromItem
- viewClick(binding.itemInternalBackgroundFromItem, Runnable {
- settingsManager.isItemEditorBackgroundFromItem = binding.itemInternalBackgroundFromItem.isChecked
- settingsManager.save()
+ private fun attachCheckBox(compoundButton: CompoundButton, booleanOption: BooleanOption) {
+ compoundButton.isChecked = booleanOption.get(sm)
+ viewClick(compoundButton, Runnable {
+ booleanOption.set(sm, compoundButton.isChecked)
+ sm.save()
})
}
@@ -245,12 +245,12 @@ class SettingsFragment : Fragment() {
val adapter = SimpleSpinnerAdapter(requireContext())
EnumUtil.addToSimpleSpinnerAdapter(requireContext(), adapter, FirstTab.values())
binding.firstTab.adapter = adapter
- binding.firstTab.setSelection(adapter.getValuePosition(settingsManager.firstTab))
+ binding.firstTab.setSelection(adapter.getValuePosition(sm.firstTab))
binding.firstTab.onItemSelectedListener = object : OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val t = adapter.getItem(position)
- settingsManager.firstTab = t
- settingsManager.save()
+ sm.firstTab = t
+ sm.save()
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
@@ -263,13 +263,13 @@ class SettingsFragment : Fragment() {
.add(requireContext().getString(R.string.settings_theme_light), AppCompatDelegate.MODE_NIGHT_NO)
.add(requireContext().getString(R.string.settings_theme_night), AppCompatDelegate.MODE_NIGHT_YES)
binding.themeSpinner.adapter = adapter
- binding.themeSpinner.setSelection(adapter.getValuePosition(settingsManager.theme))
+ binding.themeSpinner.setSelection(adapter.getValuePosition(sm.theme))
binding.themeSpinner.onItemSelectedListener = object : OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val theme = adapter.getItem(position)
UI.setTheme(theme)
- settingsManager.theme = theme
- settingsManager.save()
+ sm.theme = theme
+ sm.save()
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
@@ -282,12 +282,12 @@ class SettingsFragment : Fragment() {
.add(weekdays[Calendar.SUNDAY], Calendar.SUNDAY)
.add(weekdays[Calendar.MONDAY], Calendar.MONDAY)
binding.firstDayOfWeekSpinner.adapter = adapter
- binding.firstDayOfWeekSpinner.setSelection(adapter.getValuePosition(settingsManager.firstDayOfWeek))
+ binding.firstDayOfWeekSpinner.setSelection(adapter.getValuePosition(sm.firstDayOfWeek))
binding.firstDayOfWeekSpinner.onItemSelectedListener = object : OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val day = adapter.getItem(position)
- settingsManager.firstDayOfWeek = day
- settingsManager.save()
+ sm.firstDayOfWeek = day
+ sm.save()
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
@@ -393,6 +393,10 @@ class SettingsFragment : Fragment() {
}
private fun experimentalFeaturesInteract() {
+ if (!App.SECRET_SETTINGS_AVAILABLE) {
+ return
+ }
+
if (System.currentTimeMillis() - easterEggLastClick < 1000) {
easterEggCounter++
if (easterEggCounter >= 6) {
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/interfaces/ActivitySettingsMember.java b/app/src/main/java/com/fazziclay/opentoday/gui/interfaces/ActivitySettingsMember.java
new file mode 100644
index 00000000..c3109638
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/interfaces/ActivitySettingsMember.java
@@ -0,0 +1,4 @@
+package com.fazziclay.opentoday.gui.interfaces;
+
+public interface ActivitySettingsMember {
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/interfaces/BackStackMember.kt b/app/src/main/java/com/fazziclay/opentoday/gui/interfaces/BackStackMember.kt
index ef126b24..ada87674 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/interfaces/BackStackMember.kt
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/interfaces/BackStackMember.kt
@@ -1,5 +1,6 @@
package com.fazziclay.opentoday.gui.interfaces
interface BackStackMember {
+ // return true if block
fun popBackStack(): Boolean
}
\ No newline at end of file
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/item/AbstractItemsStorageDrawer.java b/app/src/main/java/com/fazziclay/opentoday/gui/item/AbstractItemsStorageDrawer.java
index 5b0dd343..f548d23b 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/item/AbstractItemsStorageDrawer.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/item/AbstractItemsStorageDrawer.java
@@ -1,7 +1,6 @@
package com.fazziclay.opentoday.gui.item;
import android.content.Context;
-import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
@@ -59,6 +58,8 @@ public void destroy() {
view.setAdapter(null);
}
+ protected abstract void runOnUiThread(Runnable r);
+
protected abstract int getItemCount();
protected abstract void onBindItem(@NotNull ItemViewHolder holder, int position);
@@ -81,14 +82,14 @@ protected void callWithNonNullAdapter(Consumer consumer) {
}
public void roughUpdateItemAt(int position) {
- callWithNonNullAdapter(drawerAdapter -> drawerAdapter.notifyItemChanged(position));
+ runOnUiThread(() -> callWithNonNullAdapter(drawerAdapter -> drawerAdapter.notifyItemChanged(position)));
}
public void smoothUpdateItemAt(int position) {
// if update viewHolder is null, it currently out of screen bounds
var var = (ItemViewHolder) view.findViewHolderForAdapterPosition(position);
if (var != null) {
- onBindItem(var, position);
+ runOnUiThread(() -> onBindItem(var, position));
} else {
// test change: if smooth is unavailable => rough
roughUpdateItemAt(position);
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/item/CurrentItemStorageDrawer.java b/app/src/main/java/com/fazziclay/opentoday/gui/item/CurrentItemStorageDrawer.java
index 4c098da0..bc0d1c7b 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/item/CurrentItemStorageDrawer.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/item/CurrentItemStorageDrawer.java
@@ -23,7 +23,7 @@ public class CurrentItemStorageDrawer {
private final @NotNull ItemViewGeneratorBehavior itemViewGeneratorBehavior;
private final @NotNull CurrentItemStorage currentItemStorage;
private final @NotNull OnUpdateListener listener = new OnUpdateListener();
- private final @NotNull HolderDestroyer holderDestroyer;
+ private final @NotNull Destroyer destroyer;
private final @NotNull ItemInterface onItemClick;
private @Nullable OnCurrentItemStorageUpdate userListener = null;
@@ -32,14 +32,14 @@ public CurrentItemStorageDrawer(@NonNull Activity activity,
@NonNull ItemViewGenerator itemViewGenerator,
@NonNull ItemViewGeneratorBehavior itemViewGeneratorBehavior,
@NonNull CurrentItemStorage currentItemStorage,
- @NotNull HolderDestroyer holderDestroyer,
+ @NotNull Destroyer destroyer,
@NotNull ItemInterface onItemClick) {
this.activity = activity;
this.itemViewGeneratorBehavior = itemViewGeneratorBehavior;
this.itemViewGenerator = itemViewGenerator;
this.currentItemStorage = currentItemStorage;
this.view = view;
- this.holderDestroyer = holderDestroyer;
+ this.destroyer = destroyer;
this.onItemClick = onItemClick;
}
@@ -65,7 +65,7 @@ private void updateView(Item currentItem) {
userListener.onCurrentChanged(currentItem);
}
if (currentItem != null) {
- view.addView(itemViewGenerator.generate(currentItem, view, itemViewGeneratorBehavior, holderDestroyer, onItemClick));
+ view.addView(itemViewGenerator.generate(currentItem, view, itemViewGeneratorBehavior, destroyer, onItemClick));
view.setOnClickListener(view -> onItemClick.run(currentItem));
}
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/item/HolderDestroyer.java b/app/src/main/java/com/fazziclay/opentoday/gui/item/Destroyer.java
similarity index 56%
rename from app/src/main/java/com/fazziclay/opentoday/gui/item/HolderDestroyer.java
rename to app/src/main/java/com/fazziclay/opentoday/gui/item/Destroyer.java
index 879047c7..45842a43 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/item/HolderDestroyer.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/item/Destroyer.java
@@ -5,25 +5,29 @@
import java.util.ArrayList;
import java.util.List;
-public class HolderDestroyer {
- private static final String TAG = "HolderDestroyer";
+public class Destroyer {
+ private static final String TAG = "Destroyer";
private final List listeners = new ArrayList<>();
private boolean destroyed = false;
- public void addDestroyListener(Runnable runnable) {
+ public void add(final Runnable runnable) {
listeners.add(runnable);
}
public void destroy() {
if (!destroyed) {
- for (Runnable listener : listeners) {
+ for (final Runnable listener : listeners) {
listener.run();
- Logger.d(TAG, "destroyed: " + listener);
}
destroyed = true;
} else {
- Logger.d(TAG, "destroy() called in already destroyed!");
+ Logger.w(TAG, "destroy() called when it already destroyed!");
}
}
+
+ public void recycle() {
+ destroyed = false;
+ listeners.clear();
+ }
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/item/ItemViewGenerator.java b/app/src/main/java/com/fazziclay/opentoday/gui/item/ItemViewGenerator.java
index 38fd0df6..4672ca0f 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/item/ItemViewGenerator.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/item/ItemViewGenerator.java
@@ -3,13 +3,14 @@
import static com.fazziclay.opentoday.util.InlineUtil.viewClick;
import static com.fazziclay.opentoday.util.InlineUtil.viewVisible;
+import android.animation.ArgbEvaluator;
+import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.graphics.Typeface;
-import android.os.Handler;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.util.Linkify;
@@ -17,16 +18,20 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
import android.widget.CheckBox;
-import android.widget.LinearLayout;
+import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.fazziclay.opentoday.Debug;
import com.fazziclay.opentoday.R;
import com.fazziclay.opentoday.app.App;
+import com.fazziclay.opentoday.app.items.callback.ItemCallback;
import com.fazziclay.opentoday.app.items.item.CheckboxItem;
import com.fazziclay.opentoday.app.items.item.CounterItem;
import com.fazziclay.opentoday.app.items.item.CycleListItem;
@@ -35,11 +40,11 @@
import com.fazziclay.opentoday.app.items.item.FilterGroupItem;
import com.fazziclay.opentoday.app.items.item.GroupItem;
import com.fazziclay.opentoday.app.items.item.Item;
+import com.fazziclay.opentoday.app.items.item.ItemType;
import com.fazziclay.opentoday.app.items.item.ItemUtil;
import com.fazziclay.opentoday.app.items.item.LongTextItem;
import com.fazziclay.opentoday.app.items.item.MathGameItem;
import com.fazziclay.opentoday.app.items.item.SleepTimeItem;
-import com.fazziclay.opentoday.app.items.item.MissingNoItem;
import com.fazziclay.opentoday.app.items.item.TextItem;
import com.fazziclay.opentoday.databinding.ItemCheckboxBinding;
import com.fazziclay.opentoday.databinding.ItemCounterBinding;
@@ -58,17 +63,26 @@
import com.fazziclay.opentoday.util.RandomUtil;
import com.fazziclay.opentoday.util.ResUtil;
import com.fazziclay.opentoday.util.annotation.ForItem;
+import com.fazziclay.opentoday.util.callback.CallbackImportance;
import com.fazziclay.opentoday.util.callback.Status;
import com.fazziclay.opentoday.util.time.ConvertMode;
import com.fazziclay.opentoday.util.time.TimeUtil;
+import org.jetbrains.annotations.NotNull;
+
import java.util.Arrays;
+/**
+ * Make a android View from item
+ */
public class ItemViewGenerator {
private static final String TAG = "ItemViewGenerator";
- private static final String DESTROYED_CONST = "DESTROYED";
- @NonNull private final Activity activity;
- @NonNull private final LayoutInflater layoutInflater;
+ private static final String DESTROYED_CONST = "DESTROYED"; // constant value for Debug.DESTROY_ANY_TEXTITEM_CHILD
+
+ @NonNull
+ private final Activity activity;
+ @NonNull
+ private final LayoutInflater layoutInflater;
private final boolean previewMode; // Disable items minimize view patch & disable buttons
public ItemViewGenerator(@NonNull final Activity activity, final boolean previewMode) {
@@ -77,118 +91,106 @@ public ItemViewGenerator(@NonNull final Activity activity, final boolean preview
this.previewMode = previewMode;
}
- public static CreateBuilder builder(final Activity activity) {
- return new CreateBuilder(activity);
+ // this method uses this.previewMode instead of method argument
+ public View generate(final @NotNull Item item,
+ final @Nullable ViewGroup parent,
+ final @NotNull ItemViewGeneratorBehavior behavior,
+ final @NotNull Destroyer destroyer,
+ final @NotNull ItemInterface onItemClick) {
+ return generate(item, parent, behavior, this.previewMode, destroyer, onItemClick);
}
- public View generate(final Item item, final ViewGroup parent, ItemViewGeneratorBehavior behavior, HolderDestroyer holderDestroyer, ItemInterface onItemClick) {
- return generate(item, parent, behavior, previewMode, holderDestroyer, onItemClick);
- }
-
- public View generate(final Item item, final ViewGroup parent, ItemViewGeneratorBehavior behavior, boolean previewMode, HolderDestroyer holderDestroyer, ItemInterface onItemClick) {
- final Class extends Item> type = item.getClass();
- final View resultView;
-
- if (type == Item.class) {
- throw new RuntimeException("Illegal itemType to generate view. Use children's of Item");
-
- } else if (type == TextItem.class) {
- resultView = generateTextItemView((TextItem) item, parent, behavior, previewMode, holderDestroyer);
-
- } else if (type == CheckboxItem.class) {
- resultView = generateCheckboxItemView((CheckboxItem) item, parent, behavior, previewMode, holderDestroyer);
-
- } else if (type == DebugTickCounterItem.class) {
- resultView = generateDebugTickCounterItemView((DebugTickCounterItem) item, parent, behavior, previewMode, holderDestroyer);
-
- } else if (type == DayRepeatableCheckboxItem.class) {
- resultView = generateDayRepeatableCheckboxItemView((DayRepeatableCheckboxItem) item, parent, behavior, previewMode, holderDestroyer);
-
- } else if (type == CycleListItem.class) {
- resultView = generateCycleListItemView((CycleListItem) item, parent, behavior, previewMode, holderDestroyer, onItemClick);
-
- } else if (type == CounterItem.class) {
- resultView = generateCounterItemView((CounterItem) item, parent, behavior, previewMode, holderDestroyer);
-
- } else if (type == GroupItem.class) {
- resultView = generateGroupItemView((GroupItem) item, parent, behavior, previewMode, holderDestroyer, onItemClick);
-
- } else if (type == FilterGroupItem.class) {
- resultView = generateFilterGroupItemView((FilterGroupItem) item, parent, behavior, previewMode, holderDestroyer, onItemClick);
-
- } else if (type == LongTextItem.class) {
- resultView = generateLongTextItemView((LongTextItem) item, parent, behavior, previewMode, holderDestroyer);
-
- } else if (type == MathGameItem.class) {
- resultView = generateMathGameItemView((MathGameItem) item, parent, behavior, previewMode, holderDestroyer);
-
- } else if (type == SleepTimeItem.class) {
- resultView = generateSleepTimeItemView((SleepTimeItem) item, parent, behavior, previewMode, holderDestroyer);
-
- } else if (type == MissingNoItem.class) {
- resultView = generateMissingNoItem(parent);
+ public View generate(final @NotNull Item item,
+ final @Nullable ViewGroup parent,
+ final @NotNull ItemViewGeneratorBehavior behavior,
+ boolean previewMode,
+ final @NotNull Destroyer destroyer,
+ final @NotNull ItemInterface onItemClick) {
+
+ final ItemType type = item.getItemType();
+ final View resultView = switch (type) {
+ case MISSING_NO -> generateMissingNoItem(parent);
+ case TEXT -> generateTextItemView((TextItem) item, parent, behavior, previewMode, destroyer);
+ case DEBUG_TICK_COUNTER -> generateDebugTickCounterItemView((DebugTickCounterItem) item, parent, behavior, previewMode, destroyer);
+ case LONG_TEXT -> generateLongTextItemView((LongTextItem) item, parent, behavior, previewMode, destroyer);
+ case CHECKBOX -> generateCheckboxItemView((CheckboxItem) item, parent, behavior, previewMode, destroyer);
+ case CHECKBOX_DAY_REPEATABLE -> generateDayRepeatableCheckboxItemView((DayRepeatableCheckboxItem) item, parent, behavior, previewMode, destroyer);
+ case COUNTER -> generateCounterItemView((CounterItem) item, parent, behavior, previewMode, destroyer);
+ case CYCLE_LIST -> generateCycleListItemView((CycleListItem) item, parent, behavior, previewMode, destroyer, onItemClick);
+ case GROUP -> generateGroupItemView((GroupItem) item, parent, behavior, previewMode, destroyer, onItemClick);
+ case FILTER_GROUP -> generateFilterGroupItemView((FilterGroupItem) item, parent, behavior, previewMode, destroyer, onItemClick);
+ case MATH_GAME -> generateMathGameItemView((MathGameItem) item, parent, behavior, previewMode, destroyer);
+ case SLEEP_TIME -> generateSleepTimeItemView((SleepTimeItem) item, parent, behavior, previewMode, destroyer);
+ default -> {
+ final UnsupportedOperationException exception = new UnsupportedOperationException(TAG + " can't generate view because itemType=" + type + " currently not supported... Check " + TAG + " for fix this!");
+ Logger.e(TAG, "Unexpected item type to generate view. (wait 3000ms in DebugUtil.sleep())", exception);
+ DebugUtil.sleep(3000);
+ throw exception;
+ }
+ };
- } else {
- RuntimeException exception = new RuntimeException("Unexpected item type '" + type.getName() + "'! check ItemViewGenerator for fix this.");
- Logger.e(TAG, "Unexpected item type to generate view. (wait 3000ms in DebugUtil.sleep())", exception);
- DebugUtil.sleep(3000);
- throw exception;
- }
+ final boolean isMinimized = behavior.isRenderMinimized(item);
// Minimal height
- if (!behavior.isRenderMinimized(item) && !previewMode) resultView.setMinimumHeight(item.getViewMinHeight());
+ if (!isMinimized && !previewMode) resultView.setMinimumHeight(item.getViewMinHeight());
// BackgroundColor
if (item.isViewCustomBackgroundColor()) {
resultView.setBackgroundTintList(ColorStateList.valueOf(item.getViewBackgroundColor()));
}
- // Minimize view patch
- if (!previewMode && behavior.isRenderMinimized(item)) {
- LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- layoutParams.setMargins(0, 0, 15, 0);
- resultView.setLayoutParams(layoutParams);
- }
+ // foreground
applyForeground(resultView, item, behavior);
- resultView.setOnClickListener(view -> onItemClick.run(item));
+
+ // view click
+ resultView.setOnClickListener(view -> {
+ item.dispatchClick();
+ onItemClick.run(item);
+ });
+
return resultView;
}
-
- private View generateMissingNoItem(ViewGroup parent) {
- ItemTextBinding binding = ItemTextBinding.inflate(layoutInflater, parent, false);
- binding.title.setText("missingno (error item...)");
+
+
+ @ForItem(k = ItemType.MISSING_NO)
+ private View generateMissingNoItem(@Nullable ViewGroup parent) {
+ final ItemTextBinding binding = ItemTextBinding.inflate(layoutInflater, parent, false);
+ binding.title.setText(R.string.item_missingNo);
binding.title.setTextColor(Color.RED);
binding.getRoot().setBackground(null);
return binding.getRoot();
}
- private void applyForeground(View view, Item item, ItemViewGeneratorBehavior behavior) {
- view.setForeground(behavior.getForeground(item));
- }
-
- @ForItem(key = MathGameItem.class)
- private View generateMathGameItemView(MathGameItem item, ViewGroup parent, ItemViewGeneratorBehavior behavior, boolean previewMode, HolderDestroyer destroyer) {
+ @ForItem(k = ItemType.MATH_GAME)
+ private View generateMathGameItemView(MathGameItem item,
+ ViewGroup parent,
+ ItemViewGeneratorBehavior behavior,
+ boolean previewMode,
+ Destroyer destroyer) {
final ItemMathGameBinding binding = ItemMathGameBinding.inflate(this.layoutInflater, parent, false);
final MathGameInterface gameInterface = new MathGameInterface() {
private String currentNumberStr = "0";
private int currentNumber = 0;
-
public void numberPress(byte b) {
+ if (b < 0 || b > 9) {
+ throw new IllegalArgumentException("OutOfRange of numberPress(0-9): " + b);
+ }
currentNumberStr += b;
try {
currentNumber = Integer.parseInt(currentNumberStr);
} catch (Exception ignored) {
- currentNumber = (int) (Math.PI * 10000000);
+ currentNumber = RandomUtil.nextInt(); // easter egg number (if number out of int(32-bits))
}
currentNumberStr = String.valueOf(currentNumber);
updateDisplay();
}
- public void done() {
- int color;
- if (item.isResultRight(currentNumber)) {
+ public void donePress() {
+ final int color;
+ final boolean right = item.isResultRight(currentNumber);
+ if (right) {
color = Color.GREEN;
item.postResult(currentNumber);
binding.questText.setText(item.getQuestText());
@@ -198,16 +200,22 @@ public void done() {
color = Color.RED;
}
- clear();
- binding.userEnterNumber.setBackgroundColor(color);
- new Handler().postDelayed(() -> binding.userEnterNumber.setBackgroundColor(Color.TRANSPARENT), 100);
+ clearCurrentInput();
+
+ final ValueAnimator animator = ValueAnimator.ofObject(new ArgbEvaluator(), color, Color.TRANSPARENT);
+ animator.setDuration(right ? 1000 : 512);
+ animator.setInterpolator(right ? new DecelerateInterpolator() : new AccelerateInterpolator());
+ animator.addUpdateListener(valueAnimator -> {
+ binding.userEnterNumber.setBackgroundTintList(ColorStateList.valueOf(((int) valueAnimator.getAnimatedValue())));
+ });
+ animator.start();
}
- public void clear() {
- setValue(0);
+ public void clearCurrentInput() {
+ setCurrentInput(0);
}
- private void setValue(int v) {
+ private void setCurrentInput(int v) {
currentNumber = v;
currentNumberStr = String.valueOf(v);
updateDisplay();
@@ -218,7 +226,7 @@ private void updateDisplay() {
}
public void invert() {
- setValue(-currentNumber);
+ setCurrentInput(-currentNumber);
}
@Override
@@ -240,13 +248,14 @@ public void init() {
viewClick(binding.number7, () -> numberPress((byte) 7));
viewClick(binding.number8, () -> numberPress((byte) 8));
viewClick(binding.number9, () -> numberPress((byte) 9));
- viewClick(binding.numberClear, this::clear);
- viewClick(binding.numberNext, this::done);
+ viewClick(binding.numberClear, this::clearCurrentInput);
+ viewClick(binding.numberNext, this::donePress);
}
};
// Text
applyTextItemToTextView(item, binding.title, behavior, destroyer, previewMode);
+ applyItemNotificationIndicator(item, binding.indicatorNotification, behavior, destroyer, previewMode);
gameInterface.init();
binding.keyboard.setEnabled(!previewMode);
@@ -276,59 +285,80 @@ public void init() {
return binding.getRoot();
}
- interface MathGameInterface {
+ @ForItem(k = ItemType.MATH_GAME)
+ private interface MathGameInterface {
void init();
}
- private View generateSleepTimeItemView(SleepTimeItem item, ViewGroup parent, ItemViewGeneratorBehavior behavior, boolean previewMode, HolderDestroyer holderDestroyer) {
+ @ForItem(k = ItemType.SLEEP_TIME)
+ private View generateSleepTimeItemView(SleepTimeItem item,
+ ViewGroup parent,
+ ItemViewGeneratorBehavior behavior,
+ boolean previewMode,
+ Destroyer destroyer) {
final ItemSleepTimeBinding binding = ItemSleepTimeBinding.inflate(this.layoutInflater, parent, false);
- applyTextItemToTextView(item, binding.title, behavior, holderDestroyer, previewMode);
- binding.description.setText(item.getSleepTextPattern()
+
+ applyTextItemToTextView(item, binding.title, behavior, destroyer, previewMode);
+ applyItemNotificationIndicator(item, binding.indicatorNotification, behavior, destroyer, previewMode);
+
+ final String s = item.getSleepTextPattern()
.replace("$(elapsed)", TimeUtil.convertToHumanTime(item.getElapsedTime(), ConvertMode.HHMM))
+ .replace("$(elapsedToStartSleep)", TimeUtil.convertToHumanTime(item.getElapsedTimeToStartSleep(), ConvertMode.HHMM))
+ .replace("$(current)", TimeUtil.convertToHumanTime(TimeUtil.getDaySeconds(), ConvertMode.HHMM))
.replace("$(wakeUpForRequired)", TimeUtil.convertToHumanTime(item.getWakeUpForRequiredAtCurr(), ConvertMode.HHMM))
.replace("$(wakeUpTime)", TimeUtil.convertToHumanTime(item.getWakeUpTime(), ConvertMode.HHMM))
- .replace("$(requiredSleepTime)", TimeUtil.convertToHumanTime(item.getRequiredSleepTime(), ConvertMode.HHMM)));
+ .replace("$(requiredSleepTime)", TimeUtil.convertToHumanTime(item.getRequiredSleepTime(), ConvertMode.HHMM));
+
+ binding.description.setText(colorize(s, item.getTextColor()));
return binding.getRoot();
}
- @ForItem(key = LongTextItem.class)
- public View generateLongTextItemView(final LongTextItem item, final ViewGroup parent, ItemViewGeneratorBehavior behavior, boolean previewMode, HolderDestroyer holderDestroyer) {
+ @ForItem(k = ItemType.LONG_TEXT)
+ public View generateLongTextItemView(final LongTextItem item,
+ final ViewGroup parent,
+ ItemViewGeneratorBehavior behavior,
+ boolean previewMode,
+ Destroyer destroyer) {
final ItemLongtextBinding binding = ItemLongtextBinding.inflate(this.layoutInflater, parent, false);
// Text
- applyTextItemToTextView(item, binding.title, behavior, holderDestroyer, previewMode);
+ applyTextItemToTextView(item, binding.title, behavior, destroyer, previewMode);
applyLongTextItemToLongTextView(item, binding.longText);
+ applyItemNotificationIndicator(item, binding.indicatorNotification, behavior, destroyer, previewMode);
return binding.getRoot();
}
- @ForItem(key = DebugTickCounterItem.class)
- private View generateDebugTickCounterItemView(final DebugTickCounterItem item, final ViewGroup parent, ItemViewGeneratorBehavior behavior, boolean previewMode, HolderDestroyer holderDestroyer) {
+ @ForItem(k = ItemType.DEBUG_TICK_COUNTER)
+ private View generateDebugTickCounterItemView(final DebugTickCounterItem item, final ViewGroup parent, ItemViewGeneratorBehavior behavior, boolean previewMode, Destroyer destroyer) {
+ // Warning: DebugTickCounter uses LongText layout!
final ItemLongtextBinding binding = ItemLongtextBinding.inflate(this.layoutInflater, parent, false);
// Title
- applyTextItemToTextView(item, binding.title, behavior, holderDestroyer, previewMode);
+ applyTextItemToTextView(item, binding.title, behavior, destroyer, previewMode);
+ applyItemNotificationIndicator(item, binding.indicatorNotification, behavior, destroyer, previewMode);
// Debugs
- binding.longText.setText(ColorUtil.colorize(item.getDebugStat(), Color.WHITE, Color.TRANSPARENT, Typeface.NORMAL));
+ binding.longText.setText(colorize(item.getDebugStat(), Color.WHITE));
binding.longText.setTextSize(10);
return binding.getRoot();
}
- @ForItem(key = FilterGroupItem.class)
- private View generateFilterGroupItemView(final FilterGroupItem item, final ViewGroup parent, ItemViewGeneratorBehavior behavior, boolean previewMode, HolderDestroyer holderDestroyer, ItemInterface onItemClick) {
+ @ForItem(k = ItemType.FILTER_GROUP)
+ private View generateFilterGroupItemView(final FilterGroupItem item, final ViewGroup parent, ItemViewGeneratorBehavior behavior, boolean previewMode, Destroyer destroyer, ItemInterface onItemClick) {
final ItemFilterGroupBinding binding = ItemFilterGroupBinding.inflate(this.layoutInflater, parent, false);
// Text
- applyTextItemToTextView(item, binding.title, behavior, holderDestroyer, previewMode);
+ applyTextItemToTextView(item, binding.title, behavior, destroyer, previewMode);
+ applyItemNotificationIndicator(item, binding.indicatorNotification, behavior, destroyer, previewMode);
// FilterGroup
if (!behavior.isRenderMinimized(item)) {
var drawer = createItemsStorageDrawerForFilterGroupItem(item, binding.content, behavior, previewMode, behavior.getItemsStorageDrawerBehavior(item), onItemClick);
drawer.create();
- holderDestroyer.addDestroyListener(drawer::destroy);
+ destroyer.add(drawer::destroy);
}
binding.externalEditor.setEnabled(!previewMode);
@@ -356,18 +386,19 @@ private ItemsStorageDrawer createItemsStorageDrawerForFilterGroupItem(FilterGrou
.build();
}
- @ForItem(key = GroupItem.class)
- private View generateGroupItemView(GroupItem item, ViewGroup parent, ItemViewGeneratorBehavior behavior, boolean previewMode, HolderDestroyer holderDestroyer, ItemInterface onItemClick) {
+ @ForItem(k = ItemType.GROUP)
+ private View generateGroupItemView(GroupItem item, ViewGroup parent, ItemViewGeneratorBehavior behavior, boolean previewMode, Destroyer destroyer, ItemInterface onItemClick) {
final ItemGroupBinding binding = ItemGroupBinding.inflate(this.layoutInflater, parent, false);
// Text
- applyTextItemToTextView(item, binding.title, behavior, holderDestroyer, previewMode);
+ applyTextItemToTextView(item, binding.title, behavior, destroyer, previewMode);
+ applyItemNotificationIndicator(item, binding.indicatorNotification, behavior, destroyer, previewMode);
// Group
- if (!behavior.isRenderMinimized(item)){
+ if (!behavior.isRenderMinimized(item)) {
var drawer = createItemsStorageDrawerForGroupItem(item, binding.content, behavior, previewMode, behavior.getItemsStorageDrawerBehavior(item), onItemClick);
drawer.create();
- holderDestroyer.addDestroyListener(drawer::destroy);
+ destroyer.add(drawer::destroy);
}
binding.externalEditor.setEnabled(!previewMode);
@@ -384,12 +415,13 @@ private ItemsStorageDrawer createItemsStorageDrawerForGroupItem(GroupItem item,
.build();
}
- @ForItem(key = CounterItem.class)
- public View generateCounterItemView(CounterItem item, ViewGroup parent, ItemViewGeneratorBehavior behavior, boolean previewMode, HolderDestroyer holderDestroyer) {
+ @ForItem(k = ItemType.COUNTER)
+ public View generateCounterItemView(CounterItem item, ViewGroup parent, ItemViewGeneratorBehavior behavior, boolean previewMode, Destroyer destroyer) {
final ItemCounterBinding binding = ItemCounterBinding.inflate(this.layoutInflater, parent, false);
// Title
- applyTextItemToTextView(item, binding.title, behavior, holderDestroyer, previewMode);
+ applyTextItemToTextView(item, binding.title, behavior, destroyer, previewMode);
+ applyItemNotificationIndicator(item, binding.indicatorNotification, behavior, destroyer, previewMode);
// Counter
viewClick(binding.up, () -> runFastChanges(behavior, R.string.item_counter_fastChanges_up, item::up));
@@ -402,12 +434,13 @@ public View generateCounterItemView(CounterItem item, ViewGroup parent, ItemView
return binding.getRoot();
}
- @ForItem(key = CycleListItem.class)
- public View generateCycleListItemView(CycleListItem item, ViewGroup parent, ItemViewGeneratorBehavior behavior, boolean previewMode, HolderDestroyer holderDestroyer, ItemInterface onItemClick) {
+ @ForItem(k = ItemType.CYCLE_LIST)
+ public View generateCycleListItemView(CycleListItem item, ViewGroup parent, ItemViewGeneratorBehavior behavior, boolean previewMode, Destroyer destroyer, ItemInterface onItemClick) {
final ItemCycleListBinding binding = ItemCycleListBinding.inflate(this.layoutInflater, parent, false);
// Text
- applyTextItemToTextView(item, binding.title, behavior, holderDestroyer, previewMode);
+ applyTextItemToTextView(item, binding.title, behavior, destroyer, previewMode);
+ applyItemNotificationIndicator(item, binding.indicatorNotification, behavior, destroyer, previewMode);
// CycleList
binding.next.setEnabled(!previewMode);
@@ -419,13 +452,13 @@ public View generateCycleListItemView(CycleListItem item, ViewGroup parent, Item
binding.externalEditor.setOnClickListener(_ignore -> behavior.onCycleListEdit(item));
if (!behavior.isRenderMinimized(item)) {
- final var drawer = new CurrentItemStorageDrawer(this.activity, binding.content, this, behavior, item, holderDestroyer, onItemClick);
+ final var drawer = new CurrentItemStorageDrawer(this.activity, binding.content, this, behavior, item, destroyer, onItemClick);
drawer.setOnUpdateListener(currentItem -> {
viewVisible(binding.empty, currentItem == null, View.GONE);
return Status.NONE;
});
drawer.create();
- holderDestroyer.addDestroyListener(drawer::destroy);
+ destroyer.add(drawer::destroy);
} else {
binding.empty.setVisibility(View.GONE);
}
@@ -433,39 +466,61 @@ public View generateCycleListItemView(CycleListItem item, ViewGroup parent, Item
return binding.getRoot();
}
- @ForItem(key = DayRepeatableCheckboxItem.class)
- public View generateDayRepeatableCheckboxItemView(DayRepeatableCheckboxItem item, ViewGroup parent, ItemViewGeneratorBehavior behavior, boolean previewMode, HolderDestroyer holderDestroyer) {
+ @ForItem(k = ItemType.CHECKBOX_DAY_REPEATABLE)
+ public View generateDayRepeatableCheckboxItemView(DayRepeatableCheckboxItem item, ViewGroup parent, ItemViewGeneratorBehavior behavior, boolean previewMode, Destroyer destroyer) {
final ItemDayRepeatableCheckboxBinding binding = ItemDayRepeatableCheckboxBinding.inflate(this.layoutInflater, parent, false);
- applyTextItemToTextView(item, binding.text, behavior, holderDestroyer, previewMode);
+ applyTextItemToTextView(item, binding.text, behavior, destroyer, previewMode);
applyCheckItemToCheckBoxView(item, binding.checkbox, behavior, previewMode);
+ applyItemNotificationIndicator(item, binding.indicatorNotification, behavior, destroyer, previewMode);
return binding.getRoot();
}
- @ForItem(key = CheckboxItem.class)
- public View generateCheckboxItemView(CheckboxItem item, ViewGroup parent, ItemViewGeneratorBehavior behavior, boolean previewMode, HolderDestroyer holderDestroyer) {
+ @ForItem(k = ItemType.CHECKBOX)
+ public View generateCheckboxItemView(CheckboxItem item, ViewGroup parent, ItemViewGeneratorBehavior behavior, boolean previewMode, Destroyer destroyer) {
final ItemCheckboxBinding binding = ItemCheckboxBinding.inflate(this.layoutInflater, parent, false);
- applyTextItemToTextView(item, binding.text, behavior, holderDestroyer, previewMode);
+ applyTextItemToTextView(item, binding.text, behavior, destroyer, previewMode);
applyCheckItemToCheckBoxView(item, binding.checkbox, behavior, previewMode);
+ applyItemNotificationIndicator(item, binding.indicatorNotification, behavior, destroyer, previewMode);
return binding.getRoot();
}
- @ForItem(key = TextItem.class)
- public View generateTextItemView(TextItem item, ViewGroup parent, ItemViewGeneratorBehavior behavior, boolean previewMode, HolderDestroyer holderDestroyer) {
+ @ForItem(k = ItemType.TEXT)
+ public View generateTextItemView(TextItem item, ViewGroup parent, ItemViewGeneratorBehavior behavior, boolean previewMode, Destroyer destroyer) {
final ItemTextBinding binding = ItemTextBinding.inflate(this.layoutInflater, parent, false);
// Text
- applyTextItemToTextView(item, binding.title, behavior, holderDestroyer, previewMode);
+ applyTextItemToTextView(item, binding.title, behavior, destroyer, previewMode);
+ applyItemNotificationIndicator(item, binding.indicatorNotification, behavior, destroyer, previewMode);
return binding.getRoot();
}
+ private void applyItemNotificationIndicator(final Item item, final ImageView view, ItemViewGeneratorBehavior behavior, Destroyer destroyer, boolean previewMode) {
+ Runnable updateRunnable = () -> {
+ var color = ResUtil.getAttrColor(activity, (item.getCachedNotificationStatus() ? R.attr.item_notificationIndicator_default : R.attr.item_notificationIndicator_disabledByTickPolicy));
+ view.setImageTintList(ColorStateList.valueOf(color));
+ };
+ var itemCallback = new ItemCallback() {
+ @Override
+ public Status cachedNotificationStatusChanged(Item item, boolean isUpdateNotifications) {
+ updateRunnable.run();
+ return Status.NONE;
+ }
+ };
+ item.getItemCallbacks().addCallback(CallbackImportance.LOW, itemCallback);
+ destroyer.add(() -> item.getItemCallbacks().removeCallback(itemCallback));
+
+ viewVisible(view, behavior.isRenderNotificationIndicator(item), View.GONE);
+ updateRunnable.run();
+ }
+
//
@SuppressLint("SetTextI18n")
- private void applyTextItemToTextView(final TextItem item, final TextView view, ItemViewGeneratorBehavior behavior, HolderDestroyer destroyer, boolean previewMode) {
+ private void applyTextItemToTextView(final TextItem item, final TextView view, ItemViewGeneratorBehavior behavior, Destroyer destroyer, boolean previewMode) {
if (Debug.SHOW_PATH_TO_ITEM_ON_ITEMTEXT) {
view.setText(Arrays.toString(ItemUtil.getPathToItem(item)));
view.setTextSize(15);
@@ -485,7 +540,7 @@ private void applyTextItemToTextView(final TextItem item, final TextView view, I
return;
}
if (Debug.DESTROY_ANY_TEXTITEM_CHILD) {
- destroyer.addDestroyListener(() -> {
+ destroyer.add(() -> {
view.setTextColor(Color.RED);
view.setText(DESTROYED_CONST);
view.setTextSize(15);
@@ -495,11 +550,11 @@ private void applyTextItemToTextView(final TextItem item, final TextView view, I
final int textColor = item.isCustomTextColor() ? item.getTextColor() : ResUtil.getAttrColor(activity, R.attr.item_textColor);
final SpannableString visibleText = item.isParagraphColorize() ? colorize(item.getText(), textColor) : SpannableString.valueOf(item.getText());
- final int MAX = 60;
+ final int MAX = 100;
if (!previewMode && item.isMinimize()) {
- final String text = visibleText.toString().split("\n")[0];
+ final String text = visibleText.toString();
if (text.length() > MAX) {
- view.setText(new SpannableStringBuilder().append(visibleText.subSequence(0, MAX-3)).append("..."));
+ view.setText(new SpannableStringBuilder().append(visibleText.subSequence(0, MAX - 3)).append("…"));
} else {
view.setText(visibleText);
}
@@ -516,13 +571,17 @@ private SpannableString colorize(String text, int textColor) {
return ColorUtil.colorize(text, textColor, Color.TRANSPARENT, Typeface.NORMAL);
}
+ private void applyForeground(View view, Item item, ItemViewGeneratorBehavior behavior) {
+ view.setForeground(behavior.getForeground(item));
+ }
+
private void applyLongTextItemToLongTextView(final LongTextItem item, final TextView view) {
final int longTextColor = item.isCustomLongTextColor() ? item.getLongTextColor() : ResUtil.getAttrColor(activity, R.attr.item_textColor);
final SpannableString visibleText = item.isParagraphColorize() ? colorize(item.getLongText(), longTextColor) : SpannableString.valueOf(item.getLongText());
- final int MAX = 150;
+ final int MAX = 170;
if (!previewMode && item.isMinimize()) {
if (visibleText.length() > MAX) {
- view.setText(new SpannableStringBuilder().append(visibleText.subSequence(0, MAX-3)).append("..."));
+ view.setText(new SpannableStringBuilder().append(visibleText.subSequence(0, MAX - 3)).append("…"));
} else {
view.setText(visibleText);
}
@@ -580,22 +639,4 @@ private void runFastChanges(ItemViewGeneratorBehavior behavior, String message,
runnable.run();
}
}
-
- public static class CreateBuilder {
- private final Activity activity;
- private boolean previewMode = false;
-
- public CreateBuilder(final Activity activity) {
- this.activity = activity;
- }
-
- public CreateBuilder setPreviewMode(boolean b) {
- this.previewMode = b;
- return this;
- }
-
- public ItemViewGenerator build() {
- return new ItemViewGenerator(activity, previewMode);
- }
- }
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/item/ItemViewGeneratorBehavior.java b/app/src/main/java/com/fazziclay/opentoday/gui/item/ItemViewGeneratorBehavior.java
index a70a499b..6523e45e 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/item/ItemViewGeneratorBehavior.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/item/ItemViewGeneratorBehavior.java
@@ -22,4 +22,6 @@ public interface ItemViewGeneratorBehavior {
ItemsStorageDrawerBehavior getItemsStorageDrawerBehavior(Item item);
boolean isRenderMinimized(Item item);
+
+ boolean isRenderNotificationIndicator(Item item);
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/item/ItemViewHolder.kt b/app/src/main/java/com/fazziclay/opentoday/gui/item/ItemViewHolder.kt
index e68374ea..f0bd7c6a 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/item/ItemViewHolder.kt
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/item/ItemViewHolder.kt
@@ -8,10 +8,10 @@ import com.fazziclay.opentoday.app.items.item.Item
class ItemViewHolder(context: Context) : RecyclerView.ViewHolder(FrameLayout(context)) {
companion object {
- private const val PADDING_LEFT = 0
- private const val PADDING_TOP = 5
- private const val PADDING_RIGHT = 0
- private const val PADDING_BOTTOM = 5
+ private const val PADDING_LEFT = 1
+ private const val PADDING_TOP = 8
+ private const val PADDING_RIGHT = 1
+ private const val PADDING_BOTTOM = 8
}
@@ -20,7 +20,7 @@ class ItemViewHolder(context: Context) : RecyclerView.ViewHolder(FrameLayout(con
@JvmField
var item: Item? = null
@JvmField
- var destroyer: HolderDestroyer = HolderDestroyer()
+ var destroyer: Destroyer = Destroyer()
init {
layout.setPadding(PADDING_LEFT, PADDING_TOP, PADDING_RIGHT, PADDING_BOTTOM)
@@ -28,8 +28,8 @@ class ItemViewHolder(context: Context) : RecyclerView.ViewHolder(FrameLayout(con
}
fun bind(item: Item?, view: View?) {
- this.item = item
layout.removeAllViews()
+ this.item = item
if (view == null) {
layout.visibility = View.GONE
layout.setPadding(0, 0, 0, 0)
@@ -42,12 +42,12 @@ class ItemViewHolder(context: Context) : RecyclerView.ViewHolder(FrameLayout(con
fun recycle() {
destroyer.destroy()
- destroyer = HolderDestroyer()
+ destroyer.recycle()
layout.removeAllViews()
this.item = null
}
override fun toString(): String {
- return "ItemViewHolder{${item}}"
+ return "ItemViewHolder{layout=${layout}, destroyer=${destroyer}, item=${item}}"
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/item/ItemsStorageDrawer.java b/app/src/main/java/com/fazziclay/opentoday/gui/item/ItemsStorageDrawer.java
index 8823c780..21847736 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/item/ItemsStorageDrawer.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/item/ItemsStorageDrawer.java
@@ -2,21 +2,23 @@
import android.annotation.SuppressLint;
import android.app.Activity;
+import android.os.Handler;
import android.os.Looper;
import android.view.Gravity;
import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.PopupMenu;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
import com.fazziclay.opentoday.R;
import com.fazziclay.opentoday.app.CrashReportContext;
-import com.fazziclay.opentoday.app.SettingsManager;
+import com.fazziclay.opentoday.app.settings.enums.ItemAction;
import com.fazziclay.opentoday.app.items.ItemsStorage;
import com.fazziclay.opentoday.app.items.callback.OnItemsStorageUpdate;
import com.fazziclay.opentoday.app.items.callback.SelectionCallback;
@@ -25,8 +27,9 @@
import com.fazziclay.opentoday.app.items.item.Transform;
import com.fazziclay.opentoday.app.items.selection.Selection;
import com.fazziclay.opentoday.app.items.selection.SelectionManager;
+import com.fazziclay.opentoday.gui.UI;
+import com.fazziclay.opentoday.gui.dialog.DialogSelectItemAction;
import com.fazziclay.opentoday.gui.dialog.DialogSelectItemType;
-import com.fazziclay.opentoday.gui.fragment.ItemEditorFragment;
import com.fazziclay.opentoday.gui.interfaces.ItemInterface;
import com.fazziclay.opentoday.util.Logger;
import com.fazziclay.opentoday.util.callback.CallbackImportance;
@@ -55,6 +58,7 @@ public class ItemsStorageDrawer extends AbstractItemsStorageDrawer {
private final ItemInterface itemOnClick;
private final boolean previewMode;
private ItemViewWrapper itemViewWrapper;
+ private final Handler handler;
// Private (available only with builder)
private ItemsStorageDrawer(@NonNull Activity activity,
@@ -84,6 +88,7 @@ private ItemsStorageDrawer(@NonNull Activity activity,
this.itemViewWrapper = itemViewWrapper;
this.itemViewGeneratorBehavior = itemViewGeneratorBehavior;
this.itemViewGenerator = new ItemViewGenerator(this.activity, previewMode);
+ this.handler = new Handler(Looper.getMainLooper());
}
@@ -104,6 +109,15 @@ public void destroy() {
this.selectionManager.getOnSelectionUpdated().removeCallback(selectionCallback);
}
+ @Override
+ protected void runOnUiThread(Runnable r) {
+ if (Thread.currentThread() == originalThread) {
+ r.run();
+ } else {
+ handler.post(r);
+ }
+ }
+
protected void onItemClicked(Item item) {
if (this.itemOnClick != null) {
@@ -121,14 +135,6 @@ private void throwIsBadThread() {
}
}
- private void runOnUiThread(Runnable r) {
- if (Thread.currentThread() == originalThread) {
- r.run();
- } else {
- activity.runOnUiThread(r);
- }
- }
-
public void setItemViewWrapper(ItemViewWrapper itemViewWrapper) {
this.itemViewWrapper = itemViewWrapper;
}
@@ -139,6 +145,7 @@ private class DrawerOnItemsStorageUpdated extends OnItemsStorageUpdate {
public Status onAdded(Item item, int pos) {
runOnUiThread(() -> callWithNonNullAdapter((adapter) -> {
adapter.notifyItemInserted(pos);
+ adapter.notifyItemRangeChanged(adapter.getItemCount(), pos);
if (behavior.isScrollToAddedItem()) {
smoothScrollToPosition(pos);
}
@@ -167,7 +174,7 @@ public Status onUpdated(Item item, int pos) {
@Nullable
- private View generateViewForItem(Item item, HolderDestroyer destroyer) {
+ private View generateViewForItem(Item item, Destroyer destroyer) {
boolean previewMode = this.previewMode || selectionManager.isSelected(item);
return itemViewGenerator.generate(item, getView(), itemViewGeneratorBehavior, previewMode, destroyer, this::onItemClicked);
}
@@ -184,6 +191,12 @@ protected void onBindItem(@NonNull ItemViewHolder holder, int position) {
view = generateViewForItem(item, holder.destroyer);
}
+ if (itemViewGeneratorBehavior.isRenderMinimized(item) && view != null) {
+ final FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ layoutParams.setMargins(0, 0, 17, 0);
+ view.setLayoutParams(layoutParams);
+ }
+
holder.bind(item, view);
}
@@ -215,7 +228,7 @@ protected void onItemSwiped(ItemViewHolder viewHolder, int position, int directi
roughUpdateItemAt(position);
}
- private void actionItem(Item item, SettingsManager.ItemAction action) {
+ private void actionItem(Item item, ItemAction action) {
CrashReportContext.FRONT.push("ItemsStorageDrawer.actionItem");
switch (action) {
case OPEN_EDITOR -> behavior.onItemOpenEditor(item);
@@ -245,6 +258,15 @@ private void actionItem(Item item, SettingsManager.ItemAction action) {
}
}
case DELETE_REQUEST -> behavior.onItemDeleteRequest(item);
+ case SHOW_ACTION_DIALOG -> {
+ new DialogSelectItemAction(activity, null, new DialogSelectItemAction.OnSelected() {
+ @Override
+ public void run(ItemAction dialogAction) {
+ actionItem(item, dialogAction);
+ }
+ // TODO: 21.10.2023 make translatable
+ }, "Click to action now").excludeFromList(ItemAction.SHOW_ACTION_DIALOG).show();
+ }
}
CrashReportContext.FRONT.pop();
}
@@ -267,22 +289,22 @@ private void showRightMenu(Item item, View itemView) {
}
menu.setOnMenuItemClickListener(menuItem -> {
boolean save = false;
- SettingsManager.ItemAction itemAction = null;
+ ItemAction itemAction = null;
switch (menuItem.getItemId()) {
case R.id.delete:
- itemAction = SettingsManager.ItemAction.DELETE_REQUEST;
+ itemAction = ItemAction.DELETE_REQUEST;
break;
case R.id.edit:
- itemAction = SettingsManager.ItemAction.OPEN_EDITOR;
+ itemAction = ItemAction.OPEN_EDITOR;
break;
case R.id.minimize:
- itemAction = SettingsManager.ItemAction.MINIMIZE_REVERT;
+ itemAction = ItemAction.MINIMIZE_REVERT;
break;
case R.id.selected:
- itemAction = SettingsManager.ItemAction.SELECT_REVERT;
+ itemAction = ItemAction.SELECT_REVERT;
break;
case R.id.copy:
@@ -312,14 +334,15 @@ private void showRightMenu(Item item, View itemView) {
Transform.Result result = Transform.transform(item, type);
if (result.isAllow()) {
int pos = itemsStorage.getItemPosition(item);
- itemsStorage.addItem(result.generate(), pos + 1);
+ Item newItem = result.generate();
+
+ UI.postDelayed(() -> itemsStorage.addItem(newItem, pos + 1), 500);
} else {
Toast.makeText(activity, R.string.transform_not_allowed, Toast.LENGTH_SHORT).show();
}
}, (type -> Transform.isAllow(item, type)))
.setTitle(activity.getString(R.string.transform_selectTypeDialog_title))
- .setMessage(activity.getString(R.string.transform_selectTypeDialog_message))
.show();
break;
}
@@ -336,7 +359,7 @@ private void showRightMenu(Item item, View itemView) {
@FunctionalInterface
public interface ItemViewWrapper {
@Nullable
- View wrap(Item item, Supplier viewSupplier, HolderDestroyer destroyer);
+ View wrap(Item item, Supplier viewSupplier, Destroyer destroyer);
}
public static class CreateBuilder {
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/item/ItemsStorageDrawerBehavior.java b/app/src/main/java/com/fazziclay/opentoday/gui/item/ItemsStorageDrawerBehavior.java
index a08c5c6b..920336e3 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/item/ItemsStorageDrawerBehavior.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/item/ItemsStorageDrawerBehavior.java
@@ -1,14 +1,14 @@
package com.fazziclay.opentoday.gui.item;
-import com.fazziclay.opentoday.app.SettingsManager;
+import com.fazziclay.opentoday.app.settings.enums.ItemAction;
import com.fazziclay.opentoday.app.items.item.Item;
public interface ItemsStorageDrawerBehavior {
- SettingsManager.ItemAction getItemOnClickAction();
+ ItemAction getItemOnClickAction();
boolean isScrollToAddedItem();
- SettingsManager.ItemAction getItemOnLeftAction();
+ ItemAction getItemOnLeftAction();
void onItemOpenEditor(Item item);
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/item/SettingsItemsStorageDrawerBehavior.java b/app/src/main/java/com/fazziclay/opentoday/gui/item/SettingsItemsStorageDrawerBehavior.java
index 4a57c0a2..73bde2fa 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/item/SettingsItemsStorageDrawerBehavior.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/item/SettingsItemsStorageDrawerBehavior.java
@@ -1,17 +1,18 @@
package com.fazziclay.opentoday.gui.item;
-import com.fazziclay.opentoday.app.SettingsManager;
+import com.fazziclay.opentoday.app.settings.enums.ItemAction;
+import com.fazziclay.opentoday.app.settings.SettingsManager;
public abstract class SettingsItemsStorageDrawerBehavior implements ItemsStorageDrawerBehavior {
private final SettingsManager settingsManager;
- public SettingsItemsStorageDrawerBehavior(SettingsManager settingsManager) {
+ public SettingsItemsStorageDrawerBehavior(final SettingsManager settingsManager) {
this.settingsManager = settingsManager;
}
@Override
- public SettingsManager.ItemAction getItemOnClickAction() {
+ public ItemAction getItemOnClickAction() {
return settingsManager.getItemOnClickAction();
}
@@ -21,7 +22,7 @@ public boolean isScrollToAddedItem() {
}
@Override
- public SettingsManager.ItemAction getItemOnLeftAction() {
+ public ItemAction getItemOnLeftAction() {
return settingsManager.getItemOnLeftAction();
}
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/gui/toolbar/AppToolbar.java b/app/src/main/java/com/fazziclay/opentoday/gui/toolbar/AppToolbar.java
index c61b9d66..ed93341e 100644
--- a/app/src/main/java/com/fazziclay/opentoday/gui/toolbar/AppToolbar.java
+++ b/app/src/main/java/com/fazziclay/opentoday/gui/toolbar/AppToolbar.java
@@ -5,7 +5,6 @@
import static com.fazziclay.opentoday.util.InlineUtil.viewVisible;
import android.app.Activity;
-import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.content.Context;
import android.content.Intent;
@@ -15,12 +14,15 @@
import android.os.Handler;
import android.os.Looper;
import android.text.InputFilter;
+import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.FrameLayout;
+import android.widget.ImageButton;
+import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
@@ -32,10 +34,12 @@
import com.fazziclay.opentoday.Debug;
import com.fazziclay.opentoday.R;
+import com.fazziclay.opentoday.api.EventHandler;
import com.fazziclay.opentoday.app.App;
import com.fazziclay.opentoday.app.FeatureFlag;
import com.fazziclay.opentoday.app.ImportWrapper;
-import com.fazziclay.opentoday.app.SettingsManager;
+import com.fazziclay.opentoday.app.events.gui.toolbar.AppToolbarSelectionClickEvent;
+import com.fazziclay.opentoday.app.icons.IconsRegistry;
import com.fazziclay.opentoday.app.items.ItemsStorage;
import com.fazziclay.opentoday.app.items.callback.OnTabsChanged;
import com.fazziclay.opentoday.app.items.callback.SelectionCallback;
@@ -47,6 +51,8 @@
import com.fazziclay.opentoday.app.items.tab.Debug202305RandomTab;
import com.fazziclay.opentoday.app.items.tab.Tab;
import com.fazziclay.opentoday.app.items.tab.TabsManager;
+import com.fazziclay.opentoday.app.settings.SettingsManager;
+import com.fazziclay.opentoday.app.settings.enums.ItemAddPosition;
import com.fazziclay.opentoday.databinding.ToolbarBinding;
import com.fazziclay.opentoday.databinding.ToolbarMoreDebugBinding;
import com.fazziclay.opentoday.databinding.ToolbarMoreFileBinding;
@@ -56,26 +62,30 @@
import com.fazziclay.opentoday.databinding.ToolbarMoreSelectionBinding;
import com.fazziclay.opentoday.databinding.ToolbarMoreTabsBinding;
import com.fazziclay.opentoday.gui.EnumsRegistry;
+import com.fazziclay.opentoday.gui.GuiItemsHelper;
import com.fazziclay.opentoday.gui.UI;
import com.fazziclay.opentoday.gui.activity.MainActivity;
import com.fazziclay.opentoday.gui.activity.SetupActivity;
import com.fazziclay.opentoday.gui.callbacks.UIDebugCallback;
import com.fazziclay.opentoday.gui.dialog.DialogSelectItemAction;
+import com.fazziclay.opentoday.gui.dialog.IconSelectorDialog;
import com.fazziclay.opentoday.gui.fragment.AboutFragment;
import com.fazziclay.opentoday.gui.fragment.DeleteItemsFragment;
import com.fazziclay.opentoday.gui.fragment.ImportFragment;
import com.fazziclay.opentoday.gui.fragment.ItemEditorFragment;
-import com.fazziclay.opentoday.gui.fragment.SettingsFragment;
+import com.fazziclay.opentoday.gui.fragment.settings.SettingsFragment;
import com.fazziclay.opentoday.gui.interfaces.NavigationHost;
import com.fazziclay.opentoday.util.ClipboardUtil;
import com.fazziclay.opentoday.util.Logger;
import com.fazziclay.opentoday.util.ResUtil;
import com.fazziclay.opentoday.util.callback.CallbackImportance;
import com.fazziclay.opentoday.util.callback.Status;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
+import java.util.concurrent.atomic.AtomicReference;
public class AppToolbar {
private static final String TAG = "AppToolbar";
@@ -268,7 +278,7 @@ private void onDebugClick() {
int paddingModifier = 1;
@Override
public void run() {
- color += 0x050301;
+ color = color + 55;
padding+= paddingModifier;
l.onlyTrue.setTextColor(color | 0xFF000000);
l.onlyTrue.setPadding(padding, 0, 0, 0);
@@ -290,7 +300,7 @@ public void run() {
activity.startActivity(intent);
});
viewClick(l.resetSetup, () -> {
- activity.getSharedPreferences(App.SHARED_NAME, Context.MODE_PRIVATE).edit().putBoolean(App.SHARED_KEY_IS_SETUP_DONE, false).apply();
+ SettingsManager.IS_FIRST_LAUNCH.set(settingsManager, true);
activity.finish();
activity.startActivity(new Intent(activity, SetupActivity.class));
});
@@ -439,29 +449,37 @@ public Status onTabRenamed(Tab tab, int position) {
localBinding.tabsRecycleView.getAdapter().notifyItemChanged(position);
return Status.NONE;
}
+
+ @Override
+ public Status onTabIconChanged(Tab tab, int position) {
+ localBinding.tabsRecycleView.getAdapter().notifyItemChanged(position);
+ return Status.NONE;
+ }
};
tabsManager.getOnTabsChangedCallbacks().addCallback(CallbackImportance.DEFAULT, onTabsChanged);
- viewClick(localBinding.addTab, () -> {
- EditText tabNameEditText = new EditText(activity);
- tabNameEditText.setHint(R.string.toolbar_more_tabs_addNew_name_hint);
- tabNameEditText.setFilters(new InputFilter.LengthFilter[]{new InputFilter.LengthFilter(TabsManager.TAB_NAME_MAX_LENGTH)});
- new AlertDialog.Builder(activity)
- .setTitle(R.string.toolbar_more_tabs_addNew_dialog_title)
- .setView(tabNameEditText)
- .setPositiveButton(R.string.toolbar_more_tabs_tab_add, (dialog, which) -> {
- String text = tabNameEditText.getText().toString();
- if (!text.trim().isEmpty()) {
- tabsManager.createLocalTab(tabNameEditText.getText().toString());
- } else {
- Toast.makeText(activity, R.string.tab_noEmptyName, Toast.LENGTH_SHORT).show();
- }
- })
- .setNegativeButton(R.string.abc_cancel, null)
- .show();
- });
+ viewClick(localBinding.addTab, () -> showAddTabDialog(activity, tabsManager));
+ }
+
+ public static void showAddTabDialog(Context context, TabsManager tabsManager) {
+ EditText tabNameEditText = new EditText(context);
+ tabNameEditText.setHint(R.string.toolbar_more_tabs_addNew_name_hint);
+ tabNameEditText.setFilters(new InputFilter.LengthFilter[]{new InputFilter.LengthFilter(TabsManager.TAB_NAME_MAX_LENGTH)});
+ new MaterialAlertDialogBuilder(context)
+ .setTitle(R.string.toolbar_more_tabs_addNew_dialog_title)
+ .setView(tabNameEditText)
+ .setPositiveButton(R.string.toolbar_more_tabs_tab_add, (dialog, which) -> {
+ String text = tabNameEditText.getText().toString();
+ if (!text.trim().isEmpty()) {
+ tabsManager.createLocalTab(tabNameEditText.getText().toString());
+ } else {
+ tabsManager.createLocalTab(context.getString(R.string.tab_autoName, Long.toHexString(System.nanoTime()).substring(5)));
+ }
+ })
+ .setNegativeButton(R.string.abc_cancel, null)
+ .show();
}
private void showEditTabDialog(final Tab tab) {
@@ -479,7 +497,7 @@ private void showEditTabDialog(final Tab tab) {
disableTick.setChecked(tab.isDisableTick());
viewClick(disableTick, () -> {
if (disableTick.isChecked()) {
- new AlertDialog.Builder(activity)
+ new MaterialAlertDialogBuilder(activity)
.setTitle(R.string.toolbar_more_tabs_edit_disableTick_warning_title)
.setMessage(R.string.toolbar_more_tabs_edit_disableTick_warning_message)
.setPositiveButton(R.string.abc_ok, null)
@@ -487,10 +505,25 @@ private void showEditTabDialog(final Tab tab) {
}
});
+ ImageButton icon = new ImageButton(activity);
+ icon.setScaleType(ImageView.ScaleType.FIT_XY);
+ var params = new LinearLayout.LayoutParams(90 + 10, 90);
+ params.gravity = Gravity.END;
+ icon.setLayoutParams(params);
+ icon.setImageResource(tab.getIcon().getResId());
+ icon.setImageTintList(tab.getIcon().isNone() ? ColorStateList.valueOf(Color.RED) : null);
+ AtomicReference selectedIcon = new AtomicReference<>(tab.getIcon());
+ viewClick(icon, () -> new IconSelectorDialog(activity, selected -> {
+ icon.setImageResource(selected.getResId());
+ icon.setImageTintList(selected.isNone() ? ColorStateList.valueOf(Color.RED) : null);
+ selectedIcon.set(selected);
+ }).noneIsAvailable(true).show());
+
dialogView.addView(tabNameEditText);
dialogView.addView(disableTick);
+ dialogView.addView(icon);
- new AlertDialog.Builder(activity)
+ new MaterialAlertDialogBuilder(activity)
.setTitle(activity.getString(R.string.toolbar_more_tabs_edit_dialog_title, tab.getName()))
.setView(dialogView)
.setPositiveButton(R.string.toolbar_more_tabs_tab_apply, (dialog, which) -> {
@@ -501,10 +534,11 @@ private void showEditTabDialog(final Tab tab) {
Toast.makeText(activity, R.string.tab_noEmptyName, Toast.LENGTH_SHORT).show();
}
tab.setDisableTick(disableTick.isChecked());
+ tab.setIcon(selectedIcon.get());
})
.setNegativeButton(R.string.abc_cancel, null)
- .setNeutralButton(R.string.toolbar_more_tabs_tab_delete, (dialog, w) -> new AlertDialog.Builder(activity)
- .setTitle(activity.getString(R.string.fragment_deleteItems_delete_title, String.valueOf(tab.size())))
+ .setNeutralButton(R.string.toolbar_more_tabs_tab_delete, (dialog, w) -> new MaterialAlertDialogBuilder(activity)
+ .setTitle(activity.getString(R.string.fragment_deleteItems_delete_title, String.valueOf(tab.size()), String.valueOf(tab.totalSize())))
.setNegativeButton(R.string.fragment_deleteItems_delete_cancel, null)
.setPositiveButton(R.string.fragment_deleteItems_delete_apply, ((dialog1, which) -> {
if (tabsManager.isOneTabMode()) {
@@ -523,6 +557,8 @@ private void showEditTabDialog(final Tab tab) {
}
private class ItemTypeViewHolder extends RecyclerView.ViewHolder {
+ private boolean show;
+ private final ToolbarMoreItemsItemBinding b;
private final TextView name;
private final Button create;
private final Button add;
@@ -530,15 +566,23 @@ private class ItemTypeViewHolder extends RecyclerView.ViewHolder {
public ItemTypeViewHolder(ViewGroup parent) {
super(new FrameLayout(activity));
- ToolbarMoreItemsItemBinding b = ToolbarMoreItemsItemBinding.inflate(activity.getLayoutInflater(), parent, false);
+ b = ToolbarMoreItemsItemBinding.inflate(activity.getLayoutInflater(), parent, false);
this.name = b.name;
this.create = b.create;
this.add = b.add;
this.description = b.description;
- ((FrameLayout) itemView).addView(b.getRoot());
+ this.show = false;
}
- public void clear() {
+ public void show() {
+ if (!show) {
+ show = true;
+ ((FrameLayout) itemView).addView(b.getRoot());
+ }
+ }
+
+ public void hide() {
+ show = false;
((FrameLayout) itemView).removeAllViews();
}
}
@@ -556,7 +600,7 @@ private void onItemsClick() {
localBinding.items.setLayoutManager(new LinearLayoutManager(activity, RecyclerView.VERTICAL, false));
localBinding.items.setAdapter(new RecyclerView.Adapter() {
- private int getAddItemPos(SettingsManager.ItemAddPosition fromSettings) {
+ private int getAddItemPos(ItemAddPosition fromSettings) {
return switch (fromSettings) {
case TOP -> ItemEditorFragment.VALUE_ADD_ITEM_POSITION_TOP;
case BOTTOM -> ItemEditorFragment.VALUE_ADD_ITEM_POSITION_BOTTOM;
@@ -574,20 +618,19 @@ public void onBindViewHolder(@NonNull ItemTypeViewHolder holder, int position) {
ItemsRegistry.ItemInfo itemInfo = ItemsRegistry.REGISTRY.getAllItems()[position];
if (itemInfo.isCompatibility(app.getFeatureFlags())) {
+ holder.show();
holder.name.setText(EnumsRegistry.INSTANCE.nameResId(itemInfo.getItemType()));
viewClick(holder.create, () -> {
rootNavigationHost.navigate(ItemEditorFragment.create(ItemUtil.getId(itemsStorage), itemInfo.getClassType(), getAddItemPos(settingsManager.getItemAddPosition())), true);
autoClose();
});
viewClick(holder.add, () -> {
- switch (settingsManager.getItemAddPosition()) {
- case TOP -> itemsStorage.addItem(ItemsRegistry.REGISTRY.get(itemInfo.getClassType()).create(), 0);
- case BOTTOM -> itemsStorage.addItem(ItemsRegistry.REGISTRY.get(itemInfo.getClassType()).create());
- }
+ final Item item = GuiItemsHelper.createItem(app, itemInfo, "", settingsManager);
+ GuiItemsHelper.addItem(item, itemsStorage, settingsManager);
});
viewClick(holder.description, () -> showItemDescriptionDialog(itemInfo));
} else {
- holder.clear();
+ holder.hide();
}
}
@@ -610,7 +653,7 @@ public int getItemCount() {
}
private void showItemDescriptionDialog(ItemsRegistry.ItemInfo itemInfo) {
- new AlertDialog.Builder(activity)
+ new MaterialAlertDialogBuilder(activity)
.setTitle(EnumsRegistry.INSTANCE.nameResId(itemInfo.getItemType()))
.setMessage(EnumsRegistry.INSTANCE.itemDescriptionResId(itemInfo.getItemType()))
.setPositiveButton(R.string.abc_ok, null)
@@ -665,6 +708,8 @@ public void onSelectionChanged(Selection[] selections) {
};
selectionCallback.onSelectionChanged(selectionManager.getSelections()); // First run
selectionManager.getOnSelectionUpdated().addCallback(CallbackImportance.MIN, selectionCallback); // Add to callbackStorage
+
+ EventHandler.call(new AppToolbarSelectionClickEvent(activity, localBinding, selectionManager));
}
private void exportSelected() {
@@ -684,7 +729,7 @@ private void exportSelected() {
private void showExportSelectedWithMessageDialog() {
EditText dialogMessage = new EditText(activity);
- new AlertDialog.Builder(activity)
+ new MaterialAlertDialogBuilder(activity)
.setTitle(R.string.toolbar_more_selection_export_setMessage_title)
.setView(dialogMessage)
.setNeutralButton(R.string.toolbar_more_selection_export_setMessage_nomsg, (ignore0, ignore1) -> exportSelected())
diff --git a/app/src/main/java/com/fazziclay/opentoday/plugins/PluginsRegistry.java b/app/src/main/java/com/fazziclay/opentoday/plugins/PluginsRegistry.java
new file mode 100644
index 00000000..2bad558c
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/plugins/PluginsRegistry.java
@@ -0,0 +1,66 @@
+package com.fazziclay.opentoday.plugins;
+
+import com.fazziclay.opentoday.api.OpenTodayPlugin;
+import com.fazziclay.opentoday.plugins.gcp.GlobalChangesPlugin;
+import com.fazziclay.opentoday.plugins.islp.ItemsSupportLibraryPlugin;
+
+public class PluginsRegistry {
+ public static final PluginsRegistry REGISTRY = new PluginsRegistry();
+
+ private final PluginInfo[] PLUGINS = new PluginInfo[]{
+ new PluginInfo("gcp", "fazziclay://opentoday/plugins/global_changes_plugin", GlobalChangesPlugin.class, "FazziCLAY", "1.0", new String[]{"islp"}),
+ new PluginInfo("islp", "fazziclay://opentoday/plugins/items_support_library_plugin", ItemsSupportLibraryPlugin.class, "FazziCLAY", "1.0", new String[]{}),
+ };
+
+ private PluginsRegistry() {
+ }
+
+ public static class PluginInfo {
+ private final String shortName;
+ private final String packageId;
+ private final Class extends OpenTodayPlugin> clazz;
+ private final String author;
+ private final String version;
+ private final String[] depends;
+
+ public PluginInfo(String shortName, String packageId, Class extends OpenTodayPlugin> clazz, String author, String version, String[] depends) {
+ this.shortName = shortName;
+ this.packageId = packageId;
+ this.clazz = clazz;
+ this.author = author;
+ this.version = version;
+ this.depends = depends;
+ }
+
+ public String getShortName() {
+ return shortName;
+ }
+
+ public String getPackageId() {
+ return packageId;
+ }
+
+ public Class extends OpenTodayPlugin> getClazz() {
+ return clazz;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public String[] getDepends() {
+ return depends;
+ }
+ }
+
+ public PluginInfo getByShortName(String name) {
+ for (PluginInfo plugin : PLUGINS) {
+ if (plugin.getShortName().equalsIgnoreCase(name)) return plugin;
+ }
+ return null;
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/plugins/gcp/GcpEventHandler.java b/app/src/main/java/com/fazziclay/opentoday/plugins/gcp/GcpEventHandler.java
new file mode 100644
index 00000000..ed873cd9
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/plugins/gcp/GcpEventHandler.java
@@ -0,0 +1,529 @@
+package com.fazziclay.opentoday.plugins.gcp;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.HorizontalScrollView;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.appcompat.app.AlertDialog;
+
+import com.fazziclay.javaneoutil.ArrayUtil;
+import com.fazziclay.opentoday.api.Event;
+import com.fazziclay.opentoday.api.EventExceptionEvent;
+import com.fazziclay.opentoday.api.EventHandler;
+import com.fazziclay.opentoday.app.App;
+import com.fazziclay.opentoday.app.BeautifyColorManager;
+import com.fazziclay.opentoday.app.events.gui.CurrentItemsStorageContextChanged;
+import com.fazziclay.opentoday.app.events.gui.toolbar.AppToolbarSelectionClickEvent;
+import com.fazziclay.opentoday.app.items.ItemsStorage;
+import com.fazziclay.opentoday.app.items.item.CheckboxItem;
+import com.fazziclay.opentoday.app.items.item.CycleListItem;
+import com.fazziclay.opentoday.app.items.item.FilterGroupItem;
+import com.fazziclay.opentoday.app.items.item.GroupItem;
+import com.fazziclay.opentoday.app.items.item.Item;
+import com.fazziclay.opentoday.app.items.item.ItemCodecUtil;
+import com.fazziclay.opentoday.app.items.item.ItemType;
+import com.fazziclay.opentoday.app.items.item.ItemsRegistry;
+import com.fazziclay.opentoday.app.items.item.TextItem;
+import com.fazziclay.opentoday.app.items.selection.SelectionManager;
+import com.fazziclay.opentoday.app.items.tag.ItemTag;
+import com.fazziclay.opentoday.databinding.ToolbarMoreSelectionBinding;
+import com.fazziclay.opentoday.gui.ColorPicker;
+import com.fazziclay.opentoday.gui.GuiItemsHelper;
+import com.fazziclay.opentoday.gui.item.Destroyer;
+import com.fazziclay.opentoday.gui.item.ItemViewGenerator;
+import com.fazziclay.opentoday.gui.item.ItemViewGeneratorBehavior;
+import com.fazziclay.opentoday.gui.item.ItemsStorageDrawerBehavior;
+import com.fazziclay.opentoday.util.MinBaseAdapter;
+import com.fazziclay.opentoday.util.QuickNote;
+import com.fazziclay.opentoday.util.RandomUtil;
+import com.fazziclay.opentoday.util.profiler.Profiler;
+import com.fazziclay.opentoday.util.time.TimeUtil;
+import com.google.android.material.button.MaterialButton;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+
+import org.json.JSONException;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+public class GcpEventHandler extends EventHandler {
+ private final GlobalChangesPlugin plugin;
+ private final Profiler PROFILER = App.createProfiler("plugin://gcp");
+
+ public GcpEventHandler(GlobalChangesPlugin plugin) {
+ this.plugin = plugin;
+ }
+
+ @Override
+ public void handle(Event event) {
+ super.handle(event);
+
+ // TODO: 21.10.2023 move another
+ if (event instanceof EventExceptionEvent e) {
+ Toast.makeText(App.get(), "Exception in plugin : " + e.getException().toString(), Toast.LENGTH_SHORT).show();
+ }
+
+ if (event instanceof AppToolbarSelectionClickEvent e) {
+ injectSelections(e);
+ }
+ }
+
+ private void injectSelections(AppToolbarSelectionClickEvent e) {
+ ToolbarMoreSelectionBinding localBinding = e.getLocalBinding();
+ Context context = localBinding.getRoot().getContext();
+ SelectionManager selectionManager = e.getSelectionManager();
+
+ Button massBgColor = new Button(context);
+ massBgColor.setText("Mass BG color");
+ massBgColor.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+
+ massBgColor.setOnClickListener(i -> new ColorPicker(context, 0xffff00)
+ .setting(true, true, true)
+ .setColorHistoryManager(App.get(context).getColorHistoryManager())
+ .setNeutralDialogButton("Reset ALL", () -> {
+ for (Item item : selectionManager.getItems()) {
+ item.setViewCustomBackgroundColor(false);
+ item.visibleChanged();
+ }
+ })
+ .showDialog("Mass background", "Cancel", "Apply", color -> {
+ for (Item item : selectionManager.getItems()) {
+ item.setViewBackgroundColor(color);
+ item.setViewCustomBackgroundColor(true);
+ item.visibleChanged();
+ }
+ }));
+
+
+
+
+
+
+
+ Button massRandomBgColor = new Button(context);
+ massRandomBgColor.setText("Mass random BG");
+ massRandomBgColor.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+
+ massRandomBgColor.setOnClickListener(i -> {
+ for (Item item : selectionManager.getItems()) {
+ item.setViewBackgroundColor(BeautifyColorManager.randomBackgroundColor(context));
+ item.setViewCustomBackgroundColor(true);
+ item.visibleChanged();
+ }
+ });
+
+ massRandomBgColor.setOnLongClickListener(i -> {
+ for (Item item : selectionManager.getItems()) {
+ item.setViewBackgroundColor(RandomUtil.nextInt() | 0xff000000);
+ item.setViewCustomBackgroundColor(true);
+ item.visibleChanged();
+ }
+ return true;
+ });
+
+
+
+
+ Button selectAll = new Button(context);
+ selectAll.setText("Select all");
+ selectAll.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+
+
+ selectAll.setOnClickListener(i -> {
+ var currentItemsStorage = plugin.getIslp().getCurrentItemsStorage();
+ if (currentItemsStorage != null) {
+ for (Item item : currentItemsStorage.getAllItems()) {
+ selectionManager.deselectItem(item);
+ selectionManager.selectItem(item);
+ }
+ }
+ });
+
+
+
+ Button massTextColor = new Button(context);
+ massTextColor.setText("Mass TeXT color");
+ massTextColor.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+
+ massTextColor.setOnClickListener(i -> new ColorPicker(context, 0xffff00)
+ .setting(true, true, true)
+ .setColorHistoryManager(App.get(context).getColorHistoryManager())
+ .setNeutralDialogButton("Reset ALL", () -> {
+ for (Item item : selectionManager.getItems()) {
+ if (item instanceof TextItem textItem) {
+ textItem.setCustomTextColor(false);
+ textItem.visibleChanged();
+ }
+ }
+
+ })
+ .showDialog("Mass text color", "Cancel", "Apply", color -> {
+ for (Item item : selectionManager.getItems()) {
+ if (item instanceof TextItem textItem) {
+ textItem.setCustomTextColor(true);
+ textItem.setTextColor(color);
+ textItem.visibleChanged();
+ }
+ }
+ }));
+
+
+
+
+
+ Button massRemoveNotification = new Button(context);
+ massRemoveNotification.setText("Mass remove notifications");
+ massRemoveNotification.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+
+
+ massRemoveNotification.setOnClickListener(i -> {
+ var view = new LinearLayout(context);
+ view.setOrientation(LinearLayout.VERTICAL);
+
+ ItemViewGenerator itemViewGenerator = new ItemViewGenerator(e.getActivity(), true);
+
+ ItemViewGeneratorBehavior behavior = new ItemViewGeneratorBehavior() {
+ @Override
+ public boolean isConfirmFastChanges() {
+ return false;
+ }
+
+ @Override
+ public void setConfirmFastChanges(boolean b) {
+
+ }
+
+ @Override
+ public Drawable getForeground(Item item) {
+ return null;
+ }
+
+ @Override
+ public void onGroupEdit(GroupItem groupItem) {
+
+ }
+
+ @Override
+ public void onCycleListEdit(CycleListItem cycleListItem) {
+
+ }
+
+ @Override
+ public void onFilterGroupEdit(FilterGroupItem filterGroupItem) {
+
+ }
+
+ @Override
+ public ItemsStorageDrawerBehavior getItemsStorageDrawerBehavior(Item item) {
+ return null; // null because isRenderMinimized is true
+ }
+
+ @Override
+ public boolean isRenderMinimized(Item item) {
+ return true;
+ }
+
+ @Override
+ public boolean isRenderNotificationIndicator(Item item) {
+ return item.isNotifications();
+ }
+ };
+ Destroyer destroyer = new Destroyer();
+ for (Item item : selectionManager.getItems()) {
+ View iv = itemViewGenerator.generate(item, view, behavior, destroyer, item1 -> {});
+
+ LinearLayout layout = new LinearLayout(context);
+ layout.setOrientation(LinearLayout.HORIZONTAL);
+
+ int size = item.getNotifications().length;
+ TextView t = new TextView(context);
+ t.setText(String.valueOf(size));
+ if (size > 0) {
+ t.setTextColor(Color.RED);
+ }
+ t.setTextSize(size > 0 ? 27 : 25);
+ layout.addView(t);
+ layout.addView(iv);
+ var p = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ p.setMargins(0, 5, 0, 5);
+ layout.setLayoutParams(p);
+ view.addView(layout);
+ }
+
+ var scroll = new ScrollView(context);
+ scroll.addView(view);
+
+ new AlertDialog.Builder(context)
+ .setTitle("Preview")
+ .setView(scroll)
+ .setNegativeButton("Cancel", null)
+ .setPositiveButton("Apply", (dialogInterface, i1) -> {
+ for (Item item : selectionManager.getItems()) {
+ item.removeAllNotifications();
+ item.visibleChanged();
+ }
+ })
+ .show();
+ });
+
+
+
+
+ MaterialButton massJSON = new MaterialButton(context);
+ massJSON.setText("Mass JSON");
+ massJSON.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+
+
+ massJSON.setOnClickListener(i -> {
+ var orchard = ItemCodecUtil.exportItemList(selectionManager.getItems());
+ try {
+ var currentItemsStorage = plugin.getIslp().getCurrentItemsStorage();
+ String s = "currItemsStorage=" + currentItemsStorage + "; root=" + plugin.getIslp().getItemsRoot() + "\n\n" + orchard.toJSONArray().toString(2);
+ new MaterialAlertDialogBuilder(context)
+ .setTitle("Export")
+ .setMessage(s)
+ .setPositiveButton("Close", null)
+ .show();
+ } catch (JSONException ex) {
+ Toast.makeText(context, ex.toString(), Toast.LENGTH_LONG).show();
+ }
+ });
+
+ MaterialButton sortItems = new MaterialButton(context);
+ sortItems.setText("Sort items");
+ sortItems.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+
+
+ sortItems.setOnClickListener(viewIgnore -> {
+ final Comparator
- [] comparator = new Comparator[]{Comparator.comparingInt((Item item) -> item.getText().length())};
+ final ItemsStorage finalParent = plugin.getIslp().getCurrentItemsStorage();
+
+
+ var view = new LinearLayout(context);
+ view.setOrientation(LinearLayout.VERTICAL);
+ view.setPadding(5, 5, 5, 5);
+
+ var reverted = new CheckBox(context);
+ reverted.setText("Reversed");
+
+ var currentSelected = new TextView(context);
+ currentSelected.setText("Current selected: sort by text length");
+
+ ListView listView = new ListView(context);
+ listView.setAdapter(new MinBaseAdapter() {
+ @Override
+ public int getCount() {
+ return 10;
+ }
+
+ @Override
+ public View getView(int i, View view, ViewGroup viewGroup) {
+ return switch (i) {
+ case 0:
+ var textLength = new TextView(context);
+ textLength.setText("Text length");
+ textLength.setOnClickListener(fuwbttrth -> {
+ currentSelected.setText("Current selected: sort by text length");
+ comparator[0] = Comparator.comparingInt(item -> item.getText().length());
+ });
+ yield textLength;
+
+ case 1:
+ var notificationsCount = new TextView(context);
+ notificationsCount.setText("Notifications count");
+ notificationsCount.setOnClickListener(fgdgsdqwr -> {
+ currentSelected.setText("Current selected: sort by notification count");
+ comparator[0] = Comparator.comparingInt(item -> item.getNotifications().length);
+ });
+ yield notificationsCount;
+
+ case 2:
+ var isChecked = new TextView(context);
+ isChecked.setText("Is checked");
+ isChecked.setOnClickListener((rewrewrw) -> {
+ currentSelected.setText("Current selected: sort by isChecked");
+ comparator[0] = new Comparator
- () {
+ int isChecked(Item item) {
+ if (item instanceof CheckboxItem checkboxItem) {
+ return checkboxItem.isChecked() ? 1 : 0;
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public int compare(Item item, Item t1) {
+ if (item.getItemType().isInherit(ItemType.CHECKBOX) && !item.getItemType().isInherit(ItemType.CHECKBOX)) {
+ return 1;
+ }
+ return isChecked(item) - isChecked(t1);
+ }
+ };
+ });
+ yield isChecked;
+
+ case 3:
+ var tagValue = new TextView(context);
+ tagValue.setText("Tag value");
+
+ tagValue.setOnClickListener(asfghgfj -> {
+ EditText editText = new EditText(context);
+ new AlertDialog.Builder(context)
+ .setTitle("Select tag name")
+ .setView(editText)
+ .show();
+ currentSelected.setText("Current selected: sort by tag value");
+ comparator[0] = new Comparator
- () {
+ @Override
+ public int compare(Item item, Item t1) {
+ ItemTag tag1 = null;
+ for (ItemTag tag : item.getTags()) {
+ if (tag.getName().equals(editText.getText().toString())) {
+ tag1 = tag;
+ break;
+ }
+ }
+ ItemTag tag2 = null;
+ for (ItemTag tag : t1.getTags()) {
+ if (tag.getName().equals(editText.getText().toString())) {
+ tag2 = tag;
+ break;
+ }
+ }
+
+ if (tag1 == null || tag2 == null) {
+ return tag1 == null ? 0 : -1;
+ }
+ if (tag1.getValueType() == ItemTag.ValueType.NUMBER) {
+ if (tag2.getValueType() == ItemTag.ValueType.NUMBER) {
+ int i1 = Integer.parseInt(tag1.getValue());
+ int i2 = Integer.parseInt(tag2.getValue());
+ return i1 - i2;
+ }
+ }
+
+ if (tag1.getValueType() == ItemTag.ValueType.STRING) {
+ if (tag2.getValueType() == ItemTag.ValueType.STRING) {
+ String i1 = tag1.getValue();
+ String i2 = tag2.getValue();
+ return compareStrs(i1, i2);
+ }
+ }
+ return 0;
+ }
+
+ private int compareStrs(String i1, String i2) {
+ try {
+ if (i1.contains(":")) {
+ String[] split = i1.split(":");
+ int hour;
+ int minute;
+ int second;
+ if (split.length > 2) {
+ hour = Integer.parseInt(split[0]);
+ minute = Integer.parseInt(split[1]);
+ second = Integer.parseInt(split[2]);
+ } else {
+ hour = Integer.parseInt(split[0]);
+ minute = Integer.parseInt(split[1]);
+ second = 0;
+ }
+
+ int h1seconds = second + (minute * 60) + (hour * 60 * 60);
+
+ String[] split2 = i2.split(":");
+ if (split2.length > 2) {
+ hour = Integer.parseInt(split2[0]);
+ minute = Integer.parseInt(split2[1]);
+ second = Integer.parseInt(split2[2]);
+ } else {
+ hour = Integer.parseInt(split2[0]);
+ minute = Integer.parseInt(split2[1]);
+ second = 0;
+ }
+ int h2seconds = second + (minute * 60) + (hour * 60 * 60);
+ return h1seconds - h2seconds;
+ }
+ return 0;
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+ };
+ });
+
+ yield tagValue;
+
+ default:
+ yield new CheckBox(context);
+ };
+ }
+ });
+ listView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> adapterView, View view, int i, long l) {
+ Toast.makeText(context, "i="+i, Toast.LENGTH_SHORT).show();
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> adapterView) {
+ }
+ });
+
+ view.addView(reverted);
+ view.addView(currentSelected);
+ view.addView(listView);
+
+
+ new MaterialAlertDialogBuilder(context)
+ .setTitle("Sort")
+ .setView(view)
+ .setPositiveButton("START", (irn1, ir112) -> {
+ final Item[] array = selectionManager.getItems();
+ Arrays.sort(array, (item, t1) -> comparator[0].compare(item, t1) * (reverted.isChecked() ? -1 : 1));
+
+ GroupItem sorted = new GroupItem("Sorted!");
+ GuiItemsHelper.applyInitRandomColorIfNeeded(context, sorted, App.get(context).getSettingsManager());
+ for (Item item : array) {
+ Item copy = ItemsRegistry.REGISTRY.copyItem(item);
+ sorted.addItem(copy);
+ }
+ finalParent.addItem(sorted);
+
+ })
+ .show();
+ });
+
+
+ TextView gcp = new TextView(context);
+ gcp.setText("Global Changes Plugin:");
+ localBinding.getRoot().addView(gcp);
+
+ var horizont = new LinearLayout(context);
+ horizont.setOrientation(LinearLayout.HORIZONTAL);
+ horizont.addView(massBgColor);
+ horizont.addView(massRandomBgColor);
+ horizont.addView(selectAll);
+ horizont.addView(massTextColor);
+ horizont.addView(massRemoveNotification);
+ horizont.addView(massJSON);
+ horizont.addView(sortItems);
+
+ var h = new HorizontalScrollView(context);
+ h.addView(horizont);
+ localBinding.getRoot().addView(h);
+
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/plugins/gcp/GlobalChangesPlugin.java b/app/src/main/java/com/fazziclay/opentoday/plugins/gcp/GlobalChangesPlugin.java
new file mode 100644
index 00000000..a108db54
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/plugins/gcp/GlobalChangesPlugin.java
@@ -0,0 +1,37 @@
+package com.fazziclay.opentoday.plugins.gcp;
+
+import com.fazziclay.opentoday.api.EventHandler;
+import com.fazziclay.opentoday.api.OpenTodayPlugin;
+import com.fazziclay.opentoday.api.PluginManager;
+import com.fazziclay.opentoday.plugins.PluginsRegistry;
+import com.fazziclay.opentoday.plugins.islp.ItemsSupportLibraryPlugin;
+import com.fazziclay.opentoday.util.Logger;
+
+public class GlobalChangesPlugin extends OpenTodayPlugin {
+ private static final String TAG = "plugin://GlobalChangesPlugin";
+
+ private ItemsSupportLibraryPlugin islp;
+ private final EventHandler[] handlers = new EventHandler[]{new GcpEventHandler(this)};
+
+ @Override
+ public void onEnable() {
+ super.onEnable();
+ islp = (ItemsSupportLibraryPlugin) PluginManager.getActivePlugin(PluginsRegistry.REGISTRY.getByShortName("islp").getPackageId());
+ Logger.d(TAG, "gcp plugin is enabled!");
+ }
+
+ @Override
+ public void onDisable() {
+ super.onDisable();
+ Logger.d(TAG, "gcp plugin is disabled!");
+ }
+
+ @Override
+ public EventHandler[] getEventHandlers() {
+ return handlers;
+ }
+
+ public ItemsSupportLibraryPlugin getIslp() {
+ return islp;
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/plugins/islp/ItemsSupportLibraryPlugin.java b/app/src/main/java/com/fazziclay/opentoday/plugins/islp/ItemsSupportLibraryPlugin.java
new file mode 100644
index 00000000..3342d99b
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/plugins/islp/ItemsSupportLibraryPlugin.java
@@ -0,0 +1,55 @@
+package com.fazziclay.opentoday.plugins.islp;
+
+import com.fazziclay.opentoday.api.Event;
+import com.fazziclay.opentoday.api.EventHandler;
+import com.fazziclay.opentoday.api.OpenTodayPlugin;
+import com.fazziclay.opentoday.app.events.gui.CurrentItemsStorageContextChanged;
+import com.fazziclay.opentoday.app.events.items.ItemsRootDestroyedEvent;
+import com.fazziclay.opentoday.app.events.items.ItemsRootInitializedEvent;
+import com.fazziclay.opentoday.app.items.ItemsRoot;
+import com.fazziclay.opentoday.app.items.ItemsStorage;
+
+public class ItemsSupportLibraryPlugin extends OpenTodayPlugin {
+ private ItemsRoot itemsRoot = null;
+ private ItemsStorage currentItemsStorage = null;
+
+
+ private final EventHandler eventHandler = new EventHandler() {
+ @Override
+ public void handle(Event event) {
+ if (event instanceof ItemsRootInitializedEvent initializedEvent) {
+ ItemsSupportLibraryPlugin.this.itemsRoot = initializedEvent.getItemsRoot();
+
+ } else if (event instanceof ItemsRootDestroyedEvent) {
+ ItemsSupportLibraryPlugin.this.itemsRoot = null;
+
+ } else if (event instanceof CurrentItemsStorageContextChanged e) {
+ currentItemsStorage = e.getCurrentItemsStorage();
+ }
+ }
+ };
+ private final EventHandler[] handlers = new EventHandler[]{eventHandler};
+
+ @Override
+ public void onEnable() {
+ super.onEnable();
+ }
+
+ @Override
+ public void onDisable() {
+ super.onDisable();
+ }
+
+ @Override
+ public EventHandler[] getEventHandlers() {
+ return handlers;
+ }
+
+ public ItemsRoot getItemsRoot() {
+ return itemsRoot;
+ }
+
+ public ItemsStorage getCurrentItemsStorage() {
+ return currentItemsStorage;
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/util/ColorUtil.java b/app/src/main/java/com/fazziclay/opentoday/util/ColorUtil.java
index 8df26927..7d16f370 100644
--- a/app/src/main/java/com/fazziclay/opentoday/util/ColorUtil.java
+++ b/app/src/main/java/com/fazziclay/opentoday/util/ColorUtil.java
@@ -13,12 +13,16 @@
import androidx.annotation.NonNull;
+import com.fazziclay.opentoday.app.App;
+import com.fazziclay.opentoday.util.profiler.Profiler;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ColorUtil {
private static final boolean DEBUG_COLORIZE = false;
+ public static final Profiler PROFILER = App.createProfiler("ColorUtil");
public static String colorToHex(int color) {
int a = Color.alpha(color);
@@ -34,6 +38,7 @@ private static String byteToHex(int value) {
}
public static String sysReset(String sys, char c) {
+ PROFILER.push("sysReset");
String[] args = sys.split(";");
StringBuilder result = new StringBuilder();
StringBuilder passed = new StringBuilder();
@@ -44,11 +49,13 @@ public static String sysReset(String sys, char c) {
passed.append(arg.charAt(0));
}
}
+ PROFILER.pop();
if (result.toString().isEmpty()) return "";
return result.substring(0, result.lastIndexOf(";"));
}
public static String sysSet(String sys, char c, String val) {
+ PROFILER.push("sysSet");
String[] args = sys.split(";");
StringBuilder result = new StringBuilder();
StringBuilder passed = new StringBuilder();
@@ -58,12 +65,17 @@ public static String sysSet(String sys, char c, String val) {
if (!arg.startsWith(String.valueOf(c))) {
result.append(arg).append(";");
} else {
- result.append(c).append(val).append(";");
+ if (!val.isEmpty()) {
+ result.append(c).append(val).append(";");
+ } else {
+ result.append(";");
+ }
replaced = true;
}
passed.append(arg.charAt(0));
}
if (!replaced) result.append(c).append(val).append(";");
+ PROFILER.pop();
if (result.toString().isEmpty()) return "";
return result.substring(0, result.lastIndexOf(";"));
}
@@ -94,10 +106,26 @@ public static SpannableString colorize(String text, int defaultFgColor, int defa
* @see SpannableString
* **/
public static SpannableString colorize(String text, int defaultFgColor, int defaultBgColor, int defaultStyle, boolean showSystems) {
- if (text == null) return null;
+ PROFILER.push("colorize");
+ if (text == null) {
+ PROFILER.instant("text == null");
+ PROFILER.pop();
+ return null;
+ }
- StringBuilder log = new StringBuilder();
+ // maybe performance boost
+ if (!text.contains("$[")) {
+ PROFILER.push("(dollar[ not contains optimization)");
+ final SpannableString span = new SpannableString(text);
+ span.setSpan(new ForegroundColorSpan(defaultFgColor), 0, span.length(), Spannable.SPAN_COMPOSING);
+ span.setSpan(new BackgroundColorSpan(defaultBgColor), 0, span.length(), Spanned.SPAN_COMPOSING);
+ span.setSpan(new StyleSpan(defaultStyle), 0, span.length(), Spanned.SPAN_COMPOSING);
+ PROFILER.pop2();
+ return span;
+ }
+ PROFILER.push("colorize_default");
+ final StringBuilder log = new StringBuilder();
int currentForegroundSpan = defaultFgColor;
int currentBackgroundSpan = defaultBgColor;
int currentStyleSpan = defaultStyle;
@@ -228,12 +256,13 @@ public static SpannableString colorize(String text, int defaultFgColor, int defa
if (appendOld) oi++;
if (appendNew) ni++;
}
-
+ PROFILER.swap("concat result string");
StringBuilder fullText = new StringBuilder();
for (SpanText spanText : spanTextList) {
fullText.append(spanText.text);
}
+ PROFILER.swap("apply span");
SpannableString spannableText = new SpannableString(fullText.toString());
log.append("SpannableText = ").append(spannableText).append("\n");
log.append("SpanTextList = ").append(Arrays.toString(spanTextList.toArray()));
@@ -250,6 +279,7 @@ public static SpannableString colorize(String text, int defaultFgColor, int defa
if (spanText.size > 0) spannableText.setSpan(new AbsoluteSizeSpan(spanText.size, true), start, end, Spanned.SPAN_COMPOSING);
i++;
}
+ PROFILER.pop2();
return spannableText;
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/util/InlineUtil.java b/app/src/main/java/com/fazziclay/opentoday/util/InlineUtil.java
index 9ebad708..ddbe0661 100644
--- a/app/src/main/java/com/fazziclay/opentoday/util/InlineUtil.java
+++ b/app/src/main/java/com/fazziclay/opentoday/util/InlineUtil.java
@@ -4,6 +4,9 @@
import androidx.annotation.NonNull;
+import com.fazziclay.opentoday.app.App;
+import com.fazziclay.opentoday.util.profiler.Profiler;
+
import org.intellij.lang.annotations.MagicConstant;
import java.util.Calendar;
@@ -13,6 +16,7 @@
// Utility-class
// USE: import static com.fazziclay.opentoday.util.InlineUtil.*;
public class InlineUtil {
+ public static final Profiler IPROF = App.createProfiler("InlineUtil_Profiler");
/**
* Print message to System.in stream (System.out.println(o))
* **/
diff --git a/app/src/main/java/com/fazziclay/opentoday/util/Logger.java b/app/src/main/java/com/fazziclay/opentoday/util/Logger.java
index b3e3c0c9..3b3296ae 100644
--- a/app/src/main/java/com/fazziclay/opentoday/util/Logger.java
+++ b/app/src/main/java/com/fazziclay/opentoday/util/Logger.java
@@ -51,6 +51,7 @@ private static void log(Level level, final String s) {
}
private static void log(Level level, final String s, boolean noChecks) {
+ if (level == Level.DEBUG && !App.DEBUG) return;
final String time = TimeUtil.getDebugDate(System.currentTimeMillis());
final App app = App.get();
if (app == null) return;
diff --git a/app/src/main/java/com/fazziclay/opentoday/util/NetworkUtil.java b/app/src/main/java/com/fazziclay/opentoday/util/NetworkUtil.java
index 6d36b6bc..59785466 100644
--- a/app/src/main/java/com/fazziclay/opentoday/util/NetworkUtil.java
+++ b/app/src/main/java/com/fazziclay/opentoday/util/NetworkUtil.java
@@ -5,6 +5,7 @@
import android.net.Uri;
import android.widget.Toast;
+import com.fazziclay.opentoday.Debug;
import com.fazziclay.opentoday.R;
import com.fazziclay.opentoday.app.App;
@@ -26,7 +27,7 @@ public class NetworkUtil {
static {
if (App.DEBUG) NETWORK_LISTENERS.add((logKey, state, url, result) -> Logger.d(TAG, "Networking '"+logKey+"' State: " + state + " URL: " + url + " Result: " + result));
- if (App.DEBUG_NETWORK_UTIL_SHADOWCONTENT) {
+ if (Debug.DEBUG_NETWORK_UTIL_SHADOWCONTENT) {
// Update checked test
DEBUG_CONTENTS.put("https://fazziclay.github.io/api/project_3/v2/latest_build", "999");
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/util/Profiler.java b/app/src/main/java/com/fazziclay/opentoday/util/Profiler.java
deleted file mode 100644
index 33145515..00000000
--- a/app/src/main/java/com/fazziclay/opentoday/util/Profiler.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.fazziclay.opentoday.util;
-
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.List;
-
-// unused: delete?
-public class Profiler {
- private final String key;
- private final long constructorTime;
- private long endTime;
- private final List points = new ArrayList<>();
-
- public Profiler(String key) {
- this.key = key;
- constructorTime = System.currentTimeMillis();
- }
-
- public void point(String subOperation) {
- points.add(new Point(subOperation));
- }
-
- public void end() {
- endTime = System.currentTimeMillis();
-
- StringBuilder stringBuilder = new StringBuilder();
- long latestOperationTime = constructorTime;
- int i = 0;
- while (i < points.size()) {
- stringBuilder.append("\n");
- Point point = points.get(i);
- long latestElapsed = point.time - latestOperationTime;
- latestOperationTime = point.time;
-
- stringBuilder.append("#").append(i).append(" C: ").append(latestElapsed).append(" L: ").append(point.time - constructorTime).append(" - (").append(point.operation).append(") ");
- i++;
- }
-
- long latestElapsed = endTime - latestOperationTime;
- stringBuilder.append("\n").append("#").append("E").append(" C: ").append(latestElapsed).append(" L: ").append(endTime - constructorTime).append(" - ").append("[END]");
-
- Log.d("Profiler", "[" + key + "] Ended! Constructor elapsed: " + (endTime - constructorTime) + stringBuilder);
- }
-
- private static class Point {
- String operation;
- long time;
-
- public Point(String subOperation) {
- time = System.currentTimeMillis();
- operation = subOperation;
- }
- }
-}
diff --git a/app/src/main/java/com/fazziclay/opentoday/util/QuickNote.java b/app/src/main/java/com/fazziclay/opentoday/util/QuickNote.java
index 45f4157c..a319c0ba 100644
--- a/app/src/main/java/com/fazziclay/opentoday/util/QuickNote.java
+++ b/app/src/main/java/com/fazziclay/opentoday/util/QuickNote.java
@@ -2,13 +2,13 @@
import com.fazziclay.opentoday.app.items.notification.DayItemNotification;
import com.fazziclay.opentoday.app.items.notification.ItemNotification;
-import com.fazziclay.opentoday.gui.fragment.ItemsTabIncludeFragment;
+import com.fazziclay.opentoday.gui.fragment.item.ItemsTabIncludeFragment;
import java.util.ArrayList;
import java.util.List;
public class QuickNote {
- public static final ItemsTabIncludeFragment.QuickNoteInterface QUICK_NOTE_NOTIFICATIONS_PARSE = s -> {
+ public static final QuickNoteInterface QUICK_NOTE_NOTIFICATIONS_PARSE = s -> {
List notifys = new ArrayList<>();
boolean parseTime = true;
if (parseTime) {
@@ -22,8 +22,9 @@ public class QuickNote {
int minutes = Integer.parseInt(String.valueOf(chars[i + 1]) + chars[i + 2]);
DayItemNotification noti = new DayItemNotification();
+ noti.setNotificationId(RandomUtil.nextIntPositive());
noti.setTime((hours * 60 * 60) + (minutes * 60));
- noti.setNotifyTextFromItemText(true);
+ noti.setNotifyTitleFromItemText(true);
notifys.add(noti);
}
} catch (Exception ignored) {
@@ -32,6 +33,10 @@ public class QuickNote {
i++;
}
}
- return notifys;
+ return notifys.toArray(new ItemNotification[0]);
};
+
+ public interface QuickNoteInterface {
+ ItemNotification[] run(String text);
+ }
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/util/SafeFileUtil.java b/app/src/main/java/com/fazziclay/opentoday/util/SafeFileUtil.java
index 88862aec..f99ca312 100644
--- a/app/src/main/java/com/fazziclay/opentoday/util/SafeFileUtil.java
+++ b/app/src/main/java/com/fazziclay/opentoday/util/SafeFileUtil.java
@@ -33,7 +33,9 @@ public static OutputStream getFileOutputSteam(@NotNull File f) throws IOExceptio
public static void makeBackup(@NotNull File origin, @NotNull File backup) throws IOException {
if (!FileUtil.isExist(origin)) return;
if (FileUtil.isExist(backup)) FileUtil.delete(backup);
- Files.copy(getFileInputSteam(origin), backup.toPath());
+ InputStream stream = getFileInputSteam(origin);
+ Files.copy(stream, backup.toPath());
+ stream.close();
}
public static boolean isExist(@NotNull File file) {
diff --git a/app/src/main/java/com/fazziclay/opentoday/util/annotation/AppInitIfNeed.java b/app/src/main/java/com/fazziclay/opentoday/util/annotation/AppInitIfNeed.java
deleted file mode 100644
index bfabbeeb..00000000
--- a/app/src/main/java/com/fazziclay/opentoday/util/annotation/AppInitIfNeed.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.fazziclay.opentoday.util.annotation;
-
-public @interface AppInitIfNeed {
-}
diff --git a/app/src/main/java/com/fazziclay/opentoday/util/annotation/ForItem.java b/app/src/main/java/com/fazziclay/opentoday/util/annotation/ForItem.java
index 0de5a535..bc7432c8 100644
--- a/app/src/main/java/com/fazziclay/opentoday/util/annotation/ForItem.java
+++ b/app/src/main/java/com/fazziclay/opentoday/util/annotation/ForItem.java
@@ -1,11 +1,14 @@
package com.fazziclay.opentoday.util.annotation;
-import com.fazziclay.opentoday.app.items.item.Item;
+import com.fazziclay.opentoday.app.items.item.ItemType;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
-@Target(ElementType.METHOD)
+/**
+ * Specify item
+ */
+@Target({ElementType.TYPE, ElementType.METHOD})
public @interface ForItem {
- Class extends Item>[] key();
+ ItemType[] k();
}
diff --git a/app/src/main/java/com/fazziclay/opentoday/util/opentodaybutton/MaterialButtonWithColorIndicator.java b/app/src/main/java/com/fazziclay/opentoday/util/opentodaybutton/MaterialButtonWithColorIndicator.java
new file mode 100644
index 00000000..16c9a2f1
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/util/opentodaybutton/MaterialButtonWithColorIndicator.java
@@ -0,0 +1,108 @@
+package com.fazziclay.opentoday.util.opentodaybutton;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.content.res.AppCompatResources;
+
+import com.fazziclay.opentoday.R;
+import com.fazziclay.opentoday.util.ResUtil;
+import com.google.android.material.button.MaterialButton;
+
+public class MaterialButtonWithColorIndicator extends OpenTodayButton {
+ private int color;
+ private boolean isSet = false;
+
+ public MaterialButtonWithColorIndicator(@NonNull Context context) {
+ super(context);
+ }
+
+ public MaterialButtonWithColorIndicator(@NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public MaterialButtonWithColorIndicator(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public MaterialButtonWithColorIndicator(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void initView(Context context, AttributeSet attrs) {
+ final TypedArray typedArray = context.obtainStyledAttributes(attrs, new int[]{android.R.attr.text, android.R.attr.backgroundTint, android.R.attr.textColor});
+ try {
+ final MaterialButton button = new MaterialButton(context);
+ button.setText(typedArray.getString(0));
+ button.setBackgroundTintList(ColorStateList.valueOf(typedArray.getColor(1, ResUtil.getAttrColor(context, R.attr.button_buttonWithColorIndicator))));
+ button.setTextColor(typedArray.getColor(2, ResUtil.getAttrColor(context, com.google.android.material.R.attr.colorOnPrimary)));
+
+
+ setButton(button);
+ setIndicator(new ImageView(context));
+ } finally {
+ typedArray.recycle();
+ }
+
+ }
+
+ @Override
+ protected void initIndicator(Context context, AttributeSet attrs, ImageView indicator) {
+ super.initIndicator(context, attrs, indicator);
+
+ indicator.setForeground(AppCompatResources.getDrawable(context, R.drawable.color_indicator));
+ indicator.setScaleType(ImageView.ScaleType.FIT_XY);
+ updateSetState();
+ }
+
+ @Override
+ protected void initButton(Context context, AttributeSet attrs, MaterialButton button) {
+ super.initButton(context, attrs, button);
+ }
+
+ public void setColor(int color) {
+ this.color = color;
+ setColorSet(true);
+ getIndicator().setImageTintList(ColorStateList.valueOf(color));
+ }
+
+
+
+ public void setColorSet(boolean set) {
+ this.isSet = set;
+ updateSetState();
+ }
+
+ private void updateSetState() {
+ var indicator = getIndicator();
+ indicator.setImageResource(!isSet ? R.drawable.close_24px : R.drawable.shape);
+ indicator.setBackgroundResource(!isSet ? 0 : com.rarepebble.colorpicker.R.drawable.checker_background);
+ if (!isSet) {
+ indicator.setImageTintList(ColorStateList.valueOf(Color.RED));
+ }
+ }
+
+ public int getColor() {
+ return color;
+ }
+
+ @Override
+ public void setOnClickListener(@Nullable OnClickListener l) {
+ getButton().setOnClickListener(l);
+ }
+
+ public void setText(String s) {
+ getButton().setText(s);
+ }
+
+ public void setText(int s) {
+ getButton().setText(s);
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/util/opentodaybutton/OpenTodayButton.java b/app/src/main/java/com/fazziclay/opentoday/util/opentodaybutton/OpenTodayButton.java
new file mode 100644
index 00000000..48b2a96b
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/util/opentodaybutton/OpenTodayButton.java
@@ -0,0 +1,103 @@
+package com.fazziclay.opentoday.util.opentodaybutton;
+
+import android.content.Context;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.view.AbsSavedState;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.RelativeLayout;
+
+import com.fazziclay.opentoday.util.Logger;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public abstract class OpenTodayButton extends RelativeLayout {
+ private static final String TAG = "OpenTodayButton";
+ private B button;
+ private T indicator;
+
+ public OpenTodayButton(Context context) {
+ super(context);
+ init(context, null);
+ }
+
+ public OpenTodayButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context, attrs);
+ }
+
+ public OpenTodayButton(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(context, attrs);
+ }
+
+ public OpenTodayButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init(context, attrs);
+ }
+
+ protected void setButton(B b) {
+ this.button = b;
+ }
+
+ protected void setIndicator(T t) {
+ this.indicator = t;
+ }
+
+ protected abstract void initView(Context context, AttributeSet attrs);
+
+ protected void initIndicator(Context context, AttributeSet attrs, T indicator) {
+ var params = new RelativeLayout.LayoutParams(64, 64);
+ params.addRule(RelativeLayout.CENTER_VERTICAL);
+ params.addRule(ALIGN_PARENT_END);
+ params.setMargins(10, 10, 10, 10);
+ indicator.setLayoutParams(params);
+ }
+
+ protected void initButton(Context context, AttributeSet attrs, B button) {
+ var params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ button.setPadding(0, 32, 75, 32);
+ button.setLayoutParams(params);
+ }
+
+ protected void init(@NotNull Context context, @Nullable AttributeSet attrs) {
+ Logger.d(TAG, "init() attrs="+attrs);
+ initView(context, attrs);
+
+ // indicator
+ initIndicator(context, attrs, indicator);
+
+ // button
+ initButton(context, attrs, button);
+
+ button.setElevation(0f);
+ addView(button);
+
+ indicator.setElevation(15f);
+ addView(indicator);
+ }
+
+ public B getButton() {
+ return button;
+ }
+
+ public T getIndicator() {
+ return indicator;
+ }
+
+ @androidx.annotation.Nullable
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ var v = super.onSaveInstanceState();
+ Logger.d(TAG, "onSaveInstanceState() returned v="+v + "v.s="+((AbsSavedState)v).getSuperState());
+ return v;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ Logger.d(TAG, "onRestoreInstanceState() state=" + state);
+ super.onRestoreInstanceState(state);
+ }
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/util/profiler/Profiler.java b/app/src/main/java/com/fazziclay/opentoday/util/profiler/Profiler.java
new file mode 100644
index 00000000..7af799f8
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/util/profiler/Profiler.java
@@ -0,0 +1,42 @@
+package com.fazziclay.opentoday.util.profiler;
+
+public interface Profiler {
+ Profiler EMPTY = new Profiler() {
+ @Override
+ public void push(String s) {}
+
+ @Override
+ public void pop() {}
+
+ @Override
+ public void pop2() {}
+
+ @Override
+ public void end() {}
+
+ @Override
+ public void swap(String s) {}
+
+ @Override
+ public void instant(String s) {}
+
+ @Override
+ public String getResult(int depth) {
+ return "EMPTY_PROFILER";
+ }
+ };
+
+ void push(String s);
+
+ void pop();
+
+ void pop2();
+
+ void end();
+
+ void swap(String s);
+
+ void instant(String s);
+
+ String getResult(int depth);
+}
diff --git a/app/src/main/java/com/fazziclay/opentoday/util/profiler/ProfilerImpl.java b/app/src/main/java/com/fazziclay/opentoday/util/profiler/ProfilerImpl.java
new file mode 100644
index 00000000..3c75afb0
--- /dev/null
+++ b/app/src/main/java/com/fazziclay/opentoday/util/profiler/ProfilerImpl.java
@@ -0,0 +1,182 @@
+package com.fazziclay.opentoday.util.profiler;
+
+import android.util.ArraySet;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
+
+// unused: delete?
+public class ProfilerImpl implements Profiler {
+ public static ArrayList PROFILERS;
+
+ private final String profilerName;
+ private final NodeImpl rootNode;
+ private NodeImpl currentNode;
+
+ public ProfilerImpl(String profilerName) {
+ this.profilerName = profilerName;
+ rootNode = NodeImpl.createRootNode(profilerName);
+ currentNode = rootNode;
+
+ rootNode.start();
+ }
+
+ public void push(NodeImpl node) {
+ node.parent = currentNode;
+ List list;
+ if (currentNode.children.containsKey(node.name)) {
+ list = currentNode.children.get(node.name);
+ } else {
+ list = new ArrayList<>();
+ currentNode.children.put(node.name, list);
+ }
+ if (list == null) {
+ list = new ArrayList<>();
+ currentNode.children.put(node.name, list);
+ }
+ list.add(node);
+ currentNode = node;
+ node.start();
+ }
+
+ @Override
+ public void push(String s) {
+ push(new NodeImpl(null, s));
+ }
+
+ @Override
+ public void swap(String s) {
+ pop();
+ push(s);
+ }
+
+ @Override
+ public void instant(String s) {
+ push(s);
+ pop();
+ }
+
+ @Override
+ public void pop() {
+ currentNode.end();
+ currentNode = currentNode.parent;
+ }
+
+ @Override
+ public void pop2() {
+ pop();
+ pop();
+ }
+
+ @Override
+ public void end() {
+ rootNode.end();
+ }
+
+ @Override
+ public String getResult(int depth) {
+ return "==== Profiler Results (" + profilerName + ") ====\n" + _result(0, depth, "", rootNode.name, Collections.singletonList(rootNode)).text;
+ }
+
+ @Nullable
+ private Result _result(int currDepth, int maxDepth, String spaces, String name, List nodes) {
+ if (currDepth > maxDepth && maxDepth > 0) {
+ return null;
+ }
+ final Set allKeys = new ArraySet<>();
+ long sumDur = 0;
+ long avgDur = 0;
+ long maxDur = Long.MIN_VALUE;
+ long minDur = Long.MAX_VALUE;
+ for (final NodeImpl node : nodes) {
+ long dur = node.getDuration();
+ sumDur += dur;
+ if (minDur > dur) minDur = dur;
+ if (maxDur < dur) maxDur = dur;
+ allKeys.addAll(node.children.keySet());
+ }
+ if (nodes.size() > 0) avgDur = sumDur / nodes.size();
+
+ String text = (avgDur == -1) ? (spaces + "[" + name + "]") : String.format("%s[%s] %s%sms %s%s", spaces, name, (nodes.size() == 1 ? "=" : "~"), avgDur, (nodes.size() == 1 ? "" : String.format("(max=%sms min=%sms) ", maxDur, minDur)), (nodes.size() == 1 ? "" : nodes.size() + " nodes"));
+ StringBuilder s = new StringBuilder(text);
+
+ List childResults = new ArrayList<>();
+ for (String childKey : allKeys) {
+ List child = new ArrayList<>();
+ for (NodeImpl node : nodes) {
+ if (node.children.containsKey(childKey)) {
+ child.addAll(node.children.get(childKey));
+ }
+ }
+
+ Result recursive = _result(currDepth + 1, maxDepth, spaces + " | ", childKey, child);
+ if (recursive != null) {
+ childResults.add(recursive);
+ }
+ }
+
+ Result[] results = childResults.toArray(new Result[0]);
+ Arrays.sort(results, (result, t1) -> {
+ return Math.toIntExact(t1.dur - result.dur);
+ });
+
+ for (Result result : results) {
+ s.append("\n").append(result.text);
+ }
+
+ Result r = new Result();
+ r.text = s.toString();
+ r.dur = avgDur;
+ return r;
+ }
+
+ private static class Result {
+ String text;
+ long dur;
+ }
+
+ public static class NodeImpl {
+ @Nullable
+ NodeImpl parent;
+ @NotNull
+ String name;
+ @NotNull
+ final HashMap> children = new HashMap<>();
+ long startTime;
+ long endTime;
+
+
+ public NodeImpl(@Nullable NodeImpl parent, @NonNull String name) {
+ this.parent = parent;
+ this.name = name;
+ }
+
+ public void start() {
+ if (this.startTime > 0) return;
+ this.startTime = System.currentTimeMillis();
+ }
+
+ public void end() {
+ if (this.endTime > 0) return;
+ this.endTime = System.currentTimeMillis();
+ }
+
+ public static NodeImpl createRootNode(String root) {
+ return new NodeImpl(null, "root:"+root);
+ }
+
+ public long getDuration() {
+ if (endTime == 0) return -1;
+ return endTime - startTime;
+ }
+ }
+}
diff --git a/app/src/main/res/anim/fade_in.xml b/app/src/main/res/anim/fade_in.xml
new file mode 100644
index 00000000..bf477448
--- /dev/null
+++ b/app/src/main/res/anim/fade_in.xml
@@ -0,0 +1,5 @@
+
diff --git a/app/src/main/res/anim/fade_out.xml b/app/src/main/res/anim/fade_out.xml
new file mode 100644
index 00000000..32d93ba8
--- /dev/null
+++ b/app/src/main/res/anim/fade_out.xml
@@ -0,0 +1,6 @@
+
+
diff --git a/app/src/main/res/anim/slide_in.xml b/app/src/main/res/anim/slide_in.xml
new file mode 100644
index 00000000..214d518e
--- /dev/null
+++ b/app/src/main/res/anim/slide_in.xml
@@ -0,0 +1,6 @@
+
+
diff --git a/app/src/main/res/anim/slide_out.xml b/app/src/main/res/anim/slide_out.xml
new file mode 100644
index 00000000..b26b3b77
--- /dev/null
+++ b/app/src/main/res/anim/slide_out.xml
@@ -0,0 +1,5 @@
+
diff --git a/app/src/main/res/drawable/add_24px.xml b/app/src/main/res/drawable/add_24px.xml
new file mode 100644
index 00000000..61de3dd0
--- /dev/null
+++ b/app/src/main/res/drawable/add_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/analog_clock_background.xml b/app/src/main/res/drawable/analog_clock_background.xml
new file mode 100644
index 00000000..d4c1d7c6
--- /dev/null
+++ b/app/src/main/res/drawable/analog_clock_background.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/aspect_ratio_24px.xml b/app/src/main/res/drawable/aspect_ratio_24px.xml
new file mode 100644
index 00000000..a92c6343
--- /dev/null
+++ b/app/src/main/res/drawable/aspect_ratio_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/background_replace_24px.xml b/app/src/main/res/drawable/background_replace_24px.xml
new file mode 100644
index 00000000..4b14709b
--- /dev/null
+++ b/app/src/main/res/drawable/background_replace_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/barefoot_24px.xml b/app/src/main/res/drawable/barefoot_24px.xml
new file mode 100644
index 00000000..c6e1c675
--- /dev/null
+++ b/app/src/main/res/drawable/barefoot_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/baseline_account_tree_24.xml b/app/src/main/res/drawable/baseline_account_tree_24.xml
new file mode 100644
index 00000000..d43318a6
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_account_tree_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/baseline_add_alert_24.xml b/app/src/main/res/drawable/baseline_add_alert_24.xml
new file mode 100644
index 00000000..44d55f63
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_add_alert_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/baseline_celebration_24.xml b/app/src/main/res/drawable/baseline_celebration_24.xml
new file mode 100644
index 00000000..e9d98dc8
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_celebration_24.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_thumb_up_24.xml b/app/src/main/res/drawable/baseline_thumb_up_24.xml
new file mode 100644
index 00000000..003015fb
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_thumb_up_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/baseline_upcoming_24.xml b/app/src/main/res/drawable/baseline_upcoming_24.xml
new file mode 100644
index 00000000..80434888
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_upcoming_24.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_waves_24.xml b/app/src/main/res/drawable/baseline_waves_24.xml
new file mode 100644
index 00000000..82a30bc1
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_waves_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/baseline_weekend_24.xml b/app/src/main/res/drawable/baseline_weekend_24.xml
new file mode 100644
index 00000000..3bb9ff82
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_weekend_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/baseline_window_24.xml b/app/src/main/res/drawable/baseline_window_24.xml
new file mode 100644
index 00000000..10a06bcf
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_window_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/baseline_yard_24.xml b/app/src/main/res/drawable/baseline_yard_24.xml
new file mode 100644
index 00000000..adfae1ce
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_yard_24.xml
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/bed_24px.xml b/app/src/main/res/drawable/bed_24px.xml
new file mode 100644
index 00000000..0a85e648
--- /dev/null
+++ b/app/src/main/res/drawable/bed_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/bedtime_24px.xml b/app/src/main/res/drawable/bedtime_24px.xml
new file mode 100644
index 00000000..9ae55cf7
--- /dev/null
+++ b/app/src/main/res/drawable/bedtime_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/calendar_clock_24px.xml b/app/src/main/res/drawable/calendar_clock_24px.xml
new file mode 100644
index 00000000..beea6226
--- /dev/null
+++ b/app/src/main/res/drawable/calendar_clock_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/calendar_today_24px.xml b/app/src/main/res/drawable/calendar_today_24px.xml
new file mode 100644
index 00000000..79cfa2db
--- /dev/null
+++ b/app/src/main/res/drawable/calendar_today_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/check_box_outline_blank_24px.xml b/app/src/main/res/drawable/check_box_outline_blank_24px.xml
new file mode 100644
index 00000000..55e81088
--- /dev/null
+++ b/app/src/main/res/drawable/check_box_outline_blank_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/close_24px.xml b/app/src/main/res/drawable/close_24px.xml
new file mode 100644
index 00000000..e5d6621b
--- /dev/null
+++ b/app/src/main/res/drawable/close_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/cloudy_snowing_24px.xml b/app/src/main/res/drawable/cloudy_snowing_24px.xml
new file mode 100644
index 00000000..34134b94
--- /dev/null
+++ b/app/src/main/res/drawable/cloudy_snowing_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/color_indicator.xml b/app/src/main/res/drawable/color_indicator.xml
new file mode 100644
index 00000000..72855ded
--- /dev/null
+++ b/app/src/main/res/drawable/color_indicator.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/content_copy_24px.xml b/app/src/main/res/drawable/content_copy_24px.xml
new file mode 100644
index 00000000..c17b184f
--- /dev/null
+++ b/app/src/main/res/drawable/content_copy_24px.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/app/src/main/res/drawable/delete_24px.xml b/app/src/main/res/drawable/delete_24px.xml
new file mode 100644
index 00000000..c87c217c
--- /dev/null
+++ b/app/src/main/res/drawable/delete_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/edit_24px.xml b/app/src/main/res/drawable/edit_24px.xml
new file mode 100644
index 00000000..c9407d09
--- /dev/null
+++ b/app/src/main/res/drawable/edit_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/edit_note_24px.xml b/app/src/main/res/drawable/edit_note_24px.xml
new file mode 100644
index 00000000..efb5f668
--- /dev/null
+++ b/app/src/main/res/drawable/edit_note_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/emoji_flags_24px.xml b/app/src/main/res/drawable/emoji_flags_24px.xml
new file mode 100644
index 00000000..eaa74dfd
--- /dev/null
+++ b/app/src/main/res/drawable/emoji_flags_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/emoji_food_beverage_24px.xml b/app/src/main/res/drawable/emoji_food_beverage_24px.xml
new file mode 100644
index 00000000..f49cf64f
--- /dev/null
+++ b/app/src/main/res/drawable/emoji_food_beverage_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/emoji_objects_24px.xml b/app/src/main/res/drawable/emoji_objects_24px.xml
new file mode 100644
index 00000000..a5a5aaaa
--- /dev/null
+++ b/app/src/main/res/drawable/emoji_objects_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/export_notes_24px.xml b/app/src/main/res/drawable/export_notes_24px.xml
new file mode 100644
index 00000000..761e9450
--- /dev/null
+++ b/app/src/main/res/drawable/export_notes_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/face_2_24px.xml b/app/src/main/res/drawable/face_2_24px.xml
new file mode 100644
index 00000000..f2d111a9
--- /dev/null
+++ b/app/src/main/res/drawable/face_2_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/filter_alt_24px.xml b/app/src/main/res/drawable/filter_alt_24px.xml
new file mode 100644
index 00000000..295d8ca4
--- /dev/null
+++ b/app/src/main/res/drawable/filter_alt_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/fluid_24px.xml b/app/src/main/res/drawable/fluid_24px.xml
new file mode 100644
index 00000000..7c9655c1
--- /dev/null
+++ b/app/src/main/res/drawable/fluid_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/format_bold_24px.xml b/app/src/main/res/drawable/format_bold_24px.xml
new file mode 100644
index 00000000..d66d6ee9
--- /dev/null
+++ b/app/src/main/res/drawable/format_bold_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/format_italic_24px.xml b/app/src/main/res/drawable/format_italic_24px.xml
new file mode 100644
index 00000000..0cbfd063
--- /dev/null
+++ b/app/src/main/res/drawable/format_italic_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/format_size_24px.xml b/app/src/main/res/drawable/format_size_24px.xml
new file mode 100644
index 00000000..f5365ecc
--- /dev/null
+++ b/app/src/main/res/drawable/format_size_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/format_strikethrough_24px.xml b/app/src/main/res/drawable/format_strikethrough_24px.xml
new file mode 100644
index 00000000..8a18ff47
--- /dev/null
+++ b/app/src/main/res/drawable/format_strikethrough_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/gastroenterology_24px.xml b/app/src/main/res/drawable/gastroenterology_24px.xml
new file mode 100644
index 00000000..9b856cf8
--- /dev/null
+++ b/app/src/main/res/drawable/gastroenterology_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/handyman_24px.xml b/app/src/main/res/drawable/handyman_24px.xml
new file mode 100644
index 00000000..2174ef29
--- /dev/null
+++ b/app/src/main/res/drawable/handyman_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/home_health_24px.xml b/app/src/main/res/drawable/home_health_24px.xml
new file mode 100644
index 00000000..8f92f90a
--- /dev/null
+++ b/app/src/main/res/drawable/home_health_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/home_work_24px.xml b/app/src/main/res/drawable/home_work_24px.xml
new file mode 100644
index 00000000..5ed6c4ef
--- /dev/null
+++ b/app/src/main/res/drawable/home_work_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/info_i_24px.xml b/app/src/main/res/drawable/info_i_24px.xml
new file mode 100644
index 00000000..7329b612
--- /dev/null
+++ b/app/src/main/res/drawable/info_i_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/minimize_24px.xml b/app/src/main/res/drawable/minimize_24px.xml
new file mode 100644
index 00000000..fa651831
--- /dev/null
+++ b/app/src/main/res/drawable/minimize_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/new_label_24px.xml b/app/src/main/res/drawable/new_label_24px.xml
new file mode 100644
index 00000000..e90ad055
--- /dev/null
+++ b/app/src/main/res/drawable/new_label_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/notifications_24px.xml b/app/src/main/res/drawable/notifications_24px.xml
new file mode 100644
index 00000000..5336cf14
--- /dev/null
+++ b/app/src/main/res/drawable/notifications_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/opacity_24px.xml b/app/src/main/res/drawable/opacity_24px.xml
new file mode 100644
index 00000000..ddc8b8df
--- /dev/null
+++ b/app/src/main/res/drawable/opacity_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/palette_24px.xml b/app/src/main/res/drawable/palette_24px.xml
new file mode 100644
index 00000000..d742d7f9
--- /dev/null
+++ b/app/src/main/res/drawable/palette_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/pause_presentation_24px.xml b/app/src/main/res/drawable/pause_presentation_24px.xml
new file mode 100644
index 00000000..19128161
--- /dev/null
+++ b/app/src/main/res/drawable/pause_presentation_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/pill_24px.xml b/app/src/main/res/drawable/pill_24px.xml
new file mode 100644
index 00000000..7435bb0f
--- /dev/null
+++ b/app/src/main/res/drawable/pill_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/procedure_24px.xml b/app/src/main/res/drawable/procedure_24px.xml
new file mode 100644
index 00000000..7be92352
--- /dev/null
+++ b/app/src/main/res/drawable/procedure_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/psychiatry_24px.xml b/app/src/main/res/drawable/psychiatry_24px.xml
new file mode 100644
index 00000000..c54056ba
--- /dev/null
+++ b/app/src/main/res/drawable/psychiatry_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/recommend_24px.xml b/app/src/main/res/drawable/recommend_24px.xml
new file mode 100644
index 00000000..c580027c
--- /dev/null
+++ b/app/src/main/res/drawable/recommend_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/redeem_24px.xml b/app/src/main/res/drawable/redeem_24px.xml
new file mode 100644
index 00000000..c83a15f2
--- /dev/null
+++ b/app/src/main/res/drawable/redeem_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/repeat_24px.xml b/app/src/main/res/drawable/repeat_24px.xml
new file mode 100644
index 00000000..a4133ba4
--- /dev/null
+++ b/app/src/main/res/drawable/repeat_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/rocket_24px.xml b/app/src/main/res/drawable/rocket_24px.xml
new file mode 100644
index 00000000..35407966
--- /dev/null
+++ b/app/src/main/res/drawable/rocket_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/rocket_launch_24px.xml b/app/src/main/res/drawable/rocket_launch_24px.xml
new file mode 100644
index 00000000..152999a5
--- /dev/null
+++ b/app/src/main/res/drawable/rocket_launch_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/save_24px.xml b/app/src/main/res/drawable/save_24px.xml
new file mode 100644
index 00000000..e31e44f3
--- /dev/null
+++ b/app/src/main/res/drawable/save_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/select_24px.xml b/app/src/main/res/drawable/select_24px.xml
new file mode 100644
index 00000000..0c5aa627
--- /dev/null
+++ b/app/src/main/res/drawable/select_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/sentiment_stressed_24px.xml b/app/src/main/res/drawable/sentiment_stressed_24px.xml
new file mode 100644
index 00000000..edefde77
--- /dev/null
+++ b/app/src/main/res/drawable/sentiment_stressed_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/sentiment_very_dissatisfied_24px.xml b/app/src/main/res/drawable/sentiment_very_dissatisfied_24px.xml
new file mode 100644
index 00000000..d6f4a9ff
--- /dev/null
+++ b/app/src/main/res/drawable/sentiment_very_dissatisfied_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/sentiment_worried_24px.xml b/app/src/main/res/drawable/sentiment_worried_24px.xml
new file mode 100644
index 00000000..7a8a6dd8
--- /dev/null
+++ b/app/src/main/res/drawable/sentiment_worried_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/shopping_basket_24px.xml b/app/src/main/res/drawable/shopping_basket_24px.xml
new file mode 100644
index 00000000..d47de24a
--- /dev/null
+++ b/app/src/main/res/drawable/shopping_basket_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/shopping_cart_24px.xml b/app/src/main/res/drawable/shopping_cart_24px.xml
new file mode 100644
index 00000000..fcd146a4
--- /dev/null
+++ b/app/src/main/res/drawable/shopping_cart_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/store_24px.xml b/app/src/main/res/drawable/store_24px.xml
new file mode 100644
index 00000000..228f64b5
--- /dev/null
+++ b/app/src/main/res/drawable/store_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/surgical_24px.xml b/app/src/main/res/drawable/surgical_24px.xml
new file mode 100644
index 00000000..9f240bb9
--- /dev/null
+++ b/app/src/main/res/drawable/surgical_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/swipe_left_24px.xml b/app/src/main/res/drawable/swipe_left_24px.xml
new file mode 100644
index 00000000..20e2bb58
--- /dev/null
+++ b/app/src/main/res/drawable/swipe_left_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/syringe_24px.xml b/app/src/main/res/drawable/syringe_24px.xml
new file mode 100644
index 00000000..b90ab557
--- /dev/null
+++ b/app/src/main/res/drawable/syringe_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/taunt_24px.xml b/app/src/main/res/drawable/taunt_24px.xml
new file mode 100644
index 00000000..f697c071
--- /dev/null
+++ b/app/src/main/res/drawable/taunt_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/touch_app_24px.xml b/app/src/main/res/drawable/touch_app_24px.xml
new file mode 100644
index 00000000..5d547766
--- /dev/null
+++ b/app/src/main/res/drawable/touch_app_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/tune_24px.xml b/app/src/main/res/drawable/tune_24px.xml
new file mode 100644
index 00000000..1d3ccf10
--- /dev/null
+++ b/app/src/main/res/drawable/tune_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_alarm.xml b/app/src/main/res/layout/activity_alarm.xml
index 73cfcb9d..1966fda0 100644
--- a/app/src/main/res/layout/activity_alarm.xml
+++ b/app/src/main/res/layout/activity_alarm.xml
@@ -1,12 +1,15 @@
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingEnd="6sp"
+ android:paddingStart="6sp"
+ xmlns:tools="http://schemas.android.com/tools">
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_crash_report.xml b/app/src/main/res/layout/activity_crash_report.xml
index 151001c5..53b79913 100644
--- a/app/src/main/res/layout/activity_crash_report.xml
+++ b/app/src/main/res/layout/activity_crash_report.xml
@@ -13,6 +13,14 @@
android:layout_height="wrap_content"
android:text="@string/crash_activity_sendToDeveloper" />
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 8e5a5825..7350fdf2 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -3,32 +3,34 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.fazziclay.opentoday.gui.activity.MainActivity">
+
+
+
+
+
+
+
+ android:text="@string/dialog_itemNotification_fullScreen" />
+ android:text="@string/dialog_itemNotification_previewViewOnly" />
+ android:text="@string/dialog_itemNotification_sound" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_item_editor_module_item.xml b/app/src/main/res/layout/fragment_item_editor_module_item.xml
index a2f7950d..bf1e3384 100644
--- a/app/src/main/res/layout/fragment_item_editor_module_item.xml
+++ b/app/src/main/res/layout/fragment_item_editor_module_item.xml
@@ -1,6 +1,7 @@
-
-
-
-
-
-
-
-
-
+ android:minHeight="50sp" />
-
-
+ android:layout_below="@id/notifications_title"
+ android:textSize="17sp"
+ android:visibility="gone"
+ android:layout_marginStart="10sp"
+ android:layout_marginEnd="10sp"
+ android:layout_toStartOf="@id/addNotification"
+ android:text="@string/fragment_itemEditor_module_item_notifications_notFound"
+ android:layout_height="wrap_content" />
-
+
-
-
+
@@ -104,6 +82,28 @@
android:layout_height="wrap_content"
android:minHeight="0sp"
android:layout_below="@id/minimize"
- android:layout_alignParentEnd="true"
+ android:layout_toEndOf="@id/viewMinHeight"
android:text="@string/fragment_itemEditor_module_item_selected" />
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_item_editor_module_longtext.xml b/app/src/main/res/layout/fragment_item_editor_module_longtext.xml
index aeb3e6ba..65d71a41 100644
--- a/app/src/main/res/layout/fragment_item_editor_module_longtext.xml
+++ b/app/src/main/res/layout/fragment_item_editor_module_longtext.xml
@@ -20,7 +20,7 @@
android:id="@+id/openLongTextEditor"
android:layout_width="48sp"
android:layout_height="40sp"
- android:src="@android:drawable/ic_menu_edit"
+ android:src="@drawable/edit_24px"
android:layout_alignParentEnd="true"
android:backgroundTint="#44000000"
android:contentDescription="@string/fragment_itemEditor_module_longtext_openTextEditor" />
diff --git a/app/src/main/res/layout/fragment_item_editor_module_text.xml b/app/src/main/res/layout/fragment_item_editor_module_text.xml
index 8f83322c..31872329 100644
--- a/app/src/main/res/layout/fragment_item_editor_module_text.xml
+++ b/app/src/main/res/layout/fragment_item_editor_module_text.xml
@@ -11,7 +11,7 @@
android:layout_alignTop="@id/openTextEditor"
android:layout_alignBottom="@id/openTextEditor"
android:layout_toStartOf="@id/openTextEditor"
- android:gravity="bottom"
+ android:gravity="center_vertical"
android:minHeight="23sp"
android:text="@string/fragment_itemEditor_module_text_text_title"/>
@@ -19,7 +19,7 @@
android:id="@+id/openTextEditor"
android:layout_width="48sp"
android:layout_height="40sp"
- android:src="@android:drawable/ic_menu_edit"
+ android:src="@drawable/edit_24px"
android:layout_alignParentEnd="true"
android:backgroundTint="#44000000"
android:contentDescription="@string/fragment_itemEditor_module_text_openTextEditor" />
@@ -50,33 +50,10 @@
android:minHeight="0sp"
android:text="@string/item_text_clickableUrls" />
-
-
-
-
-
-
-
-
+ android:text="@string/fragment_itemEditor_text_textColor"
+ android:layout_below="@id/clickableUrls" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_item_text_editor.xml b/app/src/main/res/layout/fragment_item_text_editor.xml
index c1fe48f6..ef669788 100644
--- a/app/src/main/res/layout/fragment_item_text_editor.xml
+++ b/app/src/main/res/layout/fragment_item_text_editor.xml
@@ -3,51 +3,82 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:paddingStart="5sp"
android:paddingEnd="5sp"
android:paddingBottom="10sp"
android:orientation="vertical">
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -61,7 +92,7 @@
android:layout_height="match_parent"
tools:text="wergwergfwregrewggergewr\nrwettrewtwetwretrwetrwe"
android:importantForAutofill="no"
- android:inputType="textMultiLine|textAutoCorrect|textAutoComplete" />
+ android:inputType="textCapSentences|textMultiLine|textAutoCorrect|textAutoComplete" />
diff --git a/app/src/main/res/layout/fragment_items_tab_include.xml b/app/src/main/res/layout/fragment_items_tab_include.xml
index 32fa3292..7d6d6a71 100644
--- a/app/src/main/res/layout/fragment_items_tab_include.xml
+++ b/app/src/main/res/layout/fragment_items_tab_include.xml
@@ -6,13 +6,37 @@
xmlns:tools="http://schemas.android.com/tools">
-
+ android:scrollbarSize="0px">
+
+
+
+
+
+
+
+
+ android:layout_below="@id/tabsScrollView" />
+ android:src="@drawable/new_label_24px" />
@@ -69,8 +95,8 @@
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingLeft="5sp"
- android:paddingRight="5sp"
+ android:paddingLeft="8sp"
+ android:paddingRight="8sp"
android:layout_alignParentBottom="true"
android:background="?attr/toolbar_background" />
diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml
index 46e58dd0..463a9229 100644
--- a/app/src/main/res/layout/fragment_settings.xml
+++ b/app/src/main/res/layout/fragment_settings.xml
@@ -3,12 +3,12 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical"
- style="@style/Theme.OpenToday.Settings.Root">
+ android:orientation="vertical">
+ android:layout_height="wrap_content"
+ style="@style/Theme.OpenToday.Settings.Root">
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_settings_analog_clock.xml b/app/src/main/res/layout/fragment_settings_analog_clock.xml
new file mode 100644
index 00000000..a10af82c
--- /dev/null
+++ b/app/src/main/res/layout/fragment_settings_analog_clock.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_checkbox.xml b/app/src/main/res/layout/item_checkbox.xml
index a49a3d0f..f4c33551 100644
--- a/app/src/main/res/layout/item_checkbox.xml
+++ b/app/src/main/res/layout/item_checkbox.xml
@@ -18,9 +18,20 @@
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- tools:text="Simple checkbox"
+ tools:text="Simple checkbox jjh hjjh uij bft kj kl fgh klh hj hj"
android:layout_toEndOf="@id/checkbox"
android:layout_alignBaseline="@id/checkbox"
+ android:layout_toStartOf="@id/indicatorNotification"
android:textSize="19sp"
android:textColor="?attr/item_checkbox_textColor" />
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_counter.xml b/app/src/main/res/layout/item_counter.xml
index ec2f8bbb..5416c00a 100644
--- a/app/src/main/res/layout/item_counter.xml
+++ b/app/src/main/res/layout/item_counter.xml
@@ -49,4 +49,15 @@
android:layout_alignLeft="@id/title"
android:layout_below="@id/title"
android:layout_height="wrap_content" />
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_cycle_list.xml b/app/src/main/res/layout/item_cycle_list.xml
index 5444df08..ea760f34 100644
--- a/app/src/main/res/layout/item_cycle_list.xml
+++ b/app/src/main/res/layout/item_cycle_list.xml
@@ -1,5 +1,5 @@
-
-
-
+
-
+
-
+
-
+
-
-
+
+
-
-
-
-
+ android:paddingRight="2sp"
+ android:layout_below="@id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
-
-
\ No newline at end of file
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_day_repeatable_checkbox.xml b/app/src/main/res/layout/item_day_repeatable_checkbox.xml
index fd0ed243..10671261 100644
--- a/app/src/main/res/layout/item_day_repeatable_checkbox.xml
+++ b/app/src/main/res/layout/item_day_repeatable_checkbox.xml
@@ -17,7 +17,7 @@
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- tools:text="Simple Checkbox (Day repeatable)"
+ tools:text="Simple Checkbox (Day repeatable) 1 1 1 1 1 1 "
android:textSize="19sp"
android:layout_toStartOf="@id/image"
android:layout_toEndOf="@id/checkbox"
@@ -29,6 +29,19 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
- android:src="@android:drawable/ic_menu_rotate"
+ android:layout_marginEnd="2sp"
+ android:layout_marginTop="2sp"
+ android:src="@drawable/repeat_24px"
android:contentDescription="@string/item_dayRepeatableCheckbox" />
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_editor_fragment_module_item_notification.xml b/app/src/main/res/layout/item_editor_fragment_module_item_notification.xml
new file mode 100644
index 00000000..4cde63bb
--- /dev/null
+++ b/app/src/main/res/layout/item_editor_fragment_module_item_notification.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_filter_group.xml b/app/src/main/res/layout/item_filter_group.xml
index 850b46ca..bde323c9 100644
--- a/app/src/main/res/layout/item_filter_group.xml
+++ b/app/src/main/res/layout/item_filter_group.xml
@@ -15,9 +15,20 @@
android:layout_alignBaseline="@id/externalEditor"
android:textColor="?attr/item_filterGroup_textColor"
android:layout_width="match_parent"
- android:layout_toStartOf="@id/externalEditor"
+ android:layout_toStartOf="@id/indicatorNotification"
android:layout_height="wrap_content" />
+
+
+
+ android:paddingLeft="3sp"
+ android:paddingRight="2sp"
+ android:paddingBottom="5sp"
+ android:paddingTop="2sp" />
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_group.xml b/app/src/main/res/layout/item_group.xml
index dbef6146..e782ae1f 100644
--- a/app/src/main/res/layout/item_group.xml
+++ b/app/src/main/res/layout/item_group.xml
@@ -14,9 +14,19 @@
android:layout_alignBaseline="@id/externalEditor"
android:textColor="?attr/item_group_textColor"
android:layout_width="match_parent"
- android:layout_toStartOf="@id/externalEditor"
+ android:layout_toStartOf="@id/indicatorNotification"
android:layout_height="wrap_content" />
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_longtext.xml b/app/src/main/res/layout/item_longtext.xml
index 663e7bd7..f2185266 100644
--- a/app/src/main/res/layout/item_longtext.xml
+++ b/app/src/main/res/layout/item_longtext.xml
@@ -12,6 +12,7 @@
android:layout_height="wrap_content"
tools:text="Simple text"
android:textSize="19sp"
+ android:layout_toStartOf="@id/indicatorNotification"
android:textColor="?attr/item_text_textColor"
android:paddingLeft="5sp" />
@@ -25,4 +26,14 @@
android:textColor="?attr/item_text_textColor"
android:paddingLeft="5sp" />
+
+
diff --git a/app/src/main/res/layout/item_math_game.xml b/app/src/main/res/layout/item_math_game.xml
index d649c5c3..fb9a7f8e 100644
--- a/app/src/main/res/layout/item_math_game.xml
+++ b/app/src/main/res/layout/item_math_game.xml
@@ -12,6 +12,7 @@
android:layout_height="wrap_content"
tools:text="Simple text"
android:textSize="19sp"
+ android:layout_toStartOf="@id/indicatorNotification"
android:textColor="?attr/item_text_textColor"
android:paddingLeft="5sp" />
@@ -31,6 +32,8 @@
android:id="@+id/userEnterNumber"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:background="@drawable/shape"
+ android:paddingStart="2sp"
tools:text="111"
android:layout_toEndOf="@id/questText"
android:textSize="20sp"
@@ -164,4 +167,14 @@
+
+
diff --git a/app/src/main/res/layout/item_sleep_time.xml b/app/src/main/res/layout/item_sleep_time.xml
index dc713c46..1c9256e6 100644
--- a/app/src/main/res/layout/item_sleep_time.xml
+++ b/app/src/main/res/layout/item_sleep_time.xml
@@ -1,5 +1,5 @@
-
@@ -22,7 +23,18 @@
android:layout_height="wrap_content"
tools:text="Simple text"
android:textSize="17sp"
+ android:layout_below="@id/title"
android:textColor="?attr/item_text_textColor"
android:paddingLeft="3sp" />
-
\ No newline at end of file
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_text.xml b/app/src/main/res/layout/item_text.xml
index a7121b19..da465d68 100644
--- a/app/src/main/res/layout/item_text.xml
+++ b/app/src/main/res/layout/item_text.xml
@@ -1,10 +1,20 @@
-
+
+
-
+
+
+
diff --git a/app/src/main/res/layout/items_storage_empty.xml b/app/src/main/res/layout/items_storage_empty.xml
index 7d5ff749..58a2812a 100644
--- a/app/src/main/res/layout/items_storage_empty.xml
+++ b/app/src/main/res/layout/items_storage_empty.xml
@@ -1,7 +1,8 @@
+ android:layout_height="match_parent"
+ android:padding="20sp">
+ android:textSize="30.6sp" />
+ android:layout_height="170sp" />
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/toolbar_more_items_item.xml b/app/src/main/res/layout/toolbar_more_items_item.xml
index 3f77921c..772ab776 100644
--- a/app/src/main/res/layout/toolbar_more_items_item.xml
+++ b/app/src/main/res/layout/toolbar_more_items_item.xml
@@ -6,21 +6,30 @@
-
@@ -18,14 +19,14 @@
android:layout_height="wrap_content"
android:orientation="horizontal">
-
-
-
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_item.xml b/app/src/main/res/menu/menu_item.xml
index 94b40a67..a6903f10 100644
--- a/app/src/main/res/menu/menu_item.xml
+++ b/app/src/main/res/menu/menu_item.xml
@@ -2,35 +2,39 @@