Update the glance section

This commit is contained in:
Tommaso Berlose 2020-10-13 16:55:42 +02:00
parent abafe108c6
commit 0a0c5a90a7
60 changed files with 665 additions and 709 deletions

View File

@ -120,7 +120,7 @@
<service android:name=".services.BatteryListenerJob" android:permission="android.permission.BIND_JOB_SERVICE" />
<service android:name=".receivers.MusicNotificationListener"
<service android:name=".receivers.NotificationListener"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />

View File

@ -1,98 +0,0 @@
package com.tommasoberlose.anotherwidget.components
import android.content.Context
import android.content.res.ColorStateList
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
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.global.Constants
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
import com.tommasoberlose.anotherwidget.helpers.GlanceProviderHelper
import com.tommasoberlose.anotherwidget.models.GlanceProvider
import kotlinx.android.synthetic.main.glance_provider_sort_bottom_menu.view.*
import kotlinx.coroutines.*
import net.idik.lib.slimadapter.SlimAdapter
import java.util.*
import kotlin.collections.ArrayList
class GlanceProviderSortMenu(
context: Context
) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
private lateinit var adapter: SlimAdapter
override fun show() {
val view = View.inflate(context, R.layout.glance_provider_sort_bottom_menu, null)
// Header
view.header_text.text = context.getString(R.string.settings_sort_glance_providers_title)
// List
adapter = SlimAdapter.create()
view.menu.setHasFixedSize(true)
val mLayoutManager = LinearLayoutManager(context)
view.menu.layoutManager = mLayoutManager
adapter = SlimAdapter.create()
adapter
.register<GlanceProvider>(R.layout.glance_provider_item) { item, injector ->
injector
.text(R.id.title, item.title)
.with<ImageView>(R.id.icon) {
it.setImageDrawable(ContextCompat.getDrawable(context, item.icon))
}
}
.attachTo(view.menu)
val mIth = ItemTouchHelper(
object : ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP or ItemTouchHelper.DOWN,
ItemTouchHelper.LEFT
) {
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder
): Boolean {
val fromPos = viewHolder.adapterPosition
val toPos = target.adapterPosition
// move item in `fromPos` to `toPos` in adapter.
adapter.notifyItemMoved(fromPos, toPos)
val list = GlanceProviderHelper.getGlanceProviders(context)
Collections.swap(list, fromPos, toPos)
GlanceProviderHelper.saveGlanceProviderOrder(list)
return true
}
override fun onSwiped(
viewHolder: RecyclerView.ViewHolder,
direction: Int
) {
// remove from adapter
}
})
mIth.attachToRecyclerView(view.menu)
adapter.updateData(
GlanceProviderHelper.getGlanceProviders(context)
.mapNotNull { GlanceProviderHelper.getGlanceProviderById(context, it) }
)
setContentView(view)
super.show()
}
}

View File

@ -0,0 +1,229 @@
package com.tommasoberlose.anotherwidget.components
import android.Manifest
import android.app.Activity
import android.app.AlarmManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.core.app.NotificationManagerCompat
import androidx.core.view.isVisible
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.karumi.dexter.Dexter
import com.karumi.dexter.MultiplePermissionsReport
import com.karumi.dexter.PermissionToken
import com.karumi.dexter.listener.PermissionRequest
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.AlarmHelper
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
import com.tommasoberlose.anotherwidget.ui.activities.MusicPlayersFilterActivity
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
import kotlinx.android.synthetic.main.fragment_glance_settings.*
import kotlinx.android.synthetic.main.glance_provider_settings_layout.view.*
class GlanceSettingsDialog(val context: Activity, val provider: Constants.GlanceProviderId, val statusCallback: (() -> Unit)?) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
override fun show() {
val view = View.inflate(context, R.layout.glance_provider_settings_layout, null)
/* TITLE */
view.title.text = when (provider) {
Constants.GlanceProviderId.PLAYING_SONG -> context.getString(R.string.settings_show_music_title)
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> context.getString(R.string.settings_show_next_alarm_title)
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> context.getString(R.string.settings_low_battery_level_title)
Constants.GlanceProviderId.CUSTOM_INFO -> context.getString(R.string.settings_custom_notes_title)
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> context.getString(R.string.settings_daily_steps_title)
}
/* SUBTITLE*/
view.subtitle.text = when (provider) {
Constants.GlanceProviderId.PLAYING_SONG -> context.getString(R.string.settings_show_music_subtitle)
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> context.getString(R.string.settings_show_next_alarm_subtitle)
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> context.getString(R.string.settings_low_battery_level_subtitle)
Constants.GlanceProviderId.CUSTOM_INFO -> ""
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> context.getString(R.string.settings_daily_steps_subtitle)
}
/* SONG */
view.action_filter_music_players.isVisible = provider == Constants.GlanceProviderId.PLAYING_SONG
view.action_filter_music_players.setOnClickListener {
context.startActivity(Intent(context, MusicPlayersFilterActivity::class.java))
}
if (provider == Constants.GlanceProviderId.PLAYING_SONG) {
checkNotificationPermission(view)
}
/* ALARM */
view.alarm_set_by_container.isVisible = provider == Constants.GlanceProviderId.NEXT_CLOCK_ALARM
if (provider == Constants.GlanceProviderId.NEXT_CLOCK_ALARM) {
view.header.text = context.getString(R.string.information_header)
}
if (provider == Constants.GlanceProviderId.NEXT_CLOCK_ALARM) {
view.warning_container.isVisible = false
checkNextAlarm(view)
}
/* GOOGLE STEPS */
if (provider == Constants.GlanceProviderId.GOOGLE_FIT_STEPS) {
checkFitnessPermission(view)
}
/* BATTERY INFO */
view.header.isVisible = provider != Constants.GlanceProviderId.BATTERY_LEVEL_LOW
if (provider == Constants.GlanceProviderId.BATTERY_LEVEL_LOW) {
view.warning_container.isVisible = false
view.divider.isVisible = false
}
/* CUSTOM NOTES */
view.subtitle.isVisible = provider != Constants.GlanceProviderId.CUSTOM_INFO
view.provider_switch.isVisible = provider != Constants.GlanceProviderId.CUSTOM_INFO
/* TOGGLE */
view.provider_switch.isChecked = when (provider) {
Constants.GlanceProviderId.PLAYING_SONG -> Preferences.showMusic
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> Preferences.showNextAlarm
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> Preferences.showBatteryCharging
Constants.GlanceProviderId.CUSTOM_INFO -> true
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> Preferences.showDailySteps
}
view.provider_switch.setOnCheckedChangeListener { _, isChecked ->
when (provider) {
Constants.GlanceProviderId.PLAYING_SONG -> {
Preferences.showMusic = isChecked
checkNotificationPermission(view)
}
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
Preferences.showNextAlarm = isChecked
checkNextAlarm(view)
}
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
Preferences.showBatteryCharging = isChecked
}
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
if (isChecked) {
val account: GoogleSignInAccount? = GoogleSignIn.getLastSignedInAccount(context)
if (!GoogleSignIn.hasPermissions(account,
ActivityDetectionReceiver.FITNESS_OPTIONS
)) {
val mGoogleSignInClient = GoogleSignIn.getClient(context, GoogleSignInOptions.Builder(
GoogleSignInOptions.DEFAULT_SIGN_IN).addExtension(
ActivityDetectionReceiver.FITNESS_OPTIONS
).build())
context.startActivityForResult(mGoogleSignInClient.signInIntent, 2)
} else {
Preferences.showDailySteps = true
}
} else {
Preferences.showDailySteps = false
}
checkFitnessPermission(view)
}
else -> {}
}
statusCallback?.invoke()
}
setContentView(view)
super.show()
}
private fun checkNextAlarm(view: View) {
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
val alarm = nextAlarmClock
if (alarm != null && alarm.showIntent != null) {
val pm = context.packageManager as PackageManager
val appNameOrPackage = try {
pm.getApplicationLabel(pm.getApplicationInfo(alarm.showIntent?.creatorPackage ?: "", 0))
} catch (e: Exception) {
alarm.showIntent?.creatorPackage ?: ""
}
view.alarm_set_by_title.text = context.getString(R.string.settings_show_next_alarm_app_title).format(appNameOrPackage)
view.alarm_set_by_subtitle.text = if (AlarmHelper.isAlarmProbablyWrong(context)) context.getString(R.string.settings_show_next_alarm_app_subtitle_wrong) else context.getString(R.string.settings_show_next_alarm_app_subtitle_correct)
view.alarm_set_by_title.isVisible = true
} else {
view.alarm_set_by_title.isVisible = false
}
}
statusCallback?.invoke()
}
private fun checkNotificationPermission(view: View) {
when {
NotificationManagerCompat.getEnabledListenerPackages(context).contains(context.packageName) -> {
view.warning_container.isVisible = false
MediaPlayerHelper.updatePlayingMediaInfo(context)
}
Preferences.showMusic -> {
view.warning_container.isVisible = true
view.warning_title.text = context.getString(R.string.settings_request_notification_access)
view.warning_container.setOnClickListener {
context.startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
}
Log.d("ciao", "ok: ${view.warning_container.isVisible}")
}
else -> {
view.warning_container.isVisible = false
}
}
statusCallback?.invoke()
}
private fun checkFitnessPermission(view: View) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || context.checkGrantedPermission(
Manifest.permission.ACTIVITY_RECOGNITION)
) {
view.warning_container.isVisible = false
if (Preferences.showDailySteps) {
ActivityDetectionReceiver.registerFence(context)
} else {
ActivityDetectionReceiver.unregisterFence(context)
}
} else if (Preferences.showDailySteps) {
ActivityDetectionReceiver.unregisterFence(context)
view.warning_container.isVisible = true
view.warning_title.text = context.getString(R.string.settings_request_fitness_access)
view.warning_container.setOnClickListener {
requireFitnessPermission(view)
}
} else {
ActivityDetectionReceiver.unregisterFence(context)
view.warning_container.isVisible = false
}
statusCallback?.invoke()
}
private fun requireFitnessPermission(view: View) {
Dexter.withContext(context)
.withPermissions(
"com.google.android.gms.permission.ACTIVITY_RECOGNITION",
"android.gms.permission.ACTIVITY_RECOGNITION",
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACTIVITY_RECOGNITION else "com.google.android.gms.permission.ACTIVITY_RECOGNITION"
).withListener(object: MultiplePermissionsListener {
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
checkFitnessPermission(view)
}
override fun onPermissionRationaleShouldBeShown(
permissions: MutableList<PermissionRequest>?,
token: PermissionToken?
) {
// Remember to invoke this method when the custom rationale is closed
// or just by default if you don't want to use any custom rationale.
token?.continuePermissionRequest()
}
})
.check()
}
}

View File

@ -30,7 +30,12 @@ object Constants {
NEXT_CLOCK_ALARM("NEXT_CLOCK_ALARM"),
BATTERY_LEVEL_LOW("BATTERY_LEVEL_LOW"),
CUSTOM_INFO("CUSTOM_INFO"),
GOOGLE_FIT_STEPS("GOOGLE_FIT_STEPS")
GOOGLE_FIT_STEPS("GOOGLE_FIT_STEPS");
companion object {
private val map = GlanceProviderId.values().associateBy(GlanceProviderId::id)
fun from(type: String) = map[type]
}
}
enum class WidgetUpdateFrequency(val value: Int) {

View File

@ -123,6 +123,7 @@ object Preferences : KotprefModel() {
var isCharging by booleanPref(default = false)
var googleFitSteps by longPref(default = -1)
var showDailySteps by booleanPref(default = false)
var showNotifications by booleanPref(default = false)
var showMusic by booleanPref(default = false)
var mediaInfoFormat by stringPref(default = "")

View File

@ -0,0 +1,19 @@
package com.tommasoberlose.anotherwidget.helpers
import android.app.NotificationManager
import android.content.Context
import android.service.notification.StatusBarNotification
import android.util.Log
import com.google.gson.Gson
object ActiveNotificationsHelper {
fun getLastNotification(context: Context): StatusBarNotification? {
with(context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager) {
activeNotifications.forEach {
Log.d("ciao", Gson().toJson(it).toString())
}
return activeNotifications.lastOrNull()
}
}
}

View File

@ -82,13 +82,15 @@ object GlanceProviderHelper {
val eventRepository = EventRepository(context)
BatteryHelper.updateBatteryInfo(context)
val showGlance = Preferences.showGlance && (eventRepository.getEventsCount() == 0 || !Preferences.showEvents) && (
val showGlance = Preferences.showGlance && (eventRepository.getEventsCount() == 0 || !Preferences.showEvents)
&& (
(Preferences.showNextAlarm && AlarmHelper.getNextAlarm(context) != "") ||
(MediaPlayerHelper.isSomeonePlaying(context)) ||
(Preferences.showBatteryCharging && Preferences.isCharging || Preferences.isBatteryLevelLow) ||
(Preferences.customNotes.isNotEmpty()) ||
(Preferences.showDailySteps && Preferences.googleFitSteps > 0)
)
(Preferences.showDailySteps && Preferences.googleFitSteps > 0) ||
(Preferences.showNotifications && ActiveNotificationsHelper.getLastNotification(context) != null)
)
eventRepository.close()
return showGlance
}

View File

@ -1,20 +1,17 @@
package com.tommasoberlose.anotherwidget.helpers
import android.app.Notification
import android.content.ComponentName
import android.content.Context
import android.media.MediaMetadata
import android.media.session.MediaController
import android.media.session.MediaSession
import android.media.session.MediaSessionManager
import android.media.session.PlaybackState
import android.util.Log
import androidx.core.app.NotificationManagerCompat
import com.chibatching.kotpref.Kotpref
import com.chibatching.kotpref.blockingBulk
import com.chibatching.kotpref.bulk
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.receivers.MusicNotificationListener
import com.tommasoberlose.anotherwidget.receivers.NotificationListener
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import java.lang.Exception
@ -34,7 +31,7 @@ object MediaPlayerHelper {
if (NotificationManagerCompat.getEnabledListenerPackages(context).contains(context.packageName)) {
val list = try {
(context.getSystemService(Context.MEDIA_SESSION_SERVICE) as MediaSessionManager).getActiveSessions(
ComponentName(context.packageName, MusicNotificationListener::class.java.name)
ComponentName(context.packageName, NotificationListener::class.java.name)
)
} catch (ex: Exception) {
emptyList<MediaController>()

View File

@ -9,15 +9,17 @@ import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification
import android.util.Log
import com.chibatching.kotpref.bulk
import com.google.gson.Gson
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
import com.tommasoberlose.anotherwidget.helpers.WidgetHelper
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
class MusicNotificationListener : NotificationListenerService() {
class NotificationListener : NotificationListenerService() {
override fun onListenerConnected() {
MediaPlayerHelper.updatePlayingMediaInfo(this)
MainWidget.updateWidget(this)
super.onListenerConnected()
}
@ -27,11 +29,17 @@ class MusicNotificationListener : NotificationListenerService() {
MediaPlayerHelper.updatePlayingMediaInfo(this)
}
}
Log.d("ciao", Gson().toJson(sbn?.notification?.smallIcon))
Log.d("ciao", Gson().toJson(sbn?.notification?.contentIntent))
Log.d("ciao", Gson().toJson(sbn?.notification))
MainWidget.updateWidget(this)
super.onNotificationPosted(sbn)
}
override fun onNotificationRemoved(sbn: StatusBarNotification?) {
MediaPlayerHelper.updatePlayingMediaInfo(this)
MainWidget.updateWidget(this)
super.onNotificationRemoved(sbn)
}
}

View File

@ -16,13 +16,18 @@ import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
@ -33,14 +38,14 @@ import com.karumi.dexter.PermissionToken
import com.karumi.dexter.listener.PermissionRequest
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
import com.tommasoberlose.anotherwidget.components.CustomNotesDialog
import com.tommasoberlose.anotherwidget.components.GlanceProviderSortMenu
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
import com.tommasoberlose.anotherwidget.components.*
import com.tommasoberlose.anotherwidget.databinding.FragmentGlanceSettingsBinding
import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.AlarmHelper
import com.tommasoberlose.anotherwidget.helpers.GlanceProviderHelper
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
import com.tommasoberlose.anotherwidget.models.GlanceProvider
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver.Companion.FITNESS_OPTIONS
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
@ -54,6 +59,8 @@ import kotlinx.android.synthetic.main.fragment_glance_settings.*
import kotlinx.android.synthetic.main.fragment_glance_settings.scrollView
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import net.idik.lib.slimadapter.SlimAdapter
import java.util.*
class GlanceTabFragment : Fragment() {
@ -62,6 +69,8 @@ class GlanceTabFragment : Fragment() {
fun newInstance() = GlanceTabFragment()
}
private var dialog: GlanceSettingsDialog? = null
private lateinit var adapter: SlimAdapter
private lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
@ -87,10 +96,125 @@ class GlanceTabFragment : Fragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
action_show_steps.isVisible = requireContext().checkIfFitInstalled()
// List
adapter = SlimAdapter.create()
providers_list.setHasFixedSize(true)
val mLayoutManager = LinearLayoutManager(context)
providers_list.layoutManager = mLayoutManager
adapter = SlimAdapter.create()
adapter
.register<GlanceProvider>(R.layout.glance_provider_item) { item, injector ->
val provider = Constants.GlanceProviderId.from(item.id)!!
injector
.text(R.id.title, item.title)
.with<ImageView>(R.id.icon) {
it.setImageDrawable(ContextCompat.getDrawable(requireContext(), item.icon))
}
.clicked(R.id.item) {
if (Preferences.showGlance) {
if (provider == Constants.GlanceProviderId.CUSTOM_INFO) {
CustomNotesDialog(requireContext()).show()
} else {
dialog = GlanceSettingsDialog(requireActivity(), provider) {
adapter.notifyItemRangeChanged(0, adapter.data.size)
}
dialog?.setOnDismissListener {
dialog = null
}
dialog?.show()
}
}
}
when (provider) {
Constants.GlanceProviderId.PLAYING_SONG -> {
when {
NotificationManagerCompat.getEnabledListenerPackages(requireContext()).contains(requireContext().packageName) -> {
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
injector.invisible(R.id.error_icon)
injector.text(R.id.label, if (Preferences.showMusic) getString(R.string.settings_visible) else getString(R.string.settings_not_visible))
}
Preferences.showMusic -> {
injector.visible(R.id.error_icon)
injector.text(R.id.label, getString(R.string.settings_not_visible))
}
else -> {
injector.invisible(R.id.error_icon)
injector.text(R.id.label, getString(R.string.settings_not_visible))
}
}
}
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
injector.text(R.id.label, if (Preferences.showNextAlarm && !AlarmHelper.isAlarmProbablyWrong(requireContext())) getString(R.string.settings_visible) else getString(R.string.settings_not_visible))
injector.visibility(R.id.error_icon, if (Preferences.showNextAlarm && AlarmHelper.isAlarmProbablyWrong(requireContext())) View.VISIBLE else View.GONE)
}
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
injector.text(R.id.label, if (Preferences.showBatteryCharging) getString(R.string.settings_visible) else getString(R.string.settings_not_visible))
injector.invisible(R.id.error_icon)
}
Constants.GlanceProviderId.CUSTOM_INFO -> {
injector.text(R.id.label, if (Preferences.customNotes != "") getString(R.string.settings_visible) else getString(R.string.settings_not_visible))
injector.invisible(R.id.error_icon)
}
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || activity?.checkGrantedPermission(Manifest.permission.ACTIVITY_RECOGNITION) == true) {
injector.text(R.id.label, if (Preferences.showDailySteps) getString(R.string.settings_visible) else getString(R.string.settings_not_visible))
injector.invisible(R.id.error_icon)
} else if (Preferences.showDailySteps) {
ActivityDetectionReceiver.unregisterFence(requireContext())
injector.visible(R.id.error_icon)
injector.text(R.id.label, getString(R.string.settings_not_visible))
} else {
ActivityDetectionReceiver.unregisterFence(requireContext())
injector.text(R.id.label, getString(R.string.settings_not_visible))
injector.invisible(R.id.error_icon)
}
}
}
}
.attachTo(providers_list)
val mIth = ItemTouchHelper(
object : ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP or ItemTouchHelper.DOWN,
0
) {
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder
): Boolean {
val fromPos = viewHolder.adapterPosition
val toPos = target.adapterPosition
// move item in `fromPos` to `toPos` in adapter.
adapter.notifyItemMoved(fromPos, toPos)
val list = GlanceProviderHelper.getGlanceProviders(requireContext())
Collections.swap(list, fromPos, toPos)
GlanceProviderHelper.saveGlanceProviderOrder(list)
return true
}
override fun getSwipeThreshold(viewHolder: RecyclerView.ViewHolder): Float {
return 1f
}
override fun onSwiped(
viewHolder: RecyclerView.ViewHolder,
direction: Int
) {
// remove from adapter
}
})
mIth.attachToRecyclerView(providers_list)
adapter.updateData(
GlanceProviderHelper.getGlanceProviders(requireContext())
.mapNotNull { GlanceProviderHelper.getGlanceProviderById(requireContext(), it) }
)
providers_list.isNestedScrollingEnabled = false
setupListener()
updateNextAlarmWarningUi()
}
private fun subscribeUi(
@ -105,45 +229,9 @@ class GlanceTabFragment : Fragment() {
show_glance_label.text = if (it) getString(R.string.description_show_glance_visible) else getString(R.string.description_show_glance_not_visible)
}
})
viewModel.showMusic.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
checkNotificationPermission()
}
})
viewModel.showNextAlarm.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
updateNextAlarmWarningUi()
}
})
viewModel.showBatteryCharging.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
show_low_battery_level_warning_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
}
})
viewModel.showDailySteps.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
show_steps_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
}
checkFitnessPermission()
})
viewModel.customInfo.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
show_custom_notes_label?.text = if (it == "") getString(R.string.settings_not_visible) else it
}
})
viewModel.musicPlayersFilter.observe(viewLifecycleOwner, Observer {
})
}
private fun setupListener() {
action_show_glance.setOnClickListener {
Preferences.showGlance = !Preferences.showGlance
}
@ -151,134 +239,20 @@ class GlanceTabFragment : Fragment() {
show_glance_switch.setOnCheckedChangeListener { _, enabled: Boolean ->
Preferences.showGlance = enabled
}
action_sort_glance_providers.setOnClickListener {
GlanceProviderSortMenu(requireContext())
.show()
}
action_show_music.setOnClickListener {
if (Preferences.showGlance) {
BottomSheetMenu<Boolean>(
requireContext(),
header = getString(R.string.settings_show_music_title)
).setSelectedValue(Preferences.showMusic)
.addItem(getString(R.string.settings_visible), true)
.addItem(getString(R.string.settings_not_visible), false)
.addOnSelectItemListener { value ->
Preferences.showMusic = value
}.show()
}
}
action_show_next_alarm.setOnClickListener {
if (Preferences.showGlance) {
BottomSheetMenu<Boolean>(
requireContext(),
header = getString(R.string.settings_show_next_alarm_title)
).setSelectedValue(Preferences.showNextAlarm)
.addItem(getString(R.string.settings_visible), true)
.addItem(getString(R.string.settings_not_visible), false)
.addOnSelectItemListener { value ->
Preferences.showNextAlarm = value
}.show()
}
}
action_show_next_alarm.setOnLongClickListener {
with(requireContext().getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
val alarm = nextAlarmClock
if (alarm != null && alarm.showIntent != null) {
val pm = requireContext().packageManager as PackageManager
val appNameOrPackage = try {
pm.getApplicationLabel(pm.getApplicationInfo(alarm.showIntent?.creatorPackage ?: "", 0))
} catch (e: Exception) {
alarm.showIntent?.creatorPackage ?: ""
}
MaterialBottomSheetDialog(requireContext(), message = getString(R.string.next_alarm_warning).format(appNameOrPackage))
.setPositiveButton(getString(android.R.string.ok))
.show()
}
}
true
}
action_show_low_battery_level_warning.setOnClickListener {
if (Preferences.showGlance) {
BottomSheetMenu<Boolean>(
requireContext(),
header = getString(R.string.settings_low_battery_level_title)
).setSelectedValue(Preferences.showBatteryCharging)
.addItem(getString(R.string.settings_visible), true)
.addItem(getString(R.string.settings_not_visible), false)
.addOnSelectItemListener { value ->
Preferences.showBatteryCharging = value
}.show()
}
}
action_show_steps.setOnClickListener {
if (Preferences.showGlance) {
BottomSheetMenu<Boolean>(
requireContext(),
header = getString(R.string.settings_daily_steps_title)
).setSelectedValue(Preferences.showDailySteps)
.addItem(getString(R.string.settings_visible), true)
.addItem(getString(R.string.settings_not_visible), false)
.addOnSelectItemListener { value ->
if (value) {
val account: GoogleSignInAccount? = GoogleSignIn.getLastSignedInAccount(requireContext())
if (!GoogleSignIn.hasPermissions(account, FITNESS_OPTIONS)) {
val mGoogleSignInClient = GoogleSignIn.getClient(requireActivity(), GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).addExtension(FITNESS_OPTIONS).build())
startActivityForResult(mGoogleSignInClient.signInIntent, 2)
} else {
Preferences.showDailySteps = true
}
} else {
Preferences.showDailySteps = false
}
}.show()
}
}
action_show_custom_notes.setOnClickListener {
if (Preferences.showGlance) {
CustomNotesDialog(requireContext()).show()
}
}
action_filter_music_players.setOnClickListener {
startActivity(Intent(requireContext(), MusicPlayersFilterActivity::class.java))
}
}
private fun updateNextAlarmWarningUi() {
with(requireContext().getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
val alarm = nextAlarmClock
if (AlarmHelper.isAlarmProbablyWrong(requireContext()) && alarm != null && alarm.showIntent != null) {
val pm = requireContext().packageManager as PackageManager
val appNameOrPackage = try {
pm.getApplicationLabel(pm.getApplicationInfo(alarm.showIntent?.creatorPackage ?: "", 0))
} catch (e: Exception) {
alarm.showIntent?.creatorPackage ?: ""
}
show_next_alarm_warning.text = getString(R.string.next_alarm_warning).format(appNameOrPackage)
} else {
show_next_alarm_label?.text = if (Preferences.showNextAlarm) getString(R.string.settings_visible) else getString(
R.string.settings_not_visible)
}
}
}
private val nextAlarmChangeBroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
updateNextAlarmWarningUi()
adapter.notifyItemChanged(1)
}
}
override fun onStart() {
super.onStart()
activity?.registerReceiver(nextAlarmChangeBroadcastReceiver, IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED))
if (dialog != null) {
dialog?.show()
}
}
override fun onStop() {
@ -286,50 +260,6 @@ class GlanceTabFragment : Fragment() {
super.onStop()
}
private fun checkNotificationPermission() {
when {
NotificationManagerCompat.getEnabledListenerPackages(requireContext()).contains(requireContext().packageName) -> {
notification_permission_alert?.isVisible = false
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
show_music_label?.text = if (Preferences.showMusic) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
}
Preferences.showMusic -> {
notification_permission_alert?.isVisible = true
show_music_label?.text = getString(R.string.settings_request_notification_access)
notification_permission_alert?.setOnClickListener {
activity?.startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
}
}
else -> {
show_music_label?.text = getString(R.string.settings_not_visible)
notification_permission_alert?.isVisible = false
}
}
}
private fun checkFitnessPermission() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || activity?.checkGrantedPermission(Manifest.permission.ACTIVITY_RECOGNITION) == true) {
fitness_permission_alert?.isVisible = false
if (Preferences.showDailySteps) {
ActivityDetectionReceiver.registerFence(requireContext())
} else {
ActivityDetectionReceiver.unregisterFence(requireContext())
}
show_steps_label?.text = if (Preferences.showDailySteps) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
} else if (Preferences.showDailySteps) {
ActivityDetectionReceiver.unregisterFence(requireContext())
fitness_permission_alert?.isVisible = true
show_steps_label?.text = getString(R.string.settings_request_fitness_access)
fitness_permission_alert?.setOnClickListener {
requireFitnessPermission()
}
} else {
ActivityDetectionReceiver.unregisterFence(requireContext())
show_steps_label?.text = getString(R.string.settings_not_visible)
fitness_permission_alert?.isVisible = false
}
}
override fun onActivityResult(
requestCode: Int,
resultCode: Int,
@ -338,9 +268,15 @@ class GlanceTabFragment : Fragment() {
when (requestCode) {
1 -> {
if (resultCode == Activity.RESULT_OK) {
checkFitnessPermission()
adapter.notifyItemChanged(2)
if (dialog != null) {
dialog?.show()
}
} else {
Preferences.showDailySteps = false
if (dialog != null) {
dialog?.show()
}
}
}
2-> {
@ -353,42 +289,22 @@ class GlanceTabFragment : Fragment() {
account,
FITNESS_OPTIONS)
} else {
checkFitnessPermission()
adapter.notifyItemChanged(2)
if (dialog != null) {
dialog?.show()
}
}
} catch (e: ApiException) {
e.printStackTrace()
Preferences.showDailySteps = false
if (dialog != null) {
dialog?.show()
}
}
}
}
}
private fun requireFitnessPermission() {
Dexter.withContext(requireContext())
.withPermissions(
"com.google.android.gms.permission.ACTIVITY_RECOGNITION",
"android.gms.permission.ACTIVITY_RECOGNITION",
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACTIVITY_RECOGNITION else "com.google.android.gms.permission.ACTIVITY_RECOGNITION"
).withListener(object: MultiplePermissionsListener {
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
report?.let {
if (report.areAllPermissionsGranted()){
checkFitnessPermission()
}
}
}
override fun onPermissionRationaleShouldBeShown(
permissions: MutableList<PermissionRequest>?,
token: PermissionToken?
) {
// Remember to invoke this method when the custom rationale is closed
// or just by default if you don't want to use any custom rationale.
token?.continuePermissionRequest()
}
})
.check()
}
private fun maintainScrollPosition(callback: () -> Unit) {
scrollView.isScrollable = false
callback.invoke()
@ -400,6 +316,6 @@ class GlanceTabFragment : Fragment() {
override fun onResume() {
super.onResume()
checkNotificationPermission()
adapter.notifyItemRangeChanged(0, adapter.data.size)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 466 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 778 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1005 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 707 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 707 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1005 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1005 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 778 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1005 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

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="M12,4c4.41,0 8,3.59 8,8s-3.59,8 -8,8s-8,-3.59 -8,-8S7.59,4 12,4M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2L12,2zM13,12l0,-3c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1l0,3H9.21c-0.45,0 -0.67,0.54 -0.35,0.85l2.79,2.79c0.2,0.2 0.51,0.2 0.71,0l2.79,-2.79c0.31,-0.31 0.09,-0.85 -0.35,-0.85H13z"/>
</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="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM13.88,11.54l-4.25,4.25c-0.39,0.39 -1.02,0.39 -1.41,0l0,0c-0.39,-0.39 -0.39,-1.02 0,-1.41l4.25,-4.25L11.2,8.86C10.88,8.54 11.11,8 11.55,8l3.94,0c0.28,0 0.5,0.22 0.5,0.5l0,3.94c0,0.45 -0.54,0.67 -0.85,0.35L13.88,11.54z"/>
</vector>

View File

@ -85,317 +85,19 @@
android:textColor="@color/colorAccent"
android:textAppearance="@style/AnotherWidget.Settings.Header"
app:textAllCaps="false" />
<LinearLayout
android:layout_width="match_parent"
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"
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_music"
android:orientation="horizontal">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="11dp"
android:src="@drawable/round_music_note"
app:tint="@color/colorPrimaryText"/>
<LinearLayout
android:layout_width="match_parent"
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_music_title"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/show_music_label"
style="@style/AnotherWidget.Settings.Subtitle"/>
<com.google.android.material.button.MaterialButton
android:layout_width="wrap_content"
android:layout_height="36dp"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:letterSpacing="0"
android:textAllCaps="false"
android:clickable="true"
android:layout_marginStart="-8dp"
android:layout_marginBottom="-8dp"
android:paddingBottom="0dp"
android:paddingTop="0dp"
android:focusable="true"
android:visibility="gone"
android:id="@+id/notification_permission_alert"
android:textColor="@color/errorColorText"
android:text="@string/action_grant_permission"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"
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_alarm"
android:orientation="horizontal">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="12dp"
android:src="@drawable/round_alarm"
app:tint="@color/colorPrimaryText"/>
<LinearLayout
android:layout_width="match_parent"
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_alarm_title"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/show_next_alarm_label"
style="@style/AnotherWidget.Settings.Subtitle"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Settings.Title"
android:textSize="14sp"
android:visibility="gone"
android:id="@+id/show_next_alarm_warning"
android:textColor="@color/warningColorText" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"
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_steps"
android:orientation="horizontal">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="11dp"
android:src="@drawable/round_directions_walk"
app:tint="@color/colorPrimaryText"/>
<LinearLayout
android:layout_width="match_parent"
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_daily_steps_title"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/show_steps_label"
style="@style/AnotherWidget.Settings.Subtitle"/>
<com.google.android.material.button.MaterialButton
android:layout_width="wrap_content"
android:layout_height="36dp"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:letterSpacing="0"
android:textAllCaps="false"
android:clickable="true"
android:layout_marginStart="-8dp"
android:layout_marginBottom="-8dp"
android:paddingBottom="0dp"
android:paddingTop="0dp"
android:focusable="true"
android:visibility="gone"
android:id="@+id/fitness_permission_alert"
android:textColor="@color/errorColorText"
android:text="@string/action_grant_permission"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"
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_low_battery_level_warning"
android:orientation="horizontal">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="12dp"
android:src="@drawable/round_battery_charging_full"
app:tint="@color/colorPrimaryText"/>
<LinearLayout
android:layout_width="match_parent"
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_low_battery_level_title"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/show_low_battery_level_warning_label"
style="@style/AnotherWidget.Settings.Subtitle"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"
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_custom_notes"
android:orientation="horizontal">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="12dp"
android:src="@drawable/round_notes"
app:tint="@color/colorPrimaryText"/>
<LinearLayout
android:layout_width="match_parent"
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_custom_notes_title"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/show_custom_notes_label"
style="@style/AnotherWidget.Settings.Subtitle"/>
</LinearLayout>
</LinearLayout>
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:text="@string/preferences_header"
android:textAlignment="viewStart"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:textSize="16sp"
android:textColor="@color/colorAccent"
android:textAppearance="@style/AnotherWidget.Settings.Header"
app:textAllCaps="false" />
<LinearLayout
android:textColor="@color/colorSecondaryText"
android:layout_marginBottom="16dp"
android:text="@string/settings_sort_glance_providers_subtitle"
android:textAppearance="@style/AnotherWidget.Settings.Header"/>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"
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_sort_glance_providers"
android:orientation="horizontal">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="11dp"
android:src="@drawable/round_flip_to_front"
app:tint="@color/colorPrimaryText"/>
<LinearLayout
android:layout_width="match_parent"
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_sort_glance_providers_title"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/settings_sort_glance_providers_subtitle"
style="@style/AnotherWidget.Settings.Subtitle"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"
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_filter_music_players"
android:orientation="horizontal">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="12dp"
android:src="@drawable/round_radio"
app:tint="@color/colorPrimaryText"/>
<LinearLayout
android:layout_width="match_parent"
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_music_players_filter_title"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/settings_music_players_filter_subtitle"
style="@style/AnotherWidget.Settings.Subtitle"/>
</LinearLayout>
</LinearLayout>
android:id="@+id/providers_list" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -4,24 +4,28 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:clickable="true"
android:focusable="true"
app:cardElevation="0dp"
app:cardBackgroundColor="@color/colorPrimary"
app:cardCornerRadius="9dp">
app:cardBackgroundColor="@color/colorPrimaryDark"
app:cardCornerRadius="3dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:id="@+id/item"
android:orientation="horizontal">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="12dp"
android:padding="11dp"
android:id="@+id/icon"
android:src="@drawable/round_music_note"
app:tint="@color/colorPrimaryText"/>
@ -35,20 +39,21 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/title"
android:textSize="16sp"
style="@style/AnotherWidget.Settings.Title"
android:id="@+id/title"
android:text="@string/settings_show_music_title"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/label"
style="@style/AnotherWidget.Settings.Subtitle"/>
</LinearLayout>
<ImageView
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="12dp"
android:clickable="true"
android:focusable="true"
android:background="?attr/selectableItemBackgroundBorderless"
android:id="@+id/action_drag"
android:src="@drawable/round_drag"
app:tint="@color/colorPrimaryText" />
android:src="@drawable/round_error"
app:tint="@color/errorColorText"
android:id="@+id/error_icon"/>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>

View File

@ -0,0 +1,178 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="56dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="16dp"
android:paddingBottom="24dp"
android:paddingLeft="32dp"
android:paddingRight="32dp">
<LinearLayout
android:layout_width="0dp"
android:layout_weight="1"
android:paddingEnd="16dp"
android:paddingStart="0dp"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Settings.Title"
android:gravity="start"
android:id="@+id/title"
android:textAlignment="viewStart"
android:text="@string/settings_weather_provider_open_weather"/>
<androidx.appcompat.widget.AppCompatTextView
android:textAppearance="@style/AnotherWidget.Settings.Subtitle"
app:textAllCaps="false"
android:letterSpacing="0"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
android:textAlignment="viewStart"
android:paddingTop="4dp"
android:id="@+id/subtitle"
android:text=""/>
</LinearLayout>
<com.google.android.material.switchmaterial.SwitchMaterial
android:layout_width="wrap_content"
android:layout_height="24dp"
android:id="@+id/provider_switch" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="1dp"
android:id="@+id/divider"
android:background="@color/disabledButtonBackground" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="@+id/settings_container">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingLeft="32dp"
android:paddingRight="32dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:background="@color/errorColorText_op10"
android:id="@+id/warning_container">
<androidx.appcompat.widget.AppCompatTextView
android:textSize="16sp"
style="@style/AnotherWidget.Settings.Title"
app:textAllCaps="false"
android:letterSpacing="0"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:gravity="start"
android:layout_marginEnd="16dp"
android:textAlignment="viewStart"
android:textColor="@color/errorColorText"
android:id="@+id/warning_title"
android:text="Errore"/>
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="10dp"
android:src="@drawable/round_arrow_circle_down"
android:rotation="-90"
app:tint="@color/errorColorText" />
</LinearLayout>
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:text="@string/preferences_header"
android:textAlignment="viewStart"
android:paddingLeft="32dp"
android:paddingRight="32dp"
android:textSize="16sp"
android:id="@+id/header"
android:textColor="@color/colorAccent"
android:textAppearance="@style/AnotherWidget.Settings.Header"
app:textAllCaps="false" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:gravity="center_vertical"
android:id="@+id/alarm_set_by_container"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
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:id="@+id/alarm_set_by_title"
android:textSize="16sp"
android:text="@string/settings_show_next_alarm_app_title"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:text="@string/settings_music_players_filter_subtitle"
android:id="@+id/alarm_set_by_subtitle"
style="@style/AnotherWidget.Settings.Subtitle"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:id="@+id/action_filter_music_players"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
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"
android:textSize="16sp"
style="@style/AnotherWidget.Settings.Title"
android:text="@string/settings_music_players_filter_title"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:text="@string/settings_music_players_filter_subtitle"
style="@style/AnotherWidget.Settings.Subtitle"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>

View File

@ -1,41 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/header"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:textAppearance="@style/AnotherWidget.Settings.Title"
app:textAllCaps="false"
android:letterSpacing="0"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="8dp"
android:paddingLeft="32dp"
android:paddingRight="32dp"
android:textSize="18sp"
android:gravity="start"
android:textAlignment="viewStart"
android:id="@+id/header_text"
android:text=""
android:textColor="@color/colorPrimaryText"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="16dp"
android:background="@color/disabledButtonBackground" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/menu"
android:clipToPadding="false"
android:paddingTop="16dp"
android:paddingBottom="16dp"/>
</LinearLayout>

View File

@ -40,7 +40,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/colorPrimaryDark" />
android:background="@color/disabledButtonBackground" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -176,7 +176,6 @@
<!-- Glance -->
<string name="settings_show_next_alarm_title">Prossimo allarme</string>
<string name="next_alarm_warning">Il prossimo allarme non sembra corretto. È stato impostato dall\'app %s.</string>
<string name="settings_at_a_glance_title">Glance</string>
<string name="settings_show_music_title">Canzone in riproduzione</string>
<string name="settings_request_notification_access">È necessario l\'accesso alle notifiche per controllare la canzone in riproduzione.</string>
@ -197,6 +196,13 @@
<string name="glance_info">Glance info will show up only when there are no events displayed and only when a few conditions are verified.</string>
<string name="settings_music_players_filter_title">Player Musica</string>
<string name="settings_music_players_filter_subtitle">Scegli i player musical che ti interessano</string>
<string name="settings_show_music_subtitle">Utilizziamo la notifica del tuo player di musica per mostrare la canzone in riproduzione.</string>
<string name="settings_low_battery_level_subtitle">Visualizza quando il dispositivo è in carica o ha la batteria scarica.</string>
<string name="settings_daily_steps_subtitle">Visualizza rapidamente i passi giornalieri una volta finita una camminata o una corsa.</string>
<string name="settings_show_next_alarm_subtitle">Guarda la tua prossima sveglia e verifica che la tua app Orologio sia l\'unica a impostare allarmi.</string>
<string name="settings_show_next_alarm_app_title">Allarme impostato da %s</string>
<string name="settings_show_next_alarm_app_subtitle_wrong">La prossima sveglia sembra impostata da un\'app errata. Disinstalla l\'app che imposta allarmi errati.</string>
<string name="settings_show_next_alarm_app_subtitle_correct">La prossima sveglia sembra corretta.</string>
<!-- Settings -->
<string name="action_share">Condividi</string>

View File

@ -29,6 +29,7 @@
<color name="colorSecondaryText">#99000000</color>
<color name="errorColorBackground">#FBD8D8</color>
<color name="errorColorText">#E93B3B</color>
<color name="errorColorText_op10">#1AE93B3B</color>
<color name="warningColorText">#FB8C00</color>
<color name="disabledButtonBackground">#efefef</color>
<color name="success">#43A047</color>

View File

@ -188,7 +188,6 @@
<!-- Glance -->
<string name="settings_show_next_alarm_title">Next clock alarm</string>
<string name="next_alarm_warning">The next alarm clock seems to be wrong.\nIt has been set by %s.</string>
<string name="settings_at_a_glance_title">Glance</string>
<string name="settings_show_music_title">Current playing song</string>
<string name="settings_request_notification_access">We need the notification access permission to check the current playing song.</string>
@ -197,7 +196,7 @@
<string name="description_show_glance_visible">Service enabled</string>
<string name="description_show_glance_not_visible">Service disabled</string>
<string name="settings_sort_glance_providers_title">Data source priority</string>
<string name="settings_sort_glance_providers_subtitle">Change the data provider importance</string>
<string name="settings_sort_glance_providers_subtitle">Change the data provider priority sorting the list below with a drag and drop of the rows.</string>
<string name="settings_custom_notes_title">Custom notes</string>
<string name="settings_low_battery_level_title">Battery</string>
<string name="settings_daily_steps_title">Daily steps</string>
@ -209,6 +208,13 @@
<string name="glance_info">Glance info will show up only when there are no events displayed and only when a few conditions are verified.</string>
<string name="settings_music_players_filter_title">Music Players</string>
<string name="settings_music_players_filter_subtitle">Choose your relevant music players</string>
<string name="settings_show_music_subtitle">We use the music players\' notification to show the current playing song.</string>
<string name="settings_low_battery_level_subtitle">Get notified when the device has the battery low or is charging.</string>
<string name="settings_daily_steps_subtitle">View your daily steps for a brief moment after when finishing a walk or a run.</string>
<string name="settings_show_next_alarm_subtitle">View your next clock alarm, check if your default clock app is the only one setting device alarms.</string>
<string name="settings_show_next_alarm_app_title">Alarm set by %s</string>
<string name="settings_show_next_alarm_app_subtitle_wrong">The next alarm clock seems to be wrong.</string>
<string name="settings_show_next_alarm_app_subtitle_correct">The next alarm clock seems to be correct.</string>
<!-- Settings -->
<string name="action_share">Share</string>