Compare commits

...

2 Commits

152 changed files with 1086 additions and 389 deletions

Binary file not shown.

View File

@ -18,7 +18,7 @@ android {
applicationId "com.tommasoberlose.anotherwidget"
minSdkVersion 23
targetSdkVersion 29
versionCode 65
versionCode 69
versionName "2.0.5"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@ -90,6 +90,7 @@ dependencies {
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'joda-time:joda-time:2.9.9'
implementation 'me.everything:providers-android:1.0.1'
implementation 'com.github.warkiz.widget:indicatorseekbar:2.1.2'
//Glide
implementation 'com.github.bumptech.glide:glide:4.11.0'

Binary file not shown.

View File

@ -65,6 +65,7 @@
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="com.tommasoberlose.anotherwidget.action.ACTION_CALENDAR_UPDATE" />
<action android:name="com.tommasoberlose.anotherwidget.action.ACTION_TIME_UPDATE" />
<action android:name="com.sec.android.widgetapp.APPWIDGET_RESIZE" />
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
<action android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />

View File

@ -8,6 +8,7 @@ import android.text.TextWatcher
import android.util.Log
import android.view.View
import android.widget.GridLayout
import android.widget.SeekBar
import androidx.annotation.ColorInt
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
@ -19,6 +20,9 @@ import com.tommasoberlose.anotherwidget.helpers.ColorHelper
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
import com.tommasoberlose.anotherwidget.utils.expand
import com.tommasoberlose.anotherwidget.utils.reveal
import com.warkiz.widget.IndicatorSeekBar
import com.warkiz.widget.OnSeekChangeListener
import com.warkiz.widget.SeekParams
import kotlinx.android.synthetic.main.bottom_sheet_menu_hor.*
import kotlinx.android.synthetic.main.bottom_sheet_menu_hor.view.*
import kotlinx.android.synthetic.main.bottom_sheet_menu_hor.view.color_loader
@ -32,7 +36,10 @@ class BottomSheetColorPicker(
private val colors: IntArray = intArrayOf(),
private val selected: Int? = null,
private val header: String? = null,
private val onColorSelected: ((selectedValue: Int) -> Unit)? = null
private val onColorSelected: ((selectedValue: Int) -> Unit)? = null,
private val showAlphaSelector: Boolean = false,
private val alpha: Int = 0,
private val onAlphaChangeListener: ((alpha: Int) -> Unit)? = null
) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
private val loadingJob: Job? = null
@ -44,6 +51,22 @@ class BottomSheetColorPicker(
view.header.isVisible = header != null
view.header_text.text = header ?: ""
view.alpha_selector_container.isVisible = showAlphaSelector
view.alpha_selector.setProgress(alpha.toFloat())
view.text_alpha.text = "%s: %s%%".format(context.getString(R.string.alpha), alpha)
view.alpha_selector.onSeekChangeListener = object : OnSeekChangeListener {
override fun onSeeking(seekParams: SeekParams?) {
seekParams?.let {
view.text_alpha.text = "%s: %s%%".format(context.getString(R.string.alpha), it.progress)
onAlphaChangeListener?.invoke(it.progress)
}
}
override fun onStartTrackingTouch(seekBar: IndicatorSeekBar?) {
}
override fun onStopTrackingTouch(seekBar: IndicatorSeekBar?) {
}
}
val itemViews: ArrayList<View> = ArrayList()
GlobalScope.launch(Dispatchers.IO) {

View File

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

View File

@ -1,12 +1,10 @@
package com.tommasoberlose.anotherwidget.db
import android.content.Context
import android.util.Log
import com.chibatching.kotpref.bulk
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.models.Event
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
import com.tommasoberlose.anotherwidget.services.UpdatesWorker
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import io.realm.Realm
import io.realm.RealmResults
@ -43,6 +41,8 @@ class EventRepository(val context: Context) {
fun getNextEvent(): Event? = realm.where(Event::class.java).equalTo("id", Preferences.nextEventId).findFirst() ?: realm.where(Event::class.java).findFirst()
fun getEventById(id: Long): Event? = realm.where(Event::class.java).equalTo("id", id).findFirst()
fun goToNextEvent() {
val eventList = realm.where(Event::class.java).findAll()
@ -56,7 +56,7 @@ class EventRepository(val context: Context) {
} else {
resetNextEventData()
}
UpdatesWorker.setUpdates(context)
UpdatesReceiver.setUpdates(context)
MainWidget.updateWidget(context)
}
@ -73,7 +73,7 @@ class EventRepository(val context: Context) {
} else {
resetNextEventData()
}
UpdatesWorker.setUpdates(context)
UpdatesReceiver.setUpdates(context)
MainWidget.updateWidget(context)
}

View File

@ -40,6 +40,11 @@ object Preferences : KotprefModel() {
var eventAppPackage by stringPref(key = "PREF_EVENT_APP_PACKAGE", default = "")
var openEventDetails by booleanPref(default = true)
var textGlobalColor by stringPref(key = "PREF_TEXT_COLOR", default = "#FFFFFF")
var textGlobalAlpha by stringPref(default = "FF")
var backgroundCardColor by stringPref(default = "#000000")
var backgroundCardAlpha by stringPref(default = "00")
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)
@ -59,4 +64,6 @@ object Preferences : KotprefModel() {
var showWallpaper by booleanPref(default = true)
var showBigClockWarning by booleanPref(default = true)
var showWeatherWarning by booleanPref(default = true)
var showPreview by booleanPref(default = true)
var showXiaomiWarning by booleanPref(default = true)
}

View File

@ -3,6 +3,7 @@ package com.tommasoberlose.anotherwidget.helpers
import android.app.AlarmManager
import android.content.Context
import android.text.format.DateFormat
import android.util.Log
import java.text.SimpleDateFormat
import java.util.*

View File

@ -2,14 +2,14 @@ package com.tommasoberlose.anotherwidget.helpers
import android.content.Context
import android.graphics.*
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.util.Log
import android.view.View
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.DrawableCompat
import androidx.core.view.drawToBitmap
import com.google.firebase.crashlytics.FirebaseCrashlytics
import java.lang.Exception
object BitmapHelper {
@ -20,13 +20,15 @@ object BitmapHelper {
view.measure(measuredWidth, measuredHeight)
return try {
Log.d("ciao", "bitmap ${view.measuredWidth}, ${view.measuredHeight} - draw = ${draw}")
if (draw) {
Log.d("ciao", "bitmap ${view.measuredWidth}, ${view.measuredHeight}")
}
val btm = Bitmap.createBitmap(
view.measuredWidth,
view.measuredHeight,
if (draw) Bitmap.Config.ARGB_8888 else Bitmap.Config.ALPHA_8
if (true || draw) Bitmap.Config.ARGB_8888 else Bitmap.Config.ALPHA_8
)
if (draw) {
if (true || draw) {
//Bind a canvas to it
val canvas = Canvas(btm)
// draw the view on the canvas
@ -74,4 +76,30 @@ object BitmapHelper {
return resultBitmap
}
fun drawableToBitmap(drawable: Drawable): Bitmap? {
var bitmap: Bitmap? = null
if (drawable is BitmapDrawable) {
if (drawable.bitmap != null) {
return drawable.bitmap
}
}
bitmap = if (drawable.intrinsicWidth <= 0 || drawable.intrinsicHeight <= 0) {
Bitmap.createBitmap(
1,
1,
Bitmap.Config.ARGB_8888
) // Single color bitmap will be created of 1x1 pixel
} else {
Bitmap.createBitmap(
drawable.intrinsicWidth,
drawable.intrinsicHeight,
Bitmap.Config.ARGB_8888
)
}
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
return bitmap
}
}

View File

@ -10,7 +10,6 @@ import com.tommasoberlose.anotherwidget.db.EventRepository
import com.tommasoberlose.anotherwidget.models.Event
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
import com.tommasoberlose.anotherwidget.services.UpdatesWorker
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
@ -125,7 +124,7 @@ object CalendarHelper {
eventRepository.resetNextEventData()
}
UpdatesWorker.setUpdates(context)
UpdatesReceiver.setUpdates(context)
Log.d("ciao", "force update? 7")
MainWidget.updateWidget(context)

View File

@ -1,14 +1,41 @@
package com.tommasoberlose.anotherwidget.helpers
import android.annotation.SuppressLint
import android.graphics.Color
import android.util.Log
import com.tommasoberlose.anotherwidget.global.Preferences
import kotlin.math.roundToInt
object ColorHelper {
fun getFontColor(): Int {
return try {
Color.parseColor(Preferences.textGlobalColor)
Color.parseColor("#%s%s".format(Preferences.textGlobalAlpha, Preferences.textGlobalColor.replace("#", "")))
} catch (e: Exception) {
Color.parseColor("#FFFFFF")
Color.parseColor("#FFFFFFFF")
}
}
fun getBackgroundColor(): Int {
return try {
Color.parseColor("#%s%s".format(Preferences.backgroundCardAlpha, Preferences.backgroundCardColor.replace("#", "")))
} catch (e: Exception) {
Color.parseColor("#00000000")
}
}
fun getBackgroundAlpha(): Int {
return try {
Preferences.backgroundCardAlpha.toIntValue().toDouble() * 255 / 100
} catch (e: Exception) {
"00".toIntValue().toDouble() * 255 / 100
}.roundToInt()
}
fun getBackgroundColorRgb(): Int {
return try {
Color.parseColor(Preferences.backgroundCardColor)
} catch (e: Exception) {
Color.parseColor("#000000")
}
}
@ -20,4 +47,16 @@ object ColorHelper {
1 - (0.299 * Color.red(this) + 0.587 * Color.green(this) + 0.114 * Color.blue(this)) / 255
return darkness >= threshold
}
@SuppressLint("DefaultLocale")
fun Int.toHexValue(): String {
val intValue = (this * 255 / 100).toDouble().roundToInt()
val hexValue = intValue.toString(16)
return hexValue.padStart(2, '0').toUpperCase()
}
fun String.toIntValue(): Int {
val hexValue = this.toInt(16).toDouble()
return (hexValue * 100 / 255).roundToInt()
}
}

View File

@ -95,7 +95,6 @@ object IntentHelper {
return when (Preferences.openEventDetails || forceEventDetails) {
true -> {
val uri = ContentUris.withAppendedId(Events.CONTENT_URI, e.eventID)
if (Preferences.calendarAppPackage == "") {
Intent(Intent.ACTION_VIEW).apply {
data = uri

View File

@ -43,7 +43,7 @@ object WeatherHelper {
fun removeWeather(context: Context) {
Preferences.remove(Preferences::weatherTemp)
Preferences.remove(Preferences::weatherTempUnit)
Preferences.remove(Preferences::weatherRealTempUnit)
MainWidget.updateWidget(context)
}

View File

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

View File

@ -1,23 +1,25 @@
package com.tommasoberlose.anotherwidget.receivers
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.app.AlarmManager
import android.app.PendingIntent
import android.util.Log
import androidx.core.app.AlarmManagerCompat
import androidx.core.content.ContextCompat.getSystemService
import com.tommasoberlose.anotherwidget.db.EventRepository
import com.tommasoberlose.anotherwidget.global.Actions
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import org.joda.time.Period
import java.text.DateFormat
import java.util.*
class UpdatesReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d("ciao", "che palle - ${intent.action}")
when (intent.action) {
Intent.ACTION_BOOT_COMPLETED,
Intent.ACTION_MY_PACKAGE_REPLACED,
@ -35,4 +37,53 @@ class UpdatesReceiver : BroadcastReceiver() {
}
}
}
companion object {
fun setUpdates(context: Context) {
removeUpdates(context)
val eventRepository = EventRepository(context)
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
eventRepository.getEvents().forEach { event ->
val now = Calendar.getInstance().apply {
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}
val diff = Period(now.timeInMillis, event.startDate)
if (event.startDate > now.timeInMillis) {
// Update the widget every hour till the event
(0..diff.hours).forEach {
AlarmManagerCompat.setExactAndAllowWhileIdle(
this,
AlarmManager.RTC_WAKEUP,
if (event.startDate - it * 1000 * 60 * 60 > 60 * 1000) event.startDate - it * 1000 * 60 * 60 else 120000,
PendingIntent.getBroadcast(
context,
0,
Intent(context, UpdatesReceiver::class.java).apply {
action = Actions.ACTION_TIME_UPDATE
},
0
)
)
}
}
// Update the widget one second after the event is finished
AlarmManagerCompat.setExactAndAllowWhileIdle(this,
AlarmManager.RTC_WAKEUP,
if (event.endDate > 60 *1000) event.endDate else 120000,
PendingIntent.getBroadcast(context, 0, Intent(context, UpdatesReceiver::class.java).apply { action = Actions.ACTION_TIME_UPDATE }, 0))
}
}
}
fun removeUpdates(context: Context) {
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
cancel(PendingIntent.getBroadcast(context, 0, Intent(context, UpdatesReceiver::class.java), 0))
}
}
}
}

View File

@ -1,51 +0,0 @@
package com.tommasoberlose.anotherwidget.services
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.Worker
import androidx.work.WorkerParameters
import com.tommasoberlose.anotherwidget.db.EventRepository
import com.tommasoberlose.anotherwidget.global.Actions
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
import org.joda.time.Period
import java.util.*
import java.util.concurrent.TimeUnit
class UpdatesWorker(appContext: Context, workerParams: WorkerParameters) : Worker(appContext, workerParams) {
override fun doWork(): Result {
CalendarHelper.updateEventList(applicationContext)
return Result.success()
}
companion object {
private const val JOB_TAG = "UPDATES_WORKER"
fun setUpdates(context: Context) {
removeUpdates(context)
val now = Calendar.getInstance().timeInMillis
val workManager = WorkManager.getInstance(context)
val eventRepository = EventRepository(context)
eventRepository.getEvents().forEach { event ->
val hoursDiff = Period(Calendar.getInstance().timeInMillis, event.startDate).hours
// Update the widget every hour till the event
(0 .. hoursDiff).forEach {
workManager.enqueue(OneTimeWorkRequestBuilder<UpdatesWorker>().setInitialDelay((event.startDate + 1000) - now - it * 1000 * 60* 60, TimeUnit.MILLISECONDS).build())
}
// Update the widget one second after the event is finished
workManager.enqueue(OneTimeWorkRequestBuilder<UpdatesWorker>().setInitialDelay(event.endDate + 1000 - now, TimeUnit.MILLISECONDS).build())
}
}
fun removeUpdates(context: Context) {
WorkManager.getInstance(context).cancelAllWorkByTag(JOB_TAG)
}
}
}

View File

@ -4,6 +4,7 @@ import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.work.*
import com.tommasoberlose.anotherwidget.global.Actions
import com.tommasoberlose.anotherwidget.global.Preferences
@ -15,6 +16,7 @@ import java.util.concurrent.TimeUnit
class WeatherWorker(appContext: Context, workerParams: WorkerParameters) : Worker(appContext, workerParams) {
override fun doWork(): Result {
Log.d("ciao1", "weather ok")
WeatherHelper.updateWeather(applicationContext)
return Result.success()
}
@ -27,27 +29,31 @@ class WeatherWorker(appContext: Context, workerParams: WorkerParameters) : Worke
if (Preferences.showWeather && Preferences.weatherProviderApi != "") {
WeatherHelper.updateWeather(context)
WorkManager.getInstance(context).enqueue(PeriodicWorkRequestBuilder<WeatherWorker>(
when (Preferences.weatherRefreshPeriod) {
0 -> 30
1 -> 60
2 -> 60L * 3
3 -> 60L * 6
4 -> 60L * 12
5 -> 60L * 24
else -> 60
}
, TimeUnit.MINUTES)
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"WEATHER_JOB_PERIODIC",
ExistingPeriodicWorkPolicy.KEEP,
PeriodicWorkRequestBuilder<WeatherWorker>(
when (Preferences.weatherRefreshPeriod) {
0 -> 30
1 -> 60
2 -> 60L * 3
3 -> 60L * 6
4 -> 60L * 12
5 -> 60L * 24
else -> 60
}
, TimeUnit.MINUTES
)
.addTag(JOB_TAG)
.build())
.build()
)
}
}
fun setOneTimeUpdate(context: Context) {
val workManager = WorkManager.getInstance(context)
listOf(10L, 15L, 20L).forEach {
workManager.enqueue(OneTimeWorkRequestBuilder<WeatherWorker>().setInitialDelay(it, TimeUnit.MINUTES).addTag(JOB_TAG).build())
listOf(10L, 20L, 30L).forEach {
workManager.enqueueUniqueWork("WEATHER_JOB_ONE_TIME_$it", ExistingWorkPolicy.KEEP, OneTimeWorkRequestBuilder<WeatherWorker>().setInitialDelay(it, TimeUnit.MINUTES).addTag(JOB_TAG).build())
}
}

View File

@ -1,36 +1,42 @@
package com.tommasoberlose.anotherwidget.ui.activities
import android.Manifest
import android.animation.ValueAnimator
import android.app.Activity
import android.appwidget.AppWidgetManager
import android.content.Intent
import android.content.SharedPreferences
import android.graphics.drawable.BitmapDrawable
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.provider.Settings
import android.util.TypedValue
import android.view.Gravity
import android.view.View
import android.widget.RelativeLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.core.animation.addListener
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.google.android.material.badge.BadgeDrawable
import com.google.android.material.tabs.TabLayoutMediator
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
import com.tommasoberlose.anotherwidget.global.Actions
import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.global.RequestCode
import com.tommasoberlose.anotherwidget.helpers.BitmapHelper
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
import com.tommasoberlose.anotherwidget.ui.adapters.ViewPagerAdapter
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
import com.tommasoberlose.anotherwidget.utils.getCurrentWallpaper
import com.tommasoberlose.anotherwidget.utils.toPixel
import kotlinx.android.synthetic.main.activity_main.*
@ -39,7 +45,6 @@ import kotlinx.coroutines.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.lang.Exception
class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
@ -72,7 +77,9 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
// Init clock
time.setTextColor(ColorHelper.getFontColor())
time.setTextSize(TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(this@MainActivity))
time.isVisible = Preferences.showClock
time_am_pm.setTextColor(ColorHelper.getFontColor())
time_am_pm.setTextSize(TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(this@MainActivity) / 5 * 2)
time_container.isVisible = Preferences.showClock
preview.layoutParams = preview.layoutParams.apply {
height = 160.toPixel(this@MainActivity) + if (Preferences.showClock) 100.toPixel(this@MainActivity) else 0
@ -83,97 +90,179 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
updateUI()
WeatherHelper.updateWeather(this)
// Warnings
if (getString(R.string.xiaomi_manufacturer).equals(Build.MANUFACTURER, ignoreCase = true) && Preferences.showXiaomiWarning) {
MaterialBottomSheetDialog(this, getString(R.string.xiaomi_warning_title), getString(R.string.xiaomi_warning_message))
.setNegativeButton(getString(R.string.action_ignore)) {
Preferences.showXiaomiWarning = false
}
.setPositiveButton(getString(R.string.action_grant_permission)) {
Preferences.showXiaomiWarning = false
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.parse("package:$packageName")
}
startActivity(intent)
}
.show()
}
}
private var uiJob: Job? = null
private fun updateUI() {
preview.setCardBackgroundColor(getColor(if (ColorHelper.getFontColor().isColorDark()) android.R.color.white else R.color.colorAccent))
uiJob?.cancel()
uiJob = lifecycleScope.launch(Dispatchers.IO) {
delay(200)
val generatedView = MainWidget.generateWidgetView(this@MainActivity)
withContext(Dispatchers.Main) {
generatedView.measure(0, 0)
preview.measure(0, 0)
try {
// Try to recycle old bitmaps
(bitmap_container.drawable as BitmapDrawable).bitmap.recycle()
} catch (ignore: Exception) {}
}
if (Preferences.showPreview) {
preview.setCardBackgroundColor(
getColor(
if (ColorHelper.getFontColor()
.isColorDark()
) android.R.color.white else R.color.colorAccent
)
)
widget_shape_background.setImageDrawable(BitmapHelper.getTintedDrawable(this, R.drawable.card_background, ColorHelper.getBackgroundColor()))
uiJob = lifecycleScope.launch(Dispatchers.IO) {
delay(200)
val generatedView = MainWidget.generateWidgetView(this@MainActivity)
val bitmap = BitmapHelper.getBitmapFromView(generatedView, if (preview.width > 0) preview.width else generatedView.measuredWidth, generatedView.measuredHeight)
withContext(Dispatchers.Main) {
// Clock
time.setTextColor(ColorHelper.getFontColor())
time.setTextSize(TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(this@MainActivity))
time.format12Hour = "hh:mm"
// Clock bottom margin
clock_bottom_margin_none.isVisible = Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.value
clock_bottom_margin_small.isVisible = Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.SMALL.value
clock_bottom_margin_medium.isVisible = Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.MEDIUM.value
clock_bottom_margin_large.isVisible = Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.LARGE.value
if ((Preferences.showClock && !time.isVisible) || (!Preferences.showClock && time.isVisible)) {
if (Preferences.showClock) {
time.layoutParams = time.layoutParams.apply {
height = RelativeLayout.LayoutParams.WRAP_CONTENT
}
time.measure(0, 0)
}
val initialHeight = time.measuredHeight
ValueAnimator.ofFloat(
if (Preferences.showClock) 0f else 1f,
if (Preferences.showClock) 1f else 0f
).apply {
duration = 500L
addUpdateListener {
val animatedValue = animatedValue as Float
time.layoutParams = time.layoutParams.apply {
height = (initialHeight * animatedValue).toInt()
}
}
addListener(
onStart = {
if (Preferences.showClock) {
time.isVisible = true
}
},
onEnd = {
if (!Preferences.showClock) {
time.isVisible = false
}
}
)
}.start()
ValueAnimator.ofInt(
preview.height,
160.toPixel(this@MainActivity) + if (Preferences.showClock) 100.toPixel(this@MainActivity) else 0
).apply {
duration = 500L
addUpdateListener {
val animatedValue = animatedValue as Int
val layoutParams = preview.layoutParams
layoutParams.height = animatedValue
preview.layoutParams = layoutParams
}
}.start()
} else {
time.layoutParams = time.layoutParams.apply {
height = RelativeLayout.LayoutParams.WRAP_CONTENT
}
time.measure(0, 0)
withContext(Dispatchers.Main) {
generatedView.measure(0, 0)
preview.measure(0, 0)
}
bitmap_container.setImageBitmap(bitmap)
widget_loader.animate().scaleX(0f).scaleY(0f).start()
widget.animate().alpha(1f).start()
val bitmap = BitmapHelper.getBitmapFromView(
generatedView,
if (preview.width > 0) preview.width else generatedView.measuredWidth,
generatedView.measuredHeight
)
withContext(Dispatchers.Main) {
// Clock
time.setTextColor(ColorHelper.getFontColor())
time_am_pm.setTextColor(ColorHelper.getFontColor())
time.setTextSize(
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(this@MainActivity)
)
time_am_pm.setTextSize(
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(this@MainActivity) / 5 * 2
)
// Clock bottom margin
clock_bottom_margin_none.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.value
clock_bottom_margin_small.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.SMALL.value
clock_bottom_margin_medium.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.MEDIUM.value
clock_bottom_margin_large.isVisible =
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.LARGE.value
if ((Preferences.showClock && !time_container.isVisible) || (!Preferences.showClock && time_container.isVisible)) {
if (Preferences.showClock) {
time_container.layoutParams = time_container.layoutParams.apply {
height = RelativeLayout.LayoutParams.WRAP_CONTENT
}
time_container.measure(0, 0)
}
val initialHeight = time_container.measuredHeight
ValueAnimator.ofFloat(
if (Preferences.showClock) 0f else 1f,
if (Preferences.showClock) 1f else 0f
).apply {
duration = 500L
addUpdateListener {
val animatedValue = animatedValue as Float
time_container.layoutParams = time_container.layoutParams.apply {
height = (initialHeight * animatedValue).toInt()
}
}
addListener(
onStart = {
if (Preferences.showClock) {
time_container.isVisible = true
}
},
onEnd = {
if (!Preferences.showClock) {
time_container.isVisible = false
}
}
)
}.start()
ValueAnimator.ofInt(
preview.height,
160.toPixel(this@MainActivity) + if (Preferences.showClock) 100.toPixel(
this@MainActivity
) else 0
).apply {
duration = 500L
addUpdateListener {
val animatedValue = animatedValue as Int
val layoutParams = preview.layoutParams
layoutParams.height = animatedValue
preview.layoutParams = layoutParams
}
}.start()
} else {
time_container.layoutParams = time_container.layoutParams.apply {
height = RelativeLayout.LayoutParams.WRAP_CONTENT
}
time_container.measure(0, 0)
}
if (preview.height == 0) {
ValueAnimator.ofInt(
preview.height,
160.toPixel(this@MainActivity) + if (Preferences.showClock) 100.toPixel(
this@MainActivity
) else 0
).apply {
duration = 300L
addUpdateListener {
val animatedValue = animatedValue as Int
val layoutParams = preview.layoutParams
layoutParams.height = animatedValue
preview.layoutParams = layoutParams
}
}.start()
}
bitmap_container.setImageBitmap(bitmap)
widget_loader.animate().scaleX(0f).scaleY(0f).start()
widget.animate().alpha(1f).start()
}
}
} else {
ValueAnimator.ofInt(
preview.height,
0
).apply {
duration = 300L
addUpdateListener {
val animatedValue = animatedValue as Int
val layoutParams = preview.layoutParams
layoutParams.height = animatedValue
preview.layoutParams = layoutParams
}
}.start()
}
// Calendar error indicator
tabs.getTabAt(1)?.orCreateBadge?.apply {
backgroundColor = ContextCompat.getColor(this@MainActivity, R.color.errorColorText)
badgeGravity = BadgeDrawable.TOP_END
}?.isVisible = Preferences.showEvents && !checkGrantedPermission(Manifest.permission.READ_CALENDAR)
// Weather error indicator
tabs.getTabAt(2)?.orCreateBadge?.apply {
backgroundColor = ContextCompat.getColor(this@MainActivity, R.color.errorColorText)
badgeGravity = BadgeDrawable.TOP_END
}?.isVisible = Preferences.showWeather && (Preferences.weatherProviderApi == "" || (Preferences.customLocationAdd == "" && !checkGrantedPermission(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACCESS_BACKGROUND_LOCATION else Manifest.permission.ACCESS_FINE_LOCATION)))
}
private fun subscribeUi(viewModel: MainViewModel) {

View File

@ -79,17 +79,31 @@ class AdvancedSettingsFragment : Fragment() {
) {
viewModel.darkThemePreference.observe(viewLifecycleOwner, Observer {
AppCompatDelegate.setDefaultNightMode(it)
theme.text = when (it) {
AppCompatDelegate.MODE_NIGHT_NO -> getString(R.string.settings_subtitle_dark_theme_light)
AppCompatDelegate.MODE_NIGHT_YES -> getString(R.string.settings_subtitle_dark_theme_dark)
AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY -> getString(R.string.settings_subtitle_dark_theme_by_battery_saver)
AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM -> getString(R.string.settings_subtitle_dark_theme_follow_system)
else -> ""
maintainScrollPosition {
theme?.text = when (it) {
AppCompatDelegate.MODE_NIGHT_NO -> getString(R.string.settings_subtitle_dark_theme_light)
AppCompatDelegate.MODE_NIGHT_YES -> getString(R.string.settings_subtitle_dark_theme_dark)
AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY -> getString(R.string.settings_subtitle_dark_theme_by_battery_saver)
AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM -> getString(R.string.settings_subtitle_dark_theme_follow_system)
else -> ""
}
}
})
viewModel.showPreview.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
show_widget_preview_label?.text =
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
}
})
viewModel.showWallpaper.observe(viewLifecycleOwner, Observer {
show_wallpaper_label.text = if (it && activity?.checkGrantedPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == true) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
maintainScrollPosition {
show_wallpaper_label?.text =
if (it && activity?.checkGrantedPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == true) getString(
R.string.settings_visible
) else getString(R.string.settings_not_visible)
}
})
}
@ -116,6 +130,24 @@ class AdvancedSettingsFragment : Fragment() {
}
}
action_show_widget_preview.setOnClickListener {
maintainScrollPosition {
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.action_show_widget_preview))
.setSelectedValue(Preferences.showPreview)
.addItem(
getString(R.string.settings_visible),
true
)
.addItem(
getString(R.string.settings_not_visible),
false
)
.addOnSelectItemListener { value ->
Preferences.showPreview = value
}.show()
}
}
action_show_wallpaper.setOnClickListener {
maintainScrollPosition {
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_title_show_wallpaper))

View File

@ -2,14 +2,12 @@ package com.tommasoberlose.anotherwidget.ui.fragments
import android.Manifest
import android.app.Activity
import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
@ -42,7 +40,6 @@ import kotlinx.android.synthetic.main.fragment_calendar_settings.*
import kotlinx.android.synthetic.main.fragment_calendar_settings.scrollView
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.*
import kotlin.Comparator
@ -89,7 +86,6 @@ class CalendarSettingsFragment : Fragment() {
binding.isCalendarEnabled = it
if (it) {
requirePermission()
CalendarHelper.setEventUpdatesAndroidN(requireContext())
} else {
CalendarHelper.removeEventUpdatesAndroidN(requireContext())
@ -100,7 +96,7 @@ class CalendarSettingsFragment : Fragment() {
viewModel.calendarAllDay.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
all_day_label.text =
all_day_label?.text =
if (it) getString(R.string.settings_all_day_subtitle_visible) else getString(R.string.settings_all_day_subtitle_gone)
}
checkReadEventsPermission()
@ -108,49 +104,49 @@ class CalendarSettingsFragment : Fragment() {
viewModel.showDeclinedEvents.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
show_declined_events_label.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
show_declined_events_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
}
checkReadEventsPermission()
})
viewModel.secondRowInformation.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
second_row_info_label.text = getString(SettingsStringHelper.getSecondRowInfoString(it))
second_row_info_label?.text = getString(SettingsStringHelper.getSecondRowInfoString(it))
}
})
viewModel.showDiffTime.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
show_diff_time_label.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
show_diff_time_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
}
})
viewModel.showUntil.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
show_until_label.text = getString(SettingsStringHelper.getShowUntilString(it))
show_until_label?.text = getString(SettingsStringHelper.getShowUntilString(it))
}
checkReadEventsPermission()
})
viewModel.showNextEvent.observe(viewLifecycleOwner, Observer {
show_multiple_events_label.setTextKeepState(if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible))
show_multiple_events_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
})
viewModel.dateFormat.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
date_format_label.text = DateHelper.getDateText(requireContext(), Calendar.getInstance())
date_format_label?.text = DateHelper.getDateText(requireContext(), Calendar.getInstance())
}
})
viewModel.calendarAppName.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
calendar_app_label.text = if (it != "") it else getString(R.string.default_calendar_app)
calendar_app_label?.text = if (it != "") it else getString(R.string.default_calendar_app)
}
})
viewModel.openEventDetails.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
open_event_details_label.text = if (it) getString(R.string.default_event_app) else getString(R.string.default_calendar_app)
open_event_details_label?.text = if (it) getString(R.string.default_event_app) else getString(R.string.default_calendar_app)
}
})
@ -320,13 +316,13 @@ class CalendarSettingsFragment : Fragment() {
private fun checkReadEventsPermission(showEvents: Boolean = Preferences.showEvents) {
if (activity?.checkGrantedPermission(Manifest.permission.READ_CALENDAR) == true) {
show_events_label.text = if (showEvents) getString(R.string.show_events_visible) else getString(R.string.show_events_not_visible)
read_calendar_permission_alert_icon.isVisible = false
show_events_label?.text = if (showEvents) getString(R.string.show_events_visible) else getString(R.string.show_events_not_visible)
read_calendar_permission_alert?.isVisible = false
CalendarHelper.updateEventList(requireContext())
} else {
show_events_label.text = if (showEvents) getString(R.string.description_permission_calendar) else getString(R.string.show_events_not_visible)
read_calendar_permission_alert_icon.isVisible = showEvents
read_calendar_permission_alert_icon.setOnClickListener {
show_events_label?.text = if (showEvents) getString(R.string.description_permission_calendar) else getString(R.string.show_events_not_visible)
read_calendar_permission_alert?.isVisible = showEvents
read_calendar_permission_alert?.setOnClickListener {
requirePermission()
}
}

View File

@ -65,13 +65,13 @@ class ClockSettingsFragment : Fragment() {
viewModel: MainViewModel
) {
viewModel.showBigClockWarning.observe(viewLifecycleOwner, Observer {
large_clock_warning.isVisible = it
small_clock_warning.isVisible = !it
large_clock_warning?.isVisible = it
small_clock_warning?.isVisible = !it
})
viewModel.showClock.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
show_clock_label.text =
show_clock_label?.text =
if (it) getString(R.string.show_clock_visible) else getString(R.string.show_clock_not_visible)
binding.isClockVisible = it
}
@ -79,13 +79,13 @@ class ClockSettingsFragment : Fragment() {
viewModel.clockTextSize.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
clock_text_size_label.text = String.format("%.0fsp", it)
clock_text_size_label?.text = String.format("%.0fsp", it)
}
})
viewModel.clockBottomMargin.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
clock_bottom_margin_label.text = when (it) {
clock_bottom_margin_label?.text = when (it) {
Constants.ClockBottomMargin.NONE.value -> getString(R.string.settings_clock_bottom_margin_subtitle_none)
Constants.ClockBottomMargin.SMALL.value -> getString(R.string.settings_clock_bottom_margin_subtitle_small)
Constants.ClockBottomMargin.LARGE.value -> getString(R.string.settings_clock_bottom_margin_subtitle_large)
@ -96,13 +96,13 @@ class ClockSettingsFragment : Fragment() {
viewModel.showNextAlarm.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
show_next_alarm_label.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
show_next_alarm_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
}
})
viewModel.clockAppName.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
clock_app_label.text =
clock_app_label?.text =
if (Preferences.clockAppName != "") Preferences.clockAppName else getString(R.string.default_clock_app)
}
})

View File

@ -1,9 +1,11 @@
package com.tommasoberlose.anotherwidget.ui.fragments
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -18,6 +20,9 @@ import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
import com.tommasoberlose.anotherwidget.databinding.FragmentGeneralSettingsBinding
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.global.RequestCode
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toHexValue
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
@ -71,42 +76,76 @@ class GeneralSettingsFragment : Fragment() {
}
@SuppressLint("DefaultLocale")
private fun subscribeUi(
viewModel: MainViewModel
) {
viewModel.textMainSize.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
main_text_size_label.text = String.format("%.0fsp", it)
main_text_size_label?.text = String.format("%.0fsp", it)
}
})
viewModel.textSecondSize.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
second_text_size_label.text = String.format("%.0fsp", it)
second_text_size_label?.text = String.format("%.0fsp", it)
}
})
viewModel.textGlobalColor.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
try {
Color.parseColor(it)
} catch (e: Exception) {
Preferences.textGlobalColor = "#FFFFFF"
if (Preferences.textGlobalAlpha == "00") {
font_color_label?.text = getString(R.string.transparent)
} else {
font_color_label?.text =
"#%s".format(Integer.toHexString(ColorHelper.getFontColor())).toUpperCase()
}
}
})
viewModel.textGlobalAlpha.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
if (Preferences.textGlobalAlpha == "00") {
font_color_label?.text = getString(R.string.transparent)
} else {
font_color_label?.text =
"#%s".format(Integer.toHexString(ColorHelper.getFontColor())).toUpperCase()
}
}
})
viewModel.backgroundCardColor.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
if (Preferences.backgroundCardAlpha == "00") {
background_color_label?.text = getString(R.string.transparent)
} else {
background_color_label?.text =
"#%s".format(Integer.toHexString(ColorHelper.getBackgroundColor())).toUpperCase()
}
}
})
viewModel.backgroundCardAlpha.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
if (Preferences.backgroundCardAlpha == "00") {
background_color_label?.text = getString(R.string.transparent)
} else {
background_color_label?.text =
"#%s".format(Integer.toHexString(ColorHelper.getBackgroundColor())).toUpperCase()
}
font_color_label.text = it.toUpperCase()
}
})
viewModel.textShadow.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
text_shadow_label.text = getString(SettingsStringHelper.getTextShadowString(it))
text_shadow_label?.text = getString(SettingsStringHelper.getTextShadowString(it))
}
})
viewModel.customFont.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
custom_font_label.text = getString(SettingsStringHelper.getCustomFontLabel(it))
custom_font_label?.text = getString(SettingsStringHelper.getCustomFontLabel(it))
}
})
}
@ -142,19 +181,35 @@ class GeneralSettingsFragment : Fragment() {
}
action_font_color.setOnClickListener {
val textColor = try {
Color.parseColor(Preferences.textGlobalColor)
} catch (e: Exception) {
Preferences.textGlobalColor = "#FFFFFF"
Color.parseColor(Preferences.textGlobalColor)
}
BottomSheetColorPicker(requireContext(),
colors = colors,
header = getString(R.string.settings_font_color_title),
selected = textColor,
selected = ColorHelper.getFontColor(),
onColorSelected = { color: Int ->
val colorString = Integer.toHexString(color)
Preferences.textGlobalColor = "#" + if (colorString.length > 6) colorString.substring(2) else colorString
},
showAlphaSelector = true,
alpha = Preferences.textGlobalAlpha.toIntValue(),
onAlphaChangeListener = { alpha ->
Preferences.textGlobalAlpha = alpha.toHexValue()
}
).show()
}
action_background_color.setOnClickListener {
BottomSheetColorPicker(requireContext(),
colors = colors,
header = getString(R.string.settings_background_color_title),
selected = ColorHelper.getBackgroundColor(),
onColorSelected = { color: Int ->
val colorString = Integer.toHexString(color)
Preferences.backgroundCardColor = "#" + if (colorString.length > 6) colorString.substring(2) else colorString
},
showAlphaSelector = true,
alpha = Preferences.backgroundCardAlpha.toIntValue(),
onAlphaChangeListener = { alpha ->
Preferences.backgroundCardAlpha = alpha.toHexValue()
}
).show()
}

View File

@ -8,6 +8,7 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
@ -80,12 +81,12 @@ class WeatherSettingsFragment : Fragment() {
viewModel: MainViewModel
) {
viewModel.showWeatherWarning.observe(viewLifecycleOwner, Observer {
weather_warning.isVisible = it
weather_warning?.isVisible = it
})
viewModel.showWeather.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
show_weather_label.text =
show_weather_label?.text =
if (it) getString(R.string.show_weather_visible) else getString(R.string.show_weather_not_visible)
binding.isWeatherVisible = it
}
@ -94,18 +95,18 @@ class WeatherSettingsFragment : Fragment() {
viewModel.weatherProviderApi.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
label_weather_provider_api_key.text =
label_weather_provider_api_key?.text =
if (it == "") getString(R.string.settings_weather_provider_api_key_subtitle_not_set) else getString(
R.string.settings_weather_provider_api_key_subtitle_all_set
)
api_key_alert_icon.isVisible = it == ""
label_weather_provider_api_key?.setTextColor(ContextCompat.getColor(requireContext(), if (it == "") R.color.errorColorText else R.color.colorSecondaryText))
}
checkLocationPermission()
})
viewModel.customLocationAdd.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
label_custom_location.text =
label_custom_location?.text =
if (it == "") getString(R.string.custom_location_gps) else it
}
checkLocationPermission()
@ -113,7 +114,7 @@ class WeatherSettingsFragment : Fragment() {
viewModel.weatherTempUnit.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
temp_unit.text =
temp_unit?.text =
if (it == "F") getString(R.string.fahrenheit) else getString(R.string.celsius)
}
checkLocationPermission()
@ -121,26 +122,31 @@ class WeatherSettingsFragment : Fragment() {
viewModel.weatherRefreshPeriod.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
label_weather_refresh_period.text = getString(SettingsStringHelper.getRefreshPeriodString(it))
label_weather_refresh_period?.text = getString(SettingsStringHelper.getRefreshPeriodString(it))
}
checkLocationPermission()
})
viewModel.weatherAppName.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
weather_app_label.text =
weather_app_label?.text =
if (it != "") it else getString(R.string.default_weather_app)
}
})
}
private fun checkLocationPermission() {
// Background permission
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && activity?.checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION) == true) {
requirePermission()
}
if (activity?.checkGrantedPermission(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACCESS_BACKGROUND_LOCATION else Manifest.permission.ACCESS_FINE_LOCATION) == true) {
location_permission_alert_icon.isVisible = false
location_permission_alert?.isVisible = false
WeatherWorker.setUpdates(requireContext())
} else if (Preferences.showWeather && Preferences.customLocationAdd == "") {
location_permission_alert_icon.isVisible = true
location_permission_alert_icon.setOnClickListener {
location_permission_alert?.isVisible = true
location_permission_alert?.setOnClickListener {
requirePermission()
}
}

View File

@ -8,6 +8,9 @@ class MainViewModel : ViewModel() {
// General Settings
val textGlobalColor = Preferences.asLiveData(Preferences::textGlobalColor)
val textGlobalAlpha = Preferences.asLiveData(Preferences::textGlobalAlpha)
val backgroundCardColor = Preferences.asLiveData(Preferences::backgroundCardColor)
val backgroundCardAlpha = Preferences.asLiveData(Preferences::backgroundCardAlpha)
val textMainSize = Preferences.asLiveData(Preferences::textMainSize)
val textSecondSize = Preferences.asLiveData(Preferences::textSecondSize)
val textShadow = Preferences.asLiveData(Preferences::textShadow)
@ -51,4 +54,5 @@ class MainViewModel : ViewModel() {
// Advanced Settings
val darkThemePreference = Preferences.asLiveData(Preferences::darkThemePreference)
val showWallpaper = Preferences.asLiveData(Preferences::showWallpaper)
val showPreview = Preferences.asLiveData(Preferences::showPreview)
}

View File

@ -30,14 +30,13 @@ import com.tommasoberlose.anotherwidget.helpers.*
import com.tommasoberlose.anotherwidget.helpers.WidgetHelper.reduceDimensionWithMaxWidth
import com.tommasoberlose.anotherwidget.receivers.NewCalendarEventReceiver
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver
import com.tommasoberlose.anotherwidget.receivers.WidgetClickListenerReceiver
import com.tommasoberlose.anotherwidget.services.UpdatesWorker
import com.tommasoberlose.anotherwidget.services.WeatherWorker
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
import com.tommasoberlose.anotherwidget.utils.getCapWordString
import com.tommasoberlose.anotherwidget.utils.toPixel
import kotlinx.android.synthetic.main.the_widget.view.*
import kotlinx.android.synthetic.main.the_widget_sans.*
import java.lang.Exception
import java.text.DateFormat
import java.util.*
@ -70,7 +69,7 @@ class MainWidget : AppWidgetProvider() {
override fun onDisabled(context: Context) {
if (getWidgetCount(context) == 0) {
UpdatesWorker.removeUpdates(context)
UpdatesReceiver.removeUpdates(context)
WeatherWorker.removeUpdates(context)
}
}
@ -98,7 +97,7 @@ class MainWidget : AppWidgetProvider() {
val displayMetrics = Resources.getSystem().displayMetrics
val width = displayMetrics.widthPixels
val dimensions = WidgetHelper.WidgetSizeProvider(context, appWidgetManager).getWidgetsSize(appWidgetId).reduceDimensionWithMaxWidth(1200)
val dimensions = WidgetHelper.WidgetSizeProvider(context, appWidgetManager).getWidgetsSize(appWidgetId)
generateWidgetView(context, appWidgetId, appWidgetManager, dimensions.first - 8.toPixel(context) /*width - 16.toPixel(context)*/)
}
@ -108,6 +107,10 @@ class MainWidget : AppWidgetProvider() {
val generatedView = generateWidgetView(context)
views.setImageViewBitmap(R.id.bitmap_container, BitmapHelper.getBitmapFromView(generatedView, width = w))
// Background
views.setInt(R.id.widget_shape_background, "setColorFilter", ColorHelper.getBackgroundColorRgb())
views.setInt(R.id.widget_shape_background, "setImageAlpha", ColorHelper.getBackgroundAlpha())
// Clock
views = updateClockView(context, views, appWidgetId)
@ -265,6 +268,7 @@ class MainWidget : AppWidgetProvider() {
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
}
} catch (ex: Exception) {
ex.printStackTrace()
FirebaseCrashlytics.getInstance().recordException(ex)
}
@ -298,6 +302,7 @@ class MainWidget : AppWidgetProvider() {
views.setViewVisibility(R.id.calendar_weather_rect, View.GONE)
}
} catch (ex: Exception) {
ex.printStackTrace()
FirebaseCrashlytics.getInstance().recordException(ex)
}
return views
@ -307,17 +312,24 @@ class MainWidget : AppWidgetProvider() {
try {
if (!Preferences.showClock) {
views.setViewVisibility(R.id.time, View.GONE)
views.setViewVisibility(R.id.time_am_pm, View.GONE)
views.setViewVisibility(R.id.clock_bottom_margin_none, View.GONE)
views.setViewVisibility(R.id.clock_bottom_margin_small, View.GONE)
views.setViewVisibility(R.id.clock_bottom_margin_medium, View.GONE)
views.setViewVisibility(R.id.clock_bottom_margin_large, View.GONE)
} else {
views.setTextColor(R.id.time, ColorHelper.getFontColor())
views.setTextColor(R.id.time_am_pm, ColorHelper.getFontColor())
views.setTextViewTextSize(
R.id.time,
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(context)
)
views.setTextViewTextSize(
R.id.time_am_pm,
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(context) / 5 * 2
)
val clockPIntent = PendingIntent.getActivity(
context,
widgetID,
@ -325,7 +337,9 @@ class MainWidget : AppWidgetProvider() {
0
)
views.setOnClickPendingIntent(R.id.time, clockPIntent)
views.setOnClickPendingIntent(R.id.time_am_pm, clockPIntent)
views.setViewVisibility(R.id.time, View.VISIBLE)
views.setViewVisibility(R.id.time_am_pm, View.VISIBLE)
views.setViewVisibility(
R.id.clock_bottom_margin_none,
@ -345,6 +359,7 @@ class MainWidget : AppWidgetProvider() {
)
}
} catch (ex: Exception) {
ex.printStackTrace()
FirebaseCrashlytics.getInstance().recordException(ex)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 711 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 781 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 927 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 590 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 881 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

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