Compare commits
157 Commits
v2.0.5-bet
...
v2.0.14-be
Author | SHA1 | Date | |
---|---|---|---|
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 | |||
2762f12151 | |||
a873c71918 | |||
e8f3c110a8 | |||
72bf3b04a7 | |||
ca6fb75dfd | |||
59dc5de21a | |||
ec40a277d7 | |||
507b7f2318 | |||
1a709a9406 | |||
770ba0cd13 | |||
6a92225edf | |||
ce801d4a7d | |||
25da807bd5 | |||
63212d13b1 | |||
79ad9b2500 | |||
9c0aa0a9ef | |||
b9197ddf2e | |||
d1362f7d81 | |||
a8c7d115ae | |||
a5a753e198 | |||
39ede20518 | |||
5527e6e405 | |||
565ed11f53 | |||
4bd8653d32 | |||
d121119ca9 | |||
e82a34bcc7 | |||
8867a1fbbd | |||
7265883d6c | |||
7a4fc6ff58 | |||
9f61215caa | |||
7ccf7eb8f6 | |||
704448a848 | |||
fa366b3d45 | |||
e58fef66aa | |||
94825808f4 | |||
c120bad9c6 | |||
0d2287dbdf | |||
9e40586456 | |||
4d75f4ca0c | |||
0859632803 | |||
47562b35ca | |||
0f4f02ea28 | |||
31cf950eee | |||
f230d300ee | |||
c610857056 | |||
770040ad93 | |||
f784817296 | |||
ec1c25cb4c | |||
e1d2f5a782 | |||
6e8c6cf055 | |||
68b5997e8d | |||
56b21be946 | |||
fdc02b2cef | |||
863b8f79d8 | |||
857a8009b6 | |||
9199f28ad9 | |||
ddb1b7494a | |||
fd2b1ba976 | |||
90f0d7de00 | |||
66ad5e0839 | |||
2ac7e072e5 | |||
a3392dabcf | |||
c2c54a04d2 | |||
2c237058b3 | |||
aa2b4b0510 | |||
4c27d1dd9b | |||
eba5575ee2 | |||
aff7e407ca | |||
f7fc31d968 | |||
90b588603d | |||
5d9bd11abb | |||
01005ec443 | |||
eaf6400e8b | |||
30339c7375 | |||
87da284be4 | |||
573c6d03e5 | |||
79e87b0648 | |||
9e9a91690e | |||
5f699af509 | |||
aae40b9dd3 | |||
cebd679856 | |||
06443ddddb | |||
233761a169 | |||
b81461f725 | |||
26b1948b70 | |||
af64818dff | |||
b04b103634 | |||
1dc050e77f | |||
ff171d4022 | |||
d91471d1ee | |||
ac381c8542 | |||
ba5a860e75 | |||
09bc9df22f | |||
385806413e | |||
7d2ea5a4d8 | |||
ce9f5a6e45 | |||
8f0f6bc868 | |||
34d8fa4b59 | |||
9401b89036 | |||
842c0d764f | |||
1754b4045b | |||
f28596c194 | |||
7f41a92a91 | |||
9a63b9bde2 | |||
26428b65da | |||
97d1caeabc | |||
f013be5a7a | |||
4cc55edb15 | |||
d08ad6171e | |||
9e2eacef73 | |||
f8f8a8f051 | |||
60531061d7 | |||
654ec3fe66 | |||
40c9253159 | |||
d86d2cadd4 | |||
cb6c2c7764 | |||
6a4cfdf22b | |||
0b9e9e081e | |||
15884bd9b2 | |||
0adf192965 | |||
d72ba08960 | |||
1848951a74 | |||
5ca06e817e |
32
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
32
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: tommasoberlose
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**Smartphone (please complete the following information):**
|
||||||
|
- Device: [e.g. OnePlus 6]
|
||||||
|
- OS Version: [e.g. Android 9.0]
|
||||||
|
- App Version (that you can find inside the advanced settings) [e.g. v2.0.5 (71)]
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: tommasoberlose
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context or screenshots about the feature request here.
|
7
.gitignore
vendored
7
.gitignore
vendored
@ -1,10 +1,11 @@
|
|||||||
*.iml
|
*.iml
|
||||||
.gradle
|
.gradle
|
||||||
/local.properties
|
/local.properties
|
||||||
/.idea/workspace.xml
|
/.idea/*
|
||||||
/.idea/libraries
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
/build
|
/build
|
||||||
/captures
|
/captures
|
||||||
.externalNativeBuild
|
.externalNativeBuild
|
||||||
/tasksintegration/build
|
/tasksintegration/build
|
||||||
|
/app/google-services.json
|
||||||
|
apikey.properties
|
BIN
.idea/caches/build_file_checksums.ser
generated
BIN
.idea/caches/build_file_checksums.ser
generated
Binary file not shown.
17
.idea/codeStyles/Project.xml
generated
17
.idea/codeStyles/Project.xml
generated
@ -1,6 +1,23 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
<code_scheme name="Project" version="173">
|
<code_scheme name="Project" version="173">
|
||||||
<JetCodeStyleSettings>
|
<JetCodeStyleSettings>
|
||||||
|
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
||||||
|
<value>
|
||||||
|
<package name="java.util" alias="false" withSubpackages="false" />
|
||||||
|
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
|
||||||
|
<package name="io.ktor" alias="false" withSubpackages="true" />
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
<option name="PACKAGES_IMPORT_LAYOUT">
|
||||||
|
<value>
|
||||||
|
<package name="" alias="false" withSubpackages="true" />
|
||||||
|
<package name="java" alias="false" withSubpackages="true" />
|
||||||
|
<package name="javax" alias="false" withSubpackages="true" />
|
||||||
|
<package name="kotlin" alias="false" withSubpackages="true" />
|
||||||
|
<package name="" alias="true" withSubpackages="true" />
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
<option name="ALLOW_TRAILING_COMMA" value="true" />
|
||||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
</JetCodeStyleSettings>
|
</JetCodeStyleSettings>
|
||||||
<codeStyleSettings language="XML">
|
<codeStyleSettings language="XML">
|
||||||
|
1
.idea/gradle.xml
generated
1
.idea/gradle.xml
generated
@ -11,7 +11,6 @@
|
|||||||
<set>
|
<set>
|
||||||
<option value="$PROJECT_DIR$" />
|
<option value="$PROJECT_DIR$" />
|
||||||
<option value="$PROJECT_DIR$/app" />
|
<option value="$PROJECT_DIR$/app" />
|
||||||
<option value="$PROJECT_DIR$/tasksintegration" />
|
|
||||||
</set>
|
</set>
|
||||||
</option>
|
</option>
|
||||||
<option name="resolveModulePerSourceSet" value="false" />
|
<option name="resolveModulePerSourceSet" value="false" />
|
||||||
|
3
.idea/modules.xml
generated
3
.idea/modules.xml
generated
@ -2,9 +2,8 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<modules>
|
||||||
<module fileurl="file://$PROJECT_DIR$/Another Widget.iml" filepath="$PROJECT_DIR$/Another Widget.iml" group="Another Widget" />
|
<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$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" group="Another Widget/app" />
|
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" group="Another Widget/app" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/tasksintegration/tasksintegration.iml" filepath="$PROJECT_DIR$/tasksintegration/tasksintegration.iml" group="Another Widget/tasksintegration" />
|
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
52
.idea/navEditor.xml
generated
Normal file
52
.idea/navEditor.xml
generated
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="navEditor-manualLayoutAlgorithm2">
|
||||||
|
<option name="myPositions">
|
||||||
|
<map>
|
||||||
|
<entry key="nav_graph.xml">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions>
|
||||||
|
<option name="myPositions">
|
||||||
|
<map>
|
||||||
|
<entry key="appMainFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions>
|
||||||
|
<option name="myPosition">
|
||||||
|
<Point>
|
||||||
|
<option name="x" value="242" />
|
||||||
|
<option name="y" value="352" />
|
||||||
|
</Point>
|
||||||
|
</option>
|
||||||
|
<option name="myPositions">
|
||||||
|
<map>
|
||||||
|
<entry key="action_appMainFragment_to_appSettingsFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions />
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</LayoutPositions>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="appSettingsFragment">
|
||||||
|
<value>
|
||||||
|
<LayoutPositions>
|
||||||
|
<option name="myPosition">
|
||||||
|
<Point>
|
||||||
|
<option name="x" value="532" />
|
||||||
|
<option name="y" value="353" />
|
||||||
|
</Point>
|
||||||
|
</option>
|
||||||
|
</LayoutPositions>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</LayoutPositions>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -11,7 +11,14 @@ 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
|
||||||
|
-------
|
||||||
|
|
||||||
|
Hey! You could view the file strings.xml ([here](https://github.com/tommasoberlose/another-widget/blob/master/app/src/main/res/values/strings.xml)) that contains the English version of the app strings.
|
||||||
|
You have to copy the file, create a copy of it inside the folder values-[LANGUAGE-SUFFIX] with the translated strings and create a pull request to submit your changes.
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
@ -10,7 +10,12 @@ 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 29
|
||||||
buildToolsVersion "29.0.3"
|
buildToolsVersion "29.0.3"
|
||||||
|
|
||||||
@ -18,10 +23,11 @@ android {
|
|||||||
applicationId "com.tommasoberlose.anotherwidget"
|
applicationId "com.tommasoberlose.anotherwidget"
|
||||||
minSdkVersion 23
|
minSdkVersion 23
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
versionCode 71
|
versionCode 106
|
||||||
versionName "2.0.5"
|
versionName "2.0.14"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
buildConfigField("String", "GOOGLE_API_KEY", apikeyProperties['GOOGLE_API_KEY'])
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
@ -52,8 +58,6 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
viewBinding.enabled = true
|
viewBinding.enabled = true
|
||||||
|
|
||||||
dynamicFeatures = [":tasksintegration"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -61,13 +65,13 @@ dependencies {
|
|||||||
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'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
|
||||||
implementation 'com.google.android.material:material:1.2.0-alpha06'
|
implementation 'com.google.android.material:material:1.3.0-alpha03'
|
||||||
implementation 'androidx.browser:browser:1.2.0'
|
implementation 'androidx.browser:browser:1.2.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'
|
||||||
@ -77,18 +81,18 @@ dependencies {
|
|||||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
|
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
|
||||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||||
|
|
||||||
implementation "androidx.work:work-runtime-ktx:2.3.4"
|
implementation "androidx.work:work-runtime-ktx:2.4.0"
|
||||||
|
|
||||||
// EventBus
|
// EventBus
|
||||||
implementation 'org.greenrobot:eventbus:3.1.1'
|
implementation 'org.greenrobot:eventbus:3.1.1'
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
implementation 'androidx.navigation:navigation-fragment:2.3.0-alpha05'
|
implementation 'androidx.navigation:navigation-fragment:2.3.0'
|
||||||
implementation 'androidx.navigation:navigation-ui-ktx:2.2.2'
|
implementation 'androidx.navigation:navigation-ui-ktx:2.3.0'
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
implementation 'androidx.multidex:multidex:2.0.1'
|
implementation 'androidx.multidex:multidex:2.0.1'
|
||||||
implementation 'joda-time:joda-time:2.9.9'
|
implementation 'joda-time:joda-time:2.10.3'
|
||||||
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'
|
||||||
|
|
||||||
@ -96,35 +100,45 @@ dependencies {
|
|||||||
implementation 'com.github.bumptech.glide:glide:4.11.0'
|
implementation 'com.github.bumptech.glide:glide:4.11.0'
|
||||||
kapt 'com.github.bumptech.glide:compiler:4.11.0'
|
kapt 'com.github.bumptech.glide:compiler:4.11.0'
|
||||||
|
|
||||||
|
// Fitness
|
||||||
|
implementation 'com.google.android.gms:play-services-fitness:18.0.0'
|
||||||
|
implementation 'com.google.android.gms:play-services-auth:18.1.0'
|
||||||
|
|
||||||
//Weather
|
//Weather
|
||||||
implementation 'com.github.KwabenBerko:OpenWeatherMap-Android-Library:2.0.2'
|
implementation 'com.github.KwabenBerko:OpenWeatherMap-Android-Library:2.0.2'
|
||||||
implementation 'com.google.android.gms:play-services-location:17.0.0'
|
implementation 'com.google.android.gms:play-services-location:17.1.0'
|
||||||
|
|
||||||
// Billing
|
// Billing
|
||||||
implementation 'com.android.billingclient:billing:2.2.0'
|
implementation 'com.android.billingclient:billing:3.0.1'
|
||||||
implementation 'com.android.billingclient:billing-ktx:2.2.0'
|
implementation 'com.android.billingclient:billing-ktx:3.0.1'
|
||||||
|
|
||||||
// KTX
|
// KTX
|
||||||
implementation "androidx.core:core-ktx:1.2.0"
|
implementation "androidx.core:core-ktx:1.3.2"
|
||||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
|
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
|
||||||
implementation "androidx.palette:palette-ktx:1.0.0"
|
implementation "androidx.palette:palette-ktx:1.0.0"
|
||||||
implementation 'androidx.core:core-ktx:1.2.0'
|
implementation 'androidx.core:core-ktx:1.3.2'
|
||||||
|
|
||||||
// Recommended: Add the Firebase SDK for Google Analytics.
|
//Retrofit
|
||||||
implementation 'com.google.firebase:firebase-analytics:17.4.0'
|
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
||||||
|
implementation 'com.google.code.gson:gson:2.8.6'
|
||||||
|
implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
|
||||||
|
implementation 'com.squareup.okhttp3:logging-interceptor:3.12.0'
|
||||||
|
implementation "com.github.haroldadmin:NetworkResponseAdapter:4.0.1"
|
||||||
|
|
||||||
|
//Coroutines
|
||||||
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.5'
|
||||||
|
|
||||||
// Add the Firebase SDK for Crashlytics.
|
// Add the Firebase SDK for Crashlytics.
|
||||||
implementation 'com.google.firebase:firebase-crashlytics:17.0.0'
|
implementation 'com.google.firebase:firebase-crashlytics:17.2.2'
|
||||||
|
|
||||||
// Preferences
|
// Preferences
|
||||||
implementation 'com.chibatching.kotpref:kotpref:2.10.0'
|
implementation 'com.chibatching.kotpref:kotpref:2.11.0'
|
||||||
implementation 'com.chibatching.kotpref:livedata-support:2.10.0'
|
implementation 'com.chibatching.kotpref:livedata-support:2.10.0'
|
||||||
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.1.0'
|
||||||
|
|
||||||
// Billing
|
// Fonts
|
||||||
implementation 'com.android.billingclient:billing:2.2.0'
|
implementation 'com.github.firatkarababa:downloadable-font-list-library:1.0.2'
|
||||||
implementation 'com.android.billingclient:billing-ktx:2.2.0'
|
|
||||||
}
|
}
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
"project_info": {
|
|
||||||
"project_number": "791844924473",
|
|
||||||
"firebase_url": "https://anotherwidget-182008.firebaseio.com",
|
|
||||||
"project_id": "anotherwidget-182008",
|
|
||||||
"storage_bucket": "anotherwidget-182008.appspot.com"
|
|
||||||
},
|
|
||||||
"client": [
|
|
||||||
{
|
|
||||||
"client_info": {
|
|
||||||
"mobilesdk_app_id": "1:791844924473:android:0ad4f6e3890f1ad320b1e8",
|
|
||||||
"android_client_info": {
|
|
||||||
"package_name": "com.tommasoberlose.anotherwidget"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"oauth_client": [
|
|
||||||
{
|
|
||||||
"client_id": "791844924473-73dh46rorjq8vm97dgbn6can2dcpqlf0.apps.googleusercontent.com",
|
|
||||||
"client_type": 3
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"api_key": [
|
|
||||||
{
|
|
||||||
"current_key": "AIzaSyAeJRXstqnzebibxmm3FRM98nbwE_kC8tA"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"services": {
|
|
||||||
"appinvite_service": {
|
|
||||||
"other_platform_oauth_client": [
|
|
||||||
{
|
|
||||||
"client_id": "791844924473-73dh46rorjq8vm97dgbn6can2dcpqlf0.apps.googleusercontent.com",
|
|
||||||
"client_type": 3
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"configuration_version": "1"
|
|
||||||
}
|
|
Binary file not shown.
@ -10,6 +10,10 @@
|
|||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
<uses-permission android:name="com.android.vending.BILLING" />
|
<uses-permission android:name="com.android.vending.BILLING" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
|
||||||
|
<uses-permission android:name="android.gms.permission.ACTIVITY_RECOGNITION"/>
|
||||||
|
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
|
||||||
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
@ -18,6 +22,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">
|
||||||
@ -28,10 +33,13 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".ui.activities.ChooseApplicationActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.ChooseApplicationActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
|
<activity android:name=".ui.activities.CustomFontActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
<activity android:name=".ui.activities.CustomLocationActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.CustomLocationActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
<activity android:name=".ui.activities.WeatherProviderActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.WeatherProviderActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
<activity android:name=".ui.activities.SupportDevActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.SupportDevActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
<activity android:name=".ui.activities.CustomDateActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
<activity android:name=".ui.activities.CustomDateActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
|
<activity android:name=".ui.activities.IntegrationsActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
|
<activity android:name=".ui.activities.MusicPlayersFilterActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||||
|
|
||||||
|
|
||||||
<receiver android:name=".ui.widgets.MainWidget">
|
<receiver android:name=".ui.widgets.MainWidget">
|
||||||
@ -80,43 +88,16 @@
|
|||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
|
||||||
<action android:name="com.tommasoberlose.anotherwidget.action.ACTION_WEATHER_UPDATE" />
|
<action android:name="com.tommasoberlose.anotherwidget.action.ACTION_WEATHER_UPDATE" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||||
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
<action android:name="android.intent.action.TIME_SET" />
|
<action android:name="android.intent.action.TIME_SET" />
|
||||||
<action android:name="android.intent.action.TIMEZONE_CHANGED" />
|
<action android:name="android.intent.action.TIMEZONE_CHANGED" />
|
||||||
<action android:name="android.intent.action.LOCALE_CHANGED" />
|
<action android:name="android.intent.action.LOCALE_CHANGED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<receiver
|
|
||||||
android:name=".receivers.PlayerReceiver"
|
|
||||||
android:enabled="true"
|
|
||||||
android:exported="true">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="com.android.music.metachanged" />
|
|
||||||
<action android:name="com.android.music.playstatechanged" />
|
|
||||||
<action android:name="com.android.music.playbackcomplete" />
|
|
||||||
<action android:name="com.android.music.queuechanged" />
|
|
||||||
|
|
||||||
<action android:name="com.htc.music.metachanged" />
|
|
||||||
<action android:name="fm.last.android.metachanged" />
|
|
||||||
<action android:name="com.sec.android.app.music.metachanged" />
|
|
||||||
<action android:name="com.nullsoft.winamp.metachanged" />
|
|
||||||
<action android:name="com.amazon.mp3.metachanged" />
|
|
||||||
<action android:name="com.miui.player.metachanged" />
|
|
||||||
<action android:name="com.real.IMP.metachanged" />
|
|
||||||
<action android:name="com.sonyericsson.music.metachanged" />
|
|
||||||
<action android:name="com.rdio.android.metachanged" />
|
|
||||||
<action android:name="com.samsung.sec.android.MusicPlayer.metachanged" />
|
|
||||||
<action android:name="com.andrew.apollo.metachanged" />
|
|
||||||
<action android:name="com.spotify.music.playbackstatechanged"/>
|
|
||||||
<action android:name="com.spotify.music.metadatachanged"/>
|
|
||||||
<action android:name="com.spotify.music.queuechanged"/>
|
|
||||||
</intent-filter>
|
|
||||||
</receiver>
|
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".receivers.WidgetClickListenerReceiver"
|
android:name=".receivers.WidgetClickListenerReceiver"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
@ -126,8 +107,52 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
<receiver
|
||||||
|
android:name=".receivers.CrashlyticsReceiver"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="false">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.tommasoberlose.anotherwidget.action.ACTION_REPORT_CRASH" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
<service android:name=".services.EventListenerJob" android:permission="android.permission.BIND_JOB_SERVICE" />
|
<service android:name=".services.EventListenerJob" android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||||
|
|
||||||
|
<service android:name=".services.BatteryListenerJob" android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||||
|
|
||||||
|
<service android:name=".receivers.MusicNotificationListener"
|
||||||
|
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.service.notification.NotificationListenerService" />
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<receiver android:name=".receivers.BatteryLevelReceiver"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
|
||||||
|
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
|
||||||
|
<action android:name="android.intent.action.BATTERY_LOW"/>
|
||||||
|
<action android:name="android.intent.action.BATTERY_OKAY"/>
|
||||||
|
<action android:name="android.intent.action.BATTERY_CHANGED"/>
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
|
<receiver android:name=".receivers.ActivityDetectionReceiver"
|
||||||
|
android:exported="false"
|
||||||
|
android:permission="com.google.android.gms.permission.ACTIVITY_RECOGNITION">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.mypackage.ACTION_PROCESS_ACTIVITY_TRANSITIONS" />
|
||||||
|
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||||
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".services.UpdateCalendarJob"
|
||||||
|
android:permission="android.permission.BIND_JOB_SERVICE"
|
||||||
|
android:exported="true"/>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</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,6 +1,7 @@
|
|||||||
package com.tommasoberlose.anotherwidget
|
package com.tommasoberlose.anotherwidget
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
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
|
||||||
|
@ -8,18 +8,24 @@ import android.text.TextWatcher
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.GridLayout
|
import android.widget.GridLayout
|
||||||
|
import android.widget.ImageView
|
||||||
import android.widget.SeekBar
|
import android.widget.SeekBar
|
||||||
import androidx.annotation.ColorInt
|
import androidx.annotation.ColorInt
|
||||||
|
import androidx.appcompat.widget.AppCompatImageView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.widget.addTextChangedListener
|
import androidx.core.widget.addTextChangedListener
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.google.android.material.card.MaterialCardView
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
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.reveal
|
import com.tommasoberlose.anotherwidget.utils.reveal
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.toPixel
|
||||||
import com.warkiz.widget.IndicatorSeekBar
|
import com.warkiz.widget.IndicatorSeekBar
|
||||||
import com.warkiz.widget.OnSeekChangeListener
|
import com.warkiz.widget.OnSeekChangeListener
|
||||||
import com.warkiz.widget.SeekParams
|
import com.warkiz.widget.SeekParams
|
||||||
@ -28,13 +34,14 @@ 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.bottom_sheet_menu_hor.view.color_loader
|
||||||
import kotlinx.android.synthetic.main.color_picker_menu_item.view.*
|
import kotlinx.android.synthetic.main.color_picker_menu_item.view.*
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
import java.util.prefs.Preferences
|
import java.util.prefs.Preferences
|
||||||
|
|
||||||
class BottomSheetColorPicker(
|
class BottomSheetColorPicker(
|
||||||
context: Context,
|
context: Context,
|
||||||
private val colors: IntArray = intArrayOf(),
|
private val colors: IntArray = intArrayOf(),
|
||||||
private val selected: Int? = null,
|
private val getSelected: (() -> Int)? = null,
|
||||||
private val header: String? = null,
|
private val header: String? = null,
|
||||||
private val onColorSelected: ((selectedValue: Int) -> Unit)? = null,
|
private val onColorSelected: ((selectedValue: Int) -> Unit)? = null,
|
||||||
private val showAlphaSelector: Boolean = false,
|
private val showAlphaSelector: Boolean = false,
|
||||||
@ -42,15 +49,19 @@ class BottomSheetColorPicker(
|
|||||||
private val onAlphaChangeListener: ((alpha: Int) -> Unit)? = null
|
private val onAlphaChangeListener: ((alpha: Int) -> Unit)? = null
|
||||||
) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
||||||
|
|
||||||
private val loadingJob: Job? = null
|
private var loadingJobs: ArrayList<Job> = ArrayList()
|
||||||
|
private lateinit var adapter: SlimAdapter
|
||||||
|
|
||||||
override fun show() {
|
override fun show() {
|
||||||
val view = View.inflate(context, R.layout.bottom_sheet_menu_hor, null)
|
val view = View.inflate(context, R.layout.bottom_sheet_menu_hor, null)
|
||||||
|
|
||||||
|
window?.setDimAmount(0f)
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
view.header.isVisible = header != null
|
view.header.isVisible = header != null
|
||||||
view.header_text.text = header ?: ""
|
view.header_text.text = header ?: ""
|
||||||
|
|
||||||
|
// Alpha
|
||||||
view.alpha_selector_container.isVisible = showAlphaSelector
|
view.alpha_selector_container.isVisible = showAlphaSelector
|
||||||
view.alpha_selector.setProgress(alpha.toFloat())
|
view.alpha_selector.setProgress(alpha.toFloat())
|
||||||
view.text_alpha.text = "%s: %s%%".format(context.getString(R.string.alpha), alpha)
|
view.text_alpha.text = "%s: %s%%".format(context.getString(R.string.alpha), alpha)
|
||||||
@ -67,44 +78,62 @@ class BottomSheetColorPicker(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val itemViews: ArrayList<View> = ArrayList()
|
// List
|
||||||
|
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
adapter = SlimAdapter.create()
|
||||||
for (@ColorInt color: Int in colors) {
|
|
||||||
val itemView = View.inflate(context, R.layout.color_picker_menu_item, null)
|
loadingJobs.add(GlobalScope.launch(Dispatchers.IO) {
|
||||||
itemView.color.setCardBackgroundColor(ColorStateList.valueOf(color))
|
val listView = View.inflate(context, R.layout.bottom_sheet_menu_list, null) as RecyclerView
|
||||||
itemView.check.setColorFilter(ContextCompat.getColor(context,
|
listView.setHasFixedSize(true)
|
||||||
if (color.isColorDark()) android.R.color.white else android.R.color.black
|
val mLayoutManager = GridLayoutManager(context, 6)
|
||||||
), android.graphics.PorterDuff.Mode.MULTIPLY)
|
listView.layoutManager = mLayoutManager
|
||||||
itemView.check.isVisible = selected == color
|
|
||||||
itemView.color.setOnClickListener {
|
adapter
|
||||||
onColorSelected?.invoke(color)
|
.register<Int>(R.layout.color_picker_menu_item) { item, injector ->
|
||||||
this@BottomSheetColorPicker.dismiss()
|
injector
|
||||||
|
.with<MaterialCardView>(R.id.color) {
|
||||||
|
it.setCardBackgroundColor(ColorStateList.valueOf(item))
|
||||||
|
}
|
||||||
|
.with<AppCompatImageView>(R.id.check) {
|
||||||
|
if (getSelected?.invoke() == item) {
|
||||||
|
it.setColorFilter(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
context,
|
||||||
|
if (item.isColorDark()) android.R.color.white else android.R.color.black
|
||||||
|
),
|
||||||
|
android.graphics.PorterDuff.Mode.MULTIPLY
|
||||||
|
)
|
||||||
|
it.isVisible = true
|
||||||
|
} else {
|
||||||
|
it.isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.clicked(R.id.color) {
|
||||||
|
adapter.notifyItemChanged(adapter.data.indexOf(getSelected?.invoke()))
|
||||||
|
onColorSelected?.invoke(item)
|
||||||
|
val position = adapter.data.indexOf(item)
|
||||||
|
adapter.notifyItemChanged(position)
|
||||||
|
(listView.layoutManager as GridLayoutManager).scrollToPositionWithOffset(position,0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
itemViews.add(itemView)
|
.attachTo(listView)
|
||||||
}
|
|
||||||
|
adapter.updateData(colors.toList())
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
itemViews.forEach {
|
view.color_loader.isVisible = false
|
||||||
view.menu.addView(it, GridLayout.LayoutParams(
|
view.list_container.addView(listView)
|
||||||
GridLayout.spec(GridLayout.UNDEFINED, 1f),
|
|
||||||
GridLayout.spec(GridLayout.UNDEFINED, 1f)
|
|
||||||
))
|
|
||||||
}
|
|
||||||
color_loader.isVisible = false
|
|
||||||
view.menu.isVisible = true
|
|
||||||
this@BottomSheetColorPicker.behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
this@BottomSheetColorPicker.behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
view.list_container.isVisible = true
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
// Menu
|
|
||||||
|
|
||||||
setContentView(view)
|
setContentView(view)
|
||||||
super.show()
|
super.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
loadingJob?.cancel()
|
loadingJobs.forEach { it.cancel() }
|
||||||
super.onStop()
|
super.onStop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package com.tommasoberlose.anotherwidget.components
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
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
|
||||||
@ -9,6 +10,7 @@ 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 kotlinx.android.synthetic.main.bottom_sheet_menu.view.*
|
||||||
import kotlinx.android.synthetic.main.bottom_sheet_menu_item.view.*
|
import kotlinx.android.synthetic.main.bottom_sheet_menu_item.view.*
|
||||||
|
import org.w3c.dom.Text
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [BottomSheetDialogFragment] that uses a custom
|
* [BottomSheetDialogFragment] that uses a custom
|
||||||
@ -32,8 +34,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
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +96,10 @@ open class BottomSheetMenu<T>(context: Context, private val header: String? = nu
|
|||||||
) else ContextCompat.getColor(context, R.color.colorSecondaryText)
|
) else ContextCompat.getColor(context, R.color.colorSecondaryText)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
item.renderCallback?.invoke(itemView.label)
|
||||||
}
|
}
|
||||||
|
|
||||||
view.menu.addView(itemView)
|
view.menu.addView(itemView)
|
||||||
} else {
|
} else {
|
||||||
val itemView = View.inflate(context, R.layout.bottom_sheet_menu_divider, null)
|
val itemView = View.inflate(context, R.layout.bottom_sheet_menu_divider, null)
|
||||||
@ -106,6 +111,6 @@ open class BottomSheetMenu<T>(context: Context, private val header: String? = nu
|
|||||||
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,64 @@
|
|||||||
|
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.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.openURI
|
||||||
|
import kotlinx.android.synthetic.main.weather_provider_settings_layout.view.*
|
||||||
|
|
||||||
|
class BottomSheetWeatherProviderSettings(context: Context, callback: () -> Unit) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
val view = View.inflate(context, R.layout.weather_provider_settings_layout, null)
|
||||||
|
view.api_key_container.isVisible = WeatherHelper.isKeyRequired()
|
||||||
|
view.action_save_key.isVisible = WeatherHelper.isKeyRequired()
|
||||||
|
|
||||||
|
WeatherHelper.getProviderInfoTitle(context).let { title ->
|
||||||
|
view.info_title.text = title
|
||||||
|
view.info_title.isVisible = title != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
WeatherHelper.getProviderInfoSubtitle(context).let { subtitle ->
|
||||||
|
view.info_subtitle.text = subtitle
|
||||||
|
view.info_subtitle.isVisible = subtitle != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
view.info_provider.text = WeatherHelper.getProviderName(context)
|
||||||
|
|
||||||
|
view.api_key.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 -> ""
|
||||||
|
})
|
||||||
|
|
||||||
|
view.action_open_provider.setOnClickListener {
|
||||||
|
context.openURI(WeatherHelper.getProviderLink())
|
||||||
|
}
|
||||||
|
|
||||||
|
view.action_save_key.setOnClickListener {
|
||||||
|
val key = view.api_key.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(view)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.components
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.View
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
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) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
val view = View.inflate(context, R.layout.custom_notes_dialog_layout, null)
|
||||||
|
view.notes.setText(Preferences.customNotes)
|
||||||
|
|
||||||
|
view.action_positive.setOnClickListener {
|
||||||
|
Preferences.customNotes = view.notes.text.toString()
|
||||||
|
this.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
view.notes.requestFocus()
|
||||||
|
|
||||||
|
setContentView(view)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.components
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Rect
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ScrollView
|
||||||
|
|
||||||
|
|
||||||
|
class FixedFocusScrollView @JvmOverloads constructor(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet? = null,
|
||||||
|
defStyle: Int = 0
|
||||||
|
) : ScrollView(context, attrs, defStyle) {
|
||||||
|
|
||||||
|
var isScrollable = true
|
||||||
|
|
||||||
|
override fun scrollTo(x: Int, y: Int) {
|
||||||
|
if (isScrollable) {
|
||||||
|
super.scrollTo(x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
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,57 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.components
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
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) {
|
||||||
|
|
||||||
|
override fun show() {
|
||||||
|
val view = View.inflate(context, R.layout.bottom_sheet_menu, null)
|
||||||
|
|
||||||
|
// Header
|
||||||
|
view.header.isVisible = header != null
|
||||||
|
view.header_text.text = header ?: ""
|
||||||
|
|
||||||
|
view.warning_text.isVisible = false
|
||||||
|
|
||||||
|
// Menu
|
||||||
|
for (item in Constants.WeatherIconPack.values()) {
|
||||||
|
val itemView = View.inflate(context, R.layout.icon_pack_menu_item, null)
|
||||||
|
itemView.label.text = context.getString(R.string.settings_weather_icon_pack_default).format(item.value + 1)
|
||||||
|
itemView.isSelected = item.value == Preferences.weatherIconPack
|
||||||
|
|
||||||
|
itemView.icon_1.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource(context, "01d", item.value)))
|
||||||
|
itemView.icon_2.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource(context, "01n", item.value)))
|
||||||
|
itemView.icon_3.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource(context, "10d", item.value)))
|
||||||
|
itemView.icon_4.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 {
|
||||||
|
if (item == Constants.WeatherIconPack.MINIMAL) {
|
||||||
|
it.setColorFilter(ContextCompat.getColor(context, R.color.colorPrimaryText))
|
||||||
|
} else {
|
||||||
|
it.setColorFilter(ContextCompat.getColor(context, android.R.color.transparent))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
itemView.setOnClickListener {
|
||||||
|
Preferences.weatherIconPack = item.value
|
||||||
|
this.dismiss()
|
||||||
|
}
|
||||||
|
view.menu.addView(itemView)
|
||||||
|
}
|
||||||
|
setContentView(view)
|
||||||
|
super.show()
|
||||||
|
}
|
||||||
|
}
|
@ -11,8 +11,8 @@ typealias DialogCallback = () -> Unit
|
|||||||
|
|
||||||
class MaterialBottomSheetDialog(
|
class MaterialBottomSheetDialog(
|
||||||
context: Context,
|
context: Context,
|
||||||
private val title: String? = "",
|
private val title: String? = null,
|
||||||
private val message: String? = ""
|
private val message: String? = null
|
||||||
) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
||||||
|
|
||||||
private var positiveButtonLabel: String? = null
|
private var positiveButtonLabel: String? = null
|
||||||
@ -36,7 +36,7 @@ class MaterialBottomSheetDialog(
|
|||||||
val view = View.inflate(context, R.layout.bottom_sheet_dialog, null)
|
val view = View.inflate(context, R.layout.bottom_sheet_dialog, null)
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
view.message.isVisible = title != null
|
view.title.isVisible = title != null
|
||||||
view.title.text = title ?: ""
|
view.title.text = title ?: ""
|
||||||
|
|
||||||
view.message.isVisible = message != null
|
view.message.isVisible = message != null
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.components
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.CompoundButton
|
||||||
|
|
||||||
|
class MenuItem (
|
||||||
|
val icon: Int,
|
||||||
|
val getIcon: (() -> Int)? = null,
|
||||||
|
val title: String,
|
||||||
|
val label: String = "",
|
||||||
|
val getLabel: (() -> String)? = null,
|
||||||
|
val isEnabled: (() -> Boolean) = fun (): Boolean { return true },
|
||||||
|
val onClick: View.OnClickListener? = null,
|
||||||
|
val onLongClick: View.OnLongClickListener? = null,
|
||||||
|
val showToggle: Boolean = false,
|
||||||
|
val toggleValue: (() -> Boolean) = fun (): Boolean { return false },
|
||||||
|
val onToggle: CompoundButton.OnCheckedChangeListener? = null,
|
||||||
|
val showPermission: (() -> Boolean) = fun (): Boolean { return false },
|
||||||
|
val onPermissionClickListener: View.OnClickListener? = null,
|
||||||
|
val render: ((view: View) -> Unit)? = null
|
||||||
|
)
|
@ -1,29 +1,37 @@
|
|||||||
package com.tommasoberlose.anotherwidget.db
|
package com.tommasoberlose.anotherwidget.db
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.provider.CalendarContract
|
||||||
|
import android.util.Log
|
||||||
import com.chibatching.kotpref.bulk
|
import com.chibatching.kotpref.bulk
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper.applyFilters
|
||||||
import com.tommasoberlose.anotherwidget.models.Event
|
import com.tommasoberlose.anotherwidget.models.Event
|
||||||
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.RealmResults
|
import io.realm.RealmResults
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.Comparator
|
||||||
|
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: ArrayList<Event>) {
|
||||||
realm.executeTransactionAsync { realm ->
|
realm.executeTransaction { realm ->
|
||||||
realm.where(Event::class.java).findAll().deleteAllFromRealm()
|
realm.where(Event::class.java).findAll().deleteAllFromRealm()
|
||||||
realm.copyToRealm(eventList)
|
realm.copyToRealm(eventList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resetNextEventData() {
|
fun clearEvents() {
|
||||||
realm.executeTransactionAsync {
|
realm.executeTransaction { realm ->
|
||||||
it.where(Event::class.java).findAll().deleteAllFromRealm()
|
realm.where(Event::class.java).findAll().deleteAllFromRealm()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resetNextEventData() {
|
||||||
Preferences.bulk {
|
Preferences.bulk {
|
||||||
remove(Preferences::nextEventId)
|
remove(Preferences::nextEventId)
|
||||||
remove(Preferences::nextEventName)
|
remove(Preferences::nextEventName)
|
||||||
@ -36,22 +44,63 @@ class EventRepository(val context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun saveNextEventData(event: Event) {
|
fun saveNextEventData(event: Event) {
|
||||||
Preferences.nextEventId = event.id
|
Preferences.nextEventId = event.eventID
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNextEvent(): Event? = realm.where(Event::class.java).equalTo("id", Preferences.nextEventId).findFirst() ?: realm.where(Event::class.java).findFirst()
|
fun getNextEvent(): Event? {
|
||||||
|
val nextEvent = getEventByEventId(Preferences.nextEventId)
|
||||||
|
val now = Calendar.getInstance().timeInMillis
|
||||||
|
val limit = Calendar.getInstance().apply {
|
||||||
|
timeInMillis = now
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val event = if (nextEvent != null && nextEvent.endDate > now && nextEvent.startDate < limit.timeInMillis) {
|
||||||
|
nextEvent
|
||||||
|
} else {
|
||||||
|
val events = getEvents()
|
||||||
|
if (events.isNotEmpty()) {
|
||||||
|
val newNextEvent = events.first()
|
||||||
|
Preferences.nextEventId = newNextEvent.eventID
|
||||||
|
newNextEvent
|
||||||
|
} else {
|
||||||
|
resetNextEventData()
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return try {
|
||||||
|
realm.copyFromRealm(event!!)
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun getEventByEventId(id: Long): Event? = realm.where(Event::class.java).equalTo("eventID", id).findFirst()
|
fun getEventByEventId(id: Long): Event? {
|
||||||
|
val event = realm.where(Event::class.java).equalTo("eventID", id).findFirst()
|
||||||
|
return try {
|
||||||
|
realm.copyFromRealm(event!!)
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun goToNextEvent() {
|
fun goToNextEvent() {
|
||||||
val eventList = realm.where(Event::class.java).findAll()
|
val eventList = getEvents()
|
||||||
|
|
||||||
if (eventList.isNotEmpty()) {
|
if (eventList.isNotEmpty()) {
|
||||||
val index = eventList.indexOfFirst { it.id == Preferences.nextEventId }
|
val index = eventList.indexOfFirst { it.eventID == Preferences.nextEventId }
|
||||||
if (index > -1 && index < eventList.size - 1) {
|
if (index > -1 && index < eventList.size - 1) {
|
||||||
Preferences.nextEventId = eventList[index + 1]!!.id
|
Preferences.nextEventId = eventList[index + 1].eventID
|
||||||
} else {
|
} else {
|
||||||
Preferences.nextEventId = eventList.first()!!.id
|
Preferences.nextEventId = eventList.first().eventID
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resetNextEventData()
|
resetNextEventData()
|
||||||
@ -61,14 +110,13 @@ class EventRepository(val context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun goToPreviousEvent() {
|
fun goToPreviousEvent() {
|
||||||
val eventList = realm.where(Event::class.java).findAll()
|
val eventList = getEvents()
|
||||||
|
|
||||||
if (eventList.isNotEmpty()) {
|
if (eventList.isNotEmpty()) {
|
||||||
val index = eventList.indexOfFirst { it.id == Preferences.nextEventId }
|
val index = eventList.indexOfFirst { it.eventID == Preferences.nextEventId }
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
Preferences.nextEventId = eventList[index - 1]!!.id
|
Preferences.nextEventId = eventList[index - 1].eventID
|
||||||
} else {
|
} else {
|
||||||
Preferences.nextEventId = eventList.last()!!.id
|
Preferences.nextEventId = eventList.last().eventID
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resetNextEventData()
|
resetNextEventData()
|
||||||
@ -77,7 +125,44 @@ class EventRepository(val context: Context) {
|
|||||||
MainWidget.updateWidget(context)
|
MainWidget.updateWidget(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getEvents(): RealmResults<Event> = realm.where(Event::class.java).findAll()
|
fun getFutureEvents(): List<Event> {
|
||||||
|
val now = Calendar.getInstance().timeInMillis
|
||||||
|
realm.refresh()
|
||||||
|
return realm
|
||||||
|
.where(Event::class.java)
|
||||||
|
.greaterThan("endDate", now)
|
||||||
|
.findAll()
|
||||||
|
.applyFilters()
|
||||||
|
}
|
||||||
|
|
||||||
fun getEventsCount(): Int = realm.where(Event::class.java).findAll().size
|
private fun getEvents(): List<Event> {
|
||||||
|
val now = Calendar.getInstance().timeInMillis
|
||||||
|
val limit = Calendar.getInstance().apply {
|
||||||
|
timeInMillis = now
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
realm.refresh()
|
||||||
|
return realm
|
||||||
|
.where(Event::class.java)
|
||||||
|
.greaterThan("endDate", now)
|
||||||
|
.lessThanOrEqualTo("startDate", limit.timeInMillis)
|
||||||
|
.findAll()
|
||||||
|
.applyFilters()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getEventsCount(): Int = getEvents().size
|
||||||
|
|
||||||
|
fun close() {
|
||||||
|
realm.close()
|
||||||
|
}
|
||||||
}
|
}
|
@ -4,10 +4,11 @@ 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_EXTRA_DISABLE_GPS_NOTIFICATION = "ACTION_EXTRA_DISABLE_GPS_NOTIFICATION"
|
||||||
|
|
||||||
const val ACTION_TIME_UPDATE = "com.tommasoberlose.anotherwidget.action.ACTION_TIME_UPDATE"
|
const val ACTION_TIME_UPDATE = "com.tommasoberlose.anotherwidget.action.TIME_UPDATE"
|
||||||
const val ACTION_CALENDAR_UPDATE = "com.tommasoberlose.anotherwidget.action.ACTION_CALENDAR_UPDATE"
|
const val ACTION_CALENDAR_UPDATE = "com.tommasoberlose.anotherwidget.action.CALENDAR_UPDATE"
|
||||||
const val ACTION_WEATHER_UPDATE = "com.tommasoberlose.anotherwidget.action.ACTION_WEATHER_UPDATE"
|
const val ACTION_WEATHER_UPDATE = "com.tommasoberlose.anotherwidget.action.WEATHER_UPDATE"
|
||||||
const val ACTION_OPEN_WEATHER_INTENT = "com.tommasoberlose.anotherwidget.action.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"
|
||||||
}
|
}
|
@ -7,11 +7,57 @@ 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),
|
||||||
MEDIUM(2),
|
MEDIUM(2),
|
||||||
LARGE(3)
|
LARGE(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class SecondRowTopMargin(val value: Int) {
|
||||||
|
NONE(0),
|
||||||
|
SMALL(1),
|
||||||
|
MEDIUM(2),
|
||||||
|
LARGE(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class GlanceProviderId(val id: String) {
|
||||||
|
PLAYING_SONG("PLAYING_SONG"),
|
||||||
|
NEXT_CLOCK_ALARM("NEXT_CLOCK_ALARM"),
|
||||||
|
BATTERY_LEVEL_LOW("BATTERY_LEVEL_LOW"),
|
||||||
|
CUSTOM_INFO("CUSTOM_INFO"),
|
||||||
|
GOOGLE_FIT_STEPS("GOOGLE_FIT_STEPS")
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class WidgetUpdateFrequency(val value: Int) {
|
||||||
|
LOW(0),
|
||||||
|
DEFAULT(1),
|
||||||
|
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 WeatherIconPack(val value: Int) {
|
||||||
|
DEFAULT(0),
|
||||||
|
MINIMAL(1),
|
||||||
|
COOL(2),
|
||||||
|
GOOGLE_NEWS(3)
|
||||||
|
}
|
||||||
}
|
}
|
@ -9,6 +9,7 @@ object Preferences : KotprefModel() {
|
|||||||
|
|
||||||
var darkThemePreference by intPref(default = MODE_NIGHT_FOLLOW_SYSTEM)
|
var darkThemePreference by intPref(default = MODE_NIGHT_FOLLOW_SYSTEM)
|
||||||
|
|
||||||
|
// Calendar and weather
|
||||||
var showEvents by booleanPref(key = "PREF_SHOW_EVENTS", default = false)
|
var showEvents by booleanPref(key = "PREF_SHOW_EVENTS", default = false)
|
||||||
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 = "")
|
||||||
@ -29,41 +30,108 @@ object Preferences : KotprefModel() {
|
|||||||
var customLocationLon by stringPref(key = "PREF_CUSTOM_LOCATION_LON", default = "")
|
var customLocationLon by stringPref(key = "PREF_CUSTOM_LOCATION_LON", default = "")
|
||||||
var customLocationAdd by stringPref(key = "PREF_CUSTOM_LOCATION_ADD", default = "")
|
var customLocationAdd by stringPref(key = "PREF_CUSTOM_LOCATION_ADD", default = "")
|
||||||
var dateFormat by stringPref(default = "")
|
var dateFormat by stringPref(default = "")
|
||||||
|
var isDateCapitalize by booleanPref(default = true)
|
||||||
|
var isDateUppercase by booleanPref(default = false)
|
||||||
var weatherRefreshPeriod by intPref(key = "PREF_WEATHER_REFRESH_PERIOD", default = 1)
|
var weatherRefreshPeriod by intPref(key = "PREF_WEATHER_REFRESH_PERIOD", default = 1)
|
||||||
var showUntil by intPref(key = "PREF_SHOW_UNTIL", default = 1)
|
var showUntil by intPref(key = "PREF_SHOW_UNTIL", default = 1)
|
||||||
var calendarAppName by stringPref(key = "PREF_CALENDAR_APP_NAME", default = "")
|
var calendarAppName by stringPref(key = "PREF_CALENDAR_APP_NAME", default = "")
|
||||||
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 = Constants.WeatherProvider.OPEN_WEATHER.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)
|
||||||
|
|
||||||
|
var widgetUpdateFrequency by intPref(default = Constants.WidgetUpdateFrequency.DEFAULT.value)
|
||||||
|
|
||||||
var textGlobalColor by stringPref(key = "PREF_TEXT_COLOR", default = "#FFFFFF")
|
var textGlobalColor by stringPref(key = "PREF_TEXT_COLOR", default = "#FFFFFF")
|
||||||
var textGlobalAlpha by stringPref(default = "FF")
|
var textGlobalAlpha by stringPref(default = "FF")
|
||||||
|
|
||||||
|
var textSecondaryColor by stringPref(default = "#FFFFFF")
|
||||||
|
var textSecondaryAlpha by stringPref(default = "FF")
|
||||||
|
|
||||||
var backgroundCardColor by stringPref(default = "#000000")
|
var backgroundCardColor by stringPref(default = "#000000")
|
||||||
var backgroundCardAlpha by stringPref(default = "00")
|
var backgroundCardAlpha by stringPref(default = "00")
|
||||||
|
|
||||||
|
var clockTextColor by stringPref(default = "#FFFFFF")
|
||||||
|
var clockTextAlpha by stringPref(default = "FF")
|
||||||
|
|
||||||
|
var textGlobalColorDark by stringPref(default = "#FFFFFF")
|
||||||
|
var textGlobalAlphaDark by stringPref(default = "FF")
|
||||||
|
|
||||||
|
var textSecondaryColorDark by stringPref(default = "#FFFFFF")
|
||||||
|
var textSecondaryAlphaDark by stringPref(default = "FF")
|
||||||
|
|
||||||
|
var backgroundCardColorDark by stringPref(default = "#000000")
|
||||||
|
var backgroundCardAlphaDark by stringPref(default = "00")
|
||||||
|
|
||||||
|
var clockTextColorDark by stringPref(default = "#FFFFFF")
|
||||||
|
var clockTextAlphaDark by stringPref(default = "FF")
|
||||||
|
|
||||||
|
|
||||||
|
var showAMPMIndicator by booleanPref(default = true)
|
||||||
|
|
||||||
|
var weatherIconPack by intPref(default = Constants.WeatherIconPack.DEFAULT.value)
|
||||||
|
|
||||||
|
// Global
|
||||||
var textMainSize by floatPref(key = "PREF_TEXT_MAIN_SIZE", default = 26f)
|
var textMainSize by floatPref(key = "PREF_TEXT_MAIN_SIZE", default = 26f)
|
||||||
var textSecondSize by floatPref(key = "PREF_TEXT_SECOND_SIZE", default = 18f)
|
var textSecondSize by floatPref(key = "PREF_TEXT_SECOND_SIZE", default = 18f)
|
||||||
var clockTextSize by floatPref(key = "PREF_TEXT_CLOCK_SIZE", default = 90f)
|
var clockTextSize by floatPref(key = "PREF_TEXT_CLOCK_SIZE", default = 90f)
|
||||||
var clockBottomMargin by intPref(default = Constants.ClockBottomMargin.MEDIUM.value)
|
var clockBottomMargin by intPref(default = Constants.ClockBottomMargin.MEDIUM.value)
|
||||||
|
var secondRowTopMargin by intPref(default = Constants.SecondRowTopMargin.NONE.value)
|
||||||
var showClock by booleanPref(key = "PREF_SHOW_CLOCK", default = false)
|
var showClock by booleanPref(key = "PREF_SHOW_CLOCK", default = false)
|
||||||
var clockAppName by stringPref(key = "PREF_CLOCK_APP_NAME", default = "")
|
var clockAppName by stringPref(key = "PREF_CLOCK_APP_NAME", default = "")
|
||||||
var clockAppPackage by stringPref(key = "PREF_CLOCK_APP_PACKAGE", default = "")
|
var clockAppPackage by stringPref(key = "PREF_CLOCK_APP_PACKAGE", default = "")
|
||||||
var showNextAlarm by booleanPref(default = false)
|
|
||||||
var textShadow by intPref(key = "PREF_TEXT_SHADOW", default = 1)
|
var textShadow by intPref(key = "PREF_TEXT_SHADOW", default = 1)
|
||||||
|
var textShadowDark by intPref(default = 1)
|
||||||
var showDiffTime by booleanPref(key = "PREF_SHOW_DIFF_TIME", default = true)
|
var showDiffTime by booleanPref(key = "PREF_SHOW_DIFF_TIME", default = true)
|
||||||
var showDeclinedEvents by booleanPref(key = "PREF_SHOW_DECLINED_EVENTS", default = false)
|
var showDeclinedEvents by booleanPref(key = "PREF_SHOW_DECLINED_EVENTS", default = false)
|
||||||
|
var showInvitedEvents by booleanPref(default = false)
|
||||||
|
var showAcceptedEvents by booleanPref(default = true)
|
||||||
|
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)
|
||||||
|
|
||||||
|
// Settings
|
||||||
var showWallpaper by booleanPref(default = true)
|
var showWallpaper by booleanPref(default = true)
|
||||||
var showBigClockWarning by booleanPref(default = true)
|
var showBigClockWarning by booleanPref(default = true)
|
||||||
var showWeatherWarning 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
|
||||||
|
var showGlance by booleanPref(default = true)
|
||||||
|
var enabledGlanceProviderOrder by stringPref(default = "")
|
||||||
|
var customNotes by stringPref(default = "")
|
||||||
|
var showNextAlarm by booleanPref(default = true)
|
||||||
|
var showBatteryCharging by booleanPref(default = false)
|
||||||
|
var isBatteryLevelLow by booleanPref(default = false)
|
||||||
|
var isCharging by booleanPref(default = false)
|
||||||
|
var googleFitSteps by longPref(default = -1)
|
||||||
|
var showDailySteps by booleanPref(default = false)
|
||||||
|
|
||||||
|
var showMusic by booleanPref(default = false)
|
||||||
|
var mediaInfoFormat by stringPref(default = "")
|
||||||
|
var mediaPlayerTitle by stringPref(default = "")
|
||||||
|
var mediaPlayerAlbum by stringPref(default = "")
|
||||||
|
var mediaPlayerArtist by stringPref(default = "")
|
||||||
|
var mediaPlayerPackage by stringPref(default = "")
|
||||||
|
var musicPlayersFilter by stringPref(default = "")
|
||||||
|
|
||||||
|
// Integrations
|
||||||
|
var installedIntegrations by intPref(default = 0)
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,7 @@ object AlarmHelper {
|
|||||||
val alarm = nextAlarmClock
|
val alarm = nextAlarmClock
|
||||||
return if (
|
return if (
|
||||||
alarm != null
|
alarm != null
|
||||||
&& alarm.triggerTime - Calendar.getInstance().timeInMillis > 10 * 60 * 1000
|
&& alarm.triggerTime - Calendar.getInstance().timeInMillis > 5 * 60 * 1000
|
||||||
&& alarm.triggerTime - Calendar.getInstance().timeInMillis < 12 * 60 * 60 * 1000
|
|
||||||
) {
|
) {
|
||||||
"%s %s".format(
|
"%s %s".format(
|
||||||
SimpleDateFormat("EEE", Locale.getDefault()).format(alarm.triggerTime),
|
SimpleDateFormat("EEE", Locale.getDefault()).format(alarm.triggerTime),
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.helpers
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Context.BATTERY_SERVICE
|
||||||
|
import android.os.BatteryManager
|
||||||
|
import androidx.core.content.ContextCompat.getSystemService
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
|
||||||
|
|
||||||
|
object BatteryHelper {
|
||||||
|
fun updateBatteryInfo(context: Context) {
|
||||||
|
with(context.getSystemService(BATTERY_SERVICE) as BatteryManager) {
|
||||||
|
Preferences.isBatteryLevelLow = getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) <= 15
|
||||||
|
Preferences.isCharging = isCharging
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBatteryLevel(context: Context): Int {
|
||||||
|
with(context.getSystemService(BATTERY_SERVICE) as BatteryManager) {
|
||||||
|
return getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,14 +15,43 @@ object BitmapHelper {
|
|||||||
|
|
||||||
fun getBitmapFromView(view: View, width: Int? = null, height: Int? = null, draw: Boolean = true): Bitmap {
|
fun getBitmapFromView(view: View, width: Int? = null, height: Int? = null, draw: Boolean = true): Bitmap {
|
||||||
//Define a bitmap with the same size as the view
|
//Define a bitmap with the same size as the view
|
||||||
val measuredWidth = View.MeasureSpec.makeMeasureSpec(width ?: view.width, if (width != null) View.MeasureSpec.EXACTLY else View.MeasureSpec.UNSPECIFIED)
|
val measuredWidth = View.MeasureSpec.makeMeasureSpec(width ?: view.width, if (width != null) View.MeasureSpec.EXACTLY else View.MeasureSpec.AT_MOST)
|
||||||
val measuredHeight = View.MeasureSpec.makeMeasureSpec(height ?: view.height, if (height != null) View.MeasureSpec.EXACTLY else View.MeasureSpec.UNSPECIFIED)
|
val measuredHeight = View.MeasureSpec.makeMeasureSpec(height ?: view.height, if (height != null) View.MeasureSpec.EXACTLY else View.MeasureSpec.UNSPECIFIED)
|
||||||
view.measure(measuredWidth, measuredHeight)
|
view.measure(
|
||||||
|
if (measuredWidth > 0) measuredWidth else 0,
|
||||||
|
if (measuredHeight > 0) measuredHeight else 0
|
||||||
|
)
|
||||||
|
|
||||||
|
val calculatedWidth = view.measuredWidth
|
||||||
|
val widgetWidth = if (calculatedWidth in 1..16000) {
|
||||||
|
calculatedWidth
|
||||||
|
} else if (width != null && width > 0) {
|
||||||
|
width
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
val calculatedHeight = view.measuredHeight
|
||||||
|
val widgetHeight = if (calculatedHeight in 1..16000) {
|
||||||
|
calculatedHeight
|
||||||
|
} else if (height != null && height > 0) {
|
||||||
|
height
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (draw) {
|
||||||
|
FirebaseCrashlytics.getInstance().setCustomKey("WIDTH SPEC", measuredWidth)
|
||||||
|
FirebaseCrashlytics.getInstance().setCustomKey("HEIGHT SPEC", measuredHeight)
|
||||||
|
FirebaseCrashlytics.getInstance().setCustomKey("VIEW measuredWidth", view.measuredWidth)
|
||||||
|
FirebaseCrashlytics.getInstance().setCustomKey("VIEW measuredHeight", view.measuredHeight)
|
||||||
|
FirebaseCrashlytics.getInstance().setCustomKey("WIDGET final width", measuredWidth)
|
||||||
|
FirebaseCrashlytics.getInstance().setCustomKey("WIDGET final height", view.measuredHeight)
|
||||||
|
}
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
val btm = Bitmap.createBitmap(
|
val btm = Bitmap.createBitmap(
|
||||||
view.measuredWidth,
|
widgetWidth,
|
||||||
view.measuredHeight,
|
widgetHeight,
|
||||||
if (draw) Bitmap.Config.ARGB_8888 else Bitmap.Config.ALPHA_8
|
if (draw) Bitmap.Config.ARGB_8888 else Bitmap.Config.ALPHA_8
|
||||||
)
|
)
|
||||||
if (draw) {
|
if (draw) {
|
||||||
@ -75,13 +104,12 @@ object BitmapHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun drawableToBitmap(drawable: Drawable): Bitmap? {
|
fun drawableToBitmap(drawable: Drawable): Bitmap? {
|
||||||
var bitmap: Bitmap? = null
|
|
||||||
if (drawable is BitmapDrawable) {
|
if (drawable is BitmapDrawable) {
|
||||||
if (drawable.bitmap != null) {
|
if (drawable.bitmap != null) {
|
||||||
return drawable.bitmap
|
return drawable.bitmap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bitmap = if (drawable.intrinsicWidth <= 0 || drawable.intrinsicHeight <= 0) {
|
val bitmap: Bitmap = if (drawable.intrinsicWidth <= 0 || drawable.intrinsicHeight <= 0) {
|
||||||
Bitmap.createBitmap(
|
Bitmap.createBitmap(
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
|
@ -1,15 +1,23 @@
|
|||||||
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.ContentUris
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
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.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.receivers.UpdatesReceiver
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
import com.tommasoberlose.anotherwidget.services.UpdateCalendarJob
|
||||||
|
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 me.everything.providers.android.calendar.CalendarProvider
|
import me.everything.providers.android.calendar.CalendarProvider
|
||||||
@ -23,110 +31,8 @@ import kotlin.collections.ArrayList
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
object CalendarHelper {
|
object CalendarHelper {
|
||||||
|
|
||||||
fun updateEventList(context: Context) {
|
fun updateEventList(context: Context) {
|
||||||
val eventRepository = EventRepository(context)
|
UpdateCalendarJob.enqueueWork(context, Intent())
|
||||||
if (Preferences.showEvents) {
|
|
||||||
val eventList = ArrayList<Event>()
|
|
||||||
|
|
||||||
val now = Calendar.getInstance()
|
|
||||||
val limit = Calendar.getInstance()
|
|
||||||
when (Preferences.showUntil) {
|
|
||||||
0 -> limit.add(Calendar.HOUR, 3)
|
|
||||||
1 -> limit.add(Calendar.HOUR, 6)
|
|
||||||
2 -> limit.add(Calendar.HOUR, 12)
|
|
||||||
3 -> limit.add(Calendar.DAY_OF_MONTH, 1)
|
|
||||||
4 -> limit.add(Calendar.DAY_OF_MONTH, 3)
|
|
||||||
5 -> limit.add(Calendar.DAY_OF_MONTH, 7)
|
|
||||||
6 -> limit.add(Calendar.MINUTE, 30)
|
|
||||||
7 -> limit.add(Calendar.HOUR, 1)
|
|
||||||
else -> limit.add(Calendar.HOUR, 6)
|
|
||||||
}
|
|
||||||
|
|
||||||
val builder = CalendarContract.Instances.CONTENT_URI.buildUpon()
|
|
||||||
ContentUris.appendId(builder, now.timeInMillis)
|
|
||||||
ContentUris.appendId(builder, limit.timeInMillis)
|
|
||||||
|
|
||||||
if (!context.checkGrantedPermission(
|
|
||||||
Manifest.permission.READ_CALENDAR
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
eventRepository.resetNextEventData()
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
val provider = CalendarProvider(context)
|
|
||||||
val data = provider.getInstances(now.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 && (Preferences.calendarAllDay || !e.allDay) && !getFilteredCalendarIdList().contains(
|
|
||||||
e.calendarId
|
|
||||||
) && (Preferences.showDeclinedEvents || e.selfAttendeeStatus.toInt() != CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED)
|
|
||||||
) {
|
|
||||||
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(
|
|
||||||
instance.id,
|
|
||||||
e.id,
|
|
||||||
e.title ?: "",
|
|
||||||
instance.begin,
|
|
||||||
instance.end,
|
|
||||||
e.calendarId.toInt(),
|
|
||||||
e.allDay,
|
|
||||||
e.eventLocation ?: ""
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} catch (ignored: Exception) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventList.isEmpty()) {
|
|
||||||
eventRepository.resetNextEventData()
|
|
||||||
} else {
|
|
||||||
eventList.sortWith(Comparator { event: Event, event1: Event ->
|
|
||||||
if (event.allDay && event1.allDay) {
|
|
||||||
event.startDate.compareTo(event1.startDate)
|
|
||||||
} else if (event.allDay) {
|
|
||||||
1
|
|
||||||
} else if (event1.allDay) {
|
|
||||||
-1
|
|
||||||
} else {
|
|
||||||
event1.startDate.compareTo(event.startDate)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
eventList.reverse()
|
|
||||||
eventRepository.saveEvents(
|
|
||||||
eventList
|
|
||||||
)
|
|
||||||
eventRepository.saveNextEventData(
|
|
||||||
eventList[0]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} catch (ignored: java.lang.Exception) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
eventRepository.resetNextEventData()
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdatesReceiver.setUpdates(context)
|
|
||||||
MainWidget.updateWidget(context)
|
|
||||||
|
|
||||||
EventBus.getDefault().post(MainActivity.UpdateUiMessageEvent())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCalendarList(context: Context): List<me.everything.providers.android.calendar.Calendar> {
|
fun getCalendarList(context: Context): List<me.everything.providers.android.calendar.Calendar> {
|
||||||
@ -148,7 +54,8 @@ object CalendarHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getFilteredCalendarIdList(): List<Long> {
|
fun getFilteredCalendarIdList(): List<Long> {
|
||||||
return Preferences.calendarFilter.split(",").map { it.replace(" ", "") }.filter { it != "" }.map { it.toLong() }
|
return Preferences.calendarFilter.split(",").map { it.replace(" ", "") }
|
||||||
|
.filter { it != "" }.map { it.toLong() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun filterCalendar(list: List<Long>) {
|
fun filterCalendar(list: List<Long>) {
|
||||||
@ -162,4 +69,15 @@ object CalendarHelper {
|
|||||||
fun removeEventUpdatesAndroidN(context: Context) {
|
fun removeEventUpdatesAndroidN(context: Context) {
|
||||||
EventListenerJob.remove(context)
|
EventListenerJob.remove(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun List<Event>.applyFilters() : List<Event> {
|
||||||
|
return this
|
||||||
|
.asSequence()
|
||||||
|
.filter { (Preferences.showDeclinedEvents || it.selfAttendeeStatus != CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED) }
|
||||||
|
.filter { (Preferences.showAcceptedEvents || it.selfAttendeeStatus != CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED) }
|
||||||
|
.filter { (Preferences.showInvitedEvents || it.selfAttendeeStatus != CalendarContract.Attendees.ATTENDEE_STATUS_INVITED) }
|
||||||
|
.filter { (Preferences.calendarAllDay || !it.allDay) }
|
||||||
|
.filter { (!Preferences.showOnlyBusyEvents || it.availability != CalendarContract.EventsEntity.AVAILABILITY_FREE) }
|
||||||
|
.toList()
|
||||||
|
}
|
||||||
}
|
}
|
@ -7,33 +7,97 @@ import com.tommasoberlose.anotherwidget.global.Preferences
|
|||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
object ColorHelper {
|
object ColorHelper {
|
||||||
fun getFontColor(): Int {
|
fun getFontColor(isDark: Boolean): Int {
|
||||||
return try {
|
return try {
|
||||||
Color.parseColor("#%s%s".format(Preferences.textGlobalAlpha, Preferences.textGlobalColor.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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getBackgroundColor(): Int {
|
fun getFontColorAlpha(isDark: Boolean): Int {
|
||||||
return try {
|
return try {
|
||||||
Color.parseColor("#%s%s".format(Preferences.backgroundCardAlpha, Preferences.backgroundCardColor.replace("#", "")))
|
(if (!isDark) Preferences.textGlobalAlpha else Preferences.textGlobalAlphaDark).toIntValue().toDouble() * 255 / 100
|
||||||
|
} catch (e: Exception) {
|
||||||
|
"FF".toIntValue().toDouble() * 255 / 100
|
||||||
|
}.roundToInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFontColorRgb(isDark: Boolean): Int {
|
||||||
|
return try {
|
||||||
|
Color.parseColor((if (!isDark) Preferences.textGlobalColor else Preferences.textGlobalColorDark))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Color.parseColor("#000000")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSecondaryFontColor(isDark: Boolean): Int {
|
||||||
|
return try {
|
||||||
|
Color.parseColor("#%s%s".format((if (!isDark) Preferences.textSecondaryAlpha else Preferences.textSecondaryAlphaDark), (if (!isDark) Preferences.textSecondaryColor else Preferences.textSecondaryColorDark).replace("#", "")))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Color.parseColor("#FFFFFFFF")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSecondaryFontColorAlpha(isDark: Boolean): Int {
|
||||||
|
return try {
|
||||||
|
(if (!isDark) Preferences.textSecondaryAlpha else Preferences.textSecondaryAlphaDark).toIntValue().toDouble() * 255 / 100
|
||||||
|
} catch (e: Exception) {
|
||||||
|
"FF".toIntValue().toDouble() * 255 / 100
|
||||||
|
}.roundToInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSecondaryFontColorRgb(isDark: Boolean): Int {
|
||||||
|
return try {
|
||||||
|
Color.parseColor((if (!isDark) Preferences.textSecondaryColor else Preferences.textSecondaryColorDark))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Color.parseColor("#000000")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getClockFontColor(isDark: Boolean): Int {
|
||||||
|
return try {
|
||||||
|
Color.parseColor("#%s%s".format((if (!isDark) Preferences.clockTextAlpha else Preferences.clockTextAlphaDark), (if (!isDark) Preferences.clockTextColor else Preferences.clockTextColorDark).replace("#", "")))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Color.parseColor("#FFFFFFFF")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getClockFontColorAlpha(isDark: Boolean): Int {
|
||||||
|
return try {
|
||||||
|
(if (!isDark) Preferences.clockTextAlpha else Preferences.clockTextAlphaDark).toIntValue().toDouble() * 255 / 100
|
||||||
|
} catch (e: Exception) {
|
||||||
|
"FF".toIntValue().toDouble() * 255 / 100
|
||||||
|
}.roundToInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getClockFontColorRgb(isDark: Boolean): Int {
|
||||||
|
return try {
|
||||||
|
Color.parseColor((if (!isDark) Preferences.clockTextColor else Preferences.clockTextColorDark))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Color.parseColor("#000000")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBackgroundColor(isDark: Boolean): Int {
|
||||||
|
return try {
|
||||||
|
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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getBackgroundAlpha(): Int {
|
fun getBackgroundAlpha(isDark: Boolean): Int {
|
||||||
return try {
|
return try {
|
||||||
Preferences.backgroundCardAlpha.toIntValue().toDouble() * 255 / 100
|
(if (!isDark) Preferences.backgroundCardAlpha else Preferences.backgroundCardAlphaDark).toIntValue().toDouble() * 255 / 100
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
"00".toIntValue().toDouble() * 255 / 100
|
"00".toIntValue().toDouble() * 255 / 100
|
||||||
}.roundToInt()
|
}.roundToInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getBackgroundColorRgb(): Int {
|
fun getBackgroundColorRgb(isDark: Boolean): Int {
|
||||||
return try {
|
return try {
|
||||||
Color.parseColor(Preferences.backgroundCardColor)
|
Color.parseColor((if (!isDark) Preferences.backgroundCardColor else Preferences.backgroundCardColorDark))
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Color.parseColor("#000000")
|
Color.parseColor("#000000")
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package com.tommasoberlose.anotherwidget.helpers
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
import android.util.Log
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.utils.getCapWordString
|
import com.tommasoberlose.anotherwidget.utils.getCapWordString
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
@ -12,18 +11,28 @@ import java.util.*
|
|||||||
object DateHelper {
|
object DateHelper {
|
||||||
fun getDateText(context: Context, date: Calendar): String {
|
fun getDateText(context: Context, date: Calendar): String {
|
||||||
return if (Preferences.dateFormat != "") {
|
return if (Preferences.dateFormat != "") {
|
||||||
try {
|
val text = try {
|
||||||
SimpleDateFormat(Preferences.dateFormat, Locale.getDefault()).format(date.time)
|
SimpleDateFormat(Preferences.dateFormat, Locale.getDefault()).format(date.time)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
getDefaultDateText(context, date)
|
getDefaultDateText(context, date)
|
||||||
}
|
}
|
||||||
|
when {
|
||||||
|
Preferences.isDateUppercase -> text.toUpperCase(Locale.getDefault())
|
||||||
|
Preferences.isDateCapitalize -> text.getCapWordString()
|
||||||
|
else -> text
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
val flags: Int =
|
val flags: Int =
|
||||||
DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NO_YEAR or DateUtils.FORMAT_ABBREV_MONTH
|
DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NO_YEAR or DateUtils.FORMAT_ABBREV_MONTH
|
||||||
"%s, %s".format(
|
val text = "%s, %s".format(
|
||||||
SimpleDateFormat("EEEE", Locale.getDefault()).format(date.time),
|
SimpleDateFormat("EEEE", Locale.getDefault()).format(date.time),
|
||||||
DateUtils.formatDateTime(context, date.timeInMillis, flags)
|
DateUtils.formatDateTime(context, date.timeInMillis, flags)
|
||||||
).getCapWordString()
|
)
|
||||||
|
when {
|
||||||
|
Preferences.isDateUppercase -> text.toUpperCase(Locale.getDefault())
|
||||||
|
Preferences.isDateCapitalize -> text.getCapWordString()
|
||||||
|
else -> text
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,6 +42,6 @@ object DateHelper {
|
|||||||
return "%s, %s".format(
|
return "%s, %s".format(
|
||||||
SimpleDateFormat("EEEE", Locale.getDefault()).format(date.time),
|
SimpleDateFormat("EEEE", Locale.getDefault()).format(date.time),
|
||||||
DateUtils.formatDateTime(context, date.timeInMillis, flags)
|
DateUtils.formatDateTime(context, date.timeInMillis, flags)
|
||||||
).getCapWordString()
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.helpers
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.Log
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.db.EventRepository
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.models.GlanceProvider
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.checkIfFitInstalled
|
||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
object GlanceProviderHelper {
|
||||||
|
fun getGlanceProviders(context: Context): ArrayList<Constants.GlanceProviderId> {
|
||||||
|
val enabledProviders = Preferences.enabledGlanceProviderOrder.split(",").filter { it != "" }
|
||||||
|
|
||||||
|
val providers = Constants.GlanceProviderId.values()
|
||||||
|
.filter {
|
||||||
|
context.checkIfFitInstalled() || it != Constants.GlanceProviderId.GOOGLE_FIT_STEPS
|
||||||
|
}.toTypedArray()
|
||||||
|
|
||||||
|
providers.sortWith(Comparator { p1, p2 ->
|
||||||
|
when {
|
||||||
|
enabledProviders.contains(p1.id) && enabledProviders.contains(p2.id) -> {
|
||||||
|
enabledProviders.indexOf(p1.id).compareTo(enabledProviders.indexOf(p2.id))
|
||||||
|
}
|
||||||
|
enabledProviders.contains(p1.id) -> {
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
enabledProviders.contains(p2.id) -> {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
p1.id.compareTo(p2.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return ArrayList(providers.toList())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getGlanceProviderById(context: Context, providerId: Constants.GlanceProviderId): GlanceProvider? {
|
||||||
|
return when(providerId) {
|
||||||
|
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
|
||||||
|
GlanceProvider(providerId.id,
|
||||||
|
context.getString(R.string.settings_show_next_alarm_title),
|
||||||
|
R.drawable.round_alarm
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.PLAYING_SONG -> {
|
||||||
|
GlanceProvider(providerId.id,
|
||||||
|
context.getString(R.string.settings_show_music_title),
|
||||||
|
R.drawable.round_music_note
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.CUSTOM_INFO -> {
|
||||||
|
GlanceProvider(providerId.id,
|
||||||
|
context.getString(R.string.settings_custom_notes_title),
|
||||||
|
R.drawable.round_notes
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
||||||
|
GlanceProvider(providerId.id,
|
||||||
|
context.getString(R.string.settings_low_battery_level_title),
|
||||||
|
R.drawable.round_battery_charging_full
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
|
||||||
|
GlanceProvider(providerId.id,
|
||||||
|
context.getString(R.string.settings_daily_steps_title),
|
||||||
|
R.drawable.round_directions_walk
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveGlanceProviderOrder(list: ArrayList<Constants.GlanceProviderId>) {
|
||||||
|
Preferences.enabledGlanceProviderOrder = list.joinToString(separator = ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun showGlanceProviders(context: Context): Boolean {
|
||||||
|
val eventRepository = EventRepository(context)
|
||||||
|
BatteryHelper.updateBatteryInfo(context)
|
||||||
|
|
||||||
|
val showGlance = Preferences.showGlance && (eventRepository.getEventsCount() == 0 || !Preferences.showEvents) && (
|
||||||
|
(Preferences.showNextAlarm && AlarmHelper.getNextAlarm(context) != "") ||
|
||||||
|
(MediaPlayerHelper.isSomeonePlaying(context)) ||
|
||||||
|
(Preferences.showBatteryCharging && Preferences.isCharging || Preferences.isBatteryLevelLow) ||
|
||||||
|
(Preferences.customNotes.isNotEmpty()) ||
|
||||||
|
(Preferences.showDailySteps && Preferences.googleFitSteps > 0)
|
||||||
|
)
|
||||||
|
eventRepository.close()
|
||||||
|
return showGlance
|
||||||
|
}
|
||||||
|
}
|
@ -10,9 +10,12 @@ import android.net.Uri
|
|||||||
import android.provider.AlarmClock
|
import android.provider.AlarmClock
|
||||||
import android.provider.CalendarContract
|
import android.provider.CalendarContract
|
||||||
import android.provider.CalendarContract.Events
|
import android.provider.CalendarContract.Events
|
||||||
|
import android.util.Log
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
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.ui.widgets.MainWidget
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.toast
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
@ -63,12 +66,8 @@ object IntentHelper {
|
|||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Intent(Intent.ACTION_VIEW).apply {
|
context.toast(context.getString(R.string.error_opening_app))
|
||||||
addCategory(Intent.CATEGORY_DEFAULT)
|
Intent()
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
|
||||||
data = Uri.parse("dynact://velour/weather/ProxyActivity")
|
|
||||||
component = ComponentName("com.google.android.googlequicksearchbox", "com.google.android.apps.gsa.velour.DynamicActivityTrampoline")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,14 +77,12 @@ object IntentHelper {
|
|||||||
val calendarUri = CalendarContract.CONTENT_URI
|
val calendarUri = CalendarContract.CONTENT_URI
|
||||||
.buildUpon()
|
.buildUpon()
|
||||||
.appendPath("time")
|
.appendPath("time")
|
||||||
.appendPath(Date(Calendar.getInstance().timeInMillis).toString())
|
.appendPath(Calendar.getInstance().timeInMillis.toString())
|
||||||
.build()
|
.build()
|
||||||
return when (Preferences.calendarAppPackage) {
|
return when (Preferences.calendarAppPackage) {
|
||||||
"" -> {
|
"" -> {
|
||||||
Intent(Intent.ACTION_MAIN).apply {
|
Intent(Intent.ACTION_VIEW).apply {
|
||||||
// data = calendarUri
|
data = calendarUri
|
||||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
addCategory(Intent.CATEGORY_APP_CALENDAR)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"_" -> {
|
"_" -> {
|
||||||
@ -95,17 +92,12 @@ object IntentHelper {
|
|||||||
val pm: PackageManager = context.packageManager
|
val pm: PackageManager = context.packageManager
|
||||||
try {
|
try {
|
||||||
pm.getLaunchIntentForPackage(Preferences.calendarAppPackage)!!.apply {
|
pm.getLaunchIntentForPackage(Preferences.calendarAppPackage)!!.apply {
|
||||||
// data = calendarUri
|
action = Intent.ACTION_VIEW
|
||||||
addCategory(Intent.CATEGORY_LAUNCHER)
|
data = calendarUri
|
||||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
context.toast(context.getString(R.string.error_opening_app))
|
||||||
Intent(Intent.ACTION_MAIN).apply {
|
Intent()
|
||||||
// data = calendarUri
|
|
||||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
addCategory(Intent.CATEGORY_APP_CALENDAR)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,16 +110,51 @@ object IntentHelper {
|
|||||||
if (Preferences.calendarAppPackage == "") {
|
if (Preferences.calendarAppPackage == "") {
|
||||||
Intent(Intent.ACTION_VIEW).apply {
|
Intent(Intent.ACTION_VIEW).apply {
|
||||||
data = uri
|
data = uri
|
||||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
flags = (Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED or Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||||
putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, e.startDate)
|
if (!e.allDay) {
|
||||||
putExtra(CalendarContract.EXTRA_EVENT_END_TIME, e.endDate)
|
putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, e.startDate)
|
||||||
|
putExtra(CalendarContract.EXTRA_EVENT_END_TIME, e.endDate)
|
||||||
|
} else {
|
||||||
|
val start = Calendar.getInstance().apply {
|
||||||
|
timeInMillis = e.startDate
|
||||||
|
}
|
||||||
|
val end = Calendar.getInstance().apply {
|
||||||
|
timeInMillis = e.endDate
|
||||||
|
}
|
||||||
|
|
||||||
|
putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, e.startDate + start.timeZone.getOffset(start.timeInMillis))
|
||||||
|
putExtra(CalendarContract.EXTRA_EVENT_END_TIME, e.endDate + end.timeZone.getOffset(end.timeInMillis))
|
||||||
|
putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
getCalendarIntent(context).apply {
|
val calendarIntent = getCalendarIntent(context)
|
||||||
action = Intent.ACTION_VIEW
|
if (calendarIntent.action == Intent.ACTION_VIEW) {
|
||||||
data = uri
|
calendarIntent.apply {
|
||||||
putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, e.startDate)
|
data = uri
|
||||||
putExtra(CalendarContract.EXTRA_EVENT_END_TIME, e.endDate)
|
if (!e.allDay) {
|
||||||
|
putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, e.startDate)
|
||||||
|
putExtra(CalendarContract.EXTRA_EVENT_END_TIME, e.endDate)
|
||||||
|
} else {
|
||||||
|
val start = Calendar.getInstance().apply {
|
||||||
|
timeInMillis = e.startDate
|
||||||
|
}
|
||||||
|
val end = Calendar.getInstance().apply {
|
||||||
|
timeInMillis = e.endDate
|
||||||
|
}
|
||||||
|
putExtra(
|
||||||
|
CalendarContract.EXTRA_EVENT_BEGIN_TIME,
|
||||||
|
start.timeInMillis + start.timeZone.getOffset(start.timeInMillis)
|
||||||
|
)
|
||||||
|
putExtra(
|
||||||
|
CalendarContract.EXTRA_EVENT_END_TIME,
|
||||||
|
end.timeInMillis + end.timeZone.getOffset(end.timeInMillis)
|
||||||
|
)
|
||||||
|
putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Intent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,11 +181,45 @@ object IntentHelper {
|
|||||||
addCategory(Intent.CATEGORY_LAUNCHER)
|
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Intent(AlarmClock.ACTION_SHOW_ALARMS).apply {
|
context.toast(context.getString(R.string.error_opening_app))
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
Intent()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getBatteryIntent(): Intent {
|
||||||
|
return Intent(Intent.ACTION_POWER_USAGE_SUMMARY)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMusicIntent(context: Context): Intent {
|
||||||
|
return when (Preferences.mediaPlayerPackage) {
|
||||||
|
"" -> {
|
||||||
|
Intent()
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val pm: PackageManager = context.packageManager
|
||||||
|
try {
|
||||||
|
pm.getLaunchIntentForPackage(Preferences.mediaPlayerPackage)!!.apply {
|
||||||
|
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
context.toast(context.getString(R.string.error_opening_app))
|
||||||
|
Intent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFitIntent(context: Context): Intent {
|
||||||
|
val pm: PackageManager = context.packageManager
|
||||||
|
return try {
|
||||||
|
pm.getLaunchIntentForPackage("com.google.android.apps.fitness")!!.apply {
|
||||||
|
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
context.toast(context.getString(R.string.error_opening_app))
|
||||||
|
Intent()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -0,0 +1,104 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.helpers
|
||||||
|
|
||||||
|
import android.app.Notification
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.media.MediaMetadata
|
||||||
|
import android.media.session.MediaController
|
||||||
|
import android.media.session.MediaSession
|
||||||
|
import android.media.session.MediaSessionManager
|
||||||
|
import android.media.session.PlaybackState
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.core.app.NotificationManagerCompat
|
||||||
|
import com.chibatching.kotpref.Kotpref
|
||||||
|
import com.chibatching.kotpref.blockingBulk
|
||||||
|
import com.chibatching.kotpref.bulk
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.receivers.MusicNotificationListener
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
|
import java.lang.Exception
|
||||||
|
|
||||||
|
object MediaPlayerHelper {
|
||||||
|
fun isSomeonePlaying(context: Context) = Preferences.showMusic && NotificationManagerCompat.getEnabledListenerPackages(context).contains(context.packageName) && Preferences.mediaPlayerTitle != ""
|
||||||
|
|
||||||
|
fun getMediaInfo(): String {
|
||||||
|
return if (Preferences.mediaPlayerArtist == "") {
|
||||||
|
Preferences.mediaPlayerTitle
|
||||||
|
} else {
|
||||||
|
"%s, %s".format(Preferences.mediaPlayerTitle, Preferences.mediaPlayerArtist)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updatePlayingMediaInfo(context: Context) {
|
||||||
|
Kotpref.init(context)
|
||||||
|
if (NotificationManagerCompat.getEnabledListenerPackages(context).contains(context.packageName)) {
|
||||||
|
val list = try {
|
||||||
|
(context.getSystemService(Context.MEDIA_SESSION_SERVICE) as MediaSessionManager).getActiveSessions(
|
||||||
|
ComponentName(context.packageName, MusicNotificationListener::class.java.name)
|
||||||
|
)
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
emptyList<MediaController>()
|
||||||
|
}.filter {
|
||||||
|
Preferences.musicPlayersFilter == "" || isMusicPlayerAccepted(it.packageName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list.isNotEmpty()) {
|
||||||
|
var isSomeonePlaying = false
|
||||||
|
list.forEach { mc ->
|
||||||
|
val metadata = mc.metadata
|
||||||
|
val isPlaying =
|
||||||
|
mc.playbackState?.state == PlaybackState.STATE_PLAYING || mc.playbackState?.state == PlaybackState.STATE_CONNECTING
|
||||||
|
|
||||||
|
if (isPlaying) {
|
||||||
|
isSomeonePlaying = true
|
||||||
|
if (metadata != null) {
|
||||||
|
Preferences.bulk {
|
||||||
|
mediaPlayerTitle =
|
||||||
|
metadata.getText(MediaMetadata.METADATA_KEY_TITLE)?.toString()
|
||||||
|
?: ""
|
||||||
|
mediaPlayerArtist =
|
||||||
|
metadata.getText(MediaMetadata.METADATA_KEY_ARTIST)?.toString()
|
||||||
|
?: ""
|
||||||
|
mediaPlayerAlbum =
|
||||||
|
metadata.getText(MediaMetadata.METADATA_KEY_ALBUM)?.toString()
|
||||||
|
?: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Preferences.mediaPlayerPackage = mc.packageName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isSomeonePlaying) {
|
||||||
|
removeMediaInfo(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
removeMediaInfo(context)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
removeMediaInfo(context)
|
||||||
|
}
|
||||||
|
MainWidget.updateWidget(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removeMediaInfo(context: Context) {
|
||||||
|
Kotpref.init(context)
|
||||||
|
Preferences.blockingBulk {
|
||||||
|
remove(Preferences::mediaPlayerTitle)
|
||||||
|
remove(Preferences::mediaPlayerArtist)
|
||||||
|
remove(Preferences::mediaPlayerAlbum)
|
||||||
|
remove(Preferences::mediaPlayerPackage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isMusicPlayerAccepted(appPkg: String): Boolean = 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 = ",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,8 @@ package com.tommasoberlose.anotherwidget.helpers
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
@ -39,7 +41,6 @@ object SettingsStringHelper {
|
|||||||
return when (info) {
|
return when (info) {
|
||||||
0 -> R.string.settings_second_row_info_subtitle_0
|
0 -> R.string.settings_second_row_info_subtitle_0
|
||||||
1 -> R.string.settings_second_row_info_subtitle_1
|
1 -> R.string.settings_second_row_info_subtitle_1
|
||||||
2 -> R.string.settings_second_row_info_subtitle_2
|
|
||||||
else -> R.string.settings_second_row_info_subtitle_0
|
else -> R.string.settings_second_row_info_subtitle_0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,14 +54,27 @@ 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.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("regular") || variant.contains("400") -> context.getString(R.string.font_400)
|
||||||
|
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)
|
||||||
@ -69,11 +83,38 @@ object SettingsStringHelper {
|
|||||||
difference += 60 * 1000 - (difference % (60 * 1000))
|
difference += 60 * 1000 - (difference % (60 * 1000))
|
||||||
|
|
||||||
when {
|
when {
|
||||||
difference <= 0 || TimeUnit.MILLISECONDS.toHours(difference) < 1 -> {
|
difference <= 0 -> {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
TimeUnit.MILLISECONDS.toHours(difference) < 1 && Preferences.widgetUpdateFrequency == Constants.WidgetUpdateFrequency.HIGH.value && TimeUnit.MILLISECONDS.toMinutes(difference) > 5 -> {
|
||||||
|
return DateUtils.getRelativeTimeSpanString(start, start - 1000 * 60 * (TimeUnit.MILLISECONDS.toMinutes(difference) - 1 - (TimeUnit.MILLISECONDS.toMinutes(difference) - 1) % 5), DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE).toString()
|
||||||
|
}
|
||||||
|
TimeUnit.MILLISECONDS.toHours(difference) < 1 && Preferences.widgetUpdateFrequency == Constants.WidgetUpdateFrequency.DEFAULT.value && TimeUnit.MILLISECONDS.toMinutes(difference) > 5 -> {
|
||||||
|
return DateUtils.getRelativeTimeSpanString(start, start - 1000 * 60 * (TimeUnit.MILLISECONDS.toMinutes(difference) - 1 - (TimeUnit.MILLISECONDS.toMinutes(difference) - 1) % 15), DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE).toString()
|
||||||
|
}
|
||||||
|
TimeUnit.MILLISECONDS.toHours(difference) < 1 && Preferences.widgetUpdateFrequency == Constants.WidgetUpdateFrequency.LOW.value -> {
|
||||||
|
return context.getString(R.string.soon)
|
||||||
|
}
|
||||||
|
TimeUnit.MILLISECONDS.toHours(difference) < 1 -> {
|
||||||
|
return context.getString(R.string.now)
|
||||||
|
}
|
||||||
TimeUnit.MILLISECONDS.toHours(difference) < 12 -> {
|
TimeUnit.MILLISECONDS.toHours(difference) < 12 -> {
|
||||||
return DateUtils.getRelativeTimeSpanString(start, now, DateUtils.HOUR_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE).toString()
|
val minutes = TimeUnit.MILLISECONDS.toMinutes(difference) - 60 * TimeUnit.MILLISECONDS.toHours(difference)
|
||||||
|
return if (minutes < 1 || minutes > 30) {
|
||||||
|
DateUtils.getRelativeTimeSpanString(
|
||||||
|
start,
|
||||||
|
now - 1000 * 60 * 40,
|
||||||
|
DateUtils.HOUR_IN_MILLIS,
|
||||||
|
DateUtils.FORMAT_ABBREV_RELATIVE
|
||||||
|
).toString()
|
||||||
|
} else {
|
||||||
|
DateUtils.getRelativeTimeSpanString(
|
||||||
|
start,
|
||||||
|
now,
|
||||||
|
DateUtils.HOUR_IN_MILLIS,
|
||||||
|
DateUtils.FORMAT_ABBREV_RELATIVE
|
||||||
|
).toString()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
eventDate.dayOfYear == nowDate.plusDays(1).dayOfYear -> {
|
eventDate.dayOfYear == nowDate.plusDays(1).dayOfYear -> {
|
||||||
return String.format("%s", context.getString(R.string.tomorrow))
|
return String.format("%s", context.getString(R.string.tomorrow))
|
||||||
|
@ -5,15 +5,18 @@ import android.content.Context
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.google.android.gms.location.LocationServices
|
import com.google.android.gms.location.LocationServices
|
||||||
import com.kwabenaberko.openweathermaplib.constants.Units
|
|
||||||
import com.kwabenaberko.openweathermaplib.implementation.OpenWeatherMapHelper
|
|
||||||
import com.kwabenaberko.openweathermaplib.implementation.callbacks.CurrentWeatherCallback
|
|
||||||
import com.kwabenaberko.openweathermaplib.models.currentweather.CurrentWeather
|
|
||||||
import com.tommasoberlose.anotherwidget.R
|
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.network.WeatherNetworkApi
|
import com.tommasoberlose.anotherwidget.network.WeatherNetworkApi
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,7 +25,7 @@ import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
|||||||
|
|
||||||
object WeatherHelper {
|
object WeatherHelper {
|
||||||
|
|
||||||
fun updateWeather(context: Context) {
|
suspend fun updateWeather(context: Context) {
|
||||||
val networkApi = WeatherNetworkApi(context)
|
val networkApi = WeatherNetworkApi(context)
|
||||||
if (Preferences.customLocationAdd != "") {
|
if (Preferences.customLocationAdd != "") {
|
||||||
networkApi.updateWeather()
|
networkApi.updateWeather()
|
||||||
@ -33,9 +36,17 @@ object WeatherHelper {
|
|||||||
if (location != null) {
|
if (location != null) {
|
||||||
Preferences.customLocationLat = location.latitude.toString()
|
Preferences.customLocationLat = location.latitude.toString()
|
||||||
Preferences.customLocationLon = location.longitude.toString()
|
Preferences.customLocationLon = location.longitude.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
networkApi.updateWeather()
|
networkApi.updateWeather()
|
||||||
}
|
}
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
} else {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
networkApi.updateWeather()
|
||||||
|
}
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -44,89 +55,455 @@ object WeatherHelper {
|
|||||||
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): Int {
|
fun getProviderName(context: Context, provider: Constants.WeatherProvider = Constants.WeatherProvider.fromInt(Preferences.weatherProvider)!!): String {
|
||||||
when (icon) {
|
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) {
|
||||||
"01d" -> {
|
"01d" -> {
|
||||||
return R.drawable.clear_day
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.clear_day_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.clear_day_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.clear_day_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.clear_day_5 else R.drawable.clear_day_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"02d" -> {
|
"02d" -> {
|
||||||
return R.drawable.partly_cloudy
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.partly_cloudy_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.partly_cloudy_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.partly_cloudy_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.partly_cloudy_5 else R.drawable.partly_cloudy_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"03d" -> {
|
"03d" -> {
|
||||||
return R.drawable.mostly_cloudy
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.mostly_cloudy_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.mostly_cloudy_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.mostly_cloudy_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.mostly_cloudy_5 else R.drawable.mostly_cloudy_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"04d" -> {
|
"04d" -> {
|
||||||
return R.drawable.cloudy_weather
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.cloudy_weather_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.cloudy_weather_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.cloudy_weather_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.cloudy_weather_5 else R.drawable.cloudy_weather_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"09d" -> {
|
"09d" -> {
|
||||||
return R.drawable.storm_weather_day
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.storm_weather_day_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.storm_weather_day_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.storm_weather_day_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.storm_weather_day_5 else R.drawable.storm_weather_day_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"10d" -> {
|
"10d" -> {
|
||||||
return R.drawable.rainy_day
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.rainy_day_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rainy_day_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rainy_day_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.rainy_day_5 else R.drawable.rainy_day_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"11d" -> {
|
"11d" -> {
|
||||||
return R.drawable.thunder_day
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.thunder_day_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.thunder_day_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.thunder_day_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.thunder_day_5 else R.drawable.thunder_day_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"13d" -> {
|
"13d" -> {
|
||||||
return R.drawable.snow_day
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.snow_day_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.snow_day_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.snow_day_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.snow_day_5 else R.drawable.snow_day_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"50d" -> {
|
"50d" -> {
|
||||||
return R.drawable.haze_day
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_day_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_day_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_day_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.haze_day_5 else R.drawable.haze_day_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"80d" -> {
|
"80d" -> {
|
||||||
return R.drawable.windy_day
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.windy_day_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.windy_day_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.windy_day_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.windy_day_5 else R.drawable.windy_day_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"81d" -> {
|
"81d" -> {
|
||||||
return R.drawable.rain_snow_day
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.rain_snow_day_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rain_snow_day_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rain_snow_day_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.rain_snow_day_5 else R.drawable.rain_snow_day_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"82d" -> {
|
"82d" -> {
|
||||||
return R.drawable.haze_weather
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_weather_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_weather_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_weather_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.haze_weather_5 else R.drawable.haze_weather_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"01n" -> {
|
"01n" -> {
|
||||||
return R.drawable.clear_night
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.clear_night_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.clear_night_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.clear_night_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.clear_night_5 else R.drawable.clear_night_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"02n" -> {
|
"02n" -> {
|
||||||
return R.drawable.partly_cloudy_night
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.partly_cloudy_night_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.partly_cloudy_night_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.partly_cloudy_night_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.partly_cloudy_night_5 else R.drawable.partly_cloudy_night_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"03n" -> {
|
"03n" -> {
|
||||||
return R.drawable.mostly_cloudy_night
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.mostly_cloudy_night_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.mostly_cloudy_night_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.mostly_cloudy_night_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.mostly_cloudy_night_5 else R.drawable.mostly_cloudy_night_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"04n" -> {
|
"04n" -> {
|
||||||
return R.drawable.cloudy_weather
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.cloudy_weather_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.cloudy_weather_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.cloudy_weather_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.cloudy_weather_5 else R.drawable.cloudy_weather_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"09n" -> {
|
"09n" -> {
|
||||||
return R.drawable.storm_weather_night
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.storm_weather_night_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.storm_weather_night_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.storm_weather_night_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.storm_weather_night_5 else R.drawable.storm_weather_night_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"10n" -> {
|
"10n" -> {
|
||||||
return R.drawable.rainy_night
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.rainy_night_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rainy_night_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rainy_night_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.rainy_night_5 else R.drawable.rainy_night_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"11n" -> {
|
"11n" -> {
|
||||||
return R.drawable.thunder_night
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.thunder_night_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.thunder_night_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.thunder_night_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.thunder_night_5 else R.drawable.thunder_night_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"13n" -> {
|
"13n" -> {
|
||||||
return R.drawable.snow_night
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.snow_night_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.snow_night_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.snow_night_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.snow_night_5 else R.drawable.snow_night_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"50n" -> {
|
"50n" -> {
|
||||||
return R.drawable.haze_night
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_night_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_night_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_night_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.haze_night_5 else R.drawable.haze_night_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"80n" -> {
|
"80n" -> {
|
||||||
return R.drawable.windy_night
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.windy_night_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.windy_night_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.windy_night_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.windy_night_5 else R.drawable.windy_night_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"81n" -> {
|
"81n" -> {
|
||||||
return R.drawable.rain_snow_night
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.rain_snow_night_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rain_snow_night_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rain_snow_night_4
|
||||||
|
else -> if (context.isDarkTheme()) R.drawable.rain_snow_night_5 else R.drawable.rain_snow_night_5_light
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"82n" -> {
|
"82n" -> {
|
||||||
return R.drawable.haze_weather
|
when (style) {
|
||||||
|
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_weather_3
|
||||||
|
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_weather_2
|
||||||
|
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_weather_4
|
||||||
|
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,6 +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 androidx.core.provider.FontRequest
|
||||||
|
import androidx.core.provider.FontsContractCompat
|
||||||
|
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.db.EventRepository
|
||||||
|
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(
|
||||||
@ -16,22 +30,14 @@ object WidgetHelper {
|
|||||||
val height = getWidgetHeight(isPortrait, 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("heightInPx", heightInPx)
|
||||||
return widthInPx to heightInPx
|
return widthInPx to heightInPx
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getWidgetWidth(isPortrait: Boolean, widgetId: Int): Int =
|
private fun getWidgetWidth(isPortrait: Boolean, widgetId: Int): Int = getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH)
|
||||||
if (isPortrait) {
|
|
||||||
getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH)
|
|
||||||
} else {
|
|
||||||
getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getWidgetHeight(isPortrait: Boolean, widgetId: Int): Int =
|
private fun getWidgetHeight(isPortrait: Boolean, widgetId: Int): Int = getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT)
|
||||||
if (isPortrait) {
|
|
||||||
getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT)
|
|
||||||
} else {
|
|
||||||
getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MIN_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)
|
||||||
@ -48,4 +54,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,5 +1,6 @@
|
|||||||
package com.tommasoberlose.anotherwidget.models
|
package com.tommasoberlose.anotherwidget.models
|
||||||
|
|
||||||
|
import android.provider.CalendarContract
|
||||||
import io.realm.RealmObject
|
import io.realm.RealmObject
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
@ -7,15 +8,19 @@ import java.util.Date
|
|||||||
* Created by tommaso on 05/10/17.
|
* Created by tommaso on 05/10/17.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
open class Event(var id: Long = 0,
|
open class Event(
|
||||||
var eventID: Long = 0,
|
var id: Long = 0,
|
||||||
var title: String = "",
|
var eventID: Long = 0,
|
||||||
var startDate: Long = 0,
|
var title: String = "",
|
||||||
var endDate: Long = 0,
|
var startDate: Long = 0,
|
||||||
var calendarID: Int = 0,
|
var endDate: Long = 0,
|
||||||
var allDay: Boolean = false,
|
var calendarID: Int = 0,
|
||||||
var address: String = "") : RealmObject() {
|
var allDay: Boolean = false,
|
||||||
|
var address: String = "",
|
||||||
|
var selfAttendeeStatus: Int = CalendarContract.Attendees.ATTENDEE_STATUS_NONE,
|
||||||
|
var availability: Int = CalendarContract.EventsEntity.AVAILABILITY_BUSY
|
||||||
|
) : RealmObject() {
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "Event:\nID: " + eventID + "\nTITLE: " + title + "\nSTART DATE: " + Date(startDate) + "\nEND DATE: " + Date(endDate) + "\nCAL ID: " + calendarID + "\nADDRESS: " + address
|
return "Event:\nEVENT ID: " + eventID + "\nTITLE: " + title + "\nSTART DATE: " + Date(startDate) + "\nEND DATE: " + Date(endDate) + "\nCAL ID: " + calendarID + "\nADDRESS: " + address
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.models
|
||||||
|
|
||||||
|
class GlanceProvider(
|
||||||
|
val id: String,
|
||||||
|
val title: String,
|
||||||
|
val icon: Int
|
||||||
|
)
|
@ -2,20 +2,55 @@ package com.tommasoberlose.anotherwidget.network
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
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.ui.activities.MainActivity
|
import com.tommasoberlose.anotherwidget.network.repository.*
|
||||||
|
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 != "") {
|
Preferences.weatherProviderError = "-"
|
||||||
val helper = OpenWeatherMapHelper(Preferences.weatherProviderApi)
|
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 {
|
||||||
@ -25,19 +60,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)
|
||||||
|
|
||||||
EventBus.getDefault().post(MainActivity.UpdateUiMessageEvent())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Preferences.weatherProviderError = ""
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(throwable: Throwable?) {
|
override fun onFailure(throwable: Throwable?) {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_missing_key)
|
||||||
|
Preferences.weatherProviderLocationError = ""
|
||||||
|
|
||||||
WeatherHelper.removeWeather(
|
WeatherHelper.removeWeather(
|
||||||
context
|
context
|
||||||
)
|
)
|
||||||
|
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,183 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.receivers
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.app.AlarmManager
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.Log
|
||||||
|
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.GoogleSignInAccount
|
||||||
|
import com.google.android.gms.fitness.Fitness
|
||||||
|
import com.google.android.gms.fitness.FitnessOptions
|
||||||
|
import com.google.android.gms.fitness.data.DataType
|
||||||
|
import com.google.android.gms.fitness.data.Field.FIELD_STEPS
|
||||||
|
import com.google.android.gms.fitness.request.DataReadRequest
|
||||||
|
import com.google.android.gms.location.*
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
|
import java.util.*
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
|
||||||
|
class ActivityDetectionReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
if (ActivityTransitionResult.hasResult(intent)) {
|
||||||
|
val result = ActivityTransitionResult.extractResult(intent)!!
|
||||||
|
val lastEvent = result.transitionEvents.last()
|
||||||
|
|
||||||
|
if (lastEvent.activityType == DetectedActivity.WALKING || lastEvent.activityType == DetectedActivity.RUNNING && lastEvent.transitionType == ActivityTransition.ACTIVITY_TRANSITION_EXIT) {
|
||||||
|
requestDailySteps(context)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (intent.action == Intent.ACTION_BOOT_COMPLETED || intent.action == Intent.ACTION_MY_PACKAGE_REPLACED && Preferences.showDailySteps && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || context.checkGrantedPermission(Manifest.permission.ACTIVITY_RECOGNITION)) {
|
||||||
|
resetDailySteps(context)
|
||||||
|
registerFence(context)
|
||||||
|
} else {
|
||||||
|
resetDailySteps(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resetDailySteps(context: Context) {
|
||||||
|
Kotpref.init(context)
|
||||||
|
Preferences.blockingBulk {
|
||||||
|
remove(Preferences::googleFitSteps)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val FITNESS_OPTIONS: FitnessOptions = FitnessOptions.builder()
|
||||||
|
.addDataType(DataType.TYPE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
|
||||||
|
.addDataType(DataType.AGGREGATE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
fun registerFence(context: Context) {
|
||||||
|
Kotpref.init(context)
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || context.checkGrantedPermission(
|
||||||
|
Manifest.permission.ACTIVITY_RECOGNITION)) {
|
||||||
|
val transitions = mutableListOf<ActivityTransition>()
|
||||||
|
|
||||||
|
transitions +=
|
||||||
|
ActivityTransition.Builder()
|
||||||
|
.setActivityType(DetectedActivity.WALKING)
|
||||||
|
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
transitions +=
|
||||||
|
ActivityTransition.Builder()
|
||||||
|
.setActivityType(DetectedActivity.RUNNING)
|
||||||
|
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val request = ActivityTransitionRequest(transitions)
|
||||||
|
|
||||||
|
// myPendingIntent is the instance of PendingIntent where the app receives callbacks.
|
||||||
|
val task = ActivityRecognition.getClient(context)
|
||||||
|
.requestActivityTransitionUpdates(
|
||||||
|
request,
|
||||||
|
PendingIntent.getBroadcast(
|
||||||
|
context,
|
||||||
|
2,
|
||||||
|
Intent(context, ActivityDetectionReceiver::class.java),
|
||||||
|
0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
task.addOnFailureListener { e: Exception ->
|
||||||
|
e.printStackTrace()
|
||||||
|
Preferences.showDailySteps = false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unregisterFence(context: Context) {
|
||||||
|
val task = ActivityRecognition.getClient(context)
|
||||||
|
.removeActivityTransitionUpdates(
|
||||||
|
PendingIntent.getBroadcast(
|
||||||
|
context,
|
||||||
|
2,
|
||||||
|
Intent(context, ActivityDetectionReceiver::class.java),
|
||||||
|
0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
task.addOnCompleteListener {
|
||||||
|
if (it.isSuccessful) {
|
||||||
|
PendingIntent.getBroadcast(
|
||||||
|
context,
|
||||||
|
2,
|
||||||
|
Intent(context, ActivityDetectionReceiver::class.java),
|
||||||
|
0
|
||||||
|
).cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun requestDailySteps(context: Context) {
|
||||||
|
Kotpref.init(context)
|
||||||
|
|
||||||
|
val account: GoogleSignInAccount? = GoogleSignIn.getLastSignedInAccount(context)
|
||||||
|
if (account != null && GoogleSignIn.hasPermissions(account, FITNESS_OPTIONS)) {
|
||||||
|
|
||||||
|
val cal: Calendar = Calendar.getInstance()
|
||||||
|
cal.set(Calendar.HOUR_OF_DAY, 0)
|
||||||
|
cal.set(Calendar.MINUTE, 0)
|
||||||
|
cal.set(Calendar.SECOND, 0)
|
||||||
|
cal.set(Calendar.MILLISECOND, 0)
|
||||||
|
val startTime: Long = cal.timeInMillis
|
||||||
|
|
||||||
|
cal.add(Calendar.DAY_OF_YEAR, 1)
|
||||||
|
val endTime: Long = cal.timeInMillis
|
||||||
|
|
||||||
|
val readRequest = DataReadRequest.Builder()
|
||||||
|
.aggregate(
|
||||||
|
DataType.TYPE_STEP_COUNT_DELTA,
|
||||||
|
DataType.AGGREGATE_STEP_COUNT_DELTA
|
||||||
|
)
|
||||||
|
.setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
|
||||||
|
.bucketByTime(1, TimeUnit.DAYS)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
Fitness.getHistoryClient(context, account)
|
||||||
|
.readData(readRequest)
|
||||||
|
.addOnSuccessListener { response ->
|
||||||
|
Preferences.googleFitSteps = response.buckets.sumBy {
|
||||||
|
try {
|
||||||
|
it.getDataSet(DataType.AGGREGATE_STEP_COUNT_DELTA)?.dataPoints?.get(
|
||||||
|
0
|
||||||
|
)?.getValue(FIELD_STEPS)?.asInt() ?: 0
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}.toLong()
|
||||||
|
MainWidget.updateWidget(context)
|
||||||
|
setTimeout(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setTimeout(context: Context) {
|
||||||
|
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
|
cancel(PendingIntent.getBroadcast(context, 5, Intent(context, ActivityDetectionReceiver::class.java), 0))
|
||||||
|
setExactAndAllowWhileIdle(
|
||||||
|
AlarmManager.RTC,
|
||||||
|
Calendar.getInstance().timeInMillis + 5 * 60 * 1000,
|
||||||
|
PendingIntent.getBroadcast(
|
||||||
|
context,
|
||||||
|
5,
|
||||||
|
Intent(context, ActivityDetectionReceiver::class.java),
|
||||||
|
0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.receivers
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.BatteryManager
|
||||||
|
import android.util.Log
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.toast
|
||||||
|
|
||||||
|
class BatteryLevelReceiver : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
when(intent.action) {
|
||||||
|
Intent.ACTION_BATTERY_LOW -> Preferences.isBatteryLevelLow = true
|
||||||
|
Intent.ACTION_BATTERY_OKAY -> Preferences.isBatteryLevelLow = false
|
||||||
|
Intent.ACTION_POWER_CONNECTED -> Preferences.isCharging = true
|
||||||
|
Intent.ACTION_POWER_DISCONNECTED -> Preferences.isCharging = false
|
||||||
|
}
|
||||||
|
MainWidget.updateWidget(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.receivers
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.util.Log
|
||||||
|
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Actions
|
||||||
|
import java.lang.Exception
|
||||||
|
|
||||||
|
class CrashlyticsReceiver : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
if (intent.action == Actions.ACTION_REPORT_CRASH) {
|
||||||
|
val exception: Exception = intent.getSerializableExtra(EXCEPTION) as Exception
|
||||||
|
FirebaseCrashlytics.getInstance().recordException(exception)
|
||||||
|
FirebaseCrashlytics.getInstance().sendUnsentReports()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val EXCEPTION = "EXCEPTION"
|
||||||
|
|
||||||
|
fun sendCrash(context: Context, exception: Exception) {
|
||||||
|
context.sendBroadcast(Intent(context, CrashlyticsReceiver::class.java).apply {
|
||||||
|
action = Actions.ACTION_REPORT_CRASH
|
||||||
|
putExtra(EXCEPTION, exception)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
@ -24,5 +24,6 @@ class NewCalendarEventReceiver : BroadcastReceiver() {
|
|||||||
eventRepository.goToPreviousEvent()
|
eventRepository.goToPreviousEvent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
eventRepository.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
package com.tommasoberlose.anotherwidget.receivers
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.util.Log
|
|
||||||
|
|
||||||
|
|
||||||
class PlayerReceiver : BroadcastReceiver() {
|
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
|
||||||
Log.d("ciao", "player ok")
|
|
||||||
|
|
||||||
// val cmd = intent.getStringExtra("command")
|
|
||||||
// Log.v("tag ", "$action / $cmd")
|
|
||||||
// val artist = intent.getStringExtra("artist")
|
|
||||||
// val album = intent.getStringExtra("album")
|
|
||||||
// val track = intent.getStringExtra("track")
|
|
||||||
// Log.v("tag", "$artist:$album:$track")
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,7 +10,11 @@ import androidx.core.app.AlarmManagerCompat
|
|||||||
import androidx.core.content.ContextCompat.getSystemService
|
import androidx.core.content.ContextCompat.getSystemService
|
||||||
import com.tommasoberlose.anotherwidget.db.EventRepository
|
import com.tommasoberlose.anotherwidget.db.EventRepository
|
||||||
import com.tommasoberlose.anotherwidget.global.Actions
|
import com.tommasoberlose.anotherwidget.global.Actions
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.BatteryHelper
|
||||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.models.Event
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
import org.joda.time.Period
|
import org.joda.time.Period
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -25,54 +29,136 @@ class UpdatesReceiver : BroadcastReceiver() {
|
|||||||
Intent.ACTION_TIME_CHANGED,
|
Intent.ACTION_TIME_CHANGED,
|
||||||
Intent.ACTION_TIMEZONE_CHANGED,
|
Intent.ACTION_TIMEZONE_CHANGED,
|
||||||
Intent.ACTION_LOCALE_CHANGED,
|
Intent.ACTION_LOCALE_CHANGED,
|
||||||
Actions.ACTION_CALENDAR_UPDATE -> CalendarHelper.updateEventList(context)
|
Intent.ACTION_DATE_CHANGED,
|
||||||
|
Actions.ACTION_CALENDAR_UPDATE -> {
|
||||||
|
CalendarHelper.updateEventList(context)
|
||||||
|
}
|
||||||
|
|
||||||
"com.sec.android.widgetapp.APPWIDGET_RESIZE",
|
"com.sec.android.widgetapp.APPWIDGET_RESIZE",
|
||||||
Intent.ACTION_DATE_CHANGED,
|
|
||||||
AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED,
|
AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED,
|
||||||
Actions.ACTION_TIME_UPDATE -> {
|
Actions.ACTION_TIME_UPDATE -> {
|
||||||
MainWidget.updateWidget(context)
|
MainWidget.updateWidget(context)
|
||||||
|
if (intent.hasExtra(EVENT_ID)) {
|
||||||
|
setUpdates(context, intent.getLongExtra(EVENT_ID, -1))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
const val EVENT_ID = "EVENT_ID"
|
||||||
|
|
||||||
fun setUpdates(context: Context) {
|
fun setUpdates(context: Context, eventId: Long? = null) {
|
||||||
removeUpdates(context)
|
|
||||||
|
|
||||||
|
|
||||||
val eventRepository = EventRepository(context)
|
val eventRepository = EventRepository(context)
|
||||||
|
if (eventId == null) {
|
||||||
|
removeUpdates(context)
|
||||||
|
|
||||||
|
eventRepository.getFutureEvents().forEach { event ->
|
||||||
|
setEventUpdate(context, event)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val event = eventRepository.getEventByEventId(eventId)
|
||||||
|
if (event != null) {
|
||||||
|
setEventUpdate(context, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eventRepository.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setEventUpdate(context: Context, event: Event) {
|
||||||
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
eventRepository.getEvents().forEach { event ->
|
val now = Calendar.getInstance().apply {
|
||||||
val now = Calendar.getInstance().apply {
|
set(Calendar.SECOND, 0)
|
||||||
set(Calendar.SECOND, 0)
|
set(Calendar.MILLISECOND, 0)
|
||||||
set(Calendar.MILLISECOND, 0)
|
}
|
||||||
}
|
val diff = Period(now.timeInMillis, event.startDate)
|
||||||
val diff = Period(now.timeInMillis, event.startDate)
|
val limit = when (Preferences.showUntil) {
|
||||||
|
0 -> 1000 * 60 * 60 * 3
|
||||||
|
1 -> 1000 * 60 * 60 * 6
|
||||||
|
2 -> 1000 * 60 * 60 * 12
|
||||||
|
3 -> 1000 * 60 * 60 * 24
|
||||||
|
4 -> 1000 * 60 * 60 * 24 * 3
|
||||||
|
5 -> 1000 * 60 * 60 * 24 * 7
|
||||||
|
6 -> 1000 * 60 * 30
|
||||||
|
7 -> 1000 * 60 * 60
|
||||||
|
else -> 1000 * 60 * 60 * 6
|
||||||
|
}
|
||||||
|
if (event.startDate <= limit) {
|
||||||
if (event.startDate > now.timeInMillis) {
|
if (event.startDate > now.timeInMillis) {
|
||||||
// Update the widget every hour till the event
|
// Update the widget every hour till the event
|
||||||
(0..diff.hours).forEach {
|
if (diff.hours == 0) {
|
||||||
setExactAndAllowWhileIdle(
|
var minutes = 0
|
||||||
|
when (Preferences.widgetUpdateFrequency) {
|
||||||
|
Constants.WidgetUpdateFrequency.DEFAULT.value -> {
|
||||||
|
minutes = when {
|
||||||
|
diff.minutes > 50 -> 50
|
||||||
|
diff.minutes > 30 -> 30
|
||||||
|
diff.minutes > 15 -> 15
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Constants.WidgetUpdateFrequency.HIGH.value -> {
|
||||||
|
minutes = diff.minutes - (diff.minutes % 5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setExact(
|
||||||
AlarmManager.RTC,
|
AlarmManager.RTC,
|
||||||
if (event.startDate - it * 1000 * 60 * 60 > 60 * 1000) event.startDate - it * 1000 * 60 * 60 else now.timeInMillis + 120000,
|
if (event.startDate - minutes * 1000 * 60 > (now.timeInMillis + 120 * 1000)) event.startDate - 60 * 1000 * minutes else now.timeInMillis + 120000,
|
||||||
PendingIntent.getBroadcast(
|
PendingIntent.getBroadcast(
|
||||||
context,
|
context,
|
||||||
event.eventID.toInt() + it,
|
event.eventID.toInt(),
|
||||||
Intent(context, UpdatesReceiver::class.java).apply {
|
Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
action = Actions.ACTION_TIME_UPDATE
|
action = Actions.ACTION_TIME_UPDATE
|
||||||
|
putExtra(EVENT_ID, event.eventID)
|
||||||
},
|
},
|
||||||
0
|
PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
setExact(
|
||||||
|
AlarmManager.RTC,
|
||||||
|
event.startDate - diff.hours * 1000 * 60 * 60 + if (diff.minutes > 30) (-30) else (+30),
|
||||||
|
PendingIntent.getBroadcast(
|
||||||
|
context,
|
||||||
|
event.eventID.toInt(),
|
||||||
|
Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
|
action = Actions.ACTION_TIME_UPDATE
|
||||||
|
putExtra(EVENT_ID, event.eventID)
|
||||||
|
},
|
||||||
|
PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Update the widget one second after the event is finished
|
||||||
|
val fireTime =
|
||||||
|
if (event.endDate > now.timeInMillis + 120 * 1000) event.endDate else now.timeInMillis + 120000
|
||||||
|
setExact(
|
||||||
|
AlarmManager.RTC,
|
||||||
|
fireTime,
|
||||||
|
PendingIntent.getBroadcast(
|
||||||
|
context,
|
||||||
|
event.eventID.toInt(),
|
||||||
|
Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
|
action = Actions.ACTION_TIME_UPDATE
|
||||||
|
},
|
||||||
|
0
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
// Update the widget one second after the event is finished
|
setExact(
|
||||||
setExactAndAllowWhileIdle(
|
|
||||||
AlarmManager.RTC,
|
AlarmManager.RTC,
|
||||||
if (event.endDate > 60 *1000) event.endDate else now.timeInMillis + 120000,
|
if (event.startDate - limit > now.timeInMillis + 120 * 1000) event.startDate - limit else now.timeInMillis + 120000,
|
||||||
PendingIntent.getBroadcast(context, 1, Intent(context, UpdatesReceiver::class.java).apply { action = Actions.ACTION_TIME_UPDATE }, 0)
|
PendingIntent.getBroadcast(
|
||||||
|
context,
|
||||||
|
event.eventID.toInt(),
|
||||||
|
Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
|
action = Actions.ACTION_TIME_UPDATE
|
||||||
|
putExtra(EVENT_ID, event.eventID)
|
||||||
|
},
|
||||||
|
PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,12 +166,11 @@ class UpdatesReceiver : BroadcastReceiver() {
|
|||||||
|
|
||||||
fun removeUpdates(context: Context) {
|
fun removeUpdates(context: Context) {
|
||||||
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
cancel(PendingIntent.getBroadcast(context, 1, Intent(context, UpdatesReceiver::class.java), 0))
|
val eventRepository = EventRepository(context)
|
||||||
EventRepository(context).getEvents().forEach {
|
eventRepository.getFutureEvents().forEach {
|
||||||
(0..24).forEach { hour ->
|
cancel(PendingIntent.getBroadcast(context, it.eventID.toInt(), Intent(context, UpdatesReceiver::class.java), 0))
|
||||||
cancel(PendingIntent.getBroadcast(context, it.eventID.toInt() * hour, Intent(context, UpdatesReceiver::class.java), 0))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
eventRepository.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,7 +25,9 @@ class WeatherReceiver : BroadcastReceiver() {
|
|||||||
Intent.ACTION_TIME_CHANGED -> setUpdates(context)
|
Intent.ACTION_TIME_CHANGED -> setUpdates(context)
|
||||||
|
|
||||||
Actions.ACTION_WEATHER_UPDATE -> {
|
Actions.ACTION_WEATHER_UPDATE -> {
|
||||||
WeatherHelper.updateWeather(context)
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
WeatherHelper.updateWeather(context)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -33,9 +37,7 @@ class WeatherReceiver : BroadcastReceiver() {
|
|||||||
fun setUpdates(context: Context) {
|
fun setUpdates(context: Context) {
|
||||||
removeUpdates(context)
|
removeUpdates(context)
|
||||||
|
|
||||||
if (Preferences.showWeather && Preferences.weatherProviderApi != "") {
|
if (Preferences.showWeather) {
|
||||||
WeatherHelper.updateWeather(context)
|
|
||||||
|
|
||||||
val interval = MINUTE * when (Preferences.weatherRefreshPeriod) {
|
val interval = MINUTE * when (Preferences.weatherRefreshPeriod) {
|
||||||
0 -> 30
|
0 -> 30
|
||||||
1 -> 60
|
1 -> 60
|
||||||
@ -48,7 +50,7 @@ class WeatherReceiver : BroadcastReceiver() {
|
|||||||
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
setRepeating(
|
setRepeating(
|
||||||
AlarmManager.RTC,
|
AlarmManager.RTC,
|
||||||
Calendar.getInstance().timeInMillis + interval,
|
Calendar.getInstance().timeInMillis,
|
||||||
interval,
|
interval,
|
||||||
PendingIntent.getBroadcast(context, 0, Intent(context, WeatherReceiver::class.java).apply { action = Actions.ACTION_WEATHER_UPDATE }, 0)
|
PendingIntent.getBroadcast(context, 0, Intent(context, WeatherReceiver::class.java).apply { action = Actions.ACTION_WEATHER_UPDATE }, 0)
|
||||||
)
|
)
|
||||||
@ -57,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,61 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.services
|
||||||
|
|
||||||
|
import android.app.job.JobInfo
|
||||||
|
import android.app.job.JobParameters
|
||||||
|
import android.app.job.JobScheduler
|
||||||
|
import android.app.job.JobService
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import android.provider.CalendarContract
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
|
|
||||||
|
class BatteryListenerJob : JobService() {
|
||||||
|
override fun onStartJob(params: JobParameters): Boolean {
|
||||||
|
MainWidget.updateWidget(this)
|
||||||
|
schedule(
|
||||||
|
this
|
||||||
|
)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun onStopJob(params: JobParameters): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val chargingJobId = 1006
|
||||||
|
private const val notChargingJobId = 1007
|
||||||
|
fun schedule(context: Context) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
remove(context)
|
||||||
|
val componentName = ComponentName(
|
||||||
|
context,
|
||||||
|
EventListenerJob::class.java
|
||||||
|
)
|
||||||
|
with(context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler) {
|
||||||
|
schedule(
|
||||||
|
JobInfo.Builder(chargingJobId, componentName)
|
||||||
|
.setRequiresCharging(true)
|
||||||
|
.setPersisted(true)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
schedule(
|
||||||
|
JobInfo.Builder(notChargingJobId, componentName)
|
||||||
|
.setRequiresCharging(false)
|
||||||
|
.setPersisted(true)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun remove(context: Context) {
|
||||||
|
val js = context.getSystemService(JobScheduler::class.java)
|
||||||
|
js?.cancel(chargingJobId)
|
||||||
|
js?.cancel(notChargingJobId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,143 @@
|
|||||||
|
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) {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
@ -6,19 +6,23 @@ import android.os.Bundle
|
|||||||
import android.util.Log
|
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.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.databinding.DataBindingUtil
|
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.bulk
|
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.helpers.DateHelper
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.CustomDateViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.CustomDateViewModel
|
||||||
|
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 kotlinx.android.synthetic.main.activity_custom_date.*
|
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.action_back
|
||||||
import kotlinx.android.synthetic.main.activity_custom_location.list_view
|
import kotlinx.android.synthetic.main.activity_custom_location.list_view
|
||||||
@ -78,7 +82,7 @@ class CustomDateActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
delay(200)
|
delay(200)
|
||||||
val text = if (dateFormat != "") {
|
var text = if (dateFormat != "") {
|
||||||
try {
|
try {
|
||||||
SimpleDateFormat(dateFormat, Locale.getDefault()).format(DATE.time)
|
SimpleDateFormat(dateFormat, Locale.getDefault()).format(DATE.time)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@ -88,6 +92,14 @@ class CustomDateActivity : AppCompatActivity() {
|
|||||||
"__"
|
"__"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (viewModel.isDateCapitalize.value == true) {
|
||||||
|
text = text.getCapWordString()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viewModel.isDateUppercase.value == true) {
|
||||||
|
text = text.toUpperCase(Locale.getDefault())
|
||||||
|
}
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
action_save.isVisible = text != ERROR_STRING
|
action_save.isVisible = text != ERROR_STRING
|
||||||
loader.visibility = View.INVISIBLE
|
loader.visibility = View.INVISIBLE
|
||||||
@ -96,6 +108,33 @@ class CustomDateActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
viewModel.isDateCapitalize.observe(this, Observer {
|
||||||
|
viewModel.dateInput.value = viewModel.dateInput.value
|
||||||
|
updateCapitalizeUi()
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.isDateUppercase.observe(this, Observer {
|
||||||
|
viewModel.dateInput.value = viewModel.dateInput.value
|
||||||
|
updateCapitalizeUi()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateCapitalizeUi() {
|
||||||
|
when {
|
||||||
|
viewModel.isDateUppercase.value == true -> {
|
||||||
|
action_capitalize.setImageDrawable(ContextCompat.getDrawable(this@CustomDateActivity, R.drawable.round_publish))
|
||||||
|
action_capitalize.alpha = 1f
|
||||||
|
}
|
||||||
|
viewModel.isDateCapitalize.value == true -> {
|
||||||
|
action_capitalize.setImageDrawable(ContextCompat.getDrawable(this@CustomDateActivity, R.drawable.ic_capitalize))
|
||||||
|
action_capitalize.alpha = 1f
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
action_capitalize.setImageDrawable(ContextCompat.getDrawable(this@CustomDateActivity, R.drawable.round_publish))
|
||||||
|
action_capitalize.alpha = 0.3f
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupListener() {
|
private fun setupListener() {
|
||||||
@ -104,10 +143,36 @@ class CustomDateActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
action_save.setOnClickListener {
|
action_save.setOnClickListener {
|
||||||
Preferences.dateFormat = viewModel.dateInput.value ?: ""
|
Preferences.blockingBulk {
|
||||||
|
dateFormat = viewModel.dateInput.value ?: ""
|
||||||
|
isDateCapitalize = viewModel.isDateCapitalize.value ?: true
|
||||||
|
isDateUppercase = viewModel.isDateUppercase.value ?: false
|
||||||
|
}
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
action_capitalize.setOnClickListener {
|
||||||
|
when {
|
||||||
|
viewModel.isDateUppercase.value == true -> {
|
||||||
|
viewModel.isDateCapitalize.value = false
|
||||||
|
viewModel.isDateUppercase.value = false
|
||||||
|
}
|
||||||
|
viewModel.isDateCapitalize.value == true -> {
|
||||||
|
viewModel.isDateCapitalize.value = false
|
||||||
|
viewModel.isDateUppercase.value = true
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
viewModel.isDateCapitalize.value = true
|
||||||
|
viewModel.isDateUppercase.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
action_capitalize.setOnLongClickListener {
|
||||||
|
toast(getString(R.string.action_capitalize_the_date))
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
action_date_format_info.setOnClickListener {
|
action_date_format_info.setOnClickListener {
|
||||||
openURI("https://developer.android.com/reference/java/text/SimpleDateFormat")
|
openURI("https://developer.android.com/reference/java/text/SimpleDateFormat")
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,239 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.activities
|
||||||
|
|
||||||
|
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.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.databinding.DataBindingUtil
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.chibatching.kotpref.blockingBulk
|
||||||
|
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.DateHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.CustomFontViewModel
|
||||||
|
import kotlinx.android.synthetic.main.activity_choose_application.*
|
||||||
|
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
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(this).get(CustomFontViewModel::class.java)
|
||||||
|
val binding = DataBindingUtil.setContentView<ActivityCustomFontBinding>(
|
||||||
|
this,
|
||||||
|
R.layout.activity_custom_font
|
||||||
|
)
|
||||||
|
|
||||||
|
list_view.setHasFixedSize(true)
|
||||||
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
|
list_view.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 { index, 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.filter { !it.contains("italic") }
|
||||||
|
.forEachIndexed { index, s ->
|
||||||
|
dialog.addItem(SettingsStringHelper.getVariantLabel(this, s), index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dialog.addOnSelectItemListener { value ->
|
||||||
|
saveFont(item, value)
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.attachTo(list_view)
|
||||||
|
|
||||||
|
setupListener()
|
||||||
|
subscribeUi(binding, viewModel)
|
||||||
|
|
||||||
|
search.requestFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
private var filterJob: Job? = null
|
||||||
|
|
||||||
|
private fun subscribeUi(binding: ActivityCustomFontBinding, viewModel: CustomFontViewModel) {
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
|
viewModel.fontList.observe(this, Observer {
|
||||||
|
updateList(list = it)
|
||||||
|
loader.visibility = View.INVISIBLE
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.searchInput.observe(this, Observer { search ->
|
||||||
|
updateList(search = search)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateList(
|
||||||
|
list: ArrayList<Font>? = viewModel.fontList.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<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)
|
||||||
|
loader.visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListener() {
|
||||||
|
action_back.setOnClickListener {
|
||||||
|
onBackPressed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
@ -28,6 +28,7 @@ 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.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
|
||||||
@ -62,7 +63,11 @@ 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) {
|
||||||
requirePermission()
|
MaterialBottomSheetDialog(this, message = getString(R.string.background_location_warning))
|
||||||
|
.setPositiveButton(getString(android.R.string.ok)) {
|
||||||
|
requirePermission()
|
||||||
|
}
|
||||||
|
.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.register<Address>(R.layout.custom_location_item) { item, injector ->
|
.register<Address>(R.layout.custom_location_item) { item, injector ->
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.activities
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.databinding.DataBindingUtil
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.ActivityIntegrationsBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.IntegrationsViewModel
|
||||||
|
import kotlinx.android.synthetic.main.activity_integrations.*
|
||||||
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
|
|
||||||
|
class IntegrationsActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private lateinit var adapter: SlimAdapter
|
||||||
|
private lateinit var viewModel: IntegrationsViewModel
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(this).get(IntegrationsViewModel::class.java)
|
||||||
|
val binding = DataBindingUtil.setContentView<ActivityIntegrationsBinding>(this, R.layout.activity_integrations)
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
}
|
||||||
|
.attachTo(list_view)
|
||||||
|
|
||||||
|
setupListener()
|
||||||
|
subscribeUi(binding, viewModel)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun subscribeUi(binding: ActivityIntegrationsBinding, viewModel: IntegrationsViewModel) {
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListener() {
|
||||||
|
action_back.setOnClickListener {
|
||||||
|
onBackPressed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,10 +6,14 @@ 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.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
|
import android.util.DisplayMetrics
|
||||||
|
import android.util.Log
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
@ -20,8 +24,16 @@ 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.navigation.NavController
|
||||||
|
import androidx.navigation.Navigation
|
||||||
|
import com.chibatching.kotpref.Kotpref
|
||||||
import com.google.android.material.badge.BadgeDrawable
|
import com.google.android.material.badge.BadgeDrawable
|
||||||
import com.google.android.material.tabs.TabLayoutMediator
|
import com.google.android.material.tabs.TabLayoutMediator
|
||||||
|
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.R
|
||||||
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
|
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
|
||||||
import com.tommasoberlose.anotherwidget.global.Actions
|
import com.tommasoberlose.anotherwidget.global.Actions
|
||||||
@ -46,10 +58,16 @@ import org.greenrobot.eventbus.Subscribe
|
|||||||
import org.greenrobot.eventbus.ThreadMode
|
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 val mainNavController: NavController? by lazy {
|
||||||
|
Navigation.findNavController(
|
||||||
|
this,
|
||||||
|
R.id.content_fragment
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -58,229 +76,21 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
|
|||||||
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
|
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
|
||||||
|
|
||||||
controlExtras(intent)
|
controlExtras(intent)
|
||||||
|
if (Preferences.showWallpaper) {
|
||||||
// Viewpager
|
requirePermission()
|
||||||
pager.adapter = ViewPagerAdapter(this)
|
|
||||||
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.advanced_settings_title)
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
}.attach()
|
|
||||||
|
|
||||||
// Init clock
|
|
||||||
time.setTextColor(ColorHelper.getFontColor())
|
|
||||||
time.setTextSize(TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(this@MainActivity))
|
|
||||||
time_am_pm.setTextColor(ColorHelper.getFontColor())
|
|
||||||
time_am_pm.setTextSize(TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(this@MainActivity) / 5 * 2)
|
|
||||||
time_container.isVisible = Preferences.showClock
|
|
||||||
|
|
||||||
preview.layoutParams = preview.layoutParams.apply {
|
|
||||||
height = 160.toPixel(this@MainActivity) + if (Preferences.showClock) 100.toPixel(this@MainActivity) else 0
|
|
||||||
}
|
|
||||||
|
|
||||||
Preferences.preferences.registerOnSharedPreferenceChangeListener(this)
|
|
||||||
subscribeUi(viewModel)
|
|
||||||
updateUI()
|
|
||||||
|
|
||||||
WeatherHelper.updateWeather(this)
|
|
||||||
|
|
||||||
|
|
||||||
// Warnings
|
|
||||||
if (getString(R.string.xiaomi_manufacturer).equals(Build.MANUFACTURER, ignoreCase = true) && Preferences.showXiaomiWarning) {
|
|
||||||
MaterialBottomSheetDialog(this, getString(R.string.xiaomi_warning_title), getString(R.string.xiaomi_warning_message))
|
|
||||||
.setNegativeButton(getString(R.string.action_ignore)) {
|
|
||||||
Preferences.showXiaomiWarning = false
|
|
||||||
}
|
|
||||||
.setPositiveButton(getString(R.string.action_grant_permission)) {
|
|
||||||
Preferences.showXiaomiWarning = false
|
|
||||||
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
|
|
||||||
data = Uri.parse("package:$packageName")
|
|
||||||
}
|
|
||||||
startActivity(intent)
|
|
||||||
}
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var uiJob: Job? = null
|
|
||||||
|
|
||||||
private fun updateUI() {
|
|
||||||
uiJob?.cancel()
|
|
||||||
|
|
||||||
if (Preferences.showPreview) {
|
|
||||||
preview.setCardBackgroundColor(
|
|
||||||
getColor(
|
|
||||||
if (ColorHelper.getFontColor()
|
|
||||||
.isColorDark()
|
|
||||||
) android.R.color.white else R.color.colorAccent
|
|
||||||
)
|
|
||||||
)
|
|
||||||
widget_shape_background.setImageDrawable(BitmapHelper.getTintedDrawable(this, R.drawable.card_background, ColorHelper.getBackgroundColor()))
|
|
||||||
uiJob = lifecycleScope.launch(Dispatchers.IO) {
|
|
||||||
delay(200)
|
|
||||||
val generatedView = MainWidget.generateWidgetView(this@MainActivity)
|
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
generatedView.measure(0, 0)
|
|
||||||
preview.measure(0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
val bitmap = BitmapHelper.getBitmapFromView(
|
|
||||||
generatedView,
|
|
||||||
if (preview.width > 0) preview.width else generatedView.measuredWidth,
|
|
||||||
generatedView.measuredHeight
|
|
||||||
)
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
// Clock
|
|
||||||
time.setTextColor(ColorHelper.getFontColor())
|
|
||||||
time_am_pm.setTextColor(ColorHelper.getFontColor())
|
|
||||||
time.setTextSize(
|
|
||||||
TypedValue.COMPLEX_UNIT_SP,
|
|
||||||
Preferences.clockTextSize.toPixel(this@MainActivity)
|
|
||||||
)
|
|
||||||
time_am_pm.setTextSize(
|
|
||||||
TypedValue.COMPLEX_UNIT_SP,
|
|
||||||
Preferences.clockTextSize.toPixel(this@MainActivity) / 5 * 2
|
|
||||||
)
|
|
||||||
|
|
||||||
// Clock bottom margin
|
|
||||||
clock_bottom_margin_none.isVisible =
|
|
||||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.value
|
|
||||||
clock_bottom_margin_small.isVisible =
|
|
||||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.SMALL.value
|
|
||||||
clock_bottom_margin_medium.isVisible =
|
|
||||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.MEDIUM.value
|
|
||||||
clock_bottom_margin_large.isVisible =
|
|
||||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.LARGE.value
|
|
||||||
|
|
||||||
if ((Preferences.showClock && !time_container.isVisible) || (!Preferences.showClock && time_container.isVisible)) {
|
|
||||||
if (Preferences.showClock) {
|
|
||||||
time_container.layoutParams = time_container.layoutParams.apply {
|
|
||||||
height = RelativeLayout.LayoutParams.WRAP_CONTENT
|
|
||||||
}
|
|
||||||
time_container.measure(0, 0)
|
|
||||||
}
|
|
||||||
val initialHeight = time_container.measuredHeight
|
|
||||||
ValueAnimator.ofFloat(
|
|
||||||
if (Preferences.showClock) 0f else 1f,
|
|
||||||
if (Preferences.showClock) 1f else 0f
|
|
||||||
).apply {
|
|
||||||
duration = 500L
|
|
||||||
addUpdateListener {
|
|
||||||
val animatedValue = animatedValue as Float
|
|
||||||
time_container.layoutParams = time_container.layoutParams.apply {
|
|
||||||
height = (initialHeight * animatedValue).toInt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addListener(
|
|
||||||
onStart = {
|
|
||||||
if (Preferences.showClock) {
|
|
||||||
time_container.isVisible = true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onEnd = {
|
|
||||||
if (!Preferences.showClock) {
|
|
||||||
time_container.isVisible = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}.start()
|
|
||||||
|
|
||||||
ValueAnimator.ofInt(
|
|
||||||
preview.height,
|
|
||||||
160.toPixel(this@MainActivity) + if (Preferences.showClock) 100.toPixel(
|
|
||||||
this@MainActivity
|
|
||||||
) else 0
|
|
||||||
).apply {
|
|
||||||
duration = 500L
|
|
||||||
addUpdateListener {
|
|
||||||
val animatedValue = animatedValue as Int
|
|
||||||
val layoutParams = preview.layoutParams
|
|
||||||
layoutParams.height = animatedValue
|
|
||||||
preview.layoutParams = layoutParams
|
|
||||||
}
|
|
||||||
}.start()
|
|
||||||
} else {
|
|
||||||
time_container.layoutParams = time_container.layoutParams.apply {
|
|
||||||
height = RelativeLayout.LayoutParams.WRAP_CONTENT
|
|
||||||
}
|
|
||||||
time_container.measure(0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (preview.height == 0) {
|
|
||||||
ValueAnimator.ofInt(
|
|
||||||
preview.height,
|
|
||||||
160.toPixel(this@MainActivity) + if (Preferences.showClock) 100.toPixel(
|
|
||||||
this@MainActivity
|
|
||||||
) else 0
|
|
||||||
).apply {
|
|
||||||
duration = 300L
|
|
||||||
addUpdateListener {
|
|
||||||
val animatedValue = animatedValue as Int
|
|
||||||
val layoutParams = preview.layoutParams
|
|
||||||
layoutParams.height = animatedValue
|
|
||||||
preview.layoutParams = layoutParams
|
|
||||||
}
|
|
||||||
}.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
bitmap_container.setImageBitmap(bitmap)
|
|
||||||
widget_loader.animate().scaleX(0f).scaleY(0f).start()
|
|
||||||
widget.animate().alpha(1f).start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ValueAnimator.ofInt(
|
|
||||||
preview.height,
|
|
||||||
0
|
|
||||||
).apply {
|
|
||||||
duration = 300L
|
|
||||||
addUpdateListener {
|
|
||||||
val animatedValue = animatedValue as Int
|
|
||||||
val layoutParams = preview.layoutParams
|
|
||||||
layoutParams.height = animatedValue
|
|
||||||
preview.layoutParams = layoutParams
|
|
||||||
}
|
|
||||||
}.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Calendar error indicator
|
|
||||||
tabs.getTabAt(1)?.orCreateBadge?.apply {
|
|
||||||
backgroundColor = ContextCompat.getColor(this@MainActivity, R.color.errorColorText)
|
|
||||||
badgeGravity = BadgeDrawable.TOP_END
|
|
||||||
}?.isVisible = Preferences.showEvents && !checkGrantedPermission(Manifest.permission.READ_CALENDAR)
|
|
||||||
|
|
||||||
// Weather error indicator
|
|
||||||
tabs.getTabAt(2)?.orCreateBadge?.apply {
|
|
||||||
backgroundColor = ContextCompat.getColor(this@MainActivity, R.color.errorColorText)
|
|
||||||
badgeGravity = BadgeDrawable.TOP_END
|
|
||||||
}?.isVisible = Preferences.showWeather && (Preferences.weatherProviderApi == "" || (Preferences.customLocationAdd == "" && !checkGrantedPermission(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACCESS_BACKGROUND_LOCATION else Manifest.permission.ACCESS_FINE_LOCATION)))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun subscribeUi(viewModel: MainViewModel) {
|
|
||||||
viewModel.showWallpaper.observe(this, Observer {
|
|
||||||
widget_bg.setImageDrawable(if (it) getCurrentWallpaper() else null)
|
|
||||||
})
|
|
||||||
|
|
||||||
logo.setOnClickListener {
|
|
||||||
// startActivity(Intent(this, SupportDevActivity::class.java))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
if (mAppWidgetId > 0) {
|
if (mainNavController?.currentDestination?.id == R.id.appMainFragment) {
|
||||||
addNewWidget()
|
if (mAppWidgetId > 0) {
|
||||||
|
addNewWidget()
|
||||||
|
} else {
|
||||||
|
setResult(Activity.RESULT_OK)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
setResult(Activity.RESULT_OK)
|
super.onBackPressed()
|
||||||
finish()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,30 +130,27 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
|
|||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
private fun requirePermission() {
|
||||||
super.onDestroy()
|
Dexter.withContext(this)
|
||||||
Preferences.preferences.unregisterOnSharedPreferenceChangeListener(this)
|
.withPermissions(
|
||||||
}
|
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||||
|
).withListener(object : MultiplePermissionsListener {
|
||||||
|
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
||||||
|
report?.let {
|
||||||
|
Preferences.showWallpaper = false
|
||||||
|
Preferences.showWallpaper = report.areAllPermissionsGranted()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(preferences: SharedPreferences, p1: String) {
|
override fun onPermissionRationaleShouldBeShown(
|
||||||
updateUI()
|
permissions: MutableList<PermissionRequest>?,
|
||||||
MainWidget.updateWidget(this)
|
token: PermissionToken?
|
||||||
}
|
) {
|
||||||
|
// Remember to invoke this method when the custom rationale is closed
|
||||||
override fun onStart() {
|
// or just by default if you don't want to use any custom rationale.
|
||||||
super.onStart()
|
token?.cancelPermissionRequest()
|
||||||
EventBus.getDefault().register(this)
|
}
|
||||||
}
|
})
|
||||||
|
.check()
|
||||||
override fun onStop() {
|
|
||||||
super.onStop()
|
|
||||||
EventBus.getDefault().unregister(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
class UpdateUiMessageEvent
|
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
|
||||||
fun onMessageEvent(ignore: UpdateUiMessageEvent?) {
|
|
||||||
updateUI()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,141 @@
|
|||||||
|
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.databinding.ActivityMusicPlayersFilterBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.ChooseApplicationViewModel
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MusicPlayersFilterViewModel
|
||||||
|
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
|
||||||
|
import kotlin.Comparator as Comparator1
|
||||||
|
|
||||||
|
|
||||||
|
class MusicPlayersFilterActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private lateinit var adapter: SlimAdapter
|
||||||
|
private lateinit var viewModel: MusicPlayersFilterViewModel
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(this).get(MusicPlayersFilterViewModel::class.java)
|
||||||
|
val binding = DataBindingUtil.setContentView<ActivityMusicPlayersFilterBinding>(this, R.layout.activity_music_players_filter)
|
||||||
|
|
||||||
|
list_view.setHasFixedSize(true)
|
||||||
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
|
list_view.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(list_view)
|
||||||
|
|
||||||
|
setupListener()
|
||||||
|
subscribeUi(binding, viewModel)
|
||||||
|
|
||||||
|
search.requestFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
private var filterJob: Job? = null
|
||||||
|
|
||||||
|
private fun subscribeUi(binding: ActivityMusicPlayersFilterBinding, viewModel: MusicPlayersFilterViewModel) {
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
|
viewModel.appList.observe(this, Observer {
|
||||||
|
updateList(list = it)
|
||||||
|
loader.visibility = View.INVISIBLE
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.searchInput.observe(this, Observer { search ->
|
||||||
|
updateList(search = search)
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.musicPlayersFilter.observe(this, {
|
||||||
|
updateList()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}.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)
|
||||||
|
loader.visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListener() {
|
||||||
|
action_back.setOnClickListener {
|
||||||
|
onBackPressed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun toggleApp(app: ResolveInfo) {
|
||||||
|
MediaPlayerHelper.toggleMusicPlayerFilter(app.activityInfo.packageName)
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ import android.location.Address
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
@ -45,8 +46,17 @@ class SupportDevActivity : AppCompatActivity(), PurchasesUpdatedListener {
|
|||||||
adapter = SlimAdapter.create()
|
adapter = SlimAdapter.create()
|
||||||
adapter
|
adapter
|
||||||
.register<SkuDetails>(R.layout.inapp_product_layout) { item, injector ->
|
.register<SkuDetails>(R.layout.inapp_product_layout) { item, injector ->
|
||||||
|
item.sku
|
||||||
injector
|
injector
|
||||||
.text(R.id.product_title, item.title.replace("(Another Widget)", ""))
|
.with<TextView>(R.id.product_title) {
|
||||||
|
it.text = when (item.sku) {
|
||||||
|
"donation_coffee" -> getString(R.string.donation_coffee)
|
||||||
|
"donation_donuts" -> getString(R.string.donation_donuts)
|
||||||
|
"donation_breakfast" -> getString(R.string.donation_breakfast)
|
||||||
|
"donation_lunch" -> getString(R.string.donation_lunch)
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
|
}
|
||||||
.text(R.id.product_price, item.price)
|
.text(R.id.product_price, item.price)
|
||||||
.clicked(R.id.item) {
|
.clicked(R.id.item) {
|
||||||
viewModel.purchase(this, item)
|
viewModel.purchase(this, item)
|
||||||
|
@ -1,42 +1,183 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.activities
|
package com.tommasoberlose.anotherwidget.ui.activities
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.AlertDialog
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.content.pm.ResolveInfo
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Html
|
import android.util.Log
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.core.widget.addTextChangedListener
|
||||||
|
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.snackbar.Snackbar
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||||
|
import com.tommasoberlose.anotherwidget.components.BottomSheetWeatherProviderSettings
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.ActivityChooseApplicationBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.ActivityWeatherProviderBinding
|
||||||
|
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.network.WeatherNetworkApi
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.ChooseApplicationViewModel
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.WeatherProviderViewModel
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.collapse
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.expand
|
||||||
import com.tommasoberlose.anotherwidget.utils.openURI
|
import com.tommasoberlose.anotherwidget.utils.openURI
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.reveal
|
||||||
import kotlinx.android.synthetic.main.activity_weather_provider.*
|
import kotlinx.android.synthetic.main.activity_weather_provider.*
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import org.greenrobot.eventbus.Subscribe
|
||||||
|
import org.greenrobot.eventbus.ThreadMode
|
||||||
|
|
||||||
class WeatherProviderActivity : AppCompatActivity() {
|
class WeatherProviderActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private lateinit var adapter: SlimAdapter
|
||||||
|
private lateinit var viewModel: WeatherProviderViewModel
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_weather_provider)
|
setContentView(R.layout.activity_weather_provider)
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(this).get(WeatherProviderViewModel::class.java)
|
||||||
|
|
||||||
|
list_view.setHasFixedSize(true)
|
||||||
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
|
list_view.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) {
|
||||||
|
val oldValue = Preferences.weatherProvider
|
||||||
|
Preferences.weatherProvider = provider.value
|
||||||
|
updateListItem(oldValue)
|
||||||
|
updateListItem()
|
||||||
|
loader.isVisible = true
|
||||||
|
|
||||||
|
lifecycleScope.launch {
|
||||||
|
WeatherHelper.updateWeather(this@WeatherProviderActivity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.clicked(R.id.radioButton) {
|
||||||
|
val oldValue = Preferences.weatherProvider
|
||||||
|
Preferences.weatherProvider = provider.value
|
||||||
|
updateListItem(oldValue)
|
||||||
|
updateListItem()
|
||||||
|
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 {
|
||||||
|
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 else R.drawable.outline_info_white))
|
||||||
|
}.attachTo(list_view)
|
||||||
|
|
||||||
|
adapter.updateData(
|
||||||
|
Constants.WeatherProvider.values().asList()
|
||||||
|
.filter { it != Constants.WeatherProvider.HERE }
|
||||||
|
.filter { it != Constants.WeatherProvider.ACCUWEATHER }
|
||||||
|
)
|
||||||
|
|
||||||
|
setupListener()
|
||||||
|
subscribeUi(viewModel)
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
||||||
action_back.setOnClickListener {
|
action_back.setOnClickListener {
|
||||||
onBackPressed()
|
onBackPressed()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
action_save.setOnClickListener {
|
override fun onBackPressed() {
|
||||||
Preferences.weatherProviderApi = api_key.editText?.text.toString()
|
setResult(Activity.RESULT_OK)
|
||||||
setResult(Activity.RESULT_OK)
|
finish()
|
||||||
finish()
|
}
|
||||||
}
|
|
||||||
|
|
||||||
action_open_provider.setOnClickListener {
|
override fun onResume() {
|
||||||
openURI("https://home.openweathermap.org/users/sign_up")
|
super.onResume()
|
||||||
}
|
EventBus.getDefault().register(this)
|
||||||
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
override fun onPause() {
|
||||||
last_info.text = Html.fromHtml(getString(R.string.api_key_info_all_set), Html.FROM_HTML_MODE_LEGACY)
|
EventBus.getDefault().unregister(this)
|
||||||
} else {
|
super.onPause()
|
||||||
last_info.text = Html.fromHtml(getString(R.string.api_key_info_all_set))
|
}
|
||||||
|
|
||||||
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
|
fun onMessageEvent(ignore: MainFragment.UpdateUiMessageEvent?) {
|
||||||
|
loader.isVisible = Preferences.weatherProviderError == "-"
|
||||||
|
if (Preferences.weatherProviderError == "" && Preferences.weatherProviderLocationError == "") {
|
||||||
|
Snackbar.make(list_view, getString(R.string.settings_weather_provider_api_key_subtitle_all_set), Snackbar.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
api_key.editText?.setText(Preferences.weatherProviderApi)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 -> CalendarSettingsFragment.newInstance()
|
1 -> CalendarTabFragment.newInstance()
|
||||||
2 -> WeatherSettingsFragment.newInstance()
|
2 -> WeatherTabFragment.newInstance()
|
||||||
3 -> ClockSettingsFragment.newInstance()
|
3 -> ClockTabFragment.newInstance()
|
||||||
4 -> AdvancedSettingsFragment.newInstance()
|
4 -> GlanceTabFragment.newInstance()
|
||||||
else -> GeneralSettingsFragment.newInstance()
|
else -> GeneralTabFragment.newInstance()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,10 +4,10 @@ import android.Manifest
|
|||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.provider.CalendarContract
|
||||||
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 androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.databinding.DataBindingUtil
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
@ -31,22 +31,21 @@ import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity
|
|||||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
||||||
import com.tommasoberlose.anotherwidget.helpers.DateHelper
|
import com.tommasoberlose.anotherwidget.helpers.IntentHelper
|
||||||
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.CustomDateActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.isDefaultSet
|
||||||
import com.tommasoberlose.anotherwidget.utils.toast
|
import com.tommasoberlose.anotherwidget.utils.toast
|
||||||
import kotlinx.android.synthetic.main.fragment_calendar_settings.*
|
import kotlinx.android.synthetic.main.fragment_calendar_settings.*
|
||||||
import kotlinx.android.synthetic.main.fragment_calendar_settings.scrollView
|
import kotlinx.android.synthetic.main.fragment_calendar_settings.scrollView
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.util.*
|
|
||||||
import kotlin.Comparator
|
import kotlin.Comparator
|
||||||
|
|
||||||
class CalendarSettingsFragment : Fragment() {
|
class CalendarTabFragment : Fragment() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun newInstance() = CalendarSettingsFragment()
|
fun newInstance() = CalendarTabFragment()
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var viewModel: MainViewModel
|
private lateinit var viewModel: MainViewModel
|
||||||
@ -74,6 +73,11 @@ class CalendarSettingsFragment : Fragment() {
|
|||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
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()
|
setupListener()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,6 +85,9 @@ class CalendarSettingsFragment : Fragment() {
|
|||||||
binding: FragmentCalendarSettingsBinding,
|
binding: FragmentCalendarSettingsBinding,
|
||||||
viewModel: MainViewModel
|
viewModel: MainViewModel
|
||||||
) {
|
) {
|
||||||
|
binding.isCalendarEnabled = Preferences.showEvents
|
||||||
|
binding.isDiffEnabled = Preferences.showDiffTime || !Preferences.showEvents
|
||||||
|
|
||||||
viewModel.showEvents.observe(viewLifecycleOwner, Observer {
|
viewModel.showEvents.observe(viewLifecycleOwner, Observer {
|
||||||
maintainScrollPosition {
|
maintainScrollPosition {
|
||||||
binding.isCalendarEnabled = it
|
binding.isCalendarEnabled = it
|
||||||
@ -90,23 +97,17 @@ class CalendarSettingsFragment : Fragment() {
|
|||||||
} else {
|
} else {
|
||||||
CalendarHelper.removeEventUpdatesAndroidN(requireContext())
|
CalendarHelper.removeEventUpdatesAndroidN(requireContext())
|
||||||
}
|
}
|
||||||
|
binding.isDiffEnabled = Preferences.showDiffTime || !it
|
||||||
}
|
}
|
||||||
checkReadEventsPermission()
|
checkReadEventsPermission()
|
||||||
|
updateCalendar()
|
||||||
})
|
})
|
||||||
|
|
||||||
viewModel.calendarAllDay.observe(viewLifecycleOwner, Observer {
|
viewModel.calendarAllDay.observe(viewLifecycleOwner, Observer {
|
||||||
maintainScrollPosition {
|
maintainScrollPosition {
|
||||||
all_day_label?.text =
|
all_day_label?.text =
|
||||||
if (it) getString(R.string.settings_all_day_subtitle_visible) else getString(R.string.settings_all_day_subtitle_gone)
|
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||||
}
|
}
|
||||||
checkReadEventsPermission()
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.showDeclinedEvents.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
show_declined_events_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
|
||||||
}
|
|
||||||
checkReadEventsPermission()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
viewModel.secondRowInformation.observe(viewLifecycleOwner, Observer {
|
viewModel.secondRowInformation.observe(viewLifecycleOwner, Observer {
|
||||||
@ -118,6 +119,18 @@ class CalendarSettingsFragment : Fragment() {
|
|||||||
viewModel.showDiffTime.observe(viewLifecycleOwner, Observer {
|
viewModel.showDiffTime.observe(viewLifecycleOwner, Observer {
|
||||||
maintainScrollPosition {
|
maintainScrollPosition {
|
||||||
show_diff_time_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
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 -> ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -125,22 +138,30 @@ class CalendarSettingsFragment : Fragment() {
|
|||||||
maintainScrollPosition {
|
maintainScrollPosition {
|
||||||
show_until_label?.text = getString(SettingsStringHelper.getShowUntilString(it))
|
show_until_label?.text = getString(SettingsStringHelper.getShowUntilString(it))
|
||||||
}
|
}
|
||||||
checkReadEventsPermission()
|
updateCalendar()
|
||||||
})
|
})
|
||||||
|
|
||||||
viewModel.showNextEvent.observe(viewLifecycleOwner, Observer {
|
viewModel.showNextEvent.observe(viewLifecycleOwner, Observer {
|
||||||
show_multiple_events_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.dateFormat.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
maintainScrollPosition {
|
||||||
date_format_label?.text = DateHelper.getDateText(requireContext(), Calendar.getInstance())
|
show_multiple_events_label?.text =
|
||||||
|
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
viewModel.calendarAppName.observe(viewLifecycleOwner, Observer {
|
viewModel.calendarAppName.observe(viewLifecycleOwner, Observer {
|
||||||
maintainScrollPosition {
|
maintainScrollPosition {
|
||||||
calendar_app_label?.text = if (it != "") it else getString(R.string.default_calendar_app)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -156,6 +177,16 @@ class CalendarSettingsFragment : Fragment() {
|
|||||||
|
|
||||||
action_show_events.setOnClickListener {
|
action_show_events.setOnClickListener {
|
||||||
Preferences.showEvents = !Preferences.showEvents
|
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 {
|
action_filter_calendar.setOnClickListener {
|
||||||
@ -195,14 +226,14 @@ class CalendarSettingsFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dialog.addItem(
|
dialog.addItem(
|
||||||
if (calendarSelectorList[index].name == calendarSelectorList[index].accountName) getString(R.string.account_events) else calendarSelectorList[index].name,
|
if (calendarSelectorList[index].name == calendarSelectorList[index].accountName) getString(R.string.main_calendar) else calendarSelectorList[index].name,
|
||||||
calendarSelectorList[index].id
|
calendarSelectorList[index].id
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog.addOnMultipleSelectItemListener { values ->
|
dialog.addOnMultipleSelectItemListener { values ->
|
||||||
CalendarHelper.filterCalendar(calendarSelectorList.map { it.id }.filter { !values.contains(it) })
|
CalendarHelper.filterCalendar(calendarSelectorList.map { it.id }.filter { !values.contains(it) })
|
||||||
checkReadEventsPermission()
|
updateCalendar()
|
||||||
}.show()
|
}.show()
|
||||||
} else {
|
} else {
|
||||||
activity?.toast(getString(R.string.calendar_settings_list_error))
|
activity?.toast(getString(R.string.calendar_settings_list_error))
|
||||||
@ -211,44 +242,100 @@ class CalendarSettingsFragment : Fragment() {
|
|||||||
|
|
||||||
action_show_all_day.setOnClickListener {
|
action_show_all_day.setOnClickListener {
|
||||||
if (Preferences.showEvents) {
|
if (Preferences.showEvents) {
|
||||||
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_all_day_title)).setSelectedValue(Preferences.calendarAllDay)
|
show_all_day_toggle.isChecked = !show_all_day_toggle.isChecked
|
||||||
.addItem(getString(R.string.settings_all_day_subtitle_visible), true)
|
|
||||||
.addItem(getString(R.string.settings_all_day_subtitle_gone), false)
|
|
||||||
.addOnSelectItemListener { value ->
|
|
||||||
Preferences.calendarAllDay = value
|
|
||||||
}.show()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
action_show_declined_events.setOnClickListener {
|
show_all_day_toggle.setOnCheckedChangeListener { _, isChecked ->
|
||||||
if (Preferences.showEvents) {
|
if (Preferences.showEvents) {
|
||||||
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_show_declined_events_title)).setSelectedValue(Preferences.showDeclinedEvents)
|
Preferences.calendarAllDay = isChecked
|
||||||
.addItem(getString(R.string.settings_visible), true)
|
updateCalendar()
|
||||||
.addItem(getString(R.string.settings_not_visible), false)
|
}
|
||||||
.addOnSelectItemListener { value ->
|
}
|
||||||
Preferences.showDeclinedEvents = value
|
|
||||||
}.show()
|
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 {
|
action_show_multiple_events.setOnClickListener {
|
||||||
if (Preferences.showEvents) {
|
if (Preferences.showEvents) {
|
||||||
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_show_multiple_events_title)).setSelectedValue(Preferences.showNextEvent)
|
show_multiple_events_toggle.isChecked = !show_multiple_events_toggle.isChecked
|
||||||
.addItem(getString(R.string.settings_visible), true)
|
}
|
||||||
.addItem(getString(R.string.settings_not_visible), false)
|
}
|
||||||
.addOnSelectItemListener { value ->
|
|
||||||
Preferences.showNextEvent = value
|
show_multiple_events_toggle.setOnCheckedChangeListener { _, isChecked ->
|
||||||
}.show()
|
if (Preferences.showEvents) {
|
||||||
|
Preferences.showNextEvent = isChecked
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
action_show_diff_time.setOnClickListener {
|
action_show_diff_time.setOnClickListener {
|
||||||
if (Preferences.showEvents) {
|
if (Preferences.showEvents) {
|
||||||
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_show_diff_time_title)).setSelectedValue(Preferences.showDiffTime)
|
show_diff_time_toggle.isChecked = !show_diff_time_toggle.isChecked
|
||||||
.addItem(getString(R.string.settings_visible), true)
|
}
|
||||||
.addItem(getString(R.string.settings_not_visible), false)
|
}
|
||||||
|
|
||||||
|
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 ->
|
.addOnSelectItemListener { value ->
|
||||||
Preferences.showDiffTime = value
|
Preferences.widgetUpdateFrequency = value
|
||||||
}.show()
|
}.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -268,7 +355,7 @@ class CalendarSettingsFragment : Fragment() {
|
|||||||
action_show_until.setOnClickListener {
|
action_show_until.setOnClickListener {
|
||||||
if (Preferences.showEvents) {
|
if (Preferences.showEvents) {
|
||||||
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_show_until_title)).setSelectedValue(Preferences.showUntil)
|
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 {
|
intArrayOf(6,7,0,1,2,3, 4, 5).forEach {
|
||||||
dialog.addItem(getString(SettingsStringHelper.getShowUntilString(it)), it)
|
dialog.addItem(getString(SettingsStringHelper.getShowUntilString(it)), it)
|
||||||
}
|
}
|
||||||
dialog.addOnSelectItemListener { value ->
|
dialog.addOnSelectItemListener { value ->
|
||||||
@ -277,27 +364,6 @@ class CalendarSettingsFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
action_date_format.setOnClickListener {
|
|
||||||
if (Preferences.showEvents) {
|
|
||||||
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 ->
|
|
||||||
if (value == "-") {
|
|
||||||
startActivity(Intent(requireContext(), CustomDateActivity::class.java))
|
|
||||||
} else {
|
|
||||||
Preferences.dateFormat = value
|
|
||||||
}
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_open_event_details.setOnClickListener {
|
action_open_event_details.setOnClickListener {
|
||||||
if (Preferences.showEvents) {
|
if (Preferences.showEvents) {
|
||||||
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_event_app_title)).setSelectedValue(Preferences.openEventDetails)
|
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_event_app_title)).setSelectedValue(Preferences.openEventDetails)
|
||||||
@ -318,7 +384,6 @@ class CalendarSettingsFragment : Fragment() {
|
|||||||
if (activity?.checkGrantedPermission(Manifest.permission.READ_CALENDAR) == true) {
|
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)
|
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
|
read_calendar_permission_alert?.isVisible = false
|
||||||
CalendarHelper.updateEventList(requireContext())
|
|
||||||
} else {
|
} else {
|
||||||
show_events_label?.text = if (showEvents) getString(R.string.description_permission_calendar) else getString(R.string.show_events_not_visible)
|
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?.isVisible = showEvents
|
||||||
@ -328,6 +393,12 @@ class CalendarSettingsFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateCalendar() {
|
||||||
|
if (activity?.checkGrantedPermission(Manifest.permission.READ_CALENDAR) == true) {
|
||||||
|
CalendarHelper.updateEventList(requireContext())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun requirePermission() {
|
private fun requirePermission() {
|
||||||
Dexter.withContext(requireContext())
|
Dexter.withContext(requireContext())
|
||||||
.withPermissions(
|
.withPermissions(
|
||||||
@ -337,6 +408,8 @@ class CalendarSettingsFragment : Fragment() {
|
|||||||
report?.let {
|
report?.let {
|
||||||
if (report.areAllPermissionsGranted()){
|
if (report.areAllPermissionsGranted()){
|
||||||
checkReadEventsPermission()
|
checkReadEventsPermission()
|
||||||
|
} else {
|
||||||
|
Preferences.showEvents = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -373,11 +446,11 @@ class CalendarSettingsFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||||
val scrollPosition = scrollView.scrollY
|
scrollView.isScrollable = false
|
||||||
callback.invoke()
|
callback.invoke()
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
delay(200)
|
delay(200)
|
||||||
scrollView.smoothScrollTo(0, scrollPosition)
|
scrollView.isScrollable = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,220 +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.ApplicationInfo
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.databinding.DataBindingUtil
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.lifecycle.Observer
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import com.chibatching.kotpref.bulk
|
|
||||||
import com.tommasoberlose.anotherwidget.R
|
|
||||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
|
||||||
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.ui.activities.ChooseApplicationActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
|
||||||
import com.tommasoberlose.anotherwidget.utils.toast
|
|
||||||
import kotlinx.android.synthetic.main.fragment_clock_settings.*
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import java.lang.Exception
|
|
||||||
|
|
||||||
|
|
||||||
class ClockSettingsFragment : Fragment() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun newInstance() = ClockSettingsFragment()
|
|
||||||
}
|
|
||||||
|
|
||||||
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<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)
|
|
||||||
|
|
||||||
setupListener()
|
|
||||||
updateNextAlarmWarningUi()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun subscribeUi(
|
|
||||||
binding: FragmentClockSettingsBinding,
|
|
||||||
viewModel: MainViewModel
|
|
||||||
) {
|
|
||||||
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.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.showNextAlarm.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
show_next_alarm_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.clockAppName.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
clock_app_label?.text =
|
|
||||||
if (Preferences.clockAppName != "") Preferences.clockAppName else getString(R.string.default_clock_app)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupListener() {
|
|
||||||
action_hide_large_clock_warning.setOnClickListener {
|
|
||||||
Preferences.showBigClockWarning = false
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_clock.setOnClickListener {
|
|
||||||
Preferences.showClock = !Preferences.showClock
|
|
||||||
}
|
|
||||||
|
|
||||||
action_clock_text_size.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()
|
|
||||||
}
|
|
||||||
|
|
||||||
action_clock_bottom_margin_size.setOnClickListener {
|
|
||||||
BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_show_next_alarm_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) {
|
|
||||||
startActivityForResult(Intent(requireContext(), ChooseApplicationActivity::class.java),
|
|
||||||
RequestCode.CLOCK_APP_REQUEST_CODE.code
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_next_alarm.setOnClickListener {
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateNextAlarmWarningUi() {
|
|
||||||
show_next_alarm_warning.isVisible = AlarmHelper.isAlarmProbablyWrong(requireContext())
|
|
||||||
with(requireContext().getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
|
||||||
val alarm = nextAlarmClock
|
|
||||||
if (alarm != null) {
|
|
||||||
val pm = requireContext().packageManager as PackageManager
|
|
||||||
val appNameOrPackage = try {
|
|
||||||
pm.getApplicationLabel(pm.getApplicationInfo(nextAlarmClock.showIntent.creatorPackage ?: "", 0))
|
|
||||||
} catch (e: Exception) {
|
|
||||||
nextAlarmClock.showIntent.creatorPackage
|
|
||||||
}
|
|
||||||
show_next_alarm_warning.text = getString(R.string.next_alarm_warning).format(appNameOrPackage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
|
||||||
val scrollPosition = scrollView.scrollY
|
|
||||||
callback.invoke()
|
|
||||||
lifecycleScope.launch {
|
|
||||||
delay(200)
|
|
||||||
scrollView.smoothScrollTo(0, scrollPosition)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,331 @@
|
|||||||
|
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,268 +0,0 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.fragments
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Intent
|
|
||||||
import android.graphics.Color
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.util.Log
|
|
||||||
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.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.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.SettingsStringHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
|
||||||
import kotlinx.android.synthetic.main.fragment_general_settings.*
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
|
|
||||||
|
|
||||||
class GeneralSettingsFragment : Fragment() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun newInstance() = GeneralSettingsFragment()
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
|
||||||
super.onActivityCreated(savedInstanceState)
|
|
||||||
|
|
||||||
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())).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())).toUpperCase()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
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())).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())).toUpperCase()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.textShadow.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
text_shadow_label?.text = getString(SettingsStringHelper.getTextShadowString(it))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.customFont.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
|
||||||
custom_font_label?.text = getString(SettingsStringHelper.getCustomFontLabel(it))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
|
||||||
val scrollPosition = scrollView.scrollY
|
|
||||||
callback.invoke()
|
|
||||||
lifecycleScope.launch {
|
|
||||||
delay(200)
|
|
||||||
scrollView.smoothScrollTo(0, scrollPosition)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupListener() {
|
|
||||||
action_main_text_size.setOnClickListener {
|
|
||||||
val dialog = BottomSheetMenu<Float>(requireContext(), header = getString(R.string.title_main_text_size)).setSelectedValue(Preferences.textMainSize)
|
|
||||||
(32 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)
|
|
||||||
(28 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),
|
|
||||||
selected = ColorHelper.getFontColor(),
|
|
||||||
onColorSelected = { color: Int ->
|
|
||||||
val colorString = Integer.toHexString(color)
|
|
||||||
Preferences.textGlobalColor = "#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
|
||||||
},
|
|
||||||
showAlphaSelector = true,
|
|
||||||
alpha = Preferences.textGlobalAlpha.toIntValue(),
|
|
||||||
onAlphaChangeListener = { alpha ->
|
|
||||||
Preferences.textGlobalAlpha = alpha.toHexValue()
|
|
||||||
}
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
|
|
||||||
action_background_color.setOnClickListener {
|
|
||||||
BottomSheetColorPicker(requireContext(),
|
|
||||||
colors = colors,
|
|
||||||
header = getString(R.string.settings_background_color_title),
|
|
||||||
selected = ColorHelper.getBackgroundColor(),
|
|
||||||
onColorSelected = { color: Int ->
|
|
||||||
val colorString = Integer.toHexString(color)
|
|
||||||
Preferences.backgroundCardColor = "#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
|
||||||
},
|
|
||||||
showAlphaSelector = true,
|
|
||||||
alpha = Preferences.backgroundCardAlpha.toIntValue(),
|
|
||||||
onAlphaChangeListener = { alpha ->
|
|
||||||
Preferences.backgroundCardAlpha = alpha.toHexValue()
|
|
||||||
}
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
|
|
||||||
action_text_shadow.setOnClickListener {
|
|
||||||
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.title_text_shadow)).setSelectedValue(Preferences.textShadow)
|
|
||||||
(2 downTo 0).forEach {
|
|
||||||
dialog.addItem(getString(SettingsStringHelper.getTextShadowString(it)), it)
|
|
||||||
}
|
|
||||||
dialog.addOnSelectItemListener { value ->
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,535 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.fragments
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import android.graphics.Typeface
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.HandlerThread
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.core.provider.FontRequest
|
||||||
|
import androidx.core.provider.FontsContractCompat
|
||||||
|
import androidx.databinding.DataBindingUtil
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.chibatching.kotpref.blockingBulk
|
||||||
|
import com.chibatching.kotpref.bulk
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker
|
||||||
|
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.FragmentGeneralSettingsBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.global.RequestCode
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toHexValue
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.DateHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.WidgetHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.CustomDateActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.CustomFontActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||||
|
import kotlinx.android.synthetic.main.fragment_clock_settings.*
|
||||||
|
import kotlinx.android.synthetic.main.fragment_general_settings.*
|
||||||
|
import kotlinx.android.synthetic.main.fragment_general_settings.scrollView
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
class GeneralTabFragment : Fragment() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance() = GeneralTabFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var viewModel: MainViewModel
|
||||||
|
private lateinit var colors: IntArray
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||||
|
val binding = DataBindingUtil.inflate<FragmentGeneralSettingsBinding>(inflater, R.layout.fragment_general_settings, container, false)
|
||||||
|
|
||||||
|
subscribeUi(viewModel)
|
||||||
|
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
binding.isDarkModeEnabled = activity?.isDarkTheme() == true
|
||||||
|
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
|
show_dividers_toggle.isChecked = Preferences.showDividers
|
||||||
|
|
||||||
|
setupListener()
|
||||||
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
val lazyColors = requireContext().resources.getIntArray(R.array.material_colors)
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
colors = lazyColors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressLint("DefaultLocale")
|
||||||
|
private fun subscribeUi(
|
||||||
|
viewModel: MainViewModel
|
||||||
|
) {
|
||||||
|
|
||||||
|
viewModel.textMainSize.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
main_text_size_label?.text = String.format("%.0fsp", it)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.textSecondSize.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
second_text_size_label?.text = String.format("%.0fsp", it)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.textGlobalColor.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
if (Preferences.textGlobalAlpha == "00") {
|
||||||
|
font_color_label?.text = getString(R.string.transparent)
|
||||||
|
} else {
|
||||||
|
font_color_label?.text =
|
||||||
|
"#%s".format(Integer.toHexString(ColorHelper.getFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.textGlobalColorDark.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
if (Preferences.textGlobalAlphaDark == "00") {
|
||||||
|
font_color_label?.text = getString(R.string.transparent)
|
||||||
|
} else {
|
||||||
|
font_color_label?.text =
|
||||||
|
"#%s".format(Integer.toHexString(ColorHelper.getFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.textGlobalAlpha.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
if (Preferences.textGlobalAlpha == "00") {
|
||||||
|
font_color_label?.text = getString(R.string.transparent)
|
||||||
|
} else {
|
||||||
|
font_color_label?.text =
|
||||||
|
"#%s".format(Integer.toHexString(ColorHelper.getFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.textGlobalAlphaDark.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
if (Preferences.textGlobalAlphaDark == "00") {
|
||||||
|
font_color_label?.text = getString(R.string.transparent)
|
||||||
|
} else {
|
||||||
|
font_color_label?.text =
|
||||||
|
"#%s".format(Integer.toHexString(ColorHelper.getFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.textSecondaryColor.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
if (Preferences.textSecondaryAlpha == "00") {
|
||||||
|
secondary_font_color_label?.text = getString(R.string.transparent)
|
||||||
|
} else {
|
||||||
|
secondary_font_color_label?.text =
|
||||||
|
"#%s".format(Integer.toHexString(ColorHelper.getSecondaryFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.textSecondaryColorDark.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
if (Preferences.textSecondaryAlphaDark == "00") {
|
||||||
|
secondary_font_color_label?.text = getString(R.string.transparent)
|
||||||
|
} else {
|
||||||
|
secondary_font_color_label?.text =
|
||||||
|
"#%s".format(Integer.toHexString(ColorHelper.getSecondaryFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.textSecondaryAlpha.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
if (Preferences.textSecondaryAlpha == "00") {
|
||||||
|
secondary_font_color_label?.text = getString(R.string.transparent)
|
||||||
|
} else {
|
||||||
|
secondary_font_color_label?.text =
|
||||||
|
"#%s".format(Integer.toHexString(ColorHelper.getSecondaryFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.textSecondaryAlphaDark.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
if (Preferences.textSecondaryAlphaDark == "00") {
|
||||||
|
secondary_font_color_label?.text = getString(R.string.transparent)
|
||||||
|
} else {
|
||||||
|
secondary_font_color_label?.text =
|
||||||
|
"#%s".format(Integer.toHexString(ColorHelper.getSecondaryFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.secondRowTopMargin.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
second_row_top_margin_label?.text = when (it) {
|
||||||
|
Constants.SecondRowTopMargin.NONE.value -> getString(R.string.settings_clock_bottom_margin_subtitle_none)
|
||||||
|
Constants.SecondRowTopMargin.SMALL.value -> getString(R.string.settings_clock_bottom_margin_subtitle_small)
|
||||||
|
Constants.SecondRowTopMargin.LARGE.value -> getString(R.string.settings_clock_bottom_margin_subtitle_large)
|
||||||
|
else -> getString(R.string.settings_clock_bottom_margin_subtitle_medium)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.backgroundCardColor.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
if (Preferences.backgroundCardAlpha == "00") {
|
||||||
|
background_color_label?.text = getString(R.string.transparent)
|
||||||
|
} else {
|
||||||
|
background_color_label?.text =
|
||||||
|
"#%s".format(Integer.toHexString(ColorHelper.getBackgroundColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.backgroundCardColorDark.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
if (Preferences.backgroundCardAlphaDark == "00") {
|
||||||
|
background_color_label?.text = getString(R.string.transparent)
|
||||||
|
} else {
|
||||||
|
background_color_label?.text =
|
||||||
|
"#%s".format(Integer.toHexString(ColorHelper.getBackgroundColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.backgroundCardAlpha.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
if (Preferences.backgroundCardAlpha == "00") {
|
||||||
|
background_color_label?.text = getString(R.string.transparent)
|
||||||
|
} else {
|
||||||
|
background_color_label?.text =
|
||||||
|
"#%s".format(Integer.toHexString(ColorHelper.getBackgroundColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.backgroundCardAlphaDark.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
if (Preferences.backgroundCardAlphaDark == "00") {
|
||||||
|
background_color_label?.text = getString(R.string.transparent)
|
||||||
|
} else {
|
||||||
|
background_color_label?.text =
|
||||||
|
"#%s".format(Integer.toHexString(ColorHelper.getBackgroundColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.textShadow.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
if (activity?.isDarkTheme() != true) {
|
||||||
|
text_shadow_label?.text =
|
||||||
|
getString(SettingsStringHelper.getTextShadowString(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.textShadowDark.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
if (activity?.isDarkTheme() == true) {
|
||||||
|
text_shadow_label?.text =
|
||||||
|
getString(SettingsStringHelper.getTextShadowString(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.dateFormat.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
date_format_label?.text = DateHelper.getDateText(requireContext(), Calendar.getInstance())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.customFont.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
custom_font_label?.text = SettingsStringHelper.getCustomFontLabel(requireContext(), it)
|
||||||
|
MainWidget.updateWidget(requireContext())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.customFontFile.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
custom_font_label?.text = SettingsStringHelper.getCustomFontLabel(requireContext(), Preferences.customFont)
|
||||||
|
MainWidget.updateWidget(requireContext())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.customFontName.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
custom_font_label?.text = SettingsStringHelper.getCustomFontLabel(requireContext(), Preferences.customFont)
|
||||||
|
MainWidget.updateWidget(requireContext())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.customFontVariant.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
custom_font_label?.text = SettingsStringHelper.getCustomFontLabel(requireContext(), Preferences.customFont)
|
||||||
|
MainWidget.updateWidget(requireContext())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.showDividers.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
show_dividers_label?.text =
|
||||||
|
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListener() {
|
||||||
|
action_main_text_size.setOnClickListener {
|
||||||
|
val dialog = BottomSheetMenu<Float>(requireContext(), header = getString(R.string.title_main_text_size)).setSelectedValue(Preferences.textMainSize)
|
||||||
|
(40 downTo 10).filter { it % 2 == 0 }.forEach {
|
||||||
|
dialog.addItem("${it}sp", it.toFloat())
|
||||||
|
}
|
||||||
|
dialog.addOnSelectItemListener { value ->
|
||||||
|
Preferences.textMainSize = value
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
action_second_text_size.setOnClickListener {
|
||||||
|
val dialog = BottomSheetMenu<Float>(requireContext(), header = getString(R.string.title_second_text_size)).setSelectedValue(Preferences.textSecondSize)
|
||||||
|
(40 downTo 10).filter { it % 2 == 0 }.forEach {
|
||||||
|
dialog.addItem("${it}sp", it.toFloat())
|
||||||
|
}
|
||||||
|
dialog.addOnSelectItemListener { value ->
|
||||||
|
Preferences.textSecondSize = value
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
action_font_color.setOnClickListener {
|
||||||
|
BottomSheetColorPicker(requireContext(),
|
||||||
|
colors = colors,
|
||||||
|
header = getString(R.string.settings_font_color_title),
|
||||||
|
getSelected = { ColorHelper.getFontColorRgb(activity?.isDarkTheme() == true) },
|
||||||
|
onColorSelected = { color: Int ->
|
||||||
|
val colorString = Integer.toHexString(color)
|
||||||
|
if (activity?.isDarkTheme() == true) {
|
||||||
|
Preferences.textGlobalColorDark = "#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||||
|
} else {
|
||||||
|
Preferences.textGlobalColor = "#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showAlphaSelector = true,
|
||||||
|
alpha = if (activity?.isDarkTheme() == true) Preferences.textGlobalAlphaDark.toIntValue() else Preferences.textGlobalAlpha.toIntValue(),
|
||||||
|
onAlphaChangeListener = { alpha ->
|
||||||
|
if (activity?.isDarkTheme() == true) {
|
||||||
|
Preferences.textGlobalAlphaDark = alpha.toHexValue()
|
||||||
|
} else {
|
||||||
|
Preferences.textGlobalAlpha = alpha.toHexValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
action_secondary_font_color.setOnClickListener {
|
||||||
|
BottomSheetColorPicker(requireContext(),
|
||||||
|
colors = colors,
|
||||||
|
header = getString(R.string.settings_secondary_font_color_title),
|
||||||
|
getSelected = { ColorHelper.getSecondaryFontColorRgb(activity?.isDarkTheme() == true) },
|
||||||
|
onColorSelected = { color: Int ->
|
||||||
|
val colorString = Integer.toHexString(color)
|
||||||
|
if (activity?.isDarkTheme() == true) {
|
||||||
|
Preferences.textSecondaryColorDark =
|
||||||
|
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||||
|
} else {
|
||||||
|
Preferences.textSecondaryColor =
|
||||||
|
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showAlphaSelector = true,
|
||||||
|
alpha = if (activity?.isDarkTheme() == true) Preferences.textSecondaryAlphaDark.toIntValue() else Preferences.textSecondaryAlpha.toIntValue(),
|
||||||
|
onAlphaChangeListener = { alpha ->
|
||||||
|
if (activity?.isDarkTheme() == true) {
|
||||||
|
Preferences.textSecondaryAlphaDark = alpha.toHexValue()
|
||||||
|
} else {
|
||||||
|
Preferences.textSecondaryAlpha = alpha.toHexValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
action_second_row_top_margin_size.setOnClickListener {
|
||||||
|
BottomSheetMenu<Int>(
|
||||||
|
requireContext(),
|
||||||
|
header = getString(R.string.settings_secondary_row_top_margin_title)
|
||||||
|
).setSelectedValue(Preferences.secondRowTopMargin)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_clock_bottom_margin_subtitle_none),
|
||||||
|
Constants.SecondRowTopMargin.NONE.value
|
||||||
|
)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_clock_bottom_margin_subtitle_small),
|
||||||
|
Constants.SecondRowTopMargin.SMALL.value
|
||||||
|
)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_clock_bottom_margin_subtitle_medium),
|
||||||
|
Constants.SecondRowTopMargin.MEDIUM.value
|
||||||
|
)
|
||||||
|
.addItem(
|
||||||
|
getString(R.string.settings_clock_bottom_margin_subtitle_large),
|
||||||
|
Constants.SecondRowTopMargin.LARGE.value
|
||||||
|
)
|
||||||
|
.addOnSelectItemListener { value ->
|
||||||
|
Preferences.secondRowTopMargin = value
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
action_date_format.setOnClickListener {
|
||||||
|
val now = Calendar.getInstance()
|
||||||
|
val dialog = BottomSheetMenu<String>(requireContext(), header = getString(R.string.settings_date_format_title)).setSelectedValue(Preferences.dateFormat)
|
||||||
|
|
||||||
|
dialog.addItem(DateHelper.getDefaultDateText(requireContext(), now), "")
|
||||||
|
if (Preferences.dateFormat != "") {
|
||||||
|
dialog.addItem(DateHelper.getDateText(requireContext(), now), Preferences.dateFormat)
|
||||||
|
}
|
||||||
|
dialog.addItem(getString(R.string.custom_date_format), "-")
|
||||||
|
|
||||||
|
dialog.addOnSelectItemListener { value ->
|
||||||
|
when (value) {
|
||||||
|
"-" -> {
|
||||||
|
startActivity(Intent(requireContext(), CustomDateActivity::class.java))
|
||||||
|
}
|
||||||
|
"" -> {
|
||||||
|
Preferences.blockingBulk {
|
||||||
|
isDateCapitalize = false
|
||||||
|
isDateUppercase = false
|
||||||
|
}
|
||||||
|
Preferences.dateFormat = value
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Preferences.dateFormat = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
action_background_color.setOnClickListener {
|
||||||
|
BottomSheetColorPicker(requireContext(),
|
||||||
|
colors = colors,
|
||||||
|
header = getString(R.string.settings_background_color_title),
|
||||||
|
getSelected = { ColorHelper.getBackgroundColorRgb(activity?.isDarkTheme() == true) },
|
||||||
|
onColorSelected = { color: Int ->
|
||||||
|
val colorString = Integer.toHexString(color)
|
||||||
|
if (activity?.isDarkTheme() == true) {
|
||||||
|
Preferences.backgroundCardColorDark =
|
||||||
|
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||||
|
} else {
|
||||||
|
Preferences.backgroundCardColor =
|
||||||
|
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showAlphaSelector = true,
|
||||||
|
alpha = if (activity?.isDarkTheme() == true) Preferences.backgroundCardAlphaDark.toIntValue() else Preferences.backgroundCardAlpha.toIntValue(),
|
||||||
|
onAlphaChangeListener = { alpha ->
|
||||||
|
if (activity?.isDarkTheme() == true) {
|
||||||
|
Preferences.backgroundCardAlphaDark = alpha.toHexValue()
|
||||||
|
} else {
|
||||||
|
Preferences.backgroundCardAlpha = alpha.toHexValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
action_text_shadow.setOnClickListener {
|
||||||
|
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.title_text_shadow)).setSelectedValue(if (activity?.isDarkTheme() == true) Preferences.textShadowDark else Preferences.textShadow)
|
||||||
|
(2 downTo 0).forEach {
|
||||||
|
dialog.addItem(getString(SettingsStringHelper.getTextShadowString(it)), it)
|
||||||
|
}
|
||||||
|
dialog.addOnSelectItemListener { value ->
|
||||||
|
if (activity?.isDarkTheme() == true) {
|
||||||
|
Preferences.textShadowDark = value
|
||||||
|
} else {
|
||||||
|
Preferences.textShadow = value
|
||||||
|
}
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
action_custom_font.setOnClickListener {
|
||||||
|
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_custom_font_title)).setSelectedValue(Preferences.customFont)
|
||||||
|
dialog.addItem(SettingsStringHelper.getCustomFontLabel(requireContext(), 0), 0)
|
||||||
|
|
||||||
|
if (Preferences.customFont == Constants.CUSTOM_FONT_GOOGLE_SANS) {
|
||||||
|
dialog.addItem(SettingsStringHelper.getCustomFontLabel(requireContext(), Constants.CUSTOM_FONT_GOOGLE_SANS), Constants.CUSTOM_FONT_GOOGLE_SANS)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Preferences.customFontFile != "") {
|
||||||
|
dialog.addItem(SettingsStringHelper.getCustomFontLabel(requireContext(), Preferences.customFont), Constants.CUSTOM_FONT_DOWNLOADED)
|
||||||
|
}
|
||||||
|
dialog.addItem(getString(R.string.action_custom_font_to_search), Constants.CUSTOM_FONT_DOWNLOAD_NEW)
|
||||||
|
dialog.addOnSelectItemListener { value ->
|
||||||
|
if (value == Constants.CUSTOM_FONT_DOWNLOAD_NEW) {
|
||||||
|
startActivityForResult(
|
||||||
|
Intent(requireContext(), CustomFontActivity::class.java),
|
||||||
|
RequestCode.CUSTOM_FONT_CHOOSER_REQUEST_CODE.code
|
||||||
|
)
|
||||||
|
} else if (value != Constants.CUSTOM_FONT_DOWNLOADED) {
|
||||||
|
Preferences.bulk {
|
||||||
|
customFont = value
|
||||||
|
customFontFile = ""
|
||||||
|
customFontName = ""
|
||||||
|
customFontVariant = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
action_show_dividers.setOnClickListener {
|
||||||
|
show_dividers_toggle.isChecked = !show_dividers_toggle.isChecked
|
||||||
|
}
|
||||||
|
|
||||||
|
show_dividers_toggle.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
Preferences.showDividers = isChecked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||||
|
scrollView.isScrollable = false
|
||||||
|
callback.invoke()
|
||||||
|
lifecycleScope.launch {
|
||||||
|
delay(200)
|
||||||
|
scrollView.isScrollable = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,405 @@
|
|||||||
|
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.activities.MusicPlayersFilterActivity
|
||||||
|
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
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.musicPlayersFilter.observe(viewLifecycleOwner, Observer {
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
action_filter_music_players.setOnClickListener {
|
||||||
|
startActivity(Intent(requireContext(), MusicPlayersFilterActivity::class.java))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,408 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.fragments
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.animation.ValueAnimator
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.provider.Settings
|
||||||
|
import android.util.DisplayMetrics
|
||||||
|
import android.util.TypedValue
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.RelativeLayout
|
||||||
|
import androidx.core.animation.addListener
|
||||||
|
import androidx.core.app.NotificationManagerCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.navigation.Navigation
|
||||||
|
import com.google.android.material.badge.BadgeDrawable
|
||||||
|
import com.google.android.material.tabs.TabLayoutMediator
|
||||||
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.BitmapHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.WidgetHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.adapters.ViewPagerAdapter
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.*
|
||||||
|
import kotlinx.android.synthetic.main.fragment_app_main.*
|
||||||
|
import kotlinx.android.synthetic.main.the_widget_sans.*
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import org.greenrobot.eventbus.Subscribe
|
||||||
|
import org.greenrobot.eventbus.ThreadMode
|
||||||
|
|
||||||
|
class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance() = MainFragment()
|
||||||
|
private const val PREVIEW_BASE_HEIGHT = 120
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var viewModel: MainViewModel
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||||
|
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||||
|
return inflater.inflate(R.layout.fragment_app_main, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
if (getString(R.string.xiaomi_manufacturer).equals(Build.MANUFACTURER, ignoreCase = true) && Preferences.showXiaomiWarning) {
|
||||||
|
MaterialBottomSheetDialog(requireContext(), getString(R.string.xiaomi_warning_title), getString(R.string.xiaomi_warning_message))
|
||||||
|
.setNegativeButton(getString(R.string.action_ignore)) {
|
||||||
|
Preferences.showXiaomiWarning = false
|
||||||
|
}
|
||||||
|
.setPositiveButton(getString(R.string.action_grant_permission)) {
|
||||||
|
Preferences.showXiaomiWarning = false
|
||||||
|
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
|
||||||
|
data = Uri.parse("package:${activity?.packageName}")
|
||||||
|
}
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var uiJob: Job? = null
|
||||||
|
|
||||||
|
private fun updateUI() {
|
||||||
|
uiJob?.cancel()
|
||||||
|
|
||||||
|
preview?.clearAnimation()
|
||||||
|
time_container?.clearAnimation()
|
||||||
|
|
||||||
|
if (Preferences.showPreview) {
|
||||||
|
preview?.setCardBackgroundColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
requireContext(),
|
||||||
|
if (ColorHelper.getFontColor(activity?.isDarkTheme() == true)
|
||||||
|
.isColorDark()
|
||||||
|
) android.R.color.white else R.color.colorAccent
|
||||||
|
)
|
||||||
|
)
|
||||||
|
widget_shape_background?.setImageDrawable(
|
||||||
|
BitmapHelper.getTintedDrawable(
|
||||||
|
requireContext(),
|
||||||
|
R.drawable.card_background,
|
||||||
|
ColorHelper.getBackgroundColor(activity?.isDarkTheme() == true)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
WidgetHelper.runWithCustomTypeface(requireContext()) { typeface ->
|
||||||
|
uiJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
val generatedView = MainWidget.generateWidgetView(requireContext(), typeface)
|
||||||
|
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
generatedView.measure(0, 0)
|
||||||
|
preview?.measure(0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
val bitmap = if (preview != null) {
|
||||||
|
BitmapHelper.getBitmapFromView(
|
||||||
|
generatedView,
|
||||||
|
if (preview.width > 0) preview.width else generatedView.measuredWidth,
|
||||||
|
generatedView.measuredHeight
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
// Clock
|
||||||
|
time?.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
|
||||||
|
time_am_pm?.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
|
||||||
|
time?.setTextSize(
|
||||||
|
TypedValue.COMPLEX_UNIT_SP,
|
||||||
|
Preferences.clockTextSize.toPixel(requireContext())
|
||||||
|
)
|
||||||
|
time_am_pm?.setTextSize(
|
||||||
|
TypedValue.COMPLEX_UNIT_SP,
|
||||||
|
Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2
|
||||||
|
)
|
||||||
|
time_am_pm?.isVisible = Preferences.showAMPMIndicator
|
||||||
|
|
||||||
|
// Clock bottom margin
|
||||||
|
clock_bottom_margin_none?.isVisible =
|
||||||
|
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.value
|
||||||
|
clock_bottom_margin_small?.isVisible =
|
||||||
|
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.SMALL.value
|
||||||
|
clock_bottom_margin_medium?.isVisible =
|
||||||
|
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.MEDIUM.value
|
||||||
|
clock_bottom_margin_large?.isVisible =
|
||||||
|
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.LARGE.value
|
||||||
|
|
||||||
|
if ((Preferences.showClock && (time?.alpha ?: 1f < 1f)) || (!Preferences.showClock && (time?.alpha ?: 0f > 0f))) {
|
||||||
|
if (Preferences.showClock) {
|
||||||
|
time_container?.layoutParams = time_container.layoutParams.apply {
|
||||||
|
height = RelativeLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
}
|
||||||
|
time_container?.measure(0, 0)
|
||||||
|
}
|
||||||
|
val initialHeight = time_container?.measuredHeight ?: 0
|
||||||
|
ValueAnimator.ofFloat(
|
||||||
|
if (Preferences.showClock) 0f else 1f,
|
||||||
|
if (Preferences.showClock) 1f else 0f
|
||||||
|
).apply {
|
||||||
|
duration = 500L
|
||||||
|
addUpdateListener {
|
||||||
|
val animatedValue = animatedValue as Float
|
||||||
|
time_container?.layoutParams =
|
||||||
|
time_container.layoutParams.apply {
|
||||||
|
height = (initialHeight * animatedValue).toInt()
|
||||||
|
}
|
||||||
|
time?.alpha = animatedValue
|
||||||
|
}
|
||||||
|
addListener(
|
||||||
|
onStart = {
|
||||||
|
if (Preferences.showClock) {
|
||||||
|
time_container?.isVisible = true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onEnd = {
|
||||||
|
if (!Preferences.showClock) {
|
||||||
|
time_container?.isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}.start()
|
||||||
|
|
||||||
|
if (preview != null) {
|
||||||
|
ValueAnimator.ofInt(
|
||||||
|
preview.height,
|
||||||
|
PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
|
||||||
|
requireContext()
|
||||||
|
) else 0
|
||||||
|
).apply {
|
||||||
|
duration = 500L
|
||||||
|
addUpdateListener {
|
||||||
|
if (preview != null) {
|
||||||
|
val animatedValue = animatedValue as Int
|
||||||
|
val layoutParams = preview.layoutParams
|
||||||
|
layoutParams.height = animatedValue
|
||||||
|
preview.layoutParams = layoutParams
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
time_container?.layoutParams = time_container.layoutParams.apply {
|
||||||
|
height = RelativeLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
}
|
||||||
|
time_container?.measure(0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preview != null && preview.height == 0) {
|
||||||
|
ValueAnimator.ofInt(
|
||||||
|
preview.height,
|
||||||
|
PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
|
||||||
|
requireContext()
|
||||||
|
) else 0
|
||||||
|
).apply {
|
||||||
|
duration = 300L
|
||||||
|
addUpdateListener {
|
||||||
|
if (preview != null) {
|
||||||
|
val animatedValue = animatedValue as Int
|
||||||
|
val layoutParams = preview.layoutParams
|
||||||
|
layoutParams.height = animatedValue
|
||||||
|
preview?.layoutParams = layoutParams
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
widget_loader?.animate()?.scaleX(0f)?.scaleY(0f)?.alpha(0f)
|
||||||
|
?.setDuration(200L)?.start()
|
||||||
|
bitmap_container?.apply {
|
||||||
|
setImageBitmap(bitmap)
|
||||||
|
scaleX = 0.9f
|
||||||
|
scaleY = 0.9f
|
||||||
|
}
|
||||||
|
widget?.animate()?.alpha(1f)?.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (preview != null) {
|
||||||
|
ValueAnimator.ofInt(
|
||||||
|
preview.height,
|
||||||
|
0
|
||||||
|
).apply {
|
||||||
|
duration = 300L
|
||||||
|
addUpdateListener {
|
||||||
|
if (preview != null) {
|
||||||
|
val animatedValue = animatedValue as Int
|
||||||
|
val layoutParams = preview.layoutParams
|
||||||
|
layoutParams.height = animatedValue
|
||||||
|
preview.layoutParams = layoutParams
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showErrorBadge()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = if (Preferences.showWeather) {
|
||||||
|
(WeatherHelper.isKeyRequired() && WeatherHelper.getApiKey() == "")
|
||||||
|
|| (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)
|
||||||
|
|| (Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-")
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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() {
|
||||||
|
super.onResume()
|
||||||
|
Preferences.preferences.registerOnSharedPreferenceChangeListener(this)
|
||||||
|
EventBus.getDefault().register(this)
|
||||||
|
showErrorBadge()
|
||||||
|
updateUI()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
Preferences.preferences.unregisterOnSharedPreferenceChangeListener(this)
|
||||||
|
EventBus.getDefault().unregister(this)
|
||||||
|
super.onPause()
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
|
fun onMessageEvent(ignore: UpdateUiMessageEvent?) {
|
||||||
|
delayJob?.cancel()
|
||||||
|
delayJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
delay(200)
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
updateUI()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,6 @@ package com.tommasoberlose.anotherwidget.ui.fragments
|
|||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
@ -15,6 +14,8 @@ 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.Navigation
|
||||||
|
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
|
||||||
@ -23,30 +24,34 @@ 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.FragmentAdvancedSettingsBinding
|
import com.tommasoberlose.anotherwidget.databinding.FragmentSettingsBinding
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.SupportDevActivity
|
import com.tommasoberlose.anotherwidget.ui.activities.SupportDevActivity
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.IntegrationsActivity
|
||||||
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_advanced_settings.*
|
import kotlinx.android.synthetic.main.fragment_settings.*
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
||||||
class AdvancedSettingsFragment : Fragment() {
|
class SettingsFragment : Fragment() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun newInstance() = AdvancedSettingsFragment()
|
fun newInstance() = SettingsFragment()
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var viewModel: MainViewModel
|
private lateinit var viewModel: MainViewModel
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||||
|
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
@ -55,23 +60,29 @@ class AdvancedSettingsFragment : Fragment() {
|
|||||||
): View {
|
): View {
|
||||||
|
|
||||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||||
val binding = DataBindingUtil.inflate<FragmentAdvancedSettingsBinding>(inflater, R.layout.fragment_advanced_settings, container, false)
|
val binding = DataBindingUtil.inflate<FragmentSettingsBinding>(inflater, R.layout.fragment_settings, container, false)
|
||||||
|
|
||||||
subscribeUi(viewModel)
|
|
||||||
|
|
||||||
binding.lifecycleOwner = this
|
binding.lifecycleOwner = this
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
|
subscribeUi(viewModel)
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
|
action_back.setOnClickListener {
|
||||||
|
Navigation.findNavController(it).popBackStack()
|
||||||
|
}
|
||||||
|
|
||||||
|
show_widget_preview_toggle.isChecked = Preferences.showPreview
|
||||||
|
show_wallpaper_toggle.isChecked = Preferences.showWallpaper
|
||||||
|
|
||||||
setupListener()
|
setupListener()
|
||||||
|
|
||||||
app_version.text = "v%s (%s)".format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)
|
app_version.text = "v%s (%s)".format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)
|
||||||
requirePermission()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun subscribeUi(
|
private fun subscribeUi(
|
||||||
@ -90,6 +101,10 @@ class AdvancedSettingsFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
viewModel.installedIntegrations.observe(viewLifecycleOwner, Observer {
|
||||||
|
integrations_count_label?.text = getString(R.string.label_count_installed_integrations).format(it)
|
||||||
|
})
|
||||||
|
|
||||||
viewModel.showPreview.observe(viewLifecycleOwner, Observer {
|
viewModel.showPreview.observe(viewLifecycleOwner, Observer {
|
||||||
maintainScrollPosition {
|
maintainScrollPosition {
|
||||||
show_widget_preview_label?.text =
|
show_widget_preview_label?.text =
|
||||||
@ -108,6 +123,33 @@ class AdvancedSettingsFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupListener() {
|
private fun setupListener() {
|
||||||
|
action_show_widget_preview.setOnClickListener {
|
||||||
|
show_widget_preview_toggle.isChecked = !show_widget_preview_toggle.isChecked
|
||||||
|
}
|
||||||
|
|
||||||
|
show_widget_preview_toggle.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
Preferences.showPreview = isChecked
|
||||||
|
}
|
||||||
|
|
||||||
|
action_show_wallpaper.setOnClickListener {
|
||||||
|
}
|
||||||
|
|
||||||
|
action_show_wallpaper.setOnClickListener {
|
||||||
|
show_wallpaper_toggle.isChecked = !show_wallpaper_toggle.isChecked
|
||||||
|
}
|
||||||
|
|
||||||
|
show_wallpaper_toggle.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
if (isChecked) {
|
||||||
|
requirePermission()
|
||||||
|
} else {
|
||||||
|
Preferences.showWallpaper = isChecked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
action_integrations.setOnClickListener {
|
||||||
|
startActivity(Intent(requireContext(), IntegrationsActivity::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
action_change_theme.setOnClickListener {
|
action_change_theme.setOnClickListener {
|
||||||
maintainScrollPosition {
|
maintainScrollPosition {
|
||||||
BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_theme_title))
|
BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_theme_title))
|
||||||
@ -130,46 +172,6 @@ class AdvancedSettingsFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
action_show_widget_preview.setOnClickListener {
|
|
||||||
maintainScrollPosition {
|
|
||||||
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.action_show_widget_preview))
|
|
||||||
.setSelectedValue(Preferences.showPreview)
|
|
||||||
.addItem(
|
|
||||||
getString(R.string.settings_visible),
|
|
||||||
true
|
|
||||||
)
|
|
||||||
.addItem(
|
|
||||||
getString(R.string.settings_not_visible),
|
|
||||||
false
|
|
||||||
)
|
|
||||||
.addOnSelectItemListener { value ->
|
|
||||||
Preferences.showPreview = value
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_wallpaper.setOnClickListener {
|
|
||||||
maintainScrollPosition {
|
|
||||||
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_title_show_wallpaper))
|
|
||||||
.setSelectedValue(Preferences.showWallpaper && activity?.checkGrantedPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == true)
|
|
||||||
.addItem(
|
|
||||||
getString(R.string.settings_visible),
|
|
||||||
true
|
|
||||||
)
|
|
||||||
.addItem(
|
|
||||||
getString(R.string.settings_not_visible),
|
|
||||||
false
|
|
||||||
)
|
|
||||||
.addOnSelectItemListener { value ->
|
|
||||||
if (value) {
|
|
||||||
requirePermission()
|
|
||||||
} else {
|
|
||||||
Preferences.showWallpaper = value
|
|
||||||
}
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_translate.setOnClickListener {
|
action_translate.setOnClickListener {
|
||||||
activity?.openURI("https://github.com/tommasoberlose/another-widget/blob/master/app/src/main/res/values/strings.xml")
|
activity?.openURI("https://github.com/tommasoberlose/another-widget/blob/master/app/src/main/res/values/strings.xml")
|
||||||
}
|
}
|
||||||
@ -182,22 +184,29 @@ class AdvancedSettingsFragment : Fragment() {
|
|||||||
activity?.openURI("https://github.com/tommasoberlose/another-widget/issues")
|
activity?.openURI("https://github.com/tommasoberlose/another-widget/issues")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
action_privacy_policy.setOnClickListener {
|
||||||
|
activity?.openURI("https://github.com/tommasoberlose/another-widget/blob/master/privacy-policy.md")
|
||||||
|
}
|
||||||
|
|
||||||
action_help_dev.setOnClickListener {
|
action_help_dev.setOnClickListener {
|
||||||
startActivity(Intent(requireContext(), SupportDevActivity::class.java))
|
startActivity(Intent(requireContext(), SupportDevActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
action_refresh_widget.setOnClickListener {
|
action_refresh_widget.setOnClickListener {
|
||||||
MainWidget.updateWidget(requireContext())
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
|
WeatherHelper.updateWeather(requireContext())
|
||||||
|
}
|
||||||
CalendarHelper.updateEventList(requireContext())
|
CalendarHelper.updateEventList(requireContext())
|
||||||
|
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||||
val scrollPosition = scrollView.scrollY
|
scrollView.isScrollable = false
|
||||||
callback.invoke()
|
callback.invoke()
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
delay(200)
|
delay(200)
|
||||||
scrollView.smoothScrollTo(0, scrollPosition)
|
scrollView.isScrollable = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,8 +217,11 @@ class AdvancedSettingsFragment : Fragment() {
|
|||||||
).withListener(object: MultiplePermissionsListener {
|
).withListener(object: MultiplePermissionsListener {
|
||||||
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
||||||
report?.let {
|
report?.let {
|
||||||
Preferences.showWallpaper = false
|
if (report.areAllPermissionsGranted()) {
|
||||||
Preferences.showWallpaper = report.areAllPermissionsGranted()
|
Preferences.showWallpaper = true
|
||||||
|
} else {
|
||||||
|
show_wallpaper_toggle?.isChecked = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
override fun onPermissionRationaleShouldBeShown(
|
override fun onPermissionRationaleShouldBeShown(
|
@ -5,10 +5,12 @@ import android.app.Activity
|
|||||||
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
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.os.BuildCompat
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.databinding.DataBindingUtil
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
@ -23,11 +25,15 @@ 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.BottomSheetMenu
|
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.databinding.FragmentWeatherSettingsBinding
|
||||||
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.global.RequestCode
|
import com.tommasoberlose.anotherwidget.global.RequestCode
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
||||||
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
||||||
import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver
|
import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity
|
import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.CustomLocationActivity
|
import com.tommasoberlose.anotherwidget.ui.activities.CustomLocationActivity
|
||||||
@ -41,10 +47,10 @@ import kotlinx.android.synthetic.main.fragment_weather_settings.scrollView
|
|||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class WeatherSettingsFragment : Fragment() {
|
class WeatherTabFragment : Fragment() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun newInstance() = WeatherSettingsFragment()
|
fun newInstance() = WeatherTabFragment()
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var viewModel: MainViewModel
|
private lateinit var viewModel: MainViewModel
|
||||||
@ -79,32 +85,41 @@ class WeatherSettingsFragment : Fragment() {
|
|||||||
binding: FragmentWeatherSettingsBinding,
|
binding: FragmentWeatherSettingsBinding,
|
||||||
viewModel: MainViewModel
|
viewModel: MainViewModel
|
||||||
) {
|
) {
|
||||||
|
binding.isWeatherVisible = Preferences.showWeather
|
||||||
|
|
||||||
viewModel.showWeatherWarning.observe(viewLifecycleOwner, Observer {
|
viewModel.showWeatherWarning.observe(viewLifecycleOwner, Observer {
|
||||||
weather_warning?.isVisible = it
|
weather_warning?.isVisible = it
|
||||||
|
checkLocationPermission()
|
||||||
})
|
})
|
||||||
|
|
||||||
viewModel.showWeather.observe(viewLifecycleOwner, Observer {
|
viewModel.showWeather.observe(viewLifecycleOwner, Observer {
|
||||||
maintainScrollPosition {
|
maintainScrollPosition {
|
||||||
show_weather_label?.text =
|
show_weather_label?.text =
|
||||||
if (it) getString(R.string.show_weather_visible) else getString(R.string.show_weather_not_visible)
|
if (it) getString(R.string.show_weather_visible) else getString(R.string.show_weather_not_visible)
|
||||||
|
checkWeatherProviderConfig()
|
||||||
binding.isWeatherVisible = it
|
binding.isWeatherVisible = it
|
||||||
}
|
}
|
||||||
checkLocationPermission()
|
checkLocationPermission()
|
||||||
})
|
})
|
||||||
|
|
||||||
viewModel.weatherProviderApi.observe(viewLifecycleOwner, Observer {
|
viewModel.weatherProvider.observe(viewLifecycleOwner, Observer {
|
||||||
maintainScrollPosition {
|
maintainScrollPosition {
|
||||||
label_weather_provider_api_key?.text =
|
label_weather_provider.text = WeatherHelper.getProviderName(requireContext(), Constants.WeatherProvider.fromInt(it)!!)
|
||||||
if (it == "") getString(R.string.settings_weather_provider_api_key_subtitle_not_set) else getString(
|
checkWeatherProviderConfig()
|
||||||
R.string.settings_weather_provider_api_key_subtitle_all_set
|
|
||||||
)
|
|
||||||
label_weather_provider_api_key?.setTextColor(ContextCompat.getColor(requireContext(), if (it == "") R.color.errorColorText else R.color.colorSecondaryText))
|
|
||||||
}
|
}
|
||||||
checkLocationPermission()
|
})
|
||||||
|
|
||||||
|
viewModel.weatherProviderError.observe(viewLifecycleOwner, Observer {
|
||||||
|
checkWeatherProviderConfig()
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.weatherProviderLocationError.observe(viewLifecycleOwner, Observer {
|
||||||
|
checkWeatherProviderConfig()
|
||||||
})
|
})
|
||||||
|
|
||||||
viewModel.customLocationAdd.observe(viewLifecycleOwner, Observer {
|
viewModel.customLocationAdd.observe(viewLifecycleOwner, Observer {
|
||||||
maintainScrollPosition {
|
maintainScrollPosition {
|
||||||
|
background_location_warning.isVisible = it == ""
|
||||||
label_custom_location?.text =
|
label_custom_location?.text =
|
||||||
if (it == "") getString(R.string.custom_location_gps) else it
|
if (it == "") getString(R.string.custom_location_gps) else it
|
||||||
}
|
}
|
||||||
@ -126,6 +141,19 @@ class WeatherSettingsFragment : Fragment() {
|
|||||||
checkLocationPermission()
|
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 {
|
viewModel.weatherAppName.observe(viewLifecycleOwner, Observer {
|
||||||
maintainScrollPosition {
|
maintainScrollPosition {
|
||||||
weather_app_label?.text =
|
weather_app_label?.text =
|
||||||
@ -142,15 +170,31 @@ class WeatherSettingsFragment : Fragment() {
|
|||||||
|
|
||||||
if (activity?.checkGrantedPermission(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACCESS_BACKGROUND_LOCATION else Manifest.permission.ACCESS_FINE_LOCATION) == true) {
|
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
|
location_permission_alert?.isVisible = false
|
||||||
|
background_location_warning.isVisible = Preferences.customLocationAdd == ""
|
||||||
WeatherReceiver.setUpdates(requireContext())
|
WeatherReceiver.setUpdates(requireContext())
|
||||||
} else if (Preferences.showWeather && Preferences.customLocationAdd == "") {
|
} else if (Preferences.showWeather && Preferences.customLocationAdd == "") {
|
||||||
location_permission_alert?.isVisible = true
|
location_permission_alert?.isVisible = true
|
||||||
|
background_location_warning.isVisible = false
|
||||||
location_permission_alert?.setOnClickListener {
|
location_permission_alert?.setOnClickListener {
|
||||||
requirePermission()
|
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() {
|
||||||
|
weather_provider_error.isVisible = Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-"
|
||||||
|
weather_provider_error?.text = Preferences.weatherProviderError
|
||||||
|
|
||||||
|
weather_provider_location_error.isVisible = Preferences.weatherProviderLocationError != ""
|
||||||
|
weather_provider_location_error?.text = Preferences.weatherProviderLocationError
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupListener() {
|
private fun setupListener() {
|
||||||
action_hide_weather_warning.setOnClickListener {
|
action_hide_weather_warning.setOnClickListener {
|
||||||
Preferences.showWeatherWarning = false
|
Preferences.showWeatherWarning = false
|
||||||
@ -160,7 +204,11 @@ class WeatherSettingsFragment : Fragment() {
|
|||||||
Preferences.showWeather = !Preferences.showWeather
|
Preferences.showWeather = !Preferences.showWeather
|
||||||
}
|
}
|
||||||
|
|
||||||
action_weather_provider_api_key.setOnClickListener {
|
show_weather_switch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
||||||
|
Preferences.showWeather = enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
action_weather_provider.setOnClickListener {
|
||||||
if (Preferences.showWeather) {
|
if (Preferences.showWeather) {
|
||||||
startActivityForResult(
|
startActivityForResult(
|
||||||
Intent(requireContext(), WeatherProviderActivity::class.java),
|
Intent(requireContext(), WeatherProviderActivity::class.java),
|
||||||
@ -184,6 +232,11 @@ class WeatherSettingsFragment : Fragment() {
|
|||||||
.addItem(getString(R.string.fahrenheit), "F")
|
.addItem(getString(R.string.fahrenheit), "F")
|
||||||
.addItem(getString(R.string.celsius), "C")
|
.addItem(getString(R.string.celsius), "C")
|
||||||
.addOnSelectItemListener { value ->
|
.addOnSelectItemListener { value ->
|
||||||
|
if (value != Preferences.weatherTempUnit) {
|
||||||
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
|
WeatherHelper.updateWeather(requireContext())
|
||||||
|
}
|
||||||
|
}
|
||||||
Preferences.weatherTempUnit = value
|
Preferences.weatherTempUnit = value
|
||||||
}.show()
|
}.show()
|
||||||
}
|
}
|
||||||
@ -203,6 +256,12 @@ class WeatherSettingsFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
action_weather_icon_pack.setOnClickListener {
|
||||||
|
if (Preferences.showWeather) {
|
||||||
|
IconPackSelector(requireContext(), header = getString(R.string.settings_weather_icon_pack_title)).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
action_weather_app.setOnClickListener {
|
action_weather_app.setOnClickListener {
|
||||||
if (Preferences.showWeather) {
|
if (Preferences.showWeather) {
|
||||||
startActivityForResult(
|
startActivityForResult(
|
||||||
@ -228,7 +287,7 @@ class WeatherSettingsFragment : Fragment() {
|
|||||||
MainWidget.updateWidget(requireContext())
|
MainWidget.updateWidget(requireContext())
|
||||||
}
|
}
|
||||||
RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code -> {
|
RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code -> {
|
||||||
WeatherReceiver.setOneTimeUpdate(requireContext())
|
checkLocationPermission()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -260,11 +319,11 @@ class WeatherSettingsFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||||
val scrollPosition = scrollView.scrollY
|
scrollView.isScrollable = false
|
||||||
callback.invoke()
|
callback.invoke()
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
delay(200)
|
delay(200)
|
||||||
scrollView.smoothScrollTo(0, scrollPosition)
|
scrollView.isScrollable = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,8 +3,11 @@ package com.tommasoberlose.anotherwidget.ui.viewmodels
|
|||||||
import android.app.Application
|
import android.app.Application
|
||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.chibatching.kotpref.livedata.asLiveData
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
|
||||||
class CustomDateViewModel(application: Application) : AndroidViewModel(application) {
|
class CustomDateViewModel(application: Application) : AndroidViewModel(application) {
|
||||||
val dateInput: MutableLiveData<String> = MutableLiveData(if (Preferences.dateFormat == "") "EEEE, MMM dd" else Preferences.dateFormat)
|
val dateInput: MutableLiveData<String> = MutableLiveData(if (Preferences.dateFormat == "") "EEEE, MMM dd" else Preferences.dateFormat)
|
||||||
|
val isDateCapitalize = MutableLiveData<Boolean>(Preferences.isDateCapitalize)
|
||||||
|
val isDateUppercase = MutableLiveData<Boolean>(Preferences.isDateUppercase)
|
||||||
}
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.viewmodels
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.ResolveInfo
|
||||||
|
import androidx.lifecycle.AndroidViewModel
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.koolio.library.DownloadableFontList
|
||||||
|
import com.koolio.library.Font
|
||||||
|
import com.koolio.library.FontList
|
||||||
|
import com.tommasoberlose.anotherwidget.BuildConfig
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
class CustomFontViewModel(application: Application) : AndroidViewModel(application) {
|
||||||
|
|
||||||
|
val fontList: MutableLiveData<ArrayList<Font>> = MutableLiveData()
|
||||||
|
val searchInput: MutableLiveData<String> = MutableLiveData("")
|
||||||
|
|
||||||
|
init {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
|
||||||
|
|
||||||
|
val fontListCallback: DownloadableFontList.FontListCallback =
|
||||||
|
object : DownloadableFontList.FontListCallback {
|
||||||
|
override fun onFontListRetrieved(downloadedList: FontList?) {
|
||||||
|
fontList.postValue(downloadedList?.fontArrayList)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTypefaceRequestFailed(reason: Int) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DownloadableFontList.requestDownloadableFontList(fontListCallback, BuildConfig.GOOGLE_API_KEY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.viewmodels
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import androidx.lifecycle.AndroidViewModel
|
||||||
|
|
||||||
|
class IntegrationsViewModel(application: Application) : AndroidViewModel(application) {
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user