Compare commits
167 Commits
v2.0.13
...
v2.2.2-bet
Author | SHA1 | Date | |
---|---|---|---|
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 | |||
5b2d245e80 | |||
0aec34dcd2 | |||
b2a9b9fbb3 | |||
768f04825e | |||
80ee877bf2 | |||
ac7839ecdc | |||
66d0214cd9 | |||
e069b8f6ab | |||
8a681f0cd7 | |||
92158ec5f2 | |||
ebb37f21ed | |||
2a389cb422 | |||
4504a0617e | |||
9ed34ee17e | |||
a7294edfd4 | |||
49ca17803e | |||
97ab72081d | |||
e6fee0dfe1 | |||
e0c4f24c43 | |||
2a7d0f171b | |||
00dcfc3149 | |||
eb11b603aa | |||
4d2f624448 | |||
7581af4dd2 | |||
0325af6582 | |||
4de0413a35 | |||
c54a24c889 | |||
98eccd2833 | |||
0119a20765 | |||
a1e54892fd | |||
17801fd164 | |||
e6087b2969 | |||
59b8ba26a2 | |||
f190ee5d15 | |||
2f266ffcf8 | |||
0e376aba80 | |||
313e4fa92d | |||
a8ec754bc4 | |||
f8d1188634 | |||
8216fc96b9 | |||
56d95c5559 | |||
c0e747a714 | |||
16076dc145 | |||
c95f9fb943 | |||
331d5772af | |||
e2719b6445 | |||
bd35022f7d | |||
6d9cb750a7 | |||
f85b4c9a6a | |||
df54a4a79e | |||
6ea97e7724 | |||
d27071739d | |||
738781225f | |||
12d32f852b | |||
f0baa60363 | |||
785eb39334 | |||
d289699d08 | |||
c68d0a8327 | |||
de2e223713 | |||
6150dd7e22 | |||
d9ecebe770 | |||
52327715b1 | |||
e301e6e6ec | |||
c884fae362 | |||
eb78257e52 | |||
109aa24af1 | |||
2403f066a3 | |||
9bc7d7b62e | |||
a1a6f9f607 | |||
815a88a079 | |||
1c1f55e20a | |||
5259a81cfb | |||
3b963dae1c | |||
878ddcb05e | |||
0ce446f0ef | |||
c5fefb0e06 | |||
c5eb5358aa | |||
c4a16224f0 | |||
122c0627d9 | |||
6d80ec97a8 | |||
1c7df585fe | |||
9f4cdc950b | |||
0a0c5a90a7 | |||
011517e12d | |||
fdd82e0f91 | |||
abafe108c6 | |||
03f08e4f08 | |||
9ecb9b4819 | |||
2bb30aae69 | |||
01d219d38c | |||
6c7831d972 | |||
4ab12e33c7 | |||
364198ef08 | |||
2c81c7cfd2 | |||
3b723e5a1b | |||
6a912ee003 | |||
1644fb7682 | |||
bd4869540b | |||
31103303be | |||
e9c0cdd61c | |||
59e42029e8 | |||
b2ef2adb2a | |||
bab92f9169 | |||
cb480ed4ee | |||
6f83a45865 | |||
9e528e1f6f | |||
20d3ae0e32 | |||
ecea1265e7 | |||
c38b7a335c | |||
6ab8e40d45 | |||
d14dfee980 | |||
0a454f0b5f | |||
b7bc93e174 | |||
1dee4cc8e5 | |||
02b521c0b8 | |||
c04040e242 | |||
a208aa97b2 | |||
e3fda9457e | |||
b84631a2b2 | |||
bad06c5762 | |||
74d8966f0a | |||
d8a76936a6 | |||
e72ca4fc6f | |||
dd62212b06 | |||
8dfc12e412 |
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
|
patreon: # Replace with a single Patreon username
|
||||||
|
open_collective: # Replace with a single Open Collective username
|
||||||
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
issuehunt: # Replace with a single IssueHunt username
|
||||||
|
otechie: # Replace with a single Otechie username
|
||||||
|
custom: ['paypal.me/tommasoberlose']
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -8,3 +8,7 @@
|
|||||||
.externalNativeBuild
|
.externalNativeBuild
|
||||||
/tasksintegration/build
|
/tasksintegration/build
|
||||||
/app/google-services.json
|
/app/google-services.json
|
||||||
|
apikey.properties
|
||||||
|
./.idea/*
|
||||||
|
app/release/*
|
||||||
|
/app/release/*
|
23
.idea/assetWizardSettings.xml
generated
23
.idea/assetWizardSettings.xml
generated
@ -123,6 +123,29 @@
|
|||||||
</PersistentState>
|
</PersistentState>
|
||||||
</value>
|
</value>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry key="vectorWizard">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="children">
|
||||||
|
<map>
|
||||||
|
<entry key="vectorAssetStep">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="assetSourceType" value="FILE" />
|
||||||
|
<entry key="outputName" value="round_aspect_ratio_24" />
|
||||||
|
<entry key="sourceFile" value="$USER_HOME$/Desktop/round_aspect_ratio_24.svg" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
</map>
|
</map>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
BIN
.idea/caches/build_file_checksums.ser
generated
BIN
.idea/caches/build_file_checksums.ser
generated
Binary file not shown.
1
.idea/gradle.xml
generated
1
.idea/gradle.xml
generated
@ -14,6 +14,7 @@
|
|||||||
</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>
|
||||||
|
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@ -61,7 +61,7 @@
|
|||||||
</profile-state>
|
</profile-state>
|
||||||
</entry>
|
</entry>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
4
.idea/modules.xml
generated
4
.idea/modules.xml
generated
@ -2,8 +2,8 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<modules>
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/Another_Widget.iml" filepath="$PROJECT_DIR$/.idea/modules/Another_Widget.iml" group="Another_Widget" />
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules/Another_Widget.iml" filepath="$PROJECT_DIR$/.idea/modules/Another_Widget.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" group="Another Widget/app" />
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules/app/Another_Widget.app.iml" filepath="$PROJECT_DIR$/.idea/modules/app/Another_Widget.app.iml" />
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
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>
|
||||||
|
@ -11,7 +11,7 @@ While respecting the design of the application, there is a great opportunity to
|
|||||||
Also, as much as possible, there are always updates and new features in the short run.
|
Also, as much as possible, there are always updates and new features in the short run.
|
||||||
|
|
||||||
Help me developing with feedback and support me on how you can.
|
Help me developing with feedback and support me on how you can.
|
||||||
<div style="text-align:center"><a href="https://play.google.com/store/apps/details?id=com.tommasoberlose.anotherwidget" target="_blank"><img src="google-play-badge.png" height="100" /></a></div>
|
<div style="text-align:center"><a href='https://play.google.com/store/apps/details?id=com.tommasoberlose.anotherwidget&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' height='100px' src='https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png'/></a></div>
|
||||||
|
|
||||||
|
|
||||||
Help with translations
|
Help with translations
|
||||||
|
@ -6,22 +6,29 @@ 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'
|
apply plugin: 'realm-android'
|
||||||
|
|
||||||
|
def apikeyPropertiesFile = rootProject.file("apikey.properties")
|
||||||
|
def apikeyProperties = new Properties()
|
||||||
|
apikeyProperties.load(new FileInputStream(apikeyPropertiesFile))
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 29
|
|
||||||
|
compileSdkVersion 30
|
||||||
buildToolsVersion "29.0.3"
|
buildToolsVersion "29.0.3"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.tommasoberlose.anotherwidget"
|
applicationId "com.tommasoberlose.anotherwidget"
|
||||||
minSdkVersion 23
|
minSdkVersion 23
|
||||||
targetSdkVersion 29
|
targetSdkVersion 30
|
||||||
versionCode 105
|
versionCode 125
|
||||||
versionName "2.0.13"
|
versionName "2.2.2"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
buildConfigField("String", "GOOGLE_API_KEY", apikeyProperties['GOOGLE_API_KEY'])
|
||||||
|
|
||||||
|
renderscriptSupportModeEnabled true
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
@ -47,28 +54,29 @@ 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'
|
testImplementation 'junit:junit:4.13.1'
|
||||||
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.2.0'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
|
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||||
implementation 'com.google.android.material:material:1.3.0-alpha03'
|
implementation 'com.google.android.material:material:1.3.0-beta01'
|
||||||
implementation 'androidx.browser:browser:1.2.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'
|
||||||
@ -78,15 +86,15 @@ dependencies {
|
|||||||
implementation "androidx.work:work-runtime-ktx:2.4.0"
|
implementation "androidx.work:work-runtime-ktx:2.4.0"
|
||||||
|
|
||||||
// EventBus
|
// EventBus
|
||||||
implementation 'org.greenrobot:eventbus:3.1.1'
|
implementation 'org.greenrobot:eventbus:3.2.0'
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
implementation 'androidx.navigation:navigation-fragment:2.3.0'
|
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.2'
|
||||||
implementation 'androidx.navigation:navigation-ui-ktx:2.3.0'
|
implementation 'androidx.navigation:navigation-ui-ktx:2.3.2'
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
implementation 'androidx.multidex:multidex:2.0.1'
|
implementation 'androidx.multidex:multidex:2.0.1'
|
||||||
implementation 'joda-time:joda-time:2.10.3'
|
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'
|
||||||
|
|
||||||
@ -95,7 +103,7 @@ dependencies {
|
|||||||
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:18.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:18.1.0'
|
||||||
|
|
||||||
//Weather
|
//Weather
|
||||||
@ -103,8 +111,8 @@ dependencies {
|
|||||||
implementation 'com.google.android.gms:play-services-location:17.1.0'
|
implementation 'com.google.android.gms:play-services-location:17.1.0'
|
||||||
|
|
||||||
// Billing
|
// Billing
|
||||||
implementation 'com.android.billingclient:billing:3.0.1'
|
implementation 'com.android.billingclient:billing:3.0.2'
|
||||||
implementation 'com.android.billingclient:billing-ktx:3.0.1'
|
implementation 'com.android.billingclient:billing-ktx:3.0.2'
|
||||||
|
|
||||||
// KTX
|
// KTX
|
||||||
implementation "androidx.core:core-ktx:1.3.2"
|
implementation "androidx.core:core-ktx:1.3.2"
|
||||||
@ -112,8 +120,18 @@ dependencies {
|
|||||||
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.3.2'
|
||||||
|
|
||||||
|
//Retrofit
|
||||||
|
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
||||||
|
implementation 'com.google.code.gson:gson:2.8.6'
|
||||||
|
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
|
||||||
|
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.0'
|
||||||
|
implementation "com.github.haroldadmin:NetworkResponseAdapter:4.0.1"
|
||||||
|
|
||||||
|
//Coroutines
|
||||||
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
|
||||||
|
|
||||||
// Add the Firebase SDK for Crashlytics.
|
// Add the Firebase SDK for Crashlytics.
|
||||||
implementation 'com.google.firebase:firebase-crashlytics:17.2.2'
|
implementation 'com.google.firebase:firebase-crashlytics:17.3.0'
|
||||||
|
|
||||||
// Preferences
|
// Preferences
|
||||||
implementation 'com.chibatching.kotpref:kotpref:2.11.0'
|
implementation 'com.chibatching.kotpref:kotpref:2.11.0'
|
||||||
@ -121,5 +139,8 @@ dependencies {
|
|||||||
implementation 'androidx.preference:preference-ktx:1.1.1'
|
implementation 'androidx.preference:preference-ktx:1.1.1'
|
||||||
|
|
||||||
// Permissions
|
// Permissions
|
||||||
implementation 'com.karumi:dexter:6.1.0'
|
implementation 'com.karumi:dexter:6.2.1'
|
||||||
|
|
||||||
|
// Fonts
|
||||||
|
implementation 'com.github.firatkarababa:downloadable-font-list-library:1.0.2'
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
<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_BACKGROUND_LOCATION" />
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_FINE_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" />
|
||||||
@ -13,7 +12,7 @@
|
|||||||
<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" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
@ -22,6 +21,7 @@
|
|||||||
android:name=".AWApplication"
|
android:name=".AWApplication"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="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.MainActivity" android:launchMode="singleInstance" android:theme="@style/AppTheme.Main" android:screenOrientation="portrait">
|
||||||
@ -31,13 +31,16 @@
|
|||||||
<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.tabs.ChooseApplicationActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
<activity android:name=".ui.activities.CustomLocationActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.tabs.CustomFontActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
<activity android:name=".ui.activities.WeatherProviderActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.tabs.CustomLocationActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
<activity android:name=".ui.activities.SupportDevActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.tabs.WeatherProviderActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
<activity android:name=".ui.activities.CustomDateActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.settings.SupportDevActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
<activity android:name=".ui.activities.IntegrationsActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.tabs.CustomDateActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
|
<activity android:name=".ui.activities.settings.IntegrationsActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
|
<activity android:name=".ui.activities.tabs.MusicPlayersFilterActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
|
<activity android:name=".ui.activities.tabs.AppNotificationsFilterActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
|
<activity android:name=".ui.activities.tabs.MediaInfoFormatActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
|
|
||||||
<receiver android:name=".ui.widgets.MainWidget">
|
<receiver android:name=".ui.widgets.MainWidget">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
@ -117,7 +120,7 @@
|
|||||||
|
|
||||||
<service android:name=".services.BatteryListenerJob" android:permission="android.permission.BIND_JOB_SERVICE" />
|
<service android:name=".services.BatteryListenerJob" android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||||
|
|
||||||
<service android:name=".receivers.MusicNotificationListener"
|
<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" />
|
||||||
@ -147,9 +150,21 @@
|
|||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".services.UpdateCalendarJob"
|
android:name=".services.UpdateCalendarService"
|
||||||
android:permission="android.permission.BIND_JOB_SERVICE"
|
android:enabled="true"
|
||||||
android:exported="true"/>
|
android:exported="false"
|
||||||
|
android:foregroundServiceType="dataSync" />
|
||||||
|
<service
|
||||||
|
android:name=".services.LocationService"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="false"
|
||||||
|
android:foregroundServiceType="location" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
|
<queries>
|
||||||
|
<package android:name="com.google.android.apps.fitness"/>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
</intent>
|
||||||
|
</queries>
|
||||||
</manifest>
|
</manifest>
|
BIN
app/src/main/assets/fonts/google_sans_black.ttf
Normal file
BIN
app/src/main/assets/fonts/google_sans_black.ttf
Normal file
Binary file not shown.
BIN
app/src/main/assets/fonts/google_sans_black_italic.ttf
Normal file
BIN
app/src/main/assets/fonts/google_sans_black_italic.ttf
Normal file
Binary file not shown.
BIN
app/src/main/assets/fonts/google_sans_bold.ttf
Normal file
BIN
app/src/main/assets/fonts/google_sans_bold.ttf
Normal file
Binary file not shown.
BIN
app/src/main/assets/fonts/google_sans_bold_italic.ttf
Normal file
BIN
app/src/main/assets/fonts/google_sans_bold_italic.ttf
Normal file
Binary file not shown.
BIN
app/src/main/assets/fonts/google_sans_italic.ttf
Normal file
BIN
app/src/main/assets/fonts/google_sans_italic.ttf
Normal file
Binary file not shown.
BIN
app/src/main/assets/fonts/google_sans_light.ttf
Normal file
BIN
app/src/main/assets/fonts/google_sans_light.ttf
Normal file
Binary file not shown.
BIN
app/src/main/assets/fonts/google_sans_light_italic.ttf
Normal file
BIN
app/src/main/assets/fonts/google_sans_light_italic.ttf
Normal file
Binary file not shown.
BIN
app/src/main/assets/fonts/google_sans_medium.ttf
Normal file
BIN
app/src/main/assets/fonts/google_sans_medium.ttf
Normal file
Binary file not shown.
BIN
app/src/main/assets/fonts/google_sans_medium_italic.ttf
Normal file
BIN
app/src/main/assets/fonts/google_sans_medium_italic.ttf
Normal file
Binary file not shown.
BIN
app/src/main/assets/fonts/google_sans_regular.ttf
Normal file
BIN
app/src/main/assets/fonts/google_sans_regular.ttf
Normal file
Binary file not shown.
BIN
app/src/main/assets/fonts/google_sans_thin.ttf
Normal file
BIN
app/src/main/assets/fonts/google_sans_thin.ttf
Normal file
Binary file not shown.
BIN
app/src/main/assets/fonts/google_sans_thin_italic.ttf
Normal file
BIN
app/src/main/assets/fonts/google_sans_thin_italic.ttf
Normal file
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.
@ -1,13 +1,16 @@
|
|||||||
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 com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.RealmConfiguration
|
import io.realm.RealmConfiguration
|
||||||
|
import net.danlew.android.joda.JodaTimeAndroid
|
||||||
|
|
||||||
class AWApplication : Application() {
|
class AWApplication : Application() {
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
|
@ -6,6 +6,7 @@ import android.graphics.Color
|
|||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.text.TextWatcher
|
import android.text.TextWatcher
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.GridLayout
|
import android.widget.GridLayout
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
@ -21,18 +22,17 @@ 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.databinding.BottomSheetMenuHorBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.BottomSheetMenuListBinding
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
|
||||||
import com.tommasoberlose.anotherwidget.utils.expand
|
import com.tommasoberlose.anotherwidget.utils.expand
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||||
import com.tommasoberlose.anotherwidget.utils.reveal
|
import com.tommasoberlose.anotherwidget.utils.reveal
|
||||||
import com.tommasoberlose.anotherwidget.utils.toPixel
|
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.lang.Exception
|
||||||
@ -52,23 +52,22 @@ class BottomSheetColorPicker(
|
|||||||
private var loadingJobs: ArrayList<Job> = ArrayList()
|
private var loadingJobs: ArrayList<Job> = ArrayList()
|
||||||
private lateinit var adapter: SlimAdapter
|
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() {
|
override fun show() {
|
||||||
val view = View.inflate(context, R.layout.bottom_sheet_menu_hor, null)
|
|
||||||
|
|
||||||
window?.setDimAmount(0f)
|
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
view.header.isVisible = header != null
|
binding.header.isVisible = header != null
|
||||||
view.header_text.text = header ?: ""
|
binding.headerText.text = header ?: ""
|
||||||
|
|
||||||
// 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)
|
||||||
onAlphaChangeListener?.invoke(it.progress)
|
onAlphaChangeListener?.invoke(it.progress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,16 +82,16 @@ class BottomSheetColorPicker(
|
|||||||
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 ->
|
||||||
injector
|
injector
|
||||||
.with<MaterialCardView>(R.id.color) {
|
.with<MaterialCardView>(R.id.color) {
|
||||||
it.setCardBackgroundColor(ColorStateList.valueOf(item))
|
it.setCardBackgroundColor(ColorStateList.valueOf(item))
|
||||||
|
it.strokeWidth = if ((colors.indexOf(item) == 0 && !context.isDarkTheme()) || (colors.indexOf(item) == 10 && context.isDarkTheme())) 2 else 0
|
||||||
}
|
}
|
||||||
.with<AppCompatImageView>(R.id.check) {
|
.with<AppCompatImageView>(R.id.check) {
|
||||||
if (getSelected?.invoke() == item) {
|
if (getSelected?.invoke() == item) {
|
||||||
@ -113,22 +112,22 @@ 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.colorLoader.isVisible = false
|
||||||
view.list_container.addView(listView)
|
binding.listContainer.addView(listBinding.root)
|
||||||
this@BottomSheetColorPicker.behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
this@BottomSheetColorPicker.behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||||
view.list_container.isVisible = true
|
binding.listContainer.isVisible = true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
setContentView(view)
|
setContentView(binding.root)
|
||||||
super.show()
|
super.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
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 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.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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [BottomSheetDialogFragment] that uses a custom
|
* [BottomSheetDialogFragment] that uses a custom
|
||||||
@ -22,6 +24,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
|
||||||
@ -32,8 +36,8 @@ open class BottomSheetMenu<T>(context: Context, private val header: String? = nu
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addItem(title: String, value: T? = null): BottomSheetMenu<T> {
|
fun addItem(title: String, value: T? = null, renderCallback: ((view: TextView) -> Unit)? = null): BottomSheetMenu<T> {
|
||||||
items.add(MenuItem(title, value))
|
items.add(MenuItem(title, value, renderCallback))
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,33 +52,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()
|
||||||
@ -86,26 +88,28 @@ 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
|
||||||
) else ContextCompat.getColor(context, R.color.colorSecondaryText)
|
) else ContextCompat.getColor(context, R.color.colorSecondaryText)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
super.show()
|
super.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
class MenuItem<T>(val title: String, val value: T? = null)
|
class MenuItem<T>(val title: String, val value: T? = null, val renderCallback: ((view: TextView) -> Unit)? = null)
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.components
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.View
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.WeatherProviderSettingsLayoutBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.openURI
|
||||||
|
|
||||||
|
class BottomSheetWeatherProviderSettings(context: Context, callback: () -> Unit) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
||||||
|
|
||||||
|
private var binding: WeatherProviderSettingsLayoutBinding = WeatherProviderSettingsLayoutBinding.inflate(android.view.LayoutInflater.from(context))
|
||||||
|
|
||||||
|
init {
|
||||||
|
binding.apiKeyContainer.isVisible = WeatherHelper.isKeyRequired()
|
||||||
|
binding.actionSaveKey.isVisible = WeatherHelper.isKeyRequired()
|
||||||
|
|
||||||
|
WeatherHelper.getProviderInfoTitle(context).let { title ->
|
||||||
|
binding.infoTitle.text = title
|
||||||
|
binding.infoTitle.isVisible = title != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
WeatherHelper.getProviderInfoSubtitle(context).let { subtitle ->
|
||||||
|
binding.infoSubtitle.text = subtitle
|
||||||
|
binding.infoSubtitle.isVisible = subtitle != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.infoProvider.text = WeatherHelper.getProviderName(context)
|
||||||
|
|
||||||
|
binding.apiKey.editText?.setText(when (Constants.WeatherProvider.fromInt(Preferences.weatherProvider)) {
|
||||||
|
Constants.WeatherProvider.OPEN_WEATHER -> Preferences.weatherProviderApiOpen
|
||||||
|
Constants.WeatherProvider.WEATHER_BIT -> Preferences.weatherProviderApiWeatherBit
|
||||||
|
Constants.WeatherProvider.WEATHER_API -> Preferences.weatherProviderApiWeatherApi
|
||||||
|
Constants.WeatherProvider.HERE -> Preferences.weatherProviderApiHere
|
||||||
|
Constants.WeatherProvider.ACCUWEATHER -> Preferences.weatherProviderApiAccuweather
|
||||||
|
Constants.WeatherProvider.WEATHER_GOV,
|
||||||
|
Constants.WeatherProvider.YR,
|
||||||
|
null -> ""
|
||||||
|
})
|
||||||
|
|
||||||
|
binding.actionOpenProvider.setOnClickListener {
|
||||||
|
context.openURI(WeatherHelper.getProviderLink())
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionSaveKey.setOnClickListener {
|
||||||
|
val key = binding.apiKey.editText?.text.toString()
|
||||||
|
when (Constants.WeatherProvider.fromInt(Preferences.weatherProvider)) {
|
||||||
|
Constants.WeatherProvider.OPEN_WEATHER -> Preferences.weatherProviderApiOpen = key
|
||||||
|
Constants.WeatherProvider.WEATHER_BIT -> Preferences.weatherProviderApiWeatherBit = key
|
||||||
|
Constants.WeatherProvider.WEATHER_API -> Preferences.weatherProviderApiWeatherApi = key
|
||||||
|
Constants.WeatherProvider.HERE -> Preferences.weatherProviderApiHere = key
|
||||||
|
Constants.WeatherProvider.ACCUWEATHER -> Preferences.weatherProviderApiAccuweather = key
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
callback.invoke()
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
setContentView(binding.root)
|
||||||
|
}
|
||||||
|
}
|
@ -1,27 +1,30 @@
|
|||||||
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) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
class CustomNotesDialog(context: Context, callback: (() -> Unit)?) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
||||||
|
|
||||||
|
private var binding: CustomNotesDialogLayoutBinding = CustomNotesDialogLayoutBinding.inflate(LayoutInflater.from(context))
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val view = View.inflate(context, R.layout.custom_notes_dialog_layout, null)
|
binding.notes.setText(Preferences.customNotes)
|
||||||
view.notes.setText(Preferences.customNotes)
|
|
||||||
|
|
||||||
view.action_positive.setOnClickListener {
|
binding.actionPositive.setOnClickListener {
|
||||||
Preferences.customNotes = view.notes.text.toString()
|
Preferences.customNotes = binding.notes.text.toString()
|
||||||
this.dismiss()
|
this.dismiss()
|
||||||
|
callback?.invoke()
|
||||||
}
|
}
|
||||||
|
|
||||||
view.notes.requestFocus()
|
binding.notes.requestFocus()
|
||||||
|
|
||||||
setContentView(view)
|
setContentView(binding.root)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,13 +6,14 @@ import android.util.AttributeSet
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ScrollView
|
import android.widget.ScrollView
|
||||||
|
import androidx.core.widget.NestedScrollView
|
||||||
|
|
||||||
|
|
||||||
class FixedFocusScrollView @JvmOverloads constructor(
|
class FixedFocusScrollView @JvmOverloads constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
attrs: AttributeSet? = null,
|
attrs: AttributeSet? = null,
|
||||||
defStyle: Int = 0
|
defStyle: Int = 0
|
||||||
) : ScrollView(context, attrs, defStyle) {
|
) : NestedScrollView(context, attrs, defStyle) {
|
||||||
|
|
||||||
var isScrollable = true
|
var isScrollable = true
|
||||||
|
|
||||||
|
@ -1,98 +0,0 @@
|
|||||||
package com.tommasoberlose.anotherwidget.components
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.res.ColorStateList
|
|
||||||
import android.view.View
|
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.appcompat.widget.AppCompatImageView
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
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.global.Constants
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.GlanceProviderHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.models.GlanceProvider
|
|
||||||
import kotlinx.android.synthetic.main.glance_provider_sort_bottom_menu.view.*
|
|
||||||
import kotlinx.coroutines.*
|
|
||||||
import net.idik.lib.slimadapter.SlimAdapter
|
|
||||||
import java.util.*
|
|
||||||
import kotlin.collections.ArrayList
|
|
||||||
|
|
||||||
class GlanceProviderSortMenu(
|
|
||||||
context: Context
|
|
||||||
) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
|
||||||
|
|
||||||
private lateinit var adapter: SlimAdapter
|
|
||||||
|
|
||||||
override fun show() {
|
|
||||||
val view = View.inflate(context, R.layout.glance_provider_sort_bottom_menu, null)
|
|
||||||
|
|
||||||
// Header
|
|
||||||
view.header_text.text = context.getString(R.string.settings_sort_glance_providers_title)
|
|
||||||
|
|
||||||
// List
|
|
||||||
adapter = SlimAdapter.create()
|
|
||||||
|
|
||||||
view.menu.setHasFixedSize(true)
|
|
||||||
val mLayoutManager = LinearLayoutManager(context)
|
|
||||||
view.menu.layoutManager = mLayoutManager
|
|
||||||
|
|
||||||
adapter = SlimAdapter.create()
|
|
||||||
adapter
|
|
||||||
.register<GlanceProvider>(R.layout.glance_provider_item) { item, injector ->
|
|
||||||
injector
|
|
||||||
.text(R.id.title, item.title)
|
|
||||||
.with<ImageView>(R.id.icon) {
|
|
||||||
it.setImageDrawable(ContextCompat.getDrawable(context, item.icon))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.attachTo(view.menu)
|
|
||||||
|
|
||||||
val mIth = ItemTouchHelper(
|
|
||||||
object : ItemTouchHelper.SimpleCallback(
|
|
||||||
ItemTouchHelper.UP or ItemTouchHelper.DOWN,
|
|
||||||
ItemTouchHelper.LEFT
|
|
||||||
) {
|
|
||||||
override fun onMove(
|
|
||||||
recyclerView: RecyclerView,
|
|
||||||
viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder
|
|
||||||
): Boolean {
|
|
||||||
val fromPos = viewHolder.adapterPosition
|
|
||||||
val toPos = target.adapterPosition
|
|
||||||
// move item in `fromPos` to `toPos` in adapter.
|
|
||||||
adapter.notifyItemMoved(fromPos, toPos)
|
|
||||||
|
|
||||||
val list = GlanceProviderHelper.getGlanceProviders(context)
|
|
||||||
Collections.swap(list, fromPos, toPos)
|
|
||||||
GlanceProviderHelper.saveGlanceProviderOrder(list)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSwiped(
|
|
||||||
viewHolder: RecyclerView.ViewHolder,
|
|
||||||
direction: Int
|
|
||||||
) {
|
|
||||||
// remove from adapter
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
mIth.attachToRecyclerView(view.menu)
|
|
||||||
|
|
||||||
adapter.updateData(
|
|
||||||
GlanceProviderHelper.getGlanceProviders(context)
|
|
||||||
.mapNotNull { GlanceProviderHelper.getGlanceProviderById(context, it) }
|
|
||||||
)
|
|
||||||
|
|
||||||
setContentView(view)
|
|
||||||
super.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,383 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.components
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.AlarmManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Build
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.navigation.Navigation
|
||||||
|
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.GoogleSignInOptions
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
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.GlanceProviderSettingsLayoutBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.AlarmHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.GreetingsHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.tabs.AppNotificationsFilterActivity
|
||||||
|
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.utils.checkGrantedPermission
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
|
||||||
|
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() {
|
||||||
|
|
||||||
|
/* TITLE */
|
||||||
|
binding.title.text = when (provider) {
|
||||||
|
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.BATTERY_LEVEL_LOW -> context.getString(R.string.settings_low_battery_level_title)
|
||||||
|
Constants.GlanceProviderId.CUSTOM_INFO -> context.getString(R.string.settings_custom_notes_title)
|
||||||
|
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> context.getString(R.string.settings_daily_steps_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.EVENTS -> context.getString(R.string.settings_show_events_as_glance_provider_title)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SUBTITLE*/
|
||||||
|
binding.subtitle.text = when (provider) {
|
||||||
|
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.BATTERY_LEVEL_LOW -> context.getString(R.string.settings_low_battery_level_subtitle)
|
||||||
|
Constants.GlanceProviderId.CUSTOM_INFO -> ""
|
||||||
|
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> context.getString(R.string.settings_daily_steps_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.EVENTS -> context.getString(R.string.settings_show_events_as_glance_provider_subtitle)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SONG */
|
||||||
|
binding.actionFilterMusicPlayers.isVisible = provider == Constants.GlanceProviderId.PLAYING_SONG
|
||||||
|
binding.actionChangeMediaInfoFormat.isVisible = provider == Constants.GlanceProviderId.PLAYING_SONG
|
||||||
|
if (provider == Constants.GlanceProviderId.PLAYING_SONG) {
|
||||||
|
binding.actionFilterMusicPlayers.setOnClickListener {
|
||||||
|
dismiss()
|
||||||
|
context.startActivityForResult(Intent(context, MusicPlayersFilterActivity::class.java), 0)
|
||||||
|
}
|
||||||
|
binding.actionChangeMediaInfoFormat.setOnClickListener {
|
||||||
|
dismiss()
|
||||||
|
context.startActivityForResult(Intent(context, MediaInfoFormatActivity::class.java), 0)
|
||||||
|
}
|
||||||
|
checkNotificationPermission()
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ALARM */
|
||||||
|
binding.alarmSetByContainer.isVisible = provider == Constants.GlanceProviderId.NEXT_CLOCK_ALARM
|
||||||
|
if (provider == Constants.GlanceProviderId.NEXT_CLOCK_ALARM) {
|
||||||
|
binding.header.text = context.getString(R.string.information_header)
|
||||||
|
binding.warningContainer.isVisible = false
|
||||||
|
checkNextAlarm()
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GOOGLE STEPS */
|
||||||
|
binding.actionToggleGoogleFit.isVisible = provider == Constants.GlanceProviderId.GOOGLE_FIT_STEPS
|
||||||
|
if (provider == Constants.GlanceProviderId.GOOGLE_FIT_STEPS) {
|
||||||
|
binding.warningContainer.isVisible = false
|
||||||
|
checkFitnessPermission()
|
||||||
|
checkGoogleFitConnection()
|
||||||
|
}
|
||||||
|
|
||||||
|
/* BATTERY INFO */
|
||||||
|
if (provider == Constants.GlanceProviderId.BATTERY_LEVEL_LOW) {
|
||||||
|
binding.warningContainer.isVisible = false
|
||||||
|
binding.header.isVisible = false
|
||||||
|
binding.divider.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTIFICATIONS */
|
||||||
|
binding.actionFilterNotificationsApp.isVisible = provider == Constants.GlanceProviderId.NOTIFICATIONS
|
||||||
|
binding.actionChangeNotificationTimer.isVisible = provider == Constants.GlanceProviderId.NOTIFICATIONS
|
||||||
|
if (provider == Constants.GlanceProviderId.NOTIFICATIONS) {
|
||||||
|
checkLastNotificationsPermission()
|
||||||
|
val stringArray = context.resources.getStringArray(R.array.glance_notifications_timeout)
|
||||||
|
binding.actionFilterNotificationsApp.setOnClickListener {
|
||||||
|
dismiss()
|
||||||
|
context.startActivityForResult(Intent(context, AppNotificationsFilterActivity::class.java), 0)
|
||||||
|
}
|
||||||
|
binding.notificationTimerLabel.text = stringArray[Preferences.hideNotificationAfter]
|
||||||
|
binding.actionChangeNotificationTimer.setOnClickListener {
|
||||||
|
val dialog = BottomSheetMenu<Int>(context, header = context.getString(R.string.glance_notification_hide_timeout_title)).setSelectedValue(Preferences.hideNotificationAfter)
|
||||||
|
Constants.GlanceNotificationTimer.values().forEachIndexed { index, timeout ->
|
||||||
|
dialog.addItem(stringArray[index], timeout.value)
|
||||||
|
}
|
||||||
|
dialog.addOnSelectItemListener { value ->
|
||||||
|
Preferences.hideNotificationAfter = value
|
||||||
|
this.show()
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GREETINGS */
|
||||||
|
if (provider == Constants.GlanceProviderId.GREETINGS) {
|
||||||
|
binding.warningContainer.isVisible = false
|
||||||
|
binding.header.isVisible = false
|
||||||
|
binding.divider.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/* EVENTS */
|
||||||
|
if (provider == Constants.GlanceProviderId.EVENTS) {
|
||||||
|
binding.header.isVisible = false
|
||||||
|
binding.divider.isVisible = false
|
||||||
|
checkCalendarConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TOGGLE */
|
||||||
|
binding.providerSwitch.setCheckedImmediatelyNoEvent(when (provider) {
|
||||||
|
Constants.GlanceProviderId.PLAYING_SONG -> Preferences.showMusic
|
||||||
|
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> Preferences.showNextAlarm
|
||||||
|
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> Preferences.showBatteryCharging
|
||||||
|
Constants.GlanceProviderId.CUSTOM_INFO -> true
|
||||||
|
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> Preferences.showDailySteps
|
||||||
|
Constants.GlanceProviderId.NOTIFICATIONS -> Preferences.showNotifications
|
||||||
|
Constants.GlanceProviderId.GREETINGS -> Preferences.showGreetings
|
||||||
|
Constants.GlanceProviderId.EVENTS -> Preferences.showEventsAsGlanceProvider
|
||||||
|
})
|
||||||
|
|
||||||
|
var job: Job? = null
|
||||||
|
|
||||||
|
binding.providerSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
job?.cancel()
|
||||||
|
job = GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
delay(300)
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
when (provider) {
|
||||||
|
Constants.GlanceProviderId.PLAYING_SONG -> {
|
||||||
|
Preferences.showMusic = isChecked
|
||||||
|
checkNotificationPermission()
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
|
||||||
|
Preferences.showNextAlarm = isChecked
|
||||||
|
checkNextAlarm()
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
||||||
|
Preferences.showBatteryCharging = isChecked
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.NOTIFICATIONS -> {
|
||||||
|
Preferences.showNotifications = isChecked
|
||||||
|
checkLastNotificationsPermission()
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.GREETINGS -> {
|
||||||
|
Preferences.showGreetings = isChecked
|
||||||
|
GreetingsHelper.toggleGreetings(context)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
|
||||||
|
if (isChecked) {
|
||||||
|
val account: GoogleSignInAccount? =
|
||||||
|
GoogleSignIn.getLastSignedInAccount(context)
|
||||||
|
if (!GoogleSignIn.hasPermissions(account,
|
||||||
|
ActivityDetectionReceiver.FITNESS_OPTIONS
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
val mGoogleSignInClient =
|
||||||
|
GoogleSignIn.getClient(context, GoogleSignInOptions.Builder(
|
||||||
|
GoogleSignInOptions.DEFAULT_SIGN_IN).addExtension(
|
||||||
|
ActivityDetectionReceiver.FITNESS_OPTIONS
|
||||||
|
).build())
|
||||||
|
context.startActivityForResult(mGoogleSignInClient.signInIntent,
|
||||||
|
2)
|
||||||
|
} else {
|
||||||
|
Preferences.showDailySteps = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Preferences.showDailySteps = false
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.warningContainer.isVisible = false
|
||||||
|
checkFitnessPermission()
|
||||||
|
checkGoogleFitConnection()
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.EVENTS -> {
|
||||||
|
Preferences.showEventsAsGlanceProvider = isChecked
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statusCallback?.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setContentView(binding.root)
|
||||||
|
super.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkNextAlarm() {
|
||||||
|
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
|
val alarm = nextAlarmClock
|
||||||
|
if (alarm != null && alarm.showIntent != null) {
|
||||||
|
val pm = context.packageManager as PackageManager
|
||||||
|
val appNameOrPackage = try {
|
||||||
|
pm.getApplicationLabel(pm.getApplicationInfo(alarm.showIntent?.creatorPackage ?: "", 0))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
alarm.showIntent?.creatorPackage ?: ""
|
||||||
|
}
|
||||||
|
binding.alarmSetByTitle.text = context.getString(R.string.settings_show_next_alarm_app_title).format(appNameOrPackage)
|
||||||
|
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)
|
||||||
|
binding.alarmSetByContainer.isVisible = true
|
||||||
|
} else {
|
||||||
|
binding.alarmSetByContainer.isVisible = false
|
||||||
|
binding.header.isVisible = false
|
||||||
|
binding.divider.isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statusCallback?.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkCalendarConfig() {
|
||||||
|
if (!Preferences.showEvents || !context.checkGrantedPermission(Manifest.permission.READ_CALENDAR)) {
|
||||||
|
binding.warningContainer.isVisible = true
|
||||||
|
binding.warningTitle.text = context.getString(R.string.settings_show_events_as_glance_provider_error)
|
||||||
|
binding.warningContainer.setOnClickListener {
|
||||||
|
dismiss()
|
||||||
|
EventBus.getDefault().post(MainFragment.ChangeTabEvent(1))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
binding.warningContainer.isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkNotificationPermission() {
|
||||||
|
when {
|
||||||
|
ActiveNotificationsHelper.checkNotificationAccess(context) -> {
|
||||||
|
binding.warningContainer.isVisible = false
|
||||||
|
MediaPlayerHelper.updatePlayingMediaInfo(context)
|
||||||
|
}
|
||||||
|
Preferences.showMusic -> {
|
||||||
|
binding.warningContainer.isVisible = true
|
||||||
|
binding.warningTitle.text = context.getString(R.string.settings_request_notification_access)
|
||||||
|
binding.warningContainer.setOnClickListener {
|
||||||
|
context.startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
binding.warningContainer.isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statusCallback?.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkLastNotificationsPermission() {
|
||||||
|
when {
|
||||||
|
ActiveNotificationsHelper.checkNotificationAccess(context) -> {
|
||||||
|
binding.warningContainer.isVisible = false
|
||||||
|
}
|
||||||
|
Preferences.showNotifications -> {
|
||||||
|
binding.warningContainer.isVisible = true
|
||||||
|
binding.warningTitle.text = context.getString(R.string.settings_request_last_notification_access)
|
||||||
|
binding.warningContainer.setOnClickListener {
|
||||||
|
context.startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
binding.warningContainer.isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statusCallback?.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkFitnessPermission() {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || context.checkGrantedPermission(
|
||||||
|
Manifest.permission.ACTIVITY_RECOGNITION)
|
||||||
|
) {
|
||||||
|
if (Preferences.showDailySteps) {
|
||||||
|
ActivityDetectionReceiver.registerFence(context)
|
||||||
|
} else {
|
||||||
|
ActivityDetectionReceiver.unregisterFence(context)
|
||||||
|
}
|
||||||
|
} else if (Preferences.showDailySteps) {
|
||||||
|
ActivityDetectionReceiver.unregisterFence(context)
|
||||||
|
binding.warningContainer.isVisible = true
|
||||||
|
binding.warningTitle.text = context.getString(R.string.settings_request_fitness_access)
|
||||||
|
binding.warningContainer.setOnClickListener {
|
||||||
|
requireFitnessPermission()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ActivityDetectionReceiver.unregisterFence(context)
|
||||||
|
}
|
||||||
|
statusCallback?.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkGoogleFitConnection() {
|
||||||
|
val account: GoogleSignInAccount? = GoogleSignIn.getLastSignedInAccount(context)
|
||||||
|
if (!GoogleSignIn.hasPermissions(account,
|
||||||
|
ActivityDetectionReceiver.FITNESS_OPTIONS
|
||||||
|
)) {
|
||||||
|
binding.warningContainer.isVisible = true
|
||||||
|
binding.warningTitle.text = context.getString(R.string.settings_request_fitness_access)
|
||||||
|
binding.warningContainer.setOnClickListener {
|
||||||
|
GoogleSignIn.requestPermissions(
|
||||||
|
context,
|
||||||
|
1,
|
||||||
|
account,
|
||||||
|
ActivityDetectionReceiver.FITNESS_OPTIONS)
|
||||||
|
}
|
||||||
|
binding.actionConnectToGoogleFit.isVisible = true
|
||||||
|
binding.actionDisconnectToGoogleFit.isVisible = false
|
||||||
|
binding.actionConnectToGoogleFit.setOnClickListener {
|
||||||
|
GoogleSignIn.requestPermissions(
|
||||||
|
context,
|
||||||
|
1,
|
||||||
|
account,
|
||||||
|
ActivityDetectionReceiver.FITNESS_OPTIONS)
|
||||||
|
}
|
||||||
|
binding.actionDisconnectToGoogleFit.setOnClickListener(null)
|
||||||
|
binding.googleFitStatusLabel.text = context.getString(R.string.google_fit_account_not_connected)
|
||||||
|
} else {
|
||||||
|
binding.actionConnectToGoogleFit.isVisible = false
|
||||||
|
binding.actionDisconnectToGoogleFit.isVisible = true
|
||||||
|
binding.actionConnectToGoogleFit.setOnClickListener(null)
|
||||||
|
binding.actionDisconnectToGoogleFit.setOnClickListener {
|
||||||
|
GoogleSignIn.getClient(context, GoogleSignInOptions.Builder(
|
||||||
|
GoogleSignInOptions.DEFAULT_SIGN_IN).addExtension(
|
||||||
|
ActivityDetectionReceiver.FITNESS_OPTIONS
|
||||||
|
).build()).signOut().addOnCompleteListener {
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binding.googleFitStatusLabel.text = context.getString(R.string.google_fit_account_connected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun requireFitnessPermission() {
|
||||||
|
Dexter.withContext(context)
|
||||||
|
.withPermissions(
|
||||||
|
"com.google.android.gms.permission.ACTIVITY_RECOGNITION",
|
||||||
|
"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 {
|
||||||
|
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
||||||
|
checkFitnessPermission()
|
||||||
|
}
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
@ -1,43 +1,42 @@
|
|||||||
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.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.value + 1)
|
||||||
itemView.isSelected = item.value == Preferences.weatherIconPack
|
itemBinding.root.isSelected = item.value == Preferences.weatherIconPack
|
||||||
|
|
||||||
itemView.icon_1.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource("01d", item.value)))
|
itemBinding.icon1.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource(context, "01d", item.value)))
|
||||||
itemView.icon_2.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource("01n", item.value)))
|
itemBinding.icon2.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource(context, "01n", item.value)))
|
||||||
itemView.icon_3.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource("10d", item.value)))
|
itemBinding.icon3.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource(context, "10d", item.value)))
|
||||||
itemView.icon_4.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource("09n", item.value)))
|
itemBinding.icon4.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource(context, "09n", item.value)))
|
||||||
|
|
||||||
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 +44,13 @@ class IconPackSelector(context: Context, private val header: String? = null) : B
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
itemView.setOnClickListener {
|
itemBinding.root.setOnClickListener {
|
||||||
Preferences.weatherIconPack = item.value
|
Preferences.weatherIconPack = item.value
|
||||||
this.dismiss()
|
this.dismiss()
|
||||||
}
|
}
|
||||||
view.menu.addView(itemView)
|
binding.menu.addView(itemBinding.root)
|
||||||
}
|
}
|
||||||
setContentView(view)
|
setContentView(binding.root)
|
||||||
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,28 @@ 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)
|
||||||
super.show()
|
super.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ import kotlin.collections.ArrayList
|
|||||||
class EventRepository(val context: Context) {
|
class EventRepository(val context: Context) {
|
||||||
private val realm by lazy { Realm.getDefaultInstance() }
|
private val realm by lazy { Realm.getDefaultInstance() }
|
||||||
|
|
||||||
fun saveEvents(eventList: ArrayList<Event>) {
|
fun saveEvents(eventList: List<Event>) {
|
||||||
realm.executeTransaction { realm ->
|
realm.executeTransaction { realm ->
|
||||||
realm.where(Event::class.java).findAll().deleteAllFromRealm()
|
realm.where(Event::class.java).findAll().deleteAllFromRealm()
|
||||||
realm.copyToRealm(eventList)
|
realm.copyToRealm(eventList)
|
||||||
|
@ -2,13 +2,17 @@ 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_CALENDAR_UPDATE = "com.tommasoberlose.anotherwidget.action.CALENDAR_UPDATE"
|
const val ACTION_CALENDAR_UPDATE = "com.tommasoberlose.anotherwidget.action.CALENDAR_UPDATE"
|
||||||
const val ACTION_WEATHER_UPDATE = "com.tommasoberlose.anotherwidget.action.WEATHER_UPDATE"
|
const val ACTION_WEATHER_UPDATE = "com.tommasoberlose.anotherwidget.action.WEATHER_UPDATE"
|
||||||
const val ACTION_OPEN_WEATHER_INTENT = "com.tommasoberlose.anotherwidget.action.OPEN_WEATHER_INTENT"
|
const val ACTION_OPEN_WEATHER_INTENT = "com.tommasoberlose.anotherwidget.action.OPEN_WEATHER_INTENT"
|
||||||
const val ACTION_GO_TO_NEXT_EVENT = "com.tommasoberlose.anotherwidget.action.GO_TO_NEXT_EVENT"
|
const val ACTION_GO_TO_NEXT_EVENT = "com.tommasoberlose.anotherwidget.action.GO_TO_NEXT_EVENT"
|
||||||
const val ACTION_GO_TO_PREVIOUS_EVENT = "com.tommasoberlose.anotherwidget.action.GO_TO_PREVIOUS_EVENT"
|
const val ACTION_GO_TO_PREVIOUS_EVENT = "com.tommasoberlose.anotherwidget.action.GO_TO_PREVIOUS_EVENT"
|
||||||
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_UPDATE_GREETINGS = "com.tommasoberlose.anotherwidget.action.UPDATE_GREETINGS"
|
||||||
|
|
||||||
|
const val ACTION_REFRESH = "com.tommasoberlose.anotherwidget.action.REFRESH"
|
||||||
}
|
}
|
@ -7,7 +7,10 @@ object Constants {
|
|||||||
const val RESULT_APP_NAME = "RESULT_APP_NAME"
|
const val RESULT_APP_NAME = "RESULT_APP_NAME"
|
||||||
const val RESULT_APP_PACKAGE = "RESULT_APP_PACKAGE"
|
const val RESULT_APP_PACKAGE = "RESULT_APP_PACKAGE"
|
||||||
|
|
||||||
const val CUSTOM_FONT_PRODUCT_SANS = 1
|
const val CUSTOM_FONT_GOOGLE_SANS = 1
|
||||||
|
const val CUSTOM_FONT_DOWNLOADED = 2
|
||||||
|
const val CUSTOM_FONT_DOWNLOAD_NEW = 3
|
||||||
|
|
||||||
enum class ClockBottomMargin(val value: Int) {
|
enum class ClockBottomMargin(val value: Int) {
|
||||||
NONE(0),
|
NONE(0),
|
||||||
SMALL(1),
|
SMALL(1),
|
||||||
@ -27,7 +30,15 @@ object Constants {
|
|||||||
NEXT_CLOCK_ALARM("NEXT_CLOCK_ALARM"),
|
NEXT_CLOCK_ALARM("NEXT_CLOCK_ALARM"),
|
||||||
BATTERY_LEVEL_LOW("BATTERY_LEVEL_LOW"),
|
BATTERY_LEVEL_LOW("BATTERY_LEVEL_LOW"),
|
||||||
CUSTOM_INFO("CUSTOM_INFO"),
|
CUSTOM_INFO("CUSTOM_INFO"),
|
||||||
GOOGLE_FIT_STEPS("GOOGLE_FIT_STEPS")
|
GOOGLE_FIT_STEPS("GOOGLE_FIT_STEPS"),
|
||||||
|
NOTIFICATIONS("NOTIFICATIONS"),
|
||||||
|
GREETINGS("GREETINGS"),
|
||||||
|
EVENTS("EVENTS");
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val map = GlanceProviderId.values().associateBy(GlanceProviderId::id)
|
||||||
|
fun from(type: String) = map[type]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class WidgetUpdateFrequency(val value: Int) {
|
enum class WidgetUpdateFrequency(val value: Int) {
|
||||||
@ -36,6 +47,35 @@ object Constants {
|
|||||||
HIGH(2)
|
HIGH(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class WeatherProvider(val value: Int) {
|
||||||
|
OPEN_WEATHER(0),
|
||||||
|
WEATHER_BIT(1),
|
||||||
|
WEATHER_API(2),
|
||||||
|
HERE(3),
|
||||||
|
ACCUWEATHER(4),
|
||||||
|
WEATHER_GOV(5),
|
||||||
|
YR(6);
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val map = WeatherProvider.values().associateBy(WeatherProvider::value)
|
||||||
|
fun fromInt(type: Int) = map[type]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class GlanceNotificationTimer(val value: Int) {
|
||||||
|
HALF_MINUTE(0),
|
||||||
|
ONE_MINUTE(1),
|
||||||
|
FIVE_MINUTES(2),
|
||||||
|
TEN_MINUTES(3),
|
||||||
|
FIFTEEN_MINUTES(4),
|
||||||
|
WHEN_DISMISSED(5);
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val map = values().associateBy(GlanceNotificationTimer::value)
|
||||||
|
fun fromInt(type: Int) = map[type]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum class WeatherIconPack(val value: Int) {
|
enum class WeatherIconPack(val value: Int) {
|
||||||
DEFAULT(0),
|
DEFAULT(0),
|
||||||
MINIMAL(1),
|
MINIMAL(1),
|
||||||
|
@ -2,7 +2,12 @@ package com.tommasoberlose.anotherwidget.global
|
|||||||
|
|
||||||
import android.os.Build
|
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
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
object Preferences : KotprefModel() {
|
object Preferences : KotprefModel() {
|
||||||
override val commitAllPropertiesByDefault: Boolean = true
|
override val commitAllPropertiesByDefault: Boolean = true
|
||||||
@ -14,8 +19,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 = "")
|
||||||
|
|
||||||
@ -38,7 +43,14 @@ object Preferences : KotprefModel() {
|
|||||||
var calendarAppPackage by stringPref(key = "PREF_CALENDAR_APP_PACKAGE", default = "")
|
var calendarAppPackage by stringPref(key = "PREF_CALENDAR_APP_PACKAGE", default = "")
|
||||||
var weatherAppName by stringPref(key = "PREF_WEATHER_APP_NAME", default = "")
|
var weatherAppName by stringPref(key = "PREF_WEATHER_APP_NAME", default = "")
|
||||||
var weatherAppPackage by stringPref(key = "PREF_WEATHER_APP_PACKAGE", default = "")
|
var weatherAppPackage by stringPref(key = "PREF_WEATHER_APP_PACKAGE", default = "")
|
||||||
var weatherProviderApi by stringPref(key = "PREF_WEATHER_PROVIDER_API_KEY", default = "")
|
var weatherProviderApiOpen by stringPref(key = "PREF_WEATHER_PROVIDER_API_KEY", default = "")
|
||||||
|
var weatherProviderApiHere by stringPref(default = "")
|
||||||
|
var weatherProviderApiWeatherApi by stringPref(default = "")
|
||||||
|
var weatherProviderApiWeatherBit by stringPref(default = "")
|
||||||
|
var weatherProviderApiAccuweather by stringPref(default = "")
|
||||||
|
var weatherProvider by intPref(default = if (ConfigurationCompat.getLocales(context.resources.configuration)[0].isMetric()) Constants.WeatherProvider.YR.value else Constants.WeatherProvider.WEATHER_GOV.value)
|
||||||
|
var weatherProviderError 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)
|
||||||
@ -91,36 +103,47 @@ object Preferences : KotprefModel() {
|
|||||||
var showAcceptedEvents by booleanPref(default = true)
|
var showAcceptedEvents by booleanPref(default = true)
|
||||||
var showOnlyBusyEvents by booleanPref(default = false)
|
var showOnlyBusyEvents by booleanPref(default = false)
|
||||||
var secondRowInformation by intPref(key = "PREF_SECOND_ROW_INFORMATION", default = 0)
|
var secondRowInformation by intPref(key = "PREF_SECOND_ROW_INFORMATION", default = 0)
|
||||||
var customFont by intPref(key = "PREF_CUSTOM_FONT", default = Constants.CUSTOM_FONT_PRODUCT_SANS)
|
var customFont by intPref(key = "PREF_CUSTOM_FONT", default = Constants.CUSTOM_FONT_GOOGLE_SANS)
|
||||||
var customFontFile by stringPref(key = "PREF_CUSTOM_FONT_FILE")
|
var customFontFile by stringPref(default = "")
|
||||||
|
var customFontName by stringPref(default = "")
|
||||||
|
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 showDividers by booleanPref(default = true)
|
var showDividers by booleanPref(default = true)
|
||||||
|
|
||||||
// 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)
|
||||||
var googleFitSteps by longPref(default = -1)
|
var googleFitSteps by longPref(default = -1)
|
||||||
var showDailySteps by booleanPref(default = false)
|
var showDailySteps by booleanPref(default = false)
|
||||||
|
var showGreetings by booleanPref(default = false)
|
||||||
|
var showNotifications by booleanPref(default = false)
|
||||||
|
var hideNotificationAfter by intPref(default = Constants.GlanceNotificationTimer.ONE_MINUTE.value)
|
||||||
|
|
||||||
|
var lastNotificationId by intPref(default = -1)
|
||||||
|
var lastNotificationTitle by stringPref(default = "")
|
||||||
|
var lastNotificationIcon by intPref(default = 0)
|
||||||
|
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 appNotificationsFilter by stringPref(default = "")
|
||||||
|
|
||||||
|
var showEventsAsGlanceProvider by booleanPref(default = false)
|
||||||
|
|
||||||
// Integrations
|
// Integrations
|
||||||
var installedIntegrations by intPref(default = 0)
|
var installedIntegrations by intPref(default = 0)
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.helpers
|
||||||
|
|
||||||
|
import android.content.ContentResolver
|
||||||
|
import android.content.Context
|
||||||
|
import android.provider.Settings
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.core.app.NotificationManagerCompat
|
||||||
|
import com.chibatching.kotpref.Kotpref
|
||||||
|
import com.chibatching.kotpref.blockingBulk
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.receivers.NotificationListener
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
|
|
||||||
|
object ActiveNotificationsHelper {
|
||||||
|
fun showLastNotification(): Boolean {
|
||||||
|
return Preferences.lastNotificationId != -1 && Preferences.lastNotificationIcon != 0 && Preferences.lastNotificationPackage.isNotBlank() && Preferences.lastNotificationTitle.isNotBlank()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearLastNotification(context: Context) {
|
||||||
|
Kotpref.init(context)
|
||||||
|
Preferences.blockingBulk {
|
||||||
|
remove(Preferences::lastNotificationId)
|
||||||
|
remove(Preferences::lastNotificationTitle)
|
||||||
|
remove(Preferences::lastNotificationPackage)
|
||||||
|
remove(Preferences::lastNotificationIcon)
|
||||||
|
}
|
||||||
|
MainWidget.updateWidget(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun checkNotificationAccess(context: Context): Boolean {
|
||||||
|
val contentResolver: ContentResolver = context.contentResolver
|
||||||
|
val enabledNotificationListeners =
|
||||||
|
Settings.Secure.getString(contentResolver, "enabled_notification_listeners")
|
||||||
|
val packageName: String = context.packageName
|
||||||
|
return NotificationManagerCompat.getEnabledListenerPackages(context).contains(packageName) && (enabledNotificationListeners != null && enabledNotificationListeners.contains(NotificationListener::class.java.name))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isAppAccepted(appPkg: String): Boolean = Preferences.appNotificationsFilter == "" || Preferences.appNotificationsFilter.contains(appPkg)
|
||||||
|
|
||||||
|
fun toggleAppFilter(appPkg: String) {
|
||||||
|
if (Preferences.appNotificationsFilter == "" || !Preferences.appNotificationsFilter.contains(appPkg)) {
|
||||||
|
Preferences.appNotificationsFilter = Preferences.appNotificationsFilter.split(",").union(listOf(appPkg)).joinToString(separator = ",")
|
||||||
|
} else {
|
||||||
|
Preferences.appNotificationsFilter = Preferences.appNotificationsFilter.split(",").filter { it != appPkg }.joinToString(separator = ",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,14 @@
|
|||||||
package com.tommasoberlose.anotherwidget.helpers
|
package com.tommasoberlose.anotherwidget.helpers
|
||||||
|
|
||||||
import android.app.AlarmManager
|
import android.app.AlarmManager
|
||||||
|
import android.app.PendingIntent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.text.format.DateFormat
|
import android.text.format.DateFormat
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Actions
|
||||||
|
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
|
||||||
|
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@ -14,6 +19,7 @@ object AlarmHelper {
|
|||||||
alarm != null
|
alarm != null
|
||||||
&& alarm.triggerTime - Calendar.getInstance().timeInMillis > 5 * 60 * 1000
|
&& alarm.triggerTime - Calendar.getInstance().timeInMillis > 5 * 60 * 1000
|
||||||
) {
|
) {
|
||||||
|
setTimeout(context, alarm.triggerTime)
|
||||||
"%s %s".format(
|
"%s %s".format(
|
||||||
SimpleDateFormat("EEE", Locale.getDefault()).format(alarm.triggerTime),
|
SimpleDateFormat("EEE", Locale.getDefault()).format(alarm.triggerTime),
|
||||||
DateFormat.getTimeFormat(context).format(Date(alarm.triggerTime))
|
DateFormat.getTimeFormat(context).format(Date(alarm.triggerTime))
|
||||||
@ -32,4 +38,25 @@ object AlarmHelper {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setTimeout(context: Context, trigger: Long) {
|
||||||
|
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, 0))
|
||||||
|
setExact(
|
||||||
|
AlarmManager.RTC,
|
||||||
|
trigger,
|
||||||
|
PendingIntent.getBroadcast(
|
||||||
|
context,
|
||||||
|
ALARM_UPDATE_ID,
|
||||||
|
intent,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val ALARM_UPDATE_ID = 24953
|
||||||
}
|
}
|
@ -1,29 +1,16 @@
|
|||||||
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.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.UpdateCalendarService
|
||||||
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 +19,7 @@ import kotlin.collections.ArrayList
|
|||||||
|
|
||||||
object CalendarHelper {
|
object CalendarHelper {
|
||||||
fun updateEventList(context: Context) {
|
fun updateEventList(context: Context) {
|
||||||
UpdateCalendarJob.enqueueWork(context, Intent())
|
UpdateCalendarService.enqueueWork(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCalendarList(context: Context): List<me.everything.providers.android.calendar.Calendar> {
|
fun getCalendarList(context: Context): List<me.everything.providers.android.calendar.Calendar> {
|
||||||
@ -80,4 +67,27 @@ object CalendarHelper {
|
|||||||
.filter { (!Preferences.showOnlyBusyEvents || it.availability != CalendarContract.EventsEntity.AVAILABILITY_FREE) }
|
.filter { (!Preferences.showOnlyBusyEvents || it.availability != CalendarContract.EventsEntity.AVAILABILITY_FREE) }
|
||||||
.toList()
|
.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun List<Event>.sortEvents(): List<Event> {
|
||||||
|
return sortedWith { event: Event, event1: Event ->
|
||||||
|
val date = Calendar.getInstance().apply { timeInMillis = event.startDate }
|
||||||
|
val date1 = Calendar.getInstance().apply { timeInMillis = event1.startDate }
|
||||||
|
|
||||||
|
if (date.get(Calendar.DAY_OF_YEAR) == date1.get(Calendar.DAY_OF_YEAR) && date.get(
|
||||||
|
Calendar.YEAR) == date1.get(Calendar.YEAR)
|
||||||
|
) {
|
||||||
|
if (event.allDay && event1.allDay) {
|
||||||
|
event.startDate.compareTo(event1.startDate)
|
||||||
|
} else if (event.allDay) {
|
||||||
|
1
|
||||||
|
} else if (event1.allDay) {
|
||||||
|
-1
|
||||||
|
} else {
|
||||||
|
event.startDate.compareTo(event1.startDate)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
event.startDate.compareTo(event1.startDate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -2,14 +2,16 @@ package com.tommasoberlose.anotherwidget.helpers
|
|||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.util.Log
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
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 +35,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 +62,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 +89,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 +134,14 @@ 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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package com.tommasoberlose.anotherwidget.helpers
|
package com.tommasoberlose.anotherwidget.helpers
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
@ -7,6 +8,7 @@ import com.tommasoberlose.anotherwidget.db.EventRepository
|
|||||||
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.models.GlanceProvider
|
import com.tommasoberlose.anotherwidget.models.GlanceProvider
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
import com.tommasoberlose.anotherwidget.utils.checkIfFitInstalled
|
import com.tommasoberlose.anotherwidget.utils.checkIfFitInstalled
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
|
|
||||||
@ -17,9 +19,10 @@ object GlanceProviderHelper {
|
|||||||
val providers = Constants.GlanceProviderId.values()
|
val providers = Constants.GlanceProviderId.values()
|
||||||
.filter {
|
.filter {
|
||||||
context.checkIfFitInstalled() || it != Constants.GlanceProviderId.GOOGLE_FIT_STEPS
|
context.checkIfFitInstalled() || it != Constants.GlanceProviderId.GOOGLE_FIT_STEPS
|
||||||
}.toTypedArray()
|
}
|
||||||
|
.toTypedArray()
|
||||||
|
|
||||||
providers.sortWith(Comparator { p1, p2 ->
|
return ArrayList(providers.filter { enabledProviders.contains(it.id) }.sortedWith(Comparator { p1, p2 ->
|
||||||
when {
|
when {
|
||||||
enabledProviders.contains(p1.id) && enabledProviders.contains(p2.id) -> {
|
enabledProviders.contains(p1.id) && enabledProviders.contains(p2.id) -> {
|
||||||
enabledProviders.indexOf(p1.id).compareTo(enabledProviders.indexOf(p2.id))
|
enabledProviders.indexOf(p1.id).compareTo(enabledProviders.indexOf(p2.id))
|
||||||
@ -34,9 +37,7 @@ object GlanceProviderHelper {
|
|||||||
p1.id.compareTo(p2.id)
|
p1.id.compareTo(p2.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}) + providers.filter { !enabledProviders.contains(it.id) })
|
||||||
|
|
||||||
return ArrayList(providers.toList())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getGlanceProviderById(context: Context, providerId: Constants.GlanceProviderId): GlanceProvider? {
|
fun getGlanceProviderById(context: Context, providerId: Constants.GlanceProviderId): GlanceProvider? {
|
||||||
@ -44,37 +45,55 @@ object GlanceProviderHelper {
|
|||||||
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
|
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
|
||||||
GlanceProvider(providerId.id,
|
GlanceProvider(providerId.id,
|
||||||
context.getString(R.string.settings_show_next_alarm_title),
|
context.getString(R.string.settings_show_next_alarm_title),
|
||||||
R.drawable.round_alarm
|
R.drawable.round_access_alarm_24
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Constants.GlanceProviderId.PLAYING_SONG -> {
|
Constants.GlanceProviderId.PLAYING_SONG -> {
|
||||||
GlanceProvider(providerId.id,
|
GlanceProvider(providerId.id,
|
||||||
context.getString(R.string.settings_show_music_title),
|
context.getString(R.string.settings_show_music_title),
|
||||||
R.drawable.round_music_note
|
R.drawable.round_music_note_24
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Constants.GlanceProviderId.CUSTOM_INFO -> {
|
Constants.GlanceProviderId.CUSTOM_INFO -> {
|
||||||
GlanceProvider(providerId.id,
|
GlanceProvider(providerId.id,
|
||||||
context.getString(R.string.settings_custom_notes_title),
|
context.getString(R.string.settings_custom_notes_title),
|
||||||
R.drawable.round_notes
|
R.drawable.round_sticky_note_2_24
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
||||||
GlanceProvider(providerId.id,
|
GlanceProvider(providerId.id,
|
||||||
context.getString(R.string.settings_low_battery_level_title),
|
context.getString(R.string.settings_low_battery_level_title),
|
||||||
R.drawable.round_battery_charging_full
|
R.drawable.round_battery_charging_full_24
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
|
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
|
||||||
GlanceProvider(providerId.id,
|
GlanceProvider(providerId.id,
|
||||||
context.getString(R.string.settings_daily_steps_title),
|
context.getString(R.string.settings_daily_steps_title),
|
||||||
R.drawable.round_directions_walk
|
R.drawable.round_favorite_border_24
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.NOTIFICATIONS -> {
|
||||||
|
GlanceProvider(providerId.id,
|
||||||
|
context.getString(R.string.settings_show_notifications_title),
|
||||||
|
R.drawable.round_notifications_24
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.GREETINGS -> {
|
||||||
|
GlanceProvider(providerId.id,
|
||||||
|
context.getString(R.string.settings_show_greetings_title),
|
||||||
|
R.drawable.round_history_edu_24
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.EVENTS -> {
|
||||||
|
GlanceProvider(providerId.id,
|
||||||
|
context.getString(R.string.settings_show_events_as_glance_provider_title),
|
||||||
|
R.drawable.round_event_note_24
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveGlanceProviderOrder(list: ArrayList<Constants.GlanceProviderId>) {
|
fun saveGlanceProviderOrder(list: List<Constants.GlanceProviderId>) {
|
||||||
Preferences.enabledGlanceProviderOrder = list.joinToString(separator = ",")
|
Preferences.enabledGlanceProviderOrder = list.joinToString(separator = ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,12 +101,17 @@ 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) && (
|
val showGlance = (eventRepository.getEventsCount() == 0 || !Preferences.showEvents || Preferences.showEventsAsGlanceProvider)
|
||||||
|
&& (
|
||||||
|
(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.showDailySteps && Preferences.googleFitSteps > 0)
|
(Preferences.showDailySteps && Preferences.googleFitSteps > 0) ||
|
||||||
|
(Preferences.showGreetings && GreetingsHelper.showGreetings()) ||
|
||||||
|
(Preferences.showEventsAsGlanceProvider && Preferences.showEvents && context.checkGrantedPermission(
|
||||||
|
Manifest.permission.READ_CALENDAR) && eventRepository.getNextEvent() != null)
|
||||||
)
|
)
|
||||||
eventRepository.close()
|
eventRepository.close()
|
||||||
return showGlance
|
return showGlance
|
||||||
|
@ -0,0 +1,110 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.helpers
|
||||||
|
|
||||||
|
import android.app.AlarmManager
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Actions
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
object GreetingsHelper {
|
||||||
|
private const val MORNING_TIME = 36
|
||||||
|
private const val MORNING_TIME_END = 37
|
||||||
|
private const val EVENING_TIME = 38
|
||||||
|
private const val NIGHT_TIME = 39
|
||||||
|
|
||||||
|
fun toggleGreetings(context: Context) {
|
||||||
|
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
|
val now = Calendar.getInstance().apply {
|
||||||
|
set(Calendar.SECOND, 0)
|
||||||
|
set(Calendar.MILLISECOND, 0)
|
||||||
|
set(Calendar.MINUTE, 0)
|
||||||
|
set(Calendar.HOUR_OF_DAY, 0)
|
||||||
|
}
|
||||||
|
if (Preferences.showGreetings) {
|
||||||
|
setRepeating(
|
||||||
|
AlarmManager.RTC,
|
||||||
|
now.apply {
|
||||||
|
set(Calendar.HOUR_OF_DAY, 5)
|
||||||
|
}.timeInMillis,
|
||||||
|
1000 * 60 * 60 * 24,
|
||||||
|
PendingIntent.getBroadcast(context,
|
||||||
|
MORNING_TIME,
|
||||||
|
Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
|
action = Actions.ACTION_UPDATE_GREETINGS
|
||||||
|
},
|
||||||
|
0)
|
||||||
|
)
|
||||||
|
|
||||||
|
setRepeating(
|
||||||
|
AlarmManager.RTC,
|
||||||
|
now.apply {
|
||||||
|
set(Calendar.HOUR_OF_DAY, 9)
|
||||||
|
}.timeInMillis,
|
||||||
|
1000 * 60 * 60 * 24,
|
||||||
|
PendingIntent.getBroadcast(context,
|
||||||
|
MORNING_TIME_END,
|
||||||
|
Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
|
action = Actions.ACTION_UPDATE_GREETINGS
|
||||||
|
},
|
||||||
|
0)
|
||||||
|
)
|
||||||
|
|
||||||
|
setRepeating(
|
||||||
|
AlarmManager.RTC,
|
||||||
|
now.apply {
|
||||||
|
set(Calendar.HOUR_OF_DAY, 19)
|
||||||
|
}.timeInMillis,
|
||||||
|
1000 * 60 * 60 * 24,
|
||||||
|
PendingIntent.getBroadcast(context,
|
||||||
|
EVENING_TIME,
|
||||||
|
Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
|
action = Actions.ACTION_UPDATE_GREETINGS
|
||||||
|
},
|
||||||
|
0)
|
||||||
|
)
|
||||||
|
|
||||||
|
setRepeating(
|
||||||
|
AlarmManager.RTC,
|
||||||
|
now.apply {
|
||||||
|
set(Calendar.HOUR_OF_DAY, 22)
|
||||||
|
}.timeInMillis,
|
||||||
|
1000 * 60 * 60 * 24,
|
||||||
|
PendingIntent.getBroadcast(context,
|
||||||
|
NIGHT_TIME,
|
||||||
|
Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
|
action = Actions.ACTION_UPDATE_GREETINGS
|
||||||
|
},
|
||||||
|
0)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
listOf(MORNING_TIME, MORNING_TIME_END, EVENING_TIME, NIGHT_TIME).forEach {
|
||||||
|
cancel(PendingIntent.getBroadcast(context, it, Intent(context,
|
||||||
|
UpdatesReceiver::class.java).apply {
|
||||||
|
action = Actions.ACTION_UPDATE_GREETINGS
|
||||||
|
}, 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun showGreetings(): Boolean {
|
||||||
|
val hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY)
|
||||||
|
return hour < 9 || hour >= 19
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getRandomString(context: Context): String {
|
||||||
|
val hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY)
|
||||||
|
val array = when {
|
||||||
|
hour in 5..8 -> context.resources.getStringArray(R.array.morning_greetings)
|
||||||
|
hour in 19..21 -> context.resources.getStringArray(R.array.evening_greetings)
|
||||||
|
hour >= 22 && hour < 5 -> context.resources.getStringArray(R.array.night_greetings)
|
||||||
|
else -> emptyArray()
|
||||||
|
}
|
||||||
|
return if (array.isNotEmpty()) array[Random().nextInt(array.size)] else ""
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.helpers
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.*
|
||||||
|
import android.renderscript.*
|
||||||
|
import android.util.TypedValue
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||||
|
import java.util.prefs.Preferences
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
object ImageHelper {
|
||||||
|
fun ImageView.applyShadow(originalView: ImageView, factor: Float = 1f) {
|
||||||
|
clearColorFilter()
|
||||||
|
val cElevation = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, when (if (context.isDarkTheme()) com.tommasoberlose.anotherwidget.global.Preferences.textShadowDark else com.tommasoberlose.anotherwidget.global.Preferences.textShadow) {
|
||||||
|
0 -> 0f * factor
|
||||||
|
1 -> 8f * factor
|
||||||
|
2 -> 16f * factor
|
||||||
|
else -> 0f * factor
|
||||||
|
}, resources.displayMetrics)
|
||||||
|
|
||||||
|
if (originalView.drawable != null) {
|
||||||
|
val btm = originalView.drawable.toBitmap().copy(Bitmap.Config.ARGB_8888, true)
|
||||||
|
val comb = Bitmap.createBitmap(btm)
|
||||||
|
val shadowBitmap = generateShadowBitmap(context, cElevation, btm, factor)
|
||||||
|
|
||||||
|
shadowBitmap?.let {
|
||||||
|
val canvas = Canvas(comb)
|
||||||
|
canvas.drawColor(Color.TRANSPARENT)
|
||||||
|
canvas.save()
|
||||||
|
val rect = Rect()
|
||||||
|
// val bounds = originalView.drawable.copyBounds()
|
||||||
|
canvas.getClipBounds(rect)
|
||||||
|
rect.inset(-2 * getBlurRadius(context, cElevation).toInt(), -2 * getBlurRadius(context, cElevation).toInt())
|
||||||
|
canvas.save()
|
||||||
|
canvas.clipRect(rect)
|
||||||
|
canvas.drawBitmap(shadowBitmap, 0f, 2f, null)
|
||||||
|
canvas.restore()
|
||||||
|
setImageBitmap(comb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateShadowBitmap(context: Context, cElevation: Float, bitmap: Bitmap?, factor: Float): Bitmap? {
|
||||||
|
val rs: RenderScript = RenderScript.create(context)
|
||||||
|
val element = Element.U8_4(rs)
|
||||||
|
val blurScript: ScriptIntrinsicBlur = ScriptIntrinsicBlur.create(rs, element)
|
||||||
|
val colorMatrixScript: ScriptIntrinsicColorMatrix = ScriptIntrinsicColorMatrix.create(rs)
|
||||||
|
val allocationIn = Allocation.createFromBitmap(rs, bitmap)
|
||||||
|
val allocationOut = Allocation.createTyped(rs, allocationIn.type)
|
||||||
|
|
||||||
|
val matrix = Matrix4f(floatArrayOf(
|
||||||
|
0f, 0f, 0f, 0f,
|
||||||
|
0f, 0f, 0f, 0f,
|
||||||
|
0f, 0f, 0f, 0f,
|
||||||
|
0f, 0f, 0f, when (if (context.isDarkTheme()) com.tommasoberlose.anotherwidget.global.Preferences.textShadowDark else com.tommasoberlose.anotherwidget.global.Preferences.textShadow) {
|
||||||
|
0 -> 0f * factor
|
||||||
|
1 -> 0.8f * factor
|
||||||
|
2 -> 1f * factor
|
||||||
|
else -> 0f
|
||||||
|
}))
|
||||||
|
|
||||||
|
colorMatrixScript.setColorMatrix(matrix)
|
||||||
|
colorMatrixScript.forEach(allocationIn, allocationOut)
|
||||||
|
|
||||||
|
blurScript.setRadius(getBlurRadius(context, cElevation))
|
||||||
|
|
||||||
|
blurScript.setInput(allocationOut)
|
||||||
|
blurScript.forEach(allocationIn)
|
||||||
|
|
||||||
|
allocationIn.copyTo(bitmap)
|
||||||
|
|
||||||
|
allocationIn.destroy()
|
||||||
|
allocationOut.destroy()
|
||||||
|
|
||||||
|
return bitmap
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getBlurRadius(context: Context, customElevation: Float): Float {
|
||||||
|
val maxElevation = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24f, context.resources.displayMetrics)
|
||||||
|
return min(25f * (customElevation / maxElevation), 25f)
|
||||||
|
}
|
||||||
|
}
|
@ -12,8 +12,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 +23,10 @@ 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 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,6 +37,12 @@ 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=$address")
|
||||||
val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
|
val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
|
||||||
@ -47,7 +59,7 @@ object IntentHelper {
|
|||||||
|
|
||||||
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)
|
addCategory(Intent.CATEGORY_DEFAULT)
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
@ -55,9 +67,12 @@ object IntentHelper {
|
|||||||
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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"_" -> {
|
DO_NOTHING_OPTION -> {
|
||||||
Intent()
|
Intent()
|
||||||
}
|
}
|
||||||
|
REFRESH_WIDGET_OPTION -> {
|
||||||
|
getWidgetRefreshIntent(context)
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val pm: PackageManager = context.packageManager
|
val pm: PackageManager = context.packageManager
|
||||||
try {
|
try {
|
||||||
@ -66,7 +81,6 @@ object IntentHelper {
|
|||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
context.toast(context.getString(R.string.error_opening_app))
|
|
||||||
Intent()
|
Intent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,14 +94,17 @@ object IntentHelper {
|
|||||||
.appendPath(Calendar.getInstance().timeInMillis.toString())
|
.appendPath(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 {
|
||||||
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 {
|
||||||
@ -96,7 +113,6 @@ object IntentHelper {
|
|||||||
data = calendarUri
|
data = calendarUri
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
context.toast(context.getString(R.string.error_opening_app))
|
|
||||||
Intent()
|
Intent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,14 +182,17 @@ object IntentHelper {
|
|||||||
|
|
||||||
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 {
|
||||||
@ -181,7 +200,6 @@ object IntentHelper {
|
|||||||
addCategory(Intent.CATEGORY_LAUNCHER)
|
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
context.toast(context.getString(R.string.error_opening_app))
|
|
||||||
Intent()
|
Intent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -194,7 +212,7 @@ object IntentHelper {
|
|||||||
|
|
||||||
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 -> {
|
||||||
@ -204,7 +222,6 @@ object IntentHelper {
|
|||||||
addCategory(Intent.CATEGORY_LAUNCHER)
|
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
context.toast(context.getString(R.string.error_opening_app))
|
|
||||||
Intent()
|
Intent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -218,7 +235,17 @@ object IntentHelper {
|
|||||||
addCategory(Intent.CATEGORY_LAUNCHER)
|
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
context.toast(context.getString(R.string.error_opening_app))
|
Intent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getNotificationIntent(context: Context): Intent {
|
||||||
|
val pm: PackageManager = context.packageManager
|
||||||
|
return try {
|
||||||
|
pm.getLaunchIntentForPackage(Preferences.lastNotificationPackage)!!.apply {
|
||||||
|
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
Intent()
|
Intent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,43 +1,59 @@
|
|||||||
package com.tommasoberlose.anotherwidget.helpers
|
package com.tommasoberlose.anotherwidget.helpers
|
||||||
|
|
||||||
import android.app.Notification
|
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.media.MediaMetadata
|
import android.media.MediaMetadata
|
||||||
import android.media.session.MediaController
|
import android.media.session.MediaController
|
||||||
import android.media.session.MediaSession
|
|
||||||
import android.media.session.MediaSessionManager
|
import android.media.session.MediaSessionManager
|
||||||
import android.media.session.PlaybackState
|
import android.media.session.PlaybackState
|
||||||
import android.util.Log
|
|
||||||
import androidx.core.app.NotificationManagerCompat
|
|
||||||
import com.chibatching.kotpref.Kotpref
|
import com.chibatching.kotpref.Kotpref
|
||||||
import com.chibatching.kotpref.blockingBulk
|
import com.chibatching.kotpref.blockingBulk
|
||||||
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.receivers.MusicNotificationListener
|
import com.tommasoberlose.anotherwidget.receivers.NotificationListener
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
|
|
||||||
object MediaPlayerHelper {
|
object MediaPlayerHelper {
|
||||||
fun isSomeonePlaying(context: Context) = Preferences.showMusic && NotificationManagerCompat.getEnabledListenerPackages(context).contains(context.packageName) && Preferences.mediaPlayerTitle != ""
|
const val MEDIA_INFO_TITLE = "%TITLE"
|
||||||
|
const val MEDIA_INFO_ARTIST = "%ARTIST"
|
||||||
|
const val MEDIA_INFO_ALBUM = "%ALBUM"
|
||||||
|
|
||||||
fun getMediaInfo(): String {
|
const val DEFAULT_MEDIA_INFO_FORMAT = "%TITLE, %ARTIST"
|
||||||
return if (Preferences.mediaPlayerArtist == "") {
|
|
||||||
|
fun isSomeonePlaying(context: Context) = Preferences.showMusic && ActiveNotificationsHelper.checkNotificationAccess(context) && Preferences.mediaPlayerTitle != ""
|
||||||
|
|
||||||
|
fun getMediaInfo(format: String = Preferences.mediaInfoFormat, title: String = Preferences.mediaPlayerTitle, artist: String = Preferences.mediaPlayerArtist, album: String = Preferences.mediaPlayerAlbum): String {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
format.replace(MEDIA_INFO_TITLE, title)
|
||||||
|
.replace(MEDIA_INFO_ARTIST, artist)
|
||||||
|
.replace(MEDIA_INFO_ALBUM, album)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updatePlayingMediaInfo(context: Context) {
|
fun updatePlayingMediaInfo(context: Context) {
|
||||||
Kotpref.init(context)
|
Kotpref.init(context)
|
||||||
if (NotificationManagerCompat.getEnabledListenerPackages(context).contains(context.packageName)) {
|
if (ActiveNotificationsHelper.checkNotificationAccess(context)) {
|
||||||
val list = try {
|
val list = try {
|
||||||
(context.getSystemService(Context.MEDIA_SESSION_SERVICE) as MediaSessionManager).getActiveSessions(
|
(context.getSystemService(Context.MEDIA_SESSION_SERVICE) as MediaSessionManager).getActiveSessions(
|
||||||
ComponentName(context.packageName, MusicNotificationListener::class.java.name)
|
ComponentName(context.packageName, NotificationListener::class.java.name)
|
||||||
)
|
)
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
emptyList<MediaController>()
|
emptyList<MediaController>()
|
||||||
|
}.filter {
|
||||||
|
Preferences.musicPlayersFilter == "" || isMusicPlayerAccepted(it.packageName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list.isNotEmpty()) {
|
if (list.isNotEmpty()) {
|
||||||
@ -89,4 +105,14 @@ object MediaPlayerHelper {
|
|||||||
remove(Preferences::mediaPlayerPackage)
|
remove(Preferences::mediaPlayerPackage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isMusicPlayerAccepted(appPkg: String): Boolean = Preferences.musicPlayersFilter == "" || Preferences.musicPlayersFilter.contains(appPkg)
|
||||||
|
|
||||||
|
fun toggleMusicPlayerFilter(appPkg: String) {
|
||||||
|
if (Preferences.musicPlayersFilter == "" || !Preferences.musicPlayersFilter.contains(appPkg)) {
|
||||||
|
Preferences.musicPlayersFilter = Preferences.musicPlayersFilter.split(",").union(listOf(appPkg)).joinToString(separator = ",")
|
||||||
|
} else {
|
||||||
|
Preferences.musicPlayersFilter = Preferences.musicPlayersFilter.split(",").filter { it != appPkg }.joinToString(separator = ",")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -54,14 +54,37 @@ object SettingsStringHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCustomFontLabel(shadow: Int): Int {
|
fun getCustomFontLabel(context: Context, font: Int): String {
|
||||||
return when (shadow) {
|
return when (font) {
|
||||||
0 -> R.string.custom_font_subtitle_0
|
Constants.CUSTOM_FONT_GOOGLE_SANS -> context.getString(R.string.custom_font_subtitle_1) + " - ${getVariantLabel(context, Preferences.customFontVariant)}"
|
||||||
1 -> R.string.custom_font_subtitle_1
|
Constants.CUSTOM_FONT_DOWNLOADED -> Preferences.customFontName + " - ${getVariantLabel(context, Preferences.customFontVariant)}"
|
||||||
else -> R.string.custom_font_subtitle_1
|
else -> context.getString(R.string.custom_font_subtitle_0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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("200") -> context.getString(R.string.font_200)
|
||||||
|
variant.contains("300") -> context.getString(R.string.font_300)
|
||||||
|
variant.contains("500") -> context.getString(R.string.font_500)
|
||||||
|
variant.contains("600") -> context.getString(R.string.font_600)
|
||||||
|
variant.contains("700") -> context.getString(R.string.font_700)
|
||||||
|
variant.contains("800") -> context.getString(R.string.font_800)
|
||||||
|
variant.contains("900") -> context.getString(R.string.font_900)
|
||||||
|
else -> context.getString(R.string.font_400)
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
@ -3,14 +3,21 @@ 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.os.Build
|
||||||
|
import android.util.Log
|
||||||
|
import com.chibatching.kotpref.Kotpref
|
||||||
import com.google.android.gms.location.LocationServices
|
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.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 com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
|
||||||
|
|
||||||
@ -20,40 +27,105 @@ import org.greenrobot.eventbus.EventBus
|
|||||||
|
|
||||||
object WeatherHelper {
|
object WeatherHelper {
|
||||||
|
|
||||||
fun updateWeather(context: Context) {
|
suspend fun updateWeather(context: Context) {
|
||||||
|
Kotpref.init(context)
|
||||||
val networkApi = WeatherNetworkApi(context)
|
val networkApi = WeatherNetworkApi(context)
|
||||||
if (Preferences.customLocationAdd != "") {
|
if (Preferences.customLocationAdd != "") {
|
||||||
networkApi.updateWeather()
|
networkApi.updateWeather()
|
||||||
} else if (context.checkGrantedPermission(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACCESS_BACKGROUND_LOCATION else Manifest.permission.ACCESS_FINE_LOCATION)) {
|
} else if (context.checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION)) {
|
||||||
LocationServices.getFusedLocationProviderClient(context).lastLocation.addOnCompleteListener { task ->
|
LocationService.requestNewLocation(context)
|
||||||
if (task.isSuccessful) {
|
|
||||||
val location = task.result
|
|
||||||
if (location != null) {
|
|
||||||
Preferences.customLocationLat = location.latitude.toString()
|
|
||||||
Preferences.customLocationLon = location.longitude.toString()
|
|
||||||
|
|
||||||
networkApi.updateWeather()
|
|
||||||
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeWeather(context: Context) {
|
fun removeWeather(context: Context) {
|
||||||
Preferences.remove(Preferences::weatherTemp)
|
Preferences.remove(Preferences::weatherTemp)
|
||||||
Preferences.remove(Preferences::weatherRealTempUnit)
|
Preferences.remove(Preferences::weatherRealTempUnit)
|
||||||
|
Preferences.remove(Preferences::weatherIcon)
|
||||||
MainWidget.updateWidget(context)
|
MainWidget.updateWidget(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getWeatherIconResource(icon: String, style: Int = Preferences.weatherIconPack): Int {
|
fun getProviderName(context: Context, provider: Constants.WeatherProvider = Constants.WeatherProvider.fromInt(Preferences.weatherProvider)!!): String {
|
||||||
|
return context.getString(when(provider) {
|
||||||
|
Constants.WeatherProvider.OPEN_WEATHER -> R.string.settings_weather_provider_open_weather
|
||||||
|
Constants.WeatherProvider.WEATHER_BIT -> R.string.settings_weather_provider_weatherbit
|
||||||
|
Constants.WeatherProvider.WEATHER_API -> R.string.settings_weather_provider_weather_api
|
||||||
|
Constants.WeatherProvider.HERE -> R.string.settings_weather_provider_here
|
||||||
|
Constants.WeatherProvider.ACCUWEATHER -> R.string.settings_weather_provider_accuweather
|
||||||
|
Constants.WeatherProvider.WEATHER_GOV -> R.string.settings_weather_provider_weather_gov
|
||||||
|
Constants.WeatherProvider.YR -> R.string.settings_weather_provider_yr
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getProviderInfoTitle(context: Context, provider: Constants.WeatherProvider? = Constants.WeatherProvider.fromInt(Preferences.weatherProvider)!!): String {
|
||||||
|
return context.getString(when(provider) {
|
||||||
|
Constants.WeatherProvider.OPEN_WEATHER -> R.string.weather_provider_info_open_weather_title
|
||||||
|
Constants.WeatherProvider.WEATHER_BIT -> R.string.weather_provider_info_weatherbit_title
|
||||||
|
Constants.WeatherProvider.WEATHER_API -> R.string.weather_provider_info_weatherapi_title
|
||||||
|
Constants.WeatherProvider.HERE -> R.string.weather_provider_info_here_title
|
||||||
|
Constants.WeatherProvider.ACCUWEATHER -> R.string.weather_provider_info_accuweather_title
|
||||||
|
Constants.WeatherProvider.WEATHER_GOV -> R.string.weather_provider_info_weather_gov_title
|
||||||
|
Constants.WeatherProvider.YR -> R.string.weather_provider_info_yr_title
|
||||||
|
else -> R.string.nothing
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getProviderInfoSubtitle(context: Context, provider: Constants.WeatherProvider? = Constants.WeatherProvider.fromInt(Preferences.weatherProvider)!!): String {
|
||||||
|
return context.getString(when(provider) {
|
||||||
|
Constants.WeatherProvider.OPEN_WEATHER -> R.string.weather_provider_info_open_weather_subtitle
|
||||||
|
Constants.WeatherProvider.WEATHER_BIT -> R.string.weather_provider_info_weatherbit_subtitle
|
||||||
|
Constants.WeatherProvider.WEATHER_API -> R.string.weather_provider_info_weatherapi_subtitle
|
||||||
|
Constants.WeatherProvider.HERE -> R.string.weather_provider_info_here_subtitle
|
||||||
|
Constants.WeatherProvider.ACCUWEATHER -> R.string.weather_provider_info_accuweather_subtitle
|
||||||
|
Constants.WeatherProvider.WEATHER_GOV -> R.string.weather_provider_info_weather_gov_subtitle
|
||||||
|
Constants.WeatherProvider.YR -> R.string.weather_provider_info_yr_subtitle
|
||||||
|
else -> R.string.nothing
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getProviderLink(provider: Constants.WeatherProvider? = Constants.WeatherProvider.fromInt(Preferences.weatherProvider)!!): String {
|
||||||
|
return when(provider) {
|
||||||
|
Constants.WeatherProvider.OPEN_WEATHER -> "https://home.openweathermap.org/users/sign_in"
|
||||||
|
Constants.WeatherProvider.WEATHER_BIT -> "https://www.weatherbit.io/account/login"
|
||||||
|
Constants.WeatherProvider.WEATHER_API -> "https://www.weatherapi.com/login.aspx"
|
||||||
|
Constants.WeatherProvider.HERE -> "https://developer.here.com/login"
|
||||||
|
Constants.WeatherProvider.ACCUWEATHER -> "https://developer.accuweather.com/user/login"
|
||||||
|
Constants.WeatherProvider.WEATHER_GOV -> "http://www.weather.gov/"
|
||||||
|
Constants.WeatherProvider.YR -> "https://www.yr.no/"
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isKeyRequired(provider: Constants.WeatherProvider? = Constants.WeatherProvider.fromInt(Preferences.weatherProvider)!!): Boolean = when (provider) {
|
||||||
|
Constants.WeatherProvider.OPEN_WEATHER,
|
||||||
|
Constants.WeatherProvider.WEATHER_BIT,
|
||||||
|
Constants.WeatherProvider.WEATHER_API,
|
||||||
|
Constants.WeatherProvider.HERE,
|
||||||
|
Constants.WeatherProvider.ACCUWEATHER -> true
|
||||||
|
|
||||||
|
Constants.WeatherProvider.WEATHER_GOV,
|
||||||
|
Constants.WeatherProvider.YR -> false
|
||||||
|
else -> true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getApiKey(provider: Constants.WeatherProvider? = Constants.WeatherProvider.fromInt(Preferences.weatherProvider)!!): String = when (provider) {
|
||||||
|
Constants.WeatherProvider.OPEN_WEATHER -> Preferences.weatherProviderApiOpen
|
||||||
|
Constants.WeatherProvider.WEATHER_BIT -> Preferences.weatherProviderApiWeatherBit
|
||||||
|
Constants.WeatherProvider.WEATHER_API -> Preferences.weatherProviderApiWeatherApi
|
||||||
|
Constants.WeatherProvider.HERE -> Preferences.weatherProviderApiHere
|
||||||
|
Constants.WeatherProvider.ACCUWEATHER -> Preferences.weatherProviderApiAccuweather
|
||||||
|
Constants.WeatherProvider.WEATHER_GOV -> ""
|
||||||
|
Constants.WeatherProvider.YR -> ""
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getWeatherIconResource(context: Context, icon: String, style: Int = Preferences.weatherIconPack): Int {
|
||||||
return when (icon) {
|
return when (icon) {
|
||||||
"01d" -> {
|
"01d" -> {
|
||||||
when (style) {
|
when (style) {
|
||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.clear_day_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.clear_day_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.clear_day_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.clear_day_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.clear_day_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.clear_day_4
|
||||||
else -> R.drawable.clear_day
|
else -> if (context.isDarkTheme()) R.drawable.clear_day_5 else R.drawable.clear_day_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"02d" -> {
|
"02d" -> {
|
||||||
@ -61,7 +133,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.partly_cloudy_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.partly_cloudy_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.partly_cloudy_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.partly_cloudy_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.partly_cloudy_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.partly_cloudy_4
|
||||||
else -> R.drawable.partly_cloudy
|
else -> if (context.isDarkTheme()) R.drawable.partly_cloudy_5 else R.drawable.partly_cloudy_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"03d" -> {
|
"03d" -> {
|
||||||
@ -69,7 +141,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.mostly_cloudy_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.mostly_cloudy_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.mostly_cloudy_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.mostly_cloudy_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.mostly_cloudy_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.mostly_cloudy_4
|
||||||
else -> R.drawable.mostly_cloudy
|
else -> if (context.isDarkTheme()) R.drawable.mostly_cloudy_5 else R.drawable.mostly_cloudy_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"04d" -> {
|
"04d" -> {
|
||||||
@ -77,7 +149,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.cloudy_weather_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.cloudy_weather_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.cloudy_weather_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.cloudy_weather_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.cloudy_weather_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.cloudy_weather_4
|
||||||
else -> R.drawable.cloudy_weather
|
else -> if (context.isDarkTheme()) R.drawable.cloudy_weather_5 else R.drawable.cloudy_weather_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"09d" -> {
|
"09d" -> {
|
||||||
@ -85,7 +157,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.storm_weather_day_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.storm_weather_day_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.storm_weather_day_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.storm_weather_day_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.storm_weather_day_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.storm_weather_day_4
|
||||||
else -> R.drawable.storm_weather_day
|
else -> if (context.isDarkTheme()) R.drawable.storm_weather_day_5 else R.drawable.storm_weather_day_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"10d" -> {
|
"10d" -> {
|
||||||
@ -93,7 +165,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.rainy_day_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.rainy_day_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rainy_day_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rainy_day_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rainy_day_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rainy_day_4
|
||||||
else -> R.drawable.rainy_day
|
else -> if (context.isDarkTheme()) R.drawable.rainy_day_5 else R.drawable.rainy_day_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"11d" -> {
|
"11d" -> {
|
||||||
@ -101,7 +173,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.thunder_day_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.thunder_day_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.thunder_day_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.thunder_day_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.thunder_day_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.thunder_day_4
|
||||||
else -> R.drawable.thunder_day
|
else -> if (context.isDarkTheme()) R.drawable.thunder_day_5 else R.drawable.thunder_day_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"13d" -> {
|
"13d" -> {
|
||||||
@ -109,7 +181,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.snow_day_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.snow_day_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.snow_day_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.snow_day_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.snow_day_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.snow_day_4
|
||||||
else -> R.drawable.snow_day
|
else -> if (context.isDarkTheme()) R.drawable.snow_day_5 else R.drawable.snow_day_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"50d" -> {
|
"50d" -> {
|
||||||
@ -117,7 +189,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_day_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_day_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_day_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_day_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_day_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_day_4
|
||||||
else -> R.drawable.haze_day
|
else -> if (context.isDarkTheme()) R.drawable.haze_day_5 else R.drawable.haze_day_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"80d" -> {
|
"80d" -> {
|
||||||
@ -125,7 +197,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.windy_day_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.windy_day_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.windy_day_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.windy_day_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.windy_day_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.windy_day_4
|
||||||
else -> R.drawable.windy_day
|
else -> if (context.isDarkTheme()) R.drawable.windy_day_5 else R.drawable.windy_day_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"81d" -> {
|
"81d" -> {
|
||||||
@ -133,7 +205,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.rain_snow_day_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.rain_snow_day_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rain_snow_day_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rain_snow_day_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rain_snow_day_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rain_snow_day_4
|
||||||
else -> R.drawable.rain_snow_day
|
else -> if (context.isDarkTheme()) R.drawable.rain_snow_day_5 else R.drawable.rain_snow_day_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"82d" -> {
|
"82d" -> {
|
||||||
@ -141,7 +213,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_weather_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_weather_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_weather_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_weather_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_weather_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_weather_4
|
||||||
else -> R.drawable.haze_weather
|
else -> if (context.isDarkTheme()) R.drawable.haze_weather_5 else R.drawable.haze_weather_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,7 +224,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.clear_night_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.clear_night_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.clear_night_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.clear_night_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.clear_night_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.clear_night_4
|
||||||
else -> R.drawable.clear_night
|
else -> if (context.isDarkTheme()) R.drawable.clear_night_5 else R.drawable.clear_night_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"02n" -> {
|
"02n" -> {
|
||||||
@ -160,7 +232,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.partly_cloudy_night_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.partly_cloudy_night_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.partly_cloudy_night_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.partly_cloudy_night_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.partly_cloudy_night_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.partly_cloudy_night_4
|
||||||
else -> R.drawable.partly_cloudy_night
|
else -> if (context.isDarkTheme()) R.drawable.partly_cloudy_night_5 else R.drawable.partly_cloudy_night_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"03n" -> {
|
"03n" -> {
|
||||||
@ -168,7 +240,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.mostly_cloudy_night_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.mostly_cloudy_night_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.mostly_cloudy_night_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.mostly_cloudy_night_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.mostly_cloudy_night_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.mostly_cloudy_night_4
|
||||||
else -> R.drawable.mostly_cloudy_night
|
else -> if (context.isDarkTheme()) R.drawable.mostly_cloudy_night_5 else R.drawable.mostly_cloudy_night_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"04n" -> {
|
"04n" -> {
|
||||||
@ -176,7 +248,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.cloudy_weather_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.cloudy_weather_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.cloudy_weather_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.cloudy_weather_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.cloudy_weather_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.cloudy_weather_4
|
||||||
else -> R.drawable.cloudy_weather
|
else -> if (context.isDarkTheme()) R.drawable.cloudy_weather_5 else R.drawable.cloudy_weather_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"09n" -> {
|
"09n" -> {
|
||||||
@ -184,7 +256,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.storm_weather_night_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.storm_weather_night_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.storm_weather_night_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.storm_weather_night_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.storm_weather_night_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.storm_weather_night_4
|
||||||
else -> R.drawable.storm_weather_night
|
else -> if (context.isDarkTheme()) R.drawable.storm_weather_night_5 else R.drawable.storm_weather_night_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"10n" -> {
|
"10n" -> {
|
||||||
@ -192,7 +264,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.rainy_night_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.rainy_night_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rainy_night_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rainy_night_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rainy_night_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rainy_night_4
|
||||||
else -> R.drawable.rainy_night
|
else -> if (context.isDarkTheme()) R.drawable.rainy_night_5 else R.drawable.rainy_night_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"11n" -> {
|
"11n" -> {
|
||||||
@ -200,7 +272,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.thunder_night_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.thunder_night_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.thunder_night_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.thunder_night_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.thunder_night_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.thunder_night_4
|
||||||
else -> R.drawable.thunder_night
|
else -> if (context.isDarkTheme()) R.drawable.thunder_night_5 else R.drawable.thunder_night_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"13n" -> {
|
"13n" -> {
|
||||||
@ -208,7 +280,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.snow_night_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.snow_night_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.snow_night_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.snow_night_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.snow_night_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.snow_night_4
|
||||||
else -> R.drawable.snow_night
|
else -> if (context.isDarkTheme()) R.drawable.snow_night_5 else R.drawable.snow_night_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"50n" -> {
|
"50n" -> {
|
||||||
@ -216,7 +288,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_night_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_night_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_night_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_night_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_night_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_night_4
|
||||||
else -> R.drawable.haze_night
|
else -> if (context.isDarkTheme()) R.drawable.haze_night_5 else R.drawable.haze_night_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"80n" -> {
|
"80n" -> {
|
||||||
@ -224,7 +296,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.windy_night_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.windy_night_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.windy_night_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.windy_night_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.windy_night_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.windy_night_4
|
||||||
else -> R.drawable.windy_night
|
else -> if (context.isDarkTheme()) R.drawable.windy_night_5 else R.drawable.windy_night_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"81n" -> {
|
"81n" -> {
|
||||||
@ -232,7 +304,7 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.rain_snow_night_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.rain_snow_night_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rain_snow_night_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rain_snow_night_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rain_snow_night_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rain_snow_night_4
|
||||||
else -> R.drawable.rain_snow_night
|
else -> if (context.isDarkTheme()) R.drawable.rain_snow_night_5 else R.drawable.rain_snow_night_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"82n" -> {
|
"82n" -> {
|
||||||
@ -240,12 +312,183 @@ object WeatherHelper {
|
|||||||
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_weather_3
|
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_weather_3
|
||||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_weather_2
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_weather_2
|
||||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_weather_4
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_weather_4
|
||||||
else -> R.drawable.haze_weather
|
else -> if (context.isDarkTheme()) R.drawable.haze_weather_5 else R.drawable.haze_weather_5_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
return R.drawable.unknown
|
return if (context.isDarkTheme()) R.drawable.unknown_dark else R.drawable.unknown_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getWeatherGovIcon(iconString: String, isDaytime: Boolean): String = when {
|
||||||
|
iconString.contains("skc") -> "01"
|
||||||
|
iconString.contains("few") -> "02"
|
||||||
|
iconString.contains("sct") -> "03"
|
||||||
|
iconString.contains("bkn") -> "04"
|
||||||
|
iconString.contains("ovc") -> "04"
|
||||||
|
iconString.contains("wind_skc") -> "01"
|
||||||
|
iconString.contains("wind_few") -> "02"
|
||||||
|
iconString.contains("wind_sct") -> "03"
|
||||||
|
iconString.contains("wind_bkn") -> "04"
|
||||||
|
iconString.contains("wind_ovc") -> "04"
|
||||||
|
iconString.contains("snow") -> "13"
|
||||||
|
iconString.contains("rain_snow") -> "81"
|
||||||
|
iconString.contains("rain_sleet") -> "81"
|
||||||
|
iconString.contains("snow_sleet") -> "81"
|
||||||
|
iconString.contains("fzra") -> "81"
|
||||||
|
iconString.contains("rain_fzra") -> "81"
|
||||||
|
iconString.contains("snow_fzra") -> "81"
|
||||||
|
iconString.contains("sleet") -> "81"
|
||||||
|
iconString.contains("rain") -> "10"
|
||||||
|
iconString.contains("rain_showers") -> "10"
|
||||||
|
iconString.contains("rain_showers_hi") -> "10"
|
||||||
|
iconString.contains("tsra") -> "82"
|
||||||
|
iconString.contains("tsra_sct") -> "82"
|
||||||
|
iconString.contains("tsra_hi") -> "82"
|
||||||
|
iconString.contains("tornado") -> "80"
|
||||||
|
iconString.contains("hurricane") -> "80"
|
||||||
|
iconString.contains("tropical_storm") -> "09"
|
||||||
|
iconString.contains("dust") -> "Dust"
|
||||||
|
iconString.contains("smoke") -> "Smoke"
|
||||||
|
iconString.contains("haze") -> "50"
|
||||||
|
iconString.contains("hot") -> "01"
|
||||||
|
iconString.contains("cold") -> "13"
|
||||||
|
iconString.contains("blizzard") -> "80"
|
||||||
|
iconString.contains("fog") -> "82"
|
||||||
|
else -> ""
|
||||||
|
} + if (isDaytime) "d" else "n"
|
||||||
|
|
||||||
|
fun getWeatherBitIcon(iconString: String): String = when {
|
||||||
|
iconString.contains("t01") -> "11"
|
||||||
|
iconString.contains("t02") -> "09"
|
||||||
|
iconString.contains("t03") -> "09"
|
||||||
|
iconString.contains("t04") -> "09"
|
||||||
|
iconString.contains("t05") -> "09"
|
||||||
|
iconString.contains("d01") -> "10"
|
||||||
|
iconString.contains("d02") -> "10"
|
||||||
|
iconString.contains("d03") -> "10"
|
||||||
|
iconString.contains("r01") -> "10"
|
||||||
|
iconString.contains("r02") -> "10"
|
||||||
|
iconString.contains("r03") -> "10"
|
||||||
|
iconString.contains("f01") -> "10"
|
||||||
|
iconString.contains("r04") -> "10"
|
||||||
|
iconString.contains("r05") -> "10"
|
||||||
|
iconString.contains("r06") -> "10"
|
||||||
|
iconString.contains("s01") -> "13"
|
||||||
|
iconString.contains("s02") -> "13"
|
||||||
|
iconString.contains("s03") -> "13"
|
||||||
|
iconString.contains("s04") -> "81"
|
||||||
|
iconString.contains("s05") -> "90"
|
||||||
|
iconString.contains("s06") -> "13"
|
||||||
|
iconString.contains("a01") -> "82"
|
||||||
|
iconString.contains("a02") -> "82"
|
||||||
|
iconString.contains("a03") -> "82"
|
||||||
|
iconString.contains("a04") -> "82"
|
||||||
|
iconString.contains("a05") -> "82"
|
||||||
|
iconString.contains("a06") -> "82"
|
||||||
|
iconString.contains("c01") -> "01"
|
||||||
|
iconString.contains("c02") -> "02"
|
||||||
|
iconString.contains("c03") -> "04"
|
||||||
|
iconString.contains("c04") -> "04"
|
||||||
|
else -> ""
|
||||||
|
} + if (iconString.contains("d")) "d" else "n"
|
||||||
|
|
||||||
|
fun getWeatherApiIcon(icon: Int, isDaytime: Boolean): String = when(icon) {
|
||||||
|
1000 -> "01"
|
||||||
|
1003 -> "02"
|
||||||
|
1006 -> "03"
|
||||||
|
1009 -> "04"
|
||||||
|
1030 -> "82"
|
||||||
|
1063 -> "10"
|
||||||
|
1066 -> "10"
|
||||||
|
1069 -> "10"
|
||||||
|
1072 -> "81"
|
||||||
|
1087 -> "11"
|
||||||
|
1114 -> "13"
|
||||||
|
1117 -> "09"
|
||||||
|
1135 -> "82"
|
||||||
|
1147 -> "82"
|
||||||
|
1150 -> "10"
|
||||||
|
1153 -> "10"
|
||||||
|
1168 -> "10"
|
||||||
|
1171 -> "10"
|
||||||
|
1180 -> "10"
|
||||||
|
1183 -> "10"
|
||||||
|
1186 -> "10"
|
||||||
|
1189 -> "10"
|
||||||
|
1192 -> "10"
|
||||||
|
1195 -> "10"
|
||||||
|
1198 -> "81"
|
||||||
|
1201 -> "81"
|
||||||
|
1204 -> "13"
|
||||||
|
1207 -> "13"
|
||||||
|
1210 -> "13"
|
||||||
|
1213 -> "13"
|
||||||
|
1216 -> "13"
|
||||||
|
1219 -> "13"
|
||||||
|
1222 -> "13"
|
||||||
|
1225 -> "13"
|
||||||
|
1237 -> "13"
|
||||||
|
1240 -> "10"
|
||||||
|
1243 -> "10"
|
||||||
|
1246 -> "10"
|
||||||
|
1249 -> "13"
|
||||||
|
1252 -> "13"
|
||||||
|
1255 -> "13"
|
||||||
|
1258 -> "13"
|
||||||
|
1261 -> "13"
|
||||||
|
1264 -> "13"
|
||||||
|
1273 -> "09"
|
||||||
|
1276 -> "09"
|
||||||
|
1279 -> "13"
|
||||||
|
1282 -> "13"
|
||||||
|
else -> ""
|
||||||
|
} + if (isDaytime) "d" else "n"
|
||||||
|
|
||||||
|
fun getYRIcon(iconCode: String, isDaytime: Boolean): String = when {
|
||||||
|
iconCode.contains("clearsky") -> "01"
|
||||||
|
iconCode.contains("cloudy") -> "04"
|
||||||
|
iconCode.contains("fair") -> "02"
|
||||||
|
iconCode.contains("fog") -> "82"
|
||||||
|
iconCode.contains("heavyrain") -> "10"
|
||||||
|
iconCode.contains("heavyrainandthunder") -> "11"
|
||||||
|
iconCode.contains("heavyrainshowers") -> "10"
|
||||||
|
iconCode.contains("heavyrainshowersandthunder") -> "11"
|
||||||
|
iconCode.contains("heavysleet") -> "10"
|
||||||
|
iconCode.contains("heavysleetandthunder") -> "11"
|
||||||
|
iconCode.contains("heavysleetshowers") -> "10"
|
||||||
|
iconCode.contains("heavysleetshowersandthunder") -> "11"
|
||||||
|
iconCode.contains("heavysnow") -> "13"
|
||||||
|
iconCode.contains("heavysnowandthunder") -> "13"
|
||||||
|
iconCode.contains("heavysnowshowers") -> "13"
|
||||||
|
iconCode.contains("heavysnowshowersandthunder") -> "13"
|
||||||
|
iconCode.contains("lightrain") -> "10"
|
||||||
|
iconCode.contains("lightrainandthunder") -> "11"
|
||||||
|
iconCode.contains("lightrainshowers") -> "10"
|
||||||
|
iconCode.contains("lightrainshowersandthunder") -> "11"
|
||||||
|
iconCode.contains("lightsleet") -> "10"
|
||||||
|
iconCode.contains("lightsleetandthunder") -> "11"
|
||||||
|
iconCode.contains("lightsleetshowers") -> "10"
|
||||||
|
iconCode.contains("lightsnow") -> "13"
|
||||||
|
iconCode.contains("lightsnowandthunder") -> "13"
|
||||||
|
iconCode.contains("lightsnowshowers") -> "13"
|
||||||
|
iconCode.contains("lightssleetshowersandthunder") -> "81"
|
||||||
|
iconCode.contains("lightssnowshowersandthunder") -> "81"
|
||||||
|
iconCode.contains("partlycloudy") -> "03"
|
||||||
|
iconCode.contains("rain") -> "10"
|
||||||
|
iconCode.contains("rainandthunder") -> "11"
|
||||||
|
iconCode.contains("rainshowers") -> "10"
|
||||||
|
iconCode.contains("rainshowersandthunder") -> "11"
|
||||||
|
iconCode.contains("sleet") -> "10"
|
||||||
|
iconCode.contains("sleetandthunder") -> "11"
|
||||||
|
iconCode.contains("sleetshowers") -> "10"
|
||||||
|
iconCode.contains("sleetshowersandthunder") -> "11"
|
||||||
|
iconCode.contains("snow") -> "13"
|
||||||
|
iconCode.contains("snowandthunder") -> "13"
|
||||||
|
iconCode.contains("snowshowers") -> "13"
|
||||||
|
iconCode.contains("snowshowersandthunder") -> "13"
|
||||||
|
else -> ""
|
||||||
|
} + if (isDaytime) "d" else "n"
|
||||||
|
|
||||||
}
|
}
|
@ -3,10 +3,20 @@ package com.tommasoberlose.anotherwidget.helpers
|
|||||||
import android.appwidget.AppWidgetManager
|
import android.appwidget.AppWidgetManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.Configuration.ORIENTATION_PORTRAIT
|
import android.content.res.Configuration.ORIENTATION_PORTRAIT
|
||||||
|
import android.graphics.Typeface
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.HandlerThread
|
||||||
|
import android.os.Looper
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.core.provider.FontRequest
|
||||||
|
import androidx.core.provider.FontsContractCompat
|
||||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import com.tommasoberlose.anotherwidget.db.EventRepository
|
import com.tommasoberlose.anotherwidget.db.EventRepository
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.toPixel
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
object WidgetHelper {
|
object WidgetHelper {
|
||||||
class WidgetSizeProvider(
|
class WidgetSizeProvider(
|
||||||
@ -15,9 +25,8 @@ 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 width = getWidgetWidth(widgetId)
|
||||||
val width = getWidgetWidth(isPortrait, widgetId)
|
val height = getWidgetHeight(widgetId)
|
||||||
val height = getWidgetHeight(isPortrait, widgetId)
|
|
||||||
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)
|
||||||
@ -25,9 +34,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)
|
||||||
@ -44,4 +53,37 @@ object WidgetHelper {
|
|||||||
width to second * factor
|
width to second * factor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun runWithCustomTypeface(context: Context, function: (typeface: Typeface?) -> Unit) {
|
||||||
|
if (Preferences.customFontFile != "") {
|
||||||
|
val request = FontRequest(
|
||||||
|
"com.google.android.gms.fonts",
|
||||||
|
"com.google.android.gms",
|
||||||
|
Preferences.customFontFile,
|
||||||
|
R.array.com_google_android_gms_fonts_certs
|
||||||
|
)
|
||||||
|
|
||||||
|
val callback = object : FontsContractCompat.FontRequestCallback() {
|
||||||
|
override fun onTypefaceRetrieved(typeface: Typeface) {
|
||||||
|
function.invoke(typeface)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTypefaceRequestFailed(reason: Int) {
|
||||||
|
function.invoke(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val handlerThread = HandlerThread("generateView")
|
||||||
|
handlerThread.start()
|
||||||
|
if (Looper.myLooper() == null) {
|
||||||
|
Looper.prepare()
|
||||||
|
}
|
||||||
|
|
||||||
|
Handler(handlerThread.looper).run {
|
||||||
|
FontsContractCompat.requestFont(context, request, callback, this)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
function.invoke(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,20 +1,58 @@
|
|||||||
package com.tommasoberlose.anotherwidget.network
|
package com.tommasoberlose.anotherwidget.network
|
||||||
|
|
||||||
import android.content.Context
|
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.haroldadmin.cnradapter.executeWithRetry
|
||||||
import com.kwabenaberko.openweathermaplib.constants.Units
|
import com.kwabenaberko.openweathermaplib.constants.Units
|
||||||
import com.kwabenaberko.openweathermaplib.implementation.OpenWeatherMapHelper
|
import com.kwabenaberko.openweathermaplib.implementation.OpenWeatherMapHelper
|
||||||
import com.kwabenaberko.openweathermaplib.implementation.callbacks.CurrentWeatherCallback
|
import com.kwabenaberko.openweathermaplib.implementation.callbacks.CurrentWeatherCallback
|
||||||
import com.kwabenaberko.openweathermaplib.models.currentweather.CurrentWeather
|
import com.kwabenaberko.openweathermaplib.models.currentweather.CurrentWeather
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
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.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 org.greenrobot.eventbus.EventBus
|
||||||
|
import java.lang.Exception
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class WeatherNetworkApi(val context: Context) {
|
class WeatherNetworkApi(val context: Context) {
|
||||||
fun updateWeather() {
|
suspend fun updateWeather() {
|
||||||
if (Preferences.showWeather && Preferences.weatherProviderApi != "" && Preferences.customLocationLat != "" && Preferences.customLocationLon != "") {
|
Kotpref.init(context)
|
||||||
val helper = OpenWeatherMapHelper(Preferences.weatherProviderApi)
|
Preferences.weatherProviderError = "-"
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
|
||||||
|
if (Preferences.showWeather && Preferences.customLocationLat != "" && Preferences.customLocationLon != "") {
|
||||||
|
when (Constants.WeatherProvider.fromInt(Preferences.weatherProvider)) {
|
||||||
|
Constants.WeatherProvider.OPEN_WEATHER -> useOpenWeatherMap(context)
|
||||||
|
Constants.WeatherProvider.WEATHER_GOV -> useWeatherGov(context)
|
||||||
|
Constants.WeatherProvider.WEATHER_BIT -> useWeatherBitProvider(context)
|
||||||
|
Constants.WeatherProvider.WEATHER_API -> useWeatherApiProvider(context)
|
||||||
|
Constants.WeatherProvider.HERE -> useHereProvider(context)
|
||||||
|
Constants.WeatherProvider.ACCUWEATHER -> useAccuweatherProvider(context)
|
||||||
|
Constants.WeatherProvider.YR -> useYrProvider(context)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
WeatherHelper.removeWeather(
|
||||||
|
context
|
||||||
|
)
|
||||||
|
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun useOpenWeatherMap(context: Context) {
|
||||||
|
if (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)
|
||||||
helper.getCurrentWeatherByGeoCoordinates(Preferences.customLocationLat.toDouble(), Preferences.customLocationLon.toDouble(), object :
|
helper.getCurrentWeatherByGeoCoordinates(Preferences.customLocationLat.toDouble(), Preferences.customLocationLon.toDouble(), object :
|
||||||
CurrentWeatherCallback {
|
CurrentWeatherCallback {
|
||||||
@ -24,19 +62,383 @@ class WeatherNetworkApi(val context: Context) {
|
|||||||
Preferences.weatherIcon = currentWeather.weather[0].icon
|
Preferences.weatherIcon = currentWeather.weather[0].icon
|
||||||
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
|
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
|
||||||
MainWidget.updateWidget(context)
|
MainWidget.updateWidget(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
Preferences.weatherProviderError = ""
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(throwable: Throwable?) {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_missing_key)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
|
||||||
|
WeatherHelper.removeWeather(
|
||||||
|
context
|
||||||
|
)
|
||||||
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(throwable: Throwable?) {
|
private suspend fun useWeatherGov(context: Context) {
|
||||||
|
val repository = WeatherGovRepository()
|
||||||
|
val pointsResponse = executeWithRetry(times = 5) {
|
||||||
|
repository.getGridPoints(
|
||||||
|
Preferences.customLocationLat,
|
||||||
|
Preferences.customLocationLon
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
when (pointsResponse) {
|
||||||
|
is NetworkResponse.Success -> {
|
||||||
|
try {
|
||||||
|
val pp = pointsResponse.body["properties"] as LinkedTreeMap<*, *>
|
||||||
|
val gridId = pp["gridId"] as String
|
||||||
|
val gridX = pp["gridX"] as Double
|
||||||
|
val gridY = pp["gridY"] as Double
|
||||||
|
|
||||||
|
when (val weatherResponse = repository.getWeather(
|
||||||
|
gridId,
|
||||||
|
gridX,
|
||||||
|
gridY,
|
||||||
|
if (Preferences.weatherTempUnit == "F") "us" else "si"
|
||||||
|
)) {
|
||||||
|
is NetworkResponse.Success -> {
|
||||||
|
try {
|
||||||
|
val props =
|
||||||
|
weatherResponse.body["properties"] as LinkedTreeMap<*, *>
|
||||||
|
val periods = props["periods"] as List<*>
|
||||||
|
val now = periods[0] as LinkedTreeMap<*, *>
|
||||||
|
|
||||||
|
val temp = now["temperature"] as Double
|
||||||
|
val fullIcon = now["icon"] as String
|
||||||
|
val isDaytime = now["isDaytime"] as Boolean
|
||||||
|
|
||||||
|
Preferences.weatherTemp = temp.toFloat()
|
||||||
|
Preferences.weatherIcon = WeatherHelper.getWeatherGovIcon(fullIcon, isDaytime)
|
||||||
|
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
|
||||||
|
|
||||||
|
Preferences.weatherProviderError = ""
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
|
||||||
|
MainWidget.updateWidget(context)
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
} finally {
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 -> {
|
||||||
|
if (pointsResponse.body?.containsKey("status") == true && (pointsResponse.body?.get("status") as Double).toInt() == 404) {
|
||||||
|
Preferences.weatherProviderError = ""
|
||||||
|
Preferences.weatherProviderLocationError = context.getString(R.string.weather_provider_error_wrong_location)
|
||||||
} else {
|
} else {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
}
|
||||||
|
|
||||||
WeatherHelper.removeWeather(
|
WeatherHelper.removeWeather(
|
||||||
context
|
context
|
||||||
)
|
)
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_connection)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun useHereProvider(context: Context) {
|
||||||
|
if (Preferences.weatherProviderApiHere != "") {
|
||||||
|
val repository = HereRepository()
|
||||||
|
|
||||||
|
when (val response = repository.getWeather()) {
|
||||||
|
is NetworkResponse.Success -> {
|
||||||
|
try {
|
||||||
|
Log.d("ciao - here", response.body.toString())
|
||||||
|
Preferences.weatherProviderError = ""
|
||||||
|
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 -> {
|
||||||
|
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 {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_missing_key)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
|
||||||
|
WeatherHelper.removeWeather(
|
||||||
|
context
|
||||||
|
)
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun useWeatherBitProvider(context: Context) {
|
||||||
|
if (Preferences.weatherProviderApiWeatherBit != "") {
|
||||||
|
val repository = WeatherbitRepository()
|
||||||
|
|
||||||
|
when (val response = repository.getWeather()) {
|
||||||
|
is NetworkResponse.Success -> {
|
||||||
|
try {
|
||||||
|
val data = response.body["data"] as List<LinkedTreeMap<String, Any>>?
|
||||||
|
data?.first()?.let {
|
||||||
|
val temp = it["temp"] as Double
|
||||||
|
val weatherInfo = it["weather"] as LinkedTreeMap<String, Any>
|
||||||
|
val iconCode = weatherInfo["icon"] as String
|
||||||
|
|
||||||
|
Preferences.weatherTemp = temp.toFloat()
|
||||||
|
Preferences.weatherIcon = WeatherHelper.getWeatherBitIcon(iconCode)
|
||||||
|
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
|
||||||
|
MainWidget.updateWidget(context)
|
||||||
|
|
||||||
|
Preferences.weatherProviderError = ""
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
}
|
||||||
|
} 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 (response.code) {
|
||||||
|
403 -> {
|
||||||
|
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
|
||||||
|
)
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_connection)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_missing_key)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
|
||||||
|
WeatherHelper.removeWeather(
|
||||||
|
context
|
||||||
|
)
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun useWeatherApiProvider(context: Context) {
|
||||||
|
if (Preferences.weatherProviderApiWeatherApi != "") {
|
||||||
|
val repository = WeatherApiRepository()
|
||||||
|
|
||||||
|
when (val response = repository.getWeather()) {
|
||||||
|
is NetworkResponse.Success -> {
|
||||||
|
try {
|
||||||
|
val current = response.body["current"] as LinkedTreeMap<String, Any>?
|
||||||
|
current?.let {
|
||||||
|
val tempC = current["temp_c"] as Double
|
||||||
|
val tempF = current["temp_f"] as Double
|
||||||
|
val isDay = current["is_day"] as Double
|
||||||
|
val condition = current["condition"] as LinkedTreeMap<String, Any>
|
||||||
|
val iconCode = condition["code"] as Double
|
||||||
|
|
||||||
|
Preferences.weatherTemp = if (Preferences.weatherTempUnit == "F") tempF.toFloat() else tempC.toFloat()
|
||||||
|
Preferences.weatherIcon = WeatherHelper.getWeatherApiIcon(iconCode.toInt(), isDay.toInt() == 1)
|
||||||
|
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
|
||||||
|
MainWidget.updateWidget(context)
|
||||||
|
|
||||||
|
Preferences.weatherProviderError = ""
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
}
|
||||||
|
} 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 (response.code) {
|
||||||
|
401 -> {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_invalid_key)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
}
|
||||||
|
403 -> {
|
||||||
|
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 {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_missing_key)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
|
||||||
|
WeatherHelper.removeWeather(
|
||||||
|
context
|
||||||
|
)
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun useAccuweatherProvider(context: Context) {
|
||||||
|
if (Preferences.weatherProviderApiAccuweather != "") {
|
||||||
|
// val repository = AccuweatherRepository()
|
||||||
|
|
||||||
|
// when (val response = repository.getWeather()) {
|
||||||
|
// is NetworkResponse.Success -> {
|
||||||
|
// try {
|
||||||
|
// Log.d("ciao", response.body.toString())
|
||||||
|
// } 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())
|
||||||
|
// }
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_missing_key)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
|
||||||
|
WeatherHelper.removeWeather(
|
||||||
|
context
|
||||||
|
)
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun useYrProvider(context: Context) {
|
||||||
|
val repository = YrRepository()
|
||||||
|
|
||||||
|
when (val response = repository.getWeather()) {
|
||||||
|
is NetworkResponse.Success -> {
|
||||||
|
try {
|
||||||
|
val pp = response.body["properties"] as LinkedTreeMap<*, *>
|
||||||
|
val data = pp["timeseries"] as List<LinkedTreeMap<String, Any>>?
|
||||||
|
data?.let {
|
||||||
|
val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
|
||||||
|
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 next = dd["next_1_hours"] as LinkedTreeMap<*, *>
|
||||||
|
|
||||||
|
val details = instant["details"] as LinkedTreeMap<*, *>
|
||||||
|
val temp = details["air_temperature"] as Double
|
||||||
|
|
||||||
|
val summary = next["summary"] as LinkedTreeMap<*, *>
|
||||||
|
val iconCode = summary["symbol_code"] as String
|
||||||
|
|
||||||
|
Preferences.weatherTemp = temp.toFloat()
|
||||||
|
Preferences.weatherIcon = WeatherHelper.getYRIcon(iconCode, now.get(Calendar.HOUR_OF_DAY) >= 22 || now.get(Calendar.HOUR_OF_DAY) <= 8)
|
||||||
|
Preferences.weatherTempUnit = "C"
|
||||||
|
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
|
||||||
|
MainWidget.updateWidget(context)
|
||||||
|
|
||||||
|
Preferences.weatherProviderError = ""
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} catch(ex: Exception) {
|
||||||
|
ex.printStackTrace()
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
} finally {
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is NetworkResponse.ServerError -> {
|
||||||
|
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())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.network.api
|
||||||
|
|
||||||
|
import com.haroldadmin.cnradapter.NetworkResponse
|
||||||
|
import retrofit2.http.*
|
||||||
|
|
||||||
|
object ApiServices {
|
||||||
|
interface WeatherGovApiService {
|
||||||
|
@Headers("User-Agent: (Another Widget, tommaso.berlose@gmail.com)")
|
||||||
|
@GET("points/{latitude},{longitude}")
|
||||||
|
suspend fun getGridPoints(
|
||||||
|
@Path("latitude") latitude: String,
|
||||||
|
@Path("longitude") longitude: String
|
||||||
|
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
|
||||||
|
|
||||||
|
@Headers("User-Agent: (Another Widget, tommaso.berlose@gmail.com)")
|
||||||
|
@GET("gridpoints/{gridId}/{gridX},{gridY}/forecast")
|
||||||
|
suspend fun getWeather(
|
||||||
|
@Path("gridId") gridId: String,
|
||||||
|
@Path("gridX") gridX: Int,
|
||||||
|
@Path("gridY") gridY: Int,
|
||||||
|
@Query("units") unit: String
|
||||||
|
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WeatherBitService {
|
||||||
|
@GET("current")
|
||||||
|
suspend fun getWeather(
|
||||||
|
@Query("key") key: String,
|
||||||
|
@Query("lat") lat: String,
|
||||||
|
@Query("lon") lon: String,
|
||||||
|
@Query("units") units: String,
|
||||||
|
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WeatherApiService {
|
||||||
|
@Headers("Accept: application/json")
|
||||||
|
@GET("current.json")
|
||||||
|
suspend fun getWeather(
|
||||||
|
@Query("key") key: String,
|
||||||
|
@Query("q") location: String,
|
||||||
|
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HereService {
|
||||||
|
@GET("report.json")
|
||||||
|
suspend fun getWeather(
|
||||||
|
@Query("apiKey") apiKey: String,
|
||||||
|
@Query("latitude") latitude: String,
|
||||||
|
@Query("longitude") longitude: String,
|
||||||
|
@Query("product") product: String,
|
||||||
|
@Query("oneobservation") oneobservation: Boolean,
|
||||||
|
@Query("metric") metric: Boolean,
|
||||||
|
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AccuweatherService {
|
||||||
|
@GET("")
|
||||||
|
suspend fun getWeather(
|
||||||
|
@Path("gridId") gridId: String,
|
||||||
|
@Path("gridX") gridX: Int,
|
||||||
|
@Path("gridY") gridY: Int,
|
||||||
|
@Query("units") unit: String
|
||||||
|
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface YrService {
|
||||||
|
@Headers("User-Agent: AnotherWidget")
|
||||||
|
@GET("compact.json")
|
||||||
|
suspend fun getWeather(
|
||||||
|
@Query("lat") lat: String,
|
||||||
|
@Query("lon") lon: String,
|
||||||
|
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
|
||||||
|
}
|
||||||
|
}
|
@ -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 AccuweatherRepository {
|
||||||
|
|
||||||
|
/* ACCUWEATHER */
|
||||||
|
private val apiServiceAccu: ApiServices.AccuweatherService = getRetrofit().create(ApiServices.AccuweatherService::class.java)
|
||||||
|
suspend fun getWeather(): Nothing = TODO()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val BASE_URL_ACCU = ""
|
||||||
|
|
||||||
|
private fun getRetrofit(): Retrofit {
|
||||||
|
return Retrofit.Builder()
|
||||||
|
.baseUrl(BASE_URL_ACCU)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
|
.addCallAdapterFactory(NetworkResponseAdapterFactory())
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.network.repository
|
||||||
|
|
||||||
|
import com.haroldadmin.cnradapter.NetworkResponseAdapterFactory
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.network.api.ApiServices
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
|
||||||
|
class HereRepository {
|
||||||
|
|
||||||
|
/* HERE */
|
||||||
|
private val apiServiceHere: ApiServices.HereService = getRetrofit().create(ApiServices.HereService::class.java)
|
||||||
|
suspend fun getWeather() = apiServiceHere.getWeather(Preferences.weatherProviderApiHere, Preferences.customLocationLat, Preferences.customLocationLon, "observation", true, Preferences.weatherTempUnit != "F")
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val BASE_URL_HERE = "https://weather.ls.hereapi.com/weather/1.0/"
|
||||||
|
|
||||||
|
private fun getRetrofit(): Retrofit {
|
||||||
|
return Retrofit.Builder()
|
||||||
|
.baseUrl(BASE_URL_HERE)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
|
.addCallAdapterFactory(NetworkResponseAdapterFactory())
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.network.repository
|
||||||
|
|
||||||
|
import com.haroldadmin.cnradapter.NetworkResponseAdapterFactory
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.network.api.ApiServices
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
|
||||||
|
class WeatherApiRepository {
|
||||||
|
|
||||||
|
/* WEATHER API*/
|
||||||
|
private val apiServiceApi: ApiServices.WeatherApiService = getRetrofit().create(ApiServices.WeatherApiService::class.java)
|
||||||
|
suspend fun getWeather() = apiServiceApi.getWeather(Preferences.weatherProviderApiWeatherApi, "${Preferences.customLocationLat},${Preferences.customLocationLon}")
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val BASE_URL_API = "http://api.weatherapi.com/v1/"
|
||||||
|
|
||||||
|
private fun getRetrofit(): Retrofit {
|
||||||
|
return Retrofit.Builder()
|
||||||
|
.baseUrl(BASE_URL_API)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
|
.addCallAdapterFactory(NetworkResponseAdapterFactory())
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
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 WeatherGovRepository {
|
||||||
|
|
||||||
|
/* WEATHER GOV*/
|
||||||
|
private val apiServiceGov: ApiServices.WeatherGovApiService = getRetrofit().create(ApiServices.WeatherGovApiService::class.java)
|
||||||
|
suspend fun getGridPoints(latitude: String, longitude: String) = apiServiceGov.getGridPoints(latitude, longitude)
|
||||||
|
suspend fun getWeather(gridId: String, gridX: Double, gridY: Double, unit: String) = apiServiceGov.getWeather(gridId, gridX.toInt(), gridY.toInt(), unit)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val BASE_URL_GOV = "https://api.weather.gov/"
|
||||||
|
|
||||||
|
private fun getRetrofit(): Retrofit {
|
||||||
|
return Retrofit.Builder()
|
||||||
|
.baseUrl(BASE_URL_GOV)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
|
.addCallAdapterFactory(NetworkResponseAdapterFactory())
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.network.repository
|
||||||
|
|
||||||
|
import com.haroldadmin.cnradapter.NetworkResponseAdapterFactory
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.network.api.ApiServices
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
|
||||||
|
class WeatherbitRepository {
|
||||||
|
|
||||||
|
/* BIT */
|
||||||
|
private val apiServiceBit: ApiServices.WeatherBitService = getRetrofit().create(ApiServices.WeatherBitService::class.java)
|
||||||
|
suspend fun getWeather() = apiServiceBit.getWeather(Preferences.weatherProviderApiWeatherBit, Preferences.customLocationLat, Preferences.customLocationLon, if (Preferences.weatherTempUnit == "F") "I" else "M")
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val BASE_URL_BIT = "https://api.weatherbit.io/v2.0/"
|
||||||
|
|
||||||
|
private fun getRetrofit(): Retrofit {
|
||||||
|
return Retrofit.Builder()
|
||||||
|
.baseUrl(BASE_URL_BIT)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
|
.addCallAdapterFactory(NetworkResponseAdapterFactory())
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.network.repository
|
||||||
|
|
||||||
|
import com.haroldadmin.cnradapter.NetworkResponseAdapterFactory
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.network.api.ApiServices
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
|
||||||
|
class YrRepository {
|
||||||
|
|
||||||
|
/* YR */
|
||||||
|
private val apiServiceYr: ApiServices.YrService = getRetrofit().create(ApiServices.YrService::class.java)
|
||||||
|
suspend fun getWeather() = apiServiceYr.getWeather(Preferences.customLocationLat, Preferences.customLocationLon)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val BASE_URL_YR = "https://api.met.no/weatherapi/locationforecast/2.0/"
|
||||||
|
|
||||||
|
private fun getRetrofit(): Retrofit {
|
||||||
|
return Retrofit.Builder()
|
||||||
|
.baseUrl(BASE_URL_YR)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
|
.addCallAdapterFactory(NetworkResponseAdapterFactory())
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@ import android.content.Intent
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.chibatching.kotpref.Kotpref
|
import com.chibatching.kotpref.Kotpref
|
||||||
|
import com.chibatching.kotpref.blockingBulk
|
||||||
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
|
||||||
import com.google.android.gms.fitness.Fitness
|
import com.google.android.gms.fitness.Fitness
|
||||||
@ -46,7 +47,9 @@ class ActivityDetectionReceiver : BroadcastReceiver() {
|
|||||||
|
|
||||||
private fun resetDailySteps(context: Context) {
|
private fun resetDailySteps(context: Context) {
|
||||||
Kotpref.init(context)
|
Kotpref.init(context)
|
||||||
Preferences.googleFitSteps = -1
|
Preferences.blockingBulk {
|
||||||
|
remove(Preferences::googleFitSteps)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -135,10 +138,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,7 +165,7 @@ class ActivityDetectionReceiver : BroadcastReceiver() {
|
|||||||
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))
|
cancel(PendingIntent.getBroadcast(context, 5, Intent(context, ActivityDetectionReceiver::class.java), 0))
|
||||||
setExactAndAllowWhileIdle(
|
setExact(
|
||||||
AlarmManager.RTC,
|
AlarmManager.RTC,
|
||||||
Calendar.getInstance().timeInMillis + 5 * 60 * 1000,
|
Calendar.getInstance().timeInMillis + 5 * 60 * 1000,
|
||||||
PendingIntent.getBroadcast(
|
PendingIntent.getBroadcast(
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
package com.tommasoberlose.anotherwidget.receivers
|
|
||||||
|
|
||||||
import android.app.Notification
|
|
||||||
import android.media.MediaMetadata
|
|
||||||
import android.media.session.MediaController
|
|
||||||
import android.media.session.MediaSession
|
|
||||||
import android.media.session.PlaybackState
|
|
||||||
import android.service.notification.NotificationListenerService
|
|
||||||
import android.service.notification.StatusBarNotification
|
|
||||||
import android.util.Log
|
|
||||||
import com.chibatching.kotpref.bulk
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.WidgetHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
|
||||||
|
|
||||||
|
|
||||||
class MusicNotificationListener : NotificationListenerService() {
|
|
||||||
override fun onListenerConnected() {
|
|
||||||
MediaPlayerHelper.updatePlayingMediaInfo(this)
|
|
||||||
super.onListenerConnected()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNotificationPosted(sbn: StatusBarNotification?) {
|
|
||||||
sbn?.notification?.extras?.let { bundle ->
|
|
||||||
bundle.getParcelable<MediaSession.Token>(Notification.EXTRA_MEDIA_SESSION)?.let {
|
|
||||||
MediaPlayerHelper.updatePlayingMediaInfo(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.onNotificationPosted(sbn)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNotificationRemoved(sbn: StatusBarNotification?) {
|
|
||||||
MediaPlayerHelper.updatePlayingMediaInfo(this)
|
|
||||||
super.onNotificationRemoved(sbn)
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,101 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.receivers
|
||||||
|
|
||||||
|
import android.app.*
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.media.session.MediaSession
|
||||||
|
import android.os.Build
|
||||||
|
import android.service.notification.NotificationListenerService
|
||||||
|
import android.service.notification.StatusBarNotification
|
||||||
|
import android.util.Log
|
||||||
|
import android.widget.Toast
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Actions
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
|
import java.lang.Exception
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
class NotificationListener : NotificationListenerService() {
|
||||||
|
override fun onListenerConnected() {
|
||||||
|
MediaPlayerHelper.updatePlayingMediaInfo(this)
|
||||||
|
MainWidget.updateWidget(this)
|
||||||
|
super.onListenerConnected()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNotificationPosted(sbn: StatusBarNotification?) {
|
||||||
|
sbn?.notification?.extras?.let { bundle ->
|
||||||
|
bundle.getParcelable<MediaSession.Token>(Notification.EXTRA_MEDIA_SESSION)?.let {
|
||||||
|
MediaPlayerHelper.updatePlayingMediaInfo(this)
|
||||||
|
} ?: run {
|
||||||
|
val isGroupHeader = sbn.notification.flags and Notification.FLAG_GROUP_SUMMARY != 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")) {
|
||||||
|
Preferences.lastNotificationId = sbn.id
|
||||||
|
Preferences.lastNotificationTitle = bundle.getString(Notification.EXTRA_TITLE) ?: ""
|
||||||
|
try {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
|
Preferences.lastNotificationIcon = sbn.notification.smallIcon.resId
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
Preferences.lastNotificationIcon = sbn.notification.icon
|
||||||
|
}
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
Preferences.lastNotificationIcon = 0
|
||||||
|
}
|
||||||
|
Preferences.lastNotificationPackage = sbn.packageName
|
||||||
|
MainWidget.updateWidget(this)
|
||||||
|
setTimeout(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onNotificationPosted(sbn)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNotificationRemoved(sbn: StatusBarNotification?) {
|
||||||
|
MediaPlayerHelper.updatePlayingMediaInfo(this)
|
||||||
|
|
||||||
|
sbn?.let {
|
||||||
|
if (sbn.id == Preferences.lastNotificationId && sbn.packageName == Preferences.lastNotificationPackage) {
|
||||||
|
ActiveNotificationsHelper.clearLastNotification(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWidget.updateWidget(this)
|
||||||
|
super.onNotificationRemoved(sbn)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setTimeout(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, 28943, intent, 0))
|
||||||
|
val timeoutPref = Constants.GlanceNotificationTimer.fromInt(Preferences.hideNotificationAfter)
|
||||||
|
if (timeoutPref != Constants.GlanceNotificationTimer.WHEN_DISMISSED) {
|
||||||
|
setExact(
|
||||||
|
AlarmManager.RTC,
|
||||||
|
Calendar.getInstance().timeInMillis + when (timeoutPref) {
|
||||||
|
Constants.GlanceNotificationTimer.HALF_MINUTE -> 30 * 1000
|
||||||
|
Constants.GlanceNotificationTimer.ONE_MINUTE -> 60 * 1000
|
||||||
|
Constants.GlanceNotificationTimer.FIVE_MINUTES -> 5 * 60 * 1000
|
||||||
|
Constants.GlanceNotificationTimer.TEN_MINUTES -> 10 * 60 * 1000
|
||||||
|
Constants.GlanceNotificationTimer.FIFTEEN_MINUTES -> 15 * 60 * 1000
|
||||||
|
else -> 0
|
||||||
|
},
|
||||||
|
PendingIntent.getBroadcast(
|
||||||
|
context,
|
||||||
|
5,
|
||||||
|
intent,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,10 +12,12 @@ 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.BatteryHelper
|
import com.tommasoberlose.anotherwidget.helpers.*
|
||||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
|
||||||
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 kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.joda.time.Period
|
import org.joda.time.Period
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@ -31,17 +33,38 @@ class UpdatesReceiver : BroadcastReceiver() {
|
|||||||
Intent.ACTION_LOCALE_CHANGED,
|
Intent.ACTION_LOCALE_CHANGED,
|
||||||
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",
|
"com.sec.android.widgetapp.APPWIDGET_RESIZE",
|
||||||
AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED,
|
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)) {
|
||||||
setUpdates(context, intent.getLongExtra(EVENT_ID, -1))
|
setUpdates(context, intent.getLongExtra(EVENT_ID, -1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Actions.ACTION_CLEAR_NOTIFICATION -> {
|
||||||
|
ActiveNotificationsHelper.clearLastNotification(context)
|
||||||
|
MainWidget.updateWidget(context)
|
||||||
|
}
|
||||||
|
Actions.ACTION_UPDATE_GREETINGS -> {
|
||||||
|
MainWidget.updateWidget(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
Actions.ACTION_REFRESH -> {
|
||||||
|
ActiveNotificationsHelper.clearLastNotification(context)
|
||||||
|
|
||||||
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
CalendarHelper.updateEventList(context)
|
||||||
|
MediaPlayerHelper.updatePlayingMediaInfo(context)
|
||||||
|
WeatherHelper.updateWeather(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,10 +5,12 @@ 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 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 kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
@ -23,17 +25,19 @@ class WeatherReceiver : BroadcastReceiver() {
|
|||||||
Intent.ACTION_TIME_CHANGED -> setUpdates(context)
|
Intent.ACTION_TIME_CHANGED -> setUpdates(context)
|
||||||
|
|
||||||
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
|
private const val MINUTE = 60 * 1000L
|
||||||
fun setUpdates(context: Context) {
|
fun setUpdates(context: Context) {
|
||||||
removeUpdates(context)
|
removeUpdates(context)
|
||||||
|
|
||||||
if (Preferences.showWeather && Preferences.weatherProviderApi != "") {
|
if (Preferences.showWeather) {
|
||||||
val interval = MINUTE * when (Preferences.weatherRefreshPeriod) {
|
val interval = MINUTE * when (Preferences.weatherRefreshPeriod) {
|
||||||
0 -> 30
|
0 -> 30
|
||||||
1 -> 60
|
1 -> 60
|
||||||
@ -55,7 +59,7 @@ class WeatherReceiver : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun setOneTimeUpdate(context: Context) {
|
fun setOneTimeUpdate(context: Context) {
|
||||||
if (Preferences.showWeather && Preferences.weatherProviderApi != "") {
|
if (Preferences.showWeather) {
|
||||||
listOf(10, 20, 30).forEach {
|
listOf(10, 20, 30).forEach {
|
||||||
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
setExactAndAllowWhileIdle(
|
setExactAndAllowWhileIdle(
|
||||||
|
@ -0,0 +1,127 @@
|
|||||||
|
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 var job: Job? = null
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
startForeground(LOCATION_ACCESS_NOTIFICATION_ID, getLocationAccessNotification())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
job?.cancel()
|
||||||
|
job = GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
if (ActivityCompat.checkSelfPermission(
|
||||||
|
this@LocationService,
|
||||||
|
Manifest.permission.ACCESS_FINE_LOCATION
|
||||||
|
) == PackageManager.PERMISSION_GRANTED
|
||||||
|
) {
|
||||||
|
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()
|
||||||
|
job?.cancel()
|
||||||
|
job = null
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
.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,143 +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.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 {
|
|
||||||
timeInMillis = begin.timeInMillis
|
|
||||||
add(Calendar.DAY_OF_YEAR, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
eventList.add(
|
|
||||||
Event(
|
|
||||||
id = instance.id,
|
|
||||||
eventID = e.id,
|
|
||||||
title = e.title ?: "",
|
|
||||||
startDate = instance.begin,
|
|
||||||
endDate = instance.end,
|
|
||||||
calendarID = e.calendarId.toInt(),
|
|
||||||
allDay = e.allDay,
|
|
||||||
address = e.eventLocation ?: "",
|
|
||||||
selfAttendeeStatus = e.selfAttendeeStatus.toInt(),
|
|
||||||
availability = e.availability
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} catch (ignored: Exception) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val filteredEventList = eventList
|
|
||||||
.applyFilters()
|
|
||||||
|
|
||||||
if (filteredEventList.isEmpty()) {
|
|
||||||
eventRepository.resetNextEventData()
|
|
||||||
eventRepository.clearEvents()
|
|
||||||
} else {
|
|
||||||
eventList.sortWith(Comparator { event: Event, event1: Event ->
|
|
||||||
val date = Calendar.getInstance().apply { timeInMillis = event.startDate }
|
|
||||||
val date1 = Calendar.getInstance().apply { timeInMillis = event1.startDate }
|
|
||||||
|
|
||||||
if (date.get(Calendar.DAY_OF_YEAR) == date1.get(Calendar.DAY_OF_YEAR) && date.get(Calendar.YEAR) == date1.get(Calendar.YEAR)) {
|
|
||||||
if (event.allDay && event1.allDay) {
|
|
||||||
event1.startDate.compareTo(event.startDate)
|
|
||||||
} else if (event.allDay) {
|
|
||||||
-1
|
|
||||||
} else if (event1.allDay) {
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
event1.startDate.compareTo(event.startDate)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
event1.startDate.compareTo(event.startDate)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
eventList.reverse()
|
|
||||||
eventRepository.saveEvents(
|
|
||||||
eventList
|
|
||||||
)
|
|
||||||
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,218 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.services
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.app.*
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.IBinder
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.core.app.NotificationManagerCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
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.activities.MainActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import me.everything.providers.android.calendar.CalendarProvider
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
|
class UpdateCalendarService : Service() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val CALENDAR_SYNC_NOTIFICATION_ID = 28468
|
||||||
|
fun enqueueWork(context: Context) {
|
||||||
|
context.startService(Intent(context, UpdateCalendarService::class.java))
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||||
|
context.startForegroundService(Intent(context, UpdateCalendarService::class.java))
|
||||||
|
} else {
|
||||||
|
context.startService(Intent(context, UpdateCalendarService::class.java))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
startForeground(CALENDAR_SYNC_NOTIFICATION_ID, getCalendarSyncNotification())
|
||||||
|
}
|
||||||
|
|
||||||
|
private var job: Job? = null
|
||||||
|
|
||||||
|
override fun onBind(intent: Intent?): IBinder? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
job?.cancel()
|
||||||
|
job = GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
|
||||||
|
val eventRepository = EventRepository(this@UpdateCalendarService)
|
||||||
|
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@UpdateCalendarService)
|
||||||
|
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@UpdateCalendarService)
|
||||||
|
MainWidget.updateWidget(this@UpdateCalendarService)
|
||||||
|
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
eventRepository.close()
|
||||||
|
|
||||||
|
stopSelf()
|
||||||
|
}
|
||||||
|
|
||||||
|
return START_STICKY
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
job?.cancel()
|
||||||
|
job = null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getCalendarSyncNotification(): 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.calendar_sync_notification_channel_id),
|
||||||
|
getString(R.string.calendar_sync_notification_channel_name),
|
||||||
|
NotificationManager.IMPORTANCE_LOW
|
||||||
|
).apply {
|
||||||
|
description = getString(R.string.calendar_sync_notification_channel_description)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val builder = NotificationCompat.Builder(this@UpdateCalendarService, getString(R.string.calendar_sync_notification_channel_id))
|
||||||
|
.setSmallIcon(R.drawable.ic_stat_notification)
|
||||||
|
.setContentTitle(getString(R.string.calendar_sync_notification_title))
|
||||||
|
.setOngoing(true)
|
||||||
|
.setColor(ContextCompat.getColor(this@UpdateCalendarService, R.color.colorAccent))
|
||||||
|
|
||||||
|
// Main intent that open the activity
|
||||||
|
builder.setContentIntent(PendingIntent.getActivity(this@UpdateCalendarService, 0, Intent(this@UpdateCalendarService, MainActivity::class.java), PendingIntent.FLAG_UPDATE_CURRENT))
|
||||||
|
|
||||||
|
return builder.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,135 +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.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.list_view
|
|
||||||
import kotlinx.coroutines.*
|
|
||||||
import net.idik.lib.slimadapter.SlimAdapter
|
|
||||||
|
|
||||||
|
|
||||||
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 = SlimAdapter.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)
|
|
||||||
.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
|
|
||||||
|
|
||||||
viewModel.appList.observe(this, Observer {
|
|
||||||
updateList(list = it)
|
|
||||||
loader.visibility = View.INVISIBLE
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.searchInput.observe(this, Observer { search ->
|
|
||||||
updateList(search = search)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,94 +1,75 @@
|
|||||||
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)
|
|
||||||
|
|
||||||
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 +91,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 +134,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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.activities
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.app.AlertDialog
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.text.Html
|
|
||||||
import android.view.View
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.R
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.openURI
|
|
||||||
import kotlinx.android.synthetic.main.activity_weather_provider.*
|
|
||||||
|
|
||||||
class WeatherProviderActivity : AppCompatActivity() {
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
setContentView(R.layout.activity_weather_provider)
|
|
||||||
|
|
||||||
action_back.setOnClickListener {
|
|
||||||
onBackPressed()
|
|
||||||
}
|
|
||||||
|
|
||||||
action_save.setOnClickListener {
|
|
||||||
Preferences.weatherProviderApi = api_key.editText?.text.toString()
|
|
||||||
setResult(Activity.RESULT_OK)
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
|
|
||||||
action_open_provider.setOnClickListener {
|
|
||||||
openURI("https://home.openweathermap.org/users/sign_up")
|
|
||||||
}
|
|
||||||
|
|
||||||
api_key.editText?.setText(Preferences.weatherProviderApi)
|
|
||||||
}
|
|
||||||
}
|
|
@ -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)))
|
||||||
})
|
})
|
@ -0,0 +1,144 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||||
|
|
||||||
|
import android.content.pm.ResolveInfo
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
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.bumptech.glide.Glide
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.ActivityAppNotificationsFilterBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.AppNotificationsViewModel
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
|
|
||||||
|
|
||||||
|
class AppNotificationsFilterActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private lateinit var adapter: SlimAdapter
|
||||||
|
private lateinit var viewModel: AppNotificationsViewModel
|
||||||
|
private lateinit var binding: ActivityAppNotificationsFilterBinding
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(this).get(AppNotificationsViewModel::class.java)
|
||||||
|
binding = ActivityAppNotificationsFilterBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
binding.listView.setHasFixedSize(true)
|
||||||
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
|
binding.listView.layoutManager = mLayoutManager
|
||||||
|
|
||||||
|
adapter = SlimAdapter.create()
|
||||||
|
adapter
|
||||||
|
.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)
|
||||||
|
}
|
||||||
|
.visible(R.id.checkBox)
|
||||||
|
.clicked(R.id.item) {
|
||||||
|
toggleApp(item)
|
||||||
|
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||||
|
}
|
||||||
|
.clicked(R.id.checkBox) {
|
||||||
|
toggleApp(item)
|
||||||
|
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||||
|
}
|
||||||
|
.checked(R.id.checkBox, ActiveNotificationsHelper.isAppAccepted(item.activityInfo.packageName))
|
||||||
|
}
|
||||||
|
.attachTo(binding.listView)
|
||||||
|
|
||||||
|
setupListener()
|
||||||
|
subscribeUi(binding, viewModel)
|
||||||
|
|
||||||
|
binding.search.requestFocus()
|
||||||
|
|
||||||
|
setContentView(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var filterJob: Job? = null
|
||||||
|
|
||||||
|
private fun subscribeUi(binding: ActivityAppNotificationsFilterBinding, viewModel: AppNotificationsViewModel) {
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
|
||||||
|
viewModel.appList.observe(this, Observer {
|
||||||
|
updateList(list = it)
|
||||||
|
binding.loader.visibility = View.INVISIBLE
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.searchInput.observe(this, Observer { search ->
|
||||||
|
updateList(search = search)
|
||||||
|
binding.clearSearch.isVisible = search.isNotBlank()
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.appNotificationsFilter.observe(this, {
|
||||||
|
updateList()
|
||||||
|
binding.clearSelection.isVisible = Preferences.appNotificationsFilter != ""
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ->
|
||||||
|
if (ActiveNotificationsHelper.isAppAccepted(app1.activityInfo.packageName) && ActiveNotificationsHelper.isAppAccepted(app2.activityInfo.packageName)) {
|
||||||
|
app1.loadLabel(viewModel.pm).toString().compareTo(app2.loadLabel(viewModel.pm).toString(), ignoreCase = true)
|
||||||
|
} else if (ActiveNotificationsHelper.isAppAccepted(app1.activityInfo.packageName)) {
|
||||||
|
-1
|
||||||
|
} else if (ActiveNotificationsHelper.isAppAccepted(app2.activityInfo.packageName)) {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
app1.loadLabel(viewModel.pm).toString().compareTo(app2.loadLabel(viewModel.pm).toString(), ignoreCase = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
adapter.updateData(filteredList)
|
||||||
|
binding.loader.visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListener() {
|
||||||
|
binding.actionBack.setOnClickListener {
|
||||||
|
onBackPressed()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.clearSearch.setOnClickListener {
|
||||||
|
viewModel.searchInput.value = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.clearSelection.setOnClickListener {
|
||||||
|
Preferences.appNotificationsFilter = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun toggleApp(app: ResolveInfo) {
|
||||||
|
ActiveNotificationsHelper.toggleAppFilter(app.activityInfo.packageName)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,200 @@
|
|||||||
|
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.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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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,19 +58,22 @@ 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) {
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
|
||||||
viewModel.dateInput.observe(this, Observer { dateFormat ->
|
viewModel.dateInput.observe(this, Observer { dateFormat ->
|
||||||
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)
|
||||||
@ -89,7 +84,7 @@ class CustomDateActivity : AppCompatActivity() {
|
|||||||
ERROR_STRING
|
ERROR_STRING
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
"__"
|
ERROR_STRING
|
||||||
}
|
}
|
||||||
|
|
||||||
if (viewModel.isDateCapitalize.value == true) {
|
if (viewModel.isDateCapitalize.value == true) {
|
||||||
@ -101,9 +96,8 @@ class CustomDateActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
action_save.isVisible = text != ERROR_STRING
|
binding.loader.visibility = View.INVISIBLE
|
||||||
loader.visibility = View.INVISIBLE
|
binding.dateFormatValue.text = text
|
||||||
date_format_value.text = text
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -123,35 +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_save.setOnClickListener {
|
binding.actionCapitalize.setOnClickListener {
|
||||||
Preferences.blockingBulk {
|
|
||||||
dateFormat = viewModel.dateInput.value ?: ""
|
|
||||||
isDateCapitalize = viewModel.isDateCapitalize.value ?: true
|
|
||||||
isDateUppercase = viewModel.isDateUppercase.value ?: false
|
|
||||||
}
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
|
|
||||||
action_capitalize.setOnClickListener {
|
|
||||||
when {
|
when {
|
||||||
viewModel.isDateUppercase.value == true -> {
|
viewModel.isDateUppercase.value == true -> {
|
||||||
viewModel.isDateCapitalize.value = false
|
viewModel.isDateCapitalize.value = false
|
||||||
@ -168,16 +153,25 @@ 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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onBackPressed() {
|
||||||
|
Preferences.blockingBulk {
|
||||||
|
dateFormat = viewModel.dateInput.value ?: ""
|
||||||
|
isDateCapitalize = viewModel.isDateCapitalize.value ?: true
|
||||||
|
isDateUppercase = viewModel.isDateUppercase.value ?: false
|
||||||
|
}
|
||||||
|
super.onBackPressed()
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val ERROR_STRING = "--"
|
const val ERROR_STRING = "--"
|
||||||
val DATE: Calendar = Calendar.getInstance().apply {
|
val DATE: Calendar = Calendar.getInstance().apply {
|
@ -0,0 +1,244 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||||
|
|
||||||
|
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.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.provider.FontRequest
|
||||||
|
import androidx.core.provider.FontsContractCompat
|
||||||
|
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.blockingBulk
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.koolio.library.Font
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.ActivityCustomFontBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.CustomFontViewModel
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
|
import net.idik.lib.slimadapter.diff.DefaultDiffCallback
|
||||||
|
|
||||||
|
|
||||||
|
class CustomFontActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private lateinit var adapter: SlimAdapter
|
||||||
|
private lateinit var viewModel: CustomFontViewModel
|
||||||
|
private lateinit var binding: ActivityCustomFontBinding
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(this).get(CustomFontViewModel::class.java)
|
||||||
|
binding = ActivityCustomFontBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
binding.listView.setHasFixedSize(true)
|
||||||
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
|
binding.listView.layoutManager = mLayoutManager
|
||||||
|
|
||||||
|
adapter = SlimAdapter.create()
|
||||||
|
adapter.enableDiff(object: DefaultDiffCallback() {
|
||||||
|
override fun areItemsTheSame(oldItem: Any?, newItem: Any?): Boolean {
|
||||||
|
return oldItem is Font && newItem is Font && oldItem.fontFamily == newItem.fontFamily
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areContentsTheSame(oldItem: Any?, newItem: Any?): Boolean {
|
||||||
|
return oldItem is Font && newItem is Font && oldItem.fontFamily == newItem.fontFamily
|
||||||
|
}
|
||||||
|
})
|
||||||
|
adapter
|
||||||
|
.register<String>(R.layout.list_item) { item, injector ->
|
||||||
|
injector
|
||||||
|
.text(R.id.text, item)
|
||||||
|
.with<TextView>(R.id.text) {
|
||||||
|
val googleSans: Typeface = when (Preferences.customFontVariant) {
|
||||||
|
"100" -> Typeface.createFromAsset(this.assets, "fonts/google_sans_thin.ttf")
|
||||||
|
"200" -> Typeface.createFromAsset(this.assets, "fonts/google_sans_light.ttf")
|
||||||
|
"500" -> Typeface.createFromAsset(this.assets, "fonts/google_sans_medium.ttf")
|
||||||
|
"700" -> Typeface.createFromAsset(this.assets, "fonts/google_sans_bold.ttf")
|
||||||
|
"800" -> Typeface.createFromAsset(this.assets, "fonts/google_sans_black.ttf")
|
||||||
|
else -> Typeface.createFromAsset(this.assets, "fonts/google_sans_regular.ttf")
|
||||||
|
}
|
||||||
|
it.typeface = googleSans
|
||||||
|
}
|
||||||
|
|
||||||
|
injector.clicked(R.id.text) {
|
||||||
|
val dialog = BottomSheetMenu<String>(this, header = item)
|
||||||
|
listOf("100", "200", "regular", "500", "700", "800").forEachIndexed { _, s ->
|
||||||
|
dialog.addItem(SettingsStringHelper.getVariantLabel(this, s), s)
|
||||||
|
}
|
||||||
|
dialog.addOnSelectItemListener { value ->
|
||||||
|
saveGoogleSansFont(value)
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.register<Font>(R.layout.list_item) { item, injector ->
|
||||||
|
injector
|
||||||
|
.text(R.id.text, item.fontFamily)
|
||||||
|
.with<TextView>(R.id.text) {
|
||||||
|
val request = FontRequest(
|
||||||
|
"com.google.android.gms.fonts",
|
||||||
|
"com.google.android.gms",
|
||||||
|
item.queryString,
|
||||||
|
R.array.com_google_android_gms_fonts_certs
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
val callback = object : FontsContractCompat.FontRequestCallback() {
|
||||||
|
override fun onTypefaceRetrieved(typeface: Typeface) {
|
||||||
|
it.typeface = typeface
|
||||||
|
it.isVisible = true
|
||||||
|
|
||||||
|
it.measure(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTypefaceRequestFailed(reason: Int) {
|
||||||
|
it.isVisible = false
|
||||||
|
it.layoutParams = it.layoutParams.apply {
|
||||||
|
height = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val handlerThread = HandlerThread(item.fontFamily)
|
||||||
|
handlerThread.start()
|
||||||
|
val mHandler = Handler(handlerThread.looper)
|
||||||
|
FontsContractCompat.requestFont(this, request, callback, mHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
injector.clicked(R.id.text) {
|
||||||
|
val dialog = BottomSheetMenu<Int>(this, header = item.fontFamily)
|
||||||
|
if (item.fontVariants.isEmpty()) {
|
||||||
|
dialog.addItem(SettingsStringHelper.getVariantLabel(this, "regular"), -1)
|
||||||
|
} else {
|
||||||
|
item.fontVariants
|
||||||
|
.forEachIndexed { index, s ->
|
||||||
|
dialog.addItem(SettingsStringHelper.getVariantLabel(this, s), index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dialog.addOnSelectItemListener { value ->
|
||||||
|
saveFont(item, value)
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.attachTo(binding.listView)
|
||||||
|
|
||||||
|
setupListener()
|
||||||
|
subscribeUi(binding, viewModel)
|
||||||
|
|
||||||
|
binding.search.requestFocus()
|
||||||
|
|
||||||
|
setContentView(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var filterJob: Job? = null
|
||||||
|
|
||||||
|
private fun subscribeUi(binding: ActivityCustomFontBinding, viewModel: CustomFontViewModel) {
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
|
||||||
|
viewModel.fontList.observe(this, Observer {
|
||||||
|
updateList(list = it)
|
||||||
|
binding.loader.visibility = View.INVISIBLE
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.searchInput.observe(this, Observer { search ->
|
||||||
|
updateList(search = search)
|
||||||
|
binding.clearSearch.isVisible = search.isNotBlank()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateList(
|
||||||
|
list: ArrayList<Font>? = viewModel.fontList.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<Any> = if (search == null || search == "") {
|
||||||
|
listOf(getString(R.string.custom_font_subtitle_1)) + list.distinctBy { it.fontFamily }
|
||||||
|
} else {
|
||||||
|
(listOf(getString(R.string.custom_font_subtitle_1)) + list.distinctBy { it.fontFamily }).filter {
|
||||||
|
when (it) {
|
||||||
|
is Font -> {
|
||||||
|
it.fontFamily.contains(search, true)
|
||||||
|
}
|
||||||
|
is String -> {
|
||||||
|
it.contains(search, ignoreCase = true)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.sortedWith { el1, el2 ->
|
||||||
|
if (el1 is Font && el2 is Font) {
|
||||||
|
el1.fontFamily.compareTo(el2.fontFamily)
|
||||||
|
} else if (el1 is Font && el2 is String) {
|
||||||
|
el1.fontFamily.compareTo(el2)
|
||||||
|
} else if (el1 is String && el2 is Font) {
|
||||||
|
el1.compareTo(el2.fontFamily)
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
adapter.updateData(filteredList)
|
||||||
|
binding.loader.visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListener() {
|
||||||
|
binding.actionBack.setOnClickListener {
|
||||||
|
onBackPressed()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.clearSearch.setOnClickListener {
|
||||||
|
viewModel.searchInput.value = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun saveFont(font: Font, variantPos: Int? = null) {
|
||||||
|
val resultIntent = Intent()
|
||||||
|
Preferences.blockingBulk {
|
||||||
|
customFont = Constants.CUSTOM_FONT_DOWNLOADED
|
||||||
|
customFontName = font.fontFamily
|
||||||
|
customFontFile = if (variantPos != null && variantPos > -1) font.getQueryString(variantPos) else font.queryString
|
||||||
|
customFontVariant = if (variantPos != null && variantPos > -1) font.fontVariants[variantPos] else "regular"
|
||||||
|
}
|
||||||
|
setResult(Activity.RESULT_OK, resultIntent)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun saveGoogleSansFont(variant: String) {
|
||||||
|
val resultIntent = Intent()
|
||||||
|
Preferences.blockingBulk {
|
||||||
|
customFont = Constants.CUSTOM_FONT_GOOGLE_SANS
|
||||||
|
customFontName = ""
|
||||||
|
customFontFile = ""
|
||||||
|
customFontVariant = variant
|
||||||
|
}
|
||||||
|
setResult(Activity.RESULT_OK, resultIntent)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
@ -1,61 +1,46 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.activities
|
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.location.Address
|
import android.location.Address
|
||||||
import android.location.Geocoder
|
import android.location.Geocoder
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import android.text.Editable
|
|
||||||
import android.text.TextWatcher
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.Window
|
|
||||||
import android.widget.AdapterView
|
|
||||||
import android.widget.ArrayAdapter
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.core.view.isVisible
|
||||||
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.bulk
|
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.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.components.MaterialBottomSheetDialog
|
|
||||||
import com.tommasoberlose.anotherwidget.databinding.ActivityChooseApplicationBinding
|
|
||||||
import com.tommasoberlose.anotherwidget.databinding.ActivityCustomLocationBinding
|
import com.tommasoberlose.anotherwidget.databinding.ActivityCustomLocationBinding
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.ChooseApplicationViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.CustomLocationViewModel
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.CustomLocationViewModel
|
|
||||||
import kotlinx.android.synthetic.main.activity_custom_location.*
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import net.idik.lib.slimadapter.SlimAdapter
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import org.greenrobot.eventbus.ThreadMode
|
|
||||||
import org.greenrobot.eventbus.Subscribe
|
|
||||||
|
|
||||||
class CustomLocationActivity : AppCompatActivity() {
|
class CustomLocationActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private lateinit var adapter: SlimAdapter
|
private lateinit var adapter: SlimAdapter
|
||||||
private lateinit var viewModel: CustomLocationViewModel
|
private lateinit var viewModel: CustomLocationViewModel
|
||||||
|
private lateinit var binding: ActivityCustomLocationBinding
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
viewModel = ViewModelProvider(this).get(CustomLocationViewModel::class.java)
|
viewModel = ViewModelProvider(this).get(CustomLocationViewModel::class.java)
|
||||||
val binding = DataBindingUtil.setContentView<ActivityCustomLocationBinding>(this, R.layout.activity_custom_location)
|
binding = ActivityCustomLocationBinding.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
|
||||||
@ -63,16 +48,12 @@ class CustomLocationActivity : AppCompatActivity() {
|
|||||||
injector
|
injector
|
||||||
.text(R.id.text, getString(R.string.custom_location_gps))
|
.text(R.id.text, getString(R.string.custom_location_gps))
|
||||||
.clicked(R.id.text) {
|
.clicked(R.id.text) {
|
||||||
MaterialBottomSheetDialog(this, message = getString(R.string.background_location_warning))
|
|
||||||
.setPositiveButton(getString(android.R.string.ok)) {
|
|
||||||
requirePermission()
|
requirePermission()
|
||||||
}
|
}
|
||||||
.show()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.register<Address>(R.layout.custom_location_item) { item, injector ->
|
.register<Address>(R.layout.custom_location_item) { item, injector ->
|
||||||
injector.text(R.id.text, item.getAddressLine(0))
|
injector.text(R.id.text, item.getAddressLine(0))
|
||||||
injector.clicked(R.id.text) {
|
injector.clicked(R.id.item) {
|
||||||
Preferences.bulk {
|
Preferences.bulk {
|
||||||
customLocationLat = item.latitude.toString()
|
customLocationLat = item.latitude.toString()
|
||||||
customLocationLon = item.longitude.toString()
|
customLocationLon = item.longitude.toString()
|
||||||
@ -82,7 +63,7 @@ class CustomLocationActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.attachTo(list_view)
|
.attachTo(binding.listView)
|
||||||
|
|
||||||
|
|
||||||
viewModel.addresses.observe(this, Observer {
|
viewModel.addresses.observe(this, Observer {
|
||||||
@ -92,20 +73,24 @@ class CustomLocationActivity : AppCompatActivity() {
|
|||||||
setupListener()
|
setupListener()
|
||||||
subscribeUi(binding, viewModel)
|
subscribeUi(binding, viewModel)
|
||||||
|
|
||||||
location.requestFocus()
|
binding.location.requestFocus()
|
||||||
|
|
||||||
|
setContentView(binding.root)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var searchJob: Job? = null
|
private var searchJob: Job? = null
|
||||||
|
|
||||||
private fun subscribeUi(binding: ActivityCustomLocationBinding, viewModel: CustomLocationViewModel) {
|
private fun subscribeUi(binding: ActivityCustomLocationBinding, viewModel: CustomLocationViewModel) {
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
|
||||||
viewModel.addresses.observe(this, Observer {
|
viewModel.addresses.observe(this, Observer {
|
||||||
adapter.updateData(listOf("Default") + it)
|
adapter.updateData(listOf("Default") + it)
|
||||||
loader.visibility = View.INVISIBLE
|
binding.loader.visibility = View.INVISIBLE
|
||||||
})
|
})
|
||||||
|
|
||||||
viewModel.locationInput.observe(this, Observer { location ->
|
viewModel.locationInput.observe(this, Observer { location ->
|
||||||
loader.visibility = View.VISIBLE
|
binding.loader.visibility = View.VISIBLE
|
||||||
searchJob?.cancel()
|
searchJob?.cancel()
|
||||||
searchJob = lifecycleScope.launch(Dispatchers.IO) {
|
searchJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||||
delay(200)
|
delay(200)
|
||||||
@ -121,17 +106,18 @@ class CustomLocationActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
viewModel.addresses.value = list
|
viewModel.addresses.value = list
|
||||||
loader.visibility = View.INVISIBLE
|
binding.loader.visibility = View.INVISIBLE
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
binding.clearSearch.isVisible = location.isNotBlank()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun requirePermission() {
|
private fun requirePermission() {
|
||||||
Dexter.withContext(this)
|
Dexter.withContext(this)
|
||||||
.withPermissions(
|
.withPermissions(
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACCESS_BACKGROUND_LOCATION else Manifest.permission.ACCESS_FINE_LOCATION
|
Manifest.permission.ACCESS_FINE_LOCATION
|
||||||
).withListener(object: MultiplePermissionsListener {
|
).withListener(object: MultiplePermissionsListener {
|
||||||
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
||||||
report?.let {
|
report?.let {
|
||||||
@ -159,8 +145,12 @@ class CustomLocationActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupListener() {
|
private fun setupListener() {
|
||||||
action_back.setOnClickListener {
|
binding.actionBack.setOnClickListener {
|
||||||
onBackPressed()
|
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"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,144 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import android.content.pm.ResolveInfo
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
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.bumptech.glide.Glide
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.ActivityMusicPlayersFilterBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.MusicPlayersFilterViewModel
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
|
|
||||||
|
|
||||||
|
class MusicPlayersFilterActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private lateinit var adapter: SlimAdapter
|
||||||
|
private lateinit var viewModel: MusicPlayersFilterViewModel
|
||||||
|
private lateinit var binding: ActivityMusicPlayersFilterBinding
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(this).get(MusicPlayersFilterViewModel::class.java)
|
||||||
|
binding = ActivityMusicPlayersFilterBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
binding.listView.setHasFixedSize(true)
|
||||||
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
|
binding.listView.layoutManager = mLayoutManager
|
||||||
|
|
||||||
|
adapter = SlimAdapter.create()
|
||||||
|
adapter
|
||||||
|
.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)
|
||||||
|
}
|
||||||
|
.visible(R.id.checkBox)
|
||||||
|
.clicked(R.id.item) {
|
||||||
|
toggleApp(item)
|
||||||
|
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||||
|
}
|
||||||
|
.clicked(R.id.checkBox) {
|
||||||
|
toggleApp(item)
|
||||||
|
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||||
|
}
|
||||||
|
.checked(R.id.checkBox, MediaPlayerHelper.isMusicPlayerAccepted(item.activityInfo.packageName))
|
||||||
|
}
|
||||||
|
.attachTo(binding.listView)
|
||||||
|
|
||||||
|
setupListener()
|
||||||
|
subscribeUi(binding, viewModel)
|
||||||
|
|
||||||
|
binding.search.requestFocus()
|
||||||
|
|
||||||
|
setContentView(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var filterJob: Job? = null
|
||||||
|
|
||||||
|
private fun subscribeUi(binding: ActivityMusicPlayersFilterBinding, viewModel: MusicPlayersFilterViewModel) {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.musicPlayersFilter.observe(this) {
|
||||||
|
updateList()
|
||||||
|
binding.clearSelection.isVisible = Preferences.musicPlayersFilter != ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ->
|
||||||
|
if (MediaPlayerHelper.isMusicPlayerAccepted(app1.activityInfo.packageName) && MediaPlayerHelper.isMusicPlayerAccepted(app2.activityInfo.packageName)) {
|
||||||
|
app1.loadLabel(viewModel.pm).toString().compareTo(app2.loadLabel(viewModel.pm).toString(), ignoreCase = true)
|
||||||
|
} else if (MediaPlayerHelper.isMusicPlayerAccepted(app1.activityInfo.packageName)) {
|
||||||
|
-1
|
||||||
|
} else if (MediaPlayerHelper.isMusicPlayerAccepted(app2.activityInfo.packageName)) {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
app1.loadLabel(viewModel.pm).toString().compareTo(app2.loadLabel(viewModel.pm).toString(), ignoreCase = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
adapter.updateData(filteredList)
|
||||||
|
binding.loader.visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListener() {
|
||||||
|
binding.actionBack.setOnClickListener {
|
||||||
|
onBackPressed()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.clearSearch.setOnClickListener {
|
||||||
|
viewModel.searchInput.value = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.clearSelection.setOnClickListener {
|
||||||
|
Preferences.musicPlayersFilter = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun toggleApp(app: ResolveInfo) {
|
||||||
|
MediaPlayerHelper.toggleMusicPlayerFilter(app.activityInfo.packageName)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,174 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.components.BottomSheetWeatherProviderSettings
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.ActivityWeatherProviderBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.WeatherProviderViewModel
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import org.greenrobot.eventbus.Subscribe
|
||||||
|
import org.greenrobot.eventbus.ThreadMode
|
||||||
|
|
||||||
|
class WeatherProviderActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private lateinit var adapter: SlimAdapter
|
||||||
|
private lateinit var viewModel: WeatherProviderViewModel
|
||||||
|
private lateinit var binding: ActivityWeatherProviderBinding
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(this).get(WeatherProviderViewModel::class.java)
|
||||||
|
binding = ActivityWeatherProviderBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
binding.listView.setHasFixedSize(true)
|
||||||
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
|
binding.listView.layoutManager = mLayoutManager
|
||||||
|
|
||||||
|
adapter = SlimAdapter.create()
|
||||||
|
adapter
|
||||||
|
.register<Constants.WeatherProvider>(R.layout.weather_provider_list_item) { provider, injector ->
|
||||||
|
injector
|
||||||
|
.text(R.id.text, WeatherHelper.getProviderName(this, provider))
|
||||||
|
.clicked(R.id.item) {
|
||||||
|
if (Preferences.weatherProvider != provider.value) {
|
||||||
|
Preferences.weatherProviderError = "-"
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
}
|
||||||
|
val oldValue = Preferences.weatherProvider
|
||||||
|
Preferences.weatherProvider = provider.value
|
||||||
|
updateListItem(oldValue)
|
||||||
|
updateListItem()
|
||||||
|
binding.loader.isVisible = true
|
||||||
|
|
||||||
|
lifecycleScope.launch {
|
||||||
|
WeatherHelper.updateWeather(this@WeatherProviderActivity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.clicked(R.id.radioButton) {
|
||||||
|
if (Preferences.weatherProvider != provider.value) {
|
||||||
|
Preferences.weatherProviderError = "-"
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
}
|
||||||
|
val oldValue = Preferences.weatherProvider
|
||||||
|
Preferences.weatherProvider = provider.value
|
||||||
|
updateListItem(oldValue)
|
||||||
|
updateListItem()
|
||||||
|
binding.loader.isVisible = true
|
||||||
|
|
||||||
|
lifecycleScope.launch {
|
||||||
|
WeatherHelper.updateWeather(this@WeatherProviderActivity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.checked(R.id.radioButton, provider.value == Preferences.weatherProvider)
|
||||||
|
.with<TextView>(R.id.text2) {
|
||||||
|
if (WeatherHelper.isKeyRequired(provider)) {
|
||||||
|
it.text = getString(R.string.api_key_required_message)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (provider == Constants.WeatherProvider.WEATHER_GOV) {
|
||||||
|
it.text = getString(R.string.us_only_message)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (provider == Constants.WeatherProvider.YR) {
|
||||||
|
it.text = getString(R.string.celsius_only_message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.clicked(R.id.action_configure) {
|
||||||
|
BottomSheetWeatherProviderSettings(this) {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
binding.loader.isVisible = true
|
||||||
|
WeatherHelper.updateWeather(this@WeatherProviderActivity)
|
||||||
|
}
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
.visibility(R.id.action_configure, if (/*WeatherHelper.isKeyRequired(provider) && */provider.value == Preferences.weatherProvider) View.VISIBLE else View.GONE)
|
||||||
|
.with<TextView>(R.id.provider_error) {
|
||||||
|
if (Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-") {
|
||||||
|
it.text = Preferences.weatherProviderError
|
||||||
|
it.isVisible = provider.value == Preferences.weatherProvider
|
||||||
|
} else if (Preferences.weatherProviderLocationError != "") {
|
||||||
|
it.text = Preferences.weatherProviderLocationError
|
||||||
|
it.isVisible = provider.value == Preferences.weatherProvider
|
||||||
|
} else {
|
||||||
|
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))
|
||||||
|
}.attachTo(binding.listView)
|
||||||
|
|
||||||
|
adapter.updateData(
|
||||||
|
Constants.WeatherProvider.values().asList()
|
||||||
|
.filter { it != Constants.WeatherProvider.HERE }
|
||||||
|
.filter { it != Constants.WeatherProvider.ACCUWEATHER }
|
||||||
|
)
|
||||||
|
|
||||||
|
setupListener()
|
||||||
|
subscribeUi(viewModel)
|
||||||
|
|
||||||
|
setContentView(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun subscribeUi(viewModel: WeatherProviderViewModel) {
|
||||||
|
viewModel.weatherProviderError.observe(this) {
|
||||||
|
updateListItem()
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.weatherProviderLocationError.observe(this) {
|
||||||
|
updateListItem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateListItem(provider: Int = Preferences.weatherProvider) {
|
||||||
|
(adapter.data).forEachIndexed { index, item ->
|
||||||
|
if (item is Constants.WeatherProvider && item.value == provider) {
|
||||||
|
adapter.notifyItemChanged(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListener() {
|
||||||
|
binding.actionBack.setOnClickListener {
|
||||||
|
onBackPressed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBackPressed() {
|
||||||
|
setResult(Activity.RESULT_OK)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
EventBus.getDefault().register(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
EventBus.getDefault().unregister(this)
|
||||||
|
super.onPause()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
|
fun onMessageEvent(ignore: MainFragment.UpdateUiMessageEvent?) {
|
||||||
|
binding.loader.isVisible = Preferences.weatherProviderError == "-"
|
||||||
|
if (Preferences.weatherProviderError == "" && Preferences.weatherProviderLocationError == "") {
|
||||||
|
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.clockAppName != "" -> Preferences.clockAppName
|
|
||||||
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,513 +0,0 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.fragments
|
|
||||||
|
|
||||||
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.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.ui.activities.CustomDateActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
|
||||||
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 = getString(SettingsStringHelper.getCustomFontLabel(it))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
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)
|
|
||||||
(0..1).forEach {
|
|
||||||
dialog.addItem(getString(SettingsStringHelper.getCustomFontLabel(it)), it)
|
|
||||||
}
|
|
||||||
dialog.addOnSelectItemListener { value ->
|
|
||||||
Preferences.customFont = value
|
|
||||||
}.show()
|
|
||||||
|
|
||||||
/*
|
|
||||||
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
|
||||||
intent.type = "* / *" TO FIX WITHOUT SPACE
|
|
||||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
|
||||||
|
|
||||||
try {
|
|
||||||
startActivityForResult(Intent.createChooser(intent, "Select a File to Upload"), Constants.CUSTOM_FONT_CHOOSER_REQUEST_CODE)
|
|
||||||
} catch (ex: android.content.ActivityNotFoundException) {
|
|
||||||
Toast.makeText(this, "Please install a File Manager.", Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_dividers.setOnClickListener {
|
|
||||||
show_dividers_toggle.isChecked = !show_dividers_toggle.isChecked
|
|
||||||
}
|
|
||||||
|
|
||||||
show_dividers_toggle.setOnCheckedChangeListener { _, isChecked ->
|
|
||||||
Preferences.showDividers = isChecked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
|
||||||
when (requestCode) {
|
|
||||||
RequestCode.CUSTOM_FONT_CHOOSER_REQUEST_CODE.code -> {
|
|
||||||
/*val uri = data.data
|
|
||||||
Log.d("AW", "File Uri: " + uri.toString())
|
|
||||||
val path = Util.getPath(this, uri)
|
|
||||||
Log.d("AW", "File Path: " + path)
|
|
||||||
SP.edit()
|
|
||||||
.putString(Constants.PREF_CUSTOM_FONT_FILE, path)
|
|
||||||
.commit()
|
|
||||||
sendBroadcast(Intent(Constants.ACTION_TIME_UPDATE))
|
|
||||||
updateSettings()*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
|
||||||
scrollView.isScrollable = false
|
|
||||||
callback.invoke()
|
|
||||||
lifecycleScope.launch {
|
|
||||||
delay(200)
|
|
||||||
scrollView.isScrollable = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,397 +0,0 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.fragments
|
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
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.net.Uri
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.provider.Settings
|
|
||||||
import android.util.Log
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.app.NotificationManagerCompat
|
|
||||||
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.google.android.gms.auth.api.signin.GoogleSignIn
|
|
||||||
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
|
|
||||||
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
|
|
||||||
import com.google.android.gms.common.api.ApiException
|
|
||||||
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.CustomNotesDialog
|
|
||||||
import com.tommasoberlose.anotherwidget.components.GlanceProviderSortMenu
|
|
||||||
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
|
|
||||||
import com.tommasoberlose.anotherwidget.databinding.FragmentGlanceSettingsBinding
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.AlarmHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
|
|
||||||
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver.Companion.FITNESS_OPTIONS
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.checkIfFitInstalled
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.toast
|
|
||||||
import kotlinx.android.synthetic.main.fragment_calendar_settings.*
|
|
||||||
import kotlinx.android.synthetic.main.fragment_glance_settings.*
|
|
||||||
import kotlinx.android.synthetic.main.fragment_glance_settings.scrollView
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
|
|
||||||
class GlanceTabFragment : Fragment() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun newInstance() = GlanceTabFragment()
|
|
||||||
}
|
|
||||||
|
|
||||||
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<FragmentGlanceSettingsBinding>(inflater, R.layout.fragment_glance_settings, container, false)
|
|
||||||
|
|
||||||
subscribeUi(binding, viewModel)
|
|
||||||
|
|
||||||
binding.lifecycleOwner = this
|
|
||||||
binding.viewModel = viewModel
|
|
||||||
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
|
||||||
super.onActivityCreated(savedInstanceState)
|
|
||||||
|
|
||||||
action_show_steps.isVisible = requireContext().checkIfFitInstalled()
|
|
||||||
|
|
||||||
setupListener()
|
|
||||||
updateNextAlarmWarningUi()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun subscribeUi(
|
|
||||||
binding: FragmentGlanceSettingsBinding,
|
|
||||||
viewModel: MainViewModel
|
|
||||||
) {
|
|
||||||
binding.isGlanceVisible = Preferences.showGlance
|
|
||||||
|
|
||||||
viewModel.showGlance.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
binding.isGlanceVisible = it
|
|
||||||
show_glance_label.text = if (it) getString(R.string.description_show_glance_visible) else getString(R.string.description_show_glance_not_visible)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.showMusic.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
checkNotificationPermission()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.showNextAlarm.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
updateNextAlarmWarningUi()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.showBatteryCharging.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
show_low_battery_level_warning_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.showDailySteps.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
show_steps_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
|
||||||
}
|
|
||||||
checkFitnessPermission()
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.customInfo.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
show_custom_notes_label?.text = if (it == "") getString(R.string.settings_not_visible) else it
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupListener() {
|
|
||||||
|
|
||||||
action_show_glance.setOnClickListener {
|
|
||||||
Preferences.showGlance = !Preferences.showGlance
|
|
||||||
}
|
|
||||||
|
|
||||||
show_glance_switch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
|
||||||
Preferences.showGlance = enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
action_sort_glance_providers.setOnClickListener {
|
|
||||||
GlanceProviderSortMenu(requireContext())
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_music.setOnClickListener {
|
|
||||||
if (Preferences.showGlance) {
|
|
||||||
BottomSheetMenu<Boolean>(
|
|
||||||
requireContext(),
|
|
||||||
header = getString(R.string.settings_show_music_title)
|
|
||||||
).setSelectedValue(Preferences.showMusic)
|
|
||||||
.addItem(getString(R.string.settings_visible), true)
|
|
||||||
.addItem(getString(R.string.settings_not_visible), false)
|
|
||||||
.addOnSelectItemListener { value ->
|
|
||||||
Preferences.showMusic = value
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_next_alarm.setOnClickListener {
|
|
||||||
if (Preferences.showGlance) {
|
|
||||||
BottomSheetMenu<Boolean>(
|
|
||||||
requireContext(),
|
|
||||||
header = getString(R.string.settings_show_next_alarm_title)
|
|
||||||
).setSelectedValue(Preferences.showNextAlarm)
|
|
||||||
.addItem(getString(R.string.settings_visible), true)
|
|
||||||
.addItem(getString(R.string.settings_not_visible), false)
|
|
||||||
.addOnSelectItemListener { value ->
|
|
||||||
Preferences.showNextAlarm = value
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_next_alarm.setOnLongClickListener {
|
|
||||||
with(requireContext().getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
|
||||||
val alarm = nextAlarmClock
|
|
||||||
if (alarm != null && alarm.showIntent != null) {
|
|
||||||
val pm = requireContext().packageManager as PackageManager
|
|
||||||
val appNameOrPackage = try {
|
|
||||||
pm.getApplicationLabel(pm.getApplicationInfo(alarm.showIntent?.creatorPackage ?: "", 0))
|
|
||||||
} catch (e: Exception) {
|
|
||||||
alarm.showIntent?.creatorPackage ?: ""
|
|
||||||
}
|
|
||||||
MaterialBottomSheetDialog(requireContext(), message = getString(R.string.next_alarm_warning).format(appNameOrPackage))
|
|
||||||
.setPositiveButton(getString(android.R.string.ok))
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_low_battery_level_warning.setOnClickListener {
|
|
||||||
if (Preferences.showGlance) {
|
|
||||||
BottomSheetMenu<Boolean>(
|
|
||||||
requireContext(),
|
|
||||||
header = getString(R.string.settings_low_battery_level_title)
|
|
||||||
).setSelectedValue(Preferences.showBatteryCharging)
|
|
||||||
.addItem(getString(R.string.settings_visible), true)
|
|
||||||
.addItem(getString(R.string.settings_not_visible), false)
|
|
||||||
.addOnSelectItemListener { value ->
|
|
||||||
Preferences.showBatteryCharging = value
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_steps.setOnClickListener {
|
|
||||||
if (Preferences.showGlance) {
|
|
||||||
BottomSheetMenu<Boolean>(
|
|
||||||
requireContext(),
|
|
||||||
header = getString(R.string.settings_daily_steps_title)
|
|
||||||
).setSelectedValue(Preferences.showDailySteps)
|
|
||||||
.addItem(getString(R.string.settings_visible), true)
|
|
||||||
.addItem(getString(R.string.settings_not_visible), false)
|
|
||||||
.addOnSelectItemListener { value ->
|
|
||||||
if (value) {
|
|
||||||
val account: GoogleSignInAccount? = GoogleSignIn.getLastSignedInAccount(requireContext())
|
|
||||||
if (!GoogleSignIn.hasPermissions(account, FITNESS_OPTIONS)) {
|
|
||||||
val mGoogleSignInClient = GoogleSignIn.getClient(requireActivity(), GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).addExtension(FITNESS_OPTIONS).build())
|
|
||||||
startActivityForResult(mGoogleSignInClient.signInIntent, 2)
|
|
||||||
} else {
|
|
||||||
Preferences.showDailySteps = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Preferences.showDailySteps = false
|
|
||||||
}
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_custom_notes.setOnClickListener {
|
|
||||||
if (Preferences.showGlance) {
|
|
||||||
CustomNotesDialog(requireContext()).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateNextAlarmWarningUi() {
|
|
||||||
with(requireContext().getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
|
||||||
val alarm = nextAlarmClock
|
|
||||||
if (AlarmHelper.isAlarmProbablyWrong(requireContext()) && alarm != null && alarm.showIntent != null) {
|
|
||||||
val pm = requireContext().packageManager as PackageManager
|
|
||||||
val appNameOrPackage = try {
|
|
||||||
pm.getApplicationLabel(pm.getApplicationInfo(alarm.showIntent?.creatorPackage ?: "", 0))
|
|
||||||
} catch (e: Exception) {
|
|
||||||
alarm.showIntent?.creatorPackage ?: ""
|
|
||||||
}
|
|
||||||
show_next_alarm_warning.text = getString(R.string.next_alarm_warning).format(appNameOrPackage)
|
|
||||||
} else {
|
|
||||||
show_next_alarm_label?.text = if (Preferences.showNextAlarm) getString(R.string.settings_visible) else getString(
|
|
||||||
R.string.settings_not_visible)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val nextAlarmChangeBroadcastReceiver = object : BroadcastReceiver() {
|
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
|
||||||
updateNextAlarmWarningUi()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStart() {
|
|
||||||
super.onStart()
|
|
||||||
activity?.registerReceiver(nextAlarmChangeBroadcastReceiver, IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStop() {
|
|
||||||
activity?.unregisterReceiver(nextAlarmChangeBroadcastReceiver)
|
|
||||||
super.onStop()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkNotificationPermission() {
|
|
||||||
when {
|
|
||||||
NotificationManagerCompat.getEnabledListenerPackages(requireContext()).contains(requireContext().packageName) -> {
|
|
||||||
notification_permission_alert?.isVisible = false
|
|
||||||
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
|
|
||||||
show_music_label?.text = if (Preferences.showMusic) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
|
||||||
}
|
|
||||||
Preferences.showMusic -> {
|
|
||||||
notification_permission_alert?.isVisible = true
|
|
||||||
show_music_label?.text = getString(R.string.settings_request_notification_access)
|
|
||||||
notification_permission_alert?.setOnClickListener {
|
|
||||||
activity?.startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
show_music_label?.text = getString(R.string.settings_not_visible)
|
|
||||||
notification_permission_alert?.isVisible = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkFitnessPermission() {
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || activity?.checkGrantedPermission(Manifest.permission.ACTIVITY_RECOGNITION) == true) {
|
|
||||||
fitness_permission_alert?.isVisible = false
|
|
||||||
if (Preferences.showDailySteps) {
|
|
||||||
ActivityDetectionReceiver.registerFence(requireContext())
|
|
||||||
} else {
|
|
||||||
ActivityDetectionReceiver.unregisterFence(requireContext())
|
|
||||||
}
|
|
||||||
show_steps_label?.text = if (Preferences.showDailySteps) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
|
||||||
} else if (Preferences.showDailySteps) {
|
|
||||||
ActivityDetectionReceiver.unregisterFence(requireContext())
|
|
||||||
fitness_permission_alert?.isVisible = true
|
|
||||||
show_steps_label?.text = getString(R.string.settings_request_fitness_access)
|
|
||||||
fitness_permission_alert?.setOnClickListener {
|
|
||||||
requireFitnessPermission()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ActivityDetectionReceiver.unregisterFence(requireContext())
|
|
||||||
show_steps_label?.text = getString(R.string.settings_not_visible)
|
|
||||||
fitness_permission_alert?.isVisible = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityResult(
|
|
||||||
requestCode: Int,
|
|
||||||
resultCode: Int,
|
|
||||||
data: Intent?
|
|
||||||
) {
|
|
||||||
when (requestCode) {
|
|
||||||
1 -> {
|
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
|
||||||
checkFitnessPermission()
|
|
||||||
} else {
|
|
||||||
Preferences.showDailySteps = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2-> {
|
|
||||||
try {
|
|
||||||
val account: GoogleSignInAccount? = GoogleSignIn.getSignedInAccountFromIntent(data).getResult(ApiException::class.java)
|
|
||||||
if (!GoogleSignIn.hasPermissions(account, FITNESS_OPTIONS)) {
|
|
||||||
GoogleSignIn.requestPermissions(
|
|
||||||
requireActivity(),
|
|
||||||
1,
|
|
||||||
account,
|
|
||||||
FITNESS_OPTIONS)
|
|
||||||
} else {
|
|
||||||
checkFitnessPermission()
|
|
||||||
}
|
|
||||||
} catch (e: ApiException) {
|
|
||||||
e.printStackTrace()
|
|
||||||
Preferences.showDailySteps = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun requireFitnessPermission() {
|
|
||||||
Dexter.withContext(requireContext())
|
|
||||||
.withPermissions(
|
|
||||||
"com.google.android.gms.permission.ACTIVITY_RECOGNITION",
|
|
||||||
"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 {
|
|
||||||
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
|
||||||
report?.let {
|
|
||||||
if (report.areAllPermissionsGranted()){
|
|
||||||
checkFitnessPermission()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
checkNotificationPermission()
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,8 +2,6 @@ package com.tommasoberlose.anotherwidget.ui.fragments
|
|||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.animation.ValueAnimator
|
import android.animation.ValueAnimator
|
||||||
import android.appwidget.AppWidgetManager
|
|
||||||
import android.appwidget.AppWidgetProviderInfo
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
@ -16,6 +14,7 @@ import android.util.TypedValue
|
|||||||
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.FrameLayout
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import androidx.core.animation.addListener
|
import androidx.core.animation.addListener
|
||||||
import androidx.core.app.NotificationManagerCompat
|
import androidx.core.app.NotificationManagerCompat
|
||||||
@ -25,33 +24,33 @@ import androidx.fragment.app.Fragment
|
|||||||
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.navigation.NavController
|
||||||
import androidx.navigation.Navigation
|
import androidx.navigation.Navigation
|
||||||
|
import androidx.navigation.fragment.FragmentNavigatorExtras
|
||||||
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
import com.google.android.material.badge.BadgeDrawable
|
import com.google.android.material.badge.BadgeDrawable
|
||||||
|
import com.google.android.material.card.MaterialCardView
|
||||||
import com.google.android.material.tabs.TabLayoutMediator
|
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.BitmapHelper
|
import com.tommasoberlose.anotherwidget.helpers.*
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
|
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.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.*
|
||||||
import com.tommasoberlose.anotherwidget.utils.getCurrentWallpaper
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.toPixel
|
|
||||||
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()
|
||||||
@ -59,12 +58,13 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
|
|||||||
}
|
}
|
||||||
|
|
||||||
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(
|
||||||
@ -72,39 +72,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)
|
|
||||||
subscribeUi(viewModel)
|
|
||||||
|
|
||||||
// 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
|
|
||||||
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)
|
|
||||||
updateUI()
|
|
||||||
|
|
||||||
// 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) {
|
||||||
@ -121,6 +89,92 @@ 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.setOnClickListener {
|
||||||
|
controller.navigateUp()
|
||||||
|
}
|
||||||
|
binding.actionSettings.animate().alpha(if (!show) 1f else 0f).setDuration(200).translationX((if (!show) 0f else -4f).convertDpToPixel(requireContext())).start()
|
||||||
|
binding.fragmentTitle.text = if (show) destination.label.toString() else getString(R.string.app_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionSettings.setOnClickListener {
|
||||||
|
Navigation.findNavController(it).navigate(R.id.action_appMainFragment_to_appSettingsFragment,)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.preview.layoutParams = binding.preview.layoutParams.apply {
|
||||||
|
height = PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
|
||||||
|
requireContext()
|
||||||
|
) else 0
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribeUi(viewModel)
|
||||||
|
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun subscribeUi(viewModel: MainViewModel) {
|
||||||
|
viewModel.showWallpaper.observe(viewLifecycleOwner) {
|
||||||
|
if (it) {
|
||||||
|
val wallpaper = requireActivity().getCurrentWallpaper()
|
||||||
|
binding.widgetBg.setImageDrawable(if (it) wallpaper else null)
|
||||||
|
if (wallpaper != null) {
|
||||||
|
binding.widgetBg.layoutParams =
|
||||||
|
(binding.widgetBg.layoutParams as ViewGroup.MarginLayoutParams).apply {
|
||||||
|
|
||||||
|
val metrics = DisplayMetrics()
|
||||||
|
|
||||||
|
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)
|
||||||
|
} else {
|
||||||
|
metrics.widthPixels to (wallpaper.intrinsicHeight) * metrics.widthPixels / (wallpaper.intrinsicWidth)
|
||||||
|
}
|
||||||
|
|
||||||
|
setMargins(0, (-80).toPixel(requireContext()), 0, 0
|
||||||
|
)
|
||||||
|
|
||||||
|
width = dimensions.first
|
||||||
|
height = dimensions.second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
binding.widgetBg.setImageDrawable(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.fragmentScrollY.observe(viewLifecycleOwner) {
|
||||||
|
binding.toolbar.cardElevation = if (it > 0) 24f else 0f
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.showPreview.observe(viewLifecycleOwner) {
|
||||||
|
updatePreviewVisibility()
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.clockPreferencesUpdate.observe(viewLifecycleOwner) {
|
||||||
|
updateClock()
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.widgetPreferencesUpdate.observe(viewLifecycleOwner) {
|
||||||
|
onUpdateUiEvent(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.showClock.observe(viewLifecycleOwner) {
|
||||||
|
updateClockVisibility(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var uiJob: Job? = null
|
private var uiJob: Job? = null
|
||||||
@ -128,274 +182,166 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
|
|||||||
private fun updateUI() {
|
private fun updateUI() {
|
||||||
uiJob?.cancel()
|
uiJob?.cancel()
|
||||||
|
|
||||||
preview?.clearAnimation()
|
|
||||||
time_container?.clearAnimation()
|
|
||||||
|
|
||||||
if (Preferences.showPreview) {
|
if (Preferences.showPreview) {
|
||||||
preview?.setCardBackgroundColor(
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
ContextCompat.getColor(
|
val bgColor: Int = ContextCompat.getColor(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
if (ColorHelper.getFontColor(activity?.isDarkTheme() == true)
|
if (ColorHelper.getFontColor(requireActivity().isDarkTheme())
|
||||||
.isColorDark()
|
.isColorDark()
|
||||||
) android.R.color.white else R.color.colorAccent
|
) android.R.color.white else R.color.colorAccent
|
||||||
)
|
)
|
||||||
)
|
|
||||||
widget_shape_background?.setImageDrawable(
|
val wallpaperDrawable = BitmapHelper.getTintedDrawable(
|
||||||
BitmapHelper.getTintedDrawable(
|
|
||||||
requireContext(),
|
requireContext(),
|
||||||
R.drawable.card_background,
|
R.drawable.card_background,
|
||||||
ColorHelper.getBackgroundColor(activity?.isDarkTheme() == true)
|
ColorHelper.getBackgroundColor(requireActivity().isDarkTheme())
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
binding.preview.setCardBackgroundColor(bgColor)
|
||||||
|
binding.widgetDetail.widgetShapeBackground.setImageDrawable(wallpaperDrawable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WidgetHelper.runWithCustomTypeface(requireContext()) { typeface ->
|
||||||
uiJob = lifecycleScope.launch(Dispatchers.IO) {
|
uiJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||||
val generatedView = MainWidget.generateWidgetView(requireContext())
|
val generatedView = MainWidget.generateWidgetView(requireContext(), typeface).root
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
generatedView.measure(0, 0)
|
generatedView.measure(0, 0)
|
||||||
preview?.measure(0, 0)
|
binding.preview.measure(0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
val bitmap = if (preview != null) {
|
val bitmap = BitmapHelper.getBitmapFromView(
|
||||||
BitmapHelper.getBitmapFromView(
|
|
||||||
generatedView,
|
generatedView,
|
||||||
if (preview.width > 0) preview.width else generatedView.measuredWidth,
|
if (binding.preview.width > 0) binding.preview.width else generatedView.measuredWidth,
|
||||||
generatedView.measuredHeight
|
generatedView.measuredHeight
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
|
binding.widgetDetail.bitmapContainer.apply {
|
||||||
|
setImageBitmap(bitmap)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.widgetLoader.animate().scaleX(0f).scaleY(0f).alpha(0f)
|
||||||
|
.setDuration(200L).start()
|
||||||
|
binding.widget.animate().alpha(1f).start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateClock() {
|
||||||
// Clock
|
// Clock
|
||||||
time?.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
|
binding.widgetDetail.time.setTextColor(ColorHelper.getClockFontColor(requireActivity().isDarkTheme()))
|
||||||
time_am_pm?.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
|
binding.widgetDetail.timeAmPm.setTextColor(ColorHelper.getClockFontColor(requireActivity().isDarkTheme()))
|
||||||
time?.setTextSize(
|
binding.widgetDetail.time.setTextSize(
|
||||||
TypedValue.COMPLEX_UNIT_SP,
|
TypedValue.COMPLEX_UNIT_SP,
|
||||||
Preferences.clockTextSize.toPixel(requireContext())
|
Preferences.clockTextSize.toPixel(requireContext())
|
||||||
)
|
)
|
||||||
time_am_pm?.setTextSize(
|
binding.widgetDetail.timeAmPm.setTextSize(
|
||||||
TypedValue.COMPLEX_UNIT_SP,
|
TypedValue.COMPLEX_UNIT_SP,
|
||||||
Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2
|
Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2
|
||||||
)
|
)
|
||||||
time_am_pm?.isVisible = Preferences.showAMPMIndicator
|
binding.widgetDetail.timeAmPm.isVisible = Preferences.showAMPMIndicator
|
||||||
|
|
||||||
// Clock bottom margin
|
// Clock bottom margin
|
||||||
clock_bottom_margin_none?.isVisible =
|
binding.widgetDetail.clockBottomMarginNone.isVisible =
|
||||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.value
|
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.value
|
||||||
clock_bottom_margin_small?.isVisible =
|
binding.widgetDetail.clockBottomMarginSmall.isVisible =
|
||||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.SMALL.value
|
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.SMALL.value
|
||||||
clock_bottom_margin_medium?.isVisible =
|
binding.widgetDetail.clockBottomMarginMedium.isVisible =
|
||||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.MEDIUM.value
|
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.MEDIUM.value
|
||||||
clock_bottom_margin_large?.isVisible =
|
binding.widgetDetail.clockBottomMarginLarge.isVisible =
|
||||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.LARGE.value
|
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 {
|
private fun updateClockVisibility(showClock: Boolean) {
|
||||||
|
binding.widgetDetail.timeContainer.clearAnimation()
|
||||||
|
binding.widgetDetail.time.clearAnimation()
|
||||||
|
|
||||||
|
updatePreviewVisibility()
|
||||||
|
|
||||||
|
if (showClock) {
|
||||||
|
binding.widgetDetail.timeContainer.layoutParams = binding.widgetDetail.timeContainer.layoutParams.apply {
|
||||||
height = RelativeLayout.LayoutParams.WRAP_CONTENT
|
height = RelativeLayout.LayoutParams.WRAP_CONTENT
|
||||||
}
|
}
|
||||||
time_container?.measure(0, 0)
|
binding.widgetDetail.timeContainer.measure(0, 0)
|
||||||
}
|
}
|
||||||
val initialHeight = time_container?.measuredHeight ?: 0
|
|
||||||
|
if ((Preferences.showClock && binding.widgetDetail.time.alpha != 1f) || (!Preferences.showClock && binding.widgetDetail.time.alpha != 0f)) {
|
||||||
|
val initialHeight = binding.widgetDetail.timeContainer.measuredHeight
|
||||||
ValueAnimator.ofFloat(
|
ValueAnimator.ofFloat(
|
||||||
if (Preferences.showClock) 0f else 1f,
|
if (showClock) 0f else 1f,
|
||||||
if (Preferences.showClock) 1f else 0f
|
if (showClock) 1f else 0f
|
||||||
).apply {
|
).apply {
|
||||||
duration = 500L
|
duration = 300L
|
||||||
addUpdateListener {
|
addUpdateListener {
|
||||||
val animatedValue = animatedValue as Float
|
val animatedValue = animatedValue as Float
|
||||||
time_container?.layoutParams =
|
binding.widgetDetail.timeContainer.layoutParams =
|
||||||
time_container.layoutParams.apply {
|
binding.widgetDetail.timeContainer.layoutParams.apply {
|
||||||
height = (initialHeight * animatedValue).toInt()
|
height = (initialHeight * animatedValue).toInt()
|
||||||
}
|
}
|
||||||
time?.alpha = animatedValue
|
binding.widgetDetail.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()
|
}.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) {
|
private fun updatePreviewVisibility() {
|
||||||
ValueAnimator.ofInt(
|
binding.preview.clearAnimation()
|
||||||
preview.height,
|
if (binding.preview.layoutParams.height != (if (Preferences.showPreview) PREVIEW_BASE_HEIGHT.toPixel(requireContext()) else 0) + (if (Preferences.showClock) 100.toPixel(
|
||||||
PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
|
|
||||||
requireContext()
|
requireContext()
|
||||||
) else 0
|
) else 0)) {
|
||||||
|
ValueAnimator.ofInt(
|
||||||
|
binding.preview.height,
|
||||||
|
(if (Preferences.showPreview) PREVIEW_BASE_HEIGHT.toPixel(requireContext()) else 0) + (if (Preferences.showClock) 100.toPixel(
|
||||||
|
requireContext()
|
||||||
|
) else 0)
|
||||||
).apply {
|
).apply {
|
||||||
duration = 300L
|
duration = 300L
|
||||||
addUpdateListener {
|
addUpdateListener {
|
||||||
if (preview != null) {
|
|
||||||
val animatedValue = animatedValue as Int
|
val animatedValue = animatedValue as Int
|
||||||
val layoutParams = preview.layoutParams
|
val layoutParams = binding.preview.layoutParams
|
||||||
layoutParams.height = animatedValue
|
layoutParams.height = animatedValue
|
||||||
preview?.layoutParams = layoutParams
|
binding.preview.layoutParams = layoutParams
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}.start()
|
}.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()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun subscribeUi(viewModel: MainViewModel) {
|
|
||||||
viewModel.showWallpaper.observe(viewLifecycleOwner, Observer {
|
|
||||||
activity?.let { act ->
|
|
||||||
val wallpaper = act.getCurrentWallpaper()
|
|
||||||
widget_bg.setImageDrawable(if (it) wallpaper else null)
|
|
||||||
if (wallpaper != null) {
|
|
||||||
widget_bg.layoutParams =
|
|
||||||
(widget_bg.layoutParams as ViewGroup.MarginLayoutParams).apply {
|
|
||||||
|
|
||||||
val metrics = DisplayMetrics()
|
|
||||||
act.windowManager.defaultDisplay.getMetrics(metrics)
|
|
||||||
|
|
||||||
val dimensions: Pair<Int, Int> = if (wallpaper.intrinsicWidth >= wallpaper.intrinsicHeight) {
|
|
||||||
metrics.heightPixels to (wallpaper.intrinsicWidth) * metrics.heightPixels / (wallpaper.intrinsicHeight)
|
|
||||||
} else {
|
|
||||||
metrics.widthPixels to (wallpaper.intrinsicHeight) * metrics.widthPixels / (wallpaper.intrinsicWidth)
|
|
||||||
}
|
|
||||||
|
|
||||||
setMargins(
|
|
||||||
if (dimensions.first >= dimensions.second) (-80).toPixel(requireContext()) else 0,
|
|
||||||
(-80).toPixel(requireContext()), 0, 0
|
|
||||||
)
|
|
||||||
|
|
||||||
width = dimensions.first
|
|
||||||
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 = Preferences.showWeather && (Preferences.weatherProviderApi == "" || (Preferences.customLocationAdd == "" && activity?.checkGrantedPermission(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACCESS_BACKGROUND_LOCATION else Manifest.permission.ACCESS_FINE_LOCATION) != true))
|
|
||||||
|
|
||||||
|
|
||||||
// Music error indicator
|
|
||||||
tabs?.getTabAt(4)?.orCreateBadge?.apply {
|
|
||||||
backgroundColor = ContextCompat.getColor(requireContext(), R.color.errorColorText)
|
|
||||||
badgeGravity = BadgeDrawable.TOP_END
|
|
||||||
}?.isVisible = Preferences.showMusic && !NotificationManagerCompat.getEnabledListenerPackages(requireContext()).contains(requireContext().packageName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun onMessageEvent(ignore: UpdateUiMessageEvent?) {
|
fun onUpdateUiEvent(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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
|
fun onChangeTabEvent(ignore: ChangeTabEvent) {
|
||||||
|
val navHost = childFragmentManager.findFragmentById(R.id.settings_fragment) as? NavHostFragment?
|
||||||
|
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,18 +24,19 @@ 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.ui.activities.MainActivity
|
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
||||||
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.openURI
|
import com.tommasoberlose.anotherwidget.utils.openURI
|
||||||
import kotlinx.android.synthetic.main.fragment_settings.*
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@ -47,20 +48,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
|
||||||
@ -73,25 +76,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.setOnClickListener {
|
||||||
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)
|
||||||
@ -99,46 +106,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 {
|
||||||
|
binding.showWallpaperToggle.isChecked = !binding.showWallpaperToggle.isChecked
|
||||||
}
|
}
|
||||||
|
|
||||||
action_show_wallpaper.setOnClickListener {
|
binding.showWallpaperToggle.setOnCheckedChangeListener { _, isChecked ->
|
||||||
show_wallpaper_toggle.isChecked = !show_wallpaper_toggle.isChecked
|
|
||||||
}
|
|
||||||
|
|
||||||
show_wallpaper_toggle.setOnCheckedChangeListener { _, isChecked ->
|
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
requirePermission()
|
requirePermission()
|
||||||
} else {
|
} else {
|
||||||
@ -146,13 +152,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),
|
||||||
@ -172,55 +179,74 @@ 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_help_dev.setOnClickListener {
|
binding.actionPrivacyPolicy.setOnClickListener {
|
||||||
|
requireActivity().openURI("https://github.com/tommasoberlose/another-widget/blob/master/privacy-policy.md")
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionHelpDev.setOnClickListener {
|
||||||
startActivity(Intent(requireContext(), SupportDevActivity::class.java))
|
startActivity(Intent(requireContext(), SupportDevActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
action_refresh_widget.setOnClickListener {
|
binding.actionRefreshWidget.setOnClickListener {
|
||||||
|
binding.actionRefreshIcon
|
||||||
|
.animate()
|
||||||
|
.rotation((binding.actionRefreshIcon.rotation - binding.actionRefreshIcon.rotation % 360f) + 360f)
|
||||||
|
.withEndAction {
|
||||||
|
viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
|
||||||
WeatherHelper.updateWeather(requireContext())
|
WeatherHelper.updateWeather(requireContext())
|
||||||
CalendarHelper.updateEventList(requireContext())
|
CalendarHelper.updateEventList(requireContext())
|
||||||
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
|
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
|
||||||
|
ActiveNotificationsHelper.clearLastNotification(requireContext())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.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(
|
||||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||||
).withListener(object: MultiplePermissionsListener {
|
).withListener(object : MultiplePermissionsListener {
|
||||||
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
||||||
report?.let {
|
report?.let {
|
||||||
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,317 +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 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.showWeatherWarning.observe(viewLifecycleOwner, Observer {
|
|
||||||
weather_warning?.isVisible = it
|
|
||||||
checkLocationPermission()
|
|
||||||
})
|
|
||||||
|
|
||||||
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()
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.weatherProviderApi.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
checkWeatherProviderConfig()
|
|
||||||
}
|
|
||||||
checkLocationPermission()
|
|
||||||
})
|
|
||||||
|
|
||||||
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() {
|
|
||||||
// Background permission
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && activity?.checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION) == true && activity?.checkGrantedPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION) != true) {
|
|
||||||
requirePermission()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (activity?.checkGrantedPermission(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACCESS_BACKGROUND_LOCATION else Manifest.permission.ACCESS_FINE_LOCATION) == true) {
|
|
||||||
location_permission_alert?.isVisible = false
|
|
||||||
WeatherReceiver.setUpdates(requireContext())
|
|
||||||
} else if (Preferences.showWeather && Preferences.customLocationAdd == "") {
|
|
||||||
location_permission_alert?.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() {
|
|
||||||
label_weather_provider_api_key?.text =
|
|
||||||
if (Preferences.weatherProviderApi == "") getString(R.string.settings_weather_provider_api_key_subtitle_not_set) else getString(
|
|
||||||
R.string.settings_weather_provider_api_key_subtitle_all_set
|
|
||||||
)
|
|
||||||
label_weather_provider_api_key?.setTextColor(ContextCompat.getColor(requireContext(), if (Preferences.weatherProviderApi == "" && Preferences.showWeather) R.color.errorColorText else R.color.colorSecondaryText))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupListener() {
|
|
||||||
action_hide_weather_warning.setOnClickListener {
|
|
||||||
Preferences.showWeatherWarning = false
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_weather.setOnClickListener {
|
|
||||||
Preferences.showWeather = !Preferences.showWeather
|
|
||||||
}
|
|
||||||
|
|
||||||
show_weather_switch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
|
||||||
Preferences.showWeather = enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
action_weather_provider_api_key.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) {
|
|
||||||
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 -> {
|
|
||||||
WeatherReceiver.setOneTimeUpdate(requireContext())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun requirePermission() {
|
|
||||||
Dexter.withContext(requireContext())
|
|
||||||
.withPermissions(
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACCESS_BACKGROUND_LOCATION else 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,292 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.fragments.tabs
|
||||||
|
|
||||||
|
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.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.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.global.RequestCode
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.tabs.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.ui.widgets.MainWidget
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.isDefaultSet
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.toast
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlin.Comparator
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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.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.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) {
|
||||||
|
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
|
||||||
|
MainWidget.updateWidget(requireContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
MainWidget.updateWidget(requireContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.actionShowDiffTime.setOnClickListener {
|
||||||
|
binding.showDiffTimeToggle.isChecked = !binding.showDiffTimeToggle.isChecked
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.showDiffTimeToggle.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
Preferences.showDiffTime = 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.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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,196 @@
|
|||||||
|
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.BottomSheetMenu
|
||||||
|
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.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.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 {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
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,241 @@
|
|||||||
|
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 -> "None, the widget will be refreshed"
|
||||||
|
it != IntentHelper.DEFAULT_OPTION -> it
|
||||||
|
else -> {
|
||||||
|
if (IntentHelper.getCalendarIntent(requireContext()).isDefaultSet(requireContext())) {
|
||||||
|
getString(
|
||||||
|
R.string.default_calendar_app
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
getString(R.string.gestures_do_nothing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 -> "None, the widget will be refreshed"
|
||||||
|
it != IntentHelper.DEFAULT_OPTION -> it
|
||||||
|
else -> {
|
||||||
|
if (IntentHelper.getClockIntent(requireContext()).isDefaultSet(requireContext())) {
|
||||||
|
getString(
|
||||||
|
R.string.default_clock_app
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
getString(R.string.gestures_do_nothing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 -> "None, the widget will be refreshed"
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,513 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.fragments.tabs
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
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.graphics.Canvas
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.animation.AnimationUtils
|
||||||
|
import android.view.animation.LayoutAnimationController
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.google.android.gms.auth.api.signin.GoogleSignIn
|
||||||
|
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
|
||||||
|
import com.google.android.gms.common.api.ApiException
|
||||||
|
import com.google.android.material.card.MaterialCardView
|
||||||
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.components.CustomNotesDialog
|
||||||
|
import com.tommasoberlose.anotherwidget.components.GlanceSettingsDialog
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.FragmentTabGlanceBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.AlarmHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.GlanceProviderHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.models.GlanceProvider
|
||||||
|
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
|
||||||
|
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver.Companion.FITNESS_OPTIONS
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.*
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
|
|
||||||
|
|
||||||
|
class GlanceTabFragment : Fragment() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance() = GlanceTabFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
private var dialog: GlanceSettingsDialog? = null
|
||||||
|
private lateinit var adapter: SlimAdapter
|
||||||
|
private lateinit var viewModel: MainViewModel
|
||||||
|
private val list: ArrayList<Constants.GlanceProviderId> by lazy {
|
||||||
|
GlanceProviderHelper.getGlanceProviders(requireContext())
|
||||||
|
}
|
||||||
|
private lateinit var binding: FragmentTabGlanceBinding
|
||||||
|
|
||||||
|
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 = FragmentTabGlanceBinding.inflate(inflater)
|
||||||
|
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
|
// List
|
||||||
|
binding.providersList.hasFixedSize()
|
||||||
|
binding.providersList.isNestedScrollingEnabled = false
|
||||||
|
val mLayoutManager = LinearLayoutManager(context)
|
||||||
|
binding.providersList.layoutManager = mLayoutManager
|
||||||
|
|
||||||
|
adapter = SlimAdapter.create()
|
||||||
|
adapter
|
||||||
|
.register<GlanceProvider>(R.layout.glance_provider_item) { item, injector ->
|
||||||
|
val provider = Constants.GlanceProviderId.from(item.id)!!
|
||||||
|
injector
|
||||||
|
.text(R.id.title, item.title)
|
||||||
|
.with<ImageView>(R.id.icon) {
|
||||||
|
it.setImageDrawable(ContextCompat.getDrawable(requireContext(), item.icon))
|
||||||
|
}
|
||||||
|
.clicked(R.id.item) {
|
||||||
|
if (provider == Constants.GlanceProviderId.CUSTOM_INFO) {
|
||||||
|
CustomNotesDialog(requireContext()){
|
||||||
|
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||||
|
}.show()
|
||||||
|
} else {
|
||||||
|
dialog = GlanceSettingsDialog(requireActivity(), provider) {
|
||||||
|
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||||
|
}
|
||||||
|
dialog?.setOnDismissListener {
|
||||||
|
dialog = null
|
||||||
|
}
|
||||||
|
dialog?.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var isVisible = false
|
||||||
|
when (provider) {
|
||||||
|
Constants.GlanceProviderId.PLAYING_SONG -> {
|
||||||
|
when {
|
||||||
|
ActiveNotificationsHelper.checkNotificationAccess(requireContext()) -> {
|
||||||
|
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
|
||||||
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
|
injector.text(
|
||||||
|
R.id.label,
|
||||||
|
if (Preferences.showMusic) getString(R.string.settings_visible) else getString(
|
||||||
|
R.string.settings_not_visible
|
||||||
|
)
|
||||||
|
)
|
||||||
|
isVisible = Preferences.showMusic
|
||||||
|
}
|
||||||
|
Preferences.showMusic -> {
|
||||||
|
injector.visibility(R.id.error_icon, View.VISIBLE)
|
||||||
|
injector.visibility(R.id.info_icon, View.GONE)
|
||||||
|
injector.text(R.id.label, getString(R.string.settings_not_visible))
|
||||||
|
isVisible = false
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
|
injector.text(R.id.label, getString(R.string.settings_not_visible))
|
||||||
|
isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
|
||||||
|
injector.text(
|
||||||
|
R.id.label,
|
||||||
|
if (Preferences.showNextAlarm && !AlarmHelper.isAlarmProbablyWrong(
|
||||||
|
requireContext()
|
||||||
|
)
|
||||||
|
) getString(R.string.settings_visible) else getString(
|
||||||
|
R.string.settings_not_visible
|
||||||
|
)
|
||||||
|
)
|
||||||
|
injector.visibility(
|
||||||
|
R.id.error_icon,
|
||||||
|
if (Preferences.showNextAlarm && AlarmHelper.isAlarmProbablyWrong(
|
||||||
|
requireContext()
|
||||||
|
)
|
||||||
|
) View.VISIBLE else View.GONE
|
||||||
|
)
|
||||||
|
injector.visibility(
|
||||||
|
R.id.info_icon,
|
||||||
|
if (!(Preferences.showNextAlarm && AlarmHelper.isAlarmProbablyWrong(
|
||||||
|
requireContext()
|
||||||
|
))
|
||||||
|
) View.VISIBLE else View.GONE
|
||||||
|
)
|
||||||
|
isVisible = (Preferences.showNextAlarm && !AlarmHelper.isAlarmProbablyWrong(
|
||||||
|
requireContext()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
||||||
|
injector.text(
|
||||||
|
R.id.label,
|
||||||
|
if (Preferences.showBatteryCharging) getString(R.string.settings_visible) else getString(
|
||||||
|
R.string.settings_not_visible
|
||||||
|
)
|
||||||
|
)
|
||||||
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
|
isVisible = Preferences.showBatteryCharging
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.NOTIFICATIONS -> {
|
||||||
|
when {
|
||||||
|
ActiveNotificationsHelper.checkNotificationAccess(requireContext()) -> {
|
||||||
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
|
injector.text(
|
||||||
|
R.id.label,
|
||||||
|
if (Preferences.showNotifications) getString(
|
||||||
|
R.string.settings_visible
|
||||||
|
) else getString(R.string.settings_not_visible)
|
||||||
|
)
|
||||||
|
isVisible = Preferences.showNotifications
|
||||||
|
}
|
||||||
|
Preferences.showNotifications -> {
|
||||||
|
injector.visibility(R.id.error_icon, View.VISIBLE)
|
||||||
|
injector.visibility(R.id.info_icon, View.GONE)
|
||||||
|
injector.text(R.id.label, getString(R.string.settings_not_visible))
|
||||||
|
isVisible = false
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
|
injector.text(R.id.label, getString(R.string.settings_not_visible))
|
||||||
|
isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.GREETINGS -> {
|
||||||
|
injector.text(
|
||||||
|
R.id.label,
|
||||||
|
if (Preferences.showGreetings) getString(R.string.settings_visible) else getString(
|
||||||
|
R.string.settings_not_visible
|
||||||
|
)
|
||||||
|
)
|
||||||
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
|
isVisible = Preferences.showGreetings
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.CUSTOM_INFO -> {
|
||||||
|
injector.text(
|
||||||
|
R.id.label,
|
||||||
|
if (Preferences.customNotes != "") getString(R.string.settings_visible) else getString(
|
||||||
|
R.string.settings_not_visible
|
||||||
|
)
|
||||||
|
)
|
||||||
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
|
isVisible = Preferences.customNotes != ""
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
|
||||||
|
val account: GoogleSignInAccount? = GoogleSignIn.getLastSignedInAccount(
|
||||||
|
context
|
||||||
|
)
|
||||||
|
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,
|
||||||
|
if (Preferences.showDailySteps) getString(R.string.settings_visible) else getString(
|
||||||
|
R.string.settings_not_visible
|
||||||
|
)
|
||||||
|
)
|
||||||
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
|
isVisible = Preferences.showDailySteps
|
||||||
|
} else if (Preferences.showDailySteps) {
|
||||||
|
ActivityDetectionReceiver.unregisterFence(requireContext())
|
||||||
|
injector.visibility(R.id.error_icon, View.VISIBLE)
|
||||||
|
injector.visibility(R.id.info_icon, View.GONE)
|
||||||
|
injector.text(R.id.label, getString(R.string.settings_not_visible))
|
||||||
|
isVisible = false
|
||||||
|
} else {
|
||||||
|
ActivityDetectionReceiver.unregisterFence(requireContext())
|
||||||
|
injector.text(R.id.label, getString(R.string.settings_not_visible))
|
||||||
|
injector.visibility(R.id.error_icon, View.GONE)
|
||||||
|
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||||
|
isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.EVENTS -> {
|
||||||
|
isVisible =
|
||||||
|
Preferences.showEventsAsGlanceProvider
|
||||||
|
val hasError = !Preferences.showEvents || !requireContext().checkGrantedPermission(
|
||||||
|
Manifest.permission.READ_CALENDAR
|
||||||
|
)
|
||||||
|
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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
injector.alpha(R.id.title, 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)
|
||||||
|
}
|
||||||
|
.attachTo(binding.providersList)
|
||||||
|
|
||||||
|
val mIth = ItemTouchHelper(
|
||||||
|
object : ItemTouchHelper.SimpleCallback(
|
||||||
|
ItemTouchHelper.UP or ItemTouchHelper.DOWN,
|
||||||
|
0
|
||||||
|
) {
|
||||||
|
|
||||||
|
override fun onMove(
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder,
|
||||||
|
): Boolean {
|
||||||
|
val fromPos = viewHolder.adapterPosition
|
||||||
|
val toPos = target.adapterPosition
|
||||||
|
// move item in `fromPos` to `toPos` in adapter.
|
||||||
|
adapter.notifyItemMoved(fromPos, toPos)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMoved(
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
viewHolder: RecyclerView.ViewHolder,
|
||||||
|
fromPos: Int,
|
||||||
|
target: RecyclerView.ViewHolder,
|
||||||
|
toPos: Int,
|
||||||
|
x: Int,
|
||||||
|
y: Int
|
||||||
|
) {
|
||||||
|
with(list[toPos]) {
|
||||||
|
list[toPos] = list[fromPos]
|
||||||
|
list[fromPos] = this
|
||||||
|
}
|
||||||
|
super.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isItemViewSwipeEnabled(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearView(
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
viewHolder: RecyclerView.ViewHolder
|
||||||
|
) {
|
||||||
|
super.clearView(recyclerView, viewHolder)
|
||||||
|
GlanceProviderHelper.saveGlanceProviderOrder(
|
||||||
|
list
|
||||||
|
)
|
||||||
|
adapter.updateData(list.mapNotNull {
|
||||||
|
GlanceProviderHelper.getGlanceProviderById(
|
||||||
|
requireContext(),
|
||||||
|
it
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onChildDraw(
|
||||||
|
c: Canvas,
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
viewHolder: RecyclerView.ViewHolder,
|
||||||
|
dX: Float,
|
||||||
|
dY: Float,
|
||||||
|
actionState: Int,
|
||||||
|
isCurrentlyActive: Boolean,
|
||||||
|
) {
|
||||||
|
val view = viewHolder.itemView as MaterialCardView
|
||||||
|
if (isCurrentlyActive) {
|
||||||
|
ViewCompat.setElevation(view, 8f.convertDpToPixel(requireContext()))
|
||||||
|
view.setCardBackgroundColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
requireContext(),
|
||||||
|
R.color.cardBorder
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
ViewCompat.setElevation(view, 0f)
|
||||||
|
view.setCardBackgroundColor(
|
||||||
|
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
|
||||||
|
|
||||||
|
super.onChildDraw(
|
||||||
|
c,
|
||||||
|
recyclerView,
|
||||||
|
viewHolder,
|
||||||
|
dX,
|
||||||
|
topEdge,
|
||||||
|
actionState,
|
||||||
|
isCurrentlyActive
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSwiped(
|
||||||
|
viewHolder: RecyclerView.ViewHolder,
|
||||||
|
direction: Int,
|
||||||
|
) {
|
||||||
|
// remove from adapter
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
mIth.attachToRecyclerView(binding.providersList)
|
||||||
|
|
||||||
|
setupListener()
|
||||||
|
|
||||||
|
binding.scrollView.viewTreeObserver.addOnScrollChangedListener {
|
||||||
|
viewModel.fragmentScrollY.value = binding.scrollView.scrollY
|
||||||
|
}
|
||||||
|
|
||||||
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
delay(500)
|
||||||
|
val l = list.mapNotNull { GlanceProviderHelper.getGlanceProviderById(
|
||||||
|
requireContext(),
|
||||||
|
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)
|
||||||
|
|
||||||
|
binding.providersList.layoutAnimation = controller
|
||||||
|
adapter.notifyDataSetChanged()
|
||||||
|
binding.providersList.scheduleLayoutAnimation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListener() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private val nextAlarmChangeBroadcastReceiver = object : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
|
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
requireActivity().registerReceiver(
|
||||||
|
nextAlarmChangeBroadcastReceiver,
|
||||||
|
IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)
|
||||||
|
)
|
||||||
|
if (dialog != null) {
|
||||||
|
dialog?.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
requireActivity().unregisterReceiver(nextAlarmChangeBroadcastReceiver)
|
||||||
|
super.onStop()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(
|
||||||
|
requestCode: Int,
|
||||||
|
resultCode: Int,
|
||||||
|
data: Intent?,
|
||||||
|
) {
|
||||||
|
when (requestCode) {
|
||||||
|
1 -> {
|
||||||
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||||
|
} else {
|
||||||
|
Preferences.showDailySteps = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dialog != null) {
|
||||||
|
dialog?.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 -> {
|
||||||
|
try {
|
||||||
|
val account: GoogleSignInAccount? = GoogleSignIn.getSignedInAccountFromIntent(
|
||||||
|
data
|
||||||
|
).getResult(ApiException::class.java)
|
||||||
|
if (!GoogleSignIn.hasPermissions(account, FITNESS_OPTIONS)) {
|
||||||
|
GoogleSignIn.requestPermissions(
|
||||||
|
requireActivity(),
|
||||||
|
1,
|
||||||
|
account,
|
||||||
|
FITNESS_OPTIONS
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||||
|
}
|
||||||
|
} catch (e: ApiException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
Preferences.showDailySteps = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dialog != null) {
|
||||||
|
dialog?.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
adapter.notifyItemRangeChanged(0, adapter.data?.size ?: 0)
|
||||||
|
if (dialog != null) {
|
||||||
|
dialog?.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,233 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.fragments.tabs
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
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.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.helpers.DateHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.tabs.CustomDateActivity
|
||||||
|
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
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
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.secondRowTopMargin.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.secondRowTopMarginLabel.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.clockBottomMargin.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.clockBottomMarginLabel.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.backgroundCardColor.observe(viewLifecycleOwner) {
|
||||||
|
maintainScrollPosition {
|
||||||
|
if (Preferences.backgroundCardAlpha == "00") {
|
||||||
|
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.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.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()
|
||||||
|
}
|
||||||
|
|
||||||
|
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.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()
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user