Compare commits
149 Commits
v2.1.0
...
v2.3.3-pat
Author | SHA1 | Date | |
---|---|---|---|
fb3f28d035 | |||
d8e204c5d9 | |||
388653f62b | |||
5763a18421 | |||
5dcf0afe02 | |||
94b1eec757 | |||
c5b41d0886 | |||
4e5bf62e23 | |||
77864cbef4 | |||
32c580bac7 | |||
85fa0cae11 | |||
05f2a745c2 | |||
ef2e89b6ff | |||
a306d92282 | |||
da9fc362af | |||
ff83cfd953 | |||
5d9dcd9701 | |||
183901534c | |||
6d7d90e762 | |||
e89b377b68 | |||
e0eb6f77da | |||
43c08204c3 | |||
6f125573e0 | |||
380dc96c40 | |||
821980e938 | |||
9f47d626a9 | |||
d3b623cf13 | |||
1389ddbfc0 | |||
0dbbe0e5d2 | |||
818b4ec0ba | |||
8c84913cd8 | |||
43f085b13c | |||
3ab42fd163 | |||
ea0be72478 | |||
c744d3c7f8 | |||
7b93548b0b | |||
260e36b305 | |||
00af2159ea | |||
c26021de03 | |||
218dae8cc2 | |||
b3e2d8d843 | |||
80d1077dab | |||
dd2a74aaf6 | |||
fb1953d513 | |||
b081b9adbb | |||
fd398faf42 | |||
e14662c534 | |||
4224562512 | |||
f13d426831 | |||
5dc7a1b30d | |||
6538cdebc2 | |||
78709ed018 | |||
c0e87047c2 | |||
1a2c97d61f | |||
4335751749 | |||
9bbc816bea | |||
e8a6743dc4 | |||
5d8ceb98cc | |||
dfff4c5e1b | |||
13f8814480 | |||
8608f9adf3 | |||
ad65cf0e84 | |||
1ecaf7a11a | |||
2578566659 | |||
61fc0da8d0 | |||
285b754dd5 | |||
194a2ab456 | |||
bca22d5aa8 | |||
35536a89a0 | |||
6780a470e9 | |||
6ca6b5ab95 | |||
7edb0635a7 | |||
d72ddd6d85 | |||
5d07cc8d73 | |||
1ac53e09a8 | |||
3412e044df | |||
80023da430 | |||
e2a2d17506 | |||
b93443b736 | |||
9842ba3ea9 | |||
75aba66987 | |||
f325af26f8 | |||
b61fbd193c | |||
03d9446369 | |||
23f94e63c6 | |||
01775d3a3a | |||
67abd14bb1 | |||
854cfac28c | |||
8fafe591e8 | |||
a85fefe4dc | |||
974185a89b | |||
bbe1497f8b | |||
1f22426dec | |||
40644f3657 | |||
a01c8eff63 | |||
1ee25bcc89 | |||
1bd18ac486 | |||
d24ac198a4 | |||
81578f5f4a | |||
8234a87a2a | |||
0774c6bdbe | |||
57eecd630d | |||
cce86a970c | |||
6ea40a51fe | |||
1721dff3cf | |||
c389d50b09 | |||
0ea55db4b1 | |||
3fba50fd2c | |||
06583197c7 | |||
5176331e84 | |||
65f83caeb5 | |||
60e8c267bf | |||
10a3204808 | |||
98c509ef27 | |||
ab1df499af | |||
ed9a4042c8 | |||
a102776214 | |||
0778ad4df5 | |||
8dce8a74b3 | |||
24bb811f93 | |||
0500e8d8e8 | |||
d2087d094f | |||
34fb35f2ab | |||
108ecdece0 | |||
e3f4995e93 | |||
0cdc5a3c6d | |||
9f039eec3c | |||
e9effbe799 | |||
889783bb4e | |||
d32f680519 | |||
c1d14f93bf | |||
b903fff10f | |||
20c5ce61b4 | |||
5bb81772f4 | |||
526a9ac6ac | |||
98db1380b7 | |||
ce9b343e0e | |||
21ec3c3f5d | |||
88950a84b4 | |||
fb853975e0 | |||
329eee6339 | |||
c595168320 | |||
61e3e43fd7 | |||
1513b96313 | |||
1cc5558d9e | |||
e12e908496 | |||
2aed9e3b25 | |||
536ed64d41 | |||
6b6ec633ee |
3
.gitignore
vendored
3
.gitignore
vendored
@ -9,3 +9,6 @@
|
|||||||
/tasksintegration/build
|
/tasksintegration/build
|
||||||
/app/google-services.json
|
/app/google-services.json
|
||||||
apikey.properties
|
apikey.properties
|
||||||
|
./.idea/*
|
||||||
|
app/release/*
|
||||||
|
/app/release/*
|
180
.idea/assetWizardSettings.xml
generated
180
.idea/assetWizardSettings.xml
generated
@ -19,6 +19,29 @@
|
|||||||
<option name="children">
|
<option name="children">
|
||||||
<map>
|
<map>
|
||||||
<entry key="clipArt">
|
<entry key="clipArt">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
<entry key="imagePath" value="/private/var/folders/cw/tkrg0g5j6lzcqwr0tfkph8w80000gn/T/ic_android_black_24dp.xml" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="text">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="textAsset">
|
||||||
<value>
|
<value>
|
||||||
<PersistentState>
|
<PersistentState>
|
||||||
<option name="values">
|
<option name="values">
|
||||||
@ -45,14 +68,47 @@
|
|||||||
<PersistentState>
|
<PersistentState>
|
||||||
<option name="children">
|
<option name="children">
|
||||||
<map>
|
<map>
|
||||||
|
<entry key="foregroundClipArt">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="imagePath" value="/private/var/folders/cw/tkrg0g5j6lzcqwr0tfkph8w80000gn/T/ic_android_black_24dp.xml" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
<entry key="foregroundImage">
|
<entry key="foregroundImage">
|
||||||
<value>
|
<value>
|
||||||
<PersistentState>
|
<PersistentState>
|
||||||
<option name="values">
|
<option name="values">
|
||||||
<map>
|
<map>
|
||||||
<entry key="color" value="000000" />
|
<entry key="color" value="000000" />
|
||||||
|
<entry key="imagePath" value="$USER_HOME$/Desktop/logo-white.png" />
|
||||||
<entry key="scalingPercent" value="70" />
|
<entry key="scalingPercent" value="70" />
|
||||||
<entry key="trimmed" value="true" />
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="foregroundText">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="foregroundTextAsset">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
</map>
|
</map>
|
||||||
</option>
|
</option>
|
||||||
</PersistentState>
|
</PersistentState>
|
||||||
@ -64,7 +120,6 @@
|
|||||||
<map>
|
<map>
|
||||||
<entry key="backgroundAssetType" value="COLOR" />
|
<entry key="backgroundAssetType" value="COLOR" />
|
||||||
<entry key="backgroundColor" value="ffffff" />
|
<entry key="backgroundColor" value="ffffff" />
|
||||||
<entry key="foregroundImage" value="$USER_HOME$/Desktop/Artboard Copy 3.png" />
|
|
||||||
<entry key="legacyIconShape" value="CIRCLE" />
|
<entry key="legacyIconShape" value="CIRCLE" />
|
||||||
</map>
|
</map>
|
||||||
</option>
|
</option>
|
||||||
@ -77,6 +132,29 @@
|
|||||||
<option name="children">
|
<option name="children">
|
||||||
<map>
|
<map>
|
||||||
<entry key="clipArt">
|
<entry key="clipArt">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
<entry key="imagePath" value="/private/var/folders/cw/tkrg0g5j6lzcqwr0tfkph8w80000gn/T/ic_android_black_24dp.xml" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="text">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="textAsset">
|
||||||
<value>
|
<value>
|
||||||
<PersistentState>
|
<PersistentState>
|
||||||
<option name="values">
|
<option name="values">
|
||||||
@ -98,6 +176,104 @@
|
|||||||
<option name="children">
|
<option name="children">
|
||||||
<map>
|
<map>
|
||||||
<entry key="clipArt">
|
<entry key="clipArt">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
<entry key="imagePath" value="/private/var/folders/cw/tkrg0g5j6lzcqwr0tfkph8w80000gn/T/ic_android_black_24dp.xml" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="text">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="textAsset">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="tvBanner">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="children">
|
||||||
|
<map>
|
||||||
|
<entry key="foregroundText">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="tvChannel">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="children">
|
||||||
|
<map>
|
||||||
|
<entry key="foregroundClipArt">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="imagePath" value="/private/var/folders/cw/tkrg0g5j6lzcqwr0tfkph8w80000gn/T/ic_android_black_24dp.xml" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="foregroundImage">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="foregroundText">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="color" value="000000" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="foregroundTextAsset">
|
||||||
<value>
|
<value>
|
||||||
<PersistentState>
|
<PersistentState>
|
||||||
<option name="values">
|
<option name="values">
|
||||||
|
BIN
.idea/caches/build_file_checksums.ser
generated
BIN
.idea/caches/build_file_checksums.ser
generated
Binary file not shown.
1
.idea/codeStyles/Project.xml
generated
1
.idea/codeStyles/Project.xml
generated
@ -17,7 +17,6 @@
|
|||||||
<package name="" alias="true" withSubpackages="true" />
|
<package name="" alias="true" withSubpackages="true" />
|
||||||
</value>
|
</value>
|
||||||
</option>
|
</option>
|
||||||
<option name="ALLOW_TRAILING_COMMA" value="true" />
|
|
||||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
</JetCodeStyleSettings>
|
</JetCodeStyleSettings>
|
||||||
<codeStyleSettings language="XML">
|
<codeStyleSettings language="XML">
|
||||||
|
3
.idea/gradle.xml
generated
3
.idea/gradle.xml
generated
@ -4,7 +4,7 @@
|
|||||||
<component name="GradleSettings">
|
<component name="GradleSettings">
|
||||||
<option name="linkedExternalProjectsSettings">
|
<option name="linkedExternalProjectsSettings">
|
||||||
<GradleProjectSettings>
|
<GradleProjectSettings>
|
||||||
<option name="testRunner" value="PLATFORM" />
|
<option name="testRunner" value="GRADLE" />
|
||||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
<option name="modules">
|
<option name="modules">
|
||||||
@ -14,7 +14,6 @@
|
|||||||
</set>
|
</set>
|
||||||
</option>
|
</option>
|
||||||
<option name="resolveModulePerSourceSet" value="false" />
|
<option name="resolveModulePerSourceSet" value="false" />
|
||||||
<option name="useQualifiedModuleNames" value="true" />
|
|
||||||
</GradleProjectSettings>
|
</GradleProjectSettings>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
140
.idea/navEditor.xml
generated
140
.idea/navEditor.xml
generated
@ -46,6 +46,146 @@
|
|||||||
</LayoutPositions>
|
</LayoutPositions>
|
||||||
</value>
|
</value>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry key="settings_nav_graph.xml">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions>
|
||||||
|
<option name="myPositions">
|
||||||
|
<map>
|
||||||
|
<entry key="calendarTabFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions>
|
||||||
|
<option name="myPosition">
|
||||||
|
<Point>
|
||||||
|
<option name="x" value="190" />
|
||||||
|
<option name="y" value="4" />
|
||||||
|
</Point>
|
||||||
|
</option>
|
||||||
|
</LayoutPositions>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="clockTabFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions>
|
||||||
|
<option name="myPosition">
|
||||||
|
<Point>
|
||||||
|
<option name="x" value="494" />
|
||||||
|
<option name="y" value="302" />
|
||||||
|
</Point>
|
||||||
|
</option>
|
||||||
|
</LayoutPositions>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="generalTabFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions>
|
||||||
|
<option name="myPosition">
|
||||||
|
<Point>
|
||||||
|
<option name="x" value="-48" />
|
||||||
|
<option name="y" value="133" />
|
||||||
|
</Point>
|
||||||
|
</option>
|
||||||
|
</LayoutPositions>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="gesturesFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions>
|
||||||
|
<option name="myPosition">
|
||||||
|
<Point>
|
||||||
|
<option name="x" value="703" />
|
||||||
|
<option name="y" value="14" />
|
||||||
|
</Point>
|
||||||
|
</option>
|
||||||
|
</LayoutPositions>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="glanceTabFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions>
|
||||||
|
<option name="myPosition">
|
||||||
|
<Point>
|
||||||
|
<option name="x" value="2" />
|
||||||
|
<option name="y" value="-198" />
|
||||||
|
</Point>
|
||||||
|
</option>
|
||||||
|
</LayoutPositions>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="tabSelectorFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions>
|
||||||
|
<option name="myPosition">
|
||||||
|
<Point>
|
||||||
|
<option name="x" value="-537" />
|
||||||
|
<option name="y" value="216" />
|
||||||
|
</Point>
|
||||||
|
</option>
|
||||||
|
<option name="myPositions">
|
||||||
|
<map>
|
||||||
|
<entry key="action_tabSelectorFragment_to_calendarTabFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions />
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="action_tabSelectorFragment_to_clockTabFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions />
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="action_tabSelectorFragment_to_generalTabFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions />
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="action_tabSelectorFragment_to_glanceTabFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions />
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="action_tabSelectorFragment_to_typographyTabFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions />
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="action_tabSelectorFragment_to_weatherTabFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions />
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</LayoutPositions>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="typographyTabFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions>
|
||||||
|
<option name="myPosition">
|
||||||
|
<Point>
|
||||||
|
<option name="x" value="470" />
|
||||||
|
<option name="y" value="-207" />
|
||||||
|
</Point>
|
||||||
|
</option>
|
||||||
|
</LayoutPositions>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="weatherTabFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions>
|
||||||
|
<option name="myPosition">
|
||||||
|
<Point>
|
||||||
|
<option name="x" value="-301" />
|
||||||
|
<option name="y" value="-160" />
|
||||||
|
</Point>
|
||||||
|
</option>
|
||||||
|
</LayoutPositions>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</LayoutPositions>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
</map>
|
</map>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
12
.idea/runConfigurations.xml
generated
12
.idea/runConfigurations.xml
generated
@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="RunConfigurationProducerService">
|
|
||||||
<option name="ignoredProducers">
|
|
||||||
<set>
|
|
||||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
|
|
||||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
|
|
||||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
|
|
||||||
</set>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -6,9 +6,6 @@ apply plugin: 'com.google.firebase.crashlytics'
|
|||||||
|
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-kapt'
|
apply plugin: 'kotlin-kapt'
|
||||||
apply plugin: 'kotlin-android-extensions'
|
|
||||||
|
|
||||||
apply plugin: 'realm-android'
|
|
||||||
|
|
||||||
def apikeyPropertiesFile = rootProject.file("apikey.properties")
|
def apikeyPropertiesFile = rootProject.file("apikey.properties")
|
||||||
def apikeyProperties = new Properties()
|
def apikeyProperties = new Properties()
|
||||||
@ -17,14 +14,13 @@ apikeyProperties.load(new FileInputStream(apikeyPropertiesFile))
|
|||||||
android {
|
android {
|
||||||
|
|
||||||
compileSdkVersion 30
|
compileSdkVersion 30
|
||||||
buildToolsVersion "29.0.3"
|
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.tommasoberlose.anotherwidget"
|
applicationId "com.tommasoberlose.anotherwidget"
|
||||||
minSdkVersion 23
|
minSdkVersion 23
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
versionCode 114
|
versionCode 139
|
||||||
versionName "2.1.0"
|
versionName "2.3.3"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
buildConfigField("String", "GOOGLE_API_KEY", apikeyProperties['GOOGLE_API_KEY'])
|
buildConfigField("String", "GOOGLE_API_KEY", apikeyProperties['GOOGLE_API_KEY'])
|
||||||
@ -55,70 +51,75 @@ android {
|
|||||||
packagingOptions {
|
packagingOptions {
|
||||||
exclude 'META-INF/DEPENDENCIES'
|
exclude 'META-INF/DEPENDENCIES'
|
||||||
}
|
}
|
||||||
dataBinding {
|
|
||||||
enabled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
viewBinding.enabled = true
|
buildFeatures {
|
||||||
|
dataBinding = true
|
||||||
|
viewBinding = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||||
testImplementation 'junit:junit:4.13.1'
|
testImplementation 'junit:junit:4.13.2'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
implementation 'androidx.appcompat:appcompat:1.3.0'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||||
implementation 'com.google.android.material:material:1.3.0-beta01'
|
implementation 'com.google.android.material:material:1.3.0'
|
||||||
implementation 'androidx.browser:browser:1.3.0'
|
implementation 'androidx.browser:browser:1.3.0'
|
||||||
implementation 'net.idik:slimadapter:2.1.2'
|
implementation 'net.idik:slimadapter:2.1.2'
|
||||||
implementation 'com.google.android:flexbox:2.0.1'
|
implementation 'com.google.android:flexbox:2.0.1'
|
||||||
|
implementation 'com.kyleduo.switchbutton:library:2.0.3'
|
||||||
|
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
|
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
|
||||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||||
|
|
||||||
implementation "androidx.work:work-runtime-ktx:2.4.0"
|
implementation "androidx.work:work-runtime-ktx:2.5.0"
|
||||||
|
|
||||||
// EventBus
|
// EventBus
|
||||||
implementation 'org.greenrobot:eventbus:3.2.0'
|
implementation 'org.greenrobot:eventbus:3.2.0'
|
||||||
|
|
||||||
|
// Room
|
||||||
|
implementation "androidx.room:room-runtime:2.3.0"
|
||||||
|
kapt "androidx.room:room-compiler:2.3.0"
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.2'
|
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
|
||||||
implementation 'androidx.navigation:navigation-ui-ktx:2.3.2'
|
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
implementation 'androidx.multidex:multidex:2.0.1'
|
implementation 'androidx.multidex:multidex:2.0.1'
|
||||||
implementation 'joda-time:joda-time:2.10.6'
|
implementation 'net.danlew:android.joda:2.10.9'
|
||||||
implementation 'me.everything:providers-android:1.0.1'
|
implementation 'me.everything:providers-android:1.0.1'
|
||||||
implementation 'com.github.warkiz.widget:indicatorseekbar:2.1.2'
|
implementation 'com.github.warkiz.widget:indicatorseekbar:2.1.2'
|
||||||
|
|
||||||
//Glide
|
//Glide
|
||||||
implementation 'com.github.bumptech.glide:glide:4.11.0'
|
implementation 'com.github.bumptech.glide:glide:4.12.0'
|
||||||
kapt 'com.github.bumptech.glide:compiler:4.11.0'
|
kapt 'com.github.bumptech.glide:compiler:4.11.0'
|
||||||
|
|
||||||
// Fitness
|
// Fitness
|
||||||
implementation 'com.google.android.gms:play-services-fitness:20.0.0'
|
implementation 'com.google.android.gms:play-services-fitness:20.0.0'
|
||||||
implementation 'com.google.android.gms:play-services-auth:18.1.0'
|
implementation 'com.google.android.gms:play-services-auth:19.0.0'
|
||||||
|
|
||||||
//Weather
|
//Weather
|
||||||
implementation 'com.github.KwabenBerko:OpenWeatherMap-Android-Library:2.0.2'
|
implementation 'com.github.KwabenBerko:OpenWeatherMap-Android-Library:2.0.2'
|
||||||
implementation 'com.google.android.gms:play-services-location:17.1.0'
|
implementation 'com.google.android.gms:play-services-location:18.0.0'
|
||||||
|
|
||||||
// Billing
|
// Billing
|
||||||
implementation 'com.android.billingclient:billing:3.0.2'
|
implementation 'com.android.billingclient:billing:3.0.3'
|
||||||
implementation 'com.android.billingclient:billing-ktx:3.0.2'
|
implementation 'com.android.billingclient:billing-ktx:3.0.3'
|
||||||
|
|
||||||
// KTX
|
// KTX
|
||||||
implementation "androidx.core:core-ktx:1.3.2"
|
implementation "androidx.core:core-ktx:1.5.0"
|
||||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
|
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1"
|
||||||
implementation "androidx.palette:palette-ktx:1.0.0"
|
implementation "androidx.palette:palette-ktx:1.0.0"
|
||||||
implementation 'androidx.core:core-ktx:1.3.2'
|
implementation 'androidx.core:core-ktx:1.5.0'
|
||||||
|
|
||||||
//Retrofit
|
//Retrofit
|
||||||
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
||||||
@ -128,14 +129,14 @@ dependencies {
|
|||||||
implementation "com.github.haroldadmin:NetworkResponseAdapter:4.0.1"
|
implementation "com.github.haroldadmin:NetworkResponseAdapter:4.0.1"
|
||||||
|
|
||||||
//Coroutines
|
//Coroutines
|
||||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'
|
||||||
|
|
||||||
// Add the Firebase SDK for Crashlytics.
|
// Add the Firebase SDK for Crashlytics.
|
||||||
implementation 'com.google.firebase:firebase-crashlytics:17.3.0'
|
implementation 'com.google.firebase:firebase-crashlytics:18.0.0'
|
||||||
|
|
||||||
// Preferences
|
// Preferences
|
||||||
implementation 'com.chibatching.kotpref:kotpref:2.11.0'
|
implementation 'com.chibatching.kotpref:kotpref:2.13.1'
|
||||||
implementation 'com.chibatching.kotpref:livedata-support:2.10.0'
|
implementation 'com.chibatching.kotpref:livedata-support:2.13.1'
|
||||||
implementation 'androidx.preference:preference-ktx:1.1.1'
|
implementation 'androidx.preference:preference-ktx:1.1.1'
|
||||||
|
|
||||||
// Permissions
|
// Permissions
|
||||||
|
Binary file not shown.
@ -6,14 +6,15 @@
|
|||||||
<uses-permission android:name="android.permission.READ_CALENDAR" />
|
<uses-permission android:name="android.permission.READ_CALENDAR" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
<uses-permission android:name="com.android.vending.BILLING" />
|
<uses-permission android:name="com.android.vending.BILLING" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
|
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
|
||||||
<uses-permission android:name="android.gms.permission.ACTIVITY_RECOGNITION"/>
|
<uses-permission android:name="android.gms.permission.ACTIVITY_RECOGNITION"/>
|
||||||
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
|
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
|
||||||
|
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
@ -25,29 +26,29 @@
|
|||||||
android:usesCleartextTraffic="true"
|
android:usesCleartextTraffic="true"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
tools:ignore="LockedOrientationActivity">
|
tools:ignore="LockedOrientationActivity">
|
||||||
<activity android:name=".ui.activities.MainActivity" android:launchMode="singleInstance" android:theme="@style/AppTheme.Main" android:screenOrientation="portrait">
|
<activity android:name=".ui.activities.SplashActivity" android:exported="true" android:theme="@style/AppTheme.Main" android:screenOrientation="portrait">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".ui.activities.ChooseApplicationActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.MainActivity" android:theme="@style/AppTheme" android:screenOrientation="portrait" />
|
||||||
<activity android:name=".ui.activities.CustomFontActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.tabs.ChooseApplicationActivity" android:screenOrientation="portrait" />
|
||||||
<activity android:name=".ui.activities.CustomLocationActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.tabs.CustomFontActivity" android:screenOrientation="portrait" />
|
||||||
<activity android:name=".ui.activities.WeatherProviderActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.tabs.CustomLocationActivity" android:screenOrientation="portrait" />
|
||||||
<activity android:name=".ui.activities.SupportDevActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.tabs.WeatherProviderActivity" android:screenOrientation="portrait" />
|
||||||
<activity android:name=".ui.activities.CustomDateActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.settings.SupportDevActivity" android:screenOrientation="portrait" />
|
||||||
<activity android:name=".ui.activities.IntegrationsActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.tabs.CustomDateActivity" android:screenOrientation="portrait" />
|
||||||
<activity android:name=".ui.activities.MusicPlayersFilterActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.settings.IntegrationsActivity" android:screenOrientation="portrait" />
|
||||||
<activity android:name=".ui.activities.AppNotificationsFilterActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.tabs.MusicPlayersFilterActivity" android:screenOrientation="portrait" />
|
||||||
|
<activity android:name=".ui.activities.tabs.AppNotificationsFilterActivity" android:screenOrientation="portrait" />
|
||||||
|
<activity android:name=".ui.activities.tabs.MediaInfoFormatActivity" android:screenOrientation="portrait" />
|
||||||
|
<activity android:name=".ui.activities.tabs.TimeZoneSelectorActivity" android:screenOrientation="portrait" />
|
||||||
|
|
||||||
|
<receiver android:name=".ui.widgets.MainWidget" android:exported="true">
|
||||||
<receiver android:name=".ui.widgets.MainWidget">
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.appwidget.provider"
|
android:name="android.appwidget.provider"
|
||||||
android:resource="@xml/the_widget_info" />
|
android:resource="@xml/the_widget_info" />
|
||||||
@ -73,8 +74,8 @@
|
|||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
<action android:name="com.tommasoberlose.anotherwidget.action.ACTION_CALENDAR_UPDATE" />
|
<action android:name="com.tommasoberlose.anotherwidget.action.CALENDAR_UPDATE" />
|
||||||
<action android:name="com.tommasoberlose.anotherwidget.action.ACTION_TIME_UPDATE" />
|
<action android:name="com.tommasoberlose.anotherwidget.action.TIME_UPDATE" />
|
||||||
<action android:name="com.sec.android.widgetapp.APPWIDGET_RESIZE" />
|
<action android:name="com.sec.android.widgetapp.APPWIDGET_RESIZE" />
|
||||||
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||||
<action android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
|
<action android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
|
||||||
@ -89,8 +90,7 @@
|
|||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="com.tommasoberlose.anotherwidget.action.ACTION_WEATHER_UPDATE" />
|
<action android:name="com.tommasoberlose.anotherwidget.action.WEATHER_UPDATE" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
<action android:name="android.intent.action.TIME_SET" />
|
<action android:name="android.intent.action.TIME_SET" />
|
||||||
@ -102,26 +102,13 @@
|
|||||||
<receiver
|
<receiver
|
||||||
android:name=".receivers.WidgetClickListenerReceiver"
|
android:name=".receivers.WidgetClickListenerReceiver"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="false">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="com.tommasoberlose.anotherwidget.action.ACTION_OPEN_WEATHER_INTENT" />
|
<action android:name="com.tommasoberlose.anotherwidget.action.OPEN_WEATHER_INTENT" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<receiver
|
<service android:name=".receivers.NotificationListener" android:exported="true"
|
||||||
android:name=".receivers.CrashlyticsReceiver"
|
|
||||||
android:enabled="true"
|
|
||||||
android:exported="false">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="com.tommasoberlose.anotherwidget.action.ACTION_REPORT_CRASH" />
|
|
||||||
</intent-filter>
|
|
||||||
</receiver>
|
|
||||||
|
|
||||||
<service android:name=".services.EventListenerJob" android:permission="android.permission.BIND_JOB_SERVICE" />
|
|
||||||
|
|
||||||
<service android:name=".services.BatteryListenerJob" android:permission="android.permission.BIND_JOB_SERVICE" />
|
|
||||||
|
|
||||||
<service android:name=".receivers.NotificationListener"
|
|
||||||
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
|
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.service.notification.NotificationListenerService" />
|
<action android:name="android.service.notification.NotificationListenerService" />
|
||||||
@ -141,7 +128,7 @@
|
|||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<receiver android:name=".receivers.ActivityDetectionReceiver"
|
<receiver android:name=".receivers.ActivityDetectionReceiver"
|
||||||
android:exported="false"
|
android:exported="true"
|
||||||
android:permission="com.google.android.gms.permission.ACTIVITY_RECOGNITION">
|
android:permission="com.google.android.gms.permission.ACTIVITY_RECOGNITION">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="com.mypackage.ACTION_PROCESS_ACTIVITY_TRANSITIONS" />
|
<action android:name="com.mypackage.ACTION_PROCESS_ACTIVITY_TRANSITIONS" />
|
||||||
@ -149,19 +136,12 @@
|
|||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<service
|
|
||||||
android:name=".services.UpdateCalendarJob"
|
|
||||||
android:permission="android.permission.BIND_JOB_SERVICE"
|
|
||||||
android:exported="true"/>
|
|
||||||
<service
|
|
||||||
android:name=".services.LocationService"
|
|
||||||
android:enabled="true"
|
|
||||||
android:exported="false"
|
|
||||||
android:foregroundServiceType="location" />
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
<queries>
|
<queries>
|
||||||
<package android:name="com.google.android.apps.fitness"/>
|
<package android:name="com.google.android.apps.fitness"/>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
</intent>
|
||||||
</queries>
|
</queries>
|
||||||
</manifest>
|
</manifest>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 44 KiB |
Binary file not shown.
Before Width: | Height: | Size: 45 KiB |
@ -1,13 +1,12 @@
|
|||||||
package com.tommasoberlose.anotherwidget
|
package com.tommasoberlose.anotherwidget
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import com.chibatching.kotpref.Kotpref
|
import com.chibatching.kotpref.Kotpref
|
||||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import io.realm.Realm
|
|
||||||
import io.realm.RealmConfiguration
|
|
||||||
|
|
||||||
class AWApplication : Application() {
|
class AWApplication : Application() {
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
@ -21,29 +20,5 @@ class AWApplication : Application() {
|
|||||||
|
|
||||||
// Dark theme
|
// Dark theme
|
||||||
AppCompatDelegate.setDefaultNightMode(Preferences.darkThemePreference)
|
AppCompatDelegate.setDefaultNightMode(Preferences.darkThemePreference)
|
||||||
|
|
||||||
// Realm
|
|
||||||
Realm.init(this)
|
|
||||||
val config = RealmConfiguration.Builder()
|
|
||||||
.deleteRealmIfMigrationNeeded()
|
|
||||||
.build()
|
|
||||||
Realm.setDefaultConfiguration(config)
|
|
||||||
|
|
||||||
calibrateVersions()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun calibrateVersions() {
|
|
||||||
// 2.0 Tolerance
|
|
||||||
if (Preferences.clockTextSize > 50f) {
|
|
||||||
Preferences.clockTextSize = 32f
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Preferences.textMainSize > 36f) {
|
|
||||||
Preferences.textMainSize = 32f
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Preferences.textSecondSize > 28f) {
|
|
||||||
Preferences.textSecondSize = 24f
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,41 +3,30 @@ package com.tommasoberlose.anotherwidget.components
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.text.Editable
|
import android.view.LayoutInflater
|
||||||
import android.text.TextWatcher
|
|
||||||
import android.util.Log
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.GridLayout
|
import android.widget.FrameLayout
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.SeekBar
|
|
||||||
import androidx.annotation.ColorInt
|
|
||||||
import androidx.appcompat.widget.AppCompatImageView
|
import androidx.appcompat.widget.AppCompatImageView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.widget.addTextChangedListener
|
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
import com.tommasoberlose.anotherwidget.databinding.BottomSheetMenuHorBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.BottomSheetMenuListBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.copyToClipboard
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isClipboardColor
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
|
||||||
import com.tommasoberlose.anotherwidget.utils.expand
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.pasteFromClipboard
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
||||||
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||||
import com.tommasoberlose.anotherwidget.utils.reveal
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.toPixel
|
|
||||||
import com.warkiz.widget.IndicatorSeekBar
|
import com.warkiz.widget.IndicatorSeekBar
|
||||||
import com.warkiz.widget.OnSeekChangeListener
|
import com.warkiz.widget.OnSeekChangeListener
|
||||||
import com.warkiz.widget.SeekParams
|
import com.warkiz.widget.SeekParams
|
||||||
import kotlinx.android.synthetic.main.bottom_sheet_menu_hor.*
|
|
||||||
import kotlinx.android.synthetic.main.bottom_sheet_menu_hor.view.*
|
|
||||||
import kotlinx.android.synthetic.main.bottom_sheet_menu_hor.view.color_loader
|
|
||||||
import kotlinx.android.synthetic.main.color_picker_menu_item.view.*
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import net.idik.lib.slimadapter.SlimAdapter
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
import java.lang.Exception
|
|
||||||
import java.util.prefs.Preferences
|
|
||||||
|
|
||||||
class BottomSheetColorPicker(
|
class BottomSheetColorPicker(
|
||||||
context: Context,
|
context: Context,
|
||||||
@ -47,32 +36,63 @@ class BottomSheetColorPicker(
|
|||||||
private val onColorSelected: ((selectedValue: Int) -> Unit)? = null,
|
private val onColorSelected: ((selectedValue: Int) -> Unit)? = null,
|
||||||
private val showAlphaSelector: Boolean = false,
|
private val showAlphaSelector: Boolean = false,
|
||||||
private val alpha: Int = 0,
|
private val alpha: Int = 0,
|
||||||
private val onAlphaChangeListener: ((alpha: Int) -> Unit)? = null
|
private val onAlphaChangeListener: ((alpha: Int) -> Unit)? = null,
|
||||||
|
private val hideCopyPaste: Boolean = false,
|
||||||
) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
||||||
|
|
||||||
private var loadingJobs: ArrayList<Job> = ArrayList()
|
private var loadingJobs: ArrayList<Job> = ArrayList()
|
||||||
private lateinit var adapter: SlimAdapter
|
private lateinit var adapter: SlimAdapter
|
||||||
|
private var alphaDebouncing: Job? = null
|
||||||
|
|
||||||
|
private var binding: BottomSheetMenuHorBinding = BottomSheetMenuHorBinding.inflate(LayoutInflater.from(context))
|
||||||
|
private var listBinding: BottomSheetMenuListBinding = BottomSheetMenuListBinding.inflate(LayoutInflater.from(context))
|
||||||
|
|
||||||
override fun show() {
|
override fun show() {
|
||||||
val view = View.inflate(context, R.layout.bottom_sheet_menu_hor, null)
|
|
||||||
|
|
||||||
window?.setDimAmount(0f)
|
window?.setDimAmount(0f)
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
view.header.isVisible = header != null
|
binding.header.isVisible = header != null
|
||||||
view.header_text.text = header ?: ""
|
binding.headerText.text = header ?: ""
|
||||||
|
|
||||||
|
if (hideCopyPaste) {
|
||||||
|
binding.actionContainer.isVisible = false
|
||||||
|
} else {
|
||||||
|
binding.actionContainer.isVisible = true
|
||||||
|
binding.actionCopy.setOnClickListener {
|
||||||
|
context.copyToClipboard(getSelected?.invoke(), alpha)
|
||||||
|
}
|
||||||
|
binding.actionPaste.setOnClickListener {
|
||||||
|
context.pasteFromClipboard { color, alpha ->
|
||||||
|
binding.alphaSelector.setProgress(alpha.toIntValue().toFloat())
|
||||||
|
|
||||||
|
adapter.notifyItemChanged(adapter.data.indexOf(getSelected?.invoke()))
|
||||||
|
onColorSelected?.invoke(Color.parseColor(color))
|
||||||
|
val idx = colors.toList().indexOf(getSelected?.invoke())
|
||||||
|
adapter.notifyItemChanged(idx)
|
||||||
|
(listBinding.root.layoutManager as GridLayoutManager).scrollToPositionWithOffset(idx,0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binding.actionPaste.isVisible = context.isClipboardColor()
|
||||||
|
}
|
||||||
|
|
||||||
// Alpha
|
// Alpha
|
||||||
view.alpha_selector_container.isVisible = showAlphaSelector
|
binding.alphaSelectorContainer.isVisible = showAlphaSelector
|
||||||
view.alpha_selector.setProgress(alpha.toFloat())
|
binding.alphaSelector.setProgress(alpha.toFloat())
|
||||||
view.text_alpha.text = "%s: %s%%".format(context.getString(R.string.alpha), alpha)
|
binding.textAlpha.text = "%s: %s%%".format(context.getString(R.string.alpha), alpha)
|
||||||
view.alpha_selector.onSeekChangeListener = object : OnSeekChangeListener {
|
binding.alphaSelector.onSeekChangeListener = object : OnSeekChangeListener {
|
||||||
override fun onSeeking(seekParams: SeekParams?) {
|
override fun onSeeking(seekParams: SeekParams?) {
|
||||||
seekParams?.let {
|
seekParams?.let {
|
||||||
view.text_alpha.text = "%s: %s%%".format(context.getString(R.string.alpha), it.progress)
|
binding.textAlpha.text =
|
||||||
|
"%s: %s%%".format(context.getString(R.string.alpha), it.progress)
|
||||||
|
alphaDebouncing?.cancel()
|
||||||
|
alphaDebouncing = GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
delay(150)
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
onAlphaChangeListener?.invoke(it.progress)
|
onAlphaChangeListener?.invoke(it.progress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
override fun onStartTrackingTouch(seekBar: IndicatorSeekBar?) {
|
override fun onStartTrackingTouch(seekBar: IndicatorSeekBar?) {
|
||||||
}
|
}
|
||||||
override fun onStopTrackingTouch(seekBar: IndicatorSeekBar?) {
|
override fun onStopTrackingTouch(seekBar: IndicatorSeekBar?) {
|
||||||
@ -80,14 +100,12 @@ class BottomSheetColorPicker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// List
|
// List
|
||||||
|
|
||||||
adapter = SlimAdapter.create()
|
adapter = SlimAdapter.create()
|
||||||
|
|
||||||
loadingJobs.add(GlobalScope.launch(Dispatchers.IO) {
|
loadingJobs.add(GlobalScope.launch(Dispatchers.IO) {
|
||||||
val listView = View.inflate(context, R.layout.bottom_sheet_menu_list, null) as RecyclerView
|
listBinding.root.setHasFixedSize(true)
|
||||||
listView.setHasFixedSize(true)
|
|
||||||
val mLayoutManager = GridLayoutManager(context, 6)
|
val mLayoutManager = GridLayoutManager(context, 6)
|
||||||
listView.layoutManager = mLayoutManager
|
listBinding.root.layoutManager = mLayoutManager
|
||||||
|
|
||||||
adapter
|
adapter
|
||||||
.register<Int>(R.layout.color_picker_menu_item) { item, injector ->
|
.register<Int>(R.layout.color_picker_menu_item) { item, injector ->
|
||||||
@ -115,22 +133,28 @@ class BottomSheetColorPicker(
|
|||||||
onColorSelected?.invoke(item)
|
onColorSelected?.invoke(item)
|
||||||
val position = adapter.data.indexOf(item)
|
val position = adapter.data.indexOf(item)
|
||||||
adapter.notifyItemChanged(position)
|
adapter.notifyItemChanged(position)
|
||||||
(listView.layoutManager as GridLayoutManager).scrollToPositionWithOffset(position,0)
|
(listBinding.root.layoutManager as GridLayoutManager).scrollToPositionWithOffset(position,0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.attachTo(listView)
|
.attachTo(listBinding.root)
|
||||||
|
|
||||||
adapter.updateData(colors.toList())
|
adapter.updateData(colors.toList())
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
view.color_loader.isVisible = false
|
binding.loader.isVisible = false
|
||||||
view.list_container.addView(listView)
|
binding.listContainer.addView(listBinding.root)
|
||||||
this@BottomSheetColorPicker.behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
binding.listContainer.isVisible = true
|
||||||
view.list_container.isVisible = true
|
|
||||||
|
val idx = colors.toList().indexOf(getSelected?.invoke())
|
||||||
|
(listBinding.root.layoutManager as GridLayoutManager).scrollToPositionWithOffset(idx,0)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
setContentView(view)
|
setContentView(binding.root)
|
||||||
|
behavior.run {
|
||||||
|
skipCollapsed = true
|
||||||
|
state = BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
}
|
||||||
super.show()
|
super.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
package com.tommasoberlose.anotherwidget.components
|
package com.tommasoberlose.anotherwidget.components
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import kotlinx.android.synthetic.main.bottom_sheet_menu.view.*
|
import com.tommasoberlose.anotherwidget.databinding.BottomSheetMenuBinding
|
||||||
import kotlinx.android.synthetic.main.bottom_sheet_menu_item.view.*
|
import com.tommasoberlose.anotherwidget.databinding.BottomSheetMenuItemBinding
|
||||||
import org.w3c.dom.Text
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [BottomSheetDialogFragment] that uses a custom
|
* [BottomSheetDialogFragment] that uses a custom
|
||||||
@ -24,6 +25,8 @@ open class BottomSheetMenu<T>(context: Context, private val header: String? = nu
|
|||||||
private var callback: ((selectedValue: T) -> Unit)? = null
|
private var callback: ((selectedValue: T) -> Unit)? = null
|
||||||
private var multipleSelectionCallback: ((selectedValues: ArrayList<T>) -> Unit)? = null
|
private var multipleSelectionCallback: ((selectedValues: ArrayList<T>) -> Unit)? = null
|
||||||
|
|
||||||
|
private var binding = BottomSheetMenuBinding.inflate(LayoutInflater.from(context))
|
||||||
|
|
||||||
fun setSelectedValue(res: T): BottomSheetMenu<T> {
|
fun setSelectedValue(res: T): BottomSheetMenu<T> {
|
||||||
selectedRes = ArrayList(listOf(res))
|
selectedRes = ArrayList(listOf(res))
|
||||||
return this
|
return this
|
||||||
@ -50,33 +53,31 @@ open class BottomSheetMenu<T>(context: Context, private val header: String? = nu
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun show() {
|
override fun show() {
|
||||||
val view = View.inflate(context, R.layout.bottom_sheet_menu, null)
|
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
view.header.isVisible = header != null
|
binding.header.isVisible = header != null
|
||||||
view.header_text.text = header ?: ""
|
binding.headerText.text = header ?: ""
|
||||||
|
|
||||||
view.warning_text.isVisible = message != null
|
binding.warningText.isVisible = message != null
|
||||||
view.warning_text.text = message ?: ""
|
binding.warningText.text = message ?: ""
|
||||||
view.warning_text.setTextColor(ContextCompat.getColor(context, if (isMessageWarning) R.color.warningColorText else R.color.colorSecondaryText))
|
binding.warningText.setTextColor(ContextCompat.getColor(context, if (isMessageWarning) R.color.warningColorText else R.color.colorSecondaryText))
|
||||||
|
|
||||||
// Menu
|
// Menu
|
||||||
for (item in items) {
|
for (item in items) {
|
||||||
|
val itemBinding = BottomSheetMenuItemBinding.inflate(LayoutInflater.from(context))
|
||||||
if (item.value != null) {
|
if (item.value != null) {
|
||||||
val itemView = View.inflate(context, R.layout.bottom_sheet_menu_item, null)
|
itemBinding.label.text = item.title
|
||||||
itemView.label.text = item.title
|
|
||||||
if (isMultiSelection) {
|
if (isMultiSelection) {
|
||||||
itemView.icon_check.isVisible = selectedRes.contains(item.value)
|
itemBinding.iconCheck.isVisible = selectedRes.contains(item.value)
|
||||||
itemView.label.setTextColor(
|
itemBinding.label.setTextColor(
|
||||||
if (selectedRes.contains(item.value)) ContextCompat.getColor(
|
if (selectedRes.contains(item.value)) ContextCompat.getColor(
|
||||||
context,
|
context,
|
||||||
R.color.colorPrimaryText
|
R.color.colorPrimaryText
|
||||||
) else ContextCompat.getColor(context, R.color.colorSecondaryText)
|
) else ContextCompat.getColor(context, R.color.colorSecondaryText)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
itemView.isSelected = selectedRes.contains(item.value)
|
itemBinding.root.isSelected = selectedRes.contains(item.value)
|
||||||
}
|
}
|
||||||
itemView.setOnClickListener {
|
itemBinding.root.setOnClickListener {
|
||||||
if (!isMultiSelection) {
|
if (!isMultiSelection) {
|
||||||
callback?.invoke(item.value)
|
callback?.invoke(item.value)
|
||||||
this.dismiss()
|
this.dismiss()
|
||||||
@ -88,8 +89,8 @@ open class BottomSheetMenu<T>(context: Context, private val header: String? = nu
|
|||||||
}
|
}
|
||||||
|
|
||||||
multipleSelectionCallback?.invoke(selectedRes)
|
multipleSelectionCallback?.invoke(selectedRes)
|
||||||
itemView.icon_check.isVisible = selectedRes.contains(item.value)
|
itemBinding.iconCheck.isVisible = selectedRes.contains(item.value)
|
||||||
itemView.label.setTextColor(
|
itemBinding.label.setTextColor(
|
||||||
if (selectedRes.contains(item.value)) ContextCompat.getColor(
|
if (selectedRes.contains(item.value)) ContextCompat.getColor(
|
||||||
context,
|
context,
|
||||||
R.color.colorPrimaryText
|
R.color.colorPrimaryText
|
||||||
@ -97,17 +98,20 @@ open class BottomSheetMenu<T>(context: Context, private val header: String? = nu
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
item.renderCallback?.invoke(itemView.label)
|
item.renderCallback?.invoke(itemBinding.label)
|
||||||
}
|
}
|
||||||
|
|
||||||
view.menu.addView(itemView)
|
binding.menu.addView(itemBinding.root)
|
||||||
} else {
|
} else {
|
||||||
val itemView = View.inflate(context, R.layout.bottom_sheet_menu_divider, null)
|
itemBinding.label.text = item.title
|
||||||
itemView.label.text = item.title
|
binding.menu.addView(itemBinding.root)
|
||||||
view.menu.addView(itemView)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setContentView(view)
|
setContentView(binding.root)
|
||||||
|
behavior.run {
|
||||||
|
skipCollapsed = true
|
||||||
|
state = com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
}
|
||||||
super.show()
|
super.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,111 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.components
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.appcompat.widget.AppCompatImageView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.google.android.material.card.MaterialCardView
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.BottomSheetMenuHorBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.BottomSheetMenuListBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.copyToClipboard
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isClipboardColor
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.pasteFromClipboard
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||||
|
import com.warkiz.widget.IndicatorSeekBar
|
||||||
|
import com.warkiz.widget.OnSeekChangeListener
|
||||||
|
import com.warkiz.widget.SeekParams
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
|
|
||||||
|
class BottomSheetPicker<T>(
|
||||||
|
context: Context,
|
||||||
|
private val items: List<MenuItem<T>> = arrayListOf(),
|
||||||
|
private val getSelected: (() -> T)? = null,
|
||||||
|
private val header: String? = null,
|
||||||
|
private val onItemSelected: ((selectedValue: T?) -> Unit)? = null,
|
||||||
|
) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
||||||
|
|
||||||
|
private var loadingJobs: ArrayList<Job> = ArrayList()
|
||||||
|
private lateinit var adapter: SlimAdapter
|
||||||
|
|
||||||
|
private var binding: BottomSheetMenuHorBinding = BottomSheetMenuHorBinding.inflate(
|
||||||
|
LayoutInflater.from(context))
|
||||||
|
private var listBinding: BottomSheetMenuListBinding = BottomSheetMenuListBinding.inflate(
|
||||||
|
LayoutInflater.from(context))
|
||||||
|
|
||||||
|
override fun show() {
|
||||||
|
window?.setDimAmount(0f)
|
||||||
|
|
||||||
|
// Header
|
||||||
|
binding.header.isVisible = header != null
|
||||||
|
binding.headerText.text = header ?: ""
|
||||||
|
|
||||||
|
// Alpha
|
||||||
|
binding.alphaSelectorContainer.isVisible = false
|
||||||
|
binding.actionContainer.isVisible = false
|
||||||
|
|
||||||
|
// List
|
||||||
|
adapter = SlimAdapter.create()
|
||||||
|
|
||||||
|
loadingJobs.add(GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
listBinding.root.setHasFixedSize(true)
|
||||||
|
val mLayoutManager = LinearLayoutManager(context)
|
||||||
|
listBinding.root.layoutManager = mLayoutManager
|
||||||
|
|
||||||
|
adapter
|
||||||
|
.register<Int>(R.layout.bottom_sheet_menu_item) { position, injector ->
|
||||||
|
val item = items[position]
|
||||||
|
val isSelected = item.value == getSelected?.invoke()
|
||||||
|
injector
|
||||||
|
.text(R.id.label, item.title)
|
||||||
|
.textColor(R.id.label, ContextCompat.getColor(context, if (isSelected) R.color.colorAccent else R.color.colorSecondaryText))
|
||||||
|
.selected(R.id.item, isSelected)
|
||||||
|
.clicked(R.id.item) {
|
||||||
|
val oldIdx = items.toList().indexOfFirst { it.value == getSelected?.invoke() }
|
||||||
|
onItemSelected?.invoke(item.value)
|
||||||
|
adapter.notifyItemChanged(position)
|
||||||
|
adapter.notifyItemChanged(oldIdx)
|
||||||
|
(listBinding.root.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(position,0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.attachTo(listBinding.root)
|
||||||
|
|
||||||
|
adapter.updateData((items.indices).toList())
|
||||||
|
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
binding.loader.isVisible = false
|
||||||
|
binding.listContainer.addView(listBinding.root)
|
||||||
|
binding.listContainer.isVisible = true
|
||||||
|
|
||||||
|
val idx = items.toList().indexOfFirst { it.value == getSelected?.invoke() }
|
||||||
|
(listBinding.root.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(idx,0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
setContentView(binding.root)
|
||||||
|
behavior.run {
|
||||||
|
skipCollapsed = true
|
||||||
|
state = BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
}
|
||||||
|
super.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
loadingJobs.forEach { it.cancel() }
|
||||||
|
super.onStop()
|
||||||
|
}
|
||||||
|
|
||||||
|
class MenuItem<T>(val title: String, val value: T? = null)
|
||||||
|
|
||||||
|
}
|
@ -5,32 +5,33 @@ import android.view.View
|
|||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.WeatherProviderSettingsLayoutBinding
|
||||||
import com.tommasoberlose.anotherwidget.global.Constants
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
||||||
import com.tommasoberlose.anotherwidget.utils.openURI
|
import com.tommasoberlose.anotherwidget.utils.openURI
|
||||||
import kotlinx.android.synthetic.main.weather_provider_settings_layout.view.*
|
|
||||||
|
|
||||||
class BottomSheetWeatherProviderSettings(context: Context, callback: () -> Unit) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
class BottomSheetWeatherProviderSettings(context: Context, callback: () -> Unit) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
||||||
|
|
||||||
|
private var binding: WeatherProviderSettingsLayoutBinding = WeatherProviderSettingsLayoutBinding.inflate(android.view.LayoutInflater.from(context))
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val view = View.inflate(context, R.layout.weather_provider_settings_layout, null)
|
binding.apiKeyContainer.isVisible = WeatherHelper.isKeyRequired()
|
||||||
view.api_key_container.isVisible = WeatherHelper.isKeyRequired()
|
binding.actionSaveKey.isVisible = WeatherHelper.isKeyRequired()
|
||||||
view.action_save_key.isVisible = WeatherHelper.isKeyRequired()
|
|
||||||
|
|
||||||
WeatherHelper.getProviderInfoTitle(context).let { title ->
|
WeatherHelper.getProviderInfoTitle(context).let { title ->
|
||||||
view.info_title.text = title
|
binding.infoTitle.text = title
|
||||||
view.info_title.isVisible = title != ""
|
binding.infoTitle.isVisible = title != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
WeatherHelper.getProviderInfoSubtitle(context).let { subtitle ->
|
WeatherHelper.getProviderInfoSubtitle(context).let { subtitle ->
|
||||||
view.info_subtitle.text = subtitle
|
binding.infoSubtitle.text = subtitle
|
||||||
view.info_subtitle.isVisible = subtitle != ""
|
binding.infoSubtitle.isVisible = subtitle != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
view.info_provider.text = WeatherHelper.getProviderName(context)
|
binding.infoProvider.text = WeatherHelper.getProviderName(context)
|
||||||
|
|
||||||
view.api_key.editText?.setText(when (Constants.WeatherProvider.fromInt(Preferences.weatherProvider)) {
|
binding.apiKey.editText?.setText(when (Constants.WeatherProvider.fromInt(Preferences.weatherProvider)) {
|
||||||
Constants.WeatherProvider.OPEN_WEATHER -> Preferences.weatherProviderApiOpen
|
Constants.WeatherProvider.OPEN_WEATHER -> Preferences.weatherProviderApiOpen
|
||||||
Constants.WeatherProvider.WEATHER_BIT -> Preferences.weatherProviderApiWeatherBit
|
Constants.WeatherProvider.WEATHER_BIT -> Preferences.weatherProviderApiWeatherBit
|
||||||
Constants.WeatherProvider.WEATHER_API -> Preferences.weatherProviderApiWeatherApi
|
Constants.WeatherProvider.WEATHER_API -> Preferences.weatherProviderApiWeatherApi
|
||||||
@ -41,12 +42,12 @@ class BottomSheetWeatherProviderSettings(context: Context, callback: () -> Unit)
|
|||||||
null -> ""
|
null -> ""
|
||||||
})
|
})
|
||||||
|
|
||||||
view.action_open_provider.setOnClickListener {
|
binding.actionOpenProvider.setOnClickListener {
|
||||||
context.openURI(WeatherHelper.getProviderLink())
|
context.openURI(WeatherHelper.getProviderLink())
|
||||||
}
|
}
|
||||||
|
|
||||||
view.action_save_key.setOnClickListener {
|
binding.actionSaveKey.setOnClickListener {
|
||||||
val key = view.api_key.editText?.text.toString()
|
val key = binding.apiKey.editText?.text.toString()
|
||||||
when (Constants.WeatherProvider.fromInt(Preferences.weatherProvider)) {
|
when (Constants.WeatherProvider.fromInt(Preferences.weatherProvider)) {
|
||||||
Constants.WeatherProvider.OPEN_WEATHER -> Preferences.weatherProviderApiOpen = key
|
Constants.WeatherProvider.OPEN_WEATHER -> Preferences.weatherProviderApiOpen = key
|
||||||
Constants.WeatherProvider.WEATHER_BIT -> Preferences.weatherProviderApiWeatherBit = key
|
Constants.WeatherProvider.WEATHER_BIT -> Preferences.weatherProviderApiWeatherBit = key
|
||||||
@ -59,6 +60,10 @@ class BottomSheetWeatherProviderSettings(context: Context, callback: () -> Unit)
|
|||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
setContentView(view)
|
setContentView(binding.root)
|
||||||
|
behavior.run {
|
||||||
|
skipCollapsed = true
|
||||||
|
state = com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,28 +1,34 @@
|
|||||||
package com.tommasoberlose.anotherwidget.components
|
package com.tommasoberlose.anotherwidget.components
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.CustomNotesDialogLayoutBinding
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import kotlinx.android.synthetic.main.custom_notes_dialog_layout.view.*
|
|
||||||
|
|
||||||
class CustomNotesDialog(context: Context, callback: (() -> Unit)?) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
class CustomNotesDialog(context: Context, callback: (() -> Unit)?) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
||||||
|
|
||||||
init {
|
private var binding: CustomNotesDialogLayoutBinding = CustomNotesDialogLayoutBinding.inflate(LayoutInflater.from(context))
|
||||||
val view = View.inflate(context, R.layout.custom_notes_dialog_layout, null)
|
|
||||||
view.notes.setText(Preferences.customNotes)
|
|
||||||
|
|
||||||
view.action_positive.setOnClickListener {
|
init {
|
||||||
Preferences.customNotes = view.notes.text.toString()
|
binding.notes.setText(Preferences.customNotes)
|
||||||
|
|
||||||
|
binding.actionPositive.setOnClickListener {
|
||||||
|
Preferences.customNotes = binding.notes.text.toString()
|
||||||
this.dismiss()
|
this.dismiss()
|
||||||
callback?.invoke()
|
callback?.invoke()
|
||||||
}
|
}
|
||||||
|
|
||||||
view.notes.requestFocus()
|
binding.notes.requestFocus()
|
||||||
|
|
||||||
setContentView(view)
|
setContentView(binding.root)
|
||||||
|
behavior.run {
|
||||||
|
skipCollapsed = true
|
||||||
|
state = com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -18,7 +18,7 @@ class FixedFocusScrollView @JvmOverloads constructor(
|
|||||||
var isScrollable = true
|
var isScrollable = true
|
||||||
|
|
||||||
override fun scrollTo(x: Int, y: Int) {
|
override fun scrollTo(x: Int, y: Int) {
|
||||||
if (isScrollable) {
|
if (isScrollable || !isLaidOut) {
|
||||||
super.scrollTo(x, y)
|
super.scrollTo(x, y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,7 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.util.EventLog
|
import android.view.LayoutInflater
|
||||||
import android.util.Log
|
|
||||||
import android.view.View
|
|
||||||
import androidx.core.app.NotificationManagerCompat
|
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.google.android.gms.auth.api.signin.GoogleSignIn
|
import com.google.android.gms.auth.api.signin.GoogleSignIn
|
||||||
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
|
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
|
||||||
@ -22,6 +19,7 @@ import com.karumi.dexter.PermissionToken
|
|||||||
import com.karumi.dexter.listener.PermissionRequest
|
import com.karumi.dexter.listener.PermissionRequest
|
||||||
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.GlanceProviderSettingsLayoutBinding
|
||||||
import com.tommasoberlose.anotherwidget.global.Constants
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
||||||
@ -29,21 +27,22 @@ import com.tommasoberlose.anotherwidget.helpers.AlarmHelper
|
|||||||
import com.tommasoberlose.anotherwidget.helpers.GreetingsHelper
|
import com.tommasoberlose.anotherwidget.helpers.GreetingsHelper
|
||||||
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||||
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
|
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.AppNotificationsFilterActivity
|
import com.tommasoberlose.anotherwidget.ui.activities.tabs.AppNotificationsFilterActivity
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.MusicPlayersFilterActivity
|
import com.tommasoberlose.anotherwidget.ui.activities.tabs.MediaInfoFormatActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.tabs.MusicPlayersFilterActivity
|
||||||
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
||||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
import kotlinx.android.synthetic.main.glance_provider_settings_layout.view.*
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
|
||||||
class GlanceSettingsDialog(val context: Activity, val provider: Constants.GlanceProviderId, private val statusCallback: (() -> Unit)?) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
class GlanceSettingsDialog(val context: Activity, val provider: Constants.GlanceProviderId, private val statusCallback: (() -> Unit)?) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
||||||
|
|
||||||
|
private var binding: GlanceProviderSettingsLayoutBinding = GlanceProviderSettingsLayoutBinding.inflate(LayoutInflater.from(context))
|
||||||
|
|
||||||
override fun show() {
|
override fun show() {
|
||||||
val view = View.inflate(context, R.layout.glance_provider_settings_layout, null)
|
|
||||||
|
|
||||||
/* TITLE */
|
/* TITLE */
|
||||||
view.title.text = when (provider) {
|
binding.title.text = when (provider) {
|
||||||
Constants.GlanceProviderId.PLAYING_SONG -> context.getString(R.string.settings_show_music_title)
|
Constants.GlanceProviderId.PLAYING_SONG -> context.getString(R.string.settings_show_music_title)
|
||||||
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> context.getString(R.string.settings_show_next_alarm_title)
|
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> context.getString(R.string.settings_show_next_alarm_title)
|
||||||
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> context.getString(R.string.settings_low_battery_level_title)
|
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> context.getString(R.string.settings_low_battery_level_title)
|
||||||
@ -52,10 +51,11 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
|||||||
Constants.GlanceProviderId.NOTIFICATIONS -> context.getString(R.string.settings_show_notifications_title)
|
Constants.GlanceProviderId.NOTIFICATIONS -> context.getString(R.string.settings_show_notifications_title)
|
||||||
Constants.GlanceProviderId.GREETINGS -> context.getString(R.string.settings_show_greetings_title)
|
Constants.GlanceProviderId.GREETINGS -> context.getString(R.string.settings_show_greetings_title)
|
||||||
Constants.GlanceProviderId.EVENTS -> context.getString(R.string.settings_show_events_as_glance_provider_title)
|
Constants.GlanceProviderId.EVENTS -> context.getString(R.string.settings_show_events_as_glance_provider_title)
|
||||||
|
Constants.GlanceProviderId.WEATHER -> context.getString(R.string.settings_show_weather_as_glance_provider_title)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SUBTITLE*/
|
/* SUBTITLE*/
|
||||||
view.subtitle.text = when (provider) {
|
binding.subtitle.text = when (provider) {
|
||||||
Constants.GlanceProviderId.PLAYING_SONG -> context.getString(R.string.settings_show_music_subtitle)
|
Constants.GlanceProviderId.PLAYING_SONG -> context.getString(R.string.settings_show_music_subtitle)
|
||||||
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> context.getString(R.string.settings_show_next_alarm_subtitle)
|
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> context.getString(R.string.settings_show_next_alarm_subtitle)
|
||||||
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> context.getString(R.string.settings_low_battery_level_subtitle)
|
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> context.getString(R.string.settings_low_battery_level_subtitle)
|
||||||
@ -64,56 +64,62 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
|||||||
Constants.GlanceProviderId.NOTIFICATIONS -> context.getString(R.string.settings_show_notifications_subtitle)
|
Constants.GlanceProviderId.NOTIFICATIONS -> context.getString(R.string.settings_show_notifications_subtitle)
|
||||||
Constants.GlanceProviderId.GREETINGS -> context.getString(R.string.settings_show_greetings_subtitle)
|
Constants.GlanceProviderId.GREETINGS -> context.getString(R.string.settings_show_greetings_subtitle)
|
||||||
Constants.GlanceProviderId.EVENTS -> context.getString(R.string.settings_show_events_as_glance_provider_subtitle)
|
Constants.GlanceProviderId.EVENTS -> context.getString(R.string.settings_show_events_as_glance_provider_subtitle)
|
||||||
|
Constants.GlanceProviderId.WEATHER -> context.getString(R.string.settings_show_weather_as_glance_provider_subtitle)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SONG */
|
/* SONG */
|
||||||
view.action_filter_music_players.isVisible = provider == Constants.GlanceProviderId.PLAYING_SONG
|
binding.actionFilterMusicPlayers.isVisible = provider == Constants.GlanceProviderId.PLAYING_SONG
|
||||||
|
binding.actionChangeMediaInfoFormat.isVisible = provider == Constants.GlanceProviderId.PLAYING_SONG
|
||||||
if (provider == Constants.GlanceProviderId.PLAYING_SONG) {
|
if (provider == Constants.GlanceProviderId.PLAYING_SONG) {
|
||||||
view.action_filter_music_players.setOnClickListener {
|
binding.actionFilterMusicPlayers.setOnClickListener {
|
||||||
dismiss()
|
dismiss()
|
||||||
context.startActivityForResult(Intent(context, MusicPlayersFilterActivity::class.java), 0)
|
context.startActivityForResult(Intent(context, MusicPlayersFilterActivity::class.java), 0)
|
||||||
}
|
}
|
||||||
checkNotificationPermission(view)
|
binding.actionChangeMediaInfoFormat.setOnClickListener {
|
||||||
|
dismiss()
|
||||||
|
context.startActivityForResult(Intent(context, MediaInfoFormatActivity::class.java), 0)
|
||||||
|
}
|
||||||
|
checkNotificationPermission()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ALARM */
|
/* ALARM */
|
||||||
view.alarm_set_by_container.isVisible = provider == Constants.GlanceProviderId.NEXT_CLOCK_ALARM
|
binding.alarmSetByContainer.isVisible = provider == Constants.GlanceProviderId.NEXT_CLOCK_ALARM
|
||||||
if (provider == Constants.GlanceProviderId.NEXT_CLOCK_ALARM) {
|
if (provider == Constants.GlanceProviderId.NEXT_CLOCK_ALARM) {
|
||||||
view.header.text = context.getString(R.string.information_header)
|
binding.header.text = context.getString(R.string.information_header)
|
||||||
view.warning_container.isVisible = false
|
binding.warningContainer.isVisible = false
|
||||||
checkNextAlarm(view)
|
checkNextAlarm()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* GOOGLE STEPS */
|
/* GOOGLE STEPS */
|
||||||
view.action_toggle_google_fit.isVisible = provider == Constants.GlanceProviderId.GOOGLE_FIT_STEPS
|
binding.actionToggleGoogleFit.isVisible = provider == Constants.GlanceProviderId.GOOGLE_FIT_STEPS
|
||||||
if (provider == Constants.GlanceProviderId.GOOGLE_FIT_STEPS) {
|
if (provider == Constants.GlanceProviderId.GOOGLE_FIT_STEPS) {
|
||||||
view.warning_container.isVisible = false
|
binding.warningContainer.isVisible = false
|
||||||
checkFitnessPermission(view)
|
checkFitnessPermission()
|
||||||
checkGoogleFitConnection(view)
|
checkGoogleFitConnection()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* BATTERY INFO */
|
/* BATTERY INFO */
|
||||||
if (provider == Constants.GlanceProviderId.BATTERY_LEVEL_LOW) {
|
if (provider == Constants.GlanceProviderId.BATTERY_LEVEL_LOW) {
|
||||||
view.warning_container.isVisible = false
|
binding.warningContainer.isVisible = false
|
||||||
view.header.isVisible = false
|
binding.header.isVisible = false
|
||||||
view.divider.isVisible = false
|
binding.divider.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTIFICATIONS */
|
/* NOTIFICATIONS */
|
||||||
view.action_filter_notifications_app.isVisible = provider == Constants.GlanceProviderId.NOTIFICATIONS
|
binding.actionFilterNotificationsApp.isVisible = provider == Constants.GlanceProviderId.NOTIFICATIONS
|
||||||
view.action_change_notification_timer.isVisible = provider == Constants.GlanceProviderId.NOTIFICATIONS
|
binding.actionChangeNotificationTimer.isVisible = provider == Constants.GlanceProviderId.NOTIFICATIONS
|
||||||
if (provider == Constants.GlanceProviderId.NOTIFICATIONS) {
|
if (provider == Constants.GlanceProviderId.NOTIFICATIONS) {
|
||||||
checkLastNotificationsPermission(view)
|
checkLastNotificationsPermission()
|
||||||
val stringArray = context.resources.getStringArray(R.array.glance_notifications_timeout)
|
val stringArray = context.resources.getStringArray(R.array.glance_notifications_timeout)
|
||||||
view.action_filter_notifications_app.setOnClickListener {
|
binding.actionFilterNotificationsApp.setOnClickListener {
|
||||||
dismiss()
|
dismiss()
|
||||||
context.startActivityForResult(Intent(context, AppNotificationsFilterActivity::class.java), 0)
|
context.startActivityForResult(Intent(context, AppNotificationsFilterActivity::class.java), 0)
|
||||||
}
|
}
|
||||||
view.notification_timer_label.text = stringArray[Preferences.hideNotificationAfter]
|
binding.notificationTimerLabel.text = stringArray[Preferences.hideNotificationAfter]
|
||||||
view.action_change_notification_timer.setOnClickListener {
|
binding.actionChangeNotificationTimer.setOnClickListener {
|
||||||
val dialog = BottomSheetMenu<Int>(context, header = context.getString(R.string.glance_notification_hide_timeout_title)).setSelectedValue(Preferences.hideNotificationAfter)
|
val dialog = BottomSheetMenu<Int>(context, header = context.getString(R.string.glance_notification_hide_timeout_title)).setSelectedValue(Preferences.hideNotificationAfter)
|
||||||
Constants.GlanceNotificationTimer.values().forEachIndexed { index, timeout ->
|
Constants.GlanceNotificationTimer.values().forEachIndexed { index, timeout ->
|
||||||
dialog.addItem(stringArray[index], timeout.value)
|
dialog.addItem(stringArray[index], timeout.rawValue)
|
||||||
}
|
}
|
||||||
dialog.addOnSelectItemListener { value ->
|
dialog.addOnSelectItemListener { value ->
|
||||||
Preferences.hideNotificationAfter = value
|
Preferences.hideNotificationAfter = value
|
||||||
@ -124,20 +130,27 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
|||||||
|
|
||||||
/* GREETINGS */
|
/* GREETINGS */
|
||||||
if (provider == Constants.GlanceProviderId.GREETINGS) {
|
if (provider == Constants.GlanceProviderId.GREETINGS) {
|
||||||
view.warning_container.isVisible = false
|
binding.warningContainer.isVisible = false
|
||||||
view.header.isVisible = false
|
binding.header.isVisible = false
|
||||||
view.divider.isVisible = false
|
binding.divider.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
/* EVENTS */
|
/* EVENTS */
|
||||||
if (provider == Constants.GlanceProviderId.EVENTS) {
|
if (provider == Constants.GlanceProviderId.EVENTS) {
|
||||||
view.header.isVisible = false
|
binding.header.isVisible = false
|
||||||
view.divider.isVisible = false
|
binding.divider.isVisible = false
|
||||||
checkCalendarConfig(view)
|
checkCalendarConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
/* WEATHER */
|
||||||
|
if (provider == Constants.GlanceProviderId.WEATHER) {
|
||||||
|
binding.header.isVisible = false
|
||||||
|
binding.divider.isVisible = false
|
||||||
|
checkWeatherConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TOGGLE */
|
/* TOGGLE */
|
||||||
view.provider_switch.isChecked = when (provider) {
|
binding.providerSwitch.setCheckedImmediatelyNoEvent(when (provider) {
|
||||||
Constants.GlanceProviderId.PLAYING_SONG -> Preferences.showMusic
|
Constants.GlanceProviderId.PLAYING_SONG -> Preferences.showMusic
|
||||||
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> Preferences.showNextAlarm
|
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> Preferences.showNextAlarm
|
||||||
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> Preferences.showBatteryCharging
|
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> Preferences.showBatteryCharging
|
||||||
@ -146,11 +159,12 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
|||||||
Constants.GlanceProviderId.NOTIFICATIONS -> Preferences.showNotifications
|
Constants.GlanceProviderId.NOTIFICATIONS -> Preferences.showNotifications
|
||||||
Constants.GlanceProviderId.GREETINGS -> Preferences.showGreetings
|
Constants.GlanceProviderId.GREETINGS -> Preferences.showGreetings
|
||||||
Constants.GlanceProviderId.EVENTS -> Preferences.showEventsAsGlanceProvider
|
Constants.GlanceProviderId.EVENTS -> Preferences.showEventsAsGlanceProvider
|
||||||
}
|
Constants.GlanceProviderId.WEATHER -> Preferences.showWeatherAsGlanceProvider
|
||||||
|
})
|
||||||
|
|
||||||
var job: Job? = null
|
var job: Job? = null
|
||||||
|
|
||||||
view.provider_switch.setOnCheckedChangeListener { _, isChecked ->
|
binding.providerSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||||
job?.cancel()
|
job?.cancel()
|
||||||
job = GlobalScope.launch(Dispatchers.IO) {
|
job = GlobalScope.launch(Dispatchers.IO) {
|
||||||
delay(300)
|
delay(300)
|
||||||
@ -158,18 +172,22 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
|||||||
when (provider) {
|
when (provider) {
|
||||||
Constants.GlanceProviderId.PLAYING_SONG -> {
|
Constants.GlanceProviderId.PLAYING_SONG -> {
|
||||||
Preferences.showMusic = isChecked
|
Preferences.showMusic = isChecked
|
||||||
checkNotificationPermission(view)
|
checkNotificationPermission()
|
||||||
}
|
}
|
||||||
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
|
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
|
||||||
Preferences.showNextAlarm = isChecked
|
Preferences.showNextAlarm = isChecked
|
||||||
checkNextAlarm(view)
|
checkNextAlarm()
|
||||||
|
if (!isChecked)
|
||||||
|
AlarmHelper.clearTimeout(context)
|
||||||
}
|
}
|
||||||
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
||||||
Preferences.showBatteryCharging = isChecked
|
Preferences.showBatteryCharging = isChecked
|
||||||
}
|
}
|
||||||
Constants.GlanceProviderId.NOTIFICATIONS -> {
|
Constants.GlanceProviderId.NOTIFICATIONS -> {
|
||||||
Preferences.showNotifications = isChecked
|
Preferences.showNotifications = isChecked
|
||||||
checkLastNotificationsPermission(view)
|
checkLastNotificationsPermission()
|
||||||
|
if (!isChecked)
|
||||||
|
ActiveNotificationsHelper.clearLastNotification(context)
|
||||||
}
|
}
|
||||||
Constants.GlanceProviderId.GREETINGS -> {
|
Constants.GlanceProviderId.GREETINGS -> {
|
||||||
Preferences.showGreetings = isChecked
|
Preferences.showGreetings = isChecked
|
||||||
@ -197,13 +215,16 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
|||||||
Preferences.showDailySteps = false
|
Preferences.showDailySteps = false
|
||||||
}
|
}
|
||||||
|
|
||||||
view.warning_container.isVisible = false
|
binding.warningContainer.isVisible = false
|
||||||
checkFitnessPermission(view)
|
checkFitnessPermission()
|
||||||
checkGoogleFitConnection(view)
|
checkGoogleFitConnection()
|
||||||
}
|
}
|
||||||
Constants.GlanceProviderId.EVENTS -> {
|
Constants.GlanceProviderId.EVENTS -> {
|
||||||
Preferences.showEventsAsGlanceProvider = isChecked
|
Preferences.showEventsAsGlanceProvider = isChecked
|
||||||
}
|
}
|
||||||
|
Constants.GlanceProviderId.WEATHER -> {
|
||||||
|
Preferences.showWeatherAsGlanceProvider = isChecked
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -212,11 +233,15 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setContentView(view)
|
setContentView(binding.root)
|
||||||
|
behavior.run {
|
||||||
|
skipCollapsed = true
|
||||||
|
state = com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
}
|
||||||
super.show()
|
super.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkNextAlarm(view: View) {
|
private fun checkNextAlarm() {
|
||||||
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
val alarm = nextAlarmClock
|
val alarm = nextAlarmClock
|
||||||
if (alarm != null && alarm.showIntent != null) {
|
if (alarm != null && alarm.showIntent != null) {
|
||||||
@ -226,69 +251,84 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
|||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
alarm.showIntent?.creatorPackage ?: ""
|
alarm.showIntent?.creatorPackage ?: ""
|
||||||
}
|
}
|
||||||
view.alarm_set_by_title.text = context.getString(R.string.settings_show_next_alarm_app_title).format(appNameOrPackage)
|
binding.alarmSetByTitle.text = context.getString(R.string.settings_show_next_alarm_app_title).format(appNameOrPackage)
|
||||||
view.alarm_set_by_subtitle.text = if (AlarmHelper.isAlarmProbablyWrong(context)) context.getString(R.string.settings_show_next_alarm_app_subtitle_wrong) else context.getString(R.string.settings_show_next_alarm_app_subtitle_correct)
|
binding.alarmSetBySubtitle.text = if (AlarmHelper.isAlarmProbablyWrong(context)) context.getString(R.string.settings_show_next_alarm_app_subtitle_wrong) else context.getString(R.string.settings_show_next_alarm_app_subtitle_correct)
|
||||||
view.alarm_set_by_title.isVisible = true
|
binding.alarmSetByContainer.isVisible = true
|
||||||
} else {
|
} else {
|
||||||
view.alarm_set_by_title.isVisible = false
|
binding.alarmSetByContainer.isVisible = false
|
||||||
|
binding.header.isVisible = false
|
||||||
|
binding.divider.isVisible = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
statusCallback?.invoke()
|
statusCallback?.invoke()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkCalendarConfig(view: View) {
|
private fun checkCalendarConfig() {
|
||||||
if (!Preferences.showEvents || !context.checkGrantedPermission(Manifest.permission.READ_CALENDAR)) {
|
if (!Preferences.showEvents || !context.checkGrantedPermission(Manifest.permission.READ_CALENDAR)) {
|
||||||
view.warning_container.isVisible = true
|
binding.warningContainer.isVisible = true
|
||||||
view.warning_title.text = context.getString(R.string.settings_show_events_as_glance_provider_error)
|
binding.warningTitle.text = context.getString(R.string.settings_show_events_as_glance_provider_error)
|
||||||
view.warning_container.setOnClickListener {
|
binding.warningContainer.setOnClickListener {
|
||||||
dismiss()
|
dismiss()
|
||||||
EventBus.getDefault().post(MainFragment.ChangeTabEvent(1))
|
EventBus.getDefault().post(MainFragment.ChangeTabEvent(1))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
view.warning_container.isVisible = false
|
binding.warningContainer.isVisible = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkNotificationPermission(view: View) {
|
private fun checkWeatherConfig() {
|
||||||
|
if (!Preferences.showWeather || (Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-") || Preferences.weatherProviderLocationError != "") {
|
||||||
|
binding.warningContainer.isVisible = true
|
||||||
|
binding.warningTitle.text = context.getString(R.string.settings_show_weather_as_glance_provider_error)
|
||||||
|
binding.warningContainer.setOnClickListener {
|
||||||
|
dismiss()
|
||||||
|
EventBus.getDefault().post(MainFragment.ChangeTabEvent(1))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
binding.warningContainer.isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkNotificationPermission() {
|
||||||
when {
|
when {
|
||||||
ActiveNotificationsHelper.checkNotificationAccess(context) -> {
|
ActiveNotificationsHelper.checkNotificationAccess(context) -> {
|
||||||
view.warning_container.isVisible = false
|
binding.warningContainer.isVisible = false
|
||||||
MediaPlayerHelper.updatePlayingMediaInfo(context)
|
MediaPlayerHelper.updatePlayingMediaInfo(context)
|
||||||
}
|
}
|
||||||
Preferences.showMusic -> {
|
Preferences.showMusic -> {
|
||||||
view.warning_container.isVisible = true
|
binding.warningContainer.isVisible = true
|
||||||
view.warning_title.text = context.getString(R.string.settings_request_notification_access)
|
binding.warningTitle.text = context.getString(R.string.settings_request_notification_access)
|
||||||
view.warning_container.setOnClickListener {
|
binding.warningContainer.setOnClickListener {
|
||||||
context.startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
|
context.startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
view.warning_container.isVisible = false
|
binding.warningContainer.isVisible = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
statusCallback?.invoke()
|
statusCallback?.invoke()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkLastNotificationsPermission(view: View) {
|
private fun checkLastNotificationsPermission() {
|
||||||
when {
|
when {
|
||||||
ActiveNotificationsHelper.checkNotificationAccess(context) -> {
|
ActiveNotificationsHelper.checkNotificationAccess(context) -> {
|
||||||
view.warning_container.isVisible = false
|
binding.warningContainer.isVisible = false
|
||||||
}
|
}
|
||||||
Preferences.showNotifications -> {
|
Preferences.showNotifications -> {
|
||||||
view.warning_container.isVisible = true
|
binding.warningContainer.isVisible = true
|
||||||
view.warning_title.text = context.getString(R.string.settings_request_last_notification_access)
|
binding.warningTitle.text = context.getString(R.string.settings_request_last_notification_access)
|
||||||
view.warning_container.setOnClickListener {
|
binding.warningContainer.setOnClickListener {
|
||||||
context.startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
|
context.startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
view.warning_container.isVisible = false
|
binding.warningContainer.isVisible = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
statusCallback?.invoke()
|
statusCallback?.invoke()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkFitnessPermission(view: View) {
|
private fun checkFitnessPermission() {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || context.checkGrantedPermission(
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || context.checkGrantedPermission(
|
||||||
Manifest.permission.ACTIVITY_RECOGNITION)
|
Manifest.permission.ACTIVITY_RECOGNITION)
|
||||||
) {
|
) {
|
||||||
@ -299,10 +339,10 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
|||||||
}
|
}
|
||||||
} else if (Preferences.showDailySteps) {
|
} else if (Preferences.showDailySteps) {
|
||||||
ActivityDetectionReceiver.unregisterFence(context)
|
ActivityDetectionReceiver.unregisterFence(context)
|
||||||
view.warning_container.isVisible = true
|
binding.warningContainer.isVisible = true
|
||||||
view.warning_title.text = context.getString(R.string.settings_request_fitness_access)
|
binding.warningTitle.text = context.getString(R.string.settings_request_fitness_access)
|
||||||
view.warning_container.setOnClickListener {
|
binding.warningContainer.setOnClickListener {
|
||||||
requireFitnessPermission(view)
|
requireFitnessPermission()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ActivityDetectionReceiver.unregisterFence(context)
|
ActivityDetectionReceiver.unregisterFence(context)
|
||||||
@ -310,36 +350,36 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
|||||||
statusCallback?.invoke()
|
statusCallback?.invoke()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkGoogleFitConnection(view: View) {
|
private fun checkGoogleFitConnection() {
|
||||||
val account: GoogleSignInAccount? = GoogleSignIn.getLastSignedInAccount(context)
|
val account: GoogleSignInAccount? = GoogleSignIn.getLastSignedInAccount(context)
|
||||||
if (!GoogleSignIn.hasPermissions(account,
|
if (!GoogleSignIn.hasPermissions(account,
|
||||||
ActivityDetectionReceiver.FITNESS_OPTIONS
|
ActivityDetectionReceiver.FITNESS_OPTIONS
|
||||||
)) {
|
)) {
|
||||||
view.warning_container.isVisible = true
|
binding.warningContainer.isVisible = true
|
||||||
view.warning_title.text = context.getString(R.string.settings_request_fitness_access)
|
binding.warningTitle.text = context.getString(R.string.settings_request_fitness_access)
|
||||||
view.warning_container.setOnClickListener {
|
binding.warningContainer.setOnClickListener {
|
||||||
GoogleSignIn.requestPermissions(
|
GoogleSignIn.requestPermissions(
|
||||||
context,
|
context,
|
||||||
1,
|
1,
|
||||||
account,
|
account,
|
||||||
ActivityDetectionReceiver.FITNESS_OPTIONS)
|
ActivityDetectionReceiver.FITNESS_OPTIONS)
|
||||||
}
|
}
|
||||||
view.action_connect_to_google_fit.isVisible = true
|
binding.actionConnectToGoogleFit.isVisible = true
|
||||||
view.action_disconnect_to_google_fit.isVisible = false
|
binding.actionDisconnectToGoogleFit.isVisible = false
|
||||||
view.action_connect_to_google_fit.setOnClickListener {
|
binding.actionConnectToGoogleFit.setOnClickListener {
|
||||||
GoogleSignIn.requestPermissions(
|
GoogleSignIn.requestPermissions(
|
||||||
context,
|
context,
|
||||||
1,
|
1,
|
||||||
account,
|
account,
|
||||||
ActivityDetectionReceiver.FITNESS_OPTIONS)
|
ActivityDetectionReceiver.FITNESS_OPTIONS)
|
||||||
}
|
}
|
||||||
view.action_disconnect_to_google_fit.setOnClickListener(null)
|
binding.actionDisconnectToGoogleFit.setOnClickListener(null)
|
||||||
view.google_fit_status_label.text = context.getString(R.string.google_fit_account_not_connected)
|
binding.googleFitStatusLabel.text = context.getString(R.string.google_fit_account_not_connected)
|
||||||
} else {
|
} else {
|
||||||
view.action_connect_to_google_fit.isVisible = false
|
binding.actionConnectToGoogleFit.isVisible = false
|
||||||
view.action_disconnect_to_google_fit.isVisible = true
|
binding.actionDisconnectToGoogleFit.isVisible = true
|
||||||
view.action_connect_to_google_fit.setOnClickListener(null)
|
binding.actionConnectToGoogleFit.setOnClickListener(null)
|
||||||
view.action_disconnect_to_google_fit.setOnClickListener {
|
binding.actionDisconnectToGoogleFit.setOnClickListener {
|
||||||
GoogleSignIn.getClient(context, GoogleSignInOptions.Builder(
|
GoogleSignIn.getClient(context, GoogleSignInOptions.Builder(
|
||||||
GoogleSignInOptions.DEFAULT_SIGN_IN).addExtension(
|
GoogleSignInOptions.DEFAULT_SIGN_IN).addExtension(
|
||||||
ActivityDetectionReceiver.FITNESS_OPTIONS
|
ActivityDetectionReceiver.FITNESS_OPTIONS
|
||||||
@ -347,11 +387,11 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
|||||||
show()
|
show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
view.google_fit_status_label.text = context.getString(R.string.google_fit_account_connected)
|
binding.googleFitStatusLabel.text = context.getString(R.string.google_fit_account_connected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun requireFitnessPermission(view: View) {
|
private fun requireFitnessPermission() {
|
||||||
Dexter.withContext(context)
|
Dexter.withContext(context)
|
||||||
.withPermissions(
|
.withPermissions(
|
||||||
"com.google.android.gms.permission.ACTIVITY_RECOGNITION",
|
"com.google.android.gms.permission.ACTIVITY_RECOGNITION",
|
||||||
@ -359,7 +399,7 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
|||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACTIVITY_RECOGNITION else "com.google.android.gms.permission.ACTIVITY_RECOGNITION"
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACTIVITY_RECOGNITION else "com.google.android.gms.permission.ACTIVITY_RECOGNITION"
|
||||||
).withListener(object: MultiplePermissionsListener {
|
).withListener(object: MultiplePermissionsListener {
|
||||||
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
||||||
checkFitnessPermission(view)
|
checkFitnessPermission()
|
||||||
}
|
}
|
||||||
override fun onPermissionRationaleShouldBeShown(
|
override fun onPermissionRationaleShouldBeShown(
|
||||||
permissions: MutableList<PermissionRequest>?,
|
permissions: MutableList<PermissionRequest>?,
|
||||||
|
@ -1,43 +1,41 @@
|
|||||||
package com.tommasoberlose.anotherwidget.components
|
package com.tommasoberlose.anotherwidget.components
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.View
|
import android.view.LayoutInflater
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.BottomSheetMenuBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.IconPackMenuItemBinding
|
||||||
import com.tommasoberlose.anotherwidget.global.Constants
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
||||||
import kotlinx.android.synthetic.main.bottom_sheet_menu.view.*
|
|
||||||
import kotlinx.android.synthetic.main.bottom_sheet_menu.view.header
|
|
||||||
import kotlinx.android.synthetic.main.fragment_weather_settings.*
|
|
||||||
import kotlinx.android.synthetic.main.icon_pack_menu_item.view.*
|
|
||||||
|
|
||||||
class IconPackSelector(context: Context, private val header: String? = null) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
class IconPackSelector(context: Context, private val header: String? = null) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
||||||
|
|
||||||
|
private var binding = BottomSheetMenuBinding.inflate(LayoutInflater.from(context))
|
||||||
|
|
||||||
override fun show() {
|
override fun show() {
|
||||||
val view = View.inflate(context, R.layout.bottom_sheet_menu, null)
|
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
view.header.isVisible = header != null
|
binding.header.isVisible = header != null
|
||||||
view.header_text.text = header ?: ""
|
binding.headerText.text = header ?: ""
|
||||||
|
|
||||||
view.warning_text.isVisible = false
|
binding.warningText.isVisible = false
|
||||||
|
|
||||||
// Menu
|
// Menu
|
||||||
for (item in Constants.WeatherIconPack.values()) {
|
for (item in Constants.WeatherIconPack.values()) {
|
||||||
val itemView = View.inflate(context, R.layout.icon_pack_menu_item, null)
|
val itemBinding = IconPackMenuItemBinding.inflate(LayoutInflater.from(context))
|
||||||
itemView.label.text = context.getString(R.string.settings_weather_icon_pack_default).format(item.value + 1)
|
itemBinding.label.text = context.getString(R.string.settings_weather_icon_pack_default).format(item.rawValue + 1)
|
||||||
itemView.isSelected = item.value == Preferences.weatherIconPack
|
itemBinding.root.isSelected = item.rawValue == Preferences.weatherIconPack
|
||||||
|
|
||||||
itemView.icon_1.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource(context, "01d", item.value)))
|
itemBinding.icon1.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource(context, "01d", item.rawValue)))
|
||||||
itemView.icon_2.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource(context, "01n", item.value)))
|
itemBinding.icon2.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource(context, "01n", item.rawValue)))
|
||||||
itemView.icon_3.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource(context, "10d", item.value)))
|
itemBinding.icon3.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource(context, "10d", item.rawValue)))
|
||||||
itemView.icon_4.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource(context, "09n", item.value)))
|
itemBinding.icon4.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource(context, "09n", item.rawValue)))
|
||||||
|
|
||||||
listOf<ImageView>(itemView.icon_1, itemView.icon_2, itemView.icon_3, itemView.icon_4).forEach {
|
listOf<ImageView>(itemBinding.icon1, itemBinding.icon2, itemBinding.icon3, itemBinding.icon4).forEach {
|
||||||
if (item == Constants.WeatherIconPack.MINIMAL) {
|
if (item == Constants.WeatherIconPack.MINIMAL) {
|
||||||
it.setColorFilter(ContextCompat.getColor(context, R.color.colorPrimaryText))
|
it.setColorFilter(ContextCompat.getColor(context, R.color.colorPrimaryText))
|
||||||
} else {
|
} else {
|
||||||
@ -45,13 +43,17 @@ class IconPackSelector(context: Context, private val header: String? = null) : B
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
itemView.setOnClickListener {
|
itemBinding.root.setOnClickListener {
|
||||||
Preferences.weatherIconPack = item.value
|
Preferences.weatherIconPack = item.rawValue
|
||||||
this.dismiss()
|
this.dismiss()
|
||||||
}
|
}
|
||||||
view.menu.addView(itemView)
|
binding.menu.addView(itemBinding.root)
|
||||||
|
}
|
||||||
|
setContentView(binding.root)
|
||||||
|
behavior.run {
|
||||||
|
skipCollapsed = true
|
||||||
|
state = com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
|
||||||
}
|
}
|
||||||
setContentView(view)
|
|
||||||
super.show()
|
super.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,11 +1,11 @@
|
|||||||
package com.tommasoberlose.anotherwidget.components
|
package com.tommasoberlose.anotherwidget.components
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.View
|
import android.view.LayoutInflater
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import kotlinx.android.synthetic.main.bottom_sheet_dialog.view.*
|
import com.tommasoberlose.anotherwidget.databinding.BottomSheetDialogBinding
|
||||||
|
|
||||||
typealias DialogCallback = () -> Unit
|
typealias DialogCallback = () -> Unit
|
||||||
|
|
||||||
@ -20,6 +20,8 @@ class MaterialBottomSheetDialog(
|
|||||||
private var positiveCallback: DialogCallback? = null
|
private var positiveCallback: DialogCallback? = null
|
||||||
private var negativeCallback: DialogCallback? = null
|
private var negativeCallback: DialogCallback? = null
|
||||||
|
|
||||||
|
private var binding = BottomSheetDialogBinding.inflate(LayoutInflater.from(context))
|
||||||
|
|
||||||
fun setPositiveButton(label: String? = context.getString(android.R.string.ok), callback: DialogCallback? = null): MaterialBottomSheetDialog {
|
fun setPositiveButton(label: String? = context.getString(android.R.string.ok), callback: DialogCallback? = null): MaterialBottomSheetDialog {
|
||||||
positiveButtonLabel = label
|
positiveButtonLabel = label
|
||||||
positiveCallback = callback
|
positiveCallback = callback
|
||||||
@ -33,30 +35,32 @@ class MaterialBottomSheetDialog(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun show() {
|
override fun show() {
|
||||||
val view = View.inflate(context, R.layout.bottom_sheet_dialog, null)
|
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
view.title.isVisible = title != null
|
binding.title.isVisible = title != null
|
||||||
view.title.text = title ?: ""
|
binding.title.text = title ?: ""
|
||||||
|
|
||||||
view.message.isVisible = message != null
|
binding.message.isVisible = message != null
|
||||||
view.message.text = message ?: ""
|
binding.message.text = message ?: ""
|
||||||
|
|
||||||
view.action_positive.isVisible = positiveButtonLabel != null
|
binding.actionPositive.isVisible = positiveButtonLabel != null
|
||||||
view.action_positive.text = positiveButtonLabel ?: ""
|
binding.actionPositive.text = positiveButtonLabel ?: ""
|
||||||
view.action_positive.setOnClickListener {
|
binding.actionPositive.setOnClickListener {
|
||||||
positiveCallback?.invoke()
|
positiveCallback?.invoke()
|
||||||
this.dismiss()
|
this.dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
view.action_negative.isVisible = negativeButtonLabel != null
|
binding.actionNegative.isVisible = negativeButtonLabel != null
|
||||||
view.action_negative.text = negativeButtonLabel ?: ""
|
binding.actionNegative.text = negativeButtonLabel ?: ""
|
||||||
view.action_negative.setOnClickListener {
|
binding.actionNegative.setOnClickListener {
|
||||||
negativeCallback?.invoke()
|
negativeCallback?.invoke()
|
||||||
this.dismiss()
|
this.dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
setContentView(view)
|
setContentView(binding.root)
|
||||||
|
behavior.run {
|
||||||
|
skipCollapsed = true
|
||||||
|
state = com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
}
|
||||||
super.show()
|
super.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.components
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
|
||||||
|
class OnSingleClickListener : View.OnClickListener {
|
||||||
|
|
||||||
|
private val onClickListener: View.OnClickListener
|
||||||
|
|
||||||
|
constructor(listener: View.OnClickListener) {
|
||||||
|
onClickListener = listener
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(listener: (View) -> Unit) {
|
||||||
|
onClickListener = View.OnClickListener { listener.invoke(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(v: View) {
|
||||||
|
val currentTimeMillis = System.currentTimeMillis()
|
||||||
|
|
||||||
|
if (currentTimeMillis >= previousClickTimeMillis + DELAY_MILLIS) {
|
||||||
|
previousClickTimeMillis = currentTimeMillis
|
||||||
|
onClickListener.onClick(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val DELAY_MILLIS = 200L
|
||||||
|
private var previousClickTimeMillis = 0L
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -3,32 +3,37 @@ package com.tommasoberlose.anotherwidget.db
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.provider.CalendarContract
|
import android.provider.CalendarContract
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Database
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.Query
|
||||||
|
import androidx.room.Room
|
||||||
|
import androidx.room.RoomDatabase
|
||||||
import com.chibatching.kotpref.bulk
|
import com.chibatching.kotpref.bulk
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper.applyFilters
|
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper.applyFilters
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper.sortEvents
|
||||||
import com.tommasoberlose.anotherwidget.models.Event
|
import com.tommasoberlose.anotherwidget.models.Event
|
||||||
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
import io.realm.Realm
|
|
||||||
import io.realm.RealmResults
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.Comparator
|
import kotlin.Comparator
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
class EventRepository(val context: Context) {
|
class EventRepository(val context: Context) {
|
||||||
private val realm by lazy { Realm.getDefaultInstance() }
|
private val db by lazy { EventDatabase.getDatabase(context) }
|
||||||
|
|
||||||
fun saveEvents(eventList: List<Event>) {
|
fun saveEvents(eventList: List<Event>) {
|
||||||
realm.executeTransaction { realm ->
|
db.runInTransaction{
|
||||||
realm.where(Event::class.java).findAll().deleteAllFromRealm()
|
db.dao().run {
|
||||||
realm.copyToRealm(eventList)
|
deleteAll()
|
||||||
|
insertAll(eventList)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clearEvents() {
|
fun clearEvents() {
|
||||||
realm.executeTransaction { realm ->
|
db.dao().deleteAll()
|
||||||
realm.where(Event::class.java).findAll().deleteAllFromRealm()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resetNextEventData() {
|
fun resetNextEventData() {
|
||||||
@ -44,11 +49,11 @@ class EventRepository(val context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun saveNextEventData(event: Event) {
|
fun saveNextEventData(event: Event) {
|
||||||
Preferences.nextEventId = event.eventID
|
Preferences.nextEventId = event.id
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNextEvent(): Event? {
|
fun getNextEvent(): Event? {
|
||||||
val nextEvent = getEventByEventId(Preferences.nextEventId)
|
val nextEvent = getEventById(Preferences.nextEventId)
|
||||||
val now = Calendar.getInstance().timeInMillis
|
val now = Calendar.getInstance().timeInMillis
|
||||||
val limit = Calendar.getInstance().apply {
|
val limit = Calendar.getInstance().apply {
|
||||||
timeInMillis = now
|
timeInMillis = now
|
||||||
@ -64,75 +69,63 @@ class EventRepository(val context: Context) {
|
|||||||
else -> add(Calendar.HOUR, 6)
|
else -> add(Calendar.HOUR, 6)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val event = if (nextEvent != null && nextEvent.endDate > now && nextEvent.startDate < limit.timeInMillis) {
|
return if (nextEvent != null && nextEvent.endDate > now && nextEvent.startDate <= limit.timeInMillis) {
|
||||||
nextEvent
|
nextEvent
|
||||||
} else {
|
} else {
|
||||||
val events = getEvents()
|
val events = getEvents()
|
||||||
if (events.isNotEmpty()) {
|
if (events.isNotEmpty()) {
|
||||||
val newNextEvent = events.first()
|
val newNextEvent = events.first()
|
||||||
Preferences.nextEventId = newNextEvent.eventID
|
Preferences.nextEventId = newNextEvent.id
|
||||||
newNextEvent
|
newNextEvent
|
||||||
} else {
|
} else {
|
||||||
resetNextEventData()
|
resetNextEventData()
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return try {
|
|
||||||
realm.copyFromRealm(event!!)
|
|
||||||
} catch (ex: Exception) {
|
|
||||||
event
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getEventByEventId(id: Long): Event? {
|
fun getEventById(id: Long): Event? {
|
||||||
val event = realm.where(Event::class.java).equalTo("eventID", id).findFirst()
|
return db.dao().findById(id)
|
||||||
return try {
|
|
||||||
realm.copyFromRealm(event!!)
|
|
||||||
} catch (ex: Exception) {
|
|
||||||
event
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun goToNextEvent() {
|
fun goToNextEvent() {
|
||||||
val eventList = getEvents()
|
val eventList = getEvents()
|
||||||
if (eventList.isNotEmpty()) {
|
if (eventList.isNotEmpty()) {
|
||||||
val index = eventList.indexOfFirst { it.eventID == Preferences.nextEventId }
|
val index = eventList.indexOfFirst { it.id == Preferences.nextEventId }
|
||||||
if (index > -1 && index < eventList.size - 1) {
|
if (index > -1 && index < eventList.size - 1) {
|
||||||
Preferences.nextEventId = eventList[index + 1].eventID
|
Preferences.nextEventId = eventList[index + 1].id
|
||||||
} else {
|
} else {
|
||||||
Preferences.nextEventId = eventList.first().eventID
|
Preferences.nextEventId = eventList.first().id
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resetNextEventData()
|
resetNextEventData()
|
||||||
}
|
}
|
||||||
UpdatesReceiver.setUpdates(context)
|
|
||||||
MainWidget.updateWidget(context)
|
MainWidget.updateWidget(context)
|
||||||
|
org.greenrobot.eventbus.EventBus.getDefault().post(
|
||||||
|
com.tommasoberlose.anotherwidget.ui.fragments.MainFragment.UpdateUiMessageEvent()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun goToPreviousEvent() {
|
fun goToPreviousEvent() {
|
||||||
val eventList = getEvents()
|
val eventList = getEvents()
|
||||||
if (eventList.isNotEmpty()) {
|
if (eventList.isNotEmpty()) {
|
||||||
val index = eventList.indexOfFirst { it.eventID == Preferences.nextEventId }
|
val index = eventList.indexOfFirst { it.id == Preferences.nextEventId }
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
Preferences.nextEventId = eventList[index - 1].eventID
|
Preferences.nextEventId = eventList[index - 1].id
|
||||||
} else {
|
} else {
|
||||||
Preferences.nextEventId = eventList.last().eventID
|
Preferences.nextEventId = eventList.last().id
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resetNextEventData()
|
resetNextEventData()
|
||||||
}
|
}
|
||||||
UpdatesReceiver.setUpdates(context)
|
|
||||||
MainWidget.updateWidget(context)
|
MainWidget.updateWidget(context)
|
||||||
|
org.greenrobot.eventbus.EventBus.getDefault().post(
|
||||||
|
com.tommasoberlose.anotherwidget.ui.fragments.MainFragment.UpdateUiMessageEvent()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFutureEvents(): List<Event> {
|
fun getFutureEvents(): List<Event> {
|
||||||
val now = Calendar.getInstance().timeInMillis
|
return db.dao().findFuture(Calendar.getInstance().timeInMillis).applyFilters().sortEvents()
|
||||||
realm.refresh()
|
|
||||||
return realm
|
|
||||||
.where(Event::class.java)
|
|
||||||
.greaterThan("endDate", now)
|
|
||||||
.findAll()
|
|
||||||
.applyFilters()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getEvents(): List<Event> {
|
private fun getEvents(): List<Event> {
|
||||||
@ -151,18 +144,54 @@ class EventRepository(val context: Context) {
|
|||||||
else -> add(Calendar.HOUR, 6)
|
else -> add(Calendar.HOUR, 6)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
realm.refresh()
|
return db.dao().find(now, limit.timeInMillis).applyFilters().sortEvents()
|
||||||
return realm
|
|
||||||
.where(Event::class.java)
|
|
||||||
.greaterThan("endDate", now)
|
|
||||||
.lessThanOrEqualTo("startDate", limit.timeInMillis)
|
|
||||||
.findAll()
|
|
||||||
.applyFilters()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getEventsCount(): Int = getEvents().size
|
fun getEventsCount(): Int = getEvents().size
|
||||||
|
|
||||||
fun close() {
|
fun close() {
|
||||||
realm.close()
|
// db.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface EventDao {
|
||||||
|
@Query("SELECT * FROM events WHERE id = :id LIMIT 1")
|
||||||
|
fun findById(id: Long) : Event?
|
||||||
|
|
||||||
|
@Query("SELECT * FROM events WHERE end_date > :from")
|
||||||
|
fun findFuture(from: Long) : List<Event>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM events WHERE end_date > :from and start_date <= :to")
|
||||||
|
fun find(from: Long, to: Long) : List<Event>
|
||||||
|
|
||||||
|
@Insert
|
||||||
|
fun insertAll(events: List<Event>)
|
||||||
|
|
||||||
|
@Query("DELETE FROM events")
|
||||||
|
fun deleteAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Database(entities = arrayOf(Event::class), version = 1, exportSchema = false)
|
||||||
|
abstract class EventDatabase : RoomDatabase() {
|
||||||
|
abstract fun dao(): EventDao
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private var INSTANCE: EventDatabase? = null
|
||||||
|
|
||||||
|
fun getDatabase(context: Context): EventDatabase {
|
||||||
|
// if the INSTANCE is not null, then return it,
|
||||||
|
// if it is, then create the database
|
||||||
|
return INSTANCE ?: synchronized(this) {
|
||||||
|
val instance = Room.databaseBuilder(
|
||||||
|
context.applicationContext,
|
||||||
|
EventDatabase::class.java,
|
||||||
|
"events"
|
||||||
|
).allowMainThreadQueries().build()
|
||||||
|
INSTANCE = instance
|
||||||
|
// return instance
|
||||||
|
instance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,7 +2,6 @@ package com.tommasoberlose.anotherwidget.global
|
|||||||
|
|
||||||
object Actions {
|
object Actions {
|
||||||
const val ACTION_EXTRA_OPEN_WEATHER_PROVIDER = "ACTION_EXTRA_OPEN_WEATHER_PROVIDER"
|
const val ACTION_EXTRA_OPEN_WEATHER_PROVIDER = "ACTION_EXTRA_OPEN_WEATHER_PROVIDER"
|
||||||
const val ACTION_EXTRA_DISABLE_GPS_NOTIFICATION = "ACTION_EXTRA_DISABLE_GPS_NOTIFICATION"
|
|
||||||
|
|
||||||
const val ACTION_TIME_UPDATE = "com.tommasoberlose.anotherwidget.action.TIME_UPDATE"
|
const val ACTION_TIME_UPDATE = "com.tommasoberlose.anotherwidget.action.TIME_UPDATE"
|
||||||
const val ACTION_ALARM_UPDATE = "com.tommasoberlose.anotherwidget.action.ALARM_UPDATE"
|
const val ACTION_ALARM_UPDATE = "com.tommasoberlose.anotherwidget.action.ALARM_UPDATE"
|
||||||
@ -14,4 +13,6 @@ object Actions {
|
|||||||
const val ACTION_REPORT_CRASH = "com.tommasoberlose.anotherwidget.action.REPORT_CRASH"
|
const val ACTION_REPORT_CRASH = "com.tommasoberlose.anotherwidget.action.REPORT_CRASH"
|
||||||
const val ACTION_CLEAR_NOTIFICATION = "com.tommasoberlose.anotherwidget.action.CLEAR_NOTIFICATION"
|
const val ACTION_CLEAR_NOTIFICATION = "com.tommasoberlose.anotherwidget.action.CLEAR_NOTIFICATION"
|
||||||
const val ACTION_UPDATE_GREETINGS = "com.tommasoberlose.anotherwidget.action.UPDATE_GREETINGS"
|
const val ACTION_UPDATE_GREETINGS = "com.tommasoberlose.anotherwidget.action.UPDATE_GREETINGS"
|
||||||
|
|
||||||
|
const val ACTION_REFRESH = "com.tommasoberlose.anotherwidget.action.REFRESH"
|
||||||
}
|
}
|
@ -1,7 +1,5 @@
|
|||||||
package com.tommasoberlose.anotherwidget.global
|
package com.tommasoberlose.anotherwidget.global
|
||||||
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
|
|
||||||
object Constants {
|
object Constants {
|
||||||
const val RESULT_CODE_CUSTOM_LOCATION = 45
|
const val RESULT_CODE_CUSTOM_LOCATION = 45
|
||||||
const val RESULT_APP_NAME = "RESULT_APP_NAME"
|
const val RESULT_APP_NAME = "RESULT_APP_NAME"
|
||||||
@ -11,20 +9,27 @@ object Constants {
|
|||||||
const val CUSTOM_FONT_DOWNLOADED = 2
|
const val CUSTOM_FONT_DOWNLOADED = 2
|
||||||
const val CUSTOM_FONT_DOWNLOAD_NEW = 3
|
const val CUSTOM_FONT_DOWNLOAD_NEW = 3
|
||||||
|
|
||||||
enum class ClockBottomMargin(val value: Int) {
|
enum class ClockBottomMargin(val rawValue: Int) {
|
||||||
NONE(0),
|
NONE(0),
|
||||||
SMALL(1),
|
SMALL(1),
|
||||||
MEDIUM(2),
|
MEDIUM(2),
|
||||||
LARGE(3)
|
LARGE(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class SecondRowTopMargin(val value: Int) {
|
enum class SecondRowTopMargin(val rawValue: Int) {
|
||||||
NONE(0),
|
NONE(0),
|
||||||
SMALL(1),
|
SMALL(1),
|
||||||
MEDIUM(2),
|
MEDIUM(2),
|
||||||
LARGE(3)
|
LARGE(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class Dimension(val rawValue: Float) {
|
||||||
|
NONE(0f),
|
||||||
|
SMALL(8f),
|
||||||
|
MEDIUM(16f),
|
||||||
|
LARGE(24f)
|
||||||
|
}
|
||||||
|
|
||||||
enum class GlanceProviderId(val id: String) {
|
enum class GlanceProviderId(val id: String) {
|
||||||
PLAYING_SONG("PLAYING_SONG"),
|
PLAYING_SONG("PLAYING_SONG"),
|
||||||
NEXT_CLOCK_ALARM("NEXT_CLOCK_ALARM"),
|
NEXT_CLOCK_ALARM("NEXT_CLOCK_ALARM"),
|
||||||
@ -33,7 +38,8 @@ object Constants {
|
|||||||
GOOGLE_FIT_STEPS("GOOGLE_FIT_STEPS"),
|
GOOGLE_FIT_STEPS("GOOGLE_FIT_STEPS"),
|
||||||
NOTIFICATIONS("NOTIFICATIONS"),
|
NOTIFICATIONS("NOTIFICATIONS"),
|
||||||
GREETINGS("GREETINGS"),
|
GREETINGS("GREETINGS"),
|
||||||
EVENTS("EVENTS");
|
EVENTS("EVENTS"),
|
||||||
|
WEATHER("WEATHER");
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val map = GlanceProviderId.values().associateBy(GlanceProviderId::id)
|
private val map = GlanceProviderId.values().associateBy(GlanceProviderId::id)
|
||||||
@ -41,13 +47,13 @@ object Constants {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class WidgetUpdateFrequency(val value: Int) {
|
enum class WidgetUpdateFrequency(val rawValue: Int) {
|
||||||
LOW(0),
|
LOW(0),
|
||||||
DEFAULT(1),
|
DEFAULT(1),
|
||||||
HIGH(2)
|
HIGH(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class WeatherProvider(val value: Int) {
|
enum class WeatherProvider(val rawValue: Int) {
|
||||||
OPEN_WEATHER(0),
|
OPEN_WEATHER(0),
|
||||||
WEATHER_BIT(1),
|
WEATHER_BIT(1),
|
||||||
WEATHER_API(2),
|
WEATHER_API(2),
|
||||||
@ -57,12 +63,12 @@ object Constants {
|
|||||||
YR(6);
|
YR(6);
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val map = WeatherProvider.values().associateBy(WeatherProvider::value)
|
private val map = WeatherProvider.values().associateBy(WeatherProvider::rawValue)
|
||||||
fun fromInt(type: Int) = map[type]
|
fun fromInt(type: Int) = map[type]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class GlanceNotificationTimer(val value: Int) {
|
enum class GlanceNotificationTimer(val rawValue: Int) {
|
||||||
HALF_MINUTE(0),
|
HALF_MINUTE(0),
|
||||||
ONE_MINUTE(1),
|
ONE_MINUTE(1),
|
||||||
FIVE_MINUTES(2),
|
FIVE_MINUTES(2),
|
||||||
@ -71,15 +77,21 @@ object Constants {
|
|||||||
WHEN_DISMISSED(5);
|
WHEN_DISMISSED(5);
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val map = values().associateBy(GlanceNotificationTimer::value)
|
private val map = values().associateBy(GlanceNotificationTimer::rawValue)
|
||||||
fun fromInt(type: Int) = map[type]
|
fun fromInt(type: Int) = map[type]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class WeatherIconPack(val value: Int) {
|
enum class WeatherIconPack(val rawValue: Int) {
|
||||||
DEFAULT(0),
|
DEFAULT(0),
|
||||||
MINIMAL(1),
|
MINIMAL(1),
|
||||||
COOL(2),
|
COOL(2),
|
||||||
GOOGLE_NEWS(3)
|
GOOGLE_NEWS(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class WidgetAlign(val rawValue: Int) {
|
||||||
|
LEFT(0),
|
||||||
|
RIGHT(1),
|
||||||
|
CENTER(2)
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,8 +1,11 @@
|
|||||||
package com.tommasoberlose.anotherwidget.global
|
package com.tommasoberlose.anotherwidget.global
|
||||||
|
|
||||||
import android.os.Build
|
|
||||||
import androidx.appcompat.app.AppCompatDelegate.*
|
import androidx.appcompat.app.AppCompatDelegate.*
|
||||||
|
import androidx.core.os.ConfigurationCompat
|
||||||
import com.chibatching.kotpref.KotprefModel
|
import com.chibatching.kotpref.KotprefModel
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.IntentHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.isMetric
|
||||||
|
|
||||||
object Preferences : KotprefModel() {
|
object Preferences : KotprefModel() {
|
||||||
override val commitAllPropertiesByDefault: Boolean = true
|
override val commitAllPropertiesByDefault: Boolean = true
|
||||||
@ -14,8 +17,8 @@ object Preferences : KotprefModel() {
|
|||||||
var showWeather by booleanPref(key = "PREF_SHOW_WEATHER", default = false)
|
var showWeather by booleanPref(key = "PREF_SHOW_WEATHER", default = false)
|
||||||
var weatherIcon by stringPref(key = "PREF_WEATHER_ICON", default = "")
|
var weatherIcon by stringPref(key = "PREF_WEATHER_ICON", default = "")
|
||||||
var weatherTemp by floatPref(key = "PREF_WEATHER_TEMP", default = 0f)
|
var weatherTemp by floatPref(key = "PREF_WEATHER_TEMP", default = 0f)
|
||||||
var weatherTempUnit by stringPref(key = "PREF_WEATHER_TEMP_UNIT", default = "F")
|
var weatherTempUnit by stringPref(key = "PREF_WEATHER_TEMP_UNIT", default = if (ConfigurationCompat.getLocales(context.resources.configuration)[0].isMetric()) "C" else "F")
|
||||||
var weatherRealTempUnit by stringPref(key = "PREF_WEATHER_REAL_TEMP_UNIT", default = "F")
|
var weatherRealTempUnit by stringPref(key = "PREF_WEATHER_REAL_TEMP_UNIT", default = if (ConfigurationCompat.getLocales(context.resources.configuration)[0].isMetric()) "C" else "F")
|
||||||
var calendarAllDay by booleanPref(key = "PREF_CALENDAR_ALL_DAY", default = true)
|
var calendarAllDay by booleanPref(key = "PREF_CALENDAR_ALL_DAY", default = true)
|
||||||
var calendarFilter by stringPref(key = "PREF_CALENDAR_FILTER", default = "")
|
var calendarFilter by stringPref(key = "PREF_CALENDAR_FILTER", default = "")
|
||||||
|
|
||||||
@ -43,14 +46,14 @@ object Preferences : KotprefModel() {
|
|||||||
var weatherProviderApiWeatherApi by stringPref(default = "")
|
var weatherProviderApiWeatherApi by stringPref(default = "")
|
||||||
var weatherProviderApiWeatherBit by stringPref(default = "")
|
var weatherProviderApiWeatherBit by stringPref(default = "")
|
||||||
var weatherProviderApiAccuweather by stringPref(default = "")
|
var weatherProviderApiAccuweather by stringPref(default = "")
|
||||||
var weatherProvider by intPref(default = Constants.WeatherProvider.OPEN_WEATHER.value)
|
var weatherProvider by intPref(default = if (ConfigurationCompat.getLocales(context.resources.configuration)[0].isMetric()) Constants.WeatherProvider.YR.rawValue else Constants.WeatherProvider.WEATHER_GOV.rawValue)
|
||||||
var weatherProviderError by stringPref(default = "")
|
var weatherProviderError by stringPref(default = "")
|
||||||
var weatherProviderLocationError by stringPref(default = "")
|
var weatherProviderLocationError by stringPref(default = "")
|
||||||
var eventAppName by stringPref(key = "PREF_EVENT_APP_NAME", default = "")
|
var eventAppName by stringPref(key = "PREF_EVENT_APP_NAME", default = "")
|
||||||
var eventAppPackage by stringPref(key = "PREF_EVENT_APP_PACKAGE", default = "")
|
var eventAppPackage by stringPref(key = "PREF_EVENT_APP_PACKAGE", default = "")
|
||||||
var openEventDetails by booleanPref(default = true)
|
var openEventDetails by booleanPref(default = true)
|
||||||
|
|
||||||
var widgetUpdateFrequency by intPref(default = Constants.WidgetUpdateFrequency.DEFAULT.value)
|
var widgetUpdateFrequency by intPref(default = Constants.WidgetUpdateFrequency.DEFAULT.rawValue)
|
||||||
|
|
||||||
var textGlobalColor by stringPref(key = "PREF_TEXT_COLOR", default = "#FFFFFF")
|
var textGlobalColor by stringPref(key = "PREF_TEXT_COLOR", default = "#FFFFFF")
|
||||||
var textGlobalAlpha by stringPref(default = "FF")
|
var textGlobalAlpha by stringPref(default = "FF")
|
||||||
@ -79,14 +82,22 @@ object Preferences : KotprefModel() {
|
|||||||
|
|
||||||
var showAMPMIndicator by booleanPref(default = true)
|
var showAMPMIndicator by booleanPref(default = true)
|
||||||
|
|
||||||
var weatherIconPack by intPref(default = Constants.WeatherIconPack.DEFAULT.value)
|
var weatherIconPack by intPref(default = Constants.WeatherIconPack.DEFAULT.rawValue)
|
||||||
|
|
||||||
|
// UI
|
||||||
|
var widgetMargin by floatPref(default = Constants.Dimension.NONE.rawValue)
|
||||||
|
var widgetPadding by floatPref(default = Constants.Dimension.SMALL.rawValue)
|
||||||
|
|
||||||
|
// Clock
|
||||||
|
var altTimezoneLabel by stringPref(default = "")
|
||||||
|
var altTimezoneId by stringPref(default = "")
|
||||||
|
|
||||||
// Global
|
// Global
|
||||||
var textMainSize by floatPref(key = "PREF_TEXT_MAIN_SIZE", default = 26f)
|
var textMainSize by floatPref(key = "PREF_TEXT_MAIN_SIZE", default = 24f)
|
||||||
var textSecondSize by floatPref(key = "PREF_TEXT_SECOND_SIZE", default = 18f)
|
var textSecondSize by floatPref(key = "PREF_TEXT_SECOND_SIZE", default = 16f)
|
||||||
var clockTextSize by floatPref(key = "PREF_TEXT_CLOCK_SIZE", default = 90f)
|
var clockTextSize by floatPref(key = "PREF_TEXT_CLOCK_SIZE", default = 72f)
|
||||||
var clockBottomMargin by intPref(default = Constants.ClockBottomMargin.MEDIUM.value)
|
var clockBottomMargin by intPref(default = Constants.ClockBottomMargin.MEDIUM.rawValue)
|
||||||
var secondRowTopMargin by intPref(default = Constants.SecondRowTopMargin.NONE.value)
|
var secondRowTopMargin by intPref(default = Constants.SecondRowTopMargin.SMALL.rawValue)
|
||||||
var showClock by booleanPref(key = "PREF_SHOW_CLOCK", default = false)
|
var showClock by booleanPref(key = "PREF_SHOW_CLOCK", default = false)
|
||||||
var clockAppName by stringPref(key = "PREF_CLOCK_APP_NAME", default = "")
|
var clockAppName by stringPref(key = "PREF_CLOCK_APP_NAME", default = "")
|
||||||
var clockAppPackage by stringPref(key = "PREF_CLOCK_APP_PACKAGE", default = "")
|
var clockAppPackage by stringPref(key = "PREF_CLOCK_APP_PACKAGE", default = "")
|
||||||
@ -103,21 +114,21 @@ object Preferences : KotprefModel() {
|
|||||||
var customFontName by stringPref(default = "")
|
var customFontName by stringPref(default = "")
|
||||||
var customFontVariant by stringPref(default = "regular")
|
var customFontVariant by stringPref(default = "regular")
|
||||||
var showNextEvent by booleanPref(key = "PREF_SHOW_NEXT_EVENT", default = true)
|
var showNextEvent by booleanPref(key = "PREF_SHOW_NEXT_EVENT", default = true)
|
||||||
|
var showNextEventOnMultipleLines by booleanPref(default = false)
|
||||||
|
|
||||||
var showDividers by booleanPref(default = true)
|
var showDividers by booleanPref(default = true)
|
||||||
|
|
||||||
|
var widgetAlign by intPref(default = Constants.WidgetAlign.CENTER.rawValue)
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
var showWallpaper by booleanPref(default = true)
|
var showWallpaper by booleanPref(default = true)
|
||||||
var showBigClockWarning by booleanPref(default = true)
|
|
||||||
var showWeatherWarning by booleanPref(default = true)
|
|
||||||
var showPreview by booleanPref(default = true)
|
var showPreview by booleanPref(default = true)
|
||||||
var showXiaomiWarning by booleanPref(default = true)
|
var showXiaomiWarning by booleanPref(default = true)
|
||||||
|
|
||||||
// Glance
|
// Glance
|
||||||
var showGlance by booleanPref(default = true)
|
|
||||||
var enabledGlanceProviderOrder by stringPref(default = "")
|
var enabledGlanceProviderOrder by stringPref(default = "")
|
||||||
var customNotes by stringPref(default = "")
|
var customNotes by stringPref(default = "")
|
||||||
var showNextAlarm by booleanPref(default = true)
|
var showNextAlarm by booleanPref(default = false)
|
||||||
var showBatteryCharging by booleanPref(default = false)
|
var showBatteryCharging by booleanPref(default = false)
|
||||||
var isBatteryLevelLow by booleanPref(default = false)
|
var isBatteryLevelLow by booleanPref(default = false)
|
||||||
var isCharging by booleanPref(default = false)
|
var isCharging by booleanPref(default = false)
|
||||||
@ -125,7 +136,7 @@ object Preferences : KotprefModel() {
|
|||||||
var showDailySteps by booleanPref(default = false)
|
var showDailySteps by booleanPref(default = false)
|
||||||
var showGreetings by booleanPref(default = false)
|
var showGreetings by booleanPref(default = false)
|
||||||
var showNotifications by booleanPref(default = false)
|
var showNotifications by booleanPref(default = false)
|
||||||
var hideNotificationAfter by intPref(default = Constants.GlanceNotificationTimer.ONE_MINUTE.value)
|
var hideNotificationAfter by intPref(default = Constants.GlanceNotificationTimer.ONE_MINUTE.rawValue)
|
||||||
|
|
||||||
var lastNotificationId by intPref(default = -1)
|
var lastNotificationId by intPref(default = -1)
|
||||||
var lastNotificationTitle by stringPref(default = "")
|
var lastNotificationTitle by stringPref(default = "")
|
||||||
@ -133,15 +144,16 @@ object Preferences : KotprefModel() {
|
|||||||
var lastNotificationPackage by stringPref(default = "")
|
var lastNotificationPackage by stringPref(default = "")
|
||||||
|
|
||||||
var showMusic by booleanPref(default = false)
|
var showMusic by booleanPref(default = false)
|
||||||
var mediaInfoFormat by stringPref(default = "")
|
var mediaInfoFormat by stringPref(default = MediaPlayerHelper.DEFAULT_MEDIA_INFO_FORMAT)
|
||||||
var mediaPlayerTitle by stringPref(default = "")
|
var mediaPlayerTitle by stringPref(default = "")
|
||||||
var mediaPlayerAlbum by stringPref(default = "")
|
var mediaPlayerAlbum by stringPref(default = "")
|
||||||
var mediaPlayerArtist by stringPref(default = "")
|
var mediaPlayerArtist by stringPref(default = "")
|
||||||
var mediaPlayerPackage by stringPref(default = "")
|
var mediaPlayerPackage by stringPref(default = IntentHelper.DO_NOTHING_OPTION)
|
||||||
var musicPlayersFilter by stringPref(default = "")
|
var musicPlayersFilter by stringPref(default = "")
|
||||||
var appNotificationsFilter by stringPref(default = "")
|
var appNotificationsFilter by stringPref(default = "")
|
||||||
|
|
||||||
var showEventsAsGlanceProvider by booleanPref(default = false)
|
var showEventsAsGlanceProvider by booleanPref(default = false)
|
||||||
|
var showWeatherAsGlanceProvider by booleanPref(default = false)
|
||||||
|
|
||||||
// Integrations
|
// Integrations
|
||||||
var installedIntegrations by intPref(default = 0)
|
var installedIntegrations by intPref(default = 0)
|
||||||
|
@ -25,6 +25,7 @@ object ActiveNotificationsHelper {
|
|||||||
remove(Preferences::lastNotificationIcon)
|
remove(Preferences::lastNotificationIcon)
|
||||||
}
|
}
|
||||||
MainWidget.updateWidget(context)
|
MainWidget.updateWidget(context)
|
||||||
|
NotificationListener.clearTimeout(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkNotificationAccess(context: Context): Boolean {
|
fun checkNotificationAccess(context: Context): Boolean {
|
||||||
|
@ -9,6 +9,7 @@ import android.util.Log
|
|||||||
import com.tommasoberlose.anotherwidget.global.Actions
|
import com.tommasoberlose.anotherwidget.global.Actions
|
||||||
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
|
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
|
||||||
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.setExactIfCanSchedule
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@ -44,19 +45,27 @@ object AlarmHelper {
|
|||||||
val intent = Intent(context, UpdatesReceiver::class.java).apply {
|
val intent = Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
action = Actions.ACTION_ALARM_UPDATE
|
action = Actions.ACTION_ALARM_UPDATE
|
||||||
}
|
}
|
||||||
cancel(PendingIntent.getBroadcast(context, ALARM_UPDATE_ID, intent, 0))
|
setExactIfCanSchedule(
|
||||||
setExact(
|
|
||||||
AlarmManager.RTC,
|
AlarmManager.RTC,
|
||||||
trigger,
|
trigger,
|
||||||
PendingIntent.getBroadcast(
|
PendingIntent.getBroadcast(
|
||||||
context,
|
context,
|
||||||
ALARM_UPDATE_ID,
|
ALARM_UPDATE_ID,
|
||||||
intent,
|
intent,
|
||||||
0
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clearTimeout(context: Context) {
|
||||||
|
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
|
val intent = Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
|
action = Actions.ACTION_ALARM_UPDATE
|
||||||
|
}
|
||||||
|
cancel(PendingIntent.getBroadcast(context, ALARM_UPDATE_ID, intent, PendingIntent.FLAG_IMMUTABLE))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private const val ALARM_UPDATE_ID = 24953
|
private const val ALARM_UPDATE_ID = 24953
|
||||||
}
|
}
|
@ -44,8 +44,8 @@ object BitmapHelper {
|
|||||||
FirebaseCrashlytics.getInstance().setCustomKey("HEIGHT SPEC", measuredHeight)
|
FirebaseCrashlytics.getInstance().setCustomKey("HEIGHT SPEC", measuredHeight)
|
||||||
FirebaseCrashlytics.getInstance().setCustomKey("VIEW measuredWidth", view.measuredWidth)
|
FirebaseCrashlytics.getInstance().setCustomKey("VIEW measuredWidth", view.measuredWidth)
|
||||||
FirebaseCrashlytics.getInstance().setCustomKey("VIEW measuredHeight", view.measuredHeight)
|
FirebaseCrashlytics.getInstance().setCustomKey("VIEW measuredHeight", view.measuredHeight)
|
||||||
FirebaseCrashlytics.getInstance().setCustomKey("WIDGET final width", measuredWidth)
|
FirebaseCrashlytics.getInstance().setCustomKey("WIDGET final width", widgetWidth)
|
||||||
FirebaseCrashlytics.getInstance().setCustomKey("WIDGET final height", view.measuredHeight)
|
FirebaseCrashlytics.getInstance().setCustomKey("WIDGET final height", widgetHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
@ -58,7 +58,7 @@ object BitmapHelper {
|
|||||||
//Bind a canvas to it
|
//Bind a canvas to it
|
||||||
val canvas = Canvas(btm)
|
val canvas = Canvas(btm)
|
||||||
// draw the view on the canvas
|
// draw the view on the canvas
|
||||||
view.layout(0, 0, measuredWidth, measuredHeight)
|
view.layout(0, 0, widgetWidth, widgetHeight)
|
||||||
view.draw(canvas)
|
view.draw(canvas)
|
||||||
//return the bitmap
|
//return the bitmap
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,15 @@
|
|||||||
package com.tommasoberlose.anotherwidget.helpers
|
package com.tommasoberlose.anotherwidget.helpers
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.app.job.JobInfo
|
|
||||||
import android.app.job.JobParameters
|
|
||||||
import android.app.job.JobScheduler
|
|
||||||
import android.app.job.JobService
|
|
||||||
import android.content.ComponentName
|
|
||||||
import android.content.ContentUris
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.provider.CalendarContract
|
import android.provider.CalendarContract
|
||||||
import android.util.Log
|
|
||||||
import com.tommasoberlose.anotherwidget.services.EventListenerJob
|
|
||||||
import com.tommasoberlose.anotherwidget.db.EventRepository
|
|
||||||
import com.tommasoberlose.anotherwidget.models.Event
|
import com.tommasoberlose.anotherwidget.models.Event
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
import com.tommasoberlose.anotherwidget.services.UpdateCalendarWorker
|
||||||
import com.tommasoberlose.anotherwidget.services.UpdateCalendarJob
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
import me.everything.providers.android.calendar.CalendarProvider
|
import me.everything.providers.android.calendar.CalendarProvider
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.Comparator
|
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,7 +18,7 @@ import kotlin.collections.ArrayList
|
|||||||
|
|
||||||
object CalendarHelper {
|
object CalendarHelper {
|
||||||
fun updateEventList(context: Context) {
|
fun updateEventList(context: Context) {
|
||||||
UpdateCalendarJob.enqueueWork(context, Intent())
|
UpdateCalendarWorker.enqueue(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCalendarList(context: Context): List<me.everything.providers.android.calendar.Calendar> {
|
fun getCalendarList(context: Context): List<me.everything.providers.android.calendar.Calendar> {
|
||||||
@ -63,11 +49,11 @@ object CalendarHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun setEventUpdatesAndroidN(context: Context) {
|
fun setEventUpdatesAndroidN(context: Context) {
|
||||||
EventListenerJob.schedule(context)
|
UpdateCalendarWorker.enqueueTrigger(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeEventUpdatesAndroidN(context: Context) {
|
fun removeEventUpdatesAndroidN(context: Context) {
|
||||||
EventListenerJob.remove(context)
|
UpdateCalendarWorker.cancelTrigger(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun List<Event>.applyFilters() : List<Event> {
|
fun List<Event>.applyFilters() : List<Event> {
|
||||||
|
@ -1,15 +1,27 @@
|
|||||||
package com.tommasoberlose.anotherwidget.helpers
|
package com.tommasoberlose.anotherwidget.helpers
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.ClipData
|
||||||
|
import android.content.ClipboardManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Context.CLIPBOARD_SERVICE
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.toast
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
|
||||||
object ColorHelper {
|
object ColorHelper {
|
||||||
fun getFontColor(isDark: Boolean): Int {
|
fun getFontColor(isDark: Boolean): Int {
|
||||||
return try {
|
return try {
|
||||||
Color.parseColor("#%s%s".format(if (!isDark) Preferences.textGlobalAlpha else Preferences.textGlobalAlphaDark, (if (!isDark) Preferences.textGlobalColor else Preferences.textGlobalColorDark).replace("#", "")))
|
Color.parseColor("#%s%s".format(if (!isDark) Preferences.textGlobalAlpha else Preferences.textGlobalAlphaDark,
|
||||||
|
(if (!isDark) Preferences.textGlobalColor else Preferences.textGlobalColorDark).replace(
|
||||||
|
"#",
|
||||||
|
"")))
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Color.parseColor("#FFFFFFFF")
|
Color.parseColor("#FFFFFFFF")
|
||||||
}
|
}
|
||||||
@ -33,7 +45,10 @@ object ColorHelper {
|
|||||||
|
|
||||||
fun getSecondaryFontColor(isDark: Boolean): Int {
|
fun getSecondaryFontColor(isDark: Boolean): Int {
|
||||||
return try {
|
return try {
|
||||||
Color.parseColor("#%s%s".format((if (!isDark) Preferences.textSecondaryAlpha else Preferences.textSecondaryAlphaDark), (if (!isDark) Preferences.textSecondaryColor else Preferences.textSecondaryColorDark).replace("#", "")))
|
Color.parseColor("#%s%s".format((if (!isDark) Preferences.textSecondaryAlpha else Preferences.textSecondaryAlphaDark),
|
||||||
|
(if (!isDark) Preferences.textSecondaryColor else Preferences.textSecondaryColorDark).replace(
|
||||||
|
"#",
|
||||||
|
"")))
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Color.parseColor("#FFFFFFFF")
|
Color.parseColor("#FFFFFFFF")
|
||||||
}
|
}
|
||||||
@ -57,7 +72,10 @@ object ColorHelper {
|
|||||||
|
|
||||||
fun getClockFontColor(isDark: Boolean): Int {
|
fun getClockFontColor(isDark: Boolean): Int {
|
||||||
return try {
|
return try {
|
||||||
Color.parseColor("#%s%s".format((if (!isDark) Preferences.clockTextAlpha else Preferences.clockTextAlphaDark), (if (!isDark) Preferences.clockTextColor else Preferences.clockTextColorDark).replace("#", "")))
|
Color.parseColor("#%s%s".format((if (!isDark) Preferences.clockTextAlpha else Preferences.clockTextAlphaDark),
|
||||||
|
(if (!isDark) Preferences.clockTextColor else Preferences.clockTextColorDark).replace(
|
||||||
|
"#",
|
||||||
|
"")))
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Color.parseColor("#FFFFFFFF")
|
Color.parseColor("#FFFFFFFF")
|
||||||
}
|
}
|
||||||
@ -81,7 +99,10 @@ object ColorHelper {
|
|||||||
|
|
||||||
fun getBackgroundColor(isDark: Boolean): Int {
|
fun getBackgroundColor(isDark: Boolean): Int {
|
||||||
return try {
|
return try {
|
||||||
Color.parseColor("#%s%s".format((if (!isDark) Preferences.backgroundCardAlpha else Preferences.backgroundCardAlphaDark), (if (!isDark) Preferences.backgroundCardColor else Preferences.backgroundCardColorDark).replace("#", "")))
|
Color.parseColor("#%s%s".format((if (!isDark) Preferences.backgroundCardAlpha else Preferences.backgroundCardAlphaDark),
|
||||||
|
(if (!isDark) Preferences.backgroundCardColor else Preferences.backgroundCardColorDark).replace(
|
||||||
|
"#",
|
||||||
|
"")))
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Color.parseColor("#00000000")
|
Color.parseColor("#00000000")
|
||||||
}
|
}
|
||||||
@ -123,4 +144,50 @@ object ColorHelper {
|
|||||||
val hexValue = this.toInt(16).toDouble()
|
val hexValue = this.toInt(16).toDouble()
|
||||||
return (hexValue * 100 / 255).roundToInt()
|
return (hexValue * 100 / 255).roundToInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun String.isColor(): Boolean {
|
||||||
|
return try {
|
||||||
|
Color.parseColor(this)
|
||||||
|
true
|
||||||
|
} catch (iae: IllegalArgumentException) {
|
||||||
|
iae.printStackTrace()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("DefaultLocale")
|
||||||
|
fun Context.copyToClipboard(color: Int?, alpha: Int) {
|
||||||
|
if (color == null) return toast(getString(R.string.error_copy_color))
|
||||||
|
with(getSystemService(CLIPBOARD_SERVICE) as ClipboardManager) {
|
||||||
|
try {
|
||||||
|
val colorString = Integer.toHexString(color)
|
||||||
|
val clip = "#%s%s".format(
|
||||||
|
alpha.toHexValue(),
|
||||||
|
if (colorString.length > 6) colorString.substring(2) else colorString
|
||||||
|
).toUpperCase()
|
||||||
|
setPrimaryClip(ClipData.newPlainText(clip, clip))
|
||||||
|
toast(getString(R.string.color_copied))
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
ex.printStackTrace()
|
||||||
|
toast(getString(R.string.error_copy_color))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.isClipboardColor(): Boolean {
|
||||||
|
with(getSystemService(CLIPBOARD_SERVICE) as ClipboardManager) {
|
||||||
|
return try { primaryClip?.getItemAt(0)?.text?.toString()?.isColor() ?: false } catch (ex: Exception) { false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.pasteFromClipboard(pasteColor: (color: String, alpha: String) -> Unit) {
|
||||||
|
with(getSystemService(CLIPBOARD_SERVICE) as ClipboardManager) {
|
||||||
|
primaryClip?.let {
|
||||||
|
val item = it.getItemAt(0).text.toString().replace("#", "")
|
||||||
|
val color = if (item.length > 6) item.substring(2) else item
|
||||||
|
val alpha = if (item.length > 6) item.substring(0, 2) else "00"
|
||||||
|
pasteColor("#$color", alpha)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -90,6 +90,12 @@ object GlanceProviderHelper {
|
|||||||
R.drawable.round_event_note_24
|
R.drawable.round_event_note_24
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Constants.GlanceProviderId.WEATHER -> {
|
||||||
|
GlanceProvider(providerId.id,
|
||||||
|
context.getString(R.string.settings_show_weather_as_glance_provider_title),
|
||||||
|
R.drawable.round_brightness_5_24
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,13 +107,14 @@ object GlanceProviderHelper {
|
|||||||
val eventRepository = EventRepository(context)
|
val eventRepository = EventRepository(context)
|
||||||
BatteryHelper.updateBatteryInfo(context)
|
BatteryHelper.updateBatteryInfo(context)
|
||||||
|
|
||||||
val showGlance = Preferences.showGlance && (eventRepository.getEventsCount() == 0 || !Preferences.showEvents || Preferences.showEventsAsGlanceProvider)
|
val showGlance = (eventRepository.getEventsCount() == 0 || !Preferences.showEvents || Preferences.showEventsAsGlanceProvider)
|
||||||
&& (
|
&& (
|
||||||
(Preferences.showNotifications && ActiveNotificationsHelper.showLastNotification()) ||
|
(Preferences.showNotifications && ActiveNotificationsHelper.showLastNotification()) ||
|
||||||
(Preferences.showNextAlarm && AlarmHelper.getNextAlarm(context) != "") ||
|
(Preferences.showNextAlarm && AlarmHelper.getNextAlarm(context) != "") ||
|
||||||
(MediaPlayerHelper.isSomeonePlaying(context)) ||
|
(MediaPlayerHelper.isSomeonePlaying(context)) ||
|
||||||
(Preferences.showBatteryCharging && Preferences.isCharging || Preferences.isBatteryLevelLow) ||
|
(Preferences.showBatteryCharging && Preferences.isCharging || Preferences.isBatteryLevelLow) ||
|
||||||
(Preferences.customNotes.isNotEmpty()) ||
|
(Preferences.customNotes.isNotEmpty()) ||
|
||||||
|
(Preferences.showWeatherAsGlanceProvider && Preferences.showWeather && Preferences.weatherIcon != "") ||
|
||||||
(Preferences.showDailySteps && Preferences.googleFitSteps > 0) ||
|
(Preferences.showDailySteps && Preferences.googleFitSteps > 0) ||
|
||||||
(Preferences.showGreetings && GreetingsHelper.showGreetings()) ||
|
(Preferences.showGreetings && GreetingsHelper.showGreetings()) ||
|
||||||
(Preferences.showEventsAsGlanceProvider && Preferences.showEvents && context.checkGrantedPermission(
|
(Preferences.showEventsAsGlanceProvider && Preferences.showEvents && context.checkGrantedPermission(
|
||||||
|
@ -37,7 +37,7 @@ object GreetingsHelper {
|
|||||||
Intent(context, UpdatesReceiver::class.java).apply {
|
Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
action = Actions.ACTION_UPDATE_GREETINGS
|
action = Actions.ACTION_UPDATE_GREETINGS
|
||||||
},
|
},
|
||||||
0)
|
PendingIntent.FLAG_IMMUTABLE)
|
||||||
)
|
)
|
||||||
|
|
||||||
setRepeating(
|
setRepeating(
|
||||||
@ -51,7 +51,7 @@ object GreetingsHelper {
|
|||||||
Intent(context, UpdatesReceiver::class.java).apply {
|
Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
action = Actions.ACTION_UPDATE_GREETINGS
|
action = Actions.ACTION_UPDATE_GREETINGS
|
||||||
},
|
},
|
||||||
0)
|
PendingIntent.FLAG_IMMUTABLE)
|
||||||
)
|
)
|
||||||
|
|
||||||
setRepeating(
|
setRepeating(
|
||||||
@ -65,7 +65,7 @@ object GreetingsHelper {
|
|||||||
Intent(context, UpdatesReceiver::class.java).apply {
|
Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
action = Actions.ACTION_UPDATE_GREETINGS
|
action = Actions.ACTION_UPDATE_GREETINGS
|
||||||
},
|
},
|
||||||
0)
|
PendingIntent.FLAG_IMMUTABLE)
|
||||||
)
|
)
|
||||||
|
|
||||||
setRepeating(
|
setRepeating(
|
||||||
@ -79,14 +79,14 @@ object GreetingsHelper {
|
|||||||
Intent(context, UpdatesReceiver::class.java).apply {
|
Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
action = Actions.ACTION_UPDATE_GREETINGS
|
action = Actions.ACTION_UPDATE_GREETINGS
|
||||||
},
|
},
|
||||||
0)
|
PendingIntent.FLAG_IMMUTABLE)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
listOf(MORNING_TIME, MORNING_TIME_END, EVENING_TIME, NIGHT_TIME).forEach {
|
listOf(MORNING_TIME, MORNING_TIME_END, EVENING_TIME, NIGHT_TIME).forEach {
|
||||||
cancel(PendingIntent.getBroadcast(context, it, Intent(context,
|
cancel(PendingIntent.getBroadcast(context, it, Intent(context,
|
||||||
UpdatesReceiver::class.java).apply {
|
UpdatesReceiver::class.java).apply {
|
||||||
action = Actions.ACTION_UPDATE_GREETINGS
|
action = Actions.ACTION_UPDATE_GREETINGS
|
||||||
}, 0))
|
}, PendingIntent.FLAG_IMMUTABLE))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,7 +102,7 @@ object GreetingsHelper {
|
|||||||
val array = when {
|
val array = when {
|
||||||
hour in 5..8 -> context.resources.getStringArray(R.array.morning_greetings)
|
hour in 5..8 -> context.resources.getStringArray(R.array.morning_greetings)
|
||||||
hour in 19..21 -> context.resources.getStringArray(R.array.evening_greetings)
|
hour in 19..21 -> context.resources.getStringArray(R.array.evening_greetings)
|
||||||
hour >= 22 && hour < 5 -> context.resources.getStringArray(R.array.night_greetings)
|
hour >= 22 || hour < 5 -> context.resources.getStringArray(R.array.night_greetings)
|
||||||
else -> emptyArray()
|
else -> emptyArray()
|
||||||
}
|
}
|
||||||
return if (array.isNotEmpty()) array[Random().nextInt(array.size)] else ""
|
return if (array.isNotEmpty()) array[Random().nextInt(array.size)] else ""
|
||||||
|
@ -17,10 +17,10 @@ object ImageHelper {
|
|||||||
0 -> 0f * factor
|
0 -> 0f * factor
|
||||||
1 -> 8f * factor
|
1 -> 8f * factor
|
||||||
2 -> 16f * factor
|
2 -> 16f * factor
|
||||||
else -> 0f * factor
|
else -> 8f * factor
|
||||||
}, resources.displayMetrics)
|
}, resources.displayMetrics)
|
||||||
|
|
||||||
if (originalView.drawable != null) {
|
if (originalView.drawable != null && originalView.drawable.intrinsicWidth > 0 && originalView.drawable.intrinsicHeight > 0) {
|
||||||
val btm = originalView.drawable.toBitmap().copy(Bitmap.Config.ARGB_8888, true)
|
val btm = originalView.drawable.toBitmap().copy(Bitmap.Config.ARGB_8888, true)
|
||||||
val comb = Bitmap.createBitmap(btm)
|
val comb = Bitmap.createBitmap(btm)
|
||||||
val shadowBitmap = generateShadowBitmap(context, cElevation, btm, factor)
|
val shadowBitmap = generateShadowBitmap(context, cElevation, btm, factor)
|
||||||
@ -30,7 +30,7 @@ object ImageHelper {
|
|||||||
canvas.drawColor(Color.TRANSPARENT)
|
canvas.drawColor(Color.TRANSPARENT)
|
||||||
canvas.save()
|
canvas.save()
|
||||||
val rect = Rect()
|
val rect = Rect()
|
||||||
val bounds = originalView.drawable.copyBounds()
|
// val bounds = originalView.drawable.copyBounds()
|
||||||
canvas.getClipBounds(rect)
|
canvas.getClipBounds(rect)
|
||||||
rect.inset(-2 * getBlurRadius(context, cElevation).toInt(), -2 * getBlurRadius(context, cElevation).toInt())
|
rect.inset(-2 * getBlurRadius(context, cElevation).toInt(), -2 * getBlurRadius(context, cElevation).toInt())
|
||||||
canvas.save()
|
canvas.save()
|
||||||
@ -58,7 +58,7 @@ object ImageHelper {
|
|||||||
0 -> 0f * factor
|
0 -> 0f * factor
|
||||||
1 -> 0.8f * factor
|
1 -> 0.8f * factor
|
||||||
2 -> 1f * factor
|
2 -> 1f * factor
|
||||||
else -> 0f
|
else -> 0.8f * factor
|
||||||
}))
|
}))
|
||||||
|
|
||||||
colorMatrixScript.setColorMatrix(matrix)
|
colorMatrixScript.setColorMatrix(matrix)
|
||||||
@ -73,6 +73,9 @@ object ImageHelper {
|
|||||||
|
|
||||||
allocationIn.destroy()
|
allocationIn.destroy()
|
||||||
allocationOut.destroy()
|
allocationOut.destroy()
|
||||||
|
colorMatrixScript.destroy()
|
||||||
|
blurScript.destroy()
|
||||||
|
//rs.destroy()
|
||||||
|
|
||||||
return bitmap
|
return bitmap
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.tommasoberlose.anotherwidget.helpers
|
package com.tommasoberlose.anotherwidget.helpers
|
||||||
|
|
||||||
|
import android.app.PendingIntent
|
||||||
import android.appwidget.AppWidgetManager
|
import android.appwidget.AppWidgetManager
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.ContentUris
|
import android.content.ContentUris
|
||||||
@ -12,8 +13,10 @@ import android.provider.CalendarContract
|
|||||||
import android.provider.CalendarContract.Events
|
import android.provider.CalendarContract.Events
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Actions
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.models.Event
|
import com.tommasoberlose.anotherwidget.models.Event
|
||||||
|
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
import com.tommasoberlose.anotherwidget.utils.toast
|
import com.tommasoberlose.anotherwidget.utils.toast
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -21,6 +24,17 @@ import java.util.*
|
|||||||
|
|
||||||
object IntentHelper {
|
object IntentHelper {
|
||||||
|
|
||||||
|
const val DEFAULT_OPTION = ""
|
||||||
|
const val DO_NOTHING_OPTION = "DO_NOTHING"
|
||||||
|
const val REFRESH_WIDGET_OPTION = "REFRESH_WIDGET"
|
||||||
|
|
||||||
|
fun getPendingIntent(context: Context, requestCode: Int, intent: Intent, flags: Int): PendingIntent {
|
||||||
|
return if (intent.flags and Intent.FLAG_ACTIVITY_NEW_TASK == Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
PendingIntent.getActivity(context, requestCode, intent, flags)
|
||||||
|
else
|
||||||
|
PendingIntent.getBroadcast(context, requestCode, intent, flags)
|
||||||
|
}
|
||||||
|
|
||||||
fun getWidgetUpdateIntent(context: Context): Intent {
|
fun getWidgetUpdateIntent(context: Context): Intent {
|
||||||
val widgetManager = AppWidgetManager.getInstance(context)
|
val widgetManager = AppWidgetManager.getInstance(context)
|
||||||
val widgetComponent = ComponentName(context, MainWidget::class.java)
|
val widgetComponent = ComponentName(context, MainWidget::class.java)
|
||||||
@ -31,33 +45,41 @@ object IntentHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getWidgetRefreshIntent(context: Context): Intent {
|
||||||
|
return Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
|
action = Actions.ACTION_REFRESH
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun getGoogleMapsIntentFromAddress(context: Context, address: String): Intent {
|
fun getGoogleMapsIntentFromAddress(context: Context, address: String): Intent {
|
||||||
val gmmIntentUri: Uri = Uri.parse("geo:0,0?q=$address")
|
val gmmIntentUri: Uri = Uri.parse("geo:0,0?q=${Uri.encode(address)}")
|
||||||
val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
|
val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
|
||||||
mapIntent.`package` = "com.google.android.apps.maps"
|
//mapIntent.`package` = "com.google.android.apps.maps"
|
||||||
|
|
||||||
return if (mapIntent.resolveActivity(context.packageManager) != null) {
|
return if (mapIntent.resolveActivity(context.packageManager) != null) {
|
||||||
mapIntent
|
mapIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
} else {
|
} else {
|
||||||
val map = "http://maps.google.co.in/maps?q=$address"
|
val map = "https://www.google.com/maps/search/?api=1&query=${Uri.encode(address)}"
|
||||||
val i = Intent(Intent.ACTION_VIEW, Uri.parse(map));
|
Intent(Intent.ACTION_VIEW, Uri.parse(map)).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
i
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getWeatherIntent(context: Context): Intent {
|
fun getWeatherIntent(context: Context): Intent {
|
||||||
return when (Preferences.weatherAppPackage) {
|
return when (Preferences.weatherAppPackage) {
|
||||||
"" -> {
|
DEFAULT_OPTION -> {
|
||||||
Intent(Intent.ACTION_VIEW).apply {
|
Intent(Intent.ACTION_VIEW).apply {
|
||||||
addCategory(Intent.CATEGORY_DEFAULT)
|
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
data = Uri.parse("dynact://velour/weather/ProxyActivity")
|
data = Uri.parse("dynact://velour/weather/ProxyActivity")
|
||||||
component = ComponentName("com.google.android.googlequicksearchbox", "com.google.android.apps.gsa.velour.DynamicActivityTrampoline")
|
component = ComponentName("com.google.android.googlequicksearchbox", "com.google.android.apps.gsa.velour.DynamicActivityTrampoline")
|
||||||
|
setClassName("com.google.android.googlequicksearchbox", "com.google.android.apps.gsa.velour.DynamicActivityTrampoline")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"_" -> {
|
DO_NOTHING_OPTION -> {
|
||||||
Intent()
|
Intent()
|
||||||
}
|
}
|
||||||
|
REFRESH_WIDGET_OPTION -> {
|
||||||
|
getWidgetRefreshIntent(context)
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val pm: PackageManager = context.packageManager
|
val pm: PackageManager = context.packageManager
|
||||||
try {
|
try {
|
||||||
@ -72,25 +94,31 @@ object IntentHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCalendarIntent(context: Context): Intent {
|
fun getCalendarIntent(context: Context, time: Long? = null): Intent {
|
||||||
val calendarUri = CalendarContract.CONTENT_URI
|
val calendarUri = CalendarContract.CONTENT_URI
|
||||||
.buildUpon()
|
.buildUpon()
|
||||||
.appendPath("time")
|
.appendPath("time")
|
||||||
.appendPath(Calendar.getInstance().timeInMillis.toString())
|
.appendPath((time ?: Calendar.getInstance().timeInMillis).toString())
|
||||||
.build()
|
.build()
|
||||||
return when (Preferences.calendarAppPackage) {
|
return when (Preferences.calendarAppPackage) {
|
||||||
"" -> {
|
DEFAULT_OPTION -> {
|
||||||
Intent(Intent.ACTION_VIEW).apply {
|
Intent(Intent.ACTION_VIEW).apply {
|
||||||
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
data = calendarUri
|
data = calendarUri
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"_" -> {
|
DO_NOTHING_OPTION -> {
|
||||||
Intent()
|
Intent()
|
||||||
}
|
}
|
||||||
|
REFRESH_WIDGET_OPTION -> {
|
||||||
|
getWidgetRefreshIntent(context)
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val pm: PackageManager = context.packageManager
|
val pm: PackageManager = context.packageManager
|
||||||
try {
|
try {
|
||||||
pm.getLaunchIntentForPackage(Preferences.calendarAppPackage)!!.apply {
|
pm.getLaunchIntentForPackage(Preferences.calendarAppPackage)!!.apply {
|
||||||
|
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
action = Intent.ACTION_VIEW
|
action = Intent.ACTION_VIEW
|
||||||
data = calendarUri
|
data = calendarUri
|
||||||
}
|
}
|
||||||
@ -157,21 +185,24 @@ object IntentHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
false -> {
|
false -> {
|
||||||
getCalendarIntent(context)
|
getCalendarIntent(context, e.startDate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getClockIntent(context: Context): Intent {
|
fun getClockIntent(context: Context): Intent {
|
||||||
return when (Preferences.clockAppPackage) {
|
return when (Preferences.clockAppPackage) {
|
||||||
"" -> {
|
DEFAULT_OPTION -> {
|
||||||
Intent(AlarmClock.ACTION_SHOW_ALARMS).apply {
|
Intent(AlarmClock.ACTION_SHOW_ALARMS).apply {
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"_" -> {
|
DO_NOTHING_OPTION -> {
|
||||||
Intent()
|
Intent()
|
||||||
}
|
}
|
||||||
|
REFRESH_WIDGET_OPTION -> {
|
||||||
|
getWidgetRefreshIntent(context)
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val pm: PackageManager = context.packageManager
|
val pm: PackageManager = context.packageManager
|
||||||
try {
|
try {
|
||||||
@ -186,12 +217,12 @@ object IntentHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getBatteryIntent(): Intent {
|
fun getBatteryIntent(): Intent {
|
||||||
return Intent(Intent.ACTION_POWER_USAGE_SUMMARY)
|
return Intent(Intent.ACTION_POWER_USAGE_SUMMARY).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMusicIntent(context: Context): Intent {
|
fun getMusicIntent(context: Context): Intent {
|
||||||
return when (Preferences.mediaPlayerPackage) {
|
return when (Preferences.mediaPlayerPackage) {
|
||||||
"" -> {
|
DO_NOTHING_OPTION -> {
|
||||||
Intent()
|
Intent()
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
@ -199,6 +230,7 @@ object IntentHelper {
|
|||||||
try {
|
try {
|
||||||
pm.getLaunchIntentForPackage(Preferences.mediaPlayerPackage)!!.apply {
|
pm.getLaunchIntentForPackage(Preferences.mediaPlayerPackage)!!.apply {
|
||||||
addCategory(Intent.CATEGORY_LAUNCHER)
|
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Intent()
|
Intent()
|
||||||
@ -212,6 +244,7 @@ object IntentHelper {
|
|||||||
return try {
|
return try {
|
||||||
pm.getLaunchIntentForPackage("com.google.android.apps.fitness")!!.apply {
|
pm.getLaunchIntentForPackage("com.google.android.apps.fitness")!!.apply {
|
||||||
addCategory(Intent.CATEGORY_LAUNCHER)
|
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Intent()
|
Intent()
|
||||||
@ -223,6 +256,7 @@ object IntentHelper {
|
|||||||
return try {
|
return try {
|
||||||
pm.getLaunchIntentForPackage(Preferences.lastNotificationPackage)!!.apply {
|
pm.getLaunchIntentForPackage(Preferences.lastNotificationPackage)!!.apply {
|
||||||
addCategory(Intent.CATEGORY_LAUNCHER)
|
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Intent()
|
Intent()
|
||||||
|
@ -12,16 +12,37 @@ import com.chibatching.kotpref.bulk
|
|||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.receivers.NotificationListener
|
import com.tommasoberlose.anotherwidget.receivers.NotificationListener
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.ignoreExceptions
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
|
|
||||||
object MediaPlayerHelper {
|
object MediaPlayerHelper {
|
||||||
|
const val MEDIA_INFO_TITLE = "%TITLE"
|
||||||
|
const val MEDIA_INFO_ARTIST = "%ARTIST"
|
||||||
|
const val MEDIA_INFO_ALBUM = "%ALBUM"
|
||||||
|
|
||||||
|
const val DEFAULT_MEDIA_INFO_FORMAT = "%TITLE, %ARTIST"
|
||||||
|
|
||||||
fun isSomeonePlaying(context: Context) = Preferences.showMusic && ActiveNotificationsHelper.checkNotificationAccess(context) && Preferences.mediaPlayerTitle != ""
|
fun isSomeonePlaying(context: Context) = Preferences.showMusic && ActiveNotificationsHelper.checkNotificationAccess(context) && Preferences.mediaPlayerTitle != ""
|
||||||
|
|
||||||
fun getMediaInfo(): String {
|
fun getMediaInfo(format: String = Preferences.mediaInfoFormat, title: String = Preferences.mediaPlayerTitle, artist: String = Preferences.mediaPlayerArtist, album: String = Preferences.mediaPlayerAlbum): String {
|
||||||
return if (Preferences.mediaPlayerArtist == "") {
|
return when (format) {
|
||||||
|
"",
|
||||||
|
DEFAULT_MEDIA_INFO_FORMAT -> {
|
||||||
|
if (Preferences.mediaPlayerArtist == "") {
|
||||||
Preferences.mediaPlayerTitle
|
Preferences.mediaPlayerTitle
|
||||||
} else {
|
} else {
|
||||||
"%s, %s".format(Preferences.mediaPlayerTitle, Preferences.mediaPlayerArtist)
|
DEFAULT_MEDIA_INFO_FORMAT.replace(MEDIA_INFO_TITLE, title)
|
||||||
|
.replace(MEDIA_INFO_ARTIST, artist)
|
||||||
|
.replace(MEDIA_INFO_ALBUM, album)
|
||||||
|
.replace("\\n", System.getProperty("line.separator") ?: " ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
format.replace(MEDIA_INFO_TITLE, title)
|
||||||
|
.replace(MEDIA_INFO_ARTIST, artist)
|
||||||
|
.replace(MEDIA_INFO_ALBUM, album)
|
||||||
|
.replace("\\n", System.getProperty("line.separator") ?: " ")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,17 +70,26 @@ object MediaPlayerHelper {
|
|||||||
isSomeonePlaying = true
|
isSomeonePlaying = true
|
||||||
if (metadata != null) {
|
if (metadata != null) {
|
||||||
Preferences.bulk {
|
Preferences.bulk {
|
||||||
|
ignoreExceptions {
|
||||||
mediaPlayerTitle =
|
mediaPlayerTitle =
|
||||||
metadata.getText(MediaMetadata.METADATA_KEY_TITLE)?.toString()
|
metadata.getText(MediaMetadata.METADATA_KEY_TITLE)
|
||||||
|
?.toString()
|
||||||
?: ""
|
?: ""
|
||||||
|
}
|
||||||
|
ignoreExceptions {
|
||||||
mediaPlayerArtist =
|
mediaPlayerArtist =
|
||||||
metadata.getText(MediaMetadata.METADATA_KEY_ARTIST)?.toString()
|
metadata.getText(MediaMetadata.METADATA_KEY_ARTIST)
|
||||||
|
?.toString()
|
||||||
?: ""
|
?: ""
|
||||||
|
}
|
||||||
|
ignoreExceptions {
|
||||||
mediaPlayerAlbum =
|
mediaPlayerAlbum =
|
||||||
metadata.getText(MediaMetadata.METADATA_KEY_ALBUM)?.toString()
|
metadata.getText(MediaMetadata.METADATA_KEY_ALBUM)
|
||||||
|
?.toString()
|
||||||
?: ""
|
?: ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Preferences.mediaPlayerPackage = mc.packageName
|
Preferences.mediaPlayerPackage = mc.packageName
|
||||||
}
|
}
|
||||||
|
@ -63,10 +63,20 @@ object SettingsStringHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getVariantLabel(context: Context, variant: String): String = when {
|
fun getVariantLabel(context: Context, variant: String): String = when {
|
||||||
|
variant == "italic" -> context.getString(R.string.font_italic)
|
||||||
|
variant.contains("100") && variant.contains("italic") -> context.getString(R.string.font_100_italic)
|
||||||
|
variant.contains("200") && variant.contains("italic") -> context.getString(R.string.font_200_italic)
|
||||||
|
variant.contains("300") && variant.contains("italic") -> context.getString(R.string.font_300_italic)
|
||||||
|
variant.contains("400") && variant.contains("italic") -> context.getString(R.string.font_400_italic)
|
||||||
|
variant.contains("500") && variant.contains("italic") -> context.getString(R.string.font_500_italic)
|
||||||
|
variant.contains("600") && variant.contains("italic") -> context.getString(R.string.font_600_italic)
|
||||||
|
variant.contains("700") && variant.contains("italic") -> context.getString(R.string.font_700_italic)
|
||||||
|
variant.contains("800") && variant.contains("italic") -> context.getString(R.string.font_800_italic)
|
||||||
|
variant.contains("900") && variant.contains("italic") -> context.getString(R.string.font_900_italic)
|
||||||
|
variant == "regular" || variant.contains("400") -> context.getString(R.string.font_400)
|
||||||
variant.contains("100") -> context.getString(R.string.font_100)
|
variant.contains("100") -> context.getString(R.string.font_100)
|
||||||
variant.contains("200") -> context.getString(R.string.font_200)
|
variant.contains("200") -> context.getString(R.string.font_200)
|
||||||
variant.contains("300") -> context.getString(R.string.font_300)
|
variant.contains("300") -> context.getString(R.string.font_300)
|
||||||
variant.contains("regular") || variant.contains("400") -> context.getString(R.string.font_400)
|
|
||||||
variant.contains("500") -> context.getString(R.string.font_500)
|
variant.contains("500") -> context.getString(R.string.font_500)
|
||||||
variant.contains("600") -> context.getString(R.string.font_600)
|
variant.contains("600") -> context.getString(R.string.font_600)
|
||||||
variant.contains("700") -> context.getString(R.string.font_700)
|
variant.contains("700") -> context.getString(R.string.font_700)
|
||||||
@ -78,43 +88,26 @@ object SettingsStringHelper {
|
|||||||
fun getDifferenceText(context: Context, now: Long, start: Long): String {
|
fun getDifferenceText(context: Context, now: Long, start: Long): String {
|
||||||
val nowDate = DateTime(now)
|
val nowDate = DateTime(now)
|
||||||
val eventDate = DateTime(start)
|
val eventDate = DateTime(start)
|
||||||
|
val difference = start - now
|
||||||
var difference = start - now
|
|
||||||
difference += 60 * 1000 - (difference % (60 * 1000))
|
|
||||||
|
|
||||||
when {
|
when {
|
||||||
difference <= 0 -> {
|
difference <= 0 -> {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
TimeUnit.MILLISECONDS.toHours(difference) < 1 && Preferences.widgetUpdateFrequency == Constants.WidgetUpdateFrequency.HIGH.value && TimeUnit.MILLISECONDS.toMinutes(difference) > 5 -> {
|
TimeUnit.MILLISECONDS.toHours(difference) < 1 && Preferences.widgetUpdateFrequency == Constants.WidgetUpdateFrequency.HIGH.rawValue && TimeUnit.MILLISECONDS.toMinutes(difference) >= 5 -> {
|
||||||
return DateUtils.getRelativeTimeSpanString(start, start - 1000 * 60 * (TimeUnit.MILLISECONDS.toMinutes(difference) - 1 - (TimeUnit.MILLISECONDS.toMinutes(difference) - 1) % 5), DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE).toString()
|
return DateUtils.getRelativeTimeSpanString(start, start - 1000 * 60 * (TimeUnit.MILLISECONDS.toMinutes(difference) - TimeUnit.MILLISECONDS.toMinutes(difference) % 5), DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE).toString()
|
||||||
}
|
}
|
||||||
TimeUnit.MILLISECONDS.toHours(difference) < 1 && Preferences.widgetUpdateFrequency == Constants.WidgetUpdateFrequency.DEFAULT.value && TimeUnit.MILLISECONDS.toMinutes(difference) > 5 -> {
|
TimeUnit.MILLISECONDS.toHours(difference) < 1 && Preferences.widgetUpdateFrequency == Constants.WidgetUpdateFrequency.DEFAULT.rawValue && TimeUnit.MILLISECONDS.toMinutes(difference) >= 15 -> {
|
||||||
return DateUtils.getRelativeTimeSpanString(start, start - 1000 * 60 * (TimeUnit.MILLISECONDS.toMinutes(difference) - 1 - (TimeUnit.MILLISECONDS.toMinutes(difference) - 1) % 15), DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE).toString()
|
return DateUtils.getRelativeTimeSpanString(start, start - 1000 * 60 * (TimeUnit.MILLISECONDS.toMinutes(difference) - TimeUnit.MILLISECONDS.toMinutes(difference) % 15), DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE).toString()
|
||||||
}
|
}
|
||||||
TimeUnit.MILLISECONDS.toHours(difference) < 1 && Preferences.widgetUpdateFrequency == Constants.WidgetUpdateFrequency.LOW.value -> {
|
TimeUnit.MILLISECONDS.toHours(difference) < 1 && Preferences.widgetUpdateFrequency == Constants.WidgetUpdateFrequency.LOW.rawValue -> {
|
||||||
return context.getString(R.string.soon)
|
return context.getString(R.string.soon)
|
||||||
}
|
}
|
||||||
TimeUnit.MILLISECONDS.toHours(difference) < 1 -> {
|
TimeUnit.MILLISECONDS.toHours(difference) < 1 -> {
|
||||||
return context.getString(R.string.now)
|
return context.getString(R.string.now)
|
||||||
}
|
}
|
||||||
TimeUnit.MILLISECONDS.toHours(difference) < 12 -> {
|
TimeUnit.MILLISECONDS.toHours(difference) < 12 -> {
|
||||||
val minutes = TimeUnit.MILLISECONDS.toMinutes(difference) - 60 * TimeUnit.MILLISECONDS.toHours(difference)
|
return DateUtils.getRelativeTimeSpanString(start, now, DateUtils.HOUR_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE).toString()
|
||||||
return if (minutes < 1 || minutes > 30) {
|
|
||||||
DateUtils.getRelativeTimeSpanString(
|
|
||||||
start,
|
|
||||||
now - 1000 * 60 * 40,
|
|
||||||
DateUtils.HOUR_IN_MILLIS,
|
|
||||||
DateUtils.FORMAT_ABBREV_RELATIVE
|
|
||||||
).toString()
|
|
||||||
} else {
|
|
||||||
DateUtils.getRelativeTimeSpanString(
|
|
||||||
start,
|
|
||||||
now,
|
|
||||||
DateUtils.HOUR_IN_MILLIS,
|
|
||||||
DateUtils.FORMAT_ABBREV_RELATIVE
|
|
||||||
).toString()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
eventDate.dayOfYear == nowDate.plusDays(1).dayOfYear -> {
|
eventDate.dayOfYear == nowDate.plusDays(1).dayOfYear -> {
|
||||||
return String.format("%s", context.getString(R.string.tomorrow))
|
return String.format("%s", context.getString(R.string.tomorrow))
|
||||||
@ -133,9 +126,6 @@ object SettingsStringHelper {
|
|||||||
val nowDate = DateTime(now)
|
val nowDate = DateTime(now)
|
||||||
val eventDate = DateTime(start)
|
val eventDate = DateTime(start)
|
||||||
|
|
||||||
var difference = start - now
|
|
||||||
difference += 60 * 1000 - (difference % (60 * 1000))
|
|
||||||
|
|
||||||
return when (eventDate.dayOfYear) {
|
return when (eventDate.dayOfYear) {
|
||||||
nowDate.dayOfYear -> {
|
nowDate.dayOfYear -> {
|
||||||
""
|
""
|
||||||
|
@ -2,23 +2,15 @@ package com.tommasoberlose.anotherwidget.helpers
|
|||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
|
||||||
import android.util.Log
|
|
||||||
import com.chibatching.kotpref.Kotpref
|
import com.chibatching.kotpref.Kotpref
|
||||||
import com.google.android.gms.location.LocationServices
|
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import com.tommasoberlose.anotherwidget.global.Constants
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.network.WeatherNetworkApi
|
import com.tommasoberlose.anotherwidget.network.WeatherNetworkApi
|
||||||
import com.tommasoberlose.anotherwidget.services.LocationService
|
import com.tommasoberlose.anotherwidget.services.WeatherWorker
|
||||||
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,13 +19,14 @@ import org.greenrobot.eventbus.EventBus
|
|||||||
|
|
||||||
object WeatherHelper {
|
object WeatherHelper {
|
||||||
|
|
||||||
suspend fun updateWeather(context: Context) {
|
fun updateWeather(context: Context, force: Boolean = false) {
|
||||||
Kotpref.init(context)
|
if (Preferences.showWeather || force)
|
||||||
val networkApi = WeatherNetworkApi(context)
|
WeatherWorker.enqueue(context, replace = force)
|
||||||
if (Preferences.customLocationAdd != "") {
|
else {
|
||||||
networkApi.updateWeather()
|
removeWeather(context)
|
||||||
} else if (context.checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION)) {
|
org.greenrobot.eventbus.EventBus.getDefault().post(
|
||||||
LocationService.requestNewLocation(context)
|
com.tommasoberlose.anotherwidget.ui.fragments.MainFragment.UpdateUiMessageEvent()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,97 +115,97 @@ object WeatherHelper {
|
|||||||
return when (icon) {
|
return when (icon) {
|
||||||
"01d" -> {
|
"01d" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.clear_day_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.clear_day_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.clear_day_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.clear_day_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.clear_day_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.clear_day_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.clear_day_5 else R.drawable.clear_day_5_light
|
else -> if (context.isDarkTheme()) R.drawable.clear_day_5 else R.drawable.clear_day_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"02d" -> {
|
"02d" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.partly_cloudy_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.partly_cloudy_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.partly_cloudy_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.partly_cloudy_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.partly_cloudy_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.partly_cloudy_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.partly_cloudy_5 else R.drawable.partly_cloudy_5_light
|
else -> if (context.isDarkTheme()) R.drawable.partly_cloudy_5 else R.drawable.partly_cloudy_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"03d" -> {
|
"03d" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.mostly_cloudy_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.mostly_cloudy_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.mostly_cloudy_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.mostly_cloudy_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.mostly_cloudy_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.mostly_cloudy_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.mostly_cloudy_5 else R.drawable.mostly_cloudy_5_light
|
else -> if (context.isDarkTheme()) R.drawable.mostly_cloudy_5 else R.drawable.mostly_cloudy_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"04d" -> {
|
"04d" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.cloudy_weather_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.cloudy_weather_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.cloudy_weather_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.cloudy_weather_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.cloudy_weather_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.cloudy_weather_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.cloudy_weather_5 else R.drawable.cloudy_weather_5_light
|
else -> if (context.isDarkTheme()) R.drawable.cloudy_weather_5 else R.drawable.cloudy_weather_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"09d" -> {
|
"09d" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.storm_weather_day_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.storm_weather_day_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.storm_weather_day_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.storm_weather_day_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.storm_weather_day_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.storm_weather_day_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.storm_weather_day_5 else R.drawable.storm_weather_day_5_light
|
else -> if (context.isDarkTheme()) R.drawable.storm_weather_day_5 else R.drawable.storm_weather_day_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"10d" -> {
|
"10d" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.rainy_day_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.rainy_day_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rainy_day_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.rainy_day_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rainy_day_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.rainy_day_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.rainy_day_5 else R.drawable.rainy_day_5_light
|
else -> if (context.isDarkTheme()) R.drawable.rainy_day_5 else R.drawable.rainy_day_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"11d" -> {
|
"11d" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.thunder_day_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.thunder_day_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.thunder_day_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.thunder_day_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.thunder_day_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.thunder_day_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.thunder_day_5 else R.drawable.thunder_day_5_light
|
else -> if (context.isDarkTheme()) R.drawable.thunder_day_5 else R.drawable.thunder_day_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"13d" -> {
|
"13d" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.snow_day_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.snow_day_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.snow_day_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.snow_day_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.snow_day_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.snow_day_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.snow_day_5 else R.drawable.snow_day_5_light
|
else -> if (context.isDarkTheme()) R.drawable.snow_day_5 else R.drawable.snow_day_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"50d" -> {
|
"50d" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_day_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.haze_day_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_day_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.haze_day_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_day_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.haze_day_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.haze_day_5 else R.drawable.haze_day_5_light
|
else -> if (context.isDarkTheme()) R.drawable.haze_day_5 else R.drawable.haze_day_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"80d" -> {
|
"80d" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.windy_day_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.windy_day_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.windy_day_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.windy_day_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.windy_day_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.windy_day_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.windy_day_5 else R.drawable.windy_day_5_light
|
else -> if (context.isDarkTheme()) R.drawable.windy_day_5 else R.drawable.windy_day_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"81d" -> {
|
"81d" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.rain_snow_day_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.rain_snow_day_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rain_snow_day_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.rain_snow_day_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rain_snow_day_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.rain_snow_day_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.rain_snow_day_5 else R.drawable.rain_snow_day_5_light
|
else -> if (context.isDarkTheme()) R.drawable.rain_snow_day_5 else R.drawable.rain_snow_day_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"82d" -> {
|
"82d" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_weather_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.haze_weather_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_weather_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.haze_weather_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_weather_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.haze_weather_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.haze_weather_5 else R.drawable.haze_weather_5_light
|
else -> if (context.isDarkTheme()) R.drawable.haze_weather_5 else R.drawable.haze_weather_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,97 +214,97 @@ object WeatherHelper {
|
|||||||
|
|
||||||
"01n" -> {
|
"01n" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.clear_night_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.clear_night_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.clear_night_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.clear_night_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.clear_night_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.clear_night_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.clear_night_5 else R.drawable.clear_night_5_light
|
else -> if (context.isDarkTheme()) R.drawable.clear_night_5 else R.drawable.clear_night_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"02n" -> {
|
"02n" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.partly_cloudy_night_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.partly_cloudy_night_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.partly_cloudy_night_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.partly_cloudy_night_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.partly_cloudy_night_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.partly_cloudy_night_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.partly_cloudy_night_5 else R.drawable.partly_cloudy_night_5_light
|
else -> if (context.isDarkTheme()) R.drawable.partly_cloudy_night_5 else R.drawable.partly_cloudy_night_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"03n" -> {
|
"03n" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.mostly_cloudy_night_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.mostly_cloudy_night_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.mostly_cloudy_night_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.mostly_cloudy_night_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.mostly_cloudy_night_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.mostly_cloudy_night_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.mostly_cloudy_night_5 else R.drawable.mostly_cloudy_night_5_light
|
else -> if (context.isDarkTheme()) R.drawable.mostly_cloudy_night_5 else R.drawable.mostly_cloudy_night_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"04n" -> {
|
"04n" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.cloudy_weather_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.cloudy_weather_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.cloudy_weather_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.cloudy_weather_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.cloudy_weather_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.cloudy_weather_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.cloudy_weather_5 else R.drawable.cloudy_weather_5_light
|
else -> if (context.isDarkTheme()) R.drawable.cloudy_weather_5 else R.drawable.cloudy_weather_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"09n" -> {
|
"09n" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.storm_weather_night_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.storm_weather_night_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.storm_weather_night_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.storm_weather_night_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.storm_weather_night_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.storm_weather_night_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.storm_weather_night_5 else R.drawable.storm_weather_night_5_light
|
else -> if (context.isDarkTheme()) R.drawable.storm_weather_night_5 else R.drawable.storm_weather_night_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"10n" -> {
|
"10n" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.rainy_night_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.rainy_night_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rainy_night_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.rainy_night_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rainy_night_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.rainy_night_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.rainy_night_5 else R.drawable.rainy_night_5_light
|
else -> if (context.isDarkTheme()) R.drawable.rainy_night_5 else R.drawable.rainy_night_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"11n" -> {
|
"11n" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.thunder_night_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.thunder_night_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.thunder_night_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.thunder_night_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.thunder_night_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.thunder_night_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.thunder_night_5 else R.drawable.thunder_night_5_light
|
else -> if (context.isDarkTheme()) R.drawable.thunder_night_5 else R.drawable.thunder_night_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"13n" -> {
|
"13n" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.snow_night_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.snow_night_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.snow_night_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.snow_night_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.snow_night_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.snow_night_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.snow_night_5 else R.drawable.snow_night_5_light
|
else -> if (context.isDarkTheme()) R.drawable.snow_night_5 else R.drawable.snow_night_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"50n" -> {
|
"50n" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_night_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.haze_night_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_night_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.haze_night_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_night_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.haze_night_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.haze_night_5 else R.drawable.haze_night_5_light
|
else -> if (context.isDarkTheme()) R.drawable.haze_night_5 else R.drawable.haze_night_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"80n" -> {
|
"80n" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.windy_night_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.windy_night_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.windy_night_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.windy_night_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.windy_night_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.windy_night_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.windy_night_5 else R.drawable.windy_night_5_light
|
else -> if (context.isDarkTheme()) R.drawable.windy_night_5 else R.drawable.windy_night_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"81n" -> {
|
"81n" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.rain_snow_night_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.rain_snow_night_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rain_snow_night_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.rain_snow_night_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rain_snow_night_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.rain_snow_night_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.rain_snow_night_5 else R.drawable.rain_snow_night_5_light
|
else -> if (context.isDarkTheme()) R.drawable.rain_snow_night_5 else R.drawable.rain_snow_night_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"82n" -> {
|
"82n" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_weather_3
|
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.haze_weather_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_weather_2
|
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.haze_weather_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_weather_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.haze_weather_4
|
||||||
else -> if (context.isDarkTheme()) R.drawable.haze_weather_5 else R.drawable.haze_weather_5_light
|
else -> if (context.isDarkTheme()) R.drawable.haze_weather_5 else R.drawable.haze_weather_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -321,92 +314,111 @@ object WeatherHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getWeatherGovIcon(iconString: String, isDaytime: Boolean): String = when {
|
fun getWeatherLabel(context: Context, icon: String): String {
|
||||||
iconString.contains("skc") -> "01"
|
return when (icon) {
|
||||||
iconString.contains("few") -> "02"
|
"01d", "01n" -> context.getString(R.string.weather_label_clear)
|
||||||
iconString.contains("sct") -> "03"
|
"02d", "02n" -> context.getString(R.string.weather_label_partly_cloudy)
|
||||||
iconString.contains("bkn") -> "04"
|
"03d", "03n" -> context.getString(R.string.weather_label_mostly_cloudy)
|
||||||
iconString.contains("ovc") -> "04"
|
"04d", "04n" -> context.getString(R.string.weather_label_cloudy_weather)
|
||||||
iconString.contains("wind_skc") -> "01"
|
"09d", "09n" -> context.getString(R.string.weather_label_storm_weather)
|
||||||
iconString.contains("wind_few") -> "02"
|
"10d", "10n" -> context.getString(R.string.weather_label_rainy)
|
||||||
iconString.contains("wind_sct") -> "03"
|
"11d", "11n" -> context.getString(R.string.weather_label_thunder)
|
||||||
iconString.contains("wind_bkn") -> "04"
|
"13d", "13n" -> context.getString(R.string.weather_label_snow)
|
||||||
iconString.contains("wind_ovc") -> "04"
|
"50d", "50n", "82d", "82n" -> context.getString(R.string.weather_label_haze)
|
||||||
iconString.contains("snow") -> "13"
|
"80d", "80n" -> context.getString(R.string.weather_label_windy)
|
||||||
iconString.contains("rain_snow") -> "81"
|
"81d", "81n" -> context.getString(R.string.weather_label_rain_snow)
|
||||||
iconString.contains("rain_sleet") -> "81"
|
else -> context.getString(R.string.weather_label_unknown)
|
||||||
iconString.contains("snow_sleet") -> "81"
|
}
|
||||||
iconString.contains("fzra") -> "81"
|
}
|
||||||
iconString.contains("rain_fzra") -> "81"
|
|
||||||
iconString.contains("snow_fzra") -> "81"
|
fun getWeatherGovIcon(iconString: String, isDaytime: Boolean): String = when (
|
||||||
iconString.contains("sleet") -> "81"
|
iconString.substringBefore('?').substringAfterLast('/').substringBefore(',')
|
||||||
iconString.contains("rain") -> "10"
|
) {
|
||||||
iconString.contains("rain_showers") -> "10"
|
"skc" -> "01"
|
||||||
iconString.contains("rain_showers_hi") -> "10"
|
"few" -> "02"
|
||||||
iconString.contains("tsra") -> "82"
|
"sct" -> "02"
|
||||||
iconString.contains("tsra_sct") -> "82"
|
"bkn" -> "03"
|
||||||
iconString.contains("tsra_hi") -> "82"
|
"ovc" -> "04"
|
||||||
iconString.contains("tornado") -> "80"
|
"wind_skc" -> "01"
|
||||||
iconString.contains("hurricane") -> "80"
|
"wind_few" -> "02"
|
||||||
iconString.contains("tropical_storm") -> "09"
|
"wind_sct" -> "02"
|
||||||
iconString.contains("dust") -> "Dust"
|
"wind_bkn" -> "03"
|
||||||
iconString.contains("smoke") -> "Smoke"
|
"wind_ovc" -> "04"
|
||||||
iconString.contains("haze") -> "50"
|
"snow" -> "13"
|
||||||
iconString.contains("hot") -> "01"
|
"rain_snow" -> "81"
|
||||||
iconString.contains("cold") -> "13"
|
"rain_sleet" -> "81"
|
||||||
iconString.contains("blizzard") -> "80"
|
"snow_sleet" -> "81"
|
||||||
iconString.contains("fog") -> "82"
|
"fzra" -> "81"
|
||||||
|
"rain_fzra" -> "81"
|
||||||
|
"snow_fzra" -> "81"
|
||||||
|
"sleet" -> "81"
|
||||||
|
"rain" -> "10"
|
||||||
|
"rain_showers" -> "10"
|
||||||
|
"rain_showers_hi" -> "10"
|
||||||
|
"tsra" -> "09"
|
||||||
|
"tsra_sct" -> "11"
|
||||||
|
"tsra_hi" -> "11"
|
||||||
|
"tornado" -> "80"
|
||||||
|
"hurricane" -> "80"
|
||||||
|
"tropical_storm" -> "09"
|
||||||
|
"dust" -> "50"
|
||||||
|
"smoke" -> "50"
|
||||||
|
"haze" -> "50"
|
||||||
|
"hot" -> "01"
|
||||||
|
"cold" -> "13"
|
||||||
|
"blizzard" -> "13"
|
||||||
|
"fog" -> "82"
|
||||||
else -> ""
|
else -> ""
|
||||||
} + if (isDaytime) "d" else "n"
|
} + if (isDaytime) "d" else "n"
|
||||||
|
|
||||||
fun getWeatherBitIcon(iconString: String): String = when {
|
fun getWeatherBitIcon(iconString: String): String = when (iconString.substring(0, 3)) {
|
||||||
iconString.contains("t01") -> "11"
|
"t01" -> "11"
|
||||||
iconString.contains("t02") -> "09"
|
"t02" -> "11"
|
||||||
iconString.contains("t03") -> "09"
|
"t03" -> "09"
|
||||||
iconString.contains("t04") -> "09"
|
"t04" -> "11"
|
||||||
iconString.contains("t05") -> "09"
|
"t05" -> "11"
|
||||||
iconString.contains("d01") -> "10"
|
"d01" -> "10"
|
||||||
iconString.contains("d02") -> "10"
|
"d02" -> "10"
|
||||||
iconString.contains("d03") -> "10"
|
"d03" -> "10"
|
||||||
iconString.contains("r01") -> "10"
|
"r01" -> "10"
|
||||||
iconString.contains("r02") -> "10"
|
"r02" -> "10"
|
||||||
iconString.contains("r03") -> "10"
|
"r03" -> "10"
|
||||||
iconString.contains("f01") -> "10"
|
"f01" -> "10"
|
||||||
iconString.contains("r04") -> "10"
|
"r04" -> "10"
|
||||||
iconString.contains("r05") -> "10"
|
"r05" -> "10"
|
||||||
iconString.contains("r06") -> "10"
|
"r06" -> "10"
|
||||||
iconString.contains("s01") -> "13"
|
"s01" -> "13"
|
||||||
iconString.contains("s02") -> "13"
|
"s02" -> "13"
|
||||||
iconString.contains("s03") -> "13"
|
"s03" -> "13"
|
||||||
iconString.contains("s04") -> "81"
|
"s04" -> "81"
|
||||||
iconString.contains("s05") -> "90"
|
"s05" -> "81"
|
||||||
iconString.contains("s06") -> "13"
|
"s06" -> "13"
|
||||||
iconString.contains("a01") -> "82"
|
"a01" -> "50"
|
||||||
iconString.contains("a02") -> "82"
|
"a02" -> "50"
|
||||||
iconString.contains("a03") -> "82"
|
"a03" -> "50"
|
||||||
iconString.contains("a04") -> "82"
|
"a04" -> "50"
|
||||||
iconString.contains("a05") -> "82"
|
"a05" -> "82"
|
||||||
iconString.contains("a06") -> "82"
|
"a06" -> "82"
|
||||||
iconString.contains("c01") -> "01"
|
"c01" -> "01"
|
||||||
iconString.contains("c02") -> "02"
|
"c02" -> "02"
|
||||||
iconString.contains("c03") -> "04"
|
"c03" -> "03"
|
||||||
iconString.contains("c04") -> "04"
|
"c04" -> "04"
|
||||||
else -> ""
|
else -> ""
|
||||||
} + if (iconString.contains("d")) "d" else "n"
|
} + iconString.substring(3)
|
||||||
|
|
||||||
fun getWeatherApiIcon(icon: Int, isDaytime: Boolean): String = when(icon) {
|
fun getWeatherApiIcon(icon: Int, isDaytime: Boolean): String = when(icon) {
|
||||||
1000 -> "01"
|
1000 -> "01"
|
||||||
1003 -> "02"
|
1003 -> "02"
|
||||||
1006 -> "03"
|
1006 -> "03"
|
||||||
1009 -> "04"
|
1009 -> "04"
|
||||||
1030 -> "82"
|
1030 -> "50"
|
||||||
1063 -> "10"
|
1063 -> "10"
|
||||||
1066 -> "10"
|
1066 -> "13"
|
||||||
1069 -> "10"
|
1069 -> "81"
|
||||||
1072 -> "81"
|
1072 -> "81"
|
||||||
1087 -> "11"
|
1087 -> "11"
|
||||||
1114 -> "13"
|
1114 -> "13"
|
||||||
1117 -> "09"
|
1117 -> "13"
|
||||||
1135 -> "82"
|
1135 -> "82"
|
||||||
1147 -> "82"
|
1147 -> "82"
|
||||||
1150 -> "10"
|
1150 -> "10"
|
||||||
@ -421,8 +433,8 @@ object WeatherHelper {
|
|||||||
1195 -> "10"
|
1195 -> "10"
|
||||||
1198 -> "81"
|
1198 -> "81"
|
||||||
1201 -> "81"
|
1201 -> "81"
|
||||||
1204 -> "13"
|
1204 -> "81"
|
||||||
1207 -> "13"
|
1207 -> "81"
|
||||||
1210 -> "13"
|
1210 -> "13"
|
||||||
1213 -> "13"
|
1213 -> "13"
|
||||||
1216 -> "13"
|
1216 -> "13"
|
||||||
@ -433,62 +445,62 @@ object WeatherHelper {
|
|||||||
1240 -> "10"
|
1240 -> "10"
|
||||||
1243 -> "10"
|
1243 -> "10"
|
||||||
1246 -> "10"
|
1246 -> "10"
|
||||||
1249 -> "13"
|
1249 -> "81"
|
||||||
1252 -> "13"
|
1252 -> "81"
|
||||||
1255 -> "13"
|
1255 -> "13"
|
||||||
1258 -> "13"
|
1258 -> "13"
|
||||||
1261 -> "13"
|
1261 -> "13"
|
||||||
1264 -> "13"
|
1264 -> "13"
|
||||||
1273 -> "09"
|
1273 -> "11"
|
||||||
1276 -> "09"
|
1276 -> "09"
|
||||||
1279 -> "13"
|
1279 -> "13"
|
||||||
1282 -> "13"
|
1282 -> "13"
|
||||||
else -> ""
|
else -> ""
|
||||||
} + if (isDaytime) "d" else "n"
|
} + if (isDaytime) "d" else "n"
|
||||||
|
|
||||||
fun getYRIcon(iconCode: String, isDaytime: Boolean): String = when {
|
fun getYRIcon(iconCode: String): String = when (iconCode.substringBefore('_')) {
|
||||||
iconCode.contains("clearsky") -> "01"
|
"clearsky" -> "01"
|
||||||
iconCode.contains("cloudy") -> "04"
|
"cloudy" -> "04"
|
||||||
iconCode.contains("fair") -> "02"
|
"fair" -> "02"
|
||||||
iconCode.contains("fog") -> "82"
|
"fog" -> "82"
|
||||||
iconCode.contains("heavyrain") -> "10"
|
"heavyrain" -> "10"
|
||||||
iconCode.contains("heavyrainandthunder") -> "11"
|
"heavyrainandthunder" -> "09"
|
||||||
iconCode.contains("heavyrainshowers") -> "10"
|
"heavyrainshowers" -> "10"
|
||||||
iconCode.contains("heavyrainshowersandthunder") -> "11"
|
"heavyrainshowersandthunder" -> "09"
|
||||||
iconCode.contains("heavysleet") -> "10"
|
"heavysleet" -> "81"
|
||||||
iconCode.contains("heavysleetandthunder") -> "11"
|
"heavysleetandthunder" -> "81"
|
||||||
iconCode.contains("heavysleetshowers") -> "10"
|
"heavysleetshowers" -> "81"
|
||||||
iconCode.contains("heavysleetshowersandthunder") -> "11"
|
"heavysleetshowersandthunder" -> "81"
|
||||||
iconCode.contains("heavysnow") -> "13"
|
"heavysnow" -> "13"
|
||||||
iconCode.contains("heavysnowandthunder") -> "13"
|
"heavysnowandthunder" -> "13"
|
||||||
iconCode.contains("heavysnowshowers") -> "13"
|
"heavysnowshowers" -> "13"
|
||||||
iconCode.contains("heavysnowshowersandthunder") -> "13"
|
"heavysnowshowersandthunder" -> "13"
|
||||||
iconCode.contains("lightrain") -> "10"
|
"lightrain" -> "10"
|
||||||
iconCode.contains("lightrainandthunder") -> "11"
|
"lightrainandthunder" -> "11"
|
||||||
iconCode.contains("lightrainshowers") -> "10"
|
"lightrainshowers" -> "10"
|
||||||
iconCode.contains("lightrainshowersandthunder") -> "11"
|
"lightrainshowersandthunder" -> "11"
|
||||||
iconCode.contains("lightsleet") -> "10"
|
"lightsleet" -> "81"
|
||||||
iconCode.contains("lightsleetandthunder") -> "11"
|
"lightsleetandthunder" -> "81"
|
||||||
iconCode.contains("lightsleetshowers") -> "10"
|
"lightsleetshowers" -> "81"
|
||||||
iconCode.contains("lightsnow") -> "13"
|
"lightsnow" -> "13"
|
||||||
iconCode.contains("lightsnowandthunder") -> "13"
|
"lightsnowandthunder" -> "13"
|
||||||
iconCode.contains("lightsnowshowers") -> "13"
|
"lightsnowshowers" -> "13"
|
||||||
iconCode.contains("lightssleetshowersandthunder") -> "81"
|
"lightssleetshowersandthunder" -> "81"
|
||||||
iconCode.contains("lightssnowshowersandthunder") -> "81"
|
"lightssnowshowersandthunder" -> "81"
|
||||||
iconCode.contains("partlycloudy") -> "03"
|
"partlycloudy" -> "03"
|
||||||
iconCode.contains("rain") -> "10"
|
"rain" -> "10"
|
||||||
iconCode.contains("rainandthunder") -> "11"
|
"rainandthunder" -> "11"
|
||||||
iconCode.contains("rainshowers") -> "10"
|
"rainshowers" -> "10"
|
||||||
iconCode.contains("rainshowersandthunder") -> "11"
|
"rainshowersandthunder" -> "11"
|
||||||
iconCode.contains("sleet") -> "10"
|
"sleet" -> "81"
|
||||||
iconCode.contains("sleetandthunder") -> "11"
|
"sleetandthunder" -> "81"
|
||||||
iconCode.contains("sleetshowers") -> "10"
|
"sleetshowers" -> "81"
|
||||||
iconCode.contains("sleetshowersandthunder") -> "11"
|
"sleetshowersandthunder" -> "81"
|
||||||
iconCode.contains("snow") -> "13"
|
"snow" -> "13"
|
||||||
iconCode.contains("snowandthunder") -> "13"
|
"snowandthunder" -> "13"
|
||||||
iconCode.contains("snowshowers") -> "13"
|
"snowshowers" -> "13"
|
||||||
iconCode.contains("snowshowersandthunder") -> "13"
|
"snowshowersandthunder" -> "13"
|
||||||
else -> ""
|
else -> ""
|
||||||
} + if (isDaytime) "d" else "n"
|
} + if (iconCode.substringAfter('_', "day") == "day") "d" else "n"
|
||||||
|
|
||||||
}
|
}
|
@ -25,9 +25,15 @@ object WidgetHelper {
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
fun getWidgetsSize(widgetId: Int): Pair<Int, Int> {
|
fun getWidgetsSize(widgetId: Int): Pair<Int, Int> {
|
||||||
val isPortrait = context.resources.configuration.orientation == ORIENTATION_PORTRAIT
|
val portrait = context.resources.configuration.orientation == ORIENTATION_PORTRAIT
|
||||||
val width = getWidgetWidth(isPortrait, widgetId)
|
val width = getWidgetSizeInDp(
|
||||||
val height = getWidgetHeight(isPortrait, widgetId)
|
widgetId,
|
||||||
|
if (portrait) AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH else AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH
|
||||||
|
)
|
||||||
|
val height = getWidgetSizeInDp(
|
||||||
|
widgetId,
|
||||||
|
if (portrait) AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT else AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT
|
||||||
|
)
|
||||||
val widthInPx = context.dip(width)
|
val widthInPx = context.dip(width)
|
||||||
val heightInPx = context.dip(height)
|
val heightInPx = context.dip(height)
|
||||||
FirebaseCrashlytics.getInstance().setCustomKey("widthInPx", widthInPx)
|
FirebaseCrashlytics.getInstance().setCustomKey("widthInPx", widthInPx)
|
||||||
@ -35,9 +41,9 @@ object WidgetHelper {
|
|||||||
return widthInPx to heightInPx
|
return widthInPx to heightInPx
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getWidgetWidth(isPortrait: Boolean, widgetId: Int): Int = getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH)
|
private fun getWidgetWidth(widgetId: Int): Int = getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH)
|
||||||
|
|
||||||
private fun getWidgetHeight(isPortrait: Boolean, widgetId: Int): Int = getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT)
|
private fun getWidgetHeight(widgetId: Int): Int = getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT)
|
||||||
|
|
||||||
private fun getWidgetSizeInDp(widgetId: Int, key: String): Int =
|
private fun getWidgetSizeInDp(widgetId: Int, key: String): Int =
|
||||||
appWidgetManager.getAppWidgetOptions(widgetId).getInt(key, 0)
|
appWidgetManager.getAppWidgetOptions(widgetId).getInt(key, 0)
|
||||||
@ -64,21 +70,23 @@ object WidgetHelper {
|
|||||||
R.array.com_google_android_gms_fonts_certs
|
R.array.com_google_android_gms_fonts_certs
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val handlerThread = HandlerThread("generateView")
|
||||||
val callback = object : FontsContractCompat.FontRequestCallback() {
|
val callback = object : FontsContractCompat.FontRequestCallback() {
|
||||||
override fun onTypefaceRetrieved(typeface: Typeface) {
|
override fun onTypefaceRetrieved(typeface: Typeface) {
|
||||||
|
handlerThread.quit()
|
||||||
function.invoke(typeface)
|
function.invoke(typeface)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTypefaceRequestFailed(reason: Int) {
|
override fun onTypefaceRequestFailed(reason: Int) {
|
||||||
|
handlerThread.quit()
|
||||||
function.invoke(null)
|
function.invoke(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val handlerThread = HandlerThread("generateView")
|
|
||||||
handlerThread.start()
|
handlerThread.start()
|
||||||
if (Looper.myLooper() == null) {
|
//if (Looper.myLooper() == null) {
|
||||||
Looper.prepare()
|
// Looper.prepare()
|
||||||
}
|
//}
|
||||||
|
|
||||||
Handler(handlerThread.looper).run {
|
Handler(handlerThread.looper).run {
|
||||||
FontsContractCompat.requestFont(context, request, callback, this)
|
FontsContractCompat.requestFont(context, request, callback, this)
|
||||||
|
@ -1,26 +1,35 @@
|
|||||||
package com.tommasoberlose.anotherwidget.models
|
package com.tommasoberlose.anotherwidget.models
|
||||||
|
|
||||||
import android.provider.CalendarContract
|
import android.provider.CalendarContract
|
||||||
import io.realm.RealmObject
|
import androidx.room.ColumnInfo
|
||||||
import java.util.Date
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by tommaso on 05/10/17.
|
* Created by tommaso on 05/10/17.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
open class Event(
|
@Entity(tableName = "events")
|
||||||
var id: Long = 0,
|
data class Event(
|
||||||
var eventID: Long = 0,
|
@PrimaryKey
|
||||||
var title: String = "",
|
val id: Long = 0,
|
||||||
var startDate: Long = 0,
|
@ColumnInfo(name = "event_id")
|
||||||
var endDate: Long = 0,
|
val eventID: Long = 0,
|
||||||
var calendarID: Int = 0,
|
val title: String = "",
|
||||||
var allDay: Boolean = false,
|
@ColumnInfo(name = "start_date")
|
||||||
var address: String = "",
|
val startDate: Long = 0,
|
||||||
var selfAttendeeStatus: Int = CalendarContract.Attendees.ATTENDEE_STATUS_NONE,
|
@ColumnInfo(name = "end_date")
|
||||||
var availability: Int = CalendarContract.EventsEntity.AVAILABILITY_BUSY
|
val endDate: Long = 0,
|
||||||
) : RealmObject() {
|
@ColumnInfo(name = "calendar_id")
|
||||||
|
val calendarID: Long = 0,
|
||||||
|
@ColumnInfo(name = "all_day")
|
||||||
|
val allDay: Boolean = false,
|
||||||
|
val address: String = "",
|
||||||
|
@ColumnInfo(name = "self_attendee_status")
|
||||||
|
val selfAttendeeStatus: Int = CalendarContract.Attendees.ATTENDEE_STATUS_NONE,
|
||||||
|
val availability: Int = CalendarContract.EventsEntity.AVAILABILITY_BUSY
|
||||||
|
)/* {
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "Event:\nEVENT ID: " + eventID + "\nTITLE: " + title + "\nSTART DATE: " + Date(startDate) + "\nEND DATE: " + Date(endDate) + "\nCAL ID: " + calendarID + "\nADDRESS: " + address
|
return "Event:\nEVENT ID: " + eventID + "\nTITLE: " + title + "\nSTART DATE: " + Date(startDate) + "\nEND DATE: " + Date(endDate) + "\nCAL ID: " + calendarID + "\nADDRESS: " + address
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.network
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.Log
|
||||||
|
import com.chibatching.kotpref.Kotpref
|
||||||
|
import com.google.gson.internal.LinkedTreeMap
|
||||||
|
import com.haroldadmin.cnradapter.NetworkResponse
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.network.repository.TimeZonesRepository
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import java.lang.Exception
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class TimeZonesApi(val context: Context) {
|
||||||
|
suspend fun getTimeZone(lat: String, long: String): String? {
|
||||||
|
Kotpref.init(context)
|
||||||
|
val repository = TimeZonesRepository()
|
||||||
|
var id: String? = null
|
||||||
|
|
||||||
|
when (val response = repository.getTimeZone(lat, long)) {
|
||||||
|
is NetworkResponse.Success -> {
|
||||||
|
try {
|
||||||
|
id = response.body["timezoneId"] as String
|
||||||
|
} catch(ex: Exception) {
|
||||||
|
ex.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ package com.tommasoberlose.anotherwidget.network
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import com.chibatching.kotpref.Kotpref
|
||||||
import com.google.gson.internal.LinkedTreeMap
|
import com.google.gson.internal.LinkedTreeMap
|
||||||
import com.haroldadmin.cnradapter.NetworkResponse
|
import com.haroldadmin.cnradapter.NetworkResponse
|
||||||
import com.haroldadmin.cnradapter.executeWithRetry
|
import com.haroldadmin.cnradapter.executeWithRetry
|
||||||
@ -16,20 +17,19 @@ import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
|||||||
import com.tommasoberlose.anotherwidget.network.repository.*
|
import com.tommasoberlose.anotherwidget.network.repository.*
|
||||||
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import kotlin.coroutines.resume
|
||||||
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
|
||||||
class WeatherNetworkApi(val context: Context) {
|
class WeatherNetworkApi(val context: Context) {
|
||||||
suspend fun updateWeather() {
|
suspend fun updateWeather() {
|
||||||
|
Kotpref.init(context)
|
||||||
Preferences.weatherProviderError = "-"
|
Preferences.weatherProviderError = "-"
|
||||||
Preferences.weatherProviderLocationError = ""
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
|
||||||
if (Preferences.showWeather && Preferences.customLocationLat != "" && Preferences.customLocationLon != "") {
|
if (Preferences.customLocationLat != "" && Preferences.customLocationLon != "") {
|
||||||
when (Constants.WeatherProvider.fromInt(Preferences.weatherProvider)) {
|
when (Constants.WeatherProvider.fromInt(Preferences.weatherProvider)) {
|
||||||
Constants.WeatherProvider.OPEN_WEATHER -> useOpenWeatherMap(context)
|
Constants.WeatherProvider.OPEN_WEATHER -> useOpenWeatherMap(context)
|
||||||
Constants.WeatherProvider.WEATHER_GOV -> useWeatherGov(context)
|
Constants.WeatherProvider.WEATHER_GOV -> useWeatherGov(context)
|
||||||
@ -40,39 +40,67 @@ class WeatherNetworkApi(val context: Context) {
|
|||||||
Constants.WeatherProvider.YR -> useYrProvider(context)
|
Constants.WeatherProvider.YR -> useYrProvider(context)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
Preferences.weatherProviderLocationError = context.getString(R.string.weather_provider_error_missing_location)
|
||||||
|
Preferences.weatherProviderError = ""
|
||||||
|
|
||||||
WeatherHelper.removeWeather(
|
WeatherHelper.removeWeather(
|
||||||
context
|
context
|
||||||
)
|
)
|
||||||
|
|
||||||
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun useOpenWeatherMap(context: Context) {
|
private suspend fun useOpenWeatherMap(context: Context) {
|
||||||
if (Preferences.weatherProviderApiOpen != "") {
|
if (Preferences.weatherProviderApiOpen != "") {
|
||||||
val helper = OpenWeatherMapHelper(Preferences.weatherProviderApiOpen)
|
val helper = OpenWeatherMapHelper(Preferences.weatherProviderApiOpen)
|
||||||
helper.setUnits(if (Preferences.weatherTempUnit == "F") Units.IMPERIAL else Units.METRIC)
|
helper.setUnits(if (Preferences.weatherTempUnit == "F") Units.IMPERIAL else Units.METRIC)
|
||||||
|
when (val response = suspendCancellableCoroutine<Any?> { continuation ->
|
||||||
helper.getCurrentWeatherByGeoCoordinates(Preferences.customLocationLat.toDouble(), Preferences.customLocationLon.toDouble(), object :
|
helper.getCurrentWeatherByGeoCoordinates(Preferences.customLocationLat.toDouble(), Preferences.customLocationLon.toDouble(), object :
|
||||||
CurrentWeatherCallback {
|
CurrentWeatherCallback {
|
||||||
override fun onSuccess(currentWeather: CurrentWeather?) {
|
override fun onSuccess(currentWeather: CurrentWeather?) {
|
||||||
currentWeather?.let {
|
continuation.resume(currentWeather)
|
||||||
Preferences.weatherTemp = currentWeather.main.temp.toFloat()
|
|
||||||
Preferences.weatherIcon = currentWeather.weather[0].icon
|
|
||||||
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
|
|
||||||
MainWidget.updateWidget(context)
|
|
||||||
}
|
|
||||||
|
|
||||||
Preferences.weatherProviderError = ""
|
|
||||||
Preferences.weatherProviderLocationError = ""
|
|
||||||
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(throwable: Throwable?) {
|
override fun onFailure(throwable: Throwable?) {
|
||||||
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
continuation.resume(throwable)
|
||||||
Preferences.weatherProviderLocationError = ""
|
|
||||||
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}) {
|
||||||
|
is CurrentWeather -> {
|
||||||
|
Preferences.weatherTemp = response.main.temp.toFloat()
|
||||||
|
Preferences.weatherIcon = response.weather[0].icon
|
||||||
|
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
|
||||||
|
MainWidget.updateWidget(context)
|
||||||
|
|
||||||
|
Preferences.weatherProviderError = ""
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
}
|
||||||
|
is Throwable -> {
|
||||||
|
if (response.javaClass == Throwable::class.java) {
|
||||||
|
// server error, see [OpenWeatherMapHelper.handleCurrentWeatherResponse]
|
||||||
|
if (response.message?.startsWith("UnAuthorized") == true) {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_invalid_key)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
}
|
||||||
|
WeatherHelper.removeWeather(
|
||||||
|
context
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_connection)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
} else {
|
} else {
|
||||||
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_missing_key)
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_missing_key)
|
||||||
Preferences.weatherProviderLocationError = ""
|
Preferences.weatherProviderLocationError = ""
|
||||||
@ -112,8 +140,17 @@ class WeatherNetworkApi(val context: Context) {
|
|||||||
val props =
|
val props =
|
||||||
weatherResponse.body["properties"] as LinkedTreeMap<*, *>
|
weatherResponse.body["properties"] as LinkedTreeMap<*, *>
|
||||||
val periods = props["periods"] as List<*>
|
val periods = props["periods"] as List<*>
|
||||||
val now = periods[0] as LinkedTreeMap<*, *>
|
@android.annotation.SuppressLint("SimpleDateFormat")
|
||||||
|
val format = SimpleDateFormat(
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N)
|
||||||
|
"yyyy-MM-dd'T'HH:mm:ssXXX"
|
||||||
|
else
|
||||||
|
"yyyy-MM-dd'T'HH:mm:ssZ"
|
||||||
|
)
|
||||||
|
for (period in periods) {
|
||||||
|
val now = period as LinkedTreeMap<*, *>
|
||||||
|
val endTime = format.parse(now["endTime"] as String)!!
|
||||||
|
if (endTime.time > System.currentTimeMillis()) {
|
||||||
val temp = now["temperature"] as Double
|
val temp = now["temperature"] as Double
|
||||||
val fullIcon = now["icon"] as String
|
val fullIcon = now["icon"] as String
|
||||||
val isDaytime = now["isDaytime"] as Boolean
|
val isDaytime = now["isDaytime"] as Boolean
|
||||||
@ -121,16 +158,16 @@ class WeatherNetworkApi(val context: Context) {
|
|||||||
Preferences.weatherTemp = temp.toFloat()
|
Preferences.weatherTemp = temp.toFloat()
|
||||||
Preferences.weatherIcon = WeatherHelper.getWeatherGovIcon(fullIcon, isDaytime)
|
Preferences.weatherIcon = WeatherHelper.getWeatherGovIcon(fullIcon, isDaytime)
|
||||||
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
|
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
|
||||||
|
MainWidget.updateWidget(context)
|
||||||
|
|
||||||
Preferences.weatherProviderError = ""
|
Preferences.weatherProviderError = ""
|
||||||
Preferences.weatherProviderLocationError = ""
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
break
|
||||||
MainWidget.updateWidget(context)
|
}
|
||||||
|
}
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
||||||
Preferences.weatherProviderLocationError = ""
|
Preferences.weatherProviderLocationError = ""
|
||||||
} finally {
|
|
||||||
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
@ -146,14 +183,16 @@ class WeatherNetworkApi(val context: Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is NetworkResponse.ServerError -> {
|
is NetworkResponse.ServerError -> {
|
||||||
if (pointsResponse.body?.containsKey("status") == true && (pointsResponse.body?.get("status") as Double).toInt() == 404) {
|
when (pointsResponse.code) {
|
||||||
|
404 -> {
|
||||||
Preferences.weatherProviderError = ""
|
Preferences.weatherProviderError = ""
|
||||||
Preferences.weatherProviderLocationError = context.getString(R.string.weather_provider_error_wrong_location)
|
Preferences.weatherProviderLocationError = context.getString(R.string.weather_provider_error_wrong_location)
|
||||||
} else {
|
}
|
||||||
|
else -> {
|
||||||
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
||||||
Preferences.weatherProviderLocationError = ""
|
Preferences.weatherProviderLocationError = ""
|
||||||
}
|
}
|
||||||
|
}
|
||||||
WeatherHelper.removeWeather(
|
WeatherHelper.removeWeather(
|
||||||
context
|
context
|
||||||
)
|
)
|
||||||
@ -174,7 +213,18 @@ class WeatherNetworkApi(val context: Context) {
|
|||||||
when (val response = repository.getWeather()) {
|
when (val response = repository.getWeather()) {
|
||||||
is NetworkResponse.Success -> {
|
is NetworkResponse.Success -> {
|
||||||
try {
|
try {
|
||||||
Log.d("ciao - here", response.body.toString())
|
val observations = response.body["observations"] as LinkedTreeMap<*, *>
|
||||||
|
val location = (observations["location"] as List<*>).first() as LinkedTreeMap<*, *>
|
||||||
|
val observation = (location["observation"] as List<*>).first() as LinkedTreeMap<*, *>
|
||||||
|
val iconName = observation["iconName"] as String
|
||||||
|
val daylight = observation["daylight"] as String
|
||||||
|
val temperature = observation["temperature"] as String
|
||||||
|
|
||||||
|
Preferences.weatherTemp = temperature.toFloat()
|
||||||
|
Preferences.weatherIcon = repository.getWeatherIcon(iconName, daylight != "N")
|
||||||
|
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
|
||||||
|
MainWidget.updateWidget(context)
|
||||||
|
|
||||||
Preferences.weatherProviderError = ""
|
Preferences.weatherProviderError = ""
|
||||||
Preferences.weatherProviderLocationError = ""
|
Preferences.weatherProviderLocationError = ""
|
||||||
} catch(ex: Exception) {
|
} catch(ex: Exception) {
|
||||||
@ -185,8 +235,16 @@ class WeatherNetworkApi(val context: Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is NetworkResponse.ServerError -> {
|
is NetworkResponse.ServerError -> {
|
||||||
|
when (response.code) {
|
||||||
|
401 -> {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_invalid_key)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
||||||
Preferences.weatherProviderLocationError = ""
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
WeatherHelper.removeWeather(
|
WeatherHelper.removeWeather(
|
||||||
context
|
context
|
||||||
)
|
)
|
||||||
@ -216,10 +274,10 @@ class WeatherNetworkApi(val context: Context) {
|
|||||||
when (val response = repository.getWeather()) {
|
when (val response = repository.getWeather()) {
|
||||||
is NetworkResponse.Success -> {
|
is NetworkResponse.Success -> {
|
||||||
try {
|
try {
|
||||||
val data = response.body["data"] as List<LinkedTreeMap<String, Any>>?
|
val data = response.body["data"] as List<*>?
|
||||||
data?.first()?.let {
|
data?.first()?.let { it as LinkedTreeMap<*, *>
|
||||||
val temp = it["temp"] as Double
|
val temp = it["temp"] as Double
|
||||||
val weatherInfo = it["weather"] as LinkedTreeMap<String, Any>
|
val weatherInfo = it["weather"] as LinkedTreeMap<*, *>
|
||||||
val iconCode = weatherInfo["icon"] as String
|
val iconCode = weatherInfo["icon"] as String
|
||||||
|
|
||||||
Preferences.weatherTemp = temp.toFloat()
|
Preferences.weatherTemp = temp.toFloat()
|
||||||
@ -229,8 +287,6 @@ class WeatherNetworkApi(val context: Context) {
|
|||||||
|
|
||||||
Preferences.weatherProviderError = ""
|
Preferences.weatherProviderError = ""
|
||||||
Preferences.weatherProviderLocationError = ""
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
|
||||||
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
|
||||||
}
|
}
|
||||||
} catch(ex: Exception) {
|
} catch(ex: Exception) {
|
||||||
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
||||||
@ -279,12 +335,12 @@ class WeatherNetworkApi(val context: Context) {
|
|||||||
when (val response = repository.getWeather()) {
|
when (val response = repository.getWeather()) {
|
||||||
is NetworkResponse.Success -> {
|
is NetworkResponse.Success -> {
|
||||||
try {
|
try {
|
||||||
val current = response.body["current"] as LinkedTreeMap<String, Any>?
|
val current = response.body["current"] as LinkedTreeMap<*, *>?
|
||||||
current?.let {
|
current?.let {
|
||||||
val tempC = current["temp_c"] as Double
|
val tempC = current["temp_c"] as Double
|
||||||
val tempF = current["temp_f"] as Double
|
val tempF = current["temp_f"] as Double
|
||||||
val isDay = current["is_day"] as Double
|
val isDay = current["is_day"] as Double
|
||||||
val condition = current["condition"] as LinkedTreeMap<String, Any>
|
val condition = current["condition"] as LinkedTreeMap<*, *>
|
||||||
val iconCode = condition["code"] as Double
|
val iconCode = condition["code"] as Double
|
||||||
|
|
||||||
Preferences.weatherTemp = if (Preferences.weatherTempUnit == "F") tempF.toFloat() else tempC.toFloat()
|
Preferences.weatherTemp = if (Preferences.weatherTempUnit == "F") tempF.toFloat() else tempC.toFloat()
|
||||||
@ -294,8 +350,6 @@ class WeatherNetworkApi(val context: Context) {
|
|||||||
|
|
||||||
Preferences.weatherProviderError = ""
|
Preferences.weatherProviderError = ""
|
||||||
Preferences.weatherProviderLocationError = ""
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
|
||||||
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
|
||||||
}
|
}
|
||||||
} catch(ex: Exception) {
|
} catch(ex: Exception) {
|
||||||
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
||||||
@ -346,26 +400,72 @@ class WeatherNetworkApi(val context: Context) {
|
|||||||
if (Preferences.weatherProviderApiAccuweather != "") {
|
if (Preferences.weatherProviderApiAccuweather != "") {
|
||||||
val repository = AccuweatherRepository()
|
val repository = AccuweatherRepository()
|
||||||
|
|
||||||
// when (val response = repository.getWeather()) {
|
when (val locationResponse = repository.getLocation()) {
|
||||||
// is NetworkResponse.Success -> {
|
is NetworkResponse.Success -> {
|
||||||
// try {
|
try {
|
||||||
// Log.d("ciao", response.body.toString())
|
val key = locationResponse.body["Key"] as String
|
||||||
// } catch(ex: Exception) {
|
|
||||||
//
|
|
||||||
// Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_missing_key)
|
|
||||||
// Preferences.weatherProviderLocationError = ""
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// is NetworkResponse.ServerError -> {
|
|
||||||
// WeatherHelper.removeWeather(
|
|
||||||
// context
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_missing_key)
|
|
||||||
// Preferences.weatherProviderLocationError = ""
|
|
||||||
// EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
when (val weatherResponse = repository.getWeather(key)) {
|
||||||
|
is NetworkResponse.Success -> {
|
||||||
|
try {
|
||||||
|
weatherResponse.body.first().let {
|
||||||
|
val temp = it["Temperature"] as LinkedTreeMap<*, *>
|
||||||
|
val tempC = (temp["Metric"] as LinkedTreeMap<*, *>)["Value"] as Double
|
||||||
|
val tempF = (temp["Imperial"] as LinkedTreeMap<*, *>)["Value"] as Double
|
||||||
|
val isDay = it["IsDayTime"] as Boolean
|
||||||
|
val icon = it["WeatherIcon"] as Double
|
||||||
|
|
||||||
|
Preferences.weatherTemp = if (Preferences.weatherTempUnit == "F") tempF.toFloat() else tempC.toFloat()
|
||||||
|
Preferences.weatherIcon = repository.getWeatherIcon(icon.toInt(), isDay)
|
||||||
|
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
|
||||||
|
MainWidget.updateWidget(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
Preferences.weatherProviderError = ""
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_connection)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(ex: Exception) {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
} finally {
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is NetworkResponse.ServerError -> {
|
||||||
|
when (locationResponse.code) {
|
||||||
|
401 -> {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_invalid_key)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
}
|
||||||
|
503 -> {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_expired_key)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WeatherHelper.removeWeather(
|
||||||
|
context
|
||||||
|
)
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_connection)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_missing_key)
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_missing_key)
|
||||||
Preferences.weatherProviderLocationError = ""
|
Preferences.weatherProviderLocationError = ""
|
||||||
@ -384,14 +484,9 @@ class WeatherNetworkApi(val context: Context) {
|
|||||||
is NetworkResponse.Success -> {
|
is NetworkResponse.Success -> {
|
||||||
try {
|
try {
|
||||||
val pp = response.body["properties"] as LinkedTreeMap<*, *>
|
val pp = response.body["properties"] as LinkedTreeMap<*, *>
|
||||||
val data = pp["timeseries"] as List<LinkedTreeMap<String, Any>>?
|
val data = pp["timeseries"] as List<*>?
|
||||||
data?.let {
|
data?.first()?.let { it as LinkedTreeMap<*, *>
|
||||||
val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
|
val dd = it["data"] as LinkedTreeMap<*, *>
|
||||||
for (item in data) {
|
|
||||||
val time = Calendar.getInstance().apply { time = format.parse(item["time"] as String)!! }
|
|
||||||
val now = Calendar.getInstance()
|
|
||||||
if (time.timeInMillis >= now.timeInMillis) {
|
|
||||||
val dd = item["data"] as LinkedTreeMap<*, *>
|
|
||||||
val instant = dd["instant"] as LinkedTreeMap<*, *>
|
val instant = dd["instant"] as LinkedTreeMap<*, *>
|
||||||
val next = dd["next_1_hours"] as LinkedTreeMap<*, *>
|
val next = dd["next_1_hours"] as LinkedTreeMap<*, *>
|
||||||
|
|
||||||
@ -402,20 +497,14 @@ class WeatherNetworkApi(val context: Context) {
|
|||||||
val iconCode = summary["symbol_code"] as String
|
val iconCode = summary["symbol_code"] as String
|
||||||
|
|
||||||
Preferences.weatherTemp = temp.toFloat()
|
Preferences.weatherTemp = temp.toFloat()
|
||||||
Preferences.weatherIcon = WeatherHelper.getYRIcon(iconCode, now.get(Calendar.HOUR_OF_DAY) >= 22 || now.get(Calendar.HOUR_OF_DAY) <= 8)
|
Preferences.weatherIcon = WeatherHelper.getYRIcon(iconCode)
|
||||||
Preferences.weatherTempUnit = "C"
|
Preferences.weatherTempUnit = "C"
|
||||||
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
|
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
|
||||||
MainWidget.updateWidget(context)
|
MainWidget.updateWidget(context)
|
||||||
|
|
||||||
Preferences.weatherProviderError = ""
|
Preferences.weatherProviderError = ""
|
||||||
Preferences.weatherProviderLocationError = ""
|
Preferences.weatherProviderLocationError = ""
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} catch(ex: Exception) {
|
} catch(ex: Exception) {
|
||||||
ex.printStackTrace()
|
ex.printStackTrace()
|
||||||
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
||||||
|
@ -13,7 +13,7 @@ object ApiServices {
|
|||||||
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
|
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
|
||||||
|
|
||||||
@Headers("User-Agent: (Another Widget, tommaso.berlose@gmail.com)")
|
@Headers("User-Agent: (Another Widget, tommaso.berlose@gmail.com)")
|
||||||
@GET("gridpoints/{gridId}/{gridX},{gridY}/forecast")
|
@GET("gridpoints/{gridId}/{gridX},{gridY}/forecast/hourly")
|
||||||
suspend fun getWeather(
|
suspend fun getWeather(
|
||||||
@Path("gridId") gridId: String,
|
@Path("gridId") gridId: String,
|
||||||
@Path("gridX") gridX: Int,
|
@Path("gridX") gridX: Int,
|
||||||
@ -54,13 +54,17 @@ object ApiServices {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface AccuweatherService {
|
interface AccuweatherService {
|
||||||
@GET("")
|
@GET("locations/v1/cities/geoposition/search")
|
||||||
suspend fun getWeather(
|
suspend fun getLocation(
|
||||||
@Path("gridId") gridId: String,
|
@Query("apikey") apikey: String,
|
||||||
@Path("gridX") gridX: Int,
|
@Query("q") location: String
|
||||||
@Path("gridY") gridY: Int,
|
|
||||||
@Query("units") unit: String
|
|
||||||
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
|
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
|
||||||
|
|
||||||
|
@GET("currentconditions/v1/{locationKey}")
|
||||||
|
suspend fun getWeather(
|
||||||
|
@Path("locationKey") locationKey: String,
|
||||||
|
@Query("apikey") apikey: String
|
||||||
|
): NetworkResponse<List<HashMap<String, Any>>, HashMap<String, Any>>
|
||||||
}
|
}
|
||||||
|
|
||||||
interface YrService {
|
interface YrService {
|
||||||
@ -71,4 +75,13 @@ object ApiServices {
|
|||||||
@Query("lon") lon: String,
|
@Query("lon") lon: String,
|
||||||
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
|
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface TimeZonesService {
|
||||||
|
@GET("timezoneJSON")
|
||||||
|
suspend fun getTimeZone(
|
||||||
|
@Query("lat") lat: String,
|
||||||
|
@Query("lng") lon: String,
|
||||||
|
@Query("username") username: String = "tommaso.berlose",
|
||||||
|
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package com.tommasoberlose.anotherwidget.network.repository
|
package com.tommasoberlose.anotherwidget.network.repository
|
||||||
|
|
||||||
import com.haroldadmin.cnradapter.NetworkResponseAdapterFactory
|
import com.haroldadmin.cnradapter.NetworkResponseAdapterFactory
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.network.api.ApiServices
|
import com.tommasoberlose.anotherwidget.network.api.ApiServices
|
||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
import retrofit2.converter.gson.GsonConverterFactory
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
@ -9,10 +10,11 @@ class AccuweatherRepository {
|
|||||||
|
|
||||||
/* ACCUWEATHER */
|
/* ACCUWEATHER */
|
||||||
private val apiServiceAccu: ApiServices.AccuweatherService = getRetrofit().create(ApiServices.AccuweatherService::class.java)
|
private val apiServiceAccu: ApiServices.AccuweatherService = getRetrofit().create(ApiServices.AccuweatherService::class.java)
|
||||||
suspend fun getWeather(): Nothing = TODO()
|
suspend fun getLocation() = apiServiceAccu.getLocation(Preferences.weatherProviderApiAccuweather, "${Preferences.customLocationLat},${Preferences.customLocationLon}")
|
||||||
|
suspend fun getWeather(locationKey: String) = apiServiceAccu.getWeather(locationKey, Preferences.weatherProviderApiAccuweather)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val BASE_URL_ACCU = ""
|
private const val BASE_URL_ACCU = "https://dataservice.accuweather.com/"
|
||||||
|
|
||||||
private fun getRetrofit(): Retrofit {
|
private fun getRetrofit(): Retrofit {
|
||||||
return Retrofit.Builder()
|
return Retrofit.Builder()
|
||||||
@ -22,4 +24,20 @@ class AccuweatherRepository {
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getWeatherIcon(icon: Int, isDaytime: Boolean): String = when(icon) {
|
||||||
|
1, 2, 30, 33, 34 -> "01"
|
||||||
|
3, 4, 35, 36 -> "02"
|
||||||
|
5, 37 -> "50"
|
||||||
|
6, 38 -> "03"
|
||||||
|
7, 8 -> "04"
|
||||||
|
11 -> "82"
|
||||||
|
12, 13, 14, 18, 39, 40 -> "10"
|
||||||
|
15 -> "09"
|
||||||
|
16, 17, 41, 42 -> "11"
|
||||||
|
32 -> "80"
|
||||||
|
19, 20, 21, 22, 23, 24, 31, 43, 44 -> "13"
|
||||||
|
25, 26, 29 -> "81"
|
||||||
|
else -> ""
|
||||||
|
} + if (isDaytime) "d" else "n"
|
||||||
}
|
}
|
@ -23,4 +23,157 @@ class HereRepository {
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getWeatherIcon(iconName: String, isDaytime: Boolean): String = when(iconName.substringAfter("night_")) {
|
||||||
|
"sunny" -> "01"
|
||||||
|
"clear" -> "01"
|
||||||
|
"mostly_sunny" -> "01"
|
||||||
|
"mostly_clear" -> "01"
|
||||||
|
"passing_clounds" -> "02"
|
||||||
|
"more_sun_than_clouds" -> "02"
|
||||||
|
"scattered_clouds" -> "02"
|
||||||
|
"partly_cloudy" -> "02"
|
||||||
|
"a_mixture_of_sun_and_clouds" -> "03"
|
||||||
|
"increasing_cloudiness" -> "03"
|
||||||
|
"breaks_of_sun_late" -> "03"
|
||||||
|
"afternoon_clouds" -> "03"
|
||||||
|
"morning_clouds" -> "03"
|
||||||
|
"partly_sunny" -> "03"
|
||||||
|
"high_level_clouds" -> "03"
|
||||||
|
"decreasing_cloudiness" -> "03"
|
||||||
|
"clearing_skies" -> "01"
|
||||||
|
"high_clouds" -> "03"
|
||||||
|
"rain_early" -> "10"
|
||||||
|
"heavy_rain_early" -> "10"
|
||||||
|
"strong_thunderstorms" -> "09"
|
||||||
|
"severe_thunderstorms" -> "09"
|
||||||
|
"thundershowers" -> "11"
|
||||||
|
"thunderstorms" -> "11"
|
||||||
|
"tstorms_early" -> "11"
|
||||||
|
"isolated_tstorms_late" -> "11"
|
||||||
|
"scattered_tstorms_late" -> "11"
|
||||||
|
"tstorms_late" -> "11"
|
||||||
|
"tstorms" -> "11"
|
||||||
|
"ice_fog" -> "82"
|
||||||
|
"more_clouds_than_sun" -> "03"
|
||||||
|
"broken_clouds" -> "03"
|
||||||
|
"scattered_showers" -> "10"
|
||||||
|
"a_few_showers" -> "10"
|
||||||
|
"light_showers" -> "10"
|
||||||
|
"passing_showers" -> "10"
|
||||||
|
"rain_showers" -> "10"
|
||||||
|
"showers" -> "10"
|
||||||
|
"widely_scattered_tstorms" -> "11"
|
||||||
|
"isolated_tstorms" -> "11"
|
||||||
|
"a_few_tstorms" -> "11"
|
||||||
|
"scattered_tstorms" -> "11"
|
||||||
|
"hazy_sunshine" -> "50"
|
||||||
|
"haze" -> "50"
|
||||||
|
"smoke" -> "50"
|
||||||
|
"low_level_haze" -> "50"
|
||||||
|
"early_fog_followed_by_sunny_skies" -> "50"
|
||||||
|
"early_fog" -> "82"
|
||||||
|
"light_fog" -> "82"
|
||||||
|
"fog" -> "82"
|
||||||
|
"dense_fog" -> "82"
|
||||||
|
//"night_haze"
|
||||||
|
//"night_smoke"
|
||||||
|
//"night_low_level_haze"
|
||||||
|
//"night_widely_scattered_tstorms"
|
||||||
|
//"night_isolated_tstorms"
|
||||||
|
//"night_a_few_tstorms"
|
||||||
|
//"night_scattered_tstorms"
|
||||||
|
//"night_tstorms"
|
||||||
|
//"night_clear"
|
||||||
|
"mostly_cloudy" -> "03"
|
||||||
|
"cloudy" -> "04"
|
||||||
|
"overcast" -> "04"
|
||||||
|
"low_clouds" -> "03"
|
||||||
|
"hail" -> "10"
|
||||||
|
"sleet" -> "81"
|
||||||
|
"light_mixture_of_precip" -> "81"
|
||||||
|
"icy_mix" -> "81"
|
||||||
|
"mixture_of_precip" -> "81"
|
||||||
|
"heavy_mixture_of_precip" -> "81"
|
||||||
|
"snow_changing_to_rain" -> "81"
|
||||||
|
"snow_changing_to_an_icy_mix" -> "81"
|
||||||
|
"an_icy_mix_changing_to_snow" -> "81"
|
||||||
|
"an_icy_mix_changing_to_rain" -> "81"
|
||||||
|
"rain_changing_to_snow" -> "81"
|
||||||
|
"rain_changing_to_an_icy_mix" -> "81"
|
||||||
|
"light_icy_mix_early" -> "81"
|
||||||
|
"icy_mix_early" -> "81"
|
||||||
|
"light_icy_mix_late" -> "81"
|
||||||
|
"icy_mix_late" -> "81"
|
||||||
|
"snow_rain_mix" -> "81"
|
||||||
|
"scattered_flurries" -> "13"
|
||||||
|
"snow_flurries" -> "13"
|
||||||
|
"light_snow_showers" -> "13"
|
||||||
|
"snow_showers" -> "13"
|
||||||
|
"light_snow" -> "13"
|
||||||
|
"flurries_early" -> "13"
|
||||||
|
"snow_showers_early" -> "13"
|
||||||
|
"light_snow_early" -> "13"
|
||||||
|
"flurries_late" -> "13"
|
||||||
|
"snow_showers_late" -> "13"
|
||||||
|
"light_snow_late" -> "13"
|
||||||
|
//"night_decreasing_cloudiness"
|
||||||
|
//"night_clearing_skies"
|
||||||
|
//"night_high_level_clouds"
|
||||||
|
//"night_high_clouds"
|
||||||
|
//"night_scattered_showers"
|
||||||
|
//"night_a_few_showers"
|
||||||
|
//"night_light_showers"
|
||||||
|
//"night_passing_showers"
|
||||||
|
//"night_rain_showers"
|
||||||
|
//"night_sprinkles"
|
||||||
|
//"night_showers"
|
||||||
|
//"night_mostly_clear"
|
||||||
|
//"night_passing_clouds"
|
||||||
|
//"night_scattered_clouds"
|
||||||
|
//"night_partly_cloudy"
|
||||||
|
//"increasing_cloudiness"
|
||||||
|
//"night_afternoon_clouds"
|
||||||
|
//"night_morning_clouds"
|
||||||
|
//"night_broken_clouds"
|
||||||
|
//"night_mostly_cloudy"
|
||||||
|
"light_freezing_rain" -> "81"
|
||||||
|
"freezing_rain" -> "81"
|
||||||
|
"heavy_rain" -> "10"
|
||||||
|
"lots_of_rain" -> "10"
|
||||||
|
"tons_of_rain" -> "10"
|
||||||
|
//"heavy_rain_early" -> "10"
|
||||||
|
"heavy_rain_late" -> "10"
|
||||||
|
"flash_floods" -> "10"
|
||||||
|
"flood" -> "10"
|
||||||
|
"drizzle" -> "10"
|
||||||
|
"sprinkles" -> "10"
|
||||||
|
"light_rain" -> "10"
|
||||||
|
"sprinkles_early" -> "10"
|
||||||
|
"light_rain_early" -> "10"
|
||||||
|
"sprinkles_late" -> "10"
|
||||||
|
"light_rain_late" -> "10"
|
||||||
|
"rain" -> "10"
|
||||||
|
"numerous_showers" -> "10"
|
||||||
|
"showery" -> "10"
|
||||||
|
"showers_early" -> "10"
|
||||||
|
//"rain_early" -> "10"
|
||||||
|
"showers_late" -> "10"
|
||||||
|
"rain_late" -> "10"
|
||||||
|
"snow" -> "13"
|
||||||
|
"moderate_snow" -> "13"
|
||||||
|
"snow_early" -> "13"
|
||||||
|
"snow_late" -> "13"
|
||||||
|
"heavy_snow" -> "13"
|
||||||
|
"heavy_snow_early" -> "13"
|
||||||
|
"heavy_snow_late" -> "13"
|
||||||
|
"tornado" -> "80"
|
||||||
|
"tropical_storm" -> "09"
|
||||||
|
"hurricane" -> "80"
|
||||||
|
"sandstorm" -> "50"
|
||||||
|
"duststorm" -> "50"
|
||||||
|
"snowstorm" -> "13"
|
||||||
|
"blizzard" -> "13"
|
||||||
|
else -> ""
|
||||||
|
} + if (isDaytime) "d" else "n"
|
||||||
}
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.network.repository
|
||||||
|
|
||||||
|
import com.haroldadmin.cnradapter.NetworkResponseAdapterFactory
|
||||||
|
import com.tommasoberlose.anotherwidget.network.api.ApiServices
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
|
||||||
|
class TimeZonesRepository {
|
||||||
|
|
||||||
|
/* YR */
|
||||||
|
private val apiService: ApiServices.TimeZonesService = getRetrofit().create(ApiServices.TimeZonesService::class.java)
|
||||||
|
suspend fun getTimeZone(lat: String, long: String) = apiService.getTimeZone(lat, long)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val BASE_URL_YR = "http://api.geonames.org/"
|
||||||
|
|
||||||
|
private fun getRetrofit(): Retrofit {
|
||||||
|
return Retrofit.Builder()
|
||||||
|
.baseUrl(BASE_URL_YR)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
|
.addCallAdapterFactory(NetworkResponseAdapterFactory())
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,7 @@ import com.google.android.gms.location.*
|
|||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.setExactIfCanSchedule
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
@ -32,11 +33,11 @@ class ActivityDetectionReceiver : BroadcastReceiver() {
|
|||||||
val result = ActivityTransitionResult.extractResult(intent)!!
|
val result = ActivityTransitionResult.extractResult(intent)!!
|
||||||
val lastEvent = result.transitionEvents.last()
|
val lastEvent = result.transitionEvents.last()
|
||||||
|
|
||||||
if (lastEvent.activityType == DetectedActivity.WALKING || lastEvent.activityType == DetectedActivity.RUNNING && lastEvent.transitionType == ActivityTransition.ACTIVITY_TRANSITION_EXIT) {
|
if ((lastEvent.activityType == DetectedActivity.WALKING || lastEvent.activityType == DetectedActivity.RUNNING) && lastEvent.transitionType == ActivityTransition.ACTIVITY_TRANSITION_EXIT) {
|
||||||
requestDailySteps(context)
|
requestDailySteps(context)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (intent.action == Intent.ACTION_BOOT_COMPLETED || intent.action == Intent.ACTION_MY_PACKAGE_REPLACED && Preferences.showDailySteps && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || context.checkGrantedPermission(Manifest.permission.ACTIVITY_RECOGNITION)) {
|
if ((intent.action == Intent.ACTION_BOOT_COMPLETED || intent.action == Intent.ACTION_MY_PACKAGE_REPLACED) && Preferences.showDailySteps && (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || context.checkGrantedPermission(Manifest.permission.ACTIVITY_RECOGNITION))) {
|
||||||
resetDailySteps(context)
|
resetDailySteps(context)
|
||||||
registerFence(context)
|
registerFence(context)
|
||||||
} else {
|
} else {
|
||||||
@ -45,13 +46,6 @@ class ActivityDetectionReceiver : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resetDailySteps(context: Context) {
|
|
||||||
Kotpref.init(context)
|
|
||||||
Preferences.blockingBulk {
|
|
||||||
remove(Preferences::googleFitSteps)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val FITNESS_OPTIONS: FitnessOptions = FitnessOptions.builder()
|
val FITNESS_OPTIONS: FitnessOptions = FitnessOptions.builder()
|
||||||
.addDataType(DataType.TYPE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
|
.addDataType(DataType.TYPE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
|
||||||
@ -86,7 +80,7 @@ class ActivityDetectionReceiver : BroadcastReceiver() {
|
|||||||
context,
|
context,
|
||||||
2,
|
2,
|
||||||
Intent(context, ActivityDetectionReceiver::class.java),
|
Intent(context, ActivityDetectionReceiver::class.java),
|
||||||
0
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -105,7 +99,7 @@ class ActivityDetectionReceiver : BroadcastReceiver() {
|
|||||||
context,
|
context,
|
||||||
2,
|
2,
|
||||||
Intent(context, ActivityDetectionReceiver::class.java),
|
Intent(context, ActivityDetectionReceiver::class.java),
|
||||||
0
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -115,10 +109,13 @@ class ActivityDetectionReceiver : BroadcastReceiver() {
|
|||||||
context,
|
context,
|
||||||
2,
|
2,
|
||||||
Intent(context, ActivityDetectionReceiver::class.java),
|
Intent(context, ActivityDetectionReceiver::class.java),
|
||||||
0
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
).cancel()
|
).cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetDailySteps(context)
|
||||||
|
clearTimeout(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requestDailySteps(context: Context) {
|
fun requestDailySteps(context: Context) {
|
||||||
@ -138,10 +135,8 @@ class ActivityDetectionReceiver : BroadcastReceiver() {
|
|||||||
val endTime: Long = cal.timeInMillis
|
val endTime: Long = cal.timeInMillis
|
||||||
|
|
||||||
val readRequest = DataReadRequest.Builder()
|
val readRequest = DataReadRequest.Builder()
|
||||||
.aggregate(
|
.aggregate(DataType.TYPE_STEP_COUNT_DELTA)
|
||||||
DataType.TYPE_STEP_COUNT_DELTA,
|
.aggregate(DataType.AGGREGATE_STEP_COUNT_DELTA)
|
||||||
DataType.AGGREGATE_STEP_COUNT_DELTA
|
|
||||||
)
|
|
||||||
.setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
|
.setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
|
||||||
.bucketByTime(1, TimeUnit.DAYS)
|
.bucketByTime(1, TimeUnit.DAYS)
|
||||||
.build()
|
.build()
|
||||||
@ -164,17 +159,36 @@ class ActivityDetectionReceiver : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun resetDailySteps(context: Context) {
|
||||||
|
Kotpref.init(context)
|
||||||
|
Preferences.blockingBulk {
|
||||||
|
remove(Preferences::googleFitSteps)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun setTimeout(context: Context) {
|
private fun setTimeout(context: Context) {
|
||||||
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
cancel(PendingIntent.getBroadcast(context, 5, Intent(context, ActivityDetectionReceiver::class.java), 0))
|
setExactIfCanSchedule(
|
||||||
setExact(
|
|
||||||
AlarmManager.RTC,
|
AlarmManager.RTC,
|
||||||
Calendar.getInstance().timeInMillis + 5 * 60 * 1000,
|
Calendar.getInstance().timeInMillis + 5 * 60 * 1000,
|
||||||
PendingIntent.getBroadcast(
|
PendingIntent.getBroadcast(
|
||||||
context,
|
context,
|
||||||
5,
|
5,
|
||||||
Intent(context, ActivityDetectionReceiver::class.java),
|
Intent(context, ActivityDetectionReceiver::class.java),
|
||||||
0
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clearTimeout(context: Context) {
|
||||||
|
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
|
cancel(
|
||||||
|
PendingIntent.getBroadcast(
|
||||||
|
context,
|
||||||
|
5,
|
||||||
|
Intent(context, ActivityDetectionReceiver::class.java),
|
||||||
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
package com.tommasoberlose.anotherwidget.receivers
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.util.Log
|
|
||||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Actions
|
|
||||||
import java.lang.Exception
|
|
||||||
|
|
||||||
class CrashlyticsReceiver : BroadcastReceiver() {
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
|
||||||
if (intent.action == Actions.ACTION_REPORT_CRASH) {
|
|
||||||
val exception: Exception = intent.getSerializableExtra(EXCEPTION) as Exception
|
|
||||||
FirebaseCrashlytics.getInstance().recordException(exception)
|
|
||||||
FirebaseCrashlytics.getInstance().sendUnsentReports()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val EXCEPTION = "EXCEPTION"
|
|
||||||
|
|
||||||
fun sendCrash(context: Context, exception: Exception) {
|
|
||||||
context.sendBroadcast(Intent(context, CrashlyticsReceiver::class.java).apply {
|
|
||||||
action = Actions.ACTION_REPORT_CRASH
|
|
||||||
putExtra(EXCEPTION, exception)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -13,8 +13,7 @@ class NewCalendarEventReceiver : BroadcastReceiver() {
|
|||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
val eventRepository = EventRepository(context)
|
val eventRepository = EventRepository(context)
|
||||||
when (intent.action) {
|
when (intent.action) {
|
||||||
Intent.ACTION_PROVIDER_CHANGED,
|
Intent.ACTION_PROVIDER_CHANGED -> {
|
||||||
Intent.ACTION_TIME_CHANGED -> {
|
|
||||||
CalendarHelper.updateEventList(context)
|
CalendarHelper.updateEventList(context)
|
||||||
}
|
}
|
||||||
Actions.ACTION_GO_TO_NEXT_EVENT -> {
|
Actions.ACTION_GO_TO_NEXT_EVENT -> {
|
||||||
|
@ -9,12 +9,14 @@ import android.service.notification.NotificationListenerService
|
|||||||
import android.service.notification.StatusBarNotification
|
import android.service.notification.StatusBarNotification
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import com.google.gson.Gson
|
||||||
import com.tommasoberlose.anotherwidget.global.Actions
|
import com.tommasoberlose.anotherwidget.global.Actions
|
||||||
import com.tommasoberlose.anotherwidget.global.Constants
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
||||||
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.setExactIfCanSchedule
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@ -22,25 +24,33 @@ import java.util.*
|
|||||||
class NotificationListener : NotificationListenerService() {
|
class NotificationListener : NotificationListenerService() {
|
||||||
override fun onListenerConnected() {
|
override fun onListenerConnected() {
|
||||||
MediaPlayerHelper.updatePlayingMediaInfo(this)
|
MediaPlayerHelper.updatePlayingMediaInfo(this)
|
||||||
MainWidget.updateWidget(this)
|
ActiveNotificationsHelper.clearLastNotification(this)
|
||||||
super.onListenerConnected()
|
super.onListenerConnected()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onListenerDisconnected() {
|
||||||
|
MediaPlayerHelper.updatePlayingMediaInfo(this)
|
||||||
|
ActiveNotificationsHelper.clearLastNotification(this)
|
||||||
|
super.onListenerDisconnected()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onNotificationPosted(sbn: StatusBarNotification?) {
|
override fun onNotificationPosted(sbn: StatusBarNotification?) {
|
||||||
sbn?.notification?.extras?.let { bundle ->
|
sbn?.notification?.extras?.let { bundle ->
|
||||||
bundle.getParcelable<MediaSession.Token>(Notification.EXTRA_MEDIA_SESSION)?.let {
|
bundle.getParcelable<MediaSession.Token>(Notification.EXTRA_MEDIA_SESSION)?.let {
|
||||||
|
if (Preferences.showMusic)
|
||||||
MediaPlayerHelper.updatePlayingMediaInfo(this)
|
MediaPlayerHelper.updatePlayingMediaInfo(this)
|
||||||
} ?: run {
|
} ?: run {
|
||||||
val isGroupHeader = sbn.notification.flags and Notification.FLAG_GROUP_SUMMARY != 0
|
val isGroupHeader = sbn.notification.flags and Notification.FLAG_GROUP_SUMMARY != 0
|
||||||
val isOngoing = sbn.notification.flags and Notification.FLAG_ONGOING_EVENT != 0
|
val isOngoing = sbn.notification.flags and Notification.FLAG_ONGOING_EVENT != 0
|
||||||
|
|
||||||
if (bundle.containsKey(Notification.EXTRA_TITLE) && !isGroupHeader && !isOngoing && ActiveNotificationsHelper.isAppAccepted(sbn.packageName) && !sbn.packageName.contains("com.android.systemui")) {
|
if (Preferences.showNotifications && bundle.containsKey(Notification.EXTRA_TITLE) && !isGroupHeader && !isOngoing && ActiveNotificationsHelper.isAppAccepted(sbn.packageName) && !sbn.packageName.contains("com.android.systemui")) {
|
||||||
Preferences.lastNotificationId = sbn.id
|
Preferences.lastNotificationId = sbn.id
|
||||||
Preferences.lastNotificationTitle = bundle.getString(Notification.EXTRA_TITLE) ?: ""
|
Preferences.lastNotificationTitle = bundle.getString(Notification.EXTRA_TITLE) ?: ""
|
||||||
try {
|
try {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
Preferences.lastNotificationIcon = sbn.notification.smallIcon.resId
|
Preferences.lastNotificationIcon = sbn.notification.smallIcon.resId
|
||||||
} else {
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
Preferences.lastNotificationIcon = sbn.notification.icon
|
Preferences.lastNotificationIcon = sbn.notification.icon
|
||||||
}
|
}
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
@ -57,15 +67,13 @@ class NotificationListener : NotificationListenerService() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onNotificationRemoved(sbn: StatusBarNotification?) {
|
override fun onNotificationRemoved(sbn: StatusBarNotification?) {
|
||||||
|
if (Preferences.showMusic)
|
||||||
MediaPlayerHelper.updatePlayingMediaInfo(this)
|
MediaPlayerHelper.updatePlayingMediaInfo(this)
|
||||||
|
|
||||||
sbn?.let {
|
sbn?.let {
|
||||||
if (sbn.id == Preferences.lastNotificationId && sbn.packageName == Preferences.lastNotificationPackage) {
|
if (Preferences.showNotifications && sbn.id == Preferences.lastNotificationId && sbn.packageName == Preferences.lastNotificationPackage) {
|
||||||
ActiveNotificationsHelper.clearLastNotification(this)
|
ActiveNotificationsHelper.clearLastNotification(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWidget.updateWidget(this)
|
|
||||||
super.onNotificationRemoved(sbn)
|
super.onNotificationRemoved(sbn)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,10 +82,9 @@ class NotificationListener : NotificationListenerService() {
|
|||||||
val intent = Intent(context, UpdatesReceiver::class.java).apply {
|
val intent = Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
action = Actions.ACTION_CLEAR_NOTIFICATION
|
action = Actions.ACTION_CLEAR_NOTIFICATION
|
||||||
}
|
}
|
||||||
cancel(PendingIntent.getBroadcast(context, 28943, intent, 0))
|
|
||||||
val timeoutPref = Constants.GlanceNotificationTimer.fromInt(Preferences.hideNotificationAfter)
|
val timeoutPref = Constants.GlanceNotificationTimer.fromInt(Preferences.hideNotificationAfter)
|
||||||
if (timeoutPref != Constants.GlanceNotificationTimer.WHEN_DISMISSED) {
|
if (timeoutPref != Constants.GlanceNotificationTimer.WHEN_DISMISSED) {
|
||||||
setExact(
|
setExactIfCanSchedule(
|
||||||
AlarmManager.RTC,
|
AlarmManager.RTC,
|
||||||
Calendar.getInstance().timeInMillis + when (timeoutPref) {
|
Calendar.getInstance().timeInMillis + when (timeoutPref) {
|
||||||
Constants.GlanceNotificationTimer.HALF_MINUTE -> 30 * 1000
|
Constants.GlanceNotificationTimer.HALF_MINUTE -> 30 * 1000
|
||||||
@ -85,16 +92,27 @@ class NotificationListener : NotificationListenerService() {
|
|||||||
Constants.GlanceNotificationTimer.FIVE_MINUTES -> 5 * 60 * 1000
|
Constants.GlanceNotificationTimer.FIVE_MINUTES -> 5 * 60 * 1000
|
||||||
Constants.GlanceNotificationTimer.TEN_MINUTES -> 10 * 60 * 1000
|
Constants.GlanceNotificationTimer.TEN_MINUTES -> 10 * 60 * 1000
|
||||||
Constants.GlanceNotificationTimer.FIFTEEN_MINUTES -> 15 * 60 * 1000
|
Constants.GlanceNotificationTimer.FIFTEEN_MINUTES -> 15 * 60 * 1000
|
||||||
else -> 0
|
else -> 60 * 1000
|
||||||
},
|
},
|
||||||
PendingIntent.getBroadcast(
|
PendingIntent.getBroadcast(
|
||||||
context,
|
context,
|
||||||
5,
|
5,
|
||||||
intent,
|
intent,
|
||||||
0
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun clearTimeout(context: Context) {
|
||||||
|
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
|
val intent = Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
|
action = Actions.ACTION_CLEAR_NOTIFICATION
|
||||||
|
}
|
||||||
|
cancel(PendingIntent.getBroadcast(context, 5, intent, PendingIntent.FLAG_IMMUTABLE))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -5,21 +5,16 @@ import android.app.PendingIntent
|
|||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.util.Log
|
|
||||||
import androidx.core.app.AlarmManagerCompat
|
|
||||||
import androidx.core.content.ContextCompat.getSystemService
|
|
||||||
import com.tommasoberlose.anotherwidget.db.EventRepository
|
import com.tommasoberlose.anotherwidget.db.EventRepository
|
||||||
import com.tommasoberlose.anotherwidget.global.Actions
|
import com.tommasoberlose.anotherwidget.global.Actions
|
||||||
import com.tommasoberlose.anotherwidget.global.Constants
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
import com.tommasoberlose.anotherwidget.helpers.*
|
||||||
import com.tommasoberlose.anotherwidget.helpers.BatteryHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.models.Event
|
import com.tommasoberlose.anotherwidget.models.Event
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
import org.joda.time.Period
|
import com.tommasoberlose.anotherwidget.utils.setExactIfCanSchedule
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import org.joda.time.Period
|
||||||
|
|
||||||
|
|
||||||
class UpdatesReceiver : BroadcastReceiver() {
|
class UpdatesReceiver : BroadcastReceiver() {
|
||||||
@ -30,17 +25,18 @@ class UpdatesReceiver : BroadcastReceiver() {
|
|||||||
Intent.ACTION_MY_PACKAGE_REPLACED,
|
Intent.ACTION_MY_PACKAGE_REPLACED,
|
||||||
Intent.ACTION_TIME_CHANGED,
|
Intent.ACTION_TIME_CHANGED,
|
||||||
Intent.ACTION_TIMEZONE_CHANGED,
|
Intent.ACTION_TIMEZONE_CHANGED,
|
||||||
Intent.ACTION_LOCALE_CHANGED,
|
Intent.ACTION_LOCALE_CHANGED -> {
|
||||||
|
CalendarHelper.updateEventList(context)
|
||||||
|
MediaPlayerHelper.updatePlayingMediaInfo(context)
|
||||||
|
ActiveNotificationsHelper.clearLastNotification(context)
|
||||||
|
GreetingsHelper.toggleGreetings(context)
|
||||||
|
}
|
||||||
|
|
||||||
Intent.ACTION_DATE_CHANGED,
|
Intent.ACTION_DATE_CHANGED,
|
||||||
Actions.ACTION_CALENDAR_UPDATE -> {
|
Actions.ACTION_CALENDAR_UPDATE -> {
|
||||||
ActiveNotificationsHelper.clearLastNotification(context)
|
|
||||||
MediaPlayerHelper.updatePlayingMediaInfo(context)
|
|
||||||
CalendarHelper.updateEventList(context)
|
CalendarHelper.updateEventList(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
"com.sec.android.widgetapp.APPWIDGET_RESIZE",
|
|
||||||
AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED,
|
|
||||||
Actions.ACTION_ALARM_UPDATE,
|
|
||||||
Actions.ACTION_TIME_UPDATE -> {
|
Actions.ACTION_TIME_UPDATE -> {
|
||||||
MainWidget.updateWidget(context)
|
MainWidget.updateWidget(context)
|
||||||
if (intent.hasExtra(EVENT_ID)) {
|
if (intent.hasExtra(EVENT_ID)) {
|
||||||
@ -48,13 +44,22 @@ class UpdatesReceiver : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Actions.ACTION_CLEAR_NOTIFICATION -> {
|
"com.sec.android.widgetapp.APPWIDGET_RESIZE",
|
||||||
ActiveNotificationsHelper.clearLastNotification(context)
|
AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED,
|
||||||
MainWidget.updateWidget(context)
|
Actions.ACTION_ALARM_UPDATE,
|
||||||
}
|
|
||||||
Actions.ACTION_UPDATE_GREETINGS -> {
|
Actions.ACTION_UPDATE_GREETINGS -> {
|
||||||
MainWidget.updateWidget(context)
|
MainWidget.updateWidget(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Actions.ACTION_CLEAR_NOTIFICATION -> {
|
||||||
|
ActiveNotificationsHelper.clearLastNotification(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
Actions.ACTION_REFRESH -> {
|
||||||
|
CalendarHelper.updateEventList(context)
|
||||||
|
MediaPlayerHelper.updatePlayingMediaInfo(context)
|
||||||
|
WeatherHelper.updateWeather(context)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,15 +67,37 @@ class UpdatesReceiver : BroadcastReceiver() {
|
|||||||
const val EVENT_ID = "EVENT_ID"
|
const val EVENT_ID = "EVENT_ID"
|
||||||
|
|
||||||
fun setUpdates(context: Context, eventId: Long? = null) {
|
fun setUpdates(context: Context, eventId: Long? = null) {
|
||||||
|
if (!Preferences.showEvents)
|
||||||
|
return
|
||||||
val eventRepository = EventRepository(context)
|
val eventRepository = EventRepository(context)
|
||||||
if (eventId == null) {
|
if (eventId == null) {
|
||||||
removeUpdates(context)
|
// schedule ACTION_CALENDAR_UPDATE at midnight (ACTION_DATE_CHANGED no longer works)
|
||||||
|
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
|
setExactIfCanSchedule(
|
||||||
|
AlarmManager.RTC,
|
||||||
|
Calendar.getInstance().apply {
|
||||||
|
set(Calendar.MILLISECOND, 0)
|
||||||
|
set(Calendar.SECOND, 0)
|
||||||
|
set(Calendar.MINUTE, 0)
|
||||||
|
set(Calendar.HOUR_OF_DAY, 0)
|
||||||
|
add(Calendar.DATE, 1)
|
||||||
|
}.timeInMillis,
|
||||||
|
PendingIntent.getBroadcast(
|
||||||
|
context,
|
||||||
|
0,
|
||||||
|
Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
|
action = Actions.ACTION_CALENDAR_UPDATE
|
||||||
|
},
|
||||||
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
eventRepository.getFutureEvents().forEach { event ->
|
eventRepository.getFutureEvents().forEach { event ->
|
||||||
setEventUpdate(context, event)
|
setEventUpdate(context, event)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val event = eventRepository.getEventByEventId(eventId)
|
val event = eventRepository.getEventById(eventId)
|
||||||
if (event != null) {
|
if (event != null) {
|
||||||
setEventUpdate(context, event)
|
setEventUpdate(context, event)
|
||||||
}
|
}
|
||||||
@ -79,12 +106,11 @@ class UpdatesReceiver : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setEventUpdate(context: Context, event: Event) {
|
private fun setEventUpdate(context: Context, event: Event) {
|
||||||
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
|
||||||
val now = Calendar.getInstance().apply {
|
val now = Calendar.getInstance().apply {
|
||||||
set(Calendar.SECOND, 0)
|
set(Calendar.SECOND, 0)
|
||||||
set(Calendar.MILLISECOND, 0)
|
set(Calendar.MILLISECOND, 0)
|
||||||
}
|
}
|
||||||
val diff = Period(now.timeInMillis, event.startDate)
|
val diff = Period(now.timeInMillis, event.startDate, org.joda.time.PeriodType.time())
|
||||||
val limit = when (Preferences.showUntil) {
|
val limit = when (Preferences.showUntil) {
|
||||||
0 -> 1000 * 60 * 60 * 3
|
0 -> 1000 * 60 * 60 * 3
|
||||||
1 -> 1000 * 60 * 60 * 6
|
1 -> 1000 * 60 * 60 * 6
|
||||||
@ -96,92 +122,74 @@ class UpdatesReceiver : BroadcastReceiver() {
|
|||||||
7 -> 1000 * 60 * 60
|
7 -> 1000 * 60 * 60
|
||||||
else -> 1000 * 60 * 60 * 6
|
else -> 1000 * 60 * 60 * 6
|
||||||
}
|
}
|
||||||
if (event.startDate <= limit) {
|
val fireTime = when {
|
||||||
if (event.startDate > now.timeInMillis) {
|
event.startDate <= now.timeInMillis
|
||||||
// Update the widget every hour till the event
|
-> event.endDate
|
||||||
if (diff.hours == 0) {
|
event.startDate > now.timeInMillis + limit
|
||||||
var minutes = 0
|
-> event.startDate - limit
|
||||||
when (Preferences.widgetUpdateFrequency) {
|
!Preferences.showDiffTime
|
||||||
Constants.WidgetUpdateFrequency.DEFAULT.value -> {
|
-> return
|
||||||
minutes = when {
|
event.allDay
|
||||||
diff.minutes > 50 -> 50
|
-> event.startDate
|
||||||
diff.minutes > 30 -> 30
|
diff.hours > 12
|
||||||
diff.minutes > 15 -> 15
|
-> event.startDate - 12 * 1000 * 60 * 60 + 1000 * 60
|
||||||
|
diff.hours > 0
|
||||||
|
-> event.startDate - diff.hours * 1000 * 60 * 60 + 1000 * 60
|
||||||
|
else
|
||||||
|
-> event.startDate - 1000 * 60 * when (Preferences.widgetUpdateFrequency) {
|
||||||
|
Constants.WidgetUpdateFrequency.DEFAULT.rawValue -> {
|
||||||
|
when {
|
||||||
|
diff.minutes >= 45 -> 44
|
||||||
|
diff.minutes >= 30 -> 29
|
||||||
|
diff.minutes >= 15 -> 14
|
||||||
else -> 0
|
else -> 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Constants.WidgetUpdateFrequency.HIGH.value -> {
|
Constants.WidgetUpdateFrequency.HIGH.rawValue -> {
|
||||||
minutes = diff.minutes - (diff.minutes % 5)
|
when {
|
||||||
|
diff.minutes >= 5 -> diff.minutes - diff.minutes % 5 - 1
|
||||||
|
else -> 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setExact(
|
else -> 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// no need to schedule updates after the next ACTION_CALENDAR_UPDATE
|
||||||
|
if (Calendar.getInstance().apply {
|
||||||
|
set(Calendar.MILLISECOND, 0)
|
||||||
|
set(Calendar.SECOND, 0)
|
||||||
|
set(Calendar.MINUTE, 0)
|
||||||
|
set(Calendar.HOUR_OF_DAY, 0)
|
||||||
|
add(Calendar.DATE, 1)
|
||||||
|
}.timeInMillis <= fireTime) return
|
||||||
|
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
|
setExactIfCanSchedule(
|
||||||
AlarmManager.RTC,
|
AlarmManager.RTC,
|
||||||
if (event.startDate - minutes * 1000 * 60 > (now.timeInMillis + 120 * 1000)) event.startDate - 60 * 1000 * minutes else now.timeInMillis + 120000,
|
fireTime.coerceAtLeast(now.timeInMillis + 1000 * 60),
|
||||||
PendingIntent.getBroadcast(
|
PendingIntent.getBroadcast(
|
||||||
context,
|
context,
|
||||||
event.eventID.toInt(),
|
event.id.toInt(),
|
||||||
Intent(context, UpdatesReceiver::class.java).apply {
|
Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
action = Actions.ACTION_TIME_UPDATE
|
action = Actions.ACTION_TIME_UPDATE
|
||||||
putExtra(EVENT_ID, event.eventID)
|
if (event.startDate > now.timeInMillis)
|
||||||
|
putExtra(EVENT_ID, event.id)
|
||||||
},
|
},
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
setExact(
|
|
||||||
AlarmManager.RTC,
|
|
||||||
event.startDate - diff.hours * 1000 * 60 * 60 + if (diff.minutes > 30) (-30) else (+30),
|
|
||||||
PendingIntent.getBroadcast(
|
|
||||||
context,
|
|
||||||
event.eventID.toInt(),
|
|
||||||
Intent(context, UpdatesReceiver::class.java).apply {
|
|
||||||
action = Actions.ACTION_TIME_UPDATE
|
|
||||||
putExtra(EVENT_ID, event.eventID)
|
|
||||||
},
|
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Update the widget one second after the event is finished
|
|
||||||
val fireTime =
|
|
||||||
if (event.endDate > now.timeInMillis + 120 * 1000) event.endDate else now.timeInMillis + 120000
|
|
||||||
setExact(
|
|
||||||
AlarmManager.RTC,
|
|
||||||
fireTime,
|
|
||||||
PendingIntent.getBroadcast(
|
|
||||||
context,
|
|
||||||
event.eventID.toInt(),
|
|
||||||
Intent(context, UpdatesReceiver::class.java).apply {
|
|
||||||
action = Actions.ACTION_TIME_UPDATE
|
|
||||||
},
|
|
||||||
0
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setExact(
|
|
||||||
AlarmManager.RTC,
|
|
||||||
if (event.startDate - limit > now.timeInMillis + 120 * 1000) event.startDate - limit else now.timeInMillis + 120000,
|
|
||||||
PendingIntent.getBroadcast(
|
|
||||||
context,
|
|
||||||
event.eventID.toInt(),
|
|
||||||
Intent(context, UpdatesReceiver::class.java).apply {
|
|
||||||
action = Actions.ACTION_TIME_UPDATE
|
|
||||||
putExtra(EVENT_ID, event.eventID)
|
|
||||||
},
|
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeUpdates(context: Context) {
|
fun removeUpdates(context: Context) {
|
||||||
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
|
cancel(PendingIntent.getBroadcast(context, 0, Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
|
action = Actions.ACTION_CALENDAR_UPDATE
|
||||||
|
}, PendingIntent.FLAG_IMMUTABLE))
|
||||||
val eventRepository = EventRepository(context)
|
val eventRepository = EventRepository(context)
|
||||||
eventRepository.getFutureEvents().forEach {
|
eventRepository.getFutureEvents().forEach {
|
||||||
cancel(PendingIntent.getBroadcast(context, it.eventID.toInt(), Intent(context, UpdatesReceiver::class.java), 0))
|
cancel(PendingIntent.getBroadcast(context, it.id.toInt(), Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
|
action = Actions.ACTION_TIME_UPDATE
|
||||||
|
}, PendingIntent.FLAG_IMMUTABLE))
|
||||||
}
|
}
|
||||||
eventRepository.close()
|
eventRepository.close()
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,12 @@
|
|||||||
package com.tommasoberlose.anotherwidget.receivers
|
package com.tommasoberlose.anotherwidget.receivers
|
||||||
|
|
||||||
import android.app.AlarmManager
|
|
||||||
import android.app.PendingIntent
|
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import com.tommasoberlose.anotherwidget.global.Actions
|
import com.tommasoberlose.anotherwidget.global.Actions
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
||||||
import kotlinx.coroutines.Dispatchers
|
import com.tommasoberlose.anotherwidget.services.WeatherWorker
|
||||||
import kotlinx.coroutines.GlobalScope
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
|
|
||||||
class WeatherReceiver : BroadcastReceiver() {
|
class WeatherReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
@ -22,63 +16,22 @@ class WeatherReceiver : BroadcastReceiver() {
|
|||||||
Intent.ACTION_MY_PACKAGE_REPLACED,
|
Intent.ACTION_MY_PACKAGE_REPLACED,
|
||||||
Intent.ACTION_TIMEZONE_CHANGED,
|
Intent.ACTION_TIMEZONE_CHANGED,
|
||||||
Intent.ACTION_LOCALE_CHANGED,
|
Intent.ACTION_LOCALE_CHANGED,
|
||||||
Intent.ACTION_TIME_CHANGED -> setUpdates(context)
|
Intent.ACTION_TIME_CHANGED,
|
||||||
|
|
||||||
Actions.ACTION_WEATHER_UPDATE -> {
|
Actions.ACTION_WEATHER_UPDATE -> {
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
|
||||||
WeatherHelper.updateWeather(context)
|
WeatherHelper.updateWeather(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val MINUTE = 60 * 1000L
|
|
||||||
fun setUpdates(context: Context) {
|
fun setUpdates(context: Context) {
|
||||||
removeUpdates(context)
|
|
||||||
|
|
||||||
if (Preferences.showWeather) {
|
if (Preferences.showWeather) {
|
||||||
val interval = MINUTE * when (Preferences.weatherRefreshPeriod) {
|
WeatherWorker.enqueueTrigger(context)
|
||||||
0 -> 30
|
|
||||||
1 -> 60
|
|
||||||
2 -> 60L * 3
|
|
||||||
3 -> 60L * 6
|
|
||||||
4 -> 60L * 12
|
|
||||||
5 -> 60L * 24
|
|
||||||
else -> 60
|
|
||||||
}
|
|
||||||
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
|
||||||
setRepeating(
|
|
||||||
AlarmManager.RTC,
|
|
||||||
Calendar.getInstance().timeInMillis,
|
|
||||||
interval,
|
|
||||||
PendingIntent.getBroadcast(context, 0, Intent(context, WeatherReceiver::class.java).apply { action = Actions.ACTION_WEATHER_UPDATE }, 0)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setOneTimeUpdate(context: Context) {
|
|
||||||
if (Preferences.showWeather) {
|
|
||||||
listOf(10, 20, 30).forEach {
|
|
||||||
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
|
||||||
setExactAndAllowWhileIdle(
|
|
||||||
AlarmManager.RTC,
|
|
||||||
it * MINUTE,
|
|
||||||
PendingIntent.getBroadcast(context, it, Intent(context, WeatherReceiver::class.java).apply { action = Actions.ACTION_WEATHER_UPDATE }, 0)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeUpdates(context: Context) {
|
fun removeUpdates(context: Context) {
|
||||||
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
WeatherWorker.cancelTrigger(context)
|
||||||
cancel(PendingIntent.getBroadcast(context, 0, Intent(context, WeatherReceiver::class.java).apply { action = Actions.ACTION_WEATHER_UPDATE }, 0))
|
|
||||||
listOf(10, 20, 30).forEach {
|
|
||||||
cancel(PendingIntent.getBroadcast(context, it, Intent(context, WeatherReceiver::class.java).apply { action = Actions.ACTION_WEATHER_UPDATE }, 0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import android.content.Intent
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import com.tommasoberlose.anotherwidget.global.Actions
|
import com.tommasoberlose.anotherwidget.global.Actions
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.helpers.IntentHelper
|
import com.tommasoberlose.anotherwidget.helpers.IntentHelper
|
||||||
import com.tommasoberlose.anotherwidget.utils.toast
|
import com.tommasoberlose.anotherwidget.utils.toast
|
||||||
|
|
||||||
@ -15,12 +16,15 @@ class WidgetClickListenerReceiver : BroadcastReceiver() {
|
|||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
if (intent.action == Actions.ACTION_OPEN_WEATHER_INTENT) {
|
if (intent.action == Actions.ACTION_OPEN_WEATHER_INTENT) {
|
||||||
try {
|
try {
|
||||||
context.startActivity(IntentHelper.getWeatherIntent(context))
|
IntentHelper.getWeatherIntent(context).run {
|
||||||
|
if (flags and Intent.FLAG_ACTIVITY_NEW_TASK == Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
context.startActivity(this)
|
||||||
|
else
|
||||||
|
context.sendBroadcast(this)
|
||||||
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
try {
|
e.printStackTrace()
|
||||||
context.applicationContext.startActivity(IntentHelper.getWeatherIntent(context.applicationContext))
|
val uri = Uri.parse("https://www.google.com/search?q=weather")
|
||||||
} catch (e: Exception) {
|
|
||||||
val uri = Uri.parse("http://www.google.com/#q=weather")
|
|
||||||
val i = Intent(Intent.ACTION_VIEW, uri)
|
val i = Intent(Intent.ACTION_VIEW, uri)
|
||||||
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
try {
|
try {
|
||||||
@ -32,4 +36,3 @@ class WidgetClickListenerReceiver : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
package com.tommasoberlose.anotherwidget.services
|
|
||||||
|
|
||||||
import android.app.job.JobInfo
|
|
||||||
import android.app.job.JobParameters
|
|
||||||
import android.app.job.JobScheduler
|
|
||||||
import android.app.job.JobService
|
|
||||||
import android.content.ComponentName
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Build
|
|
||||||
import android.provider.CalendarContract
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
|
||||||
|
|
||||||
class BatteryListenerJob : JobService() {
|
|
||||||
override fun onStartJob(params: JobParameters): Boolean {
|
|
||||||
MainWidget.updateWidget(this)
|
|
||||||
schedule(
|
|
||||||
this
|
|
||||||
)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
override fun onStopJob(params: JobParameters): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val chargingJobId = 1006
|
|
||||||
private const val notChargingJobId = 1007
|
|
||||||
fun schedule(context: Context) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
||||||
remove(context)
|
|
||||||
val componentName = ComponentName(
|
|
||||||
context,
|
|
||||||
EventListenerJob::class.java
|
|
||||||
)
|
|
||||||
with(context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler) {
|
|
||||||
schedule(
|
|
||||||
JobInfo.Builder(chargingJobId, componentName)
|
|
||||||
.setRequiresCharging(true)
|
|
||||||
.setPersisted(true)
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
schedule(
|
|
||||||
JobInfo.Builder(notChargingJobId, componentName)
|
|
||||||
.setRequiresCharging(false)
|
|
||||||
.setPersisted(true)
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun remove(context: Context) {
|
|
||||||
val js = context.getSystemService(JobScheduler::class.java)
|
|
||||||
js?.cancel(chargingJobId)
|
|
||||||
js?.cancel(notChargingJobId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
package com.tommasoberlose.anotherwidget.services
|
|
||||||
|
|
||||||
import android.app.job.JobInfo
|
|
||||||
import android.app.job.JobInfo.TriggerContentUri
|
|
||||||
import android.app.job.JobParameters
|
|
||||||
import android.app.job.JobScheduler
|
|
||||||
import android.app.job.JobService
|
|
||||||
import android.content.ComponentName
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Build
|
|
||||||
import android.provider.CalendarContract
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
|
||||||
|
|
||||||
|
|
||||||
class EventListenerJob : JobService() {
|
|
||||||
override fun onStartJob(params: JobParameters): Boolean {
|
|
||||||
CalendarHelper.updateEventList(this)
|
|
||||||
schedule(
|
|
||||||
this
|
|
||||||
)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
override fun onStopJob(params: JobParameters): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val jobId = 1005
|
|
||||||
fun schedule(context: Context) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
||||||
val componentName = ComponentName(
|
|
||||||
context,
|
|
||||||
EventListenerJob::class.java
|
|
||||||
)
|
|
||||||
with(context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler) {
|
|
||||||
schedule(
|
|
||||||
JobInfo.Builder(jobId, componentName)
|
|
||||||
.addTriggerContentUri(TriggerContentUri(
|
|
||||||
CalendarContract.CONTENT_URI,
|
|
||||||
TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS
|
|
||||||
))
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun remove(context: Context) {
|
|
||||||
val js = context.getSystemService(JobScheduler::class.java)
|
|
||||||
js?.cancel(jobId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,129 +0,0 @@
|
|||||||
package com.tommasoberlose.anotherwidget.services
|
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.app.*
|
|
||||||
import android.app.job.JobScheduler
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.location.Address
|
|
||||||
import android.location.Geocoder
|
|
||||||
import android.os.IBinder
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.core.app.*
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import com.google.android.gms.location.LocationServices
|
|
||||||
import com.tommasoberlose.anotherwidget.R
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
|
||||||
import com.tommasoberlose.anotherwidget.network.WeatherNetworkApi
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
|
||||||
import kotlinx.coroutines.*
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import java.lang.Exception
|
|
||||||
import java.util.*
|
|
||||||
import kotlin.collections.ArrayList
|
|
||||||
|
|
||||||
class LocationService : Service() {
|
|
||||||
|
|
||||||
private val jobs: ArrayList<Job> = ArrayList()
|
|
||||||
|
|
||||||
override fun onCreate() {
|
|
||||||
super.onCreate()
|
|
||||||
startForeground(LOCATION_ACCESS_NOTIFICATION_ID, getLocationAccessNotification())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
|
||||||
if (ActivityCompat.checkSelfPermission(
|
|
||||||
this,
|
|
||||||
Manifest.permission.ACCESS_FINE_LOCATION
|
|
||||||
) == PackageManager.PERMISSION_GRANTED
|
|
||||||
) {
|
|
||||||
|
|
||||||
jobs += GlobalScope.launch(Dispatchers.IO) {
|
|
||||||
LocationServices.getFusedLocationProviderClient(this@LocationService).lastLocation.addOnCompleteListener { task ->
|
|
||||||
val networkApi = WeatherNetworkApi(this@LocationService)
|
|
||||||
if (task.isSuccessful) {
|
|
||||||
val location = task.result
|
|
||||||
if (location != null) {
|
|
||||||
Preferences.customLocationLat = location.latitude.toString()
|
|
||||||
Preferences.customLocationLon = location.longitude.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
|
||||||
networkApi.updateWeather()
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
stopSelf()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
|
||||||
} else {
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
|
||||||
networkApi.updateWeather()
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
stopSelf()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
stopSelf()
|
|
||||||
}
|
|
||||||
return START_STICKY
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
super.onDestroy()
|
|
||||||
jobs.forEach {
|
|
||||||
it.cancel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val LOCATION_ACCESS_NOTIFICATION_ID = 28465
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun requestNewLocation(context: Context) {
|
|
||||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
|
||||||
context.startForegroundService(Intent(context, LocationService::class.java))
|
|
||||||
} else {
|
|
||||||
context.startService(Intent(context, LocationService::class.java))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBind(intent: Intent?): IBinder? {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getLocationAccessNotification(): Notification {
|
|
||||||
with(NotificationManagerCompat.from(this)) {
|
|
||||||
// Create channel
|
|
||||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
|
||||||
createNotificationChannel(
|
|
||||||
NotificationChannel(
|
|
||||||
getString(R.string.location_access_notification_channel_id),
|
|
||||||
getString(R.string.location_access_notification_channel_name),
|
|
||||||
NotificationManager.IMPORTANCE_LOW
|
|
||||||
).apply {
|
|
||||||
description = getString(R.string.location_access_notification_channel_description)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val builder = NotificationCompat.Builder(this@LocationService, getString(R.string.location_access_notification_channel_id))
|
|
||||||
.setSmallIcon(R.drawable.ic_stat_notification)
|
|
||||||
.setContentTitle(getString(R.string.location_access_notification_title))
|
|
||||||
.setStyle(NotificationCompat.BigTextStyle().bigText(getString(R.string.location_access_notification_subtitle)))
|
|
||||||
.setOngoing(true)
|
|
||||||
.setColor(ContextCompat.getColor(this@LocationService, R.color.colorAccent))
|
|
||||||
|
|
||||||
// Main intent that open the activity
|
|
||||||
builder.setContentIntent(PendingIntent.getActivity(this@LocationService, 0, Intent(this@LocationService, MainActivity::class.java), PendingIntent.FLAG_UPDATE_CURRENT))
|
|
||||||
|
|
||||||
return builder.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,153 +0,0 @@
|
|||||||
package com.tommasoberlose.anotherwidget.services
|
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.provider.CalendarContract
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.core.app.JobIntentService
|
|
||||||
import com.tommasoberlose.anotherwidget.db.EventRepository
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper.applyFilters
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper.sortEvents
|
|
||||||
import com.tommasoberlose.anotherwidget.models.Event
|
|
||||||
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
|
||||||
import me.everything.providers.android.calendar.CalendarProvider
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import java.util.*
|
|
||||||
import kotlin.Comparator
|
|
||||||
import kotlin.collections.ArrayList
|
|
||||||
|
|
||||||
class UpdateCalendarJob : JobIntentService() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val jobId = 1200
|
|
||||||
|
|
||||||
fun enqueueWork(context: Context, work: Intent) {
|
|
||||||
enqueueWork(context, UpdateCalendarJob::class.java, jobId, work)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onHandleWork(intent: Intent) {
|
|
||||||
val eventRepository = EventRepository(this)
|
|
||||||
if (Preferences.showEvents) {
|
|
||||||
val eventList = ArrayList<Event>()
|
|
||||||
|
|
||||||
val now = Calendar.getInstance()
|
|
||||||
val begin = Calendar.getInstance().apply {
|
|
||||||
set(Calendar.MILLISECOND, 0)
|
|
||||||
set(Calendar.SECOND, 0)
|
|
||||||
set(Calendar.MINUTE, 0)
|
|
||||||
set(Calendar.HOUR_OF_DAY, 0)
|
|
||||||
}
|
|
||||||
val limit = Calendar.getInstance().apply {
|
|
||||||
when (Preferences.showUntil) {
|
|
||||||
0 -> add(Calendar.HOUR, 3)
|
|
||||||
1 -> add(Calendar.HOUR, 6)
|
|
||||||
2 -> add(Calendar.HOUR, 12)
|
|
||||||
3 -> add(Calendar.DAY_OF_MONTH, 1)
|
|
||||||
4 -> add(Calendar.DAY_OF_MONTH, 3)
|
|
||||||
5 -> add(Calendar.DAY_OF_MONTH, 7)
|
|
||||||
6 -> add(Calendar.MINUTE, 30)
|
|
||||||
7 -> add(Calendar.HOUR, 1)
|
|
||||||
else -> add(Calendar.HOUR, 6)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!checkGrantedPermission(
|
|
||||||
Manifest.permission.READ_CALENDAR
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
eventRepository.resetNextEventData()
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
val provider = CalendarProvider(this)
|
|
||||||
val data = provider.getInstances(begin.timeInMillis, limit.timeInMillis)
|
|
||||||
if (data != null) {
|
|
||||||
val instances = data.list
|
|
||||||
for (instance in instances) {
|
|
||||||
try {
|
|
||||||
val e = provider.getEvent(instance.eventId)
|
|
||||||
if (e != null && !e.deleted && instance.begin <= limit.timeInMillis && now.timeInMillis < instance.end && !CalendarHelper.getFilteredCalendarIdList()
|
|
||||||
.contains(e.calendarId)
|
|
||||||
) {
|
|
||||||
if (e.allDay) {
|
|
||||||
val start = Calendar.getInstance()
|
|
||||||
start.timeInMillis = instance.begin
|
|
||||||
val end = Calendar.getInstance()
|
|
||||||
end.timeInMillis = instance.end
|
|
||||||
instance.begin =
|
|
||||||
start.timeInMillis - start.timeZone.getOffset(start.timeInMillis)
|
|
||||||
instance.end =
|
|
||||||
end.timeInMillis - end.timeZone.getOffset(end.timeInMillis)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check all day events
|
|
||||||
val startDate = Calendar.getInstance()
|
|
||||||
startDate.timeInMillis = instance.begin
|
|
||||||
val endDate = Calendar.getInstance()
|
|
||||||
endDate.timeInMillis = instance.end
|
|
||||||
|
|
||||||
val isAllDay = e.allDay || (
|
|
||||||
startDate.get(Calendar.MILLISECOND) == 0
|
|
||||||
&& startDate.get(Calendar.SECOND) == 0
|
|
||||||
&& startDate.get(Calendar.MINUTE) == 0
|
|
||||||
&& startDate.get(Calendar.HOUR_OF_DAY) == 0
|
|
||||||
&& endDate.get(Calendar.MILLISECOND) == 0
|
|
||||||
&& endDate.get(Calendar.SECOND) == 0
|
|
||||||
&& endDate.get(Calendar.MINUTE) == 0
|
|
||||||
&& endDate.get(Calendar.HOUR_OF_DAY) == 0
|
|
||||||
)
|
|
||||||
|
|
||||||
eventList.add(
|
|
||||||
Event(
|
|
||||||
id = instance.id,
|
|
||||||
eventID = e.id,
|
|
||||||
title = e.title ?: "",
|
|
||||||
startDate = instance.begin,
|
|
||||||
endDate = instance.end,
|
|
||||||
calendarID = e.calendarId.toInt(),
|
|
||||||
allDay = isAllDay,
|
|
||||||
address = e.eventLocation ?: "",
|
|
||||||
selfAttendeeStatus = e.selfAttendeeStatus.toInt(),
|
|
||||||
availability = e.availability
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} catch (ignored: Exception) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val sortedEvents = eventList.sortEvents()
|
|
||||||
val filteredEventList = sortedEvents
|
|
||||||
.applyFilters()
|
|
||||||
|
|
||||||
if (filteredEventList.isEmpty()) {
|
|
||||||
eventRepository.resetNextEventData()
|
|
||||||
eventRepository.clearEvents()
|
|
||||||
} else {
|
|
||||||
eventRepository.saveEvents(
|
|
||||||
sortedEvents
|
|
||||||
)
|
|
||||||
eventRepository.saveNextEventData(filteredEventList.first())
|
|
||||||
}
|
|
||||||
} catch (ignored: java.lang.Exception) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
eventRepository.resetNextEventData()
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdatesReceiver.setUpdates(this)
|
|
||||||
MainWidget.updateWidget(this)
|
|
||||||
|
|
||||||
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
|
||||||
eventRepository.close()
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,195 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.services
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import android.provider.CalendarContract
|
||||||
|
import androidx.work.Constraints
|
||||||
|
import androidx.work.ExistingWorkPolicy
|
||||||
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
|
import androidx.work.WorkManager
|
||||||
|
import androidx.work.Worker
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import com.tommasoberlose.anotherwidget.db.EventRepository
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper.applyFilters
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper.sortEvents
|
||||||
|
import com.tommasoberlose.anotherwidget.models.Event
|
||||||
|
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
|
import java.util.*
|
||||||
|
import me.everything.providers.android.calendar.CalendarProvider
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
|
||||||
|
class UpdateCalendarWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
|
||||||
|
|
||||||
|
override fun doWork(): Result {
|
||||||
|
val context = applicationContext
|
||||||
|
UpdatesReceiver.removeUpdates(context)
|
||||||
|
val eventRepository = EventRepository(context)
|
||||||
|
|
||||||
|
if (Preferences.showEvents) {
|
||||||
|
if (!context.checkGrantedPermission(Manifest.permission.READ_CALENDAR)) {
|
||||||
|
eventRepository.resetNextEventData()
|
||||||
|
eventRepository.clearEvents()
|
||||||
|
} else {
|
||||||
|
// fetch all events from now to next ACTION_CALENDAR_UPDATE + limit
|
||||||
|
val now = Calendar.getInstance()
|
||||||
|
val limit = Calendar.getInstance().apply {
|
||||||
|
set(Calendar.MILLISECOND, 0)
|
||||||
|
set(Calendar.SECOND, 0)
|
||||||
|
set(Calendar.MINUTE, 0)
|
||||||
|
set(Calendar.HOUR_OF_DAY, 0)
|
||||||
|
add(Calendar.DATE, 1)
|
||||||
|
when (Preferences.showUntil) {
|
||||||
|
0 -> add(Calendar.HOUR, 3)
|
||||||
|
1 -> add(Calendar.HOUR, 6)
|
||||||
|
2 -> add(Calendar.HOUR, 12)
|
||||||
|
3 -> add(Calendar.DAY_OF_MONTH, 1)
|
||||||
|
4 -> add(Calendar.DAY_OF_MONTH, 3)
|
||||||
|
5 -> add(Calendar.DAY_OF_MONTH, 7)
|
||||||
|
6 -> add(Calendar.MINUTE, 30)
|
||||||
|
7 -> add(Calendar.HOUR, 1)
|
||||||
|
else -> add(Calendar.HOUR, 6)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
val eventList = ArrayList<Event>()
|
||||||
|
val provider = CalendarProvider(context)
|
||||||
|
// apply time zone offset to correctly fetch all-day events
|
||||||
|
val data = provider.getInstances(
|
||||||
|
now.timeInMillis + now.timeZone.getOffset(now.timeInMillis).coerceAtMost(0),
|
||||||
|
limit.timeInMillis + limit.timeZone.getOffset(limit.timeInMillis).coerceAtLeast(0)
|
||||||
|
)
|
||||||
|
if (data != null) {
|
||||||
|
val instances = data.list
|
||||||
|
for (instance in instances) {
|
||||||
|
try {
|
||||||
|
val e = provider.getEvent(instance.eventId)
|
||||||
|
if (e == null || e.deleted || CalendarHelper.getFilteredCalendarIdList().contains(e.calendarId))
|
||||||
|
continue
|
||||||
|
if (e.allDay) {
|
||||||
|
val start = Calendar.getInstance()
|
||||||
|
start.timeInMillis = instance.begin
|
||||||
|
val end = Calendar.getInstance()
|
||||||
|
end.timeInMillis = instance.end
|
||||||
|
instance.begin =
|
||||||
|
start.timeInMillis - start.timeZone.getOffset(start.timeInMillis)
|
||||||
|
instance.end =
|
||||||
|
end.timeInMillis - end.timeZone.getOffset(end.timeInMillis)
|
||||||
|
}
|
||||||
|
if (instance.begin <= limit.timeInMillis && now.timeInMillis < instance.end) {
|
||||||
|
/* Following check may result in "fake" all-day events with
|
||||||
|
* non-UTC start/end time, and therefore cannot be found by
|
||||||
|
* Calendar when tapped to open details.
|
||||||
|
// Check all day events
|
||||||
|
val startDate = Calendar.getInstance()
|
||||||
|
startDate.timeInMillis = instance.begin
|
||||||
|
val endDate = Calendar.getInstance()
|
||||||
|
endDate.timeInMillis = instance.end
|
||||||
|
|
||||||
|
val isAllDay = e.allDay || (
|
||||||
|
startDate.get(Calendar.MILLISECOND) == 0
|
||||||
|
&& startDate.get(Calendar.SECOND) == 0
|
||||||
|
&& startDate.get(Calendar.MINUTE) == 0
|
||||||
|
&& startDate.get(Calendar.HOUR_OF_DAY) == 0
|
||||||
|
&& endDate.get(Calendar.MILLISECOND) == 0
|
||||||
|
&& endDate.get(Calendar.SECOND) == 0
|
||||||
|
&& endDate.get(Calendar.MINUTE) == 0
|
||||||
|
&& endDate.get(Calendar.HOUR_OF_DAY) == 0
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
|
||||||
|
eventList.add(
|
||||||
|
Event(
|
||||||
|
id = instance.id,
|
||||||
|
eventID = e.id,
|
||||||
|
title = e.title ?: "",
|
||||||
|
startDate = instance.begin,
|
||||||
|
endDate = instance.end,
|
||||||
|
calendarID = e.calendarId,
|
||||||
|
allDay = e.allDay,
|
||||||
|
address = e.eventLocation ?: "",
|
||||||
|
selfAttendeeStatus = e.selfAttendeeStatus.toInt(),
|
||||||
|
availability = e.availability
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (ignored: Exception) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val sortedEvents = eventList.sortEvents()
|
||||||
|
val filteredEventList = sortedEvents.applyFilters()
|
||||||
|
|
||||||
|
if (filteredEventList.isEmpty()) {
|
||||||
|
eventRepository.resetNextEventData()
|
||||||
|
eventRepository.clearEvents()
|
||||||
|
} else {
|
||||||
|
eventRepository.saveEvents(sortedEvents)
|
||||||
|
eventRepository.saveNextEventData(filteredEventList.first())
|
||||||
|
}
|
||||||
|
} catch (ignored: java.lang.Exception) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
eventRepository.resetNextEventData()
|
||||||
|
eventRepository.clearEvents()
|
||||||
|
}
|
||||||
|
eventRepository.close()
|
||||||
|
UpdatesReceiver.setUpdates(context)
|
||||||
|
|
||||||
|
MainWidget.updateWidget(context)
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
|
||||||
|
if (Preferences.showEvents)
|
||||||
|
enqueueTrigger(context)
|
||||||
|
return Result.success()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun enqueue(context: Context) {
|
||||||
|
WorkManager.getInstance(context).enqueueUniqueWork(
|
||||||
|
"updateEventList",
|
||||||
|
ExistingWorkPolicy.KEEP,
|
||||||
|
OneTimeWorkRequestBuilder<UpdateCalendarWorker>().build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun enqueueTrigger(context: Context) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
WorkManager.getInstance(context).enqueueUniqueWork(
|
||||||
|
"updateEventListTrigger",
|
||||||
|
ExistingWorkPolicy.KEEP,
|
||||||
|
OneTimeWorkRequestBuilder<Trigger>().setConstraints(
|
||||||
|
Constraints.Builder().addContentUriTrigger(
|
||||||
|
CalendarContract.CONTENT_URI,
|
||||||
|
true
|
||||||
|
).build()
|
||||||
|
).build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun cancelTrigger(context: Context) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
WorkManager.getInstance(context).cancelUniqueWork(
|
||||||
|
"updateEventListTrigger"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Trigger(context: Context, params: WorkerParameters) : Worker(context, params) {
|
||||||
|
override fun doWork(): Result {
|
||||||
|
if (Preferences.showEvents && !isStopped)
|
||||||
|
enqueue(applicationContext)
|
||||||
|
return Result.success()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,108 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.services
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.content.Context
|
||||||
|
import android.location.Location
|
||||||
|
import android.location.LocationManager
|
||||||
|
import androidx.work.CoroutineWorker
|
||||||
|
import androidx.work.ExistingWorkPolicy
|
||||||
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
|
import androidx.work.WorkManager
|
||||||
|
import androidx.work.Worker
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import com.google.android.gms.common.ConnectionResult
|
||||||
|
import com.google.android.gms.common.GoogleApiAvailability
|
||||||
|
import com.google.android.gms.location.LocationServices
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.network.WeatherNetworkApi
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import kotlin.coroutines.resume
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
class WeatherWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
|
||||||
|
|
||||||
|
override suspend fun doWork(): Result {
|
||||||
|
val context = applicationContext
|
||||||
|
if (Preferences.customLocationAdd == "" &&
|
||||||
|
context.checkGrantedPermission(Manifest.permission.ACCESS_COARSE_LOCATION)
|
||||||
|
) {
|
||||||
|
if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context)
|
||||||
|
== ConnectionResult.SUCCESS
|
||||||
|
) {
|
||||||
|
suspendCancellableCoroutine { continuation ->
|
||||||
|
LocationServices.getFusedLocationProviderClient(context).lastLocation.addOnCompleteListener {
|
||||||
|
continuation.resume(if (it.isSuccessful) it.result else null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val lm = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||||
|
var location: Location? = null
|
||||||
|
for (provider in lm.getProviders(true)) {
|
||||||
|
lm.getLastKnownLocation(provider)?.let {
|
||||||
|
if (location == null ||
|
||||||
|
it.time - location!!.time > 2 * 60 * 1000 ||
|
||||||
|
(it.time - location!!.time > -2 * 60 * 1000 && it.accuracy < location!!.accuracy))
|
||||||
|
location = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
location
|
||||||
|
}?.let { location ->
|
||||||
|
Preferences.customLocationLat = location.latitude.toString()
|
||||||
|
Preferences.customLocationLon = location.longitude.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
WeatherNetworkApi(context).updateWeather()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Preferences.showWeather)
|
||||||
|
enqueueTrigger(context)
|
||||||
|
return Result.success()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun enqueue(context: Context, replace: Boolean = false) {
|
||||||
|
WorkManager.getInstance(context).enqueueUniqueWork(
|
||||||
|
"updateWeather",
|
||||||
|
if (replace) ExistingWorkPolicy.REPLACE else ExistingWorkPolicy.KEEP,
|
||||||
|
OneTimeWorkRequestBuilder<WeatherWorker>().build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun enqueueTrigger(context: Context) {
|
||||||
|
val interval = when (Preferences.weatherRefreshPeriod) {
|
||||||
|
0 -> 30
|
||||||
|
1 -> 60
|
||||||
|
2 -> 60L * 3
|
||||||
|
3 -> 60L * 6
|
||||||
|
4 -> 60L * 12
|
||||||
|
5 -> 60L * 24
|
||||||
|
else -> 60
|
||||||
|
}
|
||||||
|
WorkManager.getInstance(context).enqueueUniqueWork(
|
||||||
|
"updateWeatherTrigger",
|
||||||
|
ExistingWorkPolicy.REPLACE,
|
||||||
|
OneTimeWorkRequestBuilder<Trigger>().setInitialDelay(
|
||||||
|
interval, TimeUnit.MINUTES
|
||||||
|
).build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun cancelTrigger(context: Context) {
|
||||||
|
WorkManager.getInstance(context).cancelUniqueWork(
|
||||||
|
"updateWeatherTrigger"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Trigger(context: Context, params: WorkerParameters) : Worker(context, params) {
|
||||||
|
override fun doWork(): Result {
|
||||||
|
if (Preferences.showWeather && !isStopped)
|
||||||
|
enqueue(applicationContext)
|
||||||
|
return Result.success()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,148 +0,0 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.activities
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.os.Bundle
|
|
||||||
import com.tommasoberlose.anotherwidget.R
|
|
||||||
import android.content.Intent
|
|
||||||
import android.content.pm.ApplicationInfo
|
|
||||||
import android.content.pm.ResolveInfo
|
|
||||||
import android.util.Log
|
|
||||||
import android.view.View
|
|
||||||
import android.widget.ImageView
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.databinding.DataBindingUtil
|
|
||||||
import androidx.lifecycle.Observer
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import com.tommasoberlose.anotherwidget.databinding.ActivityChooseApplicationBinding
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Constants
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.ChooseApplicationViewModel
|
|
||||||
import kotlinx.android.synthetic.main.activity_choose_application.*
|
|
||||||
import kotlinx.android.synthetic.main.activity_choose_application.action_back
|
|
||||||
import kotlinx.android.synthetic.main.activity_choose_application.clear_search
|
|
||||||
import kotlinx.android.synthetic.main.activity_choose_application.list_view
|
|
||||||
import kotlinx.android.synthetic.main.activity_choose_application.loader
|
|
||||||
import kotlinx.android.synthetic.main.activity_choose_application.search
|
|
||||||
import kotlinx.android.synthetic.main.activity_music_players_filter.*
|
|
||||||
import kotlinx.coroutines.*
|
|
||||||
import net.idik.lib.slimadapter.SlimAdapter
|
|
||||||
import net.idik.lib.slimadapter.SlimAdapterEx
|
|
||||||
|
|
||||||
|
|
||||||
class ChooseApplicationActivity : AppCompatActivity() {
|
|
||||||
|
|
||||||
private lateinit var adapter: SlimAdapter
|
|
||||||
private lateinit var viewModel: ChooseApplicationViewModel
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
|
|
||||||
viewModel = ViewModelProvider(this).get(ChooseApplicationViewModel::class.java)
|
|
||||||
val binding = DataBindingUtil.setContentView<ActivityChooseApplicationBinding>(this, R.layout.activity_choose_application)
|
|
||||||
|
|
||||||
list_view.setHasFixedSize(true)
|
|
||||||
val mLayoutManager = LinearLayoutManager(this)
|
|
||||||
list_view.layoutManager = mLayoutManager
|
|
||||||
|
|
||||||
adapter = SlimAdapterEx.create()
|
|
||||||
adapter
|
|
||||||
.register<String>(R.layout.application_info_layout) { _, injector ->
|
|
||||||
injector
|
|
||||||
.text(R.id.text, getString(R.string.default_name))
|
|
||||||
.image(R.id.icon, R.drawable.round_add_to_home_screen_24)
|
|
||||||
.with<ImageView>(R.id.icon) {
|
|
||||||
it.scaleX = 0.8f
|
|
||||||
it.scaleY = 0.8f
|
|
||||||
it.setColorFilter(ContextCompat.getColor(this, R.color.colorPrimaryText), android.graphics.PorterDuff.Mode.MULTIPLY)
|
|
||||||
}
|
|
||||||
.clicked(R.id.item) {
|
|
||||||
val resultIntent = Intent()
|
|
||||||
resultIntent.putExtra(Constants.RESULT_APP_NAME, "")
|
|
||||||
resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, "")
|
|
||||||
setResult(Activity.RESULT_OK, resultIntent)
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.register<ResolveInfo>(R.layout.application_info_layout) { item, injector ->
|
|
||||||
injector
|
|
||||||
.text(R.id.text, item.loadLabel(viewModel.pm))
|
|
||||||
.with<ImageView>(R.id.icon) {
|
|
||||||
Glide
|
|
||||||
.with(this)
|
|
||||||
.load(item.loadIcon(viewModel.pm))
|
|
||||||
.centerCrop()
|
|
||||||
.into(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
injector.clicked(R.id.item) {
|
|
||||||
saveApp(item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.attachTo(list_view)
|
|
||||||
|
|
||||||
setupListener()
|
|
||||||
subscribeUi(binding, viewModel)
|
|
||||||
|
|
||||||
search.requestFocus()
|
|
||||||
}
|
|
||||||
|
|
||||||
private var filterJob: Job? = null
|
|
||||||
|
|
||||||
private fun subscribeUi(binding: ActivityChooseApplicationBinding, viewModel: ChooseApplicationViewModel) {
|
|
||||||
binding.viewModel = viewModel
|
|
||||||
binding.lifecycleOwner = this
|
|
||||||
|
|
||||||
viewModel.appList.observe(this, Observer {
|
|
||||||
updateList(list = it)
|
|
||||||
loader.visibility = View.INVISIBLE
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.searchInput.observe(this, Observer { search ->
|
|
||||||
updateList(search = search)
|
|
||||||
clear_search.isVisible = search.isNotBlank()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateList(list: List<ResolveInfo>? = viewModel.appList.value, search: String? = viewModel.searchInput.value) {
|
|
||||||
loader.visibility = View.VISIBLE
|
|
||||||
filterJob?.cancel()
|
|
||||||
filterJob = lifecycleScope.launch(Dispatchers.IO) {
|
|
||||||
if (list != null && list.isNotEmpty()) {
|
|
||||||
delay(200)
|
|
||||||
val filteredList: List<ResolveInfo> = if (search == null || search == "") {
|
|
||||||
list
|
|
||||||
} else {
|
|
||||||
list.filter {
|
|
||||||
it.loadLabel(viewModel.pm).contains(search, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
adapter.updateData(listOf("Default") + filteredList)
|
|
||||||
loader.visibility = View.INVISIBLE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupListener() {
|
|
||||||
action_back.setOnClickListener {
|
|
||||||
onBackPressed()
|
|
||||||
}
|
|
||||||
|
|
||||||
clear_search.setOnClickListener {
|
|
||||||
viewModel.searchInput.value = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun saveApp(app: ResolveInfo) {
|
|
||||||
val resultIntent = Intent()
|
|
||||||
resultIntent.putExtra(Constants.RESULT_APP_NAME, app.loadLabel(viewModel.pm))
|
|
||||||
resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, app.activityInfo.packageName)
|
|
||||||
setResult(Activity.RESULT_OK, resultIntent)
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,179 +0,0 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.activities
|
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Activity
|
|
||||||
import android.location.Address
|
|
||||||
import android.location.Geocoder
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
|
||||||
import com.tommasoberlose.anotherwidget.R
|
|
||||||
import android.text.Editable
|
|
||||||
import android.text.TextWatcher
|
|
||||||
import android.view.View
|
|
||||||
import android.view.Window
|
|
||||||
import android.widget.AdapterView
|
|
||||||
import android.widget.ArrayAdapter
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.databinding.DataBindingUtil
|
|
||||||
import androidx.lifecycle.Observer
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
|
||||||
import com.chibatching.kotpref.bulk
|
|
||||||
import com.google.android.material.transition.MaterialFadeThrough
|
|
||||||
import com.google.android.material.transition.MaterialSharedAxis
|
|
||||||
import com.karumi.dexter.Dexter
|
|
||||||
import com.karumi.dexter.MultiplePermissionsReport
|
|
||||||
import com.karumi.dexter.PermissionToken
|
|
||||||
import com.karumi.dexter.listener.PermissionRequest
|
|
||||||
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
|
||||||
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
|
|
||||||
import com.tommasoberlose.anotherwidget.databinding.ActivityChooseApplicationBinding
|
|
||||||
import com.tommasoberlose.anotherwidget.databinding.ActivityCustomLocationBinding
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.ChooseApplicationViewModel
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.CustomLocationViewModel
|
|
||||||
import kotlinx.android.synthetic.main.activity_custom_location.*
|
|
||||||
import kotlinx.android.synthetic.main.activity_custom_location.action_back
|
|
||||||
import kotlinx.android.synthetic.main.activity_custom_location.clear_search
|
|
||||||
import kotlinx.android.synthetic.main.activity_custom_location.list_view
|
|
||||||
import kotlinx.android.synthetic.main.activity_custom_location.loader
|
|
||||||
import kotlinx.android.synthetic.main.activity_music_players_filter.*
|
|
||||||
import kotlinx.coroutines.*
|
|
||||||
import net.idik.lib.slimadapter.SlimAdapter
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import org.greenrobot.eventbus.ThreadMode
|
|
||||||
import org.greenrobot.eventbus.Subscribe
|
|
||||||
|
|
||||||
class CustomLocationActivity : AppCompatActivity() {
|
|
||||||
|
|
||||||
private lateinit var adapter: SlimAdapter
|
|
||||||
private lateinit var viewModel: CustomLocationViewModel
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
|
|
||||||
viewModel = ViewModelProvider(this).get(CustomLocationViewModel::class.java)
|
|
||||||
val binding = DataBindingUtil.setContentView<ActivityCustomLocationBinding>(this, R.layout.activity_custom_location)
|
|
||||||
|
|
||||||
|
|
||||||
list_view.setHasFixedSize(true)
|
|
||||||
val mLayoutManager = LinearLayoutManager(this)
|
|
||||||
list_view.layoutManager = mLayoutManager
|
|
||||||
|
|
||||||
adapter = SlimAdapter.create()
|
|
||||||
adapter
|
|
||||||
.register<String>(R.layout.custom_location_item) { _, injector ->
|
|
||||||
injector
|
|
||||||
.text(R.id.text, getString(R.string.custom_location_gps))
|
|
||||||
.clicked(R.id.text) {
|
|
||||||
MaterialBottomSheetDialog(this, message = getString(R.string.background_location_warning))
|
|
||||||
.setPositiveButton(getString(android.R.string.ok)) {
|
|
||||||
requirePermission()
|
|
||||||
}
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.register<Address>(R.layout.custom_location_item) { item, injector ->
|
|
||||||
injector.text(R.id.text, item.getAddressLine(0))
|
|
||||||
injector.clicked(R.id.text) {
|
|
||||||
Preferences.bulk {
|
|
||||||
customLocationLat = item.latitude.toString()
|
|
||||||
customLocationLon = item.longitude.toString()
|
|
||||||
customLocationAdd = item.getAddressLine(0)
|
|
||||||
setResult(Activity.RESULT_OK)
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.attachTo(list_view)
|
|
||||||
|
|
||||||
|
|
||||||
viewModel.addresses.observe(this, Observer {
|
|
||||||
adapter.updateData(listOf("Default") + it)
|
|
||||||
})
|
|
||||||
|
|
||||||
setupListener()
|
|
||||||
subscribeUi(binding, viewModel)
|
|
||||||
|
|
||||||
location.requestFocus()
|
|
||||||
|
|
||||||
}
|
|
||||||
private var searchJob: Job? = null
|
|
||||||
|
|
||||||
private fun subscribeUi(binding: ActivityCustomLocationBinding, viewModel: CustomLocationViewModel) {
|
|
||||||
binding.viewModel = viewModel
|
|
||||||
binding.lifecycleOwner = this
|
|
||||||
|
|
||||||
viewModel.addresses.observe(this, Observer {
|
|
||||||
adapter.updateData(listOf("Default") + it)
|
|
||||||
loader.visibility = View.INVISIBLE
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.locationInput.observe(this, Observer { location ->
|
|
||||||
loader.visibility = View.VISIBLE
|
|
||||||
searchJob?.cancel()
|
|
||||||
searchJob = lifecycleScope.launch(Dispatchers.IO) {
|
|
||||||
delay(200)
|
|
||||||
val list = if (location == null || location == "") {
|
|
||||||
viewModel.addresses.value!!
|
|
||||||
} else {
|
|
||||||
val coder = Geocoder(this@CustomLocationActivity)
|
|
||||||
try {
|
|
||||||
coder.getFromLocationName(location, 10) as ArrayList<Address>
|
|
||||||
} catch (ignored: Exception) {
|
|
||||||
emptyList<Address>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
viewModel.addresses.value = list
|
|
||||||
loader.visibility = View.INVISIBLE
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
clear_search.isVisible = location.isNotBlank()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun requirePermission() {
|
|
||||||
Dexter.withContext(this)
|
|
||||||
.withPermissions(
|
|
||||||
Manifest.permission.ACCESS_FINE_LOCATION
|
|
||||||
).withListener(object: MultiplePermissionsListener {
|
|
||||||
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
|
||||||
report?.let {
|
|
||||||
if (report.areAllPermissionsGranted()){
|
|
||||||
Preferences.bulk {
|
|
||||||
remove(Preferences::customLocationLat)
|
|
||||||
remove(Preferences::customLocationLon)
|
|
||||||
remove(Preferences::customLocationAdd)
|
|
||||||
}
|
|
||||||
setResult(Activity.RESULT_OK)
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
override fun onPermissionRationaleShouldBeShown(
|
|
||||||
permissions: MutableList<PermissionRequest>?,
|
|
||||||
token: PermissionToken?
|
|
||||||
) {
|
|
||||||
// Remember to invoke this method when the custom rationale is closed
|
|
||||||
// or just by default if you don't want to use any custom rationale.
|
|
||||||
token?.continuePermissionRequest()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.check()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupListener() {
|
|
||||||
action_back.setOnClickListener {
|
|
||||||
onBackPressed()
|
|
||||||
}
|
|
||||||
|
|
||||||
clear_search.setOnClickListener {
|
|
||||||
viewModel.locationInput.value = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,94 +1,76 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.activities
|
package com.tommasoberlose.anotherwidget.ui.activities
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.animation.ValueAnimator
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.appwidget.AppWidgetManager
|
import android.appwidget.AppWidgetManager
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.graphics.Matrix
|
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.Settings
|
|
||||||
import android.util.DisplayMetrics
|
|
||||||
import android.util.Log
|
|
||||||
import android.util.TypedValue
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.RelativeLayout
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.animation.addListener
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.lifecycle.Observer
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.Navigation
|
import androidx.navigation.Navigation
|
||||||
import com.chibatching.kotpref.Kotpref
|
|
||||||
import com.google.android.material.badge.BadgeDrawable
|
|
||||||
import com.google.android.material.tabs.TabLayoutMediator
|
|
||||||
import com.karumi.dexter.Dexter
|
import com.karumi.dexter.Dexter
|
||||||
import com.karumi.dexter.MultiplePermissionsReport
|
import com.karumi.dexter.MultiplePermissionsReport
|
||||||
import com.karumi.dexter.PermissionToken
|
import com.karumi.dexter.PermissionToken
|
||||||
import com.karumi.dexter.listener.PermissionRequest
|
import com.karumi.dexter.listener.PermissionRequest
|
||||||
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
|
import com.tommasoberlose.anotherwidget.databinding.ActivityMainBinding
|
||||||
import com.tommasoberlose.anotherwidget.global.Actions
|
import com.tommasoberlose.anotherwidget.global.Actions
|
||||||
import com.tommasoberlose.anotherwidget.global.Constants
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.global.RequestCode
|
import com.tommasoberlose.anotherwidget.global.RequestCode
|
||||||
import com.tommasoberlose.anotherwidget.helpers.BitmapHelper
|
import com.tommasoberlose.anotherwidget.ui.activities.tabs.WeatherProviderActivity
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.adapters.ViewPagerAdapter
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
import com.tommasoberlose.anotherwidget.utils.getCurrentWallpaper
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.toPixel
|
|
||||||
import kotlinx.android.synthetic.main.activity_main.*
|
|
||||||
import kotlinx.android.synthetic.main.the_widget_sans.*
|
|
||||||
import kotlinx.coroutines.*
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import org.greenrobot.eventbus.Subscribe
|
|
||||||
import org.greenrobot.eventbus.ThreadMode
|
|
||||||
|
|
||||||
|
class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
class MainActivity : AppCompatActivity() {
|
|
||||||
|
|
||||||
private var mAppWidgetId: Int = -1
|
private var mAppWidgetId: Int = -1
|
||||||
private lateinit var viewModel: MainViewModel
|
private lateinit var viewModel: MainViewModel
|
||||||
|
private lateinit var binding: ActivityMainBinding
|
||||||
private val mainNavController: NavController? by lazy {
|
private val mainNavController: NavController? by lazy {
|
||||||
Navigation.findNavController(
|
Navigation.findNavController(
|
||||||
this,
|
this,
|
||||||
R.id.content_fragment
|
R.id.content_fragment
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
private val settingsNavController: NavController? by lazy {
|
||||||
|
Navigation.findNavController(
|
||||||
|
this,
|
||||||
|
R.id.settings_fragment
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_main)
|
overridePendingTransition(R.anim.nav_default_enter_anim, R.anim.nav_default_exit_anim)
|
||||||
|
|
||||||
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
|
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
|
||||||
|
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
controlExtras(intent)
|
controlExtras(intent)
|
||||||
if (Preferences.showWallpaper) {
|
if (Preferences.showWallpaper) {
|
||||||
requirePermission()
|
requirePermission()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setContentView(binding.root)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
if (mainNavController?.currentDestination?.id == R.id.appMainFragment) {
|
if (mainNavController?.currentDestination?.id == R.id.appMainFragment) {
|
||||||
|
if (settingsNavController?.navigateUp() == false) {
|
||||||
if (mAppWidgetId > 0) {
|
if (mAppWidgetId > 0) {
|
||||||
addNewWidget()
|
addNewWidget()
|
||||||
} else {
|
} else {
|
||||||
setResult(Activity.RESULT_OK)
|
setResult(Activity.RESULT_OK)
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
viewModel.fragmentScrollY.value = 0
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
super.onBackPressed()
|
super.onBackPressed()
|
||||||
}
|
}
|
||||||
@ -110,8 +92,8 @@ class MainActivity : AppCompatActivity() {
|
|||||||
AppWidgetManager.INVALID_APPWIDGET_ID)
|
AppWidgetManager.INVALID_APPWIDGET_ID)
|
||||||
|
|
||||||
if (mAppWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
|
if (mAppWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
|
||||||
action_add_widget.visibility = View.VISIBLE
|
binding.actionAddWidget.visibility = View.VISIBLE
|
||||||
action_add_widget.setOnClickListener {
|
binding.actionAddWidget.setOnClickListener {
|
||||||
addNewWidget()
|
addNewWidget()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -153,4 +135,26 @@ class MainActivity : AppCompatActivity() {
|
|||||||
})
|
})
|
||||||
.check()
|
.check()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
|
||||||
|
if (Preferences.showEvents && !checkGrantedPermission(Manifest.permission.READ_CALENDAR)) {
|
||||||
|
Preferences.showEvents = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
Preferences.preferences.registerOnSharedPreferenceChangeListener(this)
|
||||||
|
super.onStart()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop()
|
||||||
|
Preferences.preferences.unregisterOnSharedPreferenceChangeListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSharedPreferenceChanged(p0: SharedPreferences?, p1: String?) {
|
||||||
|
MainWidget.updateWidget(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.activities
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.ActivityMainBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
|
class SplashActivity: AppCompatActivity() {
|
||||||
|
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
lifecycleScope.launchWhenResumed {
|
||||||
|
delay(1000)
|
||||||
|
|
||||||
|
if (!this@SplashActivity.isDestroyed) {
|
||||||
|
startActivity(Intent(this@SplashActivity, MainActivity::class.java))
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,30 +1,29 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.activities
|
package com.tommasoberlose.anotherwidget.ui.activities.settings
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.databinding.DataBindingUtil
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import com.tommasoberlose.anotherwidget.databinding.ActivityIntegrationsBinding
|
import com.tommasoberlose.anotherwidget.databinding.ActivityIntegrationsBinding
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.IntegrationsViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.settings.IntegrationsViewModel
|
||||||
import kotlinx.android.synthetic.main.activity_integrations.*
|
|
||||||
import net.idik.lib.slimadapter.SlimAdapter
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
|
|
||||||
class IntegrationsActivity : AppCompatActivity() {
|
class IntegrationsActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private lateinit var adapter: SlimAdapter
|
private lateinit var adapter: SlimAdapter
|
||||||
private lateinit var viewModel: IntegrationsViewModel
|
private lateinit var viewModel: IntegrationsViewModel
|
||||||
|
private lateinit var binding: ActivityIntegrationsBinding
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
viewModel = ViewModelProvider(this).get(IntegrationsViewModel::class.java)
|
viewModel = ViewModelProvider(this).get(IntegrationsViewModel::class.java)
|
||||||
val binding = DataBindingUtil.setContentView<ActivityIntegrationsBinding>(this, R.layout.activity_integrations)
|
binding = ActivityIntegrationsBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
list_view.setHasFixedSize(true)
|
binding.listView.setHasFixedSize(true)
|
||||||
val mLayoutManager = LinearLayoutManager(this)
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
list_view.layoutManager = mLayoutManager
|
binding.listView.layoutManager = mLayoutManager
|
||||||
|
|
||||||
adapter = SlimAdapter.create()
|
adapter = SlimAdapter.create()
|
||||||
adapter
|
adapter
|
||||||
@ -33,10 +32,12 @@ class IntegrationsActivity : AppCompatActivity() {
|
|||||||
.text(R.id.text, getString(R.string.default_name))
|
.text(R.id.text, getString(R.string.default_name))
|
||||||
|
|
||||||
}
|
}
|
||||||
.attachTo(list_view)
|
.attachTo(binding.listView)
|
||||||
|
|
||||||
setupListener()
|
setupListener()
|
||||||
subscribeUi(binding, viewModel)
|
subscribeUi(binding, viewModel)
|
||||||
|
|
||||||
|
setContentView(binding.root)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun subscribeUi(binding: ActivityIntegrationsBinding, viewModel: IntegrationsViewModel) {
|
private fun subscribeUi(binding: ActivityIntegrationsBinding, viewModel: IntegrationsViewModel) {
|
||||||
@ -45,7 +46,7 @@ class IntegrationsActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupListener() {
|
private fun setupListener() {
|
||||||
action_back.setOnClickListener {
|
binding.actionBack.setOnClickListener {
|
||||||
onBackPressed()
|
onBackPressed()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,47 +1,38 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.activities
|
package com.tommasoberlose.anotherwidget.ui.activities.settings
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Intent
|
|
||||||
import android.location.Address
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
|
||||||
import android.view.View
|
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.databinding.DataBindingUtil
|
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.android.billingclient.api.*
|
import com.android.billingclient.api.*
|
||||||
import com.android.billingclient.api.BillingClient.BillingResponseCode.OK
|
import com.android.billingclient.api.BillingClient.BillingResponseCode.OK
|
||||||
import com.android.billingclient.api.BillingClient.BillingResponseCode.USER_CANCELED
|
import com.android.billingclient.api.BillingClient.BillingResponseCode.USER_CANCELED
|
||||||
import com.chibatching.kotpref.bulk
|
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import com.tommasoberlose.anotherwidget.databinding.ActivitySupportDevBinding
|
import com.tommasoberlose.anotherwidget.databinding.ActivitySupportDevBinding
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.settings.SupportDevViewModel
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.SupportDevViewModel
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.toast
|
import com.tommasoberlose.anotherwidget.utils.toast
|
||||||
import kotlinx.android.synthetic.main.activity_support_dev.*
|
|
||||||
import net.idik.lib.slimadapter.SlimAdapter
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
|
|
||||||
class SupportDevActivity : AppCompatActivity(), PurchasesUpdatedListener {
|
class SupportDevActivity : AppCompatActivity(), PurchasesUpdatedListener {
|
||||||
|
|
||||||
private lateinit var viewModel: SupportDevViewModel
|
private lateinit var viewModel: SupportDevViewModel
|
||||||
private lateinit var adapter: SlimAdapter
|
private lateinit var adapter: SlimAdapter
|
||||||
|
private lateinit var binding: ActivitySupportDevBinding
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
viewModel = ViewModelProvider(this).get(SupportDevViewModel::class.java)
|
viewModel = ViewModelProvider(this).get(SupportDevViewModel::class.java)
|
||||||
viewModel.billingClient = BillingClient.newBuilder(this).enablePendingPurchases().setListener(this).build()
|
viewModel.billingClient = BillingClient.newBuilder(this).enablePendingPurchases().setListener(this).build()
|
||||||
DataBindingUtil.setContentView<ActivitySupportDevBinding>(this, R.layout.activity_support_dev)
|
binding = ActivitySupportDevBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
|
||||||
list_view.setHasFixedSize(true)
|
binding.listView.setHasFixedSize(true)
|
||||||
val mLayoutManager = LinearLayoutManager(this)
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
list_view.layoutManager = mLayoutManager
|
binding.listView.layoutManager = mLayoutManager
|
||||||
|
|
||||||
adapter = SlimAdapter.create()
|
adapter = SlimAdapter.create()
|
||||||
adapter
|
adapter
|
||||||
@ -62,20 +53,22 @@ class SupportDevActivity : AppCompatActivity(), PurchasesUpdatedListener {
|
|||||||
viewModel.purchase(this, item)
|
viewModel.purchase(this, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.attachTo(list_view)
|
.attachTo(binding.listView)
|
||||||
|
|
||||||
viewModel.openConnection()
|
viewModel.openConnection()
|
||||||
subscribeUi(viewModel)
|
subscribeUi(viewModel)
|
||||||
|
|
||||||
action_back.setOnClickListener {
|
binding.actionBack.setOnClickListener {
|
||||||
onBackPressed()
|
onBackPressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setContentView(binding.root)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun subscribeUi(viewModel: SupportDevViewModel) {
|
private fun subscribeUi(viewModel: SupportDevViewModel) {
|
||||||
viewModel.products.observe(this, Observer {
|
viewModel.products.observe(this, Observer {
|
||||||
if (it.isNotEmpty()) {
|
if (it.isNotEmpty()) {
|
||||||
loader.isVisible = false
|
binding.loader.isVisible = false
|
||||||
}
|
}
|
||||||
adapter.updateData(it.sortedWith(compareBy(SkuDetails::getPriceAmountMicros)))
|
adapter.updateData(it.sortedWith(compareBy(SkuDetails::getPriceAmountMicros)))
|
||||||
})
|
})
|
@ -1,4 +1,4 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.activities
|
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||||
|
|
||||||
import android.content.pm.ResolveInfo
|
import android.content.pm.ResolveInfo
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
@ -6,7 +6,6 @@ import android.view.View
|
|||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.databinding.DataBindingUtil
|
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
@ -16,8 +15,7 @@ import com.tommasoberlose.anotherwidget.R
|
|||||||
import com.tommasoberlose.anotherwidget.databinding.ActivityAppNotificationsFilterBinding
|
import com.tommasoberlose.anotherwidget.databinding.ActivityAppNotificationsFilterBinding
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.AppNotificationsViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.AppNotificationsViewModel
|
||||||
import kotlinx.android.synthetic.main.activity_app_notifications_filter.*
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import net.idik.lib.slimadapter.SlimAdapter
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
|
|
||||||
@ -26,16 +24,17 @@ class AppNotificationsFilterActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private lateinit var adapter: SlimAdapter
|
private lateinit var adapter: SlimAdapter
|
||||||
private lateinit var viewModel: AppNotificationsViewModel
|
private lateinit var viewModel: AppNotificationsViewModel
|
||||||
|
private lateinit var binding: ActivityAppNotificationsFilterBinding
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
viewModel = ViewModelProvider(this).get(AppNotificationsViewModel::class.java)
|
viewModel = ViewModelProvider(this).get(AppNotificationsViewModel::class.java)
|
||||||
val binding = DataBindingUtil.setContentView<ActivityAppNotificationsFilterBinding>(this, R.layout.activity_app_notifications_filter)
|
binding = ActivityAppNotificationsFilterBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
list_view.setHasFixedSize(true)
|
binding.listView.setHasFixedSize(true)
|
||||||
val mLayoutManager = LinearLayoutManager(this)
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
list_view.layoutManager = mLayoutManager
|
binding.listView.layoutManager = mLayoutManager
|
||||||
|
|
||||||
adapter = SlimAdapter.create()
|
adapter = SlimAdapter.create()
|
||||||
adapter
|
adapter
|
||||||
@ -60,12 +59,14 @@ class AppNotificationsFilterActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
.checked(R.id.checkBox, ActiveNotificationsHelper.isAppAccepted(item.activityInfo.packageName))
|
.checked(R.id.checkBox, ActiveNotificationsHelper.isAppAccepted(item.activityInfo.packageName))
|
||||||
}
|
}
|
||||||
.attachTo(list_view)
|
.attachTo(binding.listView)
|
||||||
|
|
||||||
setupListener()
|
setupListener()
|
||||||
subscribeUi(binding, viewModel)
|
subscribeUi(binding, viewModel)
|
||||||
|
|
||||||
search.requestFocus()
|
binding.search.requestFocus()
|
||||||
|
|
||||||
|
setContentView(binding.root)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var filterJob: Job? = null
|
private var filterJob: Job? = null
|
||||||
@ -76,22 +77,22 @@ class AppNotificationsFilterActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
viewModel.appList.observe(this, Observer {
|
viewModel.appList.observe(this, Observer {
|
||||||
updateList(list = it)
|
updateList(list = it)
|
||||||
loader.visibility = View.INVISIBLE
|
binding.loader.visibility = View.INVISIBLE
|
||||||
})
|
})
|
||||||
|
|
||||||
viewModel.searchInput.observe(this, Observer { search ->
|
viewModel.searchInput.observe(this, Observer { search ->
|
||||||
updateList(search = search)
|
updateList(search = search)
|
||||||
clear_search.isVisible = search.isNotBlank()
|
binding.clearSearch.isVisible = search.isNotBlank()
|
||||||
})
|
})
|
||||||
|
|
||||||
viewModel.appNotificationsFilter.observe(this, {
|
viewModel.appNotificationsFilter.observe(this, {
|
||||||
updateList()
|
updateList()
|
||||||
clear_selection.isVisible = Preferences.appNotificationsFilter != ""
|
binding.clearSelection.isVisible = Preferences.appNotificationsFilter != ""
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateList(list: List<ResolveInfo>? = viewModel.appList.value, search: String? = viewModel.searchInput.value) {
|
private fun updateList(list: List<ResolveInfo>? = viewModel.appList.value, search: String? = viewModel.searchInput.value) {
|
||||||
loader.visibility = View.VISIBLE
|
binding.loader.visibility = View.VISIBLE
|
||||||
filterJob?.cancel()
|
filterJob?.cancel()
|
||||||
filterJob = lifecycleScope.launch(Dispatchers.IO) {
|
filterJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||||
if (list != null && list.isNotEmpty()) {
|
if (list != null && list.isNotEmpty()) {
|
||||||
@ -117,22 +118,22 @@ class AppNotificationsFilterActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
adapter.updateData(filteredList)
|
adapter.updateData(filteredList)
|
||||||
loader.visibility = View.INVISIBLE
|
binding.loader.visibility = View.INVISIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupListener() {
|
private fun setupListener() {
|
||||||
action_back.setOnClickListener {
|
binding.actionBack.setOnClickListener {
|
||||||
onBackPressed()
|
onBackPressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_search.setOnClickListener {
|
binding.clearSearch.setOnClickListener {
|
||||||
viewModel.searchInput.value = ""
|
viewModel.searchInput.value = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_selection.setOnClickListener {
|
binding.clearSelection.setOnClickListener {
|
||||||
Preferences.appNotificationsFilter = ""
|
Preferences.appNotificationsFilter = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,213 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.os.Bundle
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.ResolveInfo
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
|
import com.google.android.material.card.MaterialCardView
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.ActivityChooseApplicationBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.IntentHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.ChooseApplicationViewModel
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
|
import net.idik.lib.slimadapter.SlimAdapterEx
|
||||||
|
|
||||||
|
|
||||||
|
class ChooseApplicationActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private lateinit var adapter: SlimAdapter
|
||||||
|
private lateinit var viewModel: ChooseApplicationViewModel
|
||||||
|
private lateinit var binding: ActivityChooseApplicationBinding
|
||||||
|
|
||||||
|
private var selectedPackage: String? = null
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
selectedPackage = intent.extras?.getString(Constants.RESULT_APP_PACKAGE)
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(this).get(ChooseApplicationViewModel::class.java)
|
||||||
|
binding = ActivityChooseApplicationBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
binding.listView.setHasFixedSize(true)
|
||||||
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
|
binding.listView.layoutManager = mLayoutManager
|
||||||
|
|
||||||
|
adapter = SlimAdapterEx.create()
|
||||||
|
adapter
|
||||||
|
.register<String>(R.layout.application_info_layout) { item, injector ->
|
||||||
|
when (item) {
|
||||||
|
IntentHelper.DO_NOTHING_OPTION -> {
|
||||||
|
injector
|
||||||
|
.text(R.id.text, getString(R.string.gestures_do_nothing))
|
||||||
|
.image(R.id.icon, R.drawable.round_no_cell_24)
|
||||||
|
.with<ImageView>(R.id.icon) {
|
||||||
|
it.scaleX = 0.8f
|
||||||
|
it.scaleY = 0.8f
|
||||||
|
it.setColorFilter(ContextCompat.getColor(this, R.color.colorPrimaryText), android.graphics.PorterDuff.Mode.MULTIPLY)
|
||||||
|
}
|
||||||
|
.clicked(R.id.item) {
|
||||||
|
val resultIntent = Intent()
|
||||||
|
resultIntent.putExtra(Constants.RESULT_APP_NAME, IntentHelper.DO_NOTHING_OPTION)
|
||||||
|
resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, IntentHelper.DO_NOTHING_OPTION)
|
||||||
|
setResult(Activity.RESULT_OK, resultIntent)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
.with<MaterialCardView>(R.id.item) {
|
||||||
|
it.strokeColor = ContextCompat.getColor(this, if (selectedPackage == IntentHelper.DO_NOTHING_OPTION) R.color.colorAccent else R.color.cardBorder)
|
||||||
|
it.setCardBackgroundColor(ContextCompat.getColor(this, if (selectedPackage == IntentHelper.DO_NOTHING_OPTION) R.color.colorAccent_op10 else R.color.colorPrimaryDark))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IntentHelper.REFRESH_WIDGET_OPTION -> {
|
||||||
|
injector
|
||||||
|
.text(R.id.text, getString(R.string.action_refresh_widget))
|
||||||
|
.image(R.id.icon, R.drawable.round_refresh)
|
||||||
|
.with<ImageView>(R.id.icon) {
|
||||||
|
it.scaleX = 0.8f
|
||||||
|
it.scaleY = 0.8f
|
||||||
|
it.setColorFilter(ContextCompat.getColor(this, R.color.colorPrimaryText), android.graphics.PorterDuff.Mode.MULTIPLY)
|
||||||
|
}
|
||||||
|
.clicked(R.id.item) {
|
||||||
|
val resultIntent = Intent()
|
||||||
|
resultIntent.putExtra(Constants.RESULT_APP_NAME, IntentHelper.REFRESH_WIDGET_OPTION)
|
||||||
|
resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, IntentHelper.REFRESH_WIDGET_OPTION)
|
||||||
|
setResult(Activity.RESULT_OK, resultIntent)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
.with<MaterialCardView>(R.id.item) {
|
||||||
|
it.strokeColor = ContextCompat.getColor(this, if (selectedPackage == IntentHelper.REFRESH_WIDGET_OPTION) R.color.colorAccent else R.color.cardBorder)
|
||||||
|
it.setCardBackgroundColor(ContextCompat.getColor(this, if (selectedPackage == IntentHelper.REFRESH_WIDGET_OPTION) R.color.colorAccent_op10 else R.color.colorPrimaryDark))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
injector
|
||||||
|
.text(R.id.text, getString(R.string.default_name))
|
||||||
|
.image(R.id.icon, R.drawable.round_add_to_home_screen_24)
|
||||||
|
.with<ImageView>(R.id.icon) {
|
||||||
|
it.scaleX = 0.8f
|
||||||
|
it.scaleY = 0.8f
|
||||||
|
it.setColorFilter(ContextCompat.getColor(this, R.color.colorPrimaryText), android.graphics.PorterDuff.Mode.MULTIPLY)
|
||||||
|
}
|
||||||
|
.clicked(R.id.item) {
|
||||||
|
val resultIntent = Intent()
|
||||||
|
resultIntent.putExtra(Constants.RESULT_APP_NAME, IntentHelper.DEFAULT_OPTION)
|
||||||
|
resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, IntentHelper.DEFAULT_OPTION)
|
||||||
|
setResult(Activity.RESULT_OK, resultIntent)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
.with<MaterialCardView>(R.id.item) {
|
||||||
|
it.strokeColor = ContextCompat.getColor(this, if (selectedPackage == IntentHelper.DEFAULT_OPTION) R.color.colorAccent else R.color.cardBorder)
|
||||||
|
it.setCardBackgroundColor(ContextCompat.getColor(this, if (selectedPackage == IntentHelper.DEFAULT_OPTION) R.color.colorAccent_op10 else R.color.colorPrimaryDark))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.register<ResolveInfo>(R.layout.application_info_layout) { item, injector ->
|
||||||
|
injector
|
||||||
|
.text(R.id.text, item.loadLabel(viewModel.pm))
|
||||||
|
.with<ImageView>(R.id.icon) {
|
||||||
|
Glide
|
||||||
|
.with(this)
|
||||||
|
.load(item.loadIcon(viewModel.pm))
|
||||||
|
.centerCrop()
|
||||||
|
.into(it)
|
||||||
|
}
|
||||||
|
.clicked(R.id.item) {
|
||||||
|
saveApp(item)
|
||||||
|
}
|
||||||
|
.with<MaterialCardView>(R.id.item) {
|
||||||
|
it.strokeColor = ContextCompat.getColor(this, if (selectedPackage == item.activityInfo.packageName) R.color.colorAccent else R.color.cardBorder)
|
||||||
|
it.setCardBackgroundColor(ContextCompat.getColor(this, if (selectedPackage == item.activityInfo.packageName) R.color.colorAccent_op10 else R.color.colorPrimaryDark))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.attachTo(binding.listView)
|
||||||
|
|
||||||
|
setupListener()
|
||||||
|
subscribeUi(binding, viewModel)
|
||||||
|
|
||||||
|
binding.search.requestFocus()
|
||||||
|
|
||||||
|
setContentView(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var filterJob: Job? = null
|
||||||
|
|
||||||
|
private fun subscribeUi(binding: ActivityChooseApplicationBinding, viewModel: ChooseApplicationViewModel) {
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
|
||||||
|
viewModel.appList.observe(this) {
|
||||||
|
updateList(list = it)
|
||||||
|
binding.loader.visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.searchInput.observe(this) { search ->
|
||||||
|
updateList(search = search)
|
||||||
|
binding.clearSearch.isVisible = search.isNotBlank()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateList(list: List<ResolveInfo>? = viewModel.appList.value, search: String? = viewModel.searchInput.value) {
|
||||||
|
binding.loader.visibility = View.VISIBLE
|
||||||
|
filterJob?.cancel()
|
||||||
|
filterJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
if (list != null && list.isNotEmpty()) {
|
||||||
|
delay(200)
|
||||||
|
val filteredList: List<ResolveInfo> = if (search == null || search == "") {
|
||||||
|
list
|
||||||
|
} else {
|
||||||
|
list.filter {
|
||||||
|
it.loadLabel(viewModel.pm).contains(search, true)
|
||||||
|
}
|
||||||
|
}.sortedWith { app1, app2 ->
|
||||||
|
when (selectedPackage) {
|
||||||
|
app1.activityInfo.packageName -> {
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
app2.activityInfo.packageName -> {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
app1.loadLabel(viewModel.pm).toString().compareTo(app2.loadLabel(viewModel.pm).toString(), ignoreCase = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
adapter.updateData(listOf(IntentHelper.DO_NOTHING_OPTION, IntentHelper.DEFAULT_OPTION, IntentHelper.REFRESH_WIDGET_OPTION) + filteredList)
|
||||||
|
binding.loader.visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListener() {
|
||||||
|
binding.actionBack.setOnClickListener {
|
||||||
|
onBackPressed()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.clearSearch.setOnClickListener {
|
||||||
|
viewModel.searchInput.value = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun saveApp(app: ResolveInfo) {
|
||||||
|
val resultIntent = Intent()
|
||||||
|
resultIntent.putExtra(Constants.RESULT_APP_NAME, app.loadLabel(viewModel.pm))
|
||||||
|
resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, app.activityInfo.packageName)
|
||||||
|
setResult(Activity.RESULT_OK, resultIntent)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
@ -1,31 +1,21 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.activities
|
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.location.Address
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.databinding.DataBindingUtil
|
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.chibatching.kotpref.blockingBulk
|
import com.chibatching.kotpref.blockingBulk
|
||||||
import com.chibatching.kotpref.bulk
|
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import com.tommasoberlose.anotherwidget.databinding.ActivityCustomDateBinding
|
import com.tommasoberlose.anotherwidget.databinding.ActivityCustomDateBinding
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.helpers.DateHelper
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.CustomDateViewModel
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.CustomDateViewModel
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.getCapWordString
|
import com.tommasoberlose.anotherwidget.utils.getCapWordString
|
||||||
import com.tommasoberlose.anotherwidget.utils.openURI
|
import com.tommasoberlose.anotherwidget.utils.openURI
|
||||||
import com.tommasoberlose.anotherwidget.utils.toast
|
import com.tommasoberlose.anotherwidget.utils.toast
|
||||||
import kotlinx.android.synthetic.main.activity_custom_date.*
|
|
||||||
import kotlinx.android.synthetic.main.activity_custom_location.action_back
|
|
||||||
import kotlinx.android.synthetic.main.activity_custom_location.list_view
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import net.idik.lib.slimadapter.SlimAdapter
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
@ -36,26 +26,28 @@ class CustomDateActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private lateinit var adapter: SlimAdapter
|
private lateinit var adapter: SlimAdapter
|
||||||
private lateinit var viewModel: CustomDateViewModel
|
private lateinit var viewModel: CustomDateViewModel
|
||||||
|
private lateinit var binding: ActivityCustomDateBinding
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
viewModel = ViewModelProvider(this).get(CustomDateViewModel::class.java)
|
viewModel = ViewModelProvider(this).get(CustomDateViewModel::class.java)
|
||||||
val binding = DataBindingUtil.setContentView<ActivityCustomDateBinding>(this, R.layout.activity_custom_date)
|
binding = ActivityCustomDateBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
|
||||||
list_view.setHasFixedSize(true)
|
binding.listView.setHasFixedSize(true)
|
||||||
val mLayoutManager = LinearLayoutManager(this)
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
list_view.layoutManager = mLayoutManager
|
binding.listView.layoutManager = mLayoutManager
|
||||||
|
|
||||||
adapter = SlimAdapter.create()
|
adapter = SlimAdapter.create()
|
||||||
adapter
|
adapter
|
||||||
.register<String>(R.layout.custom_date_example_item) { item, injector ->
|
.register<String>(R.layout.custom_date_example_item) { item, injector ->
|
||||||
injector
|
injector
|
||||||
.text(R.id.custom_date_example_format, item)
|
.text(R.id.custom_date_example_format, item)
|
||||||
.text(R.id.custom_date_example_value, SimpleDateFormat(item, Locale.getDefault()).format(DATE.time))
|
.text(R.id.custom_date_example_value, SimpleDateFormat(item, Locale.getDefault()).format(
|
||||||
|
DATE.time))
|
||||||
}
|
}
|
||||||
.attachTo(list_view)
|
.attachTo(binding.listView)
|
||||||
|
|
||||||
adapter.updateData(
|
adapter.updateData(
|
||||||
listOf(
|
listOf(
|
||||||
@ -66,9 +58,11 @@ class CustomDateActivity : AppCompatActivity() {
|
|||||||
setupListener()
|
setupListener()
|
||||||
subscribeUi(binding, viewModel)
|
subscribeUi(binding, viewModel)
|
||||||
|
|
||||||
date_format.requestFocus()
|
binding.dateFormat.requestFocus()
|
||||||
|
|
||||||
|
setContentView(binding.root)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var formatJob: Job? = null
|
private var formatJob: Job? = null
|
||||||
|
|
||||||
private fun subscribeUi(binding: ActivityCustomDateBinding, viewModel: CustomDateViewModel) {
|
private fun subscribeUi(binding: ActivityCustomDateBinding, viewModel: CustomDateViewModel) {
|
||||||
@ -79,7 +73,7 @@ class CustomDateActivity : AppCompatActivity() {
|
|||||||
formatJob?.cancel()
|
formatJob?.cancel()
|
||||||
formatJob = lifecycleScope.launch(Dispatchers.IO) {
|
formatJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
loader.visibility = View.VISIBLE
|
binding.loader.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
|
|
||||||
delay(200)
|
delay(200)
|
||||||
@ -102,8 +96,8 @@ class CustomDateActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
loader.visibility = View.INVISIBLE
|
binding.loader.visibility = View.INVISIBLE
|
||||||
date_format_value.text = text
|
binding.dateFormatValue.text = text
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -123,26 +117,26 @@ class CustomDateActivity : AppCompatActivity() {
|
|||||||
private fun updateCapitalizeUi() {
|
private fun updateCapitalizeUi() {
|
||||||
when {
|
when {
|
||||||
viewModel.isDateUppercase.value == true -> {
|
viewModel.isDateUppercase.value == true -> {
|
||||||
action_capitalize.setImageDrawable(ContextCompat.getDrawable(this@CustomDateActivity, R.drawable.round_publish))
|
binding.actionCapitalize.setImageDrawable(ContextCompat.getDrawable(this@CustomDateActivity, R.drawable.round_publish))
|
||||||
action_capitalize.alpha = 1f
|
binding.actionCapitalize.alpha = 1f
|
||||||
}
|
}
|
||||||
viewModel.isDateCapitalize.value == true -> {
|
viewModel.isDateCapitalize.value == true -> {
|
||||||
action_capitalize.setImageDrawable(ContextCompat.getDrawable(this@CustomDateActivity, R.drawable.ic_capitalize))
|
binding.actionCapitalize.setImageDrawable(ContextCompat.getDrawable(this@CustomDateActivity, R.drawable.ic_capitalize))
|
||||||
action_capitalize.alpha = 1f
|
binding.actionCapitalize.alpha = 1f
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
action_capitalize.setImageDrawable(ContextCompat.getDrawable(this@CustomDateActivity, R.drawable.round_publish))
|
binding.actionCapitalize.setImageDrawable(ContextCompat.getDrawable(this@CustomDateActivity, R.drawable.round_publish))
|
||||||
action_capitalize.alpha = 0.3f
|
binding.actionCapitalize.alpha = 0.3f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupListener() {
|
private fun setupListener() {
|
||||||
action_back.setOnClickListener {
|
binding.actionBack.setOnClickListener {
|
||||||
onBackPressed()
|
onBackPressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
action_capitalize.setOnClickListener {
|
binding.actionCapitalize.setOnClickListener {
|
||||||
when {
|
when {
|
||||||
viewModel.isDateUppercase.value == true -> {
|
viewModel.isDateUppercase.value == true -> {
|
||||||
viewModel.isDateCapitalize.value = false
|
viewModel.isDateCapitalize.value = false
|
||||||
@ -159,12 +153,12 @@ class CustomDateActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
action_capitalize.setOnLongClickListener {
|
binding.actionCapitalize.setOnLongClickListener {
|
||||||
toast(getString(R.string.action_capitalize_the_date))
|
toast(getString(R.string.action_capitalize_the_date))
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
action_date_format_info.setOnClickListener {
|
binding.actionDateFormatInfo.setOnClickListener {
|
||||||
openURI("https://developer.android.com/reference/java/text/SimpleDateFormat")
|
openURI("https://developer.android.com/reference/java/text/SimpleDateFormat")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,6 +169,7 @@ class CustomDateActivity : AppCompatActivity() {
|
|||||||
isDateCapitalize = viewModel.isDateCapitalize.value ?: true
|
isDateCapitalize = viewModel.isDateCapitalize.value ?: true
|
||||||
isDateUppercase = viewModel.isDateUppercase.value ?: false
|
isDateUppercase = viewModel.isDateUppercase.value ?: false
|
||||||
}
|
}
|
||||||
|
com.tommasoberlose.anotherwidget.ui.widgets.MainWidget.updateWidget(this)
|
||||||
super.onBackPressed()
|
super.onBackPressed()
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.activities
|
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
@ -6,6 +6,7 @@ import android.graphics.Typeface
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.HandlerThread
|
import android.os.HandlerThread
|
||||||
|
import android.util.Log
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
@ -13,28 +14,20 @@ import androidx.appcompat.app.AppCompatActivity
|
|||||||
import androidx.core.provider.FontRequest
|
import androidx.core.provider.FontRequest
|
||||||
import androidx.core.provider.FontsContractCompat
|
import androidx.core.provider.FontsContractCompat
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.databinding.DataBindingUtil
|
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.chibatching.kotpref.blockingBulk
|
import com.chibatching.kotpref.blockingBulk
|
||||||
|
import com.google.gson.Gson
|
||||||
import com.koolio.library.Font
|
import com.koolio.library.Font
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||||
import com.tommasoberlose.anotherwidget.databinding.ActivityCustomFontBinding
|
import com.tommasoberlose.anotherwidget.databinding.ActivityCustomFontBinding
|
||||||
import com.tommasoberlose.anotherwidget.global.Constants
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.helpers.DateHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.CustomFontViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.CustomFontViewModel
|
||||||
import kotlinx.android.synthetic.main.activity_choose_application.*
|
|
||||||
import kotlinx.android.synthetic.main.activity_choose_application.action_back
|
|
||||||
import kotlinx.android.synthetic.main.activity_choose_application.clear_search
|
|
||||||
import kotlinx.android.synthetic.main.activity_choose_application.list_view
|
|
||||||
import kotlinx.android.synthetic.main.activity_choose_application.loader
|
|
||||||
import kotlinx.android.synthetic.main.activity_choose_application.search
|
|
||||||
import kotlinx.android.synthetic.main.activity_music_players_filter.*
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import net.idik.lib.slimadapter.SlimAdapter
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
import net.idik.lib.slimadapter.diff.DefaultDiffCallback
|
import net.idik.lib.slimadapter.diff.DefaultDiffCallback
|
||||||
@ -44,19 +37,20 @@ class CustomFontActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private lateinit var adapter: SlimAdapter
|
private lateinit var adapter: SlimAdapter
|
||||||
private lateinit var viewModel: CustomFontViewModel
|
private lateinit var viewModel: CustomFontViewModel
|
||||||
|
private lateinit var binding: ActivityCustomFontBinding
|
||||||
|
private lateinit var handlerThread: HandlerThread
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
viewModel = ViewModelProvider(this).get(CustomFontViewModel::class.java)
|
viewModel = ViewModelProvider(this).get(CustomFontViewModel::class.java)
|
||||||
val binding = DataBindingUtil.setContentView<ActivityCustomFontBinding>(
|
binding = ActivityCustomFontBinding.inflate(layoutInflater)
|
||||||
this,
|
handlerThread = HandlerThread("listCustomFonts")
|
||||||
R.layout.activity_custom_font
|
handlerThread.start()
|
||||||
)
|
|
||||||
|
|
||||||
list_view.setHasFixedSize(true)
|
binding.listView.setHasFixedSize(true)
|
||||||
val mLayoutManager = LinearLayoutManager(this)
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
list_view.layoutManager = mLayoutManager
|
binding.listView.layoutManager = mLayoutManager
|
||||||
|
|
||||||
adapter = SlimAdapter.create()
|
adapter = SlimAdapter.create()
|
||||||
adapter.enableDiff(object: DefaultDiffCallback() {
|
adapter.enableDiff(object: DefaultDiffCallback() {
|
||||||
@ -73,20 +67,23 @@ class CustomFontActivity : AppCompatActivity() {
|
|||||||
injector
|
injector
|
||||||
.text(R.id.text, item)
|
.text(R.id.text, item)
|
||||||
.with<TextView>(R.id.text) {
|
.with<TextView>(R.id.text) {
|
||||||
val googleSans: Typeface = when (Preferences.customFontVariant) {
|
val googleSans: Typeface? = androidx.core.content.res.ResourcesCompat.getFont(
|
||||||
"100" -> Typeface.createFromAsset(this.assets, "fonts/google_sans_thin.ttf")
|
this,
|
||||||
"200" -> Typeface.createFromAsset(this.assets, "fonts/google_sans_light.ttf")
|
when (Preferences.customFontVariant) {
|
||||||
"500" -> Typeface.createFromAsset(this.assets, "fonts/google_sans_medium.ttf")
|
"100" -> R.font.google_sans_thin
|
||||||
"700" -> Typeface.createFromAsset(this.assets, "fonts/google_sans_bold.ttf")
|
"200" -> R.font.google_sans_light
|
||||||
"800" -> Typeface.createFromAsset(this.assets, "fonts/google_sans_black.ttf")
|
"500" -> R.font.google_sans_medium
|
||||||
else -> Typeface.createFromAsset(this.assets, "fonts/google_sans_regular.ttf")
|
"700" -> R.font.google_sans_bold
|
||||||
|
"800" -> R.font.google_sans_black
|
||||||
|
else -> R.font.google_sans_regular
|
||||||
}
|
}
|
||||||
|
)
|
||||||
it.typeface = googleSans
|
it.typeface = googleSans
|
||||||
}
|
}
|
||||||
|
|
||||||
injector.clicked(R.id.text) {
|
injector.clicked(R.id.text) {
|
||||||
val dialog = BottomSheetMenu<String>(this, header = item)
|
val dialog = BottomSheetMenu<String>(this, header = item)
|
||||||
listOf("100", "200", "regular", "500", "700", "800").forEachIndexed { index, s ->
|
listOf("100", "200", "regular", "500", "700", "800").forEachIndexed { _, s ->
|
||||||
dialog.addItem(SettingsStringHelper.getVariantLabel(this, s), s)
|
dialog.addItem(SettingsStringHelper.getVariantLabel(this, s), s)
|
||||||
}
|
}
|
||||||
dialog.addOnSelectItemListener { value ->
|
dialog.addOnSelectItemListener { value ->
|
||||||
@ -106,37 +103,54 @@ class CustomFontActivity : AppCompatActivity() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
val callback = object : FontsContractCompat.FontRequestCallback() {
|
class Callback : FontsContractCompat.FontRequestCallback() {
|
||||||
override fun onTypefaceRetrieved(typeface: Typeface) {
|
var handler: Handler? = Handler(handlerThread.looper)
|
||||||
it.typeface = typeface
|
|
||||||
it.isVisible = true
|
|
||||||
|
|
||||||
it.measure(
|
fun cancel() {
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
if (handler != null) {
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
handler!!.removeCallbacksAndMessages(null)
|
||||||
)
|
handler = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun finalize() {
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTypefaceRetrieved(typeface: Typeface) {
|
||||||
|
if (it.tag == this) {
|
||||||
|
it.tag = null
|
||||||
|
it.typeface = typeface
|
||||||
|
it.setTextColor(getColor(R.color.colorPrimaryText))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTypefaceRequestFailed(reason: Int) {
|
override fun onTypefaceRequestFailed(reason: Int) {
|
||||||
it.isVisible = false
|
if (it.tag == this) {
|
||||||
it.layoutParams = it.layoutParams.apply {
|
it.tag = null
|
||||||
height = 0
|
//it.text = item.fontFamily + " ($reason)"
|
||||||
|
it.setTextColor(getColor(R.color.errorColorText))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val handlerThread = HandlerThread(item.fontFamily)
|
(it.tag as Callback?)?.cancel()
|
||||||
handlerThread.start()
|
val callback = Callback()
|
||||||
val mHandler = Handler(handlerThread.looper)
|
it.tag = callback
|
||||||
|
it.typeface = null
|
||||||
|
it.setTextColor(getColor(R.color.colorSecondaryText))
|
||||||
|
|
||||||
|
val mHandler = callback.handler!!
|
||||||
FontsContractCompat.requestFont(this, request, callback, mHandler)
|
FontsContractCompat.requestFont(this, request, callback, mHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
injector.clicked(R.id.text) {
|
injector.clicked(R.id.text) {
|
||||||
|
if ((it as TextView).typeface == null) return@clicked
|
||||||
val dialog = BottomSheetMenu<Int>(this, header = item.fontFamily)
|
val dialog = BottomSheetMenu<Int>(this, header = item.fontFamily)
|
||||||
if (item.fontVariants.isEmpty()) {
|
if (item.fontVariants.isEmpty()) {
|
||||||
dialog.addItem(SettingsStringHelper.getVariantLabel(this, "regular"), -1)
|
dialog.addItem(SettingsStringHelper.getVariantLabel(this, "regular"), -1)
|
||||||
} else {
|
} else {
|
||||||
item.fontVariants.filter { !it.contains("italic") }
|
item.fontVariants
|
||||||
.forEachIndexed { index, s ->
|
.forEachIndexed { index, s ->
|
||||||
dialog.addItem(SettingsStringHelper.getVariantLabel(this, s), index)
|
dialog.addItem(SettingsStringHelper.getVariantLabel(this, s), index)
|
||||||
}
|
}
|
||||||
@ -146,12 +160,20 @@ class CustomFontActivity : AppCompatActivity() {
|
|||||||
}.show()
|
}.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.attachTo(list_view)
|
.attachTo(binding.listView)
|
||||||
|
|
||||||
setupListener()
|
setupListener()
|
||||||
subscribeUi(binding, viewModel)
|
subscribeUi(binding, viewModel)
|
||||||
|
|
||||||
search.requestFocus()
|
binding.search.requestFocus()
|
||||||
|
|
||||||
|
setContentView(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
handlerThread.quit()
|
||||||
|
filterJob?.cancel()
|
||||||
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var filterJob: Job? = null
|
private var filterJob: Job? = null
|
||||||
@ -162,12 +184,12 @@ class CustomFontActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
viewModel.fontList.observe(this, Observer {
|
viewModel.fontList.observe(this, Observer {
|
||||||
updateList(list = it)
|
updateList(list = it)
|
||||||
loader.visibility = View.INVISIBLE
|
binding.loader.visibility = View.INVISIBLE
|
||||||
})
|
})
|
||||||
|
|
||||||
viewModel.searchInput.observe(this, Observer { search ->
|
viewModel.searchInput.observe(this, Observer { search ->
|
||||||
updateList(search = search)
|
updateList(search = search)
|
||||||
clear_search.isVisible = search.isNotBlank()
|
binding.clearSearch.isVisible = search.isNotBlank()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +197,7 @@ class CustomFontActivity : AppCompatActivity() {
|
|||||||
list: ArrayList<Font>? = viewModel.fontList.value,
|
list: ArrayList<Font>? = viewModel.fontList.value,
|
||||||
search: String? = viewModel.searchInput.value
|
search: String? = viewModel.searchInput.value
|
||||||
) {
|
) {
|
||||||
loader.visibility = View.VISIBLE
|
binding.loader.visibility = View.VISIBLE
|
||||||
filterJob?.cancel()
|
filterJob?.cancel()
|
||||||
filterJob = lifecycleScope.launch(Dispatchers.IO) {
|
filterJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||||
if (list != null && list.isNotEmpty()) {
|
if (list != null && list.isNotEmpty()) {
|
||||||
@ -209,18 +231,25 @@ class CustomFontActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
adapter.updateData(filteredList)
|
adapter.updateData(filteredList)
|
||||||
loader.visibility = View.INVISIBLE
|
binding.loader.visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
delay(200)
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
adapter.updateData(listOf(getString(R.string.custom_font_subtitle_1)).filter {
|
||||||
|
it.contains(search ?: "", ignoreCase = true)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupListener() {
|
private fun setupListener() {
|
||||||
action_back.setOnClickListener {
|
binding.actionBack.setOnClickListener {
|
||||||
onBackPressed()
|
onBackPressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_search.setOnClickListener {
|
binding.clearSearch.setOnClickListener {
|
||||||
viewModel.searchInput.value = ""
|
viewModel.searchInput.value = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,132 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.app.Activity
|
||||||
|
import android.location.Address
|
||||||
|
import android.location.Geocoder
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import android.view.View
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.chibatching.kotpref.bulk
|
||||||
|
import com.karumi.dexter.Dexter
|
||||||
|
import com.karumi.dexter.MultiplePermissionsReport
|
||||||
|
import com.karumi.dexter.PermissionToken
|
||||||
|
import com.karumi.dexter.listener.PermissionRequest
|
||||||
|
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.ActivityCustomLocationBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.CustomLocationViewModel
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
|
|
||||||
|
class CustomLocationActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private lateinit var adapter: SlimAdapter
|
||||||
|
private lateinit var viewModel: CustomLocationViewModel
|
||||||
|
private lateinit var binding: ActivityCustomLocationBinding
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(this).get(CustomLocationViewModel::class.java)
|
||||||
|
binding = ActivityCustomLocationBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
|
||||||
|
binding.listView.setHasFixedSize(true)
|
||||||
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
|
binding.listView.layoutManager = mLayoutManager
|
||||||
|
|
||||||
|
adapter = SlimAdapter.create()
|
||||||
|
adapter
|
||||||
|
.register<String>(R.layout.custom_location_item) { _, injector ->
|
||||||
|
injector.text(R.id.text, getString(R.string.custom_location_gps))
|
||||||
|
injector.clicked(R.id.text) {
|
||||||
|
Preferences.bulk {
|
||||||
|
remove(Preferences::customLocationLat)
|
||||||
|
remove(Preferences::customLocationLon)
|
||||||
|
remove(Preferences::customLocationAdd)
|
||||||
|
}
|
||||||
|
setResult(Activity.RESULT_OK)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.register<Address>(R.layout.custom_location_item) { item, injector ->
|
||||||
|
injector.text(R.id.text, item.getAddressLine(0) ?: "")
|
||||||
|
injector.clicked(R.id.item) {
|
||||||
|
Preferences.bulk {
|
||||||
|
customLocationLat = item.latitude.toString()
|
||||||
|
customLocationLon = item.longitude.toString()
|
||||||
|
customLocationAdd = item.getAddressLine(0) ?: ""
|
||||||
|
}
|
||||||
|
setResult(Activity.RESULT_OK)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.attachTo(binding.listView)
|
||||||
|
|
||||||
|
|
||||||
|
viewModel.addresses.observe(this, Observer {
|
||||||
|
adapter.updateData(listOf("Default") + it)
|
||||||
|
})
|
||||||
|
|
||||||
|
setupListener()
|
||||||
|
subscribeUi(binding, viewModel)
|
||||||
|
|
||||||
|
binding.location.requestFocus()
|
||||||
|
|
||||||
|
setContentView(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var searchJob: Job? = null
|
||||||
|
|
||||||
|
private fun subscribeUi(binding: ActivityCustomLocationBinding, viewModel: CustomLocationViewModel) {
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
|
||||||
|
viewModel.addresses.observe(this, Observer {
|
||||||
|
adapter.updateData(listOf("Default") + it)
|
||||||
|
binding.loader.visibility = View.INVISIBLE
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.locationInput.observe(this, Observer { location ->
|
||||||
|
binding.loader.visibility = View.VISIBLE
|
||||||
|
searchJob?.cancel()
|
||||||
|
searchJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
delay(200)
|
||||||
|
val list = if (location == null || location == "") {
|
||||||
|
viewModel.addresses.value!!
|
||||||
|
} else {
|
||||||
|
val coder = Geocoder(this@CustomLocationActivity)
|
||||||
|
try {
|
||||||
|
coder.getFromLocationName(location, 10) as ArrayList<Address>
|
||||||
|
} catch (ignored: Exception) {
|
||||||
|
emptyList<Address>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
viewModel.addresses.value = list
|
||||||
|
binding.loader.visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
binding.clearSearch.isVisible = location.isNotBlank()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListener() {
|
||||||
|
binding.actionBack.setOnClickListener {
|
||||||
|
onBackPressed()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.clearSearch.setOnClickListener {
|
||||||
|
viewModel.locationInput.value = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,109 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.chibatching.kotpref.blockingBulk
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.ActivityMediaInfoFormatBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.MediaInfoFormatViewModel
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.getCapWordString
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.openURI
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.toast
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
|
import java.lang.Exception
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class MediaInfoFormatActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private lateinit var adapter: SlimAdapter
|
||||||
|
private lateinit var viewModel: MediaInfoFormatViewModel
|
||||||
|
private lateinit var binding: ActivityMediaInfoFormatBinding
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(this).get(MediaInfoFormatViewModel::class.java)
|
||||||
|
binding = ActivityMediaInfoFormatBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
|
||||||
|
binding.listView.setHasFixedSize(true)
|
||||||
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
|
binding.listView.layoutManager = mLayoutManager
|
||||||
|
|
||||||
|
adapter = SlimAdapter.create()
|
||||||
|
adapter
|
||||||
|
.register<String>(R.layout.custom_date_example_item) { item, injector ->
|
||||||
|
injector
|
||||||
|
.text(R.id.custom_date_example_format, item)
|
||||||
|
.text(
|
||||||
|
R.id.custom_date_example_value, MediaPlayerHelper.getMediaInfo(item, EXAMPLE_TITLE, EXAMPLE_ARTIST, EXAMPLE_ALBUM))
|
||||||
|
}
|
||||||
|
.attachTo(binding.listView)
|
||||||
|
|
||||||
|
adapter.updateData(
|
||||||
|
listOf(
|
||||||
|
MediaPlayerHelper.MEDIA_INFO_TITLE, MediaPlayerHelper.MEDIA_INFO_ARTIST, MediaPlayerHelper.MEDIA_INFO_ALBUM
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
setupListener()
|
||||||
|
subscribeUi(binding, viewModel)
|
||||||
|
|
||||||
|
binding.mediaInfoFormatInput.requestFocus()
|
||||||
|
|
||||||
|
setContentView(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var formatJob: Job? = null
|
||||||
|
|
||||||
|
private fun subscribeUi(binding: ActivityMediaInfoFormatBinding, viewModel: MediaInfoFormatViewModel) {
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
|
||||||
|
viewModel.mediaInfoFormatInput.observe(this) { mediaInfoFormatInput ->
|
||||||
|
formatJob?.cancel()
|
||||||
|
formatJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
binding.loader.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(200)
|
||||||
|
val text = MediaPlayerHelper.getMediaInfo(mediaInfoFormatInput, EXAMPLE_TITLE, EXAMPLE_ARTIST, EXAMPLE_ALBUM)
|
||||||
|
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
binding.loader.visibility = View.INVISIBLE
|
||||||
|
binding.mediaInfoFormatInputValue.text = text
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListener() {
|
||||||
|
binding.actionBack.setOnClickListener {
|
||||||
|
onBackPressed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBackPressed() {
|
||||||
|
Preferences.blockingBulk {
|
||||||
|
mediaInfoFormat = viewModel.mediaInfoFormatInput.value ?: ""
|
||||||
|
}
|
||||||
|
super.onBackPressed()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val EXAMPLE_TITLE = "Thunderstruck"
|
||||||
|
const val EXAMPLE_ARTIST = "AC/DC"
|
||||||
|
const val EXAMPLE_ALBUM = "The Razors Edge"
|
||||||
|
}
|
||||||
|
}
|
@ -1,50 +1,40 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.activities
|
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import android.content.Intent
|
|
||||||
import android.content.pm.ApplicationInfo
|
|
||||||
import android.content.pm.ResolveInfo
|
import android.content.pm.ResolveInfo
|
||||||
import android.util.Log
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.databinding.DataBindingUtil
|
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.tommasoberlose.anotherwidget.databinding.ActivityChooseApplicationBinding
|
|
||||||
import com.tommasoberlose.anotherwidget.databinding.ActivityMusicPlayersFilterBinding
|
import com.tommasoberlose.anotherwidget.databinding.ActivityMusicPlayersFilterBinding
|
||||||
import com.tommasoberlose.anotherwidget.global.Constants
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.ChooseApplicationViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.MusicPlayersFilterViewModel
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MusicPlayersFilterViewModel
|
|
||||||
import kotlinx.android.synthetic.main.activity_music_players_filter.*
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import net.idik.lib.slimadapter.SlimAdapter
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
import kotlin.Comparator as Comparator1
|
|
||||||
|
|
||||||
|
|
||||||
class MusicPlayersFilterActivity : AppCompatActivity() {
|
class MusicPlayersFilterActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private lateinit var adapter: SlimAdapter
|
private lateinit var adapter: SlimAdapter
|
||||||
private lateinit var viewModel: MusicPlayersFilterViewModel
|
private lateinit var viewModel: MusicPlayersFilterViewModel
|
||||||
|
private lateinit var binding: ActivityMusicPlayersFilterBinding
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
viewModel = ViewModelProvider(this).get(MusicPlayersFilterViewModel::class.java)
|
viewModel = ViewModelProvider(this).get(MusicPlayersFilterViewModel::class.java)
|
||||||
val binding = DataBindingUtil.setContentView<ActivityMusicPlayersFilterBinding>(this, R.layout.activity_music_players_filter)
|
binding = ActivityMusicPlayersFilterBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
list_view.setHasFixedSize(true)
|
binding.listView.setHasFixedSize(true)
|
||||||
val mLayoutManager = LinearLayoutManager(this)
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
list_view.layoutManager = mLayoutManager
|
binding.listView.layoutManager = mLayoutManager
|
||||||
|
|
||||||
adapter = SlimAdapter.create()
|
adapter = SlimAdapter.create()
|
||||||
adapter
|
adapter
|
||||||
@ -69,12 +59,14 @@ class MusicPlayersFilterActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
.checked(R.id.checkBox, MediaPlayerHelper.isMusicPlayerAccepted(item.activityInfo.packageName))
|
.checked(R.id.checkBox, MediaPlayerHelper.isMusicPlayerAccepted(item.activityInfo.packageName))
|
||||||
}
|
}
|
||||||
.attachTo(list_view)
|
.attachTo(binding.listView)
|
||||||
|
|
||||||
setupListener()
|
setupListener()
|
||||||
subscribeUi(binding, viewModel)
|
subscribeUi(binding, viewModel)
|
||||||
|
|
||||||
search.requestFocus()
|
binding.search.requestFocus()
|
||||||
|
|
||||||
|
setContentView(binding.root)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var filterJob: Job? = null
|
private var filterJob: Job? = null
|
||||||
@ -83,24 +75,24 @@ class MusicPlayersFilterActivity : AppCompatActivity() {
|
|||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
binding.lifecycleOwner = this
|
binding.lifecycleOwner = this
|
||||||
|
|
||||||
viewModel.appList.observe(this, Observer {
|
viewModel.appList.observe(this) {
|
||||||
updateList(list = it)
|
updateList(list = it)
|
||||||
loader.visibility = View.INVISIBLE
|
binding.loader.visibility = View.INVISIBLE
|
||||||
})
|
}
|
||||||
|
|
||||||
viewModel.searchInput.observe(this, Observer { search ->
|
viewModel.searchInput.observe(this) { search ->
|
||||||
updateList(search = search)
|
updateList(search = search)
|
||||||
clear_search.isVisible = search.isNotBlank()
|
binding.clearSearch.isVisible = search.isNotBlank()
|
||||||
})
|
}
|
||||||
|
|
||||||
viewModel.musicPlayersFilter.observe(this, {
|
viewModel.musicPlayersFilter.observe(this) {
|
||||||
updateList()
|
updateList()
|
||||||
clear_selection.isVisible = Preferences.musicPlayersFilter != ""
|
binding.clearSelection.isVisible = Preferences.musicPlayersFilter != ""
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateList(list: List<ResolveInfo>? = viewModel.appList.value, search: String? = viewModel.searchInput.value) {
|
private fun updateList(list: List<ResolveInfo>? = viewModel.appList.value, search: String? = viewModel.searchInput.value) {
|
||||||
loader.visibility = View.VISIBLE
|
binding.loader.visibility = View.VISIBLE
|
||||||
filterJob?.cancel()
|
filterJob?.cancel()
|
||||||
filterJob = lifecycleScope.launch(Dispatchers.IO) {
|
filterJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||||
if (list != null && list.isNotEmpty()) {
|
if (list != null && list.isNotEmpty()) {
|
||||||
@ -126,22 +118,22 @@ class MusicPlayersFilterActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
adapter.updateData(filteredList)
|
adapter.updateData(filteredList)
|
||||||
loader.visibility = View.INVISIBLE
|
binding.loader.visibility = View.INVISIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupListener() {
|
private fun setupListener() {
|
||||||
action_back.setOnClickListener {
|
binding.actionBack.setOnClickListener {
|
||||||
onBackPressed()
|
onBackPressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_search.setOnClickListener {
|
binding.clearSearch.setOnClickListener {
|
||||||
viewModel.searchInput.value = ""
|
viewModel.searchInput.value = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_selection.setOnClickListener {
|
binding.clearSelection.setOnClickListener {
|
||||||
Preferences.musicPlayersFilter = ""
|
Preferences.musicPlayersFilter = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,155 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.app.Activity
|
||||||
|
import android.location.Address
|
||||||
|
import android.location.Geocoder
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.text.method.LinkMovementMethod
|
||||||
|
import android.view.View
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.chibatching.kotpref.bulk
|
||||||
|
import com.karumi.dexter.Dexter
|
||||||
|
import com.karumi.dexter.MultiplePermissionsReport
|
||||||
|
import com.karumi.dexter.PermissionToken
|
||||||
|
import com.karumi.dexter.listener.PermissionRequest
|
||||||
|
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.ActivityTimeZoneSelectorBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.network.TimeZonesApi
|
||||||
|
import com.tommasoberlose.anotherwidget.network.WeatherNetworkApi
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.TimeZoneSelectorViewModel
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.toast
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
|
|
||||||
|
class TimeZoneSelectorActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private lateinit var adapter: SlimAdapter
|
||||||
|
private lateinit var viewModel: TimeZoneSelectorViewModel
|
||||||
|
private lateinit var binding: ActivityTimeZoneSelectorBinding
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(this).get(TimeZoneSelectorViewModel::class.java)
|
||||||
|
binding = ActivityTimeZoneSelectorBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
binding.geonameCredits.movementMethod = LinkMovementMethod.getInstance()
|
||||||
|
|
||||||
|
binding.listView.setHasFixedSize(true)
|
||||||
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
|
binding.listView.layoutManager = mLayoutManager
|
||||||
|
|
||||||
|
adapter = SlimAdapter.create()
|
||||||
|
adapter
|
||||||
|
.register<String>(R.layout.custom_location_item) { _, injector ->
|
||||||
|
injector
|
||||||
|
.text(R.id.text, getString(R.string.no_time_zone_label))
|
||||||
|
.clicked(R.id.text) {
|
||||||
|
Preferences.bulk {
|
||||||
|
altTimezoneId = ""
|
||||||
|
altTimezoneLabel = ""
|
||||||
|
}
|
||||||
|
MainWidget.updateWidget(this@TimeZoneSelectorActivity)
|
||||||
|
setResult(Activity.RESULT_OK)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.register<Address>(R.layout.custom_location_item) { item, injector ->
|
||||||
|
injector.text(R.id.text, item.getAddressLine(0))
|
||||||
|
injector.clicked(R.id.item) {
|
||||||
|
binding.loader.visibility = View.VISIBLE
|
||||||
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
val networkApi = TimeZonesApi(this@TimeZoneSelectorActivity)
|
||||||
|
val id = networkApi.getTimeZone(item.latitude.toString(), item.longitude.toString())
|
||||||
|
|
||||||
|
if (id != null) {
|
||||||
|
Preferences.bulk {
|
||||||
|
altTimezoneId = id
|
||||||
|
altTimezoneLabel = try {
|
||||||
|
item.locality
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
item.getAddressLine(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MainWidget.updateWidget(this@TimeZoneSelectorActivity)
|
||||||
|
setResult(Activity.RESULT_OK)
|
||||||
|
finish()
|
||||||
|
} else {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
binding.loader.visibility = View.INVISIBLE
|
||||||
|
toast(getString(R.string.time_zone_search_error_message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.attachTo(binding.listView)
|
||||||
|
|
||||||
|
|
||||||
|
viewModel.addresses.observe(this, Observer {
|
||||||
|
adapter.updateData(listOf("Default") + it)
|
||||||
|
})
|
||||||
|
|
||||||
|
setupListener()
|
||||||
|
subscribeUi(binding, viewModel)
|
||||||
|
|
||||||
|
binding.location.requestFocus()
|
||||||
|
|
||||||
|
setContentView(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var searchJob: Job? = null
|
||||||
|
|
||||||
|
private fun subscribeUi(binding: ActivityTimeZoneSelectorBinding, viewModel: TimeZoneSelectorViewModel) {
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
|
||||||
|
viewModel.addresses.observe(this, Observer {
|
||||||
|
adapter.updateData(listOf("Default") + it)
|
||||||
|
binding.loader.visibility = View.INVISIBLE
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.locationInput.observe(this, Observer { location ->
|
||||||
|
binding.loader.visibility = View.VISIBLE
|
||||||
|
searchJob?.cancel()
|
||||||
|
searchJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
delay(200)
|
||||||
|
val list = if (location == null || location == "") {
|
||||||
|
viewModel.addresses.value!!
|
||||||
|
} else {
|
||||||
|
val coder = Geocoder(this@TimeZoneSelectorActivity)
|
||||||
|
try {
|
||||||
|
coder.getFromLocationName(location, 10) as ArrayList<Address>
|
||||||
|
} catch (ignored: Exception) {
|
||||||
|
emptyList<Address>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
viewModel.addresses.value = list
|
||||||
|
binding.loader.visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
binding.clearSearch.isVisible = location.isNotBlank()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListener() {
|
||||||
|
binding.actionBack.setOnClickListener {
|
||||||
|
onBackPressed()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.clearSearch.setOnClickListener {
|
||||||
|
viewModel.locationInput.value = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,45 +1,25 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.activities
|
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
|
||||||
import android.content.pm.ResolveInfo
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.widget.addTextChangedListener
|
|
||||||
import androidx.lifecycle.Observer
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
|
||||||
import com.tommasoberlose.anotherwidget.components.BottomSheetWeatherProviderSettings
|
import com.tommasoberlose.anotherwidget.components.BottomSheetWeatherProviderSettings
|
||||||
import com.tommasoberlose.anotherwidget.databinding.ActivityChooseApplicationBinding
|
|
||||||
import com.tommasoberlose.anotherwidget.databinding.ActivityWeatherProviderBinding
|
import com.tommasoberlose.anotherwidget.databinding.ActivityWeatherProviderBinding
|
||||||
import com.tommasoberlose.anotherwidget.global.Constants
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
||||||
import com.tommasoberlose.anotherwidget.network.WeatherNetworkApi
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.ChooseApplicationViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.WeatherProviderViewModel
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.WeatherProviderViewModel
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.collapse
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.expand
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.openURI
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.reveal
|
|
||||||
import kotlinx.android.synthetic.main.activity_weather_provider.*
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import net.idik.lib.slimadapter.SlimAdapter
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
import org.greenrobot.eventbus.Subscribe
|
import org.greenrobot.eventbus.Subscribe
|
||||||
@ -49,16 +29,17 @@ class WeatherProviderActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private lateinit var adapter: SlimAdapter
|
private lateinit var adapter: SlimAdapter
|
||||||
private lateinit var viewModel: WeatherProviderViewModel
|
private lateinit var viewModel: WeatherProviderViewModel
|
||||||
|
private lateinit var binding: ActivityWeatherProviderBinding
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_weather_provider)
|
|
||||||
|
|
||||||
viewModel = ViewModelProvider(this).get(WeatherProviderViewModel::class.java)
|
viewModel = ViewModelProvider(this).get(WeatherProviderViewModel::class.java)
|
||||||
|
binding = ActivityWeatherProviderBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
list_view.setHasFixedSize(true)
|
binding.listView.setHasFixedSize(true)
|
||||||
val mLayoutManager = LinearLayoutManager(this)
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
list_view.layoutManager = mLayoutManager
|
binding.listView.layoutManager = mLayoutManager
|
||||||
|
|
||||||
adapter = SlimAdapter.create()
|
adapter = SlimAdapter.create()
|
||||||
adapter
|
adapter
|
||||||
@ -66,36 +47,32 @@ class WeatherProviderActivity : AppCompatActivity() {
|
|||||||
injector
|
injector
|
||||||
.text(R.id.text, WeatherHelper.getProviderName(this, provider))
|
.text(R.id.text, WeatherHelper.getProviderName(this, provider))
|
||||||
.clicked(R.id.item) {
|
.clicked(R.id.item) {
|
||||||
if (Preferences.weatherProvider != provider.value) {
|
if (Preferences.weatherProvider != provider.rawValue) {
|
||||||
Preferences.weatherProviderError = "-"
|
Preferences.weatherProviderError = "-"
|
||||||
Preferences.weatherProviderLocationError = ""
|
Preferences.weatherProviderLocationError = ""
|
||||||
}
|
}
|
||||||
val oldValue = Preferences.weatherProvider
|
val oldValue = Preferences.weatherProvider
|
||||||
Preferences.weatherProvider = provider.value
|
Preferences.weatherProvider = provider.rawValue
|
||||||
updateListItem(oldValue)
|
updateListItem(oldValue)
|
||||||
updateListItem()
|
updateListItem()
|
||||||
loader.isVisible = true
|
binding.loader.isVisible = true
|
||||||
|
|
||||||
lifecycleScope.launch {
|
WeatherHelper.updateWeather(this@WeatherProviderActivity, true)
|
||||||
WeatherHelper.updateWeather(this@WeatherProviderActivity)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.clicked(R.id.radioButton) {
|
.clicked(R.id.radioButton) {
|
||||||
if (Preferences.weatherProvider != provider.value) {
|
if (Preferences.weatherProvider != provider.rawValue) {
|
||||||
Preferences.weatherProviderError = "-"
|
Preferences.weatherProviderError = "-"
|
||||||
Preferences.weatherProviderLocationError = ""
|
Preferences.weatherProviderLocationError = ""
|
||||||
}
|
}
|
||||||
val oldValue = Preferences.weatherProvider
|
val oldValue = Preferences.weatherProvider
|
||||||
Preferences.weatherProvider = provider.value
|
Preferences.weatherProvider = provider.rawValue
|
||||||
updateListItem(oldValue)
|
updateListItem(oldValue)
|
||||||
updateListItem()
|
updateListItem()
|
||||||
loader.isVisible = true
|
binding.loader.isVisible = true
|
||||||
|
|
||||||
lifecycleScope.launch {
|
WeatherHelper.updateWeather(this@WeatherProviderActivity, true)
|
||||||
WeatherHelper.updateWeather(this@WeatherProviderActivity)
|
|
||||||
}
|
}
|
||||||
}
|
.checked(R.id.radioButton, provider.rawValue == Preferences.weatherProvider)
|
||||||
.checked(R.id.radioButton, provider.value == Preferences.weatherProvider)
|
|
||||||
.with<TextView>(R.id.text2) {
|
.with<TextView>(R.id.text2) {
|
||||||
if (WeatherHelper.isKeyRequired(provider)) {
|
if (WeatherHelper.isKeyRequired(provider)) {
|
||||||
it.text = getString(R.string.api_key_required_message)
|
it.text = getString(R.string.api_key_required_message)
|
||||||
@ -111,57 +88,55 @@ class WeatherProviderActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
.clicked(R.id.action_configure) {
|
.clicked(R.id.action_configure) {
|
||||||
BottomSheetWeatherProviderSettings(this) {
|
BottomSheetWeatherProviderSettings(this) {
|
||||||
lifecycleScope.launch {
|
binding.loader.isVisible = true
|
||||||
loader.isVisible = true
|
WeatherHelper.updateWeather(this@WeatherProviderActivity, true)
|
||||||
WeatherHelper.updateWeather(this@WeatherProviderActivity)
|
|
||||||
}
|
|
||||||
}.show()
|
}.show()
|
||||||
}
|
}
|
||||||
.visibility(R.id.action_configure, if (/*WeatherHelper.isKeyRequired(provider) && */provider.value == Preferences.weatherProvider) View.VISIBLE else View.GONE)
|
.visibility(R.id.action_configure, if (/*WeatherHelper.isKeyRequired(provider) && */provider.rawValue == Preferences.weatherProvider) View.VISIBLE else View.GONE)
|
||||||
.with<TextView>(R.id.provider_error) {
|
.with<TextView>(R.id.provider_error) {
|
||||||
if (Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-") {
|
if (Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-") {
|
||||||
it.text = Preferences.weatherProviderError
|
it.text = Preferences.weatherProviderError
|
||||||
it.isVisible = provider.value == Preferences.weatherProvider
|
it.isVisible = provider.rawValue == Preferences.weatherProvider
|
||||||
} else if (Preferences.weatherProviderLocationError != "") {
|
} else if (Preferences.weatherProviderLocationError != "") {
|
||||||
it.text = Preferences.weatherProviderLocationError
|
it.text = Preferences.weatherProviderLocationError
|
||||||
it.isVisible = provider.value == Preferences.weatherProvider
|
it.isVisible = provider.rawValue == Preferences.weatherProvider
|
||||||
} else {
|
} else {
|
||||||
it.isVisible = false
|
it.isVisible = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.image(R.id.action_configure, ContextCompat.getDrawable(this, if (WeatherHelper.isKeyRequired(provider)) R.drawable.round_settings_24 else R.drawable.outline_info_24))
|
.image(R.id.action_configure, ContextCompat.getDrawable(this, if (WeatherHelper.isKeyRequired(provider)) R.drawable.round_settings_24 else R.drawable.outline_info_24))
|
||||||
}.attachTo(list_view)
|
}.attachTo(binding.listView)
|
||||||
|
|
||||||
adapter.updateData(
|
adapter.updateData(
|
||||||
Constants.WeatherProvider.values().asList()
|
Constants.WeatherProvider.values().asList()
|
||||||
.filter { it != Constants.WeatherProvider.HERE }
|
|
||||||
.filter { it != Constants.WeatherProvider.ACCUWEATHER }
|
|
||||||
)
|
)
|
||||||
|
|
||||||
setupListener()
|
setupListener()
|
||||||
subscribeUi(viewModel)
|
subscribeUi(viewModel)
|
||||||
|
|
||||||
|
setContentView(binding.root)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun subscribeUi(viewModel: WeatherProviderViewModel) {
|
private fun subscribeUi(viewModel: WeatherProviderViewModel) {
|
||||||
viewModel.weatherProviderError.observe(this) {
|
viewModel.weatherProviderError.observe(this) {
|
||||||
updateListItem()
|
binding.listView.postDelayed({ updateListItem() }, 300)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.weatherProviderLocationError.observe(this) {
|
viewModel.weatherProviderLocationError.observe(this) {
|
||||||
updateListItem()
|
binding.listView.postDelayed({ updateListItem() }, 300)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateListItem(provider: Int = Preferences.weatherProvider) {
|
private fun updateListItem(provider: Int = Preferences.weatherProvider) {
|
||||||
(adapter.data).forEachIndexed { index, item ->
|
(adapter.data).forEachIndexed { index, item ->
|
||||||
if (item is Constants.WeatherProvider && item.value == provider) {
|
if (item is Constants.WeatherProvider && item.rawValue == provider) {
|
||||||
adapter.notifyItemChanged(index)
|
adapter.notifyItemChanged(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupListener() {
|
private fun setupListener() {
|
||||||
action_back.setOnClickListener {
|
binding.actionBack.setOnClickListener {
|
||||||
onBackPressed()
|
onBackPressed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,10 +157,10 @@ class WeatherProviderActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun onMessageEvent(ignore: MainFragment.UpdateUiMessageEvent?) {
|
fun onMessageEvent(@Suppress("UNUSED_PARAMETER") ignore: MainFragment.UpdateUiMessageEvent?) {
|
||||||
loader.isVisible = Preferences.weatherProviderError == "-"
|
binding.loader.isVisible = Preferences.weatherProviderError == "-"
|
||||||
if (Preferences.weatherProviderError == "" && Preferences.weatherProviderLocationError == "") {
|
if (Preferences.weatherProviderError == "" && Preferences.weatherProviderLocationError == "") {
|
||||||
Snackbar.make(list_view, getString(R.string.settings_weather_provider_api_key_subtitle_all_set), Snackbar.LENGTH_LONG).show()
|
Snackbar.make(binding.listView, getString(R.string.settings_weather_provider_api_key_subtitle_all_set), Snackbar.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,7 +3,7 @@ package com.tommasoberlose.anotherwidget.ui.adapters
|
|||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||||
import com.tommasoberlose.anotherwidget.ui.fragments.*
|
import com.tommasoberlose.anotherwidget.ui.fragments.tabs.*
|
||||||
|
|
||||||
class ViewPagerAdapter(fragmentActivity: FragmentActivity) :
|
class ViewPagerAdapter(fragmentActivity: FragmentActivity) :
|
||||||
FragmentStateAdapter(fragmentActivity) {
|
FragmentStateAdapter(fragmentActivity) {
|
||||||
@ -12,11 +12,11 @@ class ViewPagerAdapter(fragmentActivity: FragmentActivity) :
|
|||||||
|
|
||||||
override fun createFragment(position: Int): Fragment {
|
override fun createFragment(position: Int): Fragment {
|
||||||
return when (position) {
|
return when (position) {
|
||||||
1 -> CalendarTabFragment.newInstance()
|
1 -> CalendarFragment.newInstance()
|
||||||
2 -> WeatherTabFragment.newInstance()
|
2 -> WeatherFragment.newInstance()
|
||||||
3 -> ClockTabFragment.newInstance()
|
3 -> ClockFragment.newInstance()
|
||||||
4 -> GlanceTabFragment.newInstance()
|
4 -> GlanceTabFragment.newInstance()
|
||||||
else -> GeneralTabFragment.newInstance()
|
else -> LayoutFragment.newInstance()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,456 +0,0 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.fragments
|
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.provider.CalendarContract
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.databinding.DataBindingUtil
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.lifecycle.Observer
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import com.chibatching.kotpref.bulk
|
|
||||||
import com.karumi.dexter.Dexter
|
|
||||||
import com.karumi.dexter.MultiplePermissionsReport
|
|
||||||
import com.karumi.dexter.PermissionToken
|
|
||||||
import com.karumi.dexter.listener.PermissionRequest
|
|
||||||
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
|
||||||
import com.tommasoberlose.anotherwidget.R
|
|
||||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
|
||||||
import com.tommasoberlose.anotherwidget.models.CalendarSelector
|
|
||||||
import com.tommasoberlose.anotherwidget.databinding.FragmentCalendarSettingsBinding
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Constants
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
|
||||||
import com.tommasoberlose.anotherwidget.global.RequestCode
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.IntentHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.isDefaultSet
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.toast
|
|
||||||
import kotlinx.android.synthetic.main.fragment_calendar_settings.*
|
|
||||||
import kotlinx.android.synthetic.main.fragment_calendar_settings.scrollView
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlin.Comparator
|
|
||||||
|
|
||||||
class CalendarTabFragment : Fragment() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun newInstance() = CalendarTabFragment()
|
|
||||||
}
|
|
||||||
|
|
||||||
private lateinit var viewModel: MainViewModel
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View {
|
|
||||||
|
|
||||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
|
||||||
val binding = DataBindingUtil.inflate<FragmentCalendarSettingsBinding>(inflater, R.layout.fragment_calendar_settings, container, false)
|
|
||||||
|
|
||||||
subscribeUi(binding, viewModel)
|
|
||||||
|
|
||||||
binding.lifecycleOwner = this
|
|
||||||
binding.viewModel = viewModel
|
|
||||||
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
|
||||||
super.onActivityCreated(savedInstanceState)
|
|
||||||
|
|
||||||
show_all_day_toggle.isChecked = Preferences.calendarAllDay
|
|
||||||
show_only_busy_events_toggle.isChecked = Preferences.showOnlyBusyEvents
|
|
||||||
show_diff_time_toggle.isChecked = Preferences.showDiffTime
|
|
||||||
show_multiple_events_toggle.isChecked = Preferences.showNextEvent
|
|
||||||
|
|
||||||
setupListener()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun subscribeUi(
|
|
||||||
binding: FragmentCalendarSettingsBinding,
|
|
||||||
viewModel: MainViewModel
|
|
||||||
) {
|
|
||||||
binding.isCalendarEnabled = Preferences.showEvents
|
|
||||||
binding.isDiffEnabled = Preferences.showDiffTime || !Preferences.showEvents
|
|
||||||
|
|
||||||
viewModel.showEvents.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
binding.isCalendarEnabled = it
|
|
||||||
|
|
||||||
if (it) {
|
|
||||||
CalendarHelper.setEventUpdatesAndroidN(requireContext())
|
|
||||||
} else {
|
|
||||||
CalendarHelper.removeEventUpdatesAndroidN(requireContext())
|
|
||||||
}
|
|
||||||
binding.isDiffEnabled = Preferences.showDiffTime || !it
|
|
||||||
}
|
|
||||||
checkReadEventsPermission()
|
|
||||||
updateCalendar()
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.calendarAllDay.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
all_day_label?.text =
|
|
||||||
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.secondRowInformation.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
second_row_info_label?.text = getString(SettingsStringHelper.getSecondRowInfoString(it))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.showDiffTime.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
show_diff_time_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
|
||||||
binding.isDiffEnabled = it || !Preferences.showEvents
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.widgetUpdateFrequency.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
widget_update_frequency_label?.text = when (it) {
|
|
||||||
Constants.WidgetUpdateFrequency.HIGH.value -> getString(R.string.settings_widget_update_frequency_high)
|
|
||||||
Constants.WidgetUpdateFrequency.DEFAULT.value -> getString(R.string.settings_widget_update_frequency_default)
|
|
||||||
Constants.WidgetUpdateFrequency.LOW.value -> getString(R.string.settings_widget_update_frequency_low)
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.showUntil.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
show_until_label?.text = getString(SettingsStringHelper.getShowUntilString(it))
|
|
||||||
}
|
|
||||||
updateCalendar()
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.showNextEvent.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
show_multiple_events_label?.text =
|
|
||||||
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.calendarAppName.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
calendar_app_label?.text = when {
|
|
||||||
Preferences.calendarAppName != "" -> Preferences.calendarAppName
|
|
||||||
else -> {
|
|
||||||
if (IntentHelper.getCalendarIntent(requireContext()).isDefaultSet(requireContext())) {
|
|
||||||
getString(
|
|
||||||
R.string.default_calendar_app
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
getString(R.string.nothing)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.openEventDetails.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
open_event_details_label?.text = if (it) getString(R.string.default_event_app) else getString(R.string.default_calendar_app)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupListener() {
|
|
||||||
|
|
||||||
action_show_events.setOnClickListener {
|
|
||||||
Preferences.showEvents = !Preferences.showEvents
|
|
||||||
if (Preferences.showEvents) {
|
|
||||||
requirePermission()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
show_events_switch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
|
||||||
Preferences.showEvents = enabled
|
|
||||||
if (Preferences.showEvents) {
|
|
||||||
requirePermission()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_filter_calendar.setOnClickListener {
|
|
||||||
val calendarSelectorList: List<CalendarSelector> = CalendarHelper.getCalendarList(requireContext()).map {
|
|
||||||
CalendarSelector(
|
|
||||||
it.id,
|
|
||||||
it.displayName,
|
|
||||||
it.accountName
|
|
||||||
)
|
|
||||||
}.sortedWith(Comparator { cal1, cal2 ->
|
|
||||||
when {
|
|
||||||
cal1.accountName != cal2.accountName -> {
|
|
||||||
cal1.accountName.compareTo(cal2.accountName)
|
|
||||||
}
|
|
||||||
cal1.accountName == cal1.name -> {
|
|
||||||
-1
|
|
||||||
}
|
|
||||||
cal2.accountName == cal2.name -> {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
cal1.name.compareTo(cal2.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (calendarSelectorList.isNotEmpty()) {
|
|
||||||
val filteredCalendarIds = CalendarHelper.getFilteredCalendarIdList()
|
|
||||||
val visibleCalendarIds = calendarSelectorList.map { it.id }.filter { id: Long -> !filteredCalendarIds.contains(id) }
|
|
||||||
|
|
||||||
val dialog = BottomSheetMenu<Long>(requireContext(), header = getString(R.string.settings_filter_calendar_subtitle), isMultiSelection = true)
|
|
||||||
.setSelectedValues(visibleCalendarIds)
|
|
||||||
|
|
||||||
calendarSelectorList.indices.forEach { index ->
|
|
||||||
if (index == 0 || calendarSelectorList[index].accountName != calendarSelectorList[index - 1].accountName) {
|
|
||||||
dialog.addItem(calendarSelectorList[index].accountName)
|
|
||||||
}
|
|
||||||
|
|
||||||
dialog.addItem(
|
|
||||||
if (calendarSelectorList[index].name == calendarSelectorList[index].accountName) getString(R.string.main_calendar) else calendarSelectorList[index].name,
|
|
||||||
calendarSelectorList[index].id
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
dialog.addOnMultipleSelectItemListener { values ->
|
|
||||||
CalendarHelper.filterCalendar(calendarSelectorList.map { it.id }.filter { !values.contains(it) })
|
|
||||||
updateCalendar()
|
|
||||||
}.show()
|
|
||||||
} else {
|
|
||||||
activity?.toast(getString(R.string.calendar_settings_list_error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_all_day.setOnClickListener {
|
|
||||||
if (Preferences.showEvents) {
|
|
||||||
show_all_day_toggle.isChecked = !show_all_day_toggle.isChecked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
show_all_day_toggle.setOnCheckedChangeListener { _, isChecked ->
|
|
||||||
if (Preferences.showEvents) {
|
|
||||||
Preferences.calendarAllDay = isChecked
|
|
||||||
updateCalendar()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_change_attendee_filter.setOnClickListener {
|
|
||||||
if (Preferences.showEvents) {
|
|
||||||
val selectedValues = emptyList<Int>().toMutableList()
|
|
||||||
if (Preferences.showDeclinedEvents) {
|
|
||||||
selectedValues.add(CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED)
|
|
||||||
}
|
|
||||||
if (Preferences.showInvitedEvents) {
|
|
||||||
selectedValues.add(CalendarContract.Attendees.ATTENDEE_STATUS_INVITED)
|
|
||||||
}
|
|
||||||
if (Preferences.showAcceptedEvents) {
|
|
||||||
selectedValues.add(CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED)
|
|
||||||
}
|
|
||||||
|
|
||||||
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_attendee_status_title), isMultiSelection = true)
|
|
||||||
.setSelectedValues(selectedValues)
|
|
||||||
|
|
||||||
dialog.addItem(
|
|
||||||
getString(R.string.attendee_status_invited),
|
|
||||||
CalendarContract.Attendees.ATTENDEE_STATUS_INVITED
|
|
||||||
)
|
|
||||||
dialog.addItem(
|
|
||||||
getString(R.string.attendee_status_accepted),
|
|
||||||
CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED
|
|
||||||
)
|
|
||||||
dialog.addItem(
|
|
||||||
getString(R.string.attendee_status_declined),
|
|
||||||
CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED
|
|
||||||
)
|
|
||||||
|
|
||||||
dialog.addOnMultipleSelectItemListener { values ->
|
|
||||||
Preferences.showDeclinedEvents = values.contains(CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED)
|
|
||||||
Preferences.showAcceptedEvents = values.contains(CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED)
|
|
||||||
Preferences.showInvitedEvents = values.contains(CalendarContract.Attendees.ATTENDEE_STATUS_INVITED)
|
|
||||||
updateCalendar()
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_only_busy_events.setOnClickListener {
|
|
||||||
if (Preferences.showEvents) {
|
|
||||||
show_only_busy_events_toggle.isChecked = !show_only_busy_events_toggle.isChecked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
show_only_busy_events_toggle.setOnCheckedChangeListener { _, isChecked ->
|
|
||||||
if (Preferences.showEvents) {
|
|
||||||
Preferences.showOnlyBusyEvents = isChecked
|
|
||||||
updateCalendar()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_multiple_events.setOnClickListener {
|
|
||||||
if (Preferences.showEvents) {
|
|
||||||
show_multiple_events_toggle.isChecked = !show_multiple_events_toggle.isChecked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
show_multiple_events_toggle.setOnCheckedChangeListener { _, isChecked ->
|
|
||||||
if (Preferences.showEvents) {
|
|
||||||
Preferences.showNextEvent = isChecked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_diff_time.setOnClickListener {
|
|
||||||
if (Preferences.showEvents) {
|
|
||||||
show_diff_time_toggle.isChecked = !show_diff_time_toggle.isChecked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
show_diff_time_toggle.setOnCheckedChangeListener { _, isChecked ->
|
|
||||||
if (Preferences.showEvents) {
|
|
||||||
Preferences.showDiffTime = isChecked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_widget_update_frequency.setOnClickListener {
|
|
||||||
if (Preferences.showEvents && Preferences.showDiffTime) {
|
|
||||||
BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_widget_update_frequency_title), message = getString(R.string.settings_widget_update_frequency_subtitle)).setSelectedValue(Preferences.widgetUpdateFrequency)
|
|
||||||
.addItem(getString(R.string.settings_widget_update_frequency_high), Constants.WidgetUpdateFrequency.HIGH.value)
|
|
||||||
.addItem(getString(R.string.settings_widget_update_frequency_default), Constants.WidgetUpdateFrequency.DEFAULT.value)
|
|
||||||
.addItem(getString(R.string.settings_widget_update_frequency_low), Constants.WidgetUpdateFrequency.LOW.value)
|
|
||||||
.addOnSelectItemListener { value ->
|
|
||||||
Preferences.widgetUpdateFrequency = value
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_second_row_info.setOnClickListener {
|
|
||||||
if (Preferences.showEvents) {
|
|
||||||
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_second_row_info_title)).setSelectedValue(Preferences.secondRowInformation)
|
|
||||||
(0 .. 1).forEach {
|
|
||||||
dialog.addItem(getString(SettingsStringHelper.getSecondRowInfoString(it)), it)
|
|
||||||
}
|
|
||||||
dialog.addOnSelectItemListener { value ->
|
|
||||||
Preferences.secondRowInformation = value
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_until.setOnClickListener {
|
|
||||||
if (Preferences.showEvents) {
|
|
||||||
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_show_until_title)).setSelectedValue(Preferences.showUntil)
|
|
||||||
intArrayOf(6,7,0,1,2,3, 4, 5).forEach {
|
|
||||||
dialog.addItem(getString(SettingsStringHelper.getShowUntilString(it)), it)
|
|
||||||
}
|
|
||||||
dialog.addOnSelectItemListener { value ->
|
|
||||||
Preferences.showUntil = value
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_open_event_details.setOnClickListener {
|
|
||||||
if (Preferences.showEvents) {
|
|
||||||
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_event_app_title)).setSelectedValue(Preferences.openEventDetails)
|
|
||||||
.addItem(getString(R.string.default_event_app), true)
|
|
||||||
.addItem(getString(R.string.default_calendar_app), false)
|
|
||||||
.addOnSelectItemListener { value ->
|
|
||||||
Preferences.openEventDetails = value
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_calendar_app.setOnClickListener {
|
|
||||||
startActivityForResult(Intent(requireContext(), ChooseApplicationActivity::class.java), RequestCode.CALENDAR_APP_REQUEST_CODE.code)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkReadEventsPermission(showEvents: Boolean = Preferences.showEvents) {
|
|
||||||
if (activity?.checkGrantedPermission(Manifest.permission.READ_CALENDAR) == true) {
|
|
||||||
show_events_label?.text = if (showEvents) getString(R.string.show_events_visible) else getString(R.string.show_events_not_visible)
|
|
||||||
read_calendar_permission_alert?.isVisible = false
|
|
||||||
} else {
|
|
||||||
show_events_label?.text = if (showEvents) getString(R.string.description_permission_calendar) else getString(R.string.show_events_not_visible)
|
|
||||||
read_calendar_permission_alert?.isVisible = showEvents
|
|
||||||
read_calendar_permission_alert?.setOnClickListener {
|
|
||||||
requirePermission()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateCalendar() {
|
|
||||||
if (activity?.checkGrantedPermission(Manifest.permission.READ_CALENDAR) == true) {
|
|
||||||
CalendarHelper.updateEventList(requireContext())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun requirePermission() {
|
|
||||||
Dexter.withContext(requireContext())
|
|
||||||
.withPermissions(
|
|
||||||
Manifest.permission.READ_CALENDAR
|
|
||||||
).withListener(object: MultiplePermissionsListener {
|
|
||||||
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
|
||||||
report?.let {
|
|
||||||
if (report.areAllPermissionsGranted()){
|
|
||||||
checkReadEventsPermission()
|
|
||||||
} else {
|
|
||||||
Preferences.showEvents = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
override fun onPermissionRationaleShouldBeShown(
|
|
||||||
permissions: MutableList<PermissionRequest>?,
|
|
||||||
token: PermissionToken?
|
|
||||||
) {
|
|
||||||
// Remember to invoke this method when the custom rationale is closed
|
|
||||||
// or just by default if you don't want to use any custom rationale.
|
|
||||||
token?.continuePermissionRequest()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.check()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
|
||||||
when (requestCode) {
|
|
||||||
RequestCode.CALENDAR_APP_REQUEST_CODE.code -> {
|
|
||||||
Preferences.bulk {
|
|
||||||
calendarAppName = data?.getStringExtra(Constants.RESULT_APP_NAME) ?: getString(R.string.default_calendar_app)
|
|
||||||
calendarAppPackage = data?.getStringExtra(Constants.RESULT_APP_PACKAGE) ?: ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RequestCode.EVENT_APP_REQUEST_CODE.code -> {
|
|
||||||
Preferences.bulk {
|
|
||||||
eventAppName = data?.getStringExtra(Constants.RESULT_APP_NAME) ?: getString(R.string.default_event_app)
|
|
||||||
eventAppPackage = data?.getStringExtra(Constants.RESULT_APP_PACKAGE) ?: ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
|
||||||
scrollView.isScrollable = false
|
|
||||||
callback.invoke()
|
|
||||||
lifecycleScope.launch {
|
|
||||||
delay(200)
|
|
||||||
scrollView.isScrollable = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,331 +0,0 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.fragments
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.app.AlarmManager
|
|
||||||
import android.content.BroadcastReceiver
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.content.IntentFilter
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.text.format.DateFormat
|
|
||||||
import android.util.Log
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.databinding.DataBindingUtil
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.lifecycle.Observer
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import com.chibatching.kotpref.bulk
|
|
||||||
import com.tommasoberlose.anotherwidget.R
|
|
||||||
import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker
|
|
||||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
|
||||||
import com.tommasoberlose.anotherwidget.components.FixedFocusScrollView
|
|
||||||
import com.tommasoberlose.anotherwidget.databinding.FragmentClockSettingsBinding
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Constants
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
|
||||||
import com.tommasoberlose.anotherwidget.global.RequestCode
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.AlarmHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toHexValue
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.IntentHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.isDefaultSet
|
|
||||||
import kotlinx.android.synthetic.main.fragment_clock_settings.*
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import java.lang.Exception
|
|
||||||
|
|
||||||
|
|
||||||
class ClockTabFragment : Fragment() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun newInstance() = ClockTabFragment()
|
|
||||||
}
|
|
||||||
|
|
||||||
private lateinit var viewModel: MainViewModel
|
|
||||||
private lateinit var colors: IntArray
|
|
||||||
private lateinit var binding: FragmentClockSettingsBinding
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View {
|
|
||||||
|
|
||||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
|
||||||
binding = DataBindingUtil.inflate<FragmentClockSettingsBinding>(inflater, R.layout.fragment_clock_settings, container, false)
|
|
||||||
|
|
||||||
subscribeUi(binding, viewModel)
|
|
||||||
|
|
||||||
binding.lifecycleOwner = this
|
|
||||||
binding.viewModel = viewModel
|
|
||||||
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
|
||||||
super.onActivityCreated(savedInstanceState)
|
|
||||||
|
|
||||||
ampm_indicator_toggle.isChecked = Preferences.showAMPMIndicator
|
|
||||||
|
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
|
||||||
val lazyColors = requireContext().resources.getIntArray(R.array.material_colors)
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
colors = lazyColors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setupListener()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun subscribeUi(
|
|
||||||
binding: FragmentClockSettingsBinding,
|
|
||||||
viewModel: MainViewModel
|
|
||||||
) {
|
|
||||||
binding.isClockVisible = Preferences.showClock
|
|
||||||
binding.is24Format = DateFormat.is24HourFormat(requireContext())
|
|
||||||
binding.isDarkModeEnabled = activity?.isDarkTheme() == true
|
|
||||||
|
|
||||||
viewModel.showBigClockWarning.observe(viewLifecycleOwner, Observer {
|
|
||||||
large_clock_warning?.isVisible = it
|
|
||||||
small_clock_warning?.isVisible = !it
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.showClock.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
show_clock_label?.text =
|
|
||||||
if (it) getString(R.string.show_clock_visible) else getString(R.string.show_clock_not_visible)
|
|
||||||
binding.isClockVisible = it
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.clockTextSize.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
clock_text_size_label?.text = String.format("%.0fsp", it)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.showAMPMIndicator.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
ampm_indicator_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.clockTextColor.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
if (Preferences.clockTextAlpha == "00") {
|
|
||||||
clock_text_color_label?.text = getString(R.string.transparent)
|
|
||||||
} else {
|
|
||||||
clock_text_color_label?.text =
|
|
||||||
"#%s".format(Integer.toHexString(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.clockTextColorDark.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
if (Preferences.clockTextAlphaDark == "00") {
|
|
||||||
clock_text_color_label?.text = getString(R.string.transparent)
|
|
||||||
} else {
|
|
||||||
clock_text_color_label?.text =
|
|
||||||
"#%s".format(Integer.toHexString(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.clockTextAlpha.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
if (Preferences.clockTextAlpha == "00") {
|
|
||||||
clock_text_color_label?.text = getString(R.string.transparent)
|
|
||||||
} else {
|
|
||||||
clock_text_color_label?.text =
|
|
||||||
"#%s".format(Integer.toHexString(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.clockTextAlphaDark.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
if (Preferences.clockTextAlphaDark == "00") {
|
|
||||||
clock_text_color_label?.text = getString(R.string.transparent)
|
|
||||||
} else {
|
|
||||||
clock_text_color_label?.text =
|
|
||||||
"#%s".format(Integer.toHexString(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.clockBottomMargin.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
clock_bottom_margin_label?.text = when (it) {
|
|
||||||
Constants.ClockBottomMargin.NONE.value -> getString(R.string.settings_clock_bottom_margin_subtitle_none)
|
|
||||||
Constants.ClockBottomMargin.SMALL.value -> getString(R.string.settings_clock_bottom_margin_subtitle_small)
|
|
||||||
Constants.ClockBottomMargin.LARGE.value -> getString(R.string.settings_clock_bottom_margin_subtitle_large)
|
|
||||||
else -> getString(R.string.settings_clock_bottom_margin_subtitle_medium)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.clockAppName.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
clock_app_label?.text = when {
|
|
||||||
Preferences.clockAppName != "" -> Preferences.clockAppName
|
|
||||||
else -> {
|
|
||||||
if (IntentHelper.getClockIntent(requireContext()).isDefaultSet(requireContext())) {
|
|
||||||
getString(
|
|
||||||
R.string.default_clock_app
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
getString(R.string.nothing)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupListener() {
|
|
||||||
action_hide_large_clock_warning.setOnClickListener {
|
|
||||||
Preferences.showBigClockWarning = false
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_clock.setOnClickListener {
|
|
||||||
Preferences.showClock = !Preferences.showClock
|
|
||||||
}
|
|
||||||
|
|
||||||
show_clock_switch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
|
||||||
Preferences.showClock = enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
action_clock_text_size.setOnClickListener {
|
|
||||||
if (Preferences.showClock) {
|
|
||||||
val dialog = BottomSheetMenu<Float>(
|
|
||||||
requireContext(),
|
|
||||||
header = getString(R.string.settings_clock_text_size_title)
|
|
||||||
).setSelectedValue(Preferences.clockTextSize)
|
|
||||||
(46 downTo 12).filter { it % 2 == 0 }.forEach {
|
|
||||||
dialog.addItem("${it}sp", it.toFloat())
|
|
||||||
}
|
|
||||||
dialog.addOnSelectItemListener { value ->
|
|
||||||
Preferences.clockTextSize = value
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_ampm_indicator_size.setOnClickListener {
|
|
||||||
if (Preferences.showClock) {
|
|
||||||
ampm_indicator_toggle.isChecked = !ampm_indicator_toggle.isChecked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ampm_indicator_toggle.setOnCheckedChangeListener { _, isChecked ->
|
|
||||||
if (Preferences.showClock) {
|
|
||||||
Preferences.showAMPMIndicator = isChecked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_clock_text_color.setOnClickListener {
|
|
||||||
if (Preferences.showClock) {
|
|
||||||
BottomSheetColorPicker(requireContext(),
|
|
||||||
colors = colors,
|
|
||||||
header = getString(R.string.settings_font_color_title),
|
|
||||||
getSelected = { ColorHelper.getClockFontColorRgb(activity?.isDarkTheme() == true) },
|
|
||||||
onColorSelected = { color: Int ->
|
|
||||||
val colorString = Integer.toHexString(color)
|
|
||||||
if (activity?.isDarkTheme() == true) {
|
|
||||||
Preferences.clockTextColorDark =
|
|
||||||
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
|
||||||
} else {
|
|
||||||
Preferences.clockTextColor =
|
|
||||||
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
|
||||||
}
|
|
||||||
},
|
|
||||||
showAlphaSelector = true,
|
|
||||||
alpha = if (activity?.isDarkTheme() == true) Preferences.clockTextAlphaDark.toIntValue() else Preferences.clockTextAlpha.toIntValue(),
|
|
||||||
onAlphaChangeListener = { alpha ->
|
|
||||||
if (activity?.isDarkTheme() == true) {
|
|
||||||
Preferences.clockTextAlphaDark = alpha.toHexValue()
|
|
||||||
} else {
|
|
||||||
Preferences.clockTextAlpha = alpha.toHexValue()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_clock_bottom_margin_size.setOnClickListener {
|
|
||||||
if (Preferences.showClock) {
|
|
||||||
BottomSheetMenu<Int>(
|
|
||||||
requireContext(),
|
|
||||||
header = getString(R.string.settings_clock_bottom_margin_title)
|
|
||||||
).setSelectedValue(Preferences.clockBottomMargin)
|
|
||||||
.addItem(
|
|
||||||
getString(R.string.settings_clock_bottom_margin_subtitle_none),
|
|
||||||
Constants.ClockBottomMargin.NONE.value
|
|
||||||
)
|
|
||||||
.addItem(
|
|
||||||
getString(R.string.settings_clock_bottom_margin_subtitle_small),
|
|
||||||
Constants.ClockBottomMargin.SMALL.value
|
|
||||||
)
|
|
||||||
.addItem(
|
|
||||||
getString(R.string.settings_clock_bottom_margin_subtitle_medium),
|
|
||||||
Constants.ClockBottomMargin.MEDIUM.value
|
|
||||||
)
|
|
||||||
.addItem(
|
|
||||||
getString(R.string.settings_clock_bottom_margin_subtitle_large),
|
|
||||||
Constants.ClockBottomMargin.LARGE.value
|
|
||||||
)
|
|
||||||
.addOnSelectItemListener { value ->
|
|
||||||
Preferences.clockBottomMargin = value
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_clock_app.setOnClickListener {
|
|
||||||
if (Preferences.showClock) {
|
|
||||||
if (Preferences.showClock) {
|
|
||||||
startActivityForResult(
|
|
||||||
Intent(requireContext(), ChooseApplicationActivity::class.java),
|
|
||||||
RequestCode.CLOCK_APP_REQUEST_CODE.code
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
||||||
if (resultCode == Activity.RESULT_OK && requestCode == RequestCode.CLOCK_APP_REQUEST_CODE.code) {
|
|
||||||
Preferences.bulk {
|
|
||||||
clockAppName = data?.getStringExtra(Constants.RESULT_APP_NAME) ?: getString(R.string.default_clock_app)
|
|
||||||
clockAppPackage = data?.getStringExtra(Constants.RESULT_APP_PACKAGE) ?: ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
binding.is24Format = DateFormat.is24HourFormat(requireContext())
|
|
||||||
super.onResume()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
|
||||||
scrollView.isScrollable = false
|
|
||||||
callback.invoke()
|
|
||||||
lifecycleScope.launch {
|
|
||||||
delay(200)
|
|
||||||
scrollView.isScrollable = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,535 +0,0 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.fragments
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Intent
|
|
||||||
import android.graphics.Typeface
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.os.Handler
|
|
||||||
import android.os.HandlerThread
|
|
||||||
import android.util.Log
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.core.provider.FontRequest
|
|
||||||
import androidx.core.provider.FontsContractCompat
|
|
||||||
import androidx.databinding.DataBindingUtil
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.lifecycle.Observer
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import com.chibatching.kotpref.blockingBulk
|
|
||||||
import com.chibatching.kotpref.bulk
|
|
||||||
import com.tommasoberlose.anotherwidget.R
|
|
||||||
import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker
|
|
||||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
|
||||||
import com.tommasoberlose.anotherwidget.databinding.FragmentGeneralSettingsBinding
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Constants
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
|
||||||
import com.tommasoberlose.anotherwidget.global.RequestCode
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toHexValue
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.DateHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.WidgetHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.CustomDateActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.CustomFontActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
|
||||||
import kotlinx.android.synthetic.main.fragment_clock_settings.*
|
|
||||||
import kotlinx.android.synthetic.main.fragment_general_settings.*
|
|
||||||
import kotlinx.android.synthetic.main.fragment_general_settings.scrollView
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
|
|
||||||
class GeneralTabFragment : Fragment() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun newInstance() = GeneralTabFragment()
|
|
||||||
}
|
|
||||||
|
|
||||||
private lateinit var viewModel: MainViewModel
|
|
||||||
private lateinit var colors: IntArray
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View {
|
|
||||||
|
|
||||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
|
||||||
val binding = DataBindingUtil.inflate<FragmentGeneralSettingsBinding>(inflater, R.layout.fragment_general_settings, container, false)
|
|
||||||
|
|
||||||
subscribeUi(viewModel)
|
|
||||||
|
|
||||||
binding.lifecycleOwner = this
|
|
||||||
binding.viewModel = viewModel
|
|
||||||
binding.isDarkModeEnabled = activity?.isDarkTheme() == true
|
|
||||||
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
|
||||||
super.onActivityCreated(savedInstanceState)
|
|
||||||
|
|
||||||
show_dividers_toggle.isChecked = Preferences.showDividers
|
|
||||||
|
|
||||||
setupListener()
|
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
|
||||||
val lazyColors = requireContext().resources.getIntArray(R.array.material_colors)
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
colors = lazyColors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@SuppressLint("DefaultLocale")
|
|
||||||
private fun subscribeUi(
|
|
||||||
viewModel: MainViewModel
|
|
||||||
) {
|
|
||||||
|
|
||||||
viewModel.textMainSize.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
main_text_size_label?.text = String.format("%.0fsp", it)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.textSecondSize.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
second_text_size_label?.text = String.format("%.0fsp", it)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.textGlobalColor.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
if (Preferences.textGlobalAlpha == "00") {
|
|
||||||
font_color_label?.text = getString(R.string.transparent)
|
|
||||||
} else {
|
|
||||||
font_color_label?.text =
|
|
||||||
"#%s".format(Integer.toHexString(ColorHelper.getFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.textGlobalColorDark.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
if (Preferences.textGlobalAlphaDark == "00") {
|
|
||||||
font_color_label?.text = getString(R.string.transparent)
|
|
||||||
} else {
|
|
||||||
font_color_label?.text =
|
|
||||||
"#%s".format(Integer.toHexString(ColorHelper.getFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.textGlobalAlpha.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
if (Preferences.textGlobalAlpha == "00") {
|
|
||||||
font_color_label?.text = getString(R.string.transparent)
|
|
||||||
} else {
|
|
||||||
font_color_label?.text =
|
|
||||||
"#%s".format(Integer.toHexString(ColorHelper.getFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.textGlobalAlphaDark.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
if (Preferences.textGlobalAlphaDark == "00") {
|
|
||||||
font_color_label?.text = getString(R.string.transparent)
|
|
||||||
} else {
|
|
||||||
font_color_label?.text =
|
|
||||||
"#%s".format(Integer.toHexString(ColorHelper.getFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.textSecondaryColor.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
if (Preferences.textSecondaryAlpha == "00") {
|
|
||||||
secondary_font_color_label?.text = getString(R.string.transparent)
|
|
||||||
} else {
|
|
||||||
secondary_font_color_label?.text =
|
|
||||||
"#%s".format(Integer.toHexString(ColorHelper.getSecondaryFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.textSecondaryColorDark.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
if (Preferences.textSecondaryAlphaDark == "00") {
|
|
||||||
secondary_font_color_label?.text = getString(R.string.transparent)
|
|
||||||
} else {
|
|
||||||
secondary_font_color_label?.text =
|
|
||||||
"#%s".format(Integer.toHexString(ColorHelper.getSecondaryFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.textSecondaryAlpha.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
if (Preferences.textSecondaryAlpha == "00") {
|
|
||||||
secondary_font_color_label?.text = getString(R.string.transparent)
|
|
||||||
} else {
|
|
||||||
secondary_font_color_label?.text =
|
|
||||||
"#%s".format(Integer.toHexString(ColorHelper.getSecondaryFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.textSecondaryAlphaDark.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
if (Preferences.textSecondaryAlphaDark == "00") {
|
|
||||||
secondary_font_color_label?.text = getString(R.string.transparent)
|
|
||||||
} else {
|
|
||||||
secondary_font_color_label?.text =
|
|
||||||
"#%s".format(Integer.toHexString(ColorHelper.getSecondaryFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.secondRowTopMargin.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
second_row_top_margin_label?.text = when (it) {
|
|
||||||
Constants.SecondRowTopMargin.NONE.value -> getString(R.string.settings_clock_bottom_margin_subtitle_none)
|
|
||||||
Constants.SecondRowTopMargin.SMALL.value -> getString(R.string.settings_clock_bottom_margin_subtitle_small)
|
|
||||||
Constants.SecondRowTopMargin.LARGE.value -> getString(R.string.settings_clock_bottom_margin_subtitle_large)
|
|
||||||
else -> getString(R.string.settings_clock_bottom_margin_subtitle_medium)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.backgroundCardColor.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
if (Preferences.backgroundCardAlpha == "00") {
|
|
||||||
background_color_label?.text = getString(R.string.transparent)
|
|
||||||
} else {
|
|
||||||
background_color_label?.text =
|
|
||||||
"#%s".format(Integer.toHexString(ColorHelper.getBackgroundColor(activity?.isDarkTheme() == true))).toUpperCase()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.backgroundCardColorDark.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
if (Preferences.backgroundCardAlphaDark == "00") {
|
|
||||||
background_color_label?.text = getString(R.string.transparent)
|
|
||||||
} else {
|
|
||||||
background_color_label?.text =
|
|
||||||
"#%s".format(Integer.toHexString(ColorHelper.getBackgroundColor(activity?.isDarkTheme() == true))).toUpperCase()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.backgroundCardAlpha.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
if (Preferences.backgroundCardAlpha == "00") {
|
|
||||||
background_color_label?.text = getString(R.string.transparent)
|
|
||||||
} else {
|
|
||||||
background_color_label?.text =
|
|
||||||
"#%s".format(Integer.toHexString(ColorHelper.getBackgroundColor(activity?.isDarkTheme() == true))).toUpperCase()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.backgroundCardAlphaDark.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
if (Preferences.backgroundCardAlphaDark == "00") {
|
|
||||||
background_color_label?.text = getString(R.string.transparent)
|
|
||||||
} else {
|
|
||||||
background_color_label?.text =
|
|
||||||
"#%s".format(Integer.toHexString(ColorHelper.getBackgroundColor(activity?.isDarkTheme() == true))).toUpperCase()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.textShadow.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
if (activity?.isDarkTheme() != true) {
|
|
||||||
text_shadow_label?.text =
|
|
||||||
getString(SettingsStringHelper.getTextShadowString(it))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.textShadowDark.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
if (activity?.isDarkTheme() == true) {
|
|
||||||
text_shadow_label?.text =
|
|
||||||
getString(SettingsStringHelper.getTextShadowString(it))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.dateFormat.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
date_format_label?.text = DateHelper.getDateText(requireContext(), Calendar.getInstance())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.customFont.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
custom_font_label?.text = SettingsStringHelper.getCustomFontLabel(requireContext(), it)
|
|
||||||
MainWidget.updateWidget(requireContext())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.customFontFile.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
custom_font_label?.text = SettingsStringHelper.getCustomFontLabel(requireContext(), Preferences.customFont)
|
|
||||||
MainWidget.updateWidget(requireContext())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.customFontName.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
custom_font_label?.text = SettingsStringHelper.getCustomFontLabel(requireContext(), Preferences.customFont)
|
|
||||||
MainWidget.updateWidget(requireContext())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.customFontVariant.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
custom_font_label?.text = SettingsStringHelper.getCustomFontLabel(requireContext(), Preferences.customFont)
|
|
||||||
MainWidget.updateWidget(requireContext())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.showDividers.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
show_dividers_label?.text =
|
|
||||||
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupListener() {
|
|
||||||
action_main_text_size.setOnClickListener {
|
|
||||||
val dialog = BottomSheetMenu<Float>(requireContext(), header = getString(R.string.title_main_text_size)).setSelectedValue(Preferences.textMainSize)
|
|
||||||
(40 downTo 10).filter { it % 2 == 0 }.forEach {
|
|
||||||
dialog.addItem("${it}sp", it.toFloat())
|
|
||||||
}
|
|
||||||
dialog.addOnSelectItemListener { value ->
|
|
||||||
Preferences.textMainSize = value
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
action_second_text_size.setOnClickListener {
|
|
||||||
val dialog = BottomSheetMenu<Float>(requireContext(), header = getString(R.string.title_second_text_size)).setSelectedValue(Preferences.textSecondSize)
|
|
||||||
(40 downTo 10).filter { it % 2 == 0 }.forEach {
|
|
||||||
dialog.addItem("${it}sp", it.toFloat())
|
|
||||||
}
|
|
||||||
dialog.addOnSelectItemListener { value ->
|
|
||||||
Preferences.textSecondSize = value
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
action_font_color.setOnClickListener {
|
|
||||||
BottomSheetColorPicker(requireContext(),
|
|
||||||
colors = colors,
|
|
||||||
header = getString(R.string.settings_font_color_title),
|
|
||||||
getSelected = { ColorHelper.getFontColorRgb(activity?.isDarkTheme() == true) },
|
|
||||||
onColorSelected = { color: Int ->
|
|
||||||
val colorString = Integer.toHexString(color)
|
|
||||||
if (activity?.isDarkTheme() == true) {
|
|
||||||
Preferences.textGlobalColorDark = "#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
|
||||||
} else {
|
|
||||||
Preferences.textGlobalColor = "#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
|
||||||
}
|
|
||||||
},
|
|
||||||
showAlphaSelector = true,
|
|
||||||
alpha = if (activity?.isDarkTheme() == true) Preferences.textGlobalAlphaDark.toIntValue() else Preferences.textGlobalAlpha.toIntValue(),
|
|
||||||
onAlphaChangeListener = { alpha ->
|
|
||||||
if (activity?.isDarkTheme() == true) {
|
|
||||||
Preferences.textGlobalAlphaDark = alpha.toHexValue()
|
|
||||||
} else {
|
|
||||||
Preferences.textGlobalAlpha = alpha.toHexValue()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
|
|
||||||
action_secondary_font_color.setOnClickListener {
|
|
||||||
BottomSheetColorPicker(requireContext(),
|
|
||||||
colors = colors,
|
|
||||||
header = getString(R.string.settings_secondary_font_color_title),
|
|
||||||
getSelected = { ColorHelper.getSecondaryFontColorRgb(activity?.isDarkTheme() == true) },
|
|
||||||
onColorSelected = { color: Int ->
|
|
||||||
val colorString = Integer.toHexString(color)
|
|
||||||
if (activity?.isDarkTheme() == true) {
|
|
||||||
Preferences.textSecondaryColorDark =
|
|
||||||
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
|
||||||
} else {
|
|
||||||
Preferences.textSecondaryColor =
|
|
||||||
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
|
||||||
}
|
|
||||||
},
|
|
||||||
showAlphaSelector = true,
|
|
||||||
alpha = if (activity?.isDarkTheme() == true) Preferences.textSecondaryAlphaDark.toIntValue() else Preferences.textSecondaryAlpha.toIntValue(),
|
|
||||||
onAlphaChangeListener = { alpha ->
|
|
||||||
if (activity?.isDarkTheme() == true) {
|
|
||||||
Preferences.textSecondaryAlphaDark = alpha.toHexValue()
|
|
||||||
} else {
|
|
||||||
Preferences.textSecondaryAlpha = alpha.toHexValue()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
|
|
||||||
action_second_row_top_margin_size.setOnClickListener {
|
|
||||||
BottomSheetMenu<Int>(
|
|
||||||
requireContext(),
|
|
||||||
header = getString(R.string.settings_secondary_row_top_margin_title)
|
|
||||||
).setSelectedValue(Preferences.secondRowTopMargin)
|
|
||||||
.addItem(
|
|
||||||
getString(R.string.settings_clock_bottom_margin_subtitle_none),
|
|
||||||
Constants.SecondRowTopMargin.NONE.value
|
|
||||||
)
|
|
||||||
.addItem(
|
|
||||||
getString(R.string.settings_clock_bottom_margin_subtitle_small),
|
|
||||||
Constants.SecondRowTopMargin.SMALL.value
|
|
||||||
)
|
|
||||||
.addItem(
|
|
||||||
getString(R.string.settings_clock_bottom_margin_subtitle_medium),
|
|
||||||
Constants.SecondRowTopMargin.MEDIUM.value
|
|
||||||
)
|
|
||||||
.addItem(
|
|
||||||
getString(R.string.settings_clock_bottom_margin_subtitle_large),
|
|
||||||
Constants.SecondRowTopMargin.LARGE.value
|
|
||||||
)
|
|
||||||
.addOnSelectItemListener { value ->
|
|
||||||
Preferences.secondRowTopMargin = value
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
action_date_format.setOnClickListener {
|
|
||||||
val now = Calendar.getInstance()
|
|
||||||
val dialog = BottomSheetMenu<String>(requireContext(), header = getString(R.string.settings_date_format_title)).setSelectedValue(Preferences.dateFormat)
|
|
||||||
|
|
||||||
dialog.addItem(DateHelper.getDefaultDateText(requireContext(), now), "")
|
|
||||||
if (Preferences.dateFormat != "") {
|
|
||||||
dialog.addItem(DateHelper.getDateText(requireContext(), now), Preferences.dateFormat)
|
|
||||||
}
|
|
||||||
dialog.addItem(getString(R.string.custom_date_format), "-")
|
|
||||||
|
|
||||||
dialog.addOnSelectItemListener { value ->
|
|
||||||
when (value) {
|
|
||||||
"-" -> {
|
|
||||||
startActivity(Intent(requireContext(), CustomDateActivity::class.java))
|
|
||||||
}
|
|
||||||
"" -> {
|
|
||||||
Preferences.blockingBulk {
|
|
||||||
isDateCapitalize = false
|
|
||||||
isDateUppercase = false
|
|
||||||
}
|
|
||||||
Preferences.dateFormat = value
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
Preferences.dateFormat = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
action_background_color.setOnClickListener {
|
|
||||||
BottomSheetColorPicker(requireContext(),
|
|
||||||
colors = colors,
|
|
||||||
header = getString(R.string.settings_background_color_title),
|
|
||||||
getSelected = { ColorHelper.getBackgroundColorRgb(activity?.isDarkTheme() == true) },
|
|
||||||
onColorSelected = { color: Int ->
|
|
||||||
val colorString = Integer.toHexString(color)
|
|
||||||
if (activity?.isDarkTheme() == true) {
|
|
||||||
Preferences.backgroundCardColorDark =
|
|
||||||
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
|
||||||
} else {
|
|
||||||
Preferences.backgroundCardColor =
|
|
||||||
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
|
||||||
}
|
|
||||||
},
|
|
||||||
showAlphaSelector = true,
|
|
||||||
alpha = if (activity?.isDarkTheme() == true) Preferences.backgroundCardAlphaDark.toIntValue() else Preferences.backgroundCardAlpha.toIntValue(),
|
|
||||||
onAlphaChangeListener = { alpha ->
|
|
||||||
if (activity?.isDarkTheme() == true) {
|
|
||||||
Preferences.backgroundCardAlphaDark = alpha.toHexValue()
|
|
||||||
} else {
|
|
||||||
Preferences.backgroundCardAlpha = alpha.toHexValue()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
|
|
||||||
action_text_shadow.setOnClickListener {
|
|
||||||
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.title_text_shadow)).setSelectedValue(if (activity?.isDarkTheme() == true) Preferences.textShadowDark else Preferences.textShadow)
|
|
||||||
(2 downTo 0).forEach {
|
|
||||||
dialog.addItem(getString(SettingsStringHelper.getTextShadowString(it)), it)
|
|
||||||
}
|
|
||||||
dialog.addOnSelectItemListener { value ->
|
|
||||||
if (activity?.isDarkTheme() == true) {
|
|
||||||
Preferences.textShadowDark = value
|
|
||||||
} else {
|
|
||||||
Preferences.textShadow = value
|
|
||||||
}
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
action_custom_font.setOnClickListener {
|
|
||||||
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_custom_font_title)).setSelectedValue(Preferences.customFont)
|
|
||||||
dialog.addItem(SettingsStringHelper.getCustomFontLabel(requireContext(), 0), 0)
|
|
||||||
|
|
||||||
if (Preferences.customFont == Constants.CUSTOM_FONT_GOOGLE_SANS) {
|
|
||||||
dialog.addItem(SettingsStringHelper.getCustomFontLabel(requireContext(), Constants.CUSTOM_FONT_GOOGLE_SANS), Constants.CUSTOM_FONT_GOOGLE_SANS)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Preferences.customFontFile != "") {
|
|
||||||
dialog.addItem(SettingsStringHelper.getCustomFontLabel(requireContext(), Preferences.customFont), Constants.CUSTOM_FONT_DOWNLOADED)
|
|
||||||
}
|
|
||||||
dialog.addItem(getString(R.string.action_custom_font_to_search), Constants.CUSTOM_FONT_DOWNLOAD_NEW)
|
|
||||||
dialog.addOnSelectItemListener { value ->
|
|
||||||
if (value == Constants.CUSTOM_FONT_DOWNLOAD_NEW) {
|
|
||||||
startActivityForResult(
|
|
||||||
Intent(requireContext(), CustomFontActivity::class.java),
|
|
||||||
RequestCode.CUSTOM_FONT_CHOOSER_REQUEST_CODE.code
|
|
||||||
)
|
|
||||||
} else if (value != Constants.CUSTOM_FONT_DOWNLOADED) {
|
|
||||||
Preferences.bulk {
|
|
||||||
customFont = value
|
|
||||||
customFontFile = ""
|
|
||||||
customFontName = ""
|
|
||||||
customFontVariant = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_dividers.setOnClickListener {
|
|
||||||
show_dividers_toggle.isChecked = !show_dividers_toggle.isChecked
|
|
||||||
}
|
|
||||||
|
|
||||||
show_dividers_toggle.setOnCheckedChangeListener { _, isChecked ->
|
|
||||||
Preferences.showDividers = isChecked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
|
||||||
scrollView.isScrollable = false
|
|
||||||
callback.invoke()
|
|
||||||
lifecycleScope.launch {
|
|
||||||
delay(200)
|
|
||||||
scrollView.isScrollable = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,64 +1,54 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.fragments
|
package com.tommasoberlose.anotherwidget.ui.fragments
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.animation.ValueAnimator
|
import android.animation.ValueAnimator
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.util.DisplayMetrics
|
import android.util.DisplayMetrics
|
||||||
import android.util.TypedValue
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RemoteViews
|
||||||
import androidx.core.animation.addListener
|
|
||||||
import androidx.core.app.NotificationManagerCompat
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.Observer
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.Navigation
|
import androidx.navigation.Navigation
|
||||||
import com.google.android.material.badge.BadgeDrawable
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
import com.google.android.material.tabs.TabLayoutMediator
|
|
||||||
import com.google.android.material.transition.MaterialSharedAxis
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
|
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.FragmentAppMainBinding
|
||||||
import com.tommasoberlose.anotherwidget.global.Constants
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.helpers.*
|
import com.tommasoberlose.anotherwidget.helpers.*
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
|
|
||||||
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||||
import com.tommasoberlose.anotherwidget.ui.adapters.ViewPagerAdapter
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
import com.tommasoberlose.anotherwidget.utils.*
|
import com.tommasoberlose.anotherwidget.utils.*
|
||||||
import kotlinx.android.synthetic.main.fragment_app_main.*
|
|
||||||
import kotlinx.android.synthetic.main.the_widget_sans.*
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
import org.greenrobot.eventbus.Subscribe
|
import org.greenrobot.eventbus.Subscribe
|
||||||
import org.greenrobot.eventbus.ThreadMode
|
import org.greenrobot.eventbus.ThreadMode
|
||||||
|
|
||||||
class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeListener {
|
|
||||||
|
class MainFragment : Fragment() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun newInstance() = MainFragment()
|
fun newInstance() = MainFragment()
|
||||||
private const val PREVIEW_BASE_HEIGHT = 120
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var viewModel: MainViewModel
|
private lateinit var viewModel: MainViewModel
|
||||||
|
private lateinit var binding: FragmentAppMainBinding
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
enterTransition = MaterialSharedAxis(MaterialSharedAxis.Y, true)
|
||||||
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Y, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
@ -66,41 +56,7 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
|
|||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View {
|
): View {
|
||||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||||
return inflater.inflate(R.layout.fragment_app_main, container, false)
|
binding = FragmentAppMainBinding.inflate(inflater)
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
|
||||||
super.onActivityCreated(savedInstanceState)
|
|
||||||
|
|
||||||
// Viewpager
|
|
||||||
pager.adapter = ViewPagerAdapter(requireActivity())
|
|
||||||
pager.offscreenPageLimit = 4
|
|
||||||
TabLayoutMediator(tabs, pager) { tab, position ->
|
|
||||||
tab.text = when (position) {
|
|
||||||
0 -> getString(R.string.settings_general_title)
|
|
||||||
1 -> getString(R.string.settings_calendar_title)
|
|
||||||
2 -> getString(R.string.settings_weather_title)
|
|
||||||
3 -> getString(R.string.settings_clock_title)
|
|
||||||
4 -> getString(R.string.settings_at_a_glance_title)
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
}.attach()
|
|
||||||
|
|
||||||
// Init clock
|
|
||||||
if (Preferences.showClock) {
|
|
||||||
time.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
|
|
||||||
time.setTextSize(TypedValue.COMPLEX_UNIT_SP,
|
|
||||||
Preferences.clockTextSize.toPixel(requireContext()))
|
|
||||||
time_am_pm.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
|
|
||||||
time_am_pm.setTextSize(TypedValue.COMPLEX_UNIT_SP,
|
|
||||||
Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2)
|
|
||||||
}
|
|
||||||
time_container.isVisible = Preferences.showClock
|
|
||||||
|
|
||||||
preview.layoutParams = preview.layoutParams.apply {
|
|
||||||
height = PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(requireContext()) else 0
|
|
||||||
}
|
|
||||||
subscribeUi(viewModel)
|
|
||||||
|
|
||||||
// Warnings
|
// Warnings
|
||||||
if (getString(R.string.xiaomi_manufacturer).equals(Build.MANUFACTURER, ignoreCase = true) && Preferences.showXiaomiWarning) {
|
if (getString(R.string.xiaomi_manufacturer).equals(Build.MANUFACTURER, ignoreCase = true) && Preferences.showXiaomiWarning) {
|
||||||
@ -117,293 +73,160 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
|
|||||||
}
|
}
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val navHost = childFragmentManager.findFragmentById(R.id.settings_fragment) as? NavHostFragment?
|
||||||
|
navHost?.navController?.addOnDestinationChangedListener { controller, destination, _ ->
|
||||||
|
val show = destination.id != R.id.tabSelectorFragment
|
||||||
|
binding.actionBack.animate().alpha(if (show) 1f else 0f).setDuration(200).translationX((if (show) 0f else 4f).convertDpToPixel(requireContext())).start()
|
||||||
|
binding.actionBack.setOnSingleClickListener {
|
||||||
|
controller.navigateUp()
|
||||||
|
}
|
||||||
|
binding.actionBack.isClickable = show
|
||||||
|
binding.actionBack.isFocusable = show
|
||||||
|
binding.actionSettings.animate().alpha(if (!show) 1f else 0f).setDuration(200).translationX((if (!show) 0f else -4f).convertDpToPixel(requireContext())).start()
|
||||||
|
binding.actionSettings.isClickable = !show
|
||||||
|
binding.actionSettings.isFocusable = !show
|
||||||
|
binding.fragmentTitle.text = if (show) destination.label.toString() else getString(R.string.app_name)
|
||||||
|
binding.toolbar.cardElevation = 0f
|
||||||
}
|
}
|
||||||
|
|
||||||
private var uiJob: Job? = null
|
binding.actionSettings.setOnSingleClickListener {
|
||||||
|
Navigation.findNavController(it).navigate(R.id.action_appMainFragment_to_appSettingsFragment)
|
||||||
private fun updateUI() {
|
|
||||||
uiJob?.cancel()
|
|
||||||
|
|
||||||
preview?.clearAnimation()
|
|
||||||
time_container?.clearAnimation()
|
|
||||||
|
|
||||||
if (Preferences.showPreview) {
|
|
||||||
preview?.setCardBackgroundColor(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
requireContext(),
|
|
||||||
if (ColorHelper.getFontColor(activity?.isDarkTheme() == true)
|
|
||||||
.isColorDark()
|
|
||||||
) android.R.color.white else R.color.colorAccent
|
|
||||||
)
|
|
||||||
)
|
|
||||||
widget_shape_background?.setImageDrawable(
|
|
||||||
BitmapHelper.getTintedDrawable(
|
|
||||||
requireContext(),
|
|
||||||
R.drawable.card_background,
|
|
||||||
ColorHelper.getBackgroundColor(activity?.isDarkTheme() == true)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
WidgetHelper.runWithCustomTypeface(requireContext()) { typeface ->
|
|
||||||
uiJob = lifecycleScope.launch(Dispatchers.IO) {
|
|
||||||
val generatedView = MainWidget.generateWidgetView(requireContext(), typeface)
|
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
generatedView.measure(0, 0)
|
|
||||||
preview?.measure(0, 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val bitmap = if (preview != null) {
|
subscribeUi(viewModel)
|
||||||
BitmapHelper.getBitmapFromView(
|
|
||||||
generatedView,
|
|
||||||
if (preview.width > 0) preview.width else generatedView.measuredWidth,
|
|
||||||
generatedView.measuredHeight
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
// Clock
|
|
||||||
time?.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
|
|
||||||
time_am_pm?.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
|
|
||||||
time?.setTextSize(
|
|
||||||
TypedValue.COMPLEX_UNIT_SP,
|
|
||||||
Preferences.clockTextSize.toPixel(requireContext())
|
|
||||||
)
|
|
||||||
time_am_pm?.setTextSize(
|
|
||||||
TypedValue.COMPLEX_UNIT_SP,
|
|
||||||
Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2
|
|
||||||
)
|
|
||||||
time_am_pm?.isVisible = Preferences.showAMPMIndicator
|
|
||||||
|
|
||||||
// Clock bottom margin
|
|
||||||
clock_bottom_margin_none?.isVisible =
|
|
||||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.value
|
|
||||||
clock_bottom_margin_small?.isVisible =
|
|
||||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.SMALL.value
|
|
||||||
clock_bottom_margin_medium?.isVisible =
|
|
||||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.MEDIUM.value
|
|
||||||
clock_bottom_margin_large?.isVisible =
|
|
||||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.LARGE.value
|
|
||||||
|
|
||||||
if ((Preferences.showClock && (time?.alpha ?: 1f < 1f)) || (!Preferences.showClock && (time?.alpha ?: 0f > 0f))) {
|
|
||||||
if (Preferences.showClock) {
|
|
||||||
time_container?.layoutParams = time_container.layoutParams.apply {
|
|
||||||
height = RelativeLayout.LayoutParams.WRAP_CONTENT
|
|
||||||
}
|
|
||||||
time_container?.measure(0, 0)
|
|
||||||
}
|
|
||||||
val initialHeight = time_container?.measuredHeight ?: 0
|
|
||||||
ValueAnimator.ofFloat(
|
|
||||||
if (Preferences.showClock) 0f else 1f,
|
|
||||||
if (Preferences.showClock) 1f else 0f
|
|
||||||
).apply {
|
|
||||||
duration = 500L
|
|
||||||
addUpdateListener {
|
|
||||||
val animatedValue = animatedValue as Float
|
|
||||||
time_container?.layoutParams =
|
|
||||||
time_container.layoutParams.apply {
|
|
||||||
height = (initialHeight * animatedValue).toInt()
|
|
||||||
}
|
|
||||||
time?.alpha = animatedValue
|
|
||||||
}
|
|
||||||
addListener(
|
|
||||||
onStart = {
|
|
||||||
if (Preferences.showClock) {
|
|
||||||
time_container?.isVisible = true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onEnd = {
|
|
||||||
if (!Preferences.showClock) {
|
|
||||||
time_container?.isVisible = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}.start()
|
|
||||||
|
|
||||||
if (preview != null) {
|
|
||||||
ValueAnimator.ofInt(
|
|
||||||
preview.height,
|
|
||||||
PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
|
|
||||||
requireContext()
|
|
||||||
) else 0
|
|
||||||
).apply {
|
|
||||||
duration = 500L
|
|
||||||
addUpdateListener {
|
|
||||||
if (preview != null) {
|
|
||||||
val animatedValue = animatedValue as Int
|
|
||||||
val layoutParams = preview.layoutParams
|
|
||||||
layoutParams.height = animatedValue
|
|
||||||
preview.layoutParams = layoutParams
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.start()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
time_container?.layoutParams = time_container.layoutParams.apply {
|
|
||||||
height = RelativeLayout.LayoutParams.WRAP_CONTENT
|
|
||||||
}
|
|
||||||
time_container?.measure(0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (preview != null && preview.height == 0) {
|
|
||||||
ValueAnimator.ofInt(
|
|
||||||
preview.height,
|
|
||||||
PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
|
|
||||||
requireContext()
|
|
||||||
) else 0
|
|
||||||
).apply {
|
|
||||||
duration = 300L
|
|
||||||
addUpdateListener {
|
|
||||||
if (preview != null) {
|
|
||||||
val animatedValue = animatedValue as Int
|
|
||||||
val layoutParams = preview.layoutParams
|
|
||||||
layoutParams.height = animatedValue
|
|
||||||
preview?.layoutParams = layoutParams
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
widget_loader?.animate()?.scaleX(0f)?.scaleY(0f)?.alpha(0f)
|
|
||||||
?.setDuration(200L)?.start()
|
|
||||||
bitmap_container?.apply {
|
|
||||||
setImageBitmap(bitmap)
|
|
||||||
scaleX = 0.9f
|
|
||||||
scaleY = 0.9f
|
|
||||||
}
|
|
||||||
widget?.animate()?.alpha(1f)?.start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (preview != null) {
|
|
||||||
ValueAnimator.ofInt(
|
|
||||||
preview.height,
|
|
||||||
0
|
|
||||||
).apply {
|
|
||||||
duration = 300L
|
|
||||||
addUpdateListener {
|
|
||||||
if (preview != null) {
|
|
||||||
val animatedValue = animatedValue as Int
|
|
||||||
val layoutParams = preview.layoutParams
|
|
||||||
layoutParams.height = animatedValue
|
|
||||||
preview.layoutParams = layoutParams
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
showErrorBadge()
|
|
||||||
|
|
||||||
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun subscribeUi(viewModel: MainViewModel) {
|
private fun subscribeUi(viewModel: MainViewModel) {
|
||||||
viewModel.showWallpaper.observe(viewLifecycleOwner, Observer {
|
viewModel.showWallpaper.observe(viewLifecycleOwner) {
|
||||||
activity?.let { act ->
|
if (it) {
|
||||||
val wallpaper = act.getCurrentWallpaper()
|
val wallpaper = requireActivity().getCurrentWallpaper()
|
||||||
widget_bg.setImageDrawable(if (it) wallpaper else null)
|
binding.widgetBg.setImageDrawable(if (it) wallpaper else null)
|
||||||
if (wallpaper != null) {
|
if (wallpaper != null) {
|
||||||
widget_bg.layoutParams =
|
binding.widgetBg.layoutParams =
|
||||||
(widget_bg.layoutParams as ViewGroup.MarginLayoutParams).apply {
|
(binding.widgetBg.layoutParams as ViewGroup.MarginLayoutParams).apply {
|
||||||
|
|
||||||
val metrics = DisplayMetrics()
|
val metrics = DisplayMetrics()
|
||||||
act.windowManager.defaultDisplay.getMetrics(metrics)
|
|
||||||
|
|
||||||
val dimensions: Pair<Int, Int> = if (wallpaper.intrinsicWidth >= wallpaper.intrinsicHeight) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
val display = requireActivity().display
|
||||||
|
display?.getRealMetrics(metrics)
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
val display = requireActivity().windowManager.defaultDisplay
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
display.getMetrics(metrics)
|
||||||
|
}
|
||||||
|
|
||||||
|
val dimensions: Pair<Int, Int> =
|
||||||
|
if (wallpaper.intrinsicWidth >= wallpaper.intrinsicHeight) {
|
||||||
metrics.heightPixels to (wallpaper.intrinsicWidth) * metrics.heightPixels / (wallpaper.intrinsicHeight)
|
metrics.heightPixels to (wallpaper.intrinsicWidth) * metrics.heightPixels / (wallpaper.intrinsicHeight)
|
||||||
} else {
|
} else {
|
||||||
metrics.widthPixels to (wallpaper.intrinsicHeight) * metrics.widthPixels / (wallpaper.intrinsicWidth)
|
metrics.widthPixels to (wallpaper.intrinsicHeight) * metrics.widthPixels / (wallpaper.intrinsicWidth)
|
||||||
}
|
}
|
||||||
|
|
||||||
setMargins(
|
setMargins(0, (-80).toPixel(requireContext()), 0, 0
|
||||||
if (dimensions.first >= dimensions.second) (-80).toPixel(requireContext()) else 0,
|
|
||||||
(-80).toPixel(requireContext()), 0, 0
|
|
||||||
)
|
)
|
||||||
|
|
||||||
width = dimensions.first
|
width = dimensions.first
|
||||||
height = dimensions.second
|
height = dimensions.second
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
logo.setOnClickListener {
|
|
||||||
// startActivity(Intent(this, SupportDevActivity::class.java))
|
|
||||||
}
|
|
||||||
|
|
||||||
action_settings.setOnClickListener {
|
|
||||||
Navigation.findNavController(it).navigate(R.id.action_appMainFragment_to_appSettingsFragment)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showErrorBadge() {
|
|
||||||
// Calendar error indicator
|
|
||||||
tabs?.getTabAt(1)?.orCreateBadge?.apply {
|
|
||||||
backgroundColor = ContextCompat.getColor(requireContext(), R.color.errorColorText)
|
|
||||||
badgeGravity = BadgeDrawable.TOP_END
|
|
||||||
}?.isVisible = Preferences.showEvents && activity?.checkGrantedPermission(Manifest.permission.READ_CALENDAR) != true
|
|
||||||
|
|
||||||
// Weather error indicator
|
|
||||||
tabs?.getTabAt(2)?.orCreateBadge?.apply {
|
|
||||||
backgroundColor = ContextCompat.getColor(requireContext(), R.color.errorColorText)
|
|
||||||
badgeGravity = BadgeDrawable.TOP_END
|
|
||||||
}?.isVisible = if (Preferences.showWeather) {
|
|
||||||
(WeatherHelper.isKeyRequired() && WeatherHelper.getApiKey() == "")
|
|
||||||
|| (Preferences.customLocationAdd == "" && activity?.checkGrantedPermission(
|
|
||||||
Manifest.permission.ACCESS_FINE_LOCATION
|
|
||||||
) != true)
|
|
||||||
|| (Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-")
|
|
||||||
|| (Preferences.weatherProviderLocationError != "")
|
|
||||||
} else {
|
} else {
|
||||||
false
|
binding.widgetBg.setImageDrawable(null)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Glance error indicator
|
viewModel.fragmentScrollY.observe(viewLifecycleOwner) {
|
||||||
tabs?.getTabAt(4)?.orCreateBadge?.apply {
|
binding.toolbar.cardElevation = if (it > 0) 32f else 0f
|
||||||
backgroundColor = ContextCompat.getColor(requireContext(), R.color.errorColorText)
|
}
|
||||||
badgeGravity = BadgeDrawable.TOP_END
|
|
||||||
}?.isVisible = ((Preferences.showMusic || Preferences.showNotifications) && !ActiveNotificationsHelper.checkNotificationAccess(requireContext())) ||
|
viewModel.showPreview.observe(viewLifecycleOwner) {
|
||||||
(Preferences.showDailySteps && !(Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || requireActivity().checkGrantedPermission(Manifest.permission.ACTIVITY_RECOGNITION))) ||
|
binding.preview.isVisible = it
|
||||||
(AlarmHelper.isAlarmProbablyWrong(requireContext())) ||
|
}
|
||||||
(Preferences.showEventsAsGlanceProvider && (!Preferences.showEvents || !requireContext().checkGrantedPermission(Manifest.permission.READ_CALENDAR)))
|
|
||||||
|
viewModel.widgetPreferencesUpdate.observe(viewLifecycleOwner) {
|
||||||
|
onUpdateUiEvent(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var uiJob: Job? = null
|
||||||
|
|
||||||
|
private fun updateUI() {
|
||||||
|
if (Preferences.showPreview) {
|
||||||
|
WidgetHelper.runWithCustomTypeface(requireContext()) { typeface ->
|
||||||
|
uiJob?.cancel()
|
||||||
|
uiJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
val generatedView = MainWidget.getWidgetView(
|
||||||
|
requireContext(),
|
||||||
|
binding.widget.width - binding.widget.paddingStart - binding.widget.paddingEnd,
|
||||||
|
typeface
|
||||||
|
)
|
||||||
|
|
||||||
|
if (generatedView != null) {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
val view: View = generatedView.apply(requireActivity().applicationContext, binding.widget)
|
||||||
|
view.measure(0, 0)
|
||||||
|
|
||||||
|
binding.widgetLoader.animate().alpha(0f).setDuration(200L).start()
|
||||||
|
binding.widget.animate().alpha(0f).setDuration(200L).withEndAction {
|
||||||
|
updatePreviewVisibility(view.measuredHeight)
|
||||||
|
binding.widget.removeAllViews()
|
||||||
|
binding.widget.addView(view)
|
||||||
|
|
||||||
|
binding.widget.animate().setStartDelay(300L).alpha(1f).start()
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updatePreviewVisibility(widgetHeight: Int) {
|
||||||
|
if (isAdded) {
|
||||||
|
val newHeight = widgetHeight + 32f.convertDpToPixel(requireContext()).toInt()
|
||||||
|
if (binding.preview.layoutParams.height != newHeight) {
|
||||||
|
binding.preview.clearAnimation()
|
||||||
|
ValueAnimator.ofInt(
|
||||||
|
binding.preview.height,
|
||||||
|
newHeight
|
||||||
|
).apply {
|
||||||
|
duration = 300L
|
||||||
|
addUpdateListener {
|
||||||
|
val animatedValue = animatedValue as Int
|
||||||
|
val layoutParams = binding.preview.layoutParams
|
||||||
|
layoutParams.height = animatedValue
|
||||||
|
binding.preview.layoutParams = layoutParams
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
Preferences.preferences.registerOnSharedPreferenceChangeListener(this)
|
|
||||||
EventBus.getDefault().register(this)
|
EventBus.getDefault().register(this)
|
||||||
showErrorBadge()
|
// updateUI()
|
||||||
updateUI()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
Preferences.preferences.unregisterOnSharedPreferenceChangeListener(this)
|
|
||||||
EventBus.getDefault().unregister(this)
|
EventBus.getDefault().unregister(this)
|
||||||
super.onPause()
|
super.onPause()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var delayJob: Job? = null
|
private var delayJob: Job? = null
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(preferences: SharedPreferences, p1: String) {
|
|
||||||
delayJob?.cancel()
|
|
||||||
delayJob = lifecycleScope.launch(Dispatchers.IO) {
|
|
||||||
delay(200)
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
updateUI()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MainWidget.updateWidget(requireContext())
|
|
||||||
}
|
|
||||||
|
|
||||||
class UpdateUiMessageEvent
|
class UpdateUiMessageEvent
|
||||||
class ChangeTabEvent(val page: Int)
|
class ChangeTabEvent(val page: Int)
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun onMessageEvent(ignore: UpdateUiMessageEvent?) {
|
fun onUpdateUiEvent(@Suppress("UNUSED_PARAMETER") ignore: UpdateUiMessageEvent?) {
|
||||||
delayJob?.cancel()
|
delayJob?.cancel()
|
||||||
delayJob = lifecycleScope.launch(Dispatchers.IO) {
|
delayJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||||
delay(200)
|
delay(300)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
updateUI()
|
updateUI()
|
||||||
}
|
}
|
||||||
@ -411,9 +234,8 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun onMessageEvent(event: ChangeTabEvent?) {
|
fun onChangeTabEvent(@Suppress("UNUSED_PARAMETER") ignore: ChangeTabEvent) {
|
||||||
event?.let {
|
val navHost = childFragmentManager.findFragmentById(R.id.settings_fragment) as? NavHostFragment?
|
||||||
pager.setCurrentItem(event.page, true)
|
navHost?.navController?.navigateUp()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import android.Manifest
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@ -15,6 +14,7 @@ import androidx.lifecycle.Observer
|
|||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.Navigation
|
import androidx.navigation.Navigation
|
||||||
|
import androidx.transition.TransitionInflater
|
||||||
import com.google.android.material.transition.MaterialSharedAxis
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
import com.karumi.dexter.Dexter
|
import com.karumi.dexter.Dexter
|
||||||
import com.karumi.dexter.MultiplePermissionsReport
|
import com.karumi.dexter.MultiplePermissionsReport
|
||||||
@ -24,19 +24,21 @@ import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
|||||||
import com.tommasoberlose.anotherwidget.BuildConfig
|
import com.tommasoberlose.anotherwidget.BuildConfig
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||||
import com.tommasoberlose.anotherwidget.databinding.FragmentSettingsBinding
|
import com.tommasoberlose.anotherwidget.databinding.FragmentAppSettingsBinding
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.SupportDevActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
||||||
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||||
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.IntegrationsActivity
|
import com.tommasoberlose.anotherwidget.ui.activities.settings.IntegrationsActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.settings.SupportDevActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.ignoreExceptions
|
||||||
import com.tommasoberlose.anotherwidget.utils.openURI
|
import com.tommasoberlose.anotherwidget.utils.openURI
|
||||||
import kotlinx.android.synthetic.main.fragment_settings.*
|
import com.tommasoberlose.anotherwidget.utils.setOnSingleClickListener
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@ -48,20 +50,22 @@ class SettingsFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var viewModel: MainViewModel
|
private lateinit var viewModel: MainViewModel
|
||||||
|
private lateinit var binding: FragmentAppSettingsBinding
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
// sharedElementEnterTransition = TransitionInflater.from(context).inflateTransition(android.R.transition.move)
|
||||||
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
enterTransition = MaterialSharedAxis(MaterialSharedAxis.Y, true)
|
||||||
|
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Y, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?,
|
||||||
): View {
|
): View {
|
||||||
|
|
||||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||||
val binding = DataBindingUtil.inflate<FragmentSettingsBinding>(inflater, R.layout.fragment_settings, container, false)
|
binding = FragmentAppSettingsBinding.inflate(inflater)
|
||||||
|
|
||||||
binding.lifecycleOwner = this
|
binding.lifecycleOwner = this
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
@ -74,25 +78,29 @@ class SettingsFragment : Fragment() {
|
|||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
action_back.setOnClickListener {
|
binding.actionBack.setOnSingleClickListener {
|
||||||
Navigation.findNavController(it).popBackStack()
|
Navigation.findNavController(it).popBackStack()
|
||||||
}
|
}
|
||||||
|
|
||||||
show_widget_preview_toggle.isChecked = Preferences.showPreview
|
binding.showWidgetPreviewToggle.setCheckedImmediatelyNoEvent(Preferences.showPreview)
|
||||||
show_wallpaper_toggle.isChecked = Preferences.showWallpaper
|
binding.showWallpaperToggle.setCheckedImmediatelyNoEvent(Preferences.showWallpaper)
|
||||||
|
|
||||||
setupListener()
|
setupListener()
|
||||||
|
|
||||||
app_version.text = "v%s (%s)".format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)
|
binding.appVersion.text = "v%s (%s)".format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)
|
||||||
|
|
||||||
|
binding.scrollView.viewTreeObserver.addOnScrollChangedListener {
|
||||||
|
binding.toolbar.cardElevation = if (binding.scrollView.scrollY > 0) 32f else 0f
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun subscribeUi(
|
private fun subscribeUi(
|
||||||
viewModel: MainViewModel
|
viewModel: MainViewModel,
|
||||||
) {
|
) {
|
||||||
viewModel.darkThemePreference.observe(viewLifecycleOwner, Observer {
|
viewModel.darkThemePreference.observe(viewLifecycleOwner) {
|
||||||
AppCompatDelegate.setDefaultNightMode(it)
|
AppCompatDelegate.setDefaultNightMode(it)
|
||||||
maintainScrollPosition {
|
maintainScrollPosition {
|
||||||
theme?.text = when (it) {
|
binding.theme.text = when (it) {
|
||||||
AppCompatDelegate.MODE_NIGHT_NO -> getString(R.string.settings_subtitle_dark_theme_light)
|
AppCompatDelegate.MODE_NIGHT_NO -> getString(R.string.settings_subtitle_dark_theme_light)
|
||||||
AppCompatDelegate.MODE_NIGHT_YES -> getString(R.string.settings_subtitle_dark_theme_dark)
|
AppCompatDelegate.MODE_NIGHT_YES -> getString(R.string.settings_subtitle_dark_theme_dark)
|
||||||
AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY -> getString(R.string.settings_subtitle_dark_theme_by_battery_saver)
|
AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY -> getString(R.string.settings_subtitle_dark_theme_by_battery_saver)
|
||||||
@ -100,43 +108,45 @@ class SettingsFragment : Fragment() {
|
|||||||
else -> ""
|
else -> ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
viewModel.installedIntegrations.observe(viewLifecycleOwner, Observer {
|
viewModel.installedIntegrations.observe(viewLifecycleOwner) {
|
||||||
integrations_count_label?.text = getString(R.string.label_count_installed_integrations).format(it)
|
binding.integrationsCountLabel.text =
|
||||||
})
|
getString(R.string.label_count_installed_integrations).format(
|
||||||
|
it)
|
||||||
|
}
|
||||||
|
|
||||||
viewModel.showPreview.observe(viewLifecycleOwner, Observer {
|
viewModel.showPreview.observe(viewLifecycleOwner) {
|
||||||
maintainScrollPosition {
|
maintainScrollPosition {
|
||||||
show_widget_preview_label?.text =
|
binding.showWidgetPreviewLabel.text =
|
||||||
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
viewModel.showWallpaper.observe(viewLifecycleOwner, Observer {
|
viewModel.showWallpaper.observe(viewLifecycleOwner) {
|
||||||
maintainScrollPosition {
|
maintainScrollPosition {
|
||||||
show_wallpaper_label?.text =
|
binding.showWallpaperLabel.text =
|
||||||
if (it && activity?.checkGrantedPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == true) getString(
|
if (it && requireActivity().checkGrantedPermission(Manifest.permission.READ_EXTERNAL_STORAGE)) getString(
|
||||||
R.string.settings_visible
|
R.string.settings_visible
|
||||||
) else getString(R.string.settings_not_visible)
|
) else getString(R.string.settings_not_visible)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupListener() {
|
private fun setupListener() {
|
||||||
action_show_widget_preview.setOnClickListener {
|
binding.actionShowWidgetPreview.setOnClickListener {
|
||||||
show_widget_preview_toggle.isChecked = !show_widget_preview_toggle.isChecked
|
binding.showWidgetPreviewToggle.isChecked = !binding.showWidgetPreviewToggle.isChecked
|
||||||
}
|
}
|
||||||
|
|
||||||
show_widget_preview_toggle.setOnCheckedChangeListener { _, isChecked ->
|
binding.showWidgetPreviewToggle.setOnCheckedChangeListener { _, isChecked ->
|
||||||
Preferences.showPreview = isChecked
|
Preferences.showPreview = isChecked
|
||||||
}
|
}
|
||||||
|
|
||||||
action_show_wallpaper.setOnClickListener {
|
binding.actionShowWallpaper.setOnClickListener {
|
||||||
show_wallpaper_toggle.isChecked = !show_wallpaper_toggle.isChecked
|
binding.showWallpaperToggle.isChecked = !binding.showWallpaperToggle.isChecked
|
||||||
}
|
}
|
||||||
|
|
||||||
show_wallpaper_toggle.setOnCheckedChangeListener { _, isChecked ->
|
binding.showWallpaperToggle.setOnCheckedChangeListener { _, isChecked ->
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
requirePermission()
|
requirePermission()
|
||||||
} else {
|
} else {
|
||||||
@ -144,13 +154,14 @@ class SettingsFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
action_integrations.setOnClickListener {
|
binding.actionIntegrations.setOnClickListener {
|
||||||
startActivity(Intent(requireContext(), IntegrationsActivity::class.java))
|
startActivity(Intent(requireContext(), IntegrationsActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
action_change_theme.setOnClickListener {
|
binding.actionChangeTheme.setOnClickListener {
|
||||||
maintainScrollPosition {
|
maintainScrollPosition {
|
||||||
BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_theme_title))
|
BottomSheetMenu<Int>(requireContext(),
|
||||||
|
header = getString(R.string.settings_theme_title))
|
||||||
.setSelectedValue(Preferences.darkThemePreference)
|
.setSelectedValue(Preferences.darkThemePreference)
|
||||||
.addItem(
|
.addItem(
|
||||||
getString(R.string.settings_subtitle_dark_theme_light),
|
getString(R.string.settings_subtitle_dark_theme_light),
|
||||||
@ -170,45 +181,58 @@ class SettingsFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
action_translate.setOnClickListener {
|
binding.actionTranslate.setOnClickListener {
|
||||||
activity?.openURI("https://github.com/tommasoberlose/another-widget/blob/master/app/src/main/res/values/strings.xml")
|
requireActivity().openURI("https://github.com/tommasoberlose/another-widget/blob/master/app/src/main/res/values/strings.xml")
|
||||||
}
|
}
|
||||||
|
|
||||||
action_website.setOnClickListener {
|
binding.actionWebsite.setOnClickListener {
|
||||||
activity?.openURI("http://tommasoberlose.com/")
|
requireActivity().openURI("http://tommasoberlose.com/")
|
||||||
}
|
}
|
||||||
|
|
||||||
action_feedback.setOnClickListener {
|
binding.actionFeedback.setOnClickListener {
|
||||||
activity?.openURI("https://github.com/tommasoberlose/another-widget/issues")
|
requireActivity().openURI("https://github.com/tommasoberlose/another-widget/issues")
|
||||||
}
|
}
|
||||||
|
|
||||||
action_privacy_policy.setOnClickListener {
|
binding.actionPrivacyPolicy.setOnClickListener {
|
||||||
activity?.openURI("https://github.com/tommasoberlose/another-widget/blob/master/privacy-policy.md")
|
requireActivity().openURI("https://github.com/tommasoberlose/another-widget/blob/master/privacy-policy.md")
|
||||||
}
|
}
|
||||||
|
|
||||||
action_help_dev.setOnClickListener {
|
binding.actionHelpDev.setOnClickListener {
|
||||||
startActivity(Intent(requireContext(), SupportDevActivity::class.java))
|
startActivity(Intent(requireContext(), SupportDevActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
action_refresh_widget.setOnClickListener {
|
binding.actionRefreshWidget.setOnClickListener {
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
binding.actionRefreshIcon
|
||||||
|
.animate()
|
||||||
|
.rotation((binding.actionRefreshIcon.rotation - binding.actionRefreshIcon.rotation % 360f) + 360f)
|
||||||
|
.withEndAction {
|
||||||
|
try {
|
||||||
WeatherHelper.updateWeather(requireContext())
|
WeatherHelper.updateWeather(requireContext())
|
||||||
}
|
|
||||||
CalendarHelper.updateEventList(requireContext())
|
CalendarHelper.updateEventList(requireContext())
|
||||||
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
|
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
|
||||||
ActiveNotificationsHelper.clearLastNotification(requireContext())
|
ActiveNotificationsHelper.clearLastNotification(requireContext())
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
ex.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||||
scrollView.isScrollable = false
|
binding.scrollView.isScrollable = false
|
||||||
callback.invoke()
|
callback.invoke()
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
delay(200)
|
delay(200)
|
||||||
scrollView.isScrollable = true
|
binding.scrollView.isScrollable = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
binding.showWallpaperToggle.setCheckedNoEvent(Preferences.showWallpaper && requireActivity().checkGrantedPermission(Manifest.permission.READ_EXTERNAL_STORAGE))
|
||||||
|
}
|
||||||
|
|
||||||
private fun requirePermission() {
|
private fun requirePermission() {
|
||||||
Dexter.withContext(requireContext())
|
Dexter.withContext(requireContext())
|
||||||
.withPermissions(
|
.withPermissions(
|
||||||
@ -219,13 +243,14 @@ class SettingsFragment : Fragment() {
|
|||||||
if (report.areAllPermissionsGranted()) {
|
if (report.areAllPermissionsGranted()) {
|
||||||
Preferences.showWallpaper = true
|
Preferences.showWallpaper = true
|
||||||
} else {
|
} else {
|
||||||
show_wallpaper_toggle?.isChecked = false
|
binding.showWallpaperToggle.setCheckedNoEvent(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPermissionRationaleShouldBeShown(
|
override fun onPermissionRationaleShouldBeShown(
|
||||||
permissions: MutableList<PermissionRequest>?,
|
permissions: MutableList<PermissionRequest>?,
|
||||||
token: PermissionToken?
|
token: PermissionToken?,
|
||||||
) {
|
) {
|
||||||
// Remember to invoke this method when the custom rationale is closed
|
// Remember to invoke this method when the custom rationale is closed
|
||||||
// or just by default if you don't want to use any custom rationale.
|
// or just by default if you don't want to use any custom rationale.
|
||||||
|
@ -1,326 +0,0 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.fragments
|
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.util.Log
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.os.BuildCompat
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.databinding.DataBindingUtil
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.lifecycle.Observer
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import com.chibatching.kotpref.bulk
|
|
||||||
import com.karumi.dexter.Dexter
|
|
||||||
import com.karumi.dexter.MultiplePermissionsReport
|
|
||||||
import com.karumi.dexter.PermissionToken
|
|
||||||
import com.karumi.dexter.listener.PermissionRequest
|
|
||||||
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
|
||||||
import com.tommasoberlose.anotherwidget.R
|
|
||||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
|
||||||
import com.tommasoberlose.anotherwidget.components.IconPackSelector
|
|
||||||
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
|
|
||||||
import com.tommasoberlose.anotherwidget.databinding.FragmentWeatherSettingsBinding
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Constants
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
|
||||||
import com.tommasoberlose.anotherwidget.global.RequestCode
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.CustomLocationActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.WeatherProviderActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.collapse
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.expand
|
|
||||||
import kotlinx.android.synthetic.main.fragment_weather_settings.*
|
|
||||||
import kotlinx.android.synthetic.main.fragment_weather_settings.scrollView
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
class WeatherTabFragment : Fragment() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun newInstance() = WeatherTabFragment()
|
|
||||||
}
|
|
||||||
|
|
||||||
private lateinit var viewModel: MainViewModel
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View {
|
|
||||||
|
|
||||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
|
||||||
val binding = DataBindingUtil.inflate<FragmentWeatherSettingsBinding>(inflater, R.layout.fragment_weather_settings, container, false)
|
|
||||||
|
|
||||||
subscribeUi(binding, viewModel)
|
|
||||||
|
|
||||||
binding.lifecycleOwner = this
|
|
||||||
binding.viewModel = viewModel
|
|
||||||
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
|
||||||
super.onActivityCreated(savedInstanceState)
|
|
||||||
|
|
||||||
setupListener()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun subscribeUi(
|
|
||||||
binding: FragmentWeatherSettingsBinding,
|
|
||||||
viewModel: MainViewModel
|
|
||||||
) {
|
|
||||||
binding.isWeatherVisible = Preferences.showWeather
|
|
||||||
|
|
||||||
viewModel.showWeather.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
show_weather_label?.text =
|
|
||||||
if (it) getString(R.string.show_weather_visible) else getString(R.string.show_weather_not_visible)
|
|
||||||
checkWeatherProviderConfig()
|
|
||||||
binding.isWeatherVisible = it
|
|
||||||
}
|
|
||||||
checkLocationPermission()
|
|
||||||
checkWeatherProviderConfig()
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.weatherProvider.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
label_weather_provider.text = WeatherHelper.getProviderName(requireContext(), Constants.WeatherProvider.fromInt(it)!!)
|
|
||||||
checkWeatherProviderConfig()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.weatherProviderError.observe(viewLifecycleOwner, Observer {
|
|
||||||
checkWeatherProviderConfig()
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.weatherProviderLocationError.observe(viewLifecycleOwner, Observer {
|
|
||||||
checkWeatherProviderConfig()
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.customLocationAdd.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
background_location_warning.isVisible = it == ""
|
|
||||||
label_custom_location?.text =
|
|
||||||
if (it == "") getString(R.string.custom_location_gps) else it
|
|
||||||
}
|
|
||||||
checkLocationPermission()
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.weatherTempUnit.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
temp_unit?.text =
|
|
||||||
if (it == "F") getString(R.string.fahrenheit) else getString(R.string.celsius)
|
|
||||||
}
|
|
||||||
checkLocationPermission()
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.weatherRefreshPeriod.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
label_weather_refresh_period?.text = getString(SettingsStringHelper.getRefreshPeriodString(it))
|
|
||||||
}
|
|
||||||
checkLocationPermission()
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.weatherIconPack.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
label_weather_icon_pack?.text = getString(R.string.settings_weather_icon_pack_default).format((it + 1))
|
|
||||||
// weather_icon_pack.setImageDrawable(ContextCompat.getDrawable(requireContext(), WeatherHelper.getWeatherIconResource("02d")))
|
|
||||||
// if (it == Constants.WeatherIconPack.MINIMAL.value) {
|
|
||||||
// weather_icon_pack.setColorFilter(ContextCompat.getColor(requireContext(), R.color.colorPrimaryText))
|
|
||||||
// } else {
|
|
||||||
// weather_icon_pack.setColorFilter(ContextCompat.getColor(requireContext(), android.R.color.transparent))
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
checkLocationPermission()
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.weatherAppName.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
weather_app_label?.text =
|
|
||||||
if (it != "") it else getString(R.string.default_weather_app)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkLocationPermission() {
|
|
||||||
if (requireActivity().checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION)) {
|
|
||||||
location_permission_alert?.isVisible = false
|
|
||||||
background_location_warning.isVisible = Preferences.customLocationAdd == ""
|
|
||||||
WeatherReceiver.setUpdates(requireContext())
|
|
||||||
} else if (Preferences.showWeather && Preferences.customLocationAdd == "") {
|
|
||||||
location_permission_alert?.isVisible = true
|
|
||||||
background_location_warning.isVisible = true
|
|
||||||
location_permission_alert?.setOnClickListener {
|
|
||||||
MaterialBottomSheetDialog(requireContext(), message = getString(R.string.background_location_warning))
|
|
||||||
.setPositiveButton(getString(android.R.string.ok)) {
|
|
||||||
requirePermission()
|
|
||||||
}
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
location_permission_alert?.isVisible = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkWeatherProviderConfig() {
|
|
||||||
if (Preferences.showWeather && Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-" && !location_permission_alert.isVisible) {
|
|
||||||
weather_provider_error.expand()
|
|
||||||
} else {
|
|
||||||
weather_provider_error.collapse()
|
|
||||||
}
|
|
||||||
weather_provider_error?.text = Preferences.weatherProviderError
|
|
||||||
|
|
||||||
if (Preferences.showWeather && Preferences.weatherProviderLocationError != "" && !location_permission_alert.isVisible) {
|
|
||||||
weather_provider_location_error.expand()
|
|
||||||
} else {
|
|
||||||
weather_provider_location_error.collapse()
|
|
||||||
}
|
|
||||||
weather_provider_location_error?.text = Preferences.weatherProviderLocationError
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupListener() {
|
|
||||||
action_show_weather.setOnClickListener {
|
|
||||||
Preferences.showWeather = !Preferences.showWeather
|
|
||||||
}
|
|
||||||
|
|
||||||
show_weather_switch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
|
||||||
Preferences.showWeather = enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
action_weather_provider.setOnClickListener {
|
|
||||||
if (Preferences.showWeather) {
|
|
||||||
startActivityForResult(
|
|
||||||
Intent(requireContext(), WeatherProviderActivity::class.java),
|
|
||||||
RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_custom_location.setOnClickListener {
|
|
||||||
if (Preferences.showWeather) {
|
|
||||||
startActivityForResult(
|
|
||||||
Intent(requireContext(), CustomLocationActivity::class.java),
|
|
||||||
Constants.RESULT_CODE_CUSTOM_LOCATION
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_change_unit.setOnClickListener {
|
|
||||||
if (Preferences.showWeather) {
|
|
||||||
BottomSheetMenu<String>(requireContext(), header = getString(R.string.settings_unit_title)).setSelectedValue(Preferences.weatherTempUnit)
|
|
||||||
.addItem(getString(R.string.fahrenheit), "F")
|
|
||||||
.addItem(getString(R.string.celsius), "C")
|
|
||||||
.addOnSelectItemListener { value ->
|
|
||||||
if (value != Preferences.weatherTempUnit) {
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
|
||||||
WeatherHelper.updateWeather(requireContext())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Preferences.weatherTempUnit = value
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_weather_refresh_period.setOnClickListener {
|
|
||||||
if (Preferences.showWeather) {
|
|
||||||
val dialog =
|
|
||||||
BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_weather_refresh_period_title)).setSelectedValue(Preferences.weatherRefreshPeriod)
|
|
||||||
(5 downTo 0).forEach {
|
|
||||||
dialog.addItem(getString(SettingsStringHelper.getRefreshPeriodString(it)), it)
|
|
||||||
}
|
|
||||||
dialog
|
|
||||||
.addOnSelectItemListener { value ->
|
|
||||||
Preferences.weatherRefreshPeriod = value
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_weather_icon_pack.setOnClickListener {
|
|
||||||
if (Preferences.showWeather) {
|
|
||||||
IconPackSelector(requireContext(), header = getString(R.string.settings_weather_icon_pack_title)).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_weather_app.setOnClickListener {
|
|
||||||
if (Preferences.showWeather) {
|
|
||||||
startActivityForResult(
|
|
||||||
Intent(requireContext(), ChooseApplicationActivity::class.java),
|
|
||||||
RequestCode.WEATHER_APP_REQUEST_CODE.code
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
|
||||||
when (requestCode) {
|
|
||||||
Constants.RESULT_CODE_CUSTOM_LOCATION -> {
|
|
||||||
WeatherReceiver.setUpdates(requireContext())
|
|
||||||
checkLocationPermission()
|
|
||||||
}
|
|
||||||
RequestCode.WEATHER_APP_REQUEST_CODE.code -> {
|
|
||||||
Preferences.bulk {
|
|
||||||
weatherAppName = data?.getStringExtra(Constants.RESULT_APP_NAME) ?: getString(R.string.default_weather_app)
|
|
||||||
weatherAppPackage = data?.getStringExtra(Constants.RESULT_APP_PACKAGE) ?: ""
|
|
||||||
}
|
|
||||||
MainWidget.updateWidget(requireContext())
|
|
||||||
}
|
|
||||||
RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code -> {
|
|
||||||
checkLocationPermission()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun requirePermission() {
|
|
||||||
Dexter.withContext(requireContext())
|
|
||||||
.withPermissions(
|
|
||||||
Manifest.permission.ACCESS_FINE_LOCATION
|
|
||||||
).withListener(object: MultiplePermissionsListener {
|
|
||||||
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
|
||||||
report?.let {
|
|
||||||
if (report.areAllPermissionsGranted()){
|
|
||||||
checkLocationPermission()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
override fun onPermissionRationaleShouldBeShown(
|
|
||||||
permissions: MutableList<PermissionRequest>?,
|
|
||||||
token: PermissionToken?
|
|
||||||
) {
|
|
||||||
// Remember to invoke this method when the custom rationale is closed
|
|
||||||
// or just by default if you don't want to use any custom rationale.
|
|
||||||
token?.continuePermissionRequest()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.check()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
|
||||||
scrollView.isScrollable = false
|
|
||||||
callback.invoke()
|
|
||||||
lifecycleScope.launch {
|
|
||||||
delay(200)
|
|
||||||
scrollView.isScrollable = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,299 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.fragments.tabs
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.provider.CalendarContract
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||||
|
import com.tommasoberlose.anotherwidget.models.CalendarSelector
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.FragmentTabCalendarBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.toast
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class CalendarFragment : Fragment() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance() = CalendarFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var viewModel: MainViewModel
|
||||||
|
private lateinit var binding: FragmentTabCalendarBinding
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||||
|
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||||
|
binding = FragmentTabCalendarBinding.inflate(inflater)
|
||||||
|
|
||||||
|
subscribeUi(viewModel)
|
||||||
|
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
|
binding.showAllDayToggle.setCheckedImmediatelyNoEvent(Preferences.calendarAllDay)
|
||||||
|
binding.showOnlyBusyEventsToggle.setCheckedImmediatelyNoEvent(Preferences.showOnlyBusyEvents)
|
||||||
|
binding.showDiffTimeToggle.setCheckedImmediatelyNoEvent(Preferences.showDiffTime)
|
||||||
|
binding.showNextEventOnMultipleLinesToggle.setCheckedImmediatelyNoEvent(Preferences.showNextEventOnMultipleLines)
|
||||||
|
|
||||||
|
setupListener()
|
||||||
|
|
||||||
|
binding.scrollView.viewTreeObserver.addOnScrollChangedListener {
|
||||||
|
viewModel.fragmentScrollY.value = binding.scrollView.scrollY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun subscribeUi(
|
||||||
|
viewModel: MainViewModel
|
||||||
|
) {
|
||||||
|
binding.isCalendarEnabled = Preferences.showEvents
|
||||||
|
binding.isDiffEnabled = Preferences.showDiffTime
|
||||||
|
|
||||||
|
viewModel.calendarAllDay.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.allDayLabel.text =
|
||||||
|
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.secondRowInformation.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.secondRowInfoLabel.text = getString(SettingsStringHelper.getSecondRowInfoString(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.showNextEventOnMultipleLines.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.showNextEventOnMultipleLinesLabel.text = if (it) getString(R.string.settings_enabled) else getString(R.string.settings_disabled)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.showDiffTime.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.showDiffTimeLabel.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||||
|
binding.isDiffEnabled = it || !Preferences.showEvents
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.widgetUpdateFrequency.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.widgetUpdateFrequencyLabel.text = when (it) {
|
||||||
|
Constants.WidgetUpdateFrequency.HIGH.rawValue -> getString(R.string.settings_widget_update_frequency_high)
|
||||||
|
Constants.WidgetUpdateFrequency.DEFAULT.rawValue -> getString(R.string.settings_widget_update_frequency_default)
|
||||||
|
Constants.WidgetUpdateFrequency.LOW.rawValue -> getString(R.string.settings_widget_update_frequency_low)
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.showUntil.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.showUntilLabel.text = getString(SettingsStringHelper.getShowUntilString(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListener() {
|
||||||
|
|
||||||
|
binding.actionFilterCalendar.setOnClickListener {
|
||||||
|
val calendarSelectorList: List<CalendarSelector> = CalendarHelper.getCalendarList(requireContext()).map {
|
||||||
|
CalendarSelector(
|
||||||
|
it.id,
|
||||||
|
it.displayName,
|
||||||
|
it.accountName
|
||||||
|
)
|
||||||
|
}.sortedWith { cal1, cal2 ->
|
||||||
|
when {
|
||||||
|
cal1.accountName != cal2.accountName -> {
|
||||||
|
cal1.accountName.compareTo(cal2.accountName)
|
||||||
|
}
|
||||||
|
cal1.accountName == cal1.name -> {
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
cal2.accountName == cal2.name -> {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
cal1.name.compareTo(cal2.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (calendarSelectorList.isNotEmpty()) {
|
||||||
|
val filteredCalendarIds = CalendarHelper.getFilteredCalendarIdList()
|
||||||
|
val visibleCalendarIds = calendarSelectorList.map { it.id }.filter { id: Long -> !filteredCalendarIds.contains(id) }
|
||||||
|
|
||||||
|
val dialog = BottomSheetMenu<Long>(requireContext(), header = getString(R.string.settings_filter_calendar_subtitle), isMultiSelection = true)
|
||||||
|
.setSelectedValues(visibleCalendarIds)
|
||||||
|
|
||||||
|
calendarSelectorList.indices.forEach { index ->
|
||||||
|
if (index == 0 || calendarSelectorList[index].accountName != calendarSelectorList[index - 1].accountName) {
|
||||||
|
dialog.addItem(calendarSelectorList[index].accountName)
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.addItem(
|
||||||
|
if (calendarSelectorList[index].name == calendarSelectorList[index].accountName) getString(R.string.main_calendar) else calendarSelectorList[index].name,
|
||||||
|
calendarSelectorList[index].id
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.addOnMultipleSelectItemListener { values ->
|
||||||
|
CalendarHelper.filterCalendar(calendarSelectorList.map { it.id }.filter { !values.contains(it) })
|
||||||
|
updateCalendar()
|
||||||
|
}.show()
|
||||||
|
} else {
|
||||||
|
requireActivity().toast(getString(R.string.calendar_settings_list_error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionShowAllDay.setOnClickListener {
|
||||||
|
binding.showAllDayToggle.isChecked = !binding.showAllDayToggle.isChecked
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.showAllDayToggle.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
Preferences.calendarAllDay = isChecked
|
||||||
|
updateCalendar()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionChangeAttendeeFilter.setOnClickListener {
|
||||||
|
val selectedValues = emptyList<Int>().toMutableList()
|
||||||
|
if (Preferences.showDeclinedEvents) {
|
||||||
|
selectedValues.add(CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED)
|
||||||
|
}
|
||||||
|
if (Preferences.showInvitedEvents) {
|
||||||
|
selectedValues.add(CalendarContract.Attendees.ATTENDEE_STATUS_INVITED)
|
||||||
|
}
|
||||||
|
if (Preferences.showAcceptedEvents) {
|
||||||
|
selectedValues.add(CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED)
|
||||||
|
}
|
||||||
|
|
||||||
|
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_attendee_status_title), isMultiSelection = true)
|
||||||
|
.setSelectedValues(selectedValues)
|
||||||
|
|
||||||
|
dialog.addItem(
|
||||||
|
getString(R.string.attendee_status_invited),
|
||||||
|
CalendarContract.Attendees.ATTENDEE_STATUS_INVITED
|
||||||
|
)
|
||||||
|
dialog.addItem(
|
||||||
|
getString(R.string.attendee_status_accepted),
|
||||||
|
CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED
|
||||||
|
)
|
||||||
|
dialog.addItem(
|
||||||
|
getString(R.string.attendee_status_declined),
|
||||||
|
CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED
|
||||||
|
)
|
||||||
|
|
||||||
|
dialog.addOnMultipleSelectItemListener { values ->
|
||||||
|
Preferences.showDeclinedEvents = values.contains(CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED)
|
||||||
|
Preferences.showAcceptedEvents = values.contains(CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED)
|
||||||
|
Preferences.showInvitedEvents = values.contains(CalendarContract.Attendees.ATTENDEE_STATUS_INVITED)
|
||||||
|
updateCalendar()
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionShowOnlyBusyEvents.setOnClickListener {
|
||||||
|
binding.showOnlyBusyEventsToggle.isChecked = !binding.showOnlyBusyEventsToggle.isChecked
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.showOnlyBusyEventsToggle.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
Preferences.showOnlyBusyEvents = isChecked
|
||||||
|
updateCalendar()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionShowDiffTime.setOnClickListener {
|
||||||
|
binding.showDiffTimeToggle.isChecked = !binding.showDiffTimeToggle.isChecked
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.showDiffTimeToggle.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
Preferences.showDiffTime = isChecked
|
||||||
|
updateCalendar()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionShowNextEventOnMultipleLines.setOnClickListener {
|
||||||
|
binding.showNextEventOnMultipleLinesToggle.isChecked = !binding.showNextEventOnMultipleLinesToggle.isChecked
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.showNextEventOnMultipleLinesToggle.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
Preferences.showNextEventOnMultipleLines = isChecked
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionWidgetUpdateFrequency.setOnClickListener {
|
||||||
|
if (Preferences.showEvents && Preferences.showDiffTime) {
|
||||||
|
BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_widget_update_frequency_title), message = getString(R.string.settings_widget_update_frequency_subtitle)).setSelectedValue(Preferences.widgetUpdateFrequency)
|
||||||
|
.addItem(getString(R.string.settings_widget_update_frequency_high), Constants.WidgetUpdateFrequency.HIGH.rawValue)
|
||||||
|
.addItem(getString(R.string.settings_widget_update_frequency_default), Constants.WidgetUpdateFrequency.DEFAULT.rawValue)
|
||||||
|
.addItem(getString(R.string.settings_widget_update_frequency_low), Constants.WidgetUpdateFrequency.LOW.rawValue)
|
||||||
|
.addOnSelectItemListener { value ->
|
||||||
|
Preferences.widgetUpdateFrequency = value
|
||||||
|
updateCalendar()
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionSecondRowInfo.setOnClickListener {
|
||||||
|
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_second_row_info_title)).setSelectedValue(Preferences.secondRowInformation)
|
||||||
|
(0 .. 1).forEach {
|
||||||
|
dialog.addItem(getString(SettingsStringHelper.getSecondRowInfoString(it)), it)
|
||||||
|
}
|
||||||
|
dialog.addOnSelectItemListener { value ->
|
||||||
|
Preferences.secondRowInformation = value
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionShowUntil.setOnClickListener {
|
||||||
|
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_show_until_title)).setSelectedValue(Preferences.showUntil)
|
||||||
|
intArrayOf(6,7,0,1,2,3, 4, 5).forEach {
|
||||||
|
dialog.addItem(getString(SettingsStringHelper.getShowUntilString(it)), it)
|
||||||
|
}
|
||||||
|
dialog.addOnSelectItemListener { value ->
|
||||||
|
Preferences.showUntil = value
|
||||||
|
updateCalendar()
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateCalendar() {
|
||||||
|
if (requireActivity().checkGrantedPermission(Manifest.permission.READ_CALENDAR)) {
|
||||||
|
CalendarHelper.updateEventList(requireContext())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||||
|
binding.scrollView.isScrollable = false
|
||||||
|
callback.invoke()
|
||||||
|
lifecycleScope.launch {
|
||||||
|
delay(200)
|
||||||
|
binding.scrollView.isScrollable = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,211 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.fragments.tabs
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.text.format.DateFormat
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.databinding.DataBindingUtil
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.chibatching.kotpref.bulk
|
||||||
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker
|
||||||
|
import com.tommasoberlose.anotherwidget.components.BottomSheetPicker
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.FragmentTabClockBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.global.RequestCode
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toHexValue
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.IntentHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.tabs.ChooseApplicationActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.tabs.TimeZoneSelectorActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.isDefaultSet
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
|
||||||
|
class ClockFragment : Fragment() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance() = ClockFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var viewModel: MainViewModel
|
||||||
|
private lateinit var colors: IntArray
|
||||||
|
private lateinit var binding: FragmentTabClockBinding
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||||
|
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||||
|
binding = FragmentTabClockBinding.inflate(inflater)
|
||||||
|
|
||||||
|
subscribeUi(viewModel)
|
||||||
|
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
|
binding.ampmIndicatorToggle.setCheckedImmediatelyNoEvent(Preferences.showAMPMIndicator)
|
||||||
|
|
||||||
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
val lazyColors = requireContext().resources.getIntArray(R.array.material_colors)
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
colors = lazyColors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setupListener()
|
||||||
|
|
||||||
|
binding.scrollView.viewTreeObserver?.addOnScrollChangedListener {
|
||||||
|
viewModel.fragmentScrollY.value = binding.scrollView.scrollY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun subscribeUi(
|
||||||
|
viewModel: MainViewModel
|
||||||
|
) {
|
||||||
|
binding.isClockVisible = Preferences.showClock
|
||||||
|
binding.is24Format = DateFormat.is24HourFormat(requireContext())
|
||||||
|
binding.isDarkModeEnabled = activity?.isDarkTheme() == true
|
||||||
|
|
||||||
|
viewModel.clockTextSize.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.clockTextSizeLabel.text = String.format("%.0fsp", it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.altTimezoneLabel.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
if (it != "") {
|
||||||
|
binding.altTimezoneClockLabel.text =
|
||||||
|
String.format("%s (%s)", it, Preferences.altTimezoneId)
|
||||||
|
} else {
|
||||||
|
binding.altTimezoneClockLabel.text = getString(R.string.no_time_zone_label)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.showAMPMIndicator.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.ampmIndicatorLabel.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.clockTextColor.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
if (Preferences.clockTextAlpha == "00") {
|
||||||
|
binding.clockTextColorLabel.text = getString(R.string.transparent)
|
||||||
|
} else {
|
||||||
|
binding.clockTextColorLabel.text =
|
||||||
|
"#%s".format(Integer.toHexString(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.clockTextColorDark.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
if (Preferences.clockTextAlphaDark == "00") {
|
||||||
|
binding.clockTextColorLabel.text = getString(R.string.transparent)
|
||||||
|
} else {
|
||||||
|
binding.clockTextColorLabel.text =
|
||||||
|
"#%s".format(Integer.toHexString(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListener() {
|
||||||
|
|
||||||
|
binding.actionClockTextSize.setOnClickListener {
|
||||||
|
BottomSheetPicker(
|
||||||
|
requireContext(),
|
||||||
|
items = (120 downTo 30).filter { it % 2 == 0 }.map { BottomSheetPicker.MenuItem("${it}sp", it.toFloat()) },
|
||||||
|
getSelected = { Preferences.clockTextSize },
|
||||||
|
header = getString(R.string.settings_clock_text_size_title),
|
||||||
|
onItemSelected = {value ->
|
||||||
|
if (value != null) Preferences.clockTextSize = value
|
||||||
|
}
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionAltTimezoneClock.setOnClickListener {
|
||||||
|
startActivity(Intent(requireContext(), TimeZoneSelectorActivity::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionAmpmIndicatorSize.setOnClickListener {
|
||||||
|
binding.ampmIndicatorToggle.isChecked = !binding.ampmIndicatorToggle.isChecked
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.ampmIndicatorToggle.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
Preferences.showAMPMIndicator = isChecked
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionClockTextColor.setOnClickListener {
|
||||||
|
BottomSheetColorPicker(requireContext(),
|
||||||
|
colors = colors,
|
||||||
|
header = getString(R.string.settings_font_color_title),
|
||||||
|
getSelected = { ColorHelper.getClockFontColorRgb(activity?.isDarkTheme() == true) },
|
||||||
|
onColorSelected = { color: Int ->
|
||||||
|
val colorString = Integer.toHexString(color)
|
||||||
|
if (activity?.isDarkTheme() == true) {
|
||||||
|
Preferences.clockTextColorDark =
|
||||||
|
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||||
|
} else {
|
||||||
|
Preferences.clockTextColor =
|
||||||
|
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showAlphaSelector = true,
|
||||||
|
alpha = if (activity?.isDarkTheme() == true) Preferences.clockTextAlphaDark.toIntValue() else Preferences.clockTextAlpha.toIntValue(),
|
||||||
|
onAlphaChangeListener = { alpha ->
|
||||||
|
if (activity?.isDarkTheme() == true) {
|
||||||
|
Preferences.clockTextAlphaDark = alpha.toHexValue()
|
||||||
|
} else {
|
||||||
|
Preferences.clockTextAlpha = alpha.toHexValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
binding.is24Format = DateFormat.is24HourFormat(requireContext())
|
||||||
|
super.onResume()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||||
|
binding.scrollView.isScrollable = false
|
||||||
|
callback.invoke()
|
||||||
|
lifecycleScope.launch {
|
||||||
|
delay(200)
|
||||||
|
binding.scrollView.isScrollable = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,228 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.fragments.tabs
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.databinding.DataBindingUtil
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.chibatching.kotpref.blockingBulk
|
||||||
|
import com.chibatching.kotpref.bulk
|
||||||
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker
|
||||||
|
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.FragmentTabGesturesBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.FragmentTabLayoutBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.global.RequestCode
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toHexValue
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.DateHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.IntentHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.tabs.CustomDateActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.tabs.ChooseApplicationActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.isDefaultSet
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class GesturesFragment : Fragment() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance() = GesturesFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var viewModel: MainViewModel
|
||||||
|
private lateinit var binding: FragmentTabGesturesBinding
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||||
|
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||||
|
binding = FragmentTabGesturesBinding.inflate(inflater)
|
||||||
|
|
||||||
|
subscribeUi(viewModel)
|
||||||
|
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
|
binding.showMultipleEventsToggle.setCheckedImmediatelyNoEvent(Preferences.showNextEvent)
|
||||||
|
setupListener()
|
||||||
|
|
||||||
|
binding.scrollView.viewTreeObserver?.addOnScrollChangedListener {
|
||||||
|
viewModel.fragmentScrollY.value = binding.scrollView.scrollY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressLint("DefaultLocale")
|
||||||
|
private fun subscribeUi(
|
||||||
|
viewModel: MainViewModel
|
||||||
|
) {
|
||||||
|
|
||||||
|
viewModel.showNextEvent.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.showMultipleEventsLabel.text =
|
||||||
|
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.calendarAppName.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.calendarAppLabel.text = when {
|
||||||
|
it == IntentHelper.DO_NOTHING_OPTION -> getString(R.string.gestures_do_nothing)
|
||||||
|
it == IntentHelper.REFRESH_WIDGET_OPTION -> getString(R.string.gestures_refresh_widget)
|
||||||
|
it != IntentHelper.DEFAULT_OPTION -> it
|
||||||
|
else -> getString(R.string.default_calendar_app)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.openEventDetails.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.openEventDetailsLabel.text = if (it) getString(R.string.default_event_app) else getString(R.string.default_calendar_app)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.clockAppName.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.clockAppLabel.text = when {
|
||||||
|
it == IntentHelper.DO_NOTHING_OPTION -> getString(R.string.gestures_do_nothing)
|
||||||
|
it == IntentHelper.REFRESH_WIDGET_OPTION -> getString(R.string.gestures_refresh_widget)
|
||||||
|
it != IntentHelper.DEFAULT_OPTION -> it
|
||||||
|
else -> getString(R.string.default_clock_app)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.weatherAppName.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.weatherAppLabel.text = when {
|
||||||
|
it == IntentHelper.DO_NOTHING_OPTION -> getString(R.string.gestures_do_nothing)
|
||||||
|
it == IntentHelper.REFRESH_WIDGET_OPTION -> getString(R.string.gestures_refresh_widget)
|
||||||
|
it != IntentHelper.DEFAULT_OPTION -> it
|
||||||
|
else -> getString(R.string.default_weather_app)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListener() {
|
||||||
|
|
||||||
|
binding.actionShowMultipleEvents.setOnClickListener {
|
||||||
|
binding.showMultipleEventsToggle.isChecked = !binding.showMultipleEventsToggle.isChecked
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.showMultipleEventsToggle.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
Preferences.showNextEvent = isChecked
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionOpenEventDetails.setOnClickListener {
|
||||||
|
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_event_app_title)).setSelectedValue(Preferences.openEventDetails)
|
||||||
|
.addItem(getString(R.string.default_event_app), true)
|
||||||
|
.addItem(getString(R.string.default_calendar_app), false)
|
||||||
|
.addOnSelectItemListener { value ->
|
||||||
|
Preferences.openEventDetails = value
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionCalendarApp.setOnClickListener {
|
||||||
|
startActivityForResult(
|
||||||
|
Intent(requireContext(), ChooseApplicationActivity::class.java).apply {
|
||||||
|
putExtra(Constants.RESULT_APP_PACKAGE, Preferences.calendarAppPackage)
|
||||||
|
},
|
||||||
|
RequestCode.CALENDAR_APP_REQUEST_CODE.code
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionClockApp.setOnClickListener {
|
||||||
|
startActivityForResult(
|
||||||
|
Intent(requireContext(), ChooseApplicationActivity::class.java).apply {
|
||||||
|
putExtra(Constants.RESULT_APP_PACKAGE, Preferences.clockAppPackage)
|
||||||
|
},
|
||||||
|
RequestCode.CLOCK_APP_REQUEST_CODE.code
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionWeatherApp.setOnClickListener {
|
||||||
|
startActivityForResult(
|
||||||
|
Intent(requireContext(), ChooseApplicationActivity::class.java).apply {
|
||||||
|
putExtra(Constants.RESULT_APP_PACKAGE, Preferences.weatherAppPackage)
|
||||||
|
},
|
||||||
|
RequestCode.WEATHER_APP_REQUEST_CODE.code
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||||
|
binding.scrollView.isScrollable = false
|
||||||
|
callback.invoke()
|
||||||
|
lifecycleScope.launch {
|
||||||
|
delay(200)
|
||||||
|
binding.scrollView.isScrollable = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
if (resultCode == Activity.RESULT_OK && data != null && data.hasExtra(Constants.RESULT_APP_NAME) && data.hasExtra(Constants.RESULT_APP_PACKAGE)) {
|
||||||
|
when (requestCode) {
|
||||||
|
RequestCode.CALENDAR_APP_REQUEST_CODE.code -> {
|
||||||
|
Preferences.bulk {
|
||||||
|
calendarAppName = data.getStringExtra(Constants.RESULT_APP_NAME) ?: IntentHelper.DEFAULT_OPTION
|
||||||
|
calendarAppPackage = data.getStringExtra(Constants.RESULT_APP_PACKAGE) ?: IntentHelper.DEFAULT_OPTION
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RequestCode.EVENT_APP_REQUEST_CODE.code -> {
|
||||||
|
Preferences.bulk {
|
||||||
|
eventAppName = data.getStringExtra(Constants.RESULT_APP_NAME) ?: IntentHelper.DEFAULT_OPTION
|
||||||
|
eventAppPackage = data.getStringExtra(Constants.RESULT_APP_PACKAGE) ?: IntentHelper.DEFAULT_OPTION
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RequestCode.WEATHER_APP_REQUEST_CODE.code -> {
|
||||||
|
Preferences.bulk {
|
||||||
|
weatherAppName = data.getStringExtra(Constants.RESULT_APP_NAME) ?: IntentHelper.DEFAULT_OPTION
|
||||||
|
weatherAppPackage = data.getStringExtra(Constants.RESULT_APP_PACKAGE) ?: IntentHelper.DEFAULT_OPTION
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RequestCode.CLOCK_APP_REQUEST_CODE.code -> {
|
||||||
|
Preferences.bulk {
|
||||||
|
clockAppName = data.getStringExtra(Constants.RESULT_APP_NAME) ?: IntentHelper.DEFAULT_OPTION
|
||||||
|
clockAppPackage = data.getStringExtra(Constants.RESULT_APP_PACKAGE) ?: IntentHelper.DEFAULT_OPTION
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MainWidget.updateWidget(requireContext())
|
||||||
|
}
|
||||||
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.fragments
|
package com.tommasoberlose.anotherwidget.ui.fragments.tabs
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
@ -10,16 +10,16 @@ import android.content.IntentFilter
|
|||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.view.animation.AnimationUtils
|
||||||
|
import android.view.animation.LayoutAnimationController
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.Observer
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
@ -29,10 +29,11 @@ import com.google.android.gms.auth.api.signin.GoogleSignIn
|
|||||||
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
|
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
|
||||||
import com.google.android.gms.common.api.ApiException
|
import com.google.android.gms.common.api.ApiException
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import com.tommasoberlose.anotherwidget.components.CustomNotesDialog
|
import com.tommasoberlose.anotherwidget.components.CustomNotesDialog
|
||||||
import com.tommasoberlose.anotherwidget.components.GlanceSettingsDialog
|
import com.tommasoberlose.anotherwidget.components.GlanceSettingsDialog
|
||||||
import com.tommasoberlose.anotherwidget.databinding.FragmentGlanceSettingsBinding
|
import com.tommasoberlose.anotherwidget.databinding.FragmentTabGlanceBinding
|
||||||
import com.tommasoberlose.anotherwidget.global.Constants
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
||||||
@ -44,11 +45,11 @@ import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
|
|||||||
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver.Companion.FITNESS_OPTIONS
|
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver.Companion.FITNESS_OPTIONS
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
import com.tommasoberlose.anotherwidget.utils.*
|
||||||
import com.tommasoberlose.anotherwidget.utils.convertDpToPixel
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.android.synthetic.main.fragment_glance_settings.*
|
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import net.idik.lib.slimadapter.SlimAdapter
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
|
|
||||||
|
|
||||||
@ -61,10 +62,15 @@ class GlanceTabFragment : Fragment() {
|
|||||||
private var dialog: GlanceSettingsDialog? = null
|
private var dialog: GlanceSettingsDialog? = null
|
||||||
private lateinit var adapter: SlimAdapter
|
private lateinit var adapter: SlimAdapter
|
||||||
private lateinit var viewModel: MainViewModel
|
private lateinit var viewModel: MainViewModel
|
||||||
private lateinit var list: ArrayList<Constants.GlanceProviderId>
|
private val list: ArrayList<Constants.GlanceProviderId> by lazy {
|
||||||
|
GlanceProviderHelper.getGlanceProviders(requireContext())
|
||||||
|
}
|
||||||
|
private lateinit var binding: FragmentTabGlanceBinding
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||||
|
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
@ -73,18 +79,11 @@ class GlanceTabFragment : Fragment() {
|
|||||||
): View {
|
): View {
|
||||||
|
|
||||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||||
val binding = DataBindingUtil.inflate<FragmentGlanceSettingsBinding>(inflater,
|
binding = FragmentTabGlanceBinding.inflate(inflater)
|
||||||
R.layout.fragment_glance_settings,
|
|
||||||
container,
|
|
||||||
false)
|
|
||||||
|
|
||||||
subscribeUi(binding, viewModel)
|
|
||||||
|
|
||||||
binding.lifecycleOwner = this
|
binding.lifecycleOwner = this
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
list = GlanceProviderHelper.getGlanceProviders(requireContext())
|
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,9 +91,10 @@ class GlanceTabFragment : Fragment() {
|
|||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
// List
|
// List
|
||||||
providers_list.setHasFixedSize(true)
|
binding.providersList.hasFixedSize()
|
||||||
|
binding.providersList.isNestedScrollingEnabled = false
|
||||||
val mLayoutManager = LinearLayoutManager(context)
|
val mLayoutManager = LinearLayoutManager(context)
|
||||||
providers_list.layoutManager = mLayoutManager
|
binding.providersList.layoutManager = mLayoutManager
|
||||||
|
|
||||||
adapter = SlimAdapter.create()
|
adapter = SlimAdapter.create()
|
||||||
adapter
|
adapter
|
||||||
@ -106,7 +106,6 @@ class GlanceTabFragment : Fragment() {
|
|||||||
it.setImageDrawable(ContextCompat.getDrawable(requireContext(), item.icon))
|
it.setImageDrawable(ContextCompat.getDrawable(requireContext(), item.icon))
|
||||||
}
|
}
|
||||||
.clicked(R.id.item) {
|
.clicked(R.id.item) {
|
||||||
if (Preferences.showGlance) {
|
|
||||||
if (provider == Constants.GlanceProviderId.CUSTOM_INFO) {
|
if (provider == Constants.GlanceProviderId.CUSTOM_INFO) {
|
||||||
CustomNotesDialog(requireContext()){
|
CustomNotesDialog(requireContext()){
|
||||||
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||||
@ -121,7 +120,6 @@ class GlanceTabFragment : Fragment() {
|
|||||||
dialog?.show()
|
dialog?.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
var isVisible = false
|
var isVisible = false
|
||||||
when (provider) {
|
when (provider) {
|
||||||
Constants.GlanceProviderId.PLAYING_SONG -> {
|
Constants.GlanceProviderId.PLAYING_SONG -> {
|
||||||
@ -130,9 +128,12 @@ class GlanceTabFragment : Fragment() {
|
|||||||
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
|
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
|
||||||
injector.visibility(R.id.error_icon, View.GONE)
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
injector.visibility(R.id.info_icon, View.VISIBLE)
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
injector.text(R.id.label,
|
injector.text(
|
||||||
|
R.id.label,
|
||||||
if (Preferences.showMusic) getString(R.string.settings_visible) else getString(
|
if (Preferences.showMusic) getString(R.string.settings_visible) else getString(
|
||||||
R.string.settings_not_visible))
|
R.string.settings_not_visible
|
||||||
|
)
|
||||||
|
)
|
||||||
isVisible = Preferences.showMusic
|
isVisible = Preferences.showMusic
|
||||||
}
|
}
|
||||||
Preferences.showMusic -> {
|
Preferences.showMusic -> {
|
||||||
@ -150,26 +151,40 @@ class GlanceTabFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
|
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
|
||||||
injector.text(R.id.label,
|
injector.text(
|
||||||
|
R.id.label,
|
||||||
if (Preferences.showNextAlarm && !AlarmHelper.isAlarmProbablyWrong(
|
if (Preferences.showNextAlarm && !AlarmHelper.isAlarmProbablyWrong(
|
||||||
requireContext())
|
requireContext()
|
||||||
|
)
|
||||||
) getString(R.string.settings_visible) else getString(
|
) getString(R.string.settings_visible) else getString(
|
||||||
R.string.settings_not_visible))
|
R.string.settings_not_visible
|
||||||
injector.visibility(R.id.error_icon,
|
)
|
||||||
|
)
|
||||||
|
injector.visibility(
|
||||||
|
R.id.error_icon,
|
||||||
if (Preferences.showNextAlarm && AlarmHelper.isAlarmProbablyWrong(
|
if (Preferences.showNextAlarm && AlarmHelper.isAlarmProbablyWrong(
|
||||||
requireContext())
|
requireContext()
|
||||||
) View.VISIBLE else View.GONE)
|
)
|
||||||
injector.visibility(R.id.info_icon,
|
) View.VISIBLE else View.GONE
|
||||||
|
)
|
||||||
|
injector.visibility(
|
||||||
|
R.id.info_icon,
|
||||||
if (!(Preferences.showNextAlarm && AlarmHelper.isAlarmProbablyWrong(
|
if (!(Preferences.showNextAlarm && AlarmHelper.isAlarmProbablyWrong(
|
||||||
requireContext()))
|
requireContext()
|
||||||
) View.VISIBLE else View.GONE)
|
))
|
||||||
isVisible = !(Preferences.showNextAlarm && AlarmHelper.isAlarmProbablyWrong(
|
) View.VISIBLE else View.GONE
|
||||||
requireContext()))
|
)
|
||||||
|
isVisible = (Preferences.showNextAlarm && !AlarmHelper.isAlarmProbablyWrong(
|
||||||
|
requireContext()
|
||||||
|
))
|
||||||
}
|
}
|
||||||
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
||||||
injector.text(R.id.label,
|
injector.text(
|
||||||
|
R.id.label,
|
||||||
if (Preferences.showBatteryCharging) getString(R.string.settings_visible) else getString(
|
if (Preferences.showBatteryCharging) getString(R.string.settings_visible) else getString(
|
||||||
R.string.settings_not_visible))
|
R.string.settings_not_visible
|
||||||
|
)
|
||||||
|
)
|
||||||
injector.visibility(R.id.error_icon, View.GONE)
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
injector.visibility(R.id.info_icon, View.VISIBLE)
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
isVisible = Preferences.showBatteryCharging
|
isVisible = Preferences.showBatteryCharging
|
||||||
@ -179,9 +194,12 @@ class GlanceTabFragment : Fragment() {
|
|||||||
ActiveNotificationsHelper.checkNotificationAccess(requireContext()) -> {
|
ActiveNotificationsHelper.checkNotificationAccess(requireContext()) -> {
|
||||||
injector.visibility(R.id.error_icon, View.GONE)
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
injector.visibility(R.id.info_icon, View.VISIBLE)
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
injector.text(R.id.label,
|
injector.text(
|
||||||
|
R.id.label,
|
||||||
if (Preferences.showNotifications) getString(
|
if (Preferences.showNotifications) getString(
|
||||||
R.string.settings_visible) else getString(R.string.settings_not_visible))
|
R.string.settings_visible
|
||||||
|
) else getString(R.string.settings_not_visible)
|
||||||
|
)
|
||||||
isVisible = Preferences.showNotifications
|
isVisible = Preferences.showNotifications
|
||||||
}
|
}
|
||||||
Preferences.showNotifications -> {
|
Preferences.showNotifications -> {
|
||||||
@ -199,29 +217,44 @@ class GlanceTabFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Constants.GlanceProviderId.GREETINGS -> {
|
Constants.GlanceProviderId.GREETINGS -> {
|
||||||
injector.text(R.id.label,
|
injector.text(
|
||||||
|
R.id.label,
|
||||||
if (Preferences.showGreetings) getString(R.string.settings_visible) else getString(
|
if (Preferences.showGreetings) getString(R.string.settings_visible) else getString(
|
||||||
R.string.settings_not_visible))
|
R.string.settings_not_visible
|
||||||
|
)
|
||||||
|
)
|
||||||
injector.visibility(R.id.error_icon, View.GONE)
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
injector.visibility(R.id.info_icon, View.VISIBLE)
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
isVisible = Preferences.showGreetings
|
isVisible = Preferences.showGreetings
|
||||||
}
|
}
|
||||||
Constants.GlanceProviderId.CUSTOM_INFO -> {
|
Constants.GlanceProviderId.CUSTOM_INFO -> {
|
||||||
injector.text(R.id.label,
|
injector.text(
|
||||||
|
R.id.label,
|
||||||
if (Preferences.customNotes != "") getString(R.string.settings_visible) else getString(
|
if (Preferences.customNotes != "") getString(R.string.settings_visible) else getString(
|
||||||
R.string.settings_not_visible))
|
R.string.settings_not_visible
|
||||||
|
)
|
||||||
|
)
|
||||||
injector.visibility(R.id.error_icon, View.GONE)
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
injector.visibility(R.id.info_icon, View.VISIBLE)
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
isVisible = Preferences.customNotes != ""
|
isVisible = Preferences.customNotes != ""
|
||||||
}
|
}
|
||||||
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
|
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
|
||||||
val account: GoogleSignInAccount? = GoogleSignIn.getLastSignedInAccount(context)
|
val account: GoogleSignInAccount? = GoogleSignIn.getLastSignedInAccount(
|
||||||
if (GoogleSignIn.hasPermissions(account, FITNESS_OPTIONS) && (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || activity?.checkGrantedPermission(
|
context
|
||||||
Manifest.permission.ACTIVITY_RECOGNITION) == true)
|
)
|
||||||
|
if (GoogleSignIn.hasPermissions(
|
||||||
|
account,
|
||||||
|
FITNESS_OPTIONS
|
||||||
|
) && (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || requireActivity().checkGrantedPermission(
|
||||||
|
Manifest.permission.ACTIVITY_RECOGNITION
|
||||||
|
))
|
||||||
) {
|
) {
|
||||||
injector.text(R.id.label,
|
injector.text(
|
||||||
|
R.id.label,
|
||||||
if (Preferences.showDailySteps) getString(R.string.settings_visible) else getString(
|
if (Preferences.showDailySteps) getString(R.string.settings_visible) else getString(
|
||||||
R.string.settings_not_visible))
|
R.string.settings_not_visible
|
||||||
|
)
|
||||||
|
)
|
||||||
injector.visibility(R.id.error_icon, View.GONE)
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
injector.visibility(R.id.info_icon, View.VISIBLE)
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
isVisible = Preferences.showDailySteps
|
isVisible = Preferences.showDailySteps
|
||||||
@ -240,12 +273,44 @@ class GlanceTabFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Constants.GlanceProviderId.EVENTS -> {
|
Constants.GlanceProviderId.EVENTS -> {
|
||||||
isVisible = Preferences.showEventsAsGlanceProvider && Preferences.showEvents && requireContext().checkGrantedPermission(Manifest.permission.READ_CALENDAR)
|
isVisible =
|
||||||
injector.text(R.id.label,
|
Preferences.showEventsAsGlanceProvider
|
||||||
if (isVisible) getString(R.string.settings_visible) else getString(
|
val hasError = !Preferences.showEvents || !requireContext().checkGrantedPermission(
|
||||||
R.string.settings_not_visible))
|
Manifest.permission.READ_CALENDAR
|
||||||
injector.visibility(R.id.error_icon, if (isVisible) View.GONE else View.VISIBLE)
|
)
|
||||||
injector.visibility(R.id.info_icon, if (isVisible) View.VISIBLE else View.GONE)
|
injector.text(
|
||||||
|
R.id.label,
|
||||||
|
if (isVisible && !hasError) getString(R.string.settings_visible) else getString(
|
||||||
|
R.string.settings_not_visible
|
||||||
|
)
|
||||||
|
)
|
||||||
|
injector.visibility(
|
||||||
|
R.id.error_icon,
|
||||||
|
if (isVisible && hasError) View.VISIBLE else View.GONE
|
||||||
|
)
|
||||||
|
injector.visibility(
|
||||||
|
R.id.info_icon,
|
||||||
|
if (!(isVisible && hasError)) View.VISIBLE else View.GONE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.WEATHER -> {
|
||||||
|
isVisible =
|
||||||
|
Preferences.showWeatherAsGlanceProvider
|
||||||
|
val hasError = !Preferences.showWeather || (Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-") || Preferences.weatherProviderLocationError != ""
|
||||||
|
injector.text(
|
||||||
|
R.id.label,
|
||||||
|
if (isVisible && !hasError) getString(R.string.settings_visible) else getString(
|
||||||
|
R.string.settings_not_visible
|
||||||
|
)
|
||||||
|
)
|
||||||
|
injector.visibility(
|
||||||
|
R.id.error_icon,
|
||||||
|
if (isVisible && hasError) View.VISIBLE else View.GONE
|
||||||
|
)
|
||||||
|
injector.visibility(
|
||||||
|
R.id.info_icon,
|
||||||
|
if (!(isVisible && hasError)) View.VISIBLE else View.GONE
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,7 +318,7 @@ class GlanceTabFragment : Fragment() {
|
|||||||
injector.alpha(R.id.label, if (isVisible) 1f else .25f)
|
injector.alpha(R.id.label, if (isVisible) 1f else .25f)
|
||||||
injector.alpha(R.id.icon, if (isVisible) 1f else .25f)
|
injector.alpha(R.id.icon, if (isVisible) 1f else .25f)
|
||||||
}
|
}
|
||||||
.attachTo(providers_list)
|
.attachTo(binding.providersList)
|
||||||
|
|
||||||
val mIth = ItemTouchHelper(
|
val mIth = ItemTouchHelper(
|
||||||
object : ItemTouchHelper.SimpleCallback(
|
object : ItemTouchHelper.SimpleCallback(
|
||||||
@ -300,7 +365,12 @@ class GlanceTabFragment : Fragment() {
|
|||||||
GlanceProviderHelper.saveGlanceProviderOrder(
|
GlanceProviderHelper.saveGlanceProviderOrder(
|
||||||
list
|
list
|
||||||
)
|
)
|
||||||
adapter.updateData(list.mapNotNull { GlanceProviderHelper.getGlanceProviderById(requireContext(), it) })
|
adapter.updateData(list.mapNotNull {
|
||||||
|
GlanceProviderHelper.getGlanceProviderById(
|
||||||
|
requireContext(),
|
||||||
|
it
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onChildDraw(
|
override fun onChildDraw(
|
||||||
@ -314,24 +384,38 @@ class GlanceTabFragment : Fragment() {
|
|||||||
) {
|
) {
|
||||||
val view = viewHolder.itemView as MaterialCardView
|
val view = viewHolder.itemView as MaterialCardView
|
||||||
if (isCurrentlyActive) {
|
if (isCurrentlyActive) {
|
||||||
ViewCompat.setElevation(view, 2f.convertDpToPixel(requireContext()))
|
ViewCompat.setElevation(view, 8f.convertDpToPixel(requireContext()))
|
||||||
view.setCardBackgroundColor(ContextCompat.getColor(requireContext(),
|
view.setCardBackgroundColor(
|
||||||
R.color.colorPrimary))
|
ContextCompat.getColor(
|
||||||
|
requireContext(),
|
||||||
|
R.color.cardBorder
|
||||||
|
)
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
ViewCompat.setElevation(view, 0f)
|
ViewCompat.setElevation(view, 0f)
|
||||||
view.setCardBackgroundColor(ContextCompat.getColor(requireContext(),
|
view.setCardBackgroundColor(
|
||||||
R.color.colorPrimaryDark))
|
ContextCompat.getColor(
|
||||||
|
requireContext(),
|
||||||
|
R.color.colorPrimary
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val topEdge = if ((view.top == 0 && dY < 0) || ((view.top + view.height >= recyclerView.height - 32f.convertDpToPixel(requireContext())) && dY > 0)) 0f else dY
|
val topEdge =
|
||||||
|
if ((view.top == 0 && dY < 0) || ((view.top + view.height >= recyclerView.height - 32f.convertDpToPixel(
|
||||||
|
requireContext()
|
||||||
|
)) && dY > 0)
|
||||||
|
) 0f else dY
|
||||||
|
|
||||||
super.onChildDraw(c,
|
super.onChildDraw(
|
||||||
|
c,
|
||||||
recyclerView,
|
recyclerView,
|
||||||
viewHolder,
|
viewHolder,
|
||||||
dX,
|
dX,
|
||||||
topEdge,
|
topEdge,
|
||||||
actionState,
|
actionState,
|
||||||
isCurrentlyActive)
|
isCurrentlyActive
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSwiped(
|
override fun onSwiped(
|
||||||
@ -342,42 +426,34 @@ class GlanceTabFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
mIth.attachToRecyclerView(providers_list)
|
mIth.attachToRecyclerView(binding.providersList)
|
||||||
adapter.updateData(list.mapNotNull { GlanceProviderHelper.getGlanceProviderById(requireContext(), it) })
|
|
||||||
providers_list.isNestedScrollingEnabled = false
|
|
||||||
|
|
||||||
setupListener()
|
setupListener()
|
||||||
|
|
||||||
|
binding.scrollView.viewTreeObserver.addOnScrollChangedListener {
|
||||||
|
viewModel.fragmentScrollY.value = binding.scrollView.scrollY
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun subscribeUi(
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
binding: FragmentGlanceSettingsBinding,
|
delay(500)
|
||||||
viewModel: MainViewModel,
|
val l = list.mapNotNull { GlanceProviderHelper.getGlanceProviderById(
|
||||||
) {
|
requireContext(),
|
||||||
binding.isGlanceVisible = Preferences.showGlance
|
it
|
||||||
|
) }
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
binding.loader.animate().scaleX(0f).scaleY(0f).alpha(0f).start()
|
||||||
|
adapter.updateData(l)
|
||||||
|
val controller =
|
||||||
|
AnimationUtils.loadLayoutAnimation(context, R.anim.layout_animation_fall_down)
|
||||||
|
|
||||||
viewModel.showGlance.observe(viewLifecycleOwner, Observer {
|
binding.providersList.layoutAnimation = controller
|
||||||
maintainScrollPosition {
|
adapter.notifyDataSetChanged()
|
||||||
binding.isGlanceVisible = it
|
binding.providersList.scheduleLayoutAnimation()
|
||||||
show_glance_label.text =
|
}
|
||||||
if (it) getString(R.string.description_show_glance_visible) else getString(
|
|
||||||
R.string.description_show_glance_not_visible)
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupListener() {
|
private fun setupListener() {
|
||||||
action_show_glance.setOnClickListener {
|
|
||||||
Preferences.showGlance = !Preferences.showGlance
|
|
||||||
}
|
|
||||||
|
|
||||||
show_glance_switch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
|
||||||
Preferences.showGlance = enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_glance.setOnLongClickListener {
|
|
||||||
Preferences.enabledGlanceProviderOrder = ""
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val nextAlarmChangeBroadcastReceiver = object : BroadcastReceiver() {
|
private val nextAlarmChangeBroadcastReceiver = object : BroadcastReceiver() {
|
||||||
@ -388,15 +464,17 @@ class GlanceTabFragment : Fragment() {
|
|||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
activity?.registerReceiver(nextAlarmChangeBroadcastReceiver,
|
requireActivity().registerReceiver(
|
||||||
IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED))
|
nextAlarmChangeBroadcastReceiver,
|
||||||
|
IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)
|
||||||
|
)
|
||||||
if (dialog != null) {
|
if (dialog != null) {
|
||||||
dialog?.show()
|
dialog?.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
activity?.unregisterReceiver(nextAlarmChangeBroadcastReceiver)
|
requireActivity().unregisterReceiver(nextAlarmChangeBroadcastReceiver)
|
||||||
super.onStop()
|
super.onStop()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,13 +498,15 @@ class GlanceTabFragment : Fragment() {
|
|||||||
2 -> {
|
2 -> {
|
||||||
try {
|
try {
|
||||||
val account: GoogleSignInAccount? = GoogleSignIn.getSignedInAccountFromIntent(
|
val account: GoogleSignInAccount? = GoogleSignIn.getSignedInAccountFromIntent(
|
||||||
data).getResult(ApiException::class.java)
|
data
|
||||||
|
).getResult(ApiException::class.java)
|
||||||
if (!GoogleSignIn.hasPermissions(account, FITNESS_OPTIONS)) {
|
if (!GoogleSignIn.hasPermissions(account, FITNESS_OPTIONS)) {
|
||||||
GoogleSignIn.requestPermissions(
|
GoogleSignIn.requestPermissions(
|
||||||
requireActivity(),
|
requireActivity(),
|
||||||
1,
|
1,
|
||||||
account,
|
account,
|
||||||
FITNESS_OPTIONS)
|
FITNESS_OPTIONS
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||||
}
|
}
|
||||||
@ -442,18 +522,9 @@ class GlanceTabFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
|
||||||
scrollView.isScrollable = false
|
|
||||||
callback.invoke()
|
|
||||||
lifecycleScope.launch {
|
|
||||||
delay(200)
|
|
||||||
scrollView.isScrollable = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
adapter.notifyItemRangeChanged(0, adapter.data?.size ?: 0)
|
||||||
if (dialog != null) {
|
if (dialog != null) {
|
||||||
dialog?.show()
|
dialog?.show()
|
||||||
}
|
}
|
@ -0,0 +1,342 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.fragments.tabs
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker
|
||||||
|
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.FragmentTabLayoutBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toHexValue
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
|
||||||
|
class LayoutFragment : Fragment() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance() = LayoutFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var viewModel: MainViewModel
|
||||||
|
private lateinit var colors: IntArray
|
||||||
|
private lateinit var binding: FragmentTabLayoutBinding
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||||
|
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||||
|
binding = FragmentTabLayoutBinding.inflate(inflater)
|
||||||
|
|
||||||
|
subscribeUi(viewModel)
|
||||||
|
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
binding.isDarkModeEnabled = requireActivity().isDarkTheme()
|
||||||
|
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
|
binding.showDividersToggle.setCheckedImmediatelyNoEvent(Preferences.showDividers)
|
||||||
|
|
||||||
|
setupListener()
|
||||||
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
val lazyColors = requireContext().resources.getIntArray(R.array.material_colors)
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
colors = lazyColors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.scrollView.viewTreeObserver?.addOnScrollChangedListener {
|
||||||
|
viewModel.fragmentScrollY.value = binding.scrollView.scrollY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressLint("DefaultLocale")
|
||||||
|
private fun subscribeUi(
|
||||||
|
viewModel: MainViewModel
|
||||||
|
) {
|
||||||
|
|
||||||
|
viewModel.widgetMargin.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.widgetMarginLabel.text = when (it) {
|
||||||
|
Constants.Dimension.NONE.rawValue -> getString(R.string.settings_widget_dim_none)
|
||||||
|
Constants.Dimension.SMALL.rawValue -> getString(R.string.settings_widget_dim_small)
|
||||||
|
Constants.Dimension.LARGE.rawValue -> getString(R.string.settings_widget_dim_large)
|
||||||
|
else -> getString(R.string.settings_widget_dim_medium)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.widgetPadding.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.widgetPaddingLabel.text = when (it) {
|
||||||
|
Constants.Dimension.NONE.rawValue -> getString(R.string.settings_widget_dim_none)
|
||||||
|
Constants.Dimension.SMALL.rawValue -> getString(R.string.settings_widget_dim_small)
|
||||||
|
Constants.Dimension.LARGE.rawValue -> getString(R.string.settings_widget_dim_large)
|
||||||
|
else -> getString(R.string.settings_widget_dim_medium)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.secondRowTopMargin.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.secondRowTopMarginLabel.text = when (it) {
|
||||||
|
Constants.SecondRowTopMargin.NONE.rawValue -> getString(R.string.settings_clock_bottom_margin_subtitle_none)
|
||||||
|
Constants.SecondRowTopMargin.SMALL.rawValue -> getString(R.string.settings_clock_bottom_margin_subtitle_small)
|
||||||
|
Constants.SecondRowTopMargin.LARGE.rawValue -> getString(R.string.settings_clock_bottom_margin_subtitle_large)
|
||||||
|
else -> getString(R.string.settings_clock_bottom_margin_subtitle_medium)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.widgetAlign.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.widgetAlignIcon.setImageDrawable(when (it) {
|
||||||
|
Constants.WidgetAlign.LEFT.rawValue -> ContextCompat.getDrawable(requireContext(), R.drawable.round_align_horizontal_left_24)
|
||||||
|
Constants.WidgetAlign.RIGHT.rawValue -> ContextCompat.getDrawable(requireContext(), R.drawable.round_align_horizontal_right_24)
|
||||||
|
Constants.WidgetAlign.CENTER.rawValue -> ContextCompat.getDrawable(requireContext(), R.drawable.round_align_horizontal_center_24)
|
||||||
|
else -> ContextCompat.getDrawable(requireContext(), R.drawable.round_align_horizontal_center_24)
|
||||||
|
})
|
||||||
|
|
||||||
|
binding.widgetAlignLabel.text = when (it) {
|
||||||
|
Constants.WidgetAlign.LEFT.rawValue -> getString(R.string.settings_widget_align_left_subtitle)
|
||||||
|
Constants.WidgetAlign.RIGHT.rawValue -> getString(R.string.settings_widget_align_right_subtitle)
|
||||||
|
Constants.WidgetAlign.CENTER.rawValue -> getString(R.string.settings_widget_align_center_subtitle)
|
||||||
|
else -> getString(R.string.settings_widget_align_center_subtitle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.clockBottomMargin.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.clockBottomMarginLabel.text = when (it) {
|
||||||
|
Constants.ClockBottomMargin.NONE.rawValue -> getString(R.string.settings_clock_bottom_margin_subtitle_none)
|
||||||
|
Constants.ClockBottomMargin.SMALL.rawValue -> getString(R.string.settings_clock_bottom_margin_subtitle_small)
|
||||||
|
Constants.ClockBottomMargin.LARGE.rawValue -> getString(R.string.settings_clock_bottom_margin_subtitle_large)
|
||||||
|
else -> getString(R.string.settings_clock_bottom_margin_subtitle_medium)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.backgroundCardColor.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
if (ColorHelper.getBackgroundAlpha(requireActivity().isDarkTheme()) == 0) {
|
||||||
|
binding.backgroundColorLabel.text = getString(R.string.transparent)
|
||||||
|
} else {
|
||||||
|
binding.backgroundColorLabel.text =
|
||||||
|
"#%s".format(Integer.toHexString(ColorHelper.getBackgroundColor(requireActivity().isDarkTheme()))).toUpperCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.showDividers.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.showDividersLabel.text =
|
||||||
|
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListener() {
|
||||||
|
|
||||||
|
binding.actionWidgetMargin.setOnClickListener {
|
||||||
|
BottomSheetMenu<Float>(
|
||||||
|
requireContext(),
|
||||||
|
header = getString(R.string.settings_widget_margin_title)
|
||||||
|
).setSelectedValue(Preferences.widgetMargin)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_widget_dim_none),
|
||||||
|
Constants.Dimension.NONE.rawValue
|
||||||
|
)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_widget_dim_small),
|
||||||
|
Constants.Dimension.SMALL.rawValue
|
||||||
|
)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_widget_dim_medium),
|
||||||
|
Constants.Dimension.MEDIUM.rawValue
|
||||||
|
)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_widget_dim_large),
|
||||||
|
Constants.Dimension.LARGE.rawValue
|
||||||
|
)
|
||||||
|
.addOnSelectItemListener { value ->
|
||||||
|
Preferences.widgetMargin = value
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionWidgetPadding.setOnClickListener {
|
||||||
|
BottomSheetMenu<Float>(
|
||||||
|
requireContext(),
|
||||||
|
header = getString(R.string.settings_widget_padding_title)
|
||||||
|
).setSelectedValue(Preferences.widgetPadding)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_widget_dim_none),
|
||||||
|
Constants.Dimension.NONE.rawValue
|
||||||
|
)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_widget_dim_small),
|
||||||
|
Constants.Dimension.SMALL.rawValue
|
||||||
|
)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_widget_dim_medium),
|
||||||
|
Constants.Dimension.MEDIUM.rawValue
|
||||||
|
)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_widget_dim_large),
|
||||||
|
Constants.Dimension.LARGE.rawValue
|
||||||
|
)
|
||||||
|
.addOnSelectItemListener { value ->
|
||||||
|
Preferences.widgetPadding = value
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionSecondRowTopMarginSize.setOnClickListener {
|
||||||
|
BottomSheetMenu<Int>(
|
||||||
|
requireContext(),
|
||||||
|
header = getString(R.string.settings_secondary_row_top_margin_title)
|
||||||
|
).setSelectedValue(Preferences.secondRowTopMargin)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_clock_bottom_margin_subtitle_none),
|
||||||
|
Constants.SecondRowTopMargin.NONE.rawValue
|
||||||
|
)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_clock_bottom_margin_subtitle_small),
|
||||||
|
Constants.SecondRowTopMargin.SMALL.rawValue
|
||||||
|
)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_clock_bottom_margin_subtitle_medium),
|
||||||
|
Constants.SecondRowTopMargin.MEDIUM.rawValue
|
||||||
|
)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_clock_bottom_margin_subtitle_large),
|
||||||
|
Constants.SecondRowTopMargin.LARGE.rawValue
|
||||||
|
)
|
||||||
|
.addOnSelectItemListener { value ->
|
||||||
|
Preferences.secondRowTopMargin = value
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionClockBottomMarginSize.setOnClickListener {
|
||||||
|
BottomSheetMenu<Int>(
|
||||||
|
requireContext(),
|
||||||
|
header = getString(R.string.settings_clock_bottom_margin_title)
|
||||||
|
).setSelectedValue(Preferences.clockBottomMargin)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_clock_bottom_margin_subtitle_none),
|
||||||
|
Constants.ClockBottomMargin.NONE.rawValue
|
||||||
|
)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_clock_bottom_margin_subtitle_small),
|
||||||
|
Constants.ClockBottomMargin.SMALL.rawValue
|
||||||
|
)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_clock_bottom_margin_subtitle_medium),
|
||||||
|
Constants.ClockBottomMargin.MEDIUM.rawValue
|
||||||
|
)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_clock_bottom_margin_subtitle_large),
|
||||||
|
Constants.ClockBottomMargin.LARGE.rawValue
|
||||||
|
)
|
||||||
|
.addOnSelectItemListener { value ->
|
||||||
|
Preferences.clockBottomMargin = value
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionWidgetAlign.setOnClickListener {
|
||||||
|
BottomSheetMenu<Int>(
|
||||||
|
requireContext(),
|
||||||
|
header = getString(R.string.settings_widget_align_title)
|
||||||
|
).setSelectedValue(Preferences.widgetAlign)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_widget_align_center_subtitle),
|
||||||
|
Constants.WidgetAlign.CENTER.rawValue
|
||||||
|
)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_widget_align_left_subtitle),
|
||||||
|
Constants.WidgetAlign.LEFT.rawValue
|
||||||
|
)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_widget_align_right_subtitle),
|
||||||
|
Constants.WidgetAlign.RIGHT.rawValue
|
||||||
|
)
|
||||||
|
.addOnSelectItemListener { value ->
|
||||||
|
Preferences.widgetAlign = value
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionBackgroundColor.setOnClickListener {
|
||||||
|
BottomSheetColorPicker(requireContext(),
|
||||||
|
colors = colors,
|
||||||
|
header = getString(R.string.settings_background_color_title),
|
||||||
|
getSelected = { ColorHelper.getBackgroundColorRgb(requireActivity().isDarkTheme()) },
|
||||||
|
onColorSelected = { color: Int ->
|
||||||
|
val colorString = Integer.toHexString(color)
|
||||||
|
if (requireActivity().isDarkTheme()) {
|
||||||
|
Preferences.backgroundCardColorDark =
|
||||||
|
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||||
|
} else {
|
||||||
|
Preferences.backgroundCardColor =
|
||||||
|
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showAlphaSelector = true,
|
||||||
|
alpha = if (requireActivity().isDarkTheme()) Preferences.backgroundCardAlphaDark.toIntValue() else Preferences.backgroundCardAlpha.toIntValue(),
|
||||||
|
onAlphaChangeListener = { alpha ->
|
||||||
|
if (requireActivity().isDarkTheme()) {
|
||||||
|
Preferences.backgroundCardAlphaDark = alpha.toHexValue()
|
||||||
|
} else {
|
||||||
|
Preferences.backgroundCardAlpha = alpha.toHexValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionShowDividers.setOnClickListener {
|
||||||
|
binding.showDividersToggle.isChecked = !binding.showDividersToggle.isChecked
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.showDividersToggle.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
Preferences.showDividers = isChecked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||||
|
binding.scrollView.isScrollable = false
|
||||||
|
callback.invoke()
|
||||||
|
lifecycleScope.launch {
|
||||||
|
delay(200)
|
||||||
|
binding.scrollView.isScrollable = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,233 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.fragments.tabs
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.databinding.DataBindingUtil
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.navigation.Navigation
|
||||||
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
|
import com.karumi.dexter.Dexter
|
||||||
|
import com.karumi.dexter.MultiplePermissionsReport
|
||||||
|
import com.karumi.dexter.PermissionToken
|
||||||
|
import com.karumi.dexter.listener.PermissionRequest
|
||||||
|
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.FragmentPreferencesBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
||||||
|
import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.*
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class PreferencesFragment : Fragment() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance() = PreferencesFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var viewModel: MainViewModel
|
||||||
|
private lateinit var binding: FragmentPreferencesBinding
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||||
|
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||||
|
binding = FragmentPreferencesBinding.inflate(inflater)
|
||||||
|
|
||||||
|
subscribeUi(viewModel)
|
||||||
|
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
|
setupListener()
|
||||||
|
|
||||||
|
binding.showEventsSwitch.setCheckedImmediatelyNoEvent(Preferences.showEvents)
|
||||||
|
binding.showWeatherSwitch.setCheckedImmediatelyNoEvent(Preferences.showWeather)
|
||||||
|
binding.showClockSwitch.setCheckedImmediatelyNoEvent(Preferences.showClock)
|
||||||
|
|
||||||
|
binding.scrollView.viewTreeObserver.addOnScrollChangedListener {
|
||||||
|
viewModel.fragmentScrollY.value = binding.scrollView.scrollY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun subscribeUi(
|
||||||
|
viewModel: MainViewModel
|
||||||
|
) {
|
||||||
|
|
||||||
|
viewModel.showEvents.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.showEventsSwitch.setCheckedImmediatelyNoEvent(it)
|
||||||
|
if (it) {
|
||||||
|
CalendarHelper.setEventUpdatesAndroidN(requireContext())
|
||||||
|
} else {
|
||||||
|
CalendarHelper.removeEventUpdatesAndroidN(requireContext())
|
||||||
|
UpdatesReceiver.removeUpdates(requireContext())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.showWeather.observe(viewLifecycleOwner) {
|
||||||
|
checkWeatherProviderConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.weatherProviderError.observe(viewLifecycleOwner) {
|
||||||
|
checkWeatherProviderConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.weatherProviderLocationError.observe(viewLifecycleOwner) {
|
||||||
|
checkWeatherProviderConfig()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListener() {
|
||||||
|
|
||||||
|
binding.actionTypography.setOnSingleClickListener {
|
||||||
|
Navigation.findNavController(it).navigate(R.id.action_tabSelectorFragment_to_typographyTabFragment)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionGeneralSettings.setOnSingleClickListener {
|
||||||
|
Navigation.findNavController(it).navigate(R.id.action_tabSelectorFragment_to_generalTabFragment)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionShowEvents.setOnSingleClickListener {
|
||||||
|
Navigation.findNavController(it).navigate(R.id.action_tabSelectorFragment_to_calendarTabFragment)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.showEventsSwitch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
||||||
|
if (enabled) {
|
||||||
|
requireCalendarPermission()
|
||||||
|
} else {
|
||||||
|
Preferences.showEvents = enabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionShowWeather.setOnSingleClickListener {
|
||||||
|
Navigation.findNavController(it).navigate(R.id.action_tabSelectorFragment_to_weatherTabFragment)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.showWeatherSwitch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
||||||
|
Preferences.showWeather = enabled
|
||||||
|
if (enabled) {
|
||||||
|
Preferences.weatherProviderError = ""
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
WeatherHelper.updateWeather(requireContext())
|
||||||
|
} else {
|
||||||
|
WeatherReceiver.removeUpdates(requireContext())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionShowClock.setOnSingleClickListener {
|
||||||
|
Navigation.findNavController(it).navigate(R.id.action_tabSelectorFragment_to_clockTabFragment)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.showClockSwitch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
||||||
|
Preferences.showClock = enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionShowGlance.setOnSingleClickListener {
|
||||||
|
Navigation.findNavController(it).navigate(R.id.action_tabSelectorFragment_to_glanceTabFragment)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionTabDefaultApp.setOnSingleClickListener {
|
||||||
|
Navigation.findNavController(it).navigate(R.id.action_tabSelectorFragment_to_gesturesFragment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun requireCalendarPermission() {
|
||||||
|
Dexter.withContext(requireContext())
|
||||||
|
.withPermissions(
|
||||||
|
Manifest.permission.READ_CALENDAR
|
||||||
|
).withListener(object: MultiplePermissionsListener {
|
||||||
|
private var shouldShowRationale = false
|
||||||
|
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
||||||
|
report?.let {
|
||||||
|
val granted = report.areAllPermissionsGranted()
|
||||||
|
Preferences.showEvents = granted
|
||||||
|
if (granted) {
|
||||||
|
CalendarHelper.updateEventList(requireContext())
|
||||||
|
}
|
||||||
|
else if (!shouldShowRationale && report.isAnyPermissionPermanentlyDenied) {
|
||||||
|
MaterialBottomSheetDialog(
|
||||||
|
requireContext(),
|
||||||
|
getString(R.string.title_permission_calendar),
|
||||||
|
getString(R.string.description_permission_calendar)
|
||||||
|
).setNegativeButton(getString(R.string.action_ignore))
|
||||||
|
.setPositiveButton(getString(R.string.action_grant_permission)) {
|
||||||
|
startActivity(
|
||||||
|
android.content.Intent(
|
||||||
|
android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
||||||
|
).apply {
|
||||||
|
data = android.net.Uri.fromParts(
|
||||||
|
"package",
|
||||||
|
requireContext().packageName,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override fun onPermissionRationaleShouldBeShown(
|
||||||
|
permissions: MutableList<PermissionRequest>?,
|
||||||
|
token: PermissionToken?
|
||||||
|
) {
|
||||||
|
shouldShowRationale = true
|
||||||
|
// Remember to invoke this method when the custom rationale is closed
|
||||||
|
// or just by default if you don't want to use any custom rationale.
|
||||||
|
token?.continuePermissionRequest()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.check()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkWeatherProviderConfig() {
|
||||||
|
binding.weatherProviderError.isVisible = Preferences.showWeather && Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-"
|
||||||
|
binding.weatherProviderError.text = Preferences.weatherProviderError
|
||||||
|
|
||||||
|
binding.weatherProviderLocationError.isVisible = Preferences.showWeather && Preferences.weatherProviderLocationError != ""
|
||||||
|
binding.weatherProviderLocationError.text = Preferences.weatherProviderLocationError
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
binding.showEventsSwitch.setCheckedNoEvent(Preferences.showEvents && requireActivity().checkGrantedPermission(Manifest.permission.READ_CALENDAR))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||||
|
binding.scrollView.isScrollable = false
|
||||||
|
callback.invoke()
|
||||||
|
lifecycleScope.launch {
|
||||||
|
delay(200)
|
||||||
|
binding.scrollView.isScrollable = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user