From b93443b736d79b1a380b9f2c1a3de108917a4767 Mon Sep 17 00:00:00 2001 From: Tommaso Berlose Date: Fri, 7 May 2021 12:21:31 +0200 Subject: [PATCH] Added right-aligned widget --- app/build.gradle | 2 +- .../anotherwidget/global/Constants.kt | 2 +- .../ui/fragments/MainFragment.kt | 64 +- .../ui/fragments/tabs/LayoutFragment.kt | 6 + .../anotherwidget/ui/widgets/AlignedWidget.kt | 909 +++++++++++++++++ .../anotherwidget/ui/widgets/ClockWidget.kt | 1 + .../ui/widgets/LeftAlignedWidget.kt | 892 ----------------- .../anotherwidget/ui/widgets/MainWidget.kt | 38 +- .../ui/widgets/StandardWidget.kt | 928 +++++++++--------- .../main/res/layout/left_aligned_widget.xml | 6 +- .../res/layout/right_aligned_widget_sans.xml | 243 +++++ 11 files changed, 1689 insertions(+), 1402 deletions(-) create mode 100644 app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/AlignedWidget.kt delete mode 100644 app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/LeftAlignedWidget.kt create mode 100644 app/src/main/res/layout/right_aligned_widget_sans.xml diff --git a/app/build.gradle b/app/build.gradle index 39d1ac7..56c5a2d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -22,7 +22,7 @@ android { applicationId "com.tommasoberlose.anotherwidget" minSdkVersion 23 targetSdkVersion 30 - versionCode 134 + versionCode 135 versionName "2.3.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/global/Constants.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/global/Constants.kt index fa36ce3..a4eab88 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/global/Constants.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/global/Constants.kt @@ -83,7 +83,7 @@ object Constants { enum class WidgetAlign(val rawValue: Int) { LEFT(0), -// RIGHT(1), + RIGHT(1), CENTER(2) } } \ No newline at end of file diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/MainFragment.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/MainFragment.kt index 234df57..8bbfaea 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/MainFragment.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/MainFragment.kt @@ -208,21 +208,31 @@ class MainFragment : Fragment() { WidgetHelper.runWithCustomTypeface(requireContext()) { typeface -> uiJob?.cancel() uiJob = lifecycleScope.launch(Dispatchers.IO) { - val generatedView = MainWidget.getWidgetView(requireContext(), typeface).root + val generatedView = MainWidget.getWidgetView(requireContext(), typeface)?.root - withContext(Dispatchers.Main) { + if (generatedView != null) { + withContext(Dispatchers.Main) { - binding.widgetDetail.content.removeAllViews() - val container = LinearLayout(requireContext()).apply { - layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) + binding.widgetDetail.content.removeAllViews() + val container = LinearLayout(requireContext()).apply { + layoutParams = LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT + ) + } + container.gravity = when (Preferences.widgetAlign) { + Constants.WidgetAlign.CENTER.rawValue -> Gravity.CENTER_HORIZONTAL + Constants.WidgetAlign.LEFT.rawValue -> Gravity.START + Constants.WidgetAlign.RIGHT.rawValue -> Gravity.END + else -> Gravity.NO_GRAVITY + } + container.addView(generatedView) + binding.widgetDetail.content.addView(container) + + binding.widgetLoader.animate().scaleX(0f).scaleY(0f).alpha(0f) + .setDuration(200L).start() + binding.widget.animate().alpha(1f).start() } - container.gravity = if (Preferences.widgetAlign == Constants.WidgetAlign.CENTER.rawValue) Gravity.CENTER else Gravity.NO_GRAVITY - container.addView(generatedView) - binding.widgetDetail.content.addView(container) - - binding.widgetLoader.animate().scaleX(0f).scaleY(0f).alpha(0f) - .setDuration(200L).start() - binding.widget.animate().alpha(1f).start() } } } @@ -281,7 +291,35 @@ class MainFragment : Fragment() { // Align binding.widgetDetail.timeContainer.layoutParams = (binding.widgetDetail.timeContainer.layoutParams as LinearLayout.LayoutParams).apply { - gravity = if (Preferences.widgetAlign == Constants.WidgetAlign.CENTER.rawValue) Gravity.CENTER_HORIZONTAL else Gravity.NO_GRAVITY + gravity = when (Preferences.widgetAlign) { + Constants.WidgetAlign.CENTER.rawValue -> Gravity.CENTER_HORIZONTAL + Constants.WidgetAlign.LEFT.rawValue -> Gravity.START + Constants.WidgetAlign.RIGHT.rawValue -> Gravity.END + else -> Gravity.NO_GRAVITY + } + } + if (Preferences.widgetAlign == Constants.WidgetAlign.RIGHT.rawValue) { + with (binding.widgetDetail.timeContainer) { + val child = getChildAt(2) + if (child.id == R.id.timezones_container) { + removeViewAt(2) + child.layoutParams = (child.layoutParams as ViewGroup.MarginLayoutParams).apply { + marginEnd = 16f.convertDpToPixel(requireContext()).toInt() + } + addView(child, 0) + } + } + } else { + with (binding.widgetDetail.timeContainer) { + val child = getChildAt(0) + if (child.id == R.id.timezones_container) { + removeViewAt(0) + child.layoutParams = (child.layoutParams as ViewGroup.MarginLayoutParams).apply { + marginEnd = 0 + } + addView(child, 2) + } + } } } diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/tabs/LayoutFragment.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/tabs/LayoutFragment.kt index 2ba7cc2..d4a744c 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/tabs/LayoutFragment.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/tabs/LayoutFragment.kt @@ -101,12 +101,14 @@ class LayoutFragment : Fragment() { maintainScrollPosition { binding.widgetAlignIcon.setImageDrawable(when (it) { Constants.WidgetAlign.LEFT.rawValue -> ContextCompat.getDrawable(requireContext(), R.drawable.round_align_horizontal_left_24) + Constants.WidgetAlign.RIGHT.rawValue -> ContextCompat.getDrawable(requireContext(), R.drawable.round_align_horizontal_right_24) Constants.WidgetAlign.CENTER.rawValue -> ContextCompat.getDrawable(requireContext(), R.drawable.round_align_horizontal_center_24) else -> ContextCompat.getDrawable(requireContext(), R.drawable.round_align_horizontal_center_24) }) binding.widgetAlignLabel.text = when (it) { Constants.WidgetAlign.LEFT.rawValue -> getString(R.string.settings_widget_align_left_subtitle) + Constants.WidgetAlign.RIGHT.rawValue -> getString(R.string.settings_widget_align_right_subtitle) Constants.WidgetAlign.CENTER.rawValue -> getString(R.string.settings_widget_align_center_subtitle) else -> getString(R.string.settings_widget_align_center_subtitle) } @@ -210,6 +212,10 @@ class LayoutFragment : Fragment() { getString(R.string.settings_widget_align_left_subtitle), Constants.WidgetAlign.LEFT.rawValue ) + .addItem( + getString(R.string.settings_widget_align_right_subtitle), + Constants.WidgetAlign.RIGHT.rawValue + ) .addOnSelectItemListener { value -> Preferences.widgetAlign = value }.show() diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/AlignedWidget.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/AlignedWidget.kt new file mode 100644 index 0000000..586fcb8 --- /dev/null +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/AlignedWidget.kt @@ -0,0 +1,909 @@ +package com.tommasoberlose.anotherwidget.ui.widgets + +import android.Manifest +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import android.graphics.Color +import android.graphics.Typeface +import android.text.format.DateUtils +import android.util.Log +import android.util.TypedValue +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.* +import androidx.core.content.ContextCompat +import androidx.core.view.isVisible +import androidx.core.view.updateMargins +import com.tommasoberlose.anotherwidget.R +import com.tommasoberlose.anotherwidget.databinding.LeftAlignedWidgetBinding +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.* +import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue +import com.tommasoberlose.anotherwidget.helpers.ImageHelper.applyShadow +import com.tommasoberlose.anotherwidget.receivers.CrashlyticsReceiver +import com.tommasoberlose.anotherwidget.receivers.NewCalendarEventReceiver +import com.tommasoberlose.anotherwidget.receivers.WidgetClickListenerReceiver +import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission +import com.tommasoberlose.anotherwidget.utils.convertDpToPixel +import com.tommasoberlose.anotherwidget.utils.isDarkTheme +import java.text.DateFormat +import java.util.* +import java.util.concurrent.TimeUnit +import kotlin.math.roundToInt + +class AlignedWidget(val context: Context, val rightAligned: Boolean = false) { + fun generateWidget(appWidgetId: Int, w: Int, typeface: Typeface? = null): RemoteViews? { + + var views = RemoteViews(context.packageName, if (!rightAligned) R.layout.left_aligned_widget_sans else R.layout.right_aligned_widget_sans) + + try { + // Background + views.setInt( + R.id.widget_shape_background, + "setColorFilter", + ColorHelper.getBackgroundColorRgb(context.isDarkTheme()) + ) + views.setInt( + R.id.widget_shape_background, + "setImageAlpha", + ColorHelper.getBackgroundAlpha(context.isDarkTheme()) + ) + val refreshIntent = PendingIntent.getActivity( + context, + appWidgetId, + IntentHelper.getWidgetUpdateIntent(context), + PendingIntent.FLAG_UPDATE_CURRENT + ) + views.setOnClickPendingIntent(R.id.widget_shape_background, refreshIntent) + } catch (ex: Exception) { + ex.printStackTrace() + CrashlyticsReceiver.sendCrash(context, ex) + } + + // Clock + views = ClockWidget(context).updateClockView(views, appWidgetId) + + // Setup listener + try { + val generatedBinding = generateWidgetView(typeface) ?: return null + + views.setImageViewBitmap( + R.id.bitmap_container, + BitmapHelper.getBitmapFromView(generatedBinding.root, width = w) + ) + views = updateGridView(generatedBinding, views, appWidgetId) + } catch (ex: Exception) { + ex.printStackTrace() + CrashlyticsReceiver.sendCrash(context, ex) + } + + return views + } + + private fun updateGridView(bindingView: LeftAlignedWidgetBinding, views: RemoteViews, widgetID: Int): RemoteViews { + try { + val eventRepository = EventRepository(context) + val nextEvent = eventRepository.getNextEvent() + val eventsCount = eventRepository.getEventsCount() + eventRepository.close() + + // Weather + if (Preferences.showWeather && Preferences.weatherIcon != "") { + views.setViewVisibility(R.id.weather_rect, View.VISIBLE) + views.setViewVisibility(R.id.weather_sub_line, View.GONE) + + 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.weather_rect, weatherPIntent) + views.setOnClickPendingIntent(R.id.weather_sub_line_rect, weatherPIntent) + + views.setImageViewBitmap( + R.id.weather_rect, + BitmapHelper.getBitmapFromView(bindingView.weatherDateLine, draw = false) + ) + + views.setImageViewBitmap( + R.id.weather_sub_line_rect, + BitmapHelper.getBitmapFromView(bindingView.weatherSubLine, draw = false) + ) + } else { + views.setViewVisibility(R.id.weather_rect, View.GONE) + views.setViewVisibility(R.id.weather_sub_line, View.GONE) + } + + + // Calendar + views.setImageViewBitmap( + R.id.date_rect, + BitmapHelper.getBitmapFromView(bindingView.date, draw = false) + ) + + val calPIntent = PendingIntent.getActivity( + context, + widgetID, + IntentHelper.getCalendarIntent(context), + PendingIntent.FLAG_UPDATE_CURRENT + ) + views.setOnClickPendingIntent(R.id.date_rect, calPIntent) + views.setViewVisibility(R.id.first_line_rect, View.VISIBLE) + + val nextAlarm = AlarmHelper.getNextAlarm(context) + + // Spacing + views.setViewVisibility( + R.id.sub_line_top_margin_small_sans, + if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.rawValue) View.VISIBLE else View.GONE + ) + views.setViewVisibility( + R.id.sub_line_top_margin_medium_sans, + if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.rawValue) View.VISIBLE else View.GONE + ) + views.setViewVisibility( + R.id.sub_line_top_margin_large_sans, + if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.LARGE.rawValue) View.VISIBLE else View.GONE + ) + + if (Preferences.showEvents && context.checkGrantedPermission(Manifest.permission.READ_CALENDAR) && nextEvent != null && !Preferences.showEventsAsGlanceProvider) { + if (Preferences.showNextEvent && eventsCount > 1) { + + // Action next event + views.setImageViewBitmap( + R.id.action_next_rect, + BitmapHelper.getBitmapFromView(bindingView.actionNext, draw = false) + ) + views.setViewVisibility(R.id.action_next_rect, View.VISIBLE) + views.setOnClickPendingIntent( + R.id.action_next_rect, + PendingIntent.getBroadcast( + context, + widgetID, + Intent( + context, + NewCalendarEventReceiver::class.java + ).apply { action = Actions.ACTION_GO_TO_NEXT_EVENT }, + PendingIntent.FLAG_UPDATE_CURRENT + ) + ) + + views.setViewVisibility(R.id.action_next_rect, View.VISIBLE) + } else { + views.setViewVisibility(R.id.action_next_rect, View.GONE) + } + + // Event intent + val eventIntent = PendingIntent.getActivity( + context, + widgetID, + IntentHelper.getEventIntent(context, nextEvent), + PendingIntent.FLAG_UPDATE_CURRENT + ) + views.setOnClickPendingIntent(R.id.next_event_rect, eventIntent) + views.setViewVisibility(R.id.next_event_rect, View.VISIBLE) + + // Event time difference + if (Preferences.showDiffTime && Calendar.getInstance().timeInMillis < nextEvent.startDate) { + views.setImageViewBitmap( + R.id.next_event_difference_time_rect, + BitmapHelper.getBitmapFromView( + bindingView.nextEventDifferenceTime, + draw = false + ) + ) + + views.setOnClickPendingIntent(R.id.next_event_difference_time_rect, eventIntent) + views.setViewVisibility(R.id.next_event_difference_time_rect, View.VISIBLE) + } else { + views.setViewVisibility(R.id.next_event_difference_time_rect, View.GONE) + } + + // Event information + if (nextEvent.address != "" && Preferences.secondRowInformation == 1) { + val mapIntent = PendingIntent.getActivity( + context, + widgetID, + IntentHelper.getGoogleMapsIntentFromAddress(context, nextEvent.address), + PendingIntent.FLAG_UPDATE_CURRENT + ) + views.setOnClickPendingIntent(R.id.sub_line_rect, mapIntent) + } else { + val pIntentDetail = PendingIntent.getActivity( + context, + widgetID, + IntentHelper.getEventIntent( + context, + nextEvent, + forceEventDetails = true + ), + PendingIntent.FLAG_UPDATE_CURRENT + ) + views.setOnClickPendingIntent(R.id.sub_line_rect, pIntentDetail) + } + + views.setImageViewBitmap( + R.id.next_event_rect, + BitmapHelper.getBitmapFromView(bindingView.nextEvent, draw = false) + ) + views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE) + + views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE) + views.setViewVisibility(R.id.sub_line_rect, View.VISIBLE) + views.setViewVisibility(R.id.weather_sub_line_rect, View.VISIBLE) + views.setViewVisibility(R.id.first_line_rect, View.GONE) + + views.setViewVisibility(R.id.sub_line_top_margin_small_sans, View.GONE) + views.setViewVisibility(R.id.sub_line_top_margin_medium_sans, View.GONE) + views.setViewVisibility(R.id.sub_line_top_margin_large_sans, View.GONE) + } else if (GlanceProviderHelper.showGlanceProviders(context)) { + var showSomething = false + loop@ for (provider: Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders(context)) { + when (provider) { + Constants.GlanceProviderId.PLAYING_SONG -> { + if (MediaPlayerHelper.isSomeonePlaying(context)) { + val musicIntent = PendingIntent.getActivity( + context, + widgetID, + IntentHelper.getMusicIntent(context), + PendingIntent.FLAG_UPDATE_CURRENT + ) + views.setOnClickPendingIntent(R.id.sub_line_rect, musicIntent) + showSomething = true + break@loop + } + } + Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> { + if (Preferences.showNextAlarm && nextAlarm != "") { + val alarmIntent = PendingIntent.getActivity( + context, + widgetID, + IntentHelper.getClockIntent(context), + PendingIntent.FLAG_UPDATE_CURRENT + ) + views.setOnClickPendingIntent(R.id.sub_line_rect, alarmIntent) + showSomething = true + break@loop + } + } + Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> { + if (Preferences.showBatteryCharging) { + BatteryHelper.updateBatteryInfo(context) + if (Preferences.isCharging || Preferences.isBatteryLevelLow) { + val batteryIntent = PendingIntent.getActivity( + context, + widgetID, + IntentHelper.getBatteryIntent(), + PendingIntent.FLAG_UPDATE_CURRENT + ) + views.setOnClickPendingIntent(R.id.sub_line_rect, batteryIntent) + showSomething = true + break@loop + } + } + } + Constants.GlanceProviderId.CUSTOM_INFO -> { + if (Preferences.customNotes.isNotEmpty()) { + break@loop + } + } + Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> { + if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) { + val fitIntent = PendingIntent.getActivity( + context, + widgetID, + IntentHelper.getFitIntent(context), + PendingIntent.FLAG_UPDATE_CURRENT + ) + views.setOnClickPendingIntent(R.id.sub_line_rect, fitIntent) + showSomething = true + break@loop + } + } + Constants.GlanceProviderId.NOTIFICATIONS -> { + if (Preferences.showNotifications && ActiveNotificationsHelper.showLastNotification()) { + try { + if (Preferences.lastNotificationIcon != 0) { + val remotePackageContext = context.createPackageContext( + Preferences.lastNotificationPackage, 0) + ContextCompat.getDrawable( + remotePackageContext, + Preferences.lastNotificationIcon) + } + val notificationIntent = PendingIntent.getActivity( + context, + widgetID, + IntentHelper.getNotificationIntent(context), + PendingIntent.FLAG_UPDATE_CURRENT + ) + views.setOnClickPendingIntent( + R.id.sub_line_rect, + notificationIntent + ) + showSomething = true + break@loop + } catch (ex: Exception) {} + } + } + Constants.GlanceProviderId.GREETINGS -> { + if (Preferences.showGreetings && GreetingsHelper.showGreetings() && GreetingsHelper.getRandomString(context).isNotBlank()) { + showSomething = true + break@loop + } + } + Constants.GlanceProviderId.EVENTS -> { + if (Preferences.showEventsAsGlanceProvider&& Preferences.showEvents && context.checkGrantedPermission( + Manifest.permission.READ_CALENDAR) && nextEvent != null) { + val pIntentDetail = PendingIntent.getActivity( + context, + widgetID, + IntentHelper.getEventIntent( + context, + nextEvent, + forceEventDetails = true + ), + PendingIntent.FLAG_UPDATE_CURRENT + ) + views.setOnClickPendingIntent( + R.id.sub_line_rect, + pIntentDetail + ) + showSomething = 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.sub_line_rect, View.VISIBLE) + + views.setViewVisibility(R.id.calendar_layout_rect, View.GONE) + views.setViewVisibility(R.id.weather_sub_line_rect, View.GONE) + } else { + // Spacing + views.setViewVisibility(R.id.sub_line_top_margin_small_sans, View.GONE) + views.setViewVisibility(R.id.sub_line_top_margin_medium_sans, View.GONE) + views.setViewVisibility(R.id.sub_line_top_margin_large_sans, View.GONE) + } + } + + // Second row + views.setImageViewBitmap( + R.id.sub_line_rect, + BitmapHelper.getBitmapFromView(bindingView.subLine, draw = false) + ) + } catch (ex: Exception) { + ex.printStackTrace() + CrashlyticsReceiver.sendCrash(context, ex) + } + + return views + } + + + // Generates the widget bitmap from the view + fun generateWidgetView(typeface: Typeface? = null): LeftAlignedWidgetBinding? { + try { + val eventRepository = EventRepository(context) + val nextEvent = eventRepository.getNextEvent() + val eventsCount = eventRepository.getEventsCount() + eventRepository.close() + + val bindingView = LeftAlignedWidgetBinding.inflate(LayoutInflater.from(context)) + + bindingView.loader.isVisible = false + + // Weather + if (Preferences.showWeather && Preferences.weatherIcon != "") { + bindingView.weatherDateLine.isVisible = true + val currentTemp = String.format( + Locale.getDefault(), + "%d°%s", + Preferences.weatherTemp.roundToInt(), + Preferences.weatherRealTempUnit + ) + + val icon: String = Preferences.weatherIcon + if (icon == "") { + bindingView.weatherSubLineWeatherIcon.isVisible = false + bindingView.weatherDateLineWeatherIcon.isVisible = false + } else { + bindingView.weatherSubLineWeatherIcon.setImageResource(WeatherHelper.getWeatherIconResource(context, icon)) + bindingView.weatherDateLineWeatherIcon.setImageResource(WeatherHelper.getWeatherIconResource(context, icon)) + bindingView.weatherSubLineWeatherIcon.isVisible = true + bindingView.weatherDateLineWeatherIcon.isVisible = true + } + + bindingView.weatherDateLineTemperature.text = currentTemp + bindingView.weatherSubLineTemperature.text = currentTemp + + if (GlanceProviderHelper.showGlanceProviders(context)) { + bindingView.weatherSubLine.isVisible = false + } + } else { + bindingView.weatherDateLine.isVisible = false + bindingView.weatherSubLine.isVisible = false + } + + val now = Calendar.getInstance().apply { + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) + } + + bindingView.dateLayout.isVisible = true + bindingView.calendarLayout.isVisible = false + bindingView.nextEventDifferenceTime.isVisible = false + bindingView.actionNext.isVisible = false + + bindingView.date.text = DateHelper.getDateText(context, now) + + val nextAlarm = AlarmHelper.getNextAlarm(context) + + if (Preferences.showEvents && context.checkGrantedPermission(Manifest.permission.READ_CALENDAR) && nextEvent != null && !Preferences.showEventsAsGlanceProvider) { + // Multiple counter + bindingView.actionNext.isVisible = + Preferences.showNextEvent && eventsCount > 1 + + bindingView.nextEvent.text = nextEvent.title + + if (Preferences.showDiffTime && now.timeInMillis < nextEvent.startDate) { + bindingView.nextEventDifferenceTime.text = if (!nextEvent.allDay) { + SettingsStringHelper.getDifferenceText( + context, + now.timeInMillis, + nextEvent.startDate + ) + .toLowerCase(Locale.getDefault()) + } else { + SettingsStringHelper.getAllDayEventDifferenceText( + context, + now.timeInMillis, + nextEvent.startDate + ).toLowerCase(Locale.getDefault()) + } + bindingView.nextEventDifferenceTime.isVisible = true + } else { + bindingView.nextEventDifferenceTime.isVisible = false + } + + if (nextEvent.address != "" && Preferences.secondRowInformation == 1) { + bindingView.subLineIcon.setImageDrawable( + ContextCompat.getDrawable( + context, + R.drawable.round_place_24 + ) + ) + bindingView.subLineText.text = nextEvent.address + } else { + bindingView.subLineIcon.setImageDrawable( + ContextCompat.getDrawable( + context, + R.drawable.round_today_24 + ) + ) + if (!nextEvent.allDay) { + val startHour = + DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()) + .format(nextEvent.startDate) + val endHour = + DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()) + .format(nextEvent.endDate) + + var dayDiff = + TimeUnit.MILLISECONDS.toDays(nextEvent.endDate - nextEvent.startDate) + + val startCal = Calendar.getInstance() + startCal.timeInMillis = nextEvent.startDate + + val endCal = Calendar.getInstance() + endCal.timeInMillis = nextEvent.endDate + + if (startCal.get(Calendar.HOUR_OF_DAY) > endCal.get(Calendar.HOUR_OF_DAY)) { + dayDiff++ + } else if (startCal.get(Calendar.HOUR_OF_DAY) == endCal.get(Calendar.HOUR_OF_DAY) && startCal.get( + Calendar.MINUTE + ) > endCal.get(Calendar.MINUTE) + ) { + dayDiff++ + } + var multipleDay = "" + if (dayDiff > 0) { + multipleDay = String.format( + " (+%s%s)", + dayDiff, + context.getString(R.string.day_char) + ) + } + + if (nextEvent.startDate != nextEvent.endDate) { + bindingView.subLineText.text = + String.format("%s - %s%s", startHour, endHour, multipleDay) + } else { + bindingView.subLineText.text = + String.format("%s", startHour) + } + + } else { + val flags: Int = + DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NO_YEAR or DateUtils.FORMAT_ABBREV_MONTH + val start = Calendar.getInstance().apply { timeInMillis = nextEvent.startDate } + + bindingView.subLineText.text = if (now.get(Calendar.DAY_OF_YEAR) == start.get( + Calendar.DAY_OF_YEAR)) { + DateUtils.formatDateTime(context, nextEvent.startDate, flags) + } else if (now.get(Calendar.DAY_OF_YEAR) > start.get(Calendar.DAY_OF_YEAR) || now.get( + Calendar.YEAR) > start.get(Calendar.YEAR)) { + DateUtils.formatDateTime(context, now.timeInMillis, flags) + } else { + DateUtils.formatDateTime(context, nextEvent.startDate, flags) + } + } + } + + bindingView.dateLayout.isVisible = false + bindingView.calendarLayout.isVisible = true + bindingView.subLine.isVisible = true + bindingView.weatherSubLine.isVisible = true + + bindingView.subLineTopMarginSmall.visibility = View.GONE + bindingView.subLineTopMarginMedium.visibility = View.GONE + bindingView.subLineTopMarginLarge.visibility = View.GONE + } else if (GlanceProviderHelper.showGlanceProviders(context)) { + bindingView.subLineIcon.isVisible = true + var showSomething = false + loop@ for (provider: Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders( + context + )) { + when (provider) { + Constants.GlanceProviderId.PLAYING_SONG -> { + if (MediaPlayerHelper.isSomeonePlaying(context)) { + bindingView.subLineIcon.setImageDrawable( + ContextCompat.getDrawable( + context, + R.drawable.round_music_note_24 + ) + ) + bindingView.subLineText.text = MediaPlayerHelper.getMediaInfo() + showSomething = true + break@loop + } + } + Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> { + if (Preferences.showNextAlarm && nextAlarm != "") { + bindingView.subLineIcon.setImageDrawable( + ContextCompat.getDrawable( + context, + R.drawable.round_alarm_24 + ) + ) + bindingView.subLineText.text = AlarmHelper.getNextAlarm(context) + showSomething = true + break@loop + } + } + Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> { + if (Preferences.showBatteryCharging) { + BatteryHelper.updateBatteryInfo(context) + if (Preferences.isCharging) { + bindingView.subLineIcon.isVisible = false + val batteryLevel = BatteryHelper.getBatteryLevel(context) + if (batteryLevel != 100) { + bindingView.subLineText.text = context.getString(R.string.charging) + } else { + bindingView.subLineText.text = + context.getString(R.string.charged) + } + showSomething = true + break@loop + } else if (Preferences.isBatteryLevelLow) { + bindingView.subLineIcon.isVisible = false + bindingView.subLineText.text = + context.getString(R.string.battery_low_warning) + showSomething = true + break@loop + } + } + } + Constants.GlanceProviderId.CUSTOM_INFO -> { + if (Preferences.customNotes.isNotEmpty()) { + bindingView.subLineIcon.isVisible = false + bindingView.subLineText.text = Preferences.customNotes + bindingView.subLineText.maxLines = 2 + showSomething = true + break@loop + } + } + Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> { + if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) { + bindingView.subLineIcon.isVisible = false + bindingView.subLineText.text = + context.getString(R.string.daily_steps_counter) + .format(Preferences.googleFitSteps) + showSomething = true + break@loop + } + } + Constants.GlanceProviderId.NOTIFICATIONS -> { + if (Preferences.showNotifications && ActiveNotificationsHelper.showLastNotification()) { + try { + if (Preferences.lastNotificationIcon != 0) { + val remotePackageContext = context.createPackageContext( + Preferences.lastNotificationPackage, 0) + val icon = ContextCompat.getDrawable(remotePackageContext, + Preferences.lastNotificationIcon) + bindingView.subLineIcon.isVisible = true + bindingView.subLineIcon.setImageDrawable(icon) + } else { + bindingView.subLineIcon.isVisible = false + } + bindingView.subLineText.text = Preferences.lastNotificationTitle + showSomething = true + break@loop + } catch (ex: Exception) {} + } + } + Constants.GlanceProviderId.GREETINGS -> { + val greetingsText = GreetingsHelper.getRandomString(context) + if (Preferences.showGreetings && GreetingsHelper.showGreetings() && greetingsText.isNotBlank()) { + bindingView.subLineText.text = greetingsText + bindingView.subLineText.maxLines = 2 + bindingView.subLineIcon.isVisible = false + showSomething = true + break@loop + } + } + Constants.GlanceProviderId.EVENTS -> { + if (Preferences.showEventsAsGlanceProvider && Preferences.showEvents && context.checkGrantedPermission( + Manifest.permission.READ_CALENDAR) && nextEvent != null) { + bindingView.subLineText.text = context.getString(R.string.events_glance_provider_format).format(nextEvent.title, if (Preferences.showDiffTime && now.timeInMillis < nextEvent.startDate) { + if (!nextEvent.allDay) { + SettingsStringHelper.getDifferenceText( + context, + now.timeInMillis, + nextEvent.startDate + ) + .toLowerCase(Locale.getDefault()) + } else { + SettingsStringHelper.getAllDayEventDifferenceText( + context, + now.timeInMillis, + nextEvent.startDate + ).toLowerCase(Locale.getDefault()) + } + } else "").trimEnd() + bindingView.subLineIcon.isVisible = true + bindingView.subLineIcon.setImageDrawable( + ContextCompat.getDrawable( + context, + R.drawable.round_today_24 + ) + ) + showSomething = true + break@loop + } + } + } + } + + if (showSomething) { + bindingView.dateLayout.isVisible = true + bindingView.calendarLayout.isVisible = false + bindingView.subLine.isVisible = true + bindingView.weatherSubLine.isVisible = false + + bindingView.subLineTopMarginSmall.visibility = + if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.rawValue) View.VISIBLE else View.GONE + bindingView.subLineTopMarginMedium.visibility = + if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.rawValue) View.VISIBLE else View.GONE + bindingView.subLineTopMarginLarge.visibility = + if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.LARGE.rawValue) View.VISIBLE else View.GONE + } else { + bindingView.subLineIcon.isVisible = false + } + } + + + // Color + listOf( + bindingView.date, + bindingView.weatherDateLineTemperature, + bindingView.nextEvent, + bindingView.nextEventDifferenceTime, + ).forEach { + it.setTextColor(ColorHelper.getFontColor(context.applicationContext.isDarkTheme())) + } + + if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.rawValue) { + listOf(bindingView.actionNext) + } else { + listOf( + bindingView.actionNext, + bindingView.weatherDateLineWeatherIcon, + bindingView.weatherSubLineWeatherIcon + ) + }.forEach { + it.setColorFilter(ColorHelper.getFontColorRgb(context.applicationContext.isDarkTheme())) + it.alpha = + (if (context.isDarkTheme()) Preferences.textGlobalAlphaDark.toIntValue() + .toFloat() else Preferences.textGlobalAlpha.toIntValue() + .toFloat()) / 100 + } + + listOf(bindingView.subLineText, bindingView.weatherSubLineDivider, bindingView.weatherSubLineTemperature).forEach { + it.setTextColor(ColorHelper.getSecondaryFontColor(context.applicationContext.isDarkTheme())) + } + + if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.rawValue) { + listOf(bindingView.subLineIcon, bindingView.subLineIconShadow) + } else { + listOf(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 + listOf>( + bindingView.date to Preferences.textMainSize, + bindingView.weatherDateLineTemperature to ((Preferences.textMainSize + Preferences.textSecondSize) / 2), + bindingView.nextEvent to Preferences.textMainSize, + bindingView.nextEventDifferenceTime to Preferences.textMainSize, + bindingView.subLineText to Preferences.textSecondSize, + bindingView.weatherSubLineDivider to (Preferences.textSecondSize - 2), + bindingView.weatherSubLineTemperature to Preferences.textSecondSize, + ).forEach { + it.first.setTextSize(TypedValue.COMPLEX_UNIT_SP, it.second) + } + + // Icons scale + bindingView.subLineIcon.scaleX = Preferences.textSecondSize / 18f + bindingView.subLineIcon.scaleY = Preferences.textSecondSize / 18f + + bindingView.weatherSubLineWeatherIcon.scaleX = Preferences.textSecondSize / 18f + bindingView.weatherSubLineWeatherIcon.scaleY = Preferences.textSecondSize / 18f + + bindingView.weatherDateLineWeatherIcon.scaleX = ((Preferences.textMainSize + Preferences.textSecondSize) / 2) / 20f + bindingView.weatherDateLineWeatherIcon.scaleY = ((Preferences.textMainSize + Preferences.textSecondSize) / 2) / 20f + + bindingView.actionNext.scaleX = Preferences.textMainSize / 28f + bindingView.actionNext.scaleY = Preferences.textMainSize / 28f + + + // Shadows + val shadowRadius = + when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) { + 0 -> 0f + 1 -> 5f + 2 -> 5f + else -> 5f + } + val shadowColor = + when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) { + 0 -> Color.TRANSPARENT + 1 -> R.color.black_50 + 2 -> Color.BLACK + else -> R.color.black_50 + } + val shadowDy = + when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) { + 0 -> 0f + 1 -> 0f + 2 -> 1f + else -> 0f + } + + listOf( + bindingView.date, + bindingView.weatherDateLineTemperature, + bindingView.nextEvent, + bindingView.nextEventDifferenceTime, + bindingView.subLineText, + bindingView.weatherSubLineDivider, + bindingView.weatherSubLineTemperature, + ).forEach { + it.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor) + } + + // Icons shadow + + listOf( + Pair(bindingView.subLineIcon, bindingView.subLineIconShadow), + ).forEach { + if ((if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) == 0) { + it.second.isVisible = false + } else { + it.second.isVisible = it.first.isVisible + it.second.scaleX = it.first.scaleX + it.second.scaleY = it.first.scaleY + it.second.applyShadow(it.first) + } + } + + listOf( + Pair(bindingView.actionNext, bindingView.actionNextShadow), + ).forEach { + if ((if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) == 0) { + it.second.isVisible = false + } else { + it.second.isVisible = it.first.isVisible + it.second.scaleX = it.first.scaleX + it.second.scaleY = it.first.scaleY + it.second.applyShadow(it.first, 0.6f) + } + } + + // Custom Font + if (Preferences.customFont == Constants.CUSTOM_FONT_GOOGLE_SANS) { + val googleSans: Typeface = when (Preferences.customFontVariant) { + "100" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_thin.ttf") + "200" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_light.ttf") + "500" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_medium.ttf") + "700" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_bold.ttf") + "800" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_black.ttf") + else -> Typeface.createFromAsset(context.assets, "fonts/google_sans_regular.ttf") + } + + listOf( + bindingView.date, + bindingView.weatherDateLineTemperature, + bindingView.nextEvent, + bindingView.nextEventDifferenceTime, + bindingView.subLineText, + bindingView.weatherSubLineDivider, + bindingView.weatherSubLineTemperature, + ).forEach { + it.typeface = googleSans + } + } else if (Preferences.customFont == Constants.CUSTOM_FONT_DOWNLOADED && typeface != null) { + listOf( + bindingView.date, + bindingView.weatherDateLineTemperature, + bindingView.nextEvent, + bindingView.nextEventDifferenceTime, + bindingView.subLineText, + bindingView.weatherSubLineDivider, + bindingView.weatherSubLineTemperature, + ).forEach { + it.typeface = typeface + } + } + + // Dividers + arrayOf(bindingView.weatherSubLineDivider).forEach { + it.visibility = if (Preferences.showDividers) View.VISIBLE else View.INVISIBLE + it.layoutParams = (it.layoutParams as ViewGroup.MarginLayoutParams).apply { + this.marginEnd = if (Preferences.showDividers) 8f.convertDpToPixel(context).toInt() else 0 + } + } + + // Right Aligned + if (rightAligned) { + bindingView.mainContent.layoutParams = (bindingView.mainContent.layoutParams as RelativeLayout.LayoutParams).apply { + addRule(RelativeLayout.ALIGN_PARENT_END) + } + bindingView.mainContent.gravity = Gravity.END + bindingView.dateLayout.gravity = Gravity.END + bindingView.calendarLayout.gravity = Gravity.END or Gravity.CENTER_VERTICAL + bindingView.subLineContainer.gravity = Gravity.END or Gravity.CENTER_VERTICAL + } + + return bindingView + } catch (ex: Exception) { + ex.printStackTrace() + CrashlyticsReceiver.sendCrash(context, ex) + return null + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/ClockWidget.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/ClockWidget.kt index ea3f81e..44c750a 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/ClockWidget.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/ClockWidget.kt @@ -3,6 +3,7 @@ package com.tommasoberlose.anotherwidget.ui.widgets import android.app.PendingIntent import android.content.Context import android.util.TypedValue +import android.view.Gravity import android.view.View import android.widget.RemoteViews import com.tommasoberlose.anotherwidget.R diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/LeftAlignedWidget.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/LeftAlignedWidget.kt deleted file mode 100644 index 7ecf1e3..0000000 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/LeftAlignedWidget.kt +++ /dev/null @@ -1,892 +0,0 @@ -package com.tommasoberlose.anotherwidget.ui.widgets - -import android.Manifest -import android.app.PendingIntent -import android.content.Context -import android.content.Intent -import android.graphics.Color -import android.graphics.Typeface -import android.text.format.DateUtils -import android.util.Log -import android.util.TypedValue -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import android.widget.RemoteViews -import android.widget.TextView -import androidx.core.content.ContextCompat -import androidx.core.view.isVisible -import androidx.core.view.updateMargins -import com.tommasoberlose.anotherwidget.R -import com.tommasoberlose.anotherwidget.databinding.LeftAlignedWidgetBinding -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.* -import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue -import com.tommasoberlose.anotherwidget.helpers.ImageHelper.applyShadow -import com.tommasoberlose.anotherwidget.receivers.CrashlyticsReceiver -import com.tommasoberlose.anotherwidget.receivers.NewCalendarEventReceiver -import com.tommasoberlose.anotherwidget.receivers.WidgetClickListenerReceiver -import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission -import com.tommasoberlose.anotherwidget.utils.convertDpToPixel -import com.tommasoberlose.anotherwidget.utils.isDarkTheme -import java.text.DateFormat -import java.util.* -import java.util.concurrent.TimeUnit -import kotlin.math.roundToInt - -class LeftAlignedWidget(val context: Context) { - fun generateWidget(appWidgetId: Int, w: Int, typeface: Typeface? = null): RemoteViews { - - var views = RemoteViews(context.packageName, R.layout.left_aligned_widget_sans) - - try { - // Background - views.setInt( - R.id.widget_shape_background, - "setColorFilter", - ColorHelper.getBackgroundColorRgb(context.isDarkTheme()) - ) - views.setInt( - R.id.widget_shape_background, - "setImageAlpha", - ColorHelper.getBackgroundAlpha(context.isDarkTheme()) - ) - val refreshIntent = PendingIntent.getActivity( - context, - appWidgetId, - IntentHelper.getWidgetUpdateIntent(context), - PendingIntent.FLAG_UPDATE_CURRENT - ) - views.setOnClickPendingIntent(R.id.widget_shape_background, refreshIntent) - } catch (ex: Exception) { - ex.printStackTrace() - CrashlyticsReceiver.sendCrash(context, ex) - } - - // Clock - views = ClockWidget(context).updateClockView(views, appWidgetId) - - // Setup listener - try { - val generatedBinding = generateWidgetView(typeface) - views.setImageViewBitmap( - R.id.bitmap_container, - BitmapHelper.getBitmapFromView(generatedBinding.root, width = w) - ) - views = updateGridView(generatedBinding, views, appWidgetId) - } catch (ex: Exception) { - ex.printStackTrace() - CrashlyticsReceiver.sendCrash(context, ex) - } - - return views - } - - private fun updateGridView(bindingView: LeftAlignedWidgetBinding, views: RemoteViews, widgetID: Int): RemoteViews { - val eventRepository = EventRepository(context) - val nextEvent = eventRepository.getNextEvent() - val eventsCount = eventRepository.getEventsCount() - eventRepository.close() - - try { - // Weather - if (Preferences.showWeather && Preferences.weatherIcon != "") { - views.setViewVisibility(R.id.weather_rect, View.VISIBLE) - views.setViewVisibility(R.id.weather_sub_line, View.GONE) - - 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.weather_rect, weatherPIntent) - views.setOnClickPendingIntent(R.id.weather_sub_line_rect, weatherPIntent) - - views.setImageViewBitmap( - R.id.weather_rect, - BitmapHelper.getBitmapFromView(bindingView.weatherDateLine, draw = false) - ) - - views.setImageViewBitmap( - R.id.weather_sub_line_rect, - BitmapHelper.getBitmapFromView(bindingView.weatherSubLine, draw = false) - ) - } else { - views.setViewVisibility(R.id.weather_rect, View.GONE) - views.setViewVisibility(R.id.weather_sub_line, View.GONE) - } - - - // Calendar - views.setImageViewBitmap( - R.id.date_rect, - BitmapHelper.getBitmapFromView(bindingView.date, draw = false) - ) - - val calPIntent = PendingIntent.getActivity( - context, - widgetID, - IntentHelper.getCalendarIntent(context), - PendingIntent.FLAG_UPDATE_CURRENT - ) - views.setOnClickPendingIntent(R.id.date_rect, calPIntent) - views.setViewVisibility(R.id.first_line_rect, View.VISIBLE) - - val nextAlarm = AlarmHelper.getNextAlarm(context) - - // Spacing - views.setViewVisibility( - R.id.sub_line_top_margin_small_sans, - if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.rawValue) View.VISIBLE else View.GONE - ) - views.setViewVisibility( - R.id.sub_line_top_margin_medium_sans, - if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.rawValue) View.VISIBLE else View.GONE - ) - views.setViewVisibility( - R.id.sub_line_top_margin_large_sans, - if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.LARGE.rawValue) View.VISIBLE else View.GONE - ) - - if (Preferences.showEvents && context.checkGrantedPermission(Manifest.permission.READ_CALENDAR) && nextEvent != null && !Preferences.showEventsAsGlanceProvider) { - if (Preferences.showNextEvent && eventsCount > 1) { - - // Action next event - views.setImageViewBitmap( - R.id.action_next_rect, - BitmapHelper.getBitmapFromView(bindingView.actionNext, draw = false) - ) - views.setViewVisibility(R.id.action_next_rect, View.VISIBLE) - views.setOnClickPendingIntent( - R.id.action_next_rect, - PendingIntent.getBroadcast( - context, - widgetID, - Intent( - context, - NewCalendarEventReceiver::class.java - ).apply { action = Actions.ACTION_GO_TO_NEXT_EVENT }, - PendingIntent.FLAG_UPDATE_CURRENT - ) - ) - - views.setViewVisibility(R.id.action_next_rect, View.VISIBLE) - } else { - views.setViewVisibility(R.id.action_next_rect, View.GONE) - } - - // Event intent - val eventIntent = PendingIntent.getActivity( - context, - widgetID, - IntentHelper.getEventIntent(context, nextEvent), - PendingIntent.FLAG_UPDATE_CURRENT - ) - views.setOnClickPendingIntent(R.id.next_event_rect, eventIntent) - views.setViewVisibility(R.id.next_event_rect, View.VISIBLE) - - // Event time difference - if (Preferences.showDiffTime && Calendar.getInstance().timeInMillis < nextEvent.startDate) { - views.setImageViewBitmap( - R.id.next_event_difference_time_rect, - BitmapHelper.getBitmapFromView( - bindingView.nextEventDifferenceTime, - draw = false - ) - ) - - views.setOnClickPendingIntent(R.id.next_event_difference_time_rect, eventIntent) - views.setViewVisibility(R.id.next_event_difference_time_rect, View.VISIBLE) - } else { - views.setViewVisibility(R.id.next_event_difference_time_rect, View.GONE) - } - - // Event information - if (nextEvent.address != "" && Preferences.secondRowInformation == 1) { - val mapIntent = PendingIntent.getActivity( - context, - widgetID, - IntentHelper.getGoogleMapsIntentFromAddress(context, nextEvent.address), - PendingIntent.FLAG_UPDATE_CURRENT - ) - views.setOnClickPendingIntent(R.id.sub_line_rect, mapIntent) - } else { - val pIntentDetail = PendingIntent.getActivity( - context, - widgetID, - IntentHelper.getEventIntent( - context, - nextEvent, - forceEventDetails = true - ), - PendingIntent.FLAG_UPDATE_CURRENT - ) - views.setOnClickPendingIntent(R.id.sub_line_rect, pIntentDetail) - } - - views.setImageViewBitmap( - R.id.next_event_rect, - BitmapHelper.getBitmapFromView(bindingView.nextEvent, draw = false) - ) - views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE) - - views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE) - views.setViewVisibility(R.id.sub_line_rect, View.VISIBLE) - views.setViewVisibility(R.id.weather_sub_line_rect, View.VISIBLE) - views.setViewVisibility(R.id.first_line_rect, View.GONE) - - views.setViewVisibility(R.id.sub_line_top_margin_small_sans, View.GONE) - views.setViewVisibility(R.id.sub_line_top_margin_medium_sans, View.GONE) - views.setViewVisibility(R.id.sub_line_top_margin_large_sans, View.GONE) - } else if (GlanceProviderHelper.showGlanceProviders(context)) { - var showSomething = false - loop@ for (provider: Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders(context)) { - when (provider) { - Constants.GlanceProviderId.PLAYING_SONG -> { - if (MediaPlayerHelper.isSomeonePlaying(context)) { - val musicIntent = PendingIntent.getActivity( - context, - widgetID, - IntentHelper.getMusicIntent(context), - PendingIntent.FLAG_UPDATE_CURRENT - ) - views.setOnClickPendingIntent(R.id.sub_line_rect, musicIntent) - showSomething = true - break@loop - } - } - Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> { - if (Preferences.showNextAlarm && nextAlarm != "") { - val alarmIntent = PendingIntent.getActivity( - context, - widgetID, - IntentHelper.getClockIntent(context), - PendingIntent.FLAG_UPDATE_CURRENT - ) - views.setOnClickPendingIntent(R.id.sub_line_rect, alarmIntent) - showSomething = true - break@loop - } - } - Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> { - if (Preferences.showBatteryCharging) { - BatteryHelper.updateBatteryInfo(context) - if (Preferences.isCharging || Preferences.isBatteryLevelLow) { - val batteryIntent = PendingIntent.getActivity( - context, - widgetID, - IntentHelper.getBatteryIntent(), - PendingIntent.FLAG_UPDATE_CURRENT - ) - views.setOnClickPendingIntent(R.id.sub_line_rect, batteryIntent) - showSomething = true - break@loop - } - } - } - Constants.GlanceProviderId.CUSTOM_INFO -> { - if (Preferences.customNotes.isNotEmpty()) { - break@loop - } - } - Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> { - if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) { - val fitIntent = PendingIntent.getActivity( - context, - widgetID, - IntentHelper.getFitIntent(context), - PendingIntent.FLAG_UPDATE_CURRENT - ) - views.setOnClickPendingIntent(R.id.sub_line_rect, fitIntent) - showSomething = true - break@loop - } - } - Constants.GlanceProviderId.NOTIFICATIONS -> { - if (Preferences.showNotifications && ActiveNotificationsHelper.showLastNotification()) { - try { - if (Preferences.lastNotificationIcon != 0) { - val remotePackageContext = context.createPackageContext( - Preferences.lastNotificationPackage, 0) - ContextCompat.getDrawable( - remotePackageContext, - Preferences.lastNotificationIcon) - } - val notificationIntent = PendingIntent.getActivity( - context, - widgetID, - IntentHelper.getNotificationIntent(context), - PendingIntent.FLAG_UPDATE_CURRENT - ) - views.setOnClickPendingIntent( - R.id.sub_line_rect, - notificationIntent - ) - showSomething = true - break@loop - } catch (ex: Exception) {} - } - } - Constants.GlanceProviderId.GREETINGS -> { - if (Preferences.showGreetings && GreetingsHelper.showGreetings() && GreetingsHelper.getRandomString(context).isNotBlank()) { - showSomething = true - break@loop - } - } - Constants.GlanceProviderId.EVENTS -> { - if (Preferences.showEventsAsGlanceProvider&& Preferences.showEvents && context.checkGrantedPermission( - Manifest.permission.READ_CALENDAR) && nextEvent != null) { - val pIntentDetail = PendingIntent.getActivity( - context, - widgetID, - IntentHelper.getEventIntent( - context, - nextEvent, - forceEventDetails = true - ), - PendingIntent.FLAG_UPDATE_CURRENT - ) - views.setOnClickPendingIntent( - R.id.sub_line_rect, - pIntentDetail - ) - showSomething = 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.sub_line_rect, View.VISIBLE) - - views.setViewVisibility(R.id.calendar_layout_rect, View.GONE) - views.setViewVisibility(R.id.weather_sub_line_rect, View.GONE) - } else { - // Spacing - views.setViewVisibility(R.id.sub_line_top_margin_small_sans, View.GONE) - views.setViewVisibility(R.id.sub_line_top_margin_medium_sans, View.GONE) - views.setViewVisibility(R.id.sub_line_top_margin_large_sans, View.GONE) - } - } - - // Second row - views.setImageViewBitmap( - R.id.sub_line_rect, - BitmapHelper.getBitmapFromView(bindingView.subLine, draw = false) - ) - } catch (ex: Exception) { - ex.printStackTrace() - CrashlyticsReceiver.sendCrash(context, ex) - } - - return views - } - - - // Generates the widget bitmap from the view - fun generateWidgetView(typeface: Typeface? = null): LeftAlignedWidgetBinding { - val eventRepository = EventRepository(context) - val nextEvent = eventRepository.getNextEvent() - val eventsCount = eventRepository.getEventsCount() - eventRepository.close() - - val bindingView = LeftAlignedWidgetBinding.inflate(LayoutInflater.from(context)) - - bindingView.loader.isVisible = false - - // Weather - if (Preferences.showWeather && Preferences.weatherIcon != "") { - bindingView.weatherDateLine.isVisible = true - val currentTemp = String.format( - Locale.getDefault(), - "%d°%s", - Preferences.weatherTemp.roundToInt(), - Preferences.weatherRealTempUnit - ) - - val icon: String = Preferences.weatherIcon - if (icon == "") { - bindingView.weatherSubLineWeatherIcon.isVisible = false - bindingView.weatherDateLineWeatherIcon.isVisible = false - } else { - bindingView.weatherSubLineWeatherIcon.setImageResource(WeatherHelper.getWeatherIconResource(context, icon)) - bindingView.weatherDateLineWeatherIcon.setImageResource(WeatherHelper.getWeatherIconResource(context, icon)) - bindingView.weatherSubLineWeatherIcon.isVisible = true - bindingView.weatherDateLineWeatherIcon.isVisible = true - } - - bindingView.weatherDateLineTemperature.text = currentTemp - bindingView.weatherSubLineTemperature.text = currentTemp - - if (GlanceProviderHelper.showGlanceProviders(context)) { - bindingView.weatherSubLine.isVisible = false - } - } else { - bindingView.weatherDateLine.isVisible = false - bindingView.weatherSubLine.isVisible = false - } - - val now = Calendar.getInstance().apply { - set(Calendar.SECOND, 0) - set(Calendar.MILLISECOND, 0) - } - - bindingView.dateLayout.isVisible = true - bindingView.calendarLayout.isVisible = false - bindingView.nextEventDifferenceTime.isVisible = false - bindingView.actionNext.isVisible = false - - bindingView.date.text = DateHelper.getDateText(context, now) - - val nextAlarm = AlarmHelper.getNextAlarm(context) - - if (Preferences.showEvents && context.checkGrantedPermission(Manifest.permission.READ_CALENDAR) && nextEvent != null && !Preferences.showEventsAsGlanceProvider) { - // Multiple counter - bindingView.actionNext.isVisible = - Preferences.showNextEvent && eventsCount > 1 - - bindingView.nextEvent.text = nextEvent.title - - if (Preferences.showDiffTime && now.timeInMillis < nextEvent.startDate) { - bindingView.nextEventDifferenceTime.text = if (!nextEvent.allDay) { - SettingsStringHelper.getDifferenceText( - context, - now.timeInMillis, - nextEvent.startDate - ) - .toLowerCase(Locale.getDefault()) - } else { - SettingsStringHelper.getAllDayEventDifferenceText( - context, - now.timeInMillis, - nextEvent.startDate - ).toLowerCase(Locale.getDefault()) - } - bindingView.nextEventDifferenceTime.isVisible = true - } else { - bindingView.nextEventDifferenceTime.isVisible = false - } - - if (nextEvent.address != "" && Preferences.secondRowInformation == 1) { - bindingView.subLineIcon.setImageDrawable( - ContextCompat.getDrawable( - context, - R.drawable.round_place_24 - ) - ) - bindingView.subLineText.text = nextEvent.address - } else { - bindingView.subLineIcon.setImageDrawable( - ContextCompat.getDrawable( - context, - R.drawable.round_today_24 - ) - ) - if (!nextEvent.allDay) { - val startHour = - DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()) - .format(nextEvent.startDate) - val endHour = - DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()) - .format(nextEvent.endDate) - - var dayDiff = - TimeUnit.MILLISECONDS.toDays(nextEvent.endDate - nextEvent.startDate) - - val startCal = Calendar.getInstance() - startCal.timeInMillis = nextEvent.startDate - - val endCal = Calendar.getInstance() - endCal.timeInMillis = nextEvent.endDate - - if (startCal.get(Calendar.HOUR_OF_DAY) > endCal.get(Calendar.HOUR_OF_DAY)) { - dayDiff++ - } else if (startCal.get(Calendar.HOUR_OF_DAY) == endCal.get(Calendar.HOUR_OF_DAY) && startCal.get( - Calendar.MINUTE - ) > endCal.get(Calendar.MINUTE) - ) { - dayDiff++ - } - var multipleDay = "" - if (dayDiff > 0) { - multipleDay = String.format( - " (+%s%s)", - dayDiff, - context.getString(R.string.day_char) - ) - } - - if (nextEvent.startDate != nextEvent.endDate) { - bindingView.subLineText.text = - String.format("%s - %s%s", startHour, endHour, multipleDay) - } else { - bindingView.subLineText.text = - String.format("%s", startHour) - } - - } else { - val flags: Int = - DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NO_YEAR or DateUtils.FORMAT_ABBREV_MONTH - val start = Calendar.getInstance().apply { timeInMillis = nextEvent.startDate } - - bindingView.subLineText.text = if (now.get(Calendar.DAY_OF_YEAR) == start.get( - Calendar.DAY_OF_YEAR)) { - DateUtils.formatDateTime(context, nextEvent.startDate, flags) - } else if (now.get(Calendar.DAY_OF_YEAR) > start.get(Calendar.DAY_OF_YEAR) || now.get( - Calendar.YEAR) > start.get(Calendar.YEAR)) { - DateUtils.formatDateTime(context, now.timeInMillis, flags) - } else { - DateUtils.formatDateTime(context, nextEvent.startDate, flags) - } - } - } - - bindingView.dateLayout.isVisible = false - bindingView.calendarLayout.isVisible = true - bindingView.subLine.isVisible = true - bindingView.weatherSubLine.isVisible = true - - bindingView.subLineTopMarginSmall.visibility = View.GONE - bindingView.subLineTopMarginMedium.visibility = View.GONE - bindingView.subLineTopMarginLarge.visibility = View.GONE - } else if (GlanceProviderHelper.showGlanceProviders(context)) { - bindingView.subLineIcon.isVisible = true - var showSomething = false - loop@ for (provider: Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders( - context - )) { - when (provider) { - Constants.GlanceProviderId.PLAYING_SONG -> { - if (MediaPlayerHelper.isSomeonePlaying(context)) { - bindingView.subLineIcon.setImageDrawable( - ContextCompat.getDrawable( - context, - R.drawable.round_music_note_24 - ) - ) - bindingView.subLineText.text = MediaPlayerHelper.getMediaInfo() - showSomething = true - break@loop - } - } - Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> { - if (Preferences.showNextAlarm && nextAlarm != "") { - bindingView.subLineIcon.setImageDrawable( - ContextCompat.getDrawable( - context, - R.drawable.round_alarm_24 - ) - ) - bindingView.subLineText.text = AlarmHelper.getNextAlarm(context) - showSomething = true - break@loop - } - } - Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> { - if (Preferences.showBatteryCharging) { - BatteryHelper.updateBatteryInfo(context) - if (Preferences.isCharging) { - bindingView.subLineIcon.isVisible = false - val batteryLevel = BatteryHelper.getBatteryLevel(context) - if (batteryLevel != 100) { - bindingView.subLineText.text = context.getString(R.string.charging) - } else { - bindingView.subLineText.text = - context.getString(R.string.charged) - } - showSomething = true - break@loop - } else if (Preferences.isBatteryLevelLow) { - bindingView.subLineIcon.isVisible = false - bindingView.subLineText.text = - context.getString(R.string.battery_low_warning) - showSomething = true - break@loop - } - } - } - Constants.GlanceProviderId.CUSTOM_INFO -> { - if (Preferences.customNotes.isNotEmpty()) { - bindingView.subLineIcon.isVisible = false - bindingView.subLineText.text = Preferences.customNotes - bindingView.subLineText.maxLines = 2 - showSomething = true - break@loop - } - } - Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> { - if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) { - bindingView.subLineIcon.isVisible = false - bindingView.subLineText.text = - context.getString(R.string.daily_steps_counter) - .format(Preferences.googleFitSteps) - showSomething = true - break@loop - } - } - Constants.GlanceProviderId.NOTIFICATIONS -> { - if (Preferences.showNotifications && ActiveNotificationsHelper.showLastNotification()) { - try { - if (Preferences.lastNotificationIcon != 0) { - val remotePackageContext = context.createPackageContext( - Preferences.lastNotificationPackage, 0) - val icon = ContextCompat.getDrawable(remotePackageContext, - Preferences.lastNotificationIcon) - bindingView.subLineIcon.isVisible = true - bindingView.subLineIcon.setImageDrawable(icon) - } else { - bindingView.subLineIcon.isVisible = false - } - bindingView.subLineText.text = Preferences.lastNotificationTitle - showSomething = true - break@loop - } catch (ex: Exception) {} - } - } - Constants.GlanceProviderId.GREETINGS -> { - val greetingsText = GreetingsHelper.getRandomString(context) - if (Preferences.showGreetings && GreetingsHelper.showGreetings() && greetingsText.isNotBlank()) { - bindingView.subLineText.text = greetingsText - bindingView.subLineText.maxLines = 2 - bindingView.subLineIcon.isVisible = false - showSomething = true - break@loop - } - } - Constants.GlanceProviderId.EVENTS -> { - if (Preferences.showEventsAsGlanceProvider && Preferences.showEvents && context.checkGrantedPermission( - Manifest.permission.READ_CALENDAR) && nextEvent != null) { - bindingView.subLineText.text = context.getString(R.string.events_glance_provider_format).format(nextEvent.title, if (Preferences.showDiffTime && now.timeInMillis < nextEvent.startDate) { - if (!nextEvent.allDay) { - SettingsStringHelper.getDifferenceText( - context, - now.timeInMillis, - nextEvent.startDate - ) - .toLowerCase(Locale.getDefault()) - } else { - SettingsStringHelper.getAllDayEventDifferenceText( - context, - now.timeInMillis, - nextEvent.startDate - ).toLowerCase(Locale.getDefault()) - } - } else "").trimEnd() - bindingView.subLineIcon.isVisible = true - bindingView.subLineIcon.setImageDrawable( - ContextCompat.getDrawable( - context, - R.drawable.round_today_24 - ) - ) - showSomething = true - break@loop - } - } - } - } - - if (showSomething) { - bindingView.dateLayout.isVisible = true - bindingView.calendarLayout.isVisible = false - bindingView.subLine.isVisible = true - bindingView.weatherSubLine.isVisible = false - - bindingView.subLineTopMarginSmall.visibility = - if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.rawValue) View.VISIBLE else View.GONE - bindingView.subLineTopMarginMedium.visibility = - if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.rawValue) View.VISIBLE else View.GONE - bindingView.subLineTopMarginLarge.visibility = - if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.LARGE.rawValue) View.VISIBLE else View.GONE - } else { - bindingView.subLineIcon.isVisible = false - } - } - - - // Color - listOf( - bindingView.date, - bindingView.weatherDateLineTemperature, - bindingView.nextEvent, - bindingView.nextEventDifferenceTime, - ).forEach { - it.setTextColor(ColorHelper.getFontColor(context.applicationContext.isDarkTheme())) - } - - if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.rawValue) { - listOf(bindingView.actionNext) - } else { - listOf( - bindingView.actionNext, - bindingView.weatherDateLineWeatherIcon, - bindingView.weatherSubLineWeatherIcon - ) - }.forEach { - it.setColorFilter(ColorHelper.getFontColorRgb(context.applicationContext.isDarkTheme())) - it.alpha = - (if (context.isDarkTheme()) Preferences.textGlobalAlphaDark.toIntValue() - .toFloat() else Preferences.textGlobalAlpha.toIntValue() - .toFloat()) / 100 - } - - listOf(bindingView.subLineText, bindingView.weatherSubLineDivider, bindingView.weatherSubLineTemperature).forEach { - it.setTextColor(ColorHelper.getSecondaryFontColor(context.applicationContext.isDarkTheme())) - } - - if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.rawValue) { - listOf(bindingView.subLineIcon, bindingView.subLineIconShadow) - } else { - listOf(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 - listOf>( - bindingView.date to Preferences.textMainSize, - bindingView.weatherDateLineTemperature to ((Preferences.textMainSize + Preferences.textSecondSize) / 2), - bindingView.nextEvent to Preferences.textMainSize, - bindingView.nextEventDifferenceTime to Preferences.textMainSize, - bindingView.subLineText to Preferences.textSecondSize, - bindingView.weatherSubLineDivider to (Preferences.textSecondSize - 2), - bindingView.weatherSubLineTemperature to Preferences.textSecondSize, - ).forEach { - it.first.setTextSize(TypedValue.COMPLEX_UNIT_SP, it.second) - } - - // Icons scale - bindingView.subLineIcon.scaleX = Preferences.textSecondSize / 18f - bindingView.subLineIcon.scaleY = Preferences.textSecondSize / 18f - - bindingView.weatherSubLineWeatherIcon.scaleX = Preferences.textSecondSize / 18f - bindingView.weatherSubLineWeatherIcon.scaleY = Preferences.textSecondSize / 18f - - bindingView.weatherDateLineWeatherIcon.scaleX = ((Preferences.textMainSize + Preferences.textSecondSize) / 2) / 20f - bindingView.weatherDateLineWeatherIcon.scaleY = ((Preferences.textMainSize + Preferences.textSecondSize) / 2) / 20f - - bindingView.actionNext.scaleX = Preferences.textMainSize / 28f - bindingView.actionNext.scaleY = Preferences.textMainSize / 28f - - - // Shadows - val shadowRadius = - when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) { - 0 -> 0f - 1 -> 5f - 2 -> 5f - else -> 5f - } - val shadowColor = - when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) { - 0 -> Color.TRANSPARENT - 1 -> R.color.black_50 - 2 -> Color.BLACK - else -> R.color.black_50 - } - val shadowDy = - when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) { - 0 -> 0f - 1 -> 0f - 2 -> 1f - else -> 0f - } - - listOf( - bindingView.date, - bindingView.weatherDateLineTemperature, - bindingView.nextEvent, - bindingView.nextEventDifferenceTime, - bindingView.subLineText, - bindingView.weatherSubLineDivider, - bindingView.weatherSubLineTemperature, - ).forEach { - it.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor) - } - - // Icons shadow - - listOf( - Pair(bindingView.subLineIcon, bindingView.subLineIconShadow), - ).forEach { - if ((if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) == 0) { - it.second.isVisible = false - } else { - it.second.isVisible = it.first.isVisible - it.second.scaleX = it.first.scaleX - it.second.scaleY = it.first.scaleY - it.second.applyShadow(it.first) - } - } - - listOf( - Pair(bindingView.actionNext, bindingView.actionNextShadow), - ).forEach { - if ((if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) == 0) { - it.second.isVisible = false - } else { - it.second.isVisible = it.first.isVisible - it.second.scaleX = it.first.scaleX - it.second.scaleY = it.first.scaleY - it.second.applyShadow(it.first, 0.6f) - } - } - - // Custom Font - if (Preferences.customFont == Constants.CUSTOM_FONT_GOOGLE_SANS) { - val googleSans: Typeface = when (Preferences.customFontVariant) { - "100" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_thin.ttf") - "200" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_light.ttf") - "500" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_medium.ttf") - "700" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_bold.ttf") - "800" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_black.ttf") - else -> Typeface.createFromAsset(context.assets, "fonts/google_sans_regular.ttf") - } - - listOf( - bindingView.date, - bindingView.weatherDateLineTemperature, - bindingView.nextEvent, - bindingView.nextEventDifferenceTime, - bindingView.subLineText, - bindingView.weatherSubLineDivider, - bindingView.weatherSubLineTemperature, - ).forEach { - it.typeface = googleSans - } - } else if (Preferences.customFont == Constants.CUSTOM_FONT_DOWNLOADED && typeface != null) { - listOf( - bindingView.date, - bindingView.weatherDateLineTemperature, - bindingView.nextEvent, - bindingView.nextEventDifferenceTime, - bindingView.subLineText, - bindingView.weatherSubLineDivider, - bindingView.weatherSubLineTemperature, - ).forEach { - it.typeface = typeface - } - } - - // Dividers - arrayOf(bindingView.weatherSubLineDivider).forEach { - it.visibility = if (Preferences.showDividers) View.VISIBLE else View.INVISIBLE - it.layoutParams = (it.layoutParams as ViewGroup.MarginLayoutParams).apply { - this.marginEnd = if (Preferences.showDividers) 8f.convertDpToPixel(context).toInt() else 0 - } - } - - return bindingView - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/MainWidget.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/MainWidget.kt index ef013d5..05afdd9 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/MainWidget.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/MainWidget.kt @@ -1,47 +1,19 @@ package com.tommasoberlose.anotherwidget.ui.widgets -import android.Manifest -import android.app.PendingIntent import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetProvider import android.content.ComponentName import android.content.Context -import android.content.Intent import android.content.res.Resources -import android.graphics.Color import android.graphics.Typeface import android.os.Bundle -import android.text.format.DateUtils -import android.util.TypedValue -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import android.widget.RemoteViews -import android.widget.TextView -import androidx.core.content.ContextCompat -import androidx.core.view.isVisible import androidx.viewbinding.ViewBinding -import com.tommasoberlose.anotherwidget.R -import com.tommasoberlose.anotherwidget.databinding.LeftAlignedWidgetBinding -import com.tommasoberlose.anotherwidget.databinding.TheWidgetBinding -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.* -import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue -import com.tommasoberlose.anotherwidget.helpers.ImageHelper.applyShadow import com.tommasoberlose.anotherwidget.receivers.* -import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission -import com.tommasoberlose.anotherwidget.utils.convertDpToPixel -import com.tommasoberlose.anotherwidget.utils.isDarkTheme import com.tommasoberlose.anotherwidget.utils.toPixel -import java.text.DateFormat -import java.util.* -import java.util.concurrent.TimeUnit import kotlin.math.min -import kotlin.math.roundToInt class MainWidget : AppWidgetProvider() { @@ -98,16 +70,18 @@ class MainWidget : AppWidgetProvider() { WidgetHelper.runWithCustomTypeface(context) { val views = when (Preferences.widgetAlign) { - Constants.WidgetAlign.LEFT.rawValue -> LeftAlignedWidget(context).generateWidget(appWidgetId, min(dimensions.first - 8.toPixel(context), min(width, height) - 16.toPixel(context)), it) + Constants.WidgetAlign.LEFT.rawValue -> AlignedWidget(context).generateWidget(appWidgetId, min(dimensions.first - 8.toPixel(context), min(width, height) - 16.toPixel(context)), it) + Constants.WidgetAlign.RIGHT.rawValue -> AlignedWidget(context, rightAligned = true).generateWidget(appWidgetId, min(dimensions.first - 8.toPixel(context), min(width, height) - 16.toPixel(context)), it) else -> StandardWidget(context).generateWidget(appWidgetId, min(dimensions.first - 8.toPixel(context), min(width, height) - 16.toPixel(context)), it) } - appWidgetManager.updateAppWidget(appWidgetId, views) + if (views != null) appWidgetManager.updateAppWidget(appWidgetId, views) } } - fun getWidgetView(context: Context, typeface: Typeface?): ViewBinding { + fun getWidgetView(context: Context, typeface: Typeface?): ViewBinding? { return when (Preferences.widgetAlign) { - Constants.WidgetAlign.LEFT.rawValue -> LeftAlignedWidget(context).generateWidgetView(typeface) + Constants.WidgetAlign.LEFT.rawValue -> AlignedWidget(context).generateWidgetView(typeface) + Constants.WidgetAlign.RIGHT.rawValue -> AlignedWidget(context, rightAligned = true).generateWidgetView(typeface) else -> StandardWidget(context).generateWidgetView(typeface) } } diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/StandardWidget.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/StandardWidget.kt index 19fa1f8..918d88c 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/StandardWidget.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/StandardWidget.kt @@ -40,7 +40,7 @@ import java.util.concurrent.TimeUnit import kotlin.math.roundToInt class StandardWidget(val context: Context) { - fun generateWidget(appWidgetId: Int, w: Int, typeface: Typeface? = null): RemoteViews { + fun generateWidget(appWidgetId: Int, w: Int, typeface: Typeface? = null): RemoteViews? { var views = RemoteViews(context.packageName, R.layout.the_widget_sans) @@ -73,7 +73,8 @@ class StandardWidget(val context: Context) { // Setup listener try { - val generatedBinding = generateWidgetView(typeface) + val generatedBinding = generateWidgetView(typeface) ?: return null + views.setImageViewBitmap( R.id.bitmap_container, BitmapHelper.getBitmapFromView(generatedBinding.root, width = w) @@ -88,12 +89,12 @@ class StandardWidget(val context: Context) { } private fun updateGridView(bindingView: TheWidgetBinding, views: RemoteViews, widgetID: Int): RemoteViews { - val eventRepository = EventRepository(context) - val nextEvent = eventRepository.getNextEvent() - val eventsCount = eventRepository.getEventsCount() - eventRepository.close() - try { + val eventRepository = EventRepository(context) + val nextEvent = eventRepository.getNextEvent() + val eventsCount = eventRepository.getEventsCount() + eventRepository.close() + // Weather if (Preferences.showWeather && Preferences.weatherIcon != "") { views.setViewVisibility(R.id.weather_rect, View.VISIBLE) @@ -412,319 +413,171 @@ class StandardWidget(val context: Context) { // Generates the widget bitmap from the view - fun generateWidgetView(typeface: Typeface? = null): TheWidgetBinding { - val eventRepository = EventRepository(context) - val nextEvent = eventRepository.getNextEvent() - val eventsCount = eventRepository.getEventsCount() - eventRepository.close() + fun generateWidgetView(typeface: Typeface? = null): TheWidgetBinding? { + try { + val eventRepository = EventRepository(context) + val nextEvent = eventRepository.getNextEvent() + val eventsCount = eventRepository.getEventsCount() + eventRepository.close() - val bindingView = TheWidgetBinding.inflate(LayoutInflater.from(context)) + val bindingView = TheWidgetBinding.inflate(LayoutInflater.from(context)) - bindingView.loader.isVisible = false + bindingView.loader.isVisible = false - // Weather - if (Preferences.showWeather && Preferences.weatherIcon != "") { - bindingView.weatherDateLine.isVisible = true - val currentTemp = String.format( - Locale.getDefault(), - "%d°%s", - Preferences.weatherTemp.roundToInt(), - Preferences.weatherRealTempUnit - ) + // Weather + if (Preferences.showWeather && Preferences.weatherIcon != "") { + bindingView.weatherDateLine.isVisible = true + val currentTemp = String.format( + Locale.getDefault(), + "%d°%s", + Preferences.weatherTemp.roundToInt(), + Preferences.weatherRealTempUnit + ) - val icon: String = Preferences.weatherIcon - if (icon == "") { - bindingView.weatherSubLineWeatherIcon.isVisible = false - bindingView.weatherDateLineWeatherIcon.isVisible = false + val icon: String = Preferences.weatherIcon + if (icon == "") { + bindingView.weatherSubLineWeatherIcon.isVisible = false + bindingView.weatherDateLineWeatherIcon.isVisible = false + } else { + bindingView.weatherSubLineWeatherIcon.setImageResource(WeatherHelper.getWeatherIconResource(context, icon)) + bindingView.weatherDateLineWeatherIcon.setImageResource(WeatherHelper.getWeatherIconResource(context, icon)) + bindingView.weatherSubLineWeatherIcon.isVisible = true + bindingView.weatherDateLineWeatherIcon.isVisible = true + } + + bindingView.weatherDateLineTemperature.text = currentTemp + bindingView.weatherSubLineTemperature.text = currentTemp + + if (GlanceProviderHelper.showGlanceProviders(context)) { + bindingView.weatherSubLine.isVisible = false + } } else { - bindingView.weatherSubLineWeatherIcon.setImageResource(WeatherHelper.getWeatherIconResource(context, icon)) - bindingView.weatherDateLineWeatherIcon.setImageResource(WeatherHelper.getWeatherIconResource(context, icon)) - bindingView.weatherSubLineWeatherIcon.isVisible = true - bindingView.weatherDateLineWeatherIcon.isVisible = true - } - - bindingView.weatherDateLineTemperature.text = currentTemp - bindingView.weatherSubLineTemperature.text = currentTemp - - if (GlanceProviderHelper.showGlanceProviders(context)) { + bindingView.weatherDateLine.isVisible = false bindingView.weatherSubLine.isVisible = false } - } else { - bindingView.weatherDateLine.isVisible = false - bindingView.weatherSubLine.isVisible = false - } - val now = Calendar.getInstance().apply { - set(Calendar.SECOND, 0) - set(Calendar.MILLISECOND, 0) - } - - bindingView.dateLayout.isVisible = true - bindingView.calendarLayout.isVisible = false - bindingView.nextEventDifferenceTime.isVisible = false - bindingView.actionNext.isVisible = false - bindingView.actionPrevious.isVisible = false - - bindingView.date.text = DateHelper.getDateText(context, now) - - val nextAlarm = AlarmHelper.getNextAlarm(context) - - if (Preferences.showEvents && context.checkGrantedPermission(Manifest.permission.READ_CALENDAR) && nextEvent != null && !Preferences.showEventsAsGlanceProvider) { - // Multiple counter - bindingView.actionNext.isVisible = - Preferences.showNextEvent && eventsCount > 1 - bindingView.actionPrevious.isVisible = - Preferences.showNextEvent && eventsCount > 1 - - bindingView.nextEvent.text = nextEvent.title - - if (Preferences.showDiffTime && now.timeInMillis < nextEvent.startDate) { - bindingView.nextEventDifferenceTime.text = if (!nextEvent.allDay) { - SettingsStringHelper.getDifferenceText( - context, - now.timeInMillis, - nextEvent.startDate - ) - .toLowerCase(Locale.getDefault()) - } else { - SettingsStringHelper.getAllDayEventDifferenceText( - context, - now.timeInMillis, - nextEvent.startDate - ).toLowerCase(Locale.getDefault()) - } - bindingView.nextEventDifferenceTime.isVisible = true - } else { - bindingView.nextEventDifferenceTime.isVisible = false + val now = Calendar.getInstance().apply { + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) } - if (nextEvent.address != "" && Preferences.secondRowInformation == 1) { - bindingView.subLineIcon.setImageDrawable( - ContextCompat.getDrawable( - context, - R.drawable.round_place_24 - ) - ) - bindingView.subLineText.text = nextEvent.address - } else { - bindingView.subLineIcon.setImageDrawable( - ContextCompat.getDrawable( - context, - R.drawable.round_today_24 - ) - ) - if (!nextEvent.allDay) { - val startHour = - DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()) - .format(nextEvent.startDate) - val endHour = - DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()) - .format(nextEvent.endDate) + bindingView.dateLayout.isVisible = true + bindingView.calendarLayout.isVisible = false + bindingView.nextEventDifferenceTime.isVisible = false + bindingView.actionNext.isVisible = false + bindingView.actionPrevious.isVisible = false - var dayDiff = - TimeUnit.MILLISECONDS.toDays(nextEvent.endDate - nextEvent.startDate) + bindingView.date.text = DateHelper.getDateText(context, now) - val startCal = Calendar.getInstance() - startCal.timeInMillis = nextEvent.startDate + val nextAlarm = AlarmHelper.getNextAlarm(context) - val endCal = Calendar.getInstance() - endCal.timeInMillis = nextEvent.endDate + if (Preferences.showEvents && context.checkGrantedPermission(Manifest.permission.READ_CALENDAR) && nextEvent != null && !Preferences.showEventsAsGlanceProvider) { + // Multiple counter + bindingView.actionNext.isVisible = + Preferences.showNextEvent && eventsCount > 1 + bindingView.actionPrevious.isVisible = + Preferences.showNextEvent && eventsCount > 1 - if (startCal.get(Calendar.HOUR_OF_DAY) > endCal.get(Calendar.HOUR_OF_DAY)) { - dayDiff++ - } else if (startCal.get(Calendar.HOUR_OF_DAY) == endCal.get(Calendar.HOUR_OF_DAY) && startCal.get( - Calendar.MINUTE - ) > endCal.get(Calendar.MINUTE) - ) { - dayDiff++ - } - var multipleDay = "" - if (dayDiff > 0) { - multipleDay = String.format( - " (+%s%s)", - dayDiff, - context.getString(R.string.day_char) + bindingView.nextEvent.text = nextEvent.title + + if (Preferences.showDiffTime && now.timeInMillis < nextEvent.startDate) { + bindingView.nextEventDifferenceTime.text = if (!nextEvent.allDay) { + SettingsStringHelper.getDifferenceText( + context, + now.timeInMillis, + nextEvent.startDate ) - } - - if (nextEvent.startDate != nextEvent.endDate) { - bindingView.subLineText.text = - String.format("%s - %s%s", startHour, endHour, multipleDay) + .toLowerCase(Locale.getDefault()) } else { - bindingView.subLineText.text = - String.format("%s", startHour) + SettingsStringHelper.getAllDayEventDifferenceText( + context, + now.timeInMillis, + nextEvent.startDate + ).toLowerCase(Locale.getDefault()) } - + bindingView.nextEventDifferenceTime.isVisible = true } else { - val flags: Int = - DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NO_YEAR or DateUtils.FORMAT_ABBREV_MONTH - val start = Calendar.getInstance().apply { timeInMillis = nextEvent.startDate } - - bindingView.subLineText.text = if (now.get(Calendar.DAY_OF_YEAR) == start.get( - Calendar.DAY_OF_YEAR)) { - DateUtils.formatDateTime(context, nextEvent.startDate, flags) - } else if (now.get(Calendar.DAY_OF_YEAR) > start.get(Calendar.DAY_OF_YEAR) || now.get( - Calendar.YEAR) > start.get(Calendar.YEAR)) { - DateUtils.formatDateTime(context, now.timeInMillis, flags) - } else { - DateUtils.formatDateTime(context, nextEvent.startDate, flags) - } + bindingView.nextEventDifferenceTime.isVisible = false } - } - bindingView.dateLayout.isVisible = false - bindingView.calendarLayout.isVisible = true - bindingView.subLine.isVisible = true - bindingView.weatherSubLine.isVisible = true + if (nextEvent.address != "" && Preferences.secondRowInformation == 1) { + bindingView.subLineIcon.setImageDrawable( + ContextCompat.getDrawable( + context, + R.drawable.round_place_24 + ) + ) + bindingView.subLineText.text = nextEvent.address + } else { + bindingView.subLineIcon.setImageDrawable( + ContextCompat.getDrawable( + context, + R.drawable.round_today_24 + ) + ) + if (!nextEvent.allDay) { + val startHour = + DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()) + .format(nextEvent.startDate) + val endHour = + DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()) + .format(nextEvent.endDate) - bindingView.subLineTopMarginSmall.visibility = - if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.rawValue) View.VISIBLE else View.GONE - bindingView.subLineTopMarginMedium.visibility = - if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.rawValue) View.VISIBLE else View.GONE - bindingView.subLineTopMarginLarge.visibility = - if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.LARGE.rawValue) View.VISIBLE else View.GONE - } else if (GlanceProviderHelper.showGlanceProviders(context)) { - bindingView.subLineIcon.isVisible = true - var showSomething = false - loop@ for (provider: Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders( - context - )) { - when (provider) { - Constants.GlanceProviderId.PLAYING_SONG -> { - if (MediaPlayerHelper.isSomeonePlaying(context)) { - bindingView.subLineIcon.setImageDrawable( - ContextCompat.getDrawable( - context, - R.drawable.round_music_note_24 - ) + var dayDiff = + TimeUnit.MILLISECONDS.toDays(nextEvent.endDate - nextEvent.startDate) + + val startCal = Calendar.getInstance() + startCal.timeInMillis = nextEvent.startDate + + val endCal = Calendar.getInstance() + endCal.timeInMillis = nextEvent.endDate + + if (startCal.get(Calendar.HOUR_OF_DAY) > endCal.get(Calendar.HOUR_OF_DAY)) { + dayDiff++ + } else if (startCal.get(Calendar.HOUR_OF_DAY) == endCal.get(Calendar.HOUR_OF_DAY) && startCal.get( + Calendar.MINUTE + ) > endCal.get(Calendar.MINUTE) + ) { + dayDiff++ + } + var multipleDay = "" + if (dayDiff > 0) { + multipleDay = String.format( + " (+%s%s)", + dayDiff, + context.getString(R.string.day_char) ) - bindingView.subLineText.text = MediaPlayerHelper.getMediaInfo() - showSomething = true - break@loop } - } - Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> { - if (Preferences.showNextAlarm && nextAlarm != "") { - bindingView.subLineIcon.setImageDrawable( - ContextCompat.getDrawable( - context, - R.drawable.round_alarm_24 - ) - ) - bindingView.subLineText.text = AlarmHelper.getNextAlarm(context) - showSomething = true - break@loop - } - } - Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> { - if (Preferences.showBatteryCharging) { - BatteryHelper.updateBatteryInfo(context) - if (Preferences.isCharging) { - bindingView.subLineIcon.isVisible = false - val batteryLevel = BatteryHelper.getBatteryLevel(context) - if (batteryLevel != 100) { - bindingView.subLineText.text = context.getString(R.string.charging) - } else { - bindingView.subLineText.text = - context.getString(R.string.charged) - } - showSomething = true - break@loop - } else if (Preferences.isBatteryLevelLow) { - bindingView.subLineIcon.isVisible = false - bindingView.subLineText.text = - context.getString(R.string.battery_low_warning) - showSomething = true - break@loop - } - } - } - Constants.GlanceProviderId.CUSTOM_INFO -> { - if (Preferences.customNotes.isNotEmpty()) { - bindingView.subLineIcon.isVisible = false - bindingView.subLineText.text = Preferences.customNotes - bindingView.subLineText.maxLines = 2 - showSomething = true - break@loop - } - } - Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> { - if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) { - bindingView.subLineIcon.isVisible = false + + if (nextEvent.startDate != nextEvent.endDate) { bindingView.subLineText.text = - context.getString(R.string.daily_steps_counter) - .format(Preferences.googleFitSteps) - showSomething = true - break@loop + String.format("%s - %s%s", startHour, endHour, multipleDay) + } else { + bindingView.subLineText.text = + String.format("%s", startHour) } - } - Constants.GlanceProviderId.NOTIFICATIONS -> { - if (Preferences.showNotifications && ActiveNotificationsHelper.showLastNotification()) { - try { - if (Preferences.lastNotificationIcon != 0) { - val remotePackageContext = context.createPackageContext( - Preferences.lastNotificationPackage, 0) - val icon = ContextCompat.getDrawable(remotePackageContext, - Preferences.lastNotificationIcon) - bindingView.subLineIcon.isVisible = true - bindingView.subLineIcon.setImageDrawable(icon) - } else { - bindingView.subLineIcon.isVisible = false - } - bindingView.subLineText.text = Preferences.lastNotificationTitle - showSomething = true - break@loop - } catch (ex: Exception) {} - } - } - Constants.GlanceProviderId.GREETINGS -> { - val greetingsText = GreetingsHelper.getRandomString(context) - if (Preferences.showGreetings && GreetingsHelper.showGreetings() && greetingsText.isNotBlank()) { - bindingView.subLineText.text = greetingsText - bindingView.subLineText.maxLines = 2 - bindingView.subLineIcon.isVisible = false - showSomething = true - break@loop - } - } - Constants.GlanceProviderId.EVENTS -> { - if (Preferences.showEventsAsGlanceProvider && Preferences.showEvents && context.checkGrantedPermission( - Manifest.permission.READ_CALENDAR) && nextEvent != null) { - bindingView.subLineText.text = context.getString(R.string.events_glance_provider_format).format(nextEvent.title, if (Preferences.showDiffTime && now.timeInMillis < nextEvent.startDate) { - if (!nextEvent.allDay) { - SettingsStringHelper.getDifferenceText( - context, - now.timeInMillis, - nextEvent.startDate - ) - .toLowerCase(Locale.getDefault()) - } else { - SettingsStringHelper.getAllDayEventDifferenceText( - context, - now.timeInMillis, - nextEvent.startDate - ).toLowerCase(Locale.getDefault()) - } - } else "").trimEnd() - bindingView.subLineIcon.isVisible = true - bindingView.subLineIcon.setImageDrawable( - ContextCompat.getDrawable( - context, - R.drawable.round_today_24 - ) - ) - showSomething = true - break@loop + + } else { + val flags: Int = + DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NO_YEAR or DateUtils.FORMAT_ABBREV_MONTH + val start = Calendar.getInstance().apply { timeInMillis = nextEvent.startDate } + + bindingView.subLineText.text = if (now.get(Calendar.DAY_OF_YEAR) == start.get( + Calendar.DAY_OF_YEAR)) { + DateUtils.formatDateTime(context, nextEvent.startDate, flags) + } else if (now.get(Calendar.DAY_OF_YEAR) > start.get(Calendar.DAY_OF_YEAR) || now.get( + Calendar.YEAR) > start.get(Calendar.YEAR)) { + DateUtils.formatDateTime(context, now.timeInMillis, flags) + } else { + DateUtils.formatDateTime(context, nextEvent.startDate, flags) } } } - } - if (showSomething) { - bindingView.dateLayout.isVisible = true - bindingView.calendarLayout.isVisible = false + bindingView.dateLayout.isVisible = false + bindingView.calendarLayout.isVisible = true bindingView.subLine.isVisible = true - bindingView.weatherSubLine.isVisible = false + bindingView.weatherSubLine.isVisible = true bindingView.subLineTopMarginSmall.visibility = if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.rawValue) View.VISIBLE else View.GONE @@ -732,165 +585,258 @@ class StandardWidget(val context: Context) { if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.rawValue) View.VISIBLE else View.GONE bindingView.subLineTopMarginLarge.visibility = if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.LARGE.rawValue) View.VISIBLE else View.GONE + } else if (GlanceProviderHelper.showGlanceProviders(context)) { + bindingView.subLineIcon.isVisible = true + var showSomething = false + loop@ for (provider: Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders( + context + )) { + when (provider) { + Constants.GlanceProviderId.PLAYING_SONG -> { + if (MediaPlayerHelper.isSomeonePlaying(context)) { + bindingView.subLineIcon.setImageDrawable( + ContextCompat.getDrawable( + context, + R.drawable.round_music_note_24 + ) + ) + bindingView.subLineText.text = MediaPlayerHelper.getMediaInfo() + showSomething = true + break@loop + } + } + Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> { + if (Preferences.showNextAlarm && nextAlarm != "") { + bindingView.subLineIcon.setImageDrawable( + ContextCompat.getDrawable( + context, + R.drawable.round_alarm_24 + ) + ) + bindingView.subLineText.text = AlarmHelper.getNextAlarm(context) + showSomething = true + break@loop + } + } + Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> { + if (Preferences.showBatteryCharging) { + BatteryHelper.updateBatteryInfo(context) + if (Preferences.isCharging) { + bindingView.subLineIcon.isVisible = false + val batteryLevel = BatteryHelper.getBatteryLevel(context) + if (batteryLevel != 100) { + bindingView.subLineText.text = context.getString(R.string.charging) + } else { + bindingView.subLineText.text = + context.getString(R.string.charged) + } + showSomething = true + break@loop + } else if (Preferences.isBatteryLevelLow) { + bindingView.subLineIcon.isVisible = false + bindingView.subLineText.text = + context.getString(R.string.battery_low_warning) + showSomething = true + break@loop + } + } + } + Constants.GlanceProviderId.CUSTOM_INFO -> { + if (Preferences.customNotes.isNotEmpty()) { + bindingView.subLineIcon.isVisible = false + bindingView.subLineText.text = Preferences.customNotes + bindingView.subLineText.maxLines = 2 + showSomething = true + break@loop + } + } + Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> { + if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) { + bindingView.subLineIcon.isVisible = false + bindingView.subLineText.text = + context.getString(R.string.daily_steps_counter) + .format(Preferences.googleFitSteps) + showSomething = true + break@loop + } + } + Constants.GlanceProviderId.NOTIFICATIONS -> { + if (Preferences.showNotifications && ActiveNotificationsHelper.showLastNotification()) { + try { + if (Preferences.lastNotificationIcon != 0) { + val remotePackageContext = context.createPackageContext( + Preferences.lastNotificationPackage, 0) + val icon = ContextCompat.getDrawable(remotePackageContext, + Preferences.lastNotificationIcon) + bindingView.subLineIcon.isVisible = true + bindingView.subLineIcon.setImageDrawable(icon) + } else { + bindingView.subLineIcon.isVisible = false + } + bindingView.subLineText.text = Preferences.lastNotificationTitle + showSomething = true + break@loop + } catch (ex: Exception) {} + } + } + Constants.GlanceProviderId.GREETINGS -> { + val greetingsText = GreetingsHelper.getRandomString(context) + if (Preferences.showGreetings && GreetingsHelper.showGreetings() && greetingsText.isNotBlank()) { + bindingView.subLineText.text = greetingsText + bindingView.subLineText.maxLines = 2 + bindingView.subLineIcon.isVisible = false + showSomething = true + break@loop + } + } + Constants.GlanceProviderId.EVENTS -> { + if (Preferences.showEventsAsGlanceProvider && Preferences.showEvents && context.checkGrantedPermission( + Manifest.permission.READ_CALENDAR) && nextEvent != null) { + bindingView.subLineText.text = context.getString(R.string.events_glance_provider_format).format(nextEvent.title, if (Preferences.showDiffTime && now.timeInMillis < nextEvent.startDate) { + if (!nextEvent.allDay) { + SettingsStringHelper.getDifferenceText( + context, + now.timeInMillis, + nextEvent.startDate + ) + .toLowerCase(Locale.getDefault()) + } else { + SettingsStringHelper.getAllDayEventDifferenceText( + context, + now.timeInMillis, + nextEvent.startDate + ).toLowerCase(Locale.getDefault()) + } + } else "").trimEnd() + bindingView.subLineIcon.isVisible = true + bindingView.subLineIcon.setImageDrawable( + ContextCompat.getDrawable( + context, + R.drawable.round_today_24 + ) + ) + showSomething = true + break@loop + } + } + } + } + + if (showSomething) { + bindingView.dateLayout.isVisible = true + bindingView.calendarLayout.isVisible = false + bindingView.subLine.isVisible = true + bindingView.weatherSubLine.isVisible = false + + bindingView.subLineTopMarginSmall.visibility = + if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.rawValue) View.VISIBLE else View.GONE + bindingView.subLineTopMarginMedium.visibility = + if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.rawValue) View.VISIBLE else View.GONE + bindingView.subLineTopMarginLarge.visibility = + if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.LARGE.rawValue) View.VISIBLE else View.GONE + } else { + bindingView.subLineIcon.isVisible = false + } + } + + + // Color + listOf( + bindingView.date, + bindingView.weatherDateLineDivider, + bindingView.weatherDateLineTemperature, + bindingView.nextEvent, + bindingView.nextEventDifferenceTime, + ).forEach { + it.setTextColor(ColorHelper.getFontColor(context.applicationContext.isDarkTheme())) + } + + if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.rawValue) { + listOf(bindingView.actionNext, bindingView.actionPrevious) } else { - bindingView.subLineIcon.isVisible = false - } - } - - - // Color - listOf( - bindingView.date, - bindingView.weatherDateLineDivider, - bindingView.weatherDateLineTemperature, - bindingView.nextEvent, - bindingView.nextEventDifferenceTime, - ).forEach { - it.setTextColor(ColorHelper.getFontColor(context.applicationContext.isDarkTheme())) - } - - if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.rawValue) { - listOf(bindingView.actionNext, bindingView.actionPrevious) - } else { - listOf( - bindingView.actionNext, - bindingView.actionPrevious, - bindingView.weatherDateLineWeatherIcon, - bindingView.weatherSubLineWeatherIcon - ) - }.forEach { - it.setColorFilter(ColorHelper.getFontColorRgb(context.applicationContext.isDarkTheme())) - it.alpha = - (if (context.isDarkTheme()) Preferences.textGlobalAlphaDark.toIntValue() - .toFloat() else Preferences.textGlobalAlpha.toIntValue() - .toFloat()) / 100 - } - - listOf(bindingView.subLineText, bindingView.weatherSubLineDivider, bindingView.weatherSubLineTemperature).forEach { - it.setTextColor(ColorHelper.getSecondaryFontColor(context.applicationContext.isDarkTheme())) - } - - if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.rawValue) { - listOf(bindingView.subLineIcon, bindingView.subLineIconShadow) - } else { - listOf(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 - listOf>( - bindingView.date to Preferences.textMainSize, - bindingView.weatherDateLineDivider to (Preferences.textMainSize - 2), - bindingView.weatherDateLineTemperature to Preferences.textMainSize, - bindingView.nextEvent to Preferences.textMainSize, - bindingView.nextEventDifferenceTime to Preferences.textMainSize, - bindingView.subLineText to Preferences.textSecondSize, - bindingView.weatherSubLineDivider to (Preferences.textSecondSize - 2), - bindingView.weatherSubLineTemperature to Preferences.textSecondSize, - ).forEach { - it.first.setTextSize(TypedValue.COMPLEX_UNIT_SP, it.second) - } - - // Icons scale - bindingView.subLineIcon.scaleX = Preferences.textSecondSize / 18f - bindingView.subLineIcon.scaleY = Preferences.textSecondSize / 18f - - bindingView.weatherSubLineWeatherIcon.scaleX = Preferences.textSecondSize / 18f - bindingView.weatherSubLineWeatherIcon.scaleY = Preferences.textSecondSize / 18f - - bindingView.weatherDateLineWeatherIcon.scaleX = Preferences.textMainSize / 18f - bindingView.weatherDateLineWeatherIcon.scaleY = Preferences.textMainSize / 18f - - bindingView.actionNext.scaleX = Preferences.textMainSize / 28f - bindingView.actionNext.scaleY = Preferences.textMainSize / 28f - - bindingView.actionPrevious.scaleX = Preferences.textMainSize / 28f - bindingView.actionPrevious.scaleY = Preferences.textMainSize / 28f - - - // Shadows - val shadowRadius = - when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) { - 0 -> 0f - 1 -> 5f - 2 -> 5f - else -> 5f - } - val shadowColor = - when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) { - 0 -> Color.TRANSPARENT - 1 -> R.color.black_50 - 2 -> Color.BLACK - else -> R.color.black_50 - } - val shadowDy = - when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) { - 0 -> 0f - 1 -> 0f - 2 -> 1f - else -> 0f + listOf( + bindingView.actionNext, + bindingView.actionPrevious, + bindingView.weatherDateLineWeatherIcon, + bindingView.weatherSubLineWeatherIcon + ) + }.forEach { + it.setColorFilter(ColorHelper.getFontColorRgb(context.applicationContext.isDarkTheme())) + it.alpha = + (if (context.isDarkTheme()) Preferences.textGlobalAlphaDark.toIntValue() + .toFloat() else Preferences.textGlobalAlpha.toIntValue() + .toFloat()) / 100 } - listOf( - bindingView.date, - bindingView.weatherDateLineDivider, - bindingView.weatherDateLineTemperature, - bindingView.nextEvent, - bindingView.nextEventDifferenceTime, - bindingView.subLineText, - bindingView.weatherSubLineDivider, - bindingView.weatherSubLineTemperature, - ).forEach { - it.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor) - } + listOf(bindingView.subLineText, bindingView.weatherSubLineDivider, bindingView.weatherSubLineTemperature).forEach { + it.setTextColor(ColorHelper.getSecondaryFontColor(context.applicationContext.isDarkTheme())) + } - // Icons shadow - - listOf( - Pair(bindingView.subLineIcon, bindingView.subLineIconShadow), - ).forEach { - if ((if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) == 0) { - it.second.isVisible = false + if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.rawValue) { + listOf(bindingView.subLineIcon, bindingView.subLineIconShadow) } else { - it.second.isVisible = it.first.isVisible - it.second.scaleX = it.first.scaleX - it.second.scaleY = it.first.scaleY - it.second.applyShadow(it.first) + listOf(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 } - } - listOf( - Pair(bindingView.actionNext, bindingView.actionNextShadow), - Pair(bindingView.actionPrevious, bindingView.actionPreviousShadow), - ).forEach { - if ((if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) == 0) { - it.second.isVisible = false - } else { - it.second.isVisible = it.first.isVisible - it.second.scaleX = it.first.scaleX - it.second.scaleY = it.first.scaleY - it.second.applyShadow(it.first, 0.6f) + // Text Size + listOf>( + bindingView.date to Preferences.textMainSize, + bindingView.weatherDateLineDivider to (Preferences.textMainSize - 2), + bindingView.weatherDateLineTemperature to Preferences.textMainSize, + bindingView.nextEvent to Preferences.textMainSize, + bindingView.nextEventDifferenceTime to Preferences.textMainSize, + bindingView.subLineText to Preferences.textSecondSize, + bindingView.weatherSubLineDivider to (Preferences.textSecondSize - 2), + bindingView.weatherSubLineTemperature to Preferences.textSecondSize, + ).forEach { + it.first.setTextSize(TypedValue.COMPLEX_UNIT_SP, it.second) } - } - bindingView.actionPrevious.scaleX = bindingView.actionPrevious.scaleX * -1 - bindingView.actionPreviousShadow.scaleX = bindingView.actionPreviousShadow.scaleX * -1 + // Icons scale + bindingView.subLineIcon.scaleX = Preferences.textSecondSize / 18f + bindingView.subLineIcon.scaleY = Preferences.textSecondSize / 18f - // Custom Font - if (Preferences.customFont == Constants.CUSTOM_FONT_GOOGLE_SANS) { - val googleSans: Typeface = when (Preferences.customFontVariant) { - "100" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_thin.ttf") - "200" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_light.ttf") - "500" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_medium.ttf") - "700" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_bold.ttf") - "800" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_black.ttf") - else -> Typeface.createFromAsset(context.assets, "fonts/google_sans_regular.ttf") - } + bindingView.weatherSubLineWeatherIcon.scaleX = Preferences.textSecondSize / 18f + bindingView.weatherSubLineWeatherIcon.scaleY = Preferences.textSecondSize / 18f + + bindingView.weatherDateLineWeatherIcon.scaleX = Preferences.textMainSize / 18f + bindingView.weatherDateLineWeatherIcon.scaleY = Preferences.textMainSize / 18f + + bindingView.actionNext.scaleX = Preferences.textMainSize / 28f + bindingView.actionNext.scaleY = Preferences.textMainSize / 28f + + bindingView.actionPrevious.scaleX = Preferences.textMainSize / 28f + bindingView.actionPrevious.scaleY = Preferences.textMainSize / 28f + + + // Shadows + val shadowRadius = + when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) { + 0 -> 0f + 1 -> 5f + 2 -> 5f + else -> 5f + } + val shadowColor = + when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) { + 0 -> Color.TRANSPARENT + 1 -> R.color.black_50 + 2 -> Color.BLACK + else -> R.color.black_50 + } + val shadowDy = + when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) { + 0 -> 0f + 1 -> 0f + 2 -> 1f + else -> 0f + } listOf( bindingView.date, @@ -902,32 +848,94 @@ class StandardWidget(val context: Context) { bindingView.weatherSubLineDivider, bindingView.weatherSubLineTemperature, ).forEach { - it.typeface = googleSans + it.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor) } - } else if (Preferences.customFont == Constants.CUSTOM_FONT_DOWNLOADED && typeface != null) { - listOf( - bindingView.date, - bindingView.weatherDateLineDivider, - bindingView.weatherDateLineTemperature, - bindingView.nextEvent, - bindingView.nextEventDifferenceTime, - bindingView.subLineText, - bindingView.weatherSubLineDivider, - bindingView.weatherSubLineTemperature, + + // Icons shadow + + listOf( + Pair(bindingView.subLineIcon, bindingView.subLineIconShadow), ).forEach { - it.typeface = typeface + if ((if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) == 0) { + it.second.isVisible = false + } else { + it.second.isVisible = it.first.isVisible + it.second.scaleX = it.first.scaleX + it.second.scaleY = it.first.scaleY + it.second.applyShadow(it.first) + } } - } - // Dividers - arrayOf(bindingView.weatherDateLineDivider, bindingView.weatherSubLineDivider).forEach { - it.visibility = if (Preferences.showDividers) View.VISIBLE else View.INVISIBLE - it.layoutParams = (it.layoutParams as ViewGroup.MarginLayoutParams).apply { - this.marginEnd = if (Preferences.showDividers) 8f.convertDpToPixel(context).toInt() else 0 + listOf( + Pair(bindingView.actionNext, bindingView.actionNextShadow), + Pair(bindingView.actionPrevious, bindingView.actionPreviousShadow), + ).forEach { + if ((if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) == 0) { + it.second.isVisible = false + } else { + it.second.isVisible = it.first.isVisible + it.second.scaleX = it.first.scaleX + it.second.scaleY = it.first.scaleY + it.second.applyShadow(it.first, 0.6f) + } } + + bindingView.actionPrevious.scaleX = bindingView.actionPrevious.scaleX * -1 + bindingView.actionPreviousShadow.scaleX = bindingView.actionPreviousShadow.scaleX * -1 + + // Custom Font + if (Preferences.customFont == Constants.CUSTOM_FONT_GOOGLE_SANS) { + val googleSans: Typeface = when (Preferences.customFontVariant) { + "100" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_thin.ttf") + "200" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_light.ttf") + "500" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_medium.ttf") + "700" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_bold.ttf") + "800" -> Typeface.createFromAsset(context.assets, "fonts/google_sans_black.ttf") + else -> Typeface.createFromAsset(context.assets, "fonts/google_sans_regular.ttf") + } + + listOf( + bindingView.date, + bindingView.weatherDateLineDivider, + bindingView.weatherDateLineTemperature, + bindingView.nextEvent, + bindingView.nextEventDifferenceTime, + bindingView.subLineText, + bindingView.weatherSubLineDivider, + bindingView.weatherSubLineTemperature, + ).forEach { + it.typeface = googleSans + } + } else if (Preferences.customFont == Constants.CUSTOM_FONT_DOWNLOADED && typeface != null) { + listOf( + bindingView.date, + bindingView.weatherDateLineDivider, + bindingView.weatherDateLineTemperature, + bindingView.nextEvent, + bindingView.nextEventDifferenceTime, + bindingView.subLineText, + bindingView.weatherSubLineDivider, + bindingView.weatherSubLineTemperature, + ).forEach { + it.typeface = typeface + } + } + + // Dividers + arrayOf(bindingView.weatherDateLineDivider, bindingView.weatherSubLineDivider).forEach { + it.visibility = if (Preferences.showDividers) View.VISIBLE else View.INVISIBLE + it.layoutParams = (it.layoutParams as ViewGroup.MarginLayoutParams).apply { + this.marginEnd = if (Preferences.showDividers) 8f.convertDpToPixel(context).toInt() else 0 + } + } + + + return bindingView + + } catch (ex: Exception) { + ex.printStackTrace() + CrashlyticsReceiver.sendCrash(context, ex) + return null } - - - return bindingView } } \ No newline at end of file diff --git a/app/src/main/res/layout/left_aligned_widget.xml b/app/src/main/res/layout/left_aligned_widget.xml index 89ee934..b032445 100644 --- a/app/src/main/res/layout/left_aligned_widget.xml +++ b/app/src/main/res/layout/left_aligned_widget.xml @@ -16,11 +16,11 @@ @@ -129,10 +128,11 @@ android:layout_height="wrap_content" android:orientation="horizontal" android:baselineAligned="false" - android:layout_gravity="center_vertical" android:clipChildren="false" android:clipToPadding="false" android:paddingStart="4dp" + android:paddingEnd="4dp" + android:id="@+id/sub_line_container" android:layoutDirection="locale" android:gravity="center_vertical"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file