Moving to version 2.0
BIN
.idea/caches/build_file_checksums.ser
generated
Normal file
122
.idea/codeStyles/Project.xml
generated
Normal file
@ -0,0 +1,122 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<JetCodeStyleSettings>
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<rules>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:android</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:id</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>style</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="kotlin">
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
1
.idea/gradle.xml
generated
@ -3,6 +3,7 @@
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="testRunner" value="PLATFORM" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="modules">
|
||||
|
29
.idea/misc.xml
generated
@ -1,28 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="NullableNotNullManager">
|
||||
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
|
||||
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
|
||||
<option name="myNullables">
|
||||
<value>
|
||||
<list size="4">
|
||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
|
||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
|
||||
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
|
||||
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
<option name="myNotNulls">
|
||||
<value>
|
||||
<list size="4">
|
||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
|
||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
|
||||
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
|
||||
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
<component name="CMakeSettings">
|
||||
<configurations>
|
||||
<configuration PROFILE_NAME="Debug" CONFIG_NAME="Debug" />
|
||||
</configurations>
|
||||
</component>
|
||||
<component name="ProjectInspectionProfilesVisibleTreeState">
|
||||
<entry key="Project Default">
|
||||
@ -80,7 +61,7 @@
|
||||
</profile-state>
|
||||
</entry>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
4
.idea/modules.xml
generated
@ -2,8 +2,8 @@
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/another-widget.iml" filepath="$PROJECT_DIR$/another-widget.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Another Widget.iml" filepath="$PROJECT_DIR$/Another Widget.iml" group="Another Widget" />
|
||||
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" group="Another Widget/app" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
2
.idea/vcs.xml
generated
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
128
app/build.gradle
@ -1,59 +1,117 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
|
||||
// Apply the Crashlytics Gradle plugin
|
||||
apply plugin: 'com.google.firebase.crashlytics'
|
||||
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
|
||||
apply plugin: 'kotlin-kapt'
|
||||
|
||||
apply plugin: 'io.fabric'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
|
||||
apply plugin: 'realm-android'
|
||||
|
||||
android {
|
||||
compileSdkVersion 26
|
||||
buildToolsVersion "26.0.2"
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "29.0.3"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.tommasoberlose.anotherwidget"
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 26
|
||||
versionCode 32
|
||||
versionName "1.3"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 29
|
||||
versionCode 40
|
||||
versionName "2.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||
}
|
||||
packagingOptions {
|
||||
exclude 'META-INF/DEPENDENCIES'
|
||||
}
|
||||
dataBinding {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
viewBinding.enabled = true
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'com.android.support:appcompat-v7:26.1.0'
|
||||
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation('com.android.support.test.espresso:espresso-core:3.0.1', {
|
||||
exclude group: 'com.android.support', module: 'support-annotations'
|
||||
})
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
|
||||
implementation 'com.survivingwithandroid:weatherlib:1.6.0'
|
||||
implementation 'com.survivingwithandroid:weatherlib_volleyclient:1.6.0'
|
||||
implementation 'com.mcxiaoke.volley:library:1.0.6@aar'
|
||||
implementation 'com.android.support:customtabs:26.1.0'
|
||||
implementation 'com.android.support:cardview-v7:26.1.0'
|
||||
kapt 'com.android.databinding:compiler:3.0.0'
|
||||
implementation('com.crashlytics.sdk.android:crashlytics:2.7.0@aar') {
|
||||
transitive = true
|
||||
}
|
||||
implementation 'com.android.support:design:26.1.0'
|
||||
implementation 'org.greenrobot:eventbus:3.0.0'
|
||||
implementation 'com.android.support:recyclerview-v7:26.1.0'
|
||||
implementation 'com.google.android.gms:play-services-awareness:11.6.0'
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'androidx.core:core-ktx:1.2.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
testImplementation 'junit:junit:4.13'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
|
||||
// UI
|
||||
implementation 'com.google.android.material:material:1.2.0-alpha06'
|
||||
implementation 'androidx.browser:browser:1.2.0'
|
||||
implementation 'net.idik:slimadapter:2.1.2'
|
||||
|
||||
// Lifecycle
|
||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||
|
||||
// EventBus
|
||||
implementation 'org.greenrobot:eventbus:3.1.1'
|
||||
|
||||
// Navigation
|
||||
implementation 'androidx.navigation:navigation-fragment:2.3.0-alpha05'
|
||||
implementation 'androidx.navigation:navigation-ui-ktx:2.2.2'
|
||||
|
||||
// Other
|
||||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
implementation 'joda-time:joda-time:2.9.9'
|
||||
implementation 'com.pes.materialcolorpicker:library:1.0.4'
|
||||
implementation "dev.sasikanth:colorsheet:1.0.1"
|
||||
implementation 'com.andkulikov:transitionseverywhere:1.7.6'
|
||||
implementation 'me.everything:providers-android:1.0.1'
|
||||
compile 'com.anjlab.android.iab.v3:library:1.0.44'
|
||||
|
||||
//Weather
|
||||
implementation 'com.github.KwabenBerko:OpenWeatherMap-Android-Library:2.0.2'
|
||||
implementation 'com.google.android.gms:play-services-location:17.0.0'
|
||||
|
||||
// Billing
|
||||
implementation 'com.android.billingclient:billing:2.2.0'
|
||||
implementation 'com.android.billingclient:billing-ktx:2.2.0'
|
||||
|
||||
// KTX
|
||||
implementation "androidx.core:core-ktx:1.2.0"
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
|
||||
|
||||
// Recommended: Add the Firebase SDK for Google Analytics.
|
||||
implementation 'com.google.firebase:firebase-analytics:17.4.0'
|
||||
|
||||
// Add the Firebase SDK for Crashlytics.
|
||||
implementation 'com.google.firebase:firebase-crashlytics:17.0.0'
|
||||
|
||||
// Preferences
|
||||
implementation 'com.chibatching.kotpref:kotpref:2.10.0'
|
||||
implementation 'com.chibatching.kotpref:livedata-support:2.10.0'
|
||||
implementation 'androidx.preference:preference-ktx:1.1.1'
|
||||
|
||||
// Permissions
|
||||
implementation 'com.karumi:dexter:6.1.0'
|
||||
|
||||
// Billing
|
||||
implementation 'com.android.billingclient:billing:2.2.0'
|
||||
implementation 'com.android.billingclient:billing-ktx:2.2.0'
|
||||
}
|
||||
|
@ -1,3 +0,0 @@
|
||||
#Contains API Secret used to validate your application. Commit to internal source control; avoid making secret public.
|
||||
#Wed Oct 11 22:01:24 CEST 2017
|
||||
apiSecret=df2efbce5a4f9101ba6923b7dfa5725a5283ee08c3e748ccfafb01a5070bb532
|
40
app/google-services.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"project_info": {
|
||||
"project_number": "791844924473",
|
||||
"firebase_url": "https://anotherwidget-182008.firebaseio.com",
|
||||
"project_id": "anotherwidget-182008",
|
||||
"storage_bucket": "anotherwidget-182008.appspot.com"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:791844924473:android:0ad4f6e3890f1ad320b1e8",
|
||||
"android_client_info": {
|
||||
"package_name": "com.tommasoberlose.anotherwidget"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "791844924473-73dh46rorjq8vm97dgbn6can2dcpqlf0.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyAeJRXstqnzebibxmm3FRM98nbwE_kC8tA"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "791844924473-73dh46rorjq8vm97dgbn6can2dcpqlf0.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
@ -1 +0,0 @@
|
||||
[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":32},"path":"app-release.apk","properties":{"packageId":"com.tommasoberlose.anotherwidget","split":"","minSdkVersion":"19"}}]
|
@ -1,7 +1,7 @@
|
||||
package com.tommasoberlose.anotherwidget
|
||||
|
||||
import android.support.test.InstrumentationRegistry
|
||||
import android.support.test.runner.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
@ -15,10 +15,10 @@ import org.junit.Assert.*
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getTargetContext()
|
||||
assertEquals("com.tommasoberlose.anotherwidget", appContext.packageName)
|
||||
}
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("com.tommasoberlose.anotherwidget", appContext.packageName)
|
||||
}
|
||||
}
|
||||
|
@ -7,33 +7,30 @@
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="com.android.vending.BILLING" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:name=".ui.AWApplication"
|
||||
android:name=".components.AWApplication"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<meta-data
|
||||
android:name="com.google.android.awareness.API_KEY"
|
||||
android:value="AIzaSyAMkqiQHTdZGOUxRd0ZEvvrIE1qN_3pJb4" />
|
||||
|
||||
<activity
|
||||
android:name=".ui.activity.MainActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:launchMode="singleInstance"
|
||||
android:screenOrientation="portrait">
|
||||
<activity android:name=".ui.activities.MainActivity" android:launchMode="singleInstance" android:theme="@style/AppTheme.Main">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".ui.activities.ChooseApplicationActivity" android:launchMode="singleInstance" />
|
||||
<activity android:name=".ui.activities.CustomLocationActivity" android:launchMode="singleInstance" />
|
||||
<activity android:name=".ui.activities.WeatherProviderActivity" android:launchMode="singleInstance" />
|
||||
<activity android:name=".ui.activities.SupportDevActivity" android:launchMode="singleInstance" />
|
||||
|
||||
<receiver android:name=".ui.widget.TheWidget">
|
||||
|
||||
<receiver android:name=".ui.widgets.TheWidget">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
@ -43,77 +40,47 @@
|
||||
android:resource="@xml/the_widget_info" />
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".receiver.NewCalendarEventReceiver"
|
||||
android:name=".receivers.NewCalendarEventReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:priority="1000">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.PROVIDER_CHANGED" />
|
||||
|
||||
<data android:scheme="content" />
|
||||
<data android:host="com.android.calendar" />
|
||||
<data android:scheme="content"/>
|
||||
<data android:host="com.android.calendar"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="com.tommasoberlose.anotherwidget.action.GO_TO_NEXT_EVENT" />
|
||||
<action android:name="com.tommasoberlose.anotherwidget.action.GO_TO_PREVIOUS_EVENT" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".receiver.UpdatesReceiver"
|
||||
android:name=".receivers.UpdatesReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="false">
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="com.tommasoberlose.anotherwidget.action.ACTION_TIME_UPDATE" />
|
||||
<action android:name="com.tommasoberlose.anotherwidget.action.ACTION_CALENDAR_UPDATE" />
|
||||
<action android:name="android.intent.action.USER_PRESENT" />
|
||||
<action android:name="com.sec.android.widgetapp.APPWIDGET_RESIZE" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.PACKAGE_ADDED" />
|
||||
<action android:name="android.intent.action.PACKAGE_REPLACED" />
|
||||
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||
|
||||
<data android:scheme="package" />
|
||||
<action android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
|
||||
<action android:name="android.intent.action.DATE_CHANGED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".receiver.WeatherReceiver"
|
||||
android:name=".receivers.WeatherReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="false">
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="com.tommasoberlose.anotherwidget.action.ACTION_WEATHER_UPDATE" />
|
||||
<action android:name="android.location.PROVIDERS_CHANGED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.PACKAGE_REPLACED" />
|
||||
<action android:name="android.intent.action.PACKAGE_ADDED" />
|
||||
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||
|
||||
<data android:scheme="package" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<meta-data
|
||||
android:name="io.fabric.ApiKey"
|
||||
android:value="5232fd734b08a20a984c2de02b37df19269608ef" />
|
||||
|
||||
<activity
|
||||
android:name=".ui.activity.CustomLocationActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:launchMode="singleInstance"
|
||||
android:screenOrientation="portrait" />
|
||||
<activity
|
||||
android:name=".ui.activity.ChooseApplicationActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:screenOrientation="portrait" />
|
||||
<activity
|
||||
android:name=".ui.activity.WeatherProviderActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<receiver
|
||||
android:name=".receiver.OpenWeatherIntentReceiver"
|
||||
android:name=".receivers.WidgetClickListenerReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
@ -121,14 +88,6 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service
|
||||
android:name=".util.CrocodileService"
|
||||
android:enabled="true"/>
|
||||
|
||||
<activity android:name=".ui.activity.SupportDevActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:launchMode="singleInstance"
|
||||
android:screenOrientation="portrait" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
BIN
app/src/main/ic_launcher-playstore.png
Normal file
After Width: | Height: | Size: 50 KiB |
@ -0,0 +1,27 @@
|
||||
package com.tommasoberlose.anotherwidget.components
|
||||
|
||||
import android.app.Application
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import com.chibatching.kotpref.Kotpref
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
|
||||
class AWApplication : Application() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
// Preferences
|
||||
Kotpref.init(this)
|
||||
|
||||
// Dark theme
|
||||
AppCompatDelegate.setDefaultNightMode(Preferences.darkThemePreference)
|
||||
|
||||
// Realm
|
||||
Realm.init(this)
|
||||
val config = RealmConfiguration.Builder()
|
||||
.deleteRealmIfMigrationNeeded()
|
||||
.build()
|
||||
Realm.setDefaultConfiguration(config)
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package com.tommasoberlose.anotherwidget.components
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.annotation.MenuRes
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import androidx.core.view.isVisible
|
||||
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.*
|
||||
|
||||
/**
|
||||
* [BottomSheetDialogFragment] that uses a custom
|
||||
* theme which sets a rounded background to the dialog
|
||||
* and doesn't dim the navigation bar
|
||||
*/
|
||||
open class BottomSheetMenu<T>(context: Context, private val header: String? = null) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
||||
|
||||
private val items: ArrayList<MenuItem<T>> = ArrayList()
|
||||
private var selectedRes: T? = null
|
||||
private var callback: ((selectedValue: T) -> Unit)? = null
|
||||
|
||||
fun selectResource(res: T): BottomSheetMenu<T> {
|
||||
selectedRes = res
|
||||
return this
|
||||
}
|
||||
|
||||
fun addItem(title: String, value: T): BottomSheetMenu<T> {
|
||||
items.add(MenuItem(title, value))
|
||||
return this
|
||||
}
|
||||
|
||||
fun addOnSelectItemListener(callback: (selectedValue: T) -> Unit): BottomSheetMenu<T> {
|
||||
this.callback = callback
|
||||
return this
|
||||
}
|
||||
|
||||
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 ?: ""
|
||||
|
||||
// Menu
|
||||
for (item in items) {
|
||||
val itemView = View.inflate(context, R.layout.bottom_sheet_menu_item, null)
|
||||
itemView.label.text = item.title
|
||||
itemView.isSelected = item.value == selectedRes
|
||||
itemView.setOnClickListener {
|
||||
callback?.invoke(item.value)
|
||||
this.dismiss()
|
||||
}
|
||||
view.menu.addView(itemView)
|
||||
}
|
||||
setContentView(view)
|
||||
super.show()
|
||||
}
|
||||
|
||||
class MenuItem<T>(val title: String, val value: T)
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.tommasoberlose.anotherwidget.`object`
|
||||
package com.tommasoberlose.anotherwidget.components
|
||||
|
||||
/**
|
||||
* Created by tommaso on 08/10/17.
|
@ -1,4 +1,4 @@
|
||||
package com.tommasoberlose.anotherwidget.`object`
|
||||
package com.tommasoberlose.anotherwidget.components.events
|
||||
|
||||
import android.content.pm.ApplicationInfo
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.tommasoberlose.anotherwidget.`object`
|
||||
package com.tommasoberlose.anotherwidget.components.events
|
||||
|
||||
import android.content.pm.ApplicationInfo
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.tommasoberlose.anotherwidget.`object`
|
||||
package com.tommasoberlose.anotherwidget.components.events
|
||||
|
||||
import android.location.Address
|
||||
|
@ -1,9 +1,6 @@
|
||||
package com.tommasoberlose.anotherwidget.`object`
|
||||
package com.tommasoberlose.anotherwidget.components.events
|
||||
|
||||
import android.database.Cursor
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
|
||||
import java.util.Date
|
||||
|
||||
/**
|
||||
@ -17,7 +14,7 @@ open class Event(var id: Long = 0,
|
||||
var endDate: Long = 0,
|
||||
var calendarID: Int = 0,
|
||||
var allDay: Boolean = false,
|
||||
var address: String = ""): RealmObject(){
|
||||
var address: String = "") : RealmObject(){
|
||||
|
||||
override fun toString(): String {
|
||||
return "Event:\nID: " + id + "\nTITLE: " + title + "\nSTART DATE: " + Date(startDate) + "\nEND DATE: " + Date(endDate) + "\nCAL DAY: " + calendarID + "\nADDRESS: " + address
|
@ -0,0 +1,13 @@
|
||||
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.ACTION_TIME_UPDATE"
|
||||
const val ACTION_CALENDAR_UPDATE = "com.tommasoberlose.anotherwidget.action.ACTION_CALENDAR_UPDATE"
|
||||
const val ACTION_WEATHER_UPDATE = "com.tommasoberlose.anotherwidget.action.ACTION_WEATHER_UPDATE"
|
||||
const val ACTION_OPEN_WEATHER_INTENT = "com.tommasoberlose.anotherwidget.action.ACTION_OPEN_WEATHER_INTENT"
|
||||
const val ACTION_GO_TO_NEXT_EVENT = "com.tommasoberlose.anotherwidget.action.GO_TO_NEXT_EVENT"
|
||||
const val ACTION_GO_TO_PREVIOUS_EVENT = "com.tommasoberlose.anotherwidget.action.GO_TO_PREVIOUS_EVENT"
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
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"
|
||||
const val RESULT_APP_PACKAGE = "RESULT_APP_PACKAGE"
|
||||
|
||||
const val PREF_SHOW_EVENTS = "PREF_SHOW_EVENTS"
|
||||
const val PREF_SHOW_WEATHER = "PREF_SHOW_WEATHER"
|
||||
const val PREF_WEATHER_ICON = "PREF_WEATHER_ICON"
|
||||
const val PREF_WEATHER_TEMP = "PREF_WEATHER_TEMP"
|
||||
const val PREF_WEATHER_TEMP_UNIT = "PREF_WEATHER_TEMP_UNIT"
|
||||
const val PREF_WEATHER_REAL_TEMP_UNIT = "PREF_WEATHER_REAL_TEMP_UNIT"
|
||||
const val PREF_CALENDAR_ALL_DAY = "PREF_CALENDAR_ALL_DAY"
|
||||
const val PREF_CALENDAR_FILTER = "PREF_CALENDAR_FILTER"
|
||||
|
||||
const val PREF_EVENT_ID = "PREF_EVENT_ID"
|
||||
const val PREF_NEXT_EVENT_ID = "PREF_NEXT_EVENT_ID"
|
||||
const val PREF_NEXT_EVENT_NAME = "PREF_NEXT_EVENT_NAME"
|
||||
const val PREF_NEXT_EVENT_START_DATE = "PREF_NEXT_EVENT_START_DATE"
|
||||
const val PREF_NEXT_EVENT_ALL_DAY = "PREF_NEXT_EVENT_ALL_DAY"
|
||||
const val PREF_NEXT_EVENT_LOCATION = "PREF_NEXT_EVENT_LOCATION"
|
||||
const val PREF_NEXT_EVENT_END_DATE = "PREF_NEXT_EVENT_END_DATE"
|
||||
const val PREF_NEXT_EVENT_CALENDAR_ID = "PREF_NEXT_EVENT_CALENDAR_ID"
|
||||
const val PREF_CUSTOM_LOCATION_LAT = "PREF_CUSTOM_LOCATION_LAT"
|
||||
const val PREF_CUSTOM_LOCATION_LON = "PREF_CUSTOM_LOCATION_LON"
|
||||
const val PREF_CUSTOM_LOCATION_ADD = "PREF_CUSTOM_LOCATION_ADD"
|
||||
const val PREF_HOUR_FORMAT = "PREF_HOUR_FORMAT"
|
||||
const val PREF_ITA_FORMAT_DATE = "PREF_ITA_FORMAT_DATE"
|
||||
const val PREF_WEATHER_REFRESH_PERIOD = "PREF_WEATHER_REFRESH_PERIOD"
|
||||
const val PREF_SHOW_UNTIL = "PREF_SHOW_UNTIL"
|
||||
const val PREF_CALENDAR_APP_NAME = "PREF_CALENDAR_APP_NAME"
|
||||
const val PREF_CALENDAR_APP_PACKAGE = "PREF_CALENDAR_APP_PACKAGE"
|
||||
const val PREF_WEATHER_APP_NAME = "PREF_WEATHER_APP_NAME"
|
||||
const val PREF_WEATHER_APP_PACKAGE = "PREF_WEATHER_APP_PACKAGE"
|
||||
const val PREF_WEATHER_PROVIDER_API_KEY = "PREF_WEATHER_PROVIDER_API_KEY"
|
||||
const val PREF_EVENT_APP_NAME = "PREF_EVENT_APP_NAME"
|
||||
const val PREF_EVENT_APP_PACKAGE = "PREF_EVENT_APP_PACKAGE"
|
||||
const val PREF_SHOW_EVENT_LOCATION = "PREF_SHOW_EVENT_LOCATION"
|
||||
const val PREF_TEXT_COLOR = "PREF_TEXT_COLOR"
|
||||
const val PREF_TEXT_MAIN_SIZE = "PREF_TEXT_MAIN_SIZE"
|
||||
const val PREF_TEXT_SECOND_SIZE = "PREF_TEXT_SECOND_SIZE"
|
||||
const val PREF_TEXT_CLOCK_SIZE = "PREF_TEXT_CLOCK_SIZE"
|
||||
const val PREF_WEATHER_PROVIDER = "PREF_WEATHER_PROVIDER"
|
||||
const val PREF_SHOW_CLOCK = "PREF_SHOW_CLOCK"
|
||||
const val PREF_CLOCK_APP_NAME = "PREF_CLOCK_APP_NAME"
|
||||
const val PREF_CLOCK_APP_PACKAGE = "PREF_CLOCK_APP_PACKAGE"
|
||||
const val PREF_TEXT_SHADOW = "PREF_TEXT_SHADOW"
|
||||
const val PREF_SHOW_DIFF_TIME = "PREF_SHOW_DIFF_TIME"
|
||||
const val PREF_SHOW_DECLINED_EVENTS = "PREF_SHOW_DECLINED_EVENTS"
|
||||
const val PREF_OPEN_WEATHER_API_KEY = "PREF_OPEN_WEATHER_API_KEY"
|
||||
const val PREF_DARK_SKY_API_KEY = "PREF_DARK_SKY_API_KEY"
|
||||
const val PREF_WU_API_KEY = "PREF_WU_API_KEY"
|
||||
const val PREF_SECOND_ROW_INFORMATION = "PREF_SECOND_ROW_INFORMATION"
|
||||
const val PREF_CUSTOM_FONT = "PREF_CUSTOM_FONT"
|
||||
const val PREF_CUSTOM_FONT_FILE = "PREF_CUSTOM_FONT_FILE"
|
||||
const val PREF_SHOW_NEXT_EVENT = "PREF_SHOW_NEXT_EVENT"
|
||||
const val PREF_SHOW_WIDGET_PREVIEW = "PREF_SHOW_WIDGET_PREVIEW"
|
||||
const val PREF_SHOW_GPS_NOTIFICATION = "PREF_SHOW_GPS_NOTIFICATION"
|
||||
|
||||
const val CUSTOM_FONT_PRODUCT_SANS = 1
|
||||
|
||||
const val itDateFormat = "EEEE, d MMM"
|
||||
const val engDateFormat = "EEEE, MMM d"
|
||||
const val goodHourFormat = "HH:mm"
|
||||
const val badHourFormat = "hh:mm a"
|
||||
}
|
65
app/src/main/java/com/tommasoberlose/anotherwidget/global/Preferences.kt
Executable file
@ -0,0 +1,65 @@
|
||||
package com.tommasoberlose.anotherwidget.global
|
||||
|
||||
import android.os.Build
|
||||
import androidx.appcompat.app.AppCompatDelegate.*
|
||||
import com.chibatching.kotpref.KotprefModel
|
||||
|
||||
object Preferences : KotprefModel() {
|
||||
override val commitAllPropertiesByDefault: Boolean = true
|
||||
|
||||
var darkThemePreference by intPref(default = if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) MODE_NIGHT_FOLLOW_SYSTEM else MODE_NIGHT_AUTO_BATTERY)
|
||||
|
||||
var showEvents by booleanPref(key = "PREF_SHOW_EVENTS", default = false)
|
||||
var showWeather by booleanPref(key = "PREF_SHOW_WEATHER")
|
||||
var weatherIcon by stringPref(key = "PREF_WEATHER_ICON")
|
||||
var weatherTemp by floatPref(key = "PREF_WEATHER_TEMP")
|
||||
var weatherTempUnit by stringPref(key = "PREF_WEATHER_TEMP_UNIT", default = "F")
|
||||
var weatherRealTempUnit by stringPref(key = "PREF_WEATHER_REAL_TEMP_UNIT", default = "F")
|
||||
var calendarAllDay by booleanPref(key = "PREF_CALENDAR_ALL_DAY", default = false)
|
||||
var calendarFilter by stringPref(key = "PREF_CALENDAR_FILTER", default = "")
|
||||
|
||||
var eventId by intPref(key = "PREF_EVENT_ID", default = -1)
|
||||
var nextEventId by longPref(key = "PREF_NEXT_EVENT_ID", default = -1)
|
||||
var nextEventName by stringPref(key = "PREF_NEXT_EVENT_NAME")
|
||||
var nextEventStartDate by longPref(key = "PREF_NEXT_EVENT_START_DATE")
|
||||
var nextEventAllDay by booleanPref(key = "PREF_NEXT_EVENT_ALL_DAY")
|
||||
var nextEventLocation by stringPref(key = "PREF_NEXT_EVENT_LOCATION")
|
||||
var nextEventEndDate by longPref(key = "PREF_NEXT_EVENT_END_DATE")
|
||||
var nextEventCalendarId by intPref(key = "PREF_NEXT_EVENT_CALENDAR_ID")
|
||||
var customLocationLat by stringPref(key = "PREF_CUSTOM_LOCATION_LAT", default = "")
|
||||
var customLocationLon by stringPref(key = "PREF_CUSTOM_LOCATION_LON", default = "")
|
||||
var customLocationAdd by stringPref(key = "PREF_CUSTOM_LOCATION_ADD", default = "")
|
||||
var hourFormat by stringPref(key = "PREF_HOUR_FORMAT", default = "12")
|
||||
var dateFormat by booleanPref(key = "PREF_ITA_FORMAT_DATE", default = false)
|
||||
var weatherRefreshPeriod by intPref(key = "PREF_WEATHER_REFRESH_PERIOD", default = 1)
|
||||
var showUntil by intPref(key = "PREF_SHOW_UNTIL", default = 1)
|
||||
var calendarAppName by stringPref(key = "PREF_CALENDAR_APP_NAME", default = "")
|
||||
var calendarAppPackage by stringPref(key = "PREF_CALENDAR_APP_PACKAGE", default = "")
|
||||
var weatherAppName by stringPref(key = "PREF_WEATHER_APP_NAME", default = "")
|
||||
var weatherAppPackage by stringPref(key = "PREF_WEATHER_APP_PACKAGE", default = "")
|
||||
var weatherProviderApi by stringPref(key = "PREF_WEATHER_PROVIDER_API_KEY", default = "")
|
||||
var eventAppName by stringPref(key = "PREF_EVENT_APP_NAME", default = "")
|
||||
var eventAppPackage by stringPref(key = "PREF_EVENT_APP_PACKAGE", default = "")
|
||||
var showEventLocation by stringPref(key = "PREF_SHOW_EVENT_LOCATION", default = "")
|
||||
var textGlobalColor by stringPref(key = "PREF_TEXT_COLOR", default = "#FFFFFF")
|
||||
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 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 = "")
|
||||
var showNextAlarm by booleanPref(default = true)
|
||||
var textShadow by intPref(key = "PREF_TEXT_SHADOW", default = 1)
|
||||
var showDiffTime by booleanPref(key = "PREF_SHOW_DIFF_TIME")
|
||||
var showDeclinedEvents by booleanPref(key = "PREF_SHOW_DECLINED_EVENTS", default = true)
|
||||
var openWeatherApiKey by stringPref(key = "PREF_OPEN_WEATHER_API_KEY", default = "")
|
||||
var darkSkyApiKey by stringPref(key = "PREF_DARK_SKY_API_KEY", default = "")
|
||||
var wuApiKey by stringPref(key = "PREF_WU_API_KEY", default = "")
|
||||
var secondRowInformation by intPref(key = "PREF_SECOND_ROW_INFORMATION", default = 1)
|
||||
var customFont by intPref(key = "PREF_CUSTOM_FONT", default = Constants.CUSTOM_FONT_PRODUCT_SANS)
|
||||
var customFontFile by stringPref(key = "PREF_CUSTOM_FONT_FILE")
|
||||
var showNextEvent by booleanPref(key = "PREF_SHOW_NEXT_EVENT", default = true)
|
||||
var showGpsInformation by booleanPref(key = "PREF_SHOW_GPS_NOTIFICATION", default = true)
|
||||
|
||||
var showWallpaper by booleanPref(default = false)
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.tommasoberlose.anotherwidget.global
|
||||
|
||||
enum class RequestCode(val code: Int) {
|
||||
CALENDAR_REQUEST_CODE(1),
|
||||
LOCATION_REQUEST_CODE(2),
|
||||
CALENDAR_APP_REQUEST_CODE(3),
|
||||
WEATHER_APP_REQUEST_CODE(4),
|
||||
EVENT_APP_REQUEST_CODE(6),
|
||||
WEATHER_PROVIDER_REQUEST_CODE(5),
|
||||
CLOCK_APP_REQUEST_CODE(7),
|
||||
CUSTOM_FONT_CHOOSER_REQUEST_CODE(8)
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.`object`
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Created by tommaso on 05/10/17.
|
||||
*/
|
||||
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
object Constants {
|
||||
val CALENDAR_REQUEST_CODE = 1
|
||||
val LOCATION_REQUEST_CODE = 2
|
||||
val CALENDAR_APP_REQUEST_CODE = 3
|
||||
val WEATHER_APP_REQUEST_CODE = 4
|
||||
val EVENT_APP_REQUEST_CODE = 6
|
||||
val WEATHER_PROVIDER_REQUEST_CODE = 5
|
||||
val CLOCK_APP_REQUEST_CODE = 7
|
||||
val CUSTOM_FONT_CHOOSER_REQUEST_CODE = 8
|
||||
|
||||
|
||||
val RESULT_CODE_CUSTOM_LOCATION = 45
|
||||
val RESULT_APP_NAME = "RESULT_APP_NAME"
|
||||
val RESULT_APP_PACKAGE = "RESULT_APP_PACKAGE"
|
||||
|
||||
val PREF_SHOW_EVENTS = "PREF_SHOW_EVENTS"
|
||||
val PREF_SHOW_WEATHER = "PREF_SHOW_WEATHER"
|
||||
val PREF_WEATHER_ICON = "PREF_WEATHER_ICON"
|
||||
val PREF_WEATHER_TEMP = "PREF_WEATHER_TEMP"
|
||||
val PREF_WEATHER_TEMP_UNIT = "PREF_WEATHER_TEMP_UNIT"
|
||||
val PREF_WEATHER_REAL_TEMP_UNIT = "PREF_WEATHER_REAL_TEMP_UNIT"
|
||||
val PREF_CALENDAR_ALL_DAY = "PREF_CALENDAR_ALL_DAY"
|
||||
val PREF_CALENDAR_FILTER = "PREF_CALENDAR_FILTER"
|
||||
|
||||
val PREF_EVENT_ID = "PREF_EVENT_ID"
|
||||
val PREF_NEXT_EVENT_ID = "PREF_NEXT_EVENT_ID"
|
||||
val PREF_NEXT_EVENT_NAME = "PREF_NEXT_EVENT_NAME"
|
||||
val PREF_NEXT_EVENT_START_DATE = "PREF_NEXT_EVENT_START_DATE"
|
||||
val PREF_NEXT_EVENT_ALL_DAY = "PREF_NEXT_EVENT_ALL_DAY"
|
||||
val PREF_NEXT_EVENT_LOCATION = "PREF_NEXT_EVENT_LOCATION"
|
||||
val PREF_NEXT_EVENT_END_DATE = "PREF_NEXT_EVENT_END_DATE"
|
||||
val PREF_NEXT_EVENT_CALENDAR_ID = "PREF_NEXT_EVENT_CALENDAR_ID"
|
||||
val PREF_CUSTOM_LOCATION_LAT = "PREF_CUSTOM_LOCATION_LAT"
|
||||
val PREF_CUSTOM_LOCATION_LON = "PREF_CUSTOM_LOCATION_LON"
|
||||
val PREF_CUSTOM_LOCATION_ADD = "PREF_CUSTOM_LOCATION_ADD"
|
||||
val PREF_HOUR_FORMAT = "PREF_HOUR_FORMAT"
|
||||
val PREF_ITA_FORMAT_DATE = "PREF_ITA_FORMAT_DATE"
|
||||
val PREF_WEATHER_REFRESH_PERIOD = "PREF_WEATHER_REFRESH_PERIOD"
|
||||
val PREF_SHOW_UNTIL = "PREF_SHOW_UNTIL"
|
||||
val PREF_CALENDAR_APP_NAME = "PREF_CALENDAR_APP_NAME"
|
||||
val PREF_CALENDAR_APP_PACKAGE = "PREF_CALENDAR_APP_PACKAGE"
|
||||
val PREF_WEATHER_APP_NAME = "PREF_WEATHER_APP_NAME"
|
||||
val PREF_WEATHER_APP_PACKAGE = "PREF_WEATHER_APP_PACKAGE"
|
||||
val PREF_WEATHER_PROVIDER_API_KEY = "PREF_WEATHER_PROVIDER_API_KEY"
|
||||
val PREF_EVENT_APP_NAME = "PREF_EVENT_APP_NAME"
|
||||
val PREF_EVENT_APP_PACKAGE = "PREF_EVENT_APP_PACKAGE"
|
||||
val PREF_SHOW_EVENT_LOCATION = "PREF_SHOW_EVENT_LOCATION"
|
||||
val PREF_TEXT_COLOR = "PREF_TEXT_COLOR"
|
||||
val PREF_TEXT_MAIN_SIZE = "PREF_TEXT_MAIN_SIZE"
|
||||
val PREF_TEXT_SECOND_SIZE = "PREF_TEXT_SECOND_SIZE"
|
||||
val PREF_TEXT_CLOCK_SIZE = "PREF_TEXT_CLOCK_SIZE"
|
||||
val PREF_WEATHER_PROVIDER = "PREF_WEATHER_PROVIDER"
|
||||
val PREF_SHOW_CLOCK = "PREF_SHOW_CLOCK"
|
||||
val PREF_CLOCK_APP_NAME = "PREF_CLOCK_APP_NAME"
|
||||
val PREF_CLOCK_APP_PACKAGE = "PREF_CLOCK_APP_PACKAGE"
|
||||
val PREF_TEXT_SHADOW = "PREF_TEXT_SHADOW"
|
||||
val PREF_SHOW_DIFF_TIME = "PREF_SHOW_DIFF_TIME"
|
||||
val PREF_SHOW_DECLINED_EVENTS = "PREF_SHOW_DECLINED_EVENTS"
|
||||
val PREF_OPEN_WEATHER_API_KEY = "PREF_OPEN_WEATHER_API_KEY"
|
||||
val PREF_DARK_SKY_API_KEY = "PREF_DARK_SKY_API_KEY"
|
||||
val PREF_WU_API_KEY = "PREF_WU_API_KEY"
|
||||
val PREF_SECOND_ROW_INFORMATION = "PREF_SECOND_ROW_INFORMATION"
|
||||
val PREF_CUSTOM_FONT = "PREF_CUSTOM_FONT"
|
||||
val PREF_CUSTOM_FONT_FILE = "PREF_CUSTOM_FONT_FILE"
|
||||
val PREF_SHOW_NEXT_EVENT = "PREF_SHOW_NEXT_EVENT"
|
||||
val PREF_SHOW_WIDGET_PREVIEW = "PREF_SHOW_WIDGET_PREVIEW"
|
||||
val PREF_SHOW_GPS_NOTIFICATION = "PREF_SHOW_GPS_NOTIFICATION"
|
||||
|
||||
val CUSTOM_FONT_PRODUCT_SANS = 1
|
||||
|
||||
val ACTION_EXTRA_OPEN_WEATHER_PROVIDER = "ACTION_EXTRA_OPEN_WEATHER_PROVIDER"
|
||||
val ACTION_EXTRA_DISABLE_GPS_NOTIFICATION = "ACTION_EXTRA_DISABLE_GPS_NOTIFICATION"
|
||||
|
||||
val itDateFormat = SimpleDateFormat("EEEE, d MMM")
|
||||
val engDateFormat = SimpleDateFormat("EEEE, MMM d")
|
||||
val goodHourFormat = SimpleDateFormat("HH:mm")
|
||||
val badHourFormat = SimpleDateFormat("hh:mm a")
|
||||
|
||||
val ACTION_TIME_UPDATE = "com.tommasoberlose.anotherwidget.action.ACTION_TIME_UPDATE"
|
||||
val ACTION_CALENDAR_UPDATE = "com.tommasoberlose.anotherwidget.action.ACTION_CALENDAR_UPDATE"
|
||||
val ACTION_WEATHER_UPDATE = "com.tommasoberlose.anotherwidget.action.ACTION_WEATHER_UPDATE"
|
||||
val ACTION_SOMETHING_HAPPENED = "com.tommasoberlose.anotherwidget.action.ACTION_SOMETHING_HAPPENED"
|
||||
val ACTION_OPEN_WEATHER_INTENT = "com.tommasoberlose.anotherwidget.action.ACTION_OPEN_WEATHER_INTENT"
|
||||
val ACTION_GO_TO_NEXT_EVENT = "com.tommasoberlose.anotherwidget.action.GO_TO_NEXT_EVENT"
|
||||
|
||||
val WEATHER_PROVIDER_GOOGLE_AWARENESS = 1
|
||||
val WEATHER_PROVIDER_OPEN_WEATHER = 2
|
||||
val WEATHER_PROVIDER_DARK_SKY = 3
|
||||
val WEATHER_PROVIDER_WU = 4
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.receiver
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import com.tommasoberlose.anotherwidget.`object`.Constants
|
||||
import com.tommasoberlose.anotherwidget.util.CalendarUtil
|
||||
import com.tommasoberlose.anotherwidget.util.Util
|
||||
|
||||
class NewCalendarEventReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (intent.action.equals(Intent.ACTION_PROVIDER_CHANGED)) {
|
||||
CalendarUtil.updateEventList(context)
|
||||
} else if (intent.action == Constants.ACTION_GO_TO_NEXT_EVENT) {
|
||||
CalendarUtil.goToNextEvent(context)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.receiver
|
||||
|
||||
import android.Manifest
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import android.icu.text.LocaleDisplayNames
|
||||
import android.os.Build
|
||||
import android.preference.PreferenceManager
|
||||
import android.util.Log
|
||||
import com.tommasoberlose.anotherwidget.`object`.Constants
|
||||
import com.tommasoberlose.anotherwidget.`object`.Event
|
||||
import com.tommasoberlose.anotherwidget.util.CalendarUtil
|
||||
import com.tommasoberlose.anotherwidget.util.CrocodileService
|
||||
import com.tommasoberlose.anotherwidget.util.Util
|
||||
import java.sql.Time
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
class UpdatesReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (intent.action.equals(Intent.ACTION_BOOT_COMPLETED) || intent.action.equals(Intent.ACTION_MY_PACKAGE_REPLACED) || intent.action.equals("android.intent.action.PACKAGE_REPLACED") || intent.action.equals("android.intent.action.PACKAGE_ADDED")) {
|
||||
setUpdates(context)
|
||||
} else if (intent.action.equals(Constants.ACTION_TIME_UPDATE) || intent.action.equals("com.sec.android.widgetapp.APPWIDGET_RESIZE") || intent.action == "android.intent.action.USER_PRESENT") {
|
||||
val e: Event = CalendarUtil.getNextEvent(context)
|
||||
if (e.id == 0.toLong() || e.endDate <= Calendar.getInstance().timeInMillis) {
|
||||
CalendarUtil.updateEventList(context)
|
||||
} else {
|
||||
Util.updateWidget(context)
|
||||
}
|
||||
} else if (intent.action.equals(Constants.ACTION_CALENDAR_UPDATE)) {
|
||||
CalendarUtil.updateEventList(context)
|
||||
}
|
||||
}
|
||||
|
||||
fun setUpdates(context: Context) {
|
||||
CalendarUtil.updateEventList(context)
|
||||
removeUpdates(context)
|
||||
/*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.startForegroundService(Intent(context, CrocodileService::class.java))
|
||||
} else {
|
||||
context.startService(Intent(context, CrocodileService::class.java))
|
||||
}*/
|
||||
|
||||
val now = Calendar.getInstance()
|
||||
now.set(Calendar.MILLISECOND, 0)
|
||||
now.set(Calendar.SECOND, 0)
|
||||
|
||||
val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
val i = Intent(context, UpdatesReceiver::class.java)
|
||||
i.action = Constants.ACTION_TIME_UPDATE
|
||||
val pi = PendingIntent.getBroadcast(context, 0, i, 0)
|
||||
am.setRepeating(AlarmManager.RTC_WAKEUP, now.timeInMillis, (1000 * 60).toLong(), pi)
|
||||
}
|
||||
|
||||
fun removeUpdates(context: Context) {
|
||||
val intent = Intent(context, UpdatesReceiver::class.java)
|
||||
val sender = PendingIntent.getBroadcast(context, 0, intent, 0)
|
||||
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
alarmManager.cancel(sender)
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.receiver
|
||||
|
||||
import android.Manifest
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.preference.PreferenceManager
|
||||
import android.util.Log
|
||||
import com.tommasoberlose.anotherwidget.`object`.Constants
|
||||
import com.tommasoberlose.anotherwidget.util.CalendarUtil
|
||||
import com.tommasoberlose.anotherwidget.util.Util
|
||||
import com.tommasoberlose.anotherwidget.util.WeatherUtil
|
||||
import java.util.*
|
||||
import android.widget.Toast
|
||||
|
||||
|
||||
|
||||
class WeatherReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (intent.action.equals(Intent.ACTION_BOOT_COMPLETED) || intent.action.equals(Intent.ACTION_MY_PACKAGE_REPLACED) || intent.action.equals("android.intent.action.PACKAGE_REPLACED") || intent.action.equals("android.intent.action.PACKAGE_ADDED")) {
|
||||
setUpdates(context)
|
||||
} else if (intent.action.equals(Constants.ACTION_WEATHER_UPDATE) || intent.action.equals("android.location.PROVIDERS_CHANGED")) {
|
||||
WeatherUtil.updateWeather(context)
|
||||
} else if (intent.action == "android.location.PROVIDERS_CHANGED") {
|
||||
Util.showWeatherErrorNotification(context)
|
||||
}
|
||||
}
|
||||
|
||||
fun setUpdates(context: Context) {
|
||||
val SP: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
removeUpdates(context)
|
||||
WeatherUtil.updateWeather(context)
|
||||
|
||||
val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
val i = Intent(context, WeatherReceiver::class.java)
|
||||
i.action = Constants.ACTION_WEATHER_UPDATE
|
||||
val pi = PendingIntent.getBroadcast(context, 1, i, 0)
|
||||
val refresh: Long = when (SP.getInt(Constants.PREF_WEATHER_REFRESH_PERIOD, 1)) {
|
||||
0 -> 30
|
||||
1 -> 60
|
||||
2 -> 60 * 3
|
||||
3 -> 60 * 6
|
||||
4 -> 60 * 12
|
||||
5 -> 60 * 24
|
||||
else -> 60
|
||||
}
|
||||
val now = Calendar.getInstance()
|
||||
now.set(Calendar.MILLISECOND, 0)
|
||||
now.set(Calendar.SECOND, 0)
|
||||
am.setRepeating(AlarmManager.RTC_WAKEUP, now.timeInMillis, 1000 * 60 * refresh, pi)
|
||||
}
|
||||
|
||||
fun setOneTimeUpdate(context: Context) {
|
||||
val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
val i = Intent(context, WeatherReceiver::class.java)
|
||||
i.action = Constants.ACTION_WEATHER_UPDATE
|
||||
val pi = PendingIntent.getBroadcast(context, 1, i, 0)
|
||||
|
||||
val now = Calendar.getInstance()
|
||||
now.set(Calendar.MILLISECOND, 0)
|
||||
now.set(Calendar.SECOND, 0)
|
||||
am.setExact(AlarmManager.RTC_WAKEUP, now.timeInMillis + 1000 * 60 * 10, pi)
|
||||
am.setExact(AlarmManager.RTC_WAKEUP, now.timeInMillis + 1000 * 60 * 15, pi)
|
||||
am.setExact(AlarmManager.RTC_WAKEUP, now.timeInMillis + 1000 * 60 * 20, pi)
|
||||
}
|
||||
|
||||
fun removeUpdates(context: Context) {
|
||||
val intent = Intent(context, WeatherReceiver::class.java)
|
||||
val sender = PendingIntent.getBroadcast(context, 1, intent, 0)
|
||||
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
alarmManager.cancel(sender)
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.tommasoberlose.anotherwidget.receivers
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import com.tommasoberlose.anotherwidget.global.Actions
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.utils.CalendarUtil
|
||||
|
||||
class NewCalendarEventReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
when {
|
||||
intent.action.equals(Intent.ACTION_PROVIDER_CHANGED) -> {
|
||||
CalendarUtil.updateEventList(context)
|
||||
}
|
||||
intent.action == Actions.ACTION_GO_TO_NEXT_EVENT -> {
|
||||
CalendarUtil.goToNextEvent(context)
|
||||
}
|
||||
intent.action == Actions.ACTION_GO_TO_PREVIOUS_EVENT -> {
|
||||
CalendarUtil.goToPreviousEvent(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package com.tommasoberlose.anotherwidget.receivers
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import com.tommasoberlose.anotherwidget.components.events.Event
|
||||
import com.tommasoberlose.anotherwidget.global.Actions
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.utils.CalendarUtil
|
||||
import com.tommasoberlose.anotherwidget.utils.Util
|
||||
import org.joda.time.Period
|
||||
import java.util.*
|
||||
|
||||
|
||||
class UpdatesReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
when (intent.action) {
|
||||
Intent.ACTION_BOOT_COMPLETED,
|
||||
Intent.ACTION_MY_PACKAGE_REPLACED,
|
||||
Actions.ACTION_CALENDAR_UPDATE -> CalendarUtil.updateEventList(context)
|
||||
|
||||
"com.sec.android.widgetapp.APPWIDGET_RESIZE",
|
||||
Intent.ACTION_DATE_CHANGED,
|
||||
AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED -> Util.updateWidget(context)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun setUpdates(context: Context) {
|
||||
removeUpdates(context)
|
||||
|
||||
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||
CalendarUtil.getEvents().forEach { event ->
|
||||
val hoursDiff = Period(Calendar.getInstance().timeInMillis, event.startDate).hours
|
||||
|
||||
// Update the widget every hour till the event
|
||||
(0 .. hoursDiff).forEach {
|
||||
setExact(
|
||||
AlarmManager.RTC_WAKEUP,
|
||||
(event.startDate + 1000) - it * 1000 * 60* 60,
|
||||
PendingIntent.getBroadcast(context, 0, Intent(context, UpdatesReceiver::class.java).apply { action = Actions.ACTION_TIME_UPDATE }, 0)
|
||||
)
|
||||
}
|
||||
|
||||
// Update the widget one second after the event is finished
|
||||
setExact(
|
||||
AlarmManager.RTC_WAKEUP,
|
||||
event.endDate + 1000,
|
||||
PendingIntent.getBroadcast(context, 0, Intent(context, UpdatesReceiver::class.java).apply { action = Actions.ACTION_TIME_UPDATE }, 0)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun removeUpdates(context: Context) {
|
||||
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||
cancel(PendingIntent.getBroadcast(context, 0, Intent(context, UpdatesReceiver::class.java), 0))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package com.tommasoberlose.anotherwidget.receivers
|
||||
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.tommasoberlose.anotherwidget.global.Actions
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.utils.Util
|
||||
import com.tommasoberlose.anotherwidget.utils.WeatherUtil
|
||||
import java.util.*
|
||||
|
||||
|
||||
class WeatherReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (intent.action == Intent.ACTION_BOOT_COMPLETED || intent.action == Intent.ACTION_MY_PACKAGE_REPLACED) {
|
||||
setUpdates(context)
|
||||
} else if (intent.action == Actions.ACTION_WEATHER_UPDATE) {
|
||||
WeatherUtil.updateWeather(context)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun setUpdates(context: Context) {
|
||||
removeUpdates(context)
|
||||
|
||||
if (Preferences.showWeather && Preferences.weatherProviderApi != "") {
|
||||
WeatherUtil.updateWeather(context)
|
||||
|
||||
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||
val pi = PendingIntent.getBroadcast(
|
||||
context,
|
||||
1,
|
||||
Intent(context, WeatherReceiver::class.java).apply {
|
||||
action = Actions.ACTION_WEATHER_UPDATE
|
||||
},
|
||||
0
|
||||
)
|
||||
|
||||
val refresh: Long = when (Preferences.weatherRefreshPeriod) {
|
||||
0 -> 30
|
||||
1 -> 60
|
||||
2 -> 60 * 3
|
||||
3 -> 60 * 6
|
||||
4 -> 60 * 12
|
||||
5 -> 60 * 24
|
||||
else -> 60
|
||||
}
|
||||
val now = Calendar.getInstance().apply {
|
||||
set(Calendar.MILLISECOND, 0)
|
||||
set(Calendar.SECOND, 0)
|
||||
}
|
||||
|
||||
setRepeating(AlarmManager.RTC_WAKEUP, now.timeInMillis, 1000 * 60 * refresh, pi)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setOneTimeUpdate(context: Context) {
|
||||
// Update the weather in a few minuter when the api key has been changed
|
||||
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||
val pi = PendingIntent.getBroadcast(context, 1, Intent(context, WeatherReceiver::class.java).apply { action = Actions.ACTION_WEATHER_UPDATE }, 0)
|
||||
val now = Calendar.getInstance().apply {
|
||||
set(Calendar.MILLISECOND, 0)
|
||||
set(Calendar.SECOND, 0)
|
||||
}
|
||||
|
||||
listOf(10, 15, 20).forEach {
|
||||
setExact(AlarmManager.RTC_WAKEUP, now.timeInMillis + 1000 * 60 * it, pi)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun removeUpdates(context: Context) {
|
||||
val intent = Intent(context, WeatherReceiver::class.java)
|
||||
val sender = PendingIntent.getBroadcast(context, 1, intent, 0)
|
||||
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
alarmManager.cancel(sender)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,21 +1,19 @@
|
||||
package com.tommasoberlose.anotherwidget.receiver
|
||||
package com.tommasoberlose.anotherwidget.receivers
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import com.tommasoberlose.anotherwidget.`object`.Constants
|
||||
import com.tommasoberlose.anotherwidget.util.Util
|
||||
import android.support.v4.content.ContextCompat.startActivity
|
||||
import com.tommasoberlose.anotherwidget.global.Actions
|
||||
import com.tommasoberlose.anotherwidget.utils.Util
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
|
||||
|
||||
|
||||
class OpenWeatherIntentReceiver : BroadcastReceiver() {
|
||||
class WidgetClickListenerReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (intent.action == Constants.ACTION_OPEN_WEATHER_INTENT) {
|
||||
context.sendBroadcast(Intent(Constants.ACTION_WEATHER_UPDATE))
|
||||
if (intent.action == Actions.ACTION_OPEN_WEATHER_INTENT) {
|
||||
context.sendBroadcast(Intent(Actions.ACTION_WEATHER_UPDATE))
|
||||
try {
|
||||
context.startActivity(Util.getWeatherIntent(context))
|
||||
} catch (e: Exception) {
|
@ -1,27 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.ui
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import android.content.SharedPreferences
|
||||
import android.preference.PreferenceManager
|
||||
import android.util.Log
|
||||
import com.tommasoberlose.anotherwidget.`object`.Constants
|
||||
import com.tommasoberlose.anotherwidget.util.MyMigration
|
||||
import com.tommasoberlose.anotherwidget.util.Util
|
||||
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
|
||||
class AWApplication : Application() {
|
||||
@SuppressLint("ApplySharedPref")
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
Realm.init(this)
|
||||
val config = RealmConfiguration.Builder()
|
||||
.schemaVersion(2)
|
||||
.migration(MyMigration())
|
||||
.deleteRealmIfMigrationNeeded()
|
||||
.build()
|
||||
Realm.setDefaultConfiguration(config)
|
||||
}
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activities
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import android.content.Intent
|
||||
import android.content.pm.ApplicationInfo
|
||||
import com.tommasoberlose.anotherwidget.components.events.ApplicationListEvent
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.widget.ImageView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.databinding.Observable
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.transition.MaterialFadeThrough
|
||||
import com.tommasoberlose.anotherwidget.components.events.AppInfoSavedEvent
|
||||
import com.tommasoberlose.anotherwidget.databinding.ActivityChooseApplicationBinding
|
||||
import com.tommasoberlose.anotherwidget.databinding.FragmentClockSettingsBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.ChooseApplicationViewModel
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||
import com.tommasoberlose.anotherwidget.utils.toast
|
||||
import kotlinx.android.synthetic.main.activity_choose_application.*
|
||||
import kotlinx.android.synthetic.main.activity_choose_application.list_view
|
||||
import kotlinx.coroutines.*
|
||||
import net.idik.lib.slimadapter.SlimAdapter
|
||||
|
||||
|
||||
class ChooseApplicationActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var adapter: SlimAdapter
|
||||
private lateinit var viewModel: ChooseApplicationViewModel
|
||||
private val pm by lazy { packageManager }
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
viewModel = ViewModelProvider(this).get(ChooseApplicationViewModel::class.java)
|
||||
val binding = DataBindingUtil.setContentView<ActivityChooseApplicationBinding>(this, R.layout.activity_choose_application)
|
||||
|
||||
list_view.setHasFixedSize(true)
|
||||
val mLayoutManager = LinearLayoutManager(this)
|
||||
list_view.layoutManager = mLayoutManager
|
||||
|
||||
adapter = SlimAdapter.create()
|
||||
adapter
|
||||
.register<String>(R.layout.application_info_layout) { _, injector ->
|
||||
injector
|
||||
.text(R.id.text, getString(R.string.default_name))
|
||||
.image(R.id.icon, R.drawable.round_add_to_home_screen)
|
||||
.with<ImageView>(R.id.icon) {
|
||||
it.scaleX = 0.8f
|
||||
it.scaleY = 0.8f
|
||||
it.setColorFilter(ContextCompat.getColor(this, R.color.colorPrimaryText), android.graphics.PorterDuff.Mode.MULTIPLY)
|
||||
}
|
||||
.clicked(R.id.item) {
|
||||
val resultIntent = Intent()
|
||||
resultIntent.putExtra(Constants.RESULT_APP_NAME, "")
|
||||
resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, "")
|
||||
setResult(Activity.RESULT_OK, resultIntent)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
.register<ApplicationInfo>(R.layout.application_info_layout) { item, injector ->
|
||||
injector
|
||||
.text(R.id.text, pm.getApplicationLabel(item).toString())
|
||||
|
||||
try {
|
||||
injector.image(R.id.icon, item.loadIcon(pm))
|
||||
} catch (ignore: Exception) {
|
||||
}
|
||||
|
||||
injector.clicked(R.id.item) {
|
||||
saveApp(item)
|
||||
}
|
||||
}
|
||||
.attachTo(list_view)
|
||||
|
||||
setupListener()
|
||||
subscribeUi(binding, viewModel)
|
||||
|
||||
search.requestFocus()
|
||||
}
|
||||
|
||||
private var filterJob: Job? = null
|
||||
|
||||
private fun subscribeUi(binding: ActivityChooseApplicationBinding, viewModel: ChooseApplicationViewModel) {
|
||||
binding.viewModel = viewModel
|
||||
viewModel.appList.observe(this, Observer {
|
||||
adapter.updateData(listOf("Default") + it)
|
||||
loader.visibility = View.INVISIBLE
|
||||
})
|
||||
|
||||
viewModel.searchInput.observe(this, Observer { search ->
|
||||
loader.visibility = View.VISIBLE
|
||||
filterJob?.cancel()
|
||||
filterJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||
delay(200)
|
||||
val list = if (search == null || search == "") {
|
||||
viewModel.appList.value!!
|
||||
} else {
|
||||
viewModel.appList.value!!.filter {
|
||||
pm.getApplicationLabel(
|
||||
it
|
||||
).toString().contains(search, true)
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
adapter.updateData(listOf("Default") + list)
|
||||
loader.visibility = View.INVISIBLE
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
action_back.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveApp(app: ApplicationInfo) {
|
||||
val resultIntent = Intent()
|
||||
resultIntent.putExtra(Constants.RESULT_APP_NAME, pm.getApplicationLabel(app).toString())
|
||||
resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, app.packageName)
|
||||
setResult(Activity.RESULT_OK, resultIntent)
|
||||
finish()
|
||||
}
|
||||
}
|
@ -0,0 +1,161 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activities
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.location.Address
|
||||
import android.location.Geocoder
|
||||
import android.os.Bundle
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.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.events.CustomLocationEvent
|
||||
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.coroutines.*
|
||||
import net.idik.lib.slimadapter.SlimAdapter
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
|
||||
class CustomLocationActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var adapter: SlimAdapter
|
||||
private lateinit var viewModel: CustomLocationViewModel
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
viewModel = ViewModelProvider(this).get(CustomLocationViewModel::class.java)
|
||||
val binding = DataBindingUtil.setContentView<ActivityCustomLocationBinding>(this, R.layout.activity_custom_location)
|
||||
|
||||
|
||||
list_view.setHasFixedSize(true)
|
||||
val mLayoutManager = LinearLayoutManager(this)
|
||||
list_view.layoutManager = mLayoutManager
|
||||
|
||||
adapter = SlimAdapter.create()
|
||||
adapter
|
||||
.register<String>(R.layout.custom_location_item) { _, injector ->
|
||||
injector
|
||||
.text(R.id.text, getString(R.string.custom_location_gps))
|
||||
.clicked(R.id.text) {
|
||||
requirePermission()
|
||||
}
|
||||
}
|
||||
.register<Address>(R.layout.custom_location_item) { item, injector ->
|
||||
injector.text(R.id.text, item.getAddressLine(0))
|
||||
injector.clicked(R.id.text) {
|
||||
Preferences.bulk {
|
||||
customLocationLat = item.latitude.toString()
|
||||
customLocationLon = item.longitude.toString()
|
||||
customLocationAdd = item.getAddressLine(0)
|
||||
setResult(Activity.RESULT_OK)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
.attachTo(list_view)
|
||||
|
||||
|
||||
viewModel.addresses.observe(this, Observer {
|
||||
adapter.updateData(listOf("Default") + it)
|
||||
})
|
||||
|
||||
setupListener()
|
||||
subscribeUi(binding, viewModel)
|
||||
|
||||
location.requestFocus()
|
||||
|
||||
}
|
||||
private var searchJob: Job? = null
|
||||
|
||||
private fun subscribeUi(binding: ActivityCustomLocationBinding, viewModel: CustomLocationViewModel) {
|
||||
binding.viewModel = viewModel
|
||||
viewModel.addresses.observe(this, Observer {
|
||||
adapter.updateData(listOf("Default") + it)
|
||||
loader.visibility = View.INVISIBLE
|
||||
})
|
||||
|
||||
viewModel.locationInput.observe(this, Observer { location ->
|
||||
loader.visibility = View.VISIBLE
|
||||
searchJob?.cancel()
|
||||
searchJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||
delay(200)
|
||||
val list = if (location == null || location == "") {
|
||||
viewModel.addresses.value!!
|
||||
} else {
|
||||
val coder = Geocoder(this@CustomLocationActivity)
|
||||
try {
|
||||
coder.getFromLocationName(location, 10) as ArrayList<Address>
|
||||
} catch (ignored: Exception) {
|
||||
emptyList<Address>()
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
viewModel.addresses.value = list
|
||||
loader.visibility = View.INVISIBLE
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun requirePermission() {
|
||||
Dexter.withContext(this)
|
||||
.withPermissions(
|
||||
Manifest.permission.ACCESS_FINE_LOCATION
|
||||
).withListener(object: MultiplePermissionsListener {
|
||||
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
||||
report?.let {
|
||||
if (report.areAllPermissionsGranted()){
|
||||
Preferences.bulk {
|
||||
remove(Preferences::customLocationLat)
|
||||
remove(Preferences::customLocationLon)
|
||||
remove(Preferences::customLocationAdd)
|
||||
}
|
||||
setResult(Activity.RESULT_OK)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun onPermissionRationaleShouldBeShown(
|
||||
permissions: MutableList<PermissionRequest>?,
|
||||
token: PermissionToken?
|
||||
) {
|
||||
// Remember to invoke this method when the custom rationale is closed
|
||||
// or just by default if you don't want to use any custom rationale.
|
||||
token?.continuePermissionRequest()
|
||||
}
|
||||
})
|
||||
.check()
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
action_back.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,198 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activities
|
||||
|
||||
import android.animation.ValueAnimator
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.view.View
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.TypedValue
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.animation.addListener
|
||||
import androidx.core.animation.doOnEnd
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import com.tommasoberlose.anotherwidget.global.Actions
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.global.RequestCode
|
||||
import com.tommasoberlose.anotherwidget.ui.adapters.ViewPagerAdapter
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||
import com.tommasoberlose.anotherwidget.utils.*
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
||||
import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver
|
||||
import com.tommasoberlose.anotherwidget.ui.widgets.TheWidget
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
|
||||
class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private var mAppWidgetId: Int = -1
|
||||
private lateinit var viewModel: MainViewModel
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
|
||||
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
|
||||
|
||||
controlExtras(intent)
|
||||
|
||||
// Viewpager
|
||||
pager.adapter = ViewPagerAdapter(this)
|
||||
pager.offscreenPageLimit = 4
|
||||
TabLayoutMediator(tabs, pager) { tab, position ->
|
||||
tab.text = when (position) {
|
||||
0 -> getString(R.string.settings_general_title)
|
||||
1 -> getString(R.string.settings_calendar_title)
|
||||
2 -> getString(R.string.settings_weather_title)
|
||||
3 -> getString(R.string.settings_clock_title)
|
||||
4 -> getString(R.string.advanced_settings_title)
|
||||
else -> ""
|
||||
}
|
||||
}.attach()
|
||||
|
||||
Preferences.preferences.registerOnSharedPreferenceChangeListener(this)
|
||||
subscribeUi(viewModel)
|
||||
updateUI()
|
||||
}
|
||||
|
||||
private fun updateUI() {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val generatedView = TheWidget.generateWidgetView(this@MainActivity, preview.measuredWidth)
|
||||
generatedView.measure(0, 0)
|
||||
val bitmap = Util.getBitmapFromView(generatedView, generatedView.measuredWidth, generatedView.measuredHeight)
|
||||
withContext(Dispatchers.Main) {
|
||||
// Clock
|
||||
clock.setTextColor(Util.getFontColor())
|
||||
clock.setTextSize(TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(this@MainActivity))
|
||||
clock.format12Hour = "hh:mm"
|
||||
|
||||
if ((Preferences.showClock && !clock.isVisible) || (!Preferences.showClock && clock.isVisible)) {
|
||||
if (Preferences.showClock) {
|
||||
clock.layoutParams = clock.layoutParams.apply {
|
||||
height = RelativeLayout.LayoutParams.WRAP_CONTENT
|
||||
}
|
||||
clock.measure(0, 0)
|
||||
}
|
||||
val initialHeight = clock.measuredHeight
|
||||
ValueAnimator.ofFloat(
|
||||
if (Preferences.showClock) 0f else 1f,
|
||||
if (Preferences.showClock) 1f else 0f
|
||||
).apply {
|
||||
duration = 500L
|
||||
addUpdateListener {
|
||||
val animatedValue = animatedValue as Float
|
||||
clock.layoutParams = clock.layoutParams.apply {
|
||||
height = (initialHeight * animatedValue).toInt()
|
||||
}
|
||||
}
|
||||
addListener(
|
||||
onStart = {
|
||||
if (Preferences.showClock) {
|
||||
clock.isVisible = true
|
||||
}
|
||||
},
|
||||
onEnd = {
|
||||
if (!Preferences.showClock) {
|
||||
clock.isVisible = false
|
||||
}
|
||||
}
|
||||
)
|
||||
}.start()
|
||||
|
||||
ValueAnimator.ofInt(
|
||||
preview.measuredHeight,
|
||||
160.toPixel(this@MainActivity) + if (Preferences.showClock) 100.toPixel(this@MainActivity) else 0
|
||||
).apply {
|
||||
duration = 500L
|
||||
addUpdateListener {
|
||||
val animatedValue = animatedValue as Int
|
||||
val layoutParams = preview.layoutParams
|
||||
layoutParams.height = animatedValue
|
||||
preview.layoutParams = layoutParams
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
widget_bitmap.setImageBitmap(bitmap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeUi(viewModel: MainViewModel) {
|
||||
viewModel.showWallpaper.observe(this, Observer {
|
||||
widget_bg.setImageDrawable(if (it) Util.getCurrentWallpaper(this) else null)
|
||||
})
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (mAppWidgetId > 0) {
|
||||
addNewWidget()
|
||||
} else {
|
||||
setResult(Activity.RESULT_OK)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent?) {
|
||||
super.onNewIntent(intent)
|
||||
|
||||
if (intent != null) {
|
||||
controlExtras(intent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun controlExtras(intent: Intent) {
|
||||
val extras = intent.extras
|
||||
if (extras != null) {
|
||||
mAppWidgetId = extras.getInt(
|
||||
AppWidgetManager.EXTRA_APPWIDGET_ID,
|
||||
AppWidgetManager.INVALID_APPWIDGET_ID)
|
||||
|
||||
if (mAppWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
|
||||
action_add_widget.visibility = View.VISIBLE
|
||||
action_add_widget.setOnClickListener {
|
||||
addNewWidget()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (extras.containsKey(Actions.ACTION_EXTRA_OPEN_WEATHER_PROVIDER)) {
|
||||
startActivityForResult(Intent(this, WeatherProviderActivity::class.java), RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code)
|
||||
}
|
||||
if (extras.containsKey(Actions.ACTION_EXTRA_DISABLE_GPS_NOTIFICATION)) {
|
||||
Preferences.showGpsInformation = false
|
||||
sendBroadcast(Intent(Actions.ACTION_WEATHER_UPDATE))
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addNewWidget() {
|
||||
val resultValue = Intent()
|
||||
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId)
|
||||
setResult(Activity.RESULT_OK, resultValue)
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
Preferences.preferences.unregisterOnSharedPreferenceChangeListener(this)
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(preferences: SharedPreferences, p1: String) {
|
||||
updateUI()
|
||||
Util.updateWidget(this)
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activities
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.location.Address
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
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.utils.toast
|
||||
import kotlinx.android.synthetic.main.activity_support_dev.*
|
||||
import net.idik.lib.slimadapter.SlimAdapter
|
||||
|
||||
class SupportDevActivity : AppCompatActivity(), PurchasesUpdatedListener {
|
||||
|
||||
private val BILLING_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAox5CcxuoLJ6CmNS7s6lVQzJ253njKKGF8MoQ/gQ5gEw2Fr03fBvtHpiVMpnjhNLw5NMeIpzRvkVqeQ7BfkC7c0BLCJUqf/fFA11ArQe8na6QKt5O4d+v4sbHtP7mm3GQNPOBaqRzcpFZaiAbfk6mnalo+tzM47GXrQFt5bNSrMctCs7bbChqJfH2cyMW0F8DHWEEeO5xElBmH3lh4FVpwIUTPYJIV3n0yhE3qqRA0WXkDej66g/uAt/rebmMZLmwNwIive5cObU4o41YyKRv2wSAicrv3W40LftzXAOOordIbmzDFN8ksh3VrnESqwCDGG97nZVbPG/+3LD0xHWiRwIDAQAB"
|
||||
private lateinit var viewModel: SupportDevViewModel
|
||||
private lateinit var adapter: SlimAdapter
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
viewModel = ViewModelProvider(this).get(SupportDevViewModel::class.java)
|
||||
viewModel.billingClient = BillingClient.newBuilder(this).enablePendingPurchases().setListener(this).build()
|
||||
val binding = DataBindingUtil.setContentView<ActivitySupportDevBinding>(this, R.layout.activity_support_dev)
|
||||
|
||||
|
||||
list_view.setHasFixedSize(true)
|
||||
val mLayoutManager = LinearLayoutManager(this)
|
||||
list_view.layoutManager = mLayoutManager
|
||||
|
||||
adapter = SlimAdapter.create()
|
||||
adapter
|
||||
.register<SkuDetails>(R.layout.inapp_product_layout) { item, injector ->
|
||||
injector
|
||||
.text(R.id.product_title, item.title.replace("(Another Widget)", ""))
|
||||
.text(R.id.product_price, item.price)
|
||||
.clicked(R.id.item) {
|
||||
viewModel.purchase(this, item)
|
||||
}
|
||||
}
|
||||
.attachTo(list_view)
|
||||
|
||||
viewModel.openConnection()
|
||||
subscribeUi(viewModel)
|
||||
|
||||
action_back.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeUi(viewModel: SupportDevViewModel) {
|
||||
viewModel.products.observe(this, Observer {
|
||||
if (it.isNotEmpty()) {
|
||||
loader.isVisible = false
|
||||
}
|
||||
adapter.updateData(it.sortedWith(compareBy(SkuDetails::getPriceAmountMicros)))
|
||||
})
|
||||
}
|
||||
|
||||
override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) {
|
||||
if (billingResult.responseCode == OK && purchases != null) {
|
||||
for (purchase in purchases) {
|
||||
if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
|
||||
viewModel.handlePurchase(purchase)
|
||||
toast(getString(R.string.thanks))
|
||||
}
|
||||
}
|
||||
} else if (billingResult.responseCode == USER_CANCELED) {
|
||||
// DO nothing
|
||||
} else {
|
||||
toast(getString(R.string.error))
|
||||
}
|
||||
}
|
||||
|
||||
public override fun onDestroy() {
|
||||
viewModel.closeConnection()
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activities
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.app.AlertDialog
|
||||
import android.content.DialogInterface
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.Html
|
||||
import android.text.TextWatcher
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.utils.Util
|
||||
import com.tommasoberlose.anotherwidget.utils.WeatherUtil
|
||||
import com.tommasoberlose.anotherwidget.utils.openURI
|
||||
import kotlinx.android.synthetic.main.activity_weather_provider.*
|
||||
|
||||
class WeatherProviderActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_weather_provider)
|
||||
|
||||
action_back.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
action_save.setOnClickListener {
|
||||
Preferences.weatherProviderApi = api_key.editText?.text.toString()
|
||||
setResult(Activity.RESULT_OK)
|
||||
finish()
|
||||
}
|
||||
|
||||
action_open_provider.setOnClickListener {
|
||||
openURI("https://home.openweathermap.org/users/sign_up")
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
last_info.text = Html.fromHtml(getString(R.string.api_key_info_all_set), Html.FROM_HTML_MODE_LEGACY)
|
||||
} else {
|
||||
last_info.text = Html.fromHtml(getString(R.string.api_key_info_all_set))
|
||||
}
|
||||
api_key.editText?.setText(Preferences.weatherProviderApi)
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (api_key.editText?.text.toString() == "") {
|
||||
AlertDialog.Builder(this)
|
||||
.setMessage(getString(R.string.error_weather_api_key))
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(android.R.string.yes) { _, _ ->
|
||||
super.onBackPressed()
|
||||
}
|
||||
.show()
|
||||
} else {
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,140 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activity
|
||||
|
||||
import android.app.Activity
|
||||
import android.location.Address
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.os.Bundle
|
||||
import android.preference.PreferenceManager
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.`object`.Constants
|
||||
import com.tommasoberlose.anotherwidget.`object`.CustomLocationEvent
|
||||
import kotlinx.android.synthetic.main.activity_choose_application.*
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import android.content.Intent
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import com.tommasoberlose.anotherwidget.`object`.ApplicationListEvent
|
||||
import android.content.pm.PackageManager
|
||||
import android.location.Geocoder
|
||||
import android.support.v7.widget.LinearLayoutManager
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import com.tommasoberlose.anotherwidget.`object`.AppInfoSavedEvent
|
||||
import com.tommasoberlose.anotherwidget.ui.adapter.ApplicationInfoAdapter
|
||||
|
||||
|
||||
class ChooseApplicationActivity : AppCompatActivity() {
|
||||
lateinit var adapter: ApplicationInfoAdapter
|
||||
val appList = ArrayList<ApplicationInfo>()
|
||||
val appListFiltered = ArrayList<ApplicationInfo>()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_choose_application)
|
||||
val pm = packageManager
|
||||
|
||||
action_default.setOnClickListener {
|
||||
selectDefaultApp()
|
||||
}
|
||||
|
||||
action_back.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
action_none.setOnClickListener {
|
||||
removeClickAction()
|
||||
}
|
||||
|
||||
list_view.setHasFixedSize(true);
|
||||
val mLayoutManager = LinearLayoutManager(this);
|
||||
list_view.layoutManager = mLayoutManager;
|
||||
|
||||
adapter = ApplicationInfoAdapter(this, appListFiltered);
|
||||
list_view.setAdapter(adapter);
|
||||
|
||||
location.addTextChangedListener(object: TextWatcher {
|
||||
override fun afterTextChanged(text: Editable?) {
|
||||
Thread().run {
|
||||
val appsFiltered = if (text == null || text.equals("")) appList else appList.filter { pm.getApplicationLabel(it).toString().contains(text.toString(), true) }
|
||||
EventBus.getDefault().post(ApplicationListEvent(appsFiltered, true))
|
||||
}
|
||||
}
|
||||
|
||||
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
|
||||
}
|
||||
|
||||
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
fun selectDefaultApp() {
|
||||
val resultIntent = Intent()
|
||||
resultIntent.putExtra(Constants.RESULT_APP_NAME, "")
|
||||
resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, "")
|
||||
setResult(Activity.RESULT_OK, resultIntent)
|
||||
finish()
|
||||
}
|
||||
|
||||
fun removeClickAction() {
|
||||
val resultIntent = Intent()
|
||||
resultIntent.putExtra(Constants.RESULT_APP_NAME, getString(R.string.action_none))
|
||||
resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, "_")
|
||||
setResult(Activity.RESULT_OK, resultIntent)
|
||||
finish()
|
||||
}
|
||||
|
||||
fun multiEventAction() {
|
||||
val resultIntent = Intent()
|
||||
resultIntent.putExtra(Constants.RESULT_APP_NAME, getString(R.string.action_go_to_next_event))
|
||||
resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, Constants.PREF_SHOW_NEXT_EVENT)
|
||||
setResult(Activity.RESULT_OK, resultIntent)
|
||||
finish()
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||
fun saveApp(e: AppInfoSavedEvent) {
|
||||
val pm = packageManager
|
||||
val resultIntent = Intent()
|
||||
resultIntent.putExtra(Constants.RESULT_APP_NAME, pm.getApplicationLabel(e.app).toString())
|
||||
resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, e.app.packageName)
|
||||
setResult(Activity.RESULT_OK, resultIntent)
|
||||
finish()
|
||||
}
|
||||
|
||||
public override fun onStart() {
|
||||
super.onStart()
|
||||
EventBus.getDefault().register(this)
|
||||
}
|
||||
|
||||
public override fun onResume() {
|
||||
super.onResume()
|
||||
Thread().run {
|
||||
val pm = packageManager
|
||||
val apps = pm.getInstalledApplications(0)
|
||||
EventBus.getDefault().post(ApplicationListEvent(apps, false))
|
||||
}
|
||||
}
|
||||
|
||||
public override fun onStop() {
|
||||
EventBus.getDefault().unregister(this)
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||
fun onMessageEvent(event: ApplicationListEvent) {
|
||||
if (!event.filtered) {
|
||||
appList.clear()
|
||||
event.apps.mapTo(appList, {it})
|
||||
}
|
||||
appListFiltered.clear()
|
||||
event.apps.mapTo(appListFiltered, {it})
|
||||
adapter.changeData(appListFiltered)
|
||||
}
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activity
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.location.Address
|
||||
import android.location.Geocoder
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.os.Bundle
|
||||
import android.preference.PreferenceManager
|
||||
import android.transition.Slide
|
||||
import android.view.Gravity
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import android.support.v4.view.ViewCompat.setAlpha
|
||||
import android.support.v4.view.ViewCompat.animate
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.ListView
|
||||
import android.widget.Toast
|
||||
import com.tommasoberlose.anotherwidget.`object`.Constants
|
||||
import com.tommasoberlose.anotherwidget.`object`.CustomLocationEvent
|
||||
import com.tommasoberlose.anotherwidget.util.WeatherUtil
|
||||
import kotlinx.android.synthetic.main.activity_custom_location.*
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class CustomLocationActivity : AppCompatActivity() {
|
||||
lateinit var adapter: ArrayAdapter<String>
|
||||
val addressesList = ArrayList<Address>()
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_custom_location)
|
||||
|
||||
val SP = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
|
||||
adapter = ArrayAdapter(this, R.layout.custom_location_item, addressesList.map { it.getAddressLine(0) })
|
||||
list_view.adapter = adapter
|
||||
|
||||
list_view.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id ->
|
||||
SP.edit()
|
||||
.putString(Constants.PREF_CUSTOM_LOCATION_LAT, addressesList[position].latitude.toString())
|
||||
.putString(Constants.PREF_CUSTOM_LOCATION_LON, addressesList[position].longitude.toString())
|
||||
.putString(Constants.PREF_CUSTOM_LOCATION_ADD, addressesList[position].getAddressLine(0))
|
||||
.commit()
|
||||
setResult(Activity.RESULT_OK)
|
||||
finish()
|
||||
}
|
||||
|
||||
action_geolocation.setOnClickListener {
|
||||
SP.edit()
|
||||
.remove(Constants.PREF_CUSTOM_LOCATION_LAT)
|
||||
.remove(Constants.PREF_CUSTOM_LOCATION_LON)
|
||||
.remove(Constants.PREF_CUSTOM_LOCATION_ADD)
|
||||
.commit()
|
||||
setResult(Activity.RESULT_OK)
|
||||
finish()
|
||||
}
|
||||
|
||||
location.addTextChangedListener(object: TextWatcher {
|
||||
override fun afterTextChanged(text: Editable?) {
|
||||
if (text != null && !text.equals("")) {
|
||||
Thread().run {
|
||||
val coder = Geocoder(this@CustomLocationActivity)
|
||||
try {
|
||||
val addresses = coder.getFromLocationName(text.toString(), 10) as ArrayList<Address>
|
||||
EventBus.getDefault().post(CustomLocationEvent(addresses))
|
||||
} catch (ignored: Exception) {
|
||||
EventBus.getDefault().post(CustomLocationEvent(ArrayList<Address>()))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
EventBus.getDefault().post(CustomLocationEvent(ArrayList<Address>()))
|
||||
}
|
||||
}
|
||||
|
||||
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
|
||||
}
|
||||
|
||||
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
public override fun onStart() {
|
||||
super.onStart()
|
||||
EventBus.getDefault().register(this)
|
||||
}
|
||||
|
||||
public override fun onStop() {
|
||||
EventBus.getDefault().unregister(this)
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||
fun onMessageEvent(event: CustomLocationEvent) {
|
||||
adapter.clear()
|
||||
addressesList.clear()
|
||||
event.addresses.mapTo(addressesList, {it})
|
||||
for (a:Address in addressesList) {
|
||||
adapter.add(a.getAddressLine(0))
|
||||
}
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
@ -1,882 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activity
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.app.AlertDialog
|
||||
import android.content.pm.PackageManager
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.ActivityCompat
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.*
|
||||
import android.preference.PreferenceManager
|
||||
import android.view.View
|
||||
import com.tommasoberlose.anotherwidget.`object`.Constants
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.util.Util
|
||||
import com.tommasoberlose.anotherwidget.receiver.WeatherReceiver
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import android.content.Intent
|
||||
import android.content.BroadcastReceiver
|
||||
import com.tommasoberlose.anotherwidget.util.CalendarUtil
|
||||
import com.tommasoberlose.anotherwidget.util.WeatherUtil
|
||||
import android.content.DialogInterface
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.support.design.widget.BottomSheetDialog
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.text.Html
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableString
|
||||
import android.text.style.RelativeSizeSpan
|
||||
import android.util.Log
|
||||
import android.util.TypedValue
|
||||
import android.widget.Toast
|
||||
import com.crashlytics.android.Crashlytics
|
||||
import com.pes.androidmaterialcolorpickerdialog.ColorPicker
|
||||
import com.tommasoberlose.anotherwidget.`object`.CalendarSelector
|
||||
import com.tommasoberlose.anotherwidget.receiver.UpdatesReceiver
|
||||
import io.fabric.sdk.android.Fabric
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import kotlinx.android.synthetic.main.key_time_wait_layout.view.*
|
||||
import kotlinx.android.synthetic.main.main_menu_layout.view.*
|
||||
import kotlinx.android.synthetic.main.the_widget.*
|
||||
import kotlinx.android.synthetic.main.the_widget.view.*
|
||||
import java.io.File
|
||||
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
private var mAppWidgetId: Int = -1
|
||||
private lateinit var SP: SharedPreferences
|
||||
|
||||
private val receiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
Fabric.with(this, Crashlytics())
|
||||
sendBroadcast(Intent(Constants.ACTION_CALENDAR_UPDATE))
|
||||
sendBroadcast(Intent(Constants.ACTION_WEATHER_UPDATE))
|
||||
|
||||
SP = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
|
||||
controlExtras(intent)
|
||||
|
||||
action_menu.setOnClickListener {
|
||||
val mBottomSheetDialog = BottomSheetDialog(this)
|
||||
val menuView: View = getLayoutInflater().inflate(R.layout.main_menu_layout, null)
|
||||
|
||||
menuView.action_share.setOnClickListener(object: View.OnClickListener {
|
||||
override fun onClick(p0: View?) {
|
||||
Util.share(this@MainActivity)
|
||||
mBottomSheetDialog.dismiss()
|
||||
}
|
||||
})
|
||||
|
||||
if (SP.getBoolean(Constants.PREF_SHOW_WIDGET_PREVIEW, true)) {
|
||||
menuView.widget_preview_icon.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_action_hide_preview))
|
||||
menuView.widget_preview_label.text = getString(R.string.action_hide_widget_preview)
|
||||
menuView.action_toggle_widget_preview.setOnClickListener {
|
||||
SP.edit()
|
||||
.putBoolean(Constants.PREF_SHOW_WIDGET_PREVIEW, false)
|
||||
.commit()
|
||||
updateUI()
|
||||
mBottomSheetDialog.dismiss()
|
||||
}
|
||||
} else {
|
||||
menuView.widget_preview_icon.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_action_show_preview))
|
||||
menuView.widget_preview_label.text = getString(R.string.action_show_widget_preview)
|
||||
menuView.action_toggle_widget_preview.setOnClickListener {
|
||||
SP.edit()
|
||||
.putBoolean(Constants.PREF_SHOW_WIDGET_PREVIEW, true)
|
||||
.commit()
|
||||
updateUI()
|
||||
mBottomSheetDialog.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
menuView.action_rate.setOnClickListener(object: View.OnClickListener {
|
||||
override fun onClick(p0: View?) {
|
||||
Util.rateApp(this@MainActivity, "https://play.google.com/store/apps/details?id=com.tommasoberlose.anotherwidget")
|
||||
mBottomSheetDialog.dismiss()
|
||||
}
|
||||
})
|
||||
|
||||
menuView.action_feedback.setOnClickListener(object: View.OnClickListener {
|
||||
override fun onClick(p0: View?) {
|
||||
Util.sendEmail(this@MainActivity)
|
||||
mBottomSheetDialog.dismiss()
|
||||
}
|
||||
})
|
||||
|
||||
menuView.action_refresh.setOnClickListener {
|
||||
WeatherUtil.updateWeather(this)
|
||||
CalendarUtil.updateEventList(this)
|
||||
Util.updateWidget(this)
|
||||
mBottomSheetDialog.dismiss()
|
||||
}
|
||||
|
||||
menuView.action_support.setOnClickListener {
|
||||
startActivity(Intent(this, SupportDevActivity::class.java))
|
||||
mBottomSheetDialog.dismiss()
|
||||
}
|
||||
|
||||
mBottomSheetDialog.setContentView(menuView)
|
||||
mBottomSheetDialog.show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (mAppWidgetId > 0) {
|
||||
addNewWidget()
|
||||
} else {
|
||||
setResult(Activity.RESULT_OK)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent?) {
|
||||
super.onNewIntent(intent)
|
||||
|
||||
if (intent != null) {
|
||||
controlExtras(intent)
|
||||
}
|
||||
}
|
||||
|
||||
fun controlExtras(intent: Intent) {
|
||||
val extras = intent.extras
|
||||
if (extras != null) {
|
||||
mAppWidgetId = extras.getInt(
|
||||
AppWidgetManager.EXTRA_APPWIDGET_ID,
|
||||
AppWidgetManager.INVALID_APPWIDGET_ID)
|
||||
|
||||
if (mAppWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
|
||||
action_add_widget.visibility = View.VISIBLE
|
||||
|
||||
action_add_widget.setOnClickListener {
|
||||
addNewWidget()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (extras.containsKey(Constants.ACTION_EXTRA_OPEN_WEATHER_PROVIDER)) {
|
||||
startActivityForResult(Intent(this, WeatherProviderActivity::class.java), Constants.WEATHER_PROVIDER_REQUEST_CODE)
|
||||
}
|
||||
if (extras.containsKey(Constants.ACTION_EXTRA_DISABLE_GPS_NOTIFICATION)) {
|
||||
SP.edit()
|
||||
.putBoolean(Constants.PREF_SHOW_GPS_NOTIFICATION, false)
|
||||
.apply()
|
||||
sendBroadcast(Intent(Constants.ACTION_WEATHER_UPDATE))
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun addNewWidget() {
|
||||
val resultValue = Intent()
|
||||
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId)
|
||||
setResult(Activity.RESULT_OK, resultValue)
|
||||
finish()
|
||||
sendBroadcast(Intent(Constants.ACTION_CALENDAR_UPDATE))
|
||||
sendBroadcast(Intent(Constants.ACTION_WEATHER_UPDATE))
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
val filter = IntentFilter()
|
||||
filter.addAction(Constants.ACTION_SOMETHING_HAPPENED);
|
||||
registerReceiver(receiver, filter);
|
||||
updateUI()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
unregisterReceiver(receiver);
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>,
|
||||
grantResults: IntArray) {
|
||||
when (requestCode) {
|
||||
Constants.CALENDAR_REQUEST_CODE -> if (!(permissions.size != 1 || grantResults.size != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED)) {
|
||||
sendBroadcast(Intent(Constants.ACTION_CALENDAR_UPDATE))
|
||||
updateAppWidget()
|
||||
updateSettings()
|
||||
}
|
||||
Constants.LOCATION_REQUEST_CODE -> if (!(permissions.size != 1 || grantResults.size != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED)) {
|
||||
val SP = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
sendBroadcast(Intent(Constants.ACTION_WEATHER_UPDATE))
|
||||
updateAppWidget()
|
||||
updateSettings()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateUI() {
|
||||
updateSettings()
|
||||
updateAppWidget()
|
||||
updateClockView()
|
||||
|
||||
if (SP.getBoolean(Constants.PREF_SHOW_WIDGET_PREVIEW, true)) {
|
||||
val displayMetrics = Resources.getSystem().displayMetrics
|
||||
var width = displayMetrics.widthPixels
|
||||
if (width <= 0) {
|
||||
width = Util.convertDpToPixel(300f, this).toInt()
|
||||
}
|
||||
var height = Util.convertDpToPixel(120f, this).toInt()
|
||||
if (SP.getBoolean(Constants.PREF_SHOW_CLOCK, false)) {
|
||||
height += Util.convertSpToPixels(SP.getFloat(Constants.PREF_TEXT_CLOCK_SIZE, 90f), this).toInt() + Util.convertDpToPixel(16f, this).toInt()
|
||||
}
|
||||
if (SP.getFloat(Constants.PREF_TEXT_MAIN_SIZE, 24f) + SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f) > 50) {
|
||||
height += Util.convertDpToPixel(24f, this).toInt()
|
||||
}
|
||||
widget_bitmap.setImageBitmap(Util.getBitmapFromView(main_layout, width, height - Util.convertDpToPixel(32f, this).toInt()))
|
||||
widget.layoutParams.height = height + Util.convertDpToPixel(16f, this).toInt()
|
||||
|
||||
widget.visibility = View.VISIBLE
|
||||
} else {
|
||||
widget.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal fun updateAppWidget() {
|
||||
val wallpaper: Drawable? = Util.getCurrentWallpaper(this)
|
||||
if (wallpaper != null) {
|
||||
widget_bg.setImageDrawable(wallpaper)
|
||||
}
|
||||
widget_bg.setBackgroundColor(Color.WHITE)
|
||||
updateCalendarView()
|
||||
updateLocationView()
|
||||
updateClockView()
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == Constants.RESULT_CODE_CUSTOM_LOCATION && resultCode == Activity.RESULT_OK) {
|
||||
sendBroadcast(Intent(Constants.ACTION_WEATHER_UPDATE))
|
||||
updateSettings()
|
||||
} else if (requestCode == Constants.CALENDAR_APP_REQUEST_CODE && resultCode == Activity.RESULT_OK && data != null) {
|
||||
SP.edit()
|
||||
.putString(Constants.PREF_CALENDAR_APP_NAME, if (data.getStringExtra(Constants.RESULT_APP_NAME) != "") data.getStringExtra(Constants.RESULT_APP_NAME) else getString(R.string.default_calendar_app))
|
||||
.putString(Constants.PREF_CALENDAR_APP_PACKAGE, data.getStringExtra(Constants.RESULT_APP_PACKAGE))
|
||||
.commit()
|
||||
Util.updateWidget(this)
|
||||
updateSettings()
|
||||
} else if (requestCode == Constants.WEATHER_APP_REQUEST_CODE && resultCode == Activity.RESULT_OK && data != null) {
|
||||
SP.edit()
|
||||
.putString(Constants.PREF_WEATHER_APP_NAME, if (data.getStringExtra(Constants.RESULT_APP_NAME) != "") data.getStringExtra(Constants.RESULT_APP_NAME) else getString(R.string.default_weather_app))
|
||||
.putString(Constants.PREF_WEATHER_APP_PACKAGE, data.getStringExtra(Constants.RESULT_APP_PACKAGE))
|
||||
.commit()
|
||||
Util.updateWidget(this)
|
||||
updateSettings()
|
||||
} else if (requestCode == Constants.EVENT_APP_REQUEST_CODE && resultCode == Activity.RESULT_OK && data != null) {
|
||||
SP.edit()
|
||||
.putString(Constants.PREF_EVENT_APP_NAME, if (data.getStringExtra(Constants.RESULT_APP_NAME) != "") data.getStringExtra(Constants.RESULT_APP_NAME) else getString(R.string.default_event_app))
|
||||
.putString(Constants.PREF_EVENT_APP_PACKAGE, data.getStringExtra(Constants.RESULT_APP_PACKAGE))
|
||||
.commit()
|
||||
Util.updateWidget(this)
|
||||
updateSettings()
|
||||
} else if (requestCode == Constants.CLOCK_APP_REQUEST_CODE && resultCode == Activity.RESULT_OK && data != null) {
|
||||
SP.edit()
|
||||
.putString(Constants.PREF_CLOCK_APP_NAME, if (data.getStringExtra(Constants.RESULT_APP_NAME) != "") data.getStringExtra(Constants.RESULT_APP_NAME) else getString(R.string.default_clock_app))
|
||||
.putString(Constants.PREF_CLOCK_APP_PACKAGE, data.getStringExtra(Constants.RESULT_APP_PACKAGE))
|
||||
.commit()
|
||||
Util.updateWidget(this)
|
||||
updateSettings()
|
||||
} else if (requestCode == Constants.WEATHER_PROVIDER_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
|
||||
WeatherReceiver().setOneTimeUpdate(this)
|
||||
sendBroadcast(Intent(Constants.ACTION_WEATHER_UPDATE))
|
||||
updateSettings()
|
||||
} else if (requestCode == Constants.CUSTOM_FONT_CHOOSER_REQUEST_CODE && resultCode == Activity.RESULT_OK && data != null) {
|
||||
/*val uri = data.data
|
||||
Log.d("AW", "File Uri: " + uri.toString())
|
||||
val path = Util.getPath(this, uri)
|
||||
Log.d("AW", "File Path: " + path)
|
||||
SP.edit()
|
||||
.putString(Constants.PREF_CUSTOM_FONT_FILE, path)
|
||||
.commit()
|
||||
sendBroadcast(Intent(Constants.ACTION_TIME_UPDATE))
|
||||
updateSettings()*/
|
||||
}
|
||||
}
|
||||
|
||||
fun updateClockView() {
|
||||
if (!SP.getBoolean(Constants.PREF_SHOW_CLOCK, false)) {
|
||||
time.visibility = View.GONE
|
||||
} else {
|
||||
time.visibility = View.VISIBLE
|
||||
}
|
||||
val now = Calendar.getInstance()
|
||||
if (SP.getString(Constants.PREF_HOUR_FORMAT, "12") == "12") {
|
||||
// time.format12Hour = "hh:mm a"
|
||||
// val textBadHour = SpannableString(Constants.badHourFormat.format(time.))
|
||||
// textBadHour.setSpan(RelativeSizeSpan(0.4f), textBadHour.length - 2,
|
||||
// textBadHour.length, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
|
||||
//
|
||||
// time.text = textBadHour
|
||||
} else {
|
||||
// time.format24Hour = "HH:mm"
|
||||
// time.text = Constants.goodHourFormat.format(now.timeInMillis)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateCalendarView() {
|
||||
val now = Calendar.getInstance()
|
||||
val calendarLayout = SP.getBoolean(Constants.PREF_SHOW_EVENTS, true) && Util.checkGrantedPermission(this, Manifest.permission.READ_CALENDAR)
|
||||
|
||||
empty_layout.visibility = View.VISIBLE
|
||||
calendar_layout.visibility = View.GONE
|
||||
var dateStringValue: String = Util.getCapWordString(Constants.engDateFormat.format(now.time))
|
||||
if (SP.getBoolean(Constants.PREF_ITA_FORMAT_DATE, false)) {
|
||||
dateStringValue = Util.getCapWordString(Constants.itDateFormat.format(now.time))
|
||||
}
|
||||
empty_date.text = dateStringValue
|
||||
|
||||
if (calendarLayout) {
|
||||
val e = CalendarUtil.getNextEvent(this)
|
||||
|
||||
if (e.id != 0.toLong()) {
|
||||
next_event.text = e.title
|
||||
|
||||
if (SP.getBoolean(Constants.PREF_SHOW_NEXT_EVENT, false) && CalendarUtil.getEventsCount(this) > 1) {
|
||||
multiple_events.visibility = View.VISIBLE
|
||||
} else {
|
||||
multiple_events.visibility = View.GONE
|
||||
}
|
||||
|
||||
if (SP.getBoolean(Constants.PREF_SHOW_DIFF_TIME, true)) {
|
||||
next_event_difference_time.text = Util.getDifferenceText(this, now.timeInMillis, e.startDate)
|
||||
next_event_difference_time.visibility = View.VISIBLE
|
||||
} else {
|
||||
next_event_difference_time.visibility = View.GONE
|
||||
}
|
||||
|
||||
|
||||
if (SP.getInt(Constants.PREF_SECOND_ROW_INFORMATION, 0) == 2 && Util.getNextAlarm(this) != null) {
|
||||
second_row_icon.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_action_alarm))
|
||||
next_event_date.text = Util.getNextAlarm(this)
|
||||
} else if (!e.address.equals("") && SP.getInt(Constants.PREF_SECOND_ROW_INFORMATION, 0) == 1) {
|
||||
second_row_icon.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_action_location))
|
||||
next_event_date.text = e.address
|
||||
} else {
|
||||
second_row_icon.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_action_calendar))
|
||||
if (!e.allDay) {
|
||||
val startHour: String = if (SP.getString(Constants.PREF_HOUR_FORMAT, "12").equals("12")) Constants.badHourFormat.format(e.startDate) else Constants.goodHourFormat.format(e.startDate)
|
||||
val endHour: String = if (SP.getString(Constants.PREF_HOUR_FORMAT, "12").equals("12")) Constants.badHourFormat.format(e.endDate) else Constants.goodHourFormat.format(e.endDate)
|
||||
var dayDiff = TimeUnit.MILLISECONDS.toDays(e.endDate - e.startDate)
|
||||
|
||||
val startCal = Calendar.getInstance()
|
||||
startCal.timeInMillis = e.startDate
|
||||
|
||||
val endCal = Calendar.getInstance()
|
||||
endCal.timeInMillis = e.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: String = ""
|
||||
if (dayDiff > 0) {
|
||||
multipleDay = String.format(" (+%s%s)", dayDiff, getString(R.string.day_char))
|
||||
}
|
||||
next_event_date.text = String.format("%s - %s%s", startHour, endHour, multipleDay)
|
||||
} else {
|
||||
next_event_date.text = dateStringValue
|
||||
}
|
||||
}
|
||||
|
||||
empty_layout.visibility = View.GONE
|
||||
calendar_layout.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
empty_date.setTextColor(Util.getFontColor(SP))
|
||||
divider1.setTextColor(Util.getFontColor(SP))
|
||||
temp.setTextColor(Util.getFontColor(SP))
|
||||
next_event.setTextColor(Util.getFontColor(SP))
|
||||
next_event_difference_time.setTextColor(Util.getFontColor(SP))
|
||||
next_event_date.setTextColor(Util.getFontColor(SP))
|
||||
divider2.setTextColor(Util.getFontColor(SP))
|
||||
calendar_temp.setTextColor(Util.getFontColor(SP))
|
||||
second_row_icon.setColorFilter(Util.getFontColor(SP))
|
||||
// time.setTextColor(Util.getFontColor(SP))
|
||||
|
||||
|
||||
empty_date.setTextSize(TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_MAIN_SIZE, 24f))
|
||||
divider1.setTextSize(TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f))
|
||||
temp.setTextSize(TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_MAIN_SIZE, 24f))
|
||||
next_event.setTextSize(TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_MAIN_SIZE, 24f))
|
||||
next_event_difference_time.setTextSize(TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_MAIN_SIZE, 24f))
|
||||
next_event_date.setTextSize(TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f))
|
||||
divider2.setTextSize(TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f))
|
||||
calendar_temp.setTextSize(TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f))
|
||||
// time.setTextSize(TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_CLOCK_SIZE, 90f))
|
||||
|
||||
second_row_icon.scaleX = SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f) / 18f
|
||||
second_row_icon.scaleY = SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f) / 18f
|
||||
|
||||
weather_icon.scaleX = SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f) / 18f
|
||||
weather_icon.scaleY = SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f) / 18f
|
||||
|
||||
empty_weather_icon.scaleX = SP.getFloat(Constants.PREF_TEXT_MAIN_SIZE, 24f) / 24f
|
||||
empty_weather_icon.scaleY = SP.getFloat(Constants.PREF_TEXT_MAIN_SIZE, 24f) / 24f
|
||||
|
||||
multiple_events.scaleX = SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f) / 16f
|
||||
multiple_events.scaleY = SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f) / 16f
|
||||
|
||||
val shadowRadius = when (SP.getInt(Constants.PREF_TEXT_SHADOW, 1)) {
|
||||
0 -> 0f
|
||||
1 -> 5f
|
||||
2 -> 4f
|
||||
else -> 5f
|
||||
}
|
||||
val shadowColor = when (SP.getInt(Constants.PREF_TEXT_SHADOW, 1)) {
|
||||
0 -> Color.TRANSPARENT
|
||||
1 -> R.color.black_50
|
||||
2 -> Color.BLACK
|
||||
else -> R.color.black_50
|
||||
}
|
||||
val shadowDy = when (SP.getInt(Constants.PREF_TEXT_SHADOW, 1)) {
|
||||
0 -> 0f
|
||||
1 -> 0f
|
||||
2 -> 1f
|
||||
else -> 0f
|
||||
}
|
||||
empty_date.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
|
||||
divider1.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
|
||||
temp.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
|
||||
next_event.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
|
||||
next_event_difference_time.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
|
||||
next_event_date.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
|
||||
divider2.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
|
||||
calendar_temp.setShadowLayer(shadowRadius, 0f, 0f, shadowColor)
|
||||
// time.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
|
||||
|
||||
if (SP.getInt(Constants.PREF_CUSTOM_FONT, Constants.CUSTOM_FONT_PRODUCT_SANS) == Constants.CUSTOM_FONT_PRODUCT_SANS) {
|
||||
val product_sans: Typeface = Typeface.createFromAsset(assets, "fonts/product_sans_regular.ttf")
|
||||
val product_sans_light: Typeface = Typeface.createFromAsset(assets, "fonts/product_sans_light.ttf")
|
||||
|
||||
|
||||
/*if (SP.getString(Constants.PREF_CUSTOM_FONT_FILE, "") != "") {
|
||||
val file = File(SP.getString(Constants.PREF_CUSTOM_FONT_FILE, ""))
|
||||
if (file.exists()) {
|
||||
Log.d("AW", "OK")
|
||||
}
|
||||
// product_sans = Typeface.createFromFile("")
|
||||
}*/
|
||||
empty_date.typeface = product_sans
|
||||
divider1.typeface = product_sans
|
||||
temp.typeface = product_sans
|
||||
next_event.typeface = product_sans
|
||||
next_event_difference_time.typeface = product_sans
|
||||
next_event_date.typeface = product_sans
|
||||
divider2.typeface = product_sans
|
||||
calendar_temp.typeface = product_sans
|
||||
//time.typeface = product_sans_light
|
||||
} else {
|
||||
empty_date.typeface = Typeface.DEFAULT
|
||||
divider1.typeface = Typeface.DEFAULT
|
||||
temp.typeface = Typeface.DEFAULT
|
||||
next_event.typeface = Typeface.DEFAULT
|
||||
next_event_difference_time.typeface = Typeface.DEFAULT
|
||||
next_event_date.typeface = Typeface.DEFAULT
|
||||
divider2.typeface = Typeface.DEFAULT
|
||||
calendar_temp.typeface = Typeface.DEFAULT
|
||||
//time.typeface = Typeface.DEFAULT
|
||||
}
|
||||
}
|
||||
|
||||
fun updateLocationView() {
|
||||
val locationLayout = SP.getBoolean(Constants.PREF_SHOW_WEATHER, true)
|
||||
|
||||
if (locationLayout && SP.contains(Constants.PREF_WEATHER_TEMP) && SP.contains(Constants.PREF_WEATHER_ICON)) {
|
||||
weather.visibility = View.VISIBLE
|
||||
calendar_weather.visibility = View.VISIBLE
|
||||
val currentTemp = String.format(Locale.getDefault(), "%.0f °%s", SP.getFloat(Constants.PREF_WEATHER_TEMP, 0f), SP.getString(Constants.PREF_WEATHER_REAL_TEMP_UNIT, "F"))
|
||||
|
||||
|
||||
weather_icon.visibility = View.VISIBLE
|
||||
empty_weather_icon.visibility = View.VISIBLE
|
||||
val icon: String = SP.getString(Constants.PREF_WEATHER_ICON, "")
|
||||
if (icon.equals("")) {
|
||||
weather_icon.visibility = View.GONE
|
||||
empty_weather_icon.visibility = View.GONE
|
||||
} else {
|
||||
weather_icon.setImageResource(WeatherUtil.getWeatherIconResource(icon))
|
||||
empty_weather_icon.setImageResource(WeatherUtil.getWeatherIconResource(icon))
|
||||
}
|
||||
|
||||
temp.text = currentTemp
|
||||
calendar_temp.text = currentTemp
|
||||
} else {
|
||||
weather.visibility = View.GONE
|
||||
calendar_weather.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
fun updateSettings() {
|
||||
|
||||
if (SP.getBoolean(Constants.PREF_SHOW_CLOCK, false)) {
|
||||
clock_settings.visibility = View.VISIBLE
|
||||
action_show_clock.setOnClickListener {
|
||||
SP.edit()
|
||||
.putBoolean(Constants.PREF_SHOW_CLOCK, false)
|
||||
.commit()
|
||||
sendBroadcast(Intent(Constants.ACTION_TIME_UPDATE))
|
||||
}
|
||||
show_clock_label.text = getString(R.string.show_clock_visible)
|
||||
} else {
|
||||
clock_settings.visibility= View.GONE
|
||||
action_show_clock.setOnClickListener {
|
||||
SP.edit()
|
||||
.putBoolean(Constants.PREF_SHOW_CLOCK, true)
|
||||
.commit()
|
||||
sendBroadcast(Intent(Constants.ACTION_TIME_UPDATE))
|
||||
}
|
||||
show_clock_label.text = getString(R.string.show_clock_not_visible)
|
||||
}
|
||||
|
||||
|
||||
if (SP.getBoolean(Constants.PREF_SHOW_EVENTS, true) && Util.checkGrantedPermission(this, Manifest.permission.READ_CALENDAR)) {
|
||||
calendar_settings.visibility = View.VISIBLE
|
||||
action_show_events.setOnClickListener {
|
||||
SP.edit()
|
||||
.putBoolean(Constants.PREF_SHOW_EVENTS, false)
|
||||
.commit()
|
||||
sendBroadcast(Intent(Constants.ACTION_CALENDAR_UPDATE))
|
||||
updateSettings()
|
||||
updateAppWidget()
|
||||
}
|
||||
show_events_label.text = getString(R.string.show_events_visible)
|
||||
} else {
|
||||
calendar_settings.visibility= View.GONE
|
||||
action_show_events.setOnClickListener {
|
||||
if (Util.checkGrantedPermission(this, Manifest.permission.READ_CALENDAR)) {
|
||||
SP.edit()
|
||||
.putBoolean(Constants.PREF_SHOW_EVENTS, true)
|
||||
.commit()
|
||||
sendBroadcast(Intent(Constants.ACTION_CALENDAR_UPDATE))
|
||||
updateSettings()
|
||||
updateAppWidget()
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(this@MainActivity, arrayOf(Manifest.permission.READ_CALENDAR), Constants.CALENDAR_REQUEST_CODE)
|
||||
}
|
||||
}
|
||||
show_events_label.text = if (Util.checkGrantedPermission(this, Manifest.permission.READ_CALENDAR)) getString(R.string.show_events_not_visible) else getString(R.string.description_permission_calendar)
|
||||
}
|
||||
|
||||
if (SP.getBoolean(Constants.PREF_SHOW_WEATHER, true) && Util.checkGrantedPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
|
||||
weather_settings.visibility = View.VISIBLE
|
||||
action_show_weather.setOnClickListener {
|
||||
SP.edit()
|
||||
.putBoolean(Constants.PREF_SHOW_WEATHER, false)
|
||||
.commit()
|
||||
sendBroadcast(Intent(Constants.ACTION_WEATHER_UPDATE))
|
||||
updateSettings()
|
||||
updateAppWidget()
|
||||
}
|
||||
show_weather_label.text = getString(R.string.show_weather_visible)
|
||||
} else {
|
||||
weather_settings.visibility= View.GONE
|
||||
action_show_weather.setOnClickListener {
|
||||
if (Util.checkGrantedPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
|
||||
SP.edit()
|
||||
.putBoolean(Constants.PREF_SHOW_WEATHER, true)
|
||||
.commit()
|
||||
sendBroadcast(Intent(Constants.ACTION_WEATHER_UPDATE))
|
||||
updateSettings()
|
||||
updateAppWidget()
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(this@MainActivity, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), Constants.LOCATION_REQUEST_CODE)
|
||||
}
|
||||
}
|
||||
show_weather_label.text = if (Util.checkGrantedPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)) getString(R.string.show_weather_not_visible) else getString(R.string.description_permission_location)
|
||||
}
|
||||
|
||||
temp_unit.text = if (SP.getString(Constants.PREF_WEATHER_TEMP_UNIT, "F").equals("F")) getString(R.string.fahrenheit) else getString(R.string.celsius)
|
||||
action_change_unit.setOnClickListener {
|
||||
SP.edit().putString(Constants.PREF_WEATHER_TEMP_UNIT, if (SP.getString(Constants.PREF_WEATHER_TEMP_UNIT, "F").equals("F")) "C" else "F").commit()
|
||||
sendBroadcast(Intent(Constants.ACTION_WEATHER_UPDATE))
|
||||
updateSettings()
|
||||
}
|
||||
|
||||
all_day_label.text = if (SP.getBoolean(Constants.PREF_CALENDAR_ALL_DAY, false)) getString(R.string.settings_all_day_subtitle_visible) else getString(R.string.settings_all_day_subtitle_gone)
|
||||
action_show_all_day.setOnClickListener {
|
||||
SP.edit().putBoolean(Constants.PREF_CALENDAR_ALL_DAY, !SP.getBoolean(Constants.PREF_CALENDAR_ALL_DAY, false)).commit()
|
||||
sendBroadcast(Intent(Constants.ACTION_CALENDAR_UPDATE))
|
||||
updateSettings()
|
||||
}
|
||||
|
||||
show_multiple_events_label.text = if (SP.getBoolean(Constants.PREF_SHOW_NEXT_EVENT, true)) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||
action_show_multiple_events.setOnClickListener {
|
||||
SP.edit().putBoolean(Constants.PREF_SHOW_NEXT_EVENT, !SP.getBoolean(Constants.PREF_SHOW_NEXT_EVENT, true)).commit()
|
||||
sendBroadcast(Intent(Constants.ACTION_TIME_UPDATE))
|
||||
updateSettings()
|
||||
}
|
||||
|
||||
show_diff_time_label.text = if (SP.getBoolean(Constants.PREF_SHOW_DIFF_TIME, true)) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||
action_show_diff_time.setOnClickListener {
|
||||
SP.edit().putBoolean(Constants.PREF_SHOW_DIFF_TIME, !SP.getBoolean(Constants.PREF_SHOW_DIFF_TIME, true)).commit()
|
||||
sendBroadcast(Intent(Constants.ACTION_TIME_UPDATE))
|
||||
updateSettings()
|
||||
}
|
||||
|
||||
show_declined_events_label.text = if (SP.getBoolean(Constants.PREF_SHOW_DECLINED_EVENTS, true)) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||
action_show_declined_events.setOnClickListener {
|
||||
SP.edit().putBoolean(Constants.PREF_SHOW_DECLINED_EVENTS, !SP.getBoolean(Constants.PREF_SHOW_DECLINED_EVENTS, true)).commit()
|
||||
sendBroadcast(Intent(Constants.ACTION_CALENDAR_UPDATE))
|
||||
updateSettings()
|
||||
}
|
||||
|
||||
hour_format_label.text = if (SP.getString(Constants.PREF_HOUR_FORMAT, "12").equals("12")) getString(R.string.settings_hour_format_subtitle_12) else getString(R.string.settings_hour_format_subtitle_24)
|
||||
action_hour_format.setOnClickListener {
|
||||
SP.edit().putString(Constants.PREF_HOUR_FORMAT, if (SP.getString(Constants.PREF_HOUR_FORMAT, "12").equals("12")) "24" else "12").commit()
|
||||
Util.updateWidget(this)
|
||||
updateSettings()
|
||||
updateAppWidget()
|
||||
}
|
||||
|
||||
second_row_info_label.text = getString(Util.getSecondRowInfoString(SP.getInt(Constants.PREF_SECOND_ROW_INFORMATION, 0)))
|
||||
action_second_row_info.setOnClickListener {
|
||||
SP.edit().putInt(Constants.PREF_SECOND_ROW_INFORMATION, when (SP.getInt(Constants.PREF_SECOND_ROW_INFORMATION, 0)) {
|
||||
0 -> 1
|
||||
1 -> 2
|
||||
2 -> 0
|
||||
else -> 0
|
||||
}).commit()
|
||||
updateSettings()
|
||||
sendBroadcast(Intent(Constants.ACTION_TIME_UPDATE))
|
||||
}
|
||||
|
||||
main_text_size_label.text = String.format("%.0f%s", SP.getFloat(Constants.PREF_TEXT_MAIN_SIZE, 24f), "sp")
|
||||
action_main_text_size.setOnClickListener {
|
||||
var fontSize = SP.getFloat(Constants.PREF_TEXT_MAIN_SIZE, 24f) + 1
|
||||
if (fontSize > 36) {
|
||||
fontSize = 20f
|
||||
}
|
||||
SP.edit().putFloat(Constants.PREF_TEXT_MAIN_SIZE, fontSize).commit()
|
||||
Util.updateWidget(this)
|
||||
updateSettings()
|
||||
updateAppWidget()
|
||||
}
|
||||
|
||||
second_text_size_label.text = String.format("%.0f%s", SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f), "sp")
|
||||
action_second_text_size.setOnClickListener {
|
||||
var fontSize = SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f) + 1
|
||||
if (fontSize > 28) {
|
||||
fontSize = 12f
|
||||
}
|
||||
SP.edit().putFloat(Constants.PREF_TEXT_SECOND_SIZE, fontSize).commit()
|
||||
Util.updateWidget(this)
|
||||
updateSettings()
|
||||
}
|
||||
|
||||
clock_text_size_label.text = String.format("%.0f%s", SP.getFloat(Constants.PREF_TEXT_CLOCK_SIZE, 90f), "sp")
|
||||
action_clock_text_size.setOnClickListener {
|
||||
var fontSize = SP.getFloat(Constants.PREF_TEXT_CLOCK_SIZE, 90f) + 5
|
||||
if (fontSize > 110) {
|
||||
fontSize = 50f
|
||||
}
|
||||
SP.edit().putFloat(Constants.PREF_TEXT_CLOCK_SIZE, fontSize).commit()
|
||||
Util.updateWidget(this)
|
||||
updateSettings()
|
||||
}
|
||||
|
||||
val textColor = try {
|
||||
Color.parseColor(SP.getString(Constants.PREF_TEXT_COLOR, "#FFFFFF"))
|
||||
} catch (e: Exception) {
|
||||
SP.edit().remove(Constants.PREF_TEXT_COLOR).commit()
|
||||
Color.parseColor(SP.getString(Constants.PREF_TEXT_COLOR, "#FFFFFF"))
|
||||
}
|
||||
font_color_label.text = SP.getString(Constants.PREF_TEXT_COLOR, "#FFFFFF").toUpperCase()
|
||||
action_font_color.setOnClickListener {
|
||||
val cp: ColorPicker = ColorPicker(this@MainActivity, Color.red(textColor), Color.green(textColor), Color.blue(textColor))
|
||||
cp.setOnColorSelected { color ->
|
||||
SP.edit().putString(Constants.PREF_TEXT_COLOR, "#" + Integer.toHexString(color)).commit()
|
||||
Util.updateWidget(this)
|
||||
updateSettings()
|
||||
updateAppWidget()
|
||||
cp.dismiss()
|
||||
}
|
||||
cp.show()
|
||||
}
|
||||
|
||||
val now = Calendar.getInstance()
|
||||
var dateStringValue: String = String.format("%s%s", Constants.engDateFormat.format(now.time)[0].toUpperCase(), Constants.engDateFormat.format(now.time).substring(1))
|
||||
if (SP.getBoolean(Constants.PREF_ITA_FORMAT_DATE, false)) {
|
||||
dateStringValue = String.format("%s%s", Constants.itDateFormat.format(now.time)[0].toUpperCase(), Constants.itDateFormat.format(now.time).substring(1))
|
||||
}
|
||||
date_format_label.text = dateStringValue
|
||||
action_date_format.setOnClickListener {
|
||||
SP.edit().putBoolean(Constants.PREF_ITA_FORMAT_DATE, !SP.getBoolean(Constants.PREF_ITA_FORMAT_DATE, false)).commit()
|
||||
Util.updateWidget(this)
|
||||
updateAppWidget()
|
||||
updateSettings()
|
||||
}
|
||||
|
||||
label_weather_refresh_period.text = getString(Util.getRefreshPeriodString(SP.getInt(Constants.PREF_WEATHER_REFRESH_PERIOD, 1)))
|
||||
action_weather_refresh_period.setOnClickListener {
|
||||
SP.edit().putInt(Constants.PREF_WEATHER_REFRESH_PERIOD, when (SP.getInt(Constants.PREF_WEATHER_REFRESH_PERIOD, 1)) {
|
||||
0 -> 1
|
||||
1 -> 2
|
||||
2 -> 3
|
||||
3 -> 4
|
||||
4 -> 5
|
||||
5 -> 0
|
||||
else -> 1
|
||||
}).commit()
|
||||
updateSettings()
|
||||
WeatherReceiver().setUpdates(this@MainActivity)
|
||||
}
|
||||
|
||||
show_until_label.text = getString(Util.getShowUntilString(SP.getInt(Constants.PREF_SHOW_UNTIL, 1)))
|
||||
action_show_until.setOnClickListener {
|
||||
SP.edit().putInt(Constants.PREF_SHOW_UNTIL, when (SP.getInt(Constants.PREF_SHOW_UNTIL, 1)) {
|
||||
0 -> 1
|
||||
1 -> 2
|
||||
2 -> 3
|
||||
3 -> 4
|
||||
4 -> 5
|
||||
5 -> 6
|
||||
6 -> 7
|
||||
7 -> 0
|
||||
else -> 1
|
||||
}).commit()
|
||||
updateSettings()
|
||||
sendBroadcast(Intent(Constants.ACTION_CALENDAR_UPDATE))
|
||||
}
|
||||
|
||||
text_shadow_label.text = getString(Util.getTextShadowString(SP.getInt(Constants.PREF_TEXT_SHADOW, 1)))
|
||||
action_text_shadow.setOnClickListener {
|
||||
SP.edit().putInt(Constants.PREF_TEXT_SHADOW, when (SP.getInt(Constants.PREF_TEXT_SHADOW, 1)) {
|
||||
0 -> 1
|
||||
1 -> 2
|
||||
2 -> 0
|
||||
else -> 1
|
||||
}).commit()
|
||||
sendBroadcast(Intent(Constants.ACTION_TIME_UPDATE))
|
||||
updateSettings()
|
||||
updateAppWidget()
|
||||
}
|
||||
|
||||
custom_font_label.text = getString(Util.getCustomFontLabel(SP.getInt(Constants.PREF_CUSTOM_FONT, Constants.CUSTOM_FONT_PRODUCT_SANS)))
|
||||
action_custom_font.setOnClickListener {
|
||||
|
||||
SP.edit().putInt(Constants.PREF_CUSTOM_FONT, when (SP.getInt(Constants.PREF_CUSTOM_FONT, Constants.CUSTOM_FONT_PRODUCT_SANS)) {
|
||||
0 -> Constants.CUSTOM_FONT_PRODUCT_SANS
|
||||
Constants.CUSTOM_FONT_PRODUCT_SANS -> 0
|
||||
else -> Constants.CUSTOM_FONT_PRODUCT_SANS
|
||||
}).commit()
|
||||
/*
|
||||
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
||||
intent.type = "* / *" TO FIX WITHOUT SPACE
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
|
||||
try {
|
||||
startActivityForResult(Intent.createChooser(intent, "Select a File to Upload"), Constants.CUSTOM_FONT_CHOOSER_REQUEST_CODE)
|
||||
} catch (ex: android.content.ActivityNotFoundException) {
|
||||
Toast.makeText(this, "Please install a File Manager.", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
*/
|
||||
|
||||
sendBroadcast(Intent(Constants.ACTION_TIME_UPDATE))
|
||||
updateSettings()
|
||||
updateAppWidget()
|
||||
}
|
||||
|
||||
if (SP.getInt(Constants.PREF_WEATHER_PROVIDER, Constants.WEATHER_PROVIDER_GOOGLE_AWARENESS) == Constants.WEATHER_PROVIDER_GOOGLE_AWARENESS) {
|
||||
action_custom_location.visibility = View.GONE
|
||||
} else {
|
||||
label_custom_location.text = SP.getString(Constants.PREF_CUSTOM_LOCATION_ADD, getString(R.string.custom_location_gps))
|
||||
action_custom_location.setOnClickListener {
|
||||
startActivityForResult(Intent(this, CustomLocationActivity::class.java), Constants.RESULT_CODE_CUSTOM_LOCATION)
|
||||
}
|
||||
action_custom_location.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
if (SP.getInt(Constants.PREF_WEATHER_PROVIDER, Constants.WEATHER_PROVIDER_GOOGLE_AWARENESS) == Constants.WEATHER_PROVIDER_GOOGLE_AWARENESS) {
|
||||
label_weather_provider_api_key.text = getString(R.string.provider_google_awareness)
|
||||
alert_icon.visibility = View.GONE
|
||||
} else {
|
||||
if (WeatherUtil.getWeatherProviderKey(this, SP) == ("")) {
|
||||
label_weather_provider_api_key.text = getString(R.string.settings_weather_provider_api_key_subtitle_not_set)
|
||||
alert_icon.visibility = View.VISIBLE
|
||||
} else {
|
||||
label_weather_provider_api_key.text = getString(when (SP.getInt(Constants.PREF_WEATHER_PROVIDER, Constants.WEATHER_PROVIDER_GOOGLE_AWARENESS)) {
|
||||
Constants.WEATHER_PROVIDER_OPEN_WEATHER -> R.string.provider_open_weather
|
||||
else -> R.string.settings_weather_provider_api_key_subtitle_all_set
|
||||
})
|
||||
alert_icon.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
action_weather_provider_api_key.setOnClickListener {
|
||||
startActivityForResult(Intent(this, WeatherProviderActivity::class.java), Constants.WEATHER_PROVIDER_REQUEST_CODE)
|
||||
}
|
||||
|
||||
calendar_app_label.text = SP.getString(Constants.PREF_CALENDAR_APP_NAME, getString(R.string.default_calendar_app))
|
||||
action_calendar_app.setOnClickListener {
|
||||
val i = Intent(this, ChooseApplicationActivity::class.java)
|
||||
i.putExtra("requestCode", Constants.CALENDAR_APP_REQUEST_CODE)
|
||||
startActivityForResult(i, Constants.CALENDAR_APP_REQUEST_CODE)
|
||||
}
|
||||
|
||||
weather_app_label.text = SP.getString(Constants.PREF_WEATHER_APP_NAME, getString(R.string.default_weather_app))
|
||||
action_weather_app.setOnClickListener {
|
||||
startActivityForResult(Intent(this, ChooseApplicationActivity::class.java), Constants.WEATHER_APP_REQUEST_CODE)
|
||||
}
|
||||
|
||||
clock_app_label.text = SP.getString(Constants.PREF_CLOCK_APP_NAME, getString(R.string.default_clock_app))
|
||||
action_clock_app.setOnClickListener {
|
||||
startActivityForResult(Intent(this, ChooseApplicationActivity::class.java), Constants.CLOCK_APP_REQUEST_CODE)
|
||||
}
|
||||
|
||||
event_app_label.text = SP.getString(Constants.PREF_EVENT_APP_NAME, getString(R.string.default_event_app))
|
||||
action_event_app.setOnClickListener {
|
||||
startActivityForResult(Intent(this, ChooseApplicationActivity::class.java), Constants.EVENT_APP_REQUEST_CODE)
|
||||
}
|
||||
|
||||
action_filter_calendar.setOnClickListener {
|
||||
val calendarSelectorList: List<CalendarSelector> = CalendarUtil.getCalendarList(this).map { CalendarSelector(it.id.toInt(), it.displayName, it.accountName) }
|
||||
var calFiltered = SP.getString(Constants.PREF_CALENDAR_FILTER, "")
|
||||
|
||||
if (!calendarSelectorList.isEmpty()) {
|
||||
val calNames = calendarSelectorList.map { if (it.name.equals(it.account_name)) String.format("%s: %s", getString(R.string.main_calendar), it.name) else it.name }.toTypedArray()
|
||||
val calSelected = calendarSelectorList.map { !calFiltered.contains(" " + Integer.toString(it.id) + ",") }.toBooleanArray()
|
||||
|
||||
AlertDialog.Builder(this).setTitle(getString(R.string.settings_filter_calendar_subtitle))
|
||||
.setMultiChoiceItems(calNames, calSelected,
|
||||
DialogInterface.OnMultiChoiceClickListener { dialog, item, isChecked ->
|
||||
val dialogItem: String = String.format(" %s%s", calendarSelectorList.get(item).id, ",")
|
||||
calFiltered = calFiltered.replace(dialogItem, "");
|
||||
if (!isChecked) {
|
||||
calFiltered += dialogItem
|
||||
}
|
||||
})
|
||||
.setPositiveButton(android.R.string.ok, { dialog: DialogInterface, _: Int ->
|
||||
SP.edit().putString(Constants.PREF_CALENDAR_FILTER, calFiltered).commit()
|
||||
sendBroadcast(Intent(Constants.ACTION_CALENDAR_UPDATE))
|
||||
updateSettings()
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
} else {
|
||||
Toast.makeText(this, R.string.calendar_settings_list_error, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,121 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activity
|
||||
|
||||
import android.content.Intent
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import com.anjlab.android.iab.v3.BillingProcessor
|
||||
import com.anjlab.android.iab.v3.TransactionDetails
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.util.Util
|
||||
import kotlinx.android.synthetic.main.activity_support_dev.*
|
||||
|
||||
class SupportDevActivity : AppCompatActivity(), BillingProcessor.IBillingHandler {
|
||||
internal lateinit var bp: BillingProcessor
|
||||
|
||||
internal val BILLING_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAox5CcxuoLJ6CmNS7s6lVQzJ253njKKGF8MoQ/gQ5gEw2Fr03fBvtHpiVMpnjhNLw5NMeIpzRvkVqeQ7BfkC7c0BLCJUqf/fFA11ArQe8na6QKt5O4d+v4sbHtP7mm3GQNPOBaqRzcpFZaiAbfk6mnalo+tzM47GXrQFt5bNSrMctCs7bbChqJfH2cyMW0F8DHWEEeO5xElBmH3lh4FVpwIUTPYJIV3n0yhE3qqRA0WXkDej66g/uAt/rebmMZLmwNwIive5cObU4o41YyKRv2wSAicrv3W40LftzXAOOordIbmzDFN8ksh3VrnESqwCDGG97nZVbPG/+3LD0xHWiRwIDAQAB"
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_support_dev)
|
||||
bp = BillingProcessor(this, BILLING_KEY, this)
|
||||
|
||||
action_website.setOnClickListener {
|
||||
Util.openURI(this, "http://tommasoberlose.com/")
|
||||
}
|
||||
|
||||
action_translate.setOnClickListener {
|
||||
Util.openURI(this, "https://github.com/tommasoberlose/another-widget/blob/master/app/src/main/res/values/strings.xml")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBillingInitialized() {
|
||||
loader.visibility = View.GONE
|
||||
try {
|
||||
val isAvailable = BillingProcessor.isIabServiceAvailable(this)
|
||||
val isOneTimePurchaseSupported = bp.isOneTimePurchaseSupported
|
||||
if (isAvailable && isOneTimePurchaseSupported) {
|
||||
val coffee = bp.getPurchaseListingDetails("donation_coffee")
|
||||
val donuts = bp.getPurchaseListingDetails("donation_donuts")
|
||||
val breakfast = bp.getPurchaseListingDetails("donation_breakfast")
|
||||
val lunch = bp.getPurchaseListingDetails("donation_lunch")
|
||||
val dinner = bp.getPurchaseListingDetails("donation_dinner")
|
||||
|
||||
if (coffee != null) {
|
||||
import_donation_coffee.text = coffee.priceText
|
||||
action_donation_coffee.setOnClickListener {
|
||||
bp.purchase(this, "donation_coffee")
|
||||
}
|
||||
} else {
|
||||
action_donation_coffee.visibility = View.GONE
|
||||
}
|
||||
|
||||
if (donuts != null) {
|
||||
import_donation_donuts.text = donuts.priceText
|
||||
action_donation_donuts.setOnClickListener {
|
||||
bp.purchase(this, "donation_donuts")
|
||||
}
|
||||
} else {
|
||||
action_donation_donuts.visibility = View.GONE
|
||||
}
|
||||
|
||||
if (breakfast != null) {
|
||||
import_donation_breakfast.text = breakfast.priceText
|
||||
action_donation_breakfast.setOnClickListener {
|
||||
bp.purchase(this, "donation_breakfast")
|
||||
}
|
||||
} else {
|
||||
action_donation_breakfast.visibility = View.GONE
|
||||
}
|
||||
|
||||
if (lunch != null) {
|
||||
import_donation_lunch.text = lunch.priceText
|
||||
action_donation_lunch.setOnClickListener {
|
||||
bp.purchase(this, "donation_lunch")
|
||||
}
|
||||
} else {
|
||||
action_donation_lunch.visibility = View.GONE
|
||||
}
|
||||
|
||||
if (dinner != null) {
|
||||
import_donation_dinner.text = dinner.priceText
|
||||
action_donation_dinner.setOnClickListener {
|
||||
bp.purchase(this, "donation_dinner")
|
||||
}
|
||||
} else {
|
||||
action_donation_dinner.visibility = View.GONE
|
||||
}
|
||||
|
||||
products_list.visibility = View.VISIBLE
|
||||
} else {
|
||||
products_card.visibility = View.GONE
|
||||
}
|
||||
} catch (ignored: Exception) {
|
||||
products_card.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPurchaseHistoryRestored() {
|
||||
}
|
||||
|
||||
override fun onProductPurchased(productId: String, details: TransactionDetails?) {
|
||||
Toast.makeText(this, R.string.thanks, Toast.LENGTH_SHORT).show()
|
||||
bp.consumePurchase(productId)
|
||||
}
|
||||
|
||||
override fun onBillingError(errorCode: Int, error: Throwable?) {
|
||||
Toast.makeText(this, R.string.error, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (!bp.handleActivityResult(requestCode, resultCode, data)) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
}
|
||||
|
||||
public override fun onDestroy() {
|
||||
bp.release()
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
@ -1,119 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activity
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.app.AlertDialog
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Build
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.os.Bundle
|
||||
import android.preference.PreferenceManager
|
||||
import android.support.design.widget.BottomSheetDialog
|
||||
import android.text.Editable
|
||||
import android.text.Html
|
||||
import android.text.TextWatcher
|
||||
import android.view.View
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.`object`.Constants
|
||||
import com.tommasoberlose.anotherwidget.util.CalendarUtil
|
||||
import com.tommasoberlose.anotherwidget.util.Util
|
||||
import com.tommasoberlose.anotherwidget.util.WeatherUtil
|
||||
import kotlinx.android.synthetic.main.activity_weather_provider.*
|
||||
import kotlinx.android.synthetic.main.key_time_wait_layout.view.*
|
||||
import kotlinx.android.synthetic.main.main_menu_layout.view.*
|
||||
import kotlinx.android.synthetic.main.provider_info_layout.view.*
|
||||
|
||||
class WeatherProviderActivity : AppCompatActivity() {
|
||||
|
||||
lateinit var SP: SharedPreferences
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_weather_provider)
|
||||
|
||||
SP = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
|
||||
updateUI()
|
||||
|
||||
action_save.setOnClickListener {
|
||||
SP.edit()
|
||||
.putString(WeatherUtil.getWeatherProviderKeyConstant(this, SP), api_key.text.toString())
|
||||
.commit()
|
||||
setResult(Activity.RESULT_OK)
|
||||
finish()
|
||||
}
|
||||
|
||||
api_key.addTextChangedListener(object: TextWatcher {
|
||||
override fun afterTextChanged(text: Editable?) {
|
||||
if (text.toString().equals("") || text.toString().equals(
|
||||
WeatherUtil.getWeatherProviderKey(this@WeatherProviderActivity, SP))) {
|
||||
Util.collapse(button_container)
|
||||
} else {
|
||||
Util.expand(button_container)
|
||||
}
|
||||
}
|
||||
|
||||
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
|
||||
}
|
||||
|
||||
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
|
||||
}
|
||||
})
|
||||
|
||||
action_open_provider.setOnClickListener {
|
||||
Util.openURI(this, "https://home.openweathermap.org/users/sign_up")
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
private fun updateUI() {
|
||||
val currentProvider = SP.getInt(Constants.PREF_WEATHER_PROVIDER, Constants.WEATHER_PROVIDER_GOOGLE_AWARENESS)
|
||||
if (currentProvider == Constants.WEATHER_PROVIDER_GOOGLE_AWARENESS) {
|
||||
api_key_container.visibility = View.GONE
|
||||
content_info.visibility = View.GONE
|
||||
} else {
|
||||
api_key_container.visibility = View.VISIBLE
|
||||
content_info.visibility = View.VISIBLE
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
last_info.text = Html.fromHtml(getString(R.string.api_key_info_all_set), Html.FROM_HTML_MODE_LEGACY)
|
||||
} else {
|
||||
last_info.text = Html.fromHtml(getString(R.string.api_key_info_all_set))
|
||||
}
|
||||
}
|
||||
label_weather_provider.text = when (currentProvider) {
|
||||
Constants.WEATHER_PROVIDER_OPEN_WEATHER -> getString(R.string.provider_open_weather)
|
||||
else -> getString(R.string.provider_google_awareness)
|
||||
}
|
||||
action_change_provider.setOnClickListener {
|
||||
SP.edit()
|
||||
.putInt(Constants.PREF_WEATHER_PROVIDER, when (currentProvider) {
|
||||
Constants.WEATHER_PROVIDER_GOOGLE_AWARENESS -> Constants.WEATHER_PROVIDER_OPEN_WEATHER
|
||||
else -> Constants.WEATHER_PROVIDER_GOOGLE_AWARENESS
|
||||
}).commit()
|
||||
updateUI()
|
||||
}
|
||||
|
||||
Util.collapse(button_container)
|
||||
api_key.setText(WeatherUtil.getWeatherProviderKey(this, SP))
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
val SP = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
if (!SP.getInt(Constants.PREF_WEATHER_PROVIDER, Constants.WEATHER_PROVIDER_GOOGLE_AWARENESS).equals(Constants.WEATHER_PROVIDER_GOOGLE_AWARENESS) && (api_key.text.toString().equals("") || !api_key.text.toString().equals(WeatherUtil.getWeatherProviderKey(this, SP)))) {
|
||||
AlertDialog.Builder(this)
|
||||
.setMessage(getString(R.string.error_weather_api_key))
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(android.R.string.yes, DialogInterface.OnClickListener { _,_ ->
|
||||
super.onBackPressed()
|
||||
})
|
||||
.show()
|
||||
} else {
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.util.EventLog
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.`object`.AppInfoSavedEvent
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Created by tommaso on 15/10/17.
|
||||
*/
|
||||
class ApplicationInfoAdapter (private val context: Context, private var mDataset: ArrayList<ApplicationInfo>) : RecyclerView.Adapter<ApplicationInfoAdapter.ViewHolder>() {
|
||||
|
||||
class ViewHolder(var view: View, var text: TextView, var icon: ImageView) : RecyclerView.ViewHolder(view)
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val v = LayoutInflater.from(parent.context).inflate(R.layout.application_info_layout, parent, false)
|
||||
return ViewHolder(v, v.findViewById(R.id.text), v.findViewById(R.id.icon))
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val pm = context.packageManager
|
||||
val app = mDataset[position]
|
||||
holder.text.text = pm.getApplicationLabel(app).toString()
|
||||
try {
|
||||
holder.icon.setImageDrawable(app.loadIcon(pm))
|
||||
} catch (ignore: Exception) {
|
||||
}
|
||||
|
||||
holder.view.setOnClickListener {
|
||||
EventBus.getDefault().post(AppInfoSavedEvent(app))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return mDataset.size
|
||||
}
|
||||
|
||||
fun changeData(newData: ArrayList<ApplicationInfo>) {
|
||||
mDataset = newData
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
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.*
|
||||
|
||||
class ViewPagerAdapter(fragmentActivity: FragmentActivity) :
|
||||
FragmentStateAdapter(fragmentActivity) {
|
||||
|
||||
override fun getItemCount(): Int = 5
|
||||
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
return when (position) {
|
||||
1 -> CalendarSettingsFragment.newInstance()
|
||||
2 -> WeatherSettingsFragment.newInstance()
|
||||
3 -> ClockSettingsFragment.newInstance()
|
||||
4 -> AdvancedSettingsFragment.newInstance()
|
||||
else -> GeneralSettingsFragment.newInstance()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,175 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.fragments
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.karumi.dexter.Dexter
|
||||
import com.karumi.dexter.MultiplePermissionsReport
|
||||
import com.karumi.dexter.PermissionToken
|
||||
import com.karumi.dexter.listener.PermissionRequest
|
||||
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||
import com.tommasoberlose.anotherwidget.databinding.FragmentAdvancedSettingsBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
||||
import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver
|
||||
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.utils.CalendarUtil
|
||||
import com.tommasoberlose.anotherwidget.utils.Util
|
||||
import com.tommasoberlose.anotherwidget.utils.openURI
|
||||
import kotlinx.android.synthetic.main.fragment_advanced_settings.*
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
class AdvancedSettingsFragment : Fragment() {
|
||||
|
||||
companion object {
|
||||
fun newInstance() = AdvancedSettingsFragment()
|
||||
}
|
||||
|
||||
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<FragmentAdvancedSettingsBinding>(inflater, R.layout.fragment_advanced_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: FragmentAdvancedSettingsBinding,
|
||||
viewModel: MainViewModel
|
||||
) {
|
||||
viewModel.darkThemePreference.observe(viewLifecycleOwner, Observer {
|
||||
AppCompatDelegate.setDefaultNightMode(it)
|
||||
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)
|
||||
AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM -> getString(R.string.settings_subtitle_dark_theme_follow_system)
|
||||
else -> ""
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.showWallpaper.observe(viewLifecycleOwner, Observer {
|
||||
show_wallpaper_label.text = if (it && requireActivity().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||
})
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
action_change_theme.setOnClickListener {
|
||||
maintainScrollPosition {
|
||||
BottomSheetMenu<Int>(requireContext())
|
||||
.selectResource(Preferences.darkThemePreference)
|
||||
.addItem(
|
||||
getString(R.string.settings_subtitle_dark_theme_light),
|
||||
AppCompatDelegate.MODE_NIGHT_NO
|
||||
)
|
||||
.addItem(
|
||||
getString(R.string.settings_subtitle_dark_theme_dark),
|
||||
AppCompatDelegate.MODE_NIGHT_YES
|
||||
)
|
||||
.addItem(
|
||||
getString(R.string.settings_subtitle_dark_theme_default),
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM else AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY
|
||||
)
|
||||
.addOnSelectItemListener { value ->
|
||||
Preferences.darkThemePreference = value
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
action_show_wallpaper.setOnClickListener {
|
||||
maintainScrollPosition {
|
||||
if (Preferences.showWallpaper) {
|
||||
Preferences.showWallpaper = false
|
||||
} else {
|
||||
requirePermission()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action_translate.setOnClickListener {
|
||||
activity?.openURI("https://github.com/tommasoberlose/another-widget/blob/master/app/src/main/res/values/strings.xml")
|
||||
}
|
||||
|
||||
action_website.setOnClickListener {
|
||||
activity?.openURI("http://tommasoberlose.com/")
|
||||
}
|
||||
|
||||
action_help_dev.setOnClickListener {
|
||||
startActivity(Intent(requireContext(), SupportDevActivity::class.java))
|
||||
}
|
||||
|
||||
action_refresh_widget.setOnClickListener {
|
||||
Util.updateWidget(requireContext())
|
||||
CalendarUtil.updateEventList(requireContext())
|
||||
}
|
||||
}
|
||||
|
||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||
val scrollPosition = scrollView.scrollY
|
||||
callback.invoke()
|
||||
lifecycleScope.launch {
|
||||
delay(200)
|
||||
scrollView.smoothScrollTo(0, scrollPosition)
|
||||
}
|
||||
}
|
||||
|
||||
private fun requirePermission() {
|
||||
Dexter.withContext(requireContext())
|
||||
.withPermissions(
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
).withListener(object: MultiplePermissionsListener {
|
||||
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
||||
report?.let {
|
||||
Preferences.showWallpaper = report.areAllPermissionsGranted()
|
||||
}
|
||||
}
|
||||
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()
|
||||
}
|
||||
}
|
@ -0,0 +1,330 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.fragments
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.SimpleAdapter
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
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.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.utils.CalendarUtil
|
||||
import com.tommasoberlose.anotherwidget.utils.Util
|
||||
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.android.synthetic.main.fragment_weather_settings.*
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class CalendarSettingsFragment : Fragment() {
|
||||
|
||||
companion object {
|
||||
fun newInstance() = CalendarSettingsFragment()
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
setupListener()
|
||||
}
|
||||
|
||||
private fun subscribeUi(
|
||||
binding: FragmentCalendarSettingsBinding,
|
||||
viewModel: MainViewModel
|
||||
) {
|
||||
viewModel.showEvents.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
binding.isCalendarEnabled = it
|
||||
}
|
||||
checkReadEventsPermission()
|
||||
})
|
||||
|
||||
viewModel.calendarAllDay.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
all_day_label.text =
|
||||
if (it) getString(R.string.settings_all_day_subtitle_visible) else getString(R.string.settings_all_day_subtitle_gone)
|
||||
}
|
||||
checkReadEventsPermission()
|
||||
})
|
||||
|
||||
viewModel.showDeclinedEvents.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
show_declined_events_label.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||
}
|
||||
checkReadEventsPermission()
|
||||
})
|
||||
|
||||
viewModel.secondRowInformation.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
second_row_info_label.text = getString(Util.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)
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.showUntil.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
show_until_label.text = getString(Util.getShowUntilString(it))
|
||||
}
|
||||
checkReadEventsPermission()
|
||||
})
|
||||
|
||||
viewModel.showNextEvent.observe(viewLifecycleOwner, Observer {
|
||||
show_multiple_events_label.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||
})
|
||||
|
||||
viewModel.dateFormat.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
val now = Calendar.getInstance()
|
||||
var dateStringValue: String = String.format("%s%s", SimpleDateFormat(Constants.engDateFormat, Locale.getDefault()).format(now.time)[0].toUpperCase(), SimpleDateFormat(Constants.engDateFormat, Locale.getDefault()).format(now.time).substring(1))
|
||||
if (it) {
|
||||
dateStringValue = String.format("%s%s", SimpleDateFormat(Constants.itDateFormat, Locale.getDefault()).format(now.time)[0].toUpperCase(), SimpleDateFormat(Constants.itDateFormat, Locale.getDefault()).format(now.time).substring(1))
|
||||
}
|
||||
date_format_label.text = dateStringValue
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.calendarAppName.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
calendar_app_label.text = if (it != "") it else getString(R.string.default_calendar_app)
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.eventAppName.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
event_app_label.text = if (it != "") it else getString(R.string.default_calendar_app)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
|
||||
action_show_events.setOnClickListener {
|
||||
Preferences.showEvents = !Preferences.showEvents
|
||||
}
|
||||
|
||||
action_filter_calendar.setOnClickListener {
|
||||
val calendarSelectorList: List<CalendarSelector> = CalendarUtil.getCalendarList(requireContext()).map { CalendarSelector(it.id.toInt(), it.displayName, it.accountName) }
|
||||
var calFiltered = Preferences.calendarFilter
|
||||
|
||||
if (calendarSelectorList.isNotEmpty()) {
|
||||
val calNames = calendarSelectorList.map { if (it.name == it.account_name) String.format("%s: %s", getString(R.string.main_calendar), it.name) else it.name }.toTypedArray()
|
||||
val calSelected = calendarSelectorList.map { !calFiltered.contains(" " + it.id.toString() + ",") }.toBooleanArray()
|
||||
|
||||
AlertDialog.Builder(requireContext()).setTitle(getString(R.string.settings_filter_calendar_subtitle))
|
||||
.setMultiChoiceItems(calNames, calSelected) { _, item, isChecked ->
|
||||
val dialogItem: String = String.format(" %s%s", calendarSelectorList.get(item).id, ",")
|
||||
calFiltered = calFiltered.replace(dialogItem, "");
|
||||
if (!isChecked) {
|
||||
calFiltered += dialogItem
|
||||
}
|
||||
}
|
||||
.setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int ->
|
||||
Preferences.calendarFilter = calFiltered
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
} else {
|
||||
requireActivity().toast(getString(R.string.calendar_settings_list_error))
|
||||
}
|
||||
}
|
||||
|
||||
action_show_all_day.setOnClickListener {
|
||||
if (Preferences.showEvents) {
|
||||
BottomSheetMenu<Boolean>(requireContext()).selectResource(Preferences.calendarAllDay)
|
||||
.addItem(getString(R.string.settings_all_day_subtitle_visible), true)
|
||||
.addItem(getString(R.string.settings_all_day_subtitle_gone), false)
|
||||
.addOnSelectItemListener { value ->
|
||||
Preferences.calendarAllDay = value
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
action_show_declined_events.setOnClickListener {
|
||||
if (Preferences.showEvents) {
|
||||
BottomSheetMenu<Boolean>(requireContext()).selectResource(Preferences.showDeclinedEvents)
|
||||
.addItem(getString(R.string.settings_visible), true)
|
||||
.addItem(getString(R.string.settings_not_visible), false)
|
||||
.addOnSelectItemListener { value ->
|
||||
Preferences.showDeclinedEvents = value
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
action_show_multiple_events.setOnClickListener {
|
||||
if (Preferences.showEvents) {
|
||||
BottomSheetMenu<Boolean>(requireContext()).selectResource(Preferences.showNextEvent)
|
||||
.addItem(getString(R.string.settings_visible), true)
|
||||
.addItem(getString(R.string.settings_not_visible), false)
|
||||
.addOnSelectItemListener { value ->
|
||||
Preferences.showNextEvent = value
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
action_show_diff_time.setOnClickListener {
|
||||
if (Preferences.showEvents) {
|
||||
BottomSheetMenu<Boolean>(requireContext()).selectResource(Preferences.showDiffTime)
|
||||
.addItem(getString(R.string.settings_visible), true)
|
||||
.addItem(getString(R.string.settings_not_visible), false)
|
||||
.addOnSelectItemListener { value ->
|
||||
Preferences.showDiffTime = value
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
action_second_row_info.setOnClickListener {
|
||||
if (Preferences.showEvents) {
|
||||
val dialog = BottomSheetMenu<Int>(requireContext()).selectResource(Preferences.secondRowInformation)
|
||||
(0 .. 1).forEach {
|
||||
dialog.addItem(getString(Util.getSecondRowInfoString(it)), it)
|
||||
}
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
Preferences.secondRowInformation = value
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
action_show_until.setOnClickListener {
|
||||
if (Preferences.showEvents) {
|
||||
val dialog = BottomSheetMenu<Int>(requireContext()).selectResource(Preferences.showUntil)
|
||||
intArrayOf(6,7,0,1,2,3,4,5).forEach {
|
||||
dialog.addItem(getString(Util.getShowUntilString(it)), it)
|
||||
}
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
Preferences.showUntil = value
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
action_event_app.setOnClickListener {
|
||||
startActivityForResult(Intent(requireContext(), ChooseApplicationActivity::class.java), RequestCode.EVENT_APP_REQUEST_CODE.code)
|
||||
}
|
||||
|
||||
action_calendar_app.setOnClickListener {
|
||||
startActivityForResult(Intent(requireContext(), ChooseApplicationActivity::class.java), RequestCode.CALENDAR_APP_REQUEST_CODE.code)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkReadEventsPermission(showEvents: Boolean = Preferences.showEvents) {
|
||||
if (requireActivity().checkCallingOrSelfPermission(Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_GRANTED) {
|
||||
show_events_label.text = if (showEvents) getString(R.string.show_events_visible) else getString(R.string.show_events_not_visible)
|
||||
read_calendar_permission_alert_icon.isVisible = false
|
||||
CalendarUtil.updateEventList(requireContext())
|
||||
} 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_icon.isVisible = showEvents
|
||||
read_calendar_permission_alert_icon.setOnClickListener {
|
||||
requirePermission()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun requirePermission() {
|
||||
Dexter.withContext(requireActivity())
|
||||
.withPermissions(
|
||||
Manifest.permission.READ_CALENDAR
|
||||
).withListener(object: MultiplePermissionsListener {
|
||||
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
||||
report?.let {
|
||||
if (report.areAllPermissionsGranted()){
|
||||
checkReadEventsPermission()
|
||||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
val scrollPosition = scrollView.scrollY
|
||||
callback.invoke()
|
||||
lifecycleScope.launch {
|
||||
delay(200)
|
||||
scrollView.smoothScrollTo(0, scrollPosition)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.fragments
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.chibatching.kotpref.bulk
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||
import com.tommasoberlose.anotherwidget.databinding.FragmentCalendarSettingsBinding
|
||||
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.ui.activities.ChooseApplicationActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||
import com.tommasoberlose.anotherwidget.utils.Util
|
||||
import com.tommasoberlose.anotherwidget.utils.toast
|
||||
import kotlinx.android.synthetic.main.fragment_clock_settings.*
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ClockSettingsFragment : Fragment() {
|
||||
|
||||
companion object {
|
||||
fun newInstance() = ClockSettingsFragment()
|
||||
}
|
||||
|
||||
private lateinit var viewModel: MainViewModel
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
|
||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||
val binding = DataBindingUtil.inflate<FragmentClockSettingsBinding>(inflater, R.layout.fragment_clock_settings, container, false)
|
||||
|
||||
subscribeUi(binding, viewModel)
|
||||
|
||||
binding.lifecycleOwner = this
|
||||
binding.viewModel = viewModel
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
|
||||
setupListener()
|
||||
}
|
||||
|
||||
private fun subscribeUi(
|
||||
binding: FragmentClockSettingsBinding,
|
||||
viewModel: MainViewModel
|
||||
) {
|
||||
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.showNextAlarm.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
show_next_alarm_label.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.clockAppName.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
clock_app_label.text =
|
||||
if (Preferences.clockAppName != "") Preferences.clockAppName else getString(R.string.default_clock_app)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
action_show_clock.setOnClickListener {
|
||||
Preferences.showClock = !Preferences.showClock
|
||||
}
|
||||
|
||||
action_clock_text_size.setOnClickListener {
|
||||
val dialog = BottomSheetMenu<Float>(requireContext()).selectResource(Preferences.clockTextSize)
|
||||
(46 downTo 28).filter { it % 2 == 0 }.forEach {
|
||||
dialog.addItem("${it}sp", it.toFloat())
|
||||
}
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
Preferences.clockTextSize = value
|
||||
}.show()
|
||||
}
|
||||
|
||||
action_show_next_alarm.setOnClickListener {
|
||||
BottomSheetMenu<Boolean>(requireContext()).selectResource(Preferences.showNextAlarm)
|
||||
.addItem(getString(R.string.settings_visible), true)
|
||||
.addItem(getString(R.string.settings_not_visible), false)
|
||||
.addOnSelectItemListener { value ->
|
||||
Preferences.showNextAlarm = value
|
||||
}.show()
|
||||
}
|
||||
|
||||
action_clock_app.setOnClickListener {
|
||||
if (Preferences.showClock) {
|
||||
startActivityForResult(Intent(requireActivity(), 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)
|
||||
}
|
||||
|
||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||
val scrollPosition = scrollView.scrollY
|
||||
callback.invoke()
|
||||
lifecycleScope.launch {
|
||||
delay(200)
|
||||
scrollView.smoothScrollTo(0, scrollPosition)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,208 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.fragments
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
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.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||
import com.tommasoberlose.anotherwidget.databinding.FragmentGeneralSettingsBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.global.RequestCode
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||
import com.tommasoberlose.anotherwidget.utils.Util
|
||||
import com.tommasoberlose.anotherwidget.utils.toPixel
|
||||
import com.tommasoberlose.anotherwidget.utils.toast
|
||||
import dev.sasikanth.colorsheet.ColorSheet
|
||||
import kotlinx.android.synthetic.main.fragment_general_settings.*
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
|
||||
|
||||
class GeneralSettingsFragment : Fragment() {
|
||||
|
||||
companion object {
|
||||
fun newInstance() = GeneralSettingsFragment()
|
||||
}
|
||||
|
||||
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<FragmentGeneralSettingsBinding>(inflater, R.layout.fragment_general_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: FragmentGeneralSettingsBinding,
|
||||
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 {
|
||||
try {
|
||||
Color.parseColor(it)
|
||||
} catch (e: Exception) {
|
||||
Preferences.textGlobalColor = "#FFFFFF"
|
||||
}
|
||||
font_color_label.text = it.toUpperCase()
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.textShadow.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
text_shadow_label.text = getString(Util.getTextShadowString(it))
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.customFont.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
custom_font_label.text = getString(Util.getCustomFontLabel(it))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||
val scrollPosition = scrollView.scrollY
|
||||
callback.invoke()
|
||||
lifecycleScope.launch {
|
||||
delay(200)
|
||||
scrollView.smoothScrollTo(0, scrollPosition)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
action_main_text_size.setOnClickListener {
|
||||
val dialog = BottomSheetMenu<Float>(requireContext()).selectResource(Preferences.textMainSize)
|
||||
(32 downTo 20).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()).selectResource(Preferences.textSecondSize)
|
||||
(24 downTo 12).filter { it % 2 == 0 }.forEach {
|
||||
dialog.addItem("${it}sp", it.toFloat())
|
||||
}
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
Preferences.textSecondSize = value
|
||||
}.show()
|
||||
}
|
||||
|
||||
action_font_color.setOnClickListener {
|
||||
val textColor = try {
|
||||
Color.parseColor(Preferences.textGlobalColor)
|
||||
} catch (e: Exception) {
|
||||
Preferences.textGlobalColor = "#FFFFFF"
|
||||
Color.parseColor(Preferences.textGlobalColor)
|
||||
}
|
||||
ColorSheet()
|
||||
.cornerRadius(16.toPixel(requireContext()))
|
||||
.colorPicker(
|
||||
colors = requireActivity().resources.getIntArray(R.array.grey),
|
||||
selectedColor = textColor,
|
||||
listener = { color ->
|
||||
Preferences.textGlobalColor = "#" + Integer.toHexString(color)
|
||||
})
|
||||
.show(requireActivity().supportFragmentManager)
|
||||
}
|
||||
|
||||
action_text_shadow.setOnClickListener {
|
||||
val dialog = BottomSheetMenu<Int>(requireContext()).selectResource(Preferences.textShadow)
|
||||
(2 downTo 0).forEach {
|
||||
dialog.addItem(getString(Util.getTextShadowString(it)), it)
|
||||
}
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
Preferences.textShadow = value
|
||||
}.show()
|
||||
}
|
||||
|
||||
action_custom_font.setOnClickListener {
|
||||
val dialog = BottomSheetMenu<Int>(requireContext()).selectResource(Preferences.customFont)
|
||||
(0..1).forEach {
|
||||
dialog.addItem(getString(Util.getCustomFontLabel(it)), it)
|
||||
}
|
||||
dialog.addOnSelectItemListener { value ->
|
||||
Preferences.customFont = value
|
||||
}.show()
|
||||
|
||||
/*
|
||||
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
||||
intent.type = "* / *" TO FIX WITHOUT SPACE
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
|
||||
try {
|
||||
startActivityForResult(Intent.createChooser(intent, "Select a File to Upload"), Constants.CUSTOM_FONT_CHOOSER_REQUEST_CODE)
|
||||
} catch (ex: android.content.ActivityNotFoundException) {
|
||||
Toast.makeText(this, "Please install a File Manager.", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
RequestCode.CUSTOM_FONT_CHOOSER_REQUEST_CODE.code -> {
|
||||
/*val uri = data.data
|
||||
Log.d("AW", "File Uri: " + uri.toString())
|
||||
val path = Util.getPath(this, uri)
|
||||
Log.d("AW", "File Path: " + path)
|
||||
SP.edit()
|
||||
.putString(Constants.PREF_CUSTOM_FONT_FILE, path)
|
||||
.commit()
|
||||
sendBroadcast(Intent(Constants.ACTION_TIME_UPDATE))
|
||||
updateSettings()*/
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
}
|
@ -0,0 +1,253 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.fragments
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.chibatching.kotpref.bulk
|
||||
import com.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.databinding.FragmentWeatherSettingsBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.global.RequestCode
|
||||
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.utils.Util
|
||||
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 WeatherSettingsFragment : Fragment() {
|
||||
|
||||
companion object {
|
||||
fun newInstance() = WeatherSettingsFragment()
|
||||
}
|
||||
|
||||
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
|
||||
) {
|
||||
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)
|
||||
binding.isWeatherVisible = it
|
||||
}
|
||||
checkLocationPermission()
|
||||
})
|
||||
|
||||
viewModel.weatherProviderApi.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
label_weather_provider_api_key.text =
|
||||
if (it == "") getString(R.string.settings_weather_provider_api_key_subtitle_not_set) else getString(
|
||||
R.string.settings_weather_provider_api_key_subtitle_all_set
|
||||
)
|
||||
api_key_alert_icon.isVisible = it == ""
|
||||
}
|
||||
checkLocationPermission()
|
||||
})
|
||||
|
||||
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)
|
||||
}
|
||||
})
|
||||
|
||||
viewModel.weatherRefreshPeriod.observe(viewLifecycleOwner, Observer {
|
||||
maintainScrollPosition {
|
||||
label_weather_refresh_period.text = getString(Util.getRefreshPeriodString(it))
|
||||
}
|
||||
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().checkCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
|
||||
location_permission_alert_icon.isVisible = false
|
||||
WeatherReceiver.setUpdates(requireContext())
|
||||
} else if (Preferences.showWeather && Preferences.customLocationAdd == "") {
|
||||
location_permission_alert_icon.isVisible = true
|
||||
location_permission_alert_icon.setOnClickListener {
|
||||
requirePermission()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
|
||||
action_show_weather.setOnClickListener {
|
||||
Preferences.showWeather = !Preferences.showWeather
|
||||
}
|
||||
|
||||
action_weather_provider_api_key.setOnClickListener {
|
||||
if (Preferences.showWeather) {
|
||||
startActivityForResult(
|
||||
Intent(requireContext(), WeatherProviderActivity::class.java),
|
||||
RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
action_custom_location.setOnClickListener {
|
||||
if (Preferences.showWeather) {
|
||||
startActivityForResult(
|
||||
Intent(requireContext(), CustomLocationActivity::class.java),
|
||||
Constants.RESULT_CODE_CUSTOM_LOCATION
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
action_change_unit.setOnClickListener {
|
||||
if (Preferences.showWeather) {
|
||||
BottomSheetMenu<String>(requireContext()).selectResource(Preferences.weatherTempUnit)
|
||||
.addItem(getString(R.string.fahrenheit), "F")
|
||||
.addItem(getString(R.string.celsius), "C")
|
||||
.addOnSelectItemListener { value ->
|
||||
Preferences.weatherTempUnit = value
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
action_weather_refresh_period.setOnClickListener {
|
||||
if (Preferences.showWeather) {
|
||||
val dialog =
|
||||
BottomSheetMenu<Int>(requireContext()).selectResource(Preferences.weatherRefreshPeriod)
|
||||
(5 downTo 0).forEach {
|
||||
dialog.addItem(getString(Util.getRefreshPeriodString(it)), it)
|
||||
}
|
||||
dialog
|
||||
.addOnSelectItemListener { value ->
|
||||
Preferences.weatherRefreshPeriod = value
|
||||
}.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())
|
||||
}
|
||||
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) ?: ""
|
||||
}
|
||||
Util.updateWidget(requireContext())
|
||||
}
|
||||
RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code -> {
|
||||
WeatherReceiver.setOneTimeUpdate(requireContext())
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
private fun requirePermission() {
|
||||
Dexter.withContext(requireActivity())
|
||||
.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) {
|
||||
val scrollPosition = scrollView.scrollY
|
||||
callback.invoke()
|
||||
lifecycleScope.launch {
|
||||
delay(200)
|
||||
scrollView.smoothScrollTo(0, scrollPosition)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.view
|
||||
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Typeface
|
||||
import android.text.TextPaint
|
||||
import android.text.style.TypefaceSpan
|
||||
|
||||
class CustomTypefaceSpan(family: String, private val newType: Typeface) : TypefaceSpan(family) {
|
||||
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
applyCustomTypeFace(ds, newType)
|
||||
}
|
||||
|
||||
override fun updateMeasureState(paint: TextPaint) {
|
||||
applyCustomTypeFace(paint, newType)
|
||||
}
|
||||
|
||||
private fun applyCustomTypeFace(paint: Paint, tf: Typeface) {
|
||||
val oldStyle: Int
|
||||
val old = paint.typeface
|
||||
if (old == null) {
|
||||
oldStyle = 0
|
||||
} else {
|
||||
oldStyle = old.style
|
||||
}
|
||||
|
||||
val fake = oldStyle and tf.style.inv()
|
||||
if (fake and Typeface.BOLD != 0) {
|
||||
paint.isFakeBoldText = true
|
||||
}
|
||||
|
||||
if (fake and Typeface.ITALIC != 0) {
|
||||
paint.textSkewX = -0.25f
|
||||
}
|
||||
|
||||
paint.typeface = tf
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.view
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Typeface
|
||||
import android.content.res.TypedArray
|
||||
import android.util.AttributeSet
|
||||
import android.util.Log
|
||||
import android.widget.TextView
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
|
||||
|
||||
/**
|
||||
* Created by tommaso on 12/10/17.
|
||||
*/
|
||||
class TitleTextView : TextView {
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
|
||||
init(context, attrs)
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||
init(context, attrs)
|
||||
}
|
||||
|
||||
constructor(context: Context) : super(context) {}
|
||||
|
||||
fun init(context: Context, attrs: AttributeSet) {
|
||||
try {
|
||||
val ta = context.obtainStyledAttributes(attrs, R.styleable.FontText)
|
||||
|
||||
if (ta != null) {
|
||||
val fontAsset = ta.getString(R.styleable.FontText_typefaceAsset)
|
||||
|
||||
if (fontAsset != null && !fontAsset.isEmpty()) {
|
||||
val tf = Typeface.createFromAsset(getContext().assets, fontAsset)
|
||||
|
||||
if (tf != null)
|
||||
typeface = tf
|
||||
else
|
||||
Log.i("FontText", String.format("Could not create a font from asset: %s", fontAsset))
|
||||
}
|
||||
ta.recycle()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.i("FontText", "Could not create a font from asset")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels
|
||||
|
||||
import android.app.Application
|
||||
import android.content.pm.ApplicationInfo
|
||||
import androidx.databinding.ObservableField
|
||||
import androidx.lifecycle.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class ChooseApplicationViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
val appList: LiveData<List<ApplicationInfo>> = liveData {
|
||||
val app = application.packageManager.getInstalledApplications(0)
|
||||
emit(app)
|
||||
}
|
||||
val searchInput: MutableLiveData<String> = MutableLiveData("")
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels
|
||||
|
||||
import android.app.Application
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.location.Address
|
||||
import android.location.Geocoder
|
||||
import androidx.lifecycle.*
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
|
||||
class CustomLocationViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
val addresses: MutableLiveData<List<Address>> = MutableLiveData(emptyList())
|
||||
val locationInput: MutableLiveData<String> = MutableLiveData(Preferences.customLocationAdd)
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels
|
||||
|
||||
import androidx.lifecycle.*
|
||||
import com.chibatching.kotpref.livedata.asLiveData
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
|
||||
class MainViewModel : ViewModel() {
|
||||
|
||||
// General Settings
|
||||
val textGlobalColor = Preferences.asLiveData(Preferences::textGlobalColor)
|
||||
val textMainSize = Preferences.asLiveData(Preferences::textMainSize)
|
||||
val textSecondSize = Preferences.asLiveData(Preferences::textSecondSize)
|
||||
val textShadow = Preferences.asLiveData(Preferences::textShadow)
|
||||
val customFont = Preferences.asLiveData(Preferences::customFont)
|
||||
val secondRowInformation = Preferences.asLiveData(Preferences::secondRowInformation)
|
||||
|
||||
// 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 calendarAppName = Preferences.asLiveData(Preferences::calendarAppName)
|
||||
|
||||
val eventAppName = Preferences.asLiveData(Preferences::eventAppName)
|
||||
|
||||
|
||||
// Clock Settings
|
||||
val showClock = Preferences.asLiveData(Preferences::showClock)
|
||||
val clockTextSize = Preferences.asLiveData(Preferences::clockTextSize)
|
||||
|
||||
val clockAppName = Preferences.asLiveData(Preferences::clockAppName)
|
||||
val showNextAlarm = Preferences.asLiveData(Preferences::showNextAlarm)
|
||||
val dateFormat = Preferences.asLiveData(Preferences::dateFormat)
|
||||
|
||||
// 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::weatherProviderApi)
|
||||
|
||||
val customLocationAdd = Preferences.asLiveData(Preferences::customLocationAdd)
|
||||
|
||||
// Advanced Settings
|
||||
val darkThemePreference = Preferences.asLiveData(Preferences::darkThemePreference)
|
||||
val showWallpaper = Preferences.asLiveData(Preferences::showWallpaper)
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.android.billingclient.api.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class SupportDevViewModel : ViewModel() {
|
||||
|
||||
lateinit var billingClient: BillingClient
|
||||
val products: MutableLiveData<List<SkuDetails>> = MutableLiveData(emptyList())
|
||||
|
||||
fun openConnection() {
|
||||
|
||||
billingClient.startConnection(object : BillingClientStateListener {
|
||||
override fun onBillingSetupFinished(billingResult: BillingResult) {
|
||||
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
|
||||
val params = SkuDetailsParams.newBuilder()
|
||||
params.setSkusList(listOf("donation_coffee", "donation_donuts", "donation_breakfast", "donation_lunch", "donation_dinner")).setType(BillingClient.SkuType.INAPP)
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val skuDetailsList = billingClient.querySkuDetails(params.build()).skuDetailsList
|
||||
withContext(Dispatchers.Main) {
|
||||
products.value = skuDetailsList
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun onBillingServiceDisconnected() {
|
||||
// Try to restart the connection on the next request to
|
||||
// Google Play by calling the startConnection() method.
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun purchase(activity: Activity, product: SkuDetails) {
|
||||
val flowParams = BillingFlowParams.newBuilder()
|
||||
.setSkuDetails(product)
|
||||
.build()
|
||||
billingClient.launchBillingFlow(activity, flowParams)
|
||||
}
|
||||
|
||||
fun handlePurchase(purchase: Purchase) {
|
||||
if (!purchase.isAcknowledged) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
|
||||
.setPurchaseToken(purchase.purchaseToken)
|
||||
billingClient.acknowledgePurchase(acknowledgePurchaseParams.build())
|
||||
|
||||
val consumeParams =
|
||||
ConsumeParams.newBuilder()
|
||||
.setPurchaseToken(purchase.purchaseToken)
|
||||
.build()
|
||||
billingClient.consumePurchase(consumeParams)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun closeConnection() {
|
||||
billingClient.endConnection()
|
||||
}
|
||||
}
|
@ -1,543 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.widget
|
||||
|
||||
import android.Manifest
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.appwidget.AppWidgetProvider
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.preference.PreferenceManager
|
||||
import android.view.View
|
||||
import android.widget.RemoteViews
|
||||
|
||||
import com.tommasoberlose.anotherwidget.`object`.Constants
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.receiver.UpdatesReceiver
|
||||
import com.tommasoberlose.anotherwidget.util.Util
|
||||
import com.tommasoberlose.anotherwidget.receiver.WeatherReceiver
|
||||
|
||||
import java.util.Calendar
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
import android.app.PendingIntent
|
||||
import android.provider.CalendarContract
|
||||
import android.content.ContentUris
|
||||
import android.util.Log
|
||||
import com.tommasoberlose.anotherwidget.util.CalendarUtil
|
||||
import com.tommasoberlose.anotherwidget.util.WeatherUtil
|
||||
import android.graphics.Typeface
|
||||
import android.net.Uri
|
||||
import android.widget.TextClock
|
||||
import android.widget.TextView
|
||||
import android.content.ComponentName
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.os.Bundle
|
||||
import android.support.v4.content.ContextCompat.startActivity
|
||||
import android.provider.CalendarContract.Events
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableString
|
||||
import android.text.style.RelativeSizeSpan
|
||||
import android.text.style.StyleSpan
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.TypedValue
|
||||
import android.widget.LinearLayout
|
||||
import com.tommasoberlose.anotherwidget.receiver.OpenWeatherIntentReceiver
|
||||
import com.tommasoberlose.anotherwidget.ui.view.CustomTypefaceSpan
|
||||
import kotlinx.android.synthetic.main.the_widget.*
|
||||
import kotlinx.android.synthetic.main.the_widget.view.*
|
||||
import kotlinx.android.synthetic.main.the_widget_sans.view.*
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of App Widget functionality.
|
||||
*/
|
||||
class TheWidget : AppWidgetProvider() {
|
||||
|
||||
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
|
||||
Util.updateSettingsByDefault(context)
|
||||
|
||||
for (appWidgetId in appWidgetIds) {
|
||||
updateAppWidget(context, appWidgetManager, appWidgetId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAppWidgetOptionsChanged(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int, newOptions: Bundle?) {
|
||||
super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions)
|
||||
updateAppWidget(context, appWidgetManager, appWidgetId)
|
||||
}
|
||||
|
||||
override fun onEnabled(context: Context) {
|
||||
UpdatesReceiver().setUpdates(context)
|
||||
WeatherReceiver().setUpdates(context)
|
||||
}
|
||||
|
||||
override fun onDisabled(context: Context) {
|
||||
UpdatesReceiver().removeUpdates(context)
|
||||
WeatherReceiver().removeUpdates(context)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager,
|
||||
appWidgetId: Int) {
|
||||
val SP = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val displayMetrics = Resources.getSystem().displayMetrics
|
||||
var height = Util.convertDpToPixel(110f, context).toInt()
|
||||
val width = displayMetrics.widthPixels
|
||||
if (SP.getBoolean(Constants.PREF_SHOW_CLOCK, false)) {
|
||||
height += Util.convertSpToPixels(SP.getFloat(Constants.PREF_TEXT_CLOCK_SIZE, 90f), context).toInt() + Util.convertDpToPixel(16f, context).toInt()
|
||||
}
|
||||
if (SP.getFloat(Constants.PREF_TEXT_MAIN_SIZE, 24f) > 30 && SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f) > 22) {
|
||||
height += Util.convertDpToPixel(24f, context).toInt()
|
||||
}
|
||||
|
||||
generateWidgetView(context, appWidgetId, appWidgetManager, width - Util.convertDpToPixel(16f, context).toInt(), height)
|
||||
}
|
||||
|
||||
fun generateWidgetView(context: Context, appWidgetId: Int, appWidgetManager: AppWidgetManager, w: Int, h: Int) {
|
||||
var views = RemoteViews(context.packageName, R.layout.the_widget_sans)
|
||||
var v = View.inflate(context, R.layout.the_widget, null)
|
||||
|
||||
val SP = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
views.setTextColor(R.id.empty_date, Util.getFontColor(SP))
|
||||
views.setTextColor(R.id.divider1, Util.getFontColor(PreferenceManager.getDefaultSharedPreferences(context)))
|
||||
views.setTextColor(R.id.temp, Util.getFontColor(PreferenceManager.getDefaultSharedPreferences(context)))
|
||||
views.setTextColor(R.id.next_event, Util.getFontColor(PreferenceManager.getDefaultSharedPreferences(context)))
|
||||
views.setTextColor(R.id.next_event_difference_time, Util.getFontColor(PreferenceManager.getDefaultSharedPreferences(context)))
|
||||
views.setTextColor(R.id.next_event_date, Util.getFontColor(PreferenceManager.getDefaultSharedPreferences(context)))
|
||||
views.setTextColor(R.id.divider2, Util.getFontColor(PreferenceManager.getDefaultSharedPreferences(context)))
|
||||
views.setTextColor(R.id.calendar_temp, Util.getFontColor(PreferenceManager.getDefaultSharedPreferences(context)))
|
||||
//views.setTextColor(R.id.time, Util.getFontColor(PreferenceManager.getDefaultSharedPreferences(context)))
|
||||
|
||||
views.setTextViewTextSize(R.id.empty_date, TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_MAIN_SIZE, 24f))
|
||||
views.setTextViewTextSize(R.id.divider1, TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f))
|
||||
views.setTextViewTextSize(R.id.temp, TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_MAIN_SIZE, 24f))
|
||||
views.setTextViewTextSize(R.id.next_event, TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_MAIN_SIZE, 24f))
|
||||
views.setTextViewTextSize(R.id.next_event_difference_time, TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_MAIN_SIZE, 24f))
|
||||
views.setTextViewTextSize(R.id.next_event_date, TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f))
|
||||
views.setTextViewTextSize(R.id.divider2, TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f))
|
||||
views.setTextViewTextSize(R.id.calendar_temp, TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f))
|
||||
//views.setTextViewTextSize(R.id.time, TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_CLOCK_SIZE, 90f))
|
||||
|
||||
v = updateCalendarViewByLayout(context, v)
|
||||
v = updateLocationViewByLayout(context, v)
|
||||
v = updateClockViewByLayout(context, v)
|
||||
views.setImageViewBitmap(R.id.bitmap_container, Util.getBitmapFromView(v, w, h))
|
||||
|
||||
views = updateCalendarView(context, views, appWidgetId)
|
||||
views = updateLocationView(context, views, appWidgetId)
|
||||
views = updateClockView(context, views, appWidgetId)
|
||||
|
||||
views = fixViewsMargin(context, views)
|
||||
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||
}
|
||||
|
||||
fun updateCalendarView(context: Context, views: RemoteViews, widgetID: Int): RemoteViews {
|
||||
val SP = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val now = Calendar.getInstance()
|
||||
val calendarLayout = SP.getBoolean(Constants.PREF_SHOW_EVENTS, true) && Util.checkGrantedPermission(context, Manifest.permission.READ_CALENDAR)
|
||||
|
||||
views.setViewVisibility(R.id.empty_layout, View.VISIBLE)
|
||||
views.setViewVisibility(R.id.calendar_layout, View.GONE)
|
||||
var dateStringValue: String = Util.getCapWordString(Constants.engDateFormat.format(now.time))
|
||||
if (SP.getBoolean(Constants.PREF_ITA_FORMAT_DATE, false)) {
|
||||
dateStringValue = Util.getCapWordString(Constants.itDateFormat.format(now.time))
|
||||
}
|
||||
views.setTextViewText(R.id.empty_date, dateStringValue)
|
||||
|
||||
|
||||
val calPIntent = PendingIntent.getActivity(context, widgetID, Util.getCalendarIntent(context), 0)
|
||||
views.setOnClickPendingIntent(R.id.empty_date, calPIntent)
|
||||
|
||||
|
||||
if (calendarLayout) {
|
||||
val e = CalendarUtil.getNextEvent(context)
|
||||
|
||||
if (e.id != 0.toLong()) {
|
||||
views.setTextViewText(R.id.next_event, e.title)
|
||||
|
||||
if (SP.getBoolean(Constants.PREF_SHOW_NEXT_EVENT, false) && CalendarUtil.getEventsCount(context) > 1) {
|
||||
val multipleIntent = PendingIntent.getBroadcast(context, widgetID, Intent(Constants.ACTION_GO_TO_NEXT_EVENT), 0)
|
||||
views.setViewVisibility(R.id.multiple_events, View.VISIBLE)
|
||||
views.setOnClickPendingIntent(R.id.multiple_events, multipleIntent)
|
||||
} else {
|
||||
views.setViewVisibility(R.id.multiple_events, View.GONE)
|
||||
}
|
||||
|
||||
val pIntent = PendingIntent.getActivity(context, widgetID, Util.getEventIntent(context, e), 0)
|
||||
views.setOnClickPendingIntent(R.id.next_event, pIntent)
|
||||
views.setOnClickPendingIntent(R.id.next_event_difference_time, pIntent)
|
||||
|
||||
if (SP.getBoolean(Constants.PREF_SHOW_DIFF_TIME, true)) {
|
||||
views.setTextViewText(R.id.next_event_difference_time, Util.getDifferenceText(context, now.timeInMillis, e.startDate))
|
||||
views.setViewVisibility(R.id.next_event_difference_time, View.VISIBLE)
|
||||
} else {
|
||||
views.setViewVisibility(R.id.next_event_difference_time, View.GONE)
|
||||
}
|
||||
|
||||
if (SP.getInt(Constants.PREF_SECOND_ROW_INFORMATION, 0) == 2 && Util.getNextAlarm(context) != null) {
|
||||
val source = BitmapFactory.decodeResource(context.resources, R.drawable.ic_action_alarm);
|
||||
val result = Util.changeBitmapColor(source, Util.getFontColor(SP))
|
||||
views.setImageViewBitmap(R.id.second_row_icon, result)
|
||||
|
||||
views.setTextViewText(R.id.next_event_date, Util.getNextAlarm(context))
|
||||
|
||||
val clockIntent = PendingIntent.getActivity(context, widgetID, Util.getClockIntent(context), 0)
|
||||
views.setOnClickPendingIntent(R.id.next_event_date, clockIntent)
|
||||
} else if (e.address != "" && SP.getInt(Constants.PREF_SECOND_ROW_INFORMATION, 0) == 1) {
|
||||
|
||||
val source = BitmapFactory.decodeResource(context.resources, R.drawable.ic_action_location);
|
||||
val result = Util.changeBitmapColor(source, Util.getFontColor(SP))
|
||||
views.setImageViewBitmap(R.id.second_row_icon, result)
|
||||
|
||||
views.setTextViewText(R.id.next_event_date, e.address)
|
||||
|
||||
val mapIntent = PendingIntent.getActivity(context, widgetID, Util.getGoogleMapsIntentFromAddress(context, e.address), 0)
|
||||
views.setOnClickPendingIntent(R.id.next_event_date, mapIntent)
|
||||
} else {
|
||||
val source = BitmapFactory.decodeResource(context.resources, R.drawable.ic_action_calendar);
|
||||
val result = Util.changeBitmapColor(source, Util.getFontColor(SP))
|
||||
views.setImageViewBitmap(R.id.second_row_icon, result)
|
||||
|
||||
if (!e.allDay) {
|
||||
var startHour = Constants.goodHourFormat.format(e.startDate)
|
||||
var endHour = Constants.goodHourFormat.format(e.endDate)
|
||||
if (SP.getString(Constants.PREF_HOUR_FORMAT, "12").equals("12")) {
|
||||
startHour = Constants.badHourFormat.format(e.startDate)
|
||||
endHour = Constants.badHourFormat.format(e.endDate)
|
||||
}
|
||||
var dayDiff = TimeUnit.MILLISECONDS.toDays(e.endDate - e.startDate)
|
||||
|
||||
val startCal = Calendar.getInstance()
|
||||
startCal.timeInMillis = e.startDate
|
||||
|
||||
val endCal = Calendar.getInstance()
|
||||
endCal.timeInMillis = e.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))
|
||||
}
|
||||
|
||||
views.setTextViewText(R.id.next_event_date, String.format("%s - %s%s", startHour, endHour, multipleDay))
|
||||
} else {
|
||||
views.setTextViewText(R.id.next_event_date, dateStringValue)
|
||||
}
|
||||
|
||||
if (SP.getBoolean(Constants.PREF_SHOW_NEXT_EVENT, false) && CalendarUtil.getEventsCount(context) > 1) {
|
||||
val multipleIntent = PendingIntent.getBroadcast(context, widgetID, Intent(Constants.ACTION_GO_TO_NEXT_EVENT), 0)
|
||||
views.setOnClickPendingIntent(R.id.next_event_date, multipleIntent)
|
||||
} else {
|
||||
views.setOnClickPendingIntent(R.id.next_event_date, pIntent)
|
||||
}
|
||||
}
|
||||
|
||||
views.setViewVisibility(R.id.empty_layout, View.GONE)
|
||||
views.setViewVisibility(R.id.calendar_layout, View.VISIBLE)
|
||||
}
|
||||
}
|
||||
|
||||
return views
|
||||
}
|
||||
|
||||
fun updateLocationView(context: Context, views: RemoteViews, widgetID: Int): RemoteViews {
|
||||
val SP = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val locationLayout = SP.getBoolean(Constants.PREF_SHOW_WEATHER, true)
|
||||
|
||||
if (locationLayout && SP.contains(Constants.PREF_WEATHER_TEMP) && SP.contains(Constants.PREF_WEATHER_ICON)) {
|
||||
views.setViewVisibility(R.id.weather, View.VISIBLE)
|
||||
views.setViewVisibility(R.id.calendar_weather, View.VISIBLE)
|
||||
val temp = String.format(Locale.getDefault(), "%.0f °%s", SP.getFloat(Constants.PREF_WEATHER_TEMP, 0f), SP.getString(Constants.PREF_WEATHER_REAL_TEMP_UNIT, "F"))
|
||||
|
||||
|
||||
views.setViewVisibility(R.id.weather_icon, View.VISIBLE)
|
||||
views.setViewVisibility(R.id.empty_weather_icon, View.VISIBLE)
|
||||
val icon: String = SP.getString(Constants.PREF_WEATHER_ICON, "")
|
||||
if (icon.equals("")) {
|
||||
views.setViewVisibility(R.id.weather_icon, View.GONE)
|
||||
views.setViewVisibility(R.id.empty_weather_icon, View.GONE)
|
||||
} else {
|
||||
views.setImageViewResource(R.id.weather_icon, WeatherUtil.getWeatherIconResource(icon))
|
||||
views.setImageViewResource(R.id.empty_weather_icon, WeatherUtil.getWeatherIconResource(icon))
|
||||
}
|
||||
|
||||
views.setTextViewText(R.id.temp, temp)
|
||||
views.setTextViewText(R.id.calendar_temp, temp)
|
||||
|
||||
val i = Intent(context, OpenWeatherIntentReceiver::class.java)
|
||||
i.action = Constants.ACTION_OPEN_WEATHER_INTENT
|
||||
val weatherPIntent = PendingIntent.getBroadcast(context, widgetID, i, 0)
|
||||
|
||||
views.setOnClickPendingIntent(R.id.weather, weatherPIntent)
|
||||
views.setOnClickPendingIntent(R.id.calendar_weather, weatherPIntent)
|
||||
} else {
|
||||
views.setViewVisibility(R.id.weather, View.GONE)
|
||||
views.setViewVisibility(R.id.calendar_weather, View.GONE)
|
||||
}
|
||||
return views
|
||||
}
|
||||
|
||||
fun updateClockView(context: Context, views: RemoteViews, widgetID: Int): RemoteViews {
|
||||
val SP = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
if (!SP.getBoolean(Constants.PREF_SHOW_CLOCK, false)) {
|
||||
views.setViewVisibility(R.id.time, View.GONE)
|
||||
} else {
|
||||
// val now = Calendar.getInstance()
|
||||
// if (SP.getString(Constants.PREF_HOUR_FORMAT, "12").equals("12")) {
|
||||
// val textBadHour = SpannableString(Constants.badHourFormat.format(now.timeInMillis).replace(" ", ""))
|
||||
// textBadHour.setSpan(RelativeSizeSpan(0.4f), textBadHour.length - 2,
|
||||
// textBadHour.length, Spannable.SPAN_INCLUSIVE_INCLUSIVE)
|
||||
//
|
||||
// views.setTextViewText(R.id.time, textBadHour)
|
||||
// } else {
|
||||
// views.setTextViewText(R.id.time, Constants.goodHourFormat.format(now.timeInMillis))
|
||||
// }
|
||||
|
||||
val clockPIntent = PendingIntent.getActivity(context, widgetID, Util.getClockIntent(context), 0)
|
||||
views.setOnClickPendingIntent(R.id.time, clockPIntent)
|
||||
views.setViewVisibility(R.id.time, View.VISIBLE)
|
||||
}
|
||||
|
||||
return views
|
||||
}
|
||||
|
||||
fun fixViewsMargin(context: Context, views: RemoteViews): RemoteViews {
|
||||
val SP = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
views.setViewVisibility(R.id.bottom_divider_24, View.GONE)
|
||||
views.setViewVisibility(R.id.bottom_divider_16, View.GONE)
|
||||
views.setViewVisibility(R.id.bottom_divider_8, View.GONE)
|
||||
val eVisible = SP.getBoolean(Constants.PREF_SHOW_EVENTS, true) && Util.checkGrantedPermission(context, Manifest.permission.READ_CALENDAR)
|
||||
if (SP.getBoolean(Constants.PREF_SHOW_CLOCK, false)) {
|
||||
if (eVisible) {
|
||||
views.setViewVisibility(R.id.bottom_divider_8, View.VISIBLE)
|
||||
} else {
|
||||
views.setViewVisibility(R.id.bottom_divider_24, View.VISIBLE)
|
||||
}
|
||||
} else {
|
||||
if (eVisible) {
|
||||
views.setViewVisibility(R.id.bottom_divider_8, View.VISIBLE)
|
||||
}
|
||||
}
|
||||
return views
|
||||
}
|
||||
|
||||
fun updateCalendarViewByLayout(context: Context, v: View): View {
|
||||
val SP = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val now = Calendar.getInstance()
|
||||
val calendarLayout = SP.getBoolean(Constants.PREF_SHOW_EVENTS, true) && Util.checkGrantedPermission(context, Manifest.permission.READ_CALENDAR)
|
||||
|
||||
v.empty_layout.visibility = View.VISIBLE
|
||||
v.calendar_layout.visibility = View.GONE
|
||||
var dateStringValue: String = Util.getCapWordString(Constants.engDateFormat.format(now.time))
|
||||
if (SP.getBoolean(Constants.PREF_ITA_FORMAT_DATE, false)) {
|
||||
dateStringValue = Util.getCapWordString(Constants.itDateFormat.format(now.time))
|
||||
}
|
||||
|
||||
v.empty_date.text = dateStringValue
|
||||
|
||||
if (calendarLayout) {
|
||||
val e = CalendarUtil.getNextEvent(context)
|
||||
|
||||
if (e.id != 0.toLong()) {
|
||||
v.next_event.text = e.title
|
||||
|
||||
if (SP.getBoolean(Constants.PREF_SHOW_NEXT_EVENT, false) && CalendarUtil.getEventsCount(context) > 1) {
|
||||
v.multiple_events.visibility = View.VISIBLE
|
||||
} else {
|
||||
v.multiple_events.visibility = View.GONE
|
||||
}
|
||||
|
||||
if (SP.getBoolean(Constants.PREF_SHOW_DIFF_TIME, true)) {
|
||||
v.next_event_difference_time.text = Util.getDifferenceText(context, now.timeInMillis, e.startDate)
|
||||
v.next_event_difference_time.visibility = View.VISIBLE
|
||||
} else {
|
||||
v.next_event_difference_time.visibility = View.GONE
|
||||
}
|
||||
|
||||
if (SP.getInt(Constants.PREF_SECOND_ROW_INFORMATION, 0) == 2 && Util.getNextAlarm(context) != null) {
|
||||
v.second_row_icon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_action_alarm))
|
||||
v.next_event_date.text = Util.getNextAlarm(context)
|
||||
} else if (!e.address.equals("") && SP.getInt(Constants.PREF_SECOND_ROW_INFORMATION, 0) == 1) {
|
||||
v.second_row_icon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_action_location))
|
||||
v.next_event_date.text = e.address
|
||||
} else {
|
||||
v.second_row_icon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_action_calendar))
|
||||
if (!e.allDay) {
|
||||
var startHour = Constants.goodHourFormat.format(e.startDate)
|
||||
var endHour = Constants.goodHourFormat.format(e.endDate)
|
||||
if (SP.getString(Constants.PREF_HOUR_FORMAT, "12").equals("12")) {
|
||||
startHour = Constants.badHourFormat.format(e.startDate)
|
||||
endHour = Constants.badHourFormat.format(e.endDate)
|
||||
}
|
||||
var dayDiff = TimeUnit.MILLISECONDS.toDays(e.endDate - e.startDate)
|
||||
|
||||
val startCal = Calendar.getInstance()
|
||||
startCal.timeInMillis = e.startDate
|
||||
|
||||
val endCal = Calendar.getInstance()
|
||||
endCal.timeInMillis = e.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: String = ""
|
||||
if (dayDiff > 0) {
|
||||
multipleDay = String.format(" (+%s%s)", dayDiff, context.getString(R.string.day_char))
|
||||
}
|
||||
v.next_event_date.text = String.format("%s - %s%s", startHour, endHour, multipleDay)
|
||||
|
||||
} else {
|
||||
v.next_event_date.text = dateStringValue
|
||||
}
|
||||
}
|
||||
|
||||
v.empty_layout.visibility = View.GONE
|
||||
v.calendar_layout.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
v.empty_date.setTextColor(Util.getFontColor(SP))
|
||||
v.divider1.setTextColor(Util.getFontColor(SP))
|
||||
v.temp.setTextColor(Util.getFontColor(SP))
|
||||
v.next_event.setTextColor(Util.getFontColor(SP))
|
||||
v.next_event_difference_time.setTextColor(Util.getFontColor(SP))
|
||||
v.next_event_date.setTextColor(Util.getFontColor(SP))
|
||||
v.divider2.setTextColor(Util.getFontColor(SP))
|
||||
v.calendar_temp.setTextColor(Util.getFontColor(SP))
|
||||
v.second_row_icon.setColorFilter(Util.getFontColor(SP))
|
||||
v.time.setTextColor(Util.getFontColor(SP))
|
||||
v.multiple_events.setColorFilter(Util.getFontColor(SP))
|
||||
|
||||
|
||||
v.empty_date.setTextSize(TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_MAIN_SIZE, 24f))
|
||||
v.divider1.setTextSize(TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f))
|
||||
v.temp.setTextSize(TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_MAIN_SIZE, 24f))
|
||||
v.next_event.setTextSize(TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_MAIN_SIZE, 24f))
|
||||
v.next_event_difference_time.setTextSize(TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_MAIN_SIZE, 24f))
|
||||
v.next_event_date.setTextSize(TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f))
|
||||
v.divider2.setTextSize(TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f))
|
||||
v.calendar_temp.setTextSize(TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f))
|
||||
v.time.setTextSize(TypedValue.COMPLEX_UNIT_SP, SP.getFloat(Constants.PREF_TEXT_CLOCK_SIZE, 90f))
|
||||
|
||||
v.second_row_icon.scaleX = SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f) / 18f
|
||||
v.second_row_icon.scaleY = SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f) / 18f
|
||||
|
||||
v.weather_icon.scaleX = SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f) / 18f
|
||||
v.weather_icon.scaleY = SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f) / 18f
|
||||
|
||||
v.empty_weather_icon.scaleX = SP.getFloat(Constants.PREF_TEXT_MAIN_SIZE, 24f) / 24f
|
||||
v.empty_weather_icon.scaleY = SP.getFloat(Constants.PREF_TEXT_MAIN_SIZE, 24f) / 24f
|
||||
|
||||
v.multiple_events.scaleX = SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f) / 16f
|
||||
v.multiple_events.scaleY = SP.getFloat(Constants.PREF_TEXT_SECOND_SIZE, 16f) / 16f
|
||||
|
||||
val shadowRadius = when (SP.getInt(Constants.PREF_TEXT_SHADOW, 1)) {
|
||||
0 -> 0f
|
||||
1 -> 5f
|
||||
2 -> 5f
|
||||
else -> 5f
|
||||
}
|
||||
val shadowColor = when (SP.getInt(Constants.PREF_TEXT_SHADOW, 1)) {
|
||||
0 -> Color.TRANSPARENT
|
||||
1 -> R.color.black_50
|
||||
2 -> Color.BLACK
|
||||
else -> R.color.black_50
|
||||
}
|
||||
val shadowDy = when (SP.getInt(Constants.PREF_TEXT_SHADOW, 1)) {
|
||||
0 -> 0f
|
||||
1 -> 0f
|
||||
2 -> 1f
|
||||
else -> 0f
|
||||
}
|
||||
v.empty_date.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
|
||||
v.divider1.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
|
||||
v.temp.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
|
||||
v.next_event.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
|
||||
v.next_event_difference_time.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
|
||||
v.next_event_date.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
|
||||
v.divider2.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
|
||||
v.calendar_temp.setShadowLayer(shadowRadius, 0f, 0f, shadowColor)
|
||||
v.time.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
|
||||
|
||||
if (SP.getInt(Constants.PREF_CUSTOM_FONT, Constants.CUSTOM_FONT_PRODUCT_SANS) == Constants.CUSTOM_FONT_PRODUCT_SANS) {
|
||||
val product_sans: Typeface = Typeface.createFromAsset(context.assets, "fonts/product_sans_regular.ttf")
|
||||
val product_sans_light: Typeface = Typeface.createFromAsset(context.assets, "fonts/product_sans_light.ttf")
|
||||
v.empty_date.typeface = product_sans
|
||||
v.divider1.typeface = product_sans
|
||||
v.temp.typeface = product_sans
|
||||
v.next_event.typeface = product_sans
|
||||
v.next_event_difference_time.typeface = product_sans
|
||||
v.next_event_date.typeface = product_sans
|
||||
v.divider2.typeface = product_sans
|
||||
v.calendar_temp.typeface = product_sans
|
||||
v.time.typeface = product_sans_light
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
fun updateLocationViewByLayout(context: Context, v: View): View {
|
||||
val SP = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val locationLayout = SP.getBoolean(Constants.PREF_SHOW_WEATHER, true)
|
||||
|
||||
if (locationLayout && SP.contains(Constants.PREF_WEATHER_TEMP) && SP.contains(Constants.PREF_WEATHER_ICON)) {
|
||||
v.weather.visibility = View.VISIBLE
|
||||
v.calendar_weather.visibility = View.VISIBLE
|
||||
val currentTemp = String.format(Locale.getDefault(), "%.0f °%s", SP.getFloat(Constants.PREF_WEATHER_TEMP, 0f), SP.getString(Constants.PREF_WEATHER_REAL_TEMP_UNIT, "F"))
|
||||
|
||||
|
||||
v.weather_icon.visibility = View.VISIBLE
|
||||
v.empty_weather_icon.visibility = View.VISIBLE
|
||||
val icon: String = SP.getString(Constants.PREF_WEATHER_ICON, "")
|
||||
if (icon.equals("")) {
|
||||
v.weather_icon.visibility = View.GONE
|
||||
v.empty_weather_icon.visibility = View.GONE
|
||||
} else {
|
||||
v.weather_icon.setImageResource(WeatherUtil.getWeatherIconResource(icon))
|
||||
v.empty_weather_icon.setImageResource(WeatherUtil.getWeatherIconResource(icon))
|
||||
}
|
||||
|
||||
v.temp.text = currentTemp
|
||||
v.calendar_temp.text = currentTemp
|
||||
} else {
|
||||
v.weather.visibility = View.GONE
|
||||
v.calendar_weather.visibility = View.GONE
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
fun updateClockViewByLayout(context: Context, v: View): View {
|
||||
val SP = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
if (!SP.getBoolean(Constants.PREF_SHOW_CLOCK, false)) {
|
||||
v.time.visibility = View.GONE
|
||||
} else {
|
||||
// val now = Calendar.getInstance()
|
||||
// if (SP.getString(Constants.PREF_HOUR_FORMAT, "12").equals("12")) {
|
||||
// val textBadHour = SpannableString(Constants.badHourFormat.format(now.timeInMillis).replace(" ", ""))
|
||||
// textBadHour.setSpan(RelativeSizeSpan(0.4f), textBadHour.length - 2,
|
||||
// textBadHour.length, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
//
|
||||
// v.time.text = textBadHour
|
||||
// } else {
|
||||
// v.time.text = Constants.goodHourFormat.format(now.timeInMillis)
|
||||
// }
|
||||
v.time.visibility = View.VISIBLE
|
||||
}
|
||||
return v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,397 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.widgets
|
||||
|
||||
import android.Manifest
|
||||
import android.app.PendingIntent
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.appwidget.AppWidgetProvider
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.Resources
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.os.Bundle
|
||||
import android.text.format.DateUtils
|
||||
import android.util.Log
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.RelativeLayout
|
||||
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.global.Actions
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.receivers.NewCalendarEventReceiver
|
||||
import com.tommasoberlose.anotherwidget.receivers.WidgetClickListenerReceiver
|
||||
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
||||
import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver
|
||||
import com.tommasoberlose.anotherwidget.utils.CalendarUtil
|
||||
import com.tommasoberlose.anotherwidget.utils.Util
|
||||
import com.tommasoberlose.anotherwidget.utils.WeatherUtil
|
||||
import com.tommasoberlose.anotherwidget.utils.toPixel
|
||||
import kotlinx.android.synthetic.main.the_widget.view.*
|
||||
import java.text.DateFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
class TheWidget : AppWidgetProvider() {
|
||||
|
||||
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
|
||||
for (appWidgetId in appWidgetIds) {
|
||||
updateAppWidget(context, appWidgetManager, appWidgetId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAppWidgetOptionsChanged(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int, newOptions: Bundle?) {
|
||||
super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions)
|
||||
updateAppWidget(context, appWidgetManager, appWidgetId)
|
||||
}
|
||||
|
||||
override fun onEnabled(context: Context) {
|
||||
CalendarUtil.updateEventList(context)
|
||||
WeatherReceiver.setUpdates(context)
|
||||
}
|
||||
|
||||
override fun onDisabled(context: Context) {
|
||||
UpdatesReceiver.removeUpdates(context)
|
||||
WeatherReceiver.removeUpdates(context)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager,
|
||||
appWidgetId: Int) {
|
||||
val displayMetrics = Resources.getSystem().displayMetrics
|
||||
var height = 110.toPixel(context)
|
||||
val width = displayMetrics.widthPixels
|
||||
if (Preferences.showClock) {
|
||||
height += Util.convertSpToPixels(Preferences.clockTextSize, context).toInt() + 16.toPixel(context)
|
||||
}
|
||||
if (Preferences.textMainSize > 30 && Preferences.textSecondSize > 22) {
|
||||
height += 24.toPixel(context)
|
||||
}
|
||||
|
||||
generateWidgetView(context, appWidgetId, appWidgetManager, width - 16.toPixel(context), height)
|
||||
}
|
||||
|
||||
private fun generateWidgetView(context: Context, appWidgetId: Int, appWidgetManager: AppWidgetManager, w: Int, h: Int) {
|
||||
var views = RemoteViews(context.packageName, R.layout.the_widget_sans)
|
||||
|
||||
val generatedView = generateWidgetView(context, w)
|
||||
generatedView.measure(0, 0)
|
||||
views.setImageViewBitmap(R.id.bitmap_container, Util.getBitmapFromView(generatedView, w, generatedView.measuredHeight))
|
||||
|
||||
// Clock
|
||||
views = updateClockView(context, views, appWidgetId)
|
||||
|
||||
// Setup listener
|
||||
views = updateCalendarView(context, generatedView, views, appWidgetId)
|
||||
views = updateWeatherView(context, generatedView, views, appWidgetId)
|
||||
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||
}
|
||||
|
||||
private fun updateCalendarView(context: Context, v: View, views: RemoteViews, widgetID: Int): RemoteViews {
|
||||
|
||||
v.empty_date.measure(0, 0)
|
||||
views.setImageViewBitmap(R.id.empty_date_rect, Util.getBitmapFromView(v.empty_date))
|
||||
|
||||
views.setViewVisibility(R.id.empty_layout_rect, View.VISIBLE)
|
||||
views.setViewVisibility(R.id.calendar_layout_rect, View.GONE)
|
||||
views.setViewVisibility(R.id.second_row_rect, View.GONE)
|
||||
|
||||
val calPIntent = PendingIntent.getActivity(context, widgetID, Util.getCalendarIntent(context), 0)
|
||||
views.setOnClickPendingIntent(R.id.empty_date_rect, calPIntent)
|
||||
|
||||
val nextEvent = CalendarUtil.getNextEvent()
|
||||
val nextAlarm = Util.getNextAlarm(context)
|
||||
|
||||
if (Preferences.showEvents && Util.checkGrantedPermission(context, Manifest.permission.READ_CALENDAR) && nextEvent != null) {
|
||||
if (Preferences.showNextEvent && CalendarUtil.getEventsCount() > 1) {
|
||||
v.action_next.measure(0, 0)
|
||||
views.setImageViewBitmap(R.id.action_next_rect, Util.getBitmapFromView(v.action_next))
|
||||
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 }, 0))
|
||||
|
||||
v.action_previous.measure(0, 0)
|
||||
views.setImageViewBitmap(R.id.action_previous_rect, Util.getBitmapFromView(v.action_previous))
|
||||
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 }, 0))
|
||||
} else {
|
||||
views.setViewVisibility(R.id.action_next_rect, View.GONE)
|
||||
views.setViewVisibility(R.id.action_previous_rect, View.GONE)
|
||||
}
|
||||
|
||||
val pIntent = PendingIntent.getActivity(context, widgetID, Util.getEventIntent(context, nextEvent), 0)
|
||||
views.setOnClickPendingIntent(R.id.next_event_rect, pIntent)
|
||||
views.setOnClickPendingIntent(R.id.next_event_difference_time_rect, pIntent)
|
||||
|
||||
if (Preferences.showDiffTime && Calendar.getInstance().timeInMillis < nextEvent.startDate) {
|
||||
v.next_event_difference_time.measure(0, 0)
|
||||
views.setImageViewBitmap(R.id.next_event_difference_time_rect, Util.getBitmapFromView(v.next_event_difference_time))
|
||||
views.setViewVisibility(R.id.next_event_difference_time_rect, View.VISIBLE)
|
||||
} else {
|
||||
views.setViewVisibility(R.id.next_event_difference_time_rect, View.GONE)
|
||||
}
|
||||
|
||||
if (nextEvent.address != "" && Preferences.secondRowInformation == 1) {
|
||||
val mapIntent = PendingIntent.getActivity(context, widgetID, Util.getGoogleMapsIntentFromAddress(context, nextEvent.address), 0)
|
||||
views.setOnClickPendingIntent(R.id.second_row_rect, mapIntent)
|
||||
} else {
|
||||
views.setOnClickPendingIntent(R.id.next_event_rect, pIntent)
|
||||
}
|
||||
|
||||
v.next_event.measure(0, 0)
|
||||
views.setImageViewBitmap(R.id.next_event_rect, Util.getBitmapFromView(v.next_event))
|
||||
|
||||
|
||||
v.second_row.measure(0, 0)
|
||||
views.setImageViewBitmap(R.id.second_row_rect, Util.getBitmapFromView(v.second_row))
|
||||
views.setViewVisibility(R.id.second_row_rect, View.VISIBLE)
|
||||
|
||||
views.setViewVisibility(R.id.empty_layout_rect, View.GONE)
|
||||
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
|
||||
} else if (Preferences.secondRowInformation == 2 && nextAlarm != "") {
|
||||
val clockIntent = PendingIntent.getActivity(context, widgetID, Util.getClockIntent(context), 0)
|
||||
views.setOnClickPendingIntent(R.id.second_row_rect, clockIntent)
|
||||
|
||||
v.next_event.measure(0, 0)
|
||||
views.setImageViewBitmap(R.id.next_event_rect, Util.getBitmapFromView(v.next_event))
|
||||
|
||||
v.second_row.measure(0, 0)
|
||||
views.setImageViewBitmap(R.id.second_row_rect, Util.getBitmapFromView(v.second_row))
|
||||
views.setViewVisibility(R.id.second_row_rect, View.VISIBLE)
|
||||
|
||||
views.setViewVisibility(R.id.empty_layout_rect, View.GONE)
|
||||
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
|
||||
}
|
||||
|
||||
return views
|
||||
}
|
||||
|
||||
private fun updateWeatherView(context: Context, v: View, views: RemoteViews, widgetID: Int): RemoteViews {
|
||||
|
||||
if (Preferences.showWeather && Preferences.weatherIcon != "") {
|
||||
views.setViewVisibility(R.id.weather_rect, View.VISIBLE)
|
||||
views.setViewVisibility(R.id.calendar_weather_rect, View.VISIBLE)
|
||||
|
||||
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.calendar_weather_rect, weatherPIntent)
|
||||
|
||||
v.weather.measure(0, 0)
|
||||
views.setImageViewBitmap(R.id.weather_rect, Util.getBitmapFromView(v.weather))
|
||||
|
||||
v.calendar_weather.measure(0, 0)
|
||||
views.setImageViewBitmap(R.id.calendar_weather_rect, Util.getBitmapFromView(v.calendar_weather))
|
||||
} else {
|
||||
views.setViewVisibility(R.id.weather_rect, View.GONE)
|
||||
views.setViewVisibility(R.id.calendar_weather_rect, View.GONE)
|
||||
}
|
||||
return views
|
||||
}
|
||||
|
||||
private fun updateClockView(context: Context, views: RemoteViews, widgetID: Int): RemoteViews {
|
||||
if (!Preferences.showClock) {
|
||||
views.setViewVisibility(R.id.time, View.GONE)
|
||||
} else {
|
||||
views.setTextColor(R.id.time, Util.getFontColor())
|
||||
views.setTextViewTextSize(R.id.time, TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(context))
|
||||
val clockPIntent = PendingIntent.getActivity(context, widgetID, Util.getClockIntent(context), 0)
|
||||
views.setOnClickPendingIntent(R.id.time, clockPIntent)
|
||||
views.setViewVisibility(R.id.time, View.VISIBLE)
|
||||
}
|
||||
|
||||
return views
|
||||
}
|
||||
|
||||
fun generateWidgetView(context: Context, maxWidth: Int): View {
|
||||
val v = View.inflate(context, R.layout.the_widget, null)
|
||||
|
||||
val now = Calendar.getInstance()
|
||||
|
||||
v.empty_layout.visibility = View.VISIBLE
|
||||
v.calendar_layout.visibility = View.GONE
|
||||
|
||||
val flags: Int = DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NO_YEAR or DateUtils.FORMAT_ABBREV_MONTH
|
||||
v.empty_date.text = Util.getCapWordString("${SimpleDateFormat("EEEE", Locale.getDefault()).format(now.time)}, ${DateUtils.formatDateTime(context, now.timeInMillis, flags)}")
|
||||
|
||||
val nextEvent = CalendarUtil.getNextEvent()
|
||||
val nextAlarm = Util.getNextAlarm(context)
|
||||
|
||||
if (Preferences.showEvents && Util.checkGrantedPermission(context, Manifest.permission.READ_CALENDAR) && nextEvent != null) {
|
||||
// Multiple counter
|
||||
v.action_next.isVisible = Preferences.showNextEvent && CalendarUtil.getEventsCount() > 1
|
||||
v.action_previous.isVisible = Preferences.showNextEvent && CalendarUtil.getEventsCount() > 1
|
||||
|
||||
v.next_event.text = nextEvent.title
|
||||
|
||||
if (Preferences.showDiffTime && now.timeInMillis < nextEvent.startDate) {
|
||||
v.next_event_difference_time.text = Util.getDifferenceText(context, now.timeInMillis, nextEvent.startDate).toLowerCase(Locale.getDefault())
|
||||
v.next_event_difference_time.visibility = View.VISIBLE
|
||||
} else {
|
||||
v.next_event_difference_time.visibility = View.GONE
|
||||
}
|
||||
|
||||
if (nextEvent.address != "" && Preferences.secondRowInformation == 1) {
|
||||
v.second_row_icon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.round_place))
|
||||
v.next_event_date.text = nextEvent.address
|
||||
} else {
|
||||
v.second_row_icon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.round_today))
|
||||
if (!nextEvent.allDay) {
|
||||
val startHour = DateFormat.getTimeInstance(DateFormat.SHORT).format(nextEvent.startDate)
|
||||
val endHour = DateFormat.getTimeInstance(DateFormat.SHORT).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))
|
||||
}
|
||||
v.next_event_date.text = String.format("%s - %s%s", startHour, endHour, multipleDay)
|
||||
|
||||
} else {
|
||||
v.next_event_date.text = Util.getCapWordString(DateUtils.formatDateTime(context, now.timeInMillis, flags))
|
||||
}
|
||||
}
|
||||
|
||||
v.empty_layout.visibility = View.GONE
|
||||
v.calendar_layout.visibility = View.VISIBLE
|
||||
} else if (Preferences.secondRowInformation == 2 && nextAlarm != "") {
|
||||
v.second_row_icon.setImageDrawable(
|
||||
ContextCompat.getDrawable(
|
||||
context,
|
||||
R.drawable.round_alarm
|
||||
)
|
||||
)
|
||||
v.next_event.text = Util.getCapWordString("${SimpleDateFormat("EEEE", Locale.getDefault()).format(now.time)}, ${DateUtils.formatDateTime(context, now.timeInMillis, flags)}")
|
||||
v.next_event_date.text = Util.getNextAlarm(context)
|
||||
v.empty_layout.visibility = View.GONE
|
||||
v.calendar_layout.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
|
||||
// Color
|
||||
listOf<TextView>(v.empty_date, v.divider1, v.temp, v.next_event, v.next_event_difference_time, v.next_event_date, v.divider2, v.calendar_temp).forEach {
|
||||
it.setTextColor(Util.getFontColor())
|
||||
}
|
||||
|
||||
listOf<ImageView>(v.second_row_icon, v.action_next, v.action_previous).forEach {
|
||||
it.setColorFilter(Util.getFontColor())
|
||||
}
|
||||
|
||||
// Text Size
|
||||
listOf<Pair<TextView, Float>>(
|
||||
v.empty_date to Preferences.textMainSize,
|
||||
v.divider1 to Preferences.textSecondSize,
|
||||
v.temp to Preferences.textMainSize,
|
||||
v.next_event to Preferences.textMainSize,
|
||||
v.next_event_difference_time to Preferences.textMainSize,
|
||||
v.next_event_date to Preferences.textSecondSize,
|
||||
v.divider2 to Preferences.textSecondSize,
|
||||
v.calendar_temp to Preferences.textSecondSize
|
||||
).forEach {
|
||||
it.first.setTextSize(TypedValue.COMPLEX_UNIT_SP, it.second)
|
||||
}
|
||||
|
||||
// Icons scale
|
||||
v.second_row_icon.scaleX = Preferences.textSecondSize / 18f
|
||||
v.second_row_icon.scaleY = Preferences.textSecondSize / 18f
|
||||
|
||||
v.weather_icon.scaleX = Preferences.textSecondSize / 18f
|
||||
v.weather_icon.scaleY = Preferences.textSecondSize / 18f
|
||||
|
||||
v.empty_weather_icon.scaleX = Preferences.textMainSize / 20f
|
||||
v.empty_weather_icon.scaleY = Preferences.textMainSize / 20f
|
||||
|
||||
v.action_next.scaleX = Preferences.textMainSize / 28f
|
||||
v.action_next.scaleY = Preferences.textMainSize / 28f
|
||||
|
||||
v.action_previous.scaleX = Preferences.textMainSize / 28f
|
||||
v.action_previous.scaleY = Preferences.textMainSize / 28f
|
||||
|
||||
|
||||
// Shadows
|
||||
val shadowRadius = when (Preferences.textShadow) {
|
||||
0 -> 0f
|
||||
1 -> 5f
|
||||
2 -> 5f
|
||||
else -> 5f
|
||||
}
|
||||
val shadowColor = when (Preferences.textShadow) {
|
||||
0 -> Color.TRANSPARENT
|
||||
1 -> R.color.black_50
|
||||
2 -> Color.BLACK
|
||||
else -> R.color.black_50
|
||||
}
|
||||
val shadowDy = when (Preferences.textShadow) {
|
||||
0 -> 0f
|
||||
1 -> 0f
|
||||
2 -> 1f
|
||||
else -> 0f
|
||||
}
|
||||
|
||||
listOf<TextView>(v.empty_date, v.divider1, v.temp, v.next_event, v.next_event_difference_time, v.next_event_date, v.divider2, v.calendar_temp).forEach {
|
||||
it.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
|
||||
}
|
||||
|
||||
// Custom Font
|
||||
if (Preferences.customFont == Constants.CUSTOM_FONT_PRODUCT_SANS) {
|
||||
val productSans: Typeface = Typeface.createFromAsset(context.assets, "fonts/product_sans_regular.ttf")
|
||||
listOf<TextView>(v.empty_date, v.divider1, v.temp, v.next_event, v.next_event_difference_time, v.next_event_date, v.divider2, v.calendar_temp).forEach {
|
||||
it.typeface = productSans
|
||||
}
|
||||
}
|
||||
|
||||
// Weather
|
||||
if (Preferences.showWeather && Preferences.weatherIcon != "") {
|
||||
v.weather.visibility = View.VISIBLE
|
||||
v.calendar_weather.visibility = View.VISIBLE
|
||||
val currentTemp = String.format(Locale.getDefault(), "%.0f °%s", Preferences.weatherTemp, Preferences.weatherRealTempUnit)
|
||||
|
||||
val icon: String = Preferences.weatherIcon
|
||||
if (icon == "") {
|
||||
v.weather_icon.visibility = View.GONE
|
||||
v.empty_weather_icon.visibility = View.GONE
|
||||
} else {
|
||||
v.weather_icon.setImageResource(WeatherUtil.getWeatherIconResource(icon))
|
||||
v.empty_weather_icon.setImageResource(WeatherUtil.getWeatherIconResource(icon))
|
||||
v.weather_icon.visibility = View.VISIBLE
|
||||
v.empty_weather_icon.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
v.temp.text = currentTemp
|
||||
v.calendar_temp.text = currentTemp
|
||||
} else {
|
||||
v.weather.visibility = View.GONE
|
||||
v.calendar_weather.visibility = View.GONE
|
||||
}
|
||||
|
||||
// Apply max width
|
||||
v.main_layout.layoutParams = RelativeLayout.LayoutParams(maxWidth, RelativeLayout.LayoutParams.WRAP_CONTENT)
|
||||
|
||||
return v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,70 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.util
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.PendingIntent
|
||||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.os.IBinder
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import com.tommasoberlose.anotherwidget.`object`.Constants
|
||||
import android.content.IntentFilter
|
||||
import android.os.Build
|
||||
import android.support.v4.app.NotificationCompat
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.util.Log
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.ui.activity.MainActivity
|
||||
|
||||
|
||||
class CrocodileService : Service() {
|
||||
|
||||
private val receiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (intent.action == Intent.ACTION_TIME_TICK && isScreenOn) {
|
||||
sendBroadcast(Intent(Constants.ACTION_TIME_UPDATE))
|
||||
} else if (intent.action == Intent.ACTION_SCREEN_OFF) {
|
||||
isScreenOn = false
|
||||
} else if (intent.action == Intent.ACTION_SCREEN_ON) {
|
||||
isScreenOn = true
|
||||
sendBroadcast(Intent(Constants.ACTION_TIME_UPDATE))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var isScreenOn = true
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
val filter = IntentFilter()
|
||||
filter.addAction(Intent.ACTION_TIME_TICK)
|
||||
filter.addAction(Intent.ACTION_SCREEN_OFF)
|
||||
filter.addAction(Intent.ACTION_SCREEN_ON)
|
||||
registerReceiver(receiver, filter)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
unregisterReceiver(receiver)
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val mBuilder: NotificationCompat.Builder = NotificationCompat.Builder(this, "Config")
|
||||
.setSmallIcon(R.drawable.ic_stat_name)
|
||||
.setPriority(Notification.PRIORITY_MIN)
|
||||
.setColor(ContextCompat.getColor(this, R.color.colorPrimary))
|
||||
.setContentTitle(this.getString(R.string.background_service_title))
|
||||
.setContentText(this.getString(R.string.background_service_subtitle))
|
||||
.setAutoCancel(true);
|
||||
startForeground(5, mBuilder.build())
|
||||
}
|
||||
|
||||
return Service.START_NOT_STICKY
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent): IBinder? {
|
||||
return null
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.util;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import io.realm.DynamicRealm;
|
||||
import io.realm.DynamicRealmObject;
|
||||
import io.realm.RealmMigration;
|
||||
import io.realm.RealmObjectSchema;
|
||||
import io.realm.RealmSchema;
|
||||
|
||||
/**
|
||||
* Created by tommaso on 06/11/17.
|
||||
*/
|
||||
|
||||
public class MyMigration implements RealmMigration {
|
||||
@Override
|
||||
public void migrate(@NonNull DynamicRealm realm, long oldVersion, long newVersion) {
|
||||
|
||||
RealmSchema schema = realm.getSchema();
|
||||
if (oldVersion == 1) {
|
||||
RealmObjectSchema event = schema.get("Event");
|
||||
if (event != null) {
|
||||
if (!event.hasField("eventID")) {
|
||||
event.addField("eventID", long.class);
|
||||
}
|
||||
event
|
||||
.addField("id_tmp", long.class)
|
||||
.transform(new RealmObjectSchema.Function() {
|
||||
@Override
|
||||
public void apply(@NonNull DynamicRealmObject obj) {
|
||||
obj.setLong("id_tmp", obj.getInt("id"));
|
||||
}
|
||||
})
|
||||
.removeField("id")
|
||||
.renameField("id_tmp", "id");
|
||||
}
|
||||
oldVersion++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 37;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return (o instanceof MyMigration);
|
||||
}
|
||||
}
|
@ -1,680 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.util
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.*
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.*
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Resources
|
||||
import android.graphics.*
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import android.support.customtabs.CustomTabsIntent
|
||||
import android.support.v4.app.NotificationCompat
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.util.DisplayMetrics
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
|
||||
import com.tommasoberlose.anotherwidget.ui.activity.MainActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.widget.TheWidget
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.support.annotation.StringRes
|
||||
import android.util.TypedValue
|
||||
import android.content.Intent
|
||||
import android.content.ComponentName
|
||||
import android.database.Cursor
|
||||
import android.location.LocationManager
|
||||
import android.os.Build
|
||||
import android.preference.PreferenceManager
|
||||
import android.provider.AlarmClock
|
||||
import android.provider.CalendarContract
|
||||
import android.provider.Settings
|
||||
import android.support.v4.graphics.drawable.DrawableCompat
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.Transformation
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.RemoteViews
|
||||
import android.widget.Toast
|
||||
import com.tommasoberlose.anotherwidget.`object`.Constants
|
||||
import com.tommasoberlose.anotherwidget.`object`.Event
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import org.joda.time.DateTime
|
||||
import java.net.URISyntaxException
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
/**
|
||||
* Created by tommaso on 05/10/17.
|
||||
*/
|
||||
|
||||
object Util {
|
||||
|
||||
fun checkGrantedPermission(context: Context, permission: String): Boolean {
|
||||
return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
fun updateWidget(context: Context) {
|
||||
val widgetManager = AppWidgetManager.getInstance(context)
|
||||
val widgetComponent = ComponentName(context, TheWidget::class.java)
|
||||
val widgetIds = widgetManager.getAppWidgetIds(widgetComponent)
|
||||
val update = Intent(context, TheWidget::class.java)
|
||||
update.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, widgetIds)
|
||||
update.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
||||
context.sendBroadcast(update)
|
||||
context.sendBroadcast(Intent(Constants.ACTION_SOMETHING_HAPPENED))
|
||||
}
|
||||
|
||||
fun showNotification(context: Context) {
|
||||
val mNotificationManager: NotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
|
||||
|
||||
if (!Util.checkGrantedPermission(context, Manifest.permission.READ_CALENDAR)) {
|
||||
val mBuilder: NotificationCompat.Builder = NotificationCompat.Builder(context, "Config")
|
||||
.setSmallIcon(R.drawable.ic_stat_name)
|
||||
.setPriority(Notification.PRIORITY_MIN)
|
||||
.setColor(ContextCompat.getColor(context, R.color.colorPrimary))
|
||||
.setContentTitle(context.getString(R.string.notification_title))
|
||||
.setContentText(context.getString(R.string.notification_subtitle))
|
||||
.setAutoCancel(true);
|
||||
|
||||
val intent: Intent = Intent(context, MainActivity::class.java);
|
||||
val pi: PendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
mBuilder.setContentIntent(pi);
|
||||
mNotificationManager.notify(0, mBuilder.build());
|
||||
} else {
|
||||
mNotificationManager.cancel(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun showWeatherErrorNotification(context: Context) {
|
||||
val mNotificationManager: NotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
val SP = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
if (SP.getBoolean(Constants.PREF_SHOW_GPS_NOTIFICATION, true) && !locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) && SP.getInt(Constants.PREF_WEATHER_PROVIDER, Constants.WEATHER_PROVIDER_GOOGLE_AWARENESS) == Constants.WEATHER_PROVIDER_GOOGLE_AWARENESS) {
|
||||
val settingsIntent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
|
||||
val pi: PendingIntent = PendingIntent.getActivity(context, 50, settingsIntent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
|
||||
val providerIntent2 = Intent(context, MainActivity::class.java)
|
||||
providerIntent2.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
providerIntent2.putExtra(Constants.ACTION_EXTRA_OPEN_WEATHER_PROVIDER, true)
|
||||
val pi2: PendingIntent = PendingIntent.getActivity(context, 51, providerIntent2, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
|
||||
val providerIntentDisable = Intent(context, MainActivity::class.java)
|
||||
providerIntentDisable.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
providerIntentDisable.putExtra(Constants.ACTION_EXTRA_DISABLE_GPS_NOTIFICATION, true)
|
||||
val piDisable: PendingIntent = PendingIntent.getActivity(context, 52, providerIntentDisable, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
|
||||
val mBuilder: NotificationCompat.Builder = NotificationCompat.Builder(context, "Error")
|
||||
.setSmallIcon(R.drawable.ic_stat_name)
|
||||
.setColor(ContextCompat.getColor(context, R.color.colorPrimary))
|
||||
.setContentTitle(context.getString(R.string.notification_gps_title))
|
||||
.setContentText(context.getString(R.string.notification_gps_subtitle))
|
||||
.addAction(R.drawable.ic_action_sync, context.getString(R.string.change_provider), pi2)
|
||||
.addAction(R.drawable.ic_action_settings, context.getString(R.string.disable_notification), piDisable)
|
||||
.setContentIntent(pi)
|
||||
|
||||
mNotificationManager.notify(10, mBuilder.build());
|
||||
} else {
|
||||
mNotificationManager.cancel(10)
|
||||
}
|
||||
}
|
||||
|
||||
fun openURI(context: Context, url: String) {
|
||||
try {
|
||||
val builder: CustomTabsIntent.Builder = CustomTabsIntent.Builder()
|
||||
builder.setToolbarColor(ContextCompat.getColor(context, R.color.colorPrimary))
|
||||
val customTabsIntent: CustomTabsIntent = builder.build()
|
||||
customTabsIntent.launchUrl(context, Uri.parse(url))
|
||||
} catch (e: Exception) {
|
||||
try {
|
||||
val openIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||
context.startActivity(openIntent);
|
||||
} catch (ignored: Exception) {
|
||||
val clipboard:ClipboardManager = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText(context.getString(R.string.app_name), url);
|
||||
clipboard.primaryClip = clip;
|
||||
Toast.makeText(context, R.string.error_opening_uri, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun rateApp(context: Context, url: String) {
|
||||
val openIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
||||
context.startActivity(openIntent)
|
||||
}
|
||||
|
||||
fun share(context: Context) {
|
||||
val sendIntent = Intent(Intent.ACTION_SEND);
|
||||
sendIntent.putExtra(Intent.EXTRA_TEXT,
|
||||
"Yep, just another cool widget: https://play.google.com/store/apps/details?id=com.tommasoberlose.anotherwidget");
|
||||
sendIntent.setType("text/plain");
|
||||
context.startActivity(Intent.createChooser(sendIntent, context.getString(R.string.action_share)));
|
||||
}
|
||||
|
||||
fun getGoogleMapsIntentFromAddress(context: Context, address:String): Intent {
|
||||
val gmmIntentUri: Uri = Uri.parse("geo:0,0?q=" + address);
|
||||
val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri);
|
||||
mapIntent.`package` = "com.google.android.apps.maps";
|
||||
|
||||
return if (mapIntent.resolveActivity(context.packageManager) != null) {
|
||||
mapIntent
|
||||
} else {
|
||||
val map = "http://maps.google.co.in/maps?q=" + address
|
||||
val i = Intent(Intent.ACTION_VIEW, Uri.parse(map));
|
||||
i
|
||||
}
|
||||
}
|
||||
|
||||
fun getCurrentWallpaper(context: Context): Drawable? {
|
||||
var wallpaper: Drawable? = null
|
||||
try {
|
||||
wallpaper = WallpaperManager.getInstance(context).drawable
|
||||
} catch (e: Exception) {
|
||||
wallpaper = BitmapDrawable(context.resources, getResizedBitmap(BitmapFactory.decodeResource(context.resources, R.drawable.pixel_2_wallpaper), 800))
|
||||
} finally {
|
||||
return wallpaper
|
||||
}
|
||||
}
|
||||
|
||||
fun getBitmapFromView(view: View): Bitmap {
|
||||
//Define a bitmap with the same size as the view
|
||||
val measuredWidth = View.MeasureSpec.makeMeasureSpec(view.width, View.MeasureSpec.UNSPECIFIED)
|
||||
val measuredHeight = View.MeasureSpec.makeMeasureSpec(view.height, View.MeasureSpec.UNSPECIFIED)
|
||||
view.measure(measuredWidth, measuredHeight)
|
||||
view.layout(0,0, measuredWidth, measuredHeight)
|
||||
val returnedBitmap = Bitmap.createBitmap(view.measuredWidth, view.measuredHeight, Bitmap.Config.ARGB_8888)
|
||||
//Bind a canvas to it
|
||||
val canvas = Canvas(returnedBitmap)
|
||||
// draw the view on the canvas
|
||||
view.draw(canvas)
|
||||
//return the bitmap
|
||||
return returnedBitmap
|
||||
}
|
||||
|
||||
fun getBitmapFromView(view: View, w: Int, h: Int): Bitmap {
|
||||
//Define a bitmap with the same size as the view
|
||||
val measuredWidth = View.MeasureSpec.makeMeasureSpec(w, View.MeasureSpec.EXACTLY)
|
||||
val measuredHeight = View.MeasureSpec.makeMeasureSpec(h, View.MeasureSpec.EXACTLY)
|
||||
view.measure(measuredWidth, measuredHeight)
|
||||
view.layout(0,0, measuredWidth, measuredHeight)
|
||||
val returnedBitmap = Bitmap.createBitmap(view.measuredWidth, view.measuredHeight, Bitmap.Config.ARGB_8888)
|
||||
//Bind a canvas to it
|
||||
val canvas = Canvas(returnedBitmap)
|
||||
// draw the view on the canvas
|
||||
view.draw(canvas)
|
||||
//return the bitmap
|
||||
return returnedBitmap
|
||||
}
|
||||
|
||||
fun convertDpToPixel(dp: Float, context: Context): Float {
|
||||
val resources: Resources = context.resources
|
||||
val metrics: DisplayMetrics = resources.displayMetrics
|
||||
val px: Float = dp * (metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT)
|
||||
return px
|
||||
}
|
||||
|
||||
fun convertSpToPixels(sp: Float, context: Context): Float {
|
||||
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.resources.displayMetrics)
|
||||
}
|
||||
|
||||
fun getResizedBitmap(image: Bitmap, maxSize: Int): Bitmap {
|
||||
var width = image.width
|
||||
var height = image.height
|
||||
|
||||
val bitmapRatio = width.toFloat() / height.toFloat()
|
||||
if (bitmapRatio > 1) {
|
||||
width = maxSize
|
||||
height = (width / bitmapRatio).toInt()
|
||||
} else {
|
||||
height = maxSize
|
||||
width = (height * bitmapRatio).toInt()
|
||||
}
|
||||
|
||||
return Bitmap.createScaledBitmap(image, width, height, true)
|
||||
}
|
||||
|
||||
fun getRefreshPeriodString(period: Int): Int {
|
||||
return when (period) {
|
||||
0 -> R.string.settings_weather_refresh_period_subtitle_0
|
||||
1 -> R.string.settings_weather_refresh_period_subtitle_1
|
||||
2 -> R.string.settings_weather_refresh_period_subtitle_2
|
||||
3 -> R.string.settings_weather_refresh_period_subtitle_3
|
||||
4 -> R.string.settings_weather_refresh_period_subtitle_4
|
||||
5 -> R.string.settings_weather_refresh_period_subtitle_5
|
||||
else -> R.string.settings_weather_refresh_period_subtitle_0
|
||||
}
|
||||
}
|
||||
|
||||
fun getShowUntilString(period: Int): Int {
|
||||
return when (period) {
|
||||
0 -> R.string.settings_show_until_subtitle_0
|
||||
1 -> R.string.settings_show_until_subtitle_1
|
||||
2 -> R.string.settings_show_until_subtitle_2
|
||||
3 -> R.string.settings_show_until_subtitle_3
|
||||
4 -> R.string.settings_show_until_subtitle_4
|
||||
5 -> R.string.settings_show_until_subtitle_5
|
||||
6 -> R.string.settings_show_until_subtitle_6
|
||||
7 -> R.string.settings_show_until_subtitle_7
|
||||
else -> R.string.settings_show_until_subtitle_1
|
||||
}
|
||||
}
|
||||
|
||||
fun getSecondRowInfoString(info: Int): Int {
|
||||
return when (info) {
|
||||
0 -> R.string.settings_second_row_info_subtitle_0
|
||||
1 -> R.string.settings_second_row_info_subtitle_1
|
||||
2 -> R.string.settings_second_row_info_subtitle_2
|
||||
else -> R.string.settings_second_row_info_subtitle_0
|
||||
}
|
||||
}
|
||||
|
||||
fun getTextShadowString(shadow: Int): Int {
|
||||
return when (shadow) {
|
||||
0 -> R.string.settings_text_shadow_subtitle_none
|
||||
1 -> R.string.settings_text_shadow_subtitle_low
|
||||
2 -> R.string.settings_text_shadow_subtitle_high
|
||||
else -> R.string.settings_text_shadow_subtitle_low
|
||||
}
|
||||
}
|
||||
|
||||
fun getCustomFontLabel(shadow: Int): Int {
|
||||
return when (shadow) {
|
||||
0 -> R.string.custom_font_subtitle_0
|
||||
1 -> R.string.custom_font_subtitle_1
|
||||
else -> R.string.custom_font_subtitle_1
|
||||
}
|
||||
}
|
||||
|
||||
fun getCalendarIntent(context: Context): Intent {
|
||||
val SP = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
if (SP.getString(Constants.PREF_CALENDAR_APP_PACKAGE, "").equals("")) {
|
||||
val calIntent = Intent(Intent.ACTION_MAIN)
|
||||
calIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
calIntent.addCategory(Intent.CATEGORY_APP_CALENDAR)
|
||||
return calIntent
|
||||
} else if (SP.getString(Constants.PREF_CALENDAR_APP_PACKAGE, "").equals("_")) {
|
||||
return Intent()
|
||||
} else {
|
||||
val pm: PackageManager = context.packageManager
|
||||
return try {
|
||||
val intent: Intent = pm.getLaunchIntentForPackage(SP.getString(Constants.PREF_CALENDAR_APP_PACKAGE, ""))
|
||||
intent.addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
intent
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
val calIntent = Intent(Intent.ACTION_MAIN)
|
||||
calIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
calIntent.addCategory(Intent.CATEGORY_APP_CALENDAR)
|
||||
calIntent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getWeatherIntent(context: Context): Intent {
|
||||
val SP = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
if (SP.getString(Constants.PREF_WEATHER_APP_PACKAGE, "").equals("")) {
|
||||
val weatherIntent: Intent = Intent(Intent.ACTION_VIEW)
|
||||
weatherIntent.addCategory(Intent.CATEGORY_DEFAULT)
|
||||
weatherIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
weatherIntent.data = Uri.parse("dynact://velour/weather/ProxyActivity")
|
||||
weatherIntent.component = ComponentName("com.google.android.googlequicksearchbox", "com.google.android.apps.gsa.velour.DynamicActivityTrampoline")
|
||||
return weatherIntent
|
||||
} else if (SP.getString(Constants.PREF_WEATHER_APP_PACKAGE, "").equals("_")) {
|
||||
return Intent()
|
||||
} else {
|
||||
val pm: PackageManager = context.packageManager
|
||||
return try {
|
||||
val intent: Intent = pm.getLaunchIntentForPackage(SP.getString(Constants.PREF_WEATHER_APP_PACKAGE, ""))
|
||||
intent.addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
intent
|
||||
} catch (e: Exception) {
|
||||
val weatherIntent: Intent = Intent(Intent.ACTION_VIEW)
|
||||
weatherIntent.addCategory(Intent.CATEGORY_DEFAULT)
|
||||
weatherIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
weatherIntent.data = Uri.parse("dynact://velour/weather/ProxyActivity")
|
||||
weatherIntent.component = ComponentName("com.google.android.googlequicksearchbox", "com.google.android.apps.gsa.velour.DynamicActivityTrampoline")
|
||||
weatherIntent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getEventIntent(context: Context, e: Event): Intent {
|
||||
val SP = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
if (SP.getString(Constants.PREF_EVENT_APP_PACKAGE, "").equals("")) {
|
||||
val uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, e.eventID)
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
.setData(uri)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
intent.putExtra("beginTime", e.startDate);
|
||||
intent.putExtra("endTime", e.endDate);
|
||||
return intent
|
||||
} else if (SP.getString(Constants.PREF_EVENT_APP_PACKAGE, "") == ("_")) {
|
||||
return Intent()
|
||||
} else {
|
||||
val pm: PackageManager = context.packageManager
|
||||
return try {
|
||||
val intent: Intent = pm.getLaunchIntentForPackage(SP.getString(Constants.PREF_EVENT_APP_PACKAGE, ""))
|
||||
intent.addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
intent
|
||||
} catch (ex: Exception) {
|
||||
val uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, e.id.toLong())
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
.setData(uri)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
intent.putExtra("beginTime", e.startDate);
|
||||
intent.putExtra("endTime", e.endDate);
|
||||
intent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getClockIntent(context: Context): Intent {
|
||||
val SP = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
if (SP.getString(Constants.PREF_CLOCK_APP_PACKAGE, "").equals("")) {
|
||||
val clockIntent = Intent(AlarmClock.ACTION_SHOW_ALARMS)
|
||||
clockIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
return clockIntent
|
||||
} else if (SP.getString(Constants.PREF_CLOCK_APP_PACKAGE, "").equals("_")) {
|
||||
return Intent()
|
||||
} else {
|
||||
val pm: PackageManager = context.packageManager
|
||||
return try {
|
||||
val intent: Intent = pm.getLaunchIntentForPackage(SP.getString(Constants.PREF_CLOCK_APP_PACKAGE, ""))
|
||||
intent.addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
intent
|
||||
} catch (e: Exception) {
|
||||
val clockIntent = Intent(AlarmClock.ACTION_SHOW_ALARMS)
|
||||
clockIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
return clockIntent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getCapWordString(text: String): String {
|
||||
return try {
|
||||
val ar = text.split(" ")
|
||||
var newText = ""
|
||||
for (t: String in ar) {
|
||||
newText += " "
|
||||
newText += t.substring(0, 1).toUpperCase()
|
||||
newText += t.substring(1)
|
||||
}
|
||||
newText.substring(1)
|
||||
} catch (e: Exception) {
|
||||
text
|
||||
}
|
||||
}
|
||||
|
||||
fun showLocationNotification(context: Context, show: Boolean) {
|
||||
val mNotificationManager: NotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
|
||||
|
||||
if (show) {
|
||||
val mBuilder: NotificationCompat.Builder = NotificationCompat.Builder(context, "Config")
|
||||
.setSmallIcon(R.drawable.ic_stat_name)
|
||||
.setPriority(Notification.PRIORITY_MIN)
|
||||
.setColor(ContextCompat.getColor(context, R.color.colorPrimary))
|
||||
.setContentTitle(context.getString(R.string.notification_gps_title))
|
||||
.setContentText(context.getString(R.string.notification_gps_subtitle))
|
||||
.setAutoCancel(true);
|
||||
|
||||
val intent: Intent = Intent( Settings.ACTION_LOCATION_SOURCE_SETTINGS);
|
||||
val pi: PendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
mBuilder.setContentIntent(pi);
|
||||
mNotificationManager.notify(1, mBuilder.build());
|
||||
} else {
|
||||
mNotificationManager.cancel(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun showWeatherNotification(context: Context, show: Boolean) {
|
||||
val mNotificationManager: NotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
|
||||
|
||||
if (show) {
|
||||
val mBuilder: NotificationCompat.Builder = NotificationCompat.Builder(context, "Config")
|
||||
.setSmallIcon(R.drawable.ic_stat_name)
|
||||
.setColor(ContextCompat.getColor(context, R.color.colorPrimary))
|
||||
.setContentTitle(context.getString(R.string.settings_weather_provider_api_key_title))
|
||||
.setContentText(context.getString(R.string.settings_weather_provider_api_key_subtitle_not_set))
|
||||
.setAutoCancel(true);
|
||||
|
||||
val intent: Intent = Intent(context, MainActivity::class.java);
|
||||
intent.putExtra(Constants.ACTION_EXTRA_OPEN_WEATHER_PROVIDER, true)
|
||||
val pi: PendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
mBuilder.setContentIntent(pi);
|
||||
mNotificationManager.notify(2, mBuilder.build());
|
||||
} else {
|
||||
mNotificationManager.cancel(2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun sendEmail(context: Context) {
|
||||
val i:Intent = Intent(Intent.ACTION_SEND)
|
||||
i.type = "message/rfc822"
|
||||
i.putExtra(Intent.EXTRA_EMAIL, arrayOf("tommaso.berlose@gmail.com"))
|
||||
i.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.feedback_title))
|
||||
try {
|
||||
context.startActivity(Intent.createChooser(i, context.getString(R.string.feedback_chooser_title)))
|
||||
} catch (ex: Exception) {
|
||||
Toast.makeText(context, R.string.feedback_error, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
fun expand(v: View) {
|
||||
if (v.visibility != View.VISIBLE) {
|
||||
v.measure(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
|
||||
val targetHeight = v.getMeasuredHeight()
|
||||
|
||||
v.layoutParams.height = 0
|
||||
v.visibility = View.VISIBLE
|
||||
val a = object : Animation() {
|
||||
protected override fun applyTransformation(interpolatedTime: Float, t: Transformation) {
|
||||
v.layoutParams.height = if (interpolatedTime == 1f)
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
else
|
||||
(targetHeight * interpolatedTime).toInt()
|
||||
v.requestLayout()
|
||||
}
|
||||
|
||||
override fun willChangeBounds(): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
a.duration = (targetHeight / v.context.resources.displayMetrics.density).toLong()
|
||||
v.startAnimation(a)
|
||||
}
|
||||
}
|
||||
|
||||
fun collapse(v: View) {
|
||||
if (v.visibility != View.GONE) {
|
||||
val initialHeight = v.getMeasuredHeight()
|
||||
|
||||
val a = object : Animation() {
|
||||
protected override fun applyTransformation(interpolatedTime: Float, t: Transformation) {
|
||||
if (interpolatedTime == 1f) {
|
||||
v.visibility = View.GONE
|
||||
} else {
|
||||
v.layoutParams.height = initialHeight - (initialHeight * interpolatedTime).toInt()
|
||||
v.requestLayout()
|
||||
}
|
||||
}
|
||||
|
||||
override fun willChangeBounds(): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
a.duration = (initialHeight / v.context.resources.displayMetrics.density).toLong()
|
||||
v.startAnimation(a)
|
||||
}
|
||||
}
|
||||
|
||||
fun getEmojiByUnicode(unicode: Int): String {
|
||||
return String(Character.toChars(unicode))
|
||||
}
|
||||
|
||||
fun getDifferenceText(context: Context, now: Long, start: Long): String {
|
||||
val nowDate = DateTime(now)
|
||||
val eventDate = DateTime(start)
|
||||
|
||||
var difference = start - now
|
||||
difference += 60 * 1000 - (difference % (60 * 1000))
|
||||
|
||||
if (difference <= 0) {
|
||||
return ""
|
||||
} else if (TimeUnit.MILLISECONDS.toHours(difference) < 1) {
|
||||
val minutes = TimeUnit.MILLISECONDS.toMinutes(difference)
|
||||
var time = ""
|
||||
if (minutes > 0) {
|
||||
time += "" + minutes + context.getString(R.string.min_code)
|
||||
}
|
||||
|
||||
return String.format("%s %s", context.getString(R.string.in_code), time)
|
||||
} else if (TimeUnit.MILLISECONDS.toHours(difference) < 12) {
|
||||
val hour = TimeUnit.MILLISECONDS.toHours(difference)
|
||||
var time = ""
|
||||
if (hour > 0) {
|
||||
time = if (hour > 1) {
|
||||
hour.toString() + context.getString(R.string.hs_code) + " "
|
||||
} else {
|
||||
hour.toString() + context.getString(R.string.h_code) + " "
|
||||
}
|
||||
}
|
||||
val minutes = TimeUnit.MILLISECONDS.toMinutes(difference - hour * 3600 * 1000)
|
||||
if (minutes > 0) {
|
||||
time += "" + minutes + context.getString(R.string.min_code)
|
||||
}
|
||||
|
||||
return String.format("%s %s", context.getString(R.string.in_code), time)
|
||||
} else if (eventDate.dayOfYear == nowDate.plusDays(1).dayOfYear) {
|
||||
return String.format("%s", context.getString(R.string.tomorrow))
|
||||
} else if (eventDate.dayOfYear == nowDate.dayOfYear) {
|
||||
return String.format("%s", context.getString(R.string.today))
|
||||
} else {
|
||||
var days = TimeUnit.MILLISECONDS.toDays(difference)
|
||||
if (eventDate.hourOfDay < nowDate.hourOfDay || (eventDate.hourOfDay == nowDate.hourOfDay && eventDate.minuteOfHour <= nowDate.minuteOfHour)) {
|
||||
days++
|
||||
}
|
||||
return String.format("%s %s%s", context.getString(R.string.in_code), days, context.getString(R.string.day_char))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
fun getFontColor(SP: SharedPreferences): Int {
|
||||
return try {
|
||||
Color.parseColor(SP.getString(Constants.PREF_TEXT_COLOR, "#FFFFFF"))
|
||||
} catch (e: Exception) {
|
||||
SP.edit().remove(Constants.PREF_TEXT_COLOR).commit()
|
||||
Color.parseColor(SP.getString(Constants.PREF_TEXT_COLOR, "#FFFFFF"))
|
||||
}
|
||||
}
|
||||
|
||||
fun getTintedDrawable(context: Context, inputDrawable: Int, color: Int): Drawable {
|
||||
val wrapDrawable = ContextCompat.getDrawable(context, inputDrawable);
|
||||
DrawableCompat.setTint(wrapDrawable, color);
|
||||
DrawableCompat.setTintMode(wrapDrawable, PorterDuff.Mode.SRC_IN);
|
||||
return wrapDrawable;
|
||||
}
|
||||
|
||||
fun changeBitmapColor(sourceBitmap: Bitmap, color: Int): Bitmap {
|
||||
val resultBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0,
|
||||
sourceBitmap.getWidth() - 1, sourceBitmap.getHeight() - 1);
|
||||
val p = Paint()
|
||||
val filter = PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN);
|
||||
p.colorFilter = filter;
|
||||
|
||||
val canvas = Canvas(resultBitmap);
|
||||
canvas.drawBitmap(resultBitmap, 0f, 0f, p);
|
||||
|
||||
return resultBitmap;
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
fun updateSettingsByDefault(context: Context) {
|
||||
try {
|
||||
// context.startService(Intent(context, CrocodileService::class.java))
|
||||
} catch (e: Exception) {
|
||||
|
||||
}
|
||||
|
||||
val SP = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val editor = SP.edit()
|
||||
if (SP.contains(Constants.PREF_SHOW_EVENT_LOCATION)) {
|
||||
editor.putInt(Constants.PREF_SECOND_ROW_INFORMATION, 1)
|
||||
editor.remove(Constants.PREF_SHOW_EVENT_LOCATION)
|
||||
}
|
||||
if (SP.contains(Constants.PREF_WEATHER_PROVIDER_API_KEY)) {
|
||||
editor.putString(Constants.PREF_OPEN_WEATHER_API_KEY, SP.getString(Constants.PREF_WEATHER_PROVIDER_API_KEY, ""))
|
||||
editor.remove(Constants.PREF_WEATHER_PROVIDER_API_KEY)
|
||||
}
|
||||
editor.commit()
|
||||
}
|
||||
|
||||
fun getRealInstance(context: Context): Realm {
|
||||
Realm.init(context)
|
||||
return Realm.getDefaultInstance()
|
||||
}
|
||||
|
||||
fun getNextAlarm(context: Context): String? {
|
||||
try {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
val SP = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
val alarm = am.nextAlarmClock
|
||||
if (alarm != null) {
|
||||
val time = am.nextAlarmClock.triggerTime
|
||||
if (SP.getString(Constants.PREF_HOUR_FORMAT, "12") == "12") Constants.badHourFormat.format(time) else Constants.goodHourFormat.format(time)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else {
|
||||
val time = Settings.System.getString(context.contentResolver,
|
||||
Settings.System.NEXT_ALARM_FORMATTED)
|
||||
return if (time != "") {
|
||||
time
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
} catch (ignored: Exception) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun getPath(context: Context, uri: Uri): String? {
|
||||
if ("content".equals(uri.scheme, ignoreCase = true)) {
|
||||
val projection = arrayOf(android.provider.MediaStore.Files.FileColumns.DATA)
|
||||
var cursor: Cursor? = null
|
||||
|
||||
try {
|
||||
cursor = context.contentResolver.query(uri, projection, null, null, null)
|
||||
val column_index = cursor.getColumnIndexOrThrow(android.provider.MediaStore.Files.FileColumns.DATA)
|
||||
if (cursor.moveToFirst()) {
|
||||
Log.d("AW", "4: " + cursor.getString(0))
|
||||
return cursor.getString(0)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
} else if ("file".equals(uri.scheme, ignoreCase = true)) {
|
||||
return uri.path
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
@ -1,321 +0,0 @@
|
||||
package com.tommasoberlose.anotherwidget.util
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.UiModeManager
|
||||
import android.content.Context
|
||||
import android.content.Context.LOCATION_SERVICE
|
||||
import android.content.SharedPreferences
|
||||
import android.location.*
|
||||
import android.os.Bundle
|
||||
import android.preference.PreferenceManager
|
||||
import com.survivingwithandroid.weather.lib.WeatherClient
|
||||
import com.survivingwithandroid.weather.lib.WeatherConfig
|
||||
import com.survivingwithandroid.weather.lib.exception.WeatherLibException
|
||||
import com.survivingwithandroid.weather.lib.model.CurrentWeather
|
||||
import com.survivingwithandroid.weather.lib.provider.openweathermap.OpenweathermapProviderType
|
||||
import com.survivingwithandroid.weather.lib.request.WeatherRequest
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.`object`.Constants
|
||||
import android.content.DialogInterface
|
||||
import android.support.v4.content.ContextCompat.startActivity
|
||||
import android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS
|
||||
import android.content.Intent
|
||||
import android.location.LocationManager
|
||||
import android.support.annotation.NonNull
|
||||
import android.support.v7.app.AppCompatDelegate
|
||||
import android.util.Log
|
||||
import com.google.android.gms.awareness.Awareness
|
||||
import com.google.android.gms.awareness.snapshot.WeatherResponse
|
||||
import com.google.android.gms.awareness.snapshot.WeatherResult
|
||||
import com.google.android.gms.awareness.state.Weather
|
||||
import com.google.android.gms.common.api.GoogleApiClient
|
||||
import com.google.android.gms.common.api.ResultCallback
|
||||
import com.google.android.gms.tasks.OnFailureListener
|
||||
import com.google.android.gms.tasks.OnSuccessListener
|
||||
import java.util.*
|
||||
|
||||
|
||||
/**
|
||||
* Created by tommaso on 08/10/17.
|
||||
*/
|
||||
|
||||
object WeatherUtil {
|
||||
|
||||
fun updateWeather(context: Context) {
|
||||
Util.showLocationNotification(context, false)
|
||||
val SP: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
Util.showWeatherErrorNotification(context)
|
||||
|
||||
if (SP.getString(Constants.PREF_CUSTOM_LOCATION_ADD, "").equals("") || SP.getString(Constants.PREF_CUSTOM_LOCATION_LAT, "").equals("") || SP.getString(Constants.PREF_CUSTOM_LOCATION_LON, "").equals("")) {
|
||||
if (SP.getInt(Constants.PREF_WEATHER_PROVIDER, Constants.WEATHER_PROVIDER_GOOGLE_AWARENESS) == Constants.WEATHER_PROVIDER_GOOGLE_AWARENESS) {
|
||||
newWeatherProvider(context)
|
||||
} else {
|
||||
if (!Util.checkGrantedPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)) {
|
||||
return
|
||||
}
|
||||
val mGoogleApiClient = GoogleApiClient.Builder(context)
|
||||
.addApi(Awareness.API)
|
||||
.build()
|
||||
mGoogleApiClient.connect()
|
||||
Awareness.SnapshotApi.getLocation(mGoogleApiClient)
|
||||
.setResultCallback({ locationResult ->
|
||||
if (locationResult.status.isSuccess) {
|
||||
getCurrentWeather(context, locationResult.location)
|
||||
} else {
|
||||
val locationManager = context.getSystemService(LOCATION_SERVICE) as LocationManager
|
||||
if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
|
||||
val gpsLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
|
||||
if (gpsLocation != null) {
|
||||
getCurrentWeather(context, gpsLocation)
|
||||
} else {
|
||||
if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
|
||||
val networkLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
|
||||
if (networkLocation != null) {
|
||||
getCurrentWeather(context, networkLocation)
|
||||
} else {
|
||||
getWeatherByDefaultLocation(context)
|
||||
}
|
||||
} else {
|
||||
getWeatherByDefaultLocation(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
weatherNetworkRequest(context, SP.getString(Constants.PREF_CUSTOM_LOCATION_LAT, "").toDouble(), SP.getString(Constants.PREF_CUSTOM_LOCATION_LON, "").toDouble())
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
fun newWeatherProvider(context: Context) {
|
||||
if (!Util.checkGrantedPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)) {
|
||||
return
|
||||
}
|
||||
val mGoogleApiClient = GoogleApiClient.Builder(context)
|
||||
.addApi(Awareness.API)
|
||||
.build()
|
||||
mGoogleApiClient.connect()
|
||||
|
||||
Awareness.SnapshotApi.getWeather(mGoogleApiClient)
|
||||
.setResultCallback({ weatherResult ->
|
||||
if (weatherResult.status.isSuccess && weatherResult.weather != null) {
|
||||
val weather: Weather = weatherResult.weather
|
||||
val SP: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
SP.edit()
|
||||
.putFloat(Constants.PREF_WEATHER_TEMP, weather.getTemperature(if (SP.getString(Constants.PREF_WEATHER_TEMP_UNIT, "F").equals("F")) Weather.FAHRENHEIT else Weather.CELSIUS))
|
||||
.putString(Constants.PREF_WEATHER_ICON, getIconCodeFromAwareness(context, weather.conditions))
|
||||
.putString(Constants.PREF_WEATHER_REAL_TEMP_UNIT, SP.getString(Constants.PREF_WEATHER_TEMP_UNIT, "F"))
|
||||
.commit()
|
||||
Util.updateWidget(context)
|
||||
}
|
||||
mGoogleApiClient.disconnect()
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
fun getWeatherByDefaultLocation(context: Context) {
|
||||
val SP: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
if (!SP.getString(Constants.PREF_CUSTOM_LOCATION_LAT, "").equals("") && !SP.getString(Constants.PREF_CUSTOM_LOCATION_LON, "").equals("")) {
|
||||
weatherNetworkRequest(context, SP.getString(Constants.PREF_CUSTOM_LOCATION_LAT, "").toDouble(), SP.getString(Constants.PREF_CUSTOM_LOCATION_LON, "").toDouble())
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
fun getCurrentWeather(context: Context, location: Location?) {
|
||||
if (location != null) {
|
||||
weatherNetworkRequest(context, location.latitude, location.longitude)
|
||||
}
|
||||
}
|
||||
|
||||
fun weatherNetworkRequest(context: Context, latitude: Double, longitude: Double) {
|
||||
val SP: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
SP.edit()
|
||||
.putString(Constants.PREF_CUSTOM_LOCATION_LAT, latitude.toString())
|
||||
.putString(Constants.PREF_CUSTOM_LOCATION_LON, longitude.toString())
|
||||
.apply()
|
||||
|
||||
if (!getWeatherProviderKey(context, SP).equals("")) {
|
||||
try {
|
||||
val config = WeatherConfig()
|
||||
config.unitSystem = if (SP.getString(Constants.PREF_WEATHER_TEMP_UNIT, "F").equals("C")) WeatherConfig.UNIT_SYSTEM.M else WeatherConfig.UNIT_SYSTEM.I
|
||||
config.lang = "en"
|
||||
config.maxResult = 1
|
||||
config.numDays = 1
|
||||
config.ApiKey = WeatherUtil.getWeatherProviderKey(context, SP)
|
||||
|
||||
val client = WeatherClient.ClientBuilder().attach(context)
|
||||
.httpClient(com.survivingwithandroid.weather.lib.client.volley.WeatherClientDefault::class.java)
|
||||
.provider(OpenweathermapProviderType())
|
||||
.config(config)
|
||||
.build()
|
||||
|
||||
client.getCurrentCondition(WeatherRequest(longitude, latitude), object : WeatherClient.WeatherEventListener {
|
||||
@SuppressLint("ApplySharedPref")
|
||||
override fun onWeatherRetrieved(currentWeather: CurrentWeather) {
|
||||
SP.edit()
|
||||
.putFloat(Constants.PREF_WEATHER_TEMP, currentWeather.weather.temperature.temp)
|
||||
.putString(Constants.PREF_WEATHER_ICON, currentWeather.weather.currentCondition.icon)
|
||||
.putString(Constants.PREF_WEATHER_REAL_TEMP_UNIT, SP.getString(Constants.PREF_WEATHER_TEMP_UNIT, "F"))
|
||||
.commit()
|
||||
Util.updateWidget(context)
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
override fun onWeatherError(e: WeatherLibException?) {
|
||||
// removeWeather(context, SP)
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
override fun onConnectionError(throwable: Throwable?) {
|
||||
// removeWeather(context, SP)
|
||||
}
|
||||
})
|
||||
} catch (t: Exception) {
|
||||
// removeWeather(context, SP)
|
||||
}
|
||||
} else {
|
||||
removeWeather(context, SP)
|
||||
}
|
||||
}
|
||||
|
||||
fun getWeatherProviderKeyConstant(context: Context, SP: SharedPreferences): String {
|
||||
return when (SP.getInt(Constants.PREF_WEATHER_PROVIDER, Constants.WEATHER_PROVIDER_GOOGLE_AWARENESS)) {
|
||||
Constants.WEATHER_PROVIDER_OPEN_WEATHER -> Constants.PREF_OPEN_WEATHER_API_KEY
|
||||
Constants.WEATHER_PROVIDER_DARK_SKY -> Constants.PREF_DARK_SKY_API_KEY
|
||||
Constants.WEATHER_PROVIDER_WU -> Constants.PREF_WU_API_KEY
|
||||
else -> Constants.PREF_OPEN_WEATHER_API_KEY
|
||||
}
|
||||
}
|
||||
|
||||
fun getWeatherProviderKey(context: Context, SP: SharedPreferences): String {
|
||||
return SP.getString(getWeatherProviderKeyConstant(context, SP), "")
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
fun removeWeather(context: Context, SP: SharedPreferences) {
|
||||
SP.edit().
|
||||
remove(Constants.PREF_WEATHER_TEMP)
|
||||
.remove(Constants.PREF_WEATHER_ICON)
|
||||
.commit()
|
||||
Util.updateWidget(context)
|
||||
}
|
||||
|
||||
fun getIconCodeFromAwareness(context: Context, conditions: IntArray): String {
|
||||
var icon = ""
|
||||
return if (conditions.contains(Weather.CONDITION_UNKNOWN)) {
|
||||
""
|
||||
} else {
|
||||
if (conditions.contains(Weather.CONDITION_CLEAR)) {
|
||||
icon = "01"
|
||||
} else if (conditions.contains(Weather.CONDITION_CLOUDY)) {
|
||||
icon = "02"
|
||||
} else if (conditions.contains(Weather.CONDITION_RAINY)) {
|
||||
icon = "10"
|
||||
} else if (conditions.contains(Weather.CONDITION_STORMY)) {
|
||||
icon = "09"
|
||||
} else if (conditions.contains(Weather.CONDITION_SNOWY)) {
|
||||
icon = "13"
|
||||
} else if (conditions.contains(Weather.CONDITION_WINDY)) {
|
||||
icon = "80"
|
||||
} else if (conditions.contains(Weather.CONDITION_HAZY)) {
|
||||
icon = "50"
|
||||
} else if (conditions.contains(Weather.CONDITION_ICY)) {
|
||||
icon = "81"
|
||||
} else if (conditions.contains(Weather.CONDITION_FOGGY)) {
|
||||
icon = "82"
|
||||
}
|
||||
|
||||
return if (Calendar.getInstance().get(Calendar.HOUR_OF_DAY) >= 19 || Calendar.getInstance().get(Calendar.HOUR_OF_DAY) < 7) {
|
||||
icon + "n"
|
||||
} else {
|
||||
icon + "d"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getWeatherIconResource(icon: String): Int {
|
||||
when (icon) {
|
||||
"01d" -> {
|
||||
return R.drawable.clear_day
|
||||
}
|
||||
"02d" -> {
|
||||
return R.drawable.partly_cloudy
|
||||
}
|
||||
"03d" -> {
|
||||
return R.drawable.mostly_cloudy
|
||||
}
|
||||
"04d" -> {
|
||||
return R.drawable.cloudy_weather
|
||||
}
|
||||
"09d" -> {
|
||||
return R.drawable.storm_weather_day
|
||||
}
|
||||
"10d" -> {
|
||||
return R.drawable.rainy_day
|
||||
}
|
||||
"11d" -> {
|
||||
return R.drawable.thunder_day
|
||||
}
|
||||
"13d" -> {
|
||||
return R.drawable.snow_day
|
||||
}
|
||||
"50d" -> {
|
||||
return R.drawable.haze_day
|
||||
}
|
||||
"80d" -> {
|
||||
return R.drawable.windy_day
|
||||
}
|
||||
"81d" -> {
|
||||
return R.drawable.rain_snow_day
|
||||
}
|
||||
"82d" -> {
|
||||
return R.drawable.haze_weather
|
||||
}
|
||||
|
||||
|
||||
|
||||
"01n" -> {
|
||||
return R.drawable.clear_night
|
||||
}
|
||||
"02n" -> {
|
||||
return R.drawable.partly_cloudy_night
|
||||
}
|
||||
"03n" -> {
|
||||
return R.drawable.mostly_cloudy_night
|
||||
}
|
||||
"04n" -> {
|
||||
return R.drawable.cloudy_weather
|
||||
}
|
||||
"09n" -> {
|
||||
return R.drawable.storm_weather_night
|
||||
}
|
||||
"10n" -> {
|
||||
return R.drawable.rainy_night
|
||||
}
|
||||
"11n" -> {
|
||||
return R.drawable.thunder_night
|
||||
}
|
||||
"13n" -> {
|
||||
return R.drawable.snow_night
|
||||
}
|
||||
"50n" -> {
|
||||
return R.drawable.haze_night
|
||||
}
|
||||
"80n" -> {
|
||||
return R.drawable.windy_night
|
||||
}
|
||||
"81n" -> {
|
||||
return R.drawable.rain_snow_night
|
||||
}
|
||||
"82n" -> {
|
||||
return R.drawable.haze_weather
|
||||
}
|
||||
else -> {
|
||||
return R.drawable.unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,26 +1,19 @@
|
||||
package com.tommasoberlose.anotherwidget.util
|
||||
package com.tommasoberlose.anotherwidget.utils
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ContentUris
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
import android.preference.PreferenceManager
|
||||
import android.provider.CalendarContract
|
||||
import android.util.Log
|
||||
import android.util.TimeUtils
|
||||
import android.widget.Toast
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.`object`.CalendarSelector
|
||||
import com.tommasoberlose.anotherwidget.`object`.Constants
|
||||
import com.tommasoberlose.anotherwidget.`object`.Event
|
||||
import com.chibatching.kotpref.blockingBulk
|
||||
import com.chibatching.kotpref.bulk
|
||||
import com.tommasoberlose.anotherwidget.components.events.Event
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmResults
|
||||
import me.everything.providers.android.calendar.CalendarProvider
|
||||
import me.everything.providers.android.contacts.ContactsProvider
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.Comparator
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
@ -31,13 +24,12 @@ import kotlin.collections.ArrayList
|
||||
object CalendarUtil {
|
||||
|
||||
fun updateEventList(context: Context) {
|
||||
val SP: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
if (SP.getBoolean(Constants.PREF_SHOW_EVENTS, true)) {
|
||||
if (Preferences.showEvents) {
|
||||
val eventList = ArrayList<Event>()
|
||||
|
||||
val now = Calendar.getInstance()
|
||||
val limit = Calendar.getInstance()
|
||||
when (SP.getInt(Constants.PREF_SHOW_UNTIL, 1)) {
|
||||
when (Preferences.showUntil) {
|
||||
0 -> limit.add(Calendar.HOUR, 3)
|
||||
1 -> limit.add(Calendar.HOUR, 6)
|
||||
2 -> limit.add(Calendar.HOUR, 12)
|
||||
@ -49,7 +41,6 @@ object CalendarUtil {
|
||||
else -> limit.add(Calendar.HOUR, 6)
|
||||
}
|
||||
|
||||
|
||||
val builder = CalendarContract.Instances.CONTENT_URI.buildUpon()
|
||||
ContentUris.appendId(builder, now.timeInMillis)
|
||||
ContentUris.appendId(builder, limit.timeInMillis)
|
||||
@ -64,7 +55,7 @@ object CalendarUtil {
|
||||
for (instance in instances) {
|
||||
try {
|
||||
val e = provider.getEvent(instance.eventId)
|
||||
if (e != null && instance.begin <= limit.timeInMillis && (SP.getBoolean(Constants.PREF_CALENDAR_ALL_DAY, false) || !e.allDay) && !(SP.getString(Constants.PREF_CALENDAR_FILTER, "").contains(" " + e.calendarId + ",")) && (SP.getBoolean(Constants.PREF_SHOW_DECLINED_EVENTS, true) || !e.selfAttendeeStatus.equals(CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED))) {
|
||||
if (e != null && instance.begin <= limit.timeInMillis && (Preferences.calendarAllDay || !e.allDay) && !(Preferences.calendarFilter.contains(" " + e.calendarId + ",")) && (Preferences.showDeclinedEvents || e.selfAttendeeStatus.toInt() != CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED)) {
|
||||
if (e.allDay) {
|
||||
val start = Calendar.getInstance()
|
||||
start.timeInMillis = instance.begin
|
||||
@ -94,7 +85,7 @@ object CalendarUtil {
|
||||
}
|
||||
})
|
||||
eventList.reverse()
|
||||
saveEvents(context, eventList)
|
||||
saveEvents(eventList)
|
||||
saveNextEventData(context, eventList[0])
|
||||
}
|
||||
}
|
||||
@ -102,6 +93,8 @@ object CalendarUtil {
|
||||
resetNextEventData(context)
|
||||
}
|
||||
|
||||
UpdatesReceiver.setUpdates(context)
|
||||
Util.updateWidget(context)
|
||||
}
|
||||
|
||||
fun getCalendarList(context: Context): List<me.everything.providers.android.calendar.Calendar> {
|
||||
@ -112,104 +105,82 @@ object CalendarUtil {
|
||||
}
|
||||
val provider = CalendarProvider(context)
|
||||
val data = provider.calendars
|
||||
if (data != null) {
|
||||
return data.list
|
||||
return if (data != null) {
|
||||
data.list
|
||||
} else {
|
||||
return calendarList
|
||||
calendarList
|
||||
}
|
||||
}
|
||||
|
||||
fun saveEvents(context: Context, eventList: ArrayList<Event>) {
|
||||
val db = Util.getRealInstance(context)
|
||||
db.executeTransaction { realm ->
|
||||
private fun saveEvents(eventList: ArrayList<Event>) {
|
||||
Realm.getDefaultInstance().executeTransactionAsync { realm ->
|
||||
realm.where(Event::class.java).findAll().deleteAllFromRealm()
|
||||
realm.copyToRealm(eventList)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
fun resetNextEventData(context: Context) {
|
||||
val db = Util.getRealInstance(context)
|
||||
db.executeTransaction {
|
||||
db.where(Event::class.java).findAll().deleteAllFromRealm()
|
||||
private fun resetNextEventData(context: Context) {
|
||||
Realm.getDefaultInstance().executeTransactionAsync {
|
||||
it.where(Event::class.java).findAll().deleteAllFromRealm()
|
||||
}
|
||||
val SP: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
SP.edit()
|
||||
.remove(Constants.PREF_EVENT_ID)
|
||||
.remove(Constants.PREF_NEXT_EVENT_ID)
|
||||
.remove(Constants.PREF_NEXT_EVENT_NAME)
|
||||
.remove(Constants.PREF_NEXT_EVENT_START_DATE)
|
||||
.remove(Constants.PREF_NEXT_EVENT_END_DATE)
|
||||
.remove(Constants.PREF_NEXT_EVENT_ALL_DAY)
|
||||
.remove(Constants.PREF_NEXT_EVENT_CALENDAR_ID)
|
||||
.remove(Constants.PREF_NEXT_EVENT_LOCATION)
|
||||
.commit()
|
||||
|
||||
Preferences.bulk {
|
||||
remove(Preferences::nextEventId)
|
||||
remove(Preferences::nextEventName)
|
||||
remove(Preferences::nextEventStartDate)
|
||||
remove(Preferences::nextEventAllDay)
|
||||
remove(Preferences::nextEventLocation)
|
||||
remove(Preferences::nextEventEndDate)
|
||||
remove(Preferences::nextEventCalendarId)
|
||||
}
|
||||
|
||||
Util.updateWidget(context)
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
fun saveNextEventData(context: Context, event: Event) {
|
||||
val SP: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
SP.edit()
|
||||
.putLong(Constants.PREF_EVENT_ID, event.id)
|
||||
.commit()
|
||||
private fun saveNextEventData(context: Context, event: Event) {
|
||||
Preferences.nextEventId = event.id
|
||||
Util.updateWidget(context)
|
||||
}
|
||||
|
||||
fun getNextEvent(context: Context): Event {
|
||||
val SP: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val db = Util.getRealInstance(context)
|
||||
val nextEvent = db.where(Event::class.java).equalTo("id", SP.getLong(Constants.PREF_EVENT_ID, 0)).findFirst()
|
||||
return if (nextEvent != null) {
|
||||
nextEvent
|
||||
} else {
|
||||
val eventList = db.where(Event::class.java).findAll()
|
||||
if (eventList.isNotEmpty()) {
|
||||
eventList[0] ?: Event()
|
||||
} else {
|
||||
Event()
|
||||
}
|
||||
}
|
||||
fun getNextEvent(): Event? {
|
||||
val realm = Realm.getDefaultInstance()
|
||||
return realm.where(Event::class.java).equalTo("id", Preferences.nextEventId).findFirst() ?: realm.where(Event::class.java).findFirst()
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
fun goToNextEvent(context: Context) {
|
||||
val db = Util.getRealInstance(context)
|
||||
val SP: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val eventList = db.where(Event::class.java).findAll()
|
||||
val eventList = Realm.getDefaultInstance().where(Event::class.java).findAll()
|
||||
|
||||
if (eventList.isNotEmpty()) {
|
||||
var found = false
|
||||
for (e in eventList) {
|
||||
if (e.id == SP.getLong(Constants.PREF_EVENT_ID, 0)) {
|
||||
if (eventList.indexOf(e) < eventList.size - 1) {
|
||||
SP.edit()
|
||||
.putLong(Constants.PREF_EVENT_ID, eventList[eventList.indexOf(e) + 1]?.id ?: 0)
|
||||
.commit()
|
||||
} else {
|
||||
SP.edit()
|
||||
.putLong(Constants.PREF_EVENT_ID, eventList[0]?.id ?: 0)
|
||||
.commit()
|
||||
}
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
SP.edit()
|
||||
.putLong(Constants.PREF_EVENT_ID, eventList[0]?.id ?: 0)
|
||||
.commit()
|
||||
val index = eventList.indexOfFirst { it.id == Preferences.nextEventId }
|
||||
if (index > -1 && index < eventList.size - 1) {
|
||||
Preferences.nextEventId = eventList[index + 1]!!.id
|
||||
} else {
|
||||
Preferences.nextEventId = eventList.first()!!.id
|
||||
}
|
||||
} else {
|
||||
resetNextEventData(context)
|
||||
}
|
||||
|
||||
context.sendBroadcast(Intent(Constants.ACTION_TIME_UPDATE))
|
||||
UpdatesReceiver.setUpdates(context)
|
||||
Util.updateWidget(context)
|
||||
}
|
||||
|
||||
fun getEventsCount(context: Context): Int {
|
||||
val db = Util.getRealInstance(context)
|
||||
return db.where(Event::class.java).findAll().size
|
||||
fun goToPreviousEvent(context: Context) {
|
||||
val eventList = Realm.getDefaultInstance().where(Event::class.java).findAll()
|
||||
|
||||
if (eventList.isNotEmpty()) {
|
||||
val index = eventList.indexOfFirst { it.id == Preferences.nextEventId }
|
||||
if (index > 0) {
|
||||
Preferences.nextEventId = eventList[index - 1]!!.id
|
||||
} else {
|
||||
Preferences.nextEventId = eventList.last()!!.id
|
||||
}
|
||||
} else {
|
||||
resetNextEventData(context)
|
||||
}
|
||||
UpdatesReceiver.setUpdates(context)
|
||||
Util.updateWidget(context)
|
||||
}
|
||||
|
||||
fun getEvents(): RealmResults<Event> = Realm.getDefaultInstance().where(Event::class.java).findAll()
|
||||
fun getEventsCount(): Int = Realm.getDefaultInstance().where(Event::class.java).findAll().size
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
package com.tommasoberlose.anotherwidget.utils
|
||||
|
||||
import android.content.pm.PackageManager
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.view.ViewAnimationUtils
|
||||
import android.widget.Toast
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.app.Activity
|
||||
import android.content.*
|
||||
import android.net.Uri
|
||||
import androidx.browser.customtabs.CustomTabsIntent
|
||||
import androidx.core.content.ContextCompat
|
||||
import android.content.res.Configuration
|
||||
import android.provider.Settings
|
||||
import android.util.Patterns
|
||||
import java.security.NoSuchAlgorithmException
|
||||
import kotlin.math.max
|
||||
import android.content.Intent
|
||||
import android.util.TypedValue
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
|
||||
|
||||
fun PackageManager.missingSystemFeature(name: String): Boolean = !hasSystemFeature(name)
|
||||
|
||||
fun Context.toast(message: String) {
|
||||
val toast = Toast.makeText(this, message, Toast.LENGTH_SHORT)
|
||||
// toast.setGravity(Gravity.CENTER, 0, 0)
|
||||
toast.show()
|
||||
}
|
||||
|
||||
fun Int.toPixel(context: Context): Int = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), context.resources.displayMetrics).toInt()
|
||||
fun Float.toPixel(context: Context): Float = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this, context.resources.displayMetrics)
|
||||
|
||||
fun View.reveal(initialX: Int, initialY: Int) {
|
||||
when (visibility) {
|
||||
View.VISIBLE -> {
|
||||
val anim = ViewAnimationUtils.createCircularReveal(this, initialX, initialY, max(width.toFloat(), height.toFloat()), 0f)
|
||||
.apply {
|
||||
duration = 200
|
||||
}
|
||||
anim.addListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
visibility = View.GONE
|
||||
super.onAnimationEnd(animation)
|
||||
}
|
||||
})
|
||||
anim.start()
|
||||
} else -> {
|
||||
val anim = ViewAnimationUtils.createCircularReveal(this, initialX, initialY, 0f, max(width.toFloat(), height.toFloat()))
|
||||
.apply {
|
||||
duration = 200
|
||||
}
|
||||
visibility = View.VISIBLE
|
||||
anim.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.openURI(url: String) {
|
||||
try {
|
||||
val builder: CustomTabsIntent.Builder = CustomTabsIntent.Builder()
|
||||
builder.setToolbarColor(ContextCompat.getColor(this, R.color.colorPrimary))
|
||||
val customTabsIntent: CustomTabsIntent = builder.build()
|
||||
customTabsIntent.launchUrl(this, Uri.parse(url))
|
||||
} catch (e: Exception) {
|
||||
try {
|
||||
val openIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
||||
startActivity(openIntent)
|
||||
} catch (ignored: Exception) {
|
||||
val clipboard: ClipboardManager = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText(getString(R.string.app_name), url)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
Toast.makeText(this, R.string.error_opening_uri, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.isTablet(): Boolean {
|
||||
return (resources.configuration.screenLayout and Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE
|
||||
}
|
||||
|
||||
fun String.md5(): String {
|
||||
val MD5 = "MD5"
|
||||
try {
|
||||
// Create MD5 Hash
|
||||
val digest = java.security.MessageDigest
|
||||
.getInstance(MD5)
|
||||
digest.update(toByteArray())
|
||||
val messageDigest = digest.digest()
|
||||
|
||||
// Create Hex String
|
||||
val hexString = StringBuilder()
|
||||
for (aMessageDigest in messageDigest) {
|
||||
var h = Integer.toHexString(0xFF and aMessageDigest.toInt())
|
||||
while (h.length < 2)
|
||||
h = "0$h"
|
||||
hexString.append(h)
|
||||
}
|
||||
return hexString.toString()
|
||||
|
||||
} catch (e: NoSuchAlgorithmException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
fun String.isValidEmail(): Boolean
|
||||
= this.isNotEmpty() &&
|
||||
Patterns.EMAIL_ADDRESS.matcher(this).matches()
|
||||
|
||||
fun Activity.isDarkTheme(): Boolean {
|
||||
return resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
|
||||
}
|
||||
|
||||
fun Activity.isNotificationAccessGranted(): Boolean = Settings.Secure.getString(this.contentResolver,"enabled_notification_listeners").contains(this.packageName)
|
||||
|
||||
//fun Activity.sendEmailTo(email: String) {
|
||||
// val i = Intent(Intent.ACTION_VIEW).apply {
|
||||
// data = Uri.parse("mailto:$email")
|
||||
// }
|
||||
// try {
|
||||
// startActivity(Intent.createChooser(i, getString(R.string.settings_title_feedback)))
|
||||
// } catch (ex: java.lang.Exception) {
|
||||
// toast(getString(R.string.generic_error))
|
||||
// }
|
||||
//
|
||||
//}
|
521
app/src/main/java/com/tommasoberlose/anotherwidget/utils/Util.kt
Normal file
@ -0,0 +1,521 @@
|
||||
package com.tommasoberlose.anotherwidget.utils
|
||||
|
||||
import android.app.*
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.*
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Resources
|
||||
import android.graphics.*
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import android.util.DisplayMetrics
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.util.TypedValue
|
||||
import android.content.Intent
|
||||
import android.content.ComponentName
|
||||
import android.provider.AlarmClock
|
||||
import android.provider.CalendarContract
|
||||
import android.text.format.DateFormat
|
||||
import android.text.format.DateUtils
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.Transformation
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.drawable.DrawableCompat
|
||||
import com.tommasoberlose.anotherwidget.components.events.Event
|
||||
import com.tommasoberlose.anotherwidget.global.Actions
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.ui.widgets.TheWidget
|
||||
import org.joda.time.DateTime
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
/**
|
||||
* Created by tommaso on 05/10/17.
|
||||
*/
|
||||
|
||||
object Util {
|
||||
|
||||
fun checkGrantedPermission(context: Context, permission: String): Boolean {
|
||||
return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
fun updateWidget(context: Context) {
|
||||
val widgetManager = AppWidgetManager.getInstance(context)
|
||||
val widgetComponent = ComponentName(context, TheWidget::class.java)
|
||||
val widgetIds = widgetManager.getAppWidgetIds(widgetComponent)
|
||||
val update = Intent(context, TheWidget::class.java)
|
||||
update.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, widgetIds)
|
||||
update.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
||||
context.sendBroadcast(update)
|
||||
}
|
||||
|
||||
fun showWeatherErrorNotification(context: Context) {
|
||||
TODO("weather notification")
|
||||
// val mNotificationManager: NotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
// val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
// val SP = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
//
|
||||
// if (SP.getBoolean(Constants.PREF_SHOW_GPS_NOTIFICATION, true) && !locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) && SP.getInt(Constants.PREF_WEATHER_PROVIDER, Constants.WEATHER_PROVIDER_GOOGLE_AWARENESS) == Constants.WEATHER_PROVIDER_GOOGLE_AWARENESS) {
|
||||
// val settingsIntent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
|
||||
// val pi: PendingIntent = PendingIntent.getActivity(context, 50, settingsIntent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
//
|
||||
// val providerIntent2 = Intent(context, MainActivity::class.java)
|
||||
// providerIntent2.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
// providerIntent2.putExtra(Constants.ACTION_EXTRA_OPEN_WEATHER_PROVIDER, true)
|
||||
// val pi2: PendingIntent = PendingIntent.getActivity(context, 51, providerIntent2, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
//
|
||||
// val providerIntentDisable = Intent(context, MainActivity::class.java)
|
||||
// providerIntentDisable.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
// providerIntentDisable.putExtra(Constants.ACTION_EXTRA_DISABLE_GPS_NOTIFICATION, true)
|
||||
// val piDisable: PendingIntent = PendingIntent.getActivity(context, 52, providerIntentDisable, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
//
|
||||
// val mBuilder: NotificationCompat.Builder = NotificationCompat.Builder(context, "Error")
|
||||
// .setSmallIcon(R.drawable.ic_stat_name)
|
||||
// .setColor(ContextCompat.getColor(context, R.color.colorPrimary))
|
||||
// .setContentTitle(context.getString(R.string.notification_gps_title))
|
||||
// .setContentText(context.getString(R.string.notification_gps_subtitle))
|
||||
// .addAction(R.drawable.ic_action_sync, context.getString(R.string.change_provider), pi2)
|
||||
// .addAction(R.drawable.ic_action_settings, context.getString(R.string.disable_notification), piDisable)
|
||||
// .setContentIntent(pi)
|
||||
//
|
||||
// mNotificationManager.notify(10, mBuilder.build());
|
||||
// } else {
|
||||
// mNotificationManager.cancel(10)
|
||||
// }
|
||||
}
|
||||
|
||||
fun getGoogleMapsIntentFromAddress(context: Context, address:String): Intent {
|
||||
val gmmIntentUri: Uri = Uri.parse("geo:0,0?q=$address")
|
||||
val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
|
||||
mapIntent.`package` = "com.google.android.apps.maps"
|
||||
|
||||
return if (mapIntent.resolveActivity(context.packageManager) != null) {
|
||||
mapIntent
|
||||
} else {
|
||||
val map = "http://maps.google.co.in/maps?q=$address"
|
||||
val i = Intent(Intent.ACTION_VIEW, Uri.parse(map));
|
||||
i
|
||||
}
|
||||
}
|
||||
|
||||
fun getCurrentWallpaper(context: Context): Drawable? = try {
|
||||
WallpaperManager.getInstance(context).drawable
|
||||
} catch (e: Exception) {
|
||||
// BitmapDrawable(context.resources, getResizedBitmap(BitmapFactory.decodeResource(context.resources, R.drawable.pixel_2_wallpaper), 800))
|
||||
null
|
||||
}
|
||||
|
||||
fun getBitmapFromView(view: View): Bitmap {
|
||||
//Define a bitmap with the same size as the view
|
||||
val measuredWidth = View.MeasureSpec.makeMeasureSpec(view.width, View.MeasureSpec.UNSPECIFIED)
|
||||
val measuredHeight = View.MeasureSpec.makeMeasureSpec(view.height, View.MeasureSpec.UNSPECIFIED)
|
||||
view.measure(measuredWidth, measuredHeight)
|
||||
view.layout(0,0, measuredWidth, measuredHeight)
|
||||
val returnedBitmap = Bitmap.createBitmap(view.measuredWidth, view.measuredHeight, Bitmap.Config.ARGB_8888)
|
||||
//Bind a canvas to it
|
||||
val canvas = Canvas(returnedBitmap)
|
||||
// draw the view on the canvas
|
||||
view.draw(canvas)
|
||||
//return the bitmap
|
||||
return returnedBitmap
|
||||
}
|
||||
|
||||
fun getBitmapFromView(view: View, w: Int, h: Int): Bitmap {
|
||||
//Define a bitmap with the same size as the view
|
||||
val measuredWidth = View.MeasureSpec.makeMeasureSpec(w, View.MeasureSpec.EXACTLY)
|
||||
val measuredHeight = View.MeasureSpec.makeMeasureSpec(h, View.MeasureSpec.EXACTLY)
|
||||
view.measure(measuredWidth, measuredHeight)
|
||||
view.layout(0,0, measuredWidth, measuredHeight)
|
||||
val returnedBitmap = Bitmap.createBitmap(view.measuredWidth, view.measuredHeight, Bitmap.Config.ARGB_8888)
|
||||
//Bind a canvas to it
|
||||
val canvas = Canvas(returnedBitmap)
|
||||
// draw the view on the canvas
|
||||
view.draw(canvas)
|
||||
//return the bitmap
|
||||
return returnedBitmap
|
||||
}
|
||||
|
||||
fun convertDpToPixel(dp: Float, context: Context): Float {
|
||||
val resources: Resources = context.resources
|
||||
val metrics: DisplayMetrics = resources.displayMetrics
|
||||
val px: Float = dp * (metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT)
|
||||
return px
|
||||
}
|
||||
|
||||
fun convertSpToPixels(sp: Float, context: Context): Float {
|
||||
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.resources.displayMetrics)
|
||||
}
|
||||
|
||||
fun getResizedBitmap(image: Bitmap, maxSize: Int): Bitmap {
|
||||
var width = image.width
|
||||
var height = image.height
|
||||
|
||||
val bitmapRatio = width.toFloat() / height.toFloat()
|
||||
if (bitmapRatio > 1) {
|
||||
width = maxSize
|
||||
height = (width / bitmapRatio).toInt()
|
||||
} else {
|
||||
height = maxSize
|
||||
width = (height * bitmapRatio).toInt()
|
||||
}
|
||||
|
||||
return Bitmap.createScaledBitmap(image, width, height, true)
|
||||
}
|
||||
|
||||
fun getRefreshPeriodString(period: Int): Int {
|
||||
return when (period) {
|
||||
0 -> R.string.settings_weather_refresh_period_subtitle_0
|
||||
1 -> R.string.settings_weather_refresh_period_subtitle_1
|
||||
2 -> R.string.settings_weather_refresh_period_subtitle_2
|
||||
3 -> R.string.settings_weather_refresh_period_subtitle_3
|
||||
4 -> R.string.settings_weather_refresh_period_subtitle_4
|
||||
5 -> R.string.settings_weather_refresh_period_subtitle_5
|
||||
else -> R.string.settings_weather_refresh_period_subtitle_0
|
||||
}
|
||||
}
|
||||
|
||||
fun getShowUntilString(period: Int): Int {
|
||||
return when (period) {
|
||||
0 -> R.string.settings_show_until_subtitle_0
|
||||
1 -> R.string.settings_show_until_subtitle_1
|
||||
2 -> R.string.settings_show_until_subtitle_2
|
||||
3 -> R.string.settings_show_until_subtitle_3
|
||||
4 -> R.string.settings_show_until_subtitle_4
|
||||
5 -> R.string.settings_show_until_subtitle_5
|
||||
6 -> R.string.settings_show_until_subtitle_6
|
||||
7 -> R.string.settings_show_until_subtitle_7
|
||||
else -> R.string.settings_show_until_subtitle_1
|
||||
}
|
||||
}
|
||||
|
||||
fun getSecondRowInfoString(info: Int): Int {
|
||||
return when (info) {
|
||||
0 -> R.string.settings_second_row_info_subtitle_0
|
||||
1 -> R.string.settings_second_row_info_subtitle_1
|
||||
2 -> R.string.settings_second_row_info_subtitle_2
|
||||
else -> R.string.settings_second_row_info_subtitle_0
|
||||
}
|
||||
}
|
||||
|
||||
fun getTextShadowString(shadow: Int): Int {
|
||||
return when (shadow) {
|
||||
0 -> R.string.settings_text_shadow_subtitle_none
|
||||
1 -> R.string.settings_text_shadow_subtitle_low
|
||||
2 -> R.string.settings_text_shadow_subtitle_high
|
||||
else -> R.string.settings_text_shadow_subtitle_low
|
||||
}
|
||||
}
|
||||
|
||||
fun getCustomFontLabel(shadow: Int): Int {
|
||||
return when (shadow) {
|
||||
0 -> R.string.custom_font_subtitle_0
|
||||
1 -> R.string.custom_font_subtitle_1
|
||||
else -> R.string.custom_font_subtitle_1
|
||||
}
|
||||
}
|
||||
|
||||
fun getCalendarIntent(context: Context): Intent {
|
||||
return when (Preferences.calendarAppPackage) {
|
||||
"" -> {
|
||||
Intent(Intent.ACTION_MAIN).apply {
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
addCategory(Intent.CATEGORY_APP_CALENDAR)
|
||||
}
|
||||
}
|
||||
"_" -> {
|
||||
Intent()
|
||||
}
|
||||
else -> {
|
||||
val pm: PackageManager = context.packageManager
|
||||
try {
|
||||
pm.getLaunchIntentForPackage(Preferences.calendarAppPackage)!!.apply {
|
||||
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
Intent(Intent.ACTION_MAIN).apply {
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
addCategory(Intent.CATEGORY_APP_CALENDAR)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getWeatherIntent(context: Context): Intent {
|
||||
return when (Preferences.weatherAppPackage) {
|
||||
"" -> {
|
||||
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")
|
||||
}
|
||||
}
|
||||
"_" -> {
|
||||
Intent()
|
||||
}
|
||||
else -> {
|
||||
val pm: PackageManager = context.packageManager
|
||||
try {
|
||||
pm.getLaunchIntentForPackage(Preferences.weatherAppPackage)!!.apply {
|
||||
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getEventIntent(context: Context, e: Event): Intent {
|
||||
return when (Preferences.eventAppPackage) {
|
||||
"" -> {
|
||||
val uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, e.eventID)
|
||||
Intent(Intent.ACTION_VIEW).apply {
|
||||
data = uri
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
putExtra("beginTime", e.startDate)
|
||||
putExtra("endTime", e.endDate)
|
||||
}
|
||||
}
|
||||
"_" -> {
|
||||
Intent()
|
||||
}
|
||||
else -> {
|
||||
val pm: PackageManager = context.packageManager
|
||||
try {
|
||||
pm.getLaunchIntentForPackage(Preferences.eventAppPackage)!!.apply {
|
||||
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
val uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, e.id)
|
||||
Intent(Intent.ACTION_VIEW).apply {
|
||||
data = uri
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
putExtra("beginTime", e.startDate)
|
||||
putExtra("endTime", e.endDate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getClockIntent(context: Context): Intent {
|
||||
return when (Preferences.clockAppPackage) {
|
||||
"" -> {
|
||||
Intent(AlarmClock.ACTION_SHOW_ALARMS).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
}
|
||||
}
|
||||
"_" -> {
|
||||
Intent()
|
||||
}
|
||||
else -> {
|
||||
val pm: PackageManager = context.packageManager
|
||||
try {
|
||||
pm.getLaunchIntentForPackage(Preferences.clockAppPackage)!!.apply {
|
||||
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Intent(AlarmClock.ACTION_SHOW_ALARMS).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getCapWordString(text: String): String {
|
||||
return try {
|
||||
val ar = text.split(" ")
|
||||
var newText = ""
|
||||
for (t: String in ar) {
|
||||
newText += " "
|
||||
newText += t.substring(0, 1).toUpperCase(Locale.getDefault())
|
||||
newText += t.substring(1)
|
||||
}
|
||||
newText.substring(1)
|
||||
} catch (e: Exception) {
|
||||
text
|
||||
}
|
||||
}
|
||||
|
||||
fun showLocationNotification(context: Context, show: Boolean) {
|
||||
TODO("Show location notification")
|
||||
// val mNotificationManager: NotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
|
||||
//
|
||||
// if (show) {
|
||||
// val mBuilder: NotificationCompat.Builder = NotificationCompat.Builder(context, "Config")
|
||||
// .setSmallIcon(R.drawable.ic_stat_name)
|
||||
// .setPriority(Notification.PRIORITY_MIN)
|
||||
// .setColor(ContextCompat.getColor(context, R.color.colorPrimary))
|
||||
// .setContentTitle(context.getString(R.string.notification_gps_title))
|
||||
// .setContentText(context.getString(R.string.notification_gps_subtitle))
|
||||
// .setAutoCancel(true);
|
||||
//
|
||||
// val intent: Intent = Intent( Settings.ACTION_LOCATION_SOURCE_SETTINGS);
|
||||
// val pi: PendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
// mBuilder.setContentIntent(pi);
|
||||
// mNotificationManager.notify(1, mBuilder.build());
|
||||
// } else {
|
||||
// mNotificationManager.cancel(1);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
fun showWeatherNotification(context: Context, show: Boolean) {
|
||||
TODO("Show location notification")
|
||||
// val mNotificationManager: NotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
|
||||
//
|
||||
// if (show) {
|
||||
// val mBuilder: NotificationCompat.Builder = NotificationCompat.Builder(context, "Config")
|
||||
// .setSmallIcon(R.drawable.ic_stat_name)
|
||||
// .setColor(ContextCompat.getColor(context, R.color.colorPrimary))
|
||||
// .setContentTitle(context.getString(R.string.settings_weather_provider_api_key_title))
|
||||
// .setContentText(context.getString(R.string.settings_weather_provider_api_key_subtitle_not_set))
|
||||
// .setAutoCancel(true);
|
||||
//
|
||||
// val intent: Intent = Intent(context, MainActivity::class.java);
|
||||
// intent.putExtra(Constants.ACTION_EXTRA_OPEN_WEATHER_PROVIDER, true)
|
||||
// val pi: PendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
// mBuilder.setContentIntent(pi);
|
||||
// mNotificationManager.notify(2, mBuilder.build());
|
||||
// } else {
|
||||
// mNotificationManager.cancel(2);
|
||||
// }
|
||||
}
|
||||
|
||||
fun expand(v: View) {
|
||||
if (v.visibility != View.VISIBLE) {
|
||||
v.measure(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
|
||||
val targetHeight = v.measuredHeight
|
||||
|
||||
v.layoutParams.height = 0
|
||||
v.visibility = View.VISIBLE
|
||||
val a = object : Animation() {
|
||||
protected override fun applyTransformation(interpolatedTime: Float, t: Transformation) {
|
||||
v.layoutParams.height = if (interpolatedTime == 1f)
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
else
|
||||
(targetHeight * interpolatedTime).toInt()
|
||||
v.translationY = 0f
|
||||
v.requestLayout()
|
||||
}
|
||||
|
||||
override fun willChangeBounds(): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
a.duration = 500L
|
||||
v.startAnimation(a)
|
||||
}
|
||||
}
|
||||
|
||||
fun collapse(v: View) {
|
||||
if (v.visibility != View.GONE) {
|
||||
val initialHeight = v.measuredHeight
|
||||
|
||||
val a = object : Animation() {
|
||||
protected override fun applyTransformation(interpolatedTime: Float, t: Transformation) {
|
||||
if (interpolatedTime == 1f) {
|
||||
v.visibility = View.GONE
|
||||
} else {
|
||||
v.layoutParams.height = initialHeight - (initialHeight * interpolatedTime).toInt()
|
||||
v.requestLayout()
|
||||
}
|
||||
}
|
||||
|
||||
override fun willChangeBounds(): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
a.duration = 500L //(initialHeight / v.context.resources.displayMetrics.density).toLong()
|
||||
v.startAnimation(a)
|
||||
}
|
||||
}
|
||||
|
||||
fun getEmojiByUnicode(unicode: Int): String {
|
||||
return String(Character.toChars(unicode))
|
||||
}
|
||||
|
||||
fun getDifferenceText(context: Context, now: Long, start: Long): String {
|
||||
val nowDate = DateTime(now)
|
||||
val eventDate = DateTime(start)
|
||||
|
||||
var difference = start - now
|
||||
difference += 60 * 1000 - (difference % (60 * 1000))
|
||||
|
||||
when {
|
||||
difference <= 0 || TimeUnit.MILLISECONDS.toHours(difference) < 1 -> {
|
||||
return ""
|
||||
}
|
||||
TimeUnit.MILLISECONDS.toHours(difference) < 12 -> {
|
||||
return DateUtils.getRelativeTimeSpanString(start, now, DateUtils.HOUR_IN_MILLIS).toString()
|
||||
}
|
||||
eventDate.dayOfYear == nowDate.plusDays(1).dayOfYear -> {
|
||||
return String.format("%s", context.getString(R.string.tomorrow))
|
||||
}
|
||||
eventDate.dayOfYear == nowDate.dayOfYear -> {
|
||||
return String.format("%s", context.getString(R.string.today))
|
||||
}
|
||||
else -> {
|
||||
return DateUtils.getRelativeTimeSpanString(start, now, DateUtils.DAY_IN_MILLIS).toString()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun getFontColor(): Int {
|
||||
return try {
|
||||
Color.parseColor(Preferences.textGlobalColor)
|
||||
} catch (e: Exception) {
|
||||
Color.parseColor("#FFFFFF")
|
||||
}
|
||||
}
|
||||
|
||||
fun getTintedDrawable(context: Context, inputDrawable: Int, color: Int): Drawable? = ContextCompat.getDrawable(context, inputDrawable)?.apply {
|
||||
DrawableCompat.setTint(this, color)
|
||||
DrawableCompat.setTintMode(this, PorterDuff.Mode.SRC_IN)
|
||||
}
|
||||
|
||||
fun changeBitmapColor(sourceBitmap: Bitmap, color: Int): Bitmap {
|
||||
val resultBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0,
|
||||
sourceBitmap.width - 1, sourceBitmap.height - 1)
|
||||
val p = Paint()
|
||||
val filter = PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)
|
||||
p.colorFilter = filter
|
||||
|
||||
val canvas = Canvas(resultBitmap)
|
||||
canvas.drawBitmap(resultBitmap, 0f, 0f, p)
|
||||
|
||||
return resultBitmap
|
||||
}
|
||||
|
||||
fun getNextAlarm(context: Context): String = with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||
return if (nextAlarmClock != null && nextAlarmClock.triggerTime - Calendar.getInstance().timeInMillis > 5 * 60 * 1000) {
|
||||
DateFormat.getTimeFormat(context).format(Date(nextAlarmClock.triggerTime))
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
package com.tommasoberlose.anotherwidget.utils
|
||||
|
||||
import android.content.Context
|
||||
import com.google.android.gms.location.LocationServices
|
||||
import com.kwabenaberko.openweathermaplib.constants.Units
|
||||
import com.kwabenaberko.openweathermaplib.implementation.OpenWeatherMapHelper
|
||||
import com.kwabenaberko.openweathermaplib.implementation.callbacks.CurrentWeatherCallback
|
||||
import com.kwabenaberko.openweathermaplib.models.currentweather.CurrentWeather
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
|
||||
|
||||
/**
|
||||
* Created by tommaso on 08/10/17.
|
||||
*/
|
||||
|
||||
object WeatherUtil {
|
||||
|
||||
fun updateWeather(context: Context) {
|
||||
if (Preferences.customLocationAdd != "") {
|
||||
weatherNetworkRequest(
|
||||
context
|
||||
)
|
||||
} else {
|
||||
LocationServices.getFusedLocationProviderClient(context).lastLocation.addOnSuccessListener {
|
||||
Preferences.customLocationLat = it.latitude.toString()
|
||||
Preferences.customLocationLon = it.longitude.toString()
|
||||
|
||||
weatherNetworkRequest(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun weatherNetworkRequest(context: Context) {
|
||||
if (Preferences.showWeather && Preferences.weatherProviderApi != "" && Preferences.customLocationLat != "" && Preferences.customLocationLon != "") {
|
||||
val helper = OpenWeatherMapHelper(Preferences.weatherProviderApi)
|
||||
helper.setUnits(if (Preferences.weatherTempUnit == "F") Units.IMPERIAL else Units.METRIC)
|
||||
helper.getCurrentWeatherByGeoCoordinates(Preferences.customLocationLat.toDouble(), Preferences.customLocationLon.toDouble(), object : CurrentWeatherCallback {
|
||||
override fun onSuccess(currentWeather: CurrentWeather?) {
|
||||
currentWeather?.let {
|
||||
Preferences.weatherTemp = currentWeather.main.temp.toFloat()
|
||||
Preferences.weatherIcon = currentWeather.weather[0].icon
|
||||
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
|
||||
Util.updateWidget(context)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(throwable: Throwable?) {
|
||||
}
|
||||
|
||||
})
|
||||
} else {
|
||||
removeWeather(context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeWeather(context: Context) {
|
||||
Preferences.remove(Preferences::weatherTemp)
|
||||
Preferences.remove(Preferences::weatherTempUnit)
|
||||
Util.updateWidget(context)
|
||||
}
|
||||
|
||||
fun getWeatherIconResource(icon: String): Int {
|
||||
when (icon) {
|
||||
"01d" -> {
|
||||
return R.drawable.clear_day
|
||||
}
|
||||
"02d" -> {
|
||||
return R.drawable.partly_cloudy
|
||||
}
|
||||
"03d" -> {
|
||||
return R.drawable.mostly_cloudy
|
||||
}
|
||||
"04d" -> {
|
||||
return R.drawable.cloudy_weather
|
||||
}
|
||||
"09d" -> {
|
||||
return R.drawable.storm_weather_day
|
||||
}
|
||||
"10d" -> {
|
||||
return R.drawable.rainy_day
|
||||
}
|
||||
"11d" -> {
|
||||
return R.drawable.thunder_day
|
||||
}
|
||||
"13d" -> {
|
||||
return R.drawable.snow_day
|
||||
}
|
||||
"50d" -> {
|
||||
return R.drawable.haze_day
|
||||
}
|
||||
"80d" -> {
|
||||
return R.drawable.windy_day
|
||||
}
|
||||
"81d" -> {
|
||||
return R.drawable.rain_snow_day
|
||||
}
|
||||
"82d" -> {
|
||||
return R.drawable.haze_weather
|
||||
}
|
||||
|
||||
|
||||
|
||||
"01n" -> {
|
||||
return R.drawable.clear_night
|
||||
}
|
||||
"02n" -> {
|
||||
return R.drawable.partly_cloudy_night
|
||||
}
|
||||
"03n" -> {
|
||||
return R.drawable.mostly_cloudy_night
|
||||
}
|
||||
"04n" -> {
|
||||
return R.drawable.cloudy_weather
|
||||
}
|
||||
"09n" -> {
|
||||
return R.drawable.storm_weather_night
|
||||
}
|
||||
"10n" -> {
|
||||
return R.drawable.rainy_night
|
||||
}
|
||||
"11n" -> {
|
||||
return R.drawable.thunder_night
|
||||
}
|
||||
"13n" -> {
|
||||
return R.drawable.snow_night
|
||||
}
|
||||
"50n" -> {
|
||||
return R.drawable.haze_night
|
||||
}
|
||||
"80n" -> {
|
||||
return R.drawable.windy_night
|
||||
}
|
||||
"81n" -> {
|
||||
return R.drawable.rain_snow_night
|
||||
}
|
||||
"82n" -> {
|
||||
return R.drawable.haze_weather
|
||||
}
|
||||
else -> {
|
||||
return R.drawable.unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:interpolator="@android:anim/accelerate_decelerate_interpolator">
|
||||
|
||||
<translate
|
||||
android:duration="@android:integer/config_longAnimTime"
|
||||
android:fromYDelta="0"
|
||||
android:toYDelta="100%p" />
|
||||
|
||||
</set>
|
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:interpolator="@android:anim/accelerate_decelerate_interpolator">
|
||||
|
||||
<translate
|
||||
android:duration="@android:integer/config_longAnimTime"
|
||||
android:fromYDelta="100%p"
|
||||
android:toYDelta="0" />
|
||||
|
||||
</set>
|
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<translate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:duration="@android:integer/config_longAnimTime"
|
||||
android:fromYDelta="0%p"
|
||||
android:toYDelta="0%p" />
|
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 896 B |
Before Width: | Height: | Size: 954 B |
Before Width: | Height: | Size: 306 B |
Before Width: | Height: | Size: 363 B |
Before Width: | Height: | Size: 332 B |
Before Width: | Height: | Size: 888 B |
Before Width: | Height: | Size: 888 B |
Before Width: | Height: | Size: 282 B |
Before Width: | Height: | Size: 945 B |
Before Width: | Height: | Size: 643 B |
Before Width: | Height: | Size: 945 B |
Before Width: | Height: | Size: 854 B |
Before Width: | Height: | Size: 874 B |
Before Width: | Height: | Size: 533 B |
Before Width: | Height: | Size: 624 B |
Before Width: | Height: | Size: 215 B |
Before Width: | Height: | Size: 307 B |
Before Width: | Height: | Size: 412 B |
Before Width: | Height: | Size: 861 B |
Before Width: | Height: | Size: 815 B |
Before Width: | Height: | Size: 529 B |
Before Width: | Height: | Size: 449 B |
Before Width: | Height: | Size: 389 B |
Before Width: | Height: | Size: 451 B |
Before Width: | Height: | Size: 421 B |
Before Width: | Height: | Size: 407 B |
Before Width: | Height: | Size: 607 B |
Before Width: | Height: | Size: 291 B |