Added color copy/paste, better size and color text selection

This commit is contained in:
Tommaso Berlose 2021-05-07 17:19:23 +02:00
parent 1ac53e09a8
commit 5d07cc8d73
52 changed files with 460 additions and 75 deletions

View File

@ -22,8 +22,8 @@ android {
applicationId "com.tommasoberlose.anotherwidget"
minSdkVersion 23
targetSdkVersion 30
versionCode 135
versionName "2.3.1"
versionCode 136
versionName "2.3.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
buildConfigField("String", "GOOGLE_API_KEY", apikeyProperties['GOOGLE_API_KEY'])

View File

@ -3,40 +3,30 @@ package com.tommasoberlose.anotherwidget.components
import android.content.Context
import android.content.res.ColorStateList
import android.graphics.Color
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.widget.GridLayout
import android.widget.ImageView
import android.widget.SeekBar
import androidx.annotation.ColorInt
import android.widget.FrameLayout
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.core.widget.addTextChangedListener
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.card.MaterialCardView
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.databinding.BottomSheetMenuHorBinding
import com.tommasoberlose.anotherwidget.databinding.BottomSheetMenuListBinding
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.copyToClipboard
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isClipboardColor
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
import com.tommasoberlose.anotherwidget.utils.expand
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.pasteFromClipboard
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
import com.tommasoberlose.anotherwidget.utils.reveal
import com.tommasoberlose.anotherwidget.utils.toPixel
import com.warkiz.widget.IndicatorSeekBar
import com.warkiz.widget.OnSeekChangeListener
import com.warkiz.widget.SeekParams
import kotlinx.coroutines.*
import net.idik.lib.slimadapter.SlimAdapter
import java.lang.Exception
import java.util.prefs.Preferences
class BottomSheetColorPicker(
context: Context,
@ -46,20 +36,45 @@ class BottomSheetColorPicker(
private val onColorSelected: ((selectedValue: Int) -> Unit)? = null,
private val showAlphaSelector: Boolean = false,
private val alpha: Int = 0,
private val onAlphaChangeListener: ((alpha: Int) -> Unit)? = null
private val onAlphaChangeListener: ((alpha: Int) -> Unit)? = null,
private val hideCopyPaste: Boolean = false,
) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
private var loadingJobs: ArrayList<Job> = ArrayList()
private lateinit var adapter: SlimAdapter
private var alphaDebouncing: Job? = null
private var binding: BottomSheetMenuHorBinding = BottomSheetMenuHorBinding.inflate(LayoutInflater.from(context))
private var listBinding: BottomSheetMenuListBinding = BottomSheetMenuListBinding.inflate(LayoutInflater.from(context))
override fun show() {
window?.setDimAmount(0f)
// Header
binding.header.isVisible = header != null
binding.headerText.text = header ?: ""
if (hideCopyPaste) {
binding.actionContainer.isVisible = false
} else {
binding.actionContainer.isVisible = true
binding.actionCopy.setOnClickListener {
context.copyToClipboard(getSelected?.invoke(), alpha)
}
binding.actionPaste.setOnClickListener {
context.pasteFromClipboard { color, alpha ->
binding.alphaSelector.setProgress(alpha.toIntValue().toFloat())
adapter.notifyItemChanged(adapter.data.indexOf(getSelected?.invoke()))
onColorSelected?.invoke(Color.parseColor(color))
val idx = colors.toList().indexOf(getSelected?.invoke())
adapter.notifyItemChanged(idx)
(listBinding.root.layoutManager as GridLayoutManager).scrollToPositionWithOffset(idx,0)
}
}
binding.actionPaste.isVisible = context.isClipboardColor()
}
// Alpha
binding.alphaSelectorContainer.isVisible = showAlphaSelector
binding.alphaSelector.setProgress(alpha.toFloat())
@ -67,8 +82,15 @@ class BottomSheetColorPicker(
binding.alphaSelector.onSeekChangeListener = object : OnSeekChangeListener {
override fun onSeeking(seekParams: SeekParams?) {
seekParams?.let {
binding.textAlpha.text = "%s: %s%%".format(context.getString(R.string.alpha), it.progress)
onAlphaChangeListener?.invoke(it.progress)
binding.textAlpha.text =
"%s: %s%%".format(context.getString(R.string.alpha), it.progress)
alphaDebouncing?.cancel()
alphaDebouncing = GlobalScope.launch(Dispatchers.IO) {
delay(150)
withContext(Dispatchers.Main) {
onAlphaChangeListener?.invoke(it.progress)
}
}
}
}
override fun onStartTrackingTouch(seekBar: IndicatorSeekBar?) {
@ -78,7 +100,6 @@ class BottomSheetColorPicker(
}
// List
adapter = SlimAdapter.create()
loadingJobs.add(GlobalScope.launch(Dispatchers.IO) {
@ -120,10 +141,13 @@ class BottomSheetColorPicker(
adapter.updateData(colors.toList())
withContext(Dispatchers.Main) {
binding.colorLoader.isVisible = false
binding.loader.isVisible = false
binding.listContainer.addView(listBinding.root)
this@BottomSheetColorPicker.behavior.state = BottomSheetBehavior.STATE_EXPANDED
binding.listContainer.isVisible = true
val idx = colors.toList().indexOf(getSelected?.invoke())
(listBinding.root.layoutManager as GridLayoutManager).scrollToPositionWithOffset(idx,0)
}
})

View File

@ -6,6 +6,7 @@ import android.view.View
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.tommasoberlose.anotherwidget.R

View File

@ -0,0 +1,108 @@
package com.tommasoberlose.anotherwidget.components
import android.content.Context
import android.content.res.ColorStateList
import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.widget.TextView
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.card.MaterialCardView
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.databinding.BottomSheetMenuHorBinding
import com.tommasoberlose.anotherwidget.databinding.BottomSheetMenuListBinding
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.copyToClipboard
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isClipboardColor
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.pasteFromClipboard
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
import com.warkiz.widget.IndicatorSeekBar
import com.warkiz.widget.OnSeekChangeListener
import com.warkiz.widget.SeekParams
import kotlinx.coroutines.*
import net.idik.lib.slimadapter.SlimAdapter
class BottomSheetPicker<T>(
context: Context,
private val items: List<MenuItem<T>> = arrayListOf(),
private val getSelected: (() -> T)? = null,
private val header: String? = null,
private val onItemSelected: ((selectedValue: T?) -> Unit)? = null,
) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
private var loadingJobs: ArrayList<Job> = ArrayList()
private lateinit var adapter: SlimAdapter
private var binding: BottomSheetMenuHorBinding = BottomSheetMenuHorBinding.inflate(
LayoutInflater.from(context))
private var listBinding: BottomSheetMenuListBinding = BottomSheetMenuListBinding.inflate(
LayoutInflater.from(context))
override fun show() {
window?.setDimAmount(0f)
// Header
binding.header.isVisible = header != null
binding.headerText.text = header ?: ""
// Alpha
binding.alphaSelectorContainer.isVisible = false
binding.actionContainer.isVisible = false
// List
adapter = SlimAdapter.create()
loadingJobs.add(GlobalScope.launch(Dispatchers.IO) {
listBinding.root.setHasFixedSize(true)
val mLayoutManager = LinearLayoutManager(context)
listBinding.root.layoutManager = mLayoutManager
adapter
.register<Int>(R.layout.bottom_sheet_menu_item) { position, injector ->
val item = items[position]
val isSelected = item.value == getSelected?.invoke()
injector
.text(R.id.label, item.title)
.textColor(R.id.label, ContextCompat.getColor(context, if (isSelected) R.color.colorAccent else R.color.colorSecondaryText))
.selected(R.id.item, isSelected)
.clicked(R.id.item) {
val oldIdx = items.toList().indexOfFirst { it.value == getSelected?.invoke() }
onItemSelected?.invoke(item.value)
adapter.notifyItemChanged(position)
adapter.notifyItemChanged(oldIdx)
(listBinding.root.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(position,0)
}
}
.attachTo(listBinding.root)
adapter.updateData((items.indices).toList())
withContext(Dispatchers.Main) {
binding.loader.isVisible = false
binding.listContainer.addView(listBinding.root)
this@BottomSheetPicker.behavior.state = BottomSheetBehavior.STATE_EXPANDED
binding.listContainer.isVisible = true
val idx = items.toList().indexOfFirst { it.value == getSelected?.invoke() }
(listBinding.root.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(idx,0)
}
})
setContentView(binding.root)
super.show()
}
override fun onStop() {
loadingJobs.forEach { it.cancel() }
super.onStop()
}
class MenuItem<T>(val title: String, val value: T? = null)
}

View File

@ -110,6 +110,7 @@ object Preferences : KotprefModel() {
var customFontName by stringPref(default = "")
var customFontVariant by stringPref(default = "regular")
var showNextEvent by booleanPref(key = "PREF_SHOW_NEXT_EVENT", default = true)
var showNextEventOnMultipleLines by booleanPref(default = false)
var showDividers by booleanPref(default = true)

View File

@ -1,10 +1,20 @@
package com.tommasoberlose.anotherwidget.helpers
import android.annotation.SuppressLint
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Context.CLIPBOARD_SERVICE
import android.graphics.Color
import android.util.Log
import androidx.core.content.ContextCompat
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
import com.tommasoberlose.anotherwidget.utils.toast
import kotlin.math.roundToInt
object ColorHelper {
fun getFontColor(isDark: Boolean): Int {
return try {
@ -144,4 +154,40 @@ object ColorHelper {
false
}
}
@SuppressLint("DefaultLocale")
fun Context.copyToClipboard(color: Int?, alpha: Int) {
if (color == null) return toast(getString(R.string.error_copy_color))
with(getSystemService(CLIPBOARD_SERVICE) as ClipboardManager) {
try {
val colorString = Integer.toHexString(color)
val clip = "#%s%s".format(
alpha.toHexValue(),
if (colorString.length > 6) colorString.substring(2) else colorString
).toUpperCase()
setPrimaryClip(ClipData.newPlainText(clip, clip))
toast(getString(R.string.color_copied))
} catch (ex: Exception) {
ex.printStackTrace()
toast(getString(R.string.error_copy_color))
}
}
}
fun Context.isClipboardColor(): Boolean {
with(getSystemService(CLIPBOARD_SERVICE) as ClipboardManager) {
return primaryClip?.getItemAt(0)?.text?.toString()?.isColor() ?: false
}
}
fun Context.pasteFromClipboard(pasteColor: (color: String, alpha: String) -> Unit) {
with(getSystemService(CLIPBOARD_SERVICE) as ClipboardManager) {
primaryClip?.let {
val item = it.getItemAt(0).text.toString().replace("#", "")
val color = if (item.length > 6) item.substring(2) else item
val alpha = if (item.length > 6) item.substring(0, 2) else "00"
pasteColor("#$color", alpha)
}
}
}
}

View File

@ -12,6 +12,7 @@ import com.chibatching.kotpref.bulk
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.receivers.NotificationListener
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import com.tommasoberlose.anotherwidget.utils.ignoreExceptions
import java.lang.Exception
object MediaPlayerHelper {
@ -69,15 +70,24 @@ object MediaPlayerHelper {
isSomeonePlaying = true
if (metadata != null) {
Preferences.bulk {
mediaPlayerTitle =
metadata.getText(MediaMetadata.METADATA_KEY_TITLE)?.toString()
?: ""
mediaPlayerArtist =
metadata.getText(MediaMetadata.METADATA_KEY_ARTIST)?.toString()
?: ""
mediaPlayerAlbum =
metadata.getText(MediaMetadata.METADATA_KEY_ALBUM)?.toString()
?: ""
ignoreExceptions {
mediaPlayerTitle =
metadata.getText(MediaMetadata.METADATA_KEY_TITLE)
?.toString()
?: ""
}
ignoreExceptions {
mediaPlayerArtist =
metadata.getText(MediaMetadata.METADATA_KEY_ARTIST)
?.toString()
?: ""
}
ignoreExceptions {
mediaPlayerAlbum =
metadata.getText(MediaMetadata.METADATA_KEY_ALBUM)
?.toString()
?: ""
}
}
}

View File

@ -53,12 +53,12 @@ class CustomLocationActivity : AppCompatActivity() {
}
}
.register<Address>(R.layout.custom_location_item) { item, injector ->
injector.text(R.id.text, item.getAddressLine(0))
injector.text(R.id.text, item.getAddressLine(0) ?: "")
injector.clicked(R.id.item) {
Preferences.bulk {
customLocationLat = item.latitude.toString()
customLocationLon = item.longitude.toString()
customLocationAdd = item.getAddressLine(0)
customLocationAdd = item.getAddressLine(0) ?: ""
setResult(Activity.RESULT_OK)
finish()
}

View File

@ -63,6 +63,7 @@ class CalendarFragment : Fragment() {
binding.showAllDayToggle.setCheckedImmediatelyNoEvent(Preferences.calendarAllDay)
binding.showOnlyBusyEventsToggle.setCheckedImmediatelyNoEvent(Preferences.showOnlyBusyEvents)
binding.showDiffTimeToggle.setCheckedImmediatelyNoEvent(Preferences.showDiffTime)
binding.showNextEventOnMultipleLinesToggle.setCheckedImmediatelyNoEvent(Preferences.showNextEventOnMultipleLines)
setupListener()
@ -90,6 +91,12 @@ class CalendarFragment : Fragment() {
}
}
viewModel.showNextEventOnMultipleLines.observe(viewLifecycleOwner) {
maintainScrollPosition {
binding.showNextEventOnMultipleLinesLabel.text = if (it) getString(R.string.settings_enabled) else getString(R.string.settings_disabled)
}
}
viewModel.showDiffTime.observe(viewLifecycleOwner) {
maintainScrollPosition {
binding.showDiffTimeLabel.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
@ -231,6 +238,14 @@ class CalendarFragment : Fragment() {
Preferences.showDiffTime = isChecked
}
binding.actionShowNextEventOnMultipleLines.setOnClickListener {
binding.showNextEventOnMultipleLinesToggle.isChecked = !binding.showNextEventOnMultipleLinesToggle.isChecked
}
binding.showNextEventOnMultipleLinesToggle.setOnCheckedChangeListener { _, isChecked ->
Preferences.showNextEventOnMultipleLines = isChecked
}
binding.actionWidgetUpdateFrequency.setOnClickListener {
if (Preferences.showEvents && Preferences.showDiffTime) {
BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_widget_update_frequency_title), message = getString(R.string.settings_widget_update_frequency_subtitle)).setSelectedValue(Preferences.widgetUpdateFrequency)

View File

@ -15,6 +15,7 @@ import com.google.android.material.transition.MaterialSharedAxis
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
import com.tommasoberlose.anotherwidget.components.BottomSheetPicker
import com.tommasoberlose.anotherwidget.databinding.FragmentTabTypographyBinding
import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences
@ -167,20 +168,21 @@ class TypographyFragment : Fragment() {
private fun setupListener() {
binding.actionMainTextSize.setOnClickListener {
val dialog = BottomSheetMenu<Float>(requireContext(), header = getString(R.string.title_main_text_size)).setSelectedValue(
Preferences.textMainSize)
(40 downTo 10).filter { it % 2 == 0 }.forEach {
dialog.addItem("${it}sp", it.toFloat())
}
dialog.addOnSelectItemListener { value ->
Preferences.textMainSize = value
}.show()
BottomSheetPicker(
requireContext(),
items = (40 downTo 10).map { BottomSheetPicker.MenuItem("${it}sp", it.toFloat()) },
getSelected = { Preferences.textMainSize },
header = getString(R.string.title_main_text_size),
onItemSelected = {value ->
if (value != null) Preferences.textMainSize = value
}
).show()
}
binding.actionSecondTextSize.setOnClickListener {
val dialog = BottomSheetMenu<Float>(requireContext(), header = getString(R.string.title_second_text_size)).setSelectedValue(
Preferences.textSecondSize)
(40 downTo 10).filter { it % 2 == 0 }.forEach {
(40 downTo 10).forEach {
dialog.addItem("${it}sp", it.toFloat())
}
dialog.addOnSelectItemListener { value ->
@ -209,7 +211,7 @@ class TypographyFragment : Fragment() {
} else {
Preferences.textGlobalAlpha = alpha.toHexValue()
}
}
},
).show()
}
@ -236,7 +238,7 @@ class TypographyFragment : Fragment() {
} else {
Preferences.textSecondaryAlpha = alpha.toHexValue()
}
}
},
).show()
}

View File

@ -57,6 +57,7 @@ class MainViewModel(context: Application) : AndroidViewModel(context) {
val showUntil = Preferences.asLiveData(Preferences::showUntil)
val showDiffTime = Preferences.asLiveData(Preferences::showDiffTime)
val showNextEvent = Preferences.asLiveData(Preferences::showNextEvent)
val showNextEventOnMultipleLines = Preferences.asLiveData(Preferences::showNextEventOnMultipleLines)
val openEventDetails = Preferences.asLiveData(Preferences::openEventDetails)
val calendarAppName = Preferences.asLiveData(Preferences::calendarAppName)
val widgetUpdateFrequency = Preferences.asLiveData(Preferences::widgetUpdateFrequency)
@ -144,6 +145,7 @@ class MainViewModel(context: Application) : AndroidViewModel(context) {
addSource(Preferences.asLiveData(Preferences::calendarAllDay)) { value = true }
addSource(Preferences.asLiveData(Preferences::showDiffTime)) { value = true }
addSource(Preferences.asLiveData(Preferences::showNextEvent)) { value = true }
addSource(Preferences.asLiveData(Preferences::showNextEventOnMultipleLines)) { value = true }
addSource(Preferences.asLiveData(Preferences::showDeclinedEvents)) { value = true }
addSource(Preferences.asLiveData(Preferences::showInvitedEvents)) { value = true }
addSource(Preferences.asLiveData(Preferences::showAcceptedEvents)) { value = true }

View File

@ -107,12 +107,12 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
views.setImageViewBitmap(
R.id.weather_rect,
BitmapHelper.getBitmapFromView(bindingView.weatherDateLine, draw = false)
BitmapHelper.getBitmapFromView(bindingView.weatherDateLine, draw = false, width = bindingView.weatherDateLine.width, height = bindingView.weatherDateLine.height)
)
views.setImageViewBitmap(
R.id.weather_sub_line_rect,
BitmapHelper.getBitmapFromView(bindingView.weatherSubLine, draw = false)
BitmapHelper.getBitmapFromView(bindingView.weatherSubLine, draw = false, width = bindingView.weatherSubLine.width, height = bindingView.weatherSubLine.height)
)
} else {
views.setViewVisibility(R.id.weather_rect, View.GONE)
@ -123,7 +123,7 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
// Calendar
views.setImageViewBitmap(
R.id.date_rect,
BitmapHelper.getBitmapFromView(bindingView.date, draw = false)
BitmapHelper.getBitmapFromView(bindingView.date, draw = false, width = bindingView.date.width, height = bindingView.date.height)
)
val calPIntent = PendingIntent.getActivity(
@ -157,7 +157,7 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
// Action next event
views.setImageViewBitmap(
R.id.action_next_rect,
BitmapHelper.getBitmapFromView(bindingView.actionNext, draw = false)
BitmapHelper.getBitmapFromView(bindingView.actionNext, draw = false, width = bindingView.actionNext.width, height = bindingView.actionNext.height)
)
views.setViewVisibility(R.id.action_next_rect, View.VISIBLE)
views.setOnClickPendingIntent(
@ -186,6 +186,10 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
PendingIntent.FLAG_UPDATE_CURRENT
)
views.setOnClickPendingIntent(R.id.next_event_rect, eventIntent)
views.setImageViewBitmap(
R.id.next_event_rect,
BitmapHelper.getBitmapFromView(bindingView.nextEvent, draw = false, width = bindingView.nextEvent.width, height = bindingView.nextEvent.height)
)
views.setViewVisibility(R.id.next_event_rect, View.VISIBLE)
// Event time difference
@ -194,12 +198,18 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
R.id.next_event_difference_time_rect,
BitmapHelper.getBitmapFromView(
bindingView.nextEventDifferenceTime,
draw = false
draw = false,
width = bindingView.nextEventDifferenceTime.width,
height = bindingView.nextEventDifferenceTime.height
)
)
views.setOnClickPendingIntent(R.id.next_event_difference_time_rect, eventIntent)
views.setViewVisibility(R.id.next_event_difference_time_rect, View.VISIBLE)
if (!Preferences.showNextEventOnMultipleLines) {
views.setViewVisibility(R.id.next_event_difference_time_rect, View.VISIBLE)
} else {
views.setViewVisibility(R.id.next_event_difference_time_rect, View.GONE)
}
} else {
views.setViewVisibility(R.id.next_event_difference_time_rect, View.GONE)
}
@ -227,12 +237,6 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
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)
@ -374,12 +378,23 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
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 {
views.setViewVisibility(R.id.first_line_rect, View.VISIBLE)
views.setViewVisibility(R.id.weather_rect, View.VISIBLE)
views.setViewVisibility(R.id.calendar_layout_rect, View.GONE)
views.setViewVisibility(R.id.sub_line_rect, View.GONE)
views.setViewVisibility(R.id.weather_sub_line_rect, View.GONE)
// 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)
BitmapHelper.getBitmapFromView(bindingView.subLine, draw = false, width = bindingView.subLine.width, height = bindingView.subLine.height)
)
} catch (ex: Exception) {
ex.printStackTrace()
@ -455,8 +470,16 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
bindingView.nextEvent.text = nextEvent.title
if (Preferences.showNextEventOnMultipleLines) {
bindingView.nextEvent.apply {
isSingleLine = false
maxLines = 3
gravity = if (rightAligned) Gravity.END else Gravity.START
}
}
if (Preferences.showDiffTime && now.timeInMillis < nextEvent.startDate) {
bindingView.nextEventDifferenceTime.text = if (!nextEvent.allDay) {
val diffTime = if (!nextEvent.allDay) {
SettingsStringHelper.getDifferenceText(
context,
now.timeInMillis,
@ -470,7 +493,14 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
nextEvent.startDate
).toLowerCase(Locale.getDefault())
}
bindingView.nextEventDifferenceTime.isVisible = true
bindingView.nextEventDifferenceTime.text = diffTime
if (!Preferences.showNextEventOnMultipleLines) {
bindingView.nextEventDifferenceTime.isVisible = true
} else {
bindingView.nextEvent.text = context.getString(R.string.events_glance_provider_format).format(nextEvent.title, diffTime)
bindingView.nextEventDifferenceTime.isVisible = false
}
} else {
bindingView.nextEventDifferenceTime.isVisible = false
}

View File

@ -10,6 +10,7 @@ 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
@ -109,12 +110,12 @@ class StandardWidget(val context: Context) {
views.setImageViewBitmap(
R.id.weather_rect,
BitmapHelper.getBitmapFromView(bindingView.weatherDateLine, draw = false)
BitmapHelper.getBitmapFromView(bindingView.weatherDateLine, draw = false, width = bindingView.weatherDateLine.width, height = bindingView.weatherDateLine.height)
)
views.setImageViewBitmap(
R.id.weather_sub_line_rect,
BitmapHelper.getBitmapFromView(bindingView.weatherSubLine, draw = false)
BitmapHelper.getBitmapFromView(bindingView.weatherSubLine, draw = false, width = bindingView.weatherSubLine.width, height = bindingView.weatherSubLine.height)
)
} else {
views.setViewVisibility(R.id.weather_rect, View.GONE)
@ -125,7 +126,7 @@ class StandardWidget(val context: Context) {
// Calendar
views.setImageViewBitmap(
R.id.date_rect,
BitmapHelper.getBitmapFromView(bindingView.date, draw = false)
BitmapHelper.getBitmapFromView(bindingView.date, draw = false, width = bindingView.date.width, height = bindingView.date.height)
)
val calPIntent = PendingIntent.getActivity(
@ -140,7 +141,7 @@ class StandardWidget(val context: Context) {
// Second row
views.setImageViewBitmap(
R.id.sub_line_rect,
BitmapHelper.getBitmapFromView(bindingView.subLine, draw = false)
BitmapHelper.getBitmapFromView(bindingView.subLine, draw = false, width = bindingView.subLine.width, height = bindingView.subLine.height)
)
val nextAlarm = AlarmHelper.getNextAlarm(context)
@ -165,7 +166,7 @@ class StandardWidget(val context: Context) {
// Action next event
views.setImageViewBitmap(
R.id.action_next_rect,
BitmapHelper.getBitmapFromView(bindingView.actionNext, draw = false)
BitmapHelper.getBitmapFromView(bindingView.actionNext, draw = false, width = bindingView.actionNext.width, height = bindingView.actionNext.height)
)
views.setViewVisibility(R.id.action_next_rect, View.VISIBLE)
views.setOnClickPendingIntent(
@ -184,7 +185,7 @@ class StandardWidget(val context: Context) {
// Action previous event
views.setImageViewBitmap(
R.id.action_previous_rect,
BitmapHelper.getBitmapFromView(bindingView.actionPrevious, draw = false)
BitmapHelper.getBitmapFromView(bindingView.actionPrevious, draw = false, width = bindingView.actionPrevious.width, height = bindingView.actionPrevious.height)
)
views.setViewVisibility(R.id.action_previous_rect, View.VISIBLE)
views.setOnClickPendingIntent(
@ -223,11 +224,18 @@ class StandardWidget(val context: Context) {
R.id.next_event_difference_time_rect,
BitmapHelper.getBitmapFromView(
bindingView.nextEventDifferenceTime,
draw = false
draw = false,
width = bindingView.nextEventDifferenceTime.width,
height = bindingView.nextEventDifferenceTime.height
)
)
views.setViewVisibility(R.id.next_event_difference_time_rect, View.VISIBLE)
views.setOnClickPendingIntent(R.id.next_event_difference_time_rect, eventIntent)
if (!Preferences.showNextEventOnMultipleLines) {
views.setViewVisibility(R.id.next_event_difference_time_rect, View.VISIBLE)
} else {
views.setViewVisibility(R.id.next_event_difference_time_rect, View.GONE)
}
} else {
views.setViewVisibility(R.id.next_event_difference_time_rect, View.GONE)
}
@ -257,7 +265,7 @@ class StandardWidget(val context: Context) {
views.setImageViewBitmap(
R.id.next_event_rect,
BitmapHelper.getBitmapFromView(bindingView.nextEvent, draw = false)
BitmapHelper.getBitmapFromView(bindingView.nextEvent, draw = false, width = bindingView.nextEvent.width, height = bindingView.nextEvent.height)
)
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
views.setViewVisibility(R.id.sub_line_rect, View.VISIBLE)
@ -388,7 +396,7 @@ class StandardWidget(val context: Context) {
if (showSomething) {
views.setImageViewBitmap(
R.id.sub_line_rect,
BitmapHelper.getBitmapFromView(bindingView.subLine, draw = false)
BitmapHelper.getBitmapFromView(bindingView.subLine, draw = false, width = bindingView.subLine.width, height = bindingView.subLine.height)
)
views.setViewVisibility(R.id.first_line_rect, View.VISIBLE)
@ -402,6 +410,17 @@ class StandardWidget(val context: Context) {
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 {
views.setViewVisibility(R.id.first_line_rect, View.VISIBLE)
views.setViewVisibility(R.id.weather_rect, View.VISIBLE)
views.setViewVisibility(R.id.calendar_layout_rect, View.GONE)
views.setViewVisibility(R.id.sub_line_rect, View.GONE)
views.setViewVisibility(R.id.weather_sub_line_rect, View.GONE)
// 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)
}
} catch (ex: Exception) {
ex.printStackTrace()
@ -480,8 +499,16 @@ class StandardWidget(val context: Context) {
bindingView.nextEvent.text = nextEvent.title
if (Preferences.showNextEventOnMultipleLines) {
bindingView.nextEvent.apply {
isSingleLine = false
maxLines = 3
gravity = Gravity.CENTER
}
}
if (Preferences.showDiffTime && now.timeInMillis < nextEvent.startDate) {
bindingView.nextEventDifferenceTime.text = if (!nextEvent.allDay) {
val diffTime = if (!nextEvent.allDay) {
SettingsStringHelper.getDifferenceText(
context,
now.timeInMillis,
@ -495,7 +522,14 @@ class StandardWidget(val context: Context) {
nextEvent.startDate
).toLowerCase(Locale.getDefault())
}
bindingView.nextEventDifferenceTime.isVisible = true
bindingView.nextEventDifferenceTime.text = diffTime
if (!Preferences.showNextEventOnMultipleLines) {
bindingView.nextEventDifferenceTime.isVisible = true
} else {
bindingView.nextEvent.text = context.getString(R.string.events_glance_provider_format).format(nextEvent.title, diffTime)
bindingView.nextEventDifferenceTime.isVisible = false
}
} else {
bindingView.nextEventDifferenceTime.isVisible = false
}

View File

@ -265,3 +265,11 @@ fun View.setOnSingleClickListener(l: View.OnClickListener) {
fun View.setOnSingleClickListener(l: (View) -> Unit) {
setOnClickListener(OnSingleClickListener(l))
}
fun ignoreExceptions(function: () -> Unit) = run {
try {
function.invoke()
} catch (ex: Exception) {
ex.printStackTrace()
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 674 B

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:color="@color/colorAccent_op30" />
<item android:state_selected="true" android:color="@color/colorAccent_op10" />
<item android:color="@color/colorPrimary" />
</selector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M16.5,4h-13C2.67,4 2,4.67 2,5.5v9C2,15.33 2.67,16 3.5,16h13c0.83,0 1.5,-0.67 1.5,-1.5v-9C18,4.67 17.33,4 16.5,4zM11.25,13h-5.5C5.34,13 5,12.66 5,12.25v0c0,-0.41 0.34,-0.75 0.75,-0.75h5.5c0.41,0 0.75,0.34 0.75,0.75v0C12,12.66 11.66,13 11.25,13zM14.25,10h-5.5C8.34,10 8,9.66 8,9.25v0C8,8.84 8.34,8.5 8.75,8.5h5.5C14.66,8.5 15,8.84 15,9.25v0C15,9.66 14.66,10 14.25,10zM6.5,9.27c0,0.41 -0.34,0.75 -0.75,0.75S5,9.68 5,9.27c0,-0.41 0.34,-0.75 0.75,-0.75S6.5,8.85 6.5,9.27zM15,12.25c0,0.41 -0.34,0.75 -0.75,0.75s-0.75,-0.34 -0.75,-0.75s0.34,-0.75 0.75,-0.75S15,11.84 15,12.25z"/>
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M20,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM5,12h2c0.55,0 1,0.45 1,1s-0.45,1 -1,1L5,14c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1zM13,18L5,18c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h8c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM19,18h-2c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2c0.55,0 1,0.45 1,1s-0.45,1 -1,1zM19,14h-8c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h8c0.55,0 1,0.45 1,1s-0.45,1 -1,1z"/>
</vector>

View File

@ -41,6 +41,35 @@
android:id="@+id/header_text"
android:text="@string/settings_font_color_title"
android:textColor="@color/colorPrimaryText"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:orientation="horizontal"
android:layout_marginTop="4dp"
android:gravity="center_vertical"
android:id="@+id/action_container">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="40dp"
android:layout_height="48dp"
android:padding="8dp"
android:clickable="true"
android:focusable="true"
android:tint="@color/colorPrimaryText"
android:background="?attr/selectableItemBackgroundBorderless"
android:id="@+id/action_copy"
android:src="@drawable/round_content_copy_24" />
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="8dp"
android:clickable="true"
android:focusable="true"
android:tint="@color/colorPrimaryText"
android:background="?attr/selectableItemBackgroundBorderless"
android:id="@+id/action_paste"
android:src="@drawable/round_content_paste_24" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
@ -52,6 +81,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/alpha_selector_container"
android:visibility="gone"
android:layout_marginTop="-2dp"
android:background="@color/colorPrimary"
android:gravity="center_vertical"
@ -115,6 +145,6 @@
android:indeterminate="true"
android:layout_margin="32dp"
android:layout_centerInParent="true"
android:id="@+id/color_loader" />
android:id="@+id/loader" />
</RelativeLayout>
</LinearLayout>

View File

@ -9,6 +9,7 @@
app:cardCornerRadius="8dp"
android:clickable="true"
android:focusable="true"
android:id="@+id/item"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"

View File

@ -253,6 +253,55 @@
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:textAppearance="@style/AnotherWidget.Settings.Header" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:id="@+id/action_show_next_event_on_multiple_lines"
android:orientation="horizontal">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="12dp"
android:scaleY="-1"
android:src="@drawable/round_subtitles_24"
app:tint="@color/colorPrimaryText"/>
<LinearLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Settings.Title"
android:text="@string/settings_show_next_event_on_multiple_lines_title"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/show_next_event_on_multiple_lines_label"
style="@style/AnotherWidget.Settings.Subtitle"/>
</LinearLayout>
<com.kyleduo.switchbutton.SwitchButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:kswThumbWidth="16sp"
app:kswThumbHeight="16sp"
app:kswBackRadius="16dp"
app:kswTintColor="@color/colorAccent"
android:layout_marginEnd="16dp"
android:id="@+id/show_next_event_on_multiple_lines_toggle"
android:buttonTint="@color/colorAccent" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -72,7 +72,7 @@
android:layout_weight="1"
android:maxLines="1"
android:lines="1"
android:gravity="end"
android:gravity="start"
android:ellipsize="end"
android:includeFontPadding="false"
android:layout_height="wrap_content"
@ -85,7 +85,6 @@
android:id="@+id/next_event_difference_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:includeFontPadding="false"
style="@style/AnotherWidget.Widget.Title" />
</LinearLayout>

View File

@ -112,6 +112,7 @@
<string name="calendar_sync_notification_channel_name">Events sync service</string>
<string name="calendar_sync_notification_channel_description">Service used to synchronize the calendar events.</string>
<string name="calendar_sync_notification_title">Syncing calendar events…</string>
<string name="settings_show_next_event_on_multiple_lines_title">Show title on multiple lines</string>
<!-- Weather -->
<string name="settings_weather_title">Weather</string>
@ -368,4 +369,8 @@
<string name="smart_content_header">Smart content</string>
<string name="spacing_settings_header">Spacing</string>
<string name="gestures_refresh_widget">None, the widget will be refreshed</string>
<string name="settings_disabled">Disabled</string>
<string name="settings_enabled">Enabled</string>
<string name="color_copied">Color copied into the clipboard.</string>
<string name="error_copy_color">The color cannot be copied.</string>
</resources>