Close #310, added weather as glance provider

This commit is contained in:
Tommaso Berlose 2021-05-14 17:15:34 +02:00
parent fb1953d513
commit dd2a74aaf6
11 changed files with 230 additions and 39 deletions

View File

@ -51,6 +51,7 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
Constants.GlanceProviderId.NOTIFICATIONS -> context.getString(R.string.settings_show_notifications_title)
Constants.GlanceProviderId.GREETINGS -> context.getString(R.string.settings_show_greetings_title)
Constants.GlanceProviderId.EVENTS -> context.getString(R.string.settings_show_events_as_glance_provider_title)
Constants.GlanceProviderId.WEATHER -> context.getString(R.string.settings_show_weather_as_glance_provider_title)
}
/* SUBTITLE*/
@ -63,6 +64,7 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
Constants.GlanceProviderId.NOTIFICATIONS -> context.getString(R.string.settings_show_notifications_subtitle)
Constants.GlanceProviderId.GREETINGS -> context.getString(R.string.settings_show_greetings_subtitle)
Constants.GlanceProviderId.EVENTS -> context.getString(R.string.settings_show_events_as_glance_provider_subtitle)
Constants.GlanceProviderId.WEATHER -> context.getString(R.string.settings_show_weather_as_glance_provider_subtitle)
}
/* SONG */
@ -140,6 +142,13 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
checkCalendarConfig()
}
/* WEATHER */
if (provider == Constants.GlanceProviderId.WEATHER) {
binding.header.isVisible = false
binding.divider.isVisible = false
checkWeatherConfig()
}
/* TOGGLE */
binding.providerSwitch.setCheckedImmediatelyNoEvent(when (provider) {
Constants.GlanceProviderId.PLAYING_SONG -> Preferences.showMusic
@ -150,6 +159,7 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
Constants.GlanceProviderId.NOTIFICATIONS -> Preferences.showNotifications
Constants.GlanceProviderId.GREETINGS -> Preferences.showGreetings
Constants.GlanceProviderId.EVENTS -> Preferences.showEventsAsGlanceProvider
Constants.GlanceProviderId.WEATHER -> Preferences.showWeatherAsGlanceProvider
})
var job: Job? = null
@ -208,6 +218,9 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
Constants.GlanceProviderId.EVENTS -> {
Preferences.showEventsAsGlanceProvider = isChecked
}
Constants.GlanceProviderId.WEATHER -> {
Preferences.showWeatherAsGlanceProvider = isChecked
}
else -> {
}
}
@ -255,6 +268,19 @@ class GlanceSettingsDialog(val context: Activity, val provider: Constants.Glance
}
}
private fun checkWeatherConfig() {
if (!Preferences.showWeather || (Preferences.weatherProviderError != "" && Preferences.weatherProviderError != "-") || Preferences.weatherProviderLocationError != "") {
binding.warningContainer.isVisible = true
binding.warningTitle.text = context.getString(R.string.settings_show_weather_as_glance_provider_error)
binding.warningContainer.setOnClickListener {
dismiss()
EventBus.getDefault().post(MainFragment.ChangeTabEvent(1))
}
} else {
binding.warningContainer.isVisible = false
}
}
private fun checkNotificationPermission() {
when {
ActiveNotificationsHelper.checkNotificationAccess(context) -> {

View File

@ -38,7 +38,8 @@ object Constants {
GOOGLE_FIT_STEPS("GOOGLE_FIT_STEPS"),
NOTIFICATIONS("NOTIFICATIONS"),
GREETINGS("GREETINGS"),
EVENTS("EVENTS");
EVENTS("EVENTS"),
WEATHER("WEATHER");
companion object {
private val map = GlanceProviderId.values().associateBy(GlanceProviderId::id)

View File

@ -153,6 +153,7 @@ object Preferences : KotprefModel() {
var appNotificationsFilter by stringPref(default = "")
var showEventsAsGlanceProvider by booleanPref(default = false)
var showWeatherAsGlanceProvider by booleanPref(default = false)
// Integrations
var installedIntegrations by intPref(default = 0)

View File

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

View File

@ -313,6 +313,23 @@ object WeatherHelper {
}
}
fun getWeatherLabel(context: Context, icon: String): String {
return when (icon) {
"01d", "01n" -> context.getString(R.string.weather_label_clear)
"02d", "02n" -> context.getString(R.string.weather_label_partly_cloudy)
"03d", "03n" -> context.getString(R.string.weather_label_mostly_cloudy)
"04d", "04n" -> context.getString(R.string.weather_label_cloudy_weather)
"09d", "09n" -> context.getString(R.string.weather_label_storm_weather)
"10d", "10n" -> context.getString(R.string.weather_label_rainy)
"11d", "11n" -> context.getString(R.string.weather_label_thunder)
"13d", "13n" -> context.getString(R.string.weather_label_snow)
"50d", "50n", "82d", "82n" -> context.getString(R.string.weather_label_haze)
"80d", "80n" -> context.getString(R.string.weather_label_windy)
"81d", "81n" -> context.getString(R.string.weather_label_rain_snow)
else -> context.getString(R.string.weather_label_unknown)
}
}
fun getWeatherGovIcon(iconString: String, isDaytime: Boolean): String = when {
iconString.contains("skc") -> "01"
iconString.contains("few") -> "02"

View File

@ -141,10 +141,6 @@ class MainFragment : Fragment() {
binding.toolbar.cardElevation = if (it > 0) 24f else 0f
}
viewModel.clockPreferencesUpdate.observe(viewLifecycleOwner) {
onUpdateUiEvent(null)
}
viewModel.widgetPreferencesUpdate.observe(viewLifecycleOwner) {
onUpdateUiEvent(null)
}
@ -160,15 +156,21 @@ class MainFragment : Fragment() {
val generatedView = MainWidget.getWidgetView(requireContext(), binding.widget.width, typeface)
if (generatedView != null) {
val view: View = generatedView.apply(requireActivity().applicationContext, binding.widget)
view.measure(0, 0)
withContext(Dispatchers.Main) {
val view: View = generatedView.apply(requireActivity().applicationContext, binding.widget)
view.measure(0, 0)
binding.widget.removeAllViews()
binding.widget.addView(view)
updatePreviewVisibility(view.measuredHeight)
binding.widgetLoader.animate().scaleX(0f).scaleY(0f).alpha(0f)
binding.widgetLoader.animate().scaleX(1f).scaleY(1f).alpha(1f)
.setDuration(200L).start()
binding.widget.animate().alpha(1f).start()
binding.widget.animate().alpha(0f).setDuration(200L).withEndAction {
binding.widget.removeAllViews()
binding.widget.addView(view)
updatePreviewVisibility(view.measuredHeight)
binding.widgetLoader.animate().scaleX(0f).scaleY(0f).alpha(0f)
.setDuration(200L).start()
binding.widget.animate().alpha(1f).start()
}.start()
}
}
}
@ -177,7 +179,7 @@ class MainFragment : Fragment() {
}
private fun updatePreviewVisibility(widgetHeight: Int) {
val newHeight = widgetHeight + 16f.convertDpToPixel(requireContext()).toInt()
val newHeight = widgetHeight + 32f.convertDpToPixel(requireContext()).toInt()
if (binding.preview.layoutParams.height != newHeight) {
binding.preview.clearAnimation()
ValueAnimator.ofInt(

View File

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

View File

@ -104,7 +104,8 @@ class MainViewModel(context: Application) : AndroidViewModel(context) {
// UI
val fragmentScrollY = MutableLiveData<Int>()
val clockPreferencesUpdate = MediatorLiveData<Boolean>().apply {
val widgetPreferencesUpdate = MediatorLiveData<Boolean>().apply {
addSource(Preferences.asLiveData(Preferences::showClock)) { value = true }
addSource(Preferences.asLiveData(Preferences::clockTextSize)) { value = true }
addSource(Preferences.asLiveData(Preferences::clockTextColor)) { value = true }
addSource(Preferences.asLiveData(Preferences::clockTextAlpha)) { value = true }
@ -113,8 +114,6 @@ class MainViewModel(context: Application) : AndroidViewModel(context) {
addSource(Preferences.asLiveData(Preferences::showAMPMIndicator)) { value = true }
addSource(Preferences.asLiveData(Preferences::clockBottomMargin)) { value = true }
addSource(Preferences.asLiveData(Preferences::altTimezoneLabel)) { value = true }
}
val widgetPreferencesUpdate = MediatorLiveData<Boolean>().apply {
addSource(Preferences.asLiveData(Preferences::textGlobalColor)) { value = true }
addSource(Preferences.asLiveData(Preferences::textGlobalAlpha)) { value = true }
addSource(Preferences.asLiveData(Preferences::textSecondaryColor)) { value = true }
@ -175,6 +174,7 @@ class MainViewModel(context: Application) : AndroidViewModel(context) {
addSource(Preferences.asLiveData(Preferences::musicPlayersFilter)) { value = true }
addSource(Preferences.asLiveData(Preferences::appNotificationsFilter)) { value = true }
addSource(Preferences.asLiveData(Preferences::showEventsAsGlanceProvider)) { value = true }
addSource(Preferences.asLiveData(Preferences::showWeatherAsGlanceProvider)) { value = true }
addSource(Preferences.asLiveData(Preferences::installedIntegrations)) { value = true }
}

View File

@ -253,6 +253,7 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
views.setViewVisibility(R.id.sub_line_top_margin_large_sans, View.GONE)
} else if (GlanceProviderHelper.showGlanceProviders(context)) {
var showSomething = false
var isWeatherShown = false
loop@ for (provider: Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders(context)) {
when (provider) {
Constants.GlanceProviderId.PLAYING_SONG -> {
@ -367,13 +368,29 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
break@loop
}
}
Constants.GlanceProviderId.WEATHER -> {
if (Preferences.showWeather && Preferences.weatherIcon != "") {
val i = Intent(context, WidgetClickListenerReceiver::class.java)
i.action = Actions.ACTION_OPEN_WEATHER_INTENT
val weatherPIntent = PendingIntent.getBroadcast(context, widgetID, i, 0)
views.setOnClickPendingIntent(
R.id.sub_line_rect,
weatherPIntent
)
showSomething = true
isWeatherShown = true
break@loop
}
}
}
}
if (showSomething) {
views.setViewVisibility(R.id.first_line_rect, View.VISIBLE)
views.setViewVisibility(R.id.weather_rect, View.VISIBLE)
views.setViewVisibility(R.id.weather_rect, if (isWeatherShown) View.GONE else View.VISIBLE)
views.setViewVisibility(R.id.sub_line_rect, View.VISIBLE)
views.setViewVisibility(R.id.calendar_layout_rect, View.GONE)
@ -412,8 +429,9 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
// Generates the widget bitmap from the view
fun generateWidgetView(typeface: Typeface? = null): LeftAlignedWidgetBinding? {
private fun generateWidgetView(typeface: Typeface? = null): LeftAlignedWidgetBinding? {
try {
var isWeatherShownAsGlanceProvider = false
val eventRepository = EventRepository(context)
val nextEvent = eventRepository.getNextEvent()
val eventsCount = eventRepository.getEventsCount()
@ -727,6 +745,33 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
break@loop
}
}
Constants.GlanceProviderId.WEATHER -> {
if (Preferences.showWeatherAsGlanceProvider && Preferences.weatherIcon != "") {
bindingView.subLineText.text = String.format(
Locale.getDefault(),
"%d°%s %s",
Preferences.weatherTemp.roundToInt(),
Preferences.weatherRealTempUnit,
WeatherHelper.getWeatherLabel(context, Preferences.weatherIcon)
)
bindingView.subLineIcon.isVisible = true
val icon: String = Preferences.weatherIcon
if (icon == "") {
bindingView.subLineIcon.isVisible = false
} else {
bindingView.subLineIcon.setImageResource(WeatherHelper.getWeatherIconResource(context, icon))
bindingView.subLineIcon.isVisible = true
}
bindingView.weatherDateLine.isVisible = false
bindingView.weatherSubLine.isVisible = false
showSomething = true
isWeatherShownAsGlanceProvider = true
break@loop
}
}
}
}
@ -778,16 +823,22 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
it.setTextColor(ColorHelper.getSecondaryFontColor(context.applicationContext.isDarkTheme()))
}
if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.rawValue) {
listOf<ImageView>(bindingView.subLineIcon, bindingView.subLineIconShadow)
} else {
listOf<ImageView>(bindingView.subLineIcon, bindingView.weatherSubLineWeatherIcon, bindingView.subLineIconShadow)
}.forEach {
it.setColorFilter(ColorHelper.getSecondaryFontColorRgb(context.applicationContext.isDarkTheme()))
it.alpha =
(if (context.isDarkTheme()) Preferences.textSecondaryAlphaDark.toIntValue()
.toFloat() else Preferences.textSecondaryAlpha.toIntValue()
.toFloat()) / 100
if (!isWeatherShownAsGlanceProvider) {
if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.rawValue) {
listOf<ImageView>(bindingView.subLineIcon, bindingView.subLineIconShadow)
} else {
listOf<ImageView>(
bindingView.subLineIcon,
bindingView.weatherSubLineWeatherIcon,
bindingView.subLineIconShadow
)
}.forEach {
it.setColorFilter(ColorHelper.getSecondaryFontColorRgb(context.applicationContext.isDarkTheme()))
it.alpha =
(if (context.isDarkTheme()) Preferences.textSecondaryAlphaDark.toIntValue()
.toFloat() else Preferences.textSecondaryAlpha.toIntValue()
.toFloat()) / 100
}
}
// Text Size

View File

@ -281,6 +281,7 @@ class StandardWidget(val context: Context) {
} else if (GlanceProviderHelper.showGlanceProviders(context)) {
var showSomething = false
var isWeatherShown = false
loop@ for (provider: Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders(context)) {
when (provider) {
Constants.GlanceProviderId.PLAYING_SONG -> {
@ -395,6 +396,21 @@ class StandardWidget(val context: Context) {
break@loop
}
}
Constants.GlanceProviderId.WEATHER -> {
if (Preferences.showWeather && Preferences.weatherIcon != "") {
val i = Intent(context, WidgetClickListenerReceiver::class.java)
i.action = Actions.ACTION_OPEN_WEATHER_INTENT
val weatherPIntent = PendingIntent.getBroadcast(context, widgetID, i, 0)
views.setOnClickPendingIntent(
R.id.sub_line_rect,
weatherPIntent
)
showSomething = true
isWeatherShown = true
break@loop
}
}
}
}
@ -405,6 +421,7 @@ class StandardWidget(val context: Context) {
BitmapHelper.getBitmapFromView(bindingView.subLine, draw = false, width = bindingView.subLine.width, height = bindingView.subLine.height)
)
views.setViewVisibility(R.id.weather_rect, if (isWeatherShown) View.GONE else View.VISIBLE)
views.setViewVisibility(R.id.first_line_rect, View.VISIBLE)
views.setViewVisibility(R.id.sub_line_rect, View.VISIBLE)
@ -438,8 +455,9 @@ class StandardWidget(val context: Context) {
// Generates the widget bitmap from the view
fun generateWidgetView(typeface: Typeface? = null): TheWidgetBinding? {
private fun generateWidgetView(typeface: Typeface? = null): TheWidgetBinding? {
try {
var isWeatherShownAsGlanceProvider = false
val eventRepository = EventRepository(context)
val nextEvent = eventRepository.getNextEvent()
val eventsCount = eventRepository.getEventsCount()
@ -759,6 +777,33 @@ class StandardWidget(val context: Context) {
break@loop
}
}
Constants.GlanceProviderId.WEATHER -> {
if (Preferences.showWeatherAsGlanceProvider && Preferences.weatherIcon != "") {
bindingView.subLineText.text = String.format(
Locale.getDefault(),
"%d°%s %s",
Preferences.weatherTemp.roundToInt(),
Preferences.weatherRealTempUnit,
WeatherHelper.getWeatherLabel(context, Preferences.weatherIcon)
)
bindingView.subLineIcon.isVisible = true
val icon: String = Preferences.weatherIcon
if (icon == "") {
bindingView.subLineIcon.isVisible = false
} else {
bindingView.subLineIcon.setImageResource(WeatherHelper.getWeatherIconResource(context, icon))
bindingView.subLineIcon.isVisible = true
}
bindingView.weatherDateLine.isVisible = false
bindingView.weatherSubLine.isVisible = false
isWeatherShownAsGlanceProvider = true
showSomething = true
break@loop
}
}
}
}
@ -812,16 +857,22 @@ class StandardWidget(val context: Context) {
it.setTextColor(ColorHelper.getSecondaryFontColor(context.applicationContext.isDarkTheme()))
}
if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.rawValue) {
listOf<ImageView>(bindingView.subLineIcon, bindingView.subLineIconShadow)
} else {
listOf<ImageView>(bindingView.subLineIcon, bindingView.weatherSubLineWeatherIcon, bindingView.subLineIconShadow)
}.forEach {
it.setColorFilter(ColorHelper.getSecondaryFontColorRgb(context.applicationContext.isDarkTheme()))
it.alpha =
(if (context.isDarkTheme()) Preferences.textSecondaryAlphaDark.toIntValue()
.toFloat() else Preferences.textSecondaryAlpha.toIntValue()
.toFloat()) / 100
if (!isWeatherShownAsGlanceProvider) {
if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.rawValue) {
listOf<ImageView>(bindingView.subLineIcon, bindingView.subLineIconShadow)
} else {
listOf<ImageView>(
bindingView.subLineIcon,
bindingView.weatherSubLineWeatherIcon,
bindingView.subLineIconShadow
)
}.forEach {
it.setColorFilter(ColorHelper.getSecondaryFontColorRgb(context.applicationContext.isDarkTheme()))
it.alpha =
(if (context.isDarkTheme()) Preferences.textSecondaryAlphaDark.toIntValue()
.toFloat() else Preferences.textSecondaryAlpha.toIntValue()
.toFloat()) / 100
}
}
// Text Size

View File

@ -195,6 +195,19 @@
<string name="location_access_notification_title">Updating the weather…</string>
<string name="location_access_notification_subtitle">We\'re updating the weather based on your current location.</string>
<string name="weather_label_clear">Clear</string>
<string name="weather_label_partly_cloudy">Partly cloudy</string>
<string name="weather_label_mostly_cloudy">Mostly cloudy</string>
<string name="weather_label_cloudy_weather">Cloudy</string>
<string name="weather_label_storm_weather">Storm</string>
<string name="weather_label_rainy">Rainy</string>
<string name="weather_label_thunder">Thunder</string>
<string name="weather_label_snow">Snow</string>
<string name="weather_label_haze">Haze</string>
<string name="weather_label_windy">Windy</string>
<string name="weather_label_rain_snow">Rain and snow</string>
<string name="weather_label_unknown">Unknown</string>
<!-- Clock -->
<string name="settings_clock_title">Clock</string>
<string name="settings_clock_app_title">Clock</string>
@ -293,6 +306,9 @@
<string name="settings_show_events_as_glance_provider_subtitle">View a sneak peek of your calendar events and always show the current date.</string>
<string name="settings_show_events_as_glance_provider_error">Please enable the show of the events in the calendar tab and grant the required permission.</string>
<string name="events_glance_provider_format">%1$s %2$s</string>
<string name="settings_show_weather_as_glance_provider_title">Weather</string>
<string name="settings_show_weather_as_glance_provider_subtitle">View more information about the weather and always show the current date.</string>
<string name="settings_show_weather_as_glance_provider_error">Please enable the show of the weather and fix the configuration\'s errors.</string>
<!-- Settings -->
<string name="action_share">Share</string>