Compare commits

...

13 Commits

163 changed files with 1395 additions and 549 deletions

1
.gitignore vendored
View File

@ -7,3 +7,4 @@
/build /build
/captures /captures
.externalNativeBuild .externalNativeBuild
/tasksintegration/build

Binary file not shown.

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Tommaso Berlose
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

20
README.md Normal file
View File

@ -0,0 +1,20 @@
<img src="hero.png"/>
Another Widget
========
Another Widget intelligently summarizes the information you need most.
Watch the next events, the weather, and the information you want in an intuitive and elegant way. (Nope, reminders cannot be displayed because it's not allowed.)
While respecting the design of the application, there is a great opportunity to customize the information displayed and widget components.
Also, as much as possible, there are always updates and new features in the short run.
Help me developing with feedback and support me on how you can.
<div style="text-align:center"><a href="https://play.google.com/store/apps/details?id=com.tommasoberlose.anotherwidget" target="_blank"><img src="google-play-badge.png" height="100" /></a></div>
License
-------
Copyright (C) 2017-2020 Tommaso Berlose (http://tommasoberlose.com)
Another Widget binaries and source code can be used according to the [MIT Licence](LICENSE).

View File

@ -18,7 +18,7 @@ android {
applicationId "com.tommasoberlose.anotherwidget" applicationId "com.tommasoberlose.anotherwidget"
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 29 targetSdkVersion 29
versionCode 59 versionCode 68
versionName "2.0.5" versionName "2.0.5"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@ -59,15 +59,14 @@ android {
dependencies { dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar']) implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 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' implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.13' testImplementation 'junit:junit:4.13'
androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
// UI // UI
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.android.material:material:1.2.0-alpha06' implementation 'com.google.android.material:material:1.2.0-alpha06'
implementation 'androidx.browser:browser:1.2.0' implementation 'androidx.browser:browser:1.2.0'
implementation 'net.idik:slimadapter:2.1.2' implementation 'net.idik:slimadapter:2.1.2'
@ -78,6 +77,8 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation "androidx.work:work-runtime-ktx:2.3.4"
// EventBus // EventBus
implementation 'org.greenrobot:eventbus:3.1.1' implementation 'org.greenrobot:eventbus:3.1.1'
@ -89,6 +90,8 @@ dependencies {
implementation 'androidx.multidex:multidex:2.0.1' implementation 'androidx.multidex:multidex:2.0.1'
implementation 'joda-time:joda-time:2.9.9' implementation 'joda-time:joda-time:2.9.9'
implementation 'me.everything:providers-android:1.0.1' implementation 'me.everything:providers-android:1.0.1'
//Glide
implementation 'com.github.bumptech.glide:glide:4.11.0' implementation 'com.github.bumptech.glide:glide:4.11.0'
kapt 'com.github.bumptech.glide:compiler:4.11.0' kapt 'com.github.bumptech.glide:compiler:4.11.0'
@ -104,6 +107,7 @@ dependencies {
implementation "androidx.core:core-ktx:1.2.0" implementation "androidx.core:core-ktx:1.2.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0" implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
implementation "androidx.palette:palette-ktx:1.0.0" implementation "androidx.palette:palette-ktx:1.0.0"
implementation 'androidx.core:core-ktx:1.2.0'
// Recommended: Add the Firebase SDK for Google Analytics. // Recommended: Add the Firebase SDK for Google Analytics.
implementation 'com.google.firebase:firebase-analytics:17.4.0' implementation 'com.google.firebase:firebase-analytics:17.4.0'

Binary file not shown.

View File

@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.tommasoberlose.anotherwidget"> package="com.tommasoberlose.anotherwidget">
<uses-permission android:name="android.permission.READ_CALENDAR" /> <uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="com.android.vending.BILLING" /> <uses-permission android:name="com.android.vending.BILLING" />
@ -16,19 +18,20 @@
android:name=".AWApplication" android:name=".AWApplication"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme"
<activity android:name=".ui.activities.MainActivity" android:launchMode="singleInstance" android:theme="@style/AppTheme.Main"> tools:ignore="LockedOrientationActivity">
<activity android:name=".ui.activities.MainActivity" android:launchMode="singleInstance" android:theme="@style/AppTheme.Main" android:screenOrientation="portrait">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name=".ui.activities.ChooseApplicationActivity" android:launchMode="singleInstance" /> <activity android:name=".ui.activities.ChooseApplicationActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.CustomLocationActivity" android:launchMode="singleInstance" /> <activity android:name=".ui.activities.CustomLocationActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.WeatherProviderActivity" android:launchMode="singleInstance" /> <activity android:name=".ui.activities.WeatherProviderActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.SupportDevActivity" android:launchMode="singleInstance" /> <activity android:name=".ui.activities.SupportDevActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.CustomDateActivity" android:launchMode="singleInstance" /> <activity android:name=".ui.activities.CustomDateActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
<receiver android:name=".ui.widgets.MainWidget"> <receiver android:name=".ui.widgets.MainWidget">
@ -62,11 +65,14 @@
<intent-filter> <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="com.tommasoberlose.anotherwidget.action.ACTION_CALENDAR_UPDATE" /> <action android:name="com.tommasoberlose.anotherwidget.action.ACTION_CALENDAR_UPDATE" />
<action android:name="com.tommasoberlose.anotherwidget.action.ACTION_TIME_UPDATE" />
<action android:name="com.sec.android.widgetapp.APPWIDGET_RESIZE" /> <action android:name="com.sec.android.widgetapp.APPWIDGET_RESIZE" />
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" /> <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
<action android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" /> <action android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
<action android:name="android.intent.action.DATE_CHANGED" /> <action android:name="android.intent.action.DATE_CHANGED" />
<action android:name="android.intent.action.TIME_SET" /> <action android:name="android.intent.action.TIME_SET" />
<action android:name="android.intent.action.TIMEZONE_CHANGED" />
<action android:name="android.intent.action.LOCALE_CHANGED" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver <receiver
@ -79,6 +85,8 @@
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" /> <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
<action android:name="android.intent.action.TIME_SET" /> <action android:name="android.intent.action.TIME_SET" />
<action android:name="android.intent.action.TIMEZONE_CHANGED" />
<action android:name="android.intent.action.LOCALE_CHANGED" />
</intent-filter> </intent-filter>
</receiver> </receiver>

View File

@ -34,7 +34,7 @@ class AWApplication : Application() {
private fun calibrateVersions() { private fun calibrateVersions() {
// 2.0 Tolerance // 2.0 Tolerance
if (Preferences.clockTextSize > 50f) { if (Preferences.clockTextSize > 50f) {
Preferences.clockTextSize = 46f Preferences.clockTextSize = 32f
} }
if (Preferences.textMainSize > 36f) { if (Preferences.textMainSize > 36f) {

View File

@ -0,0 +1,63 @@
package com.tommasoberlose.anotherwidget.components
import android.content.Context
import android.view.View
import androidx.core.view.isVisible
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.tommasoberlose.anotherwidget.R
import kotlinx.android.synthetic.main.bottom_sheet_dialog.view.*
typealias DialogCallback = () -> Unit
class MaterialBottomSheetDialog(
context: Context,
private val title: String? = "",
private val message: String? = ""
) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
private var positiveButtonLabel: String? = null
private var negativeButtonLabel: String? = null
private var positiveCallback: DialogCallback? = null
private var negativeCallback: DialogCallback? = null
fun setPositiveButton(label: String? = context.getString(android.R.string.ok), callback: DialogCallback? = null): MaterialBottomSheetDialog {
positiveButtonLabel = label
positiveCallback = callback
return this
}
fun setNegativeButton(label: String? = context.getString(android.R.string.cancel), callback: DialogCallback? = null): MaterialBottomSheetDialog {
negativeButtonLabel = label
negativeCallback = callback
return this
}
override fun show() {
val view = View.inflate(context, R.layout.bottom_sheet_dialog, null)
// Header
view.message.isVisible = title != null
view.title.text = title ?: ""
view.message.isVisible = message != null
view.message.text = message ?: ""
view.action_positive.isVisible = positiveButtonLabel != null
view.action_positive.text = positiveButtonLabel ?: ""
view.action_positive.setOnClickListener {
positiveCallback?.invoke()
this.dismiss()
}
view.action_negative.isVisible = negativeButtonLabel != null
view.action_negative.text = negativeButtonLabel ?: ""
view.action_negative.setOnClickListener {
negativeCallback?.invoke()
this.dismiss()
}
setContentView(view)
super.show()
}
}

View File

@ -33,17 +33,16 @@ class EventRepository(val context: Context) {
remove(Preferences::nextEventEndDate) remove(Preferences::nextEventEndDate)
remove(Preferences::nextEventCalendarId) remove(Preferences::nextEventCalendarId)
} }
MainWidget.updateWidget(context)
} }
fun saveNextEventData(event: Event) { fun saveNextEventData(event: Event) {
Preferences.nextEventId = event.id Preferences.nextEventId = event.id
MainWidget.updateWidget(context)
} }
fun getNextEvent(): Event? = realm.where(Event::class.java).equalTo("id", Preferences.nextEventId).findFirst() ?: realm.where(Event::class.java).findFirst() fun getNextEvent(): Event? = realm.where(Event::class.java).equalTo("id", Preferences.nextEventId).findFirst() ?: realm.where(Event::class.java).findFirst()
fun getEventById(id: Long): Event? = realm.where(Event::class.java).equalTo("id", id).findFirst()
fun goToNextEvent() { fun goToNextEvent() {
val eventList = realm.where(Event::class.java).findAll() val eventList = realm.where(Event::class.java).findAll()

View File

@ -7,63 +7,11 @@ object Constants {
const val RESULT_APP_NAME = "RESULT_APP_NAME" const val RESULT_APP_NAME = "RESULT_APP_NAME"
const val RESULT_APP_PACKAGE = "RESULT_APP_PACKAGE" const val RESULT_APP_PACKAGE = "RESULT_APP_PACKAGE"
const val 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 CUSTOM_FONT_PRODUCT_SANS = 1
enum class ClockBottomMargin(val value: Int) {
const val itDateFormat = "EEEE, d MMM" NONE(0),
const val engDateFormat = "EEEE, MMM d" SMALL(1),
const val goodHourFormat = "HH:mm" MEDIUM(2),
const val badHourFormat = "hh:mm a" LARGE(3)
}
} }

View File

@ -10,15 +10,14 @@ object Preferences : KotprefModel() {
var darkThemePreference by intPref(default = if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) MODE_NIGHT_FOLLOW_SYSTEM else MODE_NIGHT_AUTO_BATTERY) 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 showEvents by booleanPref(key = "PREF_SHOW_EVENTS", default = false)
var showWeather by booleanPref(key = "PREF_SHOW_WEATHER") var showWeather by booleanPref(key = "PREF_SHOW_WEATHER", default = false)
var weatherIcon by stringPref(key = "PREF_WEATHER_ICON") var weatherIcon by stringPref(key = "PREF_WEATHER_ICON", default = "")
var weatherTemp by floatPref(key = "PREF_WEATHER_TEMP") var weatherTemp by floatPref(key = "PREF_WEATHER_TEMP", default = 0f)
var weatherTempUnit by stringPref(key = "PREF_WEATHER_TEMP_UNIT", default = "F") var weatherTempUnit by stringPref(key = "PREF_WEATHER_TEMP_UNIT", default = "F")
var weatherRealTempUnit by stringPref(key = "PREF_WEATHER_REAL_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 calendarAllDay by booleanPref(key = "PREF_CALENDAR_ALL_DAY", default = true)
var calendarFilter by stringPref(key = "PREF_CALENDAR_FILTER", default = "") 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 nextEventId by longPref(key = "PREF_NEXT_EVENT_ID", default = -1)
var nextEventName by stringPref(key = "PREF_NEXT_EVENT_NAME") var nextEventName by stringPref(key = "PREF_NEXT_EVENT_NAME")
var nextEventStartDate by longPref(key = "PREF_NEXT_EVENT_START_DATE") var nextEventStartDate by longPref(key = "PREF_NEXT_EVENT_START_DATE")
@ -29,7 +28,6 @@ object Preferences : KotprefModel() {
var customLocationLat by stringPref(key = "PREF_CUSTOM_LOCATION_LAT", default = "") var customLocationLat by stringPref(key = "PREF_CUSTOM_LOCATION_LAT", default = "")
var customLocationLon by stringPref(key = "PREF_CUSTOM_LOCATION_LON", default = "") var customLocationLon by stringPref(key = "PREF_CUSTOM_LOCATION_LON", default = "")
var customLocationAdd by stringPref(key = "PREF_CUSTOM_LOCATION_ADD", default = "") var customLocationAdd by stringPref(key = "PREF_CUSTOM_LOCATION_ADD", default = "")
var hourFormat by stringPref(key = "PREF_HOUR_FORMAT", default = "12")
var dateFormat by stringPref(default = "") var dateFormat by stringPref(default = "")
var weatherRefreshPeriod by intPref(key = "PREF_WEATHER_REFRESH_PERIOD", default = 1) var weatherRefreshPeriod by intPref(key = "PREF_WEATHER_REFRESH_PERIOD", default = 1)
var showUntil by intPref(key = "PREF_SHOW_UNTIL", default = 1) var showUntil by intPref(key = "PREF_SHOW_UNTIL", default = 1)
@ -40,28 +38,27 @@ object Preferences : KotprefModel() {
var weatherProviderApi by stringPref(key = "PREF_WEATHER_PROVIDER_API_KEY", default = "") var weatherProviderApi by stringPref(key = "PREF_WEATHER_PROVIDER_API_KEY", default = "")
var eventAppName by stringPref(key = "PREF_EVENT_APP_NAME", default = "") var eventAppName by stringPref(key = "PREF_EVENT_APP_NAME", default = "")
var eventAppPackage by stringPref(key = "PREF_EVENT_APP_PACKAGE", default = "") var eventAppPackage by stringPref(key = "PREF_EVENT_APP_PACKAGE", default = "")
var showEventLocation by stringPref(key = "PREF_SHOW_EVENT_LOCATION", default = "") var openEventDetails by booleanPref(default = true)
var textGlobalColor by stringPref(key = "PREF_TEXT_COLOR", default = "#FFFFFF") var textGlobalColor by stringPref(key = "PREF_TEXT_COLOR", default = "#FFFFFF")
var textMainSize by floatPref(key = "PREF_TEXT_MAIN_SIZE", default = 26f) var textMainSize by floatPref(key = "PREF_TEXT_MAIN_SIZE", default = 26f)
var textSecondSize by floatPref(key = "PREF_TEXT_SECOND_SIZE", default = 18f) var textSecondSize by floatPref(key = "PREF_TEXT_SECOND_SIZE", default = 18f)
var clockTextSize by floatPref(key = "PREF_TEXT_CLOCK_SIZE", default = 90f) var clockTextSize by floatPref(key = "PREF_TEXT_CLOCK_SIZE", default = 90f)
var clockBottomMargin by intPref(default = Constants.ClockBottomMargin.MEDIUM.value)
var showClock by booleanPref(key = "PREF_SHOW_CLOCK", default = false) var showClock by booleanPref(key = "PREF_SHOW_CLOCK", default = false)
var clockAppName by stringPref(key = "PREF_CLOCK_APP_NAME", default = "") var clockAppName by stringPref(key = "PREF_CLOCK_APP_NAME", default = "")
var clockAppPackage by stringPref(key = "PREF_CLOCK_APP_PACKAGE", default = "") var clockAppPackage by stringPref(key = "PREF_CLOCK_APP_PACKAGE", default = "")
var showNextAlarm by booleanPref(default = true) var showNextAlarm by booleanPref(default = false)
var textShadow by intPref(key = "PREF_TEXT_SHADOW", default = 1) var textShadow by intPref(key = "PREF_TEXT_SHADOW", default = 1)
var showDiffTime by booleanPref(key = "PREF_SHOW_DIFF_TIME") var showDiffTime by booleanPref(key = "PREF_SHOW_DIFF_TIME", default = true)
var showDeclinedEvents by booleanPref(key = "PREF_SHOW_DECLINED_EVENTS", default = true) var showDeclinedEvents by booleanPref(key = "PREF_SHOW_DECLINED_EVENTS", default = false)
var openWeatherApiKey by stringPref(key = "PREF_OPEN_WEATHER_API_KEY", default = "") var secondRowInformation by intPref(key = "PREF_SECOND_ROW_INFORMATION", default = 0)
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 customFont by intPref(key = "PREF_CUSTOM_FONT", default = Constants.CUSTOM_FONT_PRODUCT_SANS)
var customFontFile by stringPref(key = "PREF_CUSTOM_FONT_FILE") var customFontFile by stringPref(key = "PREF_CUSTOM_FONT_FILE")
var showNextEvent by booleanPref(key = "PREF_SHOW_NEXT_EVENT", default = true) 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) var showWallpaper by booleanPref(default = true)
var showBigClockWarning by booleanPref(default = true) var showBigClockWarning by booleanPref(default = true)
var showWeatherWarning by booleanPref(default = true) var showWeatherWarning by booleanPref(default = true)
var showPreview by booleanPref(default = true)
var showXiaomiWarning by booleanPref(default = true)
} }

View File

@ -11,7 +11,7 @@ object AlarmHelper {
val alarm = nextAlarmClock val alarm = nextAlarmClock
return if ( return if (
alarm != null alarm != null
&& alarm.triggerTime - Calendar.getInstance().timeInMillis > 2 * 60 * 1000 && alarm.triggerTime - Calendar.getInstance().timeInMillis > 10 * 60 * 1000
&& alarm.triggerTime - Calendar.getInstance().timeInMillis < 12 * 60 * 60 * 1000 && alarm.triggerTime - Calendar.getInstance().timeInMillis < 12 * 60 * 60 * 1000
) { ) {
"%s %s".format( "%s %s".format(

View File

@ -7,6 +7,7 @@ import android.util.Log
import android.view.View import android.view.View
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.DrawableCompat import androidx.core.graphics.drawable.DrawableCompat
import androidx.core.view.drawToBitmap
import com.google.firebase.crashlytics.FirebaseCrashlytics import com.google.firebase.crashlytics.FirebaseCrashlytics
import java.lang.Exception import java.lang.Exception
@ -19,10 +20,13 @@ object BitmapHelper {
view.measure(measuredWidth, measuredHeight) view.measure(measuredWidth, measuredHeight)
return try { return try {
if (draw) {
Log.d("ciao", "bitmap ${view.measuredWidth}, ${view.measuredHeight}")
}
val btm = Bitmap.createBitmap( val btm = Bitmap.createBitmap(
view.measuredWidth, view.measuredWidth,
view.measuredHeight, view.measuredHeight,
Bitmap.Config.ARGB_8888 if (draw) Bitmap.Config.ARGB_8888 else Bitmap.Config.ALPHA_8
) )
if (draw) { if (draw) {
//Bind a canvas to it //Bind a canvas to it
@ -35,7 +39,7 @@ object BitmapHelper {
btm btm
} catch (ex: Exception) { } catch (ex: Exception) {
FirebaseCrashlytics.getInstance().recordException(ex) FirebaseCrashlytics.getInstance().recordException(ex)
Bitmap.createBitmap(5, 5, Bitmap.Config.ARGB_8888) Bitmap.createBitmap(5, 5, Bitmap.Config.ALPHA_8)
} }
} }

View File

@ -125,6 +125,7 @@ object CalendarHelper {
} }
UpdatesReceiver.setUpdates(context) UpdatesReceiver.setUpdates(context)
Log.d("ciao", "force update? 7")
MainWidget.updateWidget(context) MainWidget.updateWidget(context)
EventBus.getDefault().post(MainActivity.UpdateUiMessageEvent()) EventBus.getDefault().post(MainActivity.UpdateUiMessageEvent())

View File

@ -30,35 +30,6 @@ object IntentHelper {
} }
} }
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 { fun getWeatherIntent(context: Context): Intent {
return when (Preferences.weatherAppPackage) { return when (Preferences.weatherAppPackage) {
"" -> { "" -> {
@ -91,15 +62,12 @@ object IntentHelper {
} }
} }
fun getEventIntent(context: Context, e: Event): Intent { fun getCalendarIntent(context: Context): Intent {
return when (Preferences.eventAppPackage) { return when (Preferences.calendarAppPackage) {
"" -> { "" -> {
val uri = ContentUris.withAppendedId(Events.CONTENT_URI, e.eventID) Intent(Intent.ACTION_MAIN).apply {
Intent(Intent.ACTION_VIEW).apply {
data = uri
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, e.startDate) addCategory(Intent.CATEGORY_APP_CALENDAR)
putExtra(CalendarContract.EXTRA_EVENT_END_TIME, e.endDate)
} }
} }
"_" -> { "_" -> {
@ -107,25 +75,45 @@ object IntentHelper {
} }
else -> { else -> {
val pm: PackageManager = context.packageManager val pm: PackageManager = context.packageManager
val uri = ContentUris.withAppendedId(Events.CONTENT_URI, e.eventID)
try { try {
pm.getLaunchIntentForPackage(Preferences.eventAppPackage)!!.apply { pm.getLaunchIntentForPackage(Preferences.calendarAppPackage)!!.apply {
action = Intent.ACTION_VIEW
data = uri
addCategory(Intent.CATEGORY_LAUNCHER) addCategory(Intent.CATEGORY_LAUNCHER)
// addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
// putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, e.startDate)
// putExtra(CalendarContract.EXTRA_EVENT_END_TIME, e.endDate)
} }
} catch (ex: Exception) { } catch (e: Exception) {
e.printStackTrace()
Intent(Intent.ACTION_MAIN).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
addCategory(Intent.CATEGORY_APP_CALENDAR)
}
}
}
}
}
fun getEventIntent(context: Context, e: Event, forceEventDetails: Boolean = false): Intent {
return when (Preferences.openEventDetails || forceEventDetails) {
true -> {
val uri = ContentUris.withAppendedId(Events.CONTENT_URI, e.eventID)
if (Preferences.calendarAppPackage == "") {
Intent(Intent.ACTION_VIEW).apply { Intent(Intent.ACTION_VIEW).apply {
data = uri data = uri
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, e.startDate) putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, e.startDate)
putExtra(CalendarContract.EXTRA_EVENT_END_TIME, e.endDate) putExtra(CalendarContract.EXTRA_EVENT_END_TIME, e.endDate)
} }
} else {
getCalendarIntent(context).apply {
action = Intent.ACTION_VIEW
data = uri
putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, e.startDate)
putExtra(CalendarContract.EXTRA_EVENT_END_TIME, e.endDate)
}
} }
} }
false -> {
getCalendarIntent(context)
}
} }
} }

View File

@ -2,6 +2,8 @@ package com.tommasoberlose.anotherwidget.helpers
import android.Manifest import android.Manifest
import android.content.Context import android.content.Context
import android.os.Build
import android.util.Log
import com.google.android.gms.location.LocationServices import com.google.android.gms.location.LocationServices
import com.kwabenaberko.openweathermaplib.constants.Units import com.kwabenaberko.openweathermaplib.constants.Units
import com.kwabenaberko.openweathermaplib.implementation.OpenWeatherMapHelper import com.kwabenaberko.openweathermaplib.implementation.OpenWeatherMapHelper
@ -24,7 +26,7 @@ object WeatherHelper {
val networkApi = WeatherNetworkApi(context) val networkApi = WeatherNetworkApi(context)
if (Preferences.customLocationAdd != "") { if (Preferences.customLocationAdd != "") {
networkApi.updateWeather() networkApi.updateWeather()
} else if (context.checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION)) { } else if (context.checkGrantedPermission(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACCESS_BACKGROUND_LOCATION else Manifest.permission.ACCESS_FINE_LOCATION)) {
LocationServices.getFusedLocationProviderClient(context).lastLocation.addOnCompleteListener { task -> LocationServices.getFusedLocationProviderClient(context).lastLocation.addOnCompleteListener { task ->
if (task.isSuccessful) { if (task.isSuccessful) {
val location = task.result val location = task.result

View File

@ -0,0 +1,51 @@
package com.tommasoberlose.anotherwidget.helpers
import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.res.Configuration.ORIENTATION_PORTRAIT
object WidgetHelper {
class WidgetSizeProvider(
private val context: Context,
private val appWidgetManager: AppWidgetManager
) {
fun getWidgetsSize(widgetId: Int): Pair<Int, Int> {
val isPortrait = context.resources.configuration.orientation == ORIENTATION_PORTRAIT
val width = getWidgetWidth(isPortrait, widgetId)
val height = getWidgetHeight(isPortrait, widgetId)
val widthInPx = context.dip(width)
val heightInPx = context.dip(height)
return widthInPx to heightInPx
}
private fun getWidgetWidth(isPortrait: Boolean, widgetId: Int): Int =
if (isPortrait) {
getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH)
} else {
getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH)
}
private fun getWidgetHeight(isPortrait: Boolean, widgetId: Int): Int =
if (isPortrait) {
getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT)
} else {
getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT)
}
private fun getWidgetSizeInDp(widgetId: Int, key: String): Int =
appWidgetManager.getAppWidgetOptions(widgetId).getInt(key, 0)
private fun Context.dip(value: Int): Int = (value * resources.displayMetrics.density).toInt()
}
fun Pair<Int, Int>.reduceDimensionWithMaxWidth(width: Int): Pair<Int, Int> {
return if (first < width) {
this
} else {
val factor = width / first
width to second * factor
}
}
}

View File

@ -14,9 +14,8 @@ open class Event(var id: Long = 0,
var endDate: Long = 0, var endDate: Long = 0,
var calendarID: Int = 0, var calendarID: Int = 0,
var allDay: Boolean = false, var allDay: Boolean = false,
var address: String = "") : RealmObject(){ var address: String = "") : RealmObject() {
override fun toString(): String { override fun toString(): String {
return "Event:\nID: " + id + "\nTITLE: " + title + "\nSTART DATE: " + Date(startDate) + "\nEND DATE: " + Date(endDate) + "\nCAL DAY: " + calendarID + "\nADDRESS: " + address return "Event:\nID: " + eventID + "\nTITLE: " + title + "\nSTART DATE: " + Date(startDate) + "\nEND DATE: " + Date(endDate) + "\nCAL ID: " + calendarID + "\nADDRESS: " + address
} }
} }

View File

@ -1,6 +1,7 @@
package com.tommasoberlose.anotherwidget.network package com.tommasoberlose.anotherwidget.network
import android.content.Context import android.content.Context
import android.util.Log
import com.kwabenaberko.openweathermaplib.constants.Units import com.kwabenaberko.openweathermaplib.constants.Units
import com.kwabenaberko.openweathermaplib.implementation.OpenWeatherMapHelper import com.kwabenaberko.openweathermaplib.implementation.OpenWeatherMapHelper
import com.kwabenaberko.openweathermaplib.implementation.callbacks.CurrentWeatherCallback import com.kwabenaberko.openweathermaplib.implementation.callbacks.CurrentWeatherCallback
@ -23,9 +24,7 @@ class WeatherNetworkApi(val context: Context) {
Preferences.weatherTemp = currentWeather.main.temp.toFloat() Preferences.weatherTemp = currentWeather.main.temp.toFloat()
Preferences.weatherIcon = currentWeather.weather[0].icon Preferences.weatherIcon = currentWeather.weather[0].icon
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
MainWidget.updateWidget( MainWidget.updateWidget(context)
context
)
EventBus.getDefault().post(MainActivity.UpdateUiMessageEvent()) EventBus.getDefault().post(MainActivity.UpdateUiMessageEvent())
} }

View File

@ -12,7 +12,6 @@ class NewCalendarEventReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
val eventRepository = EventRepository(context) val eventRepository = EventRepository(context)
Log.d("ciao", "nuovo evento")
when (intent.action) { when (intent.action) {
Intent.ACTION_PROVIDER_CHANGED, Intent.ACTION_PROVIDER_CHANGED,
Intent.ACTION_TIME_CHANGED -> { Intent.ACTION_TIME_CHANGED -> {

View File

@ -1,58 +1,81 @@
package com.tommasoberlose.anotherwidget.receivers package com.tommasoberlose.anotherwidget.receivers
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.app.AlarmManager
import android.app.PendingIntent
import android.util.Log import android.util.Log
import androidx.core.app.AlarmManagerCompat
import androidx.core.content.ContextCompat.getSystemService
import com.tommasoberlose.anotherwidget.db.EventRepository import com.tommasoberlose.anotherwidget.db.EventRepository
import com.tommasoberlose.anotherwidget.global.Actions import com.tommasoberlose.anotherwidget.global.Actions
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import org.joda.time.Period import org.joda.time.Period
import java.text.DateFormat
import java.util.* import java.util.*
class UpdatesReceiver : BroadcastReceiver() { class UpdatesReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
Log.d("ciao", "che palle - ${intent.action}")
when (intent.action) { when (intent.action) {
Intent.ACTION_BOOT_COMPLETED, Intent.ACTION_BOOT_COMPLETED,
Intent.ACTION_MY_PACKAGE_REPLACED, Intent.ACTION_MY_PACKAGE_REPLACED,
Intent.ACTION_TIME_CHANGED,
Intent.ACTION_TIMEZONE_CHANGED,
Intent.ACTION_LOCALE_CHANGED,
Actions.ACTION_CALENDAR_UPDATE -> CalendarHelper.updateEventList(context) Actions.ACTION_CALENDAR_UPDATE -> CalendarHelper.updateEventList(context)
"com.sec.android.widgetapp.APPWIDGET_RESIZE", "com.sec.android.widgetapp.APPWIDGET_RESIZE",
Intent.ACTION_DATE_CHANGED, Intent.ACTION_DATE_CHANGED,
AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED -> MainWidget.updateWidget(context) AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED,
Actions.ACTION_TIME_UPDATE -> {
Log.d("ciao", "force update? 4 - ${intent.action}")
MainWidget.updateWidget(context)
}
} }
} }
companion object { companion object {
fun setUpdates(context: Context) { fun setUpdates(context: Context) {
removeUpdates(context) removeUpdates(context)
val eventRepository = EventRepository(context) val eventRepository = EventRepository(context)
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) { with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
eventRepository.getEvents().forEach { event -> eventRepository.getEvents().forEach { event ->
val hoursDiff = Period(Calendar.getInstance().timeInMillis, event.startDate).hours val now = Calendar.getInstance().apply {
set(Calendar.SECOND, 0)
// Update the widget every hour till the event set(Calendar.MILLISECOND, 0)
(0 .. hoursDiff).forEach { }
setExact( val diff = Period(now.timeInMillis, event.startDate)
AlarmManager.RTC_WAKEUP, if (event.startDate > now.timeInMillis) {
(event.startDate + 1000) - it * 1000 * 60* 60, // Update the widget every hour till the event
PendingIntent.getBroadcast(context, 0, Intent(context, UpdatesReceiver::class.java).apply { action = Actions.ACTION_TIME_UPDATE }, 0) (0..diff.hours).forEach {
) AlarmManagerCompat.setExactAndAllowWhileIdle(
this,
AlarmManager.RTC_WAKEUP,
if (event.startDate - it * 1000 * 60 * 60 > 60 * 1000) event.startDate - it * 1000 * 60 * 60 else 120000,
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 // Update the widget one second after the event is finished
setExact( AlarmManagerCompat.setExactAndAllowWhileIdle(this,
AlarmManager.RTC_WAKEUP, AlarmManager.RTC_WAKEUP,
event.endDate + 1000, if (event.endDate > 60 *1000) event.endDate else 120000,
PendingIntent.getBroadcast(context, 0, Intent(context, UpdatesReceiver::class.java).apply { action = Actions.ACTION_TIME_UPDATE }, 0) PendingIntent.getBroadcast(context, 0, Intent(context, UpdatesReceiver::class.java).apply { action = Actions.ACTION_TIME_UPDATE }, 0))
)
} }
} }
} }

View File

@ -8,6 +8,7 @@ import android.content.Intent
import com.tommasoberlose.anotherwidget.global.Actions import com.tommasoberlose.anotherwidget.global.Actions
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
import com.tommasoberlose.anotherwidget.services.WeatherWorker
import java.util.* import java.util.*
@ -17,68 +18,9 @@ class WeatherReceiver : BroadcastReceiver() {
when (intent.action) { when (intent.action) {
Intent.ACTION_BOOT_COMPLETED, Intent.ACTION_BOOT_COMPLETED,
Intent.ACTION_MY_PACKAGE_REPLACED, Intent.ACTION_MY_PACKAGE_REPLACED,
Intent.ACTION_TIME_CHANGED -> setUpdates(context) Intent.ACTION_TIMEZONE_CHANGED,
Intent.ACTION_LOCALE_CHANGED,
Actions.ACTION_WEATHER_UPDATE -> WeatherHelper.updateWeather(context) Intent.ACTION_TIME_CHANGED -> WeatherWorker.setUpdates(context)
}
}
companion object {
fun setUpdates(context: Context) {
removeUpdates(context)
if (Preferences.showWeather && Preferences.weatherProviderApi != "") {
WeatherHelper.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

@ -0,0 +1,63 @@
package com.tommasoberlose.anotherwidget.services
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.work.*
import com.tommasoberlose.anotherwidget.global.Actions
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver
import java.util.*
import java.util.concurrent.TimeUnit
class WeatherWorker(appContext: Context, workerParams: WorkerParameters) : Worker(appContext, workerParams) {
override fun doWork(): Result {
WeatherHelper.updateWeather(applicationContext)
return Result.success()
}
companion object {
private const val JOB_TAG = "WEATHER_WORKER"
fun setUpdates(context: Context) {
removeUpdates(context)
if (Preferences.showWeather && Preferences.weatherProviderApi != "") {
WeatherHelper.updateWeather(context)
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"WEATHER_JOB_PERIODIC",
ExistingPeriodicWorkPolicy.KEEP,
PeriodicWorkRequestBuilder<WeatherWorker>(
when (Preferences.weatherRefreshPeriod) {
0 -> 30
1 -> 60
2 -> 60L * 3
3 -> 60L * 6
4 -> 60L * 12
5 -> 60L * 24
else -> 60
}
, TimeUnit.MINUTES
)
.addTag(JOB_TAG)
.build()
)
}
}
fun setOneTimeUpdate(context: Context) {
val workManager = WorkManager.getInstance(context)
listOf(10L, 20L, 30L).forEach {
workManager.enqueueUniqueWork("WEATHER_JOB_ONE_TIME_$it", ExistingWorkPolicy.KEEP, OneTimeWorkRequestBuilder<WeatherWorker>().setInitialDelay(it, TimeUnit.MINUTES).addTag(JOB_TAG).build())
}
}
fun removeUpdates(context: Context) {
WorkManager.getInstance(context).cancelAllWorkByTag(JOB_TAG)
}
}
}

View File

@ -5,6 +5,7 @@ import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.location.Address import android.location.Address
import android.location.Geocoder import android.location.Geocoder
import android.os.Build
import android.os.Bundle import android.os.Bundle
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import android.text.Editable import android.text.Editable
@ -125,7 +126,7 @@ class CustomLocationActivity : AppCompatActivity() {
private fun requirePermission() { private fun requirePermission() {
Dexter.withContext(this) Dexter.withContext(this)
.withPermissions( .withPermissions(
Manifest.permission.ACCESS_FINE_LOCATION if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACCESS_BACKGROUND_LOCATION else Manifest.permission.ACCESS_FINE_LOCATION
).withListener(object: MultiplePermissionsListener { ).withListener(object: MultiplePermissionsListener {
override fun onPermissionsChecked(report: MultiplePermissionsReport?) { override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
report?.let { report?.let {

View File

@ -5,8 +5,11 @@ import android.app.Activity
import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetManager
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.graphics.drawable.BitmapDrawable
import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.provider.Settings
import android.util.TypedValue import android.util.TypedValue
import android.view.View import android.view.View
import android.widget.RelativeLayout import android.widget.RelativeLayout
@ -18,11 +21,12 @@ import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.tabs.TabLayoutMediator
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
import com.tommasoberlose.anotherwidget.global.Actions import com.tommasoberlose.anotherwidget.global.Actions
import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.global.RequestCode import com.tommasoberlose.anotherwidget.global.RequestCode
import com.tommasoberlose.anotherwidget.helpers.BitmapHelper import com.tommasoberlose.anotherwidget.helpers.BitmapHelper
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
import com.tommasoberlose.anotherwidget.helpers.ColorHelper import com.tommasoberlose.anotherwidget.helpers.ColorHelper
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
@ -32,10 +36,8 @@ import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import com.tommasoberlose.anotherwidget.utils.getCurrentWallpaper import com.tommasoberlose.anotherwidget.utils.getCurrentWallpaper
import com.tommasoberlose.anotherwidget.utils.toPixel import com.tommasoberlose.anotherwidget.utils.toPixel
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.Dispatchers import kotlinx.android.synthetic.main.the_widget_sans.*
import kotlinx.coroutines.Job import kotlinx.coroutines.*
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode import org.greenrobot.eventbus.ThreadMode
@ -69,10 +71,9 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
}.attach() }.attach()
// Init clock // Init clock
clock.setTextColor(ColorHelper.getFontColor()) time.setTextColor(ColorHelper.getFontColor())
clock.setTextSize(TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(this@MainActivity)) time.setTextSize(TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(this@MainActivity))
clock.format12Hour = "hh:mm" time.isVisible = Preferences.showClock
clock.isVisible = Preferences.showClock
preview.layoutParams = preview.layoutParams.apply { preview.layoutParams = preview.layoutParams.apply {
height = 160.toPixel(this@MainActivity) + if (Preferences.showClock) 100.toPixel(this@MainActivity) else 0 height = 160.toPixel(this@MainActivity) + if (Preferences.showClock) 100.toPixel(this@MainActivity) else 0
@ -82,83 +83,159 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
subscribeUi(viewModel) subscribeUi(viewModel)
updateUI() updateUI()
CalendarHelper.updateEventList(this)
WeatherHelper.updateWeather(this) WeatherHelper.updateWeather(this)
if (getString(R.string.xiaomi_manufacturer).equals(Build.MANUFACTURER, ignoreCase = true) && Preferences.showXiaomiWarning) {
MaterialBottomSheetDialog(this, getString(R.string.xiaomi_warning_title), getString(R.string.xiaomi_warning_message))
.setNegativeButton(getString(R.string.action_ignore)) {
Preferences.showXiaomiWarning = false
}
.setPositiveButton(getString(R.string.action_grant_permission)) {
Preferences.showXiaomiWarning = false
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.parse("package:$packageName")
}
startActivity(intent)
}
.show()
}
} }
private var uiJob: Job? = null private var uiJob: Job? = null
private fun updateUI() { private fun updateUI() {
preview.setCardBackgroundColor(getColor(if (ColorHelper.getFontColor().isColorDark()) android.R.color.white else R.color.colorAccent))
val generatedView = MainWidget.generateWidgetView(this@MainActivity)
generatedView.measure(0, 0)
preview.measure(0, 0)
uiJob?.cancel() uiJob?.cancel()
uiJob = lifecycleScope.launch(Dispatchers.IO) {
val bitmap = BitmapHelper.getBitmapFromView(generatedView, if (preview.width > 0) preview.width else generatedView.measuredWidth, generatedView.measuredHeight)
withContext(Dispatchers.Main) {
// Clock
clock.setTextColor(ColorHelper.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.showPreview) {
if (Preferences.showClock) { preview.setCardBackgroundColor(
clock.layoutParams = clock.layoutParams.apply { getColor(
height = RelativeLayout.LayoutParams.WRAP_CONTENT if (ColorHelper.getFontColor()
} .isColorDark()
clock.measure(0, 0) ) android.R.color.white else R.color.colorAccent
} )
val initialHeight = clock.measuredHeight )
ValueAnimator.ofFloat( uiJob = lifecycleScope.launch(Dispatchers.IO) {
if (Preferences.showClock) 0f else 1f, delay(200)
if (Preferences.showClock) 1f else 0f val generatedView = MainWidget.generateWidgetView(this@MainActivity)
).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( withContext(Dispatchers.Main) {
preview.height, generatedView.measure(0, 0)
160.toPixel(this@MainActivity) + if (Preferences.showClock) 100.toPixel(this@MainActivity) else 0 preview.measure(0, 0)
).apply {
duration = 500L
addUpdateListener {
val animatedValue = animatedValue as Int
val layoutParams = preview.layoutParams
layoutParams.height = animatedValue
preview.layoutParams = layoutParams
}
}.start()
} else {
clock.layoutParams = clock.layoutParams.apply {
height = RelativeLayout.LayoutParams.WRAP_CONTENT
}
clock.measure(0, 0)
} }
widget_bitmap.setImageBitmap(bitmap) val bitmap = BitmapHelper.getBitmapFromView(
widget_loader.animate().scaleX(0f).scaleY(0f).start() generatedView,
widget.animate().alpha(1f).start() if (preview.width > 0) preview.width else generatedView.measuredWidth,
generatedView.measuredHeight
)
withContext(Dispatchers.Main) {
// Clock
time.setTextColor(ColorHelper.getFontColor())
time.setTextSize(
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(this@MainActivity)
)
time.format12Hour = "hh:mm"
// Clock bottom margin
clock_bottom_margin_none.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.value
clock_bottom_margin_small.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.SMALL.value
clock_bottom_margin_medium.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.MEDIUM.value
clock_bottom_margin_large.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.LARGE.value
if ((Preferences.showClock && !time.isVisible) || (!Preferences.showClock && time.isVisible)) {
if (Preferences.showClock) {
time.layoutParams = time.layoutParams.apply {
height = RelativeLayout.LayoutParams.WRAP_CONTENT
}
time.measure(0, 0)
}
val initialHeight = time.measuredHeight
ValueAnimator.ofFloat(
if (Preferences.showClock) 0f else 1f,
if (Preferences.showClock) 1f else 0f
).apply {
duration = 500L
addUpdateListener {
val animatedValue = animatedValue as Float
time.layoutParams = time.layoutParams.apply {
height = (initialHeight * animatedValue).toInt()
}
}
addListener(
onStart = {
if (Preferences.showClock) {
time.isVisible = true
}
},
onEnd = {
if (!Preferences.showClock) {
time.isVisible = false
}
}
)
}.start()
ValueAnimator.ofInt(
preview.height,
160.toPixel(this@MainActivity) + if (Preferences.showClock) 100.toPixel(
this@MainActivity
) else 0
).apply {
duration = 500L
addUpdateListener {
val animatedValue = animatedValue as Int
val layoutParams = preview.layoutParams
layoutParams.height = animatedValue
preview.layoutParams = layoutParams
}
}.start()
} else {
time.layoutParams = time.layoutParams.apply {
height = RelativeLayout.LayoutParams.WRAP_CONTENT
}
time.measure(0, 0)
}
if (preview.height == 0) {
ValueAnimator.ofInt(
preview.height,
160.toPixel(this@MainActivity) + if (Preferences.showClock) 100.toPixel(
this@MainActivity
) else 0
).apply {
duration = 300L
addUpdateListener {
val animatedValue = animatedValue as Int
val layoutParams = preview.layoutParams
layoutParams.height = animatedValue
preview.layoutParams = layoutParams
}
}.start()
}
bitmap_container.setImageBitmap(bitmap)
widget_loader.animate().scaleX(0f).scaleY(0f).start()
widget.animate().alpha(1f).start()
}
} }
} else {
ValueAnimator.ofInt(
preview.height,
0
).apply {
duration = 300L
addUpdateListener {
val animatedValue = animatedValue as Int
val layoutParams = preview.layoutParams
layoutParams.height = animatedValue
preview.layoutParams = layoutParams
}
}.start()
} }
} }

View File

@ -5,6 +5,7 @@ import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -69,7 +70,8 @@ class AdvancedSettingsFragment : Fragment() {
setupListener() setupListener()
app_version.text = "v%s".format(BuildConfig.VERSION_NAME) app_version.text = "v%s (%s)".format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)
requirePermission()
} }
private fun subscribeUi( private fun subscribeUi(
@ -77,7 +79,7 @@ class AdvancedSettingsFragment : Fragment() {
) { ) {
viewModel.darkThemePreference.observe(viewLifecycleOwner, Observer { viewModel.darkThemePreference.observe(viewLifecycleOwner, Observer {
AppCompatDelegate.setDefaultNightMode(it) AppCompatDelegate.setDefaultNightMode(it)
theme.text = when (it) { theme?.text = when (it) {
AppCompatDelegate.MODE_NIGHT_NO -> getString(R.string.settings_subtitle_dark_theme_light) 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_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_AUTO_BATTERY -> getString(R.string.settings_subtitle_dark_theme_by_battery_saver)
@ -86,8 +88,12 @@ class AdvancedSettingsFragment : Fragment() {
} }
}) })
viewModel.showPreview.observe(viewLifecycleOwner, Observer {
show_widget_preview_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
})
viewModel.showWallpaper.observe(viewLifecycleOwner, Observer { viewModel.showWallpaper.observe(viewLifecycleOwner, Observer {
show_wallpaper_label.text = if (it && activity?.checkGrantedPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == true) getString(R.string.settings_visible) else getString(R.string.settings_not_visible) show_wallpaper_label?.text = if (it && activity?.checkGrantedPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == true) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
}) })
} }
@ -114,10 +120,28 @@ class AdvancedSettingsFragment : Fragment() {
} }
} }
action_show_widget_preview.setOnClickListener {
maintainScrollPosition {
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.action_show_widget_preview))
.setSelectedValue(Preferences.showPreview)
.addItem(
getString(R.string.settings_visible),
true
)
.addItem(
getString(R.string.settings_not_visible),
false
)
.addOnSelectItemListener { value ->
Preferences.showPreview = value
}.show()
}
}
action_show_wallpaper.setOnClickListener { action_show_wallpaper.setOnClickListener {
maintainScrollPosition { maintainScrollPosition {
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_title_show_wallpaper)) BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_title_show_wallpaper))
.setSelectedValue(Preferences.showWallpaper) .setSelectedValue(Preferences.showWallpaper && activity?.checkGrantedPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == true)
.addItem( .addItem(
getString(R.string.settings_visible), getString(R.string.settings_visible),
true true
@ -174,6 +198,7 @@ class AdvancedSettingsFragment : Fragment() {
).withListener(object: MultiplePermissionsListener { ).withListener(object: MultiplePermissionsListener {
override fun onPermissionsChecked(report: MultiplePermissionsReport?) { override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
report?.let { report?.let {
Preferences.showWallpaper = false
Preferences.showWallpaper = report.areAllPermissionsGranted() Preferences.showWallpaper = report.areAllPermissionsGranted()
} }
} }

View File

@ -89,6 +89,7 @@ class CalendarSettingsFragment : Fragment() {
binding.isCalendarEnabled = it binding.isCalendarEnabled = it
if (it) { if (it) {
requirePermission()
CalendarHelper.setEventUpdatesAndroidN(requireContext()) CalendarHelper.setEventUpdatesAndroidN(requireContext())
} else { } else {
CalendarHelper.removeEventUpdatesAndroidN(requireContext()) CalendarHelper.removeEventUpdatesAndroidN(requireContext())
@ -99,7 +100,7 @@ class CalendarSettingsFragment : Fragment() {
viewModel.calendarAllDay.observe(viewLifecycleOwner, Observer { viewModel.calendarAllDay.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
all_day_label.text = all_day_label?.text =
if (it) getString(R.string.settings_all_day_subtitle_visible) else getString(R.string.settings_all_day_subtitle_gone) if (it) getString(R.string.settings_all_day_subtitle_visible) else getString(R.string.settings_all_day_subtitle_gone)
} }
checkReadEventsPermission() checkReadEventsPermission()
@ -107,49 +108,49 @@ class CalendarSettingsFragment : Fragment() {
viewModel.showDeclinedEvents.observe(viewLifecycleOwner, Observer { viewModel.showDeclinedEvents.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
show_declined_events_label.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible) show_declined_events_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
} }
checkReadEventsPermission() checkReadEventsPermission()
}) })
viewModel.secondRowInformation.observe(viewLifecycleOwner, Observer { viewModel.secondRowInformation.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
second_row_info_label.text = getString(SettingsStringHelper.getSecondRowInfoString(it)) second_row_info_label?.text = getString(SettingsStringHelper.getSecondRowInfoString(it))
} }
}) })
viewModel.showDiffTime.observe(viewLifecycleOwner, Observer { viewModel.showDiffTime.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
show_diff_time_label.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible) show_diff_time_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
} }
}) })
viewModel.showUntil.observe(viewLifecycleOwner, Observer { viewModel.showUntil.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
show_until_label.text = getString(SettingsStringHelper.getShowUntilString(it)) show_until_label?.text = getString(SettingsStringHelper.getShowUntilString(it))
} }
checkReadEventsPermission() checkReadEventsPermission()
}) })
viewModel.showNextEvent.observe(viewLifecycleOwner, Observer { viewModel.showNextEvent.observe(viewLifecycleOwner, Observer {
show_multiple_events_label.setTextKeepState(if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)) show_multiple_events_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
}) })
viewModel.dateFormat.observe(viewLifecycleOwner, Observer { viewModel.dateFormat.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
date_format_label.text = DateHelper.getDateText(requireContext(), Calendar.getInstance()) date_format_label?.text = DateHelper.getDateText(requireContext(), Calendar.getInstance())
} }
}) })
viewModel.calendarAppName.observe(viewLifecycleOwner, Observer { viewModel.calendarAppName.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
calendar_app_label.text = if (it != "") it else getString(R.string.default_calendar_app) calendar_app_label?.text = if (it != "") it else getString(R.string.default_calendar_app)
} }
}) })
viewModel.eventAppName.observe(viewLifecycleOwner, Observer { viewModel.openEventDetails.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
event_app_label.text = if (it != "") it else getString(R.string.default_calendar_app) open_event_details_label?.text = if (it) getString(R.string.default_event_app) else getString(R.string.default_calendar_app)
} }
}) })
@ -301,8 +302,15 @@ class CalendarSettingsFragment : Fragment() {
} }
} }
action_event_app.setOnClickListener { action_open_event_details.setOnClickListener {
startActivityForResult(Intent(requireContext(), ChooseApplicationActivity::class.java), RequestCode.EVENT_APP_REQUEST_CODE.code) if (Preferences.showEvents) {
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_event_app_title)).setSelectedValue(Preferences.openEventDetails)
.addItem(getString(R.string.default_event_app), true)
.addItem(getString(R.string.default_calendar_app), false)
.addOnSelectItemListener { value ->
Preferences.openEventDetails = value
}.show()
}
} }
action_calendar_app.setOnClickListener { action_calendar_app.setOnClickListener {
@ -312,13 +320,13 @@ class CalendarSettingsFragment : Fragment() {
private fun checkReadEventsPermission(showEvents: Boolean = Preferences.showEvents) { private fun checkReadEventsPermission(showEvents: Boolean = Preferences.showEvents) {
if (activity?.checkGrantedPermission(Manifest.permission.READ_CALENDAR) == true) { if (activity?.checkGrantedPermission(Manifest.permission.READ_CALENDAR) == true) {
show_events_label.text = if (showEvents) getString(R.string.show_events_visible) else getString(R.string.show_events_not_visible) show_events_label?.text = if (showEvents) getString(R.string.show_events_visible) else getString(R.string.show_events_not_visible)
read_calendar_permission_alert_icon.isVisible = false read_calendar_permission_alert_icon?.isVisible = false
CalendarHelper.updateEventList(requireContext()) CalendarHelper.updateEventList(requireContext())
} else { } else {
show_events_label.text = if (showEvents) getString(R.string.description_permission_calendar) else getString(R.string.show_events_not_visible) show_events_label?.text = if (showEvents) getString(R.string.description_permission_calendar) else getString(R.string.show_events_not_visible)
read_calendar_permission_alert_icon.isVisible = showEvents read_calendar_permission_alert_icon?.isVisible = showEvents
read_calendar_permission_alert_icon.setOnClickListener { read_calendar_permission_alert_icon?.setOnClickListener {
requirePermission() requirePermission()
} }
} }

View File

@ -65,13 +65,13 @@ class ClockSettingsFragment : Fragment() {
viewModel: MainViewModel viewModel: MainViewModel
) { ) {
viewModel.showBigClockWarning.observe(viewLifecycleOwner, Observer { viewModel.showBigClockWarning.observe(viewLifecycleOwner, Observer {
large_clock_warning.isVisible = it large_clock_warning?.isVisible = it
small_clock_warning.isVisible = !it small_clock_warning?.isVisible = !it
}) })
viewModel.showClock.observe(viewLifecycleOwner, Observer { viewModel.showClock.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
show_clock_label.text = show_clock_label?.text =
if (it) getString(R.string.show_clock_visible) else getString(R.string.show_clock_not_visible) if (it) getString(R.string.show_clock_visible) else getString(R.string.show_clock_not_visible)
binding.isClockVisible = it binding.isClockVisible = it
} }
@ -79,19 +79,30 @@ class ClockSettingsFragment : Fragment() {
viewModel.clockTextSize.observe(viewLifecycleOwner, Observer { viewModel.clockTextSize.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
clock_text_size_label.text = String.format("%.0fsp", it) clock_text_size_label?.text = String.format("%.0fsp", it)
}
})
viewModel.clockBottomMargin.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
clock_bottom_margin_label?.text = when (it) {
Constants.ClockBottomMargin.NONE.value -> getString(R.string.settings_clock_bottom_margin_subtitle_none)
Constants.ClockBottomMargin.SMALL.value -> getString(R.string.settings_clock_bottom_margin_subtitle_small)
Constants.ClockBottomMargin.LARGE.value -> getString(R.string.settings_clock_bottom_margin_subtitle_large)
else -> getString(R.string.settings_clock_bottom_margin_subtitle_medium)
}
} }
}) })
viewModel.showNextAlarm.observe(viewLifecycleOwner, Observer { viewModel.showNextAlarm.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
show_next_alarm_label.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible) show_next_alarm_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
} }
}) })
viewModel.clockAppName.observe(viewLifecycleOwner, Observer { viewModel.clockAppName.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
clock_app_label.text = clock_app_label?.text =
if (Preferences.clockAppName != "") Preferences.clockAppName else getString(R.string.default_clock_app) if (Preferences.clockAppName != "") Preferences.clockAppName else getString(R.string.default_clock_app)
} }
}) })
@ -116,12 +127,14 @@ class ClockSettingsFragment : Fragment() {
}.show() }.show()
} }
action_show_next_alarm.setOnClickListener { action_clock_bottom_margin_size.setOnClickListener {
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_show_next_alarm_title)).setSelectedValue(Preferences.showNextAlarm) BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_show_next_alarm_title)).setSelectedValue(Preferences.clockBottomMargin)
.addItem(getString(R.string.settings_visible), true) .addItem(getString(R.string.settings_clock_bottom_margin_subtitle_none), Constants.ClockBottomMargin.NONE.value)
.addItem(getString(R.string.settings_not_visible), false) .addItem(getString(R.string.settings_clock_bottom_margin_subtitle_small), Constants.ClockBottomMargin.SMALL.value)
.addItem(getString(R.string.settings_clock_bottom_margin_subtitle_medium), Constants.ClockBottomMargin.MEDIUM.value)
.addItem(getString(R.string.settings_clock_bottom_margin_subtitle_large), Constants.ClockBottomMargin.LARGE.value)
.addOnSelectItemListener { value -> .addOnSelectItemListener { value ->
Preferences.showNextAlarm = value Preferences.clockBottomMargin = value
}.show() }.show()
} }
@ -132,6 +145,15 @@ class ClockSettingsFragment : Fragment() {
) )
} }
} }
action_show_next_alarm.setOnClickListener {
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_show_next_alarm_title)).setSelectedValue(Preferences.showNextAlarm)
.addItem(getString(R.string.settings_visible), true)
.addItem(getString(R.string.settings_not_visible), false)
.addOnSelectItemListener { value ->
Preferences.showNextAlarm = value
}.show()
}
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {

View File

@ -77,13 +77,13 @@ class GeneralSettingsFragment : Fragment() {
viewModel.textMainSize.observe(viewLifecycleOwner, Observer { viewModel.textMainSize.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
main_text_size_label.text = String.format("%.0fsp", it) main_text_size_label?.text = String.format("%.0fsp", it)
} }
}) })
viewModel.textSecondSize.observe(viewLifecycleOwner, Observer { viewModel.textSecondSize.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
second_text_size_label.text = String.format("%.0fsp", it) second_text_size_label?.text = String.format("%.0fsp", it)
} }
}) })
@ -94,19 +94,19 @@ class GeneralSettingsFragment : Fragment() {
} catch (e: Exception) { } catch (e: Exception) {
Preferences.textGlobalColor = "#FFFFFF" Preferences.textGlobalColor = "#FFFFFF"
} }
font_color_label.text = it.toUpperCase() font_color_label?.text = it.toUpperCase()
} }
}) })
viewModel.textShadow.observe(viewLifecycleOwner, Observer { viewModel.textShadow.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
text_shadow_label.text = getString(SettingsStringHelper.getTextShadowString(it)) text_shadow_label?.text = getString(SettingsStringHelper.getTextShadowString(it))
} }
}) })
viewModel.customFont.observe(viewLifecycleOwner, Observer { viewModel.customFont.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
custom_font_label.text = getString(SettingsStringHelper.getCustomFontLabel(it)) custom_font_label?.text = getString(SettingsStringHelper.getCustomFontLabel(it))
} }
}) })
} }

View File

@ -3,8 +3,8 @@ package com.tommasoberlose.anotherwidget.ui.fragments
import android.Manifest import android.Manifest
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -28,6 +28,7 @@ import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.global.RequestCode import com.tommasoberlose.anotherwidget.global.RequestCode
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver
import com.tommasoberlose.anotherwidget.services.WeatherWorker
import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity
import com.tommasoberlose.anotherwidget.ui.activities.CustomLocationActivity import com.tommasoberlose.anotherwidget.ui.activities.CustomLocationActivity
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
@ -79,12 +80,12 @@ class WeatherSettingsFragment : Fragment() {
viewModel: MainViewModel viewModel: MainViewModel
) { ) {
viewModel.showWeatherWarning.observe(viewLifecycleOwner, Observer { viewModel.showWeatherWarning.observe(viewLifecycleOwner, Observer {
weather_warning.isVisible = it weather_warning?.isVisible = it
}) })
viewModel.showWeather.observe(viewLifecycleOwner, Observer { viewModel.showWeather.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
show_weather_label.text = show_weather_label?.text =
if (it) getString(R.string.show_weather_visible) else getString(R.string.show_weather_not_visible) if (it) getString(R.string.show_weather_visible) else getString(R.string.show_weather_not_visible)
binding.isWeatherVisible = it binding.isWeatherVisible = it
} }
@ -93,18 +94,18 @@ class WeatherSettingsFragment : Fragment() {
viewModel.weatherProviderApi.observe(viewLifecycleOwner, Observer { viewModel.weatherProviderApi.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
label_weather_provider_api_key.text = label_weather_provider_api_key?.text =
if (it == "") getString(R.string.settings_weather_provider_api_key_subtitle_not_set) else getString( 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 R.string.settings_weather_provider_api_key_subtitle_all_set
) )
api_key_alert_icon.isVisible = it == "" api_key_alert_icon?.isVisible = it == ""
} }
checkLocationPermission() checkLocationPermission()
}) })
viewModel.customLocationAdd.observe(viewLifecycleOwner, Observer { viewModel.customLocationAdd.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
label_custom_location.text = label_custom_location?.text =
if (it == "") getString(R.string.custom_location_gps) else it if (it == "") getString(R.string.custom_location_gps) else it
} }
checkLocationPermission() checkLocationPermission()
@ -112,33 +113,34 @@ class WeatherSettingsFragment : Fragment() {
viewModel.weatherTempUnit.observe(viewLifecycleOwner, Observer { viewModel.weatherTempUnit.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
temp_unit.text = temp_unit?.text =
if (it == "F") getString(R.string.fahrenheit) else getString(R.string.celsius) if (it == "F") getString(R.string.fahrenheit) else getString(R.string.celsius)
} }
checkLocationPermission()
}) })
viewModel.weatherRefreshPeriod.observe(viewLifecycleOwner, Observer { viewModel.weatherRefreshPeriod.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
label_weather_refresh_period.text = getString(SettingsStringHelper.getRefreshPeriodString(it)) label_weather_refresh_period?.text = getString(SettingsStringHelper.getRefreshPeriodString(it))
} }
checkLocationPermission() checkLocationPermission()
}) })
viewModel.weatherAppName.observe(viewLifecycleOwner, Observer { viewModel.weatherAppName.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
weather_app_label.text = weather_app_label?.text =
if (it != "") it else getString(R.string.default_weather_app) if (it != "") it else getString(R.string.default_weather_app)
} }
}) })
} }
private fun checkLocationPermission() { private fun checkLocationPermission() {
if (activity?.checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION) == true) { if (activity?.checkGrantedPermission(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACCESS_BACKGROUND_LOCATION else Manifest.permission.ACCESS_FINE_LOCATION) == true) {
location_permission_alert_icon.isVisible = false location_permission_alert_icon?.isVisible = false
WeatherReceiver.setUpdates(requireContext()) WeatherWorker.setUpdates(requireContext())
} else if (Preferences.showWeather && Preferences.customLocationAdd == "") { } else if (Preferences.showWeather && Preferences.customLocationAdd == "") {
location_permission_alert_icon.isVisible = true location_permission_alert_icon?.isVisible = true
location_permission_alert_icon.setOnClickListener { location_permission_alert_icon?.setOnClickListener {
requirePermission() requirePermission()
} }
} }
@ -210,7 +212,7 @@ class WeatherSettingsFragment : Fragment() {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
when (requestCode) { when (requestCode) {
Constants.RESULT_CODE_CUSTOM_LOCATION -> { Constants.RESULT_CODE_CUSTOM_LOCATION -> {
WeatherReceiver.setUpdates(requireContext()) WeatherWorker.setUpdates(requireContext())
checkLocationPermission() checkLocationPermission()
} }
RequestCode.WEATHER_APP_REQUEST_CODE.code -> { RequestCode.WEATHER_APP_REQUEST_CODE.code -> {
@ -221,7 +223,7 @@ class WeatherSettingsFragment : Fragment() {
MainWidget.updateWidget(requireContext()) MainWidget.updateWidget(requireContext())
} }
RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code -> { RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code -> {
WeatherReceiver.setOneTimeUpdate(requireContext()) WeatherWorker.setOneTimeUpdate(requireContext())
} }
} }
} }
@ -231,7 +233,7 @@ class WeatherSettingsFragment : Fragment() {
private fun requirePermission() { private fun requirePermission() {
Dexter.withContext(requireContext()) Dexter.withContext(requireContext())
.withPermissions( .withPermissions(
Manifest.permission.ACCESS_FINE_LOCATION if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACCESS_BACKGROUND_LOCATION else Manifest.permission.ACCESS_FINE_LOCATION
).withListener(object: MultiplePermissionsListener { ).withListener(object: MultiplePermissionsListener {
override fun onPermissionsChecked(report: MultiplePermissionsReport?) { override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
report?.let { report?.let {

View File

@ -21,10 +21,9 @@ class MainViewModel : ViewModel() {
val showDiffTime = Preferences.asLiveData(Preferences::showDiffTime) val showDiffTime = Preferences.asLiveData(Preferences::showDiffTime)
val showDeclinedEvents = Preferences.asLiveData(Preferences::showDeclinedEvents) val showDeclinedEvents = Preferences.asLiveData(Preferences::showDeclinedEvents)
val showNextEvent = Preferences.asLiveData(Preferences::showNextEvent) val showNextEvent = Preferences.asLiveData(Preferences::showNextEvent)
val openEventDetails = Preferences.asLiveData(Preferences::openEventDetails)
val calendarAppName = Preferences.asLiveData(Preferences::calendarAppName) val calendarAppName = Preferences.asLiveData(Preferences::calendarAppName)
val eventAppName = Preferences.asLiveData(Preferences::eventAppName)
// Clock Settings // Clock Settings
val showClock = Preferences.asLiveData(Preferences::showClock) val showClock = Preferences.asLiveData(Preferences::showClock)
@ -33,6 +32,7 @@ class MainViewModel : ViewModel() {
val clockAppName = Preferences.asLiveData(Preferences::clockAppName) val clockAppName = Preferences.asLiveData(Preferences::clockAppName)
val showNextAlarm = Preferences.asLiveData(Preferences::showNextAlarm) val showNextAlarm = Preferences.asLiveData(Preferences::showNextAlarm)
val dateFormat = Preferences.asLiveData(Preferences::dateFormat) val dateFormat = Preferences.asLiveData(Preferences::dateFormat)
val clockBottomMargin = Preferences.asLiveData(Preferences::clockBottomMargin)
val showBigClockWarning = Preferences.asLiveData(Preferences::showBigClockWarning) val showBigClockWarning = Preferences.asLiveData(Preferences::showBigClockWarning)
@ -51,4 +51,5 @@ class MainViewModel : ViewModel() {
// Advanced Settings // Advanced Settings
val darkThemePreference = Preferences.asLiveData(Preferences::darkThemePreference) val darkThemePreference = Preferences.asLiveData(Preferences::darkThemePreference)
val showWallpaper = Preferences.asLiveData(Preferences::showWallpaper) val showWallpaper = Preferences.asLiveData(Preferences::showWallpaper)
val showPreview = Preferences.asLiveData(Preferences::showPreview)
} }

View File

@ -12,7 +12,6 @@ import android.graphics.Color
import android.graphics.Typeface import android.graphics.Typeface
import android.os.Bundle import android.os.Bundle
import android.text.format.DateUtils import android.text.format.DateUtils
import android.util.Log
import android.util.TypedValue import android.util.TypedValue
import android.view.View import android.view.View
import android.widget.ImageView import android.widget.ImageView
@ -20,21 +19,23 @@ import android.widget.RemoteViews
import android.widget.TextView import android.widget.TextView
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.db.EventRepository import com.tommasoberlose.anotherwidget.db.EventRepository
import com.tommasoberlose.anotherwidget.global.Actions import com.tommasoberlose.anotherwidget.global.Actions
import com.tommasoberlose.anotherwidget.global.Constants import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.* import com.tommasoberlose.anotherwidget.helpers.*
import com.tommasoberlose.anotherwidget.helpers.WidgetHelper.reduceDimensionWithMaxWidth
import com.tommasoberlose.anotherwidget.receivers.NewCalendarEventReceiver import com.tommasoberlose.anotherwidget.receivers.NewCalendarEventReceiver
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver
import com.tommasoberlose.anotherwidget.receivers.WidgetClickListenerReceiver import com.tommasoberlose.anotherwidget.receivers.WidgetClickListenerReceiver
import com.tommasoberlose.anotherwidget.services.WeatherWorker
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
import com.tommasoberlose.anotherwidget.utils.convertSpToPixels
import com.tommasoberlose.anotherwidget.utils.getCapWordString import com.tommasoberlose.anotherwidget.utils.getCapWordString
import com.tommasoberlose.anotherwidget.utils.toPixel import com.tommasoberlose.anotherwidget.utils.toPixel
import kotlinx.android.synthetic.main.the_widget.view.* import kotlinx.android.synthetic.main.the_widget.view.*
import java.lang.Exception
import java.text.DateFormat import java.text.DateFormat
import java.util.* import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -55,7 +56,7 @@ class MainWidget : AppWidgetProvider() {
override fun onEnabled(context: Context) { override fun onEnabled(context: Context) {
CalendarHelper.updateEventList(context) CalendarHelper.updateEventList(context)
WeatherReceiver.setUpdates(context) WeatherWorker.setUpdates(context)
if (Preferences.showEvents) { if (Preferences.showEvents) {
CalendarHelper.setEventUpdatesAndroidN(context) CalendarHelper.setEventUpdatesAndroidN(context)
@ -65,8 +66,10 @@ class MainWidget : AppWidgetProvider() {
} }
override fun onDisabled(context: Context) { override fun onDisabled(context: Context) {
UpdatesReceiver.removeUpdates(context) if (getWidgetCount(context) == 0) {
WeatherReceiver.removeUpdates(context) UpdatesReceiver.removeUpdates(context)
WeatherWorker.removeUpdates(context)
}
} }
companion object { companion object {
@ -81,26 +84,26 @@ class MainWidget : AppWidgetProvider() {
context.sendBroadcast(update) context.sendBroadcast(update)
} }
fun getWidgetCount(context: Context): Int {
val widgetManager = AppWidgetManager.getInstance(context)
val widgetComponent = ComponentName(context, MainWidget::class.java)
return widgetManager.getAppWidgetIds(widgetComponent).size
}
internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager,
appWidgetId: Int) { appWidgetId: Int) {
val displayMetrics = Resources.getSystem().displayMetrics val displayMetrics = Resources.getSystem().displayMetrics
var height = 110.toPixel(context)
val width = displayMetrics.widthPixels val width = displayMetrics.widthPixels
if (Preferences.showClock) {
height += Preferences.clockTextSize.convertSpToPixels(context).toInt() + 16.toPixel(context)
}
if (Preferences.textMainSize > 30 && Preferences.textSecondSize > 22) {
height += 24.toPixel(context)
}
generateWidgetView(context, appWidgetId, appWidgetManager, width - 16.toPixel(context)) val dimensions = WidgetHelper.WidgetSizeProvider(context, appWidgetManager).getWidgetsSize(appWidgetId).reduceDimensionWithMaxWidth(1200)
generateWidgetView(context, appWidgetId, appWidgetManager, dimensions.first - 8.toPixel(context) /*width - 16.toPixel(context)*/)
} }
private fun generateWidgetView(context: Context, appWidgetId: Int, appWidgetManager: AppWidgetManager, w: Int) { private fun generateWidgetView(context: Context, appWidgetId: Int, appWidgetManager: AppWidgetManager, w: Int) {
var views = RemoteViews(context.packageName, R.layout.the_widget_sans) var views = RemoteViews(context.packageName, R.layout.the_widget_sans)
val generatedView = generateWidgetView(context) val generatedView = generateWidgetView(context)
views.setImageViewBitmap(R.id.bitmap_container, BitmapHelper.getBitmapFromView(generatedView, width = w - 32.toPixel(context))) views.setImageViewBitmap(R.id.bitmap_container, BitmapHelper.getBitmapFromView(generatedView, width = w))
// Clock // Clock
views = updateClockView(context, views, appWidgetId) views = updateClockView(context, views, appWidgetId)
@ -113,107 +116,233 @@ class MainWidget : AppWidgetProvider() {
} }
private fun updateCalendarView(context: Context, v: View, views: RemoteViews, widgetID: Int): RemoteViews { private fun updateCalendarView(context: Context, v: View, views: RemoteViews, widgetID: Int): RemoteViews {
val eventRepository = EventRepository(context) try {
val eventRepository = EventRepository(context)
views.setImageViewBitmap(R.id.empty_date_rect, BitmapHelper.getBitmapFromView(v.empty_date, draw = false)) views.setImageViewBitmap(
R.id.empty_date_rect,
BitmapHelper.getBitmapFromView(v.empty_date, draw = false)
)
views.setViewVisibility(R.id.empty_layout_rect, View.VISIBLE) views.setViewVisibility(R.id.empty_layout_rect, View.VISIBLE)
views.setViewVisibility(R.id.calendar_layout_rect, View.GONE) views.setViewVisibility(R.id.calendar_layout_rect, View.GONE)
views.setViewVisibility(R.id.second_row_rect, View.GONE) views.setViewVisibility(R.id.second_row_rect, View.GONE)
val calPIntent = PendingIntent.getActivity(context, widgetID, IntentHelper.getCalendarIntent(context), 0) val calPIntent = PendingIntent.getActivity(
views.setOnClickPendingIntent(R.id.empty_date_rect, calPIntent) context,
widgetID,
IntentHelper.getCalendarIntent(context),
0
)
views.setOnClickPendingIntent(R.id.empty_date_rect, calPIntent)
val nextEvent = eventRepository.getNextEvent() val nextEvent = eventRepository.getNextEvent()
val nextAlarm = AlarmHelper.getNextAlarm(context) val nextAlarm = AlarmHelper.getNextAlarm(context)
if (Preferences.showEvents && context.checkGrantedPermission(Manifest.permission.READ_CALENDAR) && nextEvent != null) { if (Preferences.showEvents && context.checkGrantedPermission(Manifest.permission.READ_CALENDAR) && nextEvent != null) {
if (Preferences.showNextEvent && eventRepository.getEventsCount() > 1) { if (Preferences.showNextEvent && eventRepository.getEventsCount() > 1) {
views.setImageViewBitmap(R.id.action_next_rect, BitmapHelper.getBitmapFromView(v.action_next, draw = false)) views.setImageViewBitmap(
views.setViewVisibility(R.id.action_next_rect, View.VISIBLE) R.id.action_next_rect,
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)) BitmapHelper.getBitmapFromView(v.action_next, draw = false)
)
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
)
)
views.setImageViewBitmap(R.id.action_previous_rect, BitmapHelper.getBitmapFromView(v.action_previous, draw = false)) views.setImageViewBitmap(
views.setViewVisibility(R.id.action_previous_rect, View.VISIBLE) R.id.action_previous_rect,
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)) BitmapHelper.getBitmapFromView(v.action_previous, draw = false)
} else { )
views.setViewVisibility(R.id.action_next_rect, View.GONE) views.setViewVisibility(R.id.action_previous_rect, View.VISIBLE)
views.setViewVisibility(R.id.action_previous_rect, View.GONE) 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,
IntentHelper.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 - 1000 * 60 * 60)) {
views.setImageViewBitmap(
R.id.next_event_difference_time_rect,
BitmapHelper.getBitmapFromView(
v.next_event_difference_time,
draw = false
)
)
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,
IntentHelper.getGoogleMapsIntentFromAddress(context, nextEvent.address),
0
)
views.setOnClickPendingIntent(R.id.second_row_rect, mapIntent)
} else {
val pIntentDetail = PendingIntent.getActivity(
context,
widgetID,
IntentHelper.getEventIntent(
context,
nextEvent,
forceEventDetails = true
),
0
)
views.setOnClickPendingIntent(R.id.second_row_rect, pIntentDetail)
}
views.setImageViewBitmap(
R.id.next_event_rect,
BitmapHelper.getBitmapFromView(v.next_event, draw = false)
)
views.setImageViewBitmap(
R.id.second_row_rect,
BitmapHelper.getBitmapFromView(v.second_row, draw = false)
)
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.showNextAlarm && nextAlarm != "") {
val clockIntent = PendingIntent.getActivity(
context,
widgetID,
IntentHelper.getClockIntent(context),
0
)
views.setOnClickPendingIntent(R.id.second_row_rect, clockIntent)
views.setImageViewBitmap(
R.id.next_event_rect,
BitmapHelper.getBitmapFromView(v.next_event, draw = false)
)
views.setImageViewBitmap(
R.id.second_row_rect,
BitmapHelper.getBitmapFromView(v.second_row, draw = false)
)
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)
} }
} catch (ex: Exception) {
val pIntent = PendingIntent.getActivity(context, widgetID, IntentHelper.getEventIntent(context, nextEvent), 0) FirebaseCrashlytics.getInstance().recordException(ex)
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 - 1000 * 60 * 60)) {
views.setImageViewBitmap(R.id.next_event_difference_time_rect, BitmapHelper.getBitmapFromView(v.next_event_difference_time, draw = false))
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, IntentHelper.getGoogleMapsIntentFromAddress(context, nextEvent.address), 0)
views.setOnClickPendingIntent(R.id.second_row_rect, mapIntent)
} else {
views.setOnClickPendingIntent(R.id.second_row_rect, pIntent)
}
views.setImageViewBitmap(R.id.next_event_rect, BitmapHelper.getBitmapFromView(v.next_event, draw = false))
views.setImageViewBitmap(R.id.second_row_rect, BitmapHelper.getBitmapFromView(v.second_row, draw = false))
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.showNextAlarm && nextAlarm != "") {
val clockIntent = PendingIntent.getActivity(context, widgetID, IntentHelper.getClockIntent(context), 0)
views.setOnClickPendingIntent(R.id.second_row_rect, clockIntent)
views.setImageViewBitmap(R.id.next_event_rect, BitmapHelper.getBitmapFromView(v.next_event, draw = false))
views.setImageViewBitmap(R.id.second_row_rect, BitmapHelper.getBitmapFromView(v.second_row, draw = false))
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 return views
} }
private fun updateWeatherView(context: Context, v: View, views: RemoteViews, widgetID: Int): RemoteViews { private fun updateWeatherView(context: Context, v: View, views: RemoteViews, widgetID: Int): RemoteViews {
try {
if (Preferences.showWeather && Preferences.weatherIcon != "") {
views.setViewVisibility(R.id.weather_rect, View.VISIBLE)
views.setViewVisibility(R.id.calendar_weather_rect, View.VISIBLE)
if (Preferences.showWeather && Preferences.weatherIcon != "") { val i = Intent(context, WidgetClickListenerReceiver::class.java)
views.setViewVisibility(R.id.weather_rect, View.VISIBLE) i.action = Actions.ACTION_OPEN_WEATHER_INTENT
views.setViewVisibility(R.id.calendar_weather_rect, View.VISIBLE) val weatherPIntent = PendingIntent.getBroadcast(context, widgetID, i, 0)
val i = Intent(context, WidgetClickListenerReceiver::class.java) views.setOnClickPendingIntent(R.id.weather_rect, weatherPIntent)
i.action = Actions.ACTION_OPEN_WEATHER_INTENT views.setOnClickPendingIntent(R.id.calendar_weather_rect, weatherPIntent)
val weatherPIntent = PendingIntent.getBroadcast(context, widgetID, i, 0)
views.setOnClickPendingIntent(R.id.weather_rect, weatherPIntent) views.setImageViewBitmap(
views.setOnClickPendingIntent(R.id.calendar_weather_rect, weatherPIntent) R.id.weather_rect,
BitmapHelper.getBitmapFromView(v.weather, draw = false)
)
views.setImageViewBitmap(R.id.weather_rect, BitmapHelper.getBitmapFromView(v.weather, draw = false)) views.setImageViewBitmap(
R.id.calendar_weather_rect,
views.setImageViewBitmap(R.id.calendar_weather_rect, BitmapHelper.getBitmapFromView(v.calendar_weather, draw = false)) BitmapHelper.getBitmapFromView(v.calendar_weather, draw = false)
} else { )
views.setViewVisibility(R.id.weather_rect, View.GONE) } else {
views.setViewVisibility(R.id.calendar_weather_rect, View.GONE) views.setViewVisibility(R.id.weather_rect, View.GONE)
views.setViewVisibility(R.id.calendar_weather_rect, View.GONE)
}
} catch (ex: Exception) {
FirebaseCrashlytics.getInstance().recordException(ex)
} }
return views return views
} }
private fun updateClockView(context: Context, views: RemoteViews, widgetID: Int): RemoteViews { private fun updateClockView(context: Context, views: RemoteViews, widgetID: Int): RemoteViews {
if (!Preferences.showClock) { try {
views.setViewVisibility(R.id.time, View.GONE) if (!Preferences.showClock) {
} else { views.setViewVisibility(R.id.time, View.GONE)
views.setTextColor(R.id.time, ColorHelper.getFontColor()) views.setViewVisibility(R.id.clock_bottom_margin_none, View.GONE)
views.setTextViewTextSize(R.id.time, TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(context)) views.setViewVisibility(R.id.clock_bottom_margin_small, View.GONE)
val clockPIntent = PendingIntent.getActivity(context, widgetID, IntentHelper.getClockIntent(context), 0) views.setViewVisibility(R.id.clock_bottom_margin_medium, View.GONE)
views.setOnClickPendingIntent(R.id.time, clockPIntent) views.setViewVisibility(R.id.clock_bottom_margin_large, View.GONE)
views.setViewVisibility(R.id.time, View.VISIBLE) } else {
views.setTextColor(R.id.time, ColorHelper.getFontColor())
views.setTextViewTextSize(
R.id.time,
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(context)
)
val clockPIntent = PendingIntent.getActivity(
context,
widgetID,
IntentHelper.getClockIntent(context),
0
)
views.setOnClickPendingIntent(R.id.time, clockPIntent)
views.setViewVisibility(R.id.time, View.VISIBLE)
views.setViewVisibility(
R.id.clock_bottom_margin_none,
if (Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.value) View.VISIBLE else View.GONE
)
views.setViewVisibility(
R.id.clock_bottom_margin_small,
if (Preferences.clockBottomMargin == Constants.ClockBottomMargin.SMALL.value) View.VISIBLE else View.GONE
)
views.setViewVisibility(
R.id.clock_bottom_margin_medium,
if (Preferences.clockBottomMargin == Constants.ClockBottomMargin.MEDIUM.value) View.VISIBLE else View.GONE
)
views.setViewVisibility(
R.id.clock_bottom_margin_large,
if (Preferences.clockBottomMargin == Constants.ClockBottomMargin.LARGE.value) View.VISIBLE else View.GONE
)
}
} catch (ex: Exception) {
FirebaseCrashlytics.getInstance().recordException(ex)
} }
return views return views

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 369 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 699 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 876 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 607 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 369 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 458 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 607 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 876 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 711 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 781 B

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