Add weather icon pack, updates frequency and fix google fit

This commit is contained in:
Tommaso Berlose
2020-05-12 23:54:07 +02:00
parent ba5a860e75
commit ac381c8542
89 changed files with 702 additions and 263 deletions

View File

@ -70,7 +70,7 @@ class GlanceProviderSortMenu(
// move item in `fromPos` to `toPos` in adapter.
adapter.notifyItemMoved(fromPos, toPos)
val list = GlanceProviderHelper.getGlanceProviders()
val list = GlanceProviderHelper.getGlanceProviders(context)
Collections.swap(list, fromPos, toPos)
GlanceProviderHelper.saveGlanceProviderOrder(list)
return true
@ -87,8 +87,7 @@ class GlanceProviderSortMenu(
mIth.attachToRecyclerView(view.menu)
adapter.updateData(
GlanceProviderHelper.getGlanceProviders()
.filter { it != Constants.GlanceProviderId.BATTERY_LEVEL_LOW }
GlanceProviderHelper.getGlanceProviders(context)
.mapNotNull { GlanceProviderHelper.getGlanceProviderById(context, it) }
)

View File

@ -22,4 +22,15 @@ object Constants {
CUSTOM_INFO("CUSTOM_INFO"),
GOOGLE_FIT_STEPS("GOOGLE_FIT_STEPS")
}
enum class WidgetUpdateFrequency(val value: Int) {
LOW(0),
DEFAULT(1),
HIGH(2)
}
enum class WeatherIconPack(val value: Int) {
DEFAULT(0),
MINIMAL(1)
}
}

View File

@ -40,9 +40,15 @@ object Preferences : KotprefModel() {
var eventAppName by stringPref(key = "PREF_EVENT_APP_NAME", default = "")
var eventAppPackage by stringPref(key = "PREF_EVENT_APP_PACKAGE", default = "")
var openEventDetails by booleanPref(default = true)
var widgetUpdateFrequency by intPref(default = Constants.WidgetUpdateFrequency.DEFAULT.value)
var textGlobalColor by stringPref(key = "PREF_TEXT_COLOR", default = "#FFFFFF")
var textGlobalAlpha by stringPref(default = "FF")
var textSecondaryColor by stringPref(default = "#FFFFFF")
var textSecondaryAlpha by stringPref(default = "FF")
var backgroundCardColor by stringPref(default = "#000000")
var backgroundCardAlpha by stringPref(default = "00")
@ -50,6 +56,8 @@ object Preferences : KotprefModel() {
var clockTextAlpha by stringPref(default = "FF")
var showAMPMIndicator by booleanPref(default = true)
var weatherIconPack by intPref(default = Constants.WeatherIconPack.DEFAULT.value)
// Global
var textMainSize by floatPref(key = "PREF_TEXT_MAIN_SIZE", default = 26f)
var textSecondSize by floatPref(key = "PREF_TEXT_SECOND_SIZE", default = 18f)

View File

@ -30,6 +30,31 @@ object ColorHelper {
Color.parseColor("#000000")
}
}
fun getSecondaryFontColor(): Int {
return try {
Color.parseColor("#%s%s".format(Preferences.textSecondaryAlpha, Preferences.textSecondaryColor.replace("#", "")))
} catch (e: Exception) {
Color.parseColor("#FFFFFFFF")
}
}
fun getSecondaryFontColorAlpha(): Int {
return try {
Preferences.textSecondaryAlpha.toIntValue().toDouble() * 255 / 100
} catch (e: Exception) {
"FF".toIntValue().toDouble() * 255 / 100
}.roundToInt()
}
fun getSecondaryFontColorRgb(): Int {
return try {
Color.parseColor(Preferences.textSecondaryColor)
} catch (e: Exception) {
Color.parseColor("#000000")
}
}
fun getClockFontColor(): Int {
return try {
Color.parseColor("#%s%s".format(Preferences.clockTextAlpha, Preferences.clockTextColor.replace("#", "")))

View File

@ -23,7 +23,7 @@ object DateHelper {
"%s, %s".format(
SimpleDateFormat("EEEE", Locale.getDefault()).format(date.time),
DateUtils.formatDateTime(context, date.timeInMillis, flags)
).getCapWordString()
)
}
}
@ -33,6 +33,6 @@ object DateHelper {
return "%s, %s".format(
SimpleDateFormat("EEEE", Locale.getDefault()).format(date.time),
DateUtils.formatDateTime(context, date.timeInMillis, flags)
).getCapWordString()
)
}
}

View File

@ -6,12 +6,18 @@ import com.tommasoberlose.anotherwidget.db.EventRepository
import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.models.GlanceProvider
import com.tommasoberlose.anotherwidget.utils.checkIfFitInstalled
import java.util.ArrayList
object GlanceProviderHelper {
fun getGlanceProviders(): ArrayList<Constants.GlanceProviderId> {
fun getGlanceProviders(context: Context): ArrayList<Constants.GlanceProviderId> {
val enabledProviders = Preferences.enabledGlanceProviderOrder.split(",").filter { it != "" }
val providers = Constants.GlanceProviderId.values()
.filter { it != Constants.GlanceProviderId.BATTERY_LEVEL_LOW }
.filter {
context.checkIfFitInstalled() || it != Constants.GlanceProviderId.GOOGLE_FIT_STEPS
}.toTypedArray()
providers.sortWith(Comparator { p1, p2 ->
when {

View File

@ -178,4 +178,15 @@ object IntentHelper {
}
}
}
fun getFitIntent(context: Context): Intent {
val pm: PackageManager = context.packageManager
return try {
pm.getLaunchIntentForPackage("com.google.android.apps.fitness")!!.apply {
addCategory(Intent.CATEGORY_LAUNCHER)
}
} catch (e: Exception) {
Intent()
}
}
}

View File

@ -3,6 +3,8 @@ package com.tommasoberlose.anotherwidget.helpers
import android.content.Context
import android.text.format.DateUtils
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences
import org.joda.time.DateTime
import java.util.concurrent.TimeUnit
@ -68,9 +70,21 @@ object SettingsStringHelper {
difference += 60 * 1000 - (difference % (60 * 1000))
when {
difference <= 0 || TimeUnit.MILLISECONDS.toHours(difference) < 1 -> {
difference <= 0 -> {
return ""
}
TimeUnit.MILLISECONDS.toHours(difference) < 1 && Preferences.widgetUpdateFrequency == Constants.WidgetUpdateFrequency.HIGH.value && 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.DEFAULT.value && 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.LOW.value -> {
return context.getString(R.string.soon)
}
TimeUnit.MILLISECONDS.toHours(difference) < 1 -> {
return context.getString(R.string.now)
}
TimeUnit.MILLISECONDS.toHours(difference) < 12 -> {
return DateUtils.getRelativeTimeSpanString(start, now, DateUtils.HOUR_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE).toString()
}

View File

@ -6,6 +6,7 @@ import android.os.Build
import com.google.android.gms.location.LocationServices
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.db.EventRepository
import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.network.WeatherNetworkApi
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
@ -49,79 +50,79 @@ object WeatherHelper {
fun getWeatherIconResource(icon: String): Int {
when (icon) {
"01d" -> {
return R.drawable.clear_day
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.clear_day else R.drawable.clear_day_2
}
"02d" -> {
return R.drawable.partly_cloudy
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.partly_cloudy else R.drawable.partly_cloudy_2
}
"03d" -> {
return R.drawable.mostly_cloudy
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.mostly_cloudy else R.drawable.mostly_cloudy_2
}
"04d" -> {
return R.drawable.cloudy_weather
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.cloudy_weather else R.drawable.cloudy_weather_2
}
"09d" -> {
return R.drawable.storm_weather_day
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.storm_weather_day else R.drawable.storm_weather_day_2
}
"10d" -> {
return R.drawable.rainy_day
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.rainy_day else R.drawable.rainy_day_2
}
"11d" -> {
return R.drawable.thunder_day
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.thunder_day else R.drawable.thunder_day_2
}
"13d" -> {
return R.drawable.snow_day
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.snow_day else R.drawable.snow_day_2
}
"50d" -> {
return R.drawable.haze_day
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.haze_day else R.drawable.haze_day_2
}
"80d" -> {
return R.drawable.windy_day
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.windy_day else R.drawable.windy_day_2
}
"81d" -> {
return R.drawable.rain_snow_day
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.rain_snow_day else R.drawable.rain_snow_day_2
}
"82d" -> {
return R.drawable.haze_weather
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.haze_weather else R.drawable.haze_weather_2
}
"01n" -> {
return R.drawable.clear_night
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.clear_night else R.drawable.clear_night_2
}
"02n" -> {
return R.drawable.partly_cloudy_night
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.partly_cloudy_night else R.drawable.partly_cloudy_night_2
}
"03n" -> {
return R.drawable.mostly_cloudy_night
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.mostly_cloudy_night else R.drawable.mostly_cloudy_night_2
}
"04n" -> {
return R.drawable.cloudy_weather
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.cloudy_weather else R.drawable.cloudy_weather_2
}
"09n" -> {
return R.drawable.storm_weather_night
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.storm_weather_night else R.drawable.storm_weather_night_2
}
"10n" -> {
return R.drawable.rainy_night
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.rainy_night else R.drawable.rainy_night_2
}
"11n" -> {
return R.drawable.thunder_night
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.thunder_night else R.drawable.thunder_night_2
}
"13n" -> {
return R.drawable.snow_night
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.snow_night else R.drawable.snow_night_2
}
"50n" -> {
return R.drawable.haze_night
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.haze_night else R.drawable.haze_night_2
}
"80n" -> {
return R.drawable.windy_night
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.windy_night else R.drawable.windy_night_2
}
"81n" -> {
return R.drawable.rain_snow_night
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.rain_snow_night else R.drawable.rain_snow_night_2
}
"82n" -> {
return R.drawable.haze_weather
return if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) R.drawable.haze_weather else R.drawable.haze_weather_2
}
else -> {
return R.drawable.unknown

View File

@ -30,6 +30,7 @@ class ActivityDetectionReceiver : BroadcastReceiver() {
val result = ActivityTransitionResult.extractResult(intent)!!
val lastEvent = result.transitionEvents.last()
Log.d("ciao", "activity detected: $lastEvent")
if (lastEvent.activityType == DetectedActivity.WALKING || lastEvent.activityType == DetectedActivity.RUNNING && lastEvent.transitionType == ActivityTransition.ACTIVITY_TRANSITION_EXIT) {
requestDailySteps(context)
}
@ -37,6 +38,8 @@ class ActivityDetectionReceiver : BroadcastReceiver() {
if (intent.action == Intent.ACTION_BOOT_COMPLETED || intent.action == Intent.ACTION_MY_PACKAGE_REPLACED && Preferences.showDailySteps && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || context.checkGrantedPermission(Manifest.permission.ACTIVITY_RECOGNITION)) {
resetDailySteps()
registerFence(context)
} else {
resetDailySteps()
}
}
}
@ -155,15 +158,15 @@ class ActivityDetectionReceiver : BroadcastReceiver() {
}
}
fun setTimeout(context: Context) {
private fun setTimeout(context: Context) {
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
cancel(PendingIntent.getBroadcast(context, 0, Intent(context, ActivityDetectionReceiver::class.java), 0))
cancel(PendingIntent.getBroadcast(context, 5, Intent(context, ActivityDetectionReceiver::class.java), 0))
setExactAndAllowWhileIdle(
AlarmManager.RTC,
Calendar.getInstance().timeInMillis + 15 * 60 * 1000,
Calendar.getInstance().timeInMillis + 5 * 60 * 1000,
PendingIntent.getBroadcast(
context,
0,
5,
Intent(context, ActivityDetectionReceiver::class.java),
0
)

View File

@ -4,6 +4,7 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.BatteryManager
import android.util.Log
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
@ -14,6 +15,8 @@ class BatteryLevelReceiver : BroadcastReceiver() {
Intent.ACTION_BATTERY_OKAY -> Preferences.isBatteryLevelLow = false
}
MainWidget.updateWidget(context)
Log.d("ciao", "intent: ${intent}")
}
}

View File

@ -10,6 +10,8 @@ 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.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
import com.tommasoberlose.anotherwidget.models.Event
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
@ -68,24 +70,54 @@ class UpdatesReceiver : BroadcastReceiver() {
val diff = Period(now.timeInMillis, event.startDate)
if (event.startDate > now.timeInMillis) {
// Update the widget every hour till the event
setExactAndAllowWhileIdle(
AlarmManager.RTC,
if (event.startDate - diff.hours * 1000 * 60 * 60 > (now.timeInMillis + 120 * 1000)) event.startDate - diff.hours * 1000 * 60 * 60 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)
},
0
if (diff.hours == 0) {
var minutes = 0
when (Preferences.widgetUpdateFrequency) {
Constants.WidgetUpdateFrequency.DEFAULT.value -> {
minutes = when {
diff.minutes > 50 -> 50
diff.minutes > 30 -> 30
diff.minutes > 15 -> 15
else -> 0
}
}
Constants.WidgetUpdateFrequency.HIGH.value -> {
minutes = diff.minutes - (diff.minutes % 5)
}
}
setExact(
AlarmManager.RTC,
if (event.startDate - minutes * 1000 * 60 > (now.timeInMillis + 120 * 1000)) event.startDate - 60 * 1000 * minutes 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)
},
0
)
)
)
} else {
setExact(
AlarmManager.RTC,
event.startDate - diff.hours * 1000 * 60 * 60,
PendingIntent.getBroadcast(
context,
event.eventID.toInt(),
Intent(context, UpdatesReceiver::class.java).apply {
action = Actions.ACTION_TIME_UPDATE
putExtra(EVENT_ID, event.eventID)
},
0
)
)
}
} 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
setExactAndAllowWhileIdle(
setExact(
AlarmManager.RTC,
fireTime,
PendingIntent.getBroadcast(

View File

@ -123,6 +123,17 @@ class CalendarTabFragment : Fragment() {
}
})
viewModel.widgetUpdateFrequency.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
widget_update_frequency_label?.text = when (it) {
Constants.WidgetUpdateFrequency.HIGH.value -> getString(R.string.settings_widget_update_frequency_high)
Constants.WidgetUpdateFrequency.DEFAULT.value -> getString(R.string.settings_widget_update_frequency_default)
Constants.WidgetUpdateFrequency.LOW.value -> getString(R.string.settings_widget_update_frequency_low)
else -> ""
}
}
})
viewModel.showUntil.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
show_until_label?.text = getString(SettingsStringHelper.getShowUntilString(it))
@ -262,6 +273,18 @@ class CalendarTabFragment : Fragment() {
}
}
action_widget_update_frequency.setOnClickListener {
if (Preferences.showEvents) {
BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_widget_update_frequency_title), message = getString(R.string.settings_widget_update_frequency_subtitle)).setSelectedValue(Preferences.widgetUpdateFrequency)
.addItem(getString(R.string.settings_widget_update_frequency_high), Constants.WidgetUpdateFrequency.HIGH.value)
.addItem(getString(R.string.settings_widget_update_frequency_default), Constants.WidgetUpdateFrequency.DEFAULT.value)
.addItem(getString(R.string.settings_widget_update_frequency_low), Constants.WidgetUpdateFrequency.LOW.value)
.addOnSelectItemListener { value ->
Preferences.widgetUpdateFrequency = value
}.show()
}
}
action_second_row_info.setOnClickListener {
if (Preferences.showEvents) {
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_second_row_info_title)).setSelectedValue(Preferences.secondRowInformation)

View File

@ -116,6 +116,28 @@ class GeneralTabFragment : Fragment() {
}
})
viewModel.textSecondaryColor.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
if (Preferences.textSecondaryAlpha == "00") {
secondary_font_color_label?.text = getString(R.string.transparent)
} else {
secondary_font_color_label?.text =
"#%s".format(Integer.toHexString(ColorHelper.getSecondaryFontColor())).toUpperCase()
}
}
})
viewModel.textSecondaryAlpha.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
if (Preferences.textSecondaryAlpha == "00") {
secondary_font_color_label?.text = getString(R.string.transparent)
} else {
secondary_font_color_label?.text =
"#%s".format(Integer.toHexString(ColorHelper.getSecondaryFontColor())).toUpperCase()
}
}
})
viewModel.backgroundCardColor.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
if (Preferences.backgroundCardAlpha == "00") {
@ -211,6 +233,23 @@ class GeneralTabFragment : Fragment() {
).show()
}
action_secondary_font_color.setOnClickListener {
BottomSheetColorPicker(requireContext(),
colors = colors,
header = getString(R.string.settings_secondary_font_color_title),
getSelected = ColorHelper::getSecondaryFontColorRgb,
onColorSelected = { color: Int ->
val colorString = Integer.toHexString(color)
Preferences.textSecondaryColor = "#" + if (colorString.length > 6) colorString.substring(2) else colorString
},
showAlphaSelector = true,
alpha = Preferences.textSecondaryAlpha.toIntValue(),
onAlphaChangeListener = { alpha ->
Preferences.textSecondaryAlpha = alpha.toHexValue()
}
).show()
}
action_date_format.setOnClickListener {
if (Preferences.showEvents) {
val now = Calendar.getInstance()

View File

@ -43,7 +43,10 @@ import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver.Comp
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
import com.tommasoberlose.anotherwidget.utils.checkIfFitInstalled
import kotlinx.android.synthetic.main.fragment_calendar_settings.*
import kotlinx.android.synthetic.main.fragment_glance_settings.*
import kotlinx.android.synthetic.main.fragment_glance_settings.scrollView
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@ -79,6 +82,8 @@ class GlanceTabFragment : Fragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
action_show_steps.isVisible = requireContext().checkIfFitInstalled()
setupListener()
updateNextAlarmWarningUi()
}

View File

@ -124,127 +124,110 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
private fun updateUI() {
uiJob?.cancel()
if (preview != null) {
preview.clearAnimation()
time_container.clearAnimation()
if (Preferences.showPreview) {
preview.setCardBackgroundColor(
ContextCompat.getColor(
requireContext(),
if (ColorHelper.getFontColor()
.isColorDark()
) android.R.color.white else R.color.colorAccent
)
preview?.clearAnimation()
time_container?.clearAnimation()
if (Preferences.showPreview) {
preview?.setCardBackgroundColor(
ContextCompat.getColor(
requireContext(),
if (ColorHelper.getFontColor()
.isColorDark()
) android.R.color.white else R.color.colorAccent
)
widget_shape_background?.setImageDrawable(
BitmapHelper.getTintedDrawable(
requireContext(),
R.drawable.card_background,
ColorHelper.getBackgroundColor()
)
)
widget_shape_background?.setImageDrawable(
BitmapHelper.getTintedDrawable(
requireContext(),
R.drawable.card_background,
ColorHelper.getBackgroundColor()
)
uiJob = viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
val generatedView = MainWidget.generateWidgetView(requireContext())
)
uiJob = viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
val generatedView = MainWidget.generateWidgetView(requireContext())
withContext(Dispatchers.Main) {
generatedView.measure(0, 0)
preview.measure(0, 0)
}
withContext(Dispatchers.Main) {
generatedView.measure(0, 0)
preview?.measure(0, 0)
}
val bitmap = BitmapHelper.getBitmapFromView(
val bitmap = if (preview != null) {
BitmapHelper.getBitmapFromView(
generatedView,
if (preview.width > 0) preview.width else generatedView.measuredWidth,
generatedView.measuredHeight
)
withContext(Dispatchers.Main) {
// Clock
time.setTextColor(ColorHelper.getClockFontColor())
time_am_pm.setTextColor(ColorHelper.getClockFontColor())
time.setTextSize(
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(requireContext())
)
time_am_pm.setTextSize(
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2
)
time_am_pm.isVisible = Preferences.showAMPMIndicator
} else {
null
}
withContext(Dispatchers.Main) {
// Clock
time?.setTextColor(ColorHelper.getClockFontColor())
time_am_pm?.setTextColor(ColorHelper.getClockFontColor())
time?.setTextSize(
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(requireContext())
)
time_am_pm?.setTextSize(
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2
)
time_am_pm?.isVisible = Preferences.showAMPMIndicator
// 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
// 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()
}
time.alpha = animatedValue
}
addListener(
onStart = {
if (Preferences.showClock) {
time_container.isVisible = true
}
},
onEnd = {
if (!Preferences.showClock) {
time_container.isVisible = false
}
}
)
}.start()
ValueAnimator.ofInt(
preview.height,
PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
requireContext()
) 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 {
if ((Preferences.showClock && time_container?.isVisible == false) || (!Preferences.showClock && time_container?.isVisible == true)) {
if (Preferences.showClock) {
time_container?.layoutParams = time_container.layoutParams.apply {
height = RelativeLayout.LayoutParams.WRAP_CONTENT
}
time_container.measure(0, 0)
time_container?.measure(0, 0)
}
val initialHeight = time_container?.measuredHeight ?: 0
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()
}
time?.alpha = animatedValue
}
addListener(
onStart = {
if (Preferences.showClock) {
time_container?.isVisible = true
}
},
onEnd = {
if (!Preferences.showClock) {
time_container?.isVisible = false
}
}
)
}.start()
if (preview.height == 0) {
if (preview != null) {
ValueAnimator.ofInt(
preview.height,
PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
requireContext()
) else 0
).apply {
duration = 300L
duration = 500L
addUpdateListener {
val animatedValue = animatedValue as Int
val layoutParams = preview.layoutParams
@ -253,14 +236,37 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
}
}.start()
}
widget_loader.animate().scaleX(0f).scaleY(0f).alpha(0f).setDuration(200L)
.start()
bitmap_container.setImageBitmap(bitmap)
widget.animate().alpha(1f).start()
} else {
time_container?.layoutParams = time_container.layoutParams.apply {
height = RelativeLayout.LayoutParams.WRAP_CONTENT
}
time_container?.measure(0, 0)
}
if (preview != null && preview.height == 0) {
ValueAnimator.ofInt(
preview.height,
PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
requireContext()
) else 0
).apply {
duration = 300L
addUpdateListener {
val animatedValue = animatedValue as Int
val layoutParams = preview.layoutParams
layoutParams.height = animatedValue
preview?.layoutParams = layoutParams
}
}.start()
}
widget_loader?.animate()?.scaleX(0f)?.scaleY(0f)?.alpha(0f)?.setDuration(200L)?.start()
bitmap_container?.setImageBitmap(bitmap)
widget?.animate()?.alpha(1f)?.start()
}
} else {
}
} else {
if (preview != null) {
ValueAnimator.ofInt(
preview.height,
0

View File

@ -5,6 +5,7 @@ import android.app.Activity
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -126,6 +127,16 @@ class WeatherTabFragment : Fragment() {
checkLocationPermission()
})
viewModel.weatherIconPack.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
label_weather_icon_pack?.text = when (it) {
Constants.WeatherIconPack.MINIMAL.value -> getString(R.string.settings_weather_icon_pack_minimal)
else -> getString(R.string.settings_weather_icon_pack_default)
}
}
checkLocationPermission()
})
viewModel.weatherAppName.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
weather_app_label?.text =
@ -217,6 +228,17 @@ class WeatherTabFragment : Fragment() {
}
}
action_weather_icon_pack.setOnClickListener {
if (Preferences.showWeather) {
BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_weather_icon_pack_title)).setSelectedValue(Preferences.weatherIconPack)
.addItem(getString(R.string.settings_weather_icon_pack_default), Constants.WeatherIconPack.DEFAULT.value)
.addItem(getString(R.string.settings_weather_icon_pack_minimal), Constants.WeatherIconPack.MINIMAL.value)
.addOnSelectItemListener { value ->
Preferences.weatherIconPack = value
}.show()
}
}
action_weather_app.setOnClickListener {
if (Preferences.showWeather) {
startActivityForResult(

View File

@ -9,6 +9,8 @@ class MainViewModel : ViewModel() {
// General Settings
val textGlobalColor = Preferences.asLiveData(Preferences::textGlobalColor)
val textGlobalAlpha = Preferences.asLiveData(Preferences::textGlobalAlpha)
val textSecondaryColor = Preferences.asLiveData(Preferences::textSecondaryColor)
val textSecondaryAlpha = Preferences.asLiveData(Preferences::textSecondaryAlpha)
val backgroundCardColor = Preferences.asLiveData(Preferences::backgroundCardColor)
val backgroundCardAlpha = Preferences.asLiveData(Preferences::backgroundCardAlpha)
val textMainSize = Preferences.asLiveData(Preferences::textMainSize)
@ -27,6 +29,7 @@ class MainViewModel : ViewModel() {
val showNextEvent = Preferences.asLiveData(Preferences::showNextEvent)
val openEventDetails = Preferences.asLiveData(Preferences::openEventDetails)
val calendarAppName = Preferences.asLiveData(Preferences::calendarAppName)
val widgetUpdateFrequency = Preferences.asLiveData(Preferences::widgetUpdateFrequency)
// Clock Settings
val showClock = Preferences.asLiveData(Preferences::showClock)
@ -52,6 +55,7 @@ class MainViewModel : ViewModel() {
val customLocationAdd = Preferences.asLiveData(Preferences::customLocationAdd)
val showWeatherWarning = Preferences.asLiveData(Preferences::showWeatherWarning)
val weatherIconPack = Preferences.asLiveData(Preferences::weatherIconPack)
// Glance
val showGlance = Preferences.asLiveData(Preferences::showGlance)

View File

@ -261,7 +261,7 @@ class MainWidget : AppWidgetProvider() {
views.setViewVisibility(R.id.empty_layout_rect, View.GONE)
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
} else if (GlanceProviderHelper.showGlanceProviders(context)) {
loop@ for (provider:Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders()) {
loop@ for (provider:Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders(context)) {
when (provider) {
Constants.GlanceProviderId.PLAYING_SONG -> {
if (MediaPlayerHelper.isSomeonePlaying(context)) {
@ -306,6 +306,13 @@ class MainWidget : AppWidgetProvider() {
}
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) {
val fitIntent = PendingIntent.getActivity(
context,
widgetID,
IntentHelper.getFitIntent(context),
0
)
views.setOnClickPendingIntent(R.id.second_row_rect, fitIntent)
break@loop
}
}
@ -446,7 +453,10 @@ class MainWidget : AppWidgetProvider() {
val eventRepository = EventRepository(context)
val v = View.inflate(context, R.layout.the_widget, null)
val now = Calendar.getInstance()
val now = Calendar.getInstance().apply {
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}
v.empty_layout.visibility = View.VISIBLE
v.calendar_layout.visibility = View.GONE
@ -466,7 +476,7 @@ class MainWidget : AppWidgetProvider() {
v.next_event.text = nextEvent.title
if (Preferences.showDiffTime && now.timeInMillis < (nextEvent.startDate - 1000 * 60 * 60)) {
if (Preferences.showDiffTime && now.timeInMillis < nextEvent.startDate) {
v.next_event_difference_time.text = if (!nextEvent.allDay) {
SettingsStringHelper.getDifferenceText(
context,
@ -512,7 +522,7 @@ class MainWidget : AppWidgetProvider() {
} else {
val flags: Int = DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NO_YEAR or DateUtils.FORMAT_ABBREV_MONTH
v.next_event_date.text = DateUtils.formatDateTime(context, now.timeInMillis, flags).getCapWordString()
v.next_event_date.text = DateUtils.formatDateTime(context, now.timeInMillis, flags)
}
}
@ -520,7 +530,7 @@ class MainWidget : AppWidgetProvider() {
v.calendar_layout.visibility = View.VISIBLE
} else if (GlanceProviderHelper.showGlanceProviders(context)) {
v.second_row_icon.isVisible = true
loop@ for (provider:Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders()) {
loop@ for (provider:Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders(context)) {
when (provider) {
Constants.GlanceProviderId.PLAYING_SONG -> {
if (MediaPlayerHelper.isSomeonePlaying(context)) {
@ -562,6 +572,7 @@ class MainWidget : AppWidgetProvider() {
if (Preferences.customNotes.isNotEmpty()) {
v.second_row_icon.isVisible = false
v.next_event_date.text = Preferences.customNotes
v.next_event_date.maxLines = 2
break@loop
}
}
@ -587,14 +598,30 @@ class MainWidget : AppWidgetProvider() {
// Color
listOf<TextView>(v.empty_date, v.divider1, v.temp, v.next_event, v.next_event_difference_time, v.next_event_date, v.divider2, v.calendar_temp, v.divider3, v.special_temp).forEach {
listOf<TextView>(v.empty_date, v.divider1, v.temp, v.next_event, v.next_event_difference_time, v.divider3, v.special_temp).forEach {
it.setTextColor(ColorHelper.getFontColor())
}
listOf<ImageView>(v.second_row_icon, v.action_next, v.action_previous).forEach {
if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) {
listOf<ImageView>(v.action_next, v.action_previous)
} else {
listOf<ImageView>(v.action_next, v.action_previous, v.empty_weather_icon, v.special_weather_icon)
}.forEach {
it.setColorFilter(ColorHelper.getFontColor())
}
listOf<TextView>(v.next_event_date, v.divider2, v.calendar_temp).forEach {
it.setTextColor(ColorHelper.getSecondaryFontColor())
}
if (Preferences.weatherIconPack == Constants.WeatherIconPack.DEFAULT.value) {
listOf<ImageView>(v.second_row_icon)
} else {
listOf<ImageView>(v.second_row_icon, v.weather_icon)
}.forEach {
it.setColorFilter(ColorHelper.getSecondaryFontColor())
}
// Text Size
listOf<Pair<TextView, Float>>(
v.empty_date to Preferences.textMainSize,
@ -615,11 +642,11 @@ class MainWidget : AppWidgetProvider() {
v.second_row_icon.scaleX = Preferences.textSecondSize / 18f
v.second_row_icon.scaleY = Preferences.textSecondSize / 18f
v.weather_icon.scaleX = Preferences.textSecondSize / 16f
v.weather_icon.scaleY = Preferences.textSecondSize / 16f
v.weather_icon.scaleX = Preferences.textSecondSize / 14f
v.weather_icon.scaleY = Preferences.textSecondSize / 14f
v.empty_weather_icon.scaleX = Preferences.textMainSize / 20f
v.empty_weather_icon.scaleY = Preferences.textMainSize / 20f
v.empty_weather_icon.scaleX = Preferences.textMainSize / 18f
v.empty_weather_icon.scaleY = Preferences.textMainSize / 18f
v.action_next.scaleX = Preferences.textMainSize / 28f
v.action_next.scaleY = Preferences.textMainSize / 28f

View File

@ -212,4 +212,13 @@ fun String.getCapWordString(): String {
} catch (e: Exception) {
this
}
}
fun Context.checkIfFitInstalled(): Boolean {
return try {
packageManager.getPackageInfo("com.google.android.apps.fitness", PackageManager.GET_ACTIVITIES)
true
} catch (e: Exception) {
false
}
}