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=".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"> android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter> <intent-filter>
<action android:name="android.service.notification.NotificationListenerService" /> <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"), NEXT_CLOCK_ALARM("NEXT_CLOCK_ALARM"),
BATTERY_LEVEL_LOW("BATTERY_LEVEL_LOW"), BATTERY_LEVEL_LOW("BATTERY_LEVEL_LOW"),
CUSTOM_INFO("CUSTOM_INFO"), 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) { enum class WidgetUpdateFrequency(val value: Int) {

View File

@ -123,6 +123,7 @@ object Preferences : KotprefModel() {
var isCharging by booleanPref(default = false) var isCharging by booleanPref(default = false)
var googleFitSteps by longPref(default = -1) var googleFitSteps by longPref(default = -1)
var showDailySteps by booleanPref(default = false) var showDailySteps by booleanPref(default = false)
var showNotifications by booleanPref(default = false)
var showMusic by booleanPref(default = false) var showMusic by booleanPref(default = false)
var mediaInfoFormat by stringPref(default = "") 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) val eventRepository = EventRepository(context)
BatteryHelper.updateBatteryInfo(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) != "") || (Preferences.showNextAlarm && AlarmHelper.getNextAlarm(context) != "") ||
(MediaPlayerHelper.isSomeonePlaying(context)) || (MediaPlayerHelper.isSomeonePlaying(context)) ||
(Preferences.showBatteryCharging && Preferences.isCharging || Preferences.isBatteryLevelLow) || (Preferences.showBatteryCharging && Preferences.isCharging || Preferences.isBatteryLevelLow) ||
(Preferences.customNotes.isNotEmpty()) || (Preferences.customNotes.isNotEmpty()) ||
(Preferences.showDailySteps && Preferences.googleFitSteps > 0) (Preferences.showDailySteps && Preferences.googleFitSteps > 0) ||
) (Preferences.showNotifications && ActiveNotificationsHelper.getLastNotification(context) != null)
)
eventRepository.close() eventRepository.close()
return showGlance return showGlance
} }

View File

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

View File

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

View File

@ -16,13 +16,18 @@ import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope 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.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInAccount import com.google.android.gms.auth.api.signin.GoogleSignInAccount
import com.google.android.gms.auth.api.signin.GoogleSignInOptions 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.PermissionRequest
import com.karumi.dexter.listener.multi.MultiplePermissionsListener import com.karumi.dexter.listener.multi.MultiplePermissionsListener
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu import com.tommasoberlose.anotherwidget.components.*
import com.tommasoberlose.anotherwidget.components.CustomNotesDialog
import com.tommasoberlose.anotherwidget.components.GlanceProviderSortMenu
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
import com.tommasoberlose.anotherwidget.databinding.FragmentGlanceSettingsBinding import com.tommasoberlose.anotherwidget.databinding.FragmentGlanceSettingsBinding
import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.AlarmHelper import com.tommasoberlose.anotherwidget.helpers.AlarmHelper
import com.tommasoberlose.anotherwidget.helpers.GlanceProviderHelper
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
import com.tommasoberlose.anotherwidget.models.GlanceProvider
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver.Companion.FITNESS_OPTIONS import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver.Companion.FITNESS_OPTIONS
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity 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.android.synthetic.main.fragment_glance_settings.scrollView
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.idik.lib.slimadapter.SlimAdapter
import java.util.*
class GlanceTabFragment : Fragment() { class GlanceTabFragment : Fragment() {
@ -62,6 +69,8 @@ class GlanceTabFragment : Fragment() {
fun newInstance() = GlanceTabFragment() fun newInstance() = GlanceTabFragment()
} }
private var dialog: GlanceSettingsDialog? = null
private lateinit var adapter: SlimAdapter
private lateinit var viewModel: MainViewModel private lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -87,10 +96,125 @@ class GlanceTabFragment : Fragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) 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() setupListener()
updateNextAlarmWarningUi()
} }
private fun subscribeUi( 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) 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() { private fun setupListener() {
action_show_glance.setOnClickListener { action_show_glance.setOnClickListener {
Preferences.showGlance = !Preferences.showGlance Preferences.showGlance = !Preferences.showGlance
} }
@ -151,134 +239,20 @@ class GlanceTabFragment : Fragment() {
show_glance_switch.setOnCheckedChangeListener { _, enabled: Boolean -> show_glance_switch.setOnCheckedChangeListener { _, enabled: Boolean ->
Preferences.showGlance = enabled 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() { private val nextAlarmChangeBroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) { override fun onReceive(context: Context?, intent: Intent?) {
updateNextAlarmWarningUi() adapter.notifyItemChanged(1)
} }
} }
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
activity?.registerReceiver(nextAlarmChangeBroadcastReceiver, IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)) activity?.registerReceiver(nextAlarmChangeBroadcastReceiver, IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED))
if (dialog != null) {
dialog?.show()
}
} }
override fun onStop() { override fun onStop() {
@ -286,50 +260,6 @@ class GlanceTabFragment : Fragment() {
super.onStop() 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( override fun onActivityResult(
requestCode: Int, requestCode: Int,
resultCode: Int, resultCode: Int,
@ -338,9 +268,15 @@ class GlanceTabFragment : Fragment() {
when (requestCode) { when (requestCode) {
1 -> { 1 -> {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
checkFitnessPermission() adapter.notifyItemChanged(2)
if (dialog != null) {
dialog?.show()
}
} else { } else {
Preferences.showDailySteps = false Preferences.showDailySteps = false
if (dialog != null) {
dialog?.show()
}
} }
} }
2-> { 2-> {
@ -353,42 +289,22 @@ class GlanceTabFragment : Fragment() {
account, account,
FITNESS_OPTIONS) FITNESS_OPTIONS)
} else { } else {
checkFitnessPermission() adapter.notifyItemChanged(2)
if (dialog != null) {
dialog?.show()
}
} }
} catch (e: ApiException) { } catch (e: ApiException) {
e.printStackTrace() e.printStackTrace()
Preferences.showDailySteps = false 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) { private fun maintainScrollPosition(callback: () -> Unit) {
scrollView.isScrollable = false scrollView.isScrollable = false
callback.invoke() callback.invoke()
@ -400,6 +316,6 @@ class GlanceTabFragment : Fragment() {
override fun onResume() { override fun onResume() {
super.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:textColor="@color/colorAccent"
android:textAppearance="@style/AnotherWidget.Settings.Header" android:textAppearance="@style/AnotherWidget.Settings.Header"
app:textAllCaps="false" /> app:textAllCaps="false" />
<LinearLayout <TextView
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="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:paddingLeft="20dp"
android:paddingRight="20dp" android:paddingRight="20dp"
android:textSize="16sp" android:textColor="@color/colorSecondaryText"
android:textColor="@color/colorAccent" android:layout_marginBottom="16dp"
android:textAppearance="@style/AnotherWidget.Settings.Header" android:text="@string/settings_sort_glance_providers_subtitle"
app:textAllCaps="false" /> android:textAppearance="@style/AnotherWidget.Settings.Header"/>
<LinearLayout <androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingTop="16dp" android:id="@+id/providers_list" />
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>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

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

View File

@ -176,7 +176,6 @@
<!-- Glance --> <!-- Glance -->
<string name="settings_show_next_alarm_title">Prossimo allarme</string> <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_at_a_glance_title">Glance</string>
<string name="settings_show_music_title">Canzone in riproduzione</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> <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="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_title">Player Musica</string>
<string name="settings_music_players_filter_subtitle">Scegli i player musical che ti interessano</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 --> <!-- Settings -->
<string name="action_share">Condividi</string> <string name="action_share">Condividi</string>

View File

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

View File

@ -188,7 +188,6 @@
<!-- Glance --> <!-- Glance -->
<string name="settings_show_next_alarm_title">Next clock alarm</string> <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_at_a_glance_title">Glance</string>
<string name="settings_show_music_title">Current playing song</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> <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_visible">Service enabled</string>
<string name="description_show_glance_not_visible">Service disabled</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_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_custom_notes_title">Custom notes</string>
<string name="settings_low_battery_level_title">Battery</string> <string name="settings_low_battery_level_title">Battery</string>
<string name="settings_daily_steps_title">Daily steps</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="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_title">Music Players</string>
<string name="settings_music_players_filter_subtitle">Choose your relevant 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 --> <!-- Settings -->
<string name="action_share">Share</string> <string name="action_share">Share</string>