Compare commits

...

87 Commits

Author SHA1 Message Date
4ab12e33c7 Beta release v2.0.14 2020-10-11 22:09:27 +02:00
364198ef08 Update the providers system 2020-10-11 22:05:20 +02:00
2c81c7cfd2 Merge pull request #197 from d-l-n/master
Translations fix
2020-10-11 22:04:06 +02:00
3b723e5a1b Merge pull request #200 from Drumber/translation
Update German translation
2020-10-11 22:03:45 +02:00
6a912ee003 Add a few more providers and fix multiple bugs 2020-10-11 21:59:44 +02:00
1644fb7682 Update the providers 2020-10-06 18:11:53 +02:00
bd4869540b Connect weather.gov api 2020-10-05 19:07:52 +02:00
31103303be Update German translation 2020-10-05 18:06:46 +02:00
e9c0cdd61c Merge 2020-10-05 14:36:56 +02:00
59e42029e8 Merge and move google sans in the custom font activity 2020-10-05 12:31:49 +02:00
b2ef2adb2a Update the weather icons 2020-10-05 11:36:33 +02:00
bab92f9169 Add music players filter, fix #188 2020-10-05 11:09:11 +02:00
cb480ed4ee Fix the events order, fix #198 2020-10-05 09:43:31 +02:00
6f83a45865 Merge branch 'master' of github.com:tommasoberlose/another-widget into font 2020-10-05 00:59:47 +02:00
9e528e1f6f Update the icons 2020-10-05 00:59:37 +02:00
20d3ae0e32 Bugfix 2020-10-05 00:46:29 +02:00
ecea1265e7 Show the variant 2020-10-04 21:23:51 +02:00
c38b7a335c Add the font variant 2020-10-04 21:19:22 +02:00
6ab8e40d45 Add downloadable fonts 2020-10-04 20:39:52 +02:00
d14dfee980 Update the provider activity 2020-10-04 18:02:08 +02:00
0a454f0b5f Merge branch 'master' of github.com:tommasoberlose/another-widget into providers 2020-10-04 11:44:21 +02:00
b7bc93e174 Change the reset of the google steps 2020-10-04 11:44:05 +02:00
1dee4cc8e5 Add some providers 2020-10-04 11:43:36 +02:00
02b521c0b8 Fixed some translations 2020-10-03 21:42:15 -03:00
c04040e242 Merge branch 'master' of github.com:tommasoberlose/another-widget 2020-10-03 17:36:41 +02:00
a208aa97b2 Merge pull request #196 from CoreyVidal/master
Replaced Product Sans with Google Sans
2020-10-03 17:36:28 +02:00
e3fda9457e Merge branch 'master' of github.com:tommasoberlose/another-widget 2020-10-03 17:32:18 +02:00
b84631a2b2 Add privacy policy link 2020-10-03 17:32:03 +02:00
bad06c5762 Replaced Product Sans with Google Sans
Product Sans is designed to be used for Google product logos.
Google Sans is designed to be used for title, header, and body text.
2020-10-03 11:06:08 -04:00
74d8966f0a Merge pull request #195 from kaprijela/master
Add Slovak translation
2020-10-03 01:27:25 +02:00
d8a76936a6 Remove tos 2020-10-03 01:24:40 +02:00
e72ca4fc6f Create the privacy policy 2020-10-03 01:23:40 +02:00
dd62212b06 Add Slovak translation 2020-10-02 20:26:45 +02:00
8dfc12e412 Update the README 2020-10-02 19:50:09 +02:00
2762f12151 Add the background location disclaimer 2020-10-02 19:46:52 +02:00
a873c71918 Update the ui 2020-10-02 18:02:22 +02:00
e8f3c110a8 Add the dark theme colors 2020-10-02 17:36:39 +02:00
72bf3b04a7 Fix #156 2020-10-02 16:16:32 +02:00
ca6fb75dfd Fix #191 2020-10-02 15:45:59 +02:00
59dc5de21a Fix #169 2020-10-02 15:00:37 +02:00
ec40a277d7 Fix #186, fix #187 2020-10-02 11:30:59 +02:00
507b7f2318 Fix #174, fix #185 2020-10-02 11:23:23 +02:00
1a709a9406 Merge pull request #172 from Matromag/patch-2
Update translation
2020-10-02 11:19:14 +02:00
770ba0cd13 Merge pull request #173 from Steve-Mr/master
Simplified Chinese translations
2020-10-02 11:18:51 +02:00
6a92225edf Merge pull request #178 from shtraus12/master
fixed Russian localisation
2020-10-02 11:17:46 +02:00
ce801d4a7d Merge pull request #192 from d-l-n/master
i have translated language app to Spanish
2020-10-02 11:16:59 +02:00
25da807bd5 Translated strings to Spanish (master branch) 2020-09-13 20:14:05 -03:00
63212d13b1 translated a few strings to Spanish (master branch) 2020-09-12 21:19:11 -03:00
79ad9b2500 updated file name lol 2020-09-11 22:26:25 -03:00
9c0aa0a9ef added model 2020-09-11 22:25:28 -03:00
b9197ddf2e fix Russian localisation 2020-06-30 15:17:50 +03:00
d1362f7d81 modify chinese translation 2020-06-16 13:17:11 +08:00
a8c7d115ae change one sentence 2020-06-13 16:16:40 +08:00
a5a753e198 Add Chinese translation 2020-06-13 16:14:42 +08:00
39ede20518 Update translation 2020-06-12 15:17:28 +02:00
5527e6e405 Merge pull request #161 from Drumber/translation
Update German translation
2020-05-25 10:59:41 +02:00
565ed11f53 Merge pull request #160 from Moutony/patch-11
Update French (v2.0.12)
2020-05-25 10:30:44 +02:00
4bd8653d32 Merge pull request #154 from zmni/translation
Update Indonesian translation
2020-05-25 10:30:32 +02:00
d121119ca9 Accept and close #162 2020-05-25 10:30:04 +02:00
e82a34bcc7 Fix #157, fix #163 2020-05-25 10:16:21 +02:00
8867a1fbbd Update strings.xml
fixed just another too long string
2020-05-23 13:57:21 +02:00
7265883d6c Update strings.xml
- fixed too long words
- small cosmetic changes
2020-05-23 13:39:28 +02:00
7a4fc6ff58 Update German translation
- removed untranslatable strings
- added new string (line 203: nothing)
- fixed typos
2020-05-23 12:14:17 +02:00
9f61215caa Update French
I shortened the word 'événement' because it was oddly long.
It made the text overstep to a second line because of the new on/off button.
2020-05-23 12:01:39 +02:00
7ccf7eb8f6 Update Indonesian translation
Ref: 0d2287dbdf (diff-01dafb3fd0217441330103cfc8300094)
2020-05-23 04:32:15 +07:00
704448a848 Double-tap on the capitalize icon to set the date to uppercase 2020-05-22 19:25:34 +02:00
fa366b3d45 Merge pull request #151 from shtraus12/master
Fixed Russian translation
2020-05-22 19:22:16 +02:00
e58fef66aa Close #148 2020-05-22 19:18:29 +02:00
94825808f4 Update the UI 2020-05-22 18:51:42 +02:00
c120bad9c6 Update strings.xml 2020-05-22 19:48:39 +03:00
0d2287dbdf Fix #144 2020-05-22 18:30:38 +02:00
9e40586456 Merge branch 'master' of github.com:tommasoberlose/another-widget 2020-05-22 18:20:29 +02:00
4d75f4ca0c Fix #150 2020-05-22 18:20:08 +02:00
0859632803 Merge pull request #147 from Drumber/master
Added German translation (values-de)
2020-05-22 17:14:24 +02:00
47562b35ca Merge pull request #146 from zmni/translation
Update Indonesian translation
2020-05-22 17:14:19 +02:00
0f4f02ea28 Merge pull request #138 from Moutony/patch-10
Update strings.xml (values-fr) - May 20 version
2020-05-22 17:14:12 +02:00
31cf950eee Update ui 2020-05-22 17:13:06 +02:00
f230d300ee fixed minor spelling mistakes 2020-05-21 18:10:55 +02:00
c610857056 Added German translation (values-de) 2020-05-21 17:26:01 +02:00
770040ad93 Fix #136, fix #142 2020-05-21 13:30:15 +02:00
f784817296 Update Indonesian translation 2020-05-21 05:03:57 +07:00
ec1c25cb4c Bugfixes 2020-05-20 20:53:22 +02:00
e1d2f5a782 Update the UI 2020-05-20 20:46:21 +02:00
6e8c6cf055 Update strings.xml 2020-05-20 20:04:11 +02:00
68b5997e8d Update strings.xml 2020-05-20 19:47:53 +02:00
56b21be946 Update stings.xml (values-fr) - Glance
I translated the Glance explanations (line 145).
I shortened the "title-show-glance" (line 133) because it was oddly long (see screenshot)
2020-05-20 18:37:58 +02:00
fdc02b2cef Update strings.xml
I translated the Glance explanations.
2020-05-20 18:06:40 +02:00
626 changed files with 6193 additions and 1321 deletions

1
.gitignore vendored
View File

@ -8,3 +8,4 @@
.externalNativeBuild .externalNativeBuild
/tasksintegration/build /tasksintegration/build
/app/google-services.json /app/google-services.json
apikey.properties

Binary file not shown.

View File

@ -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">

2
.idea/modules.xml generated
View File

@ -2,7 +2,7 @@
<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" />
</modules> </modules>
</component> </component>

View File

@ -11,7 +11,7 @@ While respecting the design of the application, there is a great opportunity to
Also, as much as possible, there are always updates and new features in the short run. Also, as much as possible, there are always updates and new features in the short run.
Help me developing with feedback and support me on how you can. Help me developing with feedback and support me on how you can.
<div style="text-align:center"><a href="https://play.google.com/store/apps/details?id=com.tommasoberlose.anotherwidget" target="_blank"><img src="google-play-badge.png" height="100" /></a></div> <div style="text-align:center"><a href='https://play.google.com/store/apps/details?id=com.tommasoberlose.anotherwidget&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' height='100px' src='https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png'/></a></div>
Help with translations Help with translations

View File

@ -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 100 versionCode 106
versionName "2.0.11" 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 {
@ -59,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'
@ -75,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,34 +102,43 @@ dependencies {
// Fitness // Fitness
implementation 'com.google.android.gms:play-services-fitness:18.0.0' implementation 'com.google.android.gms:play-services-fitness:18.0.0'
implementation 'com.google.android.gms:play-services-auth: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'
//Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.squareup.retrofit2:converter-gson:2.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'
} }

Binary file not shown.

View File

@ -22,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">
@ -32,11 +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.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">
@ -145,6 +148,11 @@
<action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<service
android:name=".services.UpdateCalendarJob"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="true"/>
</application> </application>
</manifest> </manifest>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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)
} }

View File

@ -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)
}
}

View File

@ -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)
}
}
}

View File

@ -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()
}
}

View File

@ -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

View File

@ -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
)

View File

@ -1,15 +1,18 @@
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 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 java.util.*
import kotlin.Comparator
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
class EventRepository(val context: Context) { class EventRepository(val context: Context) {
@ -67,7 +70,7 @@ class EventRepository(val context: Context) {
val events = getEvents() val events = getEvents()
if (events.isNotEmpty()) { if (events.isNotEmpty()) {
val newNextEvent = events.first() val newNextEvent = events.first()
Preferences.nextEventId = newNextEvent!!.eventID Preferences.nextEventId = newNextEvent.eventID
newNextEvent newNextEvent
} else { } else {
resetNextEventData() resetNextEventData()
@ -95,9 +98,9 @@ class EventRepository(val context: Context) {
if (eventList.isNotEmpty()) { if (eventList.isNotEmpty()) {
val index = eventList.indexOfFirst { it.eventID == 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]!!.eventID Preferences.nextEventId = eventList[index + 1].eventID
} else { } else {
Preferences.nextEventId = eventList.first()!!.eventID Preferences.nextEventId = eventList.first().eventID
} }
} else { } else {
resetNextEventData() resetNextEventData()
@ -111,9 +114,9 @@ class EventRepository(val context: Context) {
if (eventList.isNotEmpty()) { if (eventList.isNotEmpty()) {
val index = eventList.indexOfFirst { it.eventID == Preferences.nextEventId } val index = eventList.indexOfFirst { it.eventID == Preferences.nextEventId }
if (index > 0) { if (index > 0) {
Preferences.nextEventId = eventList[index - 1]!!.eventID Preferences.nextEventId = eventList[index - 1].eventID
} else { } else {
Preferences.nextEventId = eventList.last()!!.eventID Preferences.nextEventId = eventList.last().eventID
} }
} else { } else {
resetNextEventData() resetNextEventData()
@ -122,13 +125,17 @@ class EventRepository(val context: Context) {
MainWidget.updateWidget(context) MainWidget.updateWidget(context)
} }
fun getFutureEvents(): RealmResults<Event> { fun getFutureEvents(): List<Event> {
val now = Calendar.getInstance().timeInMillis val now = Calendar.getInstance().timeInMillis
realm.refresh() realm.refresh()
return realm.where(Event::class.java).greaterThan("endDate", now).findAll() return realm
.where(Event::class.java)
.greaterThan("endDate", now)
.findAll()
.applyFilters()
} }
private fun getEvents(): RealmResults<Event> { private fun getEvents(): List<Event> {
val now = Calendar.getInstance().timeInMillis val now = Calendar.getInstance().timeInMillis
val limit = Calendar.getInstance().apply { val limit = Calendar.getInstance().apply {
timeInMillis = now timeInMillis = now
@ -145,7 +152,12 @@ class EventRepository(val context: Context) {
} }
} }
realm.refresh() realm.refresh()
return realm.where(Event::class.java).greaterThan("endDate", now).lessThanOrEqualTo("startDate", limit.timeInMillis).findAll() return realm
.where(Event::class.java)
.greaterThan("endDate", now)
.lessThanOrEqualTo("startDate", limit.timeInMillis)
.findAll()
.applyFilters()
} }
fun getEventsCount(): Int = getEvents().size fun getEventsCount(): Int = getEvents().size

View File

@ -7,7 +7,10 @@ object Constants {
const val RESULT_APP_NAME = "RESULT_APP_NAME" const val RESULT_APP_NAME = "RESULT_APP_NAME"
const val RESULT_APP_PACKAGE = "RESULT_APP_PACKAGE" const val RESULT_APP_PACKAGE = "RESULT_APP_PACKAGE"
const val CUSTOM_FONT_PRODUCT_SANS = 1 const val CUSTOM_FONT_GOOGLE_SANS = 1
const val CUSTOM_FONT_DOWNLOADED = 2
const val CUSTOM_FONT_DOWNLOAD_NEW = 3
enum class ClockBottomMargin(val value: Int) { enum class ClockBottomMargin(val value: Int) {
NONE(0), NONE(0),
SMALL(1), SMALL(1),
@ -15,6 +18,13 @@ object Constants {
LARGE(3) LARGE(3)
} }
enum class SecondRowTopMargin(val value: Int) {
NONE(0),
SMALL(1),
MEDIUM(2),
LARGE(3)
}
enum class GlanceProviderId(val id: String) { enum class GlanceProviderId(val id: String) {
PLAYING_SONG("PLAYING_SONG"), PLAYING_SONG("PLAYING_SONG"),
NEXT_CLOCK_ALARM("NEXT_CLOCK_ALARM"), NEXT_CLOCK_ALARM("NEXT_CLOCK_ALARM"),
@ -29,6 +39,21 @@ object Constants {
HIGH(2) HIGH(2)
} }
enum class WeatherProvider(val value: Int) {
OPEN_WEATHER(0),
WEATHER_BIT(1),
WEATHER_API(2),
HERE(3),
ACCUWEATHER(4),
WEATHER_GOV(5),
YR(6);
companion object {
private val map = WeatherProvider.values().associateBy(WeatherProvider::value)
fun fromInt(type: Int) = map[type]
}
}
enum class WeatherIconPack(val value: Int) { enum class WeatherIconPack(val value: Int) {
DEFAULT(0), DEFAULT(0),
MINIMAL(1), MINIMAL(1),

View File

@ -31,13 +31,21 @@ object Preferences : KotprefModel() {
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 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)
@ -55,6 +63,20 @@ object Preferences : KotprefModel() {
var clockTextColor by stringPref(default = "#FFFFFF") var clockTextColor by stringPref(default = "#FFFFFF")
var clockTextAlpha by stringPref(default = "FF") 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 showAMPMIndicator by booleanPref(default = true)
var weatherIconPack by intPref(default = Constants.WeatherIconPack.DEFAULT.value) var weatherIconPack by intPref(default = Constants.WeatherIconPack.DEFAULT.value)
@ -64,15 +86,22 @@ object Preferences : KotprefModel() {
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 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) var showDividers by booleanPref(default = true)
@ -101,6 +130,7 @@ object Preferences : KotprefModel() {
var mediaPlayerAlbum by stringPref(default = "") var mediaPlayerAlbum by stringPref(default = "")
var mediaPlayerArtist by stringPref(default = "") var mediaPlayerArtist by stringPref(default = "")
var mediaPlayerPackage by stringPref(default = "") var mediaPlayerPackage by stringPref(default = "")
var musicPlayersFilter by stringPref(default = "")
// Integrations // Integrations
var installedIntegrations by intPref(default = 0) var installedIntegrations by intPref(default = 0)

View File

@ -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),

View File

@ -104,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,

View File

@ -1,8 +1,14 @@
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 android.util.Log
import com.tommasoberlose.anotherwidget.services.EventListenerJob import com.tommasoberlose.anotherwidget.services.EventListenerJob
@ -10,6 +16,7 @@ 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.services.UpdateCalendarJob
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
@ -24,106 +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 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 (!context.checkGrantedPermission(
Manifest.permission.READ_CALENDAR
)
) {
eventRepository.resetNextEventData()
} else {
try {
val provider = CalendarProvider(context)
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 && (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()
eventRepository.clearEvents()
} 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(MainFragment.UpdateUiMessageEvent())
eventRepository.close()
} }
fun getCalendarList(context: Context): List<me.everything.providers.android.calendar.Calendar> { fun getCalendarList(context: Context): List<me.everything.providers.android.calendar.Calendar> {
@ -145,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>) {
@ -159,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()
}
} }

View File

@ -7,97 +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 getFontColorAlpha(): Int { fun getFontColorAlpha(isDark: Boolean): Int {
return try { return try {
Preferences.textGlobalAlpha.toIntValue().toDouble() * 255 / 100 (if (!isDark) Preferences.textGlobalAlpha else Preferences.textGlobalAlphaDark).toIntValue().toDouble() * 255 / 100
} catch (e: Exception) { } catch (e: Exception) {
"FF".toIntValue().toDouble() * 255 / 100 "FF".toIntValue().toDouble() * 255 / 100
}.roundToInt() }.roundToInt()
} }
fun getFontColorRgb(): Int { fun getFontColorRgb(isDark: Boolean): Int {
return try { return try {
Color.parseColor(Preferences.textGlobalColor) Color.parseColor((if (!isDark) Preferences.textGlobalColor else Preferences.textGlobalColorDark))
} catch (e: Exception) { } catch (e: Exception) {
Color.parseColor("#000000") Color.parseColor("#000000")
} }
} }
fun getSecondaryFontColor(): Int { fun getSecondaryFontColor(isDark: Boolean): Int {
return try { return try {
Color.parseColor("#%s%s".format(Preferences.textSecondaryAlpha, Preferences.textSecondaryColor.replace("#", ""))) Color.parseColor("#%s%s".format((if (!isDark) Preferences.textSecondaryAlpha else Preferences.textSecondaryAlphaDark), (if (!isDark) Preferences.textSecondaryColor else Preferences.textSecondaryColorDark).replace("#", "")))
} catch (e: Exception) { } catch (e: Exception) {
Color.parseColor("#FFFFFFFF") Color.parseColor("#FFFFFFFF")
} }
} }
fun getSecondaryFontColorAlpha(): Int { fun getSecondaryFontColorAlpha(isDark: Boolean): Int {
return try { return try {
Preferences.textSecondaryAlpha.toIntValue().toDouble() * 255 / 100 (if (!isDark) Preferences.textSecondaryAlpha else Preferences.textSecondaryAlphaDark).toIntValue().toDouble() * 255 / 100
} catch (e: Exception) { } catch (e: Exception) {
"FF".toIntValue().toDouble() * 255 / 100 "FF".toIntValue().toDouble() * 255 / 100
}.roundToInt() }.roundToInt()
} }
fun getSecondaryFontColorRgb(): Int { fun getSecondaryFontColorRgb(isDark: Boolean): Int {
return try { return try {
Color.parseColor(Preferences.textSecondaryColor) Color.parseColor((if (!isDark) Preferences.textSecondaryColor else Preferences.textSecondaryColorDark))
} catch (e: Exception) { } catch (e: Exception) {
Color.parseColor("#000000") Color.parseColor("#000000")
} }
} }
fun getClockFontColor(): Int { fun getClockFontColor(isDark: Boolean): Int {
return try { return try {
Color.parseColor("#%s%s".format(Preferences.clockTextAlpha, Preferences.clockTextColor.replace("#", ""))) Color.parseColor("#%s%s".format((if (!isDark) Preferences.clockTextAlpha else Preferences.clockTextAlphaDark), (if (!isDark) Preferences.clockTextColor else Preferences.clockTextColorDark).replace("#", "")))
} catch (e: Exception) { } catch (e: Exception) {
Color.parseColor("#FFFFFFFF") Color.parseColor("#FFFFFFFF")
} }
} }
fun getClockFontColorAlpha(): Int { fun getClockFontColorAlpha(isDark: Boolean): Int {
return try { return try {
Preferences.clockTextAlpha.toIntValue().toDouble() * 255 / 100 (if (!isDark) Preferences.clockTextAlpha else Preferences.clockTextAlphaDark).toIntValue().toDouble() * 255 / 100
} catch (e: Exception) { } catch (e: Exception) {
"FF".toIntValue().toDouble() * 255 / 100 "FF".toIntValue().toDouble() * 255 / 100
}.roundToInt() }.roundToInt()
} }
fun getClockFontColorRgb(): Int { fun getClockFontColorRgb(isDark: Boolean): Int {
return try { return try {
Color.parseColor(Preferences.clockTextColor) Color.parseColor((if (!isDark) Preferences.clockTextColor else Preferences.clockTextColorDark))
} catch (e: Exception) { } catch (e: Exception) {
Color.parseColor("#000000") Color.parseColor("#000000")
} }
} }
fun getBackgroundColor(): Int { fun getBackgroundColor(isDark: Boolean): Int {
return try { return try {
Color.parseColor("#%s%s".format(Preferences.backgroundCardAlpha, Preferences.backgroundCardColor.replace("#", ""))) Color.parseColor("#%s%s".format((if (!isDark) Preferences.backgroundCardAlpha else Preferences.backgroundCardAlphaDark), (if (!isDark) Preferences.backgroundCardColor else Preferences.backgroundCardColorDark).replace("#", "")))
} catch (e: Exception) { } catch (e: Exception) {
Color.parseColor("#00000000") Color.parseColor("#00000000")
} }
} }
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")
} }

View File

@ -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
@ -17,7 +16,11 @@ object DateHelper {
} catch (e: Exception) { } catch (e: Exception) {
getDefaultDateText(context, date) getDefaultDateText(context, date)
} }
if (Preferences.isDateCapitalize) text.getCapWordString() else text 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
@ -25,17 +28,20 @@ object DateHelper {
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)
) )
if (Preferences.isDateCapitalize) text.getCapWordString() else text when {
Preferences.isDateUppercase -> text.toUpperCase(Locale.getDefault())
Preferences.isDateCapitalize -> text.getCapWordString()
else -> text
}
} }
} }
fun getDefaultDateText(context: Context, date: Calendar): String { fun getDefaultDateText(context: Context, date: Calendar): String {
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
val text = "%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)
) )
return if (Preferences.isDateCapitalize) text.getCapWordString() else text
} }
} }

View File

@ -1,6 +1,7 @@
package com.tommasoberlose.anotherwidget.helpers package com.tommasoberlose.anotherwidget.helpers
import android.content.Context import android.content.Context
import android.util.Log
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.db.EventRepository import com.tommasoberlose.anotherwidget.db.EventRepository
import com.tommasoberlose.anotherwidget.global.Constants import com.tommasoberlose.anotherwidget.global.Constants
@ -80,13 +81,14 @@ object GlanceProviderHelper {
fun showGlanceProviders(context: Context): Boolean { fun showGlanceProviders(context: Context): Boolean {
val eventRepository = EventRepository(context) val eventRepository = EventRepository(context)
BatteryHelper.updateBatteryInfo(context) BatteryHelper.updateBatteryInfo(context)
val showGlance = Preferences.showGlance && eventRepository.getEventsCount() == 0 && (
val showGlance = Preferences.showGlance && (eventRepository.getEventsCount() == 0 || !Preferences.showEvents) && (
(Preferences.showNextAlarm && AlarmHelper.getNextAlarm(context) != "") || (Preferences.showNextAlarm && AlarmHelper.getNextAlarm(context) != "") ||
(MediaPlayerHelper.isSomeonePlaying(context)) || (MediaPlayerHelper.isSomeonePlaying(context)) ||
(Preferences.showBatteryCharging && Preferences.isCharging || Preferences.isBatteryLevelLow) || (Preferences.showBatteryCharging && Preferences.isCharging || Preferences.isBatteryLevelLow) ||
(Preferences.customNotes.isNotEmpty()) || (Preferences.customNotes.isNotEmpty()) ||
(Preferences.showDailySteps && Preferences.googleFitSteps > 0) (Preferences.showDailySteps && Preferences.googleFitSteps > 0)
) )
eventRepository.close() eventRepository.close()
return showGlance return showGlance
} }

View File

@ -11,9 +11,11 @@ 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 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.*
@ -64,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")
}
} }
} }
} }
@ -98,10 +96,8 @@ object IntentHelper {
data = calendarUri data = calendarUri
} }
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() context.toast(context.getString(R.string.error_opening_app))
Intent(Intent.ACTION_VIEW).apply { Intent()
data = calendarUri
}
} }
} }
} }
@ -132,23 +128,33 @@ object IntentHelper {
} }
} }
} else { } else {
getCalendarIntent(context).apply { val calendarIntent = getCalendarIntent(context)
action = Intent.ACTION_VIEW if (calendarIntent.action == Intent.ACTION_VIEW) {
data = uri calendarIntent.apply {
if (!e.allDay) { data = uri
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)
} else { putExtra(CalendarContract.EXTRA_EVENT_END_TIME, e.endDate)
val start = Calendar.getInstance().apply { } else {
timeInMillis = e.startDate 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)
} }
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()
} }
} }
} }
@ -175,9 +181,8 @@ 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()
}
} }
} }
} }
@ -199,6 +204,7 @@ object IntentHelper {
addCategory(Intent.CATEGORY_LAUNCHER) addCategory(Intent.CATEGORY_LAUNCHER)
} }
} catch (e: Exception) { } catch (e: Exception) {
context.toast(context.getString(R.string.error_opening_app))
Intent() Intent()
} }
} }
@ -212,6 +218,7 @@ object IntentHelper {
addCategory(Intent.CATEGORY_LAUNCHER) addCategory(Intent.CATEGORY_LAUNCHER)
} }
} catch (e: Exception) { } catch (e: Exception) {
context.toast(context.getString(R.string.error_opening_app))
Intent() Intent()
} }
} }

View File

@ -10,6 +10,8 @@ import android.media.session.MediaSessionManager
import android.media.session.PlaybackState import android.media.session.PlaybackState
import android.util.Log import android.util.Log
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import com.chibatching.kotpref.Kotpref
import com.chibatching.kotpref.blockingBulk
import com.chibatching.kotpref.bulk import com.chibatching.kotpref.bulk
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.receivers.MusicNotificationListener import com.tommasoberlose.anotherwidget.receivers.MusicNotificationListener
@ -28,6 +30,7 @@ object MediaPlayerHelper {
} }
fun updatePlayingMediaInfo(context: Context) { fun updatePlayingMediaInfo(context: Context) {
Kotpref.init(context)
if (NotificationManagerCompat.getEnabledListenerPackages(context).contains(context.packageName)) { if (NotificationManagerCompat.getEnabledListenerPackages(context).contains(context.packageName)) {
val list = try { val list = try {
(context.getSystemService(Context.MEDIA_SESSION_SERVICE) as MediaSessionManager).getActiveSessions( (context.getSystemService(Context.MEDIA_SESSION_SERVICE) as MediaSessionManager).getActiveSessions(
@ -35,6 +38,8 @@ object MediaPlayerHelper {
) )
} catch (ex: Exception) { } catch (ex: Exception) {
emptyList<MediaController>() emptyList<MediaController>()
}.filter {
Preferences.musicPlayersFilter == "" || isMusicPlayerAccepted(it.packageName)
} }
if (list.isNotEmpty()) { if (list.isNotEmpty()) {
@ -65,24 +70,35 @@ object MediaPlayerHelper {
} }
if (!isSomeonePlaying) { if (!isSomeonePlaying) {
removeMediaInfo() removeMediaInfo(context)
} }
} else { } else {
removeMediaInfo() removeMediaInfo(context)
} }
} else { } else {
removeMediaInfo() removeMediaInfo(context)
} }
MainWidget.updateWidget(context) MainWidget.updateWidget(context)
} }
private fun removeMediaInfo() { private fun removeMediaInfo(context: Context) {
Preferences.bulk { Kotpref.init(context)
Preferences.blockingBulk {
remove(Preferences::mediaPlayerTitle) remove(Preferences::mediaPlayerTitle)
remove(Preferences::mediaPlayerArtist) remove(Preferences::mediaPlayerArtist)
remove(Preferences::mediaPlayerAlbum) remove(Preferences::mediaPlayerAlbum)
remove(Preferences::mediaPlayerPackage) 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 = ",")
}
}
} }

View File

@ -54,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)

View File

@ -3,6 +3,7 @@ package com.tommasoberlose.anotherwidget.helpers
import android.Manifest import android.Manifest
import android.content.Context import android.content.Context
import android.os.Build import android.os.Build
import android.util.Log
import com.google.android.gms.location.LocationServices import com.google.android.gms.location.LocationServices
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.global.Constants import com.tommasoberlose.anotherwidget.global.Constants
@ -11,6 +12,10 @@ import com.tommasoberlose.anotherwidget.network.WeatherNetworkApi
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
@ -20,7 +25,7 @@ import org.greenrobot.eventbus.EventBus
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()
@ -31,10 +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()
networkApi.updateWeather()
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
} }
CoroutineScope(Dispatchers.IO).launch {
networkApi.updateWeather()
}
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
} else {
CoroutineScope(Dispatchers.IO).launch {
networkApi.updateWeather()
}
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
} }
} }
} }
@ -43,209 +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 {
return context.getString(when(provider) {
Constants.WeatherProvider.OPEN_WEATHER -> R.string.settings_weather_provider_open_weather
Constants.WeatherProvider.WEATHER_BIT -> R.string.settings_weather_provider_weatherbit
Constants.WeatherProvider.WEATHER_API -> R.string.settings_weather_provider_weather_api
Constants.WeatherProvider.HERE -> R.string.settings_weather_provider_here
Constants.WeatherProvider.ACCUWEATHER -> R.string.settings_weather_provider_accuweather
Constants.WeatherProvider.WEATHER_GOV -> R.string.settings_weather_provider_weather_gov
Constants.WeatherProvider.YR -> R.string.settings_weather_provider_yr
})
}
fun getProviderInfoTitle(context: Context, provider: Constants.WeatherProvider? = Constants.WeatherProvider.fromInt(Preferences.weatherProvider)!!): String {
return context.getString(when(provider) {
Constants.WeatherProvider.OPEN_WEATHER -> R.string.weather_provider_info_open_weather_title
Constants.WeatherProvider.WEATHER_BIT -> R.string.weather_provider_info_weatherbit_title
Constants.WeatherProvider.WEATHER_API -> R.string.weather_provider_info_weatherapi_title
Constants.WeatherProvider.HERE -> R.string.weather_provider_info_here_title
Constants.WeatherProvider.ACCUWEATHER -> R.string.weather_provider_info_accuweather_title
Constants.WeatherProvider.WEATHER_GOV -> R.string.weather_provider_info_weather_gov_title
Constants.WeatherProvider.YR -> R.string.weather_provider_info_yr_title
else -> R.string.nothing
})
}
fun getProviderInfoSubtitle(context: Context, provider: Constants.WeatherProvider? = Constants.WeatherProvider.fromInt(Preferences.weatherProvider)!!): String {
return context.getString(when(provider) {
Constants.WeatherProvider.OPEN_WEATHER -> R.string.weather_provider_info_open_weather_subtitle
Constants.WeatherProvider.WEATHER_BIT -> R.string.weather_provider_info_weatherbit_subtitle
Constants.WeatherProvider.WEATHER_API -> R.string.weather_provider_info_weatherapi_subtitle
Constants.WeatherProvider.HERE -> R.string.weather_provider_info_here_subtitle
Constants.WeatherProvider.ACCUWEATHER -> R.string.weather_provider_info_accuweather_subtitle
Constants.WeatherProvider.WEATHER_GOV -> R.string.weather_provider_info_weather_gov_subtitle
Constants.WeatherProvider.YR -> R.string.weather_provider_info_yr_subtitle
else -> R.string.nothing
})
}
fun getProviderLink(provider: Constants.WeatherProvider? = Constants.WeatherProvider.fromInt(Preferences.weatherProvider)!!): String {
return when(provider) {
Constants.WeatherProvider.OPEN_WEATHER -> "https://home.openweathermap.org/users/sign_in"
Constants.WeatherProvider.WEATHER_BIT -> "https://www.weatherbit.io/account/login"
Constants.WeatherProvider.WEATHER_API -> "https://www.weatherapi.com/login.aspx"
Constants.WeatherProvider.HERE -> "https://developer.here.com/login"
Constants.WeatherProvider.ACCUWEATHER -> "https://developer.accuweather.com/user/login"
Constants.WeatherProvider.WEATHER_GOV -> "http://www.weather.gov/"
Constants.WeatherProvider.YR -> "https://www.yr.no/"
else -> ""
}
}
fun isKeyRequired(provider: Constants.WeatherProvider? = Constants.WeatherProvider.fromInt(Preferences.weatherProvider)!!): Boolean = when (provider) {
Constants.WeatherProvider.OPEN_WEATHER,
Constants.WeatherProvider.WEATHER_BIT,
Constants.WeatherProvider.WEATHER_API,
Constants.WeatherProvider.HERE,
Constants.WeatherProvider.ACCUWEATHER -> true
Constants.WeatherProvider.WEATHER_GOV,
Constants.WeatherProvider.YR -> false
else -> true
}
fun getApiKey(provider: Constants.WeatherProvider? = Constants.WeatherProvider.fromInt(Preferences.weatherProvider)!!): String = when (provider) {
Constants.WeatherProvider.OPEN_WEATHER -> Preferences.weatherProviderApiOpen
Constants.WeatherProvider.WEATHER_BIT -> Preferences.weatherProviderApiWeatherBit
Constants.WeatherProvider.WEATHER_API -> Preferences.weatherProviderApiWeatherApi
Constants.WeatherProvider.HERE -> Preferences.weatherProviderApiHere
Constants.WeatherProvider.ACCUWEATHER -> Preferences.weatherProviderApiAccuweather
Constants.WeatherProvider.WEATHER_GOV -> ""
Constants.WeatherProvider.YR -> ""
else -> ""
}
fun getWeatherIconResource(context: Context, icon: String, style: Int = Preferences.weatherIconPack): Int {
return when (icon) { return when (icon) {
"01d" -> { "01d" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.clear_day_3 Constants.WeatherIconPack.COOL.value -> R.drawable.clear_day_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.clear_day_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.clear_day_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.clear_day_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.clear_day_4
else -> R.drawable.clear_day else -> if (context.isDarkTheme()) R.drawable.clear_day_5 else R.drawable.clear_day_5_light
} }
} }
"02d" -> { "02d" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.partly_cloudy_3 Constants.WeatherIconPack.COOL.value -> R.drawable.partly_cloudy_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.partly_cloudy_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.partly_cloudy_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.partly_cloudy_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.partly_cloudy_4
else -> R.drawable.partly_cloudy else -> if (context.isDarkTheme()) R.drawable.partly_cloudy_5 else R.drawable.partly_cloudy_5_light
} }
} }
"03d" -> { "03d" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.mostly_cloudy_3 Constants.WeatherIconPack.COOL.value -> R.drawable.mostly_cloudy_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.mostly_cloudy_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.mostly_cloudy_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.mostly_cloudy_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.mostly_cloudy_4
else -> R.drawable.mostly_cloudy else -> if (context.isDarkTheme()) R.drawable.mostly_cloudy_5 else R.drawable.mostly_cloudy_5_light
} }
} }
"04d" -> { "04d" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.cloudy_weather_3 Constants.WeatherIconPack.COOL.value -> R.drawable.cloudy_weather_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.cloudy_weather_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.cloudy_weather_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.cloudy_weather_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.cloudy_weather_4
else -> R.drawable.cloudy_weather else -> if (context.isDarkTheme()) R.drawable.cloudy_weather_5 else R.drawable.cloudy_weather_5_light
} }
} }
"09d" -> { "09d" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.storm_weather_day_3 Constants.WeatherIconPack.COOL.value -> R.drawable.storm_weather_day_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.storm_weather_day_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.storm_weather_day_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.storm_weather_day_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.storm_weather_day_4
else -> R.drawable.storm_weather_day else -> if (context.isDarkTheme()) R.drawable.storm_weather_day_5 else R.drawable.storm_weather_day_5_light
} }
} }
"10d" -> { "10d" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.rainy_day_3 Constants.WeatherIconPack.COOL.value -> R.drawable.rainy_day_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rainy_day_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rainy_day_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rainy_day_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rainy_day_4
else -> R.drawable.rainy_day else -> if (context.isDarkTheme()) R.drawable.rainy_day_5 else R.drawable.rainy_day_5_light
} }
} }
"11d" -> { "11d" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.thunder_day_3 Constants.WeatherIconPack.COOL.value -> R.drawable.thunder_day_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.thunder_day_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.thunder_day_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.thunder_day_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.thunder_day_4
else -> R.drawable.thunder_day else -> if (context.isDarkTheme()) R.drawable.thunder_day_5 else R.drawable.thunder_day_5_light
} }
} }
"13d" -> { "13d" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.snow_day_3 Constants.WeatherIconPack.COOL.value -> R.drawable.snow_day_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.snow_day_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.snow_day_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.snow_day_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.snow_day_4
else -> R.drawable.snow_day else -> if (context.isDarkTheme()) R.drawable.snow_day_5 else R.drawable.snow_day_5_light
} }
} }
"50d" -> { "50d" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_day_3 Constants.WeatherIconPack.COOL.value -> R.drawable.haze_day_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_day_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_day_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_day_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_day_4
else -> R.drawable.haze_day else -> if (context.isDarkTheme()) R.drawable.haze_day_5 else R.drawable.haze_day_5_light
} }
} }
"80d" -> { "80d" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.windy_day_3 Constants.WeatherIconPack.COOL.value -> R.drawable.windy_day_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.windy_day_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.windy_day_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.windy_day_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.windy_day_4
else -> R.drawable.windy_day else -> if (context.isDarkTheme()) R.drawable.windy_day_5 else R.drawable.windy_day_5_light
} }
} }
"81d" -> { "81d" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.rain_snow_day_3 Constants.WeatherIconPack.COOL.value -> R.drawable.rain_snow_day_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rain_snow_day_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rain_snow_day_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rain_snow_day_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rain_snow_day_4
else -> R.drawable.rain_snow_day else -> if (context.isDarkTheme()) R.drawable.rain_snow_day_5 else R.drawable.rain_snow_day_5_light
} }
} }
"82d" -> { "82d" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_weather_3 Constants.WeatherIconPack.COOL.value -> R.drawable.haze_weather_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_weather_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_weather_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_weather_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_weather_4
else -> R.drawable.haze_weather else -> if (context.isDarkTheme()) R.drawable.haze_weather_5 else R.drawable.haze_weather_5_light
} }
} }
"01n" -> { "01n" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.clear_night_3 Constants.WeatherIconPack.COOL.value -> R.drawable.clear_night_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.clear_night_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.clear_night_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.clear_night_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.clear_night_4
else -> R.drawable.clear_night else -> if (context.isDarkTheme()) R.drawable.clear_night_5 else R.drawable.clear_night_5_light
} }
} }
"02n" -> { "02n" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.partly_cloudy_night_3 Constants.WeatherIconPack.COOL.value -> R.drawable.partly_cloudy_night_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.partly_cloudy_night_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.partly_cloudy_night_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.partly_cloudy_night_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.partly_cloudy_night_4
else -> R.drawable.partly_cloudy_night else -> if (context.isDarkTheme()) R.drawable.partly_cloudy_night_5 else R.drawable.partly_cloudy_night_5_light
} }
} }
"03n" -> { "03n" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.mostly_cloudy_night_3 Constants.WeatherIconPack.COOL.value -> R.drawable.mostly_cloudy_night_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.mostly_cloudy_night_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.mostly_cloudy_night_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.mostly_cloudy_night_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.mostly_cloudy_night_4
else -> R.drawable.mostly_cloudy_night else -> if (context.isDarkTheme()) R.drawable.mostly_cloudy_night_5 else R.drawable.mostly_cloudy_night_5_light
} }
} }
"04n" -> { "04n" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.cloudy_weather_3 Constants.WeatherIconPack.COOL.value -> R.drawable.cloudy_weather_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.cloudy_weather_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.cloudy_weather_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.cloudy_weather_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.cloudy_weather_4
else -> R.drawable.cloudy_weather else -> if (context.isDarkTheme()) R.drawable.cloudy_weather_5 else R.drawable.cloudy_weather_5_light
} }
} }
"09n" -> { "09n" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.storm_weather_night_3 Constants.WeatherIconPack.COOL.value -> R.drawable.storm_weather_night_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.storm_weather_night_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.storm_weather_night_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.storm_weather_night_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.storm_weather_night_4
else -> R.drawable.storm_weather_night else -> if (context.isDarkTheme()) R.drawable.storm_weather_night_5 else R.drawable.storm_weather_night_5_light
} }
} }
"10n" -> { "10n" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.rainy_night_3 Constants.WeatherIconPack.COOL.value -> R.drawable.rainy_night_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rainy_night_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rainy_night_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rainy_night_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rainy_night_4
else -> R.drawable.rainy_night else -> if (context.isDarkTheme()) R.drawable.rainy_night_5 else R.drawable.rainy_night_5_light
} }
} }
"11n" -> { "11n" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.thunder_night_3 Constants.WeatherIconPack.COOL.value -> R.drawable.thunder_night_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.thunder_night_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.thunder_night_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.thunder_night_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.thunder_night_4
else -> R.drawable.thunder_night else -> if (context.isDarkTheme()) R.drawable.thunder_night_5 else R.drawable.thunder_night_5_light
} }
} }
"13n" -> { "13n" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.snow_night_3 Constants.WeatherIconPack.COOL.value -> R.drawable.snow_night_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.snow_night_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.snow_night_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.snow_night_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.snow_night_4
else -> R.drawable.snow_night else -> if (context.isDarkTheme()) R.drawable.snow_night_5 else R.drawable.snow_night_5_light
} }
} }
"50n" -> { "50n" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_night_3 Constants.WeatherIconPack.COOL.value -> R.drawable.haze_night_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_night_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_night_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_night_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_night_4
else -> R.drawable.haze_night else -> if (context.isDarkTheme()) R.drawable.haze_night_5 else R.drawable.haze_night_5_light
} }
} }
"80n" -> { "80n" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.windy_night_3 Constants.WeatherIconPack.COOL.value -> R.drawable.windy_night_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.windy_night_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.windy_night_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.windy_night_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.windy_night_4
else -> R.drawable.windy_night else -> if (context.isDarkTheme()) R.drawable.windy_night_5 else R.drawable.windy_night_5_light
} }
} }
"81n" -> { "81n" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.rain_snow_night_3 Constants.WeatherIconPack.COOL.value -> R.drawable.rain_snow_night_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rain_snow_night_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rain_snow_night_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rain_snow_night_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rain_snow_night_4
else -> R.drawable.rain_snow_night else -> if (context.isDarkTheme()) R.drawable.rain_snow_night_5 else R.drawable.rain_snow_night_5_light
} }
} }
"82n" -> { "82n" -> {
when (Preferences.weatherIconPack) { when (style) {
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_weather_3 Constants.WeatherIconPack.COOL.value -> R.drawable.haze_weather_3
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_weather_2 Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_weather_2
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_weather_4 Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_weather_4
else -> R.drawable.haze_weather else -> if (context.isDarkTheme()) R.drawable.haze_weather_5 else R.drawable.haze_weather_5_light
} }
} }
else -> { else -> {
return R.drawable.unknown return if (context.isDarkTheme()) R.drawable.unknown_dark else R.drawable.unknown_light
} }
} }
} }
fun getWeatherGovIcon(iconString: String, isDaytime: Boolean): String = when {
iconString.contains("skc") -> "01"
iconString.contains("few") -> "02"
iconString.contains("sct") -> "03"
iconString.contains("bkn") -> "04"
iconString.contains("ovc") -> "04"
iconString.contains("wind_skc") -> "01"
iconString.contains("wind_few") -> "02"
iconString.contains("wind_sct") -> "03"
iconString.contains("wind_bkn") -> "04"
iconString.contains("wind_ovc") -> "04"
iconString.contains("snow") -> "13"
iconString.contains("rain_snow") -> "81"
iconString.contains("rain_sleet") -> "81"
iconString.contains("snow_sleet") -> "81"
iconString.contains("fzra") -> "81"
iconString.contains("rain_fzra") -> "81"
iconString.contains("snow_fzra") -> "81"
iconString.contains("sleet") -> "81"
iconString.contains("rain") -> "10"
iconString.contains("rain_showers") -> "10"
iconString.contains("rain_showers_hi") -> "10"
iconString.contains("tsra") -> "82"
iconString.contains("tsra_sct") -> "82"
iconString.contains("tsra_hi") -> "82"
iconString.contains("tornado") -> "80"
iconString.contains("hurricane") -> "80"
iconString.contains("tropical_storm") -> "09"
iconString.contains("dust") -> "Dust"
iconString.contains("smoke") -> "Smoke"
iconString.contains("haze") -> "50"
iconString.contains("hot") -> "01"
iconString.contains("cold") -> "13"
iconString.contains("blizzard") -> "80"
iconString.contains("fog") -> "82"
else -> ""
} + if (isDaytime) "d" else "n"
fun getWeatherBitIcon(iconString: String): String = when {
iconString.contains("t01") -> "11"
iconString.contains("t02") -> "09"
iconString.contains("t03") -> "09"
iconString.contains("t04") -> "09"
iconString.contains("t05") -> "09"
iconString.contains("d01") -> "10"
iconString.contains("d02") -> "10"
iconString.contains("d03") -> "10"
iconString.contains("r01") -> "10"
iconString.contains("r02") -> "10"
iconString.contains("r03") -> "10"
iconString.contains("f01") -> "10"
iconString.contains("r04") -> "10"
iconString.contains("r05") -> "10"
iconString.contains("r06") -> "10"
iconString.contains("s01") -> "13"
iconString.contains("s02") -> "13"
iconString.contains("s03") -> "13"
iconString.contains("s04") -> "81"
iconString.contains("s05") -> "90"
iconString.contains("s06") -> "13"
iconString.contains("a01") -> "82"
iconString.contains("a02") -> "82"
iconString.contains("a03") -> "82"
iconString.contains("a04") -> "82"
iconString.contains("a05") -> "82"
iconString.contains("a06") -> "82"
iconString.contains("c01") -> "01"
iconString.contains("c02") -> "02"
iconString.contains("c03") -> "04"
iconString.contains("c04") -> "04"
else -> ""
} + if (iconString.contains("d")) "d" else "n"
fun getWeatherApiIcon(icon: Int, isDaytime: Boolean): String = when(icon) {
1000 -> "01"
1003 -> "02"
1006 -> "03"
1009 -> "04"
1030 -> "82"
1063 -> "10"
1066 -> "10"
1069 -> "10"
1072 -> "81"
1087 -> "11"
1114 -> "13"
1117 -> "09"
1135 -> "82"
1147 -> "82"
1150 -> "10"
1153 -> "10"
1168 -> "10"
1171 -> "10"
1180 -> "10"
1183 -> "10"
1186 -> "10"
1189 -> "10"
1192 -> "10"
1195 -> "10"
1198 -> "81"
1201 -> "81"
1204 -> "13"
1207 -> "13"
1210 -> "13"
1213 -> "13"
1216 -> "13"
1219 -> "13"
1222 -> "13"
1225 -> "13"
1237 -> "13"
1240 -> "10"
1243 -> "10"
1246 -> "10"
1249 -> "13"
1252 -> "13"
1255 -> "13"
1258 -> "13"
1261 -> "13"
1264 -> "13"
1273 -> "09"
1276 -> "09"
1279 -> "13"
1282 -> "13"
else -> ""
} + if (isDaytime) "d" else "n"
fun getYRIcon(iconCode: String, isDaytime: Boolean): String = when {
iconCode.contains("clearsky") -> "01"
iconCode.contains("cloudy") -> "04"
iconCode.contains("fair") -> "02"
iconCode.contains("fog") -> "82"
iconCode.contains("heavyrain") -> "10"
iconCode.contains("heavyrainandthunder") -> "11"
iconCode.contains("heavyrainshowers") -> "10"
iconCode.contains("heavyrainshowersandthunder") -> "11"
iconCode.contains("heavysleet") -> "10"
iconCode.contains("heavysleetandthunder") -> "11"
iconCode.contains("heavysleetshowers") -> "10"
iconCode.contains("heavysleetshowersandthunder") -> "11"
iconCode.contains("heavysnow") -> "13"
iconCode.contains("heavysnowandthunder") -> "13"
iconCode.contains("heavysnowshowers") -> "13"
iconCode.contains("heavysnowshowersandthunder") -> "13"
iconCode.contains("lightrain") -> "10"
iconCode.contains("lightrainandthunder") -> "11"
iconCode.contains("lightrainshowers") -> "10"
iconCode.contains("lightrainshowersandthunder") -> "11"
iconCode.contains("lightsleet") -> "10"
iconCode.contains("lightsleetandthunder") -> "11"
iconCode.contains("lightsleetshowers") -> "10"
iconCode.contains("lightsnow") -> "13"
iconCode.contains("lightsnowandthunder") -> "13"
iconCode.contains("lightsnowshowers") -> "13"
iconCode.contains("lightssleetshowersandthunder") -> "81"
iconCode.contains("lightssnowshowersandthunder") -> "81"
iconCode.contains("partlycloudy") -> "03"
iconCode.contains("rain") -> "10"
iconCode.contains("rainandthunder") -> "11"
iconCode.contains("rainshowers") -> "10"
iconCode.contains("rainshowersandthunder") -> "11"
iconCode.contains("sleet") -> "10"
iconCode.contains("sleetandthunder") -> "11"
iconCode.contains("sleetshowers") -> "10"
iconCode.contains("sleetshowersandthunder") -> "11"
iconCode.contains("snow") -> "13"
iconCode.contains("snowandthunder") -> "13"
iconCode.contains("snowshowers") -> "13"
iconCode.contains("snowshowersandthunder") -> "13"
else -> ""
} + if (isDaytime) "d" else "n"
} }

View File

@ -3,10 +3,20 @@ package com.tommasoberlose.anotherwidget.helpers
import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetManager
import android.content.Context import android.content.Context
import android.content.res.Configuration.ORIENTATION_PORTRAIT import android.content.res.Configuration.ORIENTATION_PORTRAIT
import android.graphics.Typeface
import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import android.util.Log import android.util.Log
import androidx.core.provider.FontRequest
import androidx.core.provider.FontsContractCompat
import com.google.firebase.crashlytics.FirebaseCrashlytics import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.db.EventRepository import com.tommasoberlose.anotherwidget.db.EventRepository
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import com.tommasoberlose.anotherwidget.utils.toPixel
import kotlin.math.min
object WidgetHelper { object WidgetHelper {
class WidgetSizeProvider( class WidgetSizeProvider(
@ -44,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)
}
}
} }

View File

@ -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,14 +8,18 @@ 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:\nEVENT ID: " + eventID + "\nTITLE: " + title + "\nSTART DATE: " + Date(startDate) + "\nEND DATE: " + Date(endDate) + "\nCAL ID: " + calendarID + "\nADDRESS: " + address return "Event:\nEVENT ID: " + eventID + "\nTITLE: " + title + "\nSTART DATE: " + Date(startDate) + "\nEND DATE: " + Date(endDate) + "\nCAL ID: " + calendarID + "\nADDRESS: " + address
} }

View File

@ -1,20 +1,56 @@
package com.tommasoberlose.anotherwidget.network package com.tommasoberlose.anotherwidget.network
import android.content.Context import android.content.Context
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.network.repository.*
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import java.lang.Exception
import java.text.SimpleDateFormat
import java.util.*
class WeatherNetworkApi(val context: Context) { class WeatherNetworkApi(val context: Context) {
fun updateWeather() { suspend fun updateWeather() {
if (Preferences.showWeather && Preferences.weatherProviderApi != "" && Preferences.customLocationLat != "" && Preferences.customLocationLon != "") { 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 {
@ -24,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(MainFragment.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())
}
} }
} }
} }

View File

@ -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>>
}
}

View File

@ -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()
}
}
}

View File

@ -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()
}
}
}

View File

@ -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()
}
}
}

View File

@ -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()
}
}
}

View File

@ -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()
}
}
}

View File

@ -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()
}
}
}

View File

@ -8,6 +8,8 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Build import android.os.Build
import android.util.Log import android.util.Log
import com.chibatching.kotpref.Kotpref
import com.chibatching.kotpref.blockingBulk
import com.google.android.gms.auth.api.signin.GoogleSignIn import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInAccount import com.google.android.gms.auth.api.signin.GoogleSignInAccount
import com.google.android.gms.fitness.Fitness import com.google.android.gms.fitness.Fitness
@ -35,16 +37,19 @@ class ActivityDetectionReceiver : BroadcastReceiver() {
} }
} else { } else {
if (intent.action == Intent.ACTION_BOOT_COMPLETED || intent.action == Intent.ACTION_MY_PACKAGE_REPLACED && Preferences.showDailySteps && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || context.checkGrantedPermission(Manifest.permission.ACTIVITY_RECOGNITION)) { if (intent.action == Intent.ACTION_BOOT_COMPLETED || intent.action == Intent.ACTION_MY_PACKAGE_REPLACED && Preferences.showDailySteps && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || context.checkGrantedPermission(Manifest.permission.ACTIVITY_RECOGNITION)) {
resetDailySteps() resetDailySteps(context)
registerFence(context) registerFence(context)
} else { } else {
resetDailySteps() resetDailySteps(context)
} }
} }
} }
private fun resetDailySteps() { private fun resetDailySteps(context: Context) {
Preferences.googleFitSteps = -1 Kotpref.init(context)
Preferences.blockingBulk {
remove(Preferences::googleFitSteps)
}
} }
companion object { companion object {
@ -54,6 +59,7 @@ class ActivityDetectionReceiver : BroadcastReceiver() {
.build() .build()
fun registerFence(context: Context) { fun registerFence(context: Context) {
Kotpref.init(context)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || context.checkGrantedPermission( if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || context.checkGrantedPermission(
Manifest.permission.ACTIVITY_RECOGNITION)) { Manifest.permission.ACTIVITY_RECOGNITION)) {
val transitions = mutableListOf<ActivityTransition>() val transitions = mutableListOf<ActivityTransition>()
@ -116,6 +122,7 @@ class ActivityDetectionReceiver : BroadcastReceiver() {
} }
fun requestDailySteps(context: Context) { fun requestDailySteps(context: Context) {
Kotpref.init(context)
val account: GoogleSignInAccount? = GoogleSignIn.getLastSignedInAccount(context) val account: GoogleSignInAccount? = GoogleSignIn.getLastSignedInAccount(context)
if (account != null && GoogleSignIn.hasPermissions(account, FITNESS_OPTIONS)) { if (account != null && GoogleSignIn.hasPermissions(account, FITNESS_OPTIONS)) {

View File

@ -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,7 +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) {
val interval = MINUTE * when (Preferences.weatherRefreshPeriod) { val interval = MINUTE * when (Preferences.weatherRefreshPeriod) {
0 -> 30 0 -> 30
1 -> 60 1 -> 60
@ -55,7 +59,7 @@ class WeatherReceiver : BroadcastReceiver() {
} }
fun setOneTimeUpdate(context: Context) { fun setOneTimeUpdate(context: Context) {
if (Preferences.showWeather && Preferences.weatherProviderApi != "") { if (Preferences.showWeather) {
listOf(10, 20, 30).forEach { listOf(10, 20, 30).forEach {
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) { with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
setExactAndAllowWhileIdle( setExactAndAllowWhileIdle(

View File

@ -52,7 +52,7 @@ class BatteryListenerJob : JobService() {
} }
} }
fun remove(context: Context) { private fun remove(context: Context) {
val js = context.getSystemService(JobScheduler::class.java) val js = context.getSystemService(JobScheduler::class.java)
js?.cancel(chargingJobId) js?.cancel(chargingJobId)
js?.cancel(notChargingJobId) js?.cancel(notChargingJobId)

View File

@ -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()
}
}

View File

@ -6,12 +6,14 @@ 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
@ -90,10 +92,14 @@ class CustomDateActivity : AppCompatActivity() {
"__" "__"
} }
if (Preferences.isDateCapitalize) { if (viewModel.isDateCapitalize.value == true) {
text = text.getCapWordString() 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
@ -105,8 +111,30 @@ class CustomDateActivity : AppCompatActivity() {
viewModel.isDateCapitalize.observe(this, Observer { viewModel.isDateCapitalize.observe(this, Observer {
viewModel.dateInput.value = viewModel.dateInput.value viewModel.dateInput.value = viewModel.dateInput.value
binding.isdCapitalizeEnabled = it 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() {
@ -115,12 +143,29 @@ 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 { action_capitalize.setOnClickListener {
Preferences.isDateCapitalize = !Preferences.isDateCapitalize 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 { action_capitalize.setOnLongClickListener {

View File

@ -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()
}
}

View File

@ -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 ->

View File

@ -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)
}
}

View File

@ -1,37 +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() }
override fun onResume() {
super.onResume()
EventBus.getDefault().register(this)
}
override fun onPause() {
EventBus.getDefault().unregister(this)
super.onPause()
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(ignore: MainFragment.UpdateUiMessageEvent?) {
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()
} }
action_open_provider.setOnClickListener {
openURI("https://home.openweathermap.org/users/sign_up")
}
api_key.editText?.setText(Preferences.weatherProviderApi)
} }
} }

View File

@ -4,7 +4,7 @@ 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.util.Log 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
@ -31,16 +31,15 @@ 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 CalendarTabFragment : Fragment() { class CalendarTabFragment : Fragment() {
@ -74,6 +73,11 @@ class CalendarTabFragment : 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()
} }
@ -82,6 +86,7 @@ class CalendarTabFragment : Fragment() {
viewModel: MainViewModel viewModel: MainViewModel
) { ) {
binding.isCalendarEnabled = Preferences.showEvents binding.isCalendarEnabled = Preferences.showEvents
binding.isDiffEnabled = Preferences.showDiffTime || !Preferences.showEvents
viewModel.showEvents.observe(viewLifecycleOwner, Observer { viewModel.showEvents.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
@ -92,8 +97,10 @@ class CalendarTabFragment : 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 {
@ -101,14 +108,6 @@ class CalendarTabFragment : Fragment() {
all_day_label?.text = all_day_label?.text =
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible) if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
} }
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 {
@ -120,6 +119,7 @@ class CalendarTabFragment : 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
} }
}) })
@ -138,7 +138,7 @@ class CalendarTabFragment : 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 {
@ -150,7 +150,18 @@ class CalendarTabFragment : Fragment() {
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)
}
}
}
} }
}) })
@ -222,7 +233,7 @@ class CalendarTabFragment : Fragment() {
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))
@ -231,50 +242,94 @@ class CalendarTabFragment : 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_visible), true)
.addItem(getString(R.string.settings_not_visible), 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) }
.addOnSelectItemListener { value ->
Preferences.showDiffTime = value show_diff_time_toggle.setOnCheckedChangeListener { _, isChecked ->
}.show() if (Preferences.showEvents) {
Preferences.showDiffTime = isChecked
} }
} }
action_widget_update_frequency.setOnClickListener { action_widget_update_frequency.setOnClickListener {
if (Preferences.showEvents) { 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) 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_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_default), Constants.WidgetUpdateFrequency.DEFAULT.value)
@ -329,7 +384,6 @@ class CalendarTabFragment : 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
@ -339,6 +393,12 @@ class CalendarTabFragment : 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(
@ -386,11 +446,11 @@ class CalendarTabFragment : 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
} }
} }
} }

View File

@ -8,6 +8,8 @@ import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Bundle import android.os.Bundle
import android.text.format.DateFormat
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
@ -21,6 +23,7 @@ import com.chibatching.kotpref.bulk
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
import com.tommasoberlose.anotherwidget.components.FixedFocusScrollView
import com.tommasoberlose.anotherwidget.databinding.FragmentClockSettingsBinding import com.tommasoberlose.anotherwidget.databinding.FragmentClockSettingsBinding
import com.tommasoberlose.anotherwidget.global.Constants import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences
@ -29,9 +32,12 @@ import com.tommasoberlose.anotherwidget.helpers.AlarmHelper
import com.tommasoberlose.anotherwidget.helpers.ColorHelper import com.tommasoberlose.anotherwidget.helpers.ColorHelper
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toHexValue import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toHexValue
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue 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.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.utils.isDarkTheme
import com.tommasoberlose.anotherwidget.utils.isDefaultSet
import kotlinx.android.synthetic.main.fragment_clock_settings.* import kotlinx.android.synthetic.main.fragment_clock_settings.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@ -48,6 +54,7 @@ class ClockTabFragment : Fragment() {
private lateinit var viewModel: MainViewModel private lateinit var viewModel: MainViewModel
private lateinit var colors: IntArray private lateinit var colors: IntArray
private lateinit var binding: FragmentClockSettingsBinding
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -59,7 +66,7 @@ class ClockTabFragment : 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<FragmentClockSettingsBinding>(inflater, R.layout.fragment_clock_settings, container, false) binding = DataBindingUtil.inflate<FragmentClockSettingsBinding>(inflater, R.layout.fragment_clock_settings, container, false)
subscribeUi(binding, viewModel) subscribeUi(binding, viewModel)
@ -72,6 +79,8 @@ class ClockTabFragment : Fragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
ampm_indicator_toggle.isChecked = Preferences.showAMPMIndicator
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
val lazyColors = requireContext().resources.getIntArray(R.array.material_colors) val lazyColors = requireContext().resources.getIntArray(R.array.material_colors)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
@ -86,6 +95,8 @@ class ClockTabFragment : Fragment() {
viewModel: MainViewModel viewModel: MainViewModel
) { ) {
binding.isClockVisible = Preferences.showClock binding.isClockVisible = Preferences.showClock
binding.is24Format = DateFormat.is24HourFormat(requireContext())
binding.isDarkModeEnabled = activity?.isDarkTheme() == true
viewModel.showBigClockWarning.observe(viewLifecycleOwner, Observer { viewModel.showBigClockWarning.observe(viewLifecycleOwner, Observer {
large_clock_warning?.isVisible = it large_clock_warning?.isVisible = it
@ -118,7 +129,18 @@ class ClockTabFragment : Fragment() {
clock_text_color_label?.text = getString(R.string.transparent) clock_text_color_label?.text = getString(R.string.transparent)
} else { } else {
clock_text_color_label?.text = clock_text_color_label?.text =
"#%s".format(Integer.toHexString(ColorHelper.getClockFontColor())).toUpperCase() "#%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()
} }
} }
}) })
@ -129,7 +151,18 @@ class ClockTabFragment : Fragment() {
clock_text_color_label?.text = getString(R.string.transparent) clock_text_color_label?.text = getString(R.string.transparent)
} else { } else {
clock_text_color_label?.text = clock_text_color_label?.text =
"#%s".format(Integer.toHexString(ColorHelper.getClockFontColor())).toUpperCase() "#%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()
} }
} }
}) })
@ -147,8 +180,18 @@ class ClockTabFragment : Fragment() {
viewModel.clockAppName.observe(viewLifecycleOwner, Observer { viewModel.clockAppName.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
clock_app_label?.text = clock_app_label?.text = when {
if (Preferences.clockAppName != "") Preferences.clockAppName else getString(R.string.default_clock_app) Preferences.clockAppName != "" -> Preferences.clockAppName
else -> {
if (IntentHelper.getClockIntent(requireContext()).isDefaultSet(requireContext())) {
getString(
R.string.default_clock_app
)
} else {
getString(R.string.nothing)
}
}
}
} }
}) })
} }
@ -167,57 +210,97 @@ class ClockTabFragment : Fragment() {
} }
action_clock_text_size.setOnClickListener { action_clock_text_size.setOnClickListener {
val dialog = BottomSheetMenu<Float>(requireContext(), header = getString(R.string.settings_clock_text_size_title)).setSelectedValue(Preferences.clockTextSize) if (Preferences.showClock) {
(46 downTo 12).filter { it % 2 == 0 }.forEach { val dialog = BottomSheetMenu<Float>(
dialog.addItem("${it}sp", it.toFloat()) 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()
} }
dialog.addOnSelectItemListener { value ->
Preferences.clockTextSize = value
}.show()
} }
action_ampm_indicator_size.setOnClickListener { action_ampm_indicator_size.setOnClickListener {
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_ampm_indicator_title)).setSelectedValue(Preferences.showAMPMIndicator) if (Preferences.showClock) {
.addItem(getString(R.string.settings_visible), true) ampm_indicator_toggle.isChecked = !ampm_indicator_toggle.isChecked
.addItem(getString(R.string.settings_not_visible), false) }
.addOnSelectItemListener { value -> }
Preferences.showAMPMIndicator = value
}.show() ampm_indicator_toggle.setOnCheckedChangeListener { _, isChecked ->
if (Preferences.showClock) {
Preferences.showAMPMIndicator = isChecked
}
} }
action_clock_text_color.setOnClickListener { action_clock_text_color.setOnClickListener {
BottomSheetColorPicker(requireContext(), if (Preferences.showClock) {
colors = colors, BottomSheetColorPicker(requireContext(),
header = getString(R.string.settings_font_color_title), colors = colors,
getSelected = ColorHelper::getClockFontColorRgb, header = getString(R.string.settings_font_color_title),
onColorSelected = { color: Int -> getSelected = { ColorHelper.getClockFontColorRgb(activity?.isDarkTheme() == true) },
val colorString = Integer.toHexString(color) onColorSelected = { color: Int ->
Preferences.clockTextColor = "#" + if (colorString.length > 6) colorString.substring(2) else colorString val colorString = Integer.toHexString(color)
}, if (activity?.isDarkTheme() == true) {
showAlphaSelector = true, Preferences.clockTextColorDark =
alpha = Preferences.clockTextAlpha.toIntValue(), "#" + if (colorString.length > 6) colorString.substring(2) else colorString
onAlphaChangeListener = { alpha -> } else {
Preferences.clockTextAlpha = alpha.toHexValue() Preferences.clockTextColor =
} "#" + if (colorString.length > 6) colorString.substring(2) else colorString
).show() }
},
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 { action_clock_bottom_margin_size.setOnClickListener {
BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_clock_bottom_margin_title)).setSelectedValue(Preferences.clockBottomMargin) if (Preferences.showClock) {
.addItem(getString(R.string.settings_clock_bottom_margin_subtitle_none), Constants.ClockBottomMargin.NONE.value) BottomSheetMenu<Int>(
.addItem(getString(R.string.settings_clock_bottom_margin_subtitle_small), Constants.ClockBottomMargin.SMALL.value) requireContext(),
.addItem(getString(R.string.settings_clock_bottom_margin_subtitle_medium), Constants.ClockBottomMargin.MEDIUM.value) header = getString(R.string.settings_clock_bottom_margin_title)
.addItem(getString(R.string.settings_clock_bottom_margin_subtitle_large), Constants.ClockBottomMargin.LARGE.value) ).setSelectedValue(Preferences.clockBottomMargin)
.addOnSelectItemListener { value -> .addItem(
Preferences.clockBottomMargin = value getString(R.string.settings_clock_bottom_margin_subtitle_none),
}.show() 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 { action_clock_app.setOnClickListener {
if (Preferences.showClock) { if (Preferences.showClock) {
startActivityForResult(Intent(requireContext(), ChooseApplicationActivity::class.java), if (Preferences.showClock) {
RequestCode.CLOCK_APP_REQUEST_CODE.code startActivityForResult(
) Intent(requireContext(), ChooseApplicationActivity::class.java),
RequestCode.CLOCK_APP_REQUEST_CODE.code
)
}
} }
} }
} }
@ -232,12 +315,17 @@ class ClockTabFragment : Fragment() {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
} }
override fun onResume() {
binding.is24Format = DateFormat.is24HourFormat(requireContext())
super.onResume()
}
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
} }
} }
} }

View File

@ -3,19 +3,29 @@ package com.tommasoberlose.anotherwidget.ui.fragments
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.graphics.Typeface
import android.os.Bundle import android.os.Bundle
import android.os.Handler
import android.os.HandlerThread
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast
import androidx.core.provider.FontRequest
import androidx.core.provider.FontsContractCompat
import androidx.databinding.DataBindingUtil import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment 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 com.chibatching.kotpref.blockingBulk
import com.chibatching.kotpref.bulk
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
import com.tommasoberlose.anotherwidget.databinding.FragmentGeneralSettingsBinding import com.tommasoberlose.anotherwidget.databinding.FragmentGeneralSettingsBinding
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.ColorHelper
@ -23,10 +33,17 @@ import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toHexValue
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
import com.tommasoberlose.anotherwidget.helpers.DateHelper import com.tommasoberlose.anotherwidget.helpers.DateHelper
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper 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.CustomDateActivity
import com.tommasoberlose.anotherwidget.ui.activities.CustomFontActivity
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.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.*
import kotlinx.android.synthetic.main.fragment_general_settings.scrollView
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -60,6 +77,7 @@ class GeneralTabFragment : Fragment() {
binding.lifecycleOwner = this binding.lifecycleOwner = this
binding.viewModel = viewModel binding.viewModel = viewModel
binding.isDarkModeEnabled = activity?.isDarkTheme() == true
return binding.root return binding.root
} }
@ -67,6 +85,8 @@ class GeneralTabFragment : Fragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
show_dividers_toggle.isChecked = Preferences.showDividers
setupListener() setupListener()
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
val lazyColors = requireContext().resources.getIntArray(R.array.material_colors) val lazyColors = requireContext().resources.getIntArray(R.array.material_colors)
@ -100,7 +120,18 @@ class GeneralTabFragment : Fragment() {
font_color_label?.text = getString(R.string.transparent) font_color_label?.text = getString(R.string.transparent)
} else { } else {
font_color_label?.text = font_color_label?.text =
"#%s".format(Integer.toHexString(ColorHelper.getFontColor())).toUpperCase() "#%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()
} }
} }
}) })
@ -111,7 +142,18 @@ class GeneralTabFragment : Fragment() {
font_color_label?.text = getString(R.string.transparent) font_color_label?.text = getString(R.string.transparent)
} else { } else {
font_color_label?.text = font_color_label?.text =
"#%s".format(Integer.toHexString(ColorHelper.getFontColor())).toUpperCase() "#%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()
} }
} }
}) })
@ -122,7 +164,18 @@ class GeneralTabFragment : Fragment() {
secondary_font_color_label?.text = getString(R.string.transparent) secondary_font_color_label?.text = getString(R.string.transparent)
} else { } else {
secondary_font_color_label?.text = secondary_font_color_label?.text =
"#%s".format(Integer.toHexString(ColorHelper.getSecondaryFontColor())).toUpperCase() "#%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()
} }
} }
}) })
@ -133,7 +186,29 @@ class GeneralTabFragment : Fragment() {
secondary_font_color_label?.text = getString(R.string.transparent) secondary_font_color_label?.text = getString(R.string.transparent)
} else { } else {
secondary_font_color_label?.text = secondary_font_color_label?.text =
"#%s".format(Integer.toHexString(ColorHelper.getSecondaryFontColor())).toUpperCase() "#%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)
} }
} }
}) })
@ -144,7 +219,18 @@ class GeneralTabFragment : Fragment() {
background_color_label?.text = getString(R.string.transparent) background_color_label?.text = getString(R.string.transparent)
} else { } else {
background_color_label?.text = background_color_label?.text =
"#%s".format(Integer.toHexString(ColorHelper.getBackgroundColor())).toUpperCase() "#%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()
} }
} }
}) })
@ -155,14 +241,37 @@ class GeneralTabFragment : Fragment() {
background_color_label?.text = getString(R.string.transparent) background_color_label?.text = getString(R.string.transparent)
} else { } else {
background_color_label?.text = background_color_label?.text =
"#%s".format(Integer.toHexString(ColorHelper.getBackgroundColor())).toUpperCase() "#%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 { viewModel.textShadow.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
text_shadow_label?.text = getString(SettingsStringHelper.getTextShadowString(it)) 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))
}
} }
}) })
@ -174,7 +283,29 @@ class GeneralTabFragment : Fragment() {
viewModel.customFont.observe(viewLifecycleOwner, Observer { viewModel.customFont.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
custom_font_label?.text = getString(SettingsStringHelper.getCustomFontLabel(it)) 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())
} }
}) })
@ -186,15 +317,6 @@ class GeneralTabFragment : Fragment() {
}) })
} }
private fun maintainScrollPosition(callback: () -> Unit) {
val scrollPosition = scrollView.scrollY
callback.invoke()
lifecycleScope.launch {
delay(200)
scrollView.smoothScrollTo(0, scrollPosition)
}
}
private fun setupListener() { private fun setupListener() {
action_main_text_size.setOnClickListener { action_main_text_size.setOnClickListener {
val dialog = BottomSheetMenu<Float>(requireContext(), header = getString(R.string.title_main_text_size)).setSelectedValue(Preferences.textMainSize) val dialog = BottomSheetMenu<Float>(requireContext(), header = getString(R.string.title_main_text_size)).setSelectedValue(Preferences.textMainSize)
@ -220,15 +342,23 @@ class GeneralTabFragment : Fragment() {
BottomSheetColorPicker(requireContext(), BottomSheetColorPicker(requireContext(),
colors = colors, colors = colors,
header = getString(R.string.settings_font_color_title), header = getString(R.string.settings_font_color_title),
getSelected = ColorHelper::getFontColorRgb, getSelected = { ColorHelper.getFontColorRgb(activity?.isDarkTheme() == true) },
onColorSelected = { color: Int -> onColorSelected = { color: Int ->
val colorString = Integer.toHexString(color) val colorString = Integer.toHexString(color)
Preferences.textGlobalColor = "#" + if (colorString.length > 6) colorString.substring(2) else colorString 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, showAlphaSelector = true,
alpha = Preferences.textGlobalAlpha.toIntValue(), alpha = if (activity?.isDarkTheme() == true) Preferences.textGlobalAlphaDark.toIntValue() else Preferences.textGlobalAlpha.toIntValue(),
onAlphaChangeListener = { alpha -> onAlphaChangeListener = { alpha ->
Preferences.textGlobalAlpha = alpha.toHexValue() if (activity?.isDarkTheme() == true) {
Preferences.textGlobalAlphaDark = alpha.toHexValue()
} else {
Preferences.textGlobalAlpha = alpha.toHexValue()
}
} }
).show() ).show()
} }
@ -237,19 +367,55 @@ class GeneralTabFragment : Fragment() {
BottomSheetColorPicker(requireContext(), BottomSheetColorPicker(requireContext(),
colors = colors, colors = colors,
header = getString(R.string.settings_secondary_font_color_title), header = getString(R.string.settings_secondary_font_color_title),
getSelected = ColorHelper::getSecondaryFontColorRgb, getSelected = { ColorHelper.getSecondaryFontColorRgb(activity?.isDarkTheme() == true) },
onColorSelected = { color: Int -> onColorSelected = { color: Int ->
val colorString = Integer.toHexString(color) val colorString = Integer.toHexString(color)
Preferences.textSecondaryColor = "#" + if (colorString.length > 6) colorString.substring(2) else colorString 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, showAlphaSelector = true,
alpha = Preferences.textSecondaryAlpha.toIntValue(), alpha = if (activity?.isDarkTheme() == true) Preferences.textSecondaryAlphaDark.toIntValue() else Preferences.textSecondaryAlpha.toIntValue(),
onAlphaChangeListener = { alpha -> onAlphaChangeListener = { alpha ->
Preferences.textSecondaryAlpha = alpha.toHexValue() if (activity?.isDarkTheme() == true) {
Preferences.textSecondaryAlphaDark = alpha.toHexValue()
} else {
Preferences.textSecondaryAlpha = alpha.toHexValue()
}
} }
).show() ).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 { action_date_format.setOnClickListener {
val now = Calendar.getInstance() val now = Calendar.getInstance()
val dialog = BottomSheetMenu<String>(requireContext(), header = getString(R.string.settings_date_format_title)).setSelectedValue(Preferences.dateFormat) val dialog = BottomSheetMenu<String>(requireContext(), header = getString(R.string.settings_date_format_title)).setSelectedValue(Preferences.dateFormat)
@ -261,10 +427,20 @@ class GeneralTabFragment : Fragment() {
dialog.addItem(getString(R.string.custom_date_format), "-") dialog.addItem(getString(R.string.custom_date_format), "-")
dialog.addOnSelectItemListener { value -> dialog.addOnSelectItemListener { value ->
if (value == "-") { when (value) {
startActivity(Intent(requireContext(), CustomDateActivity::class.java)) "-" -> {
} else { startActivity(Intent(requireContext(), CustomDateActivity::class.java))
Preferences.dateFormat = value }
"" -> {
Preferences.blockingBulk {
isDateCapitalize = false
isDateUppercase = false
}
Preferences.dateFormat = value
}
else -> {
Preferences.dateFormat = value
}
} }
}.show() }.show()
} }
@ -273,77 +449,87 @@ class GeneralTabFragment : Fragment() {
BottomSheetColorPicker(requireContext(), BottomSheetColorPicker(requireContext(),
colors = colors, colors = colors,
header = getString(R.string.settings_background_color_title), header = getString(R.string.settings_background_color_title),
getSelected = { ColorHelper.getBackgroundColorRgb() }, getSelected = { ColorHelper.getBackgroundColorRgb(activity?.isDarkTheme() == true) },
onColorSelected = { color: Int -> onColorSelected = { color: Int ->
val colorString = Integer.toHexString(color) val colorString = Integer.toHexString(color)
Preferences.backgroundCardColor = "#" + if (colorString.length > 6) colorString.substring(2) else colorString 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, showAlphaSelector = true,
alpha = Preferences.backgroundCardAlpha.toIntValue(), alpha = if (activity?.isDarkTheme() == true) Preferences.backgroundCardAlphaDark.toIntValue() else Preferences.backgroundCardAlpha.toIntValue(),
onAlphaChangeListener = { alpha -> onAlphaChangeListener = { alpha ->
Preferences.backgroundCardAlpha = alpha.toHexValue() if (activity?.isDarkTheme() == true) {
Preferences.backgroundCardAlphaDark = alpha.toHexValue()
} else {
Preferences.backgroundCardAlpha = alpha.toHexValue()
}
} }
).show() ).show()
} }
action_text_shadow.setOnClickListener { action_text_shadow.setOnClickListener {
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.title_text_shadow)).setSelectedValue(Preferences.textShadow) 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 { (2 downTo 0).forEach {
dialog.addItem(getString(SettingsStringHelper.getTextShadowString(it)), it) dialog.addItem(getString(SettingsStringHelper.getTextShadowString(it)), it)
} }
dialog.addOnSelectItemListener { value -> dialog.addOnSelectItemListener { value ->
Preferences.textShadow = value if (activity?.isDarkTheme() == true) {
Preferences.textShadowDark = value
} else {
Preferences.textShadow = value
}
}.show() }.show()
} }
action_custom_font.setOnClickListener { action_custom_font.setOnClickListener {
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_custom_font_title)).setSelectedValue(Preferences.customFont) val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_custom_font_title)).setSelectedValue(Preferences.customFont)
(0..1).forEach { dialog.addItem(SettingsStringHelper.getCustomFontLabel(requireContext(), 0), 0)
dialog.addItem(getString(SettingsStringHelper.getCustomFontLabel(it)), it)
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 -> dialog.addOnSelectItemListener { value ->
Preferences.customFont = 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() }.show()
/*
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "* / *" TO FIX WITHOUT SPACE
intent.addCategory(Intent.CATEGORY_OPENABLE)
try {
startActivityForResult(Intent.createChooser(intent, "Select a File to Upload"), Constants.CUSTOM_FONT_CHOOSER_REQUEST_CODE)
} catch (ex: android.content.ActivityNotFoundException) {
Toast.makeText(this, "Please install a File Manager.", Toast.LENGTH_SHORT).show()
}
*/
} }
action_show_dividers.setOnClickListener { action_show_dividers.setOnClickListener {
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_show_dividers_title)).setSelectedValue(Preferences.showDividers) show_dividers_toggle.isChecked = !show_dividers_toggle.isChecked
.addItem(getString(R.string.settings_visible), true) }
.addItem(getString(R.string.settings_not_visible), false)
.addOnSelectItemListener { value -> show_dividers_toggle.setOnCheckedChangeListener { _, isChecked ->
Preferences.showDividers = value Preferences.showDividers = isChecked
}.show()
} }
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { private fun maintainScrollPosition(callback: () -> Unit) {
if (resultCode == Activity.RESULT_OK) { scrollView.isScrollable = false
when (requestCode) { callback.invoke()
RequestCode.CUSTOM_FONT_CHOOSER_REQUEST_CODE.code -> { lifecycleScope.launch {
/*val uri = data.data delay(200)
Log.d("AW", "File Uri: " + uri.toString()) scrollView.isScrollable = true
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)
} }
} }

View File

@ -8,8 +8,10 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.content.pm.PackageManager import android.content.pm.PackageManager
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.util.Log import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -34,6 +36,7 @@ import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
import com.tommasoberlose.anotherwidget.components.CustomNotesDialog import com.tommasoberlose.anotherwidget.components.CustomNotesDialog
import com.tommasoberlose.anotherwidget.components.GlanceProviderSortMenu import com.tommasoberlose.anotherwidget.components.GlanceProviderSortMenu
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
import com.tommasoberlose.anotherwidget.databinding.FragmentGlanceSettingsBinding import com.tommasoberlose.anotherwidget.databinding.FragmentGlanceSettingsBinding
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.AlarmHelper import com.tommasoberlose.anotherwidget.helpers.AlarmHelper
@ -41,6 +44,7 @@ import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver.Companion.FITNESS_OPTIONS import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver.Companion.FITNESS_OPTIONS
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
import com.tommasoberlose.anotherwidget.ui.activities.MusicPlayersFilterActivity
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
import com.tommasoberlose.anotherwidget.utils.checkIfFitInstalled import com.tommasoberlose.anotherwidget.utils.checkIfFitInstalled
@ -133,6 +137,9 @@ class GlanceTabFragment : Fragment() {
} }
}) })
viewModel.musicPlayersFilter.observe(viewLifecycleOwner, Observer {
})
} }
private fun setupListener() { private fun setupListener() {
@ -188,7 +195,9 @@ class GlanceTabFragment : Fragment() {
} catch (e: Exception) { } catch (e: Exception) {
alarm.showIntent?.creatorPackage ?: "" alarm.showIntent?.creatorPackage ?: ""
} }
activity?.toast(getString(R.string.next_alarm_warning).format(appNameOrPackage), long = true) MaterialBottomSheetDialog(requireContext(), message = getString(R.string.next_alarm_warning).format(appNameOrPackage))
.setPositiveButton(getString(android.R.string.ok))
.show()
} }
} }
true true
@ -237,6 +246,10 @@ class GlanceTabFragment : Fragment() {
CustomNotesDialog(requireContext()).show() CustomNotesDialog(requireContext()).show()
} }
} }
action_filter_music_players.setOnClickListener {
startActivity(Intent(requireContext(), MusicPlayersFilterActivity::class.java))
}
} }
private fun updateNextAlarmWarningUi() { private fun updateNextAlarmWarningUi() {
@ -274,19 +287,23 @@ class GlanceTabFragment : Fragment() {
} }
private fun checkNotificationPermission() { private fun checkNotificationPermission() {
if (NotificationManagerCompat.getEnabledListenerPackages(requireContext()).contains(requireContext().packageName)) { when {
notification_permission_alert?.isVisible = false NotificationManagerCompat.getEnabledListenerPackages(requireContext()).contains(requireContext().packageName) -> {
MediaPlayerHelper.updatePlayingMediaInfo(requireContext()) notification_permission_alert?.isVisible = false
show_music_label?.text = if (Preferences.showMusic) getString(R.string.settings_visible) else getString(R.string.settings_not_visible) MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
} else if (Preferences.showMusic) { show_music_label?.text = if (Preferences.showMusic) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
notification_permission_alert?.isVisible = true }
show_music_label?.text = getString(R.string.settings_request_notification_access) Preferences.showMusic -> {
notification_permission_alert?.setOnClickListener { notification_permission_alert?.isVisible = true
activity?.startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS")) 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
} }
} else {
show_music_label?.text = getString(R.string.settings_not_visible)
notification_permission_alert?.isVisible = false
} }
} }
@ -373,11 +390,11 @@ class GlanceTabFragment : 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
} }
} }

View File

@ -9,12 +9,10 @@ import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.provider.Settings import android.provider.Settings
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.util.Log
import android.util.TypedValue import android.util.TypedValue
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView
import android.widget.RelativeLayout import android.widget.RelativeLayout
import androidx.core.animation.addListener import androidx.core.animation.addListener
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
@ -35,14 +33,13 @@ import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.BitmapHelper import com.tommasoberlose.anotherwidget.helpers.BitmapHelper
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.helpers.WeatherHelper
import com.tommasoberlose.anotherwidget.helpers.WidgetHelper
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.adapters.ViewPagerAdapter import com.tommasoberlose.anotherwidget.ui.adapters.ViewPagerAdapter
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission import com.tommasoberlose.anotherwidget.utils.*
import com.tommasoberlose.anotherwidget.utils.getCurrentWallpaper
import com.tommasoberlose.anotherwidget.utils.toPixel
import kotlinx.android.synthetic.main.fragment_app_main.* import kotlinx.android.synthetic.main.fragment_app_main.*
import kotlinx.android.synthetic.main.the_widget_sans.* import kotlinx.android.synthetic.main.the_widget_sans.*
import kotlinx.coroutines.* import kotlinx.coroutines.*
@ -62,8 +59,8 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enterTransition = MaterialSharedAxis.create(MaterialSharedAxis.X, true) enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
reenterTransition = MaterialSharedAxis.create(MaterialSharedAxis.X, false) reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
} }
override fun onCreateView( override fun onCreateView(
@ -76,6 +73,7 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
subscribeUi(viewModel) subscribeUi(viewModel)
// Viewpager // Viewpager
@ -93,9 +91,9 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
}.attach() }.attach()
// Init clock // Init clock
time.setTextColor(ColorHelper.getClockFontColor()) time.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
time.setTextSize(TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(requireContext())) time.setTextSize(TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(requireContext()))
time_am_pm.setTextColor(ColorHelper.getClockFontColor()) time_am_pm.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
time_am_pm.setTextSize(TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2) time_am_pm.setTextSize(TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2)
time_container.isVisible = Preferences.showClock time_container.isVisible = Preferences.showClock
@ -134,7 +132,7 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
preview?.setCardBackgroundColor( preview?.setCardBackgroundColor(
ContextCompat.getColor( ContextCompat.getColor(
requireContext(), requireContext(),
if (ColorHelper.getFontColor() if (ColorHelper.getFontColor(activity?.isDarkTheme() == true)
.isColorDark() .isColorDark()
) android.R.color.white else R.color.colorAccent ) android.R.color.white else R.color.colorAccent
) )
@ -143,136 +141,139 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
BitmapHelper.getTintedDrawable( BitmapHelper.getTintedDrawable(
requireContext(), requireContext(),
R.drawable.card_background, R.drawable.card_background,
ColorHelper.getBackgroundColor() ColorHelper.getBackgroundColor(activity?.isDarkTheme() == true)
) )
) )
uiJob = lifecycleScope.launch(Dispatchers.IO) { WidgetHelper.runWithCustomTypeface(requireContext()) { typeface ->
val generatedView = MainWidget.generateWidgetView(requireContext()) uiJob = lifecycleScope.launch(Dispatchers.IO) {
val generatedView = MainWidget.generateWidgetView(requireContext(), typeface)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
generatedView.measure(0, 0) generatedView.measure(0, 0)
preview?.measure(0, 0) preview?.measure(0, 0)
} }
val bitmap = if (preview != null) { val bitmap = if (preview != null) {
BitmapHelper.getBitmapFromView( BitmapHelper.getBitmapFromView(
generatedView, generatedView,
if (preview.width > 0) preview.width else generatedView.measuredWidth, if (preview.width > 0) preview.width else generatedView.measuredWidth,
generatedView.measuredHeight generatedView.measuredHeight
) )
} else { } else {
null null
} }
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
// Clock // Clock
time?.setTextColor(ColorHelper.getClockFontColor()) time?.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
time_am_pm?.setTextColor(ColorHelper.getClockFontColor()) time_am_pm?.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
time?.setTextSize( time?.setTextSize(
TypedValue.COMPLEX_UNIT_SP, TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(requireContext()) Preferences.clockTextSize.toPixel(requireContext())
) )
time_am_pm?.setTextSize( time_am_pm?.setTextSize(
TypedValue.COMPLEX_UNIT_SP, TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2 Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2
) )
time_am_pm?.isVisible = Preferences.showAMPMIndicator time_am_pm?.isVisible = Preferences.showAMPMIndicator
// Clock bottom margin // Clock bottom margin
clock_bottom_margin_none?.isVisible = clock_bottom_margin_none?.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.value Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.value
clock_bottom_margin_small?.isVisible = clock_bottom_margin_small?.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.SMALL.value Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.SMALL.value
clock_bottom_margin_medium?.isVisible = clock_bottom_margin_medium?.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.MEDIUM.value Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.MEDIUM.value
clock_bottom_margin_large?.isVisible = clock_bottom_margin_large?.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.LARGE.value Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.LARGE.value
if ((Preferences.showClock && (time?.alpha ?: 1f < 1f)) || (!Preferences.showClock && (time?.alpha ?: 0f > 0f))) { if ((Preferences.showClock && (time?.alpha ?: 1f < 1f)) || (!Preferences.showClock && (time?.alpha ?: 0f > 0f))) {
if (Preferences.showClock) { 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 { time_container?.layoutParams = time_container.layoutParams.apply {
height = RelativeLayout.LayoutParams.WRAP_CONTENT height = RelativeLayout.LayoutParams.WRAP_CONTENT
} }
time_container?.measure(0, 0) 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) { if (preview != null && preview.height == 0) {
ValueAnimator.ofInt( ValueAnimator.ofInt(
preview.height, preview.height,
PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel( PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
requireContext() requireContext()
) else 0 ) else 0
).apply { ).apply {
duration = 500L duration = 300L
addUpdateListener { addUpdateListener {
if (preview != null) { if (preview != null) {
val animatedValue = animatedValue as Int val animatedValue = animatedValue as Int
val layoutParams = preview.layoutParams val layoutParams = preview.layoutParams
layoutParams.height = animatedValue layoutParams.height = animatedValue
preview.layoutParams = layoutParams preview?.layoutParams = layoutParams
} }
} }
}.start() }.start()
} }
} else {
time_container?.layoutParams = time_container.layoutParams.apply { widget_loader?.animate()?.scaleX(0f)?.scaleY(0f)?.alpha(0f)
height = RelativeLayout.LayoutParams.WRAP_CONTENT ?.setDuration(200L)?.start()
bitmap_container?.apply {
setImageBitmap(bitmap)
scaleX = 0.9f
scaleY = 0.9f
} }
time_container?.measure(0, 0) widget?.animate()?.alpha(1f)?.start()
} }
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 { } else {
@ -348,8 +349,15 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
tabs?.getTabAt(2)?.orCreateBadge?.apply { tabs?.getTabAt(2)?.orCreateBadge?.apply {
backgroundColor = ContextCompat.getColor(requireContext(), R.color.errorColorText) backgroundColor = ContextCompat.getColor(requireContext(), R.color.errorColorText)
badgeGravity = BadgeDrawable.TOP_END badgeGravity = BadgeDrawable.TOP_END
}?.isVisible = Preferences.showWeather && (Preferences.weatherProviderApi == "" || (Preferences.customLocationAdd == "" && activity?.checkGrantedPermission(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACCESS_BACKGROUND_LOCATION else Manifest.permission.ACCESS_FINE_LOCATION) != true)) }?.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 // Music error indicator
tabs?.getTabAt(4)?.orCreateBadge?.apply { tabs?.getTabAt(4)?.orCreateBadge?.apply {
@ -372,7 +380,7 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
super.onPause() super.onPause()
} }
var delayJob: Job? = null private var delayJob: Job? = null
override fun onSharedPreferenceChanged(preferences: SharedPreferences, p1: String) { override fun onSharedPreferenceChanged(preferences: SharedPreferences, p1: String) {
delayJob?.cancel() delayJob?.cancel()

View File

@ -50,8 +50,8 @@ class SettingsFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enterTransition = MaterialSharedAxis.create(MaterialSharedAxis.X, true) enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
returnTransition = MaterialSharedAxis.create(MaterialSharedAxis.X, false) returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
} }
override fun onCreateView( override fun onCreateView(
@ -65,6 +65,8 @@ class SettingsFragment : Fragment() {
binding.lifecycleOwner = this binding.lifecycleOwner = this
binding.viewModel = viewModel binding.viewModel = viewModel
subscribeUi(viewModel)
return binding.root return binding.root
} }
@ -75,7 +77,8 @@ class SettingsFragment : Fragment() {
Navigation.findNavController(it).popBackStack() Navigation.findNavController(it).popBackStack()
} }
subscribeUi(viewModel) show_widget_preview_toggle.isChecked = Preferences.showPreview
show_wallpaper_toggle.isChecked = Preferences.showWallpaper
setupListener() setupListener()
@ -120,44 +123,26 @@ class SettingsFragment : Fragment() {
} }
private fun setupListener() { private fun setupListener() {
action_show_widget_preview.setOnClickListener { action_show_widget_preview.setOnClickListener {
maintainScrollPosition { show_widget_preview_toggle.isChecked = !show_widget_preview_toggle.isChecked
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.action_show_widget_preview)) }
.setSelectedValue(Preferences.showPreview)
.addItem( show_widget_preview_toggle.setOnCheckedChangeListener { _, isChecked ->
getString(R.string.settings_visible), Preferences.showPreview = isChecked
true
)
.addItem(
getString(R.string.settings_not_visible),
false
)
.addOnSelectItemListener { value ->
Preferences.showPreview = value
}.show()
}
} }
action_show_wallpaper.setOnClickListener { 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) action_show_wallpaper.setOnClickListener {
.addItem( show_wallpaper_toggle.isChecked = !show_wallpaper_toggle.isChecked
getString(R.string.settings_visible), }
true
) show_wallpaper_toggle.setOnCheckedChangeListener { _, isChecked ->
.addItem( if (isChecked) {
getString(R.string.settings_not_visible), requirePermission()
false } else {
) Preferences.showWallpaper = isChecked
.addOnSelectItemListener { value ->
if (value) {
requirePermission()
} else {
Preferences.showWallpaper = value
}
}.show()
} }
} }
@ -199,23 +184,29 @@ class SettingsFragment : 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 {
WeatherHelper.updateWeather(requireContext()) viewLifecycleOwner.lifecycleScope.launch {
WeatherHelper.updateWeather(requireContext())
}
CalendarHelper.updateEventList(requireContext()) CalendarHelper.updateEventList(requireContext())
MediaPlayerHelper.updatePlayingMediaInfo(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
} }
} }
@ -226,8 +217,11 @@ class SettingsFragment : 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(

View File

@ -25,6 +25,8 @@ 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
@ -100,15 +102,24 @@ class WeatherTabFragment : Fragment() {
checkLocationPermission() checkLocationPermission()
}) })
viewModel.weatherProviderApi.observe(viewLifecycleOwner, Observer { viewModel.weatherProvider.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
label_weather_provider.text = WeatherHelper.getProviderName(requireContext(), Constants.WeatherProvider.fromInt(it)!!)
checkWeatherProviderConfig() checkWeatherProviderConfig()
} }
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
} }
@ -133,12 +144,12 @@ class WeatherTabFragment : Fragment() {
viewModel.weatherIconPack.observe(viewLifecycleOwner, Observer { viewModel.weatherIconPack.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
label_weather_icon_pack?.text = getString(R.string.settings_weather_icon_pack_default).format((it + 1)) 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("01d"))) // weather_icon_pack.setImageDrawable(ContextCompat.getDrawable(requireContext(), WeatherHelper.getWeatherIconResource("02d")))
if (it == Constants.WeatherIconPack.MINIMAL.value) { // if (it == Constants.WeatherIconPack.MINIMAL.value) {
weather_icon_pack.setColorFilter(ContextCompat.getColor(requireContext(), R.color.colorPrimaryText)) // weather_icon_pack.setColorFilter(ContextCompat.getColor(requireContext(), R.color.colorPrimaryText))
} else { // } else {
weather_icon_pack.setColorFilter(ContextCompat.getColor(requireContext(), android.R.color.transparent)) // weather_icon_pack.setColorFilter(ContextCompat.getColor(requireContext(), android.R.color.transparent))
} // }
} }
checkLocationPermission() checkLocationPermission()
}) })
@ -159,11 +170,17 @@ class WeatherTabFragment : 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 { } else {
location_permission_alert?.isVisible = false location_permission_alert?.isVisible = false
@ -171,11 +188,11 @@ class WeatherTabFragment : Fragment() {
} }
private fun checkWeatherProviderConfig() { private fun checkWeatherProviderConfig() {
label_weather_provider_api_key?.text = weather_provider_error.isVisible = Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-"
if (Preferences.weatherProviderApi == "") getString(R.string.settings_weather_provider_api_key_subtitle_not_set) else getString( weather_provider_error?.text = Preferences.weatherProviderError
R.string.settings_weather_provider_api_key_subtitle_all_set
) weather_provider_location_error.isVisible = Preferences.weatherProviderLocationError != ""
label_weather_provider_api_key?.setTextColor(ContextCompat.getColor(requireContext(), if (Preferences.weatherProviderApi == "" && Preferences.showWeather) R.color.errorColorText else R.color.colorSecondaryText)) weather_provider_location_error?.text = Preferences.weatherProviderLocationError
} }
private fun setupListener() { private fun setupListener() {
@ -191,7 +208,7 @@ class WeatherTabFragment : Fragment() {
Preferences.showWeather = enabled Preferences.showWeather = enabled
} }
action_weather_provider_api_key.setOnClickListener { action_weather_provider.setOnClickListener {
if (Preferences.showWeather) { if (Preferences.showWeather) {
startActivityForResult( startActivityForResult(
Intent(requireContext(), WeatherProviderActivity::class.java), Intent(requireContext(), WeatherProviderActivity::class.java),
@ -215,6 +232,11 @@ class WeatherTabFragment : 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()
} }
@ -236,13 +258,7 @@ class WeatherTabFragment : Fragment() {
action_weather_icon_pack.setOnClickListener { action_weather_icon_pack.setOnClickListener {
if (Preferences.showWeather) { if (Preferences.showWeather) {
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_weather_icon_pack_title)).setSelectedValue(Preferences.weatherIconPack) IconPackSelector(requireContext(), header = getString(R.string.settings_weather_icon_pack_title)).show()
Constants.WeatherIconPack.values().forEach {
dialog.addItem(getString(R.string.settings_weather_icon_pack_default).format(it.value + 1), it.value)
}
dialog.addOnSelectItemListener { value ->
Preferences.weatherIconPack = value
}.show()
} }
} }
@ -271,7 +287,7 @@ class WeatherTabFragment : Fragment() {
MainWidget.updateWidget(requireContext()) MainWidget.updateWidget(requireContext())
} }
RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code -> { RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code -> {
WeatherReceiver.setOneTimeUpdate(requireContext()) checkLocationPermission()
} }
} }
} }
@ -303,11 +319,11 @@ class WeatherTabFragment : 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
} }
} }
} }

View File

@ -8,5 +8,6 @@ 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 = Preferences.asLiveData(Preferences::isDateCapitalize) val isDateCapitalize = MutableLiveData<Boolean>(Preferences.isDateCapitalize)
val isDateUppercase = MutableLiveData<Boolean>(Preferences.isDateUppercase)
} }

View File

@ -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)
}
}
}

View File

@ -13,12 +13,23 @@ class MainViewModel : ViewModel() {
val textSecondaryAlpha = Preferences.asLiveData(Preferences::textSecondaryAlpha) val textSecondaryAlpha = Preferences.asLiveData(Preferences::textSecondaryAlpha)
val backgroundCardColor = Preferences.asLiveData(Preferences::backgroundCardColor) val backgroundCardColor = Preferences.asLiveData(Preferences::backgroundCardColor)
val backgroundCardAlpha = Preferences.asLiveData(Preferences::backgroundCardAlpha) val backgroundCardAlpha = Preferences.asLiveData(Preferences::backgroundCardAlpha)
val textGlobalColorDark = Preferences.asLiveData(Preferences::textGlobalColorDark)
val textGlobalAlphaDark = Preferences.asLiveData(Preferences::textGlobalAlphaDark)
val textSecondaryColorDark = Preferences.asLiveData(Preferences::textSecondaryColorDark)
val textSecondaryAlphaDark = Preferences.asLiveData(Preferences::textSecondaryAlphaDark)
val backgroundCardColorDark = Preferences.asLiveData(Preferences::backgroundCardColorDark)
val backgroundCardAlphaDark = Preferences.asLiveData(Preferences::backgroundCardAlphaDark)
val textMainSize = Preferences.asLiveData(Preferences::textMainSize) val textMainSize = Preferences.asLiveData(Preferences::textMainSize)
val textSecondSize = Preferences.asLiveData(Preferences::textSecondSize) val textSecondSize = Preferences.asLiveData(Preferences::textSecondSize)
val textShadow = Preferences.asLiveData(Preferences::textShadow) val textShadow = Preferences.asLiveData(Preferences::textShadow)
val textShadowDark = Preferences.asLiveData(Preferences::textShadowDark)
val customFont = Preferences.asLiveData(Preferences::customFont) val customFont = Preferences.asLiveData(Preferences::customFont)
val customFontFile = Preferences.asLiveData(Preferences::customFontFile)
val customFontName = Preferences.asLiveData(Preferences::customFontName)
val customFontVariant = Preferences.asLiveData(Preferences::customFontVariant)
val secondRowInformation = Preferences.asLiveData(Preferences::secondRowInformation) val secondRowInformation = Preferences.asLiveData(Preferences::secondRowInformation)
val showDividers = Preferences.asLiveData(Preferences::showDividers) val showDividers = Preferences.asLiveData(Preferences::showDividers)
val secondRowTopMargin = Preferences.asLiveData(Preferences::secondRowTopMargin)
// Calendar Settings // Calendar Settings
val showEvents = Preferences.asLiveData(Preferences::showEvents) val showEvents = Preferences.asLiveData(Preferences::showEvents)
@ -30,12 +41,15 @@ class MainViewModel : ViewModel() {
val openEventDetails = Preferences.asLiveData(Preferences::openEventDetails) val openEventDetails = Preferences.asLiveData(Preferences::openEventDetails)
val calendarAppName = Preferences.asLiveData(Preferences::calendarAppName) val calendarAppName = Preferences.asLiveData(Preferences::calendarAppName)
val widgetUpdateFrequency = Preferences.asLiveData(Preferences::widgetUpdateFrequency) val widgetUpdateFrequency = Preferences.asLiveData(Preferences::widgetUpdateFrequency)
val showOnlyBusyEvents = Preferences.asLiveData(Preferences::showOnlyBusyEvents)
// Clock Settings // Clock Settings
val showClock = Preferences.asLiveData(Preferences::showClock) val showClock = Preferences.asLiveData(Preferences::showClock)
val clockTextSize = Preferences.asLiveData(Preferences::clockTextSize) val clockTextSize = Preferences.asLiveData(Preferences::clockTextSize)
val clockTextColor = Preferences.asLiveData(Preferences::clockTextColor) val clockTextColor = Preferences.asLiveData(Preferences::clockTextColor)
val clockTextAlpha = Preferences.asLiveData(Preferences::clockTextAlpha) val clockTextAlpha = Preferences.asLiveData(Preferences::clockTextAlpha)
val clockTextColorDark = Preferences.asLiveData(Preferences::clockTextColorDark)
val clockTextAlphaDark = Preferences.asLiveData(Preferences::clockTextAlphaDark)
val showAMPMIndicator = Preferences.asLiveData(Preferences::showAMPMIndicator) val showAMPMIndicator = Preferences.asLiveData(Preferences::showAMPMIndicator)
val clockAppName = Preferences.asLiveData(Preferences::clockAppName) val clockAppName = Preferences.asLiveData(Preferences::clockAppName)
@ -50,12 +64,15 @@ class MainViewModel : ViewModel() {
val weatherRefreshPeriod = Preferences.asLiveData(Preferences::weatherRefreshPeriod) val weatherRefreshPeriod = Preferences.asLiveData(Preferences::weatherRefreshPeriod)
val weatherAppName = Preferences.asLiveData(Preferences::weatherAppName) val weatherAppName = Preferences.asLiveData(Preferences::weatherAppName)
val weatherProviderApi = Preferences.asLiveData(Preferences::weatherProviderApi) val weatherProviderApi = Preferences.asLiveData(Preferences::weatherProviderApiOpen)
val customLocationAdd = Preferences.asLiveData(Preferences::customLocationAdd) val customLocationAdd = Preferences.asLiveData(Preferences::customLocationAdd)
val showWeatherWarning = Preferences.asLiveData(Preferences::showWeatherWarning) val showWeatherWarning = Preferences.asLiveData(Preferences::showWeatherWarning)
val weatherIconPack = Preferences.asLiveData(Preferences::weatherIconPack) val weatherIconPack = Preferences.asLiveData(Preferences::weatherIconPack)
val weatherProvider = Preferences.asLiveData(Preferences::weatherProvider)
val weatherProviderError = Preferences.asLiveData(Preferences::weatherProviderError)
val weatherProviderLocationError = Preferences.asLiveData(Preferences::weatherProviderLocationError)
// Glance // Glance
val showGlance = Preferences.asLiveData(Preferences::showGlance) val showGlance = Preferences.asLiveData(Preferences::showGlance)
@ -64,6 +81,7 @@ class MainViewModel : ViewModel() {
val showBatteryCharging = Preferences.asLiveData(Preferences::showBatteryCharging) val showBatteryCharging = Preferences.asLiveData(Preferences::showBatteryCharging)
val showDailySteps = Preferences.asLiveData(Preferences::showDailySteps) val showDailySteps = Preferences.asLiveData(Preferences::showDailySteps)
val customInfo = Preferences.asLiveData(Preferences::customNotes) val customInfo = Preferences.asLiveData(Preferences::customNotes)
val musicPlayersFilter = Preferences.asLiveData(Preferences::musicPlayersFilter)
// Advanced Settings // Advanced Settings
val darkThemePreference = Preferences.asLiveData(Preferences::darkThemePreference) val darkThemePreference = Preferences.asLiveData(Preferences::darkThemePreference)

View File

@ -0,0 +1,38 @@
package com.tommasoberlose.anotherwidget.ui.viewmodels
import android.app.Application
import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.util.Log
import androidx.lifecycle.*
import com.chibatching.kotpref.livedata.asLiveData
import com.tommasoberlose.anotherwidget.global.Preferences
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class MusicPlayersFilterViewModel(application: Application) : AndroidViewModel(application) {
val pm: PackageManager by lazy { application.packageManager }
val appList: MutableLiveData<List<ResolveInfo>> = MutableLiveData()
val searchInput: MutableLiveData<String> = MutableLiveData("")
var musicPlayersFilter = Preferences.asLiveData(Preferences::musicPlayersFilter)
init {
viewModelScope.launch(Dispatchers.IO) {
val mainIntent = Intent(Intent.ACTION_MAIN, null).apply {
addCategory(Intent.CATEGORY_LAUNCHER)
}
val app = application.packageManager.queryIntentActivities(mainIntent, 0)
val sortedApp = app.sortedWith(Comparator { app1: ResolveInfo, app2: ResolveInfo ->
app1.loadLabel(pm).toString().compareTo(app2.loadLabel(pm).toString())
})
withContext(Dispatchers.Main) {
appList.postValue(sortedApp)
}
}
}
}

View File

@ -0,0 +1,19 @@
package com.tommasoberlose.anotherwidget.ui.viewmodels
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.chibatching.kotpref.livedata.asLiveData
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences
class WeatherProviderViewModel(application: Application) : AndroidViewModel(application) {
val weatherProvider = Preferences.asLiveData(Preferences::weatherProvider)
val weatherProviderError = Preferences.asLiveData(Preferences::weatherProviderError)
val weatherProviderLocationError = Preferences.asLiveData(Preferences::weatherProviderLocationError)
}

View File

@ -11,14 +11,18 @@ import android.content.res.Resources
import android.graphics.Color import android.graphics.Color
import android.graphics.Typeface import android.graphics.Typeface
import android.os.Bundle import android.os.Bundle
import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import android.text.format.DateUtils import android.text.format.DateUtils
import android.util.Log import android.util.Log
import android.util.TypedValue import android.util.TypedValue
import android.view.View import android.view.View
import android.widget.ImageView import android.view.ViewGroup
import android.widget.RemoteViews import android.widget.*
import android.widget.TextView
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.provider.FontRequest
import androidx.core.provider.FontsContractCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.db.EventRepository import com.tommasoberlose.anotherwidget.db.EventRepository
@ -26,10 +30,9 @@ import com.tommasoberlose.anotherwidget.global.Actions
import com.tommasoberlose.anotherwidget.global.Constants import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.* import com.tommasoberlose.anotherwidget.helpers.*
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
import com.tommasoberlose.anotherwidget.receivers.* import com.tommasoberlose.anotherwidget.receivers.*
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission import com.tommasoberlose.anotherwidget.utils.*
import com.tommasoberlose.anotherwidget.utils.getCapWordString
import com.tommasoberlose.anotherwidget.utils.toPixel
import kotlinx.android.synthetic.main.the_widget.view.* import kotlinx.android.synthetic.main.the_widget.view.*
import java.lang.Exception import java.lang.Exception
import java.text.DateFormat import java.text.DateFormat
@ -90,10 +93,14 @@ class MainWidget : AppWidgetProvider() {
val height = displayMetrics.heightPixels val height = displayMetrics.heightPixels
val dimensions = WidgetHelper.WidgetSizeProvider(context, appWidgetManager).getWidgetsSize(appWidgetId) val dimensions = WidgetHelper.WidgetSizeProvider(context, appWidgetManager).getWidgetsSize(appWidgetId)
generateWidgetView(context, appWidgetId, appWidgetManager, min(dimensions.first - 8.toPixel(context), min(width, height) - 16.toPixel(context)))
WidgetHelper.runWithCustomTypeface(context) {
generateWidgetView(context, appWidgetId, appWidgetManager, min(dimensions.first - 8.toPixel(context), min(width, height) - 16.toPixel(context)), it)
}
} }
private fun generateWidgetView(context: Context, appWidgetId: Int, appWidgetManager: AppWidgetManager, w: Int) { private fun generateWidgetView(context: Context, appWidgetId: Int, appWidgetManager: AppWidgetManager, w: Int, typeface: Typeface? = null) {
var views = RemoteViews(context.packageName, R.layout.the_widget_sans) var views = RemoteViews(context.packageName, R.layout.the_widget_sans)
try { try {
@ -101,12 +108,12 @@ class MainWidget : AppWidgetProvider() {
views.setInt( views.setInt(
R.id.widget_shape_background, R.id.widget_shape_background,
"setColorFilter", "setColorFilter",
ColorHelper.getBackgroundColorRgb() ColorHelper.getBackgroundColorRgb(context.isDarkTheme())
) )
views.setInt( views.setInt(
R.id.widget_shape_background, R.id.widget_shape_background,
"setImageAlpha", "setImageAlpha",
ColorHelper.getBackgroundAlpha() ColorHelper.getBackgroundAlpha(context.isDarkTheme())
) )
val refreshIntent = PendingIntent.getActivity( val refreshIntent = PendingIntent.getActivity(
context, context,
@ -125,7 +132,8 @@ class MainWidget : AppWidgetProvider() {
// Setup listener // Setup listener
try { try {
val generatedView = generateWidgetView(context)
val generatedView = generateWidgetView(context, typeface)
views.setImageViewBitmap( views.setImageViewBitmap(
R.id.bitmap_container, R.id.bitmap_container,
BitmapHelper.getBitmapFromView(generatedView, width = w) BitmapHelper.getBitmapFromView(generatedView, width = w)
@ -263,7 +271,21 @@ class MainWidget : AppWidgetProvider() {
views.setViewVisibility(R.id.empty_layout_rect, View.GONE) views.setViewVisibility(R.id.empty_layout_rect, View.GONE)
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE) views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
views.setViewVisibility(
R.id.second_row_top_margin_small_sans,
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.value) View.VISIBLE else View.GONE
)
views.setViewVisibility(
R.id.second_row_top_margin_medium_sans,
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.value) View.VISIBLE else View.GONE
)
views.setViewVisibility(
R.id.second_row_top_margin_large_sans,
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.LARGE.value) View.VISIBLE else View.GONE
)
} else if (GlanceProviderHelper.showGlanceProviders(context) && v.calendar_layout.isVisible) { } else if (GlanceProviderHelper.showGlanceProviders(context) && v.calendar_layout.isVisible) {
var showSomething = false
loop@ for (provider:Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders(context)) { loop@ for (provider:Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders(context)) {
when (provider) { when (provider) {
Constants.GlanceProviderId.PLAYING_SONG -> { Constants.GlanceProviderId.PLAYING_SONG -> {
@ -275,6 +297,7 @@ class MainWidget : AppWidgetProvider() {
PendingIntent.FLAG_UPDATE_CURRENT PendingIntent.FLAG_UPDATE_CURRENT
) )
views.setOnClickPendingIntent(R.id.second_row_rect, musicIntent) views.setOnClickPendingIntent(R.id.second_row_rect, musicIntent)
showSomething = true
break@loop break@loop
} }
} }
@ -287,6 +310,7 @@ class MainWidget : AppWidgetProvider() {
PendingIntent.FLAG_UPDATE_CURRENT PendingIntent.FLAG_UPDATE_CURRENT
) )
views.setOnClickPendingIntent(R.id.second_row_rect, alarmIntent) views.setOnClickPendingIntent(R.id.second_row_rect, alarmIntent)
showSomething = true
break@loop break@loop
} }
} }
@ -301,6 +325,7 @@ class MainWidget : AppWidgetProvider() {
PendingIntent.FLAG_UPDATE_CURRENT PendingIntent.FLAG_UPDATE_CURRENT
) )
views.setOnClickPendingIntent(R.id.second_row_rect, batteryIntent) views.setOnClickPendingIntent(R.id.second_row_rect, batteryIntent)
showSomething = true
break@loop break@loop
} }
} }
@ -319,26 +344,44 @@ class MainWidget : AppWidgetProvider() {
PendingIntent.FLAG_UPDATE_CURRENT PendingIntent.FLAG_UPDATE_CURRENT
) )
views.setOnClickPendingIntent(R.id.second_row_rect, fitIntent) views.setOnClickPendingIntent(R.id.second_row_rect, fitIntent)
showSomething = true
break@loop break@loop
} }
} }
} }
} }
views.setImageViewBitmap(
R.id.next_event_rect,
BitmapHelper.getBitmapFromView(v.next_event, draw = false)
)
views.setImageViewBitmap( if (showSomething) {
R.id.second_row_rect, views.setImageViewBitmap(
BitmapHelper.getBitmapFromView(v.second_row, draw = false) R.id.next_event_rect,
) BitmapHelper.getBitmapFromView(v.next_event, draw = false)
)
views.setViewVisibility(R.id.second_row_rect, View.VISIBLE) views.setImageViewBitmap(
views.setViewVisibility(R.id.empty_layout_rect, View.GONE) R.id.second_row_rect,
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE) BitmapHelper.getBitmapFromView(v.second_row, draw = false)
views.setOnClickPendingIntent(R.id.next_event_rect, calPIntent) )
views.setViewVisibility(R.id.second_row_rect, View.VISIBLE)
views.setViewVisibility(R.id.empty_layout_rect, View.GONE)
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
views.setOnClickPendingIntent(R.id.next_event_rect, calPIntent)
views.setViewVisibility(
R.id.second_row_top_margin_small_sans,
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.value) View.VISIBLE else View.GONE
)
views.setViewVisibility(
R.id.second_row_top_margin_medium_sans,
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.value) View.VISIBLE else View.GONE
)
views.setViewVisibility(
R.id.second_row_top_margin_large_sans,
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.LARGE.value) View.VISIBLE else View.GONE
)
}
} }
} catch (ex: Exception) { } catch (ex: Exception) {
ex.printStackTrace() ex.printStackTrace()
@ -407,8 +450,8 @@ class MainWidget : AppWidgetProvider() {
views.setViewVisibility(R.id.clock_bottom_margin_medium, View.GONE) views.setViewVisibility(R.id.clock_bottom_margin_medium, View.GONE)
views.setViewVisibility(R.id.clock_bottom_margin_large, View.GONE) views.setViewVisibility(R.id.clock_bottom_margin_large, View.GONE)
} else { } else {
views.setTextColor(R.id.time, ColorHelper.getClockFontColor()) views.setTextColor(R.id.time, ColorHelper.getClockFontColor(context.isDarkTheme()))
views.setTextColor(R.id.time_am_pm, ColorHelper.getClockFontColor()) views.setTextColor(R.id.time_am_pm, ColorHelper.getClockFontColor(context.isDarkTheme()))
views.setTextViewTextSize( views.setTextViewTextSize(
R.id.time, R.id.time,
TypedValue.COMPLEX_UNIT_SP, TypedValue.COMPLEX_UNIT_SP,
@ -457,10 +500,12 @@ class MainWidget : AppWidgetProvider() {
// Generates the widget bitmap from the view // Generates the widget bitmap from the view
fun generateWidgetView(context: Context): View { fun generateWidgetView(context: Context, typeface: Typeface? = null): View {
val eventRepository = EventRepository(context) val eventRepository = EventRepository(context)
val v = View.inflate(context, R.layout.the_widget, null) val v = View.inflate(context, R.layout.the_widget, null)
v.loader.isVisible = false
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)
@ -479,8 +524,10 @@ class MainWidget : AppWidgetProvider() {
if (Preferences.showEvents && context.checkGrantedPermission(Manifest.permission.READ_CALENDAR) && nextEvent != null) { if (Preferences.showEvents && context.checkGrantedPermission(Manifest.permission.READ_CALENDAR) && nextEvent != null) {
// Multiple counter // Multiple counter
v.action_next.isVisible = Preferences.showNextEvent && eventRepository.getEventsCount() > 1 v.action_next.isVisible =
v.action_previous.isVisible = Preferences.showNextEvent && eventRepository.getEventsCount() > 1 Preferences.showNextEvent && eventRepository.getEventsCount() > 1
v.action_previous.isVisible =
Preferences.showNextEvent && eventRepository.getEventsCount() > 1
v.next_event.text = nextEvent.title v.next_event.text = nextEvent.title
@ -493,7 +540,11 @@ class MainWidget : AppWidgetProvider() {
) )
.toLowerCase(Locale.getDefault()) .toLowerCase(Locale.getDefault())
} else { } else {
SettingsStringHelper.getAllDayEventDifferenceText(context, now.timeInMillis, nextEvent.startDate).toLowerCase(Locale.getDefault()) SettingsStringHelper.getAllDayEventDifferenceText(
context,
now.timeInMillis,
nextEvent.startDate
).toLowerCase(Locale.getDefault())
} }
v.next_event_difference_time.visibility = View.VISIBLE v.next_event_difference_time.visibility = View.VISIBLE
} else { } else {
@ -501,15 +552,30 @@ class MainWidget : AppWidgetProvider() {
} }
if (nextEvent.address != "" && Preferences.secondRowInformation == 1) { if (nextEvent.address != "" && Preferences.secondRowInformation == 1) {
v.second_row_icon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.round_place)) v.second_row_icon.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.round_place
)
)
v.next_event_date.text = nextEvent.address v.next_event_date.text = nextEvent.address
} else { } else {
v.second_row_icon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.round_today)) v.second_row_icon.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.round_today
)
)
if (!nextEvent.allDay) { if (!nextEvent.allDay) {
val startHour = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()).format(nextEvent.startDate) val startHour =
val endHour = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()).format(nextEvent.endDate) DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault())
.format(nextEvent.startDate)
val endHour =
DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault())
.format(nextEvent.endDate)
var dayDiff = TimeUnit.MILLISECONDS.toDays(nextEvent.endDate - nextEvent.startDate) var dayDiff =
TimeUnit.MILLISECONDS.toDays(nextEvent.endDate - nextEvent.startDate)
val startCal = Calendar.getInstance() val startCal = Calendar.getInstance()
startCal.timeInMillis = nextEvent.startDate startCal.timeInMillis = nextEvent.startDate
@ -519,27 +585,46 @@ class MainWidget : AppWidgetProvider() {
if (startCal.get(Calendar.HOUR_OF_DAY) > endCal.get(Calendar.HOUR_OF_DAY)) { if (startCal.get(Calendar.HOUR_OF_DAY) > endCal.get(Calendar.HOUR_OF_DAY)) {
dayDiff++ dayDiff++
} else if (startCal.get(Calendar.HOUR_OF_DAY) == endCal.get(Calendar.HOUR_OF_DAY) && startCal.get(Calendar.MINUTE) >= endCal.get(Calendar.MINUTE)) { } else if (startCal.get(Calendar.HOUR_OF_DAY) == endCal.get(Calendar.HOUR_OF_DAY) && startCal.get(
Calendar.MINUTE
) >= endCal.get(Calendar.MINUTE)
) {
dayDiff++ dayDiff++
} }
var multipleDay = "" var multipleDay = ""
if (dayDiff > 0) { if (dayDiff > 0) {
multipleDay = String.format(" (+%s%s)", dayDiff, context.getString(R.string.day_char)) multipleDay = String.format(
" (+%s%s)",
dayDiff,
context.getString(R.string.day_char)
)
} }
v.next_event_date.text = String.format("%s - %s%s", startHour, endHour, multipleDay) v.next_event_date.text =
String.format("%s - %s%s", startHour, endHour, multipleDay)
} else { } else {
val flags: Int = DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NO_YEAR or DateUtils.FORMAT_ABBREV_MONTH val flags: Int =
v.next_event_date.text = DateUtils.formatDateTime(context, nextEvent.startDate, flags) DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NO_YEAR or DateUtils.FORMAT_ABBREV_MONTH
v.next_event_date.text =
DateUtils.formatDateTime(context, nextEvent.startDate, flags)
} }
} }
v.empty_layout.visibility = View.GONE v.empty_layout.visibility = View.GONE
v.calendar_layout.visibility = View.VISIBLE v.calendar_layout.visibility = View.VISIBLE
v.second_row_top_margin_small.visibility =
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.value) View.VISIBLE else View.GONE
v.second_row_top_margin_medium.visibility =
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.value) View.VISIBLE else View.GONE
v.second_row_top_margin_large.visibility =
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.LARGE.value) View.VISIBLE else View.GONE
} else if (GlanceProviderHelper.showGlanceProviders(context)) { } else if (GlanceProviderHelper.showGlanceProviders(context)) {
v.second_row_icon.isVisible = true v.second_row_icon.isVisible = true
var showSomething = false var showSomething = false
loop@ for (provider:Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders(context)) { loop@ for (provider: Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders(
context
)) {
when (provider) { when (provider) {
Constants.GlanceProviderId.PLAYING_SONG -> { Constants.GlanceProviderId.PLAYING_SONG -> {
if (MediaPlayerHelper.isSomeonePlaying(context)) { if (MediaPlayerHelper.isSomeonePlaying(context)) {
@ -573,10 +658,11 @@ class MainWidget : AppWidgetProvider() {
if (Preferences.isCharging) { if (Preferences.isCharging) {
v.second_row_icon.isVisible = false v.second_row_icon.isVisible = false
val batteryLevel = BatteryHelper.getBatteryLevel(context) val batteryLevel = BatteryHelper.getBatteryLevel(context)
if (batteryLevel == 100) { if (batteryLevel != 100) {
v.next_event_date.text = "%s - %d%%".format(context.getString(R.string.charging), batteryLevel)
} else {
v.next_event_date.text = context.getString(R.string.charging) v.next_event_date.text = context.getString(R.string.charging)
} else {
v.next_event_date.text =
context.getString(R.string.charged)
} }
showSomething = true showSomething = true
break@loop break@loop
@ -602,7 +688,9 @@ class MainWidget : AppWidgetProvider() {
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> { Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) { if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) {
v.second_row_icon.isVisible = false v.second_row_icon.isVisible = false
v.next_event_date.text = context.getString(R.string.daily_steps_counter).format(Preferences.googleFitSteps) v.next_event_date.text =
context.getString(R.string.daily_steps_counter)
.format(Preferences.googleFitSteps)
showSomething = true showSomething = true
break@loop break@loop
} }
@ -614,6 +702,13 @@ class MainWidget : AppWidgetProvider() {
v.next_event.text = DateHelper.getDateText(context, now) v.next_event.text = DateHelper.getDateText(context, now)
v.empty_layout.visibility = View.GONE v.empty_layout.visibility = View.GONE
v.calendar_layout.visibility = View.VISIBLE v.calendar_layout.visibility = View.VISIBLE
v.second_row_top_margin_small.visibility =
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.value) View.VISIBLE else View.GONE
v.second_row_top_margin_medium.visibility =
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.value) View.VISIBLE else View.GONE
v.second_row_top_margin_large.visibility =
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.LARGE.value) View.VISIBLE else View.GONE
} else { } else {
v.second_row_icon.isVisible = false v.second_row_icon.isVisible = false
} }
@ -621,20 +716,37 @@ class MainWidget : AppWidgetProvider() {
// Color // Color
listOf<TextView>(v.empty_date, v.divider1, v.temp, v.next_event, v.next_event_difference_time, v.divider3, v.special_temp).forEach { listOf<TextView>(
it.setTextColor(ColorHelper.getFontColor()) v.empty_date,
v.divider1,
v.temp,
v.next_event,
v.next_event_difference_time,
v.divider3,
v.special_temp
).forEach {
it.setTextColor(ColorHelper.getFontColor(context.applicationContext.isDarkTheme()))
} }
if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.value) { if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.value) {
listOf<ImageView>(v.action_next, v.action_previous) listOf<ImageView>(v.action_next, v.action_previous)
} else { } else {
listOf<ImageView>(v.action_next, v.action_previous, v.empty_weather_icon, v.special_weather_icon) listOf<ImageView>(
v.action_next,
v.action_previous,
v.empty_weather_icon,
v.special_weather_icon
)
}.forEach { }.forEach {
it.setColorFilter(ColorHelper.getFontColor()) it.setColorFilter(ColorHelper.getFontColorRgb(context.applicationContext.isDarkTheme()))
it.alpha =
(if (context.isDarkTheme()) Preferences.textGlobalAlphaDark.toIntValue()
.toFloat() else Preferences.textGlobalAlpha.toIntValue()
.toFloat()) / 100
} }
listOf<TextView>(v.next_event_date, v.divider2, v.calendar_temp).forEach { listOf<TextView>(v.next_event_date, v.divider2, v.calendar_temp).forEach {
it.setTextColor(ColorHelper.getSecondaryFontColor()) it.setTextColor(ColorHelper.getSecondaryFontColor(context.applicationContext.isDarkTheme()))
} }
if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.value) { if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.value) {
@ -642,7 +754,11 @@ class MainWidget : AppWidgetProvider() {
} else { } else {
listOf<ImageView>(v.second_row_icon, v.weather_icon) listOf<ImageView>(v.second_row_icon, v.weather_icon)
}.forEach { }.forEach {
it.setColorFilter(ColorHelper.getSecondaryFontColor()) it.setColorFilter(ColorHelper.getSecondaryFontColorRgb(context.applicationContext.isDarkTheme()))
it.alpha =
(if (context.isDarkTheme()) Preferences.textSecondaryAlphaDark.toIntValue()
.toFloat() else Preferences.textSecondaryAlpha.toIntValue()
.toFloat()) / 100
} }
// Text Size // Text Size
@ -682,34 +798,82 @@ class MainWidget : AppWidgetProvider() {
// Shadows // Shadows
val shadowRadius = when (Preferences.textShadow) { val shadowRadius =
0 -> 0f when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
1 -> 5f 0 -> 0f
2 -> 5f 1 -> 5f
else -> 5f 2 -> 5f
} else -> 5f
val shadowColor = when (Preferences.textShadow) { }
0 -> Color.TRANSPARENT val shadowColor =
1 -> R.color.black_50 when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
2 -> Color.BLACK 0 -> Color.TRANSPARENT
else -> R.color.black_50 1 -> R.color.black_50
} 2 -> Color.BLACK
val shadowDy = when (Preferences.textShadow) { else -> R.color.black_50
0 -> 0f }
1 -> 0f val shadowDy =
2 -> 1f when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
else -> 0f 0 -> 0f
} 1 -> 0f
2 -> 1f
else -> 0f
}
listOf<TextView>(v.empty_date, v.divider1, v.temp, v.next_event, v.next_event_difference_time, v.next_event_date, v.divider2, v.calendar_temp, v.divider3, v.special_temp).forEach { listOf<TextView>(
v.empty_date,
v.divider1,
v.temp,
v.next_event,
v.next_event_difference_time,
v.next_event_date,
v.divider2,
v.calendar_temp,
v.divider3,
v.special_temp
).forEach {
it.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor) it.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
} }
// Custom Font // Custom Font
if (Preferences.customFont == Constants.CUSTOM_FONT_PRODUCT_SANS) { if (Preferences.customFont == Constants.CUSTOM_FONT_GOOGLE_SANS) {
val productSans: Typeface = Typeface.createFromAsset(context.assets, "fonts/product_sans_regular.ttf") val googleSans: Typeface = when (Preferences.customFontVariant) {
listOf<TextView>(v.empty_date, v.divider1, v.temp, v.next_event, v.next_event_difference_time, v.next_event_date, v.divider2, v.calendar_temp, v.divider3, v.special_temp).forEach { "100" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_thin.ttf")
it.typeface = productSans "200" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_light.ttf")
"500" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_medium.ttf")
"700" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_bold.ttf")
"800" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_black.ttf")
else -> Typeface.createFromAsset(context.assets, "fonts/google_sans_regular.ttf")
}
listOf<TextView>(
v.empty_date,
v.divider1,
v.temp,
v.next_event,
v.next_event_difference_time,
v.next_event_date,
v.divider2,
v.calendar_temp,
v.divider3,
v.special_temp
).forEach {
it.typeface = googleSans
}
} else if (Preferences.customFont == Constants.CUSTOM_FONT_DOWNLOADED && typeface != null) {
listOf<TextView>(
v.empty_date,
v.divider1,
v.temp,
v.next_event,
v.next_event_difference_time,
v.next_event_date,
v.divider2,
v.calendar_temp,
v.divider3,
v.special_temp
).forEach {
it.typeface = typeface
} }
} }
@ -718,7 +882,12 @@ class MainWidget : AppWidgetProvider() {
v.weather.visibility = View.VISIBLE v.weather.visibility = View.VISIBLE
v.calendar_weather.visibility = View.VISIBLE v.calendar_weather.visibility = View.VISIBLE
v.special_weather.visibility = View.VISIBLE v.special_weather.visibility = View.VISIBLE
val currentTemp = String.format(Locale.getDefault(), "%d °%s", Preferences.weatherTemp.roundToInt(), Preferences.weatherRealTempUnit) val currentTemp = String.format(
Locale.getDefault(),
"%d °%s",
Preferences.weatherTemp.roundToInt(),
Preferences.weatherRealTempUnit
)
val icon: String = Preferences.weatherIcon val icon: String = Preferences.weatherIcon
if (icon == "") { if (icon == "") {
@ -726,9 +895,9 @@ class MainWidget : AppWidgetProvider() {
v.empty_weather_icon.visibility = View.GONE v.empty_weather_icon.visibility = View.GONE
v.special_weather_icon.visibility = View.GONE v.special_weather_icon.visibility = View.GONE
} else { } else {
v.weather_icon.setImageResource(WeatherHelper.getWeatherIconResource(icon)) v.weather_icon.setImageResource(WeatherHelper.getWeatherIconResource(context, icon))
v.empty_weather_icon.setImageResource(WeatherHelper.getWeatherIconResource(icon)) v.empty_weather_icon.setImageResource(WeatherHelper.getWeatherIconResource(context, icon))
v.special_weather_icon.setImageResource(WeatherHelper.getWeatherIconResource(icon)) v.special_weather_icon.setImageResource(WeatherHelper.getWeatherIconResource(context, icon))
v.weather_icon.visibility = View.VISIBLE v.weather_icon.visibility = View.VISIBLE
v.empty_weather_icon.visibility = View.VISIBLE v.empty_weather_icon.visibility = View.VISIBLE
v.special_weather_icon.visibility = View.VISIBLE v.special_weather_icon.visibility = View.VISIBLE

View File

@ -95,7 +95,7 @@ fun View.expand() {
} }
} }
fun View.collapse() { fun View.collapse(duration: Long = 500L) {
if (visibility != View.GONE) { if (visibility != View.GONE) {
val initialHeight = measuredHeight val initialHeight = measuredHeight
@ -114,7 +114,7 @@ fun View.collapse() {
} }
} }
a.duration = 500L //(initialHeight / v.context.resources.displayMetrics.density).toLong() a.duration = duration //(initialHeight / v.context.resources.displayMetrics.density).toLong()
startAnimation(a) startAnimation(a)
} }
} }
@ -143,11 +143,11 @@ fun Context.isTablet(): Boolean {
} }
fun String.md5(): String { fun String.md5(): String {
val MD5 = "MD5" val mD5 = "MD5"
try { try {
// Create MD5 Hash // Create MD5 Hash
val digest = java.security.MessageDigest val digest = java.security.MessageDigest
.getInstance(MD5) .getInstance(mD5)
digest.update(toByteArray()) digest.update(toByteArray())
val messageDigest = digest.digest() val messageDigest = digest.digest()
@ -172,7 +172,7 @@ fun String.isValidEmail(): Boolean
= this.isNotEmpty() && = this.isNotEmpty() &&
Patterns.EMAIL_ADDRESS.matcher(this).matches() Patterns.EMAIL_ADDRESS.matcher(this).matches()
fun Activity.isDarkTheme(): Boolean { fun Context.isDarkTheme(): Boolean {
return resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES return resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
} }
@ -221,4 +221,13 @@ fun Context.checkIfFitInstalled(): Boolean {
} catch (e: Exception) { } catch (e: Exception) {
false false
} }
}
fun Intent.isDefaultSet(context: Context): Boolean {
val pm = context.packageManager
return try {
resolveActivity(pm) != null && resolveActivity(pm).packageName.isNotBlank()
} catch (ex: java.lang.Exception) {
false
}
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 471 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 751 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 953 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 602 B

Some files were not shown because too many files have changed in this diff Show More