Correct the widget layout.

Adjust the layout carefully, so that remote grid views perfectly overlap the bitmap generated from the binding view, whether left-aligned, right-aligned or centered, and regardless of the size of the widget, text, margins or spacing.

Display the clock in the correct text size.
This commit is contained in:
azuo
2021-09-17 12:01:41 +08:00
parent 6d7d90e762
commit 183901534c
18 changed files with 187 additions and 149 deletions

View File

@ -106,6 +106,9 @@ class EventRepository(val context: Context) {
resetNextEventData()
}
MainWidget.updateWidget(context)
org.greenrobot.eventbus.EventBus.getDefault().post(
com.tommasoberlose.anotherwidget.ui.fragments.MainFragment.UpdateUiMessageEvent()
)
}
fun goToPreviousEvent() {
@ -121,6 +124,9 @@ class EventRepository(val context: Context) {
resetNextEventData()
}
MainWidget.updateWidget(context)
org.greenrobot.eventbus.EventBus.getDefault().post(
com.tommasoberlose.anotherwidget.ui.fragments.MainFragment.UpdateUiMessageEvent()
)
}
fun getFutureEvents(): List<Event> {

View File

@ -93,9 +93,9 @@ object Preferences : KotprefModel() {
var altTimezoneId by stringPref(default = "")
// Global
var textMainSize by floatPref(key = "PREF_TEXT_MAIN_SIZE", default = 26f)
var textSecondSize by floatPref(key = "PREF_TEXT_SECOND_SIZE", default = 18f)
var clockTextSize by floatPref(key = "PREF_TEXT_CLOCK_SIZE", default = 26f)
var textMainSize by floatPref(key = "PREF_TEXT_MAIN_SIZE", default = 24f)
var textSecondSize by floatPref(key = "PREF_TEXT_SECOND_SIZE", default = 16f)
var clockTextSize by floatPref(key = "PREF_TEXT_CLOCK_SIZE", default = 72f)
var clockBottomMargin by intPref(default = Constants.ClockBottomMargin.MEDIUM.rawValue)
var secondRowTopMargin by intPref(default = Constants.SecondRowTopMargin.NONE.rawValue)
var showClock by booleanPref(key = "PREF_SHOW_CLOCK", default = false)

View File

@ -44,8 +44,8 @@ object BitmapHelper {
FirebaseCrashlytics.getInstance().setCustomKey("HEIGHT SPEC", measuredHeight)
FirebaseCrashlytics.getInstance().setCustomKey("VIEW measuredWidth", view.measuredWidth)
FirebaseCrashlytics.getInstance().setCustomKey("VIEW measuredHeight", view.measuredHeight)
FirebaseCrashlytics.getInstance().setCustomKey("WIDGET final width", measuredWidth)
FirebaseCrashlytics.getInstance().setCustomKey("WIDGET final height", view.measuredHeight)
FirebaseCrashlytics.getInstance().setCustomKey("WIDGET final width", widgetWidth)
FirebaseCrashlytics.getInstance().setCustomKey("WIDGET final height", widgetHeight)
}
return try {
@ -58,7 +58,7 @@ object BitmapHelper {
//Bind a canvas to it
val canvas = Canvas(btm)
// draw the view on the canvas
view.layout(0, 0, measuredWidth, measuredHeight)
view.layout(0, 0, widgetWidth, widgetHeight)
view.draw(canvas)
//return the bitmap
}

View File

@ -25,8 +25,15 @@ object WidgetHelper {
) {
fun getWidgetsSize(widgetId: Int): Pair<Int, Int> {
val width = getWidgetWidth(widgetId)
val height = getWidgetHeight(widgetId)
val portrait = context.resources.configuration.orientation == ORIENTATION_PORTRAIT
val width = getWidgetSizeInDp(
widgetId,
if (portrait) AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH else AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH
)
val height = getWidgetSizeInDp(
widgetId,
if (portrait) AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT else AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT
)
val widthInPx = context.dip(width)
val heightInPx = context.dip(height)
FirebaseCrashlytics.getInstance().setCustomKey("widthInPx", widthInPx)

View File

@ -153,7 +153,11 @@ class MainFragment : Fragment() {
WidgetHelper.runWithCustomTypeface(requireContext()) { typeface ->
uiJob?.cancel()
uiJob = lifecycleScope.launch(Dispatchers.IO) {
val generatedView = MainWidget.getWidgetView(requireContext(), binding.widget.width, typeface)
val generatedView = MainWidget.getWidgetView(
requireContext(),
binding.widget.width - binding.widget.paddingStart - binding.widget.paddingEnd,
typeface
)
if (generatedView != null) {
withContext(Dispatchers.Main) {

View File

@ -236,6 +236,7 @@ class CalendarFragment : Fragment() {
binding.showDiffTimeToggle.setOnCheckedChangeListener { _, isChecked ->
Preferences.showDiffTime = isChecked
updateCalendar()
}
binding.actionShowNextEventOnMultipleLines.setOnClickListener {

View File

@ -146,7 +146,7 @@ class ClockFragment : Fragment() {
binding.actionClockTextSize.setOnClickListener {
BottomSheetPicker(
requireContext(),
items = (46 downTo 12).map { BottomSheetPicker.MenuItem("${it}sp", it.toFloat()) },
items = (120 downTo 30).filter { it % 2 == 0 }.map { BottomSheetPicker.MenuItem("${it}sp", it.toFloat()) },
getSelected = { Preferences.clockTextSize },
header = getString(R.string.settings_clock_text_size_title),
onItemSelected = {value ->

View File

@ -317,6 +317,17 @@ class TypographyFragment : Fragment() {
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == android.app.Activity.RESULT_OK) {
when (requestCode) {
RequestCode.CUSTOM_FONT_CHOOSER_REQUEST_CODE.code -> {
com.tommasoberlose.anotherwidget.ui.widgets.MainWidget.updateWidget(requireContext())
}
}
}
super.onActivityResult(requestCode, resultCode, data)
}
private fun maintainScrollPosition(callback: () -> Unit) {
binding.scrollView.isScrollable = false
callback.invoke()

View File

@ -79,9 +79,10 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
try {
val generatedBinding = generateWidgetView(typeface) ?: return null
val width = w - (Preferences.widgetPadding.convertDpToPixel(context) + Preferences.widgetMargin.convertDpToPixel(context)).toInt() * 2
views.setImageViewBitmap(
R.id.bitmap_container,
BitmapHelper.getBitmapFromView(generatedBinding.root, width = w)
BitmapHelper.getBitmapFromView(generatedBinding.root, width)
)
views = updateGridView(generatedBinding, views, appWidgetId)
} catch (ex: Exception) {
@ -241,10 +242,6 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
views.setViewVisibility(R.id.sub_line_rect, View.VISIBLE)
views.setViewVisibility(R.id.weather_sub_line_rect, if (Preferences.showWeather && Preferences.weatherIcon != "") View.VISIBLE else View.GONE)
views.setViewVisibility(R.id.first_line_rect, View.GONE)
views.setViewVisibility(R.id.sub_line_top_margin_small_sans, View.GONE)
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
var isWeatherShown = false
@ -297,6 +294,7 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
}
Constants.GlanceProviderId.CUSTOM_INFO -> {
if (Preferences.customNotes.isNotEmpty()) {
showSomething = true
break@loop
}
}
@ -601,9 +599,12 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
bindingView.subLine.isVisible = true
bindingView.weatherSubLine.isVisible = Preferences.showWeather && Preferences.weatherIcon != ""
bindingView.subLineTopMarginSmall.visibility = View.GONE
bindingView.subLineTopMarginMedium.visibility = View.GONE
bindingView.subLineTopMarginLarge.visibility = View.GONE
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
@ -844,24 +845,30 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
bindingView.nextEvent to Preferences.textMainSize,
bindingView.nextEventDifferenceTime to Preferences.textMainSize,
bindingView.subLineText to Preferences.textSecondSize,
bindingView.weatherSubLineDivider to (Preferences.textSecondSize - 2),
bindingView.weatherSubLineDivider to (Preferences.textSecondSize * 0.9f),
bindingView.weatherSubLineTemperature to Preferences.textSecondSize,
).forEach {
it.first.setTextSize(TypedValue.COMPLEX_UNIT_SP, it.second)
if (!it.first.includeFontPadding && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P)
it.first.isFallbackLineSpacing = false
}
// 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
listOf(
bindingView.subLineIcon to Preferences.textSecondSize / 16f,
bindingView.subLineIconShadow to Preferences.textSecondSize / 16f,
bindingView.weatherSubLineWeatherIcon to Preferences.textSecondSize / 16f,
bindingView.weatherDateLineWeatherIcon to ((Preferences.textMainSize + Preferences.textSecondSize) / 2) / 24f,
bindingView.actionNext to Preferences.textMainSize / 24f,
bindingView.actionNextShadow to Preferences.textMainSize / 24f
).forEach {
if (it.first.tag == null)
it.first.tag = it.first.layoutParams.height
it.first.layoutParams = it.first.layoutParams.apply {
height = ((it.first.tag as Int) * it.second).roundToInt()
width = height
}
}
// Shadows
@ -910,7 +917,7 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
it.second.isVisible = it.first.isVisible
it.second.scaleX = it.first.scaleX
it.second.scaleY = it.first.scaleY
it.second.applyShadow(it.first)
it.second.applyShadow(it.first, 0.7f)
}
}
@ -968,10 +975,7 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
// 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
}
it.visibility = if (Preferences.showDividers) View.VISIBLE else View.GONE
}
// Right Aligned
@ -981,8 +985,11 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
}
bindingView.mainContent.gravity = Gravity.END
bindingView.dateLayout.gravity = Gravity.END
bindingView.date.gravity = Gravity.END
bindingView.calendarLayout.gravity = Gravity.END or Gravity.CENTER_VERTICAL
bindingView.nextEvent.gravity = Gravity.END
bindingView.subLineContainer.gravity = Gravity.END or Gravity.CENTER_VERTICAL
bindingView.subLineText.gravity = Gravity.END
}
return bindingView

View File

@ -32,12 +32,12 @@ class ClockWidget(val context: Context) {
views.setTextViewTextSize(
R.id.time,
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(context)
Preferences.clockTextSize
)
views.setTextViewTextSize(
R.id.time_am_pm,
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(context) / 5 * 2
Preferences.clockTextSize / 5 * 2
)
val clockPIntent = IntentHelper.getPendingIntent(
context,
@ -80,19 +80,29 @@ class ClockWidget(val context: Context) {
views.setTextViewTextSize(
R.id.alt_timezone_time,
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(context) / 3
Preferences.clockTextSize / 3
)
views.setTextViewTextSize(
R.id.alt_timezone_time_am_pm,
TypedValue.COMPLEX_UNIT_SP,
(Preferences.clockTextSize.toPixel(context) / 3) / 5 * 2
(Preferences.clockTextSize / 3) / 5 * 2
)
views.setTextViewTextSize(
R.id.alt_timezone_label,
TypedValue.COMPLEX_UNIT_SP,
(Preferences.clockTextSize.toPixel(context) / 3) / 5 * 2
(Preferences.clockTextSize / 3) / 5 * 2
)
val padding = (TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize,
context.resources.displayMetrics
) * 0.2).toInt()
if (Preferences.widgetAlign == Constants.WidgetAlign.RIGHT.rawValue)
views.setViewPadding(R.id.timezones_container, 0, padding, padding, 0)
else
views.setViewPadding(R.id.timezones_container, padding, padding, 0,0)
views.setOnClickPendingIntent(R.id.timezones_container, clockPIntent)
views.setViewVisibility(R.id.timezones_container, View.VISIBLE)
} else {

View File

@ -63,17 +63,13 @@ class MainWidget : AppWidgetProvider() {
internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager,
appWidgetId: Int) {
val displayMetrics = Resources.getSystem().displayMetrics
val width = displayMetrics.widthPixels
val height = displayMetrics.heightPixels
val dimensions = WidgetHelper.WidgetSizeProvider(context, appWidgetManager).getWidgetsSize(appWidgetId)
WidgetHelper.runWithCustomTypeface(context) {
val views = when (Preferences.widgetAlign) {
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)
Constants.WidgetAlign.LEFT.rawValue -> AlignedWidget(context).generateWidget(appWidgetId, dimensions.first, it)
Constants.WidgetAlign.RIGHT.rawValue -> AlignedWidget(context, rightAligned = true).generateWidget(appWidgetId, dimensions.first, it)
else -> StandardWidget(context).generateWidget(appWidgetId, dimensions.first, it)
}
try {
if (views != null) appWidgetManager.updateAppWidget(appWidgetId, views)

View File

@ -82,9 +82,10 @@ class StandardWidget(val context: Context) {
try {
val generatedBinding = generateWidgetView(typeface) ?: return null
val width = w - (Preferences.widgetPadding.convertDpToPixel(context) + Preferences.widgetMargin.convertDpToPixel(context)).toInt() * 2
views.setImageViewBitmap(
R.id.bitmap_container,
BitmapHelper.getBitmapFromView(generatedBinding.root, width = w)
BitmapHelper.getBitmapFromView(generatedBinding.root, width)
)
views = updateGridView(generatedBinding, views, appWidgetId)
} catch (ex: Exception) {
@ -325,6 +326,7 @@ class StandardWidget(val context: Context) {
}
Constants.GlanceProviderId.CUSTOM_INFO -> {
if (Preferences.customNotes.isNotEmpty()) {
showSomething = true
break@loop
}
}
@ -874,33 +876,37 @@ class StandardWidget(val context: Context) {
// Text Size
listOf<Pair<TextView, Float>>(
bindingView.date to Preferences.textMainSize,
bindingView.weatherDateLineDivider to (Preferences.textMainSize - 2),
bindingView.weatherDateLineDivider to (Preferences.textMainSize * 0.9f),
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.weatherSubLineDivider to (Preferences.textSecondSize * 0.9f),
bindingView.weatherSubLineTemperature to Preferences.textSecondSize,
).forEach {
it.first.setTextSize(TypedValue.COMPLEX_UNIT_SP, it.second)
if (!it.first.includeFontPadding && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P)
it.first.isFallbackLineSpacing = false
}
// 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
listOf(
bindingView.subLineIcon to Preferences.textSecondSize / 16f,
bindingView.subLineIconShadow to Preferences.textSecondSize / 16f,
bindingView.weatherSubLineWeatherIcon to Preferences.textSecondSize / 16f,
bindingView.weatherDateLineWeatherIcon to Preferences.textMainSize / 24f,
bindingView.actionNext to Preferences.textMainSize / 24f,
bindingView.actionNextShadow to Preferences.textMainSize / 24f,
bindingView.actionPrevious to Preferences.textMainSize / 24f,
bindingView.actionPreviousShadow to Preferences.textMainSize / 24f
).forEach {
if (it.first.tag == null)
it.first.tag = it.first.layoutParams.height
it.first.layoutParams = it.first.layoutParams.apply {
height = ((it.first.tag as Int) * it.second).roundToInt()
width = height
}
}
// Shadows
val shadowRadius =
@ -949,7 +955,7 @@ class StandardWidget(val context: Context) {
it.second.isVisible = it.first.isVisible
it.second.scaleX = it.first.scaleX
it.second.scaleY = it.first.scaleY
it.second.applyShadow(it.first)
it.second.applyShadow(it.first, 0.7f)
}
}
@ -1013,10 +1019,7 @@ class StandardWidget(val context: Context) {
// 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
}
it.visibility = if (Preferences.showDividers) View.VISIBLE else View.GONE
}