Moving to version 2.0

This commit is contained in:
Tommaso Berlose 2020-05-01 01:09:56 +02:00
parent 05a0308f8f
commit 3aecf9851a
1039 changed files with 6754 additions and 5763 deletions

BIN
.idea/caches/build_file_checksums.ser generated Normal file

Binary file not shown.

122
.idea/codeStyles/Project.xml generated Normal file
View 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
View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

1
.idea/gradle.xml generated
View File

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

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

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

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

View File

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

View File

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

Binary file not shown.

View File

@ -1 +0,0 @@
[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":32},"path":"app-release.apk","properties":{"packageId":"com.tommasoberlose.anotherwidget","split":"","minSdkVersion":"19"}}]

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

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

View File

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

View File

@ -1,4 +1,4 @@
package com.tommasoberlose.anotherwidget.`object`
package com.tommasoberlose.anotherwidget.components
/**
* Created by tommaso on 08/10/17.

View File

@ -1,4 +1,4 @@
package com.tommasoberlose.anotherwidget.`object`
package com.tommasoberlose.anotherwidget.components.events
import android.content.pm.ApplicationInfo

View File

@ -1,4 +1,4 @@
package com.tommasoberlose.anotherwidget.`object`
package com.tommasoberlose.anotherwidget.components.events
import android.content.pm.ApplicationInfo

View File

@ -1,4 +1,4 @@
package com.tommasoberlose.anotherwidget.`object`
package com.tommasoberlose.anotherwidget.components.events
import android.location.Address

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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 {
""
}
}
}

View File

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

View File

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

View File

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

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 896 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 954 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 306 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 363 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 888 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 888 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 945 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 643 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 945 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 854 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 874 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 533 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 624 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 307 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 412 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 861 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 815 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 529 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 449 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 389 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 451 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 421 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 407 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 607 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 B

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