Compare commits
77 Commits
Author | SHA1 | Date | |
---|---|---|---|
1ecaf7a11a | |||
2578566659 | |||
61fc0da8d0 | |||
7edb0635a7 | |||
d72ddd6d85 | |||
5d07cc8d73 | |||
1ac53e09a8 | |||
3412e044df | |||
80023da430 | |||
e2a2d17506 | |||
b93443b736 | |||
9842ba3ea9 | |||
75aba66987 | |||
f325af26f8 | |||
b61fbd193c | |||
03d9446369 | |||
23f94e63c6 | |||
01775d3a3a | |||
67abd14bb1 | |||
854cfac28c | |||
8fafe591e8 | |||
a85fefe4dc | |||
974185a89b | |||
bbe1497f8b | |||
1f22426dec | |||
40644f3657 | |||
a01c8eff63 | |||
1ee25bcc89 | |||
1bd18ac486 | |||
d24ac198a4 | |||
81578f5f4a | |||
8234a87a2a | |||
0774c6bdbe | |||
57eecd630d | |||
cce86a970c | |||
6ea40a51fe | |||
1721dff3cf | |||
c389d50b09 | |||
0ea55db4b1 | |||
3fba50fd2c | |||
06583197c7 | |||
5176331e84 | |||
65f83caeb5 | |||
60e8c267bf | |||
10a3204808 | |||
98c509ef27 | |||
ab1df499af | |||
ed9a4042c8 | |||
a102776214 | |||
0778ad4df5 | |||
8dce8a74b3 | |||
24bb811f93 | |||
0500e8d8e8 | |||
d2087d094f | |||
34fb35f2ab | |||
108ecdece0 | |||
e3f4995e93 | |||
0cdc5a3c6d | |||
9f039eec3c | |||
e9effbe799 | |||
889783bb4e | |||
d32f680519 | |||
c1d14f93bf | |||
b903fff10f | |||
20c5ce61b4 | |||
5bb81772f4 | |||
526a9ac6ac | |||
98db1380b7 | |||
ce9b343e0e | |||
21ec3c3f5d | |||
88950a84b4 | |||
fb853975e0 | |||
329eee6339 | |||
1cc5558d9e | |||
e12e908496 | |||
2aed9e3b25 | |||
6b6ec633ee |
180
.idea/assetWizardSettings.xml
generated
@ -19,6 +19,29 @@
|
||||
<option name="children">
|
||||
<map>
|
||||
<entry key="clipArt">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="values">
|
||||
<map>
|
||||
<entry key="color" value="000000" />
|
||||
<entry key="imagePath" value="/private/var/folders/cw/tkrg0g5j6lzcqwr0tfkph8w80000gn/T/ic_android_black_24dp.xml" />
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="text">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="values">
|
||||
<map>
|
||||
<entry key="color" value="000000" />
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="textAsset">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="values">
|
||||
@ -45,14 +68,47 @@
|
||||
<PersistentState>
|
||||
<option name="children">
|
||||
<map>
|
||||
<entry key="foregroundClipArt">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="values">
|
||||
<map>
|
||||
<entry key="imagePath" value="/private/var/folders/cw/tkrg0g5j6lzcqwr0tfkph8w80000gn/T/ic_android_black_24dp.xml" />
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="foregroundImage">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="values">
|
||||
<map>
|
||||
<entry key="color" value="000000" />
|
||||
<entry key="imagePath" value="$USER_HOME$/Desktop/logo-white.png" />
|
||||
<entry key="scalingPercent" value="70" />
|
||||
<entry key="trimmed" value="true" />
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="foregroundText">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="values">
|
||||
<map>
|
||||
<entry key="color" value="000000" />
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="foregroundTextAsset">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="values">
|
||||
<map>
|
||||
<entry key="color" value="000000" />
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
@ -64,7 +120,6 @@
|
||||
<map>
|
||||
<entry key="backgroundAssetType" value="COLOR" />
|
||||
<entry key="backgroundColor" value="ffffff" />
|
||||
<entry key="foregroundImage" value="$USER_HOME$/Desktop/Artboard Copy 3.png" />
|
||||
<entry key="legacyIconShape" value="CIRCLE" />
|
||||
</map>
|
||||
</option>
|
||||
@ -77,6 +132,29 @@
|
||||
<option name="children">
|
||||
<map>
|
||||
<entry key="clipArt">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="values">
|
||||
<map>
|
||||
<entry key="color" value="000000" />
|
||||
<entry key="imagePath" value="/private/var/folders/cw/tkrg0g5j6lzcqwr0tfkph8w80000gn/T/ic_android_black_24dp.xml" />
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="text">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="values">
|
||||
<map>
|
||||
<entry key="color" value="000000" />
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="textAsset">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="values">
|
||||
@ -98,6 +176,104 @@
|
||||
<option name="children">
|
||||
<map>
|
||||
<entry key="clipArt">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="values">
|
||||
<map>
|
||||
<entry key="color" value="000000" />
|
||||
<entry key="imagePath" value="/private/var/folders/cw/tkrg0g5j6lzcqwr0tfkph8w80000gn/T/ic_android_black_24dp.xml" />
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="text">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="values">
|
||||
<map>
|
||||
<entry key="color" value="000000" />
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="textAsset">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="values">
|
||||
<map>
|
||||
<entry key="color" value="000000" />
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="tvBanner">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="children">
|
||||
<map>
|
||||
<entry key="foregroundText">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="values">
|
||||
<map>
|
||||
<entry key="color" value="000000" />
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="tvChannel">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="children">
|
||||
<map>
|
||||
<entry key="foregroundClipArt">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="values">
|
||||
<map>
|
||||
<entry key="imagePath" value="/private/var/folders/cw/tkrg0g5j6lzcqwr0tfkph8w80000gn/T/ic_android_black_24dp.xml" />
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="foregroundImage">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="values">
|
||||
<map>
|
||||
<entry key="color" value="000000" />
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="foregroundText">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="values">
|
||||
<map>
|
||||
<entry key="color" value="000000" />
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="foregroundTextAsset">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="values">
|
||||
|
BIN
.idea/caches/build_file_checksums.ser
generated
Normal file
1
.idea/codeStyles/Project.xml
generated
@ -17,7 +17,6 @@
|
||||
<package name="" alias="true" withSubpackages="true" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="ALLOW_TRAILING_COMMA" value="true" />
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
|
2
.idea/misc.xml
generated
@ -61,7 +61,7 @@
|
||||
</profile-state>
|
||||
</entry>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
140
.idea/navEditor.xml
generated
@ -46,6 +46,146 @@
|
||||
</LayoutPositions>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="settings_nav_graph.xml">
|
||||
<value>
|
||||
<LayoutPositions>
|
||||
<option name="myPositions">
|
||||
<map>
|
||||
<entry key="calendarTabFragment">
|
||||
<value>
|
||||
<LayoutPositions>
|
||||
<option name="myPosition">
|
||||
<Point>
|
||||
<option name="x" value="190" />
|
||||
<option name="y" value="4" />
|
||||
</Point>
|
||||
</option>
|
||||
</LayoutPositions>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="clockTabFragment">
|
||||
<value>
|
||||
<LayoutPositions>
|
||||
<option name="myPosition">
|
||||
<Point>
|
||||
<option name="x" value="494" />
|
||||
<option name="y" value="302" />
|
||||
</Point>
|
||||
</option>
|
||||
</LayoutPositions>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="generalTabFragment">
|
||||
<value>
|
||||
<LayoutPositions>
|
||||
<option name="myPosition">
|
||||
<Point>
|
||||
<option name="x" value="-48" />
|
||||
<option name="y" value="133" />
|
||||
</Point>
|
||||
</option>
|
||||
</LayoutPositions>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="gesturesFragment">
|
||||
<value>
|
||||
<LayoutPositions>
|
||||
<option name="myPosition">
|
||||
<Point>
|
||||
<option name="x" value="703" />
|
||||
<option name="y" value="14" />
|
||||
</Point>
|
||||
</option>
|
||||
</LayoutPositions>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="glanceTabFragment">
|
||||
<value>
|
||||
<LayoutPositions>
|
||||
<option name="myPosition">
|
||||
<Point>
|
||||
<option name="x" value="2" />
|
||||
<option name="y" value="-198" />
|
||||
</Point>
|
||||
</option>
|
||||
</LayoutPositions>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="tabSelectorFragment">
|
||||
<value>
|
||||
<LayoutPositions>
|
||||
<option name="myPosition">
|
||||
<Point>
|
||||
<option name="x" value="-537" />
|
||||
<option name="y" value="216" />
|
||||
</Point>
|
||||
</option>
|
||||
<option name="myPositions">
|
||||
<map>
|
||||
<entry key="action_tabSelectorFragment_to_calendarTabFragment">
|
||||
<value>
|
||||
<LayoutPositions />
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="action_tabSelectorFragment_to_clockTabFragment">
|
||||
<value>
|
||||
<LayoutPositions />
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="action_tabSelectorFragment_to_generalTabFragment">
|
||||
<value>
|
||||
<LayoutPositions />
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="action_tabSelectorFragment_to_glanceTabFragment">
|
||||
<value>
|
||||
<LayoutPositions />
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="action_tabSelectorFragment_to_typographyTabFragment">
|
||||
<value>
|
||||
<LayoutPositions />
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="action_tabSelectorFragment_to_weatherTabFragment">
|
||||
<value>
|
||||
<LayoutPositions />
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</LayoutPositions>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="typographyTabFragment">
|
||||
<value>
|
||||
<LayoutPositions>
|
||||
<option name="myPosition">
|
||||
<Point>
|
||||
<option name="x" value="470" />
|
||||
<option name="y" value="-207" />
|
||||
</Point>
|
||||
</option>
|
||||
</LayoutPositions>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="weatherTabFragment">
|
||||
<value>
|
||||
<LayoutPositions>
|
||||
<option name="myPosition">
|
||||
<Point>
|
||||
<option name="x" value="-301" />
|
||||
<option name="y" value="-160" />
|
||||
</Point>
|
||||
</option>
|
||||
</LayoutPositions>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</LayoutPositions>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
|
1
.idea/runConfigurations.xml
generated
@ -3,6 +3,7 @@
|
||||
<component name="RunConfigurationProducerService">
|
||||
<option name="ignoredProducers">
|
||||
<set>
|
||||
<option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
|
||||
|
@ -6,7 +6,6 @@ apply plugin: 'com.google.firebase.crashlytics'
|
||||
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
|
||||
apply plugin: 'realm-android'
|
||||
|
||||
@ -23,8 +22,8 @@ android {
|
||||
applicationId "com.tommasoberlose.anotherwidget"
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 30
|
||||
versionCode 115
|
||||
versionName "2.1.1"
|
||||
versionCode 138
|
||||
versionName "2.3.3"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
buildConfigField("String", "GOOGLE_API_KEY", apikeyProperties['GOOGLE_API_KEY'])
|
||||
@ -55,68 +54,69 @@ android {
|
||||
packagingOptions {
|
||||
exclude 'META-INF/DEPENDENCIES'
|
||||
}
|
||||
dataBinding {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
viewBinding.enabled = true
|
||||
buildFeatures {
|
||||
dataBinding = true
|
||||
viewBinding = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
testImplementation 'junit:junit:4.13.1'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||
|
||||
// UI
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||
implementation 'com.google.android.material:material:1.3.0-beta01'
|
||||
implementation 'com.google.android.material:material:1.3.0'
|
||||
implementation 'androidx.browser:browser:1.3.0'
|
||||
implementation 'net.idik:slimadapter:2.1.2'
|
||||
implementation 'com.google.android:flexbox:2.0.1'
|
||||
implementation 'com.kyleduo.switchbutton:library:2.0.3'
|
||||
|
||||
// Lifecycle
|
||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||
|
||||
implementation "androidx.work:work-runtime-ktx:2.4.0"
|
||||
implementation "androidx.work:work-runtime-ktx:2.5.0"
|
||||
|
||||
// EventBus
|
||||
implementation 'org.greenrobot:eventbus:3.2.0'
|
||||
|
||||
// Navigation
|
||||
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.2'
|
||||
implementation 'androidx.navigation:navigation-ui-ktx:2.3.2'
|
||||
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
|
||||
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
|
||||
|
||||
// Other
|
||||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
implementation 'joda-time:joda-time:2.10.6'
|
||||
implementation 'net.danlew:android.joda:2.10.9'
|
||||
implementation 'me.everything:providers-android:1.0.1'
|
||||
implementation 'com.github.warkiz.widget:indicatorseekbar:2.1.2'
|
||||
|
||||
//Glide
|
||||
implementation 'com.github.bumptech.glide:glide:4.11.0'
|
||||
implementation 'com.github.bumptech.glide:glide:4.12.0'
|
||||
kapt 'com.github.bumptech.glide:compiler:4.11.0'
|
||||
|
||||
// Fitness
|
||||
implementation 'com.google.android.gms:play-services-fitness:20.0.0'
|
||||
implementation 'com.google.android.gms:play-services-auth:18.1.0'
|
||||
implementation 'com.google.android.gms:play-services-auth:19.0.0'
|
||||
|
||||
//Weather
|
||||
implementation 'com.github.KwabenBerko:OpenWeatherMap-Android-Library:2.0.2'
|
||||
implementation 'com.google.android.gms:play-services-location:17.1.0'
|
||||
implementation 'com.google.android.gms:play-services-location:18.0.0'
|
||||
|
||||
// Billing
|
||||
implementation 'com.android.billingclient:billing:3.0.2'
|
||||
implementation 'com.android.billingclient:billing-ktx:3.0.2'
|
||||
implementation 'com.android.billingclient:billing:3.0.3'
|
||||
implementation 'com.android.billingclient:billing-ktx:3.0.3'
|
||||
|
||||
// KTX
|
||||
implementation "androidx.core:core-ktx:1.3.2"
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1"
|
||||
implementation "androidx.palette:palette-ktx:1.0.0"
|
||||
implementation 'androidx.core:core-ktx:1.3.2'
|
||||
|
||||
@ -128,14 +128,14 @@ dependencies {
|
||||
implementation "com.github.haroldadmin:NetworkResponseAdapter:4.0.1"
|
||||
|
||||
//Coroutines
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'
|
||||
|
||||
// Add the Firebase SDK for Crashlytics.
|
||||
implementation 'com.google.firebase:firebase-crashlytics:17.3.0'
|
||||
implementation 'com.google.firebase:firebase-crashlytics:17.4.1'
|
||||
|
||||
// Preferences
|
||||
implementation 'com.chibatching.kotpref:kotpref:2.11.0'
|
||||
implementation 'com.chibatching.kotpref:livedata-support:2.10.0'
|
||||
implementation 'com.chibatching.kotpref:kotpref:2.13.1'
|
||||
implementation 'com.chibatching.kotpref:livedata-support:2.13.1'
|
||||
implementation 'androidx.preference:preference-ktx:1.1.1'
|
||||
|
||||
// Permissions
|
||||
|
@ -31,16 +31,17 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<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.WeatherProviderActivity" 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.IntegrationsActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||
<activity android:name=".ui.activities.MusicPlayersFilterActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||
<activity android:name=".ui.activities.AppNotificationsFilterActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||
|
||||
<activity android:name=".ui.activities.tabs.ChooseApplicationActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||
<activity android:name=".ui.activities.tabs.CustomFontActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||
<activity android:name=".ui.activities.tabs.CustomLocationActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||
<activity android:name=".ui.activities.tabs.WeatherProviderActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||
<activity android:name=".ui.activities.settings.SupportDevActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||
<activity android:name=".ui.activities.tabs.CustomDateActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||
<activity android:name=".ui.activities.settings.IntegrationsActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||
<activity android:name=".ui.activities.tabs.MusicPlayersFilterActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||
<activity android:name=".ui.activities.tabs.AppNotificationsFilterActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||
<activity android:name=".ui.activities.tabs.MediaInfoFormatActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||
<activity android:name=".ui.activities.tabs.TimeZoneSelectorActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
|
||||
|
||||
<receiver android:name=".ui.widgets.MainWidget">
|
||||
<intent-filter>
|
||||
@ -150,9 +151,10 @@
|
||||
</receiver>
|
||||
|
||||
<service
|
||||
android:name=".services.UpdateCalendarJob"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE"
|
||||
android:exported="true"/>
|
||||
android:name=".services.UpdateCalendarService"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:foregroundServiceType="dataSync" />
|
||||
<service
|
||||
android:name=".services.LocationService"
|
||||
android:enabled="true"
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 45 KiB |
@ -1,13 +1,16 @@
|
||||
package com.tommasoberlose.anotherwidget
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Application
|
||||
import android.util.Log
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import com.chibatching.kotpref.Kotpref
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import net.danlew.android.joda.JodaTimeAndroid
|
||||
|
||||
class AWApplication : Application() {
|
||||
override fun onCreate() {
|
||||
|
@ -3,41 +3,30 @@ package com.tommasoberlose.anotherwidget.components
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.GridLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.SeekBar
|
||||
import androidx.annotation.ColorInt
|
||||
import android.widget.FrameLayout
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
||||
import com.tommasoberlose.anotherwidget.databinding.BottomSheetMenuHorBinding
|
||||
import com.tommasoberlose.anotherwidget.databinding.BottomSheetMenuListBinding
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.copyToClipboard
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isClipboardColor
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
|
||||
import com.tommasoberlose.anotherwidget.utils.expand
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.pasteFromClipboard
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
||||
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||
import com.tommasoberlose.anotherwidget.utils.reveal
|
||||
import com.tommasoberlose.anotherwidget.utils.toPixel
|
||||
import com.warkiz.widget.IndicatorSeekBar
|
||||
import com.warkiz.widget.OnSeekChangeListener
|
||||
import com.warkiz.widget.SeekParams
|
||||
import kotlinx.android.synthetic.main.bottom_sheet_menu_hor.*
|
||||
import kotlinx.android.synthetic.main.bottom_sheet_menu_hor.view.*
|
||||
import kotlinx.android.synthetic.main.bottom_sheet_menu_hor.view.color_loader
|
||||
import kotlinx.android.synthetic.main.color_picker_menu_item.view.*
|
||||
import kotlinx.coroutines.*
|
||||
import net.idik.lib.slimadapter.SlimAdapter
|
||||
import java.lang.Exception
|
||||
import java.util.prefs.Preferences
|
||||
|
||||
class BottomSheetColorPicker(
|
||||
context: Context,
|
||||
@ -47,30 +36,61 @@ class BottomSheetColorPicker(
|
||||
private val onColorSelected: ((selectedValue: Int) -> Unit)? = null,
|
||||
private val showAlphaSelector: Boolean = false,
|
||||
private val alpha: Int = 0,
|
||||
private val onAlphaChangeListener: ((alpha: Int) -> Unit)? = null
|
||||
private val onAlphaChangeListener: ((alpha: Int) -> Unit)? = null,
|
||||
private val hideCopyPaste: Boolean = false,
|
||||
) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
||||
|
||||
private var loadingJobs: ArrayList<Job> = ArrayList()
|
||||
private lateinit var adapter: SlimAdapter
|
||||
private var alphaDebouncing: Job? = null
|
||||
|
||||
private var binding: BottomSheetMenuHorBinding = BottomSheetMenuHorBinding.inflate(LayoutInflater.from(context))
|
||||
private var listBinding: BottomSheetMenuListBinding = BottomSheetMenuListBinding.inflate(LayoutInflater.from(context))
|
||||
|
||||
override fun show() {
|
||||
val view = View.inflate(context, R.layout.bottom_sheet_menu_hor, null)
|
||||
|
||||
window?.setDimAmount(0f)
|
||||
|
||||
// Header
|
||||
view.header.isVisible = header != null
|
||||
view.header_text.text = header ?: ""
|
||||
binding.header.isVisible = header != null
|
||||
binding.headerText.text = header ?: ""
|
||||
|
||||
if (hideCopyPaste) {
|
||||
binding.actionContainer.isVisible = false
|
||||
} else {
|
||||
binding.actionContainer.isVisible = true
|
||||
binding.actionCopy.setOnClickListener {
|
||||
context.copyToClipboard(getSelected?.invoke(), alpha)
|
||||
}
|
||||
binding.actionPaste.setOnClickListener {
|
||||
context.pasteFromClipboard { color, alpha ->
|
||||
binding.alphaSelector.setProgress(alpha.toIntValue().toFloat())
|
||||
|
||||
adapter.notifyItemChanged(adapter.data.indexOf(getSelected?.invoke()))
|
||||
onColorSelected?.invoke(Color.parseColor(color))
|
||||
val idx = colors.toList().indexOf(getSelected?.invoke())
|
||||
adapter.notifyItemChanged(idx)
|
||||
(listBinding.root.layoutManager as GridLayoutManager).scrollToPositionWithOffset(idx,0)
|
||||
}
|
||||
}
|
||||
binding.actionPaste.isVisible = context.isClipboardColor()
|
||||
}
|
||||
|
||||
// Alpha
|
||||
view.alpha_selector_container.isVisible = showAlphaSelector
|
||||
view.alpha_selector.setProgress(alpha.toFloat())
|
||||
view.text_alpha.text = "%s: %s%%".format(context.getString(R.string.alpha), alpha)
|
||||
view.alpha_selector.onSeekChangeListener = object : OnSeekChangeListener {
|
||||
binding.alphaSelectorContainer.isVisible = showAlphaSelector
|
||||
binding.alphaSelector.setProgress(alpha.toFloat())
|
||||
binding.textAlpha.text = "%s: %s%%".format(context.getString(R.string.alpha), alpha)
|
||||
binding.alphaSelector.onSeekChangeListener = object : OnSeekChangeListener {
|
||||
override fun onSeeking(seekParams: SeekParams?) {
|
||||
seekParams?.let {
|
||||
view.text_alpha.text = "%s: %s%%".format(context.getString(R.string.alpha), it.progress)
|
||||
onAlphaChangeListener?.invoke(it.progress)
|
||||
binding.textAlpha.text =
|
||||
"%s: %s%%".format(context.getString(R.string.alpha), it.progress)
|
||||
alphaDebouncing?.cancel()
|
||||
alphaDebouncing = GlobalScope.launch(Dispatchers.IO) {
|
||||
delay(150)
|
||||
withContext(Dispatchers.Main) {
|
||||
onAlphaChangeListener?.invoke(it.progress)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun onStartTrackingTouch(seekBar: IndicatorSeekBar?) {
|
||||
@ -80,14 +100,12 @@ class BottomSheetColorPicker(
|
||||
}
|
||||
|
||||
// List
|
||||
|
||||
adapter = SlimAdapter.create()
|
||||
|
||||
loadingJobs.add(GlobalScope.launch(Dispatchers.IO) {
|
||||
val listView = View.inflate(context, R.layout.bottom_sheet_menu_list, null) as RecyclerView
|
||||
listView.setHasFixedSize(true)
|
||||
listBinding.root.setHasFixedSize(true)
|
||||
val mLayoutManager = GridLayoutManager(context, 6)
|
||||
listView.layoutManager = mLayoutManager
|
||||
listBinding.root.layoutManager = mLayoutManager
|
||||
|
||||
adapter
|
||||
.register<Int>(R.layout.color_picker_menu_item) { item, injector ->
|
||||
@ -115,22 +133,25 @@ class BottomSheetColorPicker(
|
||||
onColorSelected?.invoke(item)
|
||||
val position = adapter.data.indexOf(item)
|
||||
adapter.notifyItemChanged(position)
|
||||
(listView.layoutManager as GridLayoutManager).scrollToPositionWithOffset(position,0)
|
||||
(listBinding.root.layoutManager as GridLayoutManager).scrollToPositionWithOffset(position,0)
|
||||
}
|
||||
}
|
||||
.attachTo(listView)
|
||||
.attachTo(listBinding.root)
|
||||
|
||||
adapter.updateData(colors.toList())
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
view.color_loader.isVisible = false
|
||||
view.list_container.addView(listView)
|
||||
binding.loader.isVisible = false
|
||||
binding.listContainer.addView(listBinding.root)
|
||||
this@BottomSheetColorPicker.behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
view.list_container.isVisible = true
|
||||
binding.listContainer.isVisible = true
|
||||
|
||||
val idx = colors.toList().indexOf(getSelected?.invoke())
|
||||
(listBinding.root.layoutManager as GridLayoutManager).scrollToPositionWithOffset(idx,0)
|
||||
}
|
||||
})
|
||||
|
||||
setContentView(view)
|
||||
setContentView(binding.root)
|
||||
super.show()
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,17 @@
|
||||
package com.tommasoberlose.anotherwidget.components
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import kotlinx.android.synthetic.main.bottom_sheet_menu.view.*
|
||||
import kotlinx.android.synthetic.main.bottom_sheet_menu_item.view.*
|
||||
import org.w3c.dom.Text
|
||||
import com.tommasoberlose.anotherwidget.databinding.BottomSheetMenuBinding
|
||||
import com.tommasoberlose.anotherwidget.databinding.BottomSheetMenuItemBinding
|
||||
|
||||
/**
|
||||
* [BottomSheetDialogFragment] that uses a custom
|
||||
@ -24,6 +25,8 @@ open class BottomSheetMenu<T>(context: Context, private val header: String? = nu
|
||||
private var callback: ((selectedValue: T) -> Unit)? = null
|
||||
private var multipleSelectionCallback: ((selectedValues: ArrayList<T>) -> Unit)? = null
|
||||
|
||||
private var binding = BottomSheetMenuBinding.inflate(LayoutInflater.from(context))
|
||||
|
||||
fun setSelectedValue(res: T): BottomSheetMenu<T> {
|
||||
selectedRes = ArrayList(listOf(res))
|
||||
return this
|
||||
@ -50,33 +53,31 @@ open class BottomSheetMenu<T>(context: Context, private val header: String? = nu
|
||||
}
|
||||
|
||||
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 ?: ""
|
||||
binding.header.isVisible = header != null
|
||||
binding.headerText.text = header ?: ""
|
||||
|
||||
view.warning_text.isVisible = message != null
|
||||
view.warning_text.text = message ?: ""
|
||||
view.warning_text.setTextColor(ContextCompat.getColor(context, if (isMessageWarning) R.color.warningColorText else R.color.colorSecondaryText))
|
||||
binding.warningText.isVisible = message != null
|
||||
binding.warningText.text = message ?: ""
|
||||
binding.warningText.setTextColor(ContextCompat.getColor(context, if (isMessageWarning) R.color.warningColorText else R.color.colorSecondaryText))
|
||||
|
||||
// Menu
|
||||
for (item in items) {
|
||||
val itemBinding = BottomSheetMenuItemBinding.inflate(LayoutInflater.from(context))
|
||||
if (item.value != null) {
|
||||
val itemView = View.inflate(context, R.layout.bottom_sheet_menu_item, null)
|
||||
itemView.label.text = item.title
|
||||
itemBinding.label.text = item.title
|
||||
if (isMultiSelection) {
|
||||
itemView.icon_check.isVisible = selectedRes.contains(item.value)
|
||||
itemView.label.setTextColor(
|
||||
itemBinding.iconCheck.isVisible = selectedRes.contains(item.value)
|
||||
itemBinding.label.setTextColor(
|
||||
if (selectedRes.contains(item.value)) ContextCompat.getColor(
|
||||
context,
|
||||
R.color.colorPrimaryText
|
||||
) else ContextCompat.getColor(context, R.color.colorSecondaryText)
|
||||
)
|
||||
} else {
|
||||
itemView.isSelected = selectedRes.contains(item.value)
|
||||
itemBinding.root.isSelected = selectedRes.contains(item.value)
|
||||
}
|
||||
itemView.setOnClickListener {
|
||||
itemBinding.root.setOnClickListener {
|
||||
if (!isMultiSelection) {
|
||||
callback?.invoke(item.value)
|
||||
this.dismiss()
|
||||
@ -88,8 +89,8 @@ open class BottomSheetMenu<T>(context: Context, private val header: String? = nu
|
||||
}
|
||||
|
||||
multipleSelectionCallback?.invoke(selectedRes)
|
||||
itemView.icon_check.isVisible = selectedRes.contains(item.value)
|
||||
itemView.label.setTextColor(
|
||||
itemBinding.iconCheck.isVisible = selectedRes.contains(item.value)
|
||||
itemBinding.label.setTextColor(
|
||||
if (selectedRes.contains(item.value)) ContextCompat.getColor(
|
||||
context,
|
||||
R.color.colorPrimaryText
|
||||
@ -97,17 +98,16 @@ open class BottomSheetMenu<T>(context: Context, private val header: String? = nu
|
||||
)
|
||||
}
|
||||
|
||||
item.renderCallback?.invoke(itemView.label)
|
||||
item.renderCallback?.invoke(itemBinding.label)
|
||||
}
|
||||
|
||||
view.menu.addView(itemView)
|
||||
binding.menu.addView(itemBinding.root)
|
||||
} else {
|
||||
val itemView = View.inflate(context, R.layout.bottom_sheet_menu_divider, null)
|
||||
itemView.label.text = item.title
|
||||
view.menu.addView(itemView)
|
||||
itemBinding.label.text = item.title
|
||||
binding.menu.addView(itemBinding.root)
|
||||
}
|
||||
}
|
||||
setContentView(view)
|
||||
setContentView(binding.root)
|
||||
super.show()
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,108 @@
|
||||
package com.tommasoberlose.anotherwidget.components
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.databinding.BottomSheetMenuHorBinding
|
||||
import com.tommasoberlose.anotherwidget.databinding.BottomSheetMenuListBinding
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.copyToClipboard
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isClipboardColor
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.pasteFromClipboard
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
||||
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||
import com.warkiz.widget.IndicatorSeekBar
|
||||
import com.warkiz.widget.OnSeekChangeListener
|
||||
import com.warkiz.widget.SeekParams
|
||||
import kotlinx.coroutines.*
|
||||
import net.idik.lib.slimadapter.SlimAdapter
|
||||
|
||||
class BottomSheetPicker<T>(
|
||||
context: Context,
|
||||
private val items: List<MenuItem<T>> = arrayListOf(),
|
||||
private val getSelected: (() -> T)? = null,
|
||||
private val header: String? = null,
|
||||
private val onItemSelected: ((selectedValue: T?) -> Unit)? = null,
|
||||
) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
||||
|
||||
private var loadingJobs: ArrayList<Job> = ArrayList()
|
||||
private lateinit var adapter: SlimAdapter
|
||||
|
||||
private var binding: BottomSheetMenuHorBinding = BottomSheetMenuHorBinding.inflate(
|
||||
LayoutInflater.from(context))
|
||||
private var listBinding: BottomSheetMenuListBinding = BottomSheetMenuListBinding.inflate(
|
||||
LayoutInflater.from(context))
|
||||
|
||||
override fun show() {
|
||||
window?.setDimAmount(0f)
|
||||
|
||||
// Header
|
||||
binding.header.isVisible = header != null
|
||||
binding.headerText.text = header ?: ""
|
||||
|
||||
// Alpha
|
||||
binding.alphaSelectorContainer.isVisible = false
|
||||
binding.actionContainer.isVisible = false
|
||||
|
||||
// List
|
||||
adapter = SlimAdapter.create()
|
||||
|
||||
loadingJobs.add(GlobalScope.launch(Dispatchers.IO) {
|
||||
listBinding.root.setHasFixedSize(true)
|
||||
val mLayoutManager = LinearLayoutManager(context)
|
||||
listBinding.root.layoutManager = mLayoutManager
|
||||
|
||||
adapter
|
||||
.register<Int>(R.layout.bottom_sheet_menu_item) { position, injector ->
|
||||
val item = items[position]
|
||||
val isSelected = item.value == getSelected?.invoke()
|
||||
injector
|
||||
.text(R.id.label, item.title)
|
||||
.textColor(R.id.label, ContextCompat.getColor(context, if (isSelected) R.color.colorAccent else R.color.colorSecondaryText))
|
||||
.selected(R.id.item, isSelected)
|
||||
.clicked(R.id.item) {
|
||||
val oldIdx = items.toList().indexOfFirst { it.value == getSelected?.invoke() }
|
||||
onItemSelected?.invoke(item.value)
|
||||
adapter.notifyItemChanged(position)
|
||||
adapter.notifyItemChanged(oldIdx)
|
||||
(listBinding.root.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(position,0)
|
||||
}
|
||||
}
|
||||
.attachTo(listBinding.root)
|
||||
|
||||
adapter.updateData((items.indices).toList())
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.loader.isVisible = false
|
||||
binding.listContainer.addView(listBinding.root)
|
||||
this@BottomSheetPicker.behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
binding.listContainer.isVisible = true
|
||||
|
||||
val idx = items.toList().indexOfFirst { it.value == getSelected?.invoke() }
|
||||
(listBinding.root.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(idx,0)
|
||||
}
|
||||
})
|
||||
|
||||
setContentView(binding.root)
|
||||
super.show()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
loadingJobs.forEach { it.cancel() }
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
class MenuItem<T>(val title: String, val value: T? = null)
|
||||
|
||||
}
|
@ -5,32 +5,33 @@ import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.databinding.WeatherProviderSettingsLayoutBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
||||
import com.tommasoberlose.anotherwidget.utils.openURI
|
||||
import kotlinx.android.synthetic.main.weather_provider_settings_layout.view.*
|
||||
|
||||
class BottomSheetWeatherProviderSettings(context: Context, callback: () -> Unit) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
||||
|
||||
private var binding: WeatherProviderSettingsLayoutBinding = WeatherProviderSettingsLayoutBinding.inflate(android.view.LayoutInflater.from(context))
|
||||
|
||||
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()
|
||||
binding.apiKeyContainer.isVisible = WeatherHelper.isKeyRequired()
|
||||
binding.actionSaveKey.isVisible = WeatherHelper.isKeyRequired()
|
||||
|
||||
WeatherHelper.getProviderInfoTitle(context).let { title ->
|
||||
view.info_title.text = title
|
||||
view.info_title.isVisible = title != ""
|
||||
binding.infoTitle.text = title
|
||||
binding.infoTitle.isVisible = title != ""
|
||||
}
|
||||
|
||||
WeatherHelper.getProviderInfoSubtitle(context).let { subtitle ->
|
||||
view.info_subtitle.text = subtitle
|
||||
view.info_subtitle.isVisible = subtitle != ""
|
||||
binding.infoSubtitle.text = subtitle
|
||||
binding.infoSubtitle.isVisible = subtitle != ""
|
||||
}
|
||||
|
||||
view.info_provider.text = WeatherHelper.getProviderName(context)
|
||||
binding.infoProvider.text = WeatherHelper.getProviderName(context)
|
||||
|
||||
view.api_key.editText?.setText(when (Constants.WeatherProvider.fromInt(Preferences.weatherProvider)) {
|
||||
binding.apiKey.editText?.setText(when (Constants.WeatherProvider.fromInt(Preferences.weatherProvider)) {
|
||||
Constants.WeatherProvider.OPEN_WEATHER -> Preferences.weatherProviderApiOpen
|
||||
Constants.WeatherProvider.WEATHER_BIT -> Preferences.weatherProviderApiWeatherBit
|
||||
Constants.WeatherProvider.WEATHER_API -> Preferences.weatherProviderApiWeatherApi
|
||||
@ -41,12 +42,12 @@ class BottomSheetWeatherProviderSettings(context: Context, callback: () -> Unit)
|
||||
null -> ""
|
||||
})
|
||||
|
||||
view.action_open_provider.setOnClickListener {
|
||||
binding.actionOpenProvider.setOnClickListener {
|
||||
context.openURI(WeatherHelper.getProviderLink())
|
||||
}
|
||||
|
||||
view.action_save_key.setOnClickListener {
|
||||
val key = view.api_key.editText?.text.toString()
|
||||
binding.actionSaveKey.setOnClickListener {
|
||||
val key = binding.apiKey.editText?.text.toString()
|
||||
when (Constants.WeatherProvider.fromInt(Preferences.weatherProvider)) {
|
||||
Constants.WeatherProvider.OPEN_WEATHER -> Preferences.weatherProviderApiOpen = key
|
||||
Constants.WeatherProvider.WEATHER_BIT -> Preferences.weatherProviderApiWeatherBit = key
|
||||
@ -59,6 +60,6 @@ class BottomSheetWeatherProviderSettings(context: Context, callback: () -> Unit)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
setContentView(view)
|
||||
setContentView(binding.root)
|
||||
}
|
||||
}
|
@ -1,28 +1,30 @@
|
||||
package com.tommasoberlose.anotherwidget.components
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.databinding.CustomNotesDialogLayoutBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import kotlinx.android.synthetic.main.custom_notes_dialog_layout.view.*
|
||||
|
||||
class CustomNotesDialog(context: Context, callback: (() -> Unit)?) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
||||
|
||||
init {
|
||||
val view = View.inflate(context, R.layout.custom_notes_dialog_layout, null)
|
||||
view.notes.setText(Preferences.customNotes)
|
||||
private var binding: CustomNotesDialogLayoutBinding = CustomNotesDialogLayoutBinding.inflate(LayoutInflater.from(context))
|
||||
|
||||
view.action_positive.setOnClickListener {
|
||||
Preferences.customNotes = view.notes.text.toString()
|
||||
init {
|
||||
binding.notes.setText(Preferences.customNotes)
|
||||
|
||||
binding.actionPositive.setOnClickListener {
|
||||
Preferences.customNotes = binding.notes.text.toString()
|
||||
this.dismiss()
|
||||
callback?.invoke()
|
||||
}
|
||||
|
||||
view.notes.requestFocus()
|
||||
binding.notes.requestFocus()
|
||||
|
||||
setContentView(view)
|
||||
setContentView(binding.root)
|
||||
}
|
||||
}
|
@ -7,10 +7,7 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.util.EventLog
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import android.view.LayoutInflater
|
||||
import androidx.core.view.isVisible
|
||||
import com.google.android.gms.auth.api.signin.GoogleSignIn
|
||||
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
|
||||
@ -22,6 +19,7 @@ import com.karumi.dexter.PermissionToken
|
||||
import com.karumi.dexter.listener.PermissionRequest
|
||||
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.databinding.GlanceProviderSettingsLayoutBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
||||
@ -29,21 +27,22 @@ import com.tommasoberlose.anotherwidget.helpers.AlarmHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.GreetingsHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.AppNotificationsFilterActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.MusicPlayersFilterActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.tabs.AppNotificationsFilterActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.tabs.MediaInfoFormatActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.tabs.MusicPlayersFilterActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||
import kotlinx.android.synthetic.main.glance_provider_settings_layout.view.*
|
||||
import kotlinx.coroutines.*
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
|
||||
class GlanceSettingsDialog(val context: Activity, val provider: Constants.GlanceProviderId, private val statusCallback: (() -> Unit)?) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
||||
|
||||
private var binding: GlanceProviderSettingsLayoutBinding = GlanceProviderSettingsLayoutBinding.inflate(LayoutInflater.from(context))
|
||||
|
||||
override fun show() {
|
||||
val view = View.inflate(context, R.layout.glance_provider_settings_layout, null)
|
||||
|
||||
/* TITLE */
|
||||
view.title.text = when (provider) {
|
||||
binding.title.text = when (provider) {
|
||||
Constants.GlanceProviderId.PLAYING_SONG -> context.getString(R.string.settings_show_music_title)
|
||||
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> context.getString(R.string.settings_show_next_alarm_title)
|
||||
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> context.getString(R.string.settings_low_battery_level_title)
|
||||
@ -55,7 +54,7 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
||||
}
|
||||
|
||||
/* SUBTITLE*/
|
||||
view.subtitle.text = when (provider) {
|
||||
binding.subtitle.text = when (provider) {
|
||||
Constants.GlanceProviderId.PLAYING_SONG -> context.getString(R.string.settings_show_music_subtitle)
|
||||
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> context.getString(R.string.settings_show_next_alarm_subtitle)
|
||||
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> context.getString(R.string.settings_low_battery_level_subtitle)
|
||||
@ -67,53 +66,58 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
||||
}
|
||||
|
||||
/* SONG */
|
||||
view.action_filter_music_players.isVisible = provider == Constants.GlanceProviderId.PLAYING_SONG
|
||||
binding.actionFilterMusicPlayers.isVisible = provider == Constants.GlanceProviderId.PLAYING_SONG
|
||||
binding.actionChangeMediaInfoFormat.isVisible = provider == Constants.GlanceProviderId.PLAYING_SONG
|
||||
if (provider == Constants.GlanceProviderId.PLAYING_SONG) {
|
||||
view.action_filter_music_players.setOnClickListener {
|
||||
binding.actionFilterMusicPlayers.setOnClickListener {
|
||||
dismiss()
|
||||
context.startActivityForResult(Intent(context, MusicPlayersFilterActivity::class.java), 0)
|
||||
}
|
||||
checkNotificationPermission(view)
|
||||
binding.actionChangeMediaInfoFormat.setOnClickListener {
|
||||
dismiss()
|
||||
context.startActivityForResult(Intent(context, MediaInfoFormatActivity::class.java), 0)
|
||||
}
|
||||
checkNotificationPermission()
|
||||
}
|
||||
|
||||
/* ALARM */
|
||||
view.alarm_set_by_container.isVisible = provider == Constants.GlanceProviderId.NEXT_CLOCK_ALARM
|
||||
binding.alarmSetByContainer.isVisible = provider == Constants.GlanceProviderId.NEXT_CLOCK_ALARM
|
||||
if (provider == Constants.GlanceProviderId.NEXT_CLOCK_ALARM) {
|
||||
view.header.text = context.getString(R.string.information_header)
|
||||
view.warning_container.isVisible = false
|
||||
checkNextAlarm(view)
|
||||
binding.header.text = context.getString(R.string.information_header)
|
||||
binding.warningContainer.isVisible = false
|
||||
checkNextAlarm()
|
||||
}
|
||||
|
||||
/* GOOGLE STEPS */
|
||||
view.action_toggle_google_fit.isVisible = provider == Constants.GlanceProviderId.GOOGLE_FIT_STEPS
|
||||
binding.actionToggleGoogleFit.isVisible = provider == Constants.GlanceProviderId.GOOGLE_FIT_STEPS
|
||||
if (provider == Constants.GlanceProviderId.GOOGLE_FIT_STEPS) {
|
||||
view.warning_container.isVisible = false
|
||||
checkFitnessPermission(view)
|
||||
checkGoogleFitConnection(view)
|
||||
binding.warningContainer.isVisible = false
|
||||
checkFitnessPermission()
|
||||
checkGoogleFitConnection()
|
||||
}
|
||||
|
||||
/* BATTERY INFO */
|
||||
if (provider == Constants.GlanceProviderId.BATTERY_LEVEL_LOW) {
|
||||
view.warning_container.isVisible = false
|
||||
view.header.isVisible = false
|
||||
view.divider.isVisible = false
|
||||
binding.warningContainer.isVisible = false
|
||||
binding.header.isVisible = false
|
||||
binding.divider.isVisible = false
|
||||
}
|
||||
|
||||
/* NOTIFICATIONS */
|
||||
view.action_filter_notifications_app.isVisible = provider == Constants.GlanceProviderId.NOTIFICATIONS
|
||||
view.action_change_notification_timer.isVisible = provider == Constants.GlanceProviderId.NOTIFICATIONS
|
||||
binding.actionFilterNotificationsApp.isVisible = provider == Constants.GlanceProviderId.NOTIFICATIONS
|
||||
binding.actionChangeNotificationTimer.isVisible = provider == Constants.GlanceProviderId.NOTIFICATIONS
|
||||
if (provider == Constants.GlanceProviderId.NOTIFICATIONS) {
|
||||
checkLastNotificationsPermission(view)
|
||||
checkLastNotificationsPermission()
|
||||
val stringArray = context.resources.getStringArray(R.array.glance_notifications_timeout)
|
||||
view.action_filter_notifications_app.setOnClickListener {
|
||||
binding.actionFilterNotificationsApp.setOnClickListener {
|
||||
dismiss()
|
||||
context.startActivityForResult(Intent(context, AppNotificationsFilterActivity::class.java), 0)
|
||||
}
|
||||
view.notification_timer_label.text = stringArray[Preferences.hideNotificationAfter]
|
||||
view.action_change_notification_timer.setOnClickListener {
|
||||
binding.notificationTimerLabel.text = stringArray[Preferences.hideNotificationAfter]
|
||||
binding.actionChangeNotificationTimer.setOnClickListener {
|
||||
val dialog = BottomSheetMenu<Int>(context, header = context.getString(R.string.glance_notification_hide_timeout_title)).setSelectedValue(Preferences.hideNotificationAfter)
|
||||
Constants.GlanceNotificationTimer.values().forEachIndexed { index, timeout ->
|
||||
dialog.addItem(stringArray[index], timeout.value)
|
||||
dialog.addItem(stringArray[index], timeout.rawValue)
|
||||
}
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
Preferences.hideNotificationAfter = value
|
||||
@ -124,20 +128,20 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
||||
|
||||
/* GREETINGS */
|
||||
if (provider == Constants.GlanceProviderId.GREETINGS) {
|
||||
view.warning_container.isVisible = false
|
||||
view.header.isVisible = false
|
||||
view.divider.isVisible = false
|
||||
binding.warningContainer.isVisible = false
|
||||
binding.header.isVisible = false
|
||||
binding.divider.isVisible = false
|
||||
}
|
||||
|
||||
/* EVENTS */
|
||||
if (provider == Constants.GlanceProviderId.EVENTS) {
|
||||
view.header.isVisible = false
|
||||
view.divider.isVisible = false
|
||||
checkCalendarConfig(view)
|
||||
binding.header.isVisible = false
|
||||
binding.divider.isVisible = false
|
||||
checkCalendarConfig()
|
||||
}
|
||||
|
||||
/* TOGGLE */
|
||||
view.provider_switch.isChecked = when (provider) {
|
||||
binding.providerSwitch.setCheckedImmediatelyNoEvent(when (provider) {
|
||||
Constants.GlanceProviderId.PLAYING_SONG -> Preferences.showMusic
|
||||
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> Preferences.showNextAlarm
|
||||
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> Preferences.showBatteryCharging
|
||||
@ -146,11 +150,11 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
||||
Constants.GlanceProviderId.NOTIFICATIONS -> Preferences.showNotifications
|
||||
Constants.GlanceProviderId.GREETINGS -> Preferences.showGreetings
|
||||
Constants.GlanceProviderId.EVENTS -> Preferences.showEventsAsGlanceProvider
|
||||
}
|
||||
})
|
||||
|
||||
var job: Job? = null
|
||||
|
||||
view.provider_switch.setOnCheckedChangeListener { _, isChecked ->
|
||||
binding.providerSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||
job?.cancel()
|
||||
job = GlobalScope.launch(Dispatchers.IO) {
|
||||
delay(300)
|
||||
@ -158,18 +162,18 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
||||
when (provider) {
|
||||
Constants.GlanceProviderId.PLAYING_SONG -> {
|
||||
Preferences.showMusic = isChecked
|
||||
checkNotificationPermission(view)
|
||||
checkNotificationPermission()
|
||||
}
|
||||
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
|
||||
Preferences.showNextAlarm = isChecked
|
||||
checkNextAlarm(view)
|
||||
checkNextAlarm()
|
||||
}
|
||||
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
||||
Preferences.showBatteryCharging = isChecked
|
||||
}
|
||||
Constants.GlanceProviderId.NOTIFICATIONS -> {
|
||||
Preferences.showNotifications = isChecked
|
||||
checkLastNotificationsPermission(view)
|
||||
checkLastNotificationsPermission()
|
||||
}
|
||||
Constants.GlanceProviderId.GREETINGS -> {
|
||||
Preferences.showGreetings = isChecked
|
||||
@ -197,9 +201,9 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
||||
Preferences.showDailySteps = false
|
||||
}
|
||||
|
||||
view.warning_container.isVisible = false
|
||||
checkFitnessPermission(view)
|
||||
checkGoogleFitConnection(view)
|
||||
binding.warningContainer.isVisible = false
|
||||
checkFitnessPermission()
|
||||
checkGoogleFitConnection()
|
||||
}
|
||||
Constants.GlanceProviderId.EVENTS -> {
|
||||
Preferences.showEventsAsGlanceProvider = isChecked
|
||||
@ -212,11 +216,11 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
||||
}
|
||||
}
|
||||
|
||||
setContentView(view)
|
||||
setContentView(binding.root)
|
||||
super.show()
|
||||
}
|
||||
|
||||
private fun checkNextAlarm(view: View) {
|
||||
private fun checkNextAlarm() {
|
||||
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||
val alarm = nextAlarmClock
|
||||
if (alarm != null && alarm.showIntent != null) {
|
||||
@ -226,69 +230,71 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
||||
} catch (e: Exception) {
|
||||
alarm.showIntent?.creatorPackage ?: ""
|
||||
}
|
||||
view.alarm_set_by_title.text = context.getString(R.string.settings_show_next_alarm_app_title).format(appNameOrPackage)
|
||||
view.alarm_set_by_subtitle.text = if (AlarmHelper.isAlarmProbablyWrong(context)) context.getString(R.string.settings_show_next_alarm_app_subtitle_wrong) else context.getString(R.string.settings_show_next_alarm_app_subtitle_correct)
|
||||
view.alarm_set_by_title.isVisible = true
|
||||
binding.alarmSetByTitle.text = context.getString(R.string.settings_show_next_alarm_app_title).format(appNameOrPackage)
|
||||
binding.alarmSetBySubtitle.text = if (AlarmHelper.isAlarmProbablyWrong(context)) context.getString(R.string.settings_show_next_alarm_app_subtitle_wrong) else context.getString(R.string.settings_show_next_alarm_app_subtitle_correct)
|
||||
binding.alarmSetByContainer.isVisible = true
|
||||
} else {
|
||||
view.alarm_set_by_title.isVisible = false
|
||||
binding.alarmSetByContainer.isVisible = false
|
||||
binding.header.isVisible = false
|
||||
binding.divider.isVisible = false
|
||||
}
|
||||
}
|
||||
statusCallback?.invoke()
|
||||
}
|
||||
|
||||
private fun checkCalendarConfig(view: View) {
|
||||
private fun checkCalendarConfig() {
|
||||
if (!Preferences.showEvents || !context.checkGrantedPermission(Manifest.permission.READ_CALENDAR)) {
|
||||
view.warning_container.isVisible = true
|
||||
view.warning_title.text = context.getString(R.string.settings_show_events_as_glance_provider_error)
|
||||
view.warning_container.setOnClickListener {
|
||||
binding.warningContainer.isVisible = true
|
||||
binding.warningTitle.text = context.getString(R.string.settings_show_events_as_glance_provider_error)
|
||||
binding.warningContainer.setOnClickListener {
|
||||
dismiss()
|
||||
EventBus.getDefault().post(MainFragment.ChangeTabEvent(1))
|
||||
}
|
||||
} else {
|
||||
view.warning_container.isVisible = false
|
||||
binding.warningContainer.isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkNotificationPermission(view: View) {
|
||||
private fun checkNotificationPermission() {
|
||||
when {
|
||||
ActiveNotificationsHelper.checkNotificationAccess(context) -> {
|
||||
view.warning_container.isVisible = false
|
||||
binding.warningContainer.isVisible = false
|
||||
MediaPlayerHelper.updatePlayingMediaInfo(context)
|
||||
}
|
||||
Preferences.showMusic -> {
|
||||
view.warning_container.isVisible = true
|
||||
view.warning_title.text = context.getString(R.string.settings_request_notification_access)
|
||||
view.warning_container.setOnClickListener {
|
||||
binding.warningContainer.isVisible = true
|
||||
binding.warningTitle.text = context.getString(R.string.settings_request_notification_access)
|
||||
binding.warningContainer.setOnClickListener {
|
||||
context.startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
view.warning_container.isVisible = false
|
||||
binding.warningContainer.isVisible = false
|
||||
}
|
||||
}
|
||||
statusCallback?.invoke()
|
||||
}
|
||||
|
||||
private fun checkLastNotificationsPermission(view: View) {
|
||||
private fun checkLastNotificationsPermission() {
|
||||
when {
|
||||
ActiveNotificationsHelper.checkNotificationAccess(context) -> {
|
||||
view.warning_container.isVisible = false
|
||||
binding.warningContainer.isVisible = false
|
||||
}
|
||||
Preferences.showNotifications -> {
|
||||
view.warning_container.isVisible = true
|
||||
view.warning_title.text = context.getString(R.string.settings_request_last_notification_access)
|
||||
view.warning_container.setOnClickListener {
|
||||
binding.warningContainer.isVisible = true
|
||||
binding.warningTitle.text = context.getString(R.string.settings_request_last_notification_access)
|
||||
binding.warningContainer.setOnClickListener {
|
||||
context.startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
view.warning_container.isVisible = false
|
||||
binding.warningContainer.isVisible = false
|
||||
}
|
||||
}
|
||||
statusCallback?.invoke()
|
||||
}
|
||||
|
||||
private fun checkFitnessPermission(view: View) {
|
||||
private fun checkFitnessPermission() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || context.checkGrantedPermission(
|
||||
Manifest.permission.ACTIVITY_RECOGNITION)
|
||||
) {
|
||||
@ -299,10 +305,10 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
||||
}
|
||||
} else if (Preferences.showDailySteps) {
|
||||
ActivityDetectionReceiver.unregisterFence(context)
|
||||
view.warning_container.isVisible = true
|
||||
view.warning_title.text = context.getString(R.string.settings_request_fitness_access)
|
||||
view.warning_container.setOnClickListener {
|
||||
requireFitnessPermission(view)
|
||||
binding.warningContainer.isVisible = true
|
||||
binding.warningTitle.text = context.getString(R.string.settings_request_fitness_access)
|
||||
binding.warningContainer.setOnClickListener {
|
||||
requireFitnessPermission()
|
||||
}
|
||||
} else {
|
||||
ActivityDetectionReceiver.unregisterFence(context)
|
||||
@ -310,36 +316,36 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
||||
statusCallback?.invoke()
|
||||
}
|
||||
|
||||
private fun checkGoogleFitConnection(view: View) {
|
||||
private fun checkGoogleFitConnection() {
|
||||
val account: GoogleSignInAccount? = GoogleSignIn.getLastSignedInAccount(context)
|
||||
if (!GoogleSignIn.hasPermissions(account,
|
||||
ActivityDetectionReceiver.FITNESS_OPTIONS
|
||||
)) {
|
||||
view.warning_container.isVisible = true
|
||||
view.warning_title.text = context.getString(R.string.settings_request_fitness_access)
|
||||
view.warning_container.setOnClickListener {
|
||||
binding.warningContainer.isVisible = true
|
||||
binding.warningTitle.text = context.getString(R.string.settings_request_fitness_access)
|
||||
binding.warningContainer.setOnClickListener {
|
||||
GoogleSignIn.requestPermissions(
|
||||
context,
|
||||
1,
|
||||
account,
|
||||
ActivityDetectionReceiver.FITNESS_OPTIONS)
|
||||
}
|
||||
view.action_connect_to_google_fit.isVisible = true
|
||||
view.action_disconnect_to_google_fit.isVisible = false
|
||||
view.action_connect_to_google_fit.setOnClickListener {
|
||||
binding.actionConnectToGoogleFit.isVisible = true
|
||||
binding.actionDisconnectToGoogleFit.isVisible = false
|
||||
binding.actionConnectToGoogleFit.setOnClickListener {
|
||||
GoogleSignIn.requestPermissions(
|
||||
context,
|
||||
1,
|
||||
account,
|
||||
ActivityDetectionReceiver.FITNESS_OPTIONS)
|
||||
}
|
||||
view.action_disconnect_to_google_fit.setOnClickListener(null)
|
||||
view.google_fit_status_label.text = context.getString(R.string.google_fit_account_not_connected)
|
||||
binding.actionDisconnectToGoogleFit.setOnClickListener(null)
|
||||
binding.googleFitStatusLabel.text = context.getString(R.string.google_fit_account_not_connected)
|
||||
} else {
|
||||
view.action_connect_to_google_fit.isVisible = false
|
||||
view.action_disconnect_to_google_fit.isVisible = true
|
||||
view.action_connect_to_google_fit.setOnClickListener(null)
|
||||
view.action_disconnect_to_google_fit.setOnClickListener {
|
||||
binding.actionConnectToGoogleFit.isVisible = false
|
||||
binding.actionDisconnectToGoogleFit.isVisible = true
|
||||
binding.actionConnectToGoogleFit.setOnClickListener(null)
|
||||
binding.actionDisconnectToGoogleFit.setOnClickListener {
|
||||
GoogleSignIn.getClient(context, GoogleSignInOptions.Builder(
|
||||
GoogleSignInOptions.DEFAULT_SIGN_IN).addExtension(
|
||||
ActivityDetectionReceiver.FITNESS_OPTIONS
|
||||
@ -347,11 +353,11 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
||||
show()
|
||||
}
|
||||
}
|
||||
view.google_fit_status_label.text = context.getString(R.string.google_fit_account_connected)
|
||||
binding.googleFitStatusLabel.text = context.getString(R.string.google_fit_account_connected)
|
||||
}
|
||||
}
|
||||
|
||||
private fun requireFitnessPermission(view: View) {
|
||||
private fun requireFitnessPermission() {
|
||||
Dexter.withContext(context)
|
||||
.withPermissions(
|
||||
"com.google.android.gms.permission.ACTIVITY_RECOGNITION",
|
||||
@ -359,7 +365,7 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACTIVITY_RECOGNITION else "com.google.android.gms.permission.ACTIVITY_RECOGNITION"
|
||||
).withListener(object: MultiplePermissionsListener {
|
||||
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
||||
checkFitnessPermission(view)
|
||||
checkFitnessPermission()
|
||||
}
|
||||
override fun onPermissionRationaleShouldBeShown(
|
||||
permissions: MutableList<PermissionRequest>?,
|
||||
|
@ -1,43 +1,41 @@
|
||||
package com.tommasoberlose.anotherwidget.components
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.view.LayoutInflater
|
||||
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.databinding.BottomSheetMenuBinding
|
||||
import com.tommasoberlose.anotherwidget.databinding.IconPackMenuItemBinding
|
||||
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) {
|
||||
|
||||
private var binding = BottomSheetMenuBinding.inflate(LayoutInflater.from(context))
|
||||
|
||||
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 ?: ""
|
||||
binding.header.isVisible = header != null
|
||||
binding.headerText.text = header ?: ""
|
||||
|
||||
view.warning_text.isVisible = false
|
||||
binding.warningText.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
|
||||
val itemBinding = IconPackMenuItemBinding.inflate(LayoutInflater.from(context))
|
||||
itemBinding.label.text = context.getString(R.string.settings_weather_icon_pack_default).format(item.rawValue + 1)
|
||||
itemBinding.root.isSelected = item.rawValue == 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)))
|
||||
itemBinding.icon1.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource(context, "01d", item.rawValue)))
|
||||
itemBinding.icon2.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource(context, "01n", item.rawValue)))
|
||||
itemBinding.icon3.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource(context, "10d", item.rawValue)))
|
||||
itemBinding.icon4.setImageDrawable(ContextCompat.getDrawable(context, WeatherHelper.getWeatherIconResource(context, "09n", item.rawValue)))
|
||||
|
||||
listOf<ImageView>(itemView.icon_1, itemView.icon_2, itemView.icon_3, itemView.icon_4).forEach {
|
||||
listOf<ImageView>(itemBinding.icon1, itemBinding.icon2, itemBinding.icon3, itemBinding.icon4).forEach {
|
||||
if (item == Constants.WeatherIconPack.MINIMAL) {
|
||||
it.setColorFilter(ContextCompat.getColor(context, R.color.colorPrimaryText))
|
||||
} else {
|
||||
@ -45,13 +43,13 @@ class IconPackSelector(context: Context, private val header: String? = null) : B
|
||||
}
|
||||
}
|
||||
|
||||
itemView.setOnClickListener {
|
||||
Preferences.weatherIconPack = item.value
|
||||
itemBinding.root.setOnClickListener {
|
||||
Preferences.weatherIconPack = item.rawValue
|
||||
this.dismiss()
|
||||
}
|
||||
view.menu.addView(itemView)
|
||||
binding.menu.addView(itemBinding.root)
|
||||
}
|
||||
setContentView(view)
|
||||
setContentView(binding.root)
|
||||
super.show()
|
||||
}
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
package com.tommasoberlose.anotherwidget.components
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.view.LayoutInflater
|
||||
import androidx.core.view.isVisible
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import kotlinx.android.synthetic.main.bottom_sheet_dialog.view.*
|
||||
import com.tommasoberlose.anotherwidget.databinding.BottomSheetDialogBinding
|
||||
|
||||
typealias DialogCallback = () -> Unit
|
||||
|
||||
@ -20,6 +20,8 @@ class MaterialBottomSheetDialog(
|
||||
private var positiveCallback: DialogCallback? = null
|
||||
private var negativeCallback: DialogCallback? = null
|
||||
|
||||
private var binding = BottomSheetDialogBinding.inflate(LayoutInflater.from(context))
|
||||
|
||||
fun setPositiveButton(label: String? = context.getString(android.R.string.ok), callback: DialogCallback? = null): MaterialBottomSheetDialog {
|
||||
positiveButtonLabel = label
|
||||
positiveCallback = callback
|
||||
@ -33,30 +35,28 @@ class MaterialBottomSheetDialog(
|
||||
}
|
||||
|
||||
override fun show() {
|
||||
val view = View.inflate(context, R.layout.bottom_sheet_dialog, null)
|
||||
|
||||
// Header
|
||||
view.title.isVisible = title != null
|
||||
view.title.text = title ?: ""
|
||||
binding.title.isVisible = title != null
|
||||
binding.title.text = title ?: ""
|
||||
|
||||
view.message.isVisible = message != null
|
||||
view.message.text = message ?: ""
|
||||
binding.message.isVisible = message != null
|
||||
binding.message.text = message ?: ""
|
||||
|
||||
view.action_positive.isVisible = positiveButtonLabel != null
|
||||
view.action_positive.text = positiveButtonLabel ?: ""
|
||||
view.action_positive.setOnClickListener {
|
||||
binding.actionPositive.isVisible = positiveButtonLabel != null
|
||||
binding.actionPositive.text = positiveButtonLabel ?: ""
|
||||
binding.actionPositive.setOnClickListener {
|
||||
positiveCallback?.invoke()
|
||||
this.dismiss()
|
||||
}
|
||||
|
||||
view.action_negative.isVisible = negativeButtonLabel != null
|
||||
view.action_negative.text = negativeButtonLabel ?: ""
|
||||
view.action_negative.setOnClickListener {
|
||||
binding.actionNegative.isVisible = negativeButtonLabel != null
|
||||
binding.actionNegative.text = negativeButtonLabel ?: ""
|
||||
binding.actionNegative.setOnClickListener {
|
||||
negativeCallback?.invoke()
|
||||
this.dismiss()
|
||||
}
|
||||
|
||||
setContentView(view)
|
||||
setContentView(binding.root)
|
||||
super.show()
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,31 @@
|
||||
package com.tommasoberlose.anotherwidget.components
|
||||
|
||||
import android.view.View
|
||||
|
||||
class OnSingleClickListener : View.OnClickListener {
|
||||
|
||||
private val onClickListener: View.OnClickListener
|
||||
|
||||
constructor(listener: View.OnClickListener) {
|
||||
onClickListener = listener
|
||||
}
|
||||
|
||||
constructor(listener: (View) -> Unit) {
|
||||
onClickListener = View.OnClickListener { listener.invoke(it) }
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
val currentTimeMillis = System.currentTimeMillis()
|
||||
|
||||
if (currentTimeMillis >= previousClickTimeMillis + DELAY_MILLIS) {
|
||||
previousClickTimeMillis = currentTimeMillis
|
||||
onClickListener.onClick(v)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val DELAY_MILLIS = 200L
|
||||
private var previousClickTimeMillis = 0L
|
||||
}
|
||||
|
||||
}
|
@ -2,7 +2,6 @@ package com.tommasoberlose.anotherwidget.global
|
||||
|
||||
object Actions {
|
||||
const val ACTION_EXTRA_OPEN_WEATHER_PROVIDER = "ACTION_EXTRA_OPEN_WEATHER_PROVIDER"
|
||||
const val ACTION_EXTRA_DISABLE_GPS_NOTIFICATION = "ACTION_EXTRA_DISABLE_GPS_NOTIFICATION"
|
||||
|
||||
const val ACTION_TIME_UPDATE = "com.tommasoberlose.anotherwidget.action.TIME_UPDATE"
|
||||
const val ACTION_ALARM_UPDATE = "com.tommasoberlose.anotherwidget.action.ALARM_UPDATE"
|
||||
@ -14,4 +13,6 @@ object Actions {
|
||||
const val ACTION_REPORT_CRASH = "com.tommasoberlose.anotherwidget.action.REPORT_CRASH"
|
||||
const val ACTION_CLEAR_NOTIFICATION = "com.tommasoberlose.anotherwidget.action.CLEAR_NOTIFICATION"
|
||||
const val ACTION_UPDATE_GREETINGS = "com.tommasoberlose.anotherwidget.action.UPDATE_GREETINGS"
|
||||
|
||||
const val ACTION_REFRESH = "com.tommasoberlose.anotherwidget.action.REFRESH"
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
package com.tommasoberlose.anotherwidget.global
|
||||
|
||||
import java.text.SimpleDateFormat
|
||||
|
||||
object Constants {
|
||||
const val RESULT_CODE_CUSTOM_LOCATION = 45
|
||||
const val RESULT_APP_NAME = "RESULT_APP_NAME"
|
||||
@ -11,14 +9,14 @@ object Constants {
|
||||
const val CUSTOM_FONT_DOWNLOADED = 2
|
||||
const val CUSTOM_FONT_DOWNLOAD_NEW = 3
|
||||
|
||||
enum class ClockBottomMargin(val value: Int) {
|
||||
enum class ClockBottomMargin(val rawValue: Int) {
|
||||
NONE(0),
|
||||
SMALL(1),
|
||||
MEDIUM(2),
|
||||
LARGE(3)
|
||||
}
|
||||
|
||||
enum class SecondRowTopMargin(val value: Int) {
|
||||
enum class SecondRowTopMargin(val rawValue: Int) {
|
||||
NONE(0),
|
||||
SMALL(1),
|
||||
MEDIUM(2),
|
||||
@ -41,13 +39,13 @@ object Constants {
|
||||
}
|
||||
}
|
||||
|
||||
enum class WidgetUpdateFrequency(val value: Int) {
|
||||
enum class WidgetUpdateFrequency(val rawValue: Int) {
|
||||
LOW(0),
|
||||
DEFAULT(1),
|
||||
HIGH(2)
|
||||
}
|
||||
|
||||
enum class WeatherProvider(val value: Int) {
|
||||
enum class WeatherProvider(val rawValue: Int) {
|
||||
OPEN_WEATHER(0),
|
||||
WEATHER_BIT(1),
|
||||
WEATHER_API(2),
|
||||
@ -57,12 +55,12 @@ object Constants {
|
||||
YR(6);
|
||||
|
||||
companion object {
|
||||
private val map = WeatherProvider.values().associateBy(WeatherProvider::value)
|
||||
private val map = WeatherProvider.values().associateBy(WeatherProvider::rawValue)
|
||||
fun fromInt(type: Int) = map[type]
|
||||
}
|
||||
}
|
||||
|
||||
enum class GlanceNotificationTimer(val value: Int) {
|
||||
enum class GlanceNotificationTimer(val rawValue: Int) {
|
||||
HALF_MINUTE(0),
|
||||
ONE_MINUTE(1),
|
||||
FIVE_MINUTES(2),
|
||||
@ -71,15 +69,21 @@ object Constants {
|
||||
WHEN_DISMISSED(5);
|
||||
|
||||
companion object {
|
||||
private val map = values().associateBy(GlanceNotificationTimer::value)
|
||||
private val map = values().associateBy(GlanceNotificationTimer::rawValue)
|
||||
fun fromInt(type: Int) = map[type]
|
||||
}
|
||||
}
|
||||
|
||||
enum class WeatherIconPack(val value: Int) {
|
||||
enum class WeatherIconPack(val rawValue: Int) {
|
||||
DEFAULT(0),
|
||||
MINIMAL(1),
|
||||
COOL(2),
|
||||
GOOGLE_NEWS(3)
|
||||
}
|
||||
|
||||
enum class WidgetAlign(val rawValue: Int) {
|
||||
LEFT(0),
|
||||
RIGHT(1),
|
||||
CENTER(2)
|
||||
}
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
package com.tommasoberlose.anotherwidget.global
|
||||
|
||||
import android.os.Build
|
||||
import androidx.appcompat.app.AppCompatDelegate.*
|
||||
import androidx.core.os.ConfigurationCompat
|
||||
import com.chibatching.kotpref.KotprefModel
|
||||
import com.tommasoberlose.anotherwidget.helpers.IntentHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||
import com.tommasoberlose.anotherwidget.utils.isMetric
|
||||
import java.util.*
|
||||
|
||||
object Preferences : KotprefModel() {
|
||||
override val commitAllPropertiesByDefault: Boolean = true
|
||||
@ -46,14 +46,14 @@ object Preferences : KotprefModel() {
|
||||
var weatherProviderApiWeatherApi by stringPref(default = "")
|
||||
var weatherProviderApiWeatherBit by stringPref(default = "")
|
||||
var weatherProviderApiAccuweather by stringPref(default = "")
|
||||
var weatherProvider by intPref(default = if (ConfigurationCompat.getLocales(context.resources.configuration)[0].isMetric()) Constants.WeatherProvider.YR.value else Constants.WeatherProvider.WEATHER_GOV.value)
|
||||
var weatherProvider by intPref(default = if (ConfigurationCompat.getLocales(context.resources.configuration)[0].isMetric()) Constants.WeatherProvider.YR.rawValue else Constants.WeatherProvider.WEATHER_GOV.rawValue)
|
||||
var weatherProviderError by stringPref(default = "")
|
||||
var weatherProviderLocationError by stringPref(default = "")
|
||||
var eventAppName by stringPref(key = "PREF_EVENT_APP_NAME", default = "")
|
||||
var eventAppPackage by stringPref(key = "PREF_EVENT_APP_PACKAGE", default = "")
|
||||
var openEventDetails by booleanPref(default = true)
|
||||
|
||||
var widgetUpdateFrequency by intPref(default = Constants.WidgetUpdateFrequency.DEFAULT.value)
|
||||
var widgetUpdateFrequency by intPref(default = Constants.WidgetUpdateFrequency.DEFAULT.rawValue)
|
||||
|
||||
var textGlobalColor by stringPref(key = "PREF_TEXT_COLOR", default = "#FFFFFF")
|
||||
var textGlobalAlpha by stringPref(default = "FF")
|
||||
@ -82,14 +82,18 @@ object Preferences : KotprefModel() {
|
||||
|
||||
var showAMPMIndicator by booleanPref(default = true)
|
||||
|
||||
var weatherIconPack by intPref(default = Constants.WeatherIconPack.DEFAULT.value)
|
||||
var weatherIconPack by intPref(default = Constants.WeatherIconPack.DEFAULT.rawValue)
|
||||
|
||||
// Clock
|
||||
var altTimezoneLabel by stringPref(default = "")
|
||||
var altTimezoneId by stringPref(default = "")
|
||||
|
||||
// Global
|
||||
var textMainSize by floatPref(key = "PREF_TEXT_MAIN_SIZE", default = 26f)
|
||||
var textSecondSize by floatPref(key = "PREF_TEXT_SECOND_SIZE", default = 18f)
|
||||
var clockTextSize by floatPref(key = "PREF_TEXT_CLOCK_SIZE", default = 90f)
|
||||
var clockBottomMargin by intPref(default = Constants.ClockBottomMargin.MEDIUM.value)
|
||||
var secondRowTopMargin by intPref(default = Constants.SecondRowTopMargin.NONE.value)
|
||||
var clockBottomMargin by intPref(default = Constants.ClockBottomMargin.MEDIUM.rawValue)
|
||||
var secondRowTopMargin by intPref(default = Constants.SecondRowTopMargin.NONE.rawValue)
|
||||
var showClock by booleanPref(key = "PREF_SHOW_CLOCK", default = false)
|
||||
var clockAppName by stringPref(key = "PREF_CLOCK_APP_NAME", default = "")
|
||||
var clockAppPackage by stringPref(key = "PREF_CLOCK_APP_PACKAGE", default = "")
|
||||
@ -106,21 +110,21 @@ object Preferences : KotprefModel() {
|
||||
var customFontName by stringPref(default = "")
|
||||
var customFontVariant by stringPref(default = "regular")
|
||||
var showNextEvent by booleanPref(key = "PREF_SHOW_NEXT_EVENT", default = true)
|
||||
var showNextEventOnMultipleLines by booleanPref(default = false)
|
||||
|
||||
var showDividers by booleanPref(default = true)
|
||||
|
||||
var widgetAlign by intPref(default = Constants.WidgetAlign.CENTER.rawValue)
|
||||
|
||||
// Settings
|
||||
var showWallpaper by booleanPref(default = true)
|
||||
var showBigClockWarning by booleanPref(default = true)
|
||||
var showWeatherWarning by booleanPref(default = true)
|
||||
var showPreview by booleanPref(default = true)
|
||||
var showXiaomiWarning by booleanPref(default = true)
|
||||
|
||||
// Glance
|
||||
var showGlance by booleanPref(default = true)
|
||||
var enabledGlanceProviderOrder by stringPref(default = "")
|
||||
var customNotes by stringPref(default = "")
|
||||
var showNextAlarm by booleanPref(default = true)
|
||||
var showNextAlarm by booleanPref(default = false)
|
||||
var showBatteryCharging by booleanPref(default = false)
|
||||
var isBatteryLevelLow by booleanPref(default = false)
|
||||
var isCharging by booleanPref(default = false)
|
||||
@ -128,7 +132,7 @@ object Preferences : KotprefModel() {
|
||||
var showDailySteps by booleanPref(default = false)
|
||||
var showGreetings by booleanPref(default = false)
|
||||
var showNotifications by booleanPref(default = false)
|
||||
var hideNotificationAfter by intPref(default = Constants.GlanceNotificationTimer.ONE_MINUTE.value)
|
||||
var hideNotificationAfter by intPref(default = Constants.GlanceNotificationTimer.ONE_MINUTE.rawValue)
|
||||
|
||||
var lastNotificationId by intPref(default = -1)
|
||||
var lastNotificationTitle by stringPref(default = "")
|
||||
@ -136,11 +140,11 @@ object Preferences : KotprefModel() {
|
||||
var lastNotificationPackage by stringPref(default = "")
|
||||
|
||||
var showMusic by booleanPref(default = false)
|
||||
var mediaInfoFormat by stringPref(default = "")
|
||||
var mediaInfoFormat by stringPref(default = MediaPlayerHelper.DEFAULT_MEDIA_INFO_FORMAT)
|
||||
var mediaPlayerTitle by stringPref(default = "")
|
||||
var mediaPlayerAlbum by stringPref(default = "")
|
||||
var mediaPlayerArtist by stringPref(default = "")
|
||||
var mediaPlayerPackage by stringPref(default = "")
|
||||
var mediaPlayerPackage by stringPref(default = IntentHelper.DO_NOTHING_OPTION)
|
||||
var musicPlayersFilter by stringPref(default = "")
|
||||
var appNotificationsFilter by stringPref(default = "")
|
||||
|
||||
|
@ -1,29 +1,16 @@
|
||||
package com.tommasoberlose.anotherwidget.helpers
|
||||
|
||||
import android.Manifest
|
||||
import android.app.job.JobInfo
|
||||
import android.app.job.JobParameters
|
||||
import android.app.job.JobScheduler
|
||||
import android.app.job.JobService
|
||||
import android.content.ComponentName
|
||||
import android.content.ContentUris
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.provider.CalendarContract
|
||||
import android.util.Log
|
||||
import com.tommasoberlose.anotherwidget.services.EventListenerJob
|
||||
import com.tommasoberlose.anotherwidget.db.EventRepository
|
||||
import com.tommasoberlose.anotherwidget.models.Event
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
||||
import com.tommasoberlose.anotherwidget.services.UpdateCalendarJob
|
||||
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||
import com.tommasoberlose.anotherwidget.services.UpdateCalendarService
|
||||
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
|
||||
|
||||
/**
|
||||
@ -32,7 +19,7 @@ import kotlin.collections.ArrayList
|
||||
|
||||
object CalendarHelper {
|
||||
fun updateEventList(context: Context) {
|
||||
UpdateCalendarJob.enqueueWork(context, Intent())
|
||||
UpdateCalendarService.enqueueWork(context)
|
||||
}
|
||||
|
||||
fun getCalendarList(context: Context): List<me.everything.providers.android.calendar.Calendar> {
|
||||
|
@ -1,15 +1,27 @@
|
||||
package com.tommasoberlose.anotherwidget.helpers
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Context.CLIPBOARD_SERVICE
|
||||
import android.graphics.Color
|
||||
import android.util.Log
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||
import com.tommasoberlose.anotherwidget.utils.toast
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
||||
object ColorHelper {
|
||||
fun getFontColor(isDark: Boolean): Int {
|
||||
return try {
|
||||
Color.parseColor("#%s%s".format(if (!isDark) Preferences.textGlobalAlpha else Preferences.textGlobalAlphaDark, (if (!isDark) Preferences.textGlobalColor else Preferences.textGlobalColorDark).replace("#", "")))
|
||||
Color.parseColor("#%s%s".format(if (!isDark) Preferences.textGlobalAlpha else Preferences.textGlobalAlphaDark,
|
||||
(if (!isDark) Preferences.textGlobalColor else Preferences.textGlobalColorDark).replace(
|
||||
"#",
|
||||
"")))
|
||||
} catch (e: Exception) {
|
||||
Color.parseColor("#FFFFFFFF")
|
||||
}
|
||||
@ -33,7 +45,10 @@ object ColorHelper {
|
||||
|
||||
fun getSecondaryFontColor(isDark: Boolean): Int {
|
||||
return try {
|
||||
Color.parseColor("#%s%s".format((if (!isDark) Preferences.textSecondaryAlpha else Preferences.textSecondaryAlphaDark), (if (!isDark) Preferences.textSecondaryColor else Preferences.textSecondaryColorDark).replace("#", "")))
|
||||
Color.parseColor("#%s%s".format((if (!isDark) Preferences.textSecondaryAlpha else Preferences.textSecondaryAlphaDark),
|
||||
(if (!isDark) Preferences.textSecondaryColor else Preferences.textSecondaryColorDark).replace(
|
||||
"#",
|
||||
"")))
|
||||
} catch (e: Exception) {
|
||||
Color.parseColor("#FFFFFFFF")
|
||||
}
|
||||
@ -57,7 +72,10 @@ object ColorHelper {
|
||||
|
||||
fun getClockFontColor(isDark: Boolean): Int {
|
||||
return try {
|
||||
Color.parseColor("#%s%s".format((if (!isDark) Preferences.clockTextAlpha else Preferences.clockTextAlphaDark), (if (!isDark) Preferences.clockTextColor else Preferences.clockTextColorDark).replace("#", "")))
|
||||
Color.parseColor("#%s%s".format((if (!isDark) Preferences.clockTextAlpha else Preferences.clockTextAlphaDark),
|
||||
(if (!isDark) Preferences.clockTextColor else Preferences.clockTextColorDark).replace(
|
||||
"#",
|
||||
"")))
|
||||
} catch (e: Exception) {
|
||||
Color.parseColor("#FFFFFFFF")
|
||||
}
|
||||
@ -81,7 +99,10 @@ object ColorHelper {
|
||||
|
||||
fun getBackgroundColor(isDark: Boolean): Int {
|
||||
return try {
|
||||
Color.parseColor("#%s%s".format((if (!isDark) Preferences.backgroundCardAlpha else Preferences.backgroundCardAlphaDark), (if (!isDark) Preferences.backgroundCardColor else Preferences.backgroundCardColorDark).replace("#", "")))
|
||||
Color.parseColor("#%s%s".format((if (!isDark) Preferences.backgroundCardAlpha else Preferences.backgroundCardAlphaDark),
|
||||
(if (!isDark) Preferences.backgroundCardColor else Preferences.backgroundCardColorDark).replace(
|
||||
"#",
|
||||
"")))
|
||||
} catch (e: Exception) {
|
||||
Color.parseColor("#00000000")
|
||||
}
|
||||
@ -123,4 +144,50 @@ object ColorHelper {
|
||||
val hexValue = this.toInt(16).toDouble()
|
||||
return (hexValue * 100 / 255).roundToInt()
|
||||
}
|
||||
|
||||
fun String.isColor(): Boolean {
|
||||
return try {
|
||||
Color.parseColor(this)
|
||||
true
|
||||
} catch (iae: IllegalArgumentException) {
|
||||
iae.printStackTrace()
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
fun Context.copyToClipboard(color: Int?, alpha: Int) {
|
||||
if (color == null) return toast(getString(R.string.error_copy_color))
|
||||
with(getSystemService(CLIPBOARD_SERVICE) as ClipboardManager) {
|
||||
try {
|
||||
val colorString = Integer.toHexString(color)
|
||||
val clip = "#%s%s".format(
|
||||
alpha.toHexValue(),
|
||||
if (colorString.length > 6) colorString.substring(2) else colorString
|
||||
).toUpperCase()
|
||||
setPrimaryClip(ClipData.newPlainText(clip, clip))
|
||||
toast(getString(R.string.color_copied))
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
toast(getString(R.string.error_copy_color))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.isClipboardColor(): Boolean {
|
||||
with(getSystemService(CLIPBOARD_SERVICE) as ClipboardManager) {
|
||||
return try { primaryClip?.getItemAt(0)?.text?.toString()?.isColor() ?: false } catch (ex: Exception) { false }
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.pasteFromClipboard(pasteColor: (color: String, alpha: String) -> Unit) {
|
||||
with(getSystemService(CLIPBOARD_SERVICE) as ClipboardManager) {
|
||||
primaryClip?.let {
|
||||
val item = it.getItemAt(0).text.toString().replace("#", "")
|
||||
val color = if (item.length > 6) item.substring(2) else item
|
||||
val alpha = if (item.length > 6) item.substring(0, 2) else "00"
|
||||
pasteColor("#$color", alpha)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -101,7 +101,7 @@ object GlanceProviderHelper {
|
||||
val eventRepository = EventRepository(context)
|
||||
BatteryHelper.updateBatteryInfo(context)
|
||||
|
||||
val showGlance = Preferences.showGlance && (eventRepository.getEventsCount() == 0 || !Preferences.showEvents || Preferences.showEventsAsGlanceProvider)
|
||||
val showGlance = (eventRepository.getEventsCount() == 0 || !Preferences.showEvents || Preferences.showEventsAsGlanceProvider)
|
||||
&& (
|
||||
(Preferences.showNotifications && ActiveNotificationsHelper.showLastNotification()) ||
|
||||
(Preferences.showNextAlarm && AlarmHelper.getNextAlarm(context) != "") ||
|
||||
|
@ -20,7 +20,7 @@ object ImageHelper {
|
||||
else -> 0f * factor
|
||||
}, resources.displayMetrics)
|
||||
|
||||
if (originalView.drawable != null) {
|
||||
if (originalView.drawable != null && originalView.drawable.intrinsicWidth > 0 && originalView.drawable.intrinsicHeight > 0) {
|
||||
val btm = originalView.drawable.toBitmap().copy(Bitmap.Config.ARGB_8888, true)
|
||||
val comb = Bitmap.createBitmap(btm)
|
||||
val shadowBitmap = generateShadowBitmap(context, cElevation, btm, factor)
|
||||
@ -30,7 +30,7 @@ object ImageHelper {
|
||||
canvas.drawColor(Color.TRANSPARENT)
|
||||
canvas.save()
|
||||
val rect = Rect()
|
||||
val bounds = originalView.drawable.copyBounds()
|
||||
// val bounds = originalView.drawable.copyBounds()
|
||||
canvas.getClipBounds(rect)
|
||||
rect.inset(-2 * getBlurRadius(context, cElevation).toInt(), -2 * getBlurRadius(context, cElevation).toInt())
|
||||
canvas.save()
|
||||
|
@ -12,8 +12,10 @@ import android.provider.CalendarContract
|
||||
import android.provider.CalendarContract.Events
|
||||
import android.util.Log
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.global.Actions
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.models.Event
|
||||
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||
import com.tommasoberlose.anotherwidget.utils.toast
|
||||
import java.util.*
|
||||
@ -21,6 +23,10 @@ import java.util.*
|
||||
|
||||
object IntentHelper {
|
||||
|
||||
const val DEFAULT_OPTION = ""
|
||||
const val DO_NOTHING_OPTION = "DO_NOTHING"
|
||||
const val REFRESH_WIDGET_OPTION = "REFRESH_WIDGET"
|
||||
|
||||
fun getWidgetUpdateIntent(context: Context): Intent {
|
||||
val widgetManager = AppWidgetManager.getInstance(context)
|
||||
val widgetComponent = ComponentName(context, MainWidget::class.java)
|
||||
@ -31,6 +37,13 @@ object IntentHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getWidgetRefreshIntent(context: Context): Intent {
|
||||
return Intent(context, UpdatesReceiver::class.java).apply {
|
||||
action = Actions.ACTION_REFRESH
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
}
|
||||
}
|
||||
|
||||
fun getGoogleMapsIntentFromAddress(context: Context, address: String): Intent {
|
||||
val gmmIntentUri: Uri = Uri.parse("geo:0,0?q=$address")
|
||||
val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
|
||||
@ -47,17 +60,21 @@ object IntentHelper {
|
||||
|
||||
fun getWeatherIntent(context: Context): Intent {
|
||||
return when (Preferences.weatherAppPackage) {
|
||||
"" -> {
|
||||
DEFAULT_OPTION -> {
|
||||
Intent(Intent.ACTION_VIEW).apply {
|
||||
addCategory(Intent.CATEGORY_DEFAULT)
|
||||
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")
|
||||
setClassName("com.google.android.googlequicksearchbox", "com.google.android.apps.gsa.velour.DynamicActivityTrampoline")
|
||||
}
|
||||
}
|
||||
"_" -> {
|
||||
DO_NOTHING_OPTION -> {
|
||||
Intent()
|
||||
}
|
||||
REFRESH_WIDGET_OPTION -> {
|
||||
getWidgetRefreshIntent(context)
|
||||
}
|
||||
else -> {
|
||||
val pm: PackageManager = context.packageManager
|
||||
try {
|
||||
@ -79,14 +96,17 @@ object IntentHelper {
|
||||
.appendPath(Calendar.getInstance().timeInMillis.toString())
|
||||
.build()
|
||||
return when (Preferences.calendarAppPackage) {
|
||||
"" -> {
|
||||
DEFAULT_OPTION -> {
|
||||
Intent(Intent.ACTION_VIEW).apply {
|
||||
data = calendarUri
|
||||
}
|
||||
}
|
||||
"_" -> {
|
||||
DO_NOTHING_OPTION -> {
|
||||
Intent()
|
||||
}
|
||||
REFRESH_WIDGET_OPTION -> {
|
||||
getWidgetRefreshIntent(context)
|
||||
}
|
||||
else -> {
|
||||
val pm: PackageManager = context.packageManager
|
||||
try {
|
||||
@ -164,14 +184,17 @@ object IntentHelper {
|
||||
|
||||
fun getClockIntent(context: Context): Intent {
|
||||
return when (Preferences.clockAppPackage) {
|
||||
"" -> {
|
||||
DEFAULT_OPTION -> {
|
||||
Intent(AlarmClock.ACTION_SHOW_ALARMS).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
}
|
||||
}
|
||||
"_" -> {
|
||||
DO_NOTHING_OPTION -> {
|
||||
Intent()
|
||||
}
|
||||
REFRESH_WIDGET_OPTION -> {
|
||||
getWidgetRefreshIntent(context)
|
||||
}
|
||||
else -> {
|
||||
val pm: PackageManager = context.packageManager
|
||||
try {
|
||||
@ -191,7 +214,7 @@ object IntentHelper {
|
||||
|
||||
fun getMusicIntent(context: Context): Intent {
|
||||
return when (Preferences.mediaPlayerPackage) {
|
||||
"" -> {
|
||||
DO_NOTHING_OPTION -> {
|
||||
Intent()
|
||||
}
|
||||
else -> {
|
||||
|
@ -12,17 +12,38 @@ import com.chibatching.kotpref.bulk
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.receivers.NotificationListener
|
||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||
import com.tommasoberlose.anotherwidget.utils.ignoreExceptions
|
||||
import java.lang.Exception
|
||||
|
||||
object MediaPlayerHelper {
|
||||
const val MEDIA_INFO_TITLE = "%TITLE"
|
||||
const val MEDIA_INFO_ARTIST = "%ARTIST"
|
||||
const val MEDIA_INFO_ALBUM = "%ALBUM"
|
||||
|
||||
const val DEFAULT_MEDIA_INFO_FORMAT = "%TITLE, %ARTIST"
|
||||
|
||||
fun isSomeonePlaying(context: Context) = Preferences.showMusic && ActiveNotificationsHelper.checkNotificationAccess(context) && Preferences.mediaPlayerTitle != ""
|
||||
|
||||
fun getMediaInfo(): String {
|
||||
return if (Preferences.mediaPlayerArtist == "") {
|
||||
Preferences.mediaPlayerTitle
|
||||
} else {
|
||||
"%s, %s".format(Preferences.mediaPlayerTitle, Preferences.mediaPlayerArtist)
|
||||
}
|
||||
fun getMediaInfo(format: String = Preferences.mediaInfoFormat, title: String = Preferences.mediaPlayerTitle, artist: String = Preferences.mediaPlayerArtist, album: String = Preferences.mediaPlayerAlbum): String {
|
||||
return when (format) {
|
||||
"",
|
||||
DEFAULT_MEDIA_INFO_FORMAT -> {
|
||||
if (Preferences.mediaPlayerArtist == "") {
|
||||
Preferences.mediaPlayerTitle
|
||||
} else {
|
||||
DEFAULT_MEDIA_INFO_FORMAT.replace(MEDIA_INFO_TITLE, title)
|
||||
.replace(MEDIA_INFO_ARTIST, artist)
|
||||
.replace(MEDIA_INFO_ALBUM, album)
|
||||
.replace("\\n", System.getProperty("line.separator") ?: " ")
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
format.replace(MEDIA_INFO_TITLE, title)
|
||||
.replace(MEDIA_INFO_ARTIST, artist)
|
||||
.replace(MEDIA_INFO_ALBUM, album)
|
||||
.replace("\\n", System.getProperty("line.separator") ?: " ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updatePlayingMediaInfo(context: Context) {
|
||||
@ -49,15 +70,24 @@ object MediaPlayerHelper {
|
||||
isSomeonePlaying = true
|
||||
if (metadata != null) {
|
||||
Preferences.bulk {
|
||||
mediaPlayerTitle =
|
||||
metadata.getText(MediaMetadata.METADATA_KEY_TITLE)?.toString()
|
||||
?: ""
|
||||
mediaPlayerArtist =
|
||||
metadata.getText(MediaMetadata.METADATA_KEY_ARTIST)?.toString()
|
||||
?: ""
|
||||
mediaPlayerAlbum =
|
||||
metadata.getText(MediaMetadata.METADATA_KEY_ALBUM)?.toString()
|
||||
?: ""
|
||||
ignoreExceptions {
|
||||
mediaPlayerTitle =
|
||||
metadata.getText(MediaMetadata.METADATA_KEY_TITLE)
|
||||
?.toString()
|
||||
?: ""
|
||||
}
|
||||
ignoreExceptions {
|
||||
mediaPlayerArtist =
|
||||
metadata.getText(MediaMetadata.METADATA_KEY_ARTIST)
|
||||
?.toString()
|
||||
?: ""
|
||||
}
|
||||
ignoreExceptions {
|
||||
mediaPlayerAlbum =
|
||||
metadata.getText(MediaMetadata.METADATA_KEY_ALBUM)
|
||||
?.toString()
|
||||
?: ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,10 +63,20 @@ object SettingsStringHelper {
|
||||
}
|
||||
|
||||
fun getVariantLabel(context: Context, variant: String): String = when {
|
||||
variant == "italic" -> context.getString(R.string.font_italic)
|
||||
variant.contains("100") && variant.contains("italic") -> context.getString(R.string.font_100_italic)
|
||||
variant.contains("200") && variant.contains("italic") -> context.getString(R.string.font_200_italic)
|
||||
variant.contains("300") && variant.contains("italic") -> context.getString(R.string.font_300_italic)
|
||||
variant.contains("400") && variant.contains("italic") -> context.getString(R.string.font_400_italic)
|
||||
variant.contains("500") && variant.contains("italic") -> context.getString(R.string.font_500_italic)
|
||||
variant.contains("600") && variant.contains("italic") -> context.getString(R.string.font_600_italic)
|
||||
variant.contains("700") && variant.contains("italic") -> context.getString(R.string.font_700_italic)
|
||||
variant.contains("800") && variant.contains("italic") -> context.getString(R.string.font_800_italic)
|
||||
variant.contains("900") && variant.contains("italic") -> context.getString(R.string.font_900_italic)
|
||||
variant == "regular" || variant.contains("400") -> context.getString(R.string.font_400)
|
||||
variant.contains("100") -> context.getString(R.string.font_100)
|
||||
variant.contains("200") -> context.getString(R.string.font_200)
|
||||
variant.contains("300") -> context.getString(R.string.font_300)
|
||||
variant.contains("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)
|
||||
@ -86,13 +96,13 @@ object SettingsStringHelper {
|
||||
difference <= 0 -> {
|
||||
return ""
|
||||
}
|
||||
TimeUnit.MILLISECONDS.toHours(difference) < 1 && Preferences.widgetUpdateFrequency == Constants.WidgetUpdateFrequency.HIGH.value && TimeUnit.MILLISECONDS.toMinutes(difference) > 5 -> {
|
||||
TimeUnit.MILLISECONDS.toHours(difference) < 1 && Preferences.widgetUpdateFrequency == Constants.WidgetUpdateFrequency.HIGH.rawValue && TimeUnit.MILLISECONDS.toMinutes(difference) > 5 -> {
|
||||
return DateUtils.getRelativeTimeSpanString(start, start - 1000 * 60 * (TimeUnit.MILLISECONDS.toMinutes(difference) - 1 - (TimeUnit.MILLISECONDS.toMinutes(difference) - 1) % 5), DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE).toString()
|
||||
}
|
||||
TimeUnit.MILLISECONDS.toHours(difference) < 1 && Preferences.widgetUpdateFrequency == Constants.WidgetUpdateFrequency.DEFAULT.value && TimeUnit.MILLISECONDS.toMinutes(difference) > 5 -> {
|
||||
TimeUnit.MILLISECONDS.toHours(difference) < 1 && Preferences.widgetUpdateFrequency == Constants.WidgetUpdateFrequency.DEFAULT.rawValue && TimeUnit.MILLISECONDS.toMinutes(difference) > 5 -> {
|
||||
return DateUtils.getRelativeTimeSpanString(start, start - 1000 * 60 * (TimeUnit.MILLISECONDS.toMinutes(difference) - 1 - (TimeUnit.MILLISECONDS.toMinutes(difference) - 1) % 15), DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE).toString()
|
||||
}
|
||||
TimeUnit.MILLISECONDS.toHours(difference) < 1 && Preferences.widgetUpdateFrequency == Constants.WidgetUpdateFrequency.LOW.value -> {
|
||||
TimeUnit.MILLISECONDS.toHours(difference) < 1 && Preferences.widgetUpdateFrequency == Constants.WidgetUpdateFrequency.LOW.rawValue -> {
|
||||
return context.getString(R.string.soon)
|
||||
}
|
||||
TimeUnit.MILLISECONDS.toHours(difference) < 1 -> {
|
||||
|
@ -2,23 +2,15 @@ package com.tommasoberlose.anotherwidget.helpers
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import com.chibatching.kotpref.Kotpref
|
||||
import com.google.android.gms.location.LocationServices
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.network.WeatherNetworkApi
|
||||
import com.tommasoberlose.anotherwidget.services.LocationService
|
||||
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
|
||||
|
||||
/**
|
||||
@ -122,97 +114,97 @@ object WeatherHelper {
|
||||
return when (icon) {
|
||||
"01d" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.clear_day_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.clear_day_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.clear_day_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.clear_day_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.clear_day_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.clear_day_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.clear_day_5 else R.drawable.clear_day_5_light
|
||||
}
|
||||
}
|
||||
"02d" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.partly_cloudy_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.partly_cloudy_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.partly_cloudy_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.partly_cloudy_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.partly_cloudy_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.partly_cloudy_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.partly_cloudy_5 else R.drawable.partly_cloudy_5_light
|
||||
}
|
||||
}
|
||||
"03d" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.mostly_cloudy_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.mostly_cloudy_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.mostly_cloudy_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.mostly_cloudy_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.mostly_cloudy_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.mostly_cloudy_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.mostly_cloudy_5 else R.drawable.mostly_cloudy_5_light
|
||||
}
|
||||
}
|
||||
"04d" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.cloudy_weather_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.cloudy_weather_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.cloudy_weather_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.cloudy_weather_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.cloudy_weather_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.cloudy_weather_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.cloudy_weather_5 else R.drawable.cloudy_weather_5_light
|
||||
}
|
||||
}
|
||||
"09d" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.storm_weather_day_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.storm_weather_day_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.storm_weather_day_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.storm_weather_day_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.storm_weather_day_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.storm_weather_day_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.storm_weather_day_5 else R.drawable.storm_weather_day_5_light
|
||||
}
|
||||
}
|
||||
"10d" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.rainy_day_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rainy_day_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rainy_day_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.rainy_day_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.rainy_day_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.rainy_day_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.rainy_day_5 else R.drawable.rainy_day_5_light
|
||||
}
|
||||
}
|
||||
"11d" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.thunder_day_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.thunder_day_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.thunder_day_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.thunder_day_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.thunder_day_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.thunder_day_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.thunder_day_5 else R.drawable.thunder_day_5_light
|
||||
}
|
||||
}
|
||||
"13d" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.snow_day_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.snow_day_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.snow_day_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.snow_day_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.snow_day_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.snow_day_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.snow_day_5 else R.drawable.snow_day_5_light
|
||||
}
|
||||
}
|
||||
"50d" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_day_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_day_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_day_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.haze_day_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.haze_day_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.haze_day_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.haze_day_5 else R.drawable.haze_day_5_light
|
||||
}
|
||||
}
|
||||
"80d" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.windy_day_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.windy_day_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.windy_day_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.windy_day_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.windy_day_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.windy_day_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.windy_day_5 else R.drawable.windy_day_5_light
|
||||
}
|
||||
}
|
||||
"81d" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.rain_snow_day_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rain_snow_day_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rain_snow_day_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.rain_snow_day_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.rain_snow_day_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.rain_snow_day_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.rain_snow_day_5 else R.drawable.rain_snow_day_5_light
|
||||
}
|
||||
}
|
||||
"82d" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_weather_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_weather_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_weather_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.haze_weather_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.haze_weather_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.haze_weather_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.haze_weather_5 else R.drawable.haze_weather_5_light
|
||||
}
|
||||
}
|
||||
@ -221,97 +213,97 @@ object WeatherHelper {
|
||||
|
||||
"01n" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.clear_night_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.clear_night_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.clear_night_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.clear_night_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.clear_night_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.clear_night_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.clear_night_5 else R.drawable.clear_night_5_light
|
||||
}
|
||||
}
|
||||
"02n" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.partly_cloudy_night_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.partly_cloudy_night_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.partly_cloudy_night_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.partly_cloudy_night_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.partly_cloudy_night_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.partly_cloudy_night_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.partly_cloudy_night_5 else R.drawable.partly_cloudy_night_5_light
|
||||
}
|
||||
}
|
||||
"03n" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.mostly_cloudy_night_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.mostly_cloudy_night_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.mostly_cloudy_night_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.mostly_cloudy_night_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.mostly_cloudy_night_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.mostly_cloudy_night_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.mostly_cloudy_night_5 else R.drawable.mostly_cloudy_night_5_light
|
||||
}
|
||||
}
|
||||
"04n" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.cloudy_weather_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.cloudy_weather_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.cloudy_weather_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.cloudy_weather_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.cloudy_weather_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.cloudy_weather_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.cloudy_weather_5 else R.drawable.cloudy_weather_5_light
|
||||
}
|
||||
}
|
||||
"09n" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.storm_weather_night_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.storm_weather_night_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.storm_weather_night_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.storm_weather_night_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.storm_weather_night_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.storm_weather_night_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.storm_weather_night_5 else R.drawable.storm_weather_night_5_light
|
||||
}
|
||||
}
|
||||
"10n" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.rainy_night_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rainy_night_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rainy_night_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.rainy_night_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.rainy_night_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.rainy_night_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.rainy_night_5 else R.drawable.rainy_night_5_light
|
||||
}
|
||||
}
|
||||
"11n" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.thunder_night_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.thunder_night_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.thunder_night_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.thunder_night_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.thunder_night_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.thunder_night_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.thunder_night_5 else R.drawable.thunder_night_5_light
|
||||
}
|
||||
}
|
||||
"13n" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.snow_night_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.snow_night_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.snow_night_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.snow_night_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.snow_night_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.snow_night_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.snow_night_5 else R.drawable.snow_night_5_light
|
||||
}
|
||||
}
|
||||
"50n" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_night_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_night_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_night_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.haze_night_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.haze_night_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.haze_night_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.haze_night_5 else R.drawable.haze_night_5_light
|
||||
}
|
||||
}
|
||||
"80n" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.windy_night_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.windy_night_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.windy_night_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.windy_night_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.windy_night_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.windy_night_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.windy_night_5 else R.drawable.windy_night_5_light
|
||||
}
|
||||
}
|
||||
"81n" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.rain_snow_night_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.rain_snow_night_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.rain_snow_night_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.rain_snow_night_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.rain_snow_night_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.rain_snow_night_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.rain_snow_night_5 else R.drawable.rain_snow_night_5_light
|
||||
}
|
||||
}
|
||||
"82n" -> {
|
||||
when (style) {
|
||||
Constants.WeatherIconPack.COOL.value -> R.drawable.haze_weather_3
|
||||
Constants.WeatherIconPack.MINIMAL.value -> R.drawable.haze_weather_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.value -> R.drawable.haze_weather_4
|
||||
Constants.WeatherIconPack.COOL.rawValue -> R.drawable.haze_weather_3
|
||||
Constants.WeatherIconPack.MINIMAL.rawValue -> R.drawable.haze_weather_2
|
||||
Constants.WeatherIconPack.GOOGLE_NEWS.rawValue -> R.drawable.haze_weather_4
|
||||
else -> if (context.isDarkTheme()) R.drawable.haze_weather_5 else R.drawable.haze_weather_5_light
|
||||
}
|
||||
}
|
||||
|
@ -25,9 +25,8 @@ object WidgetHelper {
|
||||
) {
|
||||
|
||||
fun getWidgetsSize(widgetId: Int): Pair<Int, Int> {
|
||||
val isPortrait = context.resources.configuration.orientation == ORIENTATION_PORTRAIT
|
||||
val width = getWidgetWidth(isPortrait, widgetId)
|
||||
val height = getWidgetHeight(isPortrait, widgetId)
|
||||
val width = getWidgetWidth(widgetId)
|
||||
val height = getWidgetHeight(widgetId)
|
||||
val widthInPx = context.dip(width)
|
||||
val heightInPx = context.dip(height)
|
||||
FirebaseCrashlytics.getInstance().setCustomKey("widthInPx", widthInPx)
|
||||
@ -35,9 +34,9 @@ object WidgetHelper {
|
||||
return widthInPx to heightInPx
|
||||
}
|
||||
|
||||
private fun getWidgetWidth(isPortrait: Boolean, widgetId: Int): Int = getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH)
|
||||
private fun getWidgetWidth(widgetId: Int): Int = getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH)
|
||||
|
||||
private fun getWidgetHeight(isPortrait: Boolean, widgetId: Int): Int = getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT)
|
||||
private fun getWidgetHeight(widgetId: Int): Int = getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT)
|
||||
|
||||
private fun getWidgetSizeInDp(widgetId: Int, key: String): Int =
|
||||
appWidgetManager.getAppWidgetOptions(widgetId).getInt(key, 0)
|
||||
|
@ -0,0 +1,40 @@
|
||||
package com.tommasoberlose.anotherwidget.network
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import com.chibatching.kotpref.Kotpref
|
||||
import com.google.gson.internal.LinkedTreeMap
|
||||
import com.haroldadmin.cnradapter.NetworkResponse
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
||||
import com.tommasoberlose.anotherwidget.network.repository.TimeZonesRepository
|
||||
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import java.lang.Exception
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class TimeZonesApi(val context: Context) {
|
||||
suspend fun getTimeZone(lat: String, long: String): String? {
|
||||
Kotpref.init(context)
|
||||
val repository = TimeZonesRepository()
|
||||
var id: String? = null
|
||||
|
||||
when (val response = repository.getTimeZone(lat, long)) {
|
||||
is NetworkResponse.Success -> {
|
||||
try {
|
||||
Log.d("ciao", response.body.toString())
|
||||
id = response.body["timezoneId"] as String
|
||||
|
||||
} catch(ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package com.tommasoberlose.anotherwidget.network
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import com.chibatching.kotpref.Kotpref
|
||||
import com.google.gson.internal.LinkedTreeMap
|
||||
import com.haroldadmin.cnradapter.NetworkResponse
|
||||
import com.haroldadmin.cnradapter.executeWithRetry
|
||||
@ -26,6 +27,7 @@ import java.util.*
|
||||
|
||||
class WeatherNetworkApi(val context: Context) {
|
||||
suspend fun updateWeather() {
|
||||
Kotpref.init(context)
|
||||
Preferences.weatherProviderError = "-"
|
||||
Preferences.weatherProviderLocationError = ""
|
||||
|
||||
@ -344,7 +346,7 @@ class WeatherNetworkApi(val context: Context) {
|
||||
|
||||
private suspend fun useAccuweatherProvider(context: Context) {
|
||||
if (Preferences.weatherProviderApiAccuweather != "") {
|
||||
val repository = AccuweatherRepository()
|
||||
// val repository = AccuweatherRepository()
|
||||
|
||||
// when (val response = repository.getWeather()) {
|
||||
// is NetworkResponse.Success -> {
|
||||
|
@ -71,4 +71,13 @@ object ApiServices {
|
||||
@Query("lon") lon: String,
|
||||
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
|
||||
}
|
||||
|
||||
interface TimeZonesService {
|
||||
@GET("timezoneJSON")
|
||||
suspend fun getTimeZone(
|
||||
@Query("lat") lat: String,
|
||||
@Query("lng") lon: String,
|
||||
@Query("username") username: String = "tommaso.berlose",
|
||||
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.tommasoberlose.anotherwidget.network.repository
|
||||
|
||||
import com.haroldadmin.cnradapter.NetworkResponseAdapterFactory
|
||||
import com.tommasoberlose.anotherwidget.network.api.ApiServices
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
|
||||
class TimeZonesRepository {
|
||||
|
||||
/* YR */
|
||||
private val apiService: ApiServices.TimeZonesService = getRetrofit().create(ApiServices.TimeZonesService::class.java)
|
||||
suspend fun getTimeZone(lat: String, long: String) = apiService.getTimeZone(lat, long)
|
||||
|
||||
companion object {
|
||||
private const val BASE_URL_YR = "http://api.geonames.org/"
|
||||
|
||||
private fun getRetrofit(): Retrofit {
|
||||
return Retrofit.Builder()
|
||||
.baseUrl(BASE_URL_YR)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.addCallAdapterFactory(NetworkResponseAdapterFactory())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
@ -138,10 +138,8 @@ class ActivityDetectionReceiver : BroadcastReceiver() {
|
||||
val endTime: Long = cal.timeInMillis
|
||||
|
||||
val readRequest = DataReadRequest.Builder()
|
||||
.aggregate(
|
||||
DataType.TYPE_STEP_COUNT_DELTA,
|
||||
DataType.AGGREGATE_STEP_COUNT_DELTA
|
||||
)
|
||||
.aggregate(DataType.TYPE_STEP_COUNT_DELTA)
|
||||
.aggregate(DataType.AGGREGATE_STEP_COUNT_DELTA)
|
||||
.setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
|
||||
.bucketByTime(1, TimeUnit.DAYS)
|
||||
.build()
|
||||
|
@ -9,6 +9,7 @@ import android.service.notification.NotificationListenerService
|
||||
import android.service.notification.StatusBarNotification
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import com.google.gson.Gson
|
||||
import com.tommasoberlose.anotherwidget.global.Actions
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
@ -41,6 +42,7 @@ class NotificationListener : NotificationListenerService() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
Preferences.lastNotificationIcon = sbn.notification.smallIcon.resId
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
Preferences.lastNotificationIcon = sbn.notification.icon
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
|
@ -5,19 +5,16 @@ import android.app.PendingIntent
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import androidx.core.app.AlarmManagerCompat
|
||||
import androidx.core.content.ContextCompat.getSystemService
|
||||
import com.tommasoberlose.anotherwidget.db.EventRepository
|
||||
import com.tommasoberlose.anotherwidget.global.Actions
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.BatteryHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.*
|
||||
import com.tommasoberlose.anotherwidget.models.Event
|
||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.joda.time.Period
|
||||
import java.util.*
|
||||
|
||||
@ -55,6 +52,14 @@ class UpdatesReceiver : BroadcastReceiver() {
|
||||
Actions.ACTION_UPDATE_GREETINGS -> {
|
||||
MainWidget.updateWidget(context)
|
||||
}
|
||||
|
||||
Actions.ACTION_REFRESH -> {
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
CalendarHelper.updateEventList(context)
|
||||
MediaPlayerHelper.updatePlayingMediaInfo(context)
|
||||
WeatherHelper.updateWeather(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,7 +107,7 @@ class UpdatesReceiver : BroadcastReceiver() {
|
||||
if (diff.hours == 0) {
|
||||
var minutes = 0
|
||||
when (Preferences.widgetUpdateFrequency) {
|
||||
Constants.WidgetUpdateFrequency.DEFAULT.value -> {
|
||||
Constants.WidgetUpdateFrequency.DEFAULT.rawValue -> {
|
||||
minutes = when {
|
||||
diff.minutes > 50 -> 50
|
||||
diff.minutes > 30 -> 30
|
||||
@ -110,7 +115,7 @@ class UpdatesReceiver : BroadcastReceiver() {
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
Constants.WidgetUpdateFrequency.HIGH.value -> {
|
||||
Constants.WidgetUpdateFrequency.HIGH.rawValue -> {
|
||||
minutes = diff.minutes - (diff.minutes % 5)
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import android.content.Intent
|
||||
import android.net.Uri
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.global.Actions
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.IntentHelper
|
||||
import com.tommasoberlose.anotherwidget.utils.toast
|
||||
|
||||
@ -15,19 +16,20 @@ class WidgetClickListenerReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (intent.action == Actions.ACTION_OPEN_WEATHER_INTENT) {
|
||||
try {
|
||||
context.startActivity(IntentHelper.getWeatherIntent(context))
|
||||
if (Preferences.weatherAppPackage == IntentHelper.REFRESH_WIDGET_OPTION) {
|
||||
context.sendBroadcast(IntentHelper.getWeatherIntent(context))
|
||||
} else {
|
||||
context.startActivity(IntentHelper.getWeatherIntent(context))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
val uri = Uri.parse("http://www.google.com/search?q=weather")
|
||||
val i = Intent(Intent.ACTION_VIEW, uri)
|
||||
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
try {
|
||||
context.applicationContext.startActivity(IntentHelper.getWeatherIntent(context.applicationContext))
|
||||
} catch (e: Exception) {
|
||||
val uri = Uri.parse("http://www.google.com/#q=weather")
|
||||
val i = Intent(Intent.ACTION_VIEW, uri)
|
||||
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
try {
|
||||
context.startActivity(i)
|
||||
} catch (ignored: Exception) {
|
||||
context.toast(context.getString(R.string.error_opening_app))
|
||||
}
|
||||
context.startActivity(i)
|
||||
} catch (ignored: Exception) {
|
||||
context.toast(context.getString(R.string.error_opening_app))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ import kotlin.collections.ArrayList
|
||||
|
||||
class LocationService : Service() {
|
||||
|
||||
private val jobs: ArrayList<Job> = ArrayList()
|
||||
private var job: Job? = null
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
@ -34,13 +34,14 @@ class LocationService : Service() {
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
if (ActivityCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
|
||||
jobs += GlobalScope.launch(Dispatchers.IO) {
|
||||
startForeground(LOCATION_ACCESS_NOTIFICATION_ID, getLocationAccessNotification())
|
||||
job?.cancel()
|
||||
job = GlobalScope.launch(Dispatchers.IO) {
|
||||
if (ActivityCompat.checkSelfPermission(
|
||||
this@LocationService,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
LocationServices.getFusedLocationProviderClient(this@LocationService).lastLocation.addOnCompleteListener { task ->
|
||||
val networkApi = WeatherNetworkApi(this@LocationService)
|
||||
if (task.isSuccessful) {
|
||||
@ -67,18 +68,17 @@ class LocationService : Service() {
|
||||
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stopSelf()
|
||||
}
|
||||
} else {
|
||||
stopSelf()
|
||||
}
|
||||
return START_STICKY
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
jobs.forEach {
|
||||
it.cancel()
|
||||
}
|
||||
job?.cancel()
|
||||
job = null
|
||||
}
|
||||
|
||||
companion object {
|
||||
@ -86,11 +86,7 @@ class LocationService : Service() {
|
||||
|
||||
@JvmStatic
|
||||
fun requestNewLocation(context: Context) {
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
context.startForegroundService(Intent(context, LocationService::class.java))
|
||||
} else {
|
||||
context.startService(Intent(context, LocationService::class.java))
|
||||
}
|
||||
ContextCompat.startForegroundService(context, Intent(context, LocationService::class.java))
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,7 +112,6 @@ class LocationService : Service() {
|
||||
val builder = NotificationCompat.Builder(this@LocationService, getString(R.string.location_access_notification_channel_id))
|
||||
.setSmallIcon(R.drawable.ic_stat_notification)
|
||||
.setContentTitle(getString(R.string.location_access_notification_title))
|
||||
.setStyle(NotificationCompat.BigTextStyle().bigText(getString(R.string.location_access_notification_subtitle)))
|
||||
.setOngoing(true)
|
||||
.setColor(ContextCompat.getColor(this@LocationService, R.color.colorAccent))
|
||||
|
||||
|
@ -1,153 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.services
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.provider.CalendarContract
|
||||
import android.util.Log
|
||||
import androidx.core.app.JobIntentService
|
||||
import com.tommasoberlose.anotherwidget.db.EventRepository
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper.applyFilters
|
||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper.sortEvents
|
||||
import com.tommasoberlose.anotherwidget.models.Event
|
||||
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
||||
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||
import me.everything.providers.android.calendar.CalendarProvider
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import java.util.*
|
||||
import kotlin.Comparator
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class UpdateCalendarJob : JobIntentService() {
|
||||
|
||||
companion object {
|
||||
private const val jobId = 1200
|
||||
|
||||
fun enqueueWork(context: Context, work: Intent) {
|
||||
enqueueWork(context, UpdateCalendarJob::class.java, jobId, work)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onHandleWork(intent: Intent) {
|
||||
val eventRepository = EventRepository(this)
|
||||
if (Preferences.showEvents) {
|
||||
val eventList = ArrayList<Event>()
|
||||
|
||||
val now = Calendar.getInstance()
|
||||
val begin = Calendar.getInstance().apply {
|
||||
set(Calendar.MILLISECOND, 0)
|
||||
set(Calendar.SECOND, 0)
|
||||
set(Calendar.MINUTE, 0)
|
||||
set(Calendar.HOUR_OF_DAY, 0)
|
||||
}
|
||||
val limit = Calendar.getInstance().apply {
|
||||
when (Preferences.showUntil) {
|
||||
0 -> add(Calendar.HOUR, 3)
|
||||
1 -> add(Calendar.HOUR, 6)
|
||||
2 -> add(Calendar.HOUR, 12)
|
||||
3 -> add(Calendar.DAY_OF_MONTH, 1)
|
||||
4 -> add(Calendar.DAY_OF_MONTH, 3)
|
||||
5 -> add(Calendar.DAY_OF_MONTH, 7)
|
||||
6 -> add(Calendar.MINUTE, 30)
|
||||
7 -> add(Calendar.HOUR, 1)
|
||||
else -> add(Calendar.HOUR, 6)
|
||||
}
|
||||
}
|
||||
|
||||
if (!checkGrantedPermission(
|
||||
Manifest.permission.READ_CALENDAR
|
||||
)
|
||||
) {
|
||||
eventRepository.resetNextEventData()
|
||||
} else {
|
||||
try {
|
||||
val provider = CalendarProvider(this)
|
||||
val data = provider.getInstances(begin.timeInMillis, limit.timeInMillis)
|
||||
if (data != null) {
|
||||
val instances = data.list
|
||||
for (instance in instances) {
|
||||
try {
|
||||
val e = provider.getEvent(instance.eventId)
|
||||
if (e != null && !e.deleted && instance.begin <= limit.timeInMillis && now.timeInMillis < instance.end && !CalendarHelper.getFilteredCalendarIdList()
|
||||
.contains(e.calendarId)
|
||||
) {
|
||||
if (e.allDay) {
|
||||
val start = Calendar.getInstance()
|
||||
start.timeInMillis = instance.begin
|
||||
val end = Calendar.getInstance()
|
||||
end.timeInMillis = instance.end
|
||||
instance.begin =
|
||||
start.timeInMillis - start.timeZone.getOffset(start.timeInMillis)
|
||||
instance.end =
|
||||
end.timeInMillis - end.timeZone.getOffset(end.timeInMillis)
|
||||
}
|
||||
|
||||
// Check all day events
|
||||
val startDate = Calendar.getInstance()
|
||||
startDate.timeInMillis = instance.begin
|
||||
val endDate = Calendar.getInstance()
|
||||
endDate.timeInMillis = instance.end
|
||||
|
||||
val isAllDay = e.allDay || (
|
||||
startDate.get(Calendar.MILLISECOND) == 0
|
||||
&& startDate.get(Calendar.SECOND) == 0
|
||||
&& startDate.get(Calendar.MINUTE) == 0
|
||||
&& startDate.get(Calendar.HOUR_OF_DAY) == 0
|
||||
&& endDate.get(Calendar.MILLISECOND) == 0
|
||||
&& endDate.get(Calendar.SECOND) == 0
|
||||
&& endDate.get(Calendar.MINUTE) == 0
|
||||
&& endDate.get(Calendar.HOUR_OF_DAY) == 0
|
||||
)
|
||||
|
||||
eventList.add(
|
||||
Event(
|
||||
id = instance.id,
|
||||
eventID = e.id,
|
||||
title = e.title ?: "",
|
||||
startDate = instance.begin,
|
||||
endDate = instance.end,
|
||||
calendarID = e.calendarId.toInt(),
|
||||
allDay = isAllDay,
|
||||
address = e.eventLocation ?: "",
|
||||
selfAttendeeStatus = e.selfAttendeeStatus.toInt(),
|
||||
availability = e.availability
|
||||
)
|
||||
)
|
||||
}
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val sortedEvents = eventList.sortEvents()
|
||||
val filteredEventList = sortedEvents
|
||||
.applyFilters()
|
||||
|
||||
if (filteredEventList.isEmpty()) {
|
||||
eventRepository.resetNextEventData()
|
||||
eventRepository.clearEvents()
|
||||
} else {
|
||||
eventRepository.saveEvents(
|
||||
sortedEvents
|
||||
)
|
||||
eventRepository.saveNextEventData(filteredEventList.first())
|
||||
}
|
||||
} catch (ignored: java.lang.Exception) {
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
eventRepository.resetNextEventData()
|
||||
}
|
||||
|
||||
UpdatesReceiver.setUpdates(this)
|
||||
MainWidget.updateWidget(this)
|
||||
|
||||
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||
eventRepository.close()
|
||||
}
|
||||
}
|
@ -0,0 +1,214 @@
|
||||
package com.tommasoberlose.anotherwidget.services
|
||||
|
||||
import android.Manifest
|
||||
import android.app.*
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.IBinder
|
||||
import android.util.Log
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.db.EventRepository
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper.applyFilters
|
||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper.sortEvents
|
||||
import com.tommasoberlose.anotherwidget.models.Event
|
||||
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import me.everything.providers.android.calendar.CalendarProvider
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class UpdateCalendarService : Service() {
|
||||
|
||||
companion object {
|
||||
const val CALENDAR_SYNC_NOTIFICATION_ID = 28468
|
||||
fun enqueueWork(context: Context) {
|
||||
ContextCompat.startForegroundService(context, Intent(context, UpdateCalendarService::class.java))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
startForeground(CALENDAR_SYNC_NOTIFICATION_ID, getCalendarSyncNotification())
|
||||
}
|
||||
|
||||
private var job: Job? = null
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
startForeground(CALENDAR_SYNC_NOTIFICATION_ID, getCalendarSyncNotification())
|
||||
job?.cancel()
|
||||
job = GlobalScope.launch(Dispatchers.IO) {
|
||||
|
||||
val eventRepository = EventRepository(this@UpdateCalendarService)
|
||||
if (Preferences.showEvents) {
|
||||
val eventList = ArrayList<Event>()
|
||||
|
||||
val now = Calendar.getInstance()
|
||||
val begin = Calendar.getInstance().apply {
|
||||
set(Calendar.MILLISECOND, 0)
|
||||
set(Calendar.SECOND, 0)
|
||||
set(Calendar.MINUTE, 0)
|
||||
set(Calendar.HOUR_OF_DAY, 0)
|
||||
}
|
||||
val limit = Calendar.getInstance().apply {
|
||||
when (Preferences.showUntil) {
|
||||
0 -> add(Calendar.HOUR, 3)
|
||||
1 -> add(Calendar.HOUR, 6)
|
||||
2 -> add(Calendar.HOUR, 12)
|
||||
3 -> add(Calendar.DAY_OF_MONTH, 1)
|
||||
4 -> add(Calendar.DAY_OF_MONTH, 3)
|
||||
5 -> add(Calendar.DAY_OF_MONTH, 7)
|
||||
6 -> add(Calendar.MINUTE, 30)
|
||||
7 -> add(Calendar.HOUR, 1)
|
||||
else -> add(Calendar.HOUR, 6)
|
||||
}
|
||||
}
|
||||
|
||||
if (!checkGrantedPermission(
|
||||
Manifest.permission.READ_CALENDAR
|
||||
)
|
||||
) {
|
||||
eventRepository.resetNextEventData()
|
||||
} else {
|
||||
try {
|
||||
val provider = CalendarProvider(this@UpdateCalendarService)
|
||||
val data = provider.getInstances(begin.timeInMillis, limit.timeInMillis)
|
||||
if (data != null) {
|
||||
val instances = data.list
|
||||
for (instance in instances) {
|
||||
try {
|
||||
val e = provider.getEvent(instance.eventId)
|
||||
if (e != null && !e.deleted && instance.begin <= limit.timeInMillis && now.timeInMillis < instance.end && !CalendarHelper.getFilteredCalendarIdList()
|
||||
.contains(e.calendarId)
|
||||
) {
|
||||
if (e.allDay) {
|
||||
val start = Calendar.getInstance()
|
||||
start.timeInMillis = instance.begin
|
||||
val end = Calendar.getInstance()
|
||||
end.timeInMillis = instance.end
|
||||
instance.begin =
|
||||
start.timeInMillis - start.timeZone.getOffset(start.timeInMillis)
|
||||
instance.end =
|
||||
end.timeInMillis - end.timeZone.getOffset(end.timeInMillis)
|
||||
}
|
||||
|
||||
// Check all day events
|
||||
val startDate = Calendar.getInstance()
|
||||
startDate.timeInMillis = instance.begin
|
||||
val endDate = Calendar.getInstance()
|
||||
endDate.timeInMillis = instance.end
|
||||
|
||||
val isAllDay = e.allDay || (
|
||||
startDate.get(Calendar.MILLISECOND) == 0
|
||||
&& startDate.get(Calendar.SECOND) == 0
|
||||
&& startDate.get(Calendar.MINUTE) == 0
|
||||
&& startDate.get(Calendar.HOUR_OF_DAY) == 0
|
||||
&& endDate.get(Calendar.MILLISECOND) == 0
|
||||
&& endDate.get(Calendar.SECOND) == 0
|
||||
&& endDate.get(Calendar.MINUTE) == 0
|
||||
&& endDate.get(Calendar.HOUR_OF_DAY) == 0
|
||||
)
|
||||
|
||||
eventList.add(
|
||||
Event(
|
||||
id = instance.id,
|
||||
eventID = e.id,
|
||||
title = e.title ?: "",
|
||||
startDate = instance.begin,
|
||||
endDate = instance.end,
|
||||
calendarID = e.calendarId.toInt(),
|
||||
allDay = isAllDay,
|
||||
address = e.eventLocation ?: "",
|
||||
selfAttendeeStatus = e.selfAttendeeStatus.toInt(),
|
||||
availability = e.availability
|
||||
)
|
||||
)
|
||||
}
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val sortedEvents = eventList.sortEvents()
|
||||
val filteredEventList = sortedEvents
|
||||
.applyFilters()
|
||||
|
||||
if (filteredEventList.isEmpty()) {
|
||||
eventRepository.resetNextEventData()
|
||||
eventRepository.clearEvents()
|
||||
} else {
|
||||
eventRepository.saveEvents(
|
||||
sortedEvents
|
||||
)
|
||||
eventRepository.saveNextEventData(filteredEventList.first())
|
||||
}
|
||||
} catch (ignored: java.lang.Exception) {
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
eventRepository.resetNextEventData()
|
||||
}
|
||||
|
||||
UpdatesReceiver.setUpdates(this@UpdateCalendarService)
|
||||
MainWidget.updateWidget(this@UpdateCalendarService)
|
||||
|
||||
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||
eventRepository.close()
|
||||
|
||||
stopSelf()
|
||||
}
|
||||
|
||||
return START_STICKY
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
job?.cancel()
|
||||
job = null
|
||||
}
|
||||
|
||||
private fun getCalendarSyncNotification(): Notification {
|
||||
with(NotificationManagerCompat.from(this)) {
|
||||
// Create channel
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
createNotificationChannel(
|
||||
NotificationChannel(
|
||||
getString(R.string.calendar_sync_notification_channel_id),
|
||||
getString(R.string.calendar_sync_notification_channel_name),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
).apply {
|
||||
description = getString(R.string.calendar_sync_notification_channel_description)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
val builder = NotificationCompat.Builder(this@UpdateCalendarService, getString(R.string.calendar_sync_notification_channel_id))
|
||||
.setSmallIcon(R.drawable.ic_stat_notification)
|
||||
.setContentTitle(getString(R.string.calendar_sync_notification_title))
|
||||
.setOngoing(true)
|
||||
.setColor(ContextCompat.getColor(this@UpdateCalendarService, R.color.colorAccent))
|
||||
|
||||
// Main intent that open the activity
|
||||
builder.setContentIntent(PendingIntent.getActivity(this@UpdateCalendarService, 0, Intent(this@UpdateCalendarService, MainActivity::class.java), PendingIntent.FLAG_UPDATE_CURRENT))
|
||||
|
||||
return builder.build()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,148 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activities
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import android.content.Intent
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.ResolveInfo
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.bumptech.glide.Glide
|
||||
import com.tommasoberlose.anotherwidget.databinding.ActivityChooseApplicationBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.ChooseApplicationViewModel
|
||||
import kotlinx.android.synthetic.main.activity_choose_application.*
|
||||
import kotlinx.android.synthetic.main.activity_choose_application.action_back
|
||||
import kotlinx.android.synthetic.main.activity_choose_application.clear_search
|
||||
import kotlinx.android.synthetic.main.activity_choose_application.list_view
|
||||
import kotlinx.android.synthetic.main.activity_choose_application.loader
|
||||
import kotlinx.android.synthetic.main.activity_choose_application.search
|
||||
import kotlinx.android.synthetic.main.activity_music_players_filter.*
|
||||
import kotlinx.coroutines.*
|
||||
import net.idik.lib.slimadapter.SlimAdapter
|
||||
import net.idik.lib.slimadapter.SlimAdapterEx
|
||||
|
||||
|
||||
class ChooseApplicationActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var adapter: SlimAdapter
|
||||
private lateinit var viewModel: ChooseApplicationViewModel
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
viewModel = ViewModelProvider(this).get(ChooseApplicationViewModel::class.java)
|
||||
val binding = DataBindingUtil.setContentView<ActivityChooseApplicationBinding>(this, R.layout.activity_choose_application)
|
||||
|
||||
list_view.setHasFixedSize(true)
|
||||
val mLayoutManager = LinearLayoutManager(this)
|
||||
list_view.layoutManager = mLayoutManager
|
||||
|
||||
adapter = SlimAdapterEx.create()
|
||||
adapter
|
||||
.register<String>(R.layout.application_info_layout) { _, injector ->
|
||||
injector
|
||||
.text(R.id.text, getString(R.string.default_name))
|
||||
.image(R.id.icon, R.drawable.round_add_to_home_screen_24)
|
||||
.with<ImageView>(R.id.icon) {
|
||||
it.scaleX = 0.8f
|
||||
it.scaleY = 0.8f
|
||||
it.setColorFilter(ContextCompat.getColor(this, R.color.colorPrimaryText), android.graphics.PorterDuff.Mode.MULTIPLY)
|
||||
}
|
||||
.clicked(R.id.item) {
|
||||
val resultIntent = Intent()
|
||||
resultIntent.putExtra(Constants.RESULT_APP_NAME, "")
|
||||
resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, "")
|
||||
setResult(Activity.RESULT_OK, resultIntent)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
.register<ResolveInfo>(R.layout.application_info_layout) { item, injector ->
|
||||
injector
|
||||
.text(R.id.text, item.loadLabel(viewModel.pm))
|
||||
.with<ImageView>(R.id.icon) {
|
||||
Glide
|
||||
.with(this)
|
||||
.load(item.loadIcon(viewModel.pm))
|
||||
.centerCrop()
|
||||
.into(it)
|
||||
}
|
||||
|
||||
injector.clicked(R.id.item) {
|
||||
saveApp(item)
|
||||
}
|
||||
}
|
||||
.attachTo(list_view)
|
||||
|
||||
setupListener()
|
||||
subscribeUi(binding, viewModel)
|
||||
|
||||
search.requestFocus()
|
||||
}
|
||||
|
||||
private var filterJob: Job? = null
|
||||
|
||||
private fun subscribeUi(binding: ActivityChooseApplicationBinding, viewModel: ChooseApplicationViewModel) {
|
||||
binding.viewModel = viewModel
|
||||
binding.lifecycleOwner = this
|
||||
|
||||
viewModel.appList.observe(this, Observer {
|
||||
updateList(list = it)
|
||||
loader.visibility = View.INVISIBLE
|
||||
})
|
||||
|
||||
viewModel.searchInput.observe(this, Observer { search ->
|
||||
updateList(search = search)
|
||||
clear_search.isVisible = search.isNotBlank()
|
||||
})
|
||||
}
|
||||
|
||||
private fun updateList(list: List<ResolveInfo>? = viewModel.appList.value, search: String? = viewModel.searchInput.value) {
|
||||
loader.visibility = View.VISIBLE
|
||||
filterJob?.cancel()
|
||||
filterJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||
if (list != null && list.isNotEmpty()) {
|
||||
delay(200)
|
||||
val filteredList: List<ResolveInfo> = if (search == null || search == "") {
|
||||
list
|
||||
} else {
|
||||
list.filter {
|
||||
it.loadLabel(viewModel.pm).contains(search, true)
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
adapter.updateData(listOf("Default") + filteredList)
|
||||
loader.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
action_back.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
clear_search.setOnClickListener {
|
||||
viewModel.searchInput.value = ""
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveApp(app: ResolveInfo) {
|
||||
val resultIntent = Intent()
|
||||
resultIntent.putExtra(Constants.RESULT_APP_NAME, app.loadLabel(viewModel.pm))
|
||||
resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, app.activityInfo.packageName)
|
||||
setResult(Activity.RESULT_OK, resultIntent)
|
||||
finish()
|
||||
}
|
||||
}
|
@ -1,93 +1,74 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activities
|
||||
|
||||
import android.Manifest
|
||||
import android.animation.ValueAnimator
|
||||
import android.app.Activity
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Matrix
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Log
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.animation.addListener
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.Navigation
|
||||
import com.chibatching.kotpref.Kotpref
|
||||
import com.google.android.material.badge.BadgeDrawable
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import com.karumi.dexter.Dexter
|
||||
import com.karumi.dexter.MultiplePermissionsReport
|
||||
import com.karumi.dexter.PermissionToken
|
||||
import com.karumi.dexter.listener.PermissionRequest
|
||||
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
|
||||
import com.tommasoberlose.anotherwidget.databinding.ActivityMainBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Actions
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.global.RequestCode
|
||||
import com.tommasoberlose.anotherwidget.helpers.BitmapHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
|
||||
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
||||
import com.tommasoberlose.anotherwidget.ui.adapters.ViewPagerAdapter
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.tabs.WeatherProviderActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||
import com.tommasoberlose.anotherwidget.utils.getCurrentWallpaper
|
||||
import com.tommasoberlose.anotherwidget.utils.toPixel
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import kotlinx.android.synthetic.main.the_widget_sans.*
|
||||
import kotlinx.coroutines.*
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private var mAppWidgetId: Int = -1
|
||||
private lateinit var viewModel: MainViewModel
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
private val mainNavController: NavController? by lazy {
|
||||
Navigation.findNavController(
|
||||
this,
|
||||
R.id.content_fragment
|
||||
)
|
||||
}
|
||||
private val settingsNavController: NavController? by lazy {
|
||||
Navigation.findNavController(
|
||||
this,
|
||||
R.id.settings_fragment
|
||||
)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
|
||||
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
|
||||
controlExtras(intent)
|
||||
if (Preferences.showWallpaper) {
|
||||
requirePermission()
|
||||
}
|
||||
|
||||
setContentView(binding.root)
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (mainNavController?.currentDestination?.id == R.id.appMainFragment) {
|
||||
if (mAppWidgetId > 0) {
|
||||
addNewWidget()
|
||||
if (settingsNavController?.navigateUp() == false) {
|
||||
if (mAppWidgetId > 0) {
|
||||
addNewWidget()
|
||||
} else {
|
||||
setResult(Activity.RESULT_OK)
|
||||
finish()
|
||||
}
|
||||
} else {
|
||||
setResult(Activity.RESULT_OK)
|
||||
finish()
|
||||
viewModel.fragmentScrollY.value = 0
|
||||
}
|
||||
} else {
|
||||
super.onBackPressed()
|
||||
@ -110,8 +91,8 @@ class MainActivity : AppCompatActivity() {
|
||||
AppWidgetManager.INVALID_APPWIDGET_ID)
|
||||
|
||||
if (mAppWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
|
||||
action_add_widget.visibility = View.VISIBLE
|
||||
action_add_widget.setOnClickListener {
|
||||
binding.actionAddWidget.visibility = View.VISIBLE
|
||||
binding.actionAddWidget.setOnClickListener {
|
||||
addNewWidget()
|
||||
}
|
||||
}
|
||||
@ -153,4 +134,26 @@ class MainActivity : AppCompatActivity() {
|
||||
})
|
||||
.check()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
if (Preferences.showEvents && !checkGrantedPermission(Manifest.permission.READ_CALENDAR)) {
|
||||
Preferences.showEvents = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
Preferences.preferences.registerOnSharedPreferenceChangeListener(this)
|
||||
super.onStart()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
Preferences.preferences.unregisterOnSharedPreferenceChangeListener(this)
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(p0: SharedPreferences?, p1: String?) {
|
||||
MainWidget.updateWidget(this)
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +1,29 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activities
|
||||
package com.tommasoberlose.anotherwidget.ui.activities.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.databinding.ActivityIntegrationsBinding
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.IntegrationsViewModel
|
||||
import kotlinx.android.synthetic.main.activity_integrations.*
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.settings.IntegrationsViewModel
|
||||
import net.idik.lib.slimadapter.SlimAdapter
|
||||
|
||||
class IntegrationsActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var adapter: SlimAdapter
|
||||
private lateinit var viewModel: IntegrationsViewModel
|
||||
private lateinit var binding: ActivityIntegrationsBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
viewModel = ViewModelProvider(this).get(IntegrationsViewModel::class.java)
|
||||
val binding = DataBindingUtil.setContentView<ActivityIntegrationsBinding>(this, R.layout.activity_integrations)
|
||||
binding = ActivityIntegrationsBinding.inflate(layoutInflater)
|
||||
|
||||
list_view.setHasFixedSize(true)
|
||||
binding.listView.setHasFixedSize(true)
|
||||
val mLayoutManager = LinearLayoutManager(this)
|
||||
list_view.layoutManager = mLayoutManager
|
||||
binding.listView.layoutManager = mLayoutManager
|
||||
|
||||
adapter = SlimAdapter.create()
|
||||
adapter
|
||||
@ -33,10 +32,12 @@ class IntegrationsActivity : AppCompatActivity() {
|
||||
.text(R.id.text, getString(R.string.default_name))
|
||||
|
||||
}
|
||||
.attachTo(list_view)
|
||||
.attachTo(binding.listView)
|
||||
|
||||
setupListener()
|
||||
subscribeUi(binding, viewModel)
|
||||
|
||||
setContentView(binding.root)
|
||||
}
|
||||
|
||||
private fun subscribeUi(binding: ActivityIntegrationsBinding, viewModel: IntegrationsViewModel) {
|
||||
@ -45,7 +46,7 @@ class IntegrationsActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
action_back.setOnClickListener {
|
||||
binding.actionBack.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
}
|
@ -1,47 +1,38 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activities
|
||||
package com.tommasoberlose.anotherwidget.ui.activities.settings
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.location.Address
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.android.billingclient.api.*
|
||||
import com.android.billingclient.api.BillingClient.BillingResponseCode.OK
|
||||
import com.android.billingclient.api.BillingClient.BillingResponseCode.USER_CANCELED
|
||||
import com.chibatching.kotpref.bulk
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.databinding.ActivitySupportDevBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.SupportDevViewModel
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.settings.SupportDevViewModel
|
||||
import com.tommasoberlose.anotherwidget.utils.toast
|
||||
import kotlinx.android.synthetic.main.activity_support_dev.*
|
||||
import net.idik.lib.slimadapter.SlimAdapter
|
||||
|
||||
class SupportDevActivity : AppCompatActivity(), PurchasesUpdatedListener {
|
||||
|
||||
private lateinit var viewModel: SupportDevViewModel
|
||||
private lateinit var adapter: SlimAdapter
|
||||
private lateinit var binding: ActivitySupportDevBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
viewModel = ViewModelProvider(this).get(SupportDevViewModel::class.java)
|
||||
viewModel.billingClient = BillingClient.newBuilder(this).enablePendingPurchases().setListener(this).build()
|
||||
DataBindingUtil.setContentView<ActivitySupportDevBinding>(this, R.layout.activity_support_dev)
|
||||
binding = ActivitySupportDevBinding.inflate(layoutInflater)
|
||||
|
||||
|
||||
list_view.setHasFixedSize(true)
|
||||
binding.listView.setHasFixedSize(true)
|
||||
val mLayoutManager = LinearLayoutManager(this)
|
||||
list_view.layoutManager = mLayoutManager
|
||||
binding.listView.layoutManager = mLayoutManager
|
||||
|
||||
adapter = SlimAdapter.create()
|
||||
adapter
|
||||
@ -62,20 +53,22 @@ class SupportDevActivity : AppCompatActivity(), PurchasesUpdatedListener {
|
||||
viewModel.purchase(this, item)
|
||||
}
|
||||
}
|
||||
.attachTo(list_view)
|
||||
.attachTo(binding.listView)
|
||||
|
||||
viewModel.openConnection()
|
||||
subscribeUi(viewModel)
|
||||
|
||||
action_back.setOnClickListener {
|
||||
binding.actionBack.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
setContentView(binding.root)
|
||||
}
|
||||
|
||||
private fun subscribeUi(viewModel: SupportDevViewModel) {
|
||||
viewModel.products.observe(this, Observer {
|
||||
if (it.isNotEmpty()) {
|
||||
loader.isVisible = false
|
||||
binding.loader.isVisible = false
|
||||
}
|
||||
adapter.updateData(it.sortedWith(compareBy(SkuDetails::getPriceAmountMicros)))
|
||||
})
|
@ -1,4 +1,4 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activities
|
||||
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||
|
||||
import android.content.pm.ResolveInfo
|
||||
import android.os.Bundle
|
||||
@ -6,7 +6,6 @@ import android.view.View
|
||||
import android.widget.ImageView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
@ -16,8 +15,7 @@ import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.databinding.ActivityAppNotificationsFilterBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.AppNotificationsViewModel
|
||||
import kotlinx.android.synthetic.main.activity_app_notifications_filter.*
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.AppNotificationsViewModel
|
||||
import kotlinx.coroutines.*
|
||||
import net.idik.lib.slimadapter.SlimAdapter
|
||||
|
||||
@ -26,16 +24,17 @@ class AppNotificationsFilterActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var adapter: SlimAdapter
|
||||
private lateinit var viewModel: AppNotificationsViewModel
|
||||
private lateinit var binding: ActivityAppNotificationsFilterBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
viewModel = ViewModelProvider(this).get(AppNotificationsViewModel::class.java)
|
||||
val binding = DataBindingUtil.setContentView<ActivityAppNotificationsFilterBinding>(this, R.layout.activity_app_notifications_filter)
|
||||
binding = ActivityAppNotificationsFilterBinding.inflate(layoutInflater)
|
||||
|
||||
list_view.setHasFixedSize(true)
|
||||
binding.listView.setHasFixedSize(true)
|
||||
val mLayoutManager = LinearLayoutManager(this)
|
||||
list_view.layoutManager = mLayoutManager
|
||||
binding.listView.layoutManager = mLayoutManager
|
||||
|
||||
adapter = SlimAdapter.create()
|
||||
adapter
|
||||
@ -60,12 +59,14 @@ class AppNotificationsFilterActivity : AppCompatActivity() {
|
||||
}
|
||||
.checked(R.id.checkBox, ActiveNotificationsHelper.isAppAccepted(item.activityInfo.packageName))
|
||||
}
|
||||
.attachTo(list_view)
|
||||
.attachTo(binding.listView)
|
||||
|
||||
setupListener()
|
||||
subscribeUi(binding, viewModel)
|
||||
|
||||
search.requestFocus()
|
||||
binding.search.requestFocus()
|
||||
|
||||
setContentView(binding.root)
|
||||
}
|
||||
|
||||
private var filterJob: Job? = null
|
||||
@ -76,22 +77,22 @@ class AppNotificationsFilterActivity : AppCompatActivity() {
|
||||
|
||||
viewModel.appList.observe(this, Observer {
|
||||
updateList(list = it)
|
||||
loader.visibility = View.INVISIBLE
|
||||
binding.loader.visibility = View.INVISIBLE
|
||||
})
|
||||
|
||||
viewModel.searchInput.observe(this, Observer { search ->
|
||||
updateList(search = search)
|
||||
clear_search.isVisible = search.isNotBlank()
|
||||
binding.clearSearch.isVisible = search.isNotBlank()
|
||||
})
|
||||
|
||||
viewModel.appNotificationsFilter.observe(this, {
|
||||
updateList()
|
||||
clear_selection.isVisible = Preferences.appNotificationsFilter != ""
|
||||
binding.clearSelection.isVisible = Preferences.appNotificationsFilter != ""
|
||||
})
|
||||
}
|
||||
|
||||
private fun updateList(list: List<ResolveInfo>? = viewModel.appList.value, search: String? = viewModel.searchInput.value) {
|
||||
loader.visibility = View.VISIBLE
|
||||
binding.loader.visibility = View.VISIBLE
|
||||
filterJob?.cancel()
|
||||
filterJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||
if (list != null && list.isNotEmpty()) {
|
||||
@ -117,22 +118,22 @@ class AppNotificationsFilterActivity : AppCompatActivity() {
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
adapter.updateData(filteredList)
|
||||
loader.visibility = View.INVISIBLE
|
||||
binding.loader.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
action_back.setOnClickListener {
|
||||
binding.actionBack.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
clear_search.setOnClickListener {
|
||||
binding.clearSearch.setOnClickListener {
|
||||
viewModel.searchInput.value = ""
|
||||
}
|
||||
|
||||
clear_selection.setOnClickListener {
|
||||
binding.clearSelection.setOnClickListener {
|
||||
Preferences.appNotificationsFilter = ""
|
||||
}
|
||||
}
|
@ -0,0 +1,213 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import android.content.Intent
|
||||
import android.content.pm.ResolveInfo
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.bumptech.glide.Glide
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.tommasoberlose.anotherwidget.databinding.ActivityChooseApplicationBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.helpers.IntentHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.ChooseApplicationViewModel
|
||||
import kotlinx.coroutines.*
|
||||
import net.idik.lib.slimadapter.SlimAdapter
|
||||
import net.idik.lib.slimadapter.SlimAdapterEx
|
||||
|
||||
|
||||
class ChooseApplicationActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var adapter: SlimAdapter
|
||||
private lateinit var viewModel: ChooseApplicationViewModel
|
||||
private lateinit var binding: ActivityChooseApplicationBinding
|
||||
|
||||
private var selectedPackage: String? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
selectedPackage = intent.extras?.getString(Constants.RESULT_APP_PACKAGE)
|
||||
|
||||
viewModel = ViewModelProvider(this).get(ChooseApplicationViewModel::class.java)
|
||||
binding = ActivityChooseApplicationBinding.inflate(layoutInflater)
|
||||
|
||||
binding.listView.setHasFixedSize(true)
|
||||
val mLayoutManager = LinearLayoutManager(this)
|
||||
binding.listView.layoutManager = mLayoutManager
|
||||
|
||||
adapter = SlimAdapterEx.create()
|
||||
adapter
|
||||
.register<String>(R.layout.application_info_layout) { item, injector ->
|
||||
when (item) {
|
||||
IntentHelper.DO_NOTHING_OPTION -> {
|
||||
injector
|
||||
.text(R.id.text, getString(R.string.gestures_do_nothing))
|
||||
.image(R.id.icon, R.drawable.round_no_cell_24)
|
||||
.with<ImageView>(R.id.icon) {
|
||||
it.scaleX = 0.8f
|
||||
it.scaleY = 0.8f
|
||||
it.setColorFilter(ContextCompat.getColor(this, R.color.colorPrimaryText), android.graphics.PorterDuff.Mode.MULTIPLY)
|
||||
}
|
||||
.clicked(R.id.item) {
|
||||
val resultIntent = Intent()
|
||||
resultIntent.putExtra(Constants.RESULT_APP_NAME, IntentHelper.DO_NOTHING_OPTION)
|
||||
resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, IntentHelper.DO_NOTHING_OPTION)
|
||||
setResult(Activity.RESULT_OK, resultIntent)
|
||||
finish()
|
||||
}
|
||||
.with<MaterialCardView>(R.id.item) {
|
||||
it.strokeColor = ContextCompat.getColor(this, if (selectedPackage == IntentHelper.DO_NOTHING_OPTION) R.color.colorAccent else R.color.cardBorder)
|
||||
it.setCardBackgroundColor(ContextCompat.getColor(this, if (selectedPackage == IntentHelper.DO_NOTHING_OPTION) R.color.colorAccent_op10 else R.color.colorPrimaryDark))
|
||||
}
|
||||
}
|
||||
IntentHelper.REFRESH_WIDGET_OPTION -> {
|
||||
injector
|
||||
.text(R.id.text, getString(R.string.action_refresh_widget))
|
||||
.image(R.id.icon, R.drawable.round_refresh)
|
||||
.with<ImageView>(R.id.icon) {
|
||||
it.scaleX = 0.8f
|
||||
it.scaleY = 0.8f
|
||||
it.setColorFilter(ContextCompat.getColor(this, R.color.colorPrimaryText), android.graphics.PorterDuff.Mode.MULTIPLY)
|
||||
}
|
||||
.clicked(R.id.item) {
|
||||
val resultIntent = Intent()
|
||||
resultIntent.putExtra(Constants.RESULT_APP_NAME, IntentHelper.REFRESH_WIDGET_OPTION)
|
||||
resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, IntentHelper.REFRESH_WIDGET_OPTION)
|
||||
setResult(Activity.RESULT_OK, resultIntent)
|
||||
finish()
|
||||
}
|
||||
.with<MaterialCardView>(R.id.item) {
|
||||
it.strokeColor = ContextCompat.getColor(this, if (selectedPackage == IntentHelper.REFRESH_WIDGET_OPTION) R.color.colorAccent else R.color.cardBorder)
|
||||
it.setCardBackgroundColor(ContextCompat.getColor(this, if (selectedPackage == IntentHelper.REFRESH_WIDGET_OPTION) R.color.colorAccent_op10 else R.color.colorPrimaryDark))
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
injector
|
||||
.text(R.id.text, getString(R.string.default_name))
|
||||
.image(R.id.icon, R.drawable.round_add_to_home_screen_24)
|
||||
.with<ImageView>(R.id.icon) {
|
||||
it.scaleX = 0.8f
|
||||
it.scaleY = 0.8f
|
||||
it.setColorFilter(ContextCompat.getColor(this, R.color.colorPrimaryText), android.graphics.PorterDuff.Mode.MULTIPLY)
|
||||
}
|
||||
.clicked(R.id.item) {
|
||||
val resultIntent = Intent()
|
||||
resultIntent.putExtra(Constants.RESULT_APP_NAME, IntentHelper.DEFAULT_OPTION)
|
||||
resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, IntentHelper.DEFAULT_OPTION)
|
||||
setResult(Activity.RESULT_OK, resultIntent)
|
||||
finish()
|
||||
}
|
||||
.with<MaterialCardView>(R.id.item) {
|
||||
it.strokeColor = ContextCompat.getColor(this, if (selectedPackage == IntentHelper.DEFAULT_OPTION) R.color.colorAccent else R.color.cardBorder)
|
||||
it.setCardBackgroundColor(ContextCompat.getColor(this, if (selectedPackage == IntentHelper.DEFAULT_OPTION) R.color.colorAccent_op10 else R.color.colorPrimaryDark))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.register<ResolveInfo>(R.layout.application_info_layout) { item, injector ->
|
||||
injector
|
||||
.text(R.id.text, item.loadLabel(viewModel.pm))
|
||||
.with<ImageView>(R.id.icon) {
|
||||
Glide
|
||||
.with(this)
|
||||
.load(item.loadIcon(viewModel.pm))
|
||||
.centerCrop()
|
||||
.into(it)
|
||||
}
|
||||
.clicked(R.id.item) {
|
||||
saveApp(item)
|
||||
}
|
||||
.with<MaterialCardView>(R.id.item) {
|
||||
it.strokeColor = ContextCompat.getColor(this, if (selectedPackage == item.activityInfo.packageName) R.color.colorAccent else R.color.cardBorder)
|
||||
it.setCardBackgroundColor(ContextCompat.getColor(this, if (selectedPackage == item.activityInfo.packageName) R.color.colorAccent_op10 else R.color.colorPrimaryDark))
|
||||
}
|
||||
}
|
||||
.attachTo(binding.listView)
|
||||
|
||||
setupListener()
|
||||
subscribeUi(binding, viewModel)
|
||||
|
||||
binding.search.requestFocus()
|
||||
|
||||
setContentView(binding.root)
|
||||
}
|
||||
|
||||
private var filterJob: Job? = null
|
||||
|
||||
private fun subscribeUi(binding: ActivityChooseApplicationBinding, viewModel: ChooseApplicationViewModel) {
|
||||
binding.viewModel = viewModel
|
||||
binding.lifecycleOwner = this
|
||||
|
||||
viewModel.appList.observe(this) {
|
||||
updateList(list = it)
|
||||
binding.loader.visibility = View.INVISIBLE
|
||||
}
|
||||
|
||||
viewModel.searchInput.observe(this) { search ->
|
||||
updateList(search = search)
|
||||
binding.clearSearch.isVisible = search.isNotBlank()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateList(list: List<ResolveInfo>? = viewModel.appList.value, search: String? = viewModel.searchInput.value) {
|
||||
binding.loader.visibility = View.VISIBLE
|
||||
filterJob?.cancel()
|
||||
filterJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||
if (list != null && list.isNotEmpty()) {
|
||||
delay(200)
|
||||
val filteredList: List<ResolveInfo> = if (search == null || search == "") {
|
||||
list
|
||||
} else {
|
||||
list.filter {
|
||||
it.loadLabel(viewModel.pm).contains(search, true)
|
||||
}
|
||||
}.sortedWith { app1, app2 ->
|
||||
when (selectedPackage) {
|
||||
app1.activityInfo.packageName -> {
|
||||
-1
|
||||
}
|
||||
app2.activityInfo.packageName -> {
|
||||
1
|
||||
}
|
||||
else -> {
|
||||
app1.loadLabel(viewModel.pm).toString().compareTo(app2.loadLabel(viewModel.pm).toString(), ignoreCase = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
adapter.updateData(listOf(IntentHelper.DO_NOTHING_OPTION, IntentHelper.DEFAULT_OPTION, IntentHelper.REFRESH_WIDGET_OPTION) + filteredList)
|
||||
binding.loader.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
binding.actionBack.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
binding.clearSearch.setOnClickListener {
|
||||
viewModel.searchInput.value = ""
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveApp(app: ResolveInfo) {
|
||||
val resultIntent = Intent()
|
||||
resultIntent.putExtra(Constants.RESULT_APP_NAME, app.loadLabel(viewModel.pm))
|
||||
resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, app.activityInfo.packageName)
|
||||
setResult(Activity.RESULT_OK, resultIntent)
|
||||
finish()
|
||||
}
|
||||
}
|
@ -1,61 +1,53 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activities
|
||||
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||
|
||||
import android.app.Activity
|
||||
import android.location.Address
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.chibatching.kotpref.blockingBulk
|
||||
import com.chibatching.kotpref.bulk
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.databinding.ActivityCustomDateBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.DateHelper
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.CustomDateViewModel
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.CustomDateViewModel
|
||||
import com.tommasoberlose.anotherwidget.utils.getCapWordString
|
||||
import com.tommasoberlose.anotherwidget.utils.openURI
|
||||
import com.tommasoberlose.anotherwidget.utils.toast
|
||||
import kotlinx.android.synthetic.main.activity_custom_date.*
|
||||
import kotlinx.android.synthetic.main.activity_custom_location.action_back
|
||||
import kotlinx.android.synthetic.main.activity_custom_location.list_view
|
||||
import kotlinx.coroutines.*
|
||||
import net.idik.lib.slimadapter.SlimAdapter
|
||||
import java.lang.Exception
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class CustomDateActivity : AppCompatActivity() {
|
||||
class CustomDateActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var adapter: SlimAdapter
|
||||
private lateinit var viewModel: CustomDateViewModel
|
||||
private lateinit var binding: ActivityCustomDateBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
viewModel = ViewModelProvider(this).get(CustomDateViewModel::class.java)
|
||||
val binding = DataBindingUtil.setContentView<ActivityCustomDateBinding>(this, R.layout.activity_custom_date)
|
||||
binding = ActivityCustomDateBinding.inflate(layoutInflater)
|
||||
|
||||
|
||||
list_view.setHasFixedSize(true)
|
||||
binding.listView.setHasFixedSize(true)
|
||||
val mLayoutManager = LinearLayoutManager(this)
|
||||
list_view.layoutManager = mLayoutManager
|
||||
binding.listView.layoutManager = mLayoutManager
|
||||
|
||||
adapter = SlimAdapter.create()
|
||||
adapter
|
||||
.register<String>(R.layout.custom_date_example_item) { item, injector ->
|
||||
injector
|
||||
.text(R.id.custom_date_example_format, item)
|
||||
.text(R.id.custom_date_example_value, SimpleDateFormat(item, Locale.getDefault()).format(DATE.time))
|
||||
.text(R.id.custom_date_example_value, SimpleDateFormat(item, Locale.getDefault()).format(
|
||||
DATE.time))
|
||||
}
|
||||
.attachTo(list_view)
|
||||
.attachTo(binding.listView)
|
||||
|
||||
adapter.updateData(
|
||||
listOf(
|
||||
@ -66,9 +58,11 @@ class CustomDateActivity : AppCompatActivity() {
|
||||
setupListener()
|
||||
subscribeUi(binding, viewModel)
|
||||
|
||||
date_format.requestFocus()
|
||||
binding.dateFormat.requestFocus()
|
||||
|
||||
setContentView(binding.root)
|
||||
}
|
||||
|
||||
private var formatJob: Job? = null
|
||||
|
||||
private fun subscribeUi(binding: ActivityCustomDateBinding, viewModel: CustomDateViewModel) {
|
||||
@ -79,7 +73,7 @@ class CustomDateActivity : AppCompatActivity() {
|
||||
formatJob?.cancel()
|
||||
formatJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||
withContext(Dispatchers.Main) {
|
||||
loader.visibility = View.VISIBLE
|
||||
binding.loader.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
delay(200)
|
||||
@ -102,8 +96,8 @@ class CustomDateActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
loader.visibility = View.INVISIBLE
|
||||
date_format_value.text = text
|
||||
binding.loader.visibility = View.INVISIBLE
|
||||
binding.dateFormatValue.text = text
|
||||
}
|
||||
|
||||
}
|
||||
@ -123,26 +117,26 @@ class CustomDateActivity : AppCompatActivity() {
|
||||
private fun updateCapitalizeUi() {
|
||||
when {
|
||||
viewModel.isDateUppercase.value == true -> {
|
||||
action_capitalize.setImageDrawable(ContextCompat.getDrawable(this@CustomDateActivity, R.drawable.round_publish))
|
||||
action_capitalize.alpha = 1f
|
||||
binding.actionCapitalize.setImageDrawable(ContextCompat.getDrawable(this@CustomDateActivity, R.drawable.round_publish))
|
||||
binding.actionCapitalize.alpha = 1f
|
||||
}
|
||||
viewModel.isDateCapitalize.value == true -> {
|
||||
action_capitalize.setImageDrawable(ContextCompat.getDrawable(this@CustomDateActivity, R.drawable.ic_capitalize))
|
||||
action_capitalize.alpha = 1f
|
||||
binding.actionCapitalize.setImageDrawable(ContextCompat.getDrawable(this@CustomDateActivity, R.drawable.ic_capitalize))
|
||||
binding.actionCapitalize.alpha = 1f
|
||||
}
|
||||
else -> {
|
||||
action_capitalize.setImageDrawable(ContextCompat.getDrawable(this@CustomDateActivity, R.drawable.round_publish))
|
||||
action_capitalize.alpha = 0.3f
|
||||
binding.actionCapitalize.setImageDrawable(ContextCompat.getDrawable(this@CustomDateActivity, R.drawable.round_publish))
|
||||
binding.actionCapitalize.alpha = 0.3f
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
action_back.setOnClickListener {
|
||||
binding.actionBack.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
action_capitalize.setOnClickListener {
|
||||
binding.actionCapitalize.setOnClickListener {
|
||||
when {
|
||||
viewModel.isDateUppercase.value == true -> {
|
||||
viewModel.isDateCapitalize.value = false
|
||||
@ -159,12 +153,12 @@ class CustomDateActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
action_capitalize.setOnLongClickListener {
|
||||
binding.actionCapitalize.setOnLongClickListener {
|
||||
toast(getString(R.string.action_capitalize_the_date))
|
||||
true
|
||||
}
|
||||
|
||||
action_date_format_info.setOnClickListener {
|
||||
binding.actionDateFormatInfo.setOnClickListener {
|
||||
openURI("https://developer.android.com/reference/java/text/SimpleDateFormat")
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activities
|
||||
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
@ -6,6 +6,7 @@ import android.graphics.Typeface
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
@ -13,28 +14,20 @@ 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.google.gson.Gson
|
||||
import com.koolio.library.Font
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||
import com.tommasoberlose.anotherwidget.databinding.ActivityCustomFontBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.DateHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.CustomFontViewModel
|
||||
import kotlinx.android.synthetic.main.activity_choose_application.*
|
||||
import kotlinx.android.synthetic.main.activity_choose_application.action_back
|
||||
import kotlinx.android.synthetic.main.activity_choose_application.clear_search
|
||||
import kotlinx.android.synthetic.main.activity_choose_application.list_view
|
||||
import kotlinx.android.synthetic.main.activity_choose_application.loader
|
||||
import kotlinx.android.synthetic.main.activity_choose_application.search
|
||||
import kotlinx.android.synthetic.main.activity_music_players_filter.*
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.CustomFontViewModel
|
||||
import kotlinx.coroutines.*
|
||||
import net.idik.lib.slimadapter.SlimAdapter
|
||||
import net.idik.lib.slimadapter.diff.DefaultDiffCallback
|
||||
@ -44,19 +37,17 @@ class CustomFontActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var adapter: SlimAdapter
|
||||
private lateinit var viewModel: CustomFontViewModel
|
||||
private lateinit var binding: ActivityCustomFontBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
viewModel = ViewModelProvider(this).get(CustomFontViewModel::class.java)
|
||||
val binding = DataBindingUtil.setContentView<ActivityCustomFontBinding>(
|
||||
this,
|
||||
R.layout.activity_custom_font
|
||||
)
|
||||
binding = ActivityCustomFontBinding.inflate(layoutInflater)
|
||||
|
||||
list_view.setHasFixedSize(true)
|
||||
binding.listView.setHasFixedSize(true)
|
||||
val mLayoutManager = LinearLayoutManager(this)
|
||||
list_view.layoutManager = mLayoutManager
|
||||
binding.listView.layoutManager = mLayoutManager
|
||||
|
||||
adapter = SlimAdapter.create()
|
||||
adapter.enableDiff(object: DefaultDiffCallback() {
|
||||
@ -86,7 +77,7 @@ class CustomFontActivity : AppCompatActivity() {
|
||||
|
||||
injector.clicked(R.id.text) {
|
||||
val dialog = BottomSheetMenu<String>(this, header = item)
|
||||
listOf("100", "200", "regular", "500", "700", "800").forEachIndexed { index, s ->
|
||||
listOf("100", "200", "regular", "500", "700", "800").forEachIndexed { _, s ->
|
||||
dialog.addItem(SettingsStringHelper.getVariantLabel(this, s), s)
|
||||
}
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
@ -136,7 +127,7 @@ class CustomFontActivity : AppCompatActivity() {
|
||||
if (item.fontVariants.isEmpty()) {
|
||||
dialog.addItem(SettingsStringHelper.getVariantLabel(this, "regular"), -1)
|
||||
} else {
|
||||
item.fontVariants.filter { !it.contains("italic") }
|
||||
item.fontVariants
|
||||
.forEachIndexed { index, s ->
|
||||
dialog.addItem(SettingsStringHelper.getVariantLabel(this, s), index)
|
||||
}
|
||||
@ -146,12 +137,14 @@ class CustomFontActivity : AppCompatActivity() {
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
.attachTo(list_view)
|
||||
.attachTo(binding.listView)
|
||||
|
||||
setupListener()
|
||||
subscribeUi(binding, viewModel)
|
||||
|
||||
search.requestFocus()
|
||||
binding.search.requestFocus()
|
||||
|
||||
setContentView(binding.root)
|
||||
}
|
||||
|
||||
private var filterJob: Job? = null
|
||||
@ -162,12 +155,12 @@ class CustomFontActivity : AppCompatActivity() {
|
||||
|
||||
viewModel.fontList.observe(this, Observer {
|
||||
updateList(list = it)
|
||||
loader.visibility = View.INVISIBLE
|
||||
binding.loader.visibility = View.INVISIBLE
|
||||
})
|
||||
|
||||
viewModel.searchInput.observe(this, Observer { search ->
|
||||
updateList(search = search)
|
||||
clear_search.isVisible = search.isNotBlank()
|
||||
binding.clearSearch.isVisible = search.isNotBlank()
|
||||
})
|
||||
}
|
||||
|
||||
@ -175,7 +168,7 @@ class CustomFontActivity : AppCompatActivity() {
|
||||
list: ArrayList<Font>? = viewModel.fontList.value,
|
||||
search: String? = viewModel.searchInput.value
|
||||
) {
|
||||
loader.visibility = View.VISIBLE
|
||||
binding.loader.visibility = View.VISIBLE
|
||||
filterJob?.cancel()
|
||||
filterJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||
if (list != null && list.isNotEmpty()) {
|
||||
@ -209,18 +202,18 @@ class CustomFontActivity : AppCompatActivity() {
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
adapter.updateData(filteredList)
|
||||
loader.visibility = View.INVISIBLE
|
||||
binding.loader.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
action_back.setOnClickListener {
|
||||
binding.actionBack.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
clear_search.setOnClickListener {
|
||||
binding.clearSearch.setOnClickListener {
|
||||
viewModel.searchInput.value = ""
|
||||
}
|
||||
}
|
@ -1,67 +1,47 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activities
|
||||
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.location.Address
|
||||
import android.location.Geocoder
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.chibatching.kotpref.bulk
|
||||
import com.google.android.material.transition.MaterialFadeThrough
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import com.karumi.dexter.Dexter
|
||||
import com.karumi.dexter.MultiplePermissionsReport
|
||||
import com.karumi.dexter.PermissionToken
|
||||
import com.karumi.dexter.listener.PermissionRequest
|
||||
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
||||
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
|
||||
import com.tommasoberlose.anotherwidget.databinding.ActivityChooseApplicationBinding
|
||||
import com.tommasoberlose.anotherwidget.databinding.ActivityCustomLocationBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.ChooseApplicationViewModel
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.CustomLocationViewModel
|
||||
import kotlinx.android.synthetic.main.activity_custom_location.*
|
||||
import kotlinx.android.synthetic.main.activity_custom_location.action_back
|
||||
import kotlinx.android.synthetic.main.activity_custom_location.clear_search
|
||||
import kotlinx.android.synthetic.main.activity_custom_location.list_view
|
||||
import kotlinx.android.synthetic.main.activity_custom_location.loader
|
||||
import kotlinx.android.synthetic.main.activity_music_players_filter.*
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.CustomLocationViewModel
|
||||
import kotlinx.coroutines.*
|
||||
import net.idik.lib.slimadapter.SlimAdapter
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
|
||||
class CustomLocationActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var adapter: SlimAdapter
|
||||
private lateinit var viewModel: CustomLocationViewModel
|
||||
private lateinit var binding: ActivityCustomLocationBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
viewModel = ViewModelProvider(this).get(CustomLocationViewModel::class.java)
|
||||
val binding = DataBindingUtil.setContentView<ActivityCustomLocationBinding>(this, R.layout.activity_custom_location)
|
||||
binding = ActivityCustomLocationBinding.inflate(layoutInflater)
|
||||
|
||||
|
||||
list_view.setHasFixedSize(true)
|
||||
binding.listView.setHasFixedSize(true)
|
||||
val mLayoutManager = LinearLayoutManager(this)
|
||||
list_view.layoutManager = mLayoutManager
|
||||
binding.listView.layoutManager = mLayoutManager
|
||||
|
||||
adapter = SlimAdapter.create()
|
||||
adapter
|
||||
@ -73,18 +53,18 @@ class CustomLocationActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
.register<Address>(R.layout.custom_location_item) { item, injector ->
|
||||
injector.text(R.id.text, item.getAddressLine(0))
|
||||
injector.clicked(R.id.text) {
|
||||
injector.text(R.id.text, item.getAddressLine(0) ?: "")
|
||||
injector.clicked(R.id.item) {
|
||||
Preferences.bulk {
|
||||
customLocationLat = item.latitude.toString()
|
||||
customLocationLon = item.longitude.toString()
|
||||
customLocationAdd = item.getAddressLine(0)
|
||||
customLocationAdd = item.getAddressLine(0) ?: ""
|
||||
setResult(Activity.RESULT_OK)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
.attachTo(list_view)
|
||||
.attachTo(binding.listView)
|
||||
|
||||
|
||||
viewModel.addresses.observe(this, Observer {
|
||||
@ -94,9 +74,11 @@ class CustomLocationActivity : AppCompatActivity() {
|
||||
setupListener()
|
||||
subscribeUi(binding, viewModel)
|
||||
|
||||
location.requestFocus()
|
||||
binding.location.requestFocus()
|
||||
|
||||
setContentView(binding.root)
|
||||
}
|
||||
|
||||
private var searchJob: Job? = null
|
||||
|
||||
private fun subscribeUi(binding: ActivityCustomLocationBinding, viewModel: CustomLocationViewModel) {
|
||||
@ -105,11 +87,11 @@ class CustomLocationActivity : AppCompatActivity() {
|
||||
|
||||
viewModel.addresses.observe(this, Observer {
|
||||
adapter.updateData(listOf("Default") + it)
|
||||
loader.visibility = View.INVISIBLE
|
||||
binding.loader.visibility = View.INVISIBLE
|
||||
})
|
||||
|
||||
viewModel.locationInput.observe(this, Observer { location ->
|
||||
loader.visibility = View.VISIBLE
|
||||
binding.loader.visibility = View.VISIBLE
|
||||
searchJob?.cancel()
|
||||
searchJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||
delay(200)
|
||||
@ -125,11 +107,11 @@ class CustomLocationActivity : AppCompatActivity() {
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
viewModel.addresses.value = list
|
||||
loader.visibility = View.INVISIBLE
|
||||
binding.loader.visibility = View.INVISIBLE
|
||||
}
|
||||
|
||||
}
|
||||
clear_search.isVisible = location.isNotBlank()
|
||||
binding.clearSearch.isVisible = location.isNotBlank()
|
||||
})
|
||||
}
|
||||
|
||||
@ -164,11 +146,11 @@ class CustomLocationActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
action_back.setOnClickListener {
|
||||
binding.actionBack.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
clear_search.setOnClickListener {
|
||||
binding.clearSearch.setOnClickListener {
|
||||
viewModel.locationInput.value = ""
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.chibatching.kotpref.blockingBulk
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.databinding.ActivityMediaInfoFormatBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.MediaInfoFormatViewModel
|
||||
import com.tommasoberlose.anotherwidget.utils.getCapWordString
|
||||
import com.tommasoberlose.anotherwidget.utils.openURI
|
||||
import com.tommasoberlose.anotherwidget.utils.toast
|
||||
import kotlinx.coroutines.*
|
||||
import net.idik.lib.slimadapter.SlimAdapter
|
||||
import java.lang.Exception
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class MediaInfoFormatActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var adapter: SlimAdapter
|
||||
private lateinit var viewModel: MediaInfoFormatViewModel
|
||||
private lateinit var binding: ActivityMediaInfoFormatBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
viewModel = ViewModelProvider(this).get(MediaInfoFormatViewModel::class.java)
|
||||
binding = ActivityMediaInfoFormatBinding.inflate(layoutInflater)
|
||||
|
||||
|
||||
binding.listView.setHasFixedSize(true)
|
||||
val mLayoutManager = LinearLayoutManager(this)
|
||||
binding.listView.layoutManager = mLayoutManager
|
||||
|
||||
adapter = SlimAdapter.create()
|
||||
adapter
|
||||
.register<String>(R.layout.custom_date_example_item) { item, injector ->
|
||||
injector
|
||||
.text(R.id.custom_date_example_format, item)
|
||||
.text(
|
||||
R.id.custom_date_example_value, MediaPlayerHelper.getMediaInfo(item, EXAMPLE_TITLE, EXAMPLE_ARTIST, EXAMPLE_ALBUM))
|
||||
}
|
||||
.attachTo(binding.listView)
|
||||
|
||||
adapter.updateData(
|
||||
listOf(
|
||||
MediaPlayerHelper.MEDIA_INFO_TITLE, MediaPlayerHelper.MEDIA_INFO_ARTIST, MediaPlayerHelper.MEDIA_INFO_ALBUM
|
||||
)
|
||||
)
|
||||
|
||||
setupListener()
|
||||
subscribeUi(binding, viewModel)
|
||||
|
||||
binding.mediaInfoFormatInput.requestFocus()
|
||||
|
||||
setContentView(binding.root)
|
||||
}
|
||||
|
||||
private var formatJob: Job? = null
|
||||
|
||||
private fun subscribeUi(binding: ActivityMediaInfoFormatBinding, viewModel: MediaInfoFormatViewModel) {
|
||||
binding.viewModel = viewModel
|
||||
binding.lifecycleOwner = this
|
||||
|
||||
viewModel.mediaInfoFormatInput.observe(this) { mediaInfoFormatInput ->
|
||||
formatJob?.cancel()
|
||||
formatJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.loader.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
delay(200)
|
||||
val text = MediaPlayerHelper.getMediaInfo(mediaInfoFormatInput, EXAMPLE_TITLE, EXAMPLE_ARTIST, EXAMPLE_ALBUM)
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.loader.visibility = View.INVISIBLE
|
||||
binding.mediaInfoFormatInputValue.text = text
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
binding.actionBack.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
Preferences.blockingBulk {
|
||||
mediaInfoFormat = viewModel.mediaInfoFormatInput.value ?: ""
|
||||
}
|
||||
super.onBackPressed()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val EXAMPLE_TITLE = "Thunderstruck"
|
||||
const val EXAMPLE_ARTIST = "AC/DC"
|
||||
const val EXAMPLE_ALBUM = "The Razors Edge"
|
||||
}
|
||||
}
|
@ -1,50 +1,40 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activities
|
||||
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import android.content.Intent
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.ResolveInfo
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.bumptech.glide.Glide
|
||||
import com.tommasoberlose.anotherwidget.databinding.ActivityChooseApplicationBinding
|
||||
import com.tommasoberlose.anotherwidget.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_music_players_filter.*
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.MusicPlayersFilterViewModel
|
||||
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
|
||||
private lateinit var binding: ActivityMusicPlayersFilterBinding
|
||||
|
||||
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)
|
||||
binding = ActivityMusicPlayersFilterBinding.inflate(layoutInflater)
|
||||
|
||||
list_view.setHasFixedSize(true)
|
||||
binding.listView.setHasFixedSize(true)
|
||||
val mLayoutManager = LinearLayoutManager(this)
|
||||
list_view.layoutManager = mLayoutManager
|
||||
binding.listView.layoutManager = mLayoutManager
|
||||
|
||||
adapter = SlimAdapter.create()
|
||||
adapter
|
||||
@ -69,12 +59,14 @@ class MusicPlayersFilterActivity : AppCompatActivity() {
|
||||
}
|
||||
.checked(R.id.checkBox, MediaPlayerHelper.isMusicPlayerAccepted(item.activityInfo.packageName))
|
||||
}
|
||||
.attachTo(list_view)
|
||||
.attachTo(binding.listView)
|
||||
|
||||
setupListener()
|
||||
subscribeUi(binding, viewModel)
|
||||
|
||||
search.requestFocus()
|
||||
binding.search.requestFocus()
|
||||
|
||||
setContentView(binding.root)
|
||||
}
|
||||
|
||||
private var filterJob: Job? = null
|
||||
@ -83,24 +75,24 @@ class MusicPlayersFilterActivity : AppCompatActivity() {
|
||||
binding.viewModel = viewModel
|
||||
binding.lifecycleOwner = this
|
||||
|
||||
viewModel.appList.observe(this, Observer {
|
||||
viewModel.appList.observe(this) {
|
||||
updateList(list = it)
|
||||
loader.visibility = View.INVISIBLE
|
||||
})
|
||||
binding.loader.visibility = View.INVISIBLE
|
||||
}
|
||||
|
||||
viewModel.searchInput.observe(this, Observer { search ->
|
||||
viewModel.searchInput.observe(this) { search ->
|
||||
updateList(search = search)
|
||||
clear_search.isVisible = search.isNotBlank()
|
||||
})
|
||||
binding.clearSearch.isVisible = search.isNotBlank()
|
||||
}
|
||||
|
||||
viewModel.musicPlayersFilter.observe(this, {
|
||||
viewModel.musicPlayersFilter.observe(this) {
|
||||
updateList()
|
||||
clear_selection.isVisible = Preferences.musicPlayersFilter != ""
|
||||
})
|
||||
binding.clearSelection.isVisible = Preferences.musicPlayersFilter != ""
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateList(list: List<ResolveInfo>? = viewModel.appList.value, search: String? = viewModel.searchInput.value) {
|
||||
loader.visibility = View.VISIBLE
|
||||
binding.loader.visibility = View.VISIBLE
|
||||
filterJob?.cancel()
|
||||
filterJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||
if (list != null && list.isNotEmpty()) {
|
||||
@ -126,22 +118,22 @@ class MusicPlayersFilterActivity : AppCompatActivity() {
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
adapter.updateData(filteredList)
|
||||
loader.visibility = View.INVISIBLE
|
||||
binding.loader.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
action_back.setOnClickListener {
|
||||
binding.actionBack.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
clear_search.setOnClickListener {
|
||||
binding.clearSearch.setOnClickListener {
|
||||
viewModel.searchInput.value = ""
|
||||
}
|
||||
|
||||
clear_selection.setOnClickListener {
|
||||
binding.clearSelection.setOnClickListener {
|
||||
Preferences.musicPlayersFilter = ""
|
||||
}
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.location.Address
|
||||
import android.location.Geocoder
|
||||
import android.os.Bundle
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.chibatching.kotpref.bulk
|
||||
import com.karumi.dexter.Dexter
|
||||
import com.karumi.dexter.MultiplePermissionsReport
|
||||
import com.karumi.dexter.PermissionToken
|
||||
import com.karumi.dexter.listener.PermissionRequest
|
||||
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.databinding.ActivityTimeZoneSelectorBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.network.TimeZonesApi
|
||||
import com.tommasoberlose.anotherwidget.network.WeatherNetworkApi
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.TimeZoneSelectorViewModel
|
||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||
import com.tommasoberlose.anotherwidget.utils.toast
|
||||
import kotlinx.coroutines.*
|
||||
import net.idik.lib.slimadapter.SlimAdapter
|
||||
|
||||
class TimeZoneSelectorActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var adapter: SlimAdapter
|
||||
private lateinit var viewModel: TimeZoneSelectorViewModel
|
||||
private lateinit var binding: ActivityTimeZoneSelectorBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
viewModel = ViewModelProvider(this).get(TimeZoneSelectorViewModel::class.java)
|
||||
binding = ActivityTimeZoneSelectorBinding.inflate(layoutInflater)
|
||||
|
||||
binding.geonameCredits.movementMethod = LinkMovementMethod.getInstance()
|
||||
|
||||
binding.listView.setHasFixedSize(true)
|
||||
val mLayoutManager = LinearLayoutManager(this)
|
||||
binding.listView.layoutManager = mLayoutManager
|
||||
|
||||
adapter = SlimAdapter.create()
|
||||
adapter
|
||||
.register<String>(R.layout.custom_location_item) { _, injector ->
|
||||
injector
|
||||
.text(R.id.text, getString(R.string.no_time_zone_label))
|
||||
.clicked(R.id.text) {
|
||||
Preferences.bulk {
|
||||
altTimezoneId = ""
|
||||
altTimezoneLabel = ""
|
||||
}
|
||||
MainWidget.updateWidget(this@TimeZoneSelectorActivity)
|
||||
setResult(Activity.RESULT_OK)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
.register<Address>(R.layout.custom_location_item) { item, injector ->
|
||||
injector.text(R.id.text, item.getAddressLine(0))
|
||||
injector.clicked(R.id.item) {
|
||||
binding.loader.visibility = View.VISIBLE
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val networkApi = TimeZonesApi(this@TimeZoneSelectorActivity)
|
||||
val id = networkApi.getTimeZone(item.latitude.toString(), item.longitude.toString())
|
||||
|
||||
if (id != null) {
|
||||
Preferences.bulk {
|
||||
altTimezoneId = id
|
||||
altTimezoneLabel = try {
|
||||
item.locality
|
||||
} catch (ex: Exception) {
|
||||
item.getAddressLine(0)
|
||||
}
|
||||
}
|
||||
MainWidget.updateWidget(this@TimeZoneSelectorActivity)
|
||||
setResult(Activity.RESULT_OK)
|
||||
finish()
|
||||
} else {
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.loader.visibility = View.INVISIBLE
|
||||
toast(getString(R.string.time_zone_search_error_message))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.attachTo(binding.listView)
|
||||
|
||||
|
||||
viewModel.addresses.observe(this, Observer {
|
||||
adapter.updateData(listOf("Default") + it)
|
||||
})
|
||||
|
||||
setupListener()
|
||||
subscribeUi(binding, viewModel)
|
||||
|
||||
binding.location.requestFocus()
|
||||
|
||||
setContentView(binding.root)
|
||||
}
|
||||
|
||||
private var searchJob: Job? = null
|
||||
|
||||
private fun subscribeUi(binding: ActivityTimeZoneSelectorBinding, viewModel: TimeZoneSelectorViewModel) {
|
||||
binding.viewModel = viewModel
|
||||
binding.lifecycleOwner = this
|
||||
|
||||
viewModel.addresses.observe(this, Observer {
|
||||
adapter.updateData(listOf("Default") + it)
|
||||
binding.loader.visibility = View.INVISIBLE
|
||||
})
|
||||
|
||||
viewModel.locationInput.observe(this, Observer { location ->
|
||||
binding.loader.visibility = View.VISIBLE
|
||||
searchJob?.cancel()
|
||||
searchJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||
delay(200)
|
||||
val list = if (location == null || location == "") {
|
||||
viewModel.addresses.value!!
|
||||
} else {
|
||||
val coder = Geocoder(this@TimeZoneSelectorActivity)
|
||||
try {
|
||||
coder.getFromLocationName(location, 10) as ArrayList<Address>
|
||||
} catch (ignored: Exception) {
|
||||
emptyList<Address>()
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
viewModel.addresses.value = list
|
||||
binding.loader.visibility = View.INVISIBLE
|
||||
}
|
||||
|
||||
}
|
||||
binding.clearSearch.isVisible = location.isNotBlank()
|
||||
})
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
binding.actionBack.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
binding.clearSearch.setOnClickListener {
|
||||
viewModel.locationInput.value = ""
|
||||
}
|
||||
}
|
||||
}
|
@ -1,45 +1,25 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activities
|
||||
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.pm.ResolveInfo
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
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.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.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.reveal
|
||||
import kotlinx.android.synthetic.main.activity_weather_provider.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.WeatherProviderViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import net.idik.lib.slimadapter.SlimAdapter
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
@ -49,16 +29,17 @@ class WeatherProviderActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var adapter: SlimAdapter
|
||||
private lateinit var viewModel: WeatherProviderViewModel
|
||||
private lateinit var binding: ActivityWeatherProviderBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_weather_provider)
|
||||
|
||||
viewModel = ViewModelProvider(this).get(WeatherProviderViewModel::class.java)
|
||||
binding = ActivityWeatherProviderBinding.inflate(layoutInflater)
|
||||
|
||||
list_view.setHasFixedSize(true)
|
||||
binding.listView.setHasFixedSize(true)
|
||||
val mLayoutManager = LinearLayoutManager(this)
|
||||
list_view.layoutManager = mLayoutManager
|
||||
binding.listView.layoutManager = mLayoutManager
|
||||
|
||||
adapter = SlimAdapter.create()
|
||||
adapter
|
||||
@ -66,36 +47,36 @@ class WeatherProviderActivity : AppCompatActivity() {
|
||||
injector
|
||||
.text(R.id.text, WeatherHelper.getProviderName(this, provider))
|
||||
.clicked(R.id.item) {
|
||||
if (Preferences.weatherProvider != provider.value) {
|
||||
if (Preferences.weatherProvider != provider.rawValue) {
|
||||
Preferences.weatherProviderError = "-"
|
||||
Preferences.weatherProviderLocationError = ""
|
||||
}
|
||||
val oldValue = Preferences.weatherProvider
|
||||
Preferences.weatherProvider = provider.value
|
||||
Preferences.weatherProvider = provider.rawValue
|
||||
updateListItem(oldValue)
|
||||
updateListItem()
|
||||
loader.isVisible = true
|
||||
binding.loader.isVisible = true
|
||||
|
||||
lifecycleScope.launch {
|
||||
WeatherHelper.updateWeather(this@WeatherProviderActivity)
|
||||
}
|
||||
}
|
||||
.clicked(R.id.radioButton) {
|
||||
if (Preferences.weatherProvider != provider.value) {
|
||||
if (Preferences.weatherProvider != provider.rawValue) {
|
||||
Preferences.weatherProviderError = "-"
|
||||
Preferences.weatherProviderLocationError = ""
|
||||
}
|
||||
val oldValue = Preferences.weatherProvider
|
||||
Preferences.weatherProvider = provider.value
|
||||
Preferences.weatherProvider = provider.rawValue
|
||||
updateListItem(oldValue)
|
||||
updateListItem()
|
||||
loader.isVisible = true
|
||||
binding.loader.isVisible = true
|
||||
|
||||
lifecycleScope.launch {
|
||||
WeatherHelper.updateWeather(this@WeatherProviderActivity)
|
||||
}
|
||||
}
|
||||
.checked(R.id.radioButton, provider.value == Preferences.weatherProvider)
|
||||
.checked(R.id.radioButton, provider.rawValue == Preferences.weatherProvider)
|
||||
.with<TextView>(R.id.text2) {
|
||||
if (WeatherHelper.isKeyRequired(provider)) {
|
||||
it.text = getString(R.string.api_key_required_message)
|
||||
@ -112,25 +93,25 @@ class WeatherProviderActivity : AppCompatActivity() {
|
||||
.clicked(R.id.action_configure) {
|
||||
BottomSheetWeatherProviderSettings(this) {
|
||||
lifecycleScope.launch {
|
||||
loader.isVisible = true
|
||||
binding.loader.isVisible = true
|
||||
WeatherHelper.updateWeather(this@WeatherProviderActivity)
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
.visibility(R.id.action_configure, if (/*WeatherHelper.isKeyRequired(provider) && */provider.value == Preferences.weatherProvider) View.VISIBLE else View.GONE)
|
||||
.visibility(R.id.action_configure, if (/*WeatherHelper.isKeyRequired(provider) && */provider.rawValue == 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
|
||||
it.isVisible = provider.rawValue == Preferences.weatherProvider
|
||||
} else if (Preferences.weatherProviderLocationError != "") {
|
||||
it.text = Preferences.weatherProviderLocationError
|
||||
it.isVisible = provider.value == Preferences.weatherProvider
|
||||
it.isVisible = provider.rawValue == Preferences.weatherProvider
|
||||
} else {
|
||||
it.isVisible = false
|
||||
}
|
||||
}
|
||||
.image(R.id.action_configure, ContextCompat.getDrawable(this, if (WeatherHelper.isKeyRequired(provider)) R.drawable.round_settings_24 else R.drawable.outline_info_24))
|
||||
}.attachTo(list_view)
|
||||
}.attachTo(binding.listView)
|
||||
|
||||
adapter.updateData(
|
||||
Constants.WeatherProvider.values().asList()
|
||||
@ -140,6 +121,8 @@ class WeatherProviderActivity : AppCompatActivity() {
|
||||
|
||||
setupListener()
|
||||
subscribeUi(viewModel)
|
||||
|
||||
setContentView(binding.root)
|
||||
}
|
||||
|
||||
private fun subscribeUi(viewModel: WeatherProviderViewModel) {
|
||||
@ -154,14 +137,14 @@ class WeatherProviderActivity : AppCompatActivity() {
|
||||
|
||||
private fun updateListItem(provider: Int = Preferences.weatherProvider) {
|
||||
(adapter.data).forEachIndexed { index, item ->
|
||||
if (item is Constants.WeatherProvider && item.value == provider) {
|
||||
if (item is Constants.WeatherProvider && item.rawValue == provider) {
|
||||
adapter.notifyItemChanged(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
action_back.setOnClickListener {
|
||||
binding.actionBack.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
}
|
||||
@ -183,9 +166,9 @@ class WeatherProviderActivity : AppCompatActivity() {
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onMessageEvent(ignore: MainFragment.UpdateUiMessageEvent?) {
|
||||
loader.isVisible = Preferences.weatherProviderError == "-"
|
||||
binding.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()
|
||||
Snackbar.make(binding.listView, getString(R.string.settings_weather_provider_api_key_subtitle_all_set), Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ package com.tommasoberlose.anotherwidget.ui.adapters
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import com.tommasoberlose.anotherwidget.ui.fragments.*
|
||||
import com.tommasoberlose.anotherwidget.ui.fragments.tabs.*
|
||||
|
||||
class ViewPagerAdapter(fragmentActivity: FragmentActivity) :
|
||||
FragmentStateAdapter(fragmentActivity) {
|
||||
@ -12,11 +12,11 @@ class ViewPagerAdapter(fragmentActivity: FragmentActivity) :
|
||||
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
return when (position) {
|
||||
1 -> CalendarTabFragment.newInstance()
|
||||
2 -> WeatherTabFragment.newInstance()
|
||||
3 -> ClockTabFragment.newInstance()
|
||||
1 -> CalendarFragment.newInstance()
|
||||
2 -> WeatherFragment.newInstance()
|
||||
3 -> ClockFragment.newInstance()
|
||||
4 -> GlanceTabFragment.newInstance()
|
||||
else -> GeneralTabFragment.newInstance()
|
||||
else -> LayoutFragment.newInstance()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,456 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.fragments
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.provider.CalendarContract
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.chibatching.kotpref.bulk
|
||||
import com.karumi.dexter.Dexter
|
||||
import com.karumi.dexter.MultiplePermissionsReport
|
||||
import com.karumi.dexter.PermissionToken
|
||||
import com.karumi.dexter.listener.PermissionRequest
|
||||
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||
import com.tommasoberlose.anotherwidget.models.CalendarSelector
|
||||
import com.tommasoberlose.anotherwidget.databinding.FragmentCalendarSettingsBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.global.RequestCode
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.IntentHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||
import com.tommasoberlose.anotherwidget.utils.isDefaultSet
|
||||
import com.tommasoberlose.anotherwidget.utils.toast
|
||||
import kotlinx.android.synthetic.main.fragment_calendar_settings.*
|
||||
import kotlinx.android.synthetic.main.fragment_calendar_settings.scrollView
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.Comparator
|
||||
|
||||
class CalendarTabFragment : Fragment() {
|
||||
|
||||
companion object {
|
||||
fun newInstance() = CalendarTabFragment()
|
||||
}
|
||||
|
||||
private lateinit var viewModel: MainViewModel
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
|
||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||
val binding = DataBindingUtil.inflate<FragmentCalendarSettingsBinding>(inflater, R.layout.fragment_calendar_settings, container, false)
|
||||
|
||||
subscribeUi(binding, viewModel)
|
||||
|
||||
binding.lifecycleOwner = this
|
||||
binding.viewModel = viewModel
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
|
||||
show_all_day_toggle.isChecked = Preferences.calendarAllDay
|
||||
show_only_busy_events_toggle.isChecked = Preferences.showOnlyBusyEvents
|
||||
show_diff_time_toggle.isChecked = Preferences.showDiffTime
|
||||
show_multiple_events_toggle.isChecked = Preferences.showNextEvent
|
||||
|
||||
setupListener()
|
||||
}
|
||||
|
||||
private fun subscribeUi(
|
||||
binding: FragmentCalendarSettingsBinding,
|
||||
viewModel: MainViewModel
|
||||
) {
|
||||
binding.isCalendarEnabled = Preferences.showEvents
|
||||
binding.isDiffEnabled = Preferences.showDiffTime || !Preferences.showEvents
|
||||
|
||||
viewModel.showEvents.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
binding.isCalendarEnabled = it
|
||||
|
||||
if (it) {
|
||||
CalendarHelper.setEventUpdatesAndroidN(requireContext())
|
||||
} else {
|
||||
CalendarHelper.removeEventUpdatesAndroidN(requireContext())
|
||||
}
|
||||
binding.isDiffEnabled = Preferences.showDiffTime || !it
|
||||
}
|
||||
checkReadEventsPermission()
|
||||
updateCalendar()
|
||||
})
|
||||
|
||||
viewModel.calendarAllDay.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
all_day_label?.text =
|
||||
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.secondRowInformation.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
second_row_info_label?.text = getString(SettingsStringHelper.getSecondRowInfoString(it))
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.showDiffTime.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
show_diff_time_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||
binding.isDiffEnabled = it || !Preferences.showEvents
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.widgetUpdateFrequency.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
widget_update_frequency_label?.text = when (it) {
|
||||
Constants.WidgetUpdateFrequency.HIGH.value -> getString(R.string.settings_widget_update_frequency_high)
|
||||
Constants.WidgetUpdateFrequency.DEFAULT.value -> getString(R.string.settings_widget_update_frequency_default)
|
||||
Constants.WidgetUpdateFrequency.LOW.value -> getString(R.string.settings_widget_update_frequency_low)
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.showUntil.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
show_until_label?.text = getString(SettingsStringHelper.getShowUntilString(it))
|
||||
}
|
||||
updateCalendar()
|
||||
})
|
||||
|
||||
viewModel.showNextEvent.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
show_multiple_events_label?.text =
|
||||
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.calendarAppName.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
calendar_app_label?.text = when {
|
||||
Preferences.calendarAppName != "" -> Preferences.calendarAppName
|
||||
else -> {
|
||||
if (IntentHelper.getCalendarIntent(requireContext()).isDefaultSet(requireContext())) {
|
||||
getString(
|
||||
R.string.default_calendar_app
|
||||
)
|
||||
} else {
|
||||
getString(R.string.nothing)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.openEventDetails.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
open_event_details_label?.text = if (it) getString(R.string.default_event_app) else getString(R.string.default_calendar_app)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
|
||||
action_show_events.setOnClickListener {
|
||||
Preferences.showEvents = !Preferences.showEvents
|
||||
if (Preferences.showEvents) {
|
||||
requirePermission()
|
||||
}
|
||||
}
|
||||
|
||||
show_events_switch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
||||
Preferences.showEvents = enabled
|
||||
if (Preferences.showEvents) {
|
||||
requirePermission()
|
||||
}
|
||||
}
|
||||
|
||||
action_filter_calendar.setOnClickListener {
|
||||
val calendarSelectorList: List<CalendarSelector> = CalendarHelper.getCalendarList(requireContext()).map {
|
||||
CalendarSelector(
|
||||
it.id,
|
||||
it.displayName,
|
||||
it.accountName
|
||||
)
|
||||
}.sortedWith(Comparator { cal1, cal2 ->
|
||||
when {
|
||||
cal1.accountName != cal2.accountName -> {
|
||||
cal1.accountName.compareTo(cal2.accountName)
|
||||
}
|
||||
cal1.accountName == cal1.name -> {
|
||||
-1
|
||||
}
|
||||
cal2.accountName == cal2.name -> {
|
||||
1
|
||||
}
|
||||
else -> {
|
||||
cal1.name.compareTo(cal2.name)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (calendarSelectorList.isNotEmpty()) {
|
||||
val filteredCalendarIds = CalendarHelper.getFilteredCalendarIdList()
|
||||
val visibleCalendarIds = calendarSelectorList.map { it.id }.filter { id: Long -> !filteredCalendarIds.contains(id) }
|
||||
|
||||
val dialog = BottomSheetMenu<Long>(requireContext(), header = getString(R.string.settings_filter_calendar_subtitle), isMultiSelection = true)
|
||||
.setSelectedValues(visibleCalendarIds)
|
||||
|
||||
calendarSelectorList.indices.forEach { index ->
|
||||
if (index == 0 || calendarSelectorList[index].accountName != calendarSelectorList[index - 1].accountName) {
|
||||
dialog.addItem(calendarSelectorList[index].accountName)
|
||||
}
|
||||
|
||||
dialog.addItem(
|
||||
if (calendarSelectorList[index].name == calendarSelectorList[index].accountName) getString(R.string.main_calendar) else calendarSelectorList[index].name,
|
||||
calendarSelectorList[index].id
|
||||
)
|
||||
}
|
||||
|
||||
dialog.addOnMultipleSelectItemListener { values ->
|
||||
CalendarHelper.filterCalendar(calendarSelectorList.map { it.id }.filter { !values.contains(it) })
|
||||
updateCalendar()
|
||||
}.show()
|
||||
} else {
|
||||
activity?.toast(getString(R.string.calendar_settings_list_error))
|
||||
}
|
||||
}
|
||||
|
||||
action_show_all_day.setOnClickListener {
|
||||
if (Preferences.showEvents) {
|
||||
show_all_day_toggle.isChecked = !show_all_day_toggle.isChecked
|
||||
}
|
||||
}
|
||||
|
||||
show_all_day_toggle.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (Preferences.showEvents) {
|
||||
Preferences.calendarAllDay = isChecked
|
||||
updateCalendar()
|
||||
}
|
||||
}
|
||||
|
||||
action_change_attendee_filter.setOnClickListener {
|
||||
if (Preferences.showEvents) {
|
||||
val selectedValues = emptyList<Int>().toMutableList()
|
||||
if (Preferences.showDeclinedEvents) {
|
||||
selectedValues.add(CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED)
|
||||
}
|
||||
if (Preferences.showInvitedEvents) {
|
||||
selectedValues.add(CalendarContract.Attendees.ATTENDEE_STATUS_INVITED)
|
||||
}
|
||||
if (Preferences.showAcceptedEvents) {
|
||||
selectedValues.add(CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED)
|
||||
}
|
||||
|
||||
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_attendee_status_title), isMultiSelection = true)
|
||||
.setSelectedValues(selectedValues)
|
||||
|
||||
dialog.addItem(
|
||||
getString(R.string.attendee_status_invited),
|
||||
CalendarContract.Attendees.ATTENDEE_STATUS_INVITED
|
||||
)
|
||||
dialog.addItem(
|
||||
getString(R.string.attendee_status_accepted),
|
||||
CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED
|
||||
)
|
||||
dialog.addItem(
|
||||
getString(R.string.attendee_status_declined),
|
||||
CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED
|
||||
)
|
||||
|
||||
dialog.addOnMultipleSelectItemListener { values ->
|
||||
Preferences.showDeclinedEvents = values.contains(CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED)
|
||||
Preferences.showAcceptedEvents = values.contains(CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED)
|
||||
Preferences.showInvitedEvents = values.contains(CalendarContract.Attendees.ATTENDEE_STATUS_INVITED)
|
||||
updateCalendar()
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
action_show_only_busy_events.setOnClickListener {
|
||||
if (Preferences.showEvents) {
|
||||
show_only_busy_events_toggle.isChecked = !show_only_busy_events_toggle.isChecked
|
||||
}
|
||||
}
|
||||
|
||||
show_only_busy_events_toggle.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (Preferences.showEvents) {
|
||||
Preferences.showOnlyBusyEvents = isChecked
|
||||
updateCalendar()
|
||||
}
|
||||
}
|
||||
|
||||
action_show_multiple_events.setOnClickListener {
|
||||
if (Preferences.showEvents) {
|
||||
show_multiple_events_toggle.isChecked = !show_multiple_events_toggle.isChecked
|
||||
}
|
||||
}
|
||||
|
||||
show_multiple_events_toggle.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (Preferences.showEvents) {
|
||||
Preferences.showNextEvent = isChecked
|
||||
}
|
||||
}
|
||||
|
||||
action_show_diff_time.setOnClickListener {
|
||||
if (Preferences.showEvents) {
|
||||
show_diff_time_toggle.isChecked = !show_diff_time_toggle.isChecked
|
||||
}
|
||||
}
|
||||
|
||||
show_diff_time_toggle.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (Preferences.showEvents) {
|
||||
Preferences.showDiffTime = isChecked
|
||||
}
|
||||
}
|
||||
|
||||
action_widget_update_frequency.setOnClickListener {
|
||||
if (Preferences.showEvents && Preferences.showDiffTime) {
|
||||
BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_widget_update_frequency_title), message = getString(R.string.settings_widget_update_frequency_subtitle)).setSelectedValue(Preferences.widgetUpdateFrequency)
|
||||
.addItem(getString(R.string.settings_widget_update_frequency_high), Constants.WidgetUpdateFrequency.HIGH.value)
|
||||
.addItem(getString(R.string.settings_widget_update_frequency_default), Constants.WidgetUpdateFrequency.DEFAULT.value)
|
||||
.addItem(getString(R.string.settings_widget_update_frequency_low), Constants.WidgetUpdateFrequency.LOW.value)
|
||||
.addOnSelectItemListener { value ->
|
||||
Preferences.widgetUpdateFrequency = value
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
action_second_row_info.setOnClickListener {
|
||||
if (Preferences.showEvents) {
|
||||
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_second_row_info_title)).setSelectedValue(Preferences.secondRowInformation)
|
||||
(0 .. 1).forEach {
|
||||
dialog.addItem(getString(SettingsStringHelper.getSecondRowInfoString(it)), it)
|
||||
}
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
Preferences.secondRowInformation = value
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
action_show_until.setOnClickListener {
|
||||
if (Preferences.showEvents) {
|
||||
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_show_until_title)).setSelectedValue(Preferences.showUntil)
|
||||
intArrayOf(6,7,0,1,2,3, 4, 5).forEach {
|
||||
dialog.addItem(getString(SettingsStringHelper.getShowUntilString(it)), it)
|
||||
}
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
Preferences.showUntil = value
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
action_open_event_details.setOnClickListener {
|
||||
if (Preferences.showEvents) {
|
||||
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_event_app_title)).setSelectedValue(Preferences.openEventDetails)
|
||||
.addItem(getString(R.string.default_event_app), true)
|
||||
.addItem(getString(R.string.default_calendar_app), false)
|
||||
.addOnSelectItemListener { value ->
|
||||
Preferences.openEventDetails = value
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
action_calendar_app.setOnClickListener {
|
||||
startActivityForResult(Intent(requireContext(), ChooseApplicationActivity::class.java), RequestCode.CALENDAR_APP_REQUEST_CODE.code)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkReadEventsPermission(showEvents: Boolean = Preferences.showEvents) {
|
||||
if (activity?.checkGrantedPermission(Manifest.permission.READ_CALENDAR) == true) {
|
||||
show_events_label?.text = if (showEvents) getString(R.string.show_events_visible) else getString(R.string.show_events_not_visible)
|
||||
read_calendar_permission_alert?.isVisible = false
|
||||
} else {
|
||||
show_events_label?.text = if (showEvents) getString(R.string.description_permission_calendar) else getString(R.string.show_events_not_visible)
|
||||
read_calendar_permission_alert?.isVisible = showEvents
|
||||
read_calendar_permission_alert?.setOnClickListener {
|
||||
requirePermission()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateCalendar() {
|
||||
if (activity?.checkGrantedPermission(Manifest.permission.READ_CALENDAR) == true) {
|
||||
CalendarHelper.updateEventList(requireContext())
|
||||
}
|
||||
}
|
||||
|
||||
private fun requirePermission() {
|
||||
Dexter.withContext(requireContext())
|
||||
.withPermissions(
|
||||
Manifest.permission.READ_CALENDAR
|
||||
).withListener(object: MultiplePermissionsListener {
|
||||
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
||||
report?.let {
|
||||
if (report.areAllPermissionsGranted()){
|
||||
checkReadEventsPermission()
|
||||
} else {
|
||||
Preferences.showEvents = false
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun onPermissionRationaleShouldBeShown(
|
||||
permissions: MutableList<PermissionRequest>?,
|
||||
token: PermissionToken?
|
||||
) {
|
||||
// Remember to invoke this method when the custom rationale is closed
|
||||
// or just by default if you don't want to use any custom rationale.
|
||||
token?.continuePermissionRequest()
|
||||
}
|
||||
})
|
||||
.check()
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
RequestCode.CALENDAR_APP_REQUEST_CODE.code -> {
|
||||
Preferences.bulk {
|
||||
calendarAppName = data?.getStringExtra(Constants.RESULT_APP_NAME) ?: getString(R.string.default_calendar_app)
|
||||
calendarAppPackage = data?.getStringExtra(Constants.RESULT_APP_PACKAGE) ?: ""
|
||||
}
|
||||
}
|
||||
RequestCode.EVENT_APP_REQUEST_CODE.code -> {
|
||||
Preferences.bulk {
|
||||
eventAppName = data?.getStringExtra(Constants.RESULT_APP_NAME) ?: getString(R.string.default_event_app)
|
||||
eventAppPackage = data?.getStringExtra(Constants.RESULT_APP_PACKAGE) ?: ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||
scrollView.isScrollable = false
|
||||
callback.invoke()
|
||||
lifecycleScope.launch {
|
||||
delay(200)
|
||||
scrollView.isScrollable = true
|
||||
}
|
||||
}
|
||||
}
|
@ -1,331 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.fragments
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.AlarmManager
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Bundle
|
||||
import android.text.format.DateFormat
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.chibatching.kotpref.bulk
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||
import com.tommasoberlose.anotherwidget.components.FixedFocusScrollView
|
||||
import com.tommasoberlose.anotherwidget.databinding.FragmentClockSettingsBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.global.RequestCode
|
||||
import com.tommasoberlose.anotherwidget.helpers.AlarmHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toHexValue
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
||||
import com.tommasoberlose.anotherwidget.helpers.IntentHelper
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||
import com.tommasoberlose.anotherwidget.utils.isDefaultSet
|
||||
import kotlinx.android.synthetic.main.fragment_clock_settings.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.lang.Exception
|
||||
|
||||
|
||||
class ClockTabFragment : Fragment() {
|
||||
|
||||
companion object {
|
||||
fun newInstance() = ClockTabFragment()
|
||||
}
|
||||
|
||||
private lateinit var viewModel: MainViewModel
|
||||
private lateinit var colors: IntArray
|
||||
private lateinit var binding: FragmentClockSettingsBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
|
||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||
binding = DataBindingUtil.inflate<FragmentClockSettingsBinding>(inflater, R.layout.fragment_clock_settings, container, false)
|
||||
|
||||
subscribeUi(binding, viewModel)
|
||||
|
||||
binding.lifecycleOwner = this
|
||||
binding.viewModel = viewModel
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
|
||||
ampm_indicator_toggle.isChecked = Preferences.showAMPMIndicator
|
||||
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val lazyColors = requireContext().resources.getIntArray(R.array.material_colors)
|
||||
withContext(Dispatchers.Main) {
|
||||
colors = lazyColors
|
||||
}
|
||||
}
|
||||
setupListener()
|
||||
}
|
||||
|
||||
private fun subscribeUi(
|
||||
binding: FragmentClockSettingsBinding,
|
||||
viewModel: MainViewModel
|
||||
) {
|
||||
binding.isClockVisible = Preferences.showClock
|
||||
binding.is24Format = DateFormat.is24HourFormat(requireContext())
|
||||
binding.isDarkModeEnabled = activity?.isDarkTheme() == true
|
||||
|
||||
viewModel.showBigClockWarning.observe(viewLifecycleOwner, Observer {
|
||||
large_clock_warning?.isVisible = it
|
||||
small_clock_warning?.isVisible = !it
|
||||
})
|
||||
|
||||
viewModel.showClock.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
show_clock_label?.text =
|
||||
if (it) getString(R.string.show_clock_visible) else getString(R.string.show_clock_not_visible)
|
||||
binding.isClockVisible = it
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.clockTextSize.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
clock_text_size_label?.text = String.format("%.0fsp", it)
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.showAMPMIndicator.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
ampm_indicator_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.clockTextColor.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
if (Preferences.clockTextAlpha == "00") {
|
||||
clock_text_color_label?.text = getString(R.string.transparent)
|
||||
} else {
|
||||
clock_text_color_label?.text =
|
||||
"#%s".format(Integer.toHexString(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.clockTextColorDark.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
if (Preferences.clockTextAlphaDark == "00") {
|
||||
clock_text_color_label?.text = getString(R.string.transparent)
|
||||
} else {
|
||||
clock_text_color_label?.text =
|
||||
"#%s".format(Integer.toHexString(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.clockTextAlpha.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
if (Preferences.clockTextAlpha == "00") {
|
||||
clock_text_color_label?.text = getString(R.string.transparent)
|
||||
} else {
|
||||
clock_text_color_label?.text =
|
||||
"#%s".format(Integer.toHexString(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.clockTextAlphaDark.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
if (Preferences.clockTextAlphaDark == "00") {
|
||||
clock_text_color_label?.text = getString(R.string.transparent)
|
||||
} else {
|
||||
clock_text_color_label?.text =
|
||||
"#%s".format(Integer.toHexString(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.clockBottomMargin.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
clock_bottom_margin_label?.text = when (it) {
|
||||
Constants.ClockBottomMargin.NONE.value -> getString(R.string.settings_clock_bottom_margin_subtitle_none)
|
||||
Constants.ClockBottomMargin.SMALL.value -> getString(R.string.settings_clock_bottom_margin_subtitle_small)
|
||||
Constants.ClockBottomMargin.LARGE.value -> getString(R.string.settings_clock_bottom_margin_subtitle_large)
|
||||
else -> getString(R.string.settings_clock_bottom_margin_subtitle_medium)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.clockAppName.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
clock_app_label?.text = when {
|
||||
Preferences.clockAppName != "" -> Preferences.clockAppName
|
||||
else -> {
|
||||
if (IntentHelper.getClockIntent(requireContext()).isDefaultSet(requireContext())) {
|
||||
getString(
|
||||
R.string.default_clock_app
|
||||
)
|
||||
} else {
|
||||
getString(R.string.nothing)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
action_hide_large_clock_warning.setOnClickListener {
|
||||
Preferences.showBigClockWarning = false
|
||||
}
|
||||
|
||||
action_show_clock.setOnClickListener {
|
||||
Preferences.showClock = !Preferences.showClock
|
||||
}
|
||||
|
||||
show_clock_switch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
||||
Preferences.showClock = enabled
|
||||
}
|
||||
|
||||
action_clock_text_size.setOnClickListener {
|
||||
if (Preferences.showClock) {
|
||||
val dialog = BottomSheetMenu<Float>(
|
||||
requireContext(),
|
||||
header = getString(R.string.settings_clock_text_size_title)
|
||||
).setSelectedValue(Preferences.clockTextSize)
|
||||
(46 downTo 12).filter { it % 2 == 0 }.forEach {
|
||||
dialog.addItem("${it}sp", it.toFloat())
|
||||
}
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
Preferences.clockTextSize = value
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
action_ampm_indicator_size.setOnClickListener {
|
||||
if (Preferences.showClock) {
|
||||
ampm_indicator_toggle.isChecked = !ampm_indicator_toggle.isChecked
|
||||
}
|
||||
}
|
||||
|
||||
ampm_indicator_toggle.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (Preferences.showClock) {
|
||||
Preferences.showAMPMIndicator = isChecked
|
||||
}
|
||||
}
|
||||
|
||||
action_clock_text_color.setOnClickListener {
|
||||
if (Preferences.showClock) {
|
||||
BottomSheetColorPicker(requireContext(),
|
||||
colors = colors,
|
||||
header = getString(R.string.settings_font_color_title),
|
||||
getSelected = { ColorHelper.getClockFontColorRgb(activity?.isDarkTheme() == true) },
|
||||
onColorSelected = { color: Int ->
|
||||
val colorString = Integer.toHexString(color)
|
||||
if (activity?.isDarkTheme() == true) {
|
||||
Preferences.clockTextColorDark =
|
||||
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||
} else {
|
||||
Preferences.clockTextColor =
|
||||
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||
}
|
||||
},
|
||||
showAlphaSelector = true,
|
||||
alpha = if (activity?.isDarkTheme() == true) Preferences.clockTextAlphaDark.toIntValue() else Preferences.clockTextAlpha.toIntValue(),
|
||||
onAlphaChangeListener = { alpha ->
|
||||
if (activity?.isDarkTheme() == true) {
|
||||
Preferences.clockTextAlphaDark = alpha.toHexValue()
|
||||
} else {
|
||||
Preferences.clockTextAlpha = alpha.toHexValue()
|
||||
}
|
||||
}
|
||||
).show()
|
||||
}
|
||||
}
|
||||
|
||||
action_clock_bottom_margin_size.setOnClickListener {
|
||||
if (Preferences.showClock) {
|
||||
BottomSheetMenu<Int>(
|
||||
requireContext(),
|
||||
header = getString(R.string.settings_clock_bottom_margin_title)
|
||||
).setSelectedValue(Preferences.clockBottomMargin)
|
||||
.addItem(
|
||||
getString(R.string.settings_clock_bottom_margin_subtitle_none),
|
||||
Constants.ClockBottomMargin.NONE.value
|
||||
)
|
||||
.addItem(
|
||||
getString(R.string.settings_clock_bottom_margin_subtitle_small),
|
||||
Constants.ClockBottomMargin.SMALL.value
|
||||
)
|
||||
.addItem(
|
||||
getString(R.string.settings_clock_bottom_margin_subtitle_medium),
|
||||
Constants.ClockBottomMargin.MEDIUM.value
|
||||
)
|
||||
.addItem(
|
||||
getString(R.string.settings_clock_bottom_margin_subtitle_large),
|
||||
Constants.ClockBottomMargin.LARGE.value
|
||||
)
|
||||
.addOnSelectItemListener { value ->
|
||||
Preferences.clockBottomMargin = value
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
action_clock_app.setOnClickListener {
|
||||
if (Preferences.showClock) {
|
||||
if (Preferences.showClock) {
|
||||
startActivityForResult(
|
||||
Intent(requireContext(), ChooseApplicationActivity::class.java),
|
||||
RequestCode.CLOCK_APP_REQUEST_CODE.code
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (resultCode == Activity.RESULT_OK && requestCode == RequestCode.CLOCK_APP_REQUEST_CODE.code) {
|
||||
Preferences.bulk {
|
||||
clockAppName = data?.getStringExtra(Constants.RESULT_APP_NAME) ?: getString(R.string.default_clock_app)
|
||||
clockAppPackage = data?.getStringExtra(Constants.RESULT_APP_PACKAGE) ?: ""
|
||||
}
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
binding.is24Format = DateFormat.is24HourFormat(requireContext())
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||
scrollView.isScrollable = false
|
||||
callback.invoke()
|
||||
lifecycleScope.launch {
|
||||
delay(200)
|
||||
scrollView.isScrollable = true
|
||||
}
|
||||
}
|
||||
}
|
@ -1,535 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.fragments
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.graphics.Typeface
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.core.provider.FontRequest
|
||||
import androidx.core.provider.FontsContractCompat
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.chibatching.kotpref.blockingBulk
|
||||
import com.chibatching.kotpref.bulk
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||
import com.tommasoberlose.anotherwidget.databinding.FragmentGeneralSettingsBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.global.RequestCode
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toHexValue
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
||||
import com.tommasoberlose.anotherwidget.helpers.DateHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.WidgetHelper
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.CustomDateActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.CustomFontActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||
import kotlinx.android.synthetic.main.fragment_clock_settings.*
|
||||
import kotlinx.android.synthetic.main.fragment_general_settings.*
|
||||
import kotlinx.android.synthetic.main.fragment_general_settings.scrollView
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.*
|
||||
|
||||
|
||||
class GeneralTabFragment : Fragment() {
|
||||
|
||||
companion object {
|
||||
fun newInstance() = GeneralTabFragment()
|
||||
}
|
||||
|
||||
private lateinit var viewModel: MainViewModel
|
||||
private lateinit var colors: IntArray
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
|
||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||
val binding = DataBindingUtil.inflate<FragmentGeneralSettingsBinding>(inflater, R.layout.fragment_general_settings, container, false)
|
||||
|
||||
subscribeUi(viewModel)
|
||||
|
||||
binding.lifecycleOwner = this
|
||||
binding.viewModel = viewModel
|
||||
binding.isDarkModeEnabled = activity?.isDarkTheme() == true
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
|
||||
show_dividers_toggle.isChecked = Preferences.showDividers
|
||||
|
||||
setupListener()
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val lazyColors = requireContext().resources.getIntArray(R.array.material_colors)
|
||||
withContext(Dispatchers.Main) {
|
||||
colors = lazyColors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
private fun subscribeUi(
|
||||
viewModel: MainViewModel
|
||||
) {
|
||||
|
||||
viewModel.textMainSize.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
main_text_size_label?.text = String.format("%.0fsp", it)
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.textSecondSize.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
second_text_size_label?.text = String.format("%.0fsp", it)
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.textGlobalColor.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
if (Preferences.textGlobalAlpha == "00") {
|
||||
font_color_label?.text = getString(R.string.transparent)
|
||||
} else {
|
||||
font_color_label?.text =
|
||||
"#%s".format(Integer.toHexString(ColorHelper.getFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.textGlobalColorDark.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
if (Preferences.textGlobalAlphaDark == "00") {
|
||||
font_color_label?.text = getString(R.string.transparent)
|
||||
} else {
|
||||
font_color_label?.text =
|
||||
"#%s".format(Integer.toHexString(ColorHelper.getFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.textGlobalAlpha.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
if (Preferences.textGlobalAlpha == "00") {
|
||||
font_color_label?.text = getString(R.string.transparent)
|
||||
} else {
|
||||
font_color_label?.text =
|
||||
"#%s".format(Integer.toHexString(ColorHelper.getFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.textGlobalAlphaDark.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
if (Preferences.textGlobalAlphaDark == "00") {
|
||||
font_color_label?.text = getString(R.string.transparent)
|
||||
} else {
|
||||
font_color_label?.text =
|
||||
"#%s".format(Integer.toHexString(ColorHelper.getFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.textSecondaryColor.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
if (Preferences.textSecondaryAlpha == "00") {
|
||||
secondary_font_color_label?.text = getString(R.string.transparent)
|
||||
} else {
|
||||
secondary_font_color_label?.text =
|
||||
"#%s".format(Integer.toHexString(ColorHelper.getSecondaryFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.textSecondaryColorDark.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
if (Preferences.textSecondaryAlphaDark == "00") {
|
||||
secondary_font_color_label?.text = getString(R.string.transparent)
|
||||
} else {
|
||||
secondary_font_color_label?.text =
|
||||
"#%s".format(Integer.toHexString(ColorHelper.getSecondaryFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.textSecondaryAlpha.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
if (Preferences.textSecondaryAlpha == "00") {
|
||||
secondary_font_color_label?.text = getString(R.string.transparent)
|
||||
} else {
|
||||
secondary_font_color_label?.text =
|
||||
"#%s".format(Integer.toHexString(ColorHelper.getSecondaryFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.textSecondaryAlphaDark.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
if (Preferences.textSecondaryAlphaDark == "00") {
|
||||
secondary_font_color_label?.text = getString(R.string.transparent)
|
||||
} else {
|
||||
secondary_font_color_label?.text =
|
||||
"#%s".format(Integer.toHexString(ColorHelper.getSecondaryFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.secondRowTopMargin.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
second_row_top_margin_label?.text = when (it) {
|
||||
Constants.SecondRowTopMargin.NONE.value -> getString(R.string.settings_clock_bottom_margin_subtitle_none)
|
||||
Constants.SecondRowTopMargin.SMALL.value -> getString(R.string.settings_clock_bottom_margin_subtitle_small)
|
||||
Constants.SecondRowTopMargin.LARGE.value -> getString(R.string.settings_clock_bottom_margin_subtitle_large)
|
||||
else -> getString(R.string.settings_clock_bottom_margin_subtitle_medium)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.backgroundCardColor.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
if (Preferences.backgroundCardAlpha == "00") {
|
||||
background_color_label?.text = getString(R.string.transparent)
|
||||
} else {
|
||||
background_color_label?.text =
|
||||
"#%s".format(Integer.toHexString(ColorHelper.getBackgroundColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.backgroundCardColorDark.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
if (Preferences.backgroundCardAlphaDark == "00") {
|
||||
background_color_label?.text = getString(R.string.transparent)
|
||||
} else {
|
||||
background_color_label?.text =
|
||||
"#%s".format(Integer.toHexString(ColorHelper.getBackgroundColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.backgroundCardAlpha.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
if (Preferences.backgroundCardAlpha == "00") {
|
||||
background_color_label?.text = getString(R.string.transparent)
|
||||
} else {
|
||||
background_color_label?.text =
|
||||
"#%s".format(Integer.toHexString(ColorHelper.getBackgroundColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.backgroundCardAlphaDark.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
if (Preferences.backgroundCardAlphaDark == "00") {
|
||||
background_color_label?.text = getString(R.string.transparent)
|
||||
} else {
|
||||
background_color_label?.text =
|
||||
"#%s".format(Integer.toHexString(ColorHelper.getBackgroundColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.textShadow.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
if (activity?.isDarkTheme() != true) {
|
||||
text_shadow_label?.text =
|
||||
getString(SettingsStringHelper.getTextShadowString(it))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.textShadowDark.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
if (activity?.isDarkTheme() == true) {
|
||||
text_shadow_label?.text =
|
||||
getString(SettingsStringHelper.getTextShadowString(it))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.dateFormat.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
date_format_label?.text = DateHelper.getDateText(requireContext(), Calendar.getInstance())
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.customFont.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
custom_font_label?.text = SettingsStringHelper.getCustomFontLabel(requireContext(), it)
|
||||
MainWidget.updateWidget(requireContext())
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.customFontFile.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
custom_font_label?.text = SettingsStringHelper.getCustomFontLabel(requireContext(), Preferences.customFont)
|
||||
MainWidget.updateWidget(requireContext())
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.customFontName.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
custom_font_label?.text = SettingsStringHelper.getCustomFontLabel(requireContext(), Preferences.customFont)
|
||||
MainWidget.updateWidget(requireContext())
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.customFontVariant.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
custom_font_label?.text = SettingsStringHelper.getCustomFontLabel(requireContext(), Preferences.customFont)
|
||||
MainWidget.updateWidget(requireContext())
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.showDividers.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
show_dividers_label?.text =
|
||||
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
action_main_text_size.setOnClickListener {
|
||||
val dialog = BottomSheetMenu<Float>(requireContext(), header = getString(R.string.title_main_text_size)).setSelectedValue(Preferences.textMainSize)
|
||||
(40 downTo 10).filter { it % 2 == 0 }.forEach {
|
||||
dialog.addItem("${it}sp", it.toFloat())
|
||||
}
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
Preferences.textMainSize = value
|
||||
}.show()
|
||||
}
|
||||
|
||||
action_second_text_size.setOnClickListener {
|
||||
val dialog = BottomSheetMenu<Float>(requireContext(), header = getString(R.string.title_second_text_size)).setSelectedValue(Preferences.textSecondSize)
|
||||
(40 downTo 10).filter { it % 2 == 0 }.forEach {
|
||||
dialog.addItem("${it}sp", it.toFloat())
|
||||
}
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
Preferences.textSecondSize = value
|
||||
}.show()
|
||||
}
|
||||
|
||||
action_font_color.setOnClickListener {
|
||||
BottomSheetColorPicker(requireContext(),
|
||||
colors = colors,
|
||||
header = getString(R.string.settings_font_color_title),
|
||||
getSelected = { ColorHelper.getFontColorRgb(activity?.isDarkTheme() == true) },
|
||||
onColorSelected = { color: Int ->
|
||||
val colorString = Integer.toHexString(color)
|
||||
if (activity?.isDarkTheme() == true) {
|
||||
Preferences.textGlobalColorDark = "#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||
} else {
|
||||
Preferences.textGlobalColor = "#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||
}
|
||||
},
|
||||
showAlphaSelector = true,
|
||||
alpha = if (activity?.isDarkTheme() == true) Preferences.textGlobalAlphaDark.toIntValue() else Preferences.textGlobalAlpha.toIntValue(),
|
||||
onAlphaChangeListener = { alpha ->
|
||||
if (activity?.isDarkTheme() == true) {
|
||||
Preferences.textGlobalAlphaDark = alpha.toHexValue()
|
||||
} else {
|
||||
Preferences.textGlobalAlpha = alpha.toHexValue()
|
||||
}
|
||||
}
|
||||
).show()
|
||||
}
|
||||
|
||||
action_secondary_font_color.setOnClickListener {
|
||||
BottomSheetColorPicker(requireContext(),
|
||||
colors = colors,
|
||||
header = getString(R.string.settings_secondary_font_color_title),
|
||||
getSelected = { ColorHelper.getSecondaryFontColorRgb(activity?.isDarkTheme() == true) },
|
||||
onColorSelected = { color: Int ->
|
||||
val colorString = Integer.toHexString(color)
|
||||
if (activity?.isDarkTheme() == true) {
|
||||
Preferences.textSecondaryColorDark =
|
||||
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||
} else {
|
||||
Preferences.textSecondaryColor =
|
||||
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||
}
|
||||
},
|
||||
showAlphaSelector = true,
|
||||
alpha = if (activity?.isDarkTheme() == true) Preferences.textSecondaryAlphaDark.toIntValue() else Preferences.textSecondaryAlpha.toIntValue(),
|
||||
onAlphaChangeListener = { alpha ->
|
||||
if (activity?.isDarkTheme() == true) {
|
||||
Preferences.textSecondaryAlphaDark = alpha.toHexValue()
|
||||
} else {
|
||||
Preferences.textSecondaryAlpha = alpha.toHexValue()
|
||||
}
|
||||
}
|
||||
).show()
|
||||
}
|
||||
|
||||
action_second_row_top_margin_size.setOnClickListener {
|
||||
BottomSheetMenu<Int>(
|
||||
requireContext(),
|
||||
header = getString(R.string.settings_secondary_row_top_margin_title)
|
||||
).setSelectedValue(Preferences.secondRowTopMargin)
|
||||
.addItem(
|
||||
getString(R.string.settings_clock_bottom_margin_subtitle_none),
|
||||
Constants.SecondRowTopMargin.NONE.value
|
||||
)
|
||||
.addItem(
|
||||
getString(R.string.settings_clock_bottom_margin_subtitle_small),
|
||||
Constants.SecondRowTopMargin.SMALL.value
|
||||
)
|
||||
.addItem(
|
||||
getString(R.string.settings_clock_bottom_margin_subtitle_medium),
|
||||
Constants.SecondRowTopMargin.MEDIUM.value
|
||||
)
|
||||
.addItem(
|
||||
getString(R.string.settings_clock_bottom_margin_subtitle_large),
|
||||
Constants.SecondRowTopMargin.LARGE.value
|
||||
)
|
||||
.addOnSelectItemListener { value ->
|
||||
Preferences.secondRowTopMargin = value
|
||||
}.show()
|
||||
}
|
||||
|
||||
action_date_format.setOnClickListener {
|
||||
val now = Calendar.getInstance()
|
||||
val dialog = BottomSheetMenu<String>(requireContext(), header = getString(R.string.settings_date_format_title)).setSelectedValue(Preferences.dateFormat)
|
||||
|
||||
dialog.addItem(DateHelper.getDefaultDateText(requireContext(), now), "")
|
||||
if (Preferences.dateFormat != "") {
|
||||
dialog.addItem(DateHelper.getDateText(requireContext(), now), Preferences.dateFormat)
|
||||
}
|
||||
dialog.addItem(getString(R.string.custom_date_format), "-")
|
||||
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
when (value) {
|
||||
"-" -> {
|
||||
startActivity(Intent(requireContext(), CustomDateActivity::class.java))
|
||||
}
|
||||
"" -> {
|
||||
Preferences.blockingBulk {
|
||||
isDateCapitalize = false
|
||||
isDateUppercase = false
|
||||
}
|
||||
Preferences.dateFormat = value
|
||||
}
|
||||
else -> {
|
||||
Preferences.dateFormat = value
|
||||
}
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
|
||||
action_background_color.setOnClickListener {
|
||||
BottomSheetColorPicker(requireContext(),
|
||||
colors = colors,
|
||||
header = getString(R.string.settings_background_color_title),
|
||||
getSelected = { ColorHelper.getBackgroundColorRgb(activity?.isDarkTheme() == true) },
|
||||
onColorSelected = { color: Int ->
|
||||
val colorString = Integer.toHexString(color)
|
||||
if (activity?.isDarkTheme() == true) {
|
||||
Preferences.backgroundCardColorDark =
|
||||
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||
} else {
|
||||
Preferences.backgroundCardColor =
|
||||
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||
}
|
||||
},
|
||||
showAlphaSelector = true,
|
||||
alpha = if (activity?.isDarkTheme() == true) Preferences.backgroundCardAlphaDark.toIntValue() else Preferences.backgroundCardAlpha.toIntValue(),
|
||||
onAlphaChangeListener = { alpha ->
|
||||
if (activity?.isDarkTheme() == true) {
|
||||
Preferences.backgroundCardAlphaDark = alpha.toHexValue()
|
||||
} else {
|
||||
Preferences.backgroundCardAlpha = alpha.toHexValue()
|
||||
}
|
||||
}
|
||||
).show()
|
||||
}
|
||||
|
||||
action_text_shadow.setOnClickListener {
|
||||
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.title_text_shadow)).setSelectedValue(if (activity?.isDarkTheme() == true) Preferences.textShadowDark else Preferences.textShadow)
|
||||
(2 downTo 0).forEach {
|
||||
dialog.addItem(getString(SettingsStringHelper.getTextShadowString(it)), it)
|
||||
}
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
if (activity?.isDarkTheme() == true) {
|
||||
Preferences.textShadowDark = value
|
||||
} else {
|
||||
Preferences.textShadow = value
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
|
||||
action_custom_font.setOnClickListener {
|
||||
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_custom_font_title)).setSelectedValue(Preferences.customFont)
|
||||
dialog.addItem(SettingsStringHelper.getCustomFontLabel(requireContext(), 0), 0)
|
||||
|
||||
if (Preferences.customFont == Constants.CUSTOM_FONT_GOOGLE_SANS) {
|
||||
dialog.addItem(SettingsStringHelper.getCustomFontLabel(requireContext(), Constants.CUSTOM_FONT_GOOGLE_SANS), Constants.CUSTOM_FONT_GOOGLE_SANS)
|
||||
}
|
||||
|
||||
if (Preferences.customFontFile != "") {
|
||||
dialog.addItem(SettingsStringHelper.getCustomFontLabel(requireContext(), Preferences.customFont), Constants.CUSTOM_FONT_DOWNLOADED)
|
||||
}
|
||||
dialog.addItem(getString(R.string.action_custom_font_to_search), Constants.CUSTOM_FONT_DOWNLOAD_NEW)
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
if (value == Constants.CUSTOM_FONT_DOWNLOAD_NEW) {
|
||||
startActivityForResult(
|
||||
Intent(requireContext(), CustomFontActivity::class.java),
|
||||
RequestCode.CUSTOM_FONT_CHOOSER_REQUEST_CODE.code
|
||||
)
|
||||
} else if (value != Constants.CUSTOM_FONT_DOWNLOADED) {
|
||||
Preferences.bulk {
|
||||
customFont = value
|
||||
customFontFile = ""
|
||||
customFontName = ""
|
||||
customFontVariant = ""
|
||||
}
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
|
||||
action_show_dividers.setOnClickListener {
|
||||
show_dividers_toggle.isChecked = !show_dividers_toggle.isChecked
|
||||
}
|
||||
|
||||
show_dividers_toggle.setOnCheckedChangeListener { _, isChecked ->
|
||||
Preferences.showDividers = isChecked
|
||||
}
|
||||
}
|
||||
|
||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||
scrollView.isScrollable = false
|
||||
callback.invoke()
|
||||
lifecycleScope.launch {
|
||||
delay(200)
|
||||
scrollView.isScrollable = true
|
||||
}
|
||||
}
|
||||
}
|
@ -1,64 +1,62 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.fragments
|
||||
|
||||
import android.Manifest
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Log
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.core.animation.addListener
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.Navigation
|
||||
import com.google.android.material.badge.BadgeDrawable
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
|
||||
import com.tommasoberlose.anotherwidget.databinding.FragmentAppMainBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.*
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
|
||||
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.adapters.ViewPagerAdapter
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||
import com.tommasoberlose.anotherwidget.ui.widgets.StandardWidget
|
||||
import com.tommasoberlose.anotherwidget.utils.*
|
||||
import kotlinx.android.synthetic.main.fragment_app_main.*
|
||||
import kotlinx.android.synthetic.main.the_widget_sans.*
|
||||
import kotlinx.coroutines.*
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
class MainFragment : Fragment() {
|
||||
|
||||
companion object {
|
||||
fun newInstance() = MainFragment()
|
||||
private const val PREVIEW_BASE_HEIGHT = 120
|
||||
private val PREVIEW_BASE_HEIGHT: Int
|
||||
get() = if (Preferences.widgetAlign == Constants.WidgetAlign.CENTER.rawValue) 120 else 180
|
||||
}
|
||||
|
||||
private lateinit var viewModel: MainViewModel
|
||||
private lateinit var binding: FragmentAppMainBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.Y, true)
|
||||
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Y, false)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
@ -66,41 +64,7 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||
return inflater.inflate(R.layout.fragment_app_main, container, false)
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
|
||||
// Viewpager
|
||||
pager.adapter = ViewPagerAdapter(requireActivity())
|
||||
pager.offscreenPageLimit = 4
|
||||
TabLayoutMediator(tabs, pager) { tab, position ->
|
||||
tab.text = when (position) {
|
||||
0 -> getString(R.string.settings_general_title)
|
||||
1 -> getString(R.string.settings_calendar_title)
|
||||
2 -> getString(R.string.settings_weather_title)
|
||||
3 -> getString(R.string.settings_clock_title)
|
||||
4 -> getString(R.string.settings_at_a_glance_title)
|
||||
else -> ""
|
||||
}
|
||||
}.attach()
|
||||
|
||||
// Init clock
|
||||
if (Preferences.showClock) {
|
||||
time.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
|
||||
time.setTextSize(TypedValue.COMPLEX_UNIT_SP,
|
||||
Preferences.clockTextSize.toPixel(requireContext()))
|
||||
time_am_pm.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
|
||||
time_am_pm.setTextSize(TypedValue.COMPLEX_UNIT_SP,
|
||||
Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2)
|
||||
}
|
||||
time_container.isVisible = Preferences.showClock
|
||||
|
||||
preview.layoutParams = preview.layoutParams.apply {
|
||||
height = PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(requireContext()) else 0
|
||||
}
|
||||
subscribeUi(viewModel)
|
||||
binding = FragmentAppMainBinding.inflate(inflater)
|
||||
|
||||
// Warnings
|
||||
if (getString(R.string.xiaomi_manufacturer).equals(Build.MANUFACTURER, ignoreCase = true) && Preferences.showXiaomiWarning) {
|
||||
@ -117,293 +81,327 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
private var uiJob: Job? = null
|
||||
|
||||
private fun updateUI() {
|
||||
uiJob?.cancel()
|
||||
|
||||
preview?.clearAnimation()
|
||||
time_container?.clearAnimation()
|
||||
|
||||
if (Preferences.showPreview) {
|
||||
preview?.setCardBackgroundColor(
|
||||
ContextCompat.getColor(
|
||||
requireContext(),
|
||||
if (ColorHelper.getFontColor(activity?.isDarkTheme() == true)
|
||||
.isColorDark()
|
||||
) android.R.color.white else R.color.colorAccent
|
||||
)
|
||||
)
|
||||
widget_shape_background?.setImageDrawable(
|
||||
BitmapHelper.getTintedDrawable(
|
||||
requireContext(),
|
||||
R.drawable.card_background,
|
||||
ColorHelper.getBackgroundColor(activity?.isDarkTheme() == true)
|
||||
)
|
||||
)
|
||||
WidgetHelper.runWithCustomTypeface(requireContext()) { typeface ->
|
||||
uiJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||
val generatedView = MainWidget.generateWidgetView(requireContext(), typeface)
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
generatedView.measure(0, 0)
|
||||
preview?.measure(0, 0)
|
||||
}
|
||||
|
||||
val bitmap = if (preview != null) {
|
||||
BitmapHelper.getBitmapFromView(
|
||||
generatedView,
|
||||
if (preview.width > 0) preview.width else generatedView.measuredWidth,
|
||||
generatedView.measuredHeight
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
// Clock
|
||||
time?.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
|
||||
time_am_pm?.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
|
||||
time?.setTextSize(
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
Preferences.clockTextSize.toPixel(requireContext())
|
||||
)
|
||||
time_am_pm?.setTextSize(
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2
|
||||
)
|
||||
time_am_pm?.isVisible = Preferences.showAMPMIndicator
|
||||
|
||||
// Clock bottom margin
|
||||
clock_bottom_margin_none?.isVisible =
|
||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.value
|
||||
clock_bottom_margin_small?.isVisible =
|
||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.SMALL.value
|
||||
clock_bottom_margin_medium?.isVisible =
|
||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.MEDIUM.value
|
||||
clock_bottom_margin_large?.isVisible =
|
||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.LARGE.value
|
||||
|
||||
if ((Preferences.showClock && (time?.alpha ?: 1f < 1f)) || (!Preferences.showClock && (time?.alpha ?: 0f > 0f))) {
|
||||
if (Preferences.showClock) {
|
||||
time_container?.layoutParams = time_container.layoutParams.apply {
|
||||
height = RelativeLayout.LayoutParams.WRAP_CONTENT
|
||||
}
|
||||
time_container?.measure(0, 0)
|
||||
}
|
||||
val initialHeight = time_container?.measuredHeight ?: 0
|
||||
ValueAnimator.ofFloat(
|
||||
if (Preferences.showClock) 0f else 1f,
|
||||
if (Preferences.showClock) 1f else 0f
|
||||
).apply {
|
||||
duration = 500L
|
||||
addUpdateListener {
|
||||
val animatedValue = animatedValue as Float
|
||||
time_container?.layoutParams =
|
||||
time_container.layoutParams.apply {
|
||||
height = (initialHeight * animatedValue).toInt()
|
||||
}
|
||||
time?.alpha = animatedValue
|
||||
}
|
||||
addListener(
|
||||
onStart = {
|
||||
if (Preferences.showClock) {
|
||||
time_container?.isVisible = true
|
||||
}
|
||||
},
|
||||
onEnd = {
|
||||
if (!Preferences.showClock) {
|
||||
time_container?.isVisible = false
|
||||
}
|
||||
}
|
||||
)
|
||||
}.start()
|
||||
|
||||
if (preview != null) {
|
||||
ValueAnimator.ofInt(
|
||||
preview.height,
|
||||
PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
|
||||
requireContext()
|
||||
) else 0
|
||||
).apply {
|
||||
duration = 500L
|
||||
addUpdateListener {
|
||||
if (preview != null) {
|
||||
val animatedValue = animatedValue as Int
|
||||
val layoutParams = preview.layoutParams
|
||||
layoutParams.height = animatedValue
|
||||
preview.layoutParams = layoutParams
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
} else {
|
||||
time_container?.layoutParams = time_container.layoutParams.apply {
|
||||
height = RelativeLayout.LayoutParams.WRAP_CONTENT
|
||||
}
|
||||
time_container?.measure(0, 0)
|
||||
}
|
||||
|
||||
if (preview != null && preview.height == 0) {
|
||||
ValueAnimator.ofInt(
|
||||
preview.height,
|
||||
PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
|
||||
requireContext()
|
||||
) else 0
|
||||
).apply {
|
||||
duration = 300L
|
||||
addUpdateListener {
|
||||
if (preview != null) {
|
||||
val animatedValue = animatedValue as Int
|
||||
val layoutParams = preview.layoutParams
|
||||
layoutParams.height = animatedValue
|
||||
preview?.layoutParams = layoutParams
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
widget_loader?.animate()?.scaleX(0f)?.scaleY(0f)?.alpha(0f)
|
||||
?.setDuration(200L)?.start()
|
||||
bitmap_container?.apply {
|
||||
setImageBitmap(bitmap)
|
||||
scaleX = 0.9f
|
||||
scaleY = 0.9f
|
||||
}
|
||||
widget?.animate()?.alpha(1f)?.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (preview != null) {
|
||||
ValueAnimator.ofInt(
|
||||
preview.height,
|
||||
0
|
||||
).apply {
|
||||
duration = 300L
|
||||
addUpdateListener {
|
||||
if (preview != null) {
|
||||
val animatedValue = animatedValue as Int
|
||||
val layoutParams = preview.layoutParams
|
||||
layoutParams.height = animatedValue
|
||||
preview.layoutParams = layoutParams
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
val navHost = childFragmentManager.findFragmentById(R.id.settings_fragment) as? NavHostFragment?
|
||||
navHost?.navController?.addOnDestinationChangedListener { controller, destination, _ ->
|
||||
val show = destination.id != R.id.tabSelectorFragment
|
||||
binding.actionBack.animate().alpha(if (show) 1f else 0f).setDuration(200).translationX((if (show) 0f else 4f).convertDpToPixel(requireContext())).start()
|
||||
binding.actionBack.setOnSingleClickListener {
|
||||
controller.navigateUp()
|
||||
}
|
||||
binding.actionBack.isClickable = show
|
||||
binding.actionBack.isFocusable = show
|
||||
binding.actionSettings.animate().alpha(if (!show) 1f else 0f).setDuration(200).translationX((if (!show) 0f else -4f).convertDpToPixel(requireContext())).start()
|
||||
binding.actionSettings.isClickable = !show
|
||||
binding.actionSettings.isFocusable = !show
|
||||
binding.fragmentTitle.text = if (show) destination.label.toString() else getString(R.string.app_name)
|
||||
}
|
||||
|
||||
showErrorBadge()
|
||||
binding.actionSettings.setOnSingleClickListener {
|
||||
Navigation.findNavController(it).navigate(R.id.action_appMainFragment_to_appSettingsFragment,)
|
||||
}
|
||||
|
||||
binding.preview.layoutParams = binding.preview.layoutParams.apply {
|
||||
height = PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
|
||||
requireContext()
|
||||
) else 0
|
||||
}
|
||||
|
||||
subscribeUi(viewModel)
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
private fun subscribeUi(viewModel: MainViewModel) {
|
||||
viewModel.showWallpaper.observe(viewLifecycleOwner, Observer {
|
||||
activity?.let { act ->
|
||||
val wallpaper = act.getCurrentWallpaper()
|
||||
widget_bg.setImageDrawable(if (it) wallpaper else null)
|
||||
viewModel.showWallpaper.observe(viewLifecycleOwner) {
|
||||
if (it) {
|
||||
val wallpaper = requireActivity().getCurrentWallpaper()
|
||||
binding.widgetBg.setImageDrawable(if (it) wallpaper else null)
|
||||
if (wallpaper != null) {
|
||||
widget_bg.layoutParams =
|
||||
(widget_bg.layoutParams as ViewGroup.MarginLayoutParams).apply {
|
||||
binding.widgetBg.layoutParams =
|
||||
(binding.widgetBg.layoutParams as ViewGroup.MarginLayoutParams).apply {
|
||||
|
||||
val metrics = DisplayMetrics()
|
||||
act.windowManager.defaultDisplay.getMetrics(metrics)
|
||||
|
||||
val dimensions: Pair<Int, Int> = if (wallpaper.intrinsicWidth >= wallpaper.intrinsicHeight) {
|
||||
metrics.heightPixels to (wallpaper.intrinsicWidth) * metrics.heightPixels / (wallpaper.intrinsicHeight)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
val display = requireActivity().display
|
||||
display?.getRealMetrics(metrics)
|
||||
} else {
|
||||
metrics.widthPixels to (wallpaper.intrinsicHeight) * metrics.widthPixels / (wallpaper.intrinsicWidth)
|
||||
@Suppress("DEPRECATION")
|
||||
val display = requireActivity().windowManager.defaultDisplay
|
||||
@Suppress("DEPRECATION")
|
||||
display.getMetrics(metrics)
|
||||
}
|
||||
|
||||
setMargins(
|
||||
if (dimensions.first >= dimensions.second) (-80).toPixel(requireContext()) else 0,
|
||||
(-80).toPixel(requireContext()), 0, 0
|
||||
val dimensions: Pair<Int, Int> =
|
||||
if (wallpaper.intrinsicWidth >= wallpaper.intrinsicHeight) {
|
||||
metrics.heightPixels to (wallpaper.intrinsicWidth) * metrics.heightPixels / (wallpaper.intrinsicHeight)
|
||||
} else {
|
||||
metrics.widthPixels to (wallpaper.intrinsicHeight) * metrics.widthPixels / (wallpaper.intrinsicWidth)
|
||||
}
|
||||
|
||||
setMargins(0, (-80).toPixel(requireContext()), 0, 0
|
||||
)
|
||||
|
||||
width = dimensions.first
|
||||
height = dimensions.second
|
||||
}
|
||||
}
|
||||
} else {
|
||||
binding.widgetBg.setImageDrawable(null)
|
||||
}
|
||||
})
|
||||
|
||||
logo.setOnClickListener {
|
||||
// startActivity(Intent(this, SupportDevActivity::class.java))
|
||||
}
|
||||
|
||||
action_settings.setOnClickListener {
|
||||
Navigation.findNavController(it).navigate(R.id.action_appMainFragment_to_appSettingsFragment)
|
||||
viewModel.fragmentScrollY.observe(viewLifecycleOwner) {
|
||||
binding.toolbar.cardElevation = if (it > 0) 24f else 0f
|
||||
}
|
||||
|
||||
viewModel.widgetAlign.observe(viewLifecycleOwner) {
|
||||
updatePreviewVisibility()
|
||||
lifecycleScope.launch {
|
||||
delay(350)
|
||||
updateClock()
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.showPreview.observe(viewLifecycleOwner) {
|
||||
updatePreviewVisibility()
|
||||
}
|
||||
|
||||
viewModel.clockPreferencesUpdate.observe(viewLifecycleOwner) {
|
||||
updateClock()
|
||||
}
|
||||
|
||||
viewModel.widgetPreferencesUpdate.observe(viewLifecycleOwner) {
|
||||
onUpdateUiEvent(null)
|
||||
}
|
||||
|
||||
viewModel.showClock.observe(viewLifecycleOwner) {
|
||||
updateClockVisibility(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showErrorBadge() {
|
||||
// Calendar error indicator
|
||||
tabs?.getTabAt(1)?.orCreateBadge?.apply {
|
||||
backgroundColor = ContextCompat.getColor(requireContext(), R.color.errorColorText)
|
||||
badgeGravity = BadgeDrawable.TOP_END
|
||||
}?.isVisible = Preferences.showEvents && activity?.checkGrantedPermission(Manifest.permission.READ_CALENDAR) != true
|
||||
private var uiJob: Job? = null
|
||||
|
||||
// Weather error indicator
|
||||
tabs?.getTabAt(2)?.orCreateBadge?.apply {
|
||||
backgroundColor = ContextCompat.getColor(requireContext(), R.color.errorColorText)
|
||||
badgeGravity = BadgeDrawable.TOP_END
|
||||
}?.isVisible = if (Preferences.showWeather) {
|
||||
(WeatherHelper.isKeyRequired() && WeatherHelper.getApiKey() == "")
|
||||
|| (Preferences.customLocationAdd == "" && activity?.checkGrantedPermission(
|
||||
Manifest.permission.ACCESS_FINE_LOCATION
|
||||
) != true)
|
||||
|| (Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-")
|
||||
|| (Preferences.weatherProviderLocationError != "")
|
||||
private fun updateUI() {
|
||||
if (Preferences.showPreview) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val bgColor: Int = ContextCompat.getColor(
|
||||
requireContext(),
|
||||
if (ColorHelper.getFontColor(requireActivity().isDarkTheme())
|
||||
.isColorDark()
|
||||
) android.R.color.white else R.color.colorAccent
|
||||
)
|
||||
|
||||
val wallpaperDrawable = BitmapHelper.getTintedDrawable(
|
||||
requireContext(),
|
||||
R.drawable.card_background,
|
||||
ColorHelper.getBackgroundColor(requireActivity().isDarkTheme())
|
||||
)
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.preview.setCardBackgroundColor(bgColor)
|
||||
binding.widgetDetail.widgetShapeBackground.setImageDrawable(wallpaperDrawable)
|
||||
}
|
||||
}
|
||||
|
||||
WidgetHelper.runWithCustomTypeface(requireContext()) { typeface ->
|
||||
uiJob?.cancel()
|
||||
uiJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||
val generatedView = MainWidget.getWidgetView(requireContext(), typeface)?.root
|
||||
|
||||
if (generatedView != null) {
|
||||
withContext(Dispatchers.Main) {
|
||||
|
||||
binding.widgetDetail.content.removeAllViews()
|
||||
val container = LinearLayout(requireContext()).apply {
|
||||
layoutParams = LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
}
|
||||
container.gravity = when (Preferences.widgetAlign) {
|
||||
Constants.WidgetAlign.CENTER.rawValue -> Gravity.CENTER_HORIZONTAL
|
||||
Constants.WidgetAlign.LEFT.rawValue -> Gravity.START
|
||||
Constants.WidgetAlign.RIGHT.rawValue -> Gravity.END
|
||||
else -> Gravity.NO_GRAVITY
|
||||
}
|
||||
container.addView(generatedView)
|
||||
binding.widgetDetail.content.addView(container)
|
||||
|
||||
binding.widgetLoader.animate().scaleX(0f).scaleY(0f).alpha(0f)
|
||||
.setDuration(200L).start()
|
||||
binding.widget.animate().alpha(1f).start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateClock() {
|
||||
// Clock
|
||||
binding.widgetDetail.time.setTextColor(ColorHelper.getClockFontColor(requireActivity().isDarkTheme()))
|
||||
binding.widgetDetail.timeAmPm.setTextColor(ColorHelper.getClockFontColor(requireActivity().isDarkTheme()))
|
||||
binding.widgetDetail.time.setTextSize(
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
Preferences.clockTextSize.toPixel(requireContext())
|
||||
)
|
||||
binding.widgetDetail.timeAmPm.setTextSize(
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2
|
||||
)
|
||||
binding.widgetDetail.timeAmPm.isVisible = Preferences.showAMPMIndicator
|
||||
|
||||
// Timezones
|
||||
if (Preferences.altTimezoneId != "" && Preferences.altTimezoneLabel != "") {
|
||||
// Clock
|
||||
binding.widgetDetail.altTimezoneTime.timeZone = Preferences.altTimezoneId
|
||||
binding.widgetDetail.altTimezoneTimeAmPm.timeZone = Preferences.altTimezoneId
|
||||
binding.widgetDetail.altTimezoneLabel.text = Preferences.altTimezoneLabel
|
||||
binding.widgetDetail.altTimezoneTime.setTextColor(ColorHelper.getClockFontColor(requireActivity().isDarkTheme()))
|
||||
binding.widgetDetail.altTimezoneTimeAmPm.setTextColor(ColorHelper.getClockFontColor(requireActivity().isDarkTheme()))
|
||||
binding.widgetDetail.altTimezoneLabel.setTextColor(ColorHelper.getClockFontColor(requireActivity().isDarkTheme()))
|
||||
binding.widgetDetail.altTimezoneTime.setTextSize(
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
Preferences.clockTextSize.toPixel(requireContext()) / 3
|
||||
)
|
||||
binding.widgetDetail.altTimezoneTimeAmPm.setTextSize(
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
(Preferences.clockTextSize.toPixel(requireContext()) / 3) / 5 * 2
|
||||
)
|
||||
binding.widgetDetail.altTimezoneLabel.setTextSize(
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
(Preferences.clockTextSize.toPixel(requireContext()) / 3) / 5 * 2
|
||||
)
|
||||
binding.widgetDetail.timezonesContainer.isVisible = true
|
||||
} else {
|
||||
false
|
||||
binding.widgetDetail.timezonesContainer.isVisible = false
|
||||
}
|
||||
|
||||
// Glance error indicator
|
||||
tabs?.getTabAt(4)?.orCreateBadge?.apply {
|
||||
backgroundColor = ContextCompat.getColor(requireContext(), R.color.errorColorText)
|
||||
badgeGravity = BadgeDrawable.TOP_END
|
||||
}?.isVisible = ((Preferences.showMusic || Preferences.showNotifications) && !ActiveNotificationsHelper.checkNotificationAccess(requireContext())) ||
|
||||
(Preferences.showDailySteps && !(Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || requireActivity().checkGrantedPermission(Manifest.permission.ACTIVITY_RECOGNITION))) ||
|
||||
(AlarmHelper.isAlarmProbablyWrong(requireContext())) ||
|
||||
(Preferences.showEventsAsGlanceProvider && (!Preferences.showEvents || !requireContext().checkGrantedPermission(Manifest.permission.READ_CALENDAR)))
|
||||
// Clock bottom margin
|
||||
binding.widgetDetail.clockBottomMarginNone.isVisible =
|
||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.rawValue
|
||||
binding.widgetDetail.clockBottomMarginSmall.isVisible =
|
||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.SMALL.rawValue
|
||||
binding.widgetDetail.clockBottomMarginMedium.isVisible =
|
||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.MEDIUM.rawValue
|
||||
binding.widgetDetail.clockBottomMarginLarge.isVisible =
|
||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.LARGE.rawValue
|
||||
|
||||
// Align
|
||||
binding.widgetDetail.timeContainer.layoutParams = (binding.widgetDetail.timeContainer.layoutParams as LinearLayout.LayoutParams).apply {
|
||||
gravity = when (Preferences.widgetAlign) {
|
||||
Constants.WidgetAlign.CENTER.rawValue -> Gravity.CENTER_HORIZONTAL
|
||||
Constants.WidgetAlign.LEFT.rawValue -> Gravity.START
|
||||
Constants.WidgetAlign.RIGHT.rawValue -> Gravity.END
|
||||
else -> Gravity.NO_GRAVITY
|
||||
}
|
||||
}
|
||||
if (Preferences.widgetAlign == Constants.WidgetAlign.RIGHT.rawValue) {
|
||||
with (binding.widgetDetail.timeContainer) {
|
||||
val child = getChildAt(2)
|
||||
if (child.id == R.id.timezones_container) {
|
||||
removeViewAt(2)
|
||||
child.layoutParams = (child.layoutParams as ViewGroup.MarginLayoutParams).apply {
|
||||
marginEnd = 16f.convertDpToPixel(requireContext()).toInt()
|
||||
}
|
||||
addView(child, 0)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
with (binding.widgetDetail.timeContainer) {
|
||||
val child = getChildAt(0)
|
||||
if (child.id == R.id.timezones_container) {
|
||||
removeViewAt(0)
|
||||
child.layoutParams = (child.layoutParams as ViewGroup.MarginLayoutParams).apply {
|
||||
marginEnd = 0
|
||||
}
|
||||
addView(child, 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateClockVisibility(showClock: Boolean) {
|
||||
binding.widgetDetail.timeContainer.clearAnimation()
|
||||
binding.widgetDetail.time.clearAnimation()
|
||||
|
||||
updatePreviewVisibility()
|
||||
|
||||
if (showClock) {
|
||||
binding.widgetDetail.timeContainer.layoutParams = (binding.widgetDetail.timeContainer.layoutParams as LinearLayout.LayoutParams).apply {
|
||||
height = RelativeLayout.LayoutParams.WRAP_CONTENT
|
||||
}
|
||||
binding.widgetDetail.timeContainer.measure(0, 0)
|
||||
}
|
||||
|
||||
if ((Preferences.showClock && binding.widgetDetail.time.alpha != 1f) || (!Preferences.showClock && binding.widgetDetail.time.alpha != 0f)) {
|
||||
val initialHeight = binding.widgetDetail.timeContainer.measuredHeight
|
||||
ValueAnimator.ofFloat(
|
||||
if (showClock) 0f else 1f,
|
||||
if (showClock) 1f else 0f
|
||||
).apply {
|
||||
duration = 500L
|
||||
addUpdateListener {
|
||||
val animatedValue = animatedValue as Float
|
||||
binding.widgetDetail.timeContainer.layoutParams =
|
||||
binding.widgetDetail.timeContainer.layoutParams.apply {
|
||||
height = (initialHeight * animatedValue).toInt()
|
||||
}
|
||||
binding.widgetDetail.time.alpha = animatedValue
|
||||
binding.widgetDetail.timeAmPm.alpha = animatedValue
|
||||
binding.widgetDetail.altTimezoneTime.alpha = animatedValue
|
||||
binding.widgetDetail.altTimezoneTimeAmPm.alpha = animatedValue
|
||||
binding.widgetDetail.altTimezoneLabel.alpha = animatedValue
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updatePreviewVisibility() {
|
||||
binding.preview.clearAnimation()
|
||||
if (binding.preview.layoutParams.height != (if (Preferences.showPreview) PREVIEW_BASE_HEIGHT.toPixel(requireContext()) else 0) + (if (Preferences.showClock) 100.toPixel(
|
||||
requireContext()
|
||||
) else 0)) {
|
||||
ValueAnimator.ofInt(
|
||||
binding.preview.height,
|
||||
(if (Preferences.showPreview) PREVIEW_BASE_HEIGHT.toPixel(requireContext()) else 0) + (if (Preferences.showClock) 100.toPixel(
|
||||
requireContext()
|
||||
) else 0)
|
||||
).apply {
|
||||
duration = 500L
|
||||
addUpdateListener {
|
||||
val animatedValue = animatedValue as Int
|
||||
val layoutParams = binding.preview.layoutParams
|
||||
layoutParams.height = animatedValue
|
||||
binding.preview.layoutParams = layoutParams
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
Preferences.preferences.registerOnSharedPreferenceChangeListener(this)
|
||||
EventBus.getDefault().register(this)
|
||||
showErrorBadge()
|
||||
updateUI()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
Preferences.preferences.unregisterOnSharedPreferenceChangeListener(this)
|
||||
EventBus.getDefault().unregister(this)
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
private var delayJob: Job? = null
|
||||
|
||||
override fun onSharedPreferenceChanged(preferences: SharedPreferences, p1: String) {
|
||||
delayJob?.cancel()
|
||||
delayJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||
delay(200)
|
||||
withContext(Dispatchers.Main) {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
MainWidget.updateWidget(requireContext())
|
||||
}
|
||||
|
||||
class UpdateUiMessageEvent
|
||||
class ChangeTabEvent(val page: Int)
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onMessageEvent(ignore: UpdateUiMessageEvent?) {
|
||||
fun onUpdateUiEvent(ignore: UpdateUiMessageEvent?) {
|
||||
delayJob?.cancel()
|
||||
delayJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||
delay(200)
|
||||
delay(300)
|
||||
withContext(Dispatchers.Main) {
|
||||
updateUI()
|
||||
}
|
||||
@ -411,9 +409,8 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onMessageEvent(event: ChangeTabEvent?) {
|
||||
event?.let {
|
||||
pager.setCurrentItem(event.page, true)
|
||||
}
|
||||
fun onChangeTabEvent(ignore: ChangeTabEvent) {
|
||||
val navHost = childFragmentManager.findFragmentById(R.id.settings_fragment) as? NavHostFragment?
|
||||
navHost?.navController?.navigateUp()
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
@ -15,6 +14,7 @@ import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.Navigation
|
||||
import androidx.transition.TransitionInflater
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import com.karumi.dexter.Dexter
|
||||
import com.karumi.dexter.MultiplePermissionsReport
|
||||
@ -24,19 +24,21 @@ import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
||||
import com.tommasoberlose.anotherwidget.BuildConfig
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||
import com.tommasoberlose.anotherwidget.databinding.FragmentSettingsBinding
|
||||
import com.tommasoberlose.anotherwidget.databinding.FragmentAppSettingsBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.SupportDevActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.IntegrationsActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.settings.IntegrationsActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.settings.SupportDevActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||
import com.tommasoberlose.anotherwidget.utils.ignoreExceptions
|
||||
import com.tommasoberlose.anotherwidget.utils.openURI
|
||||
import kotlinx.android.synthetic.main.fragment_settings.*
|
||||
import com.tommasoberlose.anotherwidget.utils.setOnSingleClickListener
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@ -48,20 +50,22 @@ class SettingsFragment : Fragment() {
|
||||
}
|
||||
|
||||
private lateinit var viewModel: MainViewModel
|
||||
private lateinit var binding: FragmentAppSettingsBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
// sharedElementEnterTransition = TransitionInflater.from(context).inflateTransition(android.R.transition.move)
|
||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.Y, true)
|
||||
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Y, false)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
|
||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||
val binding = DataBindingUtil.inflate<FragmentSettingsBinding>(inflater, R.layout.fragment_settings, container, false)
|
||||
binding = FragmentAppSettingsBinding.inflate(inflater)
|
||||
|
||||
binding.lifecycleOwner = this
|
||||
binding.viewModel = viewModel
|
||||
@ -74,25 +78,29 @@ class SettingsFragment : Fragment() {
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
|
||||
action_back.setOnClickListener {
|
||||
binding.actionBack.setOnSingleClickListener {
|
||||
Navigation.findNavController(it).popBackStack()
|
||||
}
|
||||
|
||||
show_widget_preview_toggle.isChecked = Preferences.showPreview
|
||||
show_wallpaper_toggle.isChecked = Preferences.showWallpaper
|
||||
binding.showWidgetPreviewToggle.setCheckedImmediatelyNoEvent(Preferences.showPreview)
|
||||
binding.showWallpaperToggle.setCheckedImmediatelyNoEvent(Preferences.showWallpaper)
|
||||
|
||||
setupListener()
|
||||
|
||||
app_version.text = "v%s (%s)".format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)
|
||||
binding.appVersion.text = "v%s (%s)".format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)
|
||||
|
||||
binding.scrollView.viewTreeObserver.addOnScrollChangedListener {
|
||||
binding.toolbar.cardElevation = if (binding.scrollView.scrollY > 0) 32f else 0f
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeUi(
|
||||
viewModel: MainViewModel
|
||||
viewModel: MainViewModel,
|
||||
) {
|
||||
viewModel.darkThemePreference.observe(viewLifecycleOwner, Observer {
|
||||
viewModel.darkThemePreference.observe(viewLifecycleOwner) {
|
||||
AppCompatDelegate.setDefaultNightMode(it)
|
||||
maintainScrollPosition {
|
||||
theme?.text = when (it) {
|
||||
binding.theme.text = when (it) {
|
||||
AppCompatDelegate.MODE_NIGHT_NO -> getString(R.string.settings_subtitle_dark_theme_light)
|
||||
AppCompatDelegate.MODE_NIGHT_YES -> getString(R.string.settings_subtitle_dark_theme_dark)
|
||||
AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY -> getString(R.string.settings_subtitle_dark_theme_by_battery_saver)
|
||||
@ -100,43 +108,45 @@ class SettingsFragment : Fragment() {
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
viewModel.installedIntegrations.observe(viewLifecycleOwner, Observer {
|
||||
integrations_count_label?.text = getString(R.string.label_count_installed_integrations).format(it)
|
||||
})
|
||||
viewModel.installedIntegrations.observe(viewLifecycleOwner) {
|
||||
binding.integrationsCountLabel.text =
|
||||
getString(R.string.label_count_installed_integrations).format(
|
||||
it)
|
||||
}
|
||||
|
||||
viewModel.showPreview.observe(viewLifecycleOwner, Observer {
|
||||
viewModel.showPreview.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
show_widget_preview_label?.text =
|
||||
binding.showWidgetPreviewLabel.text =
|
||||
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
viewModel.showWallpaper.observe(viewLifecycleOwner, Observer {
|
||||
viewModel.showWallpaper.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
show_wallpaper_label?.text =
|
||||
if (it && activity?.checkGrantedPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == true) getString(
|
||||
binding.showWallpaperLabel.text =
|
||||
if (it && requireActivity().checkGrantedPermission(Manifest.permission.READ_EXTERNAL_STORAGE)) getString(
|
||||
R.string.settings_visible
|
||||
) else getString(R.string.settings_not_visible)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
action_show_widget_preview.setOnClickListener {
|
||||
show_widget_preview_toggle.isChecked = !show_widget_preview_toggle.isChecked
|
||||
binding.actionShowWidgetPreview.setOnClickListener {
|
||||
binding.showWidgetPreviewToggle.isChecked = !binding.showWidgetPreviewToggle.isChecked
|
||||
}
|
||||
|
||||
show_widget_preview_toggle.setOnCheckedChangeListener { _, isChecked ->
|
||||
binding.showWidgetPreviewToggle.setOnCheckedChangeListener { _, isChecked ->
|
||||
Preferences.showPreview = isChecked
|
||||
}
|
||||
|
||||
action_show_wallpaper.setOnClickListener {
|
||||
show_wallpaper_toggle.isChecked = !show_wallpaper_toggle.isChecked
|
||||
binding.actionShowWallpaper.setOnClickListener {
|
||||
binding.showWallpaperToggle.isChecked = !binding.showWallpaperToggle.isChecked
|
||||
}
|
||||
|
||||
show_wallpaper_toggle.setOnCheckedChangeListener { _, isChecked ->
|
||||
binding.showWallpaperToggle.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked) {
|
||||
requirePermission()
|
||||
} else {
|
||||
@ -144,13 +154,14 @@ class SettingsFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
action_integrations.setOnClickListener {
|
||||
binding.actionIntegrations.setOnClickListener {
|
||||
startActivity(Intent(requireContext(), IntegrationsActivity::class.java))
|
||||
}
|
||||
|
||||
action_change_theme.setOnClickListener {
|
||||
binding.actionChangeTheme.setOnClickListener {
|
||||
maintainScrollPosition {
|
||||
BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_theme_title))
|
||||
BottomSheetMenu<Int>(requireContext(),
|
||||
header = getString(R.string.settings_theme_title))
|
||||
.setSelectedValue(Preferences.darkThemePreference)
|
||||
.addItem(
|
||||
getString(R.string.settings_subtitle_dark_theme_light),
|
||||
@ -170,62 +181,78 @@ class SettingsFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
action_translate.setOnClickListener {
|
||||
activity?.openURI("https://github.com/tommasoberlose/another-widget/blob/master/app/src/main/res/values/strings.xml")
|
||||
binding.actionTranslate.setOnClickListener {
|
||||
requireActivity().openURI("https://github.com/tommasoberlose/another-widget/blob/master/app/src/main/res/values/strings.xml")
|
||||
}
|
||||
|
||||
action_website.setOnClickListener {
|
||||
activity?.openURI("http://tommasoberlose.com/")
|
||||
binding.actionWebsite.setOnClickListener {
|
||||
requireActivity().openURI("http://tommasoberlose.com/")
|
||||
}
|
||||
|
||||
action_feedback.setOnClickListener {
|
||||
activity?.openURI("https://github.com/tommasoberlose/another-widget/issues")
|
||||
binding.actionFeedback.setOnClickListener {
|
||||
requireActivity().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")
|
||||
binding.actionPrivacyPolicy.setOnClickListener {
|
||||
requireActivity().openURI("https://github.com/tommasoberlose/another-widget/blob/master/privacy-policy.md")
|
||||
}
|
||||
|
||||
action_help_dev.setOnClickListener {
|
||||
binding.actionHelpDev.setOnClickListener {
|
||||
startActivity(Intent(requireContext(), SupportDevActivity::class.java))
|
||||
}
|
||||
|
||||
action_refresh_widget.setOnClickListener {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
WeatherHelper.updateWeather(requireContext())
|
||||
}
|
||||
CalendarHelper.updateEventList(requireContext())
|
||||
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
|
||||
ActiveNotificationsHelper.clearLastNotification(requireContext())
|
||||
binding.actionRefreshWidget.setOnClickListener {
|
||||
binding.actionRefreshIcon
|
||||
.animate()
|
||||
.rotation((binding.actionRefreshIcon.rotation - binding.actionRefreshIcon.rotation % 360f) + 360f)
|
||||
.withEndAction {
|
||||
viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
WeatherHelper.updateWeather(requireContext())
|
||||
CalendarHelper.updateEventList(requireContext())
|
||||
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
|
||||
ActiveNotificationsHelper.clearLastNotification(requireContext())
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
.start()
|
||||
}
|
||||
}
|
||||
|
||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||
scrollView.isScrollable = false
|
||||
binding.scrollView.isScrollable = false
|
||||
callback.invoke()
|
||||
lifecycleScope.launch {
|
||||
delay(200)
|
||||
scrollView.isScrollable = true
|
||||
binding.scrollView.isScrollable = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
binding.showWallpaperToggle.setCheckedNoEvent(Preferences.showWallpaper && requireActivity().checkGrantedPermission(Manifest.permission.READ_EXTERNAL_STORAGE))
|
||||
}
|
||||
|
||||
private fun requirePermission() {
|
||||
Dexter.withContext(requireContext())
|
||||
.withPermissions(
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
).withListener(object: MultiplePermissionsListener {
|
||||
).withListener(object : MultiplePermissionsListener {
|
||||
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
||||
report?.let {
|
||||
if (report.areAllPermissionsGranted()) {
|
||||
Preferences.showWallpaper = true
|
||||
} else {
|
||||
show_wallpaper_toggle?.isChecked = false
|
||||
binding.showWallpaperToggle.setCheckedNoEvent(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPermissionRationaleShouldBeShown(
|
||||
permissions: MutableList<PermissionRequest>?,
|
||||
token: PermissionToken?
|
||||
token: PermissionToken?,
|
||||
) {
|
||||
// Remember to invoke this method when the custom rationale is closed
|
||||
// or just by default if you don't want to use any custom rationale.
|
||||
|
@ -1,323 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.fragments
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.os.BuildCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.chibatching.kotpref.bulk
|
||||
import com.karumi.dexter.Dexter
|
||||
import com.karumi.dexter.MultiplePermissionsReport
|
||||
import com.karumi.dexter.PermissionToken
|
||||
import com.karumi.dexter.listener.PermissionRequest
|
||||
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||
import com.tommasoberlose.anotherwidget.components.IconPackSelector
|
||||
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
|
||||
import com.tommasoberlose.anotherwidget.databinding.FragmentWeatherSettingsBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.global.RequestCode
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
||||
import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.CustomLocationActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.WeatherProviderActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||
import com.tommasoberlose.anotherwidget.utils.collapse
|
||||
import com.tommasoberlose.anotherwidget.utils.expand
|
||||
import kotlinx.android.synthetic.main.fragment_weather_settings.*
|
||||
import kotlinx.android.synthetic.main.fragment_weather_settings.scrollView
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class WeatherTabFragment : Fragment() {
|
||||
|
||||
companion object {
|
||||
fun newInstance() = WeatherTabFragment()
|
||||
}
|
||||
|
||||
private lateinit var viewModel: MainViewModel
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
|
||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||
val binding = DataBindingUtil.inflate<FragmentWeatherSettingsBinding>(inflater, R.layout.fragment_weather_settings, container, false)
|
||||
|
||||
subscribeUi(binding, viewModel)
|
||||
|
||||
binding.lifecycleOwner = this
|
||||
binding.viewModel = viewModel
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
|
||||
setupListener()
|
||||
}
|
||||
|
||||
private fun subscribeUi(
|
||||
binding: FragmentWeatherSettingsBinding,
|
||||
viewModel: MainViewModel
|
||||
) {
|
||||
binding.isWeatherVisible = Preferences.showWeather
|
||||
|
||||
viewModel.showWeather.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
show_weather_label?.text =
|
||||
if (it) getString(R.string.show_weather_visible) else getString(R.string.show_weather_not_visible)
|
||||
checkWeatherProviderConfig()
|
||||
binding.isWeatherVisible = it
|
||||
}
|
||||
checkLocationPermission()
|
||||
checkWeatherProviderConfig()
|
||||
})
|
||||
|
||||
viewModel.weatherProvider.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
label_weather_provider.text = WeatherHelper.getProviderName(requireContext(), Constants.WeatherProvider.fromInt(it)!!)
|
||||
checkWeatherProviderConfig()
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.weatherProviderError.observe(viewLifecycleOwner, Observer {
|
||||
checkWeatherProviderConfig()
|
||||
})
|
||||
|
||||
viewModel.weatherProviderLocationError.observe(viewLifecycleOwner, Observer {
|
||||
checkWeatherProviderConfig()
|
||||
})
|
||||
|
||||
viewModel.customLocationAdd.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
label_custom_location?.text =
|
||||
if (it == "") getString(R.string.custom_location_gps) else it
|
||||
}
|
||||
checkLocationPermission()
|
||||
})
|
||||
|
||||
viewModel.weatherTempUnit.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
temp_unit?.text =
|
||||
if (it == "F") getString(R.string.fahrenheit) else getString(R.string.celsius)
|
||||
}
|
||||
checkLocationPermission()
|
||||
})
|
||||
|
||||
viewModel.weatherRefreshPeriod.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
label_weather_refresh_period?.text = getString(SettingsStringHelper.getRefreshPeriodString(it))
|
||||
}
|
||||
checkLocationPermission()
|
||||
})
|
||||
|
||||
viewModel.weatherIconPack.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
label_weather_icon_pack?.text = getString(R.string.settings_weather_icon_pack_default).format((it + 1))
|
||||
// weather_icon_pack.setImageDrawable(ContextCompat.getDrawable(requireContext(), WeatherHelper.getWeatherIconResource("02d")))
|
||||
// if (it == Constants.WeatherIconPack.MINIMAL.value) {
|
||||
// weather_icon_pack.setColorFilter(ContextCompat.getColor(requireContext(), R.color.colorPrimaryText))
|
||||
// } else {
|
||||
// weather_icon_pack.setColorFilter(ContextCompat.getColor(requireContext(), android.R.color.transparent))
|
||||
// }
|
||||
}
|
||||
checkLocationPermission()
|
||||
})
|
||||
|
||||
viewModel.weatherAppName.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
weather_app_label?.text =
|
||||
if (it != "") it else getString(R.string.default_weather_app)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun checkLocationPermission() {
|
||||
if (requireActivity().checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION)) {
|
||||
location_permission_alert?.isVisible = false
|
||||
WeatherReceiver.setUpdates(requireContext())
|
||||
} else if (Preferences.showWeather && Preferences.customLocationAdd == "") {
|
||||
location_permission_alert?.isVisible = true
|
||||
location_permission_alert?.setOnClickListener {
|
||||
MaterialBottomSheetDialog(requireContext(), message = getString(R.string.background_location_warning))
|
||||
.setPositiveButton(getString(android.R.string.ok)) {
|
||||
requirePermission()
|
||||
}
|
||||
.show()
|
||||
}
|
||||
} else {
|
||||
location_permission_alert?.isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkWeatherProviderConfig() {
|
||||
if (Preferences.showWeather && Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-" && !location_permission_alert.isVisible) {
|
||||
weather_provider_error.expand()
|
||||
} else {
|
||||
weather_provider_error.collapse()
|
||||
}
|
||||
weather_provider_error?.text = Preferences.weatherProviderError
|
||||
|
||||
if (Preferences.showWeather && Preferences.weatherProviderLocationError != "" && !location_permission_alert.isVisible) {
|
||||
weather_provider_location_error.expand()
|
||||
} else {
|
||||
weather_provider_location_error.collapse()
|
||||
}
|
||||
weather_provider_location_error?.text = Preferences.weatherProviderLocationError
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
action_show_weather.setOnClickListener {
|
||||
Preferences.showWeather = !Preferences.showWeather
|
||||
}
|
||||
|
||||
show_weather_switch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
||||
Preferences.showWeather = enabled
|
||||
}
|
||||
|
||||
action_weather_provider.setOnClickListener {
|
||||
if (Preferences.showWeather) {
|
||||
startActivityForResult(
|
||||
Intent(requireContext(), WeatherProviderActivity::class.java),
|
||||
RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
action_custom_location.setOnClickListener {
|
||||
if (Preferences.showWeather) {
|
||||
startActivityForResult(
|
||||
Intent(requireContext(), CustomLocationActivity::class.java),
|
||||
Constants.RESULT_CODE_CUSTOM_LOCATION
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
action_change_unit.setOnClickListener {
|
||||
if (Preferences.showWeather) {
|
||||
BottomSheetMenu<String>(requireContext(), header = getString(R.string.settings_unit_title)).setSelectedValue(Preferences.weatherTempUnit)
|
||||
.addItem(getString(R.string.fahrenheit), "F")
|
||||
.addItem(getString(R.string.celsius), "C")
|
||||
.addOnSelectItemListener { value ->
|
||||
if (value != Preferences.weatherTempUnit) {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
WeatherHelper.updateWeather(requireContext())
|
||||
}
|
||||
}
|
||||
Preferences.weatherTempUnit = value
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
action_weather_refresh_period.setOnClickListener {
|
||||
if (Preferences.showWeather) {
|
||||
val dialog =
|
||||
BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_weather_refresh_period_title)).setSelectedValue(Preferences.weatherRefreshPeriod)
|
||||
(5 downTo 0).forEach {
|
||||
dialog.addItem(getString(SettingsStringHelper.getRefreshPeriodString(it)), it)
|
||||
}
|
||||
dialog
|
||||
.addOnSelectItemListener { value ->
|
||||
Preferences.weatherRefreshPeriod = value
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
action_weather_icon_pack.setOnClickListener {
|
||||
if (Preferences.showWeather) {
|
||||
IconPackSelector(requireContext(), header = getString(R.string.settings_weather_icon_pack_title)).show()
|
||||
}
|
||||
}
|
||||
|
||||
action_weather_app.setOnClickListener {
|
||||
if (Preferences.showWeather) {
|
||||
startActivityForResult(
|
||||
Intent(requireContext(), ChooseApplicationActivity::class.java),
|
||||
RequestCode.WEATHER_APP_REQUEST_CODE.code
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
Constants.RESULT_CODE_CUSTOM_LOCATION -> {
|
||||
WeatherReceiver.setUpdates(requireContext())
|
||||
checkLocationPermission()
|
||||
}
|
||||
RequestCode.WEATHER_APP_REQUEST_CODE.code -> {
|
||||
Preferences.bulk {
|
||||
weatherAppName = data?.getStringExtra(Constants.RESULT_APP_NAME) ?: getString(R.string.default_weather_app)
|
||||
weatherAppPackage = data?.getStringExtra(Constants.RESULT_APP_PACKAGE) ?: ""
|
||||
}
|
||||
MainWidget.updateWidget(requireContext())
|
||||
}
|
||||
RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code -> {
|
||||
checkLocationPermission()
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
private fun requirePermission() {
|
||||
Dexter.withContext(requireContext())
|
||||
.withPermissions(
|
||||
Manifest.permission.ACCESS_FINE_LOCATION
|
||||
).withListener(object: MultiplePermissionsListener {
|
||||
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
||||
report?.let {
|
||||
if (report.areAllPermissionsGranted()){
|
||||
checkLocationPermission()
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun onPermissionRationaleShouldBeShown(
|
||||
permissions: MutableList<PermissionRequest>?,
|
||||
token: PermissionToken?
|
||||
) {
|
||||
// Remember to invoke this method when the custom rationale is closed
|
||||
// or just by default if you don't want to use any custom rationale.
|
||||
token?.continuePermissionRequest()
|
||||
}
|
||||
})
|
||||
.check()
|
||||
}
|
||||
|
||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||
scrollView.isScrollable = false
|
||||
callback.invoke()
|
||||
lifecycleScope.launch {
|
||||
delay(200)
|
||||
scrollView.isScrollable = true
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,297 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.fragments.tabs
|
||||
|
||||
import android.Manifest
|
||||
import android.os.Bundle
|
||||
import android.provider.CalendarContract
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||
import com.tommasoberlose.anotherwidget.models.CalendarSelector
|
||||
import com.tommasoberlose.anotherwidget.databinding.FragmentTabCalendarBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||
import com.tommasoberlose.anotherwidget.utils.toast
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class CalendarFragment : Fragment() {
|
||||
|
||||
companion object {
|
||||
fun newInstance() = CalendarFragment()
|
||||
}
|
||||
|
||||
private lateinit var viewModel: MainViewModel
|
||||
private lateinit var binding: FragmentTabCalendarBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
|
||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||
binding = FragmentTabCalendarBinding.inflate(inflater)
|
||||
|
||||
subscribeUi(viewModel)
|
||||
|
||||
binding.lifecycleOwner = this
|
||||
binding.viewModel = viewModel
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
|
||||
binding.showAllDayToggle.setCheckedImmediatelyNoEvent(Preferences.calendarAllDay)
|
||||
binding.showOnlyBusyEventsToggle.setCheckedImmediatelyNoEvent(Preferences.showOnlyBusyEvents)
|
||||
binding.showDiffTimeToggle.setCheckedImmediatelyNoEvent(Preferences.showDiffTime)
|
||||
binding.showNextEventOnMultipleLinesToggle.setCheckedImmediatelyNoEvent(Preferences.showNextEventOnMultipleLines)
|
||||
|
||||
setupListener()
|
||||
|
||||
binding.scrollView.viewTreeObserver.addOnScrollChangedListener {
|
||||
viewModel.fragmentScrollY.value = binding.scrollView.scrollY
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeUi(
|
||||
viewModel: MainViewModel
|
||||
) {
|
||||
binding.isCalendarEnabled = Preferences.showEvents
|
||||
binding.isDiffEnabled = Preferences.showDiffTime
|
||||
|
||||
viewModel.calendarAllDay.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.allDayLabel.text =
|
||||
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.secondRowInformation.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.secondRowInfoLabel.text = getString(SettingsStringHelper.getSecondRowInfoString(it))
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.showNextEventOnMultipleLines.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.showNextEventOnMultipleLinesLabel.text = if (it) getString(R.string.settings_enabled) else getString(R.string.settings_disabled)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.showDiffTime.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.showDiffTimeLabel.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||
binding.isDiffEnabled = it || !Preferences.showEvents
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.widgetUpdateFrequency.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.widgetUpdateFrequencyLabel.text = when (it) {
|
||||
Constants.WidgetUpdateFrequency.HIGH.rawValue -> getString(R.string.settings_widget_update_frequency_high)
|
||||
Constants.WidgetUpdateFrequency.DEFAULT.rawValue -> getString(R.string.settings_widget_update_frequency_default)
|
||||
Constants.WidgetUpdateFrequency.LOW.rawValue -> getString(R.string.settings_widget_update_frequency_low)
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.showUntil.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.showUntilLabel.text = getString(SettingsStringHelper.getShowUntilString(it))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
|
||||
binding.actionFilterCalendar.setOnClickListener {
|
||||
val calendarSelectorList: List<CalendarSelector> = CalendarHelper.getCalendarList(requireContext()).map {
|
||||
CalendarSelector(
|
||||
it.id,
|
||||
it.displayName,
|
||||
it.accountName
|
||||
)
|
||||
}.sortedWith { cal1, cal2 ->
|
||||
when {
|
||||
cal1.accountName != cal2.accountName -> {
|
||||
cal1.accountName.compareTo(cal2.accountName)
|
||||
}
|
||||
cal1.accountName == cal1.name -> {
|
||||
-1
|
||||
}
|
||||
cal2.accountName == cal2.name -> {
|
||||
1
|
||||
}
|
||||
else -> {
|
||||
cal1.name.compareTo(cal2.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (calendarSelectorList.isNotEmpty()) {
|
||||
val filteredCalendarIds = CalendarHelper.getFilteredCalendarIdList()
|
||||
val visibleCalendarIds = calendarSelectorList.map { it.id }.filter { id: Long -> !filteredCalendarIds.contains(id) }
|
||||
|
||||
val dialog = BottomSheetMenu<Long>(requireContext(), header = getString(R.string.settings_filter_calendar_subtitle), isMultiSelection = true)
|
||||
.setSelectedValues(visibleCalendarIds)
|
||||
|
||||
calendarSelectorList.indices.forEach { index ->
|
||||
if (index == 0 || calendarSelectorList[index].accountName != calendarSelectorList[index - 1].accountName) {
|
||||
dialog.addItem(calendarSelectorList[index].accountName)
|
||||
}
|
||||
|
||||
dialog.addItem(
|
||||
if (calendarSelectorList[index].name == calendarSelectorList[index].accountName) getString(R.string.main_calendar) else calendarSelectorList[index].name,
|
||||
calendarSelectorList[index].id
|
||||
)
|
||||
}
|
||||
|
||||
dialog.addOnMultipleSelectItemListener { values ->
|
||||
CalendarHelper.filterCalendar(calendarSelectorList.map { it.id }.filter { !values.contains(it) })
|
||||
updateCalendar()
|
||||
}.show()
|
||||
} else {
|
||||
requireActivity().toast(getString(R.string.calendar_settings_list_error))
|
||||
}
|
||||
}
|
||||
|
||||
binding.actionShowAllDay.setOnClickListener {
|
||||
binding.showAllDayToggle.isChecked = !binding.showAllDayToggle.isChecked
|
||||
}
|
||||
|
||||
binding.showAllDayToggle.setOnCheckedChangeListener { _, isChecked ->
|
||||
Preferences.calendarAllDay = isChecked
|
||||
MainWidget.updateWidget(requireContext())
|
||||
}
|
||||
|
||||
binding.actionChangeAttendeeFilter.setOnClickListener {
|
||||
val selectedValues = emptyList<Int>().toMutableList()
|
||||
if (Preferences.showDeclinedEvents) {
|
||||
selectedValues.add(CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED)
|
||||
}
|
||||
if (Preferences.showInvitedEvents) {
|
||||
selectedValues.add(CalendarContract.Attendees.ATTENDEE_STATUS_INVITED)
|
||||
}
|
||||
if (Preferences.showAcceptedEvents) {
|
||||
selectedValues.add(CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED)
|
||||
}
|
||||
|
||||
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_attendee_status_title), isMultiSelection = true)
|
||||
.setSelectedValues(selectedValues)
|
||||
|
||||
dialog.addItem(
|
||||
getString(R.string.attendee_status_invited),
|
||||
CalendarContract.Attendees.ATTENDEE_STATUS_INVITED
|
||||
)
|
||||
dialog.addItem(
|
||||
getString(R.string.attendee_status_accepted),
|
||||
CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED
|
||||
)
|
||||
dialog.addItem(
|
||||
getString(R.string.attendee_status_declined),
|
||||
CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED
|
||||
)
|
||||
|
||||
dialog.addOnMultipleSelectItemListener { values ->
|
||||
Preferences.showDeclinedEvents = values.contains(CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED)
|
||||
Preferences.showAcceptedEvents = values.contains(CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED)
|
||||
Preferences.showInvitedEvents = values.contains(CalendarContract.Attendees.ATTENDEE_STATUS_INVITED)
|
||||
updateCalendar()
|
||||
}.show()
|
||||
}
|
||||
|
||||
binding.actionShowOnlyBusyEvents.setOnClickListener {
|
||||
binding.showOnlyBusyEventsToggle.isChecked = !binding.showOnlyBusyEventsToggle.isChecked
|
||||
}
|
||||
|
||||
binding.showOnlyBusyEventsToggle.setOnCheckedChangeListener { _, isChecked ->
|
||||
Preferences.showOnlyBusyEvents = isChecked
|
||||
MainWidget.updateWidget(requireContext())
|
||||
}
|
||||
|
||||
binding.actionShowDiffTime.setOnClickListener {
|
||||
binding.showDiffTimeToggle.isChecked = !binding.showDiffTimeToggle.isChecked
|
||||
}
|
||||
|
||||
binding.showDiffTimeToggle.setOnCheckedChangeListener { _, isChecked ->
|
||||
Preferences.showDiffTime = isChecked
|
||||
}
|
||||
|
||||
binding.actionShowNextEventOnMultipleLines.setOnClickListener {
|
||||
binding.showNextEventOnMultipleLinesToggle.isChecked = !binding.showNextEventOnMultipleLinesToggle.isChecked
|
||||
}
|
||||
|
||||
binding.showNextEventOnMultipleLinesToggle.setOnCheckedChangeListener { _, isChecked ->
|
||||
Preferences.showNextEventOnMultipleLines = isChecked
|
||||
}
|
||||
|
||||
binding.actionWidgetUpdateFrequency.setOnClickListener {
|
||||
if (Preferences.showEvents && Preferences.showDiffTime) {
|
||||
BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_widget_update_frequency_title), message = getString(R.string.settings_widget_update_frequency_subtitle)).setSelectedValue(Preferences.widgetUpdateFrequency)
|
||||
.addItem(getString(R.string.settings_widget_update_frequency_high), Constants.WidgetUpdateFrequency.HIGH.rawValue)
|
||||
.addItem(getString(R.string.settings_widget_update_frequency_default), Constants.WidgetUpdateFrequency.DEFAULT.rawValue)
|
||||
.addItem(getString(R.string.settings_widget_update_frequency_low), Constants.WidgetUpdateFrequency.LOW.rawValue)
|
||||
.addOnSelectItemListener { value ->
|
||||
Preferences.widgetUpdateFrequency = value
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
binding.actionSecondRowInfo.setOnClickListener {
|
||||
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_second_row_info_title)).setSelectedValue(Preferences.secondRowInformation)
|
||||
(0 .. 1).forEach {
|
||||
dialog.addItem(getString(SettingsStringHelper.getSecondRowInfoString(it)), it)
|
||||
}
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
Preferences.secondRowInformation = value
|
||||
}.show()
|
||||
}
|
||||
|
||||
binding.actionShowUntil.setOnClickListener {
|
||||
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_show_until_title)).setSelectedValue(Preferences.showUntil)
|
||||
intArrayOf(6,7,0,1,2,3, 4, 5).forEach {
|
||||
dialog.addItem(getString(SettingsStringHelper.getShowUntilString(it)), it)
|
||||
}
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
Preferences.showUntil = value
|
||||
updateCalendar()
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateCalendar() {
|
||||
if (requireActivity().checkGrantedPermission(Manifest.permission.READ_CALENDAR)) {
|
||||
CalendarHelper.updateEventList(requireContext())
|
||||
}
|
||||
}
|
||||
|
||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||
binding.scrollView.isScrollable = false
|
||||
callback.invoke()
|
||||
lifecycleScope.launch {
|
||||
delay(200)
|
||||
binding.scrollView.isScrollable = true
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,212 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.fragments.tabs
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.text.format.DateFormat
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.chibatching.kotpref.bulk
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||
import com.tommasoberlose.anotherwidget.databinding.FragmentTabClockBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.global.RequestCode
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toHexValue
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
||||
import com.tommasoberlose.anotherwidget.helpers.IntentHelper
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.tabs.ChooseApplicationActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.tabs.TimeZoneSelectorActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||
import com.tommasoberlose.anotherwidget.utils.isDefaultSet
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
|
||||
class ClockFragment : Fragment() {
|
||||
|
||||
companion object {
|
||||
fun newInstance() = ClockFragment()
|
||||
}
|
||||
|
||||
private lateinit var viewModel: MainViewModel
|
||||
private lateinit var colors: IntArray
|
||||
private lateinit var binding: FragmentTabClockBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
|
||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||
binding = FragmentTabClockBinding.inflate(inflater)
|
||||
|
||||
subscribeUi(viewModel)
|
||||
|
||||
binding.lifecycleOwner = this
|
||||
binding.viewModel = viewModel
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
|
||||
binding.ampmIndicatorToggle.setCheckedImmediatelyNoEvent(Preferences.showAMPMIndicator)
|
||||
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val lazyColors = requireContext().resources.getIntArray(R.array.material_colors)
|
||||
withContext(Dispatchers.Main) {
|
||||
colors = lazyColors
|
||||
}
|
||||
}
|
||||
setupListener()
|
||||
|
||||
binding.scrollView.viewTreeObserver?.addOnScrollChangedListener {
|
||||
viewModel.fragmentScrollY.value = binding.scrollView.scrollY
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeUi(
|
||||
viewModel: MainViewModel
|
||||
) {
|
||||
binding.isClockVisible = Preferences.showClock
|
||||
binding.is24Format = DateFormat.is24HourFormat(requireContext())
|
||||
binding.isDarkModeEnabled = activity?.isDarkTheme() == true
|
||||
|
||||
viewModel.clockTextSize.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.clockTextSizeLabel.text = String.format("%.0fsp", it)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.altTimezoneLabel.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
if (it != "") {
|
||||
binding.altTimezoneClockLabel.text =
|
||||
String.format("%s (%s)", it, Preferences.altTimezoneId)
|
||||
} else {
|
||||
binding.altTimezoneClockLabel.text = getString(R.string.no_time_zone_label)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.showAMPMIndicator.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.ampmIndicatorLabel.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.clockTextColor.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
if (Preferences.clockTextAlpha == "00") {
|
||||
binding.clockTextColorLabel.text = getString(R.string.transparent)
|
||||
} else {
|
||||
binding.clockTextColorLabel.text =
|
||||
"#%s".format(Integer.toHexString(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.clockTextColorDark.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
if (Preferences.clockTextAlphaDark == "00") {
|
||||
binding.clockTextColorLabel.text = getString(R.string.transparent)
|
||||
} else {
|
||||
binding.clockTextColorLabel.text =
|
||||
"#%s".format(Integer.toHexString(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))).toUpperCase()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
|
||||
binding.actionClockTextSize.setOnClickListener {
|
||||
val dialog = BottomSheetMenu<Float>(
|
||||
requireContext(),
|
||||
header = getString(R.string.settings_clock_text_size_title)
|
||||
).setSelectedValue(Preferences.clockTextSize)
|
||||
(46 downTo 12).filter { it % 2 == 0 }.forEach {
|
||||
dialog.addItem("${it}sp", it.toFloat())
|
||||
}
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
Preferences.clockTextSize = value
|
||||
}.show()
|
||||
}
|
||||
|
||||
binding.actionAltTimezoneClock.setOnClickListener {
|
||||
startActivity(Intent(requireContext(), TimeZoneSelectorActivity::class.java))
|
||||
}
|
||||
|
||||
binding.actionAmpmIndicatorSize.setOnClickListener {
|
||||
binding.ampmIndicatorToggle.isChecked = !binding.ampmIndicatorToggle.isChecked
|
||||
}
|
||||
|
||||
binding.ampmIndicatorToggle.setOnCheckedChangeListener { _, isChecked ->
|
||||
Preferences.showAMPMIndicator = isChecked
|
||||
}
|
||||
|
||||
binding.actionClockTextColor.setOnClickListener {
|
||||
BottomSheetColorPicker(requireContext(),
|
||||
colors = colors,
|
||||
header = getString(R.string.settings_font_color_title),
|
||||
getSelected = { ColorHelper.getClockFontColorRgb(activity?.isDarkTheme() == true) },
|
||||
onColorSelected = { color: Int ->
|
||||
val colorString = Integer.toHexString(color)
|
||||
if (activity?.isDarkTheme() == true) {
|
||||
Preferences.clockTextColorDark =
|
||||
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||
} else {
|
||||
Preferences.clockTextColor =
|
||||
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||
}
|
||||
},
|
||||
showAlphaSelector = true,
|
||||
alpha = if (activity?.isDarkTheme() == true) Preferences.clockTextAlphaDark.toIntValue() else Preferences.clockTextAlpha.toIntValue(),
|
||||
onAlphaChangeListener = { alpha ->
|
||||
if (activity?.isDarkTheme() == true) {
|
||||
Preferences.clockTextAlphaDark = alpha.toHexValue()
|
||||
} else {
|
||||
Preferences.clockTextAlpha = alpha.toHexValue()
|
||||
}
|
||||
}
|
||||
).show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
binding.is24Format = DateFormat.is24HourFormat(requireContext())
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||
binding.scrollView.isScrollable = false
|
||||
callback.invoke()
|
||||
lifecycleScope.launch {
|
||||
delay(200)
|
||||
binding.scrollView.isScrollable = true
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,241 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.fragments.tabs
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.chibatching.kotpref.blockingBulk
|
||||
import com.chibatching.kotpref.bulk
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||
import com.tommasoberlose.anotherwidget.databinding.FragmentTabGesturesBinding
|
||||
import com.tommasoberlose.anotherwidget.databinding.FragmentTabLayoutBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.global.RequestCode
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toHexValue
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
||||
import com.tommasoberlose.anotherwidget.helpers.DateHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.IntentHelper
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.tabs.CustomDateActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.tabs.ChooseApplicationActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||
import com.tommasoberlose.anotherwidget.utils.isDefaultSet
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.*
|
||||
|
||||
class GesturesFragment : Fragment() {
|
||||
|
||||
companion object {
|
||||
fun newInstance() = GesturesFragment()
|
||||
}
|
||||
|
||||
private lateinit var viewModel: MainViewModel
|
||||
private lateinit var binding: FragmentTabGesturesBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
|
||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||
binding = FragmentTabGesturesBinding.inflate(inflater)
|
||||
|
||||
subscribeUi(viewModel)
|
||||
|
||||
binding.lifecycleOwner = this
|
||||
binding.viewModel = viewModel
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
|
||||
binding.showMultipleEventsToggle.setCheckedImmediatelyNoEvent(Preferences.showNextEvent)
|
||||
setupListener()
|
||||
|
||||
binding.scrollView.viewTreeObserver?.addOnScrollChangedListener {
|
||||
viewModel.fragmentScrollY.value = binding.scrollView.scrollY
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
private fun subscribeUi(
|
||||
viewModel: MainViewModel
|
||||
) {
|
||||
|
||||
viewModel.showNextEvent.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.showMultipleEventsLabel.text =
|
||||
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.calendarAppName.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.calendarAppLabel.text = when {
|
||||
it == IntentHelper.DO_NOTHING_OPTION -> getString(R.string.gestures_do_nothing)
|
||||
it == IntentHelper.REFRESH_WIDGET_OPTION -> getString(R.string.gestures_refresh_widget)
|
||||
it != IntentHelper.DEFAULT_OPTION -> it
|
||||
else -> {
|
||||
if (IntentHelper.getCalendarIntent(requireContext()).isDefaultSet(requireContext())) {
|
||||
getString(
|
||||
R.string.default_calendar_app
|
||||
)
|
||||
} else {
|
||||
getString(R.string.gestures_do_nothing)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.openEventDetails.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.openEventDetailsLabel.text = if (it) getString(R.string.default_event_app) else getString(R.string.default_calendar_app)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.clockAppName.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.clockAppLabel.text = when {
|
||||
it == IntentHelper.DO_NOTHING_OPTION -> getString(R.string.gestures_do_nothing)
|
||||
it == IntentHelper.REFRESH_WIDGET_OPTION -> getString(R.string.gestures_refresh_widget)
|
||||
it != IntentHelper.DEFAULT_OPTION -> it
|
||||
else -> {
|
||||
if (IntentHelper.getClockIntent(requireContext()).isDefaultSet(requireContext())) {
|
||||
getString(
|
||||
R.string.default_clock_app
|
||||
)
|
||||
} else {
|
||||
getString(R.string.gestures_do_nothing)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.weatherAppName.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.weatherAppLabel.text = when {
|
||||
it == IntentHelper.DO_NOTHING_OPTION -> getString(R.string.gestures_do_nothing)
|
||||
it == IntentHelper.REFRESH_WIDGET_OPTION -> getString(R.string.gestures_refresh_widget)
|
||||
it != IntentHelper.DEFAULT_OPTION -> it
|
||||
else -> getString(R.string.default_weather_app)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
|
||||
binding.actionShowMultipleEvents.setOnClickListener {
|
||||
binding.showMultipleEventsToggle.isChecked = !binding.showMultipleEventsToggle.isChecked
|
||||
}
|
||||
|
||||
binding.showMultipleEventsToggle.setOnCheckedChangeListener { _, isChecked ->
|
||||
Preferences.showNextEvent = isChecked
|
||||
}
|
||||
|
||||
binding.actionOpenEventDetails.setOnClickListener {
|
||||
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_event_app_title)).setSelectedValue(Preferences.openEventDetails)
|
||||
.addItem(getString(R.string.default_event_app), true)
|
||||
.addItem(getString(R.string.default_calendar_app), false)
|
||||
.addOnSelectItemListener { value ->
|
||||
Preferences.openEventDetails = value
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
binding.actionCalendarApp.setOnClickListener {
|
||||
startActivityForResult(Intent(requireContext(), ChooseApplicationActivity::class.java).apply {
|
||||
putExtra(Constants.RESULT_APP_PACKAGE, Preferences.calendarAppPackage)
|
||||
}, RequestCode.CALENDAR_APP_REQUEST_CODE.code)
|
||||
}
|
||||
|
||||
binding.actionClockApp.setOnClickListener {
|
||||
startActivityForResult(
|
||||
Intent(requireContext(), ChooseApplicationActivity::class.java).apply {
|
||||
putExtra(Constants.RESULT_APP_PACKAGE, Preferences.clockAppPackage)
|
||||
},
|
||||
RequestCode.CLOCK_APP_REQUEST_CODE.code
|
||||
)
|
||||
}
|
||||
|
||||
binding.actionWeatherApp.setOnClickListener {
|
||||
startActivityForResult(
|
||||
Intent(requireContext(), ChooseApplicationActivity::class.java).apply {
|
||||
putExtra(Constants.RESULT_APP_PACKAGE, Preferences.weatherAppPackage)
|
||||
},
|
||||
RequestCode.WEATHER_APP_REQUEST_CODE.code
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||
binding.scrollView.isScrollable = false
|
||||
callback.invoke()
|
||||
lifecycleScope.launch {
|
||||
delay(200)
|
||||
binding.scrollView.isScrollable = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (resultCode == Activity.RESULT_OK && data != null && data.hasExtra(Constants.RESULT_APP_NAME) && data.hasExtra(Constants.RESULT_APP_PACKAGE)) {
|
||||
when (requestCode) {
|
||||
RequestCode.CALENDAR_APP_REQUEST_CODE.code -> {
|
||||
Preferences.bulk {
|
||||
calendarAppName = data.getStringExtra(Constants.RESULT_APP_NAME) ?: IntentHelper.DEFAULT_OPTION
|
||||
calendarAppPackage = data.getStringExtra(Constants.RESULT_APP_PACKAGE) ?: IntentHelper.DEFAULT_OPTION
|
||||
}
|
||||
}
|
||||
RequestCode.EVENT_APP_REQUEST_CODE.code -> {
|
||||
Preferences.bulk {
|
||||
eventAppName = data.getStringExtra(Constants.RESULT_APP_NAME) ?: IntentHelper.DEFAULT_OPTION
|
||||
eventAppPackage = data.getStringExtra(Constants.RESULT_APP_PACKAGE) ?: IntentHelper.DEFAULT_OPTION
|
||||
}
|
||||
}
|
||||
RequestCode.WEATHER_APP_REQUEST_CODE.code -> {
|
||||
Preferences.bulk {
|
||||
weatherAppName = data.getStringExtra(Constants.RESULT_APP_NAME) ?: IntentHelper.DEFAULT_OPTION
|
||||
weatherAppPackage = data.getStringExtra(Constants.RESULT_APP_PACKAGE) ?: IntentHelper.DEFAULT_OPTION
|
||||
}
|
||||
}
|
||||
RequestCode.CLOCK_APP_REQUEST_CODE.code -> {
|
||||
Preferences.bulk {
|
||||
clockAppName = data.getStringExtra(Constants.RESULT_APP_NAME) ?: IntentHelper.DEFAULT_OPTION
|
||||
clockAppPackage = data.getStringExtra(Constants.RESULT_APP_PACKAGE) ?: IntentHelper.DEFAULT_OPTION
|
||||
}
|
||||
}
|
||||
}
|
||||
MainWidget.updateWidget(requireContext())
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.fragments
|
||||
package com.tommasoberlose.anotherwidget.ui.fragments.tabs
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
@ -10,16 +10,16 @@ import android.content.IntentFilter
|
||||
import android.graphics.Canvas
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.AnimationUtils
|
||||
import android.view.animation.LayoutAnimationController
|
||||
import android.widget.ImageView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
@ -29,10 +29,11 @@ import com.google.android.gms.auth.api.signin.GoogleSignIn
|
||||
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
|
||||
import com.google.android.gms.common.api.ApiException
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.components.CustomNotesDialog
|
||||
import com.tommasoberlose.anotherwidget.components.GlanceSettingsDialog
|
||||
import com.tommasoberlose.anotherwidget.databinding.FragmentGlanceSettingsBinding
|
||||
import com.tommasoberlose.anotherwidget.databinding.FragmentTabGlanceBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.ActiveNotificationsHelper
|
||||
@ -44,11 +45,11 @@ import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
|
||||
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver.Companion.FITNESS_OPTIONS
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||
import com.tommasoberlose.anotherwidget.utils.convertDpToPixel
|
||||
import kotlinx.android.synthetic.main.fragment_glance_settings.*
|
||||
import com.tommasoberlose.anotherwidget.utils.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import net.idik.lib.slimadapter.SlimAdapter
|
||||
|
||||
|
||||
@ -61,10 +62,15 @@ class GlanceTabFragment : Fragment() {
|
||||
private var dialog: GlanceSettingsDialog? = null
|
||||
private lateinit var adapter: SlimAdapter
|
||||
private lateinit var viewModel: MainViewModel
|
||||
private lateinit var list: ArrayList<Constants.GlanceProviderId>
|
||||
private val list: ArrayList<Constants.GlanceProviderId> by lazy {
|
||||
GlanceProviderHelper.getGlanceProviders(requireContext())
|
||||
}
|
||||
private lateinit var binding: FragmentTabGlanceBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
@ -73,18 +79,11 @@ class GlanceTabFragment : Fragment() {
|
||||
): View {
|
||||
|
||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||
val binding = DataBindingUtil.inflate<FragmentGlanceSettingsBinding>(inflater,
|
||||
R.layout.fragment_glance_settings,
|
||||
container,
|
||||
false)
|
||||
|
||||
subscribeUi(binding, viewModel)
|
||||
binding = FragmentTabGlanceBinding.inflate(inflater)
|
||||
|
||||
binding.lifecycleOwner = this
|
||||
binding.viewModel = viewModel
|
||||
|
||||
list = GlanceProviderHelper.getGlanceProviders(requireContext())
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
@ -92,9 +91,10 @@ class GlanceTabFragment : Fragment() {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
|
||||
// List
|
||||
providers_list.setHasFixedSize(true)
|
||||
binding.providersList.hasFixedSize()
|
||||
binding.providersList.isNestedScrollingEnabled = false
|
||||
val mLayoutManager = LinearLayoutManager(context)
|
||||
providers_list.layoutManager = mLayoutManager
|
||||
binding.providersList.layoutManager = mLayoutManager
|
||||
|
||||
adapter = SlimAdapter.create()
|
||||
adapter
|
||||
@ -106,20 +106,18 @@ class GlanceTabFragment : Fragment() {
|
||||
it.setImageDrawable(ContextCompat.getDrawable(requireContext(), item.icon))
|
||||
}
|
||||
.clicked(R.id.item) {
|
||||
if (Preferences.showGlance) {
|
||||
if (provider == Constants.GlanceProviderId.CUSTOM_INFO) {
|
||||
CustomNotesDialog(requireContext()){
|
||||
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||
}.show()
|
||||
} else {
|
||||
dialog = GlanceSettingsDialog(requireActivity(), provider) {
|
||||
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||
}
|
||||
dialog?.setOnDismissListener {
|
||||
dialog = null
|
||||
}
|
||||
dialog?.show()
|
||||
if (provider == Constants.GlanceProviderId.CUSTOM_INFO) {
|
||||
CustomNotesDialog(requireContext()){
|
||||
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||
}.show()
|
||||
} else {
|
||||
dialog = GlanceSettingsDialog(requireActivity(), provider) {
|
||||
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||
}
|
||||
dialog?.setOnDismissListener {
|
||||
dialog = null
|
||||
}
|
||||
dialog?.show()
|
||||
}
|
||||
}
|
||||
var isVisible = false
|
||||
@ -130,9 +128,12 @@ class GlanceTabFragment : Fragment() {
|
||||
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
|
||||
injector.visibility(R.id.error_icon, View.GONE)
|
||||
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||
injector.text(R.id.label,
|
||||
injector.text(
|
||||
R.id.label,
|
||||
if (Preferences.showMusic) getString(R.string.settings_visible) else getString(
|
||||
R.string.settings_not_visible))
|
||||
R.string.settings_not_visible
|
||||
)
|
||||
)
|
||||
isVisible = Preferences.showMusic
|
||||
}
|
||||
Preferences.showMusic -> {
|
||||
@ -150,26 +151,40 @@ class GlanceTabFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
|
||||
injector.text(R.id.label,
|
||||
injector.text(
|
||||
R.id.label,
|
||||
if (Preferences.showNextAlarm && !AlarmHelper.isAlarmProbablyWrong(
|
||||
requireContext())
|
||||
requireContext()
|
||||
)
|
||||
) getString(R.string.settings_visible) else getString(
|
||||
R.string.settings_not_visible))
|
||||
injector.visibility(R.id.error_icon,
|
||||
R.string.settings_not_visible
|
||||
)
|
||||
)
|
||||
injector.visibility(
|
||||
R.id.error_icon,
|
||||
if (Preferences.showNextAlarm && AlarmHelper.isAlarmProbablyWrong(
|
||||
requireContext())
|
||||
) View.VISIBLE else View.GONE)
|
||||
injector.visibility(R.id.info_icon,
|
||||
requireContext()
|
||||
)
|
||||
) View.VISIBLE else View.GONE
|
||||
)
|
||||
injector.visibility(
|
||||
R.id.info_icon,
|
||||
if (!(Preferences.showNextAlarm && AlarmHelper.isAlarmProbablyWrong(
|
||||
requireContext()))
|
||||
) View.VISIBLE else View.GONE)
|
||||
isVisible = !(Preferences.showNextAlarm && AlarmHelper.isAlarmProbablyWrong(
|
||||
requireContext()))
|
||||
requireContext()
|
||||
))
|
||||
) View.VISIBLE else View.GONE
|
||||
)
|
||||
isVisible = (Preferences.showNextAlarm && !AlarmHelper.isAlarmProbablyWrong(
|
||||
requireContext()
|
||||
))
|
||||
}
|
||||
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
||||
injector.text(R.id.label,
|
||||
injector.text(
|
||||
R.id.label,
|
||||
if (Preferences.showBatteryCharging) getString(R.string.settings_visible) else getString(
|
||||
R.string.settings_not_visible))
|
||||
R.string.settings_not_visible
|
||||
)
|
||||
)
|
||||
injector.visibility(R.id.error_icon, View.GONE)
|
||||
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||
isVisible = Preferences.showBatteryCharging
|
||||
@ -179,9 +194,12 @@ class GlanceTabFragment : Fragment() {
|
||||
ActiveNotificationsHelper.checkNotificationAccess(requireContext()) -> {
|
||||
injector.visibility(R.id.error_icon, View.GONE)
|
||||
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||
injector.text(R.id.label,
|
||||
injector.text(
|
||||
R.id.label,
|
||||
if (Preferences.showNotifications) getString(
|
||||
R.string.settings_visible) else getString(R.string.settings_not_visible))
|
||||
R.string.settings_visible
|
||||
) else getString(R.string.settings_not_visible)
|
||||
)
|
||||
isVisible = Preferences.showNotifications
|
||||
}
|
||||
Preferences.showNotifications -> {
|
||||
@ -199,29 +217,44 @@ class GlanceTabFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.GREETINGS -> {
|
||||
injector.text(R.id.label,
|
||||
injector.text(
|
||||
R.id.label,
|
||||
if (Preferences.showGreetings) getString(R.string.settings_visible) else getString(
|
||||
R.string.settings_not_visible))
|
||||
R.string.settings_not_visible
|
||||
)
|
||||
)
|
||||
injector.visibility(R.id.error_icon, View.GONE)
|
||||
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||
isVisible = Preferences.showGreetings
|
||||
}
|
||||
Constants.GlanceProviderId.CUSTOM_INFO -> {
|
||||
injector.text(R.id.label,
|
||||
injector.text(
|
||||
R.id.label,
|
||||
if (Preferences.customNotes != "") getString(R.string.settings_visible) else getString(
|
||||
R.string.settings_not_visible))
|
||||
R.string.settings_not_visible
|
||||
)
|
||||
)
|
||||
injector.visibility(R.id.error_icon, View.GONE)
|
||||
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||
isVisible = Preferences.customNotes != ""
|
||||
}
|
||||
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
|
||||
val account: GoogleSignInAccount? = GoogleSignIn.getLastSignedInAccount(context)
|
||||
if (GoogleSignIn.hasPermissions(account, FITNESS_OPTIONS) && (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || activity?.checkGrantedPermission(
|
||||
Manifest.permission.ACTIVITY_RECOGNITION) == true)
|
||||
val account: GoogleSignInAccount? = GoogleSignIn.getLastSignedInAccount(
|
||||
context
|
||||
)
|
||||
if (GoogleSignIn.hasPermissions(
|
||||
account,
|
||||
FITNESS_OPTIONS
|
||||
) && (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || requireActivity().checkGrantedPermission(
|
||||
Manifest.permission.ACTIVITY_RECOGNITION
|
||||
))
|
||||
) {
|
||||
injector.text(R.id.label,
|
||||
injector.text(
|
||||
R.id.label,
|
||||
if (Preferences.showDailySteps) getString(R.string.settings_visible) else getString(
|
||||
R.string.settings_not_visible))
|
||||
R.string.settings_not_visible
|
||||
)
|
||||
)
|
||||
injector.visibility(R.id.error_icon, View.GONE)
|
||||
injector.visibility(R.id.info_icon, View.VISIBLE)
|
||||
isVisible = Preferences.showDailySteps
|
||||
@ -240,12 +273,25 @@ class GlanceTabFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.EVENTS -> {
|
||||
isVisible = Preferences.showEventsAsGlanceProvider && Preferences.showEvents && requireContext().checkGrantedPermission(Manifest.permission.READ_CALENDAR)
|
||||
injector.text(R.id.label,
|
||||
if (isVisible) getString(R.string.settings_visible) else getString(
|
||||
R.string.settings_not_visible))
|
||||
injector.visibility(R.id.error_icon, if (isVisible) View.GONE else View.VISIBLE)
|
||||
injector.visibility(R.id.info_icon, if (isVisible) View.VISIBLE else View.GONE)
|
||||
isVisible =
|
||||
Preferences.showEventsAsGlanceProvider
|
||||
val hasError = !Preferences.showEvents || !requireContext().checkGrantedPermission(
|
||||
Manifest.permission.READ_CALENDAR
|
||||
)
|
||||
injector.text(
|
||||
R.id.label,
|
||||
if (isVisible && !hasError) getString(R.string.settings_visible) else getString(
|
||||
R.string.settings_not_visible
|
||||
)
|
||||
)
|
||||
injector.visibility(
|
||||
R.id.error_icon,
|
||||
if (isVisible && hasError) View.VISIBLE else View.GONE
|
||||
)
|
||||
injector.visibility(
|
||||
R.id.info_icon,
|
||||
if (!(isVisible && hasError)) View.VISIBLE else View.GONE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -253,7 +299,7 @@ class GlanceTabFragment : Fragment() {
|
||||
injector.alpha(R.id.label, if (isVisible) 1f else .25f)
|
||||
injector.alpha(R.id.icon, if (isVisible) 1f else .25f)
|
||||
}
|
||||
.attachTo(providers_list)
|
||||
.attachTo(binding.providersList)
|
||||
|
||||
val mIth = ItemTouchHelper(
|
||||
object : ItemTouchHelper.SimpleCallback(
|
||||
@ -300,7 +346,12 @@ class GlanceTabFragment : Fragment() {
|
||||
GlanceProviderHelper.saveGlanceProviderOrder(
|
||||
list
|
||||
)
|
||||
adapter.updateData(list.mapNotNull { GlanceProviderHelper.getGlanceProviderById(requireContext(), it) })
|
||||
adapter.updateData(list.mapNotNull {
|
||||
GlanceProviderHelper.getGlanceProviderById(
|
||||
requireContext(),
|
||||
it
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
override fun onChildDraw(
|
||||
@ -314,24 +365,38 @@ class GlanceTabFragment : Fragment() {
|
||||
) {
|
||||
val view = viewHolder.itemView as MaterialCardView
|
||||
if (isCurrentlyActive) {
|
||||
ViewCompat.setElevation(view, 2f.convertDpToPixel(requireContext()))
|
||||
view.setCardBackgroundColor(ContextCompat.getColor(requireContext(),
|
||||
R.color.colorPrimary))
|
||||
ViewCompat.setElevation(view, 8f.convertDpToPixel(requireContext()))
|
||||
view.setCardBackgroundColor(
|
||||
ContextCompat.getColor(
|
||||
requireContext(),
|
||||
R.color.cardBorder
|
||||
)
|
||||
)
|
||||
} else {
|
||||
ViewCompat.setElevation(view, 0f)
|
||||
view.setCardBackgroundColor(ContextCompat.getColor(requireContext(),
|
||||
R.color.colorPrimaryDark))
|
||||
view.setCardBackgroundColor(
|
||||
ContextCompat.getColor(
|
||||
requireContext(),
|
||||
R.color.colorPrimary
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val topEdge = if ((view.top == 0 && dY < 0) || ((view.top + view.height >= recyclerView.height - 32f.convertDpToPixel(requireContext())) && dY > 0)) 0f else dY
|
||||
val topEdge =
|
||||
if ((view.top == 0 && dY < 0) || ((view.top + view.height >= recyclerView.height - 32f.convertDpToPixel(
|
||||
requireContext()
|
||||
)) && dY > 0)
|
||||
) 0f else dY
|
||||
|
||||
super.onChildDraw(c,
|
||||
super.onChildDraw(
|
||||
c,
|
||||
recyclerView,
|
||||
viewHolder,
|
||||
dX,
|
||||
topEdge,
|
||||
actionState,
|
||||
isCurrentlyActive)
|
||||
isCurrentlyActive
|
||||
)
|
||||
}
|
||||
|
||||
override fun onSwiped(
|
||||
@ -342,42 +407,34 @@ class GlanceTabFragment : Fragment() {
|
||||
}
|
||||
})
|
||||
|
||||
mIth.attachToRecyclerView(providers_list)
|
||||
adapter.updateData(list.mapNotNull { GlanceProviderHelper.getGlanceProviderById(requireContext(), it) })
|
||||
providers_list.isNestedScrollingEnabled = false
|
||||
mIth.attachToRecyclerView(binding.providersList)
|
||||
|
||||
setupListener()
|
||||
}
|
||||
|
||||
private fun subscribeUi(
|
||||
binding: FragmentGlanceSettingsBinding,
|
||||
viewModel: MainViewModel,
|
||||
) {
|
||||
binding.isGlanceVisible = Preferences.showGlance
|
||||
binding.scrollView.viewTreeObserver.addOnScrollChangedListener {
|
||||
viewModel.fragmentScrollY.value = binding.scrollView.scrollY
|
||||
}
|
||||
|
||||
viewModel.showGlance.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
binding.isGlanceVisible = it
|
||||
show_glance_label.text =
|
||||
if (it) getString(R.string.description_show_glance_visible) else getString(
|
||||
R.string.description_show_glance_not_visible)
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
delay(500)
|
||||
val l = list.mapNotNull { GlanceProviderHelper.getGlanceProviderById(
|
||||
requireContext(),
|
||||
it
|
||||
) }
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.loader.animate().scaleX(0f).scaleY(0f).alpha(0f).start()
|
||||
adapter.updateData(l)
|
||||
val controller =
|
||||
AnimationUtils.loadLayoutAnimation(context, R.anim.layout_animation_fall_down)
|
||||
|
||||
binding.providersList.layoutAnimation = controller
|
||||
adapter.notifyDataSetChanged()
|
||||
binding.providersList.scheduleLayoutAnimation()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
action_show_glance.setOnClickListener {
|
||||
Preferences.showGlance = !Preferences.showGlance
|
||||
}
|
||||
|
||||
show_glance_switch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
||||
Preferences.showGlance = enabled
|
||||
}
|
||||
|
||||
action_show_glance.setOnLongClickListener {
|
||||
Preferences.enabledGlanceProviderOrder = ""
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private val nextAlarmChangeBroadcastReceiver = object : BroadcastReceiver() {
|
||||
@ -388,15 +445,17 @@ class GlanceTabFragment : Fragment() {
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
activity?.registerReceiver(nextAlarmChangeBroadcastReceiver,
|
||||
IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED))
|
||||
requireActivity().registerReceiver(
|
||||
nextAlarmChangeBroadcastReceiver,
|
||||
IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)
|
||||
)
|
||||
if (dialog != null) {
|
||||
dialog?.show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
activity?.unregisterReceiver(nextAlarmChangeBroadcastReceiver)
|
||||
requireActivity().unregisterReceiver(nextAlarmChangeBroadcastReceiver)
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
@ -420,13 +479,15 @@ class GlanceTabFragment : Fragment() {
|
||||
2 -> {
|
||||
try {
|
||||
val account: GoogleSignInAccount? = GoogleSignIn.getSignedInAccountFromIntent(
|
||||
data).getResult(ApiException::class.java)
|
||||
data
|
||||
).getResult(ApiException::class.java)
|
||||
if (!GoogleSignIn.hasPermissions(account, FITNESS_OPTIONS)) {
|
||||
GoogleSignIn.requestPermissions(
|
||||
requireActivity(),
|
||||
1,
|
||||
account,
|
||||
FITNESS_OPTIONS)
|
||||
FITNESS_OPTIONS
|
||||
)
|
||||
} else {
|
||||
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||
}
|
||||
@ -442,18 +503,9 @@ class GlanceTabFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||
scrollView.isScrollable = false
|
||||
callback.invoke()
|
||||
lifecycleScope.launch {
|
||||
delay(200)
|
||||
scrollView.isScrollable = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
adapter.notifyItemRangeChanged(0, adapter.data.size)
|
||||
adapter.notifyItemRangeChanged(0, adapter.data?.size ?: 0)
|
||||
if (dialog != null) {
|
||||
dialog?.show()
|
||||
}
|
@ -0,0 +1,268 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.fragments.tabs
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||
import com.tommasoberlose.anotherwidget.databinding.FragmentTabLayoutBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toHexValue
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
|
||||
class LayoutFragment : Fragment() {
|
||||
|
||||
companion object {
|
||||
fun newInstance() = LayoutFragment()
|
||||
}
|
||||
|
||||
private lateinit var viewModel: MainViewModel
|
||||
private lateinit var colors: IntArray
|
||||
private lateinit var binding: FragmentTabLayoutBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
|
||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||
binding = FragmentTabLayoutBinding.inflate(inflater)
|
||||
|
||||
subscribeUi(viewModel)
|
||||
|
||||
binding.lifecycleOwner = this
|
||||
binding.viewModel = viewModel
|
||||
binding.isDarkModeEnabled = requireActivity().isDarkTheme()
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
|
||||
binding.showDividersToggle.setCheckedImmediatelyNoEvent(Preferences.showDividers)
|
||||
|
||||
setupListener()
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val lazyColors = requireContext().resources.getIntArray(R.array.material_colors)
|
||||
withContext(Dispatchers.Main) {
|
||||
colors = lazyColors
|
||||
}
|
||||
}
|
||||
|
||||
binding.scrollView.viewTreeObserver?.addOnScrollChangedListener {
|
||||
viewModel.fragmentScrollY.value = binding.scrollView.scrollY
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
private fun subscribeUi(
|
||||
viewModel: MainViewModel
|
||||
) {
|
||||
|
||||
viewModel.secondRowTopMargin.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.secondRowTopMarginLabel.text = when (it) {
|
||||
Constants.SecondRowTopMargin.NONE.rawValue -> getString(R.string.settings_clock_bottom_margin_subtitle_none)
|
||||
Constants.SecondRowTopMargin.SMALL.rawValue -> getString(R.string.settings_clock_bottom_margin_subtitle_small)
|
||||
Constants.SecondRowTopMargin.LARGE.rawValue -> getString(R.string.settings_clock_bottom_margin_subtitle_large)
|
||||
else -> getString(R.string.settings_clock_bottom_margin_subtitle_medium)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.widgetAlign.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.widgetAlignIcon.setImageDrawable(when (it) {
|
||||
Constants.WidgetAlign.LEFT.rawValue -> ContextCompat.getDrawable(requireContext(), R.drawable.round_align_horizontal_left_24)
|
||||
Constants.WidgetAlign.RIGHT.rawValue -> ContextCompat.getDrawable(requireContext(), R.drawable.round_align_horizontal_right_24)
|
||||
Constants.WidgetAlign.CENTER.rawValue -> ContextCompat.getDrawable(requireContext(), R.drawable.round_align_horizontal_center_24)
|
||||
else -> ContextCompat.getDrawable(requireContext(), R.drawable.round_align_horizontal_center_24)
|
||||
})
|
||||
|
||||
binding.widgetAlignLabel.text = when (it) {
|
||||
Constants.WidgetAlign.LEFT.rawValue -> getString(R.string.settings_widget_align_left_subtitle)
|
||||
Constants.WidgetAlign.RIGHT.rawValue -> getString(R.string.settings_widget_align_right_subtitle)
|
||||
Constants.WidgetAlign.CENTER.rawValue -> getString(R.string.settings_widget_align_center_subtitle)
|
||||
else -> getString(R.string.settings_widget_align_center_subtitle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.clockBottomMargin.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.clockBottomMarginLabel.text = when (it) {
|
||||
Constants.ClockBottomMargin.NONE.rawValue -> getString(R.string.settings_clock_bottom_margin_subtitle_none)
|
||||
Constants.ClockBottomMargin.SMALL.rawValue -> getString(R.string.settings_clock_bottom_margin_subtitle_small)
|
||||
Constants.ClockBottomMargin.LARGE.rawValue -> getString(R.string.settings_clock_bottom_margin_subtitle_large)
|
||||
else -> getString(R.string.settings_clock_bottom_margin_subtitle_medium)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.backgroundCardColor.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
if (ColorHelper.getBackgroundAlpha(requireActivity().isDarkTheme()) == 0) {
|
||||
binding.backgroundColorLabel.text = getString(R.string.transparent)
|
||||
} else {
|
||||
binding.backgroundColorLabel.text =
|
||||
"#%s".format(Integer.toHexString(ColorHelper.getBackgroundColor(requireActivity().isDarkTheme()))).toUpperCase()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.showDividers.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.showDividersLabel.text =
|
||||
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
|
||||
binding.actionSecondRowTopMarginSize.setOnClickListener {
|
||||
BottomSheetMenu<Int>(
|
||||
requireContext(),
|
||||
header = getString(R.string.settings_secondary_row_top_margin_title)
|
||||
).setSelectedValue(Preferences.secondRowTopMargin)
|
||||
.addItem(
|
||||
getString(R.string.settings_clock_bottom_margin_subtitle_none),
|
||||
Constants.SecondRowTopMargin.NONE.rawValue
|
||||
)
|
||||
.addItem(
|
||||
getString(R.string.settings_clock_bottom_margin_subtitle_small),
|
||||
Constants.SecondRowTopMargin.SMALL.rawValue
|
||||
)
|
||||
.addItem(
|
||||
getString(R.string.settings_clock_bottom_margin_subtitle_medium),
|
||||
Constants.SecondRowTopMargin.MEDIUM.rawValue
|
||||
)
|
||||
.addItem(
|
||||
getString(R.string.settings_clock_bottom_margin_subtitle_large),
|
||||
Constants.SecondRowTopMargin.LARGE.rawValue
|
||||
)
|
||||
.addOnSelectItemListener { value ->
|
||||
Preferences.secondRowTopMargin = value
|
||||
}.show()
|
||||
}
|
||||
|
||||
binding.actionClockBottomMarginSize.setOnClickListener {
|
||||
BottomSheetMenu<Int>(
|
||||
requireContext(),
|
||||
header = getString(R.string.settings_clock_bottom_margin_title)
|
||||
).setSelectedValue(Preferences.clockBottomMargin)
|
||||
.addItem(
|
||||
getString(R.string.settings_clock_bottom_margin_subtitle_none),
|
||||
Constants.ClockBottomMargin.NONE.rawValue
|
||||
)
|
||||
.addItem(
|
||||
getString(R.string.settings_clock_bottom_margin_subtitle_small),
|
||||
Constants.ClockBottomMargin.SMALL.rawValue
|
||||
)
|
||||
.addItem(
|
||||
getString(R.string.settings_clock_bottom_margin_subtitle_medium),
|
||||
Constants.ClockBottomMargin.MEDIUM.rawValue
|
||||
)
|
||||
.addItem(
|
||||
getString(R.string.settings_clock_bottom_margin_subtitle_large),
|
||||
Constants.ClockBottomMargin.LARGE.rawValue
|
||||
)
|
||||
.addOnSelectItemListener { value ->
|
||||
Preferences.clockBottomMargin = value
|
||||
}.show()
|
||||
}
|
||||
|
||||
binding.actionWidgetAlign.setOnClickListener {
|
||||
BottomSheetMenu<Int>(
|
||||
requireContext(),
|
||||
header = getString(R.string.settings_widget_align_title)
|
||||
).setSelectedValue(Preferences.widgetAlign)
|
||||
.addItem(
|
||||
getString(R.string.settings_widget_align_center_subtitle),
|
||||
Constants.WidgetAlign.CENTER.rawValue
|
||||
)
|
||||
.addItem(
|
||||
getString(R.string.settings_widget_align_left_subtitle),
|
||||
Constants.WidgetAlign.LEFT.rawValue
|
||||
)
|
||||
.addItem(
|
||||
getString(R.string.settings_widget_align_right_subtitle),
|
||||
Constants.WidgetAlign.RIGHT.rawValue
|
||||
)
|
||||
.addOnSelectItemListener { value ->
|
||||
Preferences.widgetAlign = value
|
||||
}.show()
|
||||
}
|
||||
|
||||
binding.actionBackgroundColor.setOnClickListener {
|
||||
BottomSheetColorPicker(requireContext(),
|
||||
colors = colors,
|
||||
header = getString(R.string.settings_background_color_title),
|
||||
getSelected = { ColorHelper.getBackgroundColorRgb(requireActivity().isDarkTheme()) },
|
||||
onColorSelected = { color: Int ->
|
||||
val colorString = Integer.toHexString(color)
|
||||
if (requireActivity().isDarkTheme()) {
|
||||
Preferences.backgroundCardColorDark =
|
||||
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||
} else {
|
||||
Preferences.backgroundCardColor =
|
||||
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||
}
|
||||
},
|
||||
showAlphaSelector = true,
|
||||
alpha = if (requireActivity().isDarkTheme()) Preferences.backgroundCardAlphaDark.toIntValue() else Preferences.backgroundCardAlpha.toIntValue(),
|
||||
onAlphaChangeListener = { alpha ->
|
||||
if (requireActivity().isDarkTheme()) {
|
||||
Preferences.backgroundCardAlphaDark = alpha.toHexValue()
|
||||
} else {
|
||||
Preferences.backgroundCardAlpha = alpha.toHexValue()
|
||||
}
|
||||
}
|
||||
).show()
|
||||
}
|
||||
|
||||
binding.actionShowDividers.setOnClickListener {
|
||||
binding.showDividersToggle.isChecked = !binding.showDividersToggle.isChecked
|
||||
}
|
||||
|
||||
binding.showDividersToggle.setOnCheckedChangeListener { _, isChecked ->
|
||||
Preferences.showDividers = isChecked
|
||||
}
|
||||
}
|
||||
|
||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||
binding.scrollView.isScrollable = false
|
||||
callback.invoke()
|
||||
lifecycleScope.launch {
|
||||
delay(200)
|
||||
binding.scrollView.isScrollable = true
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,206 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.fragments.tabs
|
||||
|
||||
import android.Manifest
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.Navigation
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import com.karumi.dexter.Dexter
|
||||
import com.karumi.dexter.MultiplePermissionsReport
|
||||
import com.karumi.dexter.PermissionToken
|
||||
import com.karumi.dexter.listener.PermissionRequest
|
||||
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
|
||||
import com.tommasoberlose.anotherwidget.databinding.FragmentPreferencesBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
||||
import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||
import com.tommasoberlose.anotherwidget.utils.*
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class PreferencesFragment : Fragment() {
|
||||
|
||||
companion object {
|
||||
fun newInstance() = PreferencesFragment()
|
||||
}
|
||||
|
||||
private lateinit var viewModel: MainViewModel
|
||||
private lateinit var binding: FragmentPreferencesBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
|
||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||
binding = FragmentPreferencesBinding.inflate(inflater)
|
||||
|
||||
subscribeUi(viewModel)
|
||||
|
||||
binding.lifecycleOwner = this
|
||||
binding.viewModel = viewModel
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
|
||||
setupListener()
|
||||
|
||||
binding.showEventsSwitch.setCheckedImmediatelyNoEvent(Preferences.showEvents)
|
||||
binding.showWeatherSwitch.setCheckedImmediatelyNoEvent(Preferences.showWeather)
|
||||
binding.showClockSwitch.setCheckedImmediatelyNoEvent(Preferences.showClock)
|
||||
|
||||
binding.scrollView.viewTreeObserver.addOnScrollChangedListener {
|
||||
viewModel.fragmentScrollY.value = binding.scrollView.scrollY
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeUi(
|
||||
viewModel: MainViewModel
|
||||
) {
|
||||
|
||||
viewModel.showEvents.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.showEventsSwitch.setCheckedImmediatelyNoEvent(it)
|
||||
if (it) {
|
||||
CalendarHelper.setEventUpdatesAndroidN(requireContext())
|
||||
} else {
|
||||
CalendarHelper.removeEventUpdatesAndroidN(requireContext())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.showWeather.observe(viewLifecycleOwner) {
|
||||
checkWeatherProviderConfig()
|
||||
}
|
||||
|
||||
viewModel.weatherProviderError.observe(viewLifecycleOwner) {
|
||||
checkWeatherProviderConfig()
|
||||
}
|
||||
|
||||
viewModel.weatherProviderLocationError.observe(viewLifecycleOwner) {
|
||||
checkWeatherProviderConfig()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
|
||||
binding.actionTypography.setOnSingleClickListener {
|
||||
Navigation.findNavController(it).navigate(R.id.action_tabSelectorFragment_to_typographyTabFragment)
|
||||
}
|
||||
|
||||
binding.actionGeneralSettings.setOnSingleClickListener {
|
||||
Navigation.findNavController(it).navigate(R.id.action_tabSelectorFragment_to_generalTabFragment)
|
||||
}
|
||||
|
||||
binding.actionShowEvents.setOnSingleClickListener {
|
||||
Navigation.findNavController(it).navigate(R.id.action_tabSelectorFragment_to_calendarTabFragment)
|
||||
}
|
||||
|
||||
binding.showEventsSwitch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
||||
if (enabled) {
|
||||
requireCalendarPermission()
|
||||
} else {
|
||||
Preferences.showEvents = enabled
|
||||
}
|
||||
}
|
||||
|
||||
binding.actionShowWeather.setOnSingleClickListener {
|
||||
Navigation.findNavController(it).navigate(R.id.action_tabSelectorFragment_to_weatherTabFragment)
|
||||
}
|
||||
|
||||
binding.showWeatherSwitch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
||||
Preferences.showWeather = enabled
|
||||
if (enabled) {
|
||||
WeatherReceiver.setUpdates(requireContext())
|
||||
} else {
|
||||
WeatherReceiver.removeUpdates(requireContext())
|
||||
}
|
||||
}
|
||||
|
||||
binding.actionShowClock.setOnSingleClickListener {
|
||||
Navigation.findNavController(it).navigate(R.id.action_tabSelectorFragment_to_clockTabFragment)
|
||||
}
|
||||
|
||||
binding.showClockSwitch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
||||
Preferences.showClock = enabled
|
||||
}
|
||||
|
||||
binding.actionShowGlance.setOnSingleClickListener {
|
||||
Navigation.findNavController(it).navigate(R.id.action_tabSelectorFragment_to_glanceTabFragment)
|
||||
}
|
||||
|
||||
binding.actionTabDefaultApp.setOnSingleClickListener {
|
||||
Navigation.findNavController(it).navigate(R.id.action_tabSelectorFragment_to_gesturesFragment)
|
||||
}
|
||||
}
|
||||
|
||||
private fun requireCalendarPermission() {
|
||||
Dexter.withContext(requireContext())
|
||||
.withPermissions(
|
||||
Manifest.permission.READ_CALENDAR
|
||||
).withListener(object: MultiplePermissionsListener {
|
||||
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
||||
report?.let {
|
||||
val granted = report.areAllPermissionsGranted()
|
||||
Preferences.showEvents = granted
|
||||
if (granted) {
|
||||
CalendarHelper.updateEventList(requireContext())
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun onPermissionRationaleShouldBeShown(
|
||||
permissions: MutableList<PermissionRequest>?,
|
||||
token: PermissionToken?
|
||||
) {
|
||||
// Remember to invoke this method when the custom rationale is closed
|
||||
// or just by default if you don't want to use any custom rationale.
|
||||
token?.continuePermissionRequest()
|
||||
}
|
||||
})
|
||||
.check()
|
||||
}
|
||||
|
||||
private fun checkWeatherProviderConfig() {
|
||||
binding.weatherProviderError.isVisible = Preferences.showWeather && Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-"
|
||||
binding.weatherProviderError.text = Preferences.weatherProviderError
|
||||
|
||||
binding.weatherProviderLocationError.isVisible = Preferences.showWeather && Preferences.weatherProviderLocationError != ""
|
||||
binding.weatherProviderLocationError.text = Preferences.weatherProviderLocationError
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
binding.showEventsSwitch.setCheckedNoEvent(Preferences.showEvents && requireActivity().checkGrantedPermission(Manifest.permission.READ_CALENDAR))
|
||||
}
|
||||
|
||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||
binding.scrollView.isScrollable = false
|
||||
callback.invoke()
|
||||
lifecycleScope.launch {
|
||||
delay(200)
|
||||
binding.scrollView.isScrollable = true
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,328 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.fragments.tabs
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.chibatching.kotpref.blockingBulk
|
||||
import com.chibatching.kotpref.bulk
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetPicker
|
||||
import com.tommasoberlose.anotherwidget.databinding.FragmentTabTypographyBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.global.RequestCode
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toHexValue
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
||||
import com.tommasoberlose.anotherwidget.helpers.DateHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.tabs.CustomFontActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.tabs.CustomDateActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.*
|
||||
|
||||
class TypographyFragment : Fragment() {
|
||||
|
||||
companion object {
|
||||
fun newInstance() = TypographyFragment()
|
||||
}
|
||||
|
||||
private lateinit var viewModel: MainViewModel
|
||||
private lateinit var colors: IntArray
|
||||
|
||||
private lateinit var binding: FragmentTabTypographyBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
|
||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||
binding = FragmentTabTypographyBinding.inflate(inflater)
|
||||
|
||||
subscribeUi(viewModel)
|
||||
|
||||
binding.lifecycleOwner = this
|
||||
binding.viewModel = viewModel
|
||||
binding.isDarkModeEnabled = activity?.isDarkTheme() == true
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
|
||||
setupListener()
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val lazyColors = requireContext().resources.getIntArray(R.array.material_colors)
|
||||
withContext(Dispatchers.Main) {
|
||||
colors = lazyColors
|
||||
}
|
||||
}
|
||||
|
||||
binding.scrollView.viewTreeObserver.addOnScrollChangedListener {
|
||||
viewModel.fragmentScrollY.value = binding.scrollView.scrollY
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
private fun subscribeUi(
|
||||
viewModel: MainViewModel
|
||||
) {
|
||||
|
||||
viewModel.textMainSize.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.mainTextSizeLabel.text = String.format("%.0fsp", it)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.textSecondSize.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.secondTextSizeLabel.text = String.format("%.0fsp", it)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.textGlobalColor.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
if (Preferences.textGlobalAlpha == "00") {
|
||||
binding.fontColorLabel.text = getString(R.string.transparent)
|
||||
} else {
|
||||
binding.fontColorLabel.text =
|
||||
"#%s".format(Integer.toHexString(ColorHelper.getFontColor(requireActivity().isDarkTheme()))).toUpperCase()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.textSecondaryColor.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
if (Preferences.textSecondaryAlpha == "00") {
|
||||
binding.secondaryFontColorLabel.text = getString(R.string.transparent)
|
||||
} else {
|
||||
binding.secondaryFontColorLabel.text =
|
||||
"#%s".format(Integer.toHexString(ColorHelper.getSecondaryFontColor(requireActivity().isDarkTheme()))).toUpperCase()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.textShadow.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
if (requireActivity().isDarkTheme()) {
|
||||
binding.textShadowLabel.text =
|
||||
getString(SettingsStringHelper.getTextShadowString(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.textShadow.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
if (!requireActivity().isDarkTheme()) {
|
||||
binding.textShadowLabel.text =
|
||||
getString(SettingsStringHelper.getTextShadowString(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.textShadowDark.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
if (requireActivity().isDarkTheme()) {
|
||||
binding.textShadowLabel.text =
|
||||
getString(SettingsStringHelper.getTextShadowString(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.font.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.customFontLabel.text = SettingsStringHelper.getCustomFontLabel(requireContext(), Preferences.customFont)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.dateFormat.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.dateFormatLabel.text = DateHelper.getDateText(requireContext(), Calendar.getInstance())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
binding.actionMainTextSize.setOnClickListener {
|
||||
BottomSheetPicker(
|
||||
requireContext(),
|
||||
items = (40 downTo 10).map { BottomSheetPicker.MenuItem("${it}sp", it.toFloat()) },
|
||||
getSelected = { Preferences.textMainSize },
|
||||
header = getString(R.string.title_main_text_size),
|
||||
onItemSelected = {value ->
|
||||
if (value != null) Preferences.textMainSize = value
|
||||
}
|
||||
).show()
|
||||
}
|
||||
|
||||
binding.actionSecondTextSize.setOnClickListener {
|
||||
BottomSheetPicker(
|
||||
requireContext(),
|
||||
items = (40 downTo 10).map { BottomSheetPicker.MenuItem("${it}sp", it.toFloat()) },
|
||||
getSelected = { Preferences.textSecondSize },
|
||||
header = getString(R.string.title_second_text_size),
|
||||
onItemSelected = {value ->
|
||||
if (value != null) Preferences.textSecondSize = value
|
||||
}
|
||||
).show()
|
||||
}
|
||||
|
||||
binding.actionFontColor.setOnClickListener {
|
||||
BottomSheetColorPicker(requireContext(),
|
||||
colors = colors,
|
||||
header = getString(R.string.settings_font_color_title),
|
||||
getSelected = { ColorHelper.getFontColorRgb(requireActivity().isDarkTheme()) },
|
||||
onColorSelected = { color: Int ->
|
||||
val colorString = Integer.toHexString(color)
|
||||
if (requireActivity().isDarkTheme()) {
|
||||
Preferences.textGlobalColorDark = "#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||
} else {
|
||||
Preferences.textGlobalColor = "#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||
}
|
||||
},
|
||||
showAlphaSelector = true,
|
||||
alpha = if (requireActivity().isDarkTheme()) Preferences.textGlobalAlphaDark.toIntValue() else Preferences.textGlobalAlpha.toIntValue(),
|
||||
onAlphaChangeListener = { alpha ->
|
||||
if (requireActivity().isDarkTheme()) {
|
||||
Preferences.textGlobalAlphaDark = alpha.toHexValue()
|
||||
} else {
|
||||
Preferences.textGlobalAlpha = alpha.toHexValue()
|
||||
}
|
||||
},
|
||||
).show()
|
||||
}
|
||||
|
||||
binding.actionSecondaryFontColor.setOnClickListener {
|
||||
BottomSheetColorPicker(requireContext(),
|
||||
colors = colors,
|
||||
header = getString(R.string.settings_secondary_font_color_title),
|
||||
getSelected = { ColorHelper.getSecondaryFontColorRgb(requireActivity().isDarkTheme()) },
|
||||
onColorSelected = { color: Int ->
|
||||
val colorString = Integer.toHexString(color)
|
||||
if (requireActivity().isDarkTheme()) {
|
||||
Preferences.textSecondaryColorDark =
|
||||
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||
} else {
|
||||
Preferences.textSecondaryColor =
|
||||
"#" + if (colorString.length > 6) colorString.substring(2) else colorString
|
||||
}
|
||||
},
|
||||
showAlphaSelector = true,
|
||||
alpha = if (requireActivity().isDarkTheme()) Preferences.textSecondaryAlphaDark.toIntValue() else Preferences.textSecondaryAlpha.toIntValue(),
|
||||
onAlphaChangeListener = { alpha ->
|
||||
if (requireActivity().isDarkTheme()) {
|
||||
Preferences.textSecondaryAlphaDark = alpha.toHexValue()
|
||||
} else {
|
||||
Preferences.textSecondaryAlpha = alpha.toHexValue()
|
||||
}
|
||||
},
|
||||
).show()
|
||||
}
|
||||
|
||||
binding.actionTextShadow.setOnClickListener {
|
||||
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.title_text_shadow)).setSelectedValue(if (requireActivity().isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow)
|
||||
(2 downTo 0).forEach {
|
||||
dialog.addItem(getString(SettingsStringHelper.getTextShadowString(it)), it)
|
||||
}
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
if (requireActivity().isDarkTheme()) {
|
||||
Preferences.textShadowDark = value
|
||||
} else {
|
||||
Preferences.textShadow = value
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
|
||||
binding.actionCustomFont.setOnClickListener {
|
||||
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_custom_font_title)).setSelectedValue(
|
||||
Preferences.customFont)
|
||||
dialog.addItem(SettingsStringHelper.getCustomFontLabel(requireContext(), 0), 0)
|
||||
|
||||
if (Preferences.customFont == Constants.CUSTOM_FONT_GOOGLE_SANS) {
|
||||
dialog.addItem(SettingsStringHelper.getCustomFontLabel(requireContext(), Constants.CUSTOM_FONT_GOOGLE_SANS), Constants.CUSTOM_FONT_GOOGLE_SANS)
|
||||
}
|
||||
|
||||
if (Preferences.customFontFile != "") {
|
||||
dialog.addItem(SettingsStringHelper.getCustomFontLabel(requireContext(), Preferences.customFont), Constants.CUSTOM_FONT_DOWNLOADED)
|
||||
}
|
||||
dialog.addItem(getString(R.string.action_custom_font_to_search), Constants.CUSTOM_FONT_DOWNLOAD_NEW)
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
if (value == Constants.CUSTOM_FONT_DOWNLOAD_NEW) {
|
||||
startActivityForResult(
|
||||
Intent(requireContext(), CustomFontActivity::class.java),
|
||||
RequestCode.CUSTOM_FONT_CHOOSER_REQUEST_CODE.code
|
||||
)
|
||||
} else if (value != Constants.CUSTOM_FONT_DOWNLOADED) {
|
||||
Preferences.bulk {
|
||||
customFont = value
|
||||
customFontFile = ""
|
||||
customFontName = ""
|
||||
customFontVariant = ""
|
||||
}
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
|
||||
binding.actionDateFormat.setOnClickListener {
|
||||
val now = Calendar.getInstance()
|
||||
val dialog = BottomSheetMenu<String>(requireContext(), header = getString(R.string.settings_date_format_title)).setSelectedValue(Preferences.dateFormat)
|
||||
|
||||
dialog.addItem(DateHelper.getDefaultDateText(requireContext(), now), "")
|
||||
if (Preferences.dateFormat != "") {
|
||||
dialog.addItem(DateHelper.getDateText(requireContext(), now), Preferences.dateFormat)
|
||||
}
|
||||
dialog.addItem(getString(R.string.custom_date_format), "-")
|
||||
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
when (value) {
|
||||
"-" -> {
|
||||
startActivity(Intent(requireContext(), CustomDateActivity::class.java))
|
||||
}
|
||||
"" -> {
|
||||
Preferences.blockingBulk {
|
||||
isDateCapitalize = false
|
||||
isDateUppercase = false
|
||||
}
|
||||
Preferences.dateFormat = value
|
||||
}
|
||||
else -> {
|
||||
Preferences.dateFormat = value
|
||||
}
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||
binding.scrollView.isScrollable = false
|
||||
callback.invoke()
|
||||
lifecycleScope.launch {
|
||||
delay(200)
|
||||
binding.scrollView.isScrollable = true
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,252 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.fragments.tabs
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.chibatching.kotpref.bulk
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import com.karumi.dexter.Dexter
|
||||
import com.karumi.dexter.MultiplePermissionsReport
|
||||
import com.karumi.dexter.PermissionToken
|
||||
import com.karumi.dexter.listener.PermissionRequest
|
||||
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||
import com.tommasoberlose.anotherwidget.components.IconPackSelector
|
||||
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
|
||||
import com.tommasoberlose.anotherwidget.databinding.FragmentTabWeatherBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.global.RequestCode
|
||||
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
||||
import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.tabs.ChooseApplicationActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.tabs.CustomLocationActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.tabs.WeatherProviderActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||
import com.tommasoberlose.anotherwidget.utils.collapse
|
||||
import com.tommasoberlose.anotherwidget.utils.expand
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class WeatherFragment : Fragment() {
|
||||
|
||||
companion object {
|
||||
fun newInstance() = WeatherFragment()
|
||||
}
|
||||
|
||||
private lateinit var viewModel: MainViewModel
|
||||
private lateinit var binding: FragmentTabWeatherBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
|
||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||
binding = FragmentTabWeatherBinding.inflate(inflater)
|
||||
|
||||
subscribeUi(viewModel)
|
||||
|
||||
binding.lifecycleOwner = this
|
||||
binding.viewModel = viewModel
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
setupListener()
|
||||
|
||||
binding.scrollView.viewTreeObserver.addOnScrollChangedListener {
|
||||
viewModel.fragmentScrollY.value = binding.scrollView.scrollY
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeUi(
|
||||
viewModel: MainViewModel
|
||||
) {
|
||||
binding.isWeatherVisible = Preferences.showWeather
|
||||
|
||||
viewModel.weatherProvider.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.labelWeatherProvider.text = WeatherHelper.getProviderName(requireContext(), Constants.WeatherProvider.fromInt(it)!!)
|
||||
checkWeatherProviderConfig()
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.weatherProviderError.observe(viewLifecycleOwner) {
|
||||
checkWeatherProviderConfig()
|
||||
}
|
||||
|
||||
viewModel.weatherProviderLocationError.observe(viewLifecycleOwner) {
|
||||
checkWeatherProviderConfig()
|
||||
}
|
||||
|
||||
viewModel.customLocationAdd.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.labelCustomLocation.text =
|
||||
if (it == "") getString(R.string.custom_location_gps) else it
|
||||
}
|
||||
checkLocationPermission()
|
||||
}
|
||||
|
||||
viewModel.weatherTempUnit.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.tempUnit.text =
|
||||
if (it == "F") getString(R.string.fahrenheit) else getString(R.string.celsius)
|
||||
}
|
||||
checkLocationPermission()
|
||||
}
|
||||
|
||||
viewModel.weatherRefreshPeriod.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.labelWeatherRefreshPeriod.text = getString(SettingsStringHelper.getRefreshPeriodString(it))
|
||||
}
|
||||
checkLocationPermission()
|
||||
}
|
||||
|
||||
viewModel.weatherIconPack.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.labelWeatherIconPack.text = getString(R.string.settings_weather_icon_pack_default).format((it + 1))
|
||||
}
|
||||
checkLocationPermission()
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkLocationPermission() {
|
||||
if (requireActivity().checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION)) {
|
||||
binding.locationPermissionAlert.isVisible = false
|
||||
WeatherReceiver.setUpdates(requireContext())
|
||||
} else if (Preferences.showWeather && Preferences.customLocationAdd == "") {
|
||||
binding.locationPermissionAlert.isVisible = true
|
||||
binding.locationPermissionAlert.setOnClickListener {
|
||||
requirePermission()
|
||||
}
|
||||
} else {
|
||||
binding.locationPermissionAlert.isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkWeatherProviderConfig() {
|
||||
binding.weatherProviderError.isVisible = Preferences.showWeather && Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-"
|
||||
binding.weatherProviderError.text = Preferences.weatherProviderError
|
||||
|
||||
binding.weatherProviderLocationError.isVisible = Preferences.showWeather && Preferences.weatherProviderLocationError != ""
|
||||
binding.weatherProviderLocationError.text = Preferences.weatherProviderLocationError
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
binding.actionWeatherProvider.setOnClickListener {
|
||||
startActivityForResult(
|
||||
Intent(requireContext(), WeatherProviderActivity::class.java),
|
||||
RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code
|
||||
)
|
||||
}
|
||||
|
||||
binding.actionCustomLocation.setOnClickListener {
|
||||
startActivityForResult(
|
||||
Intent(requireContext(), CustomLocationActivity::class.java),
|
||||
Constants.RESULT_CODE_CUSTOM_LOCATION
|
||||
)
|
||||
}
|
||||
|
||||
binding.actionChangeUnit.setOnClickListener {
|
||||
BottomSheetMenu<String>(requireContext(), header = getString(R.string.settings_unit_title)).setSelectedValue(Preferences.weatherTempUnit)
|
||||
.addItem(getString(R.string.fahrenheit), "F")
|
||||
.addItem(getString(R.string.celsius), "C")
|
||||
.addOnSelectItemListener { value ->
|
||||
if (value != Preferences.weatherTempUnit) {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
WeatherHelper.updateWeather(requireContext())
|
||||
}
|
||||
}
|
||||
Preferences.weatherTempUnit = value
|
||||
}.show()
|
||||
}
|
||||
|
||||
binding.actionWeatherRefreshPeriod.setOnClickListener {
|
||||
val dialog =
|
||||
BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_weather_refresh_period_title)).setSelectedValue(Preferences.weatherRefreshPeriod)
|
||||
(5 downTo 0).forEach {
|
||||
dialog.addItem(getString(SettingsStringHelper.getRefreshPeriodString(it)), it)
|
||||
}
|
||||
dialog
|
||||
.addOnSelectItemListener { value ->
|
||||
Preferences.weatherRefreshPeriod = value
|
||||
}.show()
|
||||
}
|
||||
|
||||
binding.actionWeatherIconPack.setOnClickListener {
|
||||
IconPackSelector(requireContext(), header = getString(R.string.settings_weather_icon_pack_title)).show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
Constants.RESULT_CODE_CUSTOM_LOCATION -> {
|
||||
WeatherReceiver.setUpdates(requireContext())
|
||||
checkLocationPermission()
|
||||
}
|
||||
RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code -> {
|
||||
checkLocationPermission()
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
private fun requirePermission() {
|
||||
Dexter.withContext(requireContext())
|
||||
.withPermissions(
|
||||
Manifest.permission.ACCESS_FINE_LOCATION
|
||||
).withListener(object: MultiplePermissionsListener {
|
||||
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
||||
report?.let {
|
||||
if (report.areAllPermissionsGranted()){
|
||||
checkLocationPermission()
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun onPermissionRationaleShouldBeShown(
|
||||
permissions: MutableList<PermissionRequest>?,
|
||||
token: PermissionToken?
|
||||
) {
|
||||
// Remember to invoke this method when the custom rationale is closed
|
||||
// or just by default if you don't want to use any custom rationale.
|
||||
token?.continuePermissionRequest()
|
||||
}
|
||||
})
|
||||
.check()
|
||||
}
|
||||
|
||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||
binding.scrollView.isScrollable = false
|
||||
callback.invoke()
|
||||
lifecycleScope.launch {
|
||||
delay(200)
|
||||
binding.scrollView.isScrollable = true
|
||||
}
|
||||
}
|
||||
}
|
@ -1,91 +1,177 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels
|
||||
|
||||
import android.app.Application
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import androidx.core.os.ConfigurationCompat
|
||||
import androidx.lifecycle.*
|
||||
import com.chibatching.kotpref.livedata.asLiveData
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColor
|
||||
import com.tommasoberlose.anotherwidget.utils.isMetric
|
||||
|
||||
class MainViewModel : ViewModel() {
|
||||
class MainViewModel(context: Application) : AndroidViewModel(context) {
|
||||
|
||||
// General Settings
|
||||
val textGlobalColor = Preferences.asLiveData(Preferences::textGlobalColor)
|
||||
val textGlobalAlpha = Preferences.asLiveData(Preferences::textGlobalAlpha)
|
||||
val textSecondaryColor = Preferences.asLiveData(Preferences::textSecondaryColor)
|
||||
val textSecondaryAlpha = Preferences.asLiveData(Preferences::textSecondaryAlpha)
|
||||
val backgroundCardColor = Preferences.asLiveData(Preferences::backgroundCardColor)
|
||||
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 textGlobalColor = MediatorLiveData<Boolean>().apply {
|
||||
addSource(Preferences.asLiveData(Preferences::textGlobalColor)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::textGlobalAlpha)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::textGlobalColorDark)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::textGlobalAlphaDark)) { value = true }
|
||||
}
|
||||
val textSecondaryColor = MediatorLiveData<Boolean>().apply {
|
||||
addSource(Preferences.asLiveData(Preferences::textSecondaryColor)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::textSecondaryAlpha)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::textSecondaryColorDark)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::textSecondaryAlphaDark)) { value = true }
|
||||
}
|
||||
val backgroundCardColor = MediatorLiveData<Boolean>().apply {
|
||||
addSource(Preferences.asLiveData(Preferences::backgroundCardColor)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::backgroundCardAlpha)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::backgroundCardColorDark)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::backgroundCardAlphaDark)) { value = true }
|
||||
}
|
||||
|
||||
val textMainSize = Preferences.asLiveData(Preferences::textMainSize)
|
||||
val textSecondSize = Preferences.asLiveData(Preferences::textSecondSize)
|
||||
val textShadow = Preferences.asLiveData(Preferences::textShadow)
|
||||
val textShadowDark = Preferences.asLiveData(Preferences::textShadowDark)
|
||||
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 font = MediatorLiveData<Boolean>().apply {
|
||||
addSource(Preferences.asLiveData(Preferences::customFont)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::customFontFile)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::customFontName)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::customFontVariant)) { value = true }
|
||||
}
|
||||
|
||||
val secondRowInformation = Preferences.asLiveData(Preferences::secondRowInformation)
|
||||
val showDividers = Preferences.asLiveData(Preferences::showDividers)
|
||||
val secondRowTopMargin = Preferences.asLiveData(Preferences::secondRowTopMargin)
|
||||
val widgetAlign = Preferences.asLiveData(Preferences::widgetAlign)
|
||||
|
||||
// Calendar Settings
|
||||
val showEvents = Preferences.asLiveData(Preferences::showEvents)
|
||||
val calendarAllDay = Preferences.asLiveData(Preferences::calendarAllDay)
|
||||
val showUntil = Preferences.asLiveData(Preferences::showUntil)
|
||||
val showDiffTime = Preferences.asLiveData(Preferences::showDiffTime)
|
||||
val showDeclinedEvents = Preferences.asLiveData(Preferences::showDeclinedEvents)
|
||||
val showNextEvent = Preferences.asLiveData(Preferences::showNextEvent)
|
||||
val showNextEventOnMultipleLines = Preferences.asLiveData(Preferences::showNextEventOnMultipleLines)
|
||||
val openEventDetails = Preferences.asLiveData(Preferences::openEventDetails)
|
||||
val calendarAppName = Preferences.asLiveData(Preferences::calendarAppName)
|
||||
val widgetUpdateFrequency = Preferences.asLiveData(Preferences::widgetUpdateFrequency)
|
||||
val showOnlyBusyEvents = Preferences.asLiveData(Preferences::showOnlyBusyEvents)
|
||||
val dateFormat = Preferences.asLiveData(Preferences::dateFormat)
|
||||
|
||||
// Clock Settings
|
||||
val showClock = Preferences.asLiveData(Preferences::showClock)
|
||||
val clockTextSize = Preferences.asLiveData(Preferences::clockTextSize)
|
||||
val clockTextColor = Preferences.asLiveData(Preferences::clockTextColor)
|
||||
val clockTextAlpha = Preferences.asLiveData(Preferences::clockTextAlpha)
|
||||
val clockTextColorDark = Preferences.asLiveData(Preferences::clockTextColorDark)
|
||||
val clockTextAlphaDark = Preferences.asLiveData(Preferences::clockTextAlphaDark)
|
||||
val altTimezoneLabel = Preferences.asLiveData(Preferences::altTimezoneLabel)
|
||||
val clockTextColor = MediatorLiveData<Boolean>().apply {
|
||||
addSource(Preferences.asLiveData(Preferences::clockTextColor)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::clockTextAlpha)) { value = true }
|
||||
}
|
||||
val clockTextColorDark = MediatorLiveData<Boolean>().apply {
|
||||
addSource(Preferences.asLiveData(Preferences::clockTextColorDark)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::clockTextAlphaDark)) { value = true }
|
||||
}
|
||||
val showAMPMIndicator = Preferences.asLiveData(Preferences::showAMPMIndicator)
|
||||
|
||||
val clockAppName = Preferences.asLiveData(Preferences::clockAppName)
|
||||
val dateFormat = Preferences.asLiveData(Preferences::dateFormat)
|
||||
val clockBottomMargin = Preferences.asLiveData(Preferences::clockBottomMargin)
|
||||
|
||||
val showBigClockWarning = Preferences.asLiveData(Preferences::showBigClockWarning)
|
||||
|
||||
// Weather Settings
|
||||
val showWeather = Preferences.asLiveData(Preferences::showWeather)
|
||||
val weatherTempUnit = Preferences.asLiveData(Preferences::weatherTempUnit)
|
||||
val weatherRefreshPeriod = Preferences.asLiveData(Preferences::weatherRefreshPeriod)
|
||||
|
||||
val weatherAppName = Preferences.asLiveData(Preferences::weatherAppName)
|
||||
val weatherProviderApi = Preferences.asLiveData(Preferences::weatherProviderApiOpen)
|
||||
|
||||
val customLocationAdd = Preferences.asLiveData(Preferences::customLocationAdd)
|
||||
|
||||
val showWeatherWarning = Preferences.asLiveData(Preferences::showWeatherWarning)
|
||||
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
|
||||
val showGlance = Preferences.asLiveData(Preferences::showGlance)
|
||||
val showMusic = Preferences.asLiveData(Preferences::showMusic)
|
||||
val showNextAlarm = Preferences.asLiveData(Preferences::showNextAlarm)
|
||||
val showBatteryCharging = Preferences.asLiveData(Preferences::showBatteryCharging)
|
||||
val showDailySteps = Preferences.asLiveData(Preferences::showDailySteps)
|
||||
val customInfo = Preferences.asLiveData(Preferences::customNotes)
|
||||
val musicPlayersFilter = Preferences.asLiveData(Preferences::musicPlayersFilter)
|
||||
|
||||
// Advanced Settings
|
||||
val darkThemePreference = Preferences.asLiveData(Preferences::darkThemePreference)
|
||||
val showWallpaper = Preferences.asLiveData(Preferences::showWallpaper)
|
||||
val showPreview = Preferences.asLiveData(Preferences::showPreview)
|
||||
val installedIntegrations = Preferences.asLiveData(Preferences::installedIntegrations)
|
||||
|
||||
// UI
|
||||
val fragmentScrollY = MutableLiveData<Int>()
|
||||
val clockPreferencesUpdate = MediatorLiveData<Boolean>().apply {
|
||||
addSource(Preferences.asLiveData(Preferences::clockTextSize)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::clockTextColor)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::clockTextAlpha)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::clockTextColorDark)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::clockTextAlphaDark)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::showAMPMIndicator)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::clockBottomMargin)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::altTimezoneLabel)) { value = true }
|
||||
}
|
||||
val widgetPreferencesUpdate = MediatorLiveData<Boolean>().apply {
|
||||
addSource(Preferences.asLiveData(Preferences::textGlobalColor)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::textGlobalAlpha)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::textSecondaryColor)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::textSecondaryAlpha)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::backgroundCardColor)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::backgroundCardAlpha)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::textGlobalColorDark)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::textGlobalAlphaDark)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::dateFormat)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::textSecondaryColorDark)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::textSecondaryAlphaDark)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::backgroundCardColorDark)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::backgroundCardAlphaDark)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::textMainSize)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::textSecondSize)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::textShadow)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::textShadowDark)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::customFont)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::customFontFile)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::customFontName)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::customFontVariant)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::secondRowInformation)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::widgetAlign)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::showDividers)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::secondRowTopMargin)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::isDateCapitalize)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::isDateUppercase)) { value = true }
|
||||
|
||||
addSource(Preferences.asLiveData(Preferences::showEvents)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::calendarAllDay)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::showDiffTime)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::showNextEvent)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::showNextEventOnMultipleLines)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::showDeclinedEvents)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::showInvitedEvents)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::showAcceptedEvents)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::showOnlyBusyEvents)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::secondRowInformation)) { value = true }
|
||||
|
||||
addSource(Preferences.asLiveData(Preferences::showWeather)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::weatherTempUnit)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::weatherIconPack)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::customLocationLat)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::customLocationLon)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::customLocationAdd)) { value = true }
|
||||
|
||||
addSource(Preferences.asLiveData(Preferences::enabledGlanceProviderOrder)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::customNotes)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::showNextAlarm)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::showBatteryCharging)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::showDailySteps)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::showGreetings)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::showNotifications)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::showMusic)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::mediaInfoFormat)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::musicPlayersFilter)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::appNotificationsFilter)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::showEventsAsGlanceProvider)) { value = true }
|
||||
|
||||
addSource(Preferences.asLiveData(Preferences::installedIntegrations)) { value = true }
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels.settings
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
@ -1,4 +1,4 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels.settings
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
@ -1,4 +1,4 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels.tabs
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Intent
|
@ -1,11 +1,9 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels.tabs
|
||||
|
||||
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 kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
@ -1,4 +1,4 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels.tabs
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
@ -1,4 +1,4 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels.tabs
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Intent
|
@ -1,4 +1,4 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels.tabs
|
||||
|
||||
import android.app.Application
|
||||
import android.content.pm.ApplicationInfo
|
@ -0,0 +1,11 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels.tabs
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||
|
||||
class MediaInfoFormatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
val mediaInfoFormatInput: MutableLiveData<String> = MutableLiveData(if (Preferences.mediaInfoFormat == "") MediaPlayerHelper.DEFAULT_MEDIA_INFO_FORMAT else Preferences.mediaInfoFormat)
|
||||
}
|
@ -1,11 +1,9 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels.tabs
|
||||
|
||||
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
|
@ -0,0 +1,13 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels.tabs
|
||||
|
||||
import android.app.Application
|
||||
import android.location.Address
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
|
||||
class TimeZoneSelectorViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
val addresses: MutableLiveData<List<Address>> = MutableLiveData(emptyList())
|
||||
val locationInput: MutableLiveData<String> = MutableLiveData(Preferences.altTimezoneLabel)
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels.tabs
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
@ -0,0 +1,939 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.widgets
|
||||
|
||||
import android.Manifest
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.text.format.DateUtils
|
||||
import android.util.Log
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.*
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateMargins
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.databinding.LeftAlignedWidgetBinding
|
||||
import com.tommasoberlose.anotherwidget.db.EventRepository
|
||||
import com.tommasoberlose.anotherwidget.global.Actions
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.*
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
||||
import com.tommasoberlose.anotherwidget.helpers.ImageHelper.applyShadow
|
||||
import com.tommasoberlose.anotherwidget.receivers.CrashlyticsReceiver
|
||||
import com.tommasoberlose.anotherwidget.receivers.NewCalendarEventReceiver
|
||||
import com.tommasoberlose.anotherwidget.receivers.WidgetClickListenerReceiver
|
||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||
import com.tommasoberlose.anotherwidget.utils.convertDpToPixel
|
||||
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||
import java.text.DateFormat
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
|
||||
fun generateWidget(appWidgetId: Int, w: Int, typeface: Typeface? = null): RemoteViews? {
|
||||
|
||||
var views = RemoteViews(context.packageName, if (!rightAligned) R.layout.left_aligned_widget_sans else R.layout.right_aligned_widget_sans)
|
||||
|
||||
try {
|
||||
// Background
|
||||
views.setInt(
|
||||
R.id.widget_shape_background,
|
||||
"setColorFilter",
|
||||
ColorHelper.getBackgroundColorRgb(context.isDarkTheme())
|
||||
)
|
||||
views.setInt(
|
||||
R.id.widget_shape_background,
|
||||
"setImageAlpha",
|
||||
ColorHelper.getBackgroundAlpha(context.isDarkTheme())
|
||||
)
|
||||
val refreshIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
appWidgetId,
|
||||
IntentHelper.getWidgetUpdateIntent(context),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(R.id.widget_shape_background, refreshIntent)
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
CrashlyticsReceiver.sendCrash(context, ex)
|
||||
}
|
||||
|
||||
// Clock
|
||||
views = ClockWidget(context).updateClockView(views, appWidgetId)
|
||||
|
||||
// Setup listener
|
||||
try {
|
||||
val generatedBinding = generateWidgetView(typeface) ?: return null
|
||||
|
||||
views.setImageViewBitmap(
|
||||
R.id.bitmap_container,
|
||||
BitmapHelper.getBitmapFromView(generatedBinding.root, width = w)
|
||||
)
|
||||
views = updateGridView(generatedBinding, views, appWidgetId)
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
CrashlyticsReceiver.sendCrash(context, ex)
|
||||
}
|
||||
|
||||
return views
|
||||
}
|
||||
|
||||
private fun updateGridView(bindingView: LeftAlignedWidgetBinding, views: RemoteViews, widgetID: Int): RemoteViews {
|
||||
try {
|
||||
val eventRepository = EventRepository(context)
|
||||
val nextEvent = eventRepository.getNextEvent()
|
||||
val eventsCount = eventRepository.getEventsCount()
|
||||
eventRepository.close()
|
||||
|
||||
// Weather
|
||||
if (Preferences.showWeather && Preferences.weatherIcon != "") {
|
||||
views.setViewVisibility(R.id.weather_rect, View.VISIBLE)
|
||||
views.setViewVisibility(R.id.weather_sub_line, View.GONE)
|
||||
|
||||
val i = Intent(context, WidgetClickListenerReceiver::class.java)
|
||||
i.action = Actions.ACTION_OPEN_WEATHER_INTENT
|
||||
val weatherPIntent = PendingIntent.getBroadcast(context, widgetID, i, 0)
|
||||
|
||||
views.setOnClickPendingIntent(R.id.weather_rect, weatherPIntent)
|
||||
views.setOnClickPendingIntent(R.id.weather_sub_line_rect, weatherPIntent)
|
||||
|
||||
views.setImageViewBitmap(
|
||||
R.id.weather_rect,
|
||||
BitmapHelper.getBitmapFromView(bindingView.weatherDateLine, draw = false, width = bindingView.weatherDateLine.width, height = bindingView.weatherDateLine.height)
|
||||
)
|
||||
|
||||
views.setImageViewBitmap(
|
||||
R.id.weather_sub_line_rect,
|
||||
BitmapHelper.getBitmapFromView(bindingView.weatherSubLine, draw = false, width = bindingView.weatherSubLine.width, height = bindingView.weatherSubLine.height)
|
||||
)
|
||||
} else {
|
||||
views.setViewVisibility(R.id.weather_rect, View.GONE)
|
||||
views.setViewVisibility(R.id.weather_sub_line, View.GONE)
|
||||
}
|
||||
|
||||
|
||||
// Calendar
|
||||
views.setImageViewBitmap(
|
||||
R.id.date_rect,
|
||||
BitmapHelper.getBitmapFromView(bindingView.date, draw = false, width = bindingView.date.width, height = bindingView.date.height)
|
||||
)
|
||||
|
||||
val calPIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
widgetID,
|
||||
IntentHelper.getCalendarIntent(context),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(R.id.date_rect, calPIntent)
|
||||
views.setViewVisibility(R.id.first_line_rect, View.VISIBLE)
|
||||
|
||||
val nextAlarm = AlarmHelper.getNextAlarm(context)
|
||||
|
||||
// Spacing
|
||||
views.setViewVisibility(
|
||||
R.id.sub_line_top_margin_small_sans,
|
||||
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.rawValue) View.VISIBLE else View.GONE
|
||||
)
|
||||
views.setViewVisibility(
|
||||
R.id.sub_line_top_margin_medium_sans,
|
||||
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.rawValue) View.VISIBLE else View.GONE
|
||||
)
|
||||
views.setViewVisibility(
|
||||
R.id.sub_line_top_margin_large_sans,
|
||||
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.LARGE.rawValue) View.VISIBLE else View.GONE
|
||||
)
|
||||
|
||||
if (Preferences.showEvents && context.checkGrantedPermission(Manifest.permission.READ_CALENDAR) && nextEvent != null && !Preferences.showEventsAsGlanceProvider) {
|
||||
if (Preferences.showNextEvent && eventsCount > 1) {
|
||||
|
||||
// Action next event
|
||||
views.setImageViewBitmap(
|
||||
R.id.action_next_rect,
|
||||
BitmapHelper.getBitmapFromView(bindingView.actionNext, draw = false, width = bindingView.actionNext.width, height = bindingView.actionNext.height)
|
||||
)
|
||||
views.setViewVisibility(R.id.action_next_rect, View.VISIBLE)
|
||||
views.setOnClickPendingIntent(
|
||||
R.id.action_next_rect,
|
||||
PendingIntent.getBroadcast(
|
||||
context,
|
||||
widgetID,
|
||||
Intent(
|
||||
context,
|
||||
NewCalendarEventReceiver::class.java
|
||||
).apply { action = Actions.ACTION_GO_TO_NEXT_EVENT },
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
)
|
||||
|
||||
views.setViewVisibility(R.id.action_next_rect, View.VISIBLE)
|
||||
} else {
|
||||
views.setViewVisibility(R.id.action_next_rect, View.GONE)
|
||||
}
|
||||
|
||||
// Event intent
|
||||
val eventIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
widgetID,
|
||||
IntentHelper.getEventIntent(context, nextEvent),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(R.id.next_event_rect, eventIntent)
|
||||
views.setImageViewBitmap(
|
||||
R.id.next_event_rect,
|
||||
BitmapHelper.getBitmapFromView(bindingView.nextEvent, draw = false, width = bindingView.nextEvent.width, height = bindingView.nextEvent.height)
|
||||
)
|
||||
views.setViewVisibility(R.id.next_event_rect, View.VISIBLE)
|
||||
|
||||
// Event time difference
|
||||
if (Preferences.showDiffTime && Calendar.getInstance().timeInMillis < nextEvent.startDate) {
|
||||
views.setImageViewBitmap(
|
||||
R.id.next_event_difference_time_rect,
|
||||
BitmapHelper.getBitmapFromView(
|
||||
bindingView.nextEventDifferenceTime,
|
||||
draw = false,
|
||||
width = bindingView.nextEventDifferenceTime.width,
|
||||
height = bindingView.nextEventDifferenceTime.height
|
||||
)
|
||||
)
|
||||
|
||||
views.setOnClickPendingIntent(R.id.next_event_difference_time_rect, eventIntent)
|
||||
if (!Preferences.showNextEventOnMultipleLines) {
|
||||
views.setViewVisibility(R.id.next_event_difference_time_rect, View.VISIBLE)
|
||||
} else {
|
||||
views.setViewVisibility(R.id.next_event_difference_time_rect, View.GONE)
|
||||
}
|
||||
} else {
|
||||
views.setViewVisibility(R.id.next_event_difference_time_rect, View.GONE)
|
||||
}
|
||||
|
||||
// Event information
|
||||
if (nextEvent.address != "" && Preferences.secondRowInformation == 1) {
|
||||
val mapIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
widgetID,
|
||||
IntentHelper.getGoogleMapsIntentFromAddress(context, nextEvent.address),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(R.id.sub_line_rect, mapIntent)
|
||||
} else {
|
||||
val pIntentDetail = PendingIntent.getActivity(
|
||||
context,
|
||||
widgetID,
|
||||
IntentHelper.getEventIntent(
|
||||
context,
|
||||
nextEvent,
|
||||
forceEventDetails = true
|
||||
),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(R.id.sub_line_rect, pIntentDetail)
|
||||
}
|
||||
|
||||
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
|
||||
views.setViewVisibility(R.id.sub_line_rect, View.VISIBLE)
|
||||
views.setViewVisibility(R.id.weather_sub_line_rect, View.VISIBLE)
|
||||
views.setViewVisibility(R.id.first_line_rect, View.GONE)
|
||||
|
||||
views.setViewVisibility(R.id.sub_line_top_margin_small_sans, View.GONE)
|
||||
views.setViewVisibility(R.id.sub_line_top_margin_medium_sans, View.GONE)
|
||||
views.setViewVisibility(R.id.sub_line_top_margin_large_sans, View.GONE)
|
||||
} else if (GlanceProviderHelper.showGlanceProviders(context)) {
|
||||
var showSomething = false
|
||||
loop@ for (provider: Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders(context)) {
|
||||
when (provider) {
|
||||
Constants.GlanceProviderId.PLAYING_SONG -> {
|
||||
if (MediaPlayerHelper.isSomeonePlaying(context)) {
|
||||
val musicIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
widgetID,
|
||||
IntentHelper.getMusicIntent(context),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(R.id.sub_line_rect, musicIntent)
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
|
||||
if (Preferences.showNextAlarm && nextAlarm != "") {
|
||||
val alarmIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
widgetID,
|
||||
IntentHelper.getClockIntent(context),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(R.id.sub_line_rect, alarmIntent)
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
||||
if (Preferences.showBatteryCharging) {
|
||||
BatteryHelper.updateBatteryInfo(context)
|
||||
if (Preferences.isCharging || Preferences.isBatteryLevelLow) {
|
||||
val batteryIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
widgetID,
|
||||
IntentHelper.getBatteryIntent(),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(R.id.sub_line_rect, batteryIntent)
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.CUSTOM_INFO -> {
|
||||
if (Preferences.customNotes.isNotEmpty()) {
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
|
||||
if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) {
|
||||
val fitIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
widgetID,
|
||||
IntentHelper.getFitIntent(context),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(R.id.sub_line_rect, fitIntent)
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.NOTIFICATIONS -> {
|
||||
if (Preferences.showNotifications && ActiveNotificationsHelper.showLastNotification()) {
|
||||
try {
|
||||
if (Preferences.lastNotificationIcon != 0) {
|
||||
val remotePackageContext = context.createPackageContext(
|
||||
Preferences.lastNotificationPackage, 0)
|
||||
ContextCompat.getDrawable(
|
||||
remotePackageContext,
|
||||
Preferences.lastNotificationIcon)
|
||||
}
|
||||
val notificationIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
widgetID,
|
||||
IntentHelper.getNotificationIntent(context),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(
|
||||
R.id.sub_line_rect,
|
||||
notificationIntent
|
||||
)
|
||||
showSomething = true
|
||||
break@loop
|
||||
} catch (ex: Exception) {}
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.GREETINGS -> {
|
||||
if (Preferences.showGreetings && GreetingsHelper.showGreetings() && GreetingsHelper.getRandomString(context).isNotBlank()) {
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.EVENTS -> {
|
||||
if (Preferences.showEventsAsGlanceProvider&& Preferences.showEvents && context.checkGrantedPermission(
|
||||
Manifest.permission.READ_CALENDAR) && nextEvent != null) {
|
||||
val pIntentDetail = PendingIntent.getActivity(
|
||||
context,
|
||||
widgetID,
|
||||
IntentHelper.getEventIntent(
|
||||
context,
|
||||
nextEvent,
|
||||
forceEventDetails = true
|
||||
),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(
|
||||
R.id.sub_line_rect,
|
||||
pIntentDetail
|
||||
)
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (showSomething) {
|
||||
views.setViewVisibility(R.id.first_line_rect, View.VISIBLE)
|
||||
views.setViewVisibility(R.id.weather_rect, View.VISIBLE)
|
||||
views.setViewVisibility(R.id.sub_line_rect, View.VISIBLE)
|
||||
|
||||
views.setViewVisibility(R.id.calendar_layout_rect, View.GONE)
|
||||
views.setViewVisibility(R.id.weather_sub_line_rect, View.GONE)
|
||||
} else {
|
||||
// Spacing
|
||||
views.setViewVisibility(R.id.sub_line_top_margin_small_sans, View.GONE)
|
||||
views.setViewVisibility(R.id.sub_line_top_margin_medium_sans, View.GONE)
|
||||
views.setViewVisibility(R.id.sub_line_top_margin_large_sans, View.GONE)
|
||||
}
|
||||
} else {
|
||||
views.setViewVisibility(R.id.first_line_rect, View.VISIBLE)
|
||||
views.setViewVisibility(R.id.weather_rect, View.VISIBLE)
|
||||
|
||||
views.setViewVisibility(R.id.calendar_layout_rect, View.GONE)
|
||||
views.setViewVisibility(R.id.sub_line_rect, View.GONE)
|
||||
views.setViewVisibility(R.id.weather_sub_line_rect, View.GONE)
|
||||
// Spacing
|
||||
views.setViewVisibility(R.id.sub_line_top_margin_small_sans, View.GONE)
|
||||
views.setViewVisibility(R.id.sub_line_top_margin_medium_sans, View.GONE)
|
||||
views.setViewVisibility(R.id.sub_line_top_margin_large_sans, View.GONE)
|
||||
}
|
||||
|
||||
// Second row
|
||||
views.setImageViewBitmap(
|
||||
R.id.sub_line_rect,
|
||||
BitmapHelper.getBitmapFromView(bindingView.subLine, draw = false, width = bindingView.subLine.width, height = bindingView.subLine.height)
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
CrashlyticsReceiver.sendCrash(context, ex)
|
||||
}
|
||||
|
||||
return views
|
||||
}
|
||||
|
||||
|
||||
// Generates the widget bitmap from the view
|
||||
fun generateWidgetView(typeface: Typeface? = null): LeftAlignedWidgetBinding? {
|
||||
try {
|
||||
val eventRepository = EventRepository(context)
|
||||
val nextEvent = eventRepository.getNextEvent()
|
||||
val eventsCount = eventRepository.getEventsCount()
|
||||
eventRepository.close()
|
||||
|
||||
val bindingView = LeftAlignedWidgetBinding.inflate(LayoutInflater.from(context))
|
||||
|
||||
bindingView.loader.isVisible = false
|
||||
|
||||
// Weather
|
||||
if (Preferences.showWeather && Preferences.weatherIcon != "") {
|
||||
bindingView.weatherDateLine.isVisible = true
|
||||
val currentTemp = String.format(
|
||||
Locale.getDefault(),
|
||||
"%d°%s",
|
||||
Preferences.weatherTemp.roundToInt(),
|
||||
Preferences.weatherRealTempUnit
|
||||
)
|
||||
|
||||
val icon: String = Preferences.weatherIcon
|
||||
if (icon == "") {
|
||||
bindingView.weatherSubLineWeatherIcon.isVisible = false
|
||||
bindingView.weatherDateLineWeatherIcon.isVisible = false
|
||||
} else {
|
||||
bindingView.weatherSubLineWeatherIcon.setImageResource(WeatherHelper.getWeatherIconResource(context, icon))
|
||||
bindingView.weatherDateLineWeatherIcon.setImageResource(WeatherHelper.getWeatherIconResource(context, icon))
|
||||
bindingView.weatherSubLineWeatherIcon.isVisible = true
|
||||
bindingView.weatherDateLineWeatherIcon.isVisible = true
|
||||
}
|
||||
|
||||
bindingView.weatherDateLineTemperature.text = currentTemp
|
||||
bindingView.weatherSubLineTemperature.text = currentTemp
|
||||
|
||||
if (GlanceProviderHelper.showGlanceProviders(context)) {
|
||||
bindingView.weatherSubLine.isVisible = false
|
||||
}
|
||||
} else {
|
||||
bindingView.weatherDateLine.isVisible = false
|
||||
bindingView.weatherSubLine.isVisible = false
|
||||
}
|
||||
|
||||
val now = Calendar.getInstance().apply {
|
||||
set(Calendar.SECOND, 0)
|
||||
set(Calendar.MILLISECOND, 0)
|
||||
}
|
||||
|
||||
bindingView.dateLayout.isVisible = true
|
||||
bindingView.calendarLayout.isVisible = false
|
||||
bindingView.nextEventDifferenceTime.isVisible = false
|
||||
bindingView.actionNext.isVisible = false
|
||||
|
||||
bindingView.date.text = DateHelper.getDateText(context, now)
|
||||
|
||||
val nextAlarm = AlarmHelper.getNextAlarm(context)
|
||||
|
||||
if (Preferences.showEvents && context.checkGrantedPermission(Manifest.permission.READ_CALENDAR) && nextEvent != null && !Preferences.showEventsAsGlanceProvider) {
|
||||
// Multiple counter
|
||||
bindingView.actionNext.isVisible =
|
||||
Preferences.showNextEvent && eventsCount > 1
|
||||
|
||||
bindingView.nextEvent.text = nextEvent.title
|
||||
|
||||
if (Preferences.showNextEventOnMultipleLines) {
|
||||
bindingView.nextEvent.apply {
|
||||
isSingleLine = false
|
||||
maxLines = 3
|
||||
gravity = if (rightAligned) Gravity.END else Gravity.START
|
||||
}
|
||||
}
|
||||
|
||||
if (Preferences.showDiffTime && now.timeInMillis < nextEvent.startDate) {
|
||||
val diffTime = if (!nextEvent.allDay) {
|
||||
SettingsStringHelper.getDifferenceText(
|
||||
context,
|
||||
now.timeInMillis,
|
||||
nextEvent.startDate
|
||||
)
|
||||
.toLowerCase(Locale.getDefault())
|
||||
} else {
|
||||
SettingsStringHelper.getAllDayEventDifferenceText(
|
||||
context,
|
||||
now.timeInMillis,
|
||||
nextEvent.startDate
|
||||
).toLowerCase(Locale.getDefault())
|
||||
}
|
||||
bindingView.nextEventDifferenceTime.text = diffTime
|
||||
|
||||
if (!Preferences.showNextEventOnMultipleLines) {
|
||||
bindingView.nextEventDifferenceTime.isVisible = true
|
||||
} else {
|
||||
bindingView.nextEvent.text = context.getString(R.string.events_glance_provider_format).format(nextEvent.title, diffTime)
|
||||
bindingView.nextEventDifferenceTime.isVisible = false
|
||||
}
|
||||
} else {
|
||||
bindingView.nextEventDifferenceTime.isVisible = false
|
||||
}
|
||||
|
||||
if (nextEvent.address != "" && Preferences.secondRowInformation == 1) {
|
||||
bindingView.subLineIcon.setImageDrawable(
|
||||
ContextCompat.getDrawable(
|
||||
context,
|
||||
R.drawable.round_place_24
|
||||
)
|
||||
)
|
||||
bindingView.subLineText.text = nextEvent.address
|
||||
} else {
|
||||
bindingView.subLineIcon.setImageDrawable(
|
||||
ContextCompat.getDrawable(
|
||||
context,
|
||||
R.drawable.round_today_24
|
||||
)
|
||||
)
|
||||
if (!nextEvent.allDay) {
|
||||
val startHour =
|
||||
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)
|
||||
|
||||
val startCal = Calendar.getInstance()
|
||||
startCal.timeInMillis = nextEvent.startDate
|
||||
|
||||
val endCal = Calendar.getInstance()
|
||||
endCal.timeInMillis = nextEvent.endDate
|
||||
|
||||
if (startCal.get(Calendar.HOUR_OF_DAY) > endCal.get(Calendar.HOUR_OF_DAY)) {
|
||||
dayDiff++
|
||||
} else if (startCal.get(Calendar.HOUR_OF_DAY) == endCal.get(Calendar.HOUR_OF_DAY) && startCal.get(
|
||||
Calendar.MINUTE
|
||||
) > endCal.get(Calendar.MINUTE)
|
||||
) {
|
||||
dayDiff++
|
||||
}
|
||||
var multipleDay = ""
|
||||
if (dayDiff > 0) {
|
||||
multipleDay = String.format(
|
||||
" (+%s%s)",
|
||||
dayDiff,
|
||||
context.getString(R.string.day_char)
|
||||
)
|
||||
}
|
||||
|
||||
if (nextEvent.startDate != nextEvent.endDate) {
|
||||
bindingView.subLineText.text =
|
||||
String.format("%s - %s%s", startHour, endHour, multipleDay)
|
||||
} else {
|
||||
bindingView.subLineText.text =
|
||||
String.format("%s", startHour)
|
||||
}
|
||||
|
||||
} else {
|
||||
val flags: Int =
|
||||
DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NO_YEAR or DateUtils.FORMAT_ABBREV_MONTH
|
||||
val start = Calendar.getInstance().apply { timeInMillis = nextEvent.startDate }
|
||||
|
||||
bindingView.subLineText.text = if (now.get(Calendar.DAY_OF_YEAR) == start.get(
|
||||
Calendar.DAY_OF_YEAR)) {
|
||||
DateUtils.formatDateTime(context, nextEvent.startDate, flags)
|
||||
} else if (now.get(Calendar.DAY_OF_YEAR) > start.get(Calendar.DAY_OF_YEAR) || now.get(
|
||||
Calendar.YEAR) > start.get(Calendar.YEAR)) {
|
||||
DateUtils.formatDateTime(context, now.timeInMillis, flags)
|
||||
} else {
|
||||
DateUtils.formatDateTime(context, nextEvent.startDate, flags)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bindingView.dateLayout.isVisible = false
|
||||
bindingView.calendarLayout.isVisible = true
|
||||
bindingView.subLine.isVisible = true
|
||||
bindingView.weatherSubLine.isVisible = true
|
||||
|
||||
bindingView.subLineTopMarginSmall.visibility = View.GONE
|
||||
bindingView.subLineTopMarginMedium.visibility = View.GONE
|
||||
bindingView.subLineTopMarginLarge.visibility = View.GONE
|
||||
} else if (GlanceProviderHelper.showGlanceProviders(context)) {
|
||||
bindingView.subLineIcon.isVisible = true
|
||||
var showSomething = false
|
||||
loop@ for (provider: Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders(
|
||||
context
|
||||
)) {
|
||||
when (provider) {
|
||||
Constants.GlanceProviderId.PLAYING_SONG -> {
|
||||
if (MediaPlayerHelper.isSomeonePlaying(context)) {
|
||||
bindingView.subLineIcon.setImageDrawable(
|
||||
ContextCompat.getDrawable(
|
||||
context,
|
||||
R.drawable.round_music_note_24
|
||||
)
|
||||
)
|
||||
bindingView.subLineText.text = MediaPlayerHelper.getMediaInfo()
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
|
||||
if (Preferences.showNextAlarm && nextAlarm != "") {
|
||||
bindingView.subLineIcon.setImageDrawable(
|
||||
ContextCompat.getDrawable(
|
||||
context,
|
||||
R.drawable.round_alarm_24
|
||||
)
|
||||
)
|
||||
bindingView.subLineText.text = AlarmHelper.getNextAlarm(context)
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
||||
if (Preferences.showBatteryCharging) {
|
||||
BatteryHelper.updateBatteryInfo(context)
|
||||
if (Preferences.isCharging) {
|
||||
bindingView.subLineIcon.isVisible = false
|
||||
val batteryLevel = BatteryHelper.getBatteryLevel(context)
|
||||
if (batteryLevel != 100) {
|
||||
bindingView.subLineText.text = context.getString(R.string.charging)
|
||||
} else {
|
||||
bindingView.subLineText.text =
|
||||
context.getString(R.string.charged)
|
||||
}
|
||||
showSomething = true
|
||||
break@loop
|
||||
} else if (Preferences.isBatteryLevelLow) {
|
||||
bindingView.subLineIcon.isVisible = false
|
||||
bindingView.subLineText.text =
|
||||
context.getString(R.string.battery_low_warning)
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.CUSTOM_INFO -> {
|
||||
if (Preferences.customNotes.isNotEmpty()) {
|
||||
bindingView.subLineIcon.isVisible = false
|
||||
bindingView.subLineText.text = Preferences.customNotes
|
||||
bindingView.subLineText.maxLines = 2
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
|
||||
if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) {
|
||||
bindingView.subLineIcon.isVisible = false
|
||||
bindingView.subLineText.text =
|
||||
context.getString(R.string.daily_steps_counter)
|
||||
.format(Preferences.googleFitSteps)
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.NOTIFICATIONS -> {
|
||||
if (Preferences.showNotifications && ActiveNotificationsHelper.showLastNotification()) {
|
||||
try {
|
||||
if (Preferences.lastNotificationIcon != 0) {
|
||||
val remotePackageContext = context.createPackageContext(
|
||||
Preferences.lastNotificationPackage, 0)
|
||||
val icon = ContextCompat.getDrawable(remotePackageContext,
|
||||
Preferences.lastNotificationIcon)
|
||||
bindingView.subLineIcon.isVisible = true
|
||||
bindingView.subLineIcon.setImageDrawable(icon)
|
||||
} else {
|
||||
bindingView.subLineIcon.isVisible = false
|
||||
}
|
||||
bindingView.subLineText.text = Preferences.lastNotificationTitle
|
||||
showSomething = true
|
||||
break@loop
|
||||
} catch (ex: Exception) {}
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.GREETINGS -> {
|
||||
val greetingsText = GreetingsHelper.getRandomString(context)
|
||||
if (Preferences.showGreetings && GreetingsHelper.showGreetings() && greetingsText.isNotBlank()) {
|
||||
bindingView.subLineText.text = greetingsText
|
||||
bindingView.subLineText.maxLines = 2
|
||||
bindingView.subLineIcon.isVisible = false
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.EVENTS -> {
|
||||
if (Preferences.showEventsAsGlanceProvider && Preferences.showEvents && context.checkGrantedPermission(
|
||||
Manifest.permission.READ_CALENDAR) && nextEvent != null) {
|
||||
bindingView.subLineText.text = context.getString(R.string.events_glance_provider_format).format(nextEvent.title, if (Preferences.showDiffTime && now.timeInMillis < nextEvent.startDate) {
|
||||
if (!nextEvent.allDay) {
|
||||
SettingsStringHelper.getDifferenceText(
|
||||
context,
|
||||
now.timeInMillis,
|
||||
nextEvent.startDate
|
||||
)
|
||||
.toLowerCase(Locale.getDefault())
|
||||
} else {
|
||||
SettingsStringHelper.getAllDayEventDifferenceText(
|
||||
context,
|
||||
now.timeInMillis,
|
||||
nextEvent.startDate
|
||||
).toLowerCase(Locale.getDefault())
|
||||
}
|
||||
} else "").trimEnd()
|
||||
bindingView.subLineIcon.isVisible = true
|
||||
bindingView.subLineIcon.setImageDrawable(
|
||||
ContextCompat.getDrawable(
|
||||
context,
|
||||
R.drawable.round_today_24
|
||||
)
|
||||
)
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (showSomething) {
|
||||
bindingView.dateLayout.isVisible = true
|
||||
bindingView.calendarLayout.isVisible = false
|
||||
bindingView.subLine.isVisible = true
|
||||
bindingView.weatherSubLine.isVisible = false
|
||||
|
||||
bindingView.subLineTopMarginSmall.visibility =
|
||||
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.rawValue) View.VISIBLE else View.GONE
|
||||
bindingView.subLineTopMarginMedium.visibility =
|
||||
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.rawValue) View.VISIBLE else View.GONE
|
||||
bindingView.subLineTopMarginLarge.visibility =
|
||||
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.LARGE.rawValue) View.VISIBLE else View.GONE
|
||||
} else {
|
||||
bindingView.subLineIcon.isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Color
|
||||
listOf<TextView>(
|
||||
bindingView.date,
|
||||
bindingView.weatherDateLineTemperature,
|
||||
bindingView.nextEvent,
|
||||
bindingView.nextEventDifferenceTime,
|
||||
).forEach {
|
||||
it.setTextColor(ColorHelper.getFontColor(context.applicationContext.isDarkTheme()))
|
||||
}
|
||||
|
||||
if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.rawValue) {
|
||||
listOf<ImageView>(bindingView.actionNext)
|
||||
} else {
|
||||
listOf<ImageView>(
|
||||
bindingView.actionNext,
|
||||
bindingView.weatherDateLineWeatherIcon,
|
||||
bindingView.weatherSubLineWeatherIcon
|
||||
)
|
||||
}.forEach {
|
||||
it.setColorFilter(ColorHelper.getFontColorRgb(context.applicationContext.isDarkTheme()))
|
||||
it.alpha =
|
||||
(if (context.isDarkTheme()) Preferences.textGlobalAlphaDark.toIntValue()
|
||||
.toFloat() else Preferences.textGlobalAlpha.toIntValue()
|
||||
.toFloat()) / 100
|
||||
}
|
||||
|
||||
listOf<TextView>(bindingView.subLineText, bindingView.weatherSubLineDivider, bindingView.weatherSubLineTemperature).forEach {
|
||||
it.setTextColor(ColorHelper.getSecondaryFontColor(context.applicationContext.isDarkTheme()))
|
||||
}
|
||||
|
||||
if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.rawValue) {
|
||||
listOf<ImageView>(bindingView.subLineIcon, bindingView.subLineIconShadow)
|
||||
} else {
|
||||
listOf<ImageView>(bindingView.subLineIcon, bindingView.weatherSubLineWeatherIcon, bindingView.subLineIconShadow)
|
||||
}.forEach {
|
||||
it.setColorFilter(ColorHelper.getSecondaryFontColorRgb(context.applicationContext.isDarkTheme()))
|
||||
it.alpha =
|
||||
(if (context.isDarkTheme()) Preferences.textSecondaryAlphaDark.toIntValue()
|
||||
.toFloat() else Preferences.textSecondaryAlpha.toIntValue()
|
||||
.toFloat()) / 100
|
||||
}
|
||||
|
||||
// Text Size
|
||||
listOf<Pair<TextView, Float>>(
|
||||
bindingView.date to Preferences.textMainSize,
|
||||
bindingView.weatherDateLineTemperature to ((Preferences.textMainSize + Preferences.textSecondSize) / 2),
|
||||
bindingView.nextEvent to Preferences.textMainSize,
|
||||
bindingView.nextEventDifferenceTime to Preferences.textMainSize,
|
||||
bindingView.subLineText to Preferences.textSecondSize,
|
||||
bindingView.weatherSubLineDivider to (Preferences.textSecondSize - 2),
|
||||
bindingView.weatherSubLineTemperature to Preferences.textSecondSize,
|
||||
).forEach {
|
||||
it.first.setTextSize(TypedValue.COMPLEX_UNIT_SP, it.second)
|
||||
}
|
||||
|
||||
// Icons scale
|
||||
bindingView.subLineIcon.scaleX = Preferences.textSecondSize / 18f
|
||||
bindingView.subLineIcon.scaleY = Preferences.textSecondSize / 18f
|
||||
|
||||
bindingView.weatherSubLineWeatherIcon.scaleX = Preferences.textSecondSize / 18f
|
||||
bindingView.weatherSubLineWeatherIcon.scaleY = Preferences.textSecondSize / 18f
|
||||
|
||||
bindingView.weatherDateLineWeatherIcon.scaleX = ((Preferences.textMainSize + Preferences.textSecondSize) / 2) / 20f
|
||||
bindingView.weatherDateLineWeatherIcon.scaleY = ((Preferences.textMainSize + Preferences.textSecondSize) / 2) / 20f
|
||||
|
||||
bindingView.actionNext.scaleX = Preferences.textMainSize / 28f
|
||||
bindingView.actionNext.scaleY = Preferences.textMainSize / 28f
|
||||
|
||||
|
||||
// Shadows
|
||||
val shadowRadius =
|
||||
when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
|
||||
0 -> 0f
|
||||
1 -> 5f
|
||||
2 -> 5f
|
||||
else -> 5f
|
||||
}
|
||||
val shadowColor =
|
||||
when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
|
||||
0 -> Color.TRANSPARENT
|
||||
1 -> R.color.black_50
|
||||
2 -> Color.BLACK
|
||||
else -> R.color.black_50
|
||||
}
|
||||
val shadowDy =
|
||||
when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
|
||||
0 -> 0f
|
||||
1 -> 0f
|
||||
2 -> 1f
|
||||
else -> 0f
|
||||
}
|
||||
|
||||
listOf<TextView>(
|
||||
bindingView.date,
|
||||
bindingView.weatherDateLineTemperature,
|
||||
bindingView.nextEvent,
|
||||
bindingView.nextEventDifferenceTime,
|
||||
bindingView.subLineText,
|
||||
bindingView.weatherSubLineDivider,
|
||||
bindingView.weatherSubLineTemperature,
|
||||
).forEach {
|
||||
it.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
|
||||
}
|
||||
|
||||
// Icons shadow
|
||||
|
||||
listOf(
|
||||
Pair(bindingView.subLineIcon, bindingView.subLineIconShadow),
|
||||
).forEach {
|
||||
if ((if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) == 0) {
|
||||
it.second.isVisible = false
|
||||
} else {
|
||||
it.second.isVisible = it.first.isVisible
|
||||
it.second.scaleX = it.first.scaleX
|
||||
it.second.scaleY = it.first.scaleY
|
||||
it.second.applyShadow(it.first)
|
||||
}
|
||||
}
|
||||
|
||||
listOf(
|
||||
Pair(bindingView.actionNext, bindingView.actionNextShadow),
|
||||
).forEach {
|
||||
if ((if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) == 0) {
|
||||
it.second.isVisible = false
|
||||
} else {
|
||||
it.second.isVisible = it.first.isVisible
|
||||
it.second.scaleX = it.first.scaleX
|
||||
it.second.scaleY = it.first.scaleY
|
||||
it.second.applyShadow(it.first, 0.6f)
|
||||
}
|
||||
}
|
||||
|
||||
// Custom Font
|
||||
if (Preferences.customFont == Constants.CUSTOM_FONT_GOOGLE_SANS) {
|
||||
val googleSans: Typeface = when (Preferences.customFontVariant) {
|
||||
"100" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_thin.ttf")
|
||||
"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>(
|
||||
bindingView.date,
|
||||
bindingView.weatherDateLineTemperature,
|
||||
bindingView.nextEvent,
|
||||
bindingView.nextEventDifferenceTime,
|
||||
bindingView.subLineText,
|
||||
bindingView.weatherSubLineDivider,
|
||||
bindingView.weatherSubLineTemperature,
|
||||
).forEach {
|
||||
it.typeface = googleSans
|
||||
}
|
||||
} else if (Preferences.customFont == Constants.CUSTOM_FONT_DOWNLOADED && typeface != null) {
|
||||
listOf<TextView>(
|
||||
bindingView.date,
|
||||
bindingView.weatherDateLineTemperature,
|
||||
bindingView.nextEvent,
|
||||
bindingView.nextEventDifferenceTime,
|
||||
bindingView.subLineText,
|
||||
bindingView.weatherSubLineDivider,
|
||||
bindingView.weatherSubLineTemperature,
|
||||
).forEach {
|
||||
it.typeface = typeface
|
||||
}
|
||||
}
|
||||
|
||||
// Dividers
|
||||
arrayOf(bindingView.weatherSubLineDivider).forEach {
|
||||
it.visibility = if (Preferences.showDividers) View.VISIBLE else View.INVISIBLE
|
||||
it.layoutParams = (it.layoutParams as ViewGroup.MarginLayoutParams).apply {
|
||||
this.marginEnd = if (Preferences.showDividers) 8f.convertDpToPixel(context).toInt() else 0
|
||||
}
|
||||
}
|
||||
|
||||
// Right Aligned
|
||||
if (rightAligned) {
|
||||
bindingView.mainContent.layoutParams = (bindingView.mainContent.layoutParams as RelativeLayout.LayoutParams).apply {
|
||||
addRule(RelativeLayout.ALIGN_PARENT_END)
|
||||
}
|
||||
bindingView.mainContent.gravity = Gravity.END
|
||||
bindingView.dateLayout.gravity = Gravity.END
|
||||
bindingView.calendarLayout.gravity = Gravity.END or Gravity.CENTER_VERTICAL
|
||||
bindingView.subLineContainer.gravity = Gravity.END or Gravity.CENTER_VERTICAL
|
||||
}
|
||||
|
||||
return bindingView
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
CrashlyticsReceiver.sendCrash(context, ex)
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.widgets
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.widget.RemoteViews
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
||||
import com.tommasoberlose.anotherwidget.helpers.IntentHelper
|
||||
import com.tommasoberlose.anotherwidget.receivers.CrashlyticsReceiver
|
||||
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||
import com.tommasoberlose.anotherwidget.utils.toPixel
|
||||
|
||||
class ClockWidget(val context: Context) {
|
||||
fun updateClockView(views: RemoteViews, widgetID: Int): RemoteViews {
|
||||
try {
|
||||
if (!Preferences.showClock) {
|
||||
views.setViewVisibility(R.id.time, View.GONE)
|
||||
views.setViewVisibility(R.id.time_am_pm, View.GONE)
|
||||
views.setViewVisibility(R.id.clock_bottom_margin_none, View.GONE)
|
||||
views.setViewVisibility(R.id.clock_bottom_margin_small, 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.timezones_container, View.GONE)
|
||||
} else {
|
||||
views.setTextColor(R.id.time, ColorHelper.getClockFontColor(context.isDarkTheme()))
|
||||
views.setTextColor(R.id.time_am_pm, ColorHelper.getClockFontColor(context.isDarkTheme()))
|
||||
views.setTextViewTextSize(
|
||||
R.id.time,
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
Preferences.clockTextSize.toPixel(context)
|
||||
)
|
||||
views.setTextViewTextSize(
|
||||
R.id.time_am_pm,
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
Preferences.clockTextSize.toPixel(context) / 5 * 2
|
||||
)
|
||||
val clockPIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
widgetID,
|
||||
IntentHelper.getClockIntent(context),
|
||||
0
|
||||
)
|
||||
views.setOnClickPendingIntent(R.id.time, clockPIntent)
|
||||
views.setOnClickPendingIntent(R.id.time_am_pm, clockPIntent)
|
||||
views.setViewVisibility(R.id.time, View.VISIBLE)
|
||||
views.setViewVisibility(R.id.time_am_pm, if (Preferences.showAMPMIndicator) View.VISIBLE else View.GONE)
|
||||
|
||||
views.setViewVisibility(
|
||||
R.id.clock_bottom_margin_none,
|
||||
if (Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.rawValue) View.VISIBLE else View.GONE
|
||||
)
|
||||
views.setViewVisibility(
|
||||
R.id.clock_bottom_margin_small,
|
||||
if (Preferences.clockBottomMargin == Constants.ClockBottomMargin.SMALL.rawValue) View.VISIBLE else View.GONE
|
||||
)
|
||||
views.setViewVisibility(
|
||||
R.id.clock_bottom_margin_medium,
|
||||
if (Preferences.clockBottomMargin == Constants.ClockBottomMargin.MEDIUM.rawValue) View.VISIBLE else View.GONE
|
||||
)
|
||||
views.setViewVisibility(
|
||||
R.id.clock_bottom_margin_large,
|
||||
if (Preferences.clockBottomMargin == Constants.ClockBottomMargin.LARGE.rawValue) View.VISIBLE else View.GONE
|
||||
)
|
||||
|
||||
|
||||
// Timezones
|
||||
if (Preferences.altTimezoneId != "" && Preferences.altTimezoneLabel != "") {
|
||||
views.setString(R.id.alt_timezone_time, "setTimeZone", Preferences.altTimezoneId)
|
||||
views.setString(R.id.alt_timezone_time_am_pm, "setTimeZone", Preferences.altTimezoneId)
|
||||
views.setTextViewText(R.id.alt_timezone_label, Preferences.altTimezoneLabel)
|
||||
|
||||
views.setTextColor(R.id.alt_timezone_time, ColorHelper.getClockFontColor(context.isDarkTheme()))
|
||||
views.setTextColor(R.id.alt_timezone_time_am_pm, ColorHelper.getClockFontColor(context.isDarkTheme()))
|
||||
views.setTextColor(R.id.alt_timezone_label, ColorHelper.getClockFontColor(context.isDarkTheme()))
|
||||
views.setTextViewTextSize(
|
||||
R.id.alt_timezone_time,
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
Preferences.clockTextSize.toPixel(context) / 3
|
||||
)
|
||||
views.setTextViewTextSize(
|
||||
R.id.alt_timezone_time_am_pm,
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
(Preferences.clockTextSize.toPixel(context) / 3) / 5 * 2
|
||||
)
|
||||
views.setTextViewTextSize(
|
||||
R.id.alt_timezone_label,
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
(Preferences.clockTextSize.toPixel(context) / 3) / 5 * 2
|
||||
)
|
||||
|
||||
views.setOnClickPendingIntent(R.id.timezones_container, clockPIntent)
|
||||
views.setViewVisibility(R.id.timezones_container, View.VISIBLE)
|
||||
} else {
|
||||
views.setViewVisibility(R.id.timezones_container, View.GONE)
|
||||
}
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
CrashlyticsReceiver.sendCrash(context, ex)
|
||||
}
|
||||
|
||||
return views
|
||||
}
|
||||
}
|
@ -0,0 +1,975 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.widgets
|
||||
|
||||
import android.Manifest
|
||||
import android.app.PendingIntent
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.text.format.DateUtils
|
||||
import android.util.Log
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.RemoteViews
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.databinding.TheWidgetBinding
|
||||
import com.tommasoberlose.anotherwidget.db.EventRepository
|
||||
import com.tommasoberlose.anotherwidget.global.Actions
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.*
|
||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
||||
import com.tommasoberlose.anotherwidget.helpers.ImageHelper.applyShadow
|
||||
import com.tommasoberlose.anotherwidget.receivers.CrashlyticsReceiver
|
||||
import com.tommasoberlose.anotherwidget.receivers.NewCalendarEventReceiver
|
||||
import com.tommasoberlose.anotherwidget.receivers.WidgetClickListenerReceiver
|
||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||
import com.tommasoberlose.anotherwidget.utils.convertDpToPixel
|
||||
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||
import com.tommasoberlose.anotherwidget.utils.toPixel
|
||||
import java.text.DateFormat
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class StandardWidget(val context: Context) {
|
||||
fun generateWidget(appWidgetId: Int, w: Int, typeface: Typeface? = null): RemoteViews? {
|
||||
|
||||
var views = RemoteViews(context.packageName, R.layout.the_widget_sans)
|
||||
|
||||
try {
|
||||
// Background
|
||||
views.setInt(
|
||||
R.id.widget_shape_background,
|
||||
"setColorFilter",
|
||||
ColorHelper.getBackgroundColorRgb(context.isDarkTheme())
|
||||
)
|
||||
views.setInt(
|
||||
R.id.widget_shape_background,
|
||||
"setImageAlpha",
|
||||
ColorHelper.getBackgroundAlpha(context.isDarkTheme())
|
||||
)
|
||||
val refreshIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
appWidgetId,
|
||||
IntentHelper.getWidgetUpdateIntent(context),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(R.id.widget_shape_background, refreshIntent)
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
CrashlyticsReceiver.sendCrash(context, ex)
|
||||
}
|
||||
|
||||
// Clock
|
||||
views = ClockWidget(context).updateClockView(views, appWidgetId)
|
||||
|
||||
// Setup listener
|
||||
try {
|
||||
val generatedBinding = generateWidgetView(typeface) ?: return null
|
||||
|
||||
views.setImageViewBitmap(
|
||||
R.id.bitmap_container,
|
||||
BitmapHelper.getBitmapFromView(generatedBinding.root, width = w)
|
||||
)
|
||||
views = updateGridView(generatedBinding, views, appWidgetId)
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
CrashlyticsReceiver.sendCrash(context, ex)
|
||||
}
|
||||
|
||||
return views
|
||||
}
|
||||
|
||||
private fun updateGridView(bindingView: TheWidgetBinding, views: RemoteViews, widgetID: Int): RemoteViews {
|
||||
try {
|
||||
val eventRepository = EventRepository(context)
|
||||
val nextEvent = eventRepository.getNextEvent()
|
||||
val eventsCount = eventRepository.getEventsCount()
|
||||
eventRepository.close()
|
||||
|
||||
// Weather
|
||||
if (Preferences.showWeather && Preferences.weatherIcon != "") {
|
||||
views.setViewVisibility(R.id.weather_rect, View.VISIBLE)
|
||||
views.setViewVisibility(R.id.weather_sub_line, View.GONE)
|
||||
|
||||
val i = Intent(context, WidgetClickListenerReceiver::class.java)
|
||||
i.action = Actions.ACTION_OPEN_WEATHER_INTENT
|
||||
val weatherPIntent = PendingIntent.getBroadcast(context, widgetID, i, 0)
|
||||
|
||||
views.setOnClickPendingIntent(R.id.weather_rect, weatherPIntent)
|
||||
views.setOnClickPendingIntent(R.id.weather_sub_line_rect, weatherPIntent)
|
||||
|
||||
views.setImageViewBitmap(
|
||||
R.id.weather_rect,
|
||||
BitmapHelper.getBitmapFromView(bindingView.weatherDateLine, draw = false, width = bindingView.weatherDateLine.width, height = bindingView.weatherDateLine.height)
|
||||
)
|
||||
|
||||
views.setImageViewBitmap(
|
||||
R.id.weather_sub_line_rect,
|
||||
BitmapHelper.getBitmapFromView(bindingView.weatherSubLine, draw = false, width = bindingView.weatherSubLine.width, height = bindingView.weatherSubLine.height)
|
||||
)
|
||||
} else {
|
||||
views.setViewVisibility(R.id.weather_rect, View.GONE)
|
||||
views.setViewVisibility(R.id.weather_sub_line, View.GONE)
|
||||
}
|
||||
|
||||
|
||||
// Calendar
|
||||
views.setImageViewBitmap(
|
||||
R.id.date_rect,
|
||||
BitmapHelper.getBitmapFromView(bindingView.date, draw = false, width = bindingView.date.width, height = bindingView.date.height)
|
||||
)
|
||||
|
||||
val calPIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
widgetID,
|
||||
IntentHelper.getCalendarIntent(context),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(R.id.date_rect, calPIntent)
|
||||
views.setViewVisibility(R.id.first_line_rect, View.VISIBLE)
|
||||
|
||||
// Second row
|
||||
views.setImageViewBitmap(
|
||||
R.id.sub_line_rect,
|
||||
BitmapHelper.getBitmapFromView(bindingView.subLine, draw = false, width = bindingView.subLine.width, height = bindingView.subLine.height)
|
||||
)
|
||||
|
||||
val nextAlarm = AlarmHelper.getNextAlarm(context)
|
||||
|
||||
// Spacing
|
||||
views.setViewVisibility(
|
||||
R.id.sub_line_top_margin_small_sans,
|
||||
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.rawValue) View.VISIBLE else View.GONE
|
||||
)
|
||||
views.setViewVisibility(
|
||||
R.id.sub_line_top_margin_medium_sans,
|
||||
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.rawValue) View.VISIBLE else View.GONE
|
||||
)
|
||||
views.setViewVisibility(
|
||||
R.id.sub_line_top_margin_large_sans,
|
||||
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.LARGE.rawValue) View.VISIBLE else View.GONE
|
||||
)
|
||||
|
||||
if (Preferences.showEvents && context.checkGrantedPermission(Manifest.permission.READ_CALENDAR) && nextEvent != null && !Preferences.showEventsAsGlanceProvider) {
|
||||
if (Preferences.showNextEvent && eventsCount > 1) {
|
||||
|
||||
// Action next event
|
||||
views.setImageViewBitmap(
|
||||
R.id.action_next_rect,
|
||||
BitmapHelper.getBitmapFromView(bindingView.actionNext, draw = false, width = bindingView.actionNext.width, height = bindingView.actionNext.height)
|
||||
)
|
||||
views.setViewVisibility(R.id.action_next_rect, View.VISIBLE)
|
||||
views.setOnClickPendingIntent(
|
||||
R.id.action_next_rect,
|
||||
PendingIntent.getBroadcast(
|
||||
context,
|
||||
widgetID,
|
||||
Intent(
|
||||
context,
|
||||
NewCalendarEventReceiver::class.java
|
||||
).apply { action = Actions.ACTION_GO_TO_NEXT_EVENT },
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
)
|
||||
|
||||
// Action previous event
|
||||
views.setImageViewBitmap(
|
||||
R.id.action_previous_rect,
|
||||
BitmapHelper.getBitmapFromView(bindingView.actionPrevious, draw = false, width = bindingView.actionPrevious.width, height = bindingView.actionPrevious.height)
|
||||
)
|
||||
views.setViewVisibility(R.id.action_previous_rect, View.VISIBLE)
|
||||
views.setOnClickPendingIntent(
|
||||
R.id.action_previous_rect,
|
||||
PendingIntent.getBroadcast(
|
||||
context,
|
||||
widgetID,
|
||||
Intent(
|
||||
context,
|
||||
NewCalendarEventReceiver::class.java
|
||||
).apply { action = Actions.ACTION_GO_TO_PREVIOUS_EVENT },
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
)
|
||||
|
||||
views.setViewVisibility(R.id.action_next_rect, View.VISIBLE)
|
||||
views.setViewVisibility(R.id.action_previous_rect, View.VISIBLE)
|
||||
} else {
|
||||
views.setViewVisibility(R.id.action_next_rect, View.GONE)
|
||||
views.setViewVisibility(R.id.action_previous_rect, View.GONE)
|
||||
}
|
||||
|
||||
// Event intent
|
||||
val eventIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
widgetID,
|
||||
IntentHelper.getEventIntent(context, nextEvent),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(R.id.next_event_rect, eventIntent)
|
||||
views.setViewVisibility(R.id.next_event_rect, View.VISIBLE)
|
||||
|
||||
// Event time difference
|
||||
if (Preferences.showDiffTime && Calendar.getInstance().timeInMillis < nextEvent.startDate) {
|
||||
views.setImageViewBitmap(
|
||||
R.id.next_event_difference_time_rect,
|
||||
BitmapHelper.getBitmapFromView(
|
||||
bindingView.nextEventDifferenceTime,
|
||||
draw = false,
|
||||
width = bindingView.nextEventDifferenceTime.width,
|
||||
height = bindingView.nextEventDifferenceTime.height
|
||||
)
|
||||
)
|
||||
|
||||
views.setOnClickPendingIntent(R.id.next_event_difference_time_rect, eventIntent)
|
||||
if (!Preferences.showNextEventOnMultipleLines) {
|
||||
views.setViewVisibility(R.id.next_event_difference_time_rect, View.VISIBLE)
|
||||
} else {
|
||||
views.setViewVisibility(R.id.next_event_difference_time_rect, View.GONE)
|
||||
}
|
||||
} else {
|
||||
views.setViewVisibility(R.id.next_event_difference_time_rect, View.GONE)
|
||||
}
|
||||
|
||||
// Event information
|
||||
if (nextEvent.address != "" && Preferences.secondRowInformation == 1) {
|
||||
val mapIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
widgetID,
|
||||
IntentHelper.getGoogleMapsIntentFromAddress(context, nextEvent.address),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(R.id.sub_line_rect, mapIntent)
|
||||
} else {
|
||||
val pIntentDetail = PendingIntent.getActivity(
|
||||
context,
|
||||
widgetID,
|
||||
IntentHelper.getEventIntent(
|
||||
context,
|
||||
nextEvent,
|
||||
forceEventDetails = true
|
||||
),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(R.id.sub_line_rect, pIntentDetail)
|
||||
}
|
||||
|
||||
views.setImageViewBitmap(
|
||||
R.id.next_event_rect,
|
||||
BitmapHelper.getBitmapFromView(bindingView.nextEvent, draw = false, width = bindingView.nextEvent.width, height = bindingView.nextEvent.height)
|
||||
)
|
||||
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
|
||||
views.setViewVisibility(R.id.sub_line_rect, View.VISIBLE)
|
||||
views.setViewVisibility(R.id.weather_sub_line_rect, View.VISIBLE)
|
||||
|
||||
views.setViewVisibility(R.id.first_line_rect, View.GONE)
|
||||
|
||||
} else if (GlanceProviderHelper.showGlanceProviders(context)) {
|
||||
var showSomething = false
|
||||
loop@ for (provider: Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders(context)) {
|
||||
when (provider) {
|
||||
Constants.GlanceProviderId.PLAYING_SONG -> {
|
||||
if (MediaPlayerHelper.isSomeonePlaying(context)) {
|
||||
val musicIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
widgetID,
|
||||
IntentHelper.getMusicIntent(context),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(R.id.sub_line_rect, musicIntent)
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
|
||||
if (Preferences.showNextAlarm && nextAlarm != "") {
|
||||
val alarmIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
widgetID,
|
||||
IntentHelper.getClockIntent(context),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(R.id.sub_line_rect, alarmIntent)
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
||||
if (Preferences.showBatteryCharging) {
|
||||
BatteryHelper.updateBatteryInfo(context)
|
||||
if (Preferences.isCharging || Preferences.isBatteryLevelLow) {
|
||||
val batteryIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
widgetID,
|
||||
IntentHelper.getBatteryIntent(),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(R.id.sub_line_rect, batteryIntent)
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.CUSTOM_INFO -> {
|
||||
if (Preferences.customNotes.isNotEmpty()) {
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
|
||||
if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) {
|
||||
val fitIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
widgetID,
|
||||
IntentHelper.getFitIntent(context),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(R.id.sub_line_rect, fitIntent)
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.NOTIFICATIONS -> {
|
||||
if (Preferences.showNotifications && ActiveNotificationsHelper.showLastNotification()) {
|
||||
try {
|
||||
if (Preferences.lastNotificationIcon != 0) {
|
||||
val remotePackageContext = context.createPackageContext(
|
||||
Preferences.lastNotificationPackage, 0)
|
||||
ContextCompat.getDrawable(
|
||||
remotePackageContext,
|
||||
Preferences.lastNotificationIcon)
|
||||
}
|
||||
val notificationIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
widgetID,
|
||||
IntentHelper.getNotificationIntent(context),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(
|
||||
R.id.sub_line_rect,
|
||||
notificationIntent
|
||||
)
|
||||
showSomething = true
|
||||
break@loop
|
||||
} catch (ex: Exception) {}
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.GREETINGS -> {
|
||||
if (Preferences.showGreetings && GreetingsHelper.showGreetings() && GreetingsHelper.getRandomString(context).isNotBlank()) {
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.EVENTS -> {
|
||||
if (Preferences.showEventsAsGlanceProvider&& Preferences.showEvents && context.checkGrantedPermission(
|
||||
Manifest.permission.READ_CALENDAR) && nextEvent != null) {
|
||||
val pIntentDetail = PendingIntent.getActivity(
|
||||
context,
|
||||
widgetID,
|
||||
IntentHelper.getEventIntent(
|
||||
context,
|
||||
nextEvent,
|
||||
forceEventDetails = true
|
||||
),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
views.setOnClickPendingIntent(
|
||||
R.id.sub_line_rect,
|
||||
pIntentDetail
|
||||
)
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (showSomething) {
|
||||
views.setImageViewBitmap(
|
||||
R.id.sub_line_rect,
|
||||
BitmapHelper.getBitmapFromView(bindingView.subLine, draw = false, width = bindingView.subLine.width, height = bindingView.subLine.height)
|
||||
)
|
||||
|
||||
views.setViewVisibility(R.id.first_line_rect, View.VISIBLE)
|
||||
views.setViewVisibility(R.id.sub_line_rect, View.VISIBLE)
|
||||
|
||||
views.setViewVisibility(R.id.calendar_layout_rect, View.GONE)
|
||||
views.setViewVisibility(R.id.weather_sub_line_rect, View.GONE)
|
||||
} else {
|
||||
// Spacing
|
||||
views.setViewVisibility(R.id.sub_line_top_margin_small_sans, View.GONE)
|
||||
views.setViewVisibility(R.id.sub_line_top_margin_medium_sans, View.GONE)
|
||||
views.setViewVisibility(R.id.sub_line_top_margin_large_sans, View.GONE)
|
||||
}
|
||||
} else {
|
||||
views.setViewVisibility(R.id.first_line_rect, View.VISIBLE)
|
||||
views.setViewVisibility(R.id.weather_rect, View.VISIBLE)
|
||||
|
||||
views.setViewVisibility(R.id.calendar_layout_rect, View.GONE)
|
||||
views.setViewVisibility(R.id.sub_line_rect, View.GONE)
|
||||
views.setViewVisibility(R.id.weather_sub_line_rect, View.GONE)
|
||||
// Spacing
|
||||
views.setViewVisibility(R.id.sub_line_top_margin_small_sans, View.GONE)
|
||||
views.setViewVisibility(R.id.sub_line_top_margin_medium_sans, View.GONE)
|
||||
views.setViewVisibility(R.id.sub_line_top_margin_large_sans, View.GONE)
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
CrashlyticsReceiver.sendCrash(context, ex)
|
||||
}
|
||||
|
||||
return views
|
||||
}
|
||||
|
||||
|
||||
// Generates the widget bitmap from the view
|
||||
fun generateWidgetView(typeface: Typeface? = null): TheWidgetBinding? {
|
||||
try {
|
||||
val eventRepository = EventRepository(context)
|
||||
val nextEvent = eventRepository.getNextEvent()
|
||||
val eventsCount = eventRepository.getEventsCount()
|
||||
eventRepository.close()
|
||||
|
||||
val bindingView = TheWidgetBinding.inflate(LayoutInflater.from(context))
|
||||
|
||||
bindingView.loader.isVisible = false
|
||||
|
||||
// Weather
|
||||
if (Preferences.showWeather && Preferences.weatherIcon != "") {
|
||||
bindingView.weatherDateLine.isVisible = true
|
||||
val currentTemp = String.format(
|
||||
Locale.getDefault(),
|
||||
"%d°%s",
|
||||
Preferences.weatherTemp.roundToInt(),
|
||||
Preferences.weatherRealTempUnit
|
||||
)
|
||||
|
||||
val icon: String = Preferences.weatherIcon
|
||||
if (icon == "") {
|
||||
bindingView.weatherSubLineWeatherIcon.isVisible = false
|
||||
bindingView.weatherDateLineWeatherIcon.isVisible = false
|
||||
} else {
|
||||
bindingView.weatherSubLineWeatherIcon.setImageResource(WeatherHelper.getWeatherIconResource(context, icon))
|
||||
bindingView.weatherDateLineWeatherIcon.setImageResource(WeatherHelper.getWeatherIconResource(context, icon))
|
||||
bindingView.weatherSubLineWeatherIcon.isVisible = true
|
||||
bindingView.weatherDateLineWeatherIcon.isVisible = true
|
||||
}
|
||||
|
||||
bindingView.weatherDateLineTemperature.text = currentTemp
|
||||
bindingView.weatherSubLineTemperature.text = currentTemp
|
||||
|
||||
if (GlanceProviderHelper.showGlanceProviders(context)) {
|
||||
bindingView.weatherSubLine.isVisible = false
|
||||
}
|
||||
} else {
|
||||
bindingView.weatherDateLine.isVisible = false
|
||||
bindingView.weatherSubLine.isVisible = false
|
||||
}
|
||||
|
||||
val now = Calendar.getInstance().apply {
|
||||
set(Calendar.SECOND, 0)
|
||||
set(Calendar.MILLISECOND, 0)
|
||||
}
|
||||
|
||||
bindingView.dateLayout.isVisible = true
|
||||
bindingView.calendarLayout.isVisible = false
|
||||
bindingView.nextEventDifferenceTime.isVisible = false
|
||||
bindingView.actionNext.isVisible = false
|
||||
bindingView.actionPrevious.isVisible = false
|
||||
|
||||
bindingView.date.text = DateHelper.getDateText(context, now)
|
||||
|
||||
val nextAlarm = AlarmHelper.getNextAlarm(context)
|
||||
|
||||
if (Preferences.showEvents && context.checkGrantedPermission(Manifest.permission.READ_CALENDAR) && nextEvent != null && !Preferences.showEventsAsGlanceProvider) {
|
||||
// Multiple counter
|
||||
bindingView.actionNext.isVisible =
|
||||
Preferences.showNextEvent && eventsCount > 1
|
||||
bindingView.actionPrevious.isVisible =
|
||||
Preferences.showNextEvent && eventsCount > 1
|
||||
|
||||
bindingView.nextEvent.text = nextEvent.title
|
||||
|
||||
if (Preferences.showNextEventOnMultipleLines) {
|
||||
bindingView.nextEvent.apply {
|
||||
isSingleLine = false
|
||||
maxLines = 3
|
||||
gravity = Gravity.CENTER
|
||||
}
|
||||
}
|
||||
|
||||
if (Preferences.showDiffTime && now.timeInMillis < nextEvent.startDate) {
|
||||
val diffTime = if (!nextEvent.allDay) {
|
||||
SettingsStringHelper.getDifferenceText(
|
||||
context,
|
||||
now.timeInMillis,
|
||||
nextEvent.startDate
|
||||
)
|
||||
.toLowerCase(Locale.getDefault())
|
||||
} else {
|
||||
SettingsStringHelper.getAllDayEventDifferenceText(
|
||||
context,
|
||||
now.timeInMillis,
|
||||
nextEvent.startDate
|
||||
).toLowerCase(Locale.getDefault())
|
||||
}
|
||||
bindingView.nextEventDifferenceTime.text = diffTime
|
||||
|
||||
if (!Preferences.showNextEventOnMultipleLines) {
|
||||
bindingView.nextEventDifferenceTime.isVisible = true
|
||||
} else {
|
||||
bindingView.nextEvent.text = context.getString(R.string.events_glance_provider_format).format(nextEvent.title, diffTime)
|
||||
bindingView.nextEventDifferenceTime.isVisible = false
|
||||
}
|
||||
} else {
|
||||
bindingView.nextEventDifferenceTime.isVisible = false
|
||||
}
|
||||
|
||||
if (nextEvent.address != "" && Preferences.secondRowInformation == 1) {
|
||||
bindingView.subLineIcon.setImageDrawable(
|
||||
ContextCompat.getDrawable(
|
||||
context,
|
||||
R.drawable.round_place_24
|
||||
)
|
||||
)
|
||||
bindingView.subLineText.text = nextEvent.address
|
||||
} else {
|
||||
bindingView.subLineIcon.setImageDrawable(
|
||||
ContextCompat.getDrawable(
|
||||
context,
|
||||
R.drawable.round_today_24
|
||||
)
|
||||
)
|
||||
if (!nextEvent.allDay) {
|
||||
val startHour =
|
||||
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)
|
||||
|
||||
val startCal = Calendar.getInstance()
|
||||
startCal.timeInMillis = nextEvent.startDate
|
||||
|
||||
val endCal = Calendar.getInstance()
|
||||
endCal.timeInMillis = nextEvent.endDate
|
||||
|
||||
if (startCal.get(Calendar.HOUR_OF_DAY) > endCal.get(Calendar.HOUR_OF_DAY)) {
|
||||
dayDiff++
|
||||
} else if (startCal.get(Calendar.HOUR_OF_DAY) == endCal.get(Calendar.HOUR_OF_DAY) && startCal.get(
|
||||
Calendar.MINUTE
|
||||
) > endCal.get(Calendar.MINUTE)
|
||||
) {
|
||||
dayDiff++
|
||||
}
|
||||
var multipleDay = ""
|
||||
if (dayDiff > 0) {
|
||||
multipleDay = String.format(
|
||||
" (+%s%s)",
|
||||
dayDiff,
|
||||
context.getString(R.string.day_char)
|
||||
)
|
||||
}
|
||||
|
||||
if (nextEvent.startDate != nextEvent.endDate) {
|
||||
bindingView.subLineText.text =
|
||||
String.format("%s - %s%s", startHour, endHour, multipleDay)
|
||||
} else {
|
||||
bindingView.subLineText.text =
|
||||
String.format("%s", startHour)
|
||||
}
|
||||
|
||||
} else {
|
||||
val flags: Int =
|
||||
DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NO_YEAR or DateUtils.FORMAT_ABBREV_MONTH
|
||||
val start = Calendar.getInstance().apply { timeInMillis = nextEvent.startDate }
|
||||
|
||||
bindingView.subLineText.text = if (now.get(Calendar.DAY_OF_YEAR) == start.get(
|
||||
Calendar.DAY_OF_YEAR)) {
|
||||
DateUtils.formatDateTime(context, nextEvent.startDate, flags)
|
||||
} else if (now.get(Calendar.DAY_OF_YEAR) > start.get(Calendar.DAY_OF_YEAR) || now.get(
|
||||
Calendar.YEAR) > start.get(Calendar.YEAR)) {
|
||||
DateUtils.formatDateTime(context, now.timeInMillis, flags)
|
||||
} else {
|
||||
DateUtils.formatDateTime(context, nextEvent.startDate, flags)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bindingView.dateLayout.isVisible = false
|
||||
bindingView.calendarLayout.isVisible = true
|
||||
bindingView.subLine.isVisible = true
|
||||
bindingView.weatherSubLine.isVisible = true
|
||||
|
||||
bindingView.subLineTopMarginSmall.visibility =
|
||||
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.rawValue) View.VISIBLE else View.GONE
|
||||
bindingView.subLineTopMarginMedium.visibility =
|
||||
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.rawValue) View.VISIBLE else View.GONE
|
||||
bindingView.subLineTopMarginLarge.visibility =
|
||||
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.LARGE.rawValue) View.VISIBLE else View.GONE
|
||||
} else if (GlanceProviderHelper.showGlanceProviders(context)) {
|
||||
bindingView.subLineIcon.isVisible = true
|
||||
var showSomething = false
|
||||
loop@ for (provider: Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders(
|
||||
context
|
||||
)) {
|
||||
when (provider) {
|
||||
Constants.GlanceProviderId.PLAYING_SONG -> {
|
||||
if (MediaPlayerHelper.isSomeonePlaying(context)) {
|
||||
bindingView.subLineIcon.setImageDrawable(
|
||||
ContextCompat.getDrawable(
|
||||
context,
|
||||
R.drawable.round_music_note_24
|
||||
)
|
||||
)
|
||||
bindingView.subLineText.text = MediaPlayerHelper.getMediaInfo()
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
|
||||
if (Preferences.showNextAlarm && nextAlarm != "") {
|
||||
bindingView.subLineIcon.setImageDrawable(
|
||||
ContextCompat.getDrawable(
|
||||
context,
|
||||
R.drawable.round_alarm_24
|
||||
)
|
||||
)
|
||||
bindingView.subLineText.text = AlarmHelper.getNextAlarm(context)
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
||||
if (Preferences.showBatteryCharging) {
|
||||
BatteryHelper.updateBatteryInfo(context)
|
||||
if (Preferences.isCharging) {
|
||||
bindingView.subLineIcon.isVisible = false
|
||||
val batteryLevel = BatteryHelper.getBatteryLevel(context)
|
||||
if (batteryLevel != 100) {
|
||||
bindingView.subLineText.text = context.getString(R.string.charging)
|
||||
} else {
|
||||
bindingView.subLineText.text =
|
||||
context.getString(R.string.charged)
|
||||
}
|
||||
showSomething = true
|
||||
break@loop
|
||||
} else if (Preferences.isBatteryLevelLow) {
|
||||
bindingView.subLineIcon.isVisible = false
|
||||
bindingView.subLineText.text =
|
||||
context.getString(R.string.battery_low_warning)
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.CUSTOM_INFO -> {
|
||||
if (Preferences.customNotes.isNotEmpty()) {
|
||||
bindingView.subLineIcon.isVisible = false
|
||||
bindingView.subLineText.text = Preferences.customNotes
|
||||
bindingView.subLineText.maxLines = 2
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
|
||||
if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) {
|
||||
bindingView.subLineIcon.isVisible = false
|
||||
bindingView.subLineText.text =
|
||||
context.getString(R.string.daily_steps_counter)
|
||||
.format(Preferences.googleFitSteps)
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.NOTIFICATIONS -> {
|
||||
if (Preferences.showNotifications && ActiveNotificationsHelper.showLastNotification()) {
|
||||
try {
|
||||
if (Preferences.lastNotificationIcon != 0) {
|
||||
val remotePackageContext = context.createPackageContext(
|
||||
Preferences.lastNotificationPackage, 0)
|
||||
val icon = ContextCompat.getDrawable(remotePackageContext,
|
||||
Preferences.lastNotificationIcon)
|
||||
bindingView.subLineIcon.isVisible = true
|
||||
bindingView.subLineIcon.setImageDrawable(icon)
|
||||
} else {
|
||||
bindingView.subLineIcon.isVisible = false
|
||||
}
|
||||
bindingView.subLineText.text = Preferences.lastNotificationTitle
|
||||
showSomething = true
|
||||
break@loop
|
||||
} catch (ex: Exception) {}
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.GREETINGS -> {
|
||||
val greetingsText = GreetingsHelper.getRandomString(context)
|
||||
if (Preferences.showGreetings && GreetingsHelper.showGreetings() && greetingsText.isNotBlank()) {
|
||||
bindingView.subLineText.text = greetingsText
|
||||
bindingView.subLineText.maxLines = 2
|
||||
bindingView.subLineIcon.isVisible = false
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
Constants.GlanceProviderId.EVENTS -> {
|
||||
if (Preferences.showEventsAsGlanceProvider && Preferences.showEvents && context.checkGrantedPermission(
|
||||
Manifest.permission.READ_CALENDAR) && nextEvent != null) {
|
||||
bindingView.subLineText.text = context.getString(R.string.events_glance_provider_format).format(nextEvent.title, if (Preferences.showDiffTime && now.timeInMillis < nextEvent.startDate) {
|
||||
if (!nextEvent.allDay) {
|
||||
SettingsStringHelper.getDifferenceText(
|
||||
context,
|
||||
now.timeInMillis,
|
||||
nextEvent.startDate
|
||||
)
|
||||
.toLowerCase(Locale.getDefault())
|
||||
} else {
|
||||
SettingsStringHelper.getAllDayEventDifferenceText(
|
||||
context,
|
||||
now.timeInMillis,
|
||||
nextEvent.startDate
|
||||
).toLowerCase(Locale.getDefault())
|
||||
}
|
||||
} else "").trimEnd()
|
||||
bindingView.subLineIcon.isVisible = true
|
||||
bindingView.subLineIcon.setImageDrawable(
|
||||
ContextCompat.getDrawable(
|
||||
context,
|
||||
R.drawable.round_today_24
|
||||
)
|
||||
)
|
||||
showSomething = true
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (showSomething) {
|
||||
bindingView.dateLayout.isVisible = true
|
||||
bindingView.calendarLayout.isVisible = false
|
||||
bindingView.subLine.isVisible = true
|
||||
bindingView.weatherSubLine.isVisible = false
|
||||
|
||||
bindingView.subLineTopMarginSmall.visibility =
|
||||
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.rawValue) View.VISIBLE else View.GONE
|
||||
bindingView.subLineTopMarginMedium.visibility =
|
||||
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.rawValue) View.VISIBLE else View.GONE
|
||||
bindingView.subLineTopMarginLarge.visibility =
|
||||
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.LARGE.rawValue) View.VISIBLE else View.GONE
|
||||
} else {
|
||||
bindingView.subLineIcon.isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Color
|
||||
listOf<TextView>(
|
||||
bindingView.date,
|
||||
bindingView.weatherDateLineDivider,
|
||||
bindingView.weatherDateLineTemperature,
|
||||
bindingView.nextEvent,
|
||||
bindingView.nextEventDifferenceTime,
|
||||
).forEach {
|
||||
it.setTextColor(ColorHelper.getFontColor(context.applicationContext.isDarkTheme()))
|
||||
}
|
||||
|
||||
if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.rawValue) {
|
||||
listOf<ImageView>(bindingView.actionNext, bindingView.actionPrevious)
|
||||
} else {
|
||||
listOf<ImageView>(
|
||||
bindingView.actionNext,
|
||||
bindingView.actionPrevious,
|
||||
bindingView.weatherDateLineWeatherIcon,
|
||||
bindingView.weatherSubLineWeatherIcon
|
||||
)
|
||||
}.forEach {
|
||||
it.setColorFilter(ColorHelper.getFontColorRgb(context.applicationContext.isDarkTheme()))
|
||||
it.alpha =
|
||||
(if (context.isDarkTheme()) Preferences.textGlobalAlphaDark.toIntValue()
|
||||
.toFloat() else Preferences.textGlobalAlpha.toIntValue()
|
||||
.toFloat()) / 100
|
||||
}
|
||||
|
||||
listOf<TextView>(bindingView.subLineText, bindingView.weatherSubLineDivider, bindingView.weatherSubLineTemperature).forEach {
|
||||
it.setTextColor(ColorHelper.getSecondaryFontColor(context.applicationContext.isDarkTheme()))
|
||||
}
|
||||
|
||||
if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.rawValue) {
|
||||
listOf<ImageView>(bindingView.subLineIcon, bindingView.subLineIconShadow)
|
||||
} else {
|
||||
listOf<ImageView>(bindingView.subLineIcon, bindingView.weatherSubLineWeatherIcon, bindingView.subLineIconShadow)
|
||||
}.forEach {
|
||||
it.setColorFilter(ColorHelper.getSecondaryFontColorRgb(context.applicationContext.isDarkTheme()))
|
||||
it.alpha =
|
||||
(if (context.isDarkTheme()) Preferences.textSecondaryAlphaDark.toIntValue()
|
||||
.toFloat() else Preferences.textSecondaryAlpha.toIntValue()
|
||||
.toFloat()) / 100
|
||||
}
|
||||
|
||||
// Text Size
|
||||
listOf<Pair<TextView, Float>>(
|
||||
bindingView.date to Preferences.textMainSize,
|
||||
bindingView.weatherDateLineDivider to (Preferences.textMainSize - 2),
|
||||
bindingView.weatherDateLineTemperature to Preferences.textMainSize,
|
||||
bindingView.nextEvent to Preferences.textMainSize,
|
||||
bindingView.nextEventDifferenceTime to Preferences.textMainSize,
|
||||
bindingView.subLineText to Preferences.textSecondSize,
|
||||
bindingView.weatherSubLineDivider to (Preferences.textSecondSize - 2),
|
||||
bindingView.weatherSubLineTemperature to Preferences.textSecondSize,
|
||||
).forEach {
|
||||
it.first.setTextSize(TypedValue.COMPLEX_UNIT_SP, it.second)
|
||||
}
|
||||
|
||||
// Icons scale
|
||||
bindingView.subLineIcon.scaleX = Preferences.textSecondSize / 18f
|
||||
bindingView.subLineIcon.scaleY = Preferences.textSecondSize / 18f
|
||||
|
||||
bindingView.weatherSubLineWeatherIcon.scaleX = Preferences.textSecondSize / 18f
|
||||
bindingView.weatherSubLineWeatherIcon.scaleY = Preferences.textSecondSize / 18f
|
||||
|
||||
bindingView.weatherDateLineWeatherIcon.scaleX = Preferences.textMainSize / 18f
|
||||
bindingView.weatherDateLineWeatherIcon.scaleY = Preferences.textMainSize / 18f
|
||||
|
||||
bindingView.actionNext.scaleX = Preferences.textMainSize / 28f
|
||||
bindingView.actionNext.scaleY = Preferences.textMainSize / 28f
|
||||
|
||||
bindingView.actionPrevious.scaleX = Preferences.textMainSize / 28f
|
||||
bindingView.actionPrevious.scaleY = Preferences.textMainSize / 28f
|
||||
|
||||
|
||||
// Shadows
|
||||
val shadowRadius =
|
||||
when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
|
||||
0 -> 0f
|
||||
1 -> 5f
|
||||
2 -> 5f
|
||||
else -> 5f
|
||||
}
|
||||
val shadowColor =
|
||||
when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
|
||||
0 -> Color.TRANSPARENT
|
||||
1 -> R.color.black_50
|
||||
2 -> Color.BLACK
|
||||
else -> R.color.black_50
|
||||
}
|
||||
val shadowDy =
|
||||
when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
|
||||
0 -> 0f
|
||||
1 -> 0f
|
||||
2 -> 1f
|
||||
else -> 0f
|
||||
}
|
||||
|
||||
listOf<TextView>(
|
||||
bindingView.date,
|
||||
bindingView.weatherDateLineDivider,
|
||||
bindingView.weatherDateLineTemperature,
|
||||
bindingView.nextEvent,
|
||||
bindingView.nextEventDifferenceTime,
|
||||
bindingView.subLineText,
|
||||
bindingView.weatherSubLineDivider,
|
||||
bindingView.weatherSubLineTemperature,
|
||||
).forEach {
|
||||
it.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
|
||||
}
|
||||
|
||||
// Icons shadow
|
||||
|
||||
listOf(
|
||||
Pair(bindingView.subLineIcon, bindingView.subLineIconShadow),
|
||||
).forEach {
|
||||
if ((if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) == 0) {
|
||||
it.second.isVisible = false
|
||||
} else {
|
||||
it.second.isVisible = it.first.isVisible
|
||||
it.second.scaleX = it.first.scaleX
|
||||
it.second.scaleY = it.first.scaleY
|
||||
it.second.applyShadow(it.first)
|
||||
}
|
||||
}
|
||||
|
||||
listOf(
|
||||
Pair(bindingView.actionNext, bindingView.actionNextShadow),
|
||||
Pair(bindingView.actionPrevious, bindingView.actionPreviousShadow),
|
||||
).forEach {
|
||||
if ((if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) == 0) {
|
||||
it.second.isVisible = false
|
||||
} else {
|
||||
it.second.isVisible = it.first.isVisible
|
||||
it.second.scaleX = it.first.scaleX
|
||||
it.second.scaleY = it.first.scaleY
|
||||
it.second.applyShadow(it.first, 0.6f)
|
||||
}
|
||||
}
|
||||
|
||||
bindingView.actionPrevious.scaleX = bindingView.actionPrevious.scaleX * -1
|
||||
bindingView.actionPreviousShadow.scaleX = bindingView.actionPreviousShadow.scaleX * -1
|
||||
|
||||
// Custom Font
|
||||
if (Preferences.customFont == Constants.CUSTOM_FONT_GOOGLE_SANS) {
|
||||
val googleSans: Typeface = when (Preferences.customFontVariant) {
|
||||
"100" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_thin.ttf")
|
||||
"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>(
|
||||
bindingView.date,
|
||||
bindingView.weatherDateLineDivider,
|
||||
bindingView.weatherDateLineTemperature,
|
||||
bindingView.nextEvent,
|
||||
bindingView.nextEventDifferenceTime,
|
||||
bindingView.subLineText,
|
||||
bindingView.weatherSubLineDivider,
|
||||
bindingView.weatherSubLineTemperature,
|
||||
).forEach {
|
||||
it.typeface = googleSans
|
||||
}
|
||||
} else if (Preferences.customFont == Constants.CUSTOM_FONT_DOWNLOADED && typeface != null) {
|
||||
listOf<TextView>(
|
||||
bindingView.date,
|
||||
bindingView.weatherDateLineDivider,
|
||||
bindingView.weatherDateLineTemperature,
|
||||
bindingView.nextEvent,
|
||||
bindingView.nextEventDifferenceTime,
|
||||
bindingView.subLineText,
|
||||
bindingView.weatherSubLineDivider,
|
||||
bindingView.weatherSubLineTemperature,
|
||||
).forEach {
|
||||
it.typeface = typeface
|
||||
}
|
||||
}
|
||||
|
||||
// Dividers
|
||||
arrayOf(bindingView.weatherDateLineDivider, bindingView.weatherSubLineDivider).forEach {
|
||||
it.visibility = if (Preferences.showDividers) View.VISIBLE else View.INVISIBLE
|
||||
it.layoutParams = (it.layoutParams as ViewGroup.MarginLayoutParams).apply {
|
||||
this.marginEnd = if (Preferences.showDividers) 8f.convertDpToPixel(context).toInt() else 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return bindingView
|
||||
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
CrashlyticsReceiver.sendCrash(context, ex)
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ package com.tommasoberlose.anotherwidget.utils
|
||||
|
||||
import android.animation.*
|
||||
import android.content.pm.PackageManager
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.view.ViewAnimationUtils
|
||||
import android.widget.Toast
|
||||
@ -21,22 +20,15 @@ import android.content.Intent
|
||||
import android.content.res.Resources
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Log
|
||||
import android.util.TypedValue
|
||||
import android.view.ViewPropertyAnimator
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.Transformation
|
||||
import android.widget.LinearLayout
|
||||
import android.view.animation.AlphaAnimation
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.annotation.UiThread
|
||||
import androidx.browser.customtabs.CustomTabColorSchemeParams
|
||||
import androidx.core.animation.addListener
|
||||
import androidx.core.animation.doOnEnd
|
||||
import androidx.core.animation.doOnStart
|
||||
import androidx.core.view.isVisible
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
||||
import kotlinx.android.synthetic.main.fragment_app_main.*
|
||||
import kotlinx.android.synthetic.main.the_widget_sans.*
|
||||
import com.tommasoberlose.anotherwidget.components.OnSingleClickListener
|
||||
import java.util.*
|
||||
|
||||
|
||||
@ -149,7 +141,7 @@ fun View.collapse(duration: Long = 500L) {
|
||||
fun Context.openURI(url: String) {
|
||||
try {
|
||||
val builder: CustomTabsIntent.Builder = CustomTabsIntent.Builder()
|
||||
builder.setToolbarColor(ContextCompat.getColor(this, R.color.colorPrimary))
|
||||
builder.setDefaultColorSchemeParams(CustomTabColorSchemeParams.Builder().setToolbarColor(ContextCompat.getColor(this, R.color.colorPrimary)).build())
|
||||
val customTabsIntent: CustomTabsIntent = builder.build()
|
||||
customTabsIntent.launchUrl(this, Uri.parse(url))
|
||||
} catch (e: Exception) {
|
||||
@ -264,4 +256,20 @@ fun Locale.isMetric(): Boolean {
|
||||
"US", "LR", "MM", "GB" -> false
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun View.setOnSingleClickListener(l: View.OnClickListener) {
|
||||
setOnClickListener(OnSingleClickListener(l))
|
||||
}
|
||||
|
||||
fun View.setOnSingleClickListener(l: (View) -> Unit) {
|
||||
setOnClickListener(OnSingleClickListener(l))
|
||||
}
|
||||
|
||||
fun ignoreExceptions(function: () -> Unit) = run {
|
||||
try {
|
||||
function.invoke()
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
26
app/src/main/res/anim/item_animation_fall_down.xml
Normal file
@ -0,0 +1,26 @@
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:duration="400">
|
||||
|
||||
<translate
|
||||
android:fromYDelta="-20%"
|
||||
android:toYDelta="0"
|
||||
android:interpolator="@android:anim/decelerate_interpolator"
|
||||
/>
|
||||
|
||||
<alpha
|
||||
android:fromAlpha="0"
|
||||
android:toAlpha="1"
|
||||
android:interpolator="@android:anim/decelerate_interpolator"
|
||||
/>
|
||||
|
||||
<scale
|
||||
android:fromXScale="105%"
|
||||
android:fromYScale="105%"
|
||||
android:toXScale="100%"
|
||||
android:toYScale="100%"
|
||||
android:pivotX="50%"
|
||||
android:pivotY="50%"
|
||||
android:interpolator="@android:anim/decelerate_interpolator"
|
||||
/>
|
||||
|
||||
</set>
|
7
app/src/main/res/anim/layout_animation_fall_down.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layoutAnimation
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:animation="@anim/item_animation_fall_down"
|
||||
android:delay="15%"
|
||||
android:animationOrder="normal"
|
||||
/>
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 674 B After Width: | Height: | Size: 750 B |
After Width: | Height: | Size: 207 B |
After Width: | Height: | Size: 210 B |
After Width: | Height: | Size: 203 B |
After Width: | Height: | Size: 292 B |
After Width: | Height: | Size: 245 B |
After Width: | Height: | Size: 184 B |
After Width: | Height: | Size: 186 B |
After Width: | Height: | Size: 174 B |