Compare commits

...

50 Commits

Author SHA1 Message Date
6d7d90e762 Correct the algorithm to check if to show weather as a glance provider. 2021-09-14 13:49:52 +08:00
e89b377b68 Fix crash in MainFragment.updateUI() on some devices. 2021-09-14 13:48:23 +08:00
e0eb6f77da Merge branch 'patch-4' into patch-develop 2021-09-14 13:40:14 +08:00
43c08204c3 Merge branch 'patch-3' into patch-develop 2021-09-14 13:39:59 +08:00
6f125573e0 Merge branch 'patch-2' into patch-develop
# Conflicts:
#	app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/AlignedWidget.kt
#	app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/StandardWidget.kt
2021-09-14 13:39:30 +08:00
380dc96c40 Merge branch 'patch-1' into patch-develop 2021-09-14 13:38:49 +08:00
821980e938 Use getBroadcast instead of getActivity for ACTION_REFRESH intents. 2021-09-13 23:34:54 +08:00
9f47d626a9 setExact is more reliable than setRepeating on some ROMs (e.g., MIUI). 2021-09-13 23:24:58 +08:00
d3b623cf13 Add ACCESS_BACKGROUND_LOCATION permission required by Android 11. 2021-09-13 19:28:47 +08:00
1389ddbfc0 Avoid the initial vertical position of BottomSheetDialogs being capped. 2021-09-13 11:55:29 +08:00
0dbbe0e5d2 Fix RenderScript leaks; set a reasonable default value for PREF_TEXT_CLOCK_SIZE. 2021-09-10 23:15:47 +08:00
818b4ec0ba Avoid redundant updates. 2021-09-04 18:35:39 +08:00
8c84913cd8 Remove trailing semicolons in code. 2021-09-03 20:54:02 +08:00
43f085b13c Remove extra spacing after event time when weather disabled. 2021-09-03 20:40:44 +08:00
3ab42fd163 Correct and improve calendar events updating algorithm.
1. UpdateCalendarService will fetch all events from now to the next fetch time + Preferences.showUntil, so that EventRepository holds all events need to be shown before the next fetch;
2. Every event is updated 1 minute after the corresponding time span, to make the actual time difference consistent with the displayed getRelativeTimeSpanString;
3. Update events only when necessary, eliminate redundant alarms; cancel all update alarms when showEvents is turned off.
2021-09-03 18:20:01 +08:00
ea0be72478 Do not schedule unnecessary ACTION_ALARM_UPDATE alarm. 2021-09-02 13:54:24 +08:00
c744d3c7f8 Improve translation. 2021-08-19 11:31:24 +08:00
7b93548b0b Use any available Maps app, not just explicitly Google Maps. 2021-08-16 12:39:11 +08:00
260e36b305 Show & hide all-day events at the right time. 2021-08-15 19:13:46 +08:00
00af2159ea Correct some translations. 2021-08-15 18:06:11 +08:00
c26021de03 Fix #321; Update Simplified Chinese. 2021-08-14 00:55:37 +08:00
218dae8cc2 When tapping the event time, it is more reasonable to open the calendar rather than the event details (tap the event title for the details). 2021-08-13 22:10:44 +08:00
b3e2d8d843 Fix FontRequest thread leaks and UI bugs related to custom fonts. 2021-08-13 22:09:46 +08:00
80d1077dab Make LocationService work in case GMS is not available. 2021-08-12 14:12:30 +08:00
dd2a74aaf6 Close #310, added weather as glance provider 2021-05-14 17:15:34 +02:00
fb1953d513 Added custom widget margin and padding, added new preview manager 2021-05-14 16:10:56 +02:00
b081b9adbb Merge pull request #327 from Moutony/patch-31
Update French to try fixing #321
2021-05-14 16:10:16 +02:00
fd398faf42 Update French to try fixing #321 2021-05-14 11:41:43 +02:00
e14662c534 Merge pull request #324 from Moutony/patch-30
French update v2.3.3 (139) - 13th May 2021
2021-05-14 08:57:58 +02:00
4224562512 Merge pull request #323 from Moutony/patch-29
GeoNames was missing an S
2021-05-14 08:57:51 +02:00
f13d426831 Fixed : Widget alignment 2021-05-14 02:33:56 +02:00
5dc7a1b30d Fixed : Widget alignment 2021-05-14 02:25:29 +02:00
6538cdebc2 Text alignment 2021-05-13 09:20:04 +02:00
78709ed018 Text alignment is more relevent than Widget align
Alignment is more correct too
2021-05-13 09:18:58 +02:00
c0e87047c2 French update v2.3.3 (139) - 13th May 2021
Loving the new logo!
2021-05-13 09:06:53 +02:00
1a2c97d61f GeoNames was missing an S 2021-05-13 08:58:28 +02:00
4335751749 Merge pull request #320 from Drumber/translation
Updated German translation
2021-05-12 20:44:24 +02:00
9bbc816bea Merge pull request #319 from chreddy/patch-8
Updating Danish translation
2021-05-12 20:44:02 +02:00
e8a6743dc4 Updated German translation 2021-05-12 18:28:42 +02:00
5d8ceb98cc Updating Danish translation
Adding a translation for default_apps_settings_header, making the translation complete
2021-05-11 23:02:22 +02:00
dfff4c5e1b Merge branch 'develop' into main 2021-05-11 21:05:26 +02:00
13f8814480 Bumped the version 2021-05-11 21:05:19 +02:00
8608f9adf3 Merge branch 'main' of github.com:tommasoberlose/another-widget into develop 2021-05-11 21:01:56 +02:00
ad65cf0e84 Merge branch 'main' of github.com:tommasoberlose/another-widget into main 2021-05-11 21:01:31 +02:00
285b754dd5 Merge pull request #315 from Drumber/translation
Update German translation
2021-05-10 12:36:56 +02:00
194a2ab456 Merge pull request #316 from Moutony/patch-28
Update French 9th May 2021
2021-05-10 12:36:44 +02:00
bca22d5aa8 Merge pull request #314 from chreddy/patch-7
Final update - Danish translation
2021-05-10 12:36:36 +02:00
35536a89a0 Update French 9th May 2021 2021-05-09 21:23:55 +02:00
6780a470e9 Update German translation
Added new strings
2021-05-08 09:23:38 +02:00
6ca6b5ab95 Final update - Danish translation
I realized I forgot to update a few strings. Should be all done now.

I also just noticed that there's no string for the text "Default apps" in the Gestures menu, right above the app selection for calendar, weather and clock. So this text keeps showing up in English on my phone, even though the translation is complete.
2021-05-07 20:30:29 +02:00
161 changed files with 1312 additions and 833 deletions

View File

@ -22,7 +22,7 @@ android {
applicationId "com.tommasoberlose.anotherwidget"
minSdkVersion 23
targetSdkVersion 30
versionCode 138
versionCode 139
versionName "2.3.3"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View File

@ -6,6 +6,7 @@
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
@ -13,6 +14,7 @@
<uses-permission android:name="android.gms.permission.ACTIVITY_RECOGNITION"/>
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<application
android:allowBackup="true"
@ -24,24 +26,24 @@
android:usesCleartextTraffic="true"
android:theme="@style/AppTheme"
tools:ignore="LockedOrientationActivity">
<activity android:name=".ui.activities.MainActivity" android:launchMode="singleInstance" android:theme="@style/AppTheme.Main" android:screenOrientation="portrait">
<activity android:name=".ui.activities.MainActivity" android:theme="@style/AppTheme.Main" android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ui.activities.tabs.ChooseApplicationActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.tabs.CustomFontActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.tabs.CustomLocationActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.tabs.WeatherProviderActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.settings.SupportDevActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.tabs.CustomDateActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.settings.IntegrationsActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.tabs.MusicPlayersFilterActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.tabs.AppNotificationsFilterActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.tabs.MediaInfoFormatActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.tabs.TimeZoneSelectorActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.tabs.ChooseApplicationActivity" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.tabs.CustomFontActivity" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.tabs.CustomLocationActivity" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.tabs.WeatherProviderActivity" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.settings.SupportDevActivity" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.tabs.CustomDateActivity" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.settings.IntegrationsActivity" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.tabs.MusicPlayersFilterActivity" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.tabs.AppNotificationsFilterActivity" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.tabs.MediaInfoFormatActivity" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.tabs.TimeZoneSelectorActivity" android:screenOrientation="portrait" />
<receiver android:name=".ui.widgets.MainWidget">
<intent-filter>

View File

@ -31,22 +31,5 @@ class AWApplication : Application() {
.deleteRealmIfMigrationNeeded()
.build()
Realm.setDefaultConfiguration(config)
calibrateVersions()
}
private fun calibrateVersions() {
// 2.0 Tolerance
if (Preferences.clockTextSize > 50f) {
Preferences.clockTextSize = 32f
}
if (Preferences.textMainSize > 36f) {
Preferences.textMainSize = 32f
}
if (Preferences.textSecondSize > 28f) {
Preferences.textSecondSize = 24f
}
}
}

View File

@ -143,7 +143,6 @@ class BottomSheetColorPicker(
withContext(Dispatchers.Main) {
binding.loader.isVisible = false
binding.listContainer.addView(listBinding.root)
this@BottomSheetColorPicker.behavior.state = BottomSheetBehavior.STATE_EXPANDED
binding.listContainer.isVisible = true
val idx = colors.toList().indexOf(getSelected?.invoke())
@ -152,6 +151,10 @@ class BottomSheetColorPicker(
})
setContentView(binding.root)
behavior.run {
skipCollapsed = true
state = BottomSheetBehavior.STATE_EXPANDED
}
super.show()
}

View File

@ -108,6 +108,10 @@ open class BottomSheetMenu<T>(context: Context, private val header: String? = nu
}
}
setContentView(binding.root)
behavior.run {
skipCollapsed = true
state = com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
}
super.show()
}

View File

@ -86,7 +86,6 @@ class BottomSheetPicker<T>(
withContext(Dispatchers.Main) {
binding.loader.isVisible = false
binding.listContainer.addView(listBinding.root)
this@BottomSheetPicker.behavior.state = BottomSheetBehavior.STATE_EXPANDED
binding.listContainer.isVisible = true
val idx = items.toList().indexOfFirst { it.value == getSelected?.invoke() }
@ -95,6 +94,10 @@ class BottomSheetPicker<T>(
})
setContentView(binding.root)
behavior.run {
skipCollapsed = true
state = BottomSheetBehavior.STATE_EXPANDED
}
super.show()
}

View File

@ -61,5 +61,9 @@ class BottomSheetWeatherProviderSettings(context: Context, callback: () -> Unit)
}
setContentView(binding.root)
behavior.run {
skipCollapsed = true
state = com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
}
}
}

View File

@ -26,5 +26,9 @@ class CustomNotesDialog(context: Context, callback: (() -> Unit)?) : BottomSheet
binding.notes.requestFocus()
setContentView(binding.root)
behavior.run {
skipCollapsed = true
state = com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
}
}
}

View File

@ -51,6 +51,7 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
Constants.GlanceProviderId.NOTIFICATIONS -> context.getString(R.string.settings_show_notifications_title)
Constants.GlanceProviderId.GREETINGS -> context.getString(R.string.settings_show_greetings_title)
Constants.GlanceProviderId.EVENTS -> context.getString(R.string.settings_show_events_as_glance_provider_title)
Constants.GlanceProviderId.WEATHER -> context.getString(R.string.settings_show_weather_as_glance_provider_title)
}
/* SUBTITLE*/
@ -63,6 +64,7 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
Constants.GlanceProviderId.NOTIFICATIONS -> context.getString(R.string.settings_show_notifications_subtitle)
Constants.GlanceProviderId.GREETINGS -> context.getString(R.string.settings_show_greetings_subtitle)
Constants.GlanceProviderId.EVENTS -> context.getString(R.string.settings_show_events_as_glance_provider_subtitle)
Constants.GlanceProviderId.WEATHER -> context.getString(R.string.settings_show_weather_as_glance_provider_subtitle)
}
/* SONG */
@ -140,6 +142,13 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
checkCalendarConfig()
}
/* WEATHER */
if (provider == Constants.GlanceProviderId.WEATHER) {
binding.header.isVisible = false
binding.divider.isVisible = false
checkWeatherConfig()
}
/* TOGGLE */
binding.providerSwitch.setCheckedImmediatelyNoEvent(when (provider) {
Constants.GlanceProviderId.PLAYING_SONG -> Preferences.showMusic
@ -150,6 +159,7 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
Constants.GlanceProviderId.NOTIFICATIONS -> Preferences.showNotifications
Constants.GlanceProviderId.GREETINGS -> Preferences.showGreetings
Constants.GlanceProviderId.EVENTS -> Preferences.showEventsAsGlanceProvider
Constants.GlanceProviderId.WEATHER -> Preferences.showWeatherAsGlanceProvider
})
var job: Job? = null
@ -208,6 +218,9 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
Constants.GlanceProviderId.EVENTS -> {
Preferences.showEventsAsGlanceProvider = isChecked
}
Constants.GlanceProviderId.WEATHER -> {
Preferences.showWeatherAsGlanceProvider = isChecked
}
else -> {
}
}
@ -217,10 +230,16 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
}
setContentView(binding.root)
behavior.run {
skipCollapsed = true
state = com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
}
super.show()
}
private fun checkNextAlarm() {
if (!Preferences.showNextAlarm)
AlarmHelper.clearTimeout(context)
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
val alarm = nextAlarmClock
if (alarm != null && alarm.showIntent != null) {
@ -255,6 +274,19 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
}
}
private fun checkWeatherConfig() {
if (!Preferences.showWeather || (Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-") || Preferences.weatherProviderLocationError != "") {
binding.warningContainer.isVisible = true
binding.warningTitle.text = context.getString(R.string.settings_show_weather_as_glance_provider_error)
binding.warningContainer.setOnClickListener {
dismiss()
EventBus.getDefault().post(MainFragment.ChangeTabEvent(1))
}
} else {
binding.warningContainer.isVisible = false
}
}
private fun checkNotificationPermission() {
when {
ActiveNotificationsHelper.checkNotificationAccess(context) -> {

View File

@ -50,6 +50,10 @@ class IconPackSelector(context: Context, private val header: String? = null) : B
binding.menu.addView(itemBinding.root)
}
setContentView(binding.root)
behavior.run {
skipCollapsed = true
state = com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
}
super.show()
}
}

View File

@ -57,6 +57,10 @@ class MaterialBottomSheetDialog(
}
setContentView(binding.root)
behavior.run {
skipCollapsed = true
state = com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
}
super.show()
}

View File

@ -64,7 +64,7 @@ class EventRepository(val context: Context) {
else -> add(Calendar.HOUR, 6)
}
}
val event = if (nextEvent != null && nextEvent.endDate > now && nextEvent.startDate < limit.timeInMillis) {
val event = if (nextEvent != null && nextEvent.endDate > now && nextEvent.startDate <= limit.timeInMillis) {
nextEvent
} else {
val events = getEvents()
@ -105,7 +105,6 @@ class EventRepository(val context: Context) {
} else {
resetNextEventData()
}
UpdatesReceiver.setUpdates(context)
MainWidget.updateWidget(context)
}
@ -121,7 +120,6 @@ class EventRepository(val context: Context) {
} else {
resetNextEventData()
}
UpdatesReceiver.setUpdates(context)
MainWidget.updateWidget(context)
}

View File

@ -23,6 +23,13 @@ object Constants {
LARGE(3)
}
enum class Dimension(val rawValue: Float) {
NONE(0f),
SMALL(8f),
MEDIUM(16f),
LARGE(24f)
}
enum class GlanceProviderId(val id: String) {
PLAYING_SONG("PLAYING_SONG"),
NEXT_CLOCK_ALARM("NEXT_CLOCK_ALARM"),
@ -31,7 +38,8 @@ object Constants {
GOOGLE_FIT_STEPS("GOOGLE_FIT_STEPS"),
NOTIFICATIONS("NOTIFICATIONS"),
GREETINGS("GREETINGS"),
EVENTS("EVENTS");
EVENTS("EVENTS"),
WEATHER("WEATHER");
companion object {
private val map = GlanceProviderId.values().associateBy(GlanceProviderId::id)

View File

@ -84,6 +84,10 @@ object Preferences : KotprefModel() {
var weatherIconPack by intPref(default = Constants.WeatherIconPack.DEFAULT.rawValue)
// UI
var widgetMargin by floatPref(default = Constants.Dimension.SMALL.rawValue)
var widgetPadding by floatPref(default = Constants.Dimension.SMALL.rawValue)
// Clock
var altTimezoneLabel by stringPref(default = "")
var altTimezoneId by stringPref(default = "")
@ -91,7 +95,7 @@ object Preferences : KotprefModel() {
// Global
var textMainSize by floatPref(key = "PREF_TEXT_MAIN_SIZE", default = 26f)
var textSecondSize by floatPref(key = "PREF_TEXT_SECOND_SIZE", default = 18f)
var clockTextSize by floatPref(key = "PREF_TEXT_CLOCK_SIZE", default = 90f)
var clockTextSize by floatPref(key = "PREF_TEXT_CLOCK_SIZE", default = 26f)
var clockBottomMargin by intPref(default = Constants.ClockBottomMargin.MEDIUM.rawValue)
var secondRowTopMargin by intPref(default = Constants.SecondRowTopMargin.NONE.rawValue)
var showClock by booleanPref(key = "PREF_SHOW_CLOCK", default = false)
@ -149,6 +153,7 @@ object Preferences : KotprefModel() {
var appNotificationsFilter by stringPref(default = "")
var showEventsAsGlanceProvider by booleanPref(default = false)
var showWeatherAsGlanceProvider by booleanPref(default = false)
// Integrations
var installedIntegrations by intPref(default = 0)

View File

@ -44,7 +44,6 @@ object AlarmHelper {
val intent = Intent(context, UpdatesReceiver::class.java).apply {
action = Actions.ACTION_ALARM_UPDATE
}
cancel(PendingIntent.getBroadcast(context, ALARM_UPDATE_ID, intent, 0))
setExact(
AlarmManager.RTC,
trigger,
@ -58,5 +57,14 @@ object AlarmHelper {
}
}
fun clearTimeout(context: Context) {
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
val intent = Intent(context, UpdatesReceiver::class.java).apply {
action = Actions.ACTION_ALARM_UPDATE
}
cancel(PendingIntent.getBroadcast(context, ALARM_UPDATE_ID, intent, 0))
}
}
private const val ALARM_UPDATE_ID = 24953
}

View File

@ -90,6 +90,12 @@ object GlanceProviderHelper {
R.drawable.round_event_note_24
)
}
Constants.GlanceProviderId.WEATHER -> {
GlanceProvider(providerId.id,
context.getString(R.string.settings_show_weather_as_glance_provider_title),
R.drawable.round_brightness_5_24
)
}
}
}
@ -108,6 +114,7 @@ object GlanceProviderHelper {
(MediaPlayerHelper.isSomeonePlaying(context)) ||
(Preferences.showBatteryCharging && Preferences.isCharging || Preferences.isBatteryLevelLow) ||
(Preferences.customNotes.isNotEmpty()) ||
(Preferences.showWeatherAsGlanceProvider && Preferences.showWeather && Preferences.weatherIcon != "") ||
(Preferences.showDailySteps && Preferences.googleFitSteps > 0) ||
(Preferences.showGreetings && GreetingsHelper.showGreetings()) ||
(Preferences.showEventsAsGlanceProvider && Preferences.showEvents && context.checkGrantedPermission(

View File

@ -73,6 +73,9 @@ object ImageHelper {
allocationIn.destroy()
allocationOut.destroy()
colorMatrixScript.destroy()
blurScript.destroy()
//rs.destroy()
return bitmap
}

View File

@ -1,5 +1,6 @@
package com.tommasoberlose.anotherwidget.helpers
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.content.ContentUris
@ -27,6 +28,13 @@ object IntentHelper {
const val DO_NOTHING_OPTION = "DO_NOTHING"
const val REFRESH_WIDGET_OPTION = "REFRESH_WIDGET"
fun getPendingIntent(context: Context, requestCode: Int, intent: Intent, flags: Int): PendingIntent {
return if (intent.flags and Intent.FLAG_ACTIVITY_NEW_TASK == Intent.FLAG_ACTIVITY_NEW_TASK)
PendingIntent.getActivity(context, requestCode, intent, flags)
else
PendingIntent.getBroadcast(context, requestCode, intent, 0)
}
fun getWidgetUpdateIntent(context: Context): Intent {
val widgetManager = AppWidgetManager.getInstance(context)
val widgetComponent = ComponentName(context, MainWidget::class.java)
@ -40,21 +48,19 @@ object IntentHelper {
private fun getWidgetRefreshIntent(context: Context): Intent {
return Intent(context, UpdatesReceiver::class.java).apply {
action = Actions.ACTION_REFRESH
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
}
fun getGoogleMapsIntentFromAddress(context: Context, address: String): Intent {
val gmmIntentUri: Uri = Uri.parse("geo:0,0?q=$address")
val gmmIntentUri: Uri = Uri.parse("geo:0,0?q=${Uri.encode(address)}")
val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
mapIntent.`package` = "com.google.android.apps.maps"
//mapIntent.`package` = "com.google.android.apps.maps"
return if (mapIntent.resolveActivity(context.packageManager) != null) {
mapIntent
mapIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
} else {
val map = "http://maps.google.co.in/maps?q=$address"
val i = Intent(Intent.ACTION_VIEW, Uri.parse(map));
i
val map = "https://www.google.com/maps/search/?api=1&query=${Uri.encode(address)}"
Intent(Intent.ACTION_VIEW, Uri.parse(map)).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
}
@ -62,7 +68,6 @@ object IntentHelper {
return when (Preferences.weatherAppPackage) {
DEFAULT_OPTION -> {
Intent(Intent.ACTION_VIEW).apply {
addCategory(Intent.CATEGORY_DEFAULT)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
data = Uri.parse("dynact://velour/weather/ProxyActivity")
component = ComponentName("com.google.android.googlequicksearchbox", "com.google.android.apps.gsa.velour.DynamicActivityTrampoline")
@ -89,15 +94,16 @@ object IntentHelper {
}
}
fun getCalendarIntent(context: Context): Intent {
fun getCalendarIntent(context: Context, time: Long? = null): Intent {
val calendarUri = CalendarContract.CONTENT_URI
.buildUpon()
.appendPath("time")
.appendPath(Calendar.getInstance().timeInMillis.toString())
.appendPath((time ?: Calendar.getInstance().timeInMillis).toString())
.build()
return when (Preferences.calendarAppPackage) {
DEFAULT_OPTION -> {
Intent(Intent.ACTION_VIEW).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK
data = calendarUri
}
}
@ -111,6 +117,8 @@ object IntentHelper {
val pm: PackageManager = context.packageManager
try {
pm.getLaunchIntentForPackage(Preferences.calendarAppPackage)!!.apply {
addCategory(Intent.CATEGORY_LAUNCHER)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
action = Intent.ACTION_VIEW
data = calendarUri
}
@ -177,7 +185,7 @@ object IntentHelper {
}
}
false -> {
getCalendarIntent(context)
getCalendarIntent(context, e.startDate)
}
}
}
@ -209,7 +217,7 @@ object IntentHelper {
}
fun getBatteryIntent(): Intent {
return Intent(Intent.ACTION_POWER_USAGE_SUMMARY)
return Intent(Intent.ACTION_POWER_USAGE_SUMMARY).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
fun getMusicIntent(context: Context): Intent {
@ -222,6 +230,7 @@ object IntentHelper {
try {
pm.getLaunchIntentForPackage(Preferences.mediaPlayerPackage)!!.apply {
addCategory(Intent.CATEGORY_LAUNCHER)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
} catch (e: Exception) {
Intent()
@ -235,6 +244,7 @@ object IntentHelper {
return try {
pm.getLaunchIntentForPackage("com.google.android.apps.fitness")!!.apply {
addCategory(Intent.CATEGORY_LAUNCHER)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
} catch (e: Exception) {
Intent()
@ -246,6 +256,7 @@ object IntentHelper {
return try {
pm.getLaunchIntentForPackage(Preferences.lastNotificationPackage)!!.apply {
addCategory(Intent.CATEGORY_LAUNCHER)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
} catch (e: Exception) {
Intent()

View File

@ -88,19 +88,17 @@ object SettingsStringHelper {
fun getDifferenceText(context: Context, now: Long, start: Long): String {
val nowDate = DateTime(now)
val eventDate = DateTime(start)
var difference = start - now
difference += 60 * 1000 - (difference % (60 * 1000))
val difference = start - now
when {
difference <= 0 -> {
return ""
}
TimeUnit.MILLISECONDS.toHours(difference) < 1 && Preferences.widgetUpdateFrequency == Constants.WidgetUpdateFrequency.HIGH.rawValue && TimeUnit.MILLISECONDS.toMinutes(difference) > 5 -> {
return DateUtils.getRelativeTimeSpanString(start, start - 1000 * 60 * (TimeUnit.MILLISECONDS.toMinutes(difference) - 1 - (TimeUnit.MILLISECONDS.toMinutes(difference) - 1) % 5), DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE).toString()
TimeUnit.MILLISECONDS.toHours(difference) < 1 && Preferences.widgetUpdateFrequency == Constants.WidgetUpdateFrequency.HIGH.rawValue && TimeUnit.MILLISECONDS.toMinutes(difference) >= 5 -> {
return DateUtils.getRelativeTimeSpanString(start, start - 1000 * 60 * (TimeUnit.MILLISECONDS.toMinutes(difference) - TimeUnit.MILLISECONDS.toMinutes(difference) % 5), DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE).toString()
}
TimeUnit.MILLISECONDS.toHours(difference) < 1 && Preferences.widgetUpdateFrequency == Constants.WidgetUpdateFrequency.DEFAULT.rawValue && TimeUnit.MILLISECONDS.toMinutes(difference) > 5 -> {
return DateUtils.getRelativeTimeSpanString(start, start - 1000 * 60 * (TimeUnit.MILLISECONDS.toMinutes(difference) - 1 - (TimeUnit.MILLISECONDS.toMinutes(difference) - 1) % 15), DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE).toString()
TimeUnit.MILLISECONDS.toHours(difference) < 1 && Preferences.widgetUpdateFrequency == Constants.WidgetUpdateFrequency.DEFAULT.rawValue && TimeUnit.MILLISECONDS.toMinutes(difference) >= 15 -> {
return DateUtils.getRelativeTimeSpanString(start, start - 1000 * 60 * (TimeUnit.MILLISECONDS.toMinutes(difference) - TimeUnit.MILLISECONDS.toMinutes(difference) % 15), DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE).toString()
}
TimeUnit.MILLISECONDS.toHours(difference) < 1 && Preferences.widgetUpdateFrequency == Constants.WidgetUpdateFrequency.LOW.rawValue -> {
return context.getString(R.string.soon)
@ -109,22 +107,7 @@ object SettingsStringHelper {
return context.getString(R.string.now)
}
TimeUnit.MILLISECONDS.toHours(difference) < 12 -> {
val minutes = TimeUnit.MILLISECONDS.toMinutes(difference) - 60 * TimeUnit.MILLISECONDS.toHours(difference)
return if (minutes < 1 || minutes > 30) {
DateUtils.getRelativeTimeSpanString(
start,
now - 1000 * 60 * 40,
DateUtils.HOUR_IN_MILLIS,
DateUtils.FORMAT_ABBREV_RELATIVE
).toString()
} else {
DateUtils.getRelativeTimeSpanString(
start,
now,
DateUtils.HOUR_IN_MILLIS,
DateUtils.FORMAT_ABBREV_RELATIVE
).toString()
}
return DateUtils.getRelativeTimeSpanString(start, now, DateUtils.HOUR_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE).toString()
}
eventDate.dayOfYear == nowDate.plusDays(1).dayOfYear -> {
return String.format("%s", context.getString(R.string.tomorrow))
@ -143,9 +126,6 @@ object SettingsStringHelper {
val nowDate = DateTime(now)
val eventDate = DateTime(start)
var difference = start - now
difference += 60 * 1000 - (difference % (60 * 1000))
return when (eventDate.dayOfYear) {
nowDate.dayOfYear -> {
""

View File

@ -21,11 +21,20 @@ object WeatherHelper {
suspend fun updateWeather(context: Context) {
Kotpref.init(context)
val networkApi = WeatherNetworkApi(context)
if (Preferences.customLocationAdd != "") {
networkApi.updateWeather()
} else if (context.checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION)) {
WeatherNetworkApi(context).updateWeather()
} else if (context.checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION) &&
(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.R ||
context.checkGrantedPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION))
) {
LocationService.requestNewLocation(context)
} else {
Preferences.weatherProviderLocationError = context.getString(R.string.weather_provider_error_missing_location)
Preferences.weatherProviderError = ""
removeWeather(context)
org.greenrobot.eventbus.EventBus.getDefault().post(
com.tommasoberlose.anotherwidget.ui.fragments.MainFragment.UpdateUiMessageEvent()
)
}
}
@ -313,6 +322,23 @@ object WeatherHelper {
}
}
fun getWeatherLabel(context: Context, icon: String): String {
return when (icon) {
"01d", "01n" -> context.getString(R.string.weather_label_clear)
"02d", "02n" -> context.getString(R.string.weather_label_partly_cloudy)
"03d", "03n" -> context.getString(R.string.weather_label_mostly_cloudy)
"04d", "04n" -> context.getString(R.string.weather_label_cloudy_weather)
"09d", "09n" -> context.getString(R.string.weather_label_storm_weather)
"10d", "10n" -> context.getString(R.string.weather_label_rainy)
"11d", "11n" -> context.getString(R.string.weather_label_thunder)
"13d", "13n" -> context.getString(R.string.weather_label_snow)
"50d", "50n", "82d", "82n" -> context.getString(R.string.weather_label_haze)
"80d", "80n" -> context.getString(R.string.weather_label_windy)
"81d", "81n" -> context.getString(R.string.weather_label_rain_snow)
else -> context.getString(R.string.weather_label_unknown)
}
}
fun getWeatherGovIcon(iconString: String, isDaytime: Boolean): String = when {
iconString.contains("skc") -> "01"
iconString.contains("few") -> "02"

View File

@ -63,21 +63,23 @@ object WidgetHelper {
R.array.com_google_android_gms_fonts_certs
)
val handlerThread = HandlerThread("generateView")
val callback = object : FontsContractCompat.FontRequestCallback() {
override fun onTypefaceRetrieved(typeface: Typeface) {
handlerThread.quit()
function.invoke(typeface)
}
override fun onTypefaceRequestFailed(reason: Int) {
handlerThread.quit()
function.invoke(null)
}
}
val handlerThread = HandlerThread("generateView")
handlerThread.start()
if (Looper.myLooper() == null) {
Looper.prepare()
}
//if (Looper.myLooper() == null) {
// Looper.prepare()
//}
Handler(handlerThread.looper).run {
FontsContractCompat.requestFont(context, request, callback, this)

View File

@ -42,6 +42,13 @@ class WeatherNetworkApi(val context: Context) {
Constants.WeatherProvider.YR -> useYrProvider(context)
}
} else {
if (!Preferences.showWeather)
Preferences.weatherProviderError = context.getString(R.string.show_weather_not_visible)
else {
Preferences.weatherProviderLocationError = context.getString(R.string.weather_provider_error_missing_location)
Preferences.weatherProviderError = ""
}
WeatherHelper.removeWeather(
context
)

View File

@ -13,8 +13,7 @@ class NewCalendarEventReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val eventRepository = EventRepository(context)
when (intent.action) {
Intent.ACTION_PROVIDER_CHANGED,
Intent.ACTION_TIME_CHANGED -> {
Intent.ACTION_PROVIDER_CHANGED -> {
CalendarHelper.updateEventList(context)
}
Actions.ACTION_GO_TO_NEXT_EVENT -> {

View File

@ -38,6 +38,7 @@ class UpdatesReceiver : BroadcastReceiver() {
"com.sec.android.widgetapp.APPWIDGET_RESIZE",
AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED,
Actions.ACTION_ALARM_UPDATE,
Actions.ACTION_UPDATE_GREETINGS,
Actions.ACTION_TIME_UPDATE -> {
MainWidget.updateWidget(context)
if (intent.hasExtra(EVENT_ID)) {
@ -49,9 +50,6 @@ class UpdatesReceiver : BroadcastReceiver() {
ActiveNotificationsHelper.clearLastNotification(context)
MainWidget.updateWidget(context)
}
Actions.ACTION_UPDATE_GREETINGS -> {
MainWidget.updateWidget(context)
}
Actions.ACTION_REFRESH -> {
GlobalScope.launch(Dispatchers.IO) {
@ -67,9 +65,31 @@ class UpdatesReceiver : BroadcastReceiver() {
const val EVENT_ID = "EVENT_ID"
fun setUpdates(context: Context, eventId: Long? = null) {
if (!Preferences.showEvents)
return
val eventRepository = EventRepository(context)
if (eventId == null) {
removeUpdates(context)
// schedule ACTION_CALENDAR_UPDATE at midnight (ACTION_DATE_CHANGED no longer works)
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
setExact(
AlarmManager.RTC,
Calendar.getInstance().apply {
set(Calendar.MILLISECOND, 0)
set(Calendar.SECOND, 0)
set(Calendar.MINUTE, 0)
set(Calendar.HOUR_OF_DAY, 0)
add(Calendar.DATE, 1)
}.timeInMillis,
PendingIntent.getBroadcast(
context,
0,
Intent(context, UpdatesReceiver::class.java).apply {
action = Actions.ACTION_CALENDAR_UPDATE
},
0
)
)
}
eventRepository.getFutureEvents().forEach { event ->
setEventUpdate(context, event)
@ -84,12 +104,11 @@ class UpdatesReceiver : BroadcastReceiver() {
}
private fun setEventUpdate(context: Context, event: Event) {
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
val now = Calendar.getInstance().apply {
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}
val diff = Period(now.timeInMillis, event.startDate)
val diff = Period(now.timeInMillis, event.startDate, org.joda.time.PeriodType.time())
val limit = when (Preferences.showUntil) {
0 -> 1000 * 60 * 60 * 3
1 -> 1000 * 60 * 60 * 6
@ -101,92 +120,74 @@ class UpdatesReceiver : BroadcastReceiver() {
7 -> 1000 * 60 * 60
else -> 1000 * 60 * 60 * 6
}
if (event.startDate <= limit) {
if (event.startDate > now.timeInMillis) {
// Update the widget every hour till the event
if (diff.hours == 0) {
var minutes = 0
when (Preferences.widgetUpdateFrequency) {
val fireTime = when {
event.startDate <= now.timeInMillis
-> event.endDate
event.startDate > now.timeInMillis + limit
-> event.startDate - limit
!Preferences.showDiffTime
-> return
event.allDay
-> event.startDate
diff.hours > 12
-> event.startDate - 12 * 1000 * 60 * 60 + 1000 * 60
diff.hours > 0
-> event.startDate - diff.hours * 1000 * 60 * 60 + 1000 * 60
else
-> event.startDate - 1000 * 60 * when (Preferences.widgetUpdateFrequency) {
Constants.WidgetUpdateFrequency.DEFAULT.rawValue -> {
minutes = when {
diff.minutes > 50 -> 50
diff.minutes > 30 -> 30
diff.minutes > 15 -> 15
when {
diff.minutes >= 45 -> 44
diff.minutes >= 30 -> 29
diff.minutes >= 15 -> 14
else -> 0
}
}
Constants.WidgetUpdateFrequency.HIGH.rawValue -> {
minutes = diff.minutes - (diff.minutes % 5)
when {
diff.minutes >= 5 -> diff.minutes - diff.minutes % 5 - 1
else -> 0
}
}
else -> 0
}
}
// no need to schedule updates after the next ACTION_CALENDAR_UPDATE
if (Calendar.getInstance().apply {
set(Calendar.MILLISECOND, 0)
set(Calendar.SECOND, 0)
set(Calendar.MINUTE, 0)
set(Calendar.HOUR_OF_DAY, 0)
add(Calendar.DATE, 1)
}.timeInMillis <= fireTime) return
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
setExact(
AlarmManager.RTC,
if (event.startDate - minutes * 1000 * 60 > (now.timeInMillis + 120 * 1000)) event.startDate - 60 * 1000 * minutes else now.timeInMillis + 120000,
fireTime.coerceAtLeast(now.timeInMillis + 1000 * 60),
PendingIntent.getBroadcast(
context,
event.eventID.toInt(),
Intent(context, UpdatesReceiver::class.java).apply {
action = Actions.ACTION_TIME_UPDATE
if (event.startDate > now.timeInMillis)
putExtra(EVENT_ID, event.eventID)
},
PendingIntent.FLAG_UPDATE_CURRENT
)
)
} else {
setExact(
AlarmManager.RTC,
event.startDate - diff.hours * 1000 * 60 * 60 + if (diff.minutes > 30) (-30) else (+30),
PendingIntent.getBroadcast(
context,
event.eventID.toInt(),
Intent(context, UpdatesReceiver::class.java).apply {
action = Actions.ACTION_TIME_UPDATE
putExtra(EVENT_ID, event.eventID)
},
PendingIntent.FLAG_UPDATE_CURRENT
)
)
}
} else {
// Update the widget one second after the event is finished
val fireTime =
if (event.endDate > now.timeInMillis + 120 * 1000) event.endDate else now.timeInMillis + 120000
setExact(
AlarmManager.RTC,
fireTime,
PendingIntent.getBroadcast(
context,
event.eventID.toInt(),
Intent(context, UpdatesReceiver::class.java).apply {
action = Actions.ACTION_TIME_UPDATE
},
0
)
)
}
} else {
setExact(
AlarmManager.RTC,
if (event.startDate - limit > now.timeInMillis + 120 * 1000) event.startDate - limit else now.timeInMillis + 120000,
PendingIntent.getBroadcast(
context,
event.eventID.toInt(),
Intent(context, UpdatesReceiver::class.java).apply {
action = Actions.ACTION_TIME_UPDATE
putExtra(EVENT_ID, event.eventID)
},
PendingIntent.FLAG_UPDATE_CURRENT
)
)
}
}
}
fun removeUpdates(context: Context) {
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
cancel(PendingIntent.getBroadcast(context, 0, Intent(context, UpdatesReceiver::class.java).apply {
action = Actions.ACTION_CALENDAR_UPDATE
}, 0))
val eventRepository = EventRepository(context)
eventRepository.getFutureEvents().forEach {
cancel(PendingIntent.getBroadcast(context, it.eventID.toInt(), Intent(context, UpdatesReceiver::class.java), 0))
cancel(PendingIntent.getBroadcast(context, it.eventID.toInt(), Intent(context, UpdatesReceiver::class.java).apply {
action = Actions.ACTION_TIME_UPDATE
}, 0))
}
eventRepository.close()
}

View File

@ -22,21 +22,14 @@ class WeatherReceiver : BroadcastReceiver() {
Intent.ACTION_MY_PACKAGE_REPLACED,
Intent.ACTION_TIMEZONE_CHANGED,
Intent.ACTION_LOCALE_CHANGED,
Intent.ACTION_TIME_CHANGED -> setUpdates(context)
Actions.ACTION_WEATHER_UPDATE -> {
GlobalScope.launch(Dispatchers.IO) {
WeatherHelper.updateWeather(context)
}
}
Intent.ACTION_TIME_CHANGED,
Actions.ACTION_WEATHER_UPDATE -> setUpdates(context)
}
}
companion object {
private const val MINUTE = 60 * 1000L
fun setUpdates(context: Context) {
removeUpdates(context)
if (Preferences.showWeather) {
val interval = MINUTE * when (Preferences.weatherRefreshPeriod) {
0 -> 30
@ -48,13 +41,15 @@ class WeatherReceiver : BroadcastReceiver() {
else -> 60
}
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
setRepeating(
setExact(
AlarmManager.RTC,
Calendar.getInstance().timeInMillis,
interval,
System.currentTimeMillis() + interval,
PendingIntent.getBroadcast(context, 0, Intent(context, WeatherReceiver::class.java).apply { action = Actions.ACTION_WEATHER_UPDATE }, 0)
)
}
GlobalScope.launch(Dispatchers.IO) {
WeatherHelper.updateWeather(context)
}
}
}

View File

@ -16,14 +16,15 @@ class WidgetClickListenerReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == Actions.ACTION_OPEN_WEATHER_INTENT) {
try {
if (Preferences.weatherAppPackage == IntentHelper.REFRESH_WIDGET_OPTION) {
context.sendBroadcast(IntentHelper.getWeatherIntent(context))
} else {
context.startActivity(IntentHelper.getWeatherIntent(context))
IntentHelper.getWeatherIntent(context).run {
if (flags and Intent.FLAG_ACTIVITY_NEW_TASK == Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(this)
else
context.sendBroadcast(this)
}
} catch (e: Exception) {
e.printStackTrace()
val uri = Uri.parse("http://www.google.com/search?q=weather")
val uri = Uri.parse("https://www.google.com/search?q=weather")
val i = Intent(Intent.ACTION_VIEW, uri)
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
try {

View File

@ -18,6 +18,7 @@ import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.network.WeatherNetworkApi
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
import kotlinx.coroutines.*
import org.greenrobot.eventbus.EventBus
import java.lang.Exception
@ -37,12 +38,31 @@ class LocationService : Service() {
startForeground(LOCATION_ACCESS_NOTIFICATION_ID, getLocationAccessNotification())
job?.cancel()
job = GlobalScope.launch(Dispatchers.IO) {
if (ActivityCompat.checkSelfPermission(
this@LocationService,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
if (checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION) &&
(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.R ||
checkGrantedPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION))
) {
LocationServices.getFusedLocationProviderClient(this@LocationService).lastLocation.addOnCompleteListener { task ->
if (com.google.android.gms.common.GoogleApiAvailability.getInstance()
.isGooglePlayServicesAvailable(this@LocationService)
== com.google.android.gms.common.ConnectionResult.SUCCESS
) {
LocationServices.getFusedLocationProviderClient(this@LocationService).lastLocation
} else {
val lm = getSystemService(LOCATION_SERVICE) as android.location.LocationManager
var location: android.location.Location? = null
for (provider in arrayOf(
"fused", // LocationManager.FUSED_PROVIDER,
android.location.LocationManager.GPS_PROVIDER,
android.location.LocationManager.NETWORK_PROVIDER,
android.location.LocationManager.PASSIVE_PROVIDER
)) {
if (lm.isProviderEnabled(provider)) {
location = lm.getLastKnownLocation(provider)
if (location != null) break
}
}
com.google.android.gms.tasks.Tasks.forResult(location)
}.addOnCompleteListener { task ->
val networkApi = WeatherNetworkApi(this@LocationService)
if (task.isSuccessful) {
val location = task.result

View File

@ -55,18 +55,20 @@ class UpdateCalendarService : Service() {
job?.cancel()
job = GlobalScope.launch(Dispatchers.IO) {
UpdatesReceiver.removeUpdates(this@UpdateCalendarService)
val eventRepository = EventRepository(this@UpdateCalendarService)
if (Preferences.showEvents) {
val eventList = ArrayList<Event>()
// fetch all events from now to next ACTION_CALENDAR_UPDATE + limit
val now = Calendar.getInstance()
val begin = Calendar.getInstance().apply {
val limit = Calendar.getInstance().apply {
set(Calendar.MILLISECOND, 0)
set(Calendar.SECOND, 0)
set(Calendar.MINUTE, 0)
set(Calendar.HOUR_OF_DAY, 0)
}
val limit = Calendar.getInstance().apply {
add(Calendar.DATE, 1)
when (Preferences.showUntil) {
0 -> add(Calendar.HOUR, 3)
1 -> add(Calendar.HOUR, 6)
@ -85,18 +87,23 @@ class UpdateCalendarService : Service() {
)
) {
eventRepository.resetNextEventData()
eventRepository.clearEvents()
Preferences.showEvents = false
} else {
try {
val provider = CalendarProvider(this@UpdateCalendarService)
val data = provider.getInstances(begin.timeInMillis, limit.timeInMillis)
// apply time zone offset to correctly fetch all-day events
val data = provider.getInstances(
now.timeInMillis + now.timeZone.getOffset(now.timeInMillis).coerceAtMost(0),
limit.timeInMillis + limit.timeZone.getOffset(limit.timeInMillis).coerceAtLeast(0)
)
if (data != null) {
val instances = data.list
for (instance in instances) {
try {
val e = provider.getEvent(instance.eventId)
if (e != null && !e.deleted && instance.begin <= limit.timeInMillis && now.timeInMillis < instance.end && !CalendarHelper.getFilteredCalendarIdList()
.contains(e.calendarId)
) {
if (e == null || e.deleted || CalendarHelper.getFilteredCalendarIdList().contains(e.calendarId))
continue
if (e.allDay) {
val start = Calendar.getInstance()
start.timeInMillis = instance.begin
@ -107,7 +114,10 @@ class UpdateCalendarService : Service() {
instance.end =
end.timeInMillis - end.timeZone.getOffset(end.timeInMillis)
}
if (instance.begin <= limit.timeInMillis && now.timeInMillis < instance.end) {
/* Following check may result in "fake" all-day events with
* non-UTC start/end time, and therefore cannot be found by
* Calendar when tapped to open details.
// Check all day events
val startDate = Calendar.getInstance()
startDate.timeInMillis = instance.begin
@ -124,6 +134,7 @@ class UpdateCalendarService : Service() {
&& endDate.get(Calendar.MINUTE) == 0
&& endDate.get(Calendar.HOUR_OF_DAY) == 0
)
*/
eventList.add(
Event(
@ -133,7 +144,7 @@ class UpdateCalendarService : Service() {
startDate = instance.begin,
endDate = instance.end,
calendarID = e.calendarId.toInt(),
allDay = isAllDay,
allDay = e.allDay,
address = e.eventLocation ?: "",
selfAttendeeStatus = e.selfAttendeeStatus.toInt(),
availability = e.availability
@ -164,13 +175,14 @@ class UpdateCalendarService : Service() {
}
} else {
eventRepository.resetNextEventData()
eventRepository.clearEvents()
}
eventRepository.close()
UpdatesReceiver.setUpdates(this@UpdateCalendarService)
MainWidget.updateWidget(this@UpdateCalendarService)
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
eventRepository.close()
stopSelf()
}

View File

@ -140,6 +140,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
if (Preferences.showEvents && !checkGrantedPermission(Manifest.permission.READ_CALENDAR)) {
Preferences.showEvents = false
com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver.removeUpdates(this)
}
}

View File

@ -38,12 +38,15 @@ class CustomFontActivity : AppCompatActivity() {
private lateinit var adapter: SlimAdapter
private lateinit var viewModel: CustomFontViewModel
private lateinit var binding: ActivityCustomFontBinding
private lateinit var handlerThread: HandlerThread
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel = ViewModelProvider(this).get(CustomFontViewModel::class.java)
binding = ActivityCustomFontBinding.inflate(layoutInflater)
handlerThread = HandlerThread("listCustomFonts")
handlerThread.start()
binding.listView.setHasFixedSize(true)
val mLayoutManager = LinearLayoutManager(this)
@ -64,14 +67,17 @@ class CustomFontActivity : AppCompatActivity() {
injector
.text(R.id.text, item)
.with<TextView>(R.id.text) {
val googleSans: Typeface = when (Preferences.customFontVariant) {
"100" -> Typeface.createFromAsset(this.assets, "fonts/google_sans_thin.ttf")
"200" -> Typeface.createFromAsset(this.assets, "fonts/google_sans_light.ttf")
"500" -> Typeface.createFromAsset(this.assets, "fonts/google_sans_medium.ttf")
"700" -> Typeface.createFromAsset(this.assets, "fonts/google_sans_bold.ttf")
"800" -> Typeface.createFromAsset(this.assets, "fonts/google_sans_black.ttf")
else -> Typeface.createFromAsset(this.assets, "fonts/google_sans_regular.ttf")
val googleSans: Typeface? = androidx.core.content.res.ResourcesCompat.getFont(
this,
when (Preferences.customFontVariant) {
"100" -> R.font.google_sans_thin
"200" -> R.font.google_sans_light
"500" -> R.font.google_sans_medium
"700" -> R.font.google_sans_bold
"800" -> R.font.google_sans_black
else -> R.font.google_sans_regular
}
)
it.typeface = googleSans
}
@ -97,32 +103,49 @@ class CustomFontActivity : AppCompatActivity() {
)
val callback = object : FontsContractCompat.FontRequestCallback() {
override fun onTypefaceRetrieved(typeface: Typeface) {
it.typeface = typeface
it.isVisible = true
class Callback : FontsContractCompat.FontRequestCallback() {
var handler: Handler? = Handler(handlerThread.looper)
it.measure(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
fun cancel() {
if (handler != null) {
handler!!.removeCallbacksAndMessages(null)
handler = null
}
}
protected fun finalize() {
cancel()
}
override fun onTypefaceRetrieved(typeface: Typeface) {
if (it.tag == this) {
it.tag = null
it.typeface = typeface
it.setTextColor(getColor(R.color.colorPrimaryText))
}
}
override fun onTypefaceRequestFailed(reason: Int) {
it.isVisible = false
it.layoutParams = it.layoutParams.apply {
height = 0
if (it.tag == this) {
it.tag = null
//it.text = item.fontFamily + " ($reason)"
it.setTextColor(getColor(R.color.errorColorText))
}
}
}
val handlerThread = HandlerThread(item.fontFamily)
handlerThread.start()
val mHandler = Handler(handlerThread.looper)
(it.tag as Callback?)?.cancel()
val callback = Callback()
it.tag = callback
it.typeface = null
it.setTextColor(getColor(R.color.colorSecondaryText))
val mHandler = callback.handler!!
FontsContractCompat.requestFont(this, request, callback, mHandler)
}
injector.clicked(R.id.text) {
if ((it as TextView).typeface == null) return@clicked
val dialog = BottomSheetMenu<Int>(this, header = item.fontFamily)
if (item.fontVariants.isEmpty()) {
dialog.addItem(SettingsStringHelper.getVariantLabel(this, "regular"), -1)
@ -147,6 +170,12 @@ class CustomFontActivity : AppCompatActivity() {
setContentView(binding.root)
}
override fun onDestroy() {
handlerThread.quit()
filterJob?.cancel()
super.onDestroy()
}
private var filterJob: Job? = null
private fun subscribeUi(binding: ActivityCustomFontBinding, viewModel: CustomFontViewModel) {
@ -204,6 +233,13 @@ class CustomFontActivity : AppCompatActivity() {
adapter.updateData(filteredList)
binding.loader.visibility = View.INVISIBLE
}
} else {
delay(200)
withContext(Dispatchers.Main) {
adapter.updateData(listOf(getString(R.string.custom_font_subtitle_1)).filter {
it.contains(search ?: "", ignoreCase = true)
})
}
}
}
}

View File

@ -46,10 +46,15 @@ class CustomLocationActivity : AppCompatActivity() {
adapter = SlimAdapter.create()
adapter
.register<String>(R.layout.custom_location_item) { _, injector ->
injector
.text(R.id.text, getString(R.string.custom_location_gps))
.clicked(R.id.text) {
requirePermission()
injector.text(R.id.text, getString(R.string.custom_location_gps))
injector.clicked(R.id.text) {
Preferences.bulk {
remove(Preferences::customLocationLat)
remove(Preferences::customLocationLon)
remove(Preferences::customLocationAdd)
}
setResult(Activity.RESULT_OK)
finish()
}
}
.register<Address>(R.layout.custom_location_item) { item, injector ->
@ -59,11 +64,11 @@ class CustomLocationActivity : AppCompatActivity() {
customLocationLat = item.latitude.toString()
customLocationLon = item.longitude.toString()
customLocationAdd = item.getAddressLine(0) ?: ""
}
setResult(Activity.RESULT_OK)
finish()
}
}
}
.attachTo(binding.listView)
@ -115,36 +120,6 @@ class CustomLocationActivity : AppCompatActivity() {
})
}
private fun requirePermission() {
Dexter.withContext(this)
.withPermissions(
Manifest.permission.ACCESS_FINE_LOCATION
).withListener(object: MultiplePermissionsListener {
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
report?.let {
if (report.areAllPermissionsGranted()){
Preferences.bulk {
remove(Preferences::customLocationLat)
remove(Preferences::customLocationLon)
remove(Preferences::customLocationAdd)
}
setResult(Activity.RESULT_OK)
finish()
}
}
}
override fun onPermissionRationaleShouldBeShown(
permissions: MutableList<PermissionRequest>?,
token: PermissionToken?
) {
// Remember to invoke this method when the custom rationale is closed
// or just by default if you don't want to use any custom rationale.
token?.continuePermissionRequest()
}
})
.check()
}
private fun setupListener() {
binding.actionBack.setOnClickListener {
onBackPressed()

View File

@ -127,11 +127,11 @@ class WeatherProviderActivity : AppCompatActivity() {
private fun subscribeUi(viewModel: WeatherProviderViewModel) {
viewModel.weatherProviderError.observe(this) {
updateListItem()
binding.listView.postDelayed({ updateListItem() }, 300)
}
viewModel.weatherProviderLocationError.observe(this) {
updateListItem()
binding.listView.postDelayed({ updateListItem() }, 300)
}
}

View File

@ -8,16 +8,10 @@ import android.os.Bundle
import android.provider.Settings
import android.util.DisplayMetrics
import android.util.Log
import android.util.TypedValue
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.RelativeLayout
import androidx.core.content.ContextCompat
import androidx.core.view.children
import androidx.core.view.isVisible
import android.widget.RemoteViews
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
@ -30,23 +24,20 @@ import com.tommasoberlose.anotherwidget.databinding.FragmentAppMainBinding
import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.*
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import com.tommasoberlose.anotherwidget.ui.widgets.StandardWidget
import com.tommasoberlose.anotherwidget.utils.*
import kotlinx.coroutines.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
class MainFragment : Fragment() {
companion object {
fun newInstance() = MainFragment()
private val PREVIEW_BASE_HEIGHT: Int
get() = if (Preferences.widgetAlign == Constants.WidgetAlign.CENTER.rawValue) 120 else 180
}
private lateinit var viewModel: MainViewModel
@ -98,13 +89,7 @@ class MainFragment : Fragment() {
}
binding.actionSettings.setOnSingleClickListener {
Navigation.findNavController(it).navigate(R.id.action_appMainFragment_to_appSettingsFragment,)
}
binding.preview.layoutParams = binding.preview.layoutParams.apply {
height = PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
requireContext()
) else 0
Navigation.findNavController(it).navigate(R.id.action_appMainFragment_to_appSettingsFragment)
}
subscribeUi(viewModel)
@ -156,219 +141,50 @@ class MainFragment : Fragment() {
binding.toolbar.cardElevation = if (it > 0) 24f else 0f
}
viewModel.widgetAlign.observe(viewLifecycleOwner) {
updatePreviewVisibility()
lifecycleScope.launch {
delay(350)
updateClock()
}
}
viewModel.showPreview.observe(viewLifecycleOwner) {
updatePreviewVisibility()
}
viewModel.clockPreferencesUpdate.observe(viewLifecycleOwner) {
updateClock()
}
viewModel.widgetPreferencesUpdate.observe(viewLifecycleOwner) {
onUpdateUiEvent(null)
}
viewModel.showClock.observe(viewLifecycleOwner) {
updateClockVisibility(it)
}
}
private var uiJob: Job? = null
private fun updateUI() {
if (Preferences.showPreview) {
lifecycleScope.launch(Dispatchers.IO) {
val bgColor: Int = ContextCompat.getColor(
requireContext(),
if (ColorHelper.getFontColor(requireActivity().isDarkTheme())
.isColorDark()
) android.R.color.white else R.color.colorAccent
)
val wallpaperDrawable = BitmapHelper.getTintedDrawable(
requireContext(),
R.drawable.card_background,
ColorHelper.getBackgroundColor(requireActivity().isDarkTheme())
)
withContext(Dispatchers.Main) {
binding.preview.setCardBackgroundColor(bgColor)
binding.widgetDetail.widgetShapeBackground.setImageDrawable(wallpaperDrawable)
}
}
WidgetHelper.runWithCustomTypeface(requireContext()) { typeface ->
uiJob?.cancel()
uiJob = lifecycleScope.launch(Dispatchers.IO) {
val generatedView = MainWidget.getWidgetView(requireContext(), typeface)?.root
val generatedView = MainWidget.getWidgetView(requireContext(), binding.widget.width, typeface)
if (generatedView != null) {
withContext(Dispatchers.Main) {
val view: View = generatedView.apply(requireActivity().applicationContext, binding.widget)
view.measure(0, 0)
binding.widgetDetail.content.removeAllViews()
val container = LinearLayout(requireContext()).apply {
layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
}
container.gravity = when (Preferences.widgetAlign) {
Constants.WidgetAlign.CENTER.rawValue -> Gravity.CENTER_HORIZONTAL
Constants.WidgetAlign.LEFT.rawValue -> Gravity.START
Constants.WidgetAlign.RIGHT.rawValue -> Gravity.END
else -> Gravity.NO_GRAVITY
}
container.addView(generatedView)
binding.widgetDetail.content.addView(container)
binding.widgetLoader.animate().scaleX(1f).scaleY(1f).alpha(1f)
.setDuration(200L).start()
binding.widget.animate().alpha(0f).setDuration(200L).withEndAction {
binding.widget.removeAllViews()
binding.widget.addView(view)
updatePreviewVisibility(view.measuredHeight)
binding.widgetLoader.animate().scaleX(0f).scaleY(0f).alpha(0f)
.setDuration(200L).start()
binding.widget.animate().alpha(1f).start()
}
}
}
}
}
}
private fun updateClock() {
// Clock
binding.widgetDetail.time.setTextColor(ColorHelper.getClockFontColor(requireActivity().isDarkTheme()))
binding.widgetDetail.timeAmPm.setTextColor(ColorHelper.getClockFontColor(requireActivity().isDarkTheme()))
binding.widgetDetail.time.setTextSize(
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(requireContext())
)
binding.widgetDetail.timeAmPm.setTextSize(
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2
)
binding.widgetDetail.timeAmPm.isVisible = Preferences.showAMPMIndicator
// Timezones
if (Preferences.altTimezoneId != "" && Preferences.altTimezoneLabel != "") {
// Clock
binding.widgetDetail.altTimezoneTime.timeZone = Preferences.altTimezoneId
binding.widgetDetail.altTimezoneTimeAmPm.timeZone = Preferences.altTimezoneId
binding.widgetDetail.altTimezoneLabel.text = Preferences.altTimezoneLabel
binding.widgetDetail.altTimezoneTime.setTextColor(ColorHelper.getClockFontColor(requireActivity().isDarkTheme()))
binding.widgetDetail.altTimezoneTimeAmPm.setTextColor(ColorHelper.getClockFontColor(requireActivity().isDarkTheme()))
binding.widgetDetail.altTimezoneLabel.setTextColor(ColorHelper.getClockFontColor(requireActivity().isDarkTheme()))
binding.widgetDetail.altTimezoneTime.setTextSize(
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(requireContext()) / 3
)
binding.widgetDetail.altTimezoneTimeAmPm.setTextSize(
TypedValue.COMPLEX_UNIT_SP,
(Preferences.clockTextSize.toPixel(requireContext()) / 3) / 5 * 2
)
binding.widgetDetail.altTimezoneLabel.setTextSize(
TypedValue.COMPLEX_UNIT_SP,
(Preferences.clockTextSize.toPixel(requireContext()) / 3) / 5 * 2
)
binding.widgetDetail.timezonesContainer.isVisible = true
} else {
binding.widgetDetail.timezonesContainer.isVisible = false
}
// Clock bottom margin
binding.widgetDetail.clockBottomMarginNone.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.rawValue
binding.widgetDetail.clockBottomMarginSmall.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.SMALL.rawValue
binding.widgetDetail.clockBottomMarginMedium.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.MEDIUM.rawValue
binding.widgetDetail.clockBottomMarginLarge.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.LARGE.rawValue
// Align
binding.widgetDetail.timeContainer.layoutParams = (binding.widgetDetail.timeContainer.layoutParams as LinearLayout.LayoutParams).apply {
gravity = when (Preferences.widgetAlign) {
Constants.WidgetAlign.CENTER.rawValue -> Gravity.CENTER_HORIZONTAL
Constants.WidgetAlign.LEFT.rawValue -> Gravity.START
Constants.WidgetAlign.RIGHT.rawValue -> Gravity.END
else -> Gravity.NO_GRAVITY
}
}
if (Preferences.widgetAlign == Constants.WidgetAlign.RIGHT.rawValue) {
with (binding.widgetDetail.timeContainer) {
val child = getChildAt(2)
if (child.id == R.id.timezones_container) {
removeViewAt(2)
child.layoutParams = (child.layoutParams as ViewGroup.MarginLayoutParams).apply {
marginEnd = 16f.convertDpToPixel(requireContext()).toInt()
}
addView(child, 0)
}
}
} else {
with (binding.widgetDetail.timeContainer) {
val child = getChildAt(0)
if (child.id == R.id.timezones_container) {
removeViewAt(0)
child.layoutParams = (child.layoutParams as ViewGroup.MarginLayoutParams).apply {
marginEnd = 0
}
addView(child, 2)
}
}
}
}
private fun updateClockVisibility(showClock: Boolean) {
binding.widgetDetail.timeContainer.clearAnimation()
binding.widgetDetail.time.clearAnimation()
updatePreviewVisibility()
if (showClock) {
binding.widgetDetail.timeContainer.layoutParams = (binding.widgetDetail.timeContainer.layoutParams as LinearLayout.LayoutParams).apply {
height = RelativeLayout.LayoutParams.WRAP_CONTENT
}
binding.widgetDetail.timeContainer.measure(0, 0)
}
if ((Preferences.showClock && binding.widgetDetail.time.alpha != 1f) || (!Preferences.showClock && binding.widgetDetail.time.alpha != 0f)) {
val initialHeight = binding.widgetDetail.timeContainer.measuredHeight
ValueAnimator.ofFloat(
if (showClock) 0f else 1f,
if (showClock) 1f else 0f
).apply {
duration = 500L
addUpdateListener {
val animatedValue = animatedValue as Float
binding.widgetDetail.timeContainer.layoutParams =
binding.widgetDetail.timeContainer.layoutParams.apply {
height = (initialHeight * animatedValue).toInt()
}
binding.widgetDetail.time.alpha = animatedValue
binding.widgetDetail.timeAmPm.alpha = animatedValue
binding.widgetDetail.altTimezoneTime.alpha = animatedValue
binding.widgetDetail.altTimezoneTimeAmPm.alpha = animatedValue
binding.widgetDetail.altTimezoneLabel.alpha = animatedValue
}
}.start()
}
}
}
}
}
}
private fun updatePreviewVisibility() {
private fun updatePreviewVisibility(widgetHeight: Int) {
val newHeight = widgetHeight + 32f.convertDpToPixel(requireContext()).toInt()
if (binding.preview.layoutParams.height != newHeight) {
binding.preview.clearAnimation()
if (binding.preview.layoutParams.height != (if (Preferences.showPreview) PREVIEW_BASE_HEIGHT.toPixel(requireContext()) else 0) + (if (Preferences.showClock) 100.toPixel(
requireContext()
) else 0)) {
ValueAnimator.ofInt(
binding.preview.height,
(if (Preferences.showPreview) PREVIEW_BASE_HEIGHT.toPixel(requireContext()) else 0) + (if (Preferences.showClock) 100.toPixel(
requireContext()
) else 0)
newHeight
).apply {
duration = 500L
addUpdateListener {

View File

@ -182,7 +182,7 @@ class CalendarFragment : Fragment() {
binding.showAllDayToggle.setOnCheckedChangeListener { _, isChecked ->
Preferences.calendarAllDay = isChecked
MainWidget.updateWidget(requireContext())
updateCalendar()
}
binding.actionChangeAttendeeFilter.setOnClickListener {
@ -227,7 +227,7 @@ class CalendarFragment : Fragment() {
binding.showOnlyBusyEventsToggle.setOnCheckedChangeListener { _, isChecked ->
Preferences.showOnlyBusyEvents = isChecked
MainWidget.updateWidget(requireContext())
updateCalendar()
}
binding.actionShowDiffTime.setOnClickListener {
@ -254,6 +254,7 @@ class CalendarFragment : Fragment() {
.addItem(getString(R.string.settings_widget_update_frequency_low), Constants.WidgetUpdateFrequency.LOW.rawValue)
.addOnSelectItemListener { value ->
Preferences.widgetUpdateFrequency = value
updateCalendar()
}.show()
}
}

View File

@ -17,7 +17,7 @@ import com.chibatching.kotpref.bulk
import com.google.android.material.transition.MaterialSharedAxis
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
import com.tommasoberlose.anotherwidget.components.BottomSheetPicker
import com.tommasoberlose.anotherwidget.databinding.FragmentTabClockBinding
import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences
@ -144,16 +144,15 @@ class ClockFragment : Fragment() {
private fun setupListener() {
binding.actionClockTextSize.setOnClickListener {
val dialog = BottomSheetMenu<Float>(
BottomSheetPicker(
requireContext(),
header = getString(R.string.settings_clock_text_size_title)
).setSelectedValue(Preferences.clockTextSize)
(46 downTo 12).filter { it % 2 == 0 }.forEach {
dialog.addItem("${it}sp", it.toFloat())
items = (46 downTo 12).map { BottomSheetPicker.MenuItem("${it}sp", it.toFloat()) },
getSelected = { Preferences.clockTextSize },
header = getString(R.string.settings_clock_text_size_title),
onItemSelected = {value ->
if (value != null) Preferences.clockTextSize = value
}
dialog.addOnSelectItemListener { value ->
Preferences.clockTextSize = value
}.show()
).show()
}
binding.actionAltTimezoneClock.setOnClickListener {

View File

@ -102,15 +102,7 @@ class GesturesFragment : Fragment() {
it == IntentHelper.DO_NOTHING_OPTION -> getString(R.string.gestures_do_nothing)
it == IntentHelper.REFRESH_WIDGET_OPTION -> getString(R.string.gestures_refresh_widget)
it != IntentHelper.DEFAULT_OPTION -> it
else -> {
if (IntentHelper.getCalendarIntent(requireContext()).isDefaultSet(requireContext())) {
getString(
R.string.default_calendar_app
)
} else {
getString(R.string.gestures_do_nothing)
}
}
else -> getString(R.string.default_calendar_app)
}
}
}
@ -127,15 +119,7 @@ class GesturesFragment : Fragment() {
it == IntentHelper.DO_NOTHING_OPTION -> getString(R.string.gestures_do_nothing)
it == IntentHelper.REFRESH_WIDGET_OPTION -> getString(R.string.gestures_refresh_widget)
it != IntentHelper.DEFAULT_OPTION -> it
else -> {
if (IntentHelper.getClockIntent(requireContext()).isDefaultSet(requireContext())) {
getString(
R.string.default_clock_app
)
} else {
getString(R.string.gestures_do_nothing)
}
}
else -> getString(R.string.default_clock_app)
}
}
}
@ -173,9 +157,12 @@ class GesturesFragment : Fragment() {
}
binding.actionCalendarApp.setOnClickListener {
startActivityForResult(Intent(requireContext(), ChooseApplicationActivity::class.java).apply {
startActivityForResult(
Intent(requireContext(), ChooseApplicationActivity::class.java).apply {
putExtra(Constants.RESULT_APP_PACKAGE, Preferences.calendarAppPackage)
}, RequestCode.CALENDAR_APP_REQUEST_CODE.code)
},
RequestCode.CALENDAR_APP_REQUEST_CODE.code
)
}
binding.actionClockApp.setOnClickListener {

View File

@ -293,6 +293,25 @@ class GlanceTabFragment : Fragment() {
if (!(isVisible && hasError)) View.VISIBLE else View.GONE
)
}
Constants.GlanceProviderId.WEATHER -> {
isVisible =
Preferences.showWeatherAsGlanceProvider
val hasError = !Preferences.showWeather || (Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-") || Preferences.weatherProviderLocationError != ""
injector.text(
R.id.label,
if (isVisible && !hasError) getString(R.string.settings_visible) else getString(
R.string.settings_not_visible
)
)
injector.visibility(
R.id.error_icon,
if (isVisible && hasError) View.VISIBLE else View.GONE
)
injector.visibility(
R.id.info_icon,
if (!(isVisible && hasError)) View.VISIBLE else View.GONE
)
}
}
injector.alpha(R.id.title, if (isVisible) 1f else .25f)

View File

@ -86,6 +86,28 @@ class LayoutFragment : Fragment() {
viewModel: MainViewModel
) {
viewModel.widgetMargin.observe(viewLifecycleOwner) {
maintainScrollPosition {
binding.widgetMarginLabel.text = when (it) {
Constants.Dimension.NONE.rawValue -> getString(R.string.settings_widget_dim_none)
Constants.Dimension.SMALL.rawValue -> getString(R.string.settings_widget_dim_small)
Constants.Dimension.LARGE.rawValue -> getString(R.string.settings_widget_dim_large)
else -> getString(R.string.settings_widget_dim_medium)
}
}
}
viewModel.widgetPadding.observe(viewLifecycleOwner) {
maintainScrollPosition {
binding.widgetPaddingLabel.text = when (it) {
Constants.Dimension.NONE.rawValue -> getString(R.string.settings_widget_dim_none)
Constants.Dimension.SMALL.rawValue -> getString(R.string.settings_widget_dim_small)
Constants.Dimension.LARGE.rawValue -> getString(R.string.settings_widget_dim_large)
else -> getString(R.string.settings_widget_dim_medium)
}
}
}
viewModel.secondRowTopMargin.observe(viewLifecycleOwner) {
maintainScrollPosition {
binding.secondRowTopMarginLabel.text = when (it) {
@ -147,6 +169,58 @@ class LayoutFragment : Fragment() {
private fun setupListener() {
binding.actionWidgetMargin.setOnClickListener {
BottomSheetMenu<Float>(
requireContext(),
header = getString(R.string.settings_widget_margin_title)
).setSelectedValue(Preferences.widgetMargin)
.addItem(
getString(R.string.settings_widget_dim_none),
Constants.Dimension.NONE.rawValue
)
.addItem(
getString(R.string.settings_widget_dim_small),
Constants.Dimension.SMALL.rawValue
)
.addItem(
getString(R.string.settings_widget_dim_medium),
Constants.Dimension.MEDIUM.rawValue
)
.addItem(
getString(R.string.settings_widget_dim_large),
Constants.Dimension.LARGE.rawValue
)
.addOnSelectItemListener { value ->
Preferences.widgetMargin = value
}.show()
}
binding.actionWidgetPadding.setOnClickListener {
BottomSheetMenu<Float>(
requireContext(),
header = getString(R.string.settings_widget_padding_title)
).setSelectedValue(Preferences.widgetPadding)
.addItem(
getString(R.string.settings_widget_dim_none),
Constants.Dimension.NONE.rawValue
)
.addItem(
getString(R.string.settings_widget_dim_small),
Constants.Dimension.SMALL.rawValue
)
.addItem(
getString(R.string.settings_widget_dim_medium),
Constants.Dimension.MEDIUM.rawValue
)
.addItem(
getString(R.string.settings_widget_dim_large),
Constants.Dimension.LARGE.rawValue
)
.addOnSelectItemListener { value ->
Preferences.widgetPadding = value
}.show()
}
binding.actionSecondRowTopMarginSize.setOnClickListener {
BottomSheetMenu<Int>(
requireContext(),

View File

@ -23,6 +23,7 @@ import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
import com.tommasoberlose.anotherwidget.databinding.FragmentPreferencesBinding
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
@ -123,6 +124,7 @@ class PreferencesFragment : Fragment() {
requireCalendarPermission()
} else {
Preferences.showEvents = enabled
UpdatesReceiver.removeUpdates(requireContext())
}
}
@ -133,6 +135,8 @@ class PreferencesFragment : Fragment() {
binding.showWeatherSwitch.setOnCheckedChangeListener { _, enabled: Boolean ->
Preferences.showWeather = enabled
if (enabled) {
Preferences.weatherProviderError = ""
Preferences.weatherProviderLocationError = ""
WeatherReceiver.setUpdates(requireContext())
} else {
WeatherReceiver.removeUpdates(requireContext())

View File

@ -276,7 +276,7 @@ class TypographyFragment : Fragment() {
Intent(requireContext(), CustomFontActivity::class.java),
RequestCode.CUSTOM_FONT_CHOOSER_REQUEST_CODE.code
)
} else if (value != Constants.CUSTOM_FONT_DOWNLOADED) {
} else if (value != Preferences.customFont) {
Preferences.bulk {
customFont = value
customFontFile = ""

View File

@ -91,16 +91,17 @@ class WeatherFragment : Fragment() {
viewModel.weatherProvider.observe(viewLifecycleOwner) {
maintainScrollPosition {
binding.labelWeatherProvider.text = WeatherHelper.getProviderName(requireContext(), Constants.WeatherProvider.fromInt(it)!!)
checkWeatherProviderConfig()
}
}
viewModel.weatherProviderError.observe(viewLifecycleOwner) {
checkWeatherProviderConfig()
checkLocationPermission()
}
viewModel.weatherProviderLocationError.observe(viewLifecycleOwner) {
checkWeatherProviderConfig()
checkLocationPermission()
}
viewModel.customLocationAdd.observe(viewLifecycleOwner) {
@ -108,6 +109,7 @@ class WeatherFragment : Fragment() {
binding.labelCustomLocation.text =
if (it == "") getString(R.string.custom_location_gps) else it
}
checkWeatherProviderConfig()
checkLocationPermission()
}
@ -116,43 +118,50 @@ class WeatherFragment : Fragment() {
binding.tempUnit.text =
if (it == "F") getString(R.string.fahrenheit) else getString(R.string.celsius)
}
checkLocationPermission()
}
viewModel.weatherRefreshPeriod.observe(viewLifecycleOwner) {
maintainScrollPosition {
binding.labelWeatherRefreshPeriod.text = getString(SettingsStringHelper.getRefreshPeriodString(it))
}
checkLocationPermission()
}
viewModel.weatherIconPack.observe(viewLifecycleOwner) {
maintainScrollPosition {
binding.labelWeatherIconPack.text = getString(R.string.settings_weather_icon_pack_default).format((it + 1))
}
checkLocationPermission()
}
}
private fun checkLocationPermission() {
if (requireActivity().checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION)) {
if (requireActivity().checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION) &&
(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.R ||
requireActivity().checkGrantedPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION))
) {
binding.locationPermissionAlert.isVisible = false
WeatherReceiver.setUpdates(requireContext())
} else if (Preferences.showWeather && Preferences.customLocationAdd == "") {
} else if (Preferences.customLocationAdd == "") {
binding.locationPermissionAlert.isVisible = true
binding.locationPermissionAlert.setOnClickListener {
requirePermission()
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R &&
requireActivity().checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION)
) {
val text = getString(R.string.action_grant_permission) + " - " +
requireContext().packageManager.backgroundPermissionOptionLabel
binding.locationPermissionAlert.text = text
}
binding.weatherProviderLocationError.isVisible = false
} else {
binding.locationPermissionAlert.isVisible = false
}
}
private fun checkWeatherProviderConfig() {
binding.weatherProviderError.isVisible = Preferences.showWeather && Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-"
binding.weatherProviderError.isVisible = Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-"
binding.weatherProviderError.text = Preferences.weatherProviderError
binding.weatherProviderLocationError.isVisible = Preferences.showWeather && Preferences.weatherProviderLocationError != ""
binding.weatherProviderLocationError.isVisible = Preferences.weatherProviderLocationError != ""
binding.weatherProviderLocationError.text = Preferences.weatherProviderLocationError
}
@ -177,11 +186,11 @@ class WeatherFragment : Fragment() {
.addItem(getString(R.string.celsius), "C")
.addOnSelectItemListener { value ->
if (value != Preferences.weatherTempUnit) {
Preferences.weatherTempUnit = value
viewLifecycleOwner.lifecycleScope.launch {
WeatherHelper.updateWeather(requireContext())
}
}
Preferences.weatherTempUnit = value
}.show()
}
@ -193,7 +202,10 @@ class WeatherFragment : Fragment() {
}
dialog
.addOnSelectItemListener { value ->
if (value != Preferences.weatherRefreshPeriod) {
Preferences.weatherRefreshPeriod = value
WeatherReceiver.setUpdates(requireContext())
}
}.show()
}
@ -206,12 +218,12 @@ class WeatherFragment : Fragment() {
if (resultCode == Activity.RESULT_OK) {
when (requestCode) {
Constants.RESULT_CODE_CUSTOM_LOCATION -> {
WeatherReceiver.setUpdates(requireContext())
checkLocationPermission()
viewLifecycleOwner.lifecycleScope.launch {
WeatherHelper.updateWeather(requireContext())
}
RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code -> {
checkLocationPermission()
}
//RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code -> {
//}
}
}
super.onActivityResult(requestCode, resultCode, data)
@ -220,12 +232,19 @@ class WeatherFragment : Fragment() {
private fun requirePermission() {
Dexter.withContext(requireContext())
.withPermissions(
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R &&
requireActivity().checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION))
Manifest.permission.ACCESS_BACKGROUND_LOCATION
else
Manifest.permission.ACCESS_FINE_LOCATION
).withListener(object: MultiplePermissionsListener {
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
report?.let {
if (report.areAllPermissionsGranted()) {
checkLocationPermission()
viewLifecycleOwner.lifecycleScope.launch {
WeatherHelper.updateWeather(requireContext())
}
}
}
}

View File

@ -50,6 +50,8 @@ class MainViewModel(context: Application) : AndroidViewModel(context) {
val showDividers = Preferences.asLiveData(Preferences::showDividers)
val secondRowTopMargin = Preferences.asLiveData(Preferences::secondRowTopMargin)
val widgetAlign = Preferences.asLiveData(Preferences::widgetAlign)
val widgetMargin = Preferences.asLiveData(Preferences::widgetMargin)
val widgetPadding = Preferences.asLiveData(Preferences::widgetPadding)
// Calendar Settings
val showEvents = Preferences.asLiveData(Preferences::showEvents)
@ -102,7 +104,8 @@ class MainViewModel(context: Application) : AndroidViewModel(context) {
// UI
val fragmentScrollY = MutableLiveData<Int>()
val clockPreferencesUpdate = MediatorLiveData<Boolean>().apply {
val widgetPreferencesUpdate = MediatorLiveData<Boolean>().apply {
addSource(Preferences.asLiveData(Preferences::showClock)) { value = true }
addSource(Preferences.asLiveData(Preferences::clockTextSize)) { value = true }
addSource(Preferences.asLiveData(Preferences::clockTextColor)) { value = true }
addSource(Preferences.asLiveData(Preferences::clockTextAlpha)) { value = true }
@ -111,8 +114,6 @@ class MainViewModel(context: Application) : AndroidViewModel(context) {
addSource(Preferences.asLiveData(Preferences::showAMPMIndicator)) { value = true }
addSource(Preferences.asLiveData(Preferences::clockBottomMargin)) { value = true }
addSource(Preferences.asLiveData(Preferences::altTimezoneLabel)) { value = true }
}
val widgetPreferencesUpdate = MediatorLiveData<Boolean>().apply {
addSource(Preferences.asLiveData(Preferences::textGlobalColor)) { value = true }
addSource(Preferences.asLiveData(Preferences::textGlobalAlpha)) { value = true }
addSource(Preferences.asLiveData(Preferences::textSecondaryColor)) { value = true }
@ -136,6 +137,8 @@ class MainViewModel(context: Application) : AndroidViewModel(context) {
addSource(Preferences.asLiveData(Preferences::customFontVariant)) { value = true }
addSource(Preferences.asLiveData(Preferences::secondRowInformation)) { value = true }
addSource(Preferences.asLiveData(Preferences::widgetAlign)) { value = true }
addSource(Preferences.asLiveData(Preferences::widgetMargin)) { value = true }
addSource(Preferences.asLiveData(Preferences::widgetPadding)) { value = true }
addSource(Preferences.asLiveData(Preferences::showDividers)) { value = true }
addSource(Preferences.asLiveData(Preferences::secondRowTopMargin)) { value = true }
addSource(Preferences.asLiveData(Preferences::isDateCapitalize)) { value = true }
@ -171,6 +174,7 @@ class MainViewModel(context: Application) : AndroidViewModel(context) {
addSource(Preferences.asLiveData(Preferences::musicPlayersFilter)) { value = true }
addSource(Preferences.asLiveData(Preferences::appNotificationsFilter)) { value = true }
addSource(Preferences.asLiveData(Preferences::showEventsAsGlanceProvider)) { value = true }
addSource(Preferences.asLiveData(Preferences::showWeatherAsGlanceProvider)) { value = true }
addSource(Preferences.asLiveData(Preferences::installedIntegrations)) { value = true }
}

View File

@ -54,13 +54,19 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
"setImageAlpha",
ColorHelper.getBackgroundAlpha(context.isDarkTheme())
)
val refreshIntent = PendingIntent.getActivity(
val margin = Preferences.widgetMargin.convertDpToPixel(context).toInt()
views.setViewPadding(R.id.widget_shape_background, margin, margin, margin, margin)
val refreshIntent = IntentHelper.getPendingIntent(
context,
appWidgetId,
IntentHelper.getWidgetUpdateIntent(context),
PendingIntent.FLAG_UPDATE_CURRENT
)
views.setOnClickPendingIntent(R.id.widget_shape_background, refreshIntent)
// Padding
val padding = (Preferences.widgetPadding.convertDpToPixel(context) + Preferences.widgetMargin.convertDpToPixel(context)).toInt()
views.setViewPadding(R.id.main_layout, padding, padding, padding, padding)
} catch (ex: Exception) {
ex.printStackTrace()
CrashlyticsReceiver.sendCrash(context, ex)
@ -96,7 +102,7 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
// Weather
if (Preferences.showWeather && Preferences.weatherIcon != "") {
views.setViewVisibility(R.id.weather_rect, View.VISIBLE)
views.setViewVisibility(R.id.weather_sub_line, View.GONE)
views.setViewVisibility(R.id.weather_sub_line_rect, View.GONE)
val i = Intent(context, WidgetClickListenerReceiver::class.java)
i.action = Actions.ACTION_OPEN_WEATHER_INTENT
@ -116,7 +122,7 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
)
} else {
views.setViewVisibility(R.id.weather_rect, View.GONE)
views.setViewVisibility(R.id.weather_sub_line, View.GONE)
views.setViewVisibility(R.id.weather_sub_line_rect, View.GONE)
}
@ -126,7 +132,7 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
BitmapHelper.getBitmapFromView(bindingView.date, draw = false, width = bindingView.date.width, height = bindingView.date.height)
)
val calPIntent = PendingIntent.getActivity(
val calPIntent = IntentHelper.getPendingIntent(
context,
widgetID,
IntentHelper.getCalendarIntent(context),
@ -135,8 +141,6 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
views.setOnClickPendingIntent(R.id.date_rect, calPIntent)
views.setViewVisibility(R.id.first_line_rect, View.VISIBLE)
val nextAlarm = AlarmHelper.getNextAlarm(context)
// Spacing
views.setViewVisibility(
R.id.sub_line_top_margin_small_sans,
@ -179,7 +183,7 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
}
// Event intent
val eventIntent = PendingIntent.getActivity(
val eventIntent = IntentHelper.getPendingIntent(
context,
widgetID,
IntentHelper.getEventIntent(context, nextEvent),
@ -216,7 +220,7 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
// Event information
if (nextEvent.address != "" && Preferences.secondRowInformation == 1) {
val mapIntent = PendingIntent.getActivity(
val mapIntent = IntentHelper.getPendingIntent(
context,
widgetID,
IntentHelper.getGoogleMapsIntentFromAddress(context, nextEvent.address),
@ -224,14 +228,10 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
)
views.setOnClickPendingIntent(R.id.sub_line_rect, mapIntent)
} else {
val pIntentDetail = PendingIntent.getActivity(
val pIntentDetail = IntentHelper.getPendingIntent(
context,
widgetID,
IntentHelper.getEventIntent(
context,
nextEvent,
forceEventDetails = true
),
IntentHelper.getCalendarIntent(context, nextEvent.startDate),
PendingIntent.FLAG_UPDATE_CURRENT
)
views.setOnClickPendingIntent(R.id.sub_line_rect, pIntentDetail)
@ -239,7 +239,7 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
views.setViewVisibility(R.id.sub_line_rect, View.VISIBLE)
views.setViewVisibility(R.id.weather_sub_line_rect, View.VISIBLE)
views.setViewVisibility(R.id.weather_sub_line_rect, if (Preferences.showWeather && Preferences.weatherIcon != "") View.VISIBLE else View.GONE)
views.setViewVisibility(R.id.first_line_rect, View.GONE)
views.setViewVisibility(R.id.sub_line_top_margin_small_sans, View.GONE)
@ -247,11 +247,12 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
views.setViewVisibility(R.id.sub_line_top_margin_large_sans, View.GONE)
} else if (GlanceProviderHelper.showGlanceProviders(context)) {
var showSomething = false
var isWeatherShown = false
loop@ for (provider: Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders(context)) {
when (provider) {
Constants.GlanceProviderId.PLAYING_SONG -> {
if (MediaPlayerHelper.isSomeonePlaying(context)) {
val musicIntent = PendingIntent.getActivity(
val musicIntent = IntentHelper.getPendingIntent(
context,
widgetID,
IntentHelper.getMusicIntent(context),
@ -263,8 +264,10 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
}
}
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
if (Preferences.showNextAlarm && nextAlarm != "") {
val alarmIntent = PendingIntent.getActivity(
if (Preferences.showNextAlarm) {
val nextAlarm = AlarmHelper.getNextAlarm(context)
if (nextAlarm != "") {
val alarmIntent = IntentHelper.getPendingIntent(
context,
widgetID,
IntentHelper.getClockIntent(context),
@ -275,11 +278,12 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
break@loop
}
}
}
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
if (Preferences.showBatteryCharging) {
BatteryHelper.updateBatteryInfo(context)
if (Preferences.isCharging || Preferences.isBatteryLevelLow) {
val batteryIntent = PendingIntent.getActivity(
val batteryIntent = IntentHelper.getPendingIntent(
context,
widgetID,
IntentHelper.getBatteryIntent(),
@ -298,7 +302,7 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
}
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) {
val fitIntent = PendingIntent.getActivity(
val fitIntent = IntentHelper.getPendingIntent(
context,
widgetID,
IntentHelper.getFitIntent(context),
@ -319,7 +323,7 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
remotePackageContext,
Preferences.lastNotificationIcon)
}
val notificationIntent = PendingIntent.getActivity(
val notificationIntent = IntentHelper.getPendingIntent(
context,
widgetID,
IntentHelper.getNotificationIntent(context),
@ -343,7 +347,7 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
Constants.GlanceProviderId.EVENTS -> {
if (Preferences.showEventsAsGlanceProvider&& Preferences.showEvents && context.checkGrantedPermission(
Manifest.permission.READ_CALENDAR) && nextEvent != null) {
val pIntentDetail = PendingIntent.getActivity(
val pIntentDetail = IntentHelper.getPendingIntent(
context,
widgetID,
IntentHelper.getEventIntent(
@ -361,13 +365,29 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
break@loop
}
}
Constants.GlanceProviderId.WEATHER -> {
if (Preferences.showWeatherAsGlanceProvider && Preferences.showWeather && Preferences.weatherIcon != "") {
val i = Intent(context, WidgetClickListenerReceiver::class.java)
i.action = Actions.ACTION_OPEN_WEATHER_INTENT
val weatherPIntent = PendingIntent.getBroadcast(context, widgetID, i, 0)
views.setOnClickPendingIntent(
R.id.sub_line_rect,
weatherPIntent
)
showSomething = true
isWeatherShown = true
break@loop
}
}
}
}
if (showSomething) {
views.setViewVisibility(R.id.first_line_rect, View.VISIBLE)
views.setViewVisibility(R.id.weather_rect, View.VISIBLE)
views.setViewVisibility(R.id.weather_rect, if (isWeatherShown) View.GONE else View.VISIBLE)
views.setViewVisibility(R.id.sub_line_rect, View.VISIBLE)
views.setViewVisibility(R.id.calendar_layout_rect, View.GONE)
@ -406,8 +426,9 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
// Generates the widget bitmap from the view
fun generateWidgetView(typeface: Typeface? = null): LeftAlignedWidgetBinding? {
private fun generateWidgetView(typeface: Typeface? = null): LeftAlignedWidgetBinding? {
try {
var isWeatherShownAsGlanceProvider = false
val eventRepository = EventRepository(context)
val nextEvent = eventRepository.getNextEvent()
val eventsCount = eventRepository.getEventsCount()
@ -461,8 +482,6 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
bindingView.date.text = DateHelper.getDateText(context, now)
val nextAlarm = AlarmHelper.getNextAlarm(context)
if (Preferences.showEvents && context.checkGrantedPermission(Manifest.permission.READ_CALENDAR) && nextEvent != null && !Preferences.showEventsAsGlanceProvider) {
// Multiple counter
bindingView.actionNext.isVisible =
@ -563,18 +582,16 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
}
} else {
val flags: Int =
DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NO_YEAR or DateUtils.FORMAT_ABBREV_MONTH
val start = Calendar.getInstance().apply { timeInMillis = nextEvent.startDate }
bindingView.subLineText.text = if (now.get(Calendar.DAY_OF_YEAR) == start.get(
Calendar.DAY_OF_YEAR)) {
DateUtils.formatDateTime(context, nextEvent.startDate, flags)
DateHelper.getDateText(context, start)
} else if (now.get(Calendar.DAY_OF_YEAR) > start.get(Calendar.DAY_OF_YEAR) || now.get(
Calendar.YEAR) > start.get(Calendar.YEAR)) {
DateUtils.formatDateTime(context, now.timeInMillis, flags)
DateHelper.getDateText(context, now)
} else {
DateUtils.formatDateTime(context, nextEvent.startDate, flags)
DateHelper.getDateText(context, start)
}
}
}
@ -582,7 +599,7 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
bindingView.dateLayout.isVisible = false
bindingView.calendarLayout.isVisible = true
bindingView.subLine.isVisible = true
bindingView.weatherSubLine.isVisible = true
bindingView.weatherSubLine.isVisible = Preferences.showWeather && Preferences.weatherIcon != ""
bindingView.subLineTopMarginSmall.visibility = View.GONE
bindingView.subLineTopMarginMedium.visibility = View.GONE
@ -608,18 +625,21 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
}
}
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
if (Preferences.showNextAlarm && nextAlarm != "") {
if (Preferences.showNextAlarm) {
val nextAlarm = AlarmHelper.getNextAlarm(context)
if (nextAlarm != "") {
bindingView.subLineIcon.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.round_alarm_24
)
)
bindingView.subLineText.text = AlarmHelper.getNextAlarm(context)
bindingView.subLineText.text = nextAlarm
showSomething = true
break@loop
}
}
}
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
if (Preferences.showBatteryCharging) {
BatteryHelper.updateBatteryInfo(context)
@ -721,6 +741,33 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
break@loop
}
}
Constants.GlanceProviderId.WEATHER -> {
if (Preferences.showWeatherAsGlanceProvider && Preferences.showWeather && Preferences.weatherIcon != "") {
bindingView.subLineText.text = String.format(
Locale.getDefault(),
"%d°%s %s",
Preferences.weatherTemp.roundToInt(),
Preferences.weatherRealTempUnit,
WeatherHelper.getWeatherLabel(context, Preferences.weatherIcon)
)
bindingView.subLineIcon.isVisible = true
val icon: String = Preferences.weatherIcon
if (icon == "") {
bindingView.subLineIcon.isVisible = false
} else {
bindingView.subLineIcon.setImageResource(WeatherHelper.getWeatherIconResource(context, icon))
bindingView.subLineIcon.isVisible = true
}
bindingView.weatherDateLine.isVisible = false
bindingView.weatherSubLine.isVisible = false
showSomething = true
isWeatherShownAsGlanceProvider = true
break@loop
}
}
}
}
@ -772,10 +819,15 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
it.setTextColor(ColorHelper.getSecondaryFontColor(context.applicationContext.isDarkTheme()))
}
if (!isWeatherShownAsGlanceProvider) {
if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.rawValue) {
listOf<ImageView>(bindingView.subLineIcon, bindingView.subLineIconShadow)
} else {
listOf<ImageView>(bindingView.subLineIcon, bindingView.weatherSubLineWeatherIcon, bindingView.subLineIconShadow)
listOf<ImageView>(
bindingView.subLineIcon,
bindingView.weatherSubLineWeatherIcon,
bindingView.subLineIconShadow
)
}.forEach {
it.setColorFilter(ColorHelper.getSecondaryFontColorRgb(context.applicationContext.isDarkTheme()))
it.alpha =
@ -783,6 +835,7 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
.toFloat() else Preferences.textSecondaryAlpha.toIntValue()
.toFloat()) / 100
}
}
// Text Size
listOf<Pair<TextView, Float>>(
@ -876,14 +929,17 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
// Custom Font
if (Preferences.customFont == Constants.CUSTOM_FONT_GOOGLE_SANS) {
val googleSans: Typeface = when (Preferences.customFontVariant) {
"100" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_thin.ttf")
"200" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_light.ttf")
"500" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_medium.ttf")
"700" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_bold.ttf")
"800" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_black.ttf")
else -> Typeface.createFromAsset(context.assets, "fonts/google_sans_regular.ttf")
val googleSans: Typeface? = androidx.core.content.res.ResourcesCompat.getFont(
context,
when (Preferences.customFontVariant) {
"100" -> R.font.google_sans_thin
"200" -> R.font.google_sans_light
"500" -> R.font.google_sans_medium
"700" -> R.font.google_sans_bold
"800" -> R.font.google_sans_black
else -> R.font.google_sans_regular
}
)
listOf<TextView>(
bindingView.date,

View File

@ -39,7 +39,7 @@ class ClockWidget(val context: Context) {
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(context) / 5 * 2
)
val clockPIntent = PendingIntent.getActivity(
val clockPIntent = IntentHelper.getPendingIntent(
context,
widgetID,
IntentHelper.getClockIntent(context),

View File

@ -7,7 +7,7 @@ import android.content.Context
import android.content.res.Resources
import android.graphics.Typeface
import android.os.Bundle
import androidx.viewbinding.ViewBinding
import android.widget.RemoteViews
import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.*
@ -83,11 +83,18 @@ class MainWidget : AppWidgetProvider() {
}
}
fun getWidgetView(context: Context, typeface: Typeface?): ViewBinding? {
fun getWidgetView(context: Context, width: Int, typeface: Typeface?): RemoteViews? {
return when (Preferences.widgetAlign) {
Constants.WidgetAlign.LEFT.rawValue -> AlignedWidget(context).generateWidgetView(typeface)
Constants.WidgetAlign.RIGHT.rawValue -> AlignedWidget(context, rightAligned = true).generateWidgetView(typeface)
else -> StandardWidget(context).generateWidgetView(typeface)
Constants.WidgetAlign.LEFT.rawValue -> AlignedWidget(context).generateWidget(
0,
width,
typeface
)
Constants.WidgetAlign.RIGHT.rawValue -> AlignedWidget(
context,
rightAligned = true
).generateWidget(0, width, typeface)
else -> StandardWidget(context).generateWidget(0, width, typeface)
}
}
}

View File

@ -57,13 +57,19 @@ class StandardWidget(val context: Context) {
"setImageAlpha",
ColorHelper.getBackgroundAlpha(context.isDarkTheme())
)
val refreshIntent = PendingIntent.getActivity(
val margin = Preferences.widgetMargin.convertDpToPixel(context).toInt()
views.setViewPadding(R.id.widget_shape_background, margin, margin, margin, margin)
val refreshIntent = IntentHelper.getPendingIntent(
context,
appWidgetId,
IntentHelper.getWidgetUpdateIntent(context),
PendingIntent.FLAG_UPDATE_CURRENT
)
views.setOnClickPendingIntent(R.id.widget_shape_background, refreshIntent)
// Padding
val padding = (Preferences.widgetPadding.convertDpToPixel(context) + Preferences.widgetMargin.convertDpToPixel(context)).toInt()
views.setViewPadding(R.id.main_layout, padding, padding, padding, padding)
} catch (ex: Exception) {
ex.printStackTrace()
CrashlyticsReceiver.sendCrash(context, ex)
@ -99,7 +105,7 @@ class StandardWidget(val context: Context) {
// Weather
if (Preferences.showWeather && Preferences.weatherIcon != "") {
views.setViewVisibility(R.id.weather_rect, View.VISIBLE)
views.setViewVisibility(R.id.weather_sub_line, View.GONE)
views.setViewVisibility(R.id.weather_sub_line_rect, View.GONE)
val i = Intent(context, WidgetClickListenerReceiver::class.java)
i.action = Actions.ACTION_OPEN_WEATHER_INTENT
@ -119,7 +125,7 @@ class StandardWidget(val context: Context) {
)
} else {
views.setViewVisibility(R.id.weather_rect, View.GONE)
views.setViewVisibility(R.id.weather_sub_line, View.GONE)
views.setViewVisibility(R.id.weather_sub_line_rect, View.GONE)
}
@ -129,7 +135,7 @@ class StandardWidget(val context: Context) {
BitmapHelper.getBitmapFromView(bindingView.date, draw = false, width = bindingView.date.width, height = bindingView.date.height)
)
val calPIntent = PendingIntent.getActivity(
val calPIntent = IntentHelper.getPendingIntent(
context,
widgetID,
IntentHelper.getCalendarIntent(context),
@ -144,8 +150,6 @@ class StandardWidget(val context: Context) {
BitmapHelper.getBitmapFromView(bindingView.subLine, draw = false, width = bindingView.subLine.width, height = bindingView.subLine.height)
)
val nextAlarm = AlarmHelper.getNextAlarm(context)
// Spacing
views.setViewVisibility(
R.id.sub_line_top_margin_small_sans,
@ -209,7 +213,7 @@ class StandardWidget(val context: Context) {
}
// Event intent
val eventIntent = PendingIntent.getActivity(
val eventIntent = IntentHelper.getPendingIntent(
context,
widgetID,
IntentHelper.getEventIntent(context, nextEvent),
@ -242,7 +246,7 @@ class StandardWidget(val context: Context) {
// Event information
if (nextEvent.address != "" && Preferences.secondRowInformation == 1) {
val mapIntent = PendingIntent.getActivity(
val mapIntent = IntentHelper.getPendingIntent(
context,
widgetID,
IntentHelper.getGoogleMapsIntentFromAddress(context, nextEvent.address),
@ -250,14 +254,10 @@ class StandardWidget(val context: Context) {
)
views.setOnClickPendingIntent(R.id.sub_line_rect, mapIntent)
} else {
val pIntentDetail = PendingIntent.getActivity(
val pIntentDetail = IntentHelper.getPendingIntent(
context,
widgetID,
IntentHelper.getEventIntent(
context,
nextEvent,
forceEventDetails = true
),
IntentHelper.getCalendarIntent(context, nextEvent.startDate),
PendingIntent.FLAG_UPDATE_CURRENT
)
views.setOnClickPendingIntent(R.id.sub_line_rect, pIntentDetail)
@ -269,17 +269,18 @@ class StandardWidget(val context: Context) {
)
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
views.setViewVisibility(R.id.sub_line_rect, View.VISIBLE)
views.setViewVisibility(R.id.weather_sub_line_rect, View.VISIBLE)
views.setViewVisibility(R.id.weather_sub_line_rect, if (Preferences.showWeather && Preferences.weatherIcon != "") View.VISIBLE else View.GONE)
views.setViewVisibility(R.id.first_line_rect, View.GONE)
} else if (GlanceProviderHelper.showGlanceProviders(context)) {
var showSomething = false
var isWeatherShown = false
loop@ for (provider: Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders(context)) {
when (provider) {
Constants.GlanceProviderId.PLAYING_SONG -> {
if (MediaPlayerHelper.isSomeonePlaying(context)) {
val musicIntent = PendingIntent.getActivity(
val musicIntent = IntentHelper.getPendingIntent(
context,
widgetID,
IntentHelper.getMusicIntent(context),
@ -291,8 +292,10 @@ class StandardWidget(val context: Context) {
}
}
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
if (Preferences.showNextAlarm && nextAlarm != "") {
val alarmIntent = PendingIntent.getActivity(
if (Preferences.showNextAlarm) {
val nextAlarm = AlarmHelper.getNextAlarm(context)
if (nextAlarm != "") {
val alarmIntent = IntentHelper.getPendingIntent(
context,
widgetID,
IntentHelper.getClockIntent(context),
@ -303,11 +306,12 @@ class StandardWidget(val context: Context) {
break@loop
}
}
}
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
if (Preferences.showBatteryCharging) {
BatteryHelper.updateBatteryInfo(context)
if (Preferences.isCharging || Preferences.isBatteryLevelLow) {
val batteryIntent = PendingIntent.getActivity(
val batteryIntent = IntentHelper.getPendingIntent(
context,
widgetID,
IntentHelper.getBatteryIntent(),
@ -326,7 +330,7 @@ class StandardWidget(val context: Context) {
}
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) {
val fitIntent = PendingIntent.getActivity(
val fitIntent = IntentHelper.getPendingIntent(
context,
widgetID,
IntentHelper.getFitIntent(context),
@ -347,7 +351,7 @@ class StandardWidget(val context: Context) {
remotePackageContext,
Preferences.lastNotificationIcon)
}
val notificationIntent = PendingIntent.getActivity(
val notificationIntent = IntentHelper.getPendingIntent(
context,
widgetID,
IntentHelper.getNotificationIntent(context),
@ -371,7 +375,7 @@ class StandardWidget(val context: Context) {
Constants.GlanceProviderId.EVENTS -> {
if (Preferences.showEventsAsGlanceProvider&& Preferences.showEvents && context.checkGrantedPermission(
Manifest.permission.READ_CALENDAR) && nextEvent != null) {
val pIntentDetail = PendingIntent.getActivity(
val pIntentDetail = IntentHelper.getPendingIntent(
context,
widgetID,
IntentHelper.getEventIntent(
@ -389,6 +393,21 @@ class StandardWidget(val context: Context) {
break@loop
}
}
Constants.GlanceProviderId.WEATHER -> {
if (Preferences.showWeatherAsGlanceProvider && Preferences.showWeather && Preferences.weatherIcon != "") {
val i = Intent(context, WidgetClickListenerReceiver::class.java)
i.action = Actions.ACTION_OPEN_WEATHER_INTENT
val weatherPIntent = PendingIntent.getBroadcast(context, widgetID, i, 0)
views.setOnClickPendingIntent(
R.id.sub_line_rect,
weatherPIntent
)
showSomething = true
isWeatherShown = true
break@loop
}
}
}
}
@ -399,6 +418,7 @@ class StandardWidget(val context: Context) {
BitmapHelper.getBitmapFromView(bindingView.subLine, draw = false, width = bindingView.subLine.width, height = bindingView.subLine.height)
)
views.setViewVisibility(R.id.weather_rect, if (isWeatherShown) View.GONE else View.VISIBLE)
views.setViewVisibility(R.id.first_line_rect, View.VISIBLE)
views.setViewVisibility(R.id.sub_line_rect, View.VISIBLE)
@ -432,8 +452,9 @@ class StandardWidget(val context: Context) {
// Generates the widget bitmap from the view
fun generateWidgetView(typeface: Typeface? = null): TheWidgetBinding? {
private fun generateWidgetView(typeface: Typeface? = null): TheWidgetBinding? {
try {
var isWeatherShownAsGlanceProvider = false
val eventRepository = EventRepository(context)
val nextEvent = eventRepository.getNextEvent()
val eventsCount = eventRepository.getEventsCount()
@ -488,8 +509,6 @@ class StandardWidget(val context: Context) {
bindingView.date.text = DateHelper.getDateText(context, now)
val nextAlarm = AlarmHelper.getNextAlarm(context)
if (Preferences.showEvents && context.checkGrantedPermission(Manifest.permission.READ_CALENDAR) && nextEvent != null && !Preferences.showEventsAsGlanceProvider) {
// Multiple counter
bindingView.actionNext.isVisible =
@ -592,18 +611,16 @@ class StandardWidget(val context: Context) {
}
} else {
val flags: Int =
DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NO_YEAR or DateUtils.FORMAT_ABBREV_MONTH
val start = Calendar.getInstance().apply { timeInMillis = nextEvent.startDate }
bindingView.subLineText.text = if (now.get(Calendar.DAY_OF_YEAR) == start.get(
Calendar.DAY_OF_YEAR)) {
DateUtils.formatDateTime(context, nextEvent.startDate, flags)
DateHelper.getDateText(context, start)
} else if (now.get(Calendar.DAY_OF_YEAR) > start.get(Calendar.DAY_OF_YEAR) || now.get(
Calendar.YEAR) > start.get(Calendar.YEAR)) {
DateUtils.formatDateTime(context, now.timeInMillis, flags)
DateHelper.getDateText(context, now)
} else {
DateUtils.formatDateTime(context, nextEvent.startDate, flags)
DateHelper.getDateText(context, start)
}
}
}
@ -611,7 +628,7 @@ class StandardWidget(val context: Context) {
bindingView.dateLayout.isVisible = false
bindingView.calendarLayout.isVisible = true
bindingView.subLine.isVisible = true
bindingView.weatherSubLine.isVisible = true
bindingView.weatherSubLine.isVisible = Preferences.showWeather && Preferences.weatherIcon != ""
bindingView.subLineTopMarginSmall.visibility =
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.rawValue) View.VISIBLE else View.GONE
@ -640,18 +657,21 @@ class StandardWidget(val context: Context) {
}
}
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
if (Preferences.showNextAlarm && nextAlarm != "") {
if (Preferences.showNextAlarm) {
val nextAlarm = AlarmHelper.getNextAlarm(context)
if (nextAlarm != "") {
bindingView.subLineIcon.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.round_alarm_24
)
)
bindingView.subLineText.text = AlarmHelper.getNextAlarm(context)
bindingView.subLineText.text = nextAlarm
showSomething = true
break@loop
}
}
}
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
if (Preferences.showBatteryCharging) {
BatteryHelper.updateBatteryInfo(context)
@ -753,6 +773,33 @@ class StandardWidget(val context: Context) {
break@loop
}
}
Constants.GlanceProviderId.WEATHER -> {
if (Preferences.showWeatherAsGlanceProvider && Preferences.showWeather && Preferences.weatherIcon != "") {
bindingView.subLineText.text = String.format(
Locale.getDefault(),
"%d°%s %s",
Preferences.weatherTemp.roundToInt(),
Preferences.weatherRealTempUnit,
WeatherHelper.getWeatherLabel(context, Preferences.weatherIcon)
)
bindingView.subLineIcon.isVisible = true
val icon: String = Preferences.weatherIcon
if (icon == "") {
bindingView.subLineIcon.isVisible = false
} else {
bindingView.subLineIcon.setImageResource(WeatherHelper.getWeatherIconResource(context, icon))
bindingView.subLineIcon.isVisible = true
}
bindingView.weatherDateLine.isVisible = false
bindingView.weatherSubLine.isVisible = false
isWeatherShownAsGlanceProvider = true
showSomething = true
break@loop
}
}
}
}
@ -806,10 +853,15 @@ class StandardWidget(val context: Context) {
it.setTextColor(ColorHelper.getSecondaryFontColor(context.applicationContext.isDarkTheme()))
}
if (!isWeatherShownAsGlanceProvider) {
if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.rawValue) {
listOf<ImageView>(bindingView.subLineIcon, bindingView.subLineIconShadow)
} else {
listOf<ImageView>(bindingView.subLineIcon, bindingView.weatherSubLineWeatherIcon, bindingView.subLineIconShadow)
listOf<ImageView>(
bindingView.subLineIcon,
bindingView.weatherSubLineWeatherIcon,
bindingView.subLineIconShadow
)
}.forEach {
it.setColorFilter(ColorHelper.getSecondaryFontColorRgb(context.applicationContext.isDarkTheme()))
it.alpha =
@ -817,6 +869,7 @@ class StandardWidget(val context: Context) {
.toFloat() else Preferences.textSecondaryAlpha.toIntValue()
.toFloat()) / 100
}
}
// Text Size
listOf<Pair<TextView, Float>>(
@ -919,14 +972,17 @@ class StandardWidget(val context: Context) {
// Custom Font
if (Preferences.customFont == Constants.CUSTOM_FONT_GOOGLE_SANS) {
val googleSans: Typeface = when (Preferences.customFontVariant) {
"100" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_thin.ttf")
"200" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_light.ttf")
"500" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_medium.ttf")
"700" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_bold.ttf")
"800" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_black.ttf")
else -> Typeface.createFromAsset(context.assets, "fonts/google_sans_regular.ttf")
val googleSans: Typeface? = androidx.core.content.res.ResourcesCompat.getFont(
context,
when (Preferences.customFontVariant) {
"100" -> R.font.google_sans_thin
"200" -> R.font.google_sans_light
"500" -> R.font.google_sans_medium
"700" -> R.font.google_sans_bold
"800" -> R.font.google_sans_black
else -> R.font.google_sans_regular
}
)
listOf<TextView>(
bindingView.date,

View File

@ -24,18 +24,20 @@ import android.util.TypedValue
import android.view.animation.AlphaAnimation
import android.widget.RelativeLayout
import androidx.annotation.UiThread
import androidx.appcompat.app.AppCompatDelegate
import androidx.browser.customtabs.CustomTabColorSchemeParams
import androidx.core.animation.addListener
import androidx.core.view.isVisible
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.components.OnSingleClickListener
import com.tommasoberlose.anotherwidget.global.Preferences
import java.util.*
fun PackageManager.missingSystemFeature(name: String): Boolean = !hasSystemFeature(name)
fun Context.toast(message: String, long: Boolean = false) {
val toast = Toast.makeText(this, message, if (long) Toast.LENGTH_LONG else Toast.LENGTH_SHORT)
val toast = Toast.makeText(applicationContext, message, if (long) Toast.LENGTH_LONG else Toast.LENGTH_SHORT)
// toast.setGravity(Gravity.CENTER, 0, 0)
toast.show()
}
@ -192,7 +194,7 @@ fun String.isValidEmail(): Boolean
Patterns.EMAIL_ADDRESS.matcher(this).matches()
fun Context.isDarkTheme(): Boolean {
return resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
return Preferences.darkThemePreference == AppCompatDelegate.MODE_NIGHT_YES || Preferences.darkThemePreference == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM && resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
}
fun Activity.isNotificationAccessGranted(): Boolean = Settings.Secure.getString(this.contentResolver,"enabled_notification_listeners").contains(this.packageName)

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 571 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

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