Redesign notification visibility controls
This commit is contained in:
@@ -1,19 +1,23 @@
|
|||||||
package se.ajpanton.notificationsmaster
|
package se.ajpanton.notificationsmaster
|
||||||
|
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.Button
|
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.LinearLayout
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.commit
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.switchmaterial.SwitchMaterial
|
import com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
import se.ajpanton.notificationsmaster.databinding.FragmentAppVisibilityBinding
|
import se.ajpanton.notificationsmaster.databinding.FragmentAppVisibilityBinding
|
||||||
|
import se.ajpanton.notificationsmaster.databinding.ItemVisibilityExceptionBinding
|
||||||
import se.ajpanton.notificationsmaster.visibility.AppVisibilityPolicy
|
import se.ajpanton.notificationsmaster.visibility.AppVisibilityPolicy
|
||||||
import se.ajpanton.notificationsmaster.visibility.NotificationSurface
|
import se.ajpanton.notificationsmaster.visibility.NotificationSurface
|
||||||
import se.ajpanton.notificationsmaster.visibility.VisibilityExceptionRule
|
import se.ajpanton.notificationsmaster.visibility.VisibilityExceptionRule
|
||||||
@@ -24,7 +28,8 @@ class AppVisibilityFragment : Fragment(R.layout.fragment_app_visibility) {
|
|||||||
private var binding: FragmentAppVisibilityBinding? = null
|
private var binding: FragmentAppVisibilityBinding? = null
|
||||||
private lateinit var store: VisibilityPolicyStore
|
private lateinit var store: VisibilityPolicyStore
|
||||||
private lateinit var packageName: String
|
private lateinit var packageName: String
|
||||||
private val adapter = ExceptionAdapter(::editException, ::deleteException)
|
private lateinit var adapter: ExceptionAdapter
|
||||||
|
private lateinit var touchHelper: ItemTouchHelper
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
binding = FragmentAppVisibilityBinding.bind(view)
|
binding = FragmentAppVisibilityBinding.bind(view)
|
||||||
@@ -32,17 +37,29 @@ class AppVisibilityFragment : Fragment(R.layout.fragment_app_visibility) {
|
|||||||
packageName = requireArguments().getString(ARG_PACKAGE)!!
|
packageName = requireArguments().getString(ARG_PACKAGE)!!
|
||||||
binding!!.appName.text = InstalledApps.name(requireContext(), packageName)
|
binding!!.appName.text = InstalledApps.name(requireContext(), packageName)
|
||||||
binding!!.packageName.text = packageName
|
binding!!.packageName.text = packageName
|
||||||
|
binding!!.returnToList.setOnClickListener(::returnToList)
|
||||||
|
|
||||||
|
val icon = requireContext().packageManager.getApplicationIcon(packageName)
|
||||||
|
adapter = ExceptionAdapter(icon, ::editException, ::deleteException, ::saveExceptions) {
|
||||||
|
touchHelper.startDrag(it)
|
||||||
|
}
|
||||||
binding!!.exceptions.layoutManager = LinearLayoutManager(requireContext())
|
binding!!.exceptions.layoutManager = LinearLayoutManager(requireContext())
|
||||||
binding!!.exceptions.adapter = adapter
|
binding!!.exceptions.adapter = adapter
|
||||||
ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(UP or DOWN, 0) {
|
touchHelper = ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(UP or DOWN, 0) {
|
||||||
override fun onMove(list: RecyclerView, from: RecyclerView.ViewHolder, to: RecyclerView.ViewHolder): Boolean {
|
override fun isLongPressDragEnabled() = false
|
||||||
|
|
||||||
|
override fun onMove(
|
||||||
|
list: RecyclerView,
|
||||||
|
from: RecyclerView.ViewHolder,
|
||||||
|
to: RecyclerView.ViewHolder,
|
||||||
|
): Boolean {
|
||||||
adapter.move(from.bindingAdapterPosition, to.bindingAdapterPosition)
|
adapter.move(from.bindingAdapterPosition, to.bindingAdapterPosition)
|
||||||
saveApp { copy(exceptions = adapter.rules()) }
|
saveExceptions(adapter.rules())
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSwiped(holder: RecyclerView.ViewHolder, direction: Int) = Unit
|
override fun onSwiped(holder: RecyclerView.ViewHolder, direction: Int) = Unit
|
||||||
}).attachToRecyclerView(binding!!.exceptions)
|
}).also { it.attachToRecyclerView(binding!!.exceptions) }
|
||||||
binding!!.addException.setOnClickListener { showExceptionDialog(null) }
|
binding!!.addException.setOnClickListener { showExceptionDialog(null) }
|
||||||
bind()
|
bind()
|
||||||
}
|
}
|
||||||
@@ -57,21 +74,27 @@ class AppVisibilityFragment : Fragment(R.layout.fragment_app_visibility) {
|
|||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun returnToList(@Suppress("UNUSED_PARAMETER") view: View) {
|
||||||
|
if (!parentFragmentManager.popBackStackImmediate()) {
|
||||||
|
parentFragmentManager.commit { replace(R.id.content_frame, NotificationVisibilityFragment()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun bind() {
|
private fun bind() {
|
||||||
val policy = appPolicy()
|
val policy = appPolicy()
|
||||||
bindSurface(binding!!.hideUnlocked, NotificationSurface.UNLOCKED_STATUSBAR, policy)
|
bindSurface(binding!!.showAod, NotificationSurface.AOD, policy)
|
||||||
bindSurface(binding!!.hideLockscreen, NotificationSurface.LOCKSCREEN_COLLAPSED, policy)
|
bindSurface(binding!!.showLockscreen, NotificationSurface.LOCKSCREEN_COLLAPSED, policy)
|
||||||
bindSurface(binding!!.hideAod, NotificationSurface.AOD, policy)
|
bindSurface(binding!!.showUnlocked, NotificationSurface.UNLOCKED_STATUSBAR, policy)
|
||||||
adapter.submit(policy.exceptions)
|
adapter.submit(policy.exceptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindSurface(toggle: SwitchMaterial, surface: NotificationSurface, policy: AppVisibilityPolicy) {
|
private fun bindSurface(toggle: SwitchMaterial, surface: NotificationSurface, policy: AppVisibilityPolicy) {
|
||||||
toggle.setOnCheckedChangeListener(null)
|
toggle.setOnCheckedChangeListener(null)
|
||||||
toggle.isChecked = surface in policy.blockedSurfaces
|
toggle.isChecked = surface !in policy.blockedSurfaces
|
||||||
toggle.setOnCheckedChangeListener { _, hidden ->
|
toggle.setOnCheckedChangeListener { _, visible ->
|
||||||
saveApp {
|
saveApp {
|
||||||
copy(blockedSurfaces = blockedSurfaces.toMutableSet().apply {
|
copy(blockedSurfaces = blockedSurfaces.toMutableSet().apply {
|
||||||
if (hidden) add(surface) else remove(surface)
|
if (visible) remove(surface) else add(surface)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,59 +113,46 @@ class AppVisibilityFragment : Fragment(R.layout.fragment_app_visibility) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun saveExceptions(rules: List<VisibilityExceptionRule>) {
|
||||||
|
saveApp { copy(exceptions = rules) }
|
||||||
|
}
|
||||||
|
|
||||||
private fun editException(position: Int) = showExceptionDialog(position)
|
private fun editException(position: Int) = showExceptionDialog(position)
|
||||||
|
|
||||||
private fun deleteException(position: Int) {
|
private fun deleteException(position: Int) {
|
||||||
saveApp { copy(exceptions = exceptions.toMutableList().apply { removeAt(position) }) }
|
adapter.submit(adapter.rules().toMutableList().apply { removeAt(position) })
|
||||||
bind()
|
saveExceptions(adapter.rules())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showExceptionDialog(position: Int?) {
|
private fun showExceptionDialog(position: Int?) {
|
||||||
val existing = position?.let { appPolicy().exceptions[it] }
|
val existing = position?.let { adapter.rules().getOrNull(it) }
|
||||||
val content = LinearLayout(requireContext()).apply {
|
|
||||||
orientation = LinearLayout.VERTICAL
|
|
||||||
setPadding(dp(24), 0, dp(24), 0)
|
|
||||||
}
|
|
||||||
val pattern = EditText(requireContext()).apply {
|
val pattern = EditText(requireContext()).apply {
|
||||||
hint = "Regular expression"
|
hint = "Regular expression"
|
||||||
setText(existing?.pattern)
|
setText(existing?.pattern)
|
||||||
maxLines = 4
|
maxLines = 4
|
||||||
}
|
setPadding(dp(24), 0, dp(24), 0)
|
||||||
content.addView(pattern)
|
|
||||||
val toggles = listOf(
|
|
||||||
NotificationSurface.UNLOCKED_STATUSBAR to "Hide in unlocked status bar",
|
|
||||||
NotificationSurface.LOCKSCREEN_COLLAPSED to "Hide on collapsed lockscreen",
|
|
||||||
NotificationSurface.AOD to "Hide on always-on display",
|
|
||||||
).associate { (surface, label) ->
|
|
||||||
surface to SwitchMaterial(requireContext()).apply {
|
|
||||||
text = label
|
|
||||||
isChecked = surface in existing?.blockedSurfaces.orEmpty()
|
|
||||||
content.addView(this)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
val dialog = MaterialAlertDialogBuilder(requireContext())
|
val dialog = MaterialAlertDialogBuilder(requireContext())
|
||||||
.setTitle(if (existing == null) "Add text exception" else "Edit text exception")
|
.setTitle(if (existing == null) "Add text exception" else "Edit text exception")
|
||||||
.setView(content)
|
.setView(pattern)
|
||||||
.setNegativeButton("Cancel", null)
|
.setNegativeButton("Cancel", null)
|
||||||
.setPositiveButton("Save", null)
|
.setPositiveButton("Save", null)
|
||||||
.create()
|
.create()
|
||||||
dialog.setOnShowListener {
|
dialog.setOnShowListener {
|
||||||
dialog.getButton(android.app.AlertDialog.BUTTON_POSITIVE).setOnClickListener {
|
dialog.getButton(android.app.AlertDialog.BUTTON_POSITIVE).setOnClickListener {
|
||||||
val rule = runCatching {
|
val rule = VisibilityExceptionRule(
|
||||||
VisibilityExceptionRule(
|
pattern.text.toString(),
|
||||||
pattern.text.toString(),
|
existing?.blockedSurfaces ?: appPolicy().blockedSurfaces,
|
||||||
toggles.filterValues { it.isChecked }.keys,
|
)
|
||||||
).also { require(it.hasValidPattern()) }
|
if (!rule.hasValidPattern()) {
|
||||||
}.getOrElse {
|
|
||||||
pattern.error = "Enter a valid, non-empty regular expression"
|
pattern.error = "Enter a valid, non-empty regular expression"
|
||||||
return@setOnClickListener
|
return@setOnClickListener
|
||||||
}
|
}
|
||||||
saveApp {
|
val rules = adapter.rules().toMutableList().apply {
|
||||||
copy(exceptions = exceptions.toMutableList().apply {
|
if (position == null) add(rule) else set(position, rule)
|
||||||
if (position == null) add(rule) else set(position, rule)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
bind()
|
adapter.submit(rules)
|
||||||
|
saveExceptions(rules)
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,8 +162,11 @@ class AppVisibilityFragment : Fragment(R.layout.fragment_app_visibility) {
|
|||||||
private fun dp(value: Int) = (value * resources.displayMetrics.density).toInt()
|
private fun dp(value: Int) = (value * resources.displayMetrics.density).toInt()
|
||||||
|
|
||||||
private class ExceptionAdapter(
|
private class ExceptionAdapter(
|
||||||
|
private val appIcon: Drawable,
|
||||||
private val edit: (Int) -> Unit,
|
private val edit: (Int) -> Unit,
|
||||||
private val delete: (Int) -> Unit,
|
private val delete: (Int) -> Unit,
|
||||||
|
private val changed: (List<VisibilityExceptionRule>) -> Unit,
|
||||||
|
private val startDrag: (ExceptionHolder) -> Unit,
|
||||||
) : RecyclerView.Adapter<ExceptionHolder>() {
|
) : RecyclerView.Adapter<ExceptionHolder>() {
|
||||||
private val items = mutableListOf<VisibilityExceptionRule>()
|
private val items = mutableListOf<VisibilityExceptionRule>()
|
||||||
|
|
||||||
@@ -170,74 +183,72 @@ class AppVisibilityFragment : Fragment(R.layout.fragment_app_visibility) {
|
|||||||
|
|
||||||
fun rules() = items.toList()
|
fun rules() = items.toList()
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ExceptionHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ExceptionHolder(
|
||||||
val row = LinearLayout(parent.context).apply {
|
ItemVisibilityExceptionBinding.inflate(LayoutInflater.from(parent.context), parent, false),
|
||||||
orientation = LinearLayout.HORIZONTAL
|
)
|
||||||
gravity = android.view.Gravity.CENTER_VERTICAL
|
|
||||||
setPadding(0, dp(parent, 6), 0, dp(parent, 6))
|
|
||||||
isClickable = true
|
|
||||||
isFocusable = true
|
|
||||||
background = context.obtainStyledAttributes(intArrayOf(android.R.attr.selectableItemBackground))
|
|
||||||
.let { values -> values.getDrawable(0).also { values.recycle() } }
|
|
||||||
}
|
|
||||||
val handle = TextView(parent.context).apply {
|
|
||||||
text = "↕"
|
|
||||||
textSize = 22f
|
|
||||||
gravity = android.view.Gravity.CENTER
|
|
||||||
contentDescription = "Drag to reorder"
|
|
||||||
layoutParams = LinearLayout.LayoutParams(dp(parent, 40), dp(parent, 48))
|
|
||||||
}
|
|
||||||
val textColumn = LinearLayout(parent.context).apply {
|
|
||||||
orientation = LinearLayout.VERTICAL
|
|
||||||
layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f)
|
|
||||||
}
|
|
||||||
val pattern = TextView(parent.context).apply { textSize = 15f }
|
|
||||||
val summary = TextView(parent.context).apply { textSize = 12f }
|
|
||||||
textColumn.addView(pattern)
|
|
||||||
textColumn.addView(summary)
|
|
||||||
val remove = Button(parent.context).apply {
|
|
||||||
text = "Delete"
|
|
||||||
isAllCaps = false
|
|
||||||
}
|
|
||||||
row.addView(handle)
|
|
||||||
row.addView(textColumn)
|
|
||||||
row.addView(remove)
|
|
||||||
return ExceptionHolder(row, pattern, summary, remove)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ExceptionHolder, position: Int) {
|
override fun onBindViewHolder(holder: ExceptionHolder, position: Int) {
|
||||||
|
val binding = holder.binding
|
||||||
val rule = items[position]
|
val rule = items[position]
|
||||||
holder.pattern.text = rule.pattern
|
binding.pattern.text = rule.pattern
|
||||||
holder.summary.text = surfaceSummary(rule.blockedSurfaces)
|
bindSurface(binding.aodIcon, binding.aodCross, rule, NotificationSurface.AOD)
|
||||||
holder.itemView.setOnClickListener {
|
bindSurface(
|
||||||
holder.bindingAdapterPosition.takeIf { it != RecyclerView.NO_POSITION }?.let(edit)
|
binding.lockscreenIcon,
|
||||||
|
binding.lockscreenCross,
|
||||||
|
rule,
|
||||||
|
NotificationSurface.LOCKSCREEN_COLLAPSED,
|
||||||
|
)
|
||||||
|
bindSurface(
|
||||||
|
binding.unlockedIcon,
|
||||||
|
binding.unlockedCross,
|
||||||
|
rule,
|
||||||
|
NotificationSurface.UNLOCKED_STATUSBAR,
|
||||||
|
)
|
||||||
|
binding.aodCell.setOnClickListener { toggle(holder, NotificationSurface.AOD) }
|
||||||
|
binding.lockscreenCell.setOnClickListener {
|
||||||
|
toggle(holder, NotificationSurface.LOCKSCREEN_COLLAPSED)
|
||||||
}
|
}
|
||||||
holder.remove.setOnClickListener {
|
binding.unlockedCell.setOnClickListener {
|
||||||
holder.bindingAdapterPosition.takeIf { it != RecyclerView.NO_POSITION }?.let(delete)
|
toggle(holder, NotificationSurface.UNLOCKED_STATUSBAR)
|
||||||
|
}
|
||||||
|
binding.edit.setOnClickListener { holder.positionOrNull()?.let(edit) }
|
||||||
|
binding.delete.setOnClickListener { holder.positionOrNull()?.let(delete) }
|
||||||
|
binding.dragHandle.setOnTouchListener { _, event ->
|
||||||
|
if (event.actionMasked == MotionEvent.ACTION_DOWN) startDrag(holder)
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount() = items.size
|
override fun getItemCount() = items.size
|
||||||
|
|
||||||
private fun surfaceSummary(surfaces: Set<NotificationSurface>): String {
|
private fun toggle(holder: ExceptionHolder, surface: NotificationSurface) {
|
||||||
val names = listOf(
|
val position = holder.positionOrNull() ?: return
|
||||||
NotificationSurface.UNLOCKED_STATUSBAR to "status bar",
|
val current = items[position]
|
||||||
NotificationSurface.LOCKSCREEN_COLLAPSED to "lockscreen",
|
items[position] = current.copy(blockedSurfaces = current.blockedSurfaces.toMutableSet().apply {
|
||||||
NotificationSurface.AOD to "AOD",
|
if (surface in current.blockedSurfaces) remove(surface) else add(surface)
|
||||||
).filter { it.first in surfaces }.joinToString { it.second }
|
})
|
||||||
return if (names.isEmpty()) "Show on all surfaces" else "Hide: $names"
|
notifyItemChanged(position)
|
||||||
|
changed(rules())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun dp(parent: ViewGroup, value: Int) =
|
private fun bindSurface(
|
||||||
(value * parent.resources.displayMetrics.density).toInt()
|
icon: ImageView,
|
||||||
|
cross: TextView,
|
||||||
|
rule: VisibilityExceptionRule,
|
||||||
|
surface: NotificationSurface,
|
||||||
|
) {
|
||||||
|
icon.setImageDrawable(appIcon.constantState?.newDrawable()?.mutate() ?: appIcon)
|
||||||
|
val hidden = surface in rule.blockedSurfaces
|
||||||
|
icon.alpha = if (hidden) 0.25f else 1f
|
||||||
|
cross.visibility = if (hidden) View.VISIBLE else View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ExceptionHolder.positionOrNull() =
|
||||||
|
bindingAdapterPosition.takeIf { it != RecyclerView.NO_POSITION }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ExceptionHolder(
|
private class ExceptionHolder(val binding: ItemVisibilityExceptionBinding) :
|
||||||
view: View,
|
RecyclerView.ViewHolder(binding.root)
|
||||||
val pattern: TextView,
|
|
||||||
val summary: TextView,
|
|
||||||
val remove: Button,
|
|
||||||
) : RecyclerView.ViewHolder(view)
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val ARG_PACKAGE = "package"
|
private const val ARG_PACKAGE = "package"
|
||||||
|
|||||||
@@ -78,7 +78,15 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
|||||||
})
|
})
|
||||||
|
|
||||||
currentItemId = savedInstanceState?.getInt(STATE_CURRENT_ITEM_ID) ?: R.id.nav_view_logs
|
currentItemId = savedInstanceState?.getInt(STATE_CURRENT_ITEM_ID) ?: R.id.nav_view_logs
|
||||||
navigateTo(currentItemId)
|
if (savedInstanceState == null) {
|
||||||
|
navigateTo(currentItemId)
|
||||||
|
} else {
|
||||||
|
val page = Page.fromMenuItem(currentItemId)
|
||||||
|
refreshLogProtection(requestUnlock = hasWindowFocus())
|
||||||
|
syncDrawerSelection(currentItemId)
|
||||||
|
title = getString(page.titleRes)
|
||||||
|
binding.root.post(::applyPageTitleVisibility)
|
||||||
|
}
|
||||||
applyNavigationDrawerInsets()
|
applyNavigationDrawerInsets()
|
||||||
syncDrawerToggle()
|
syncDrawerToggle()
|
||||||
}
|
}
|
||||||
@@ -156,6 +164,10 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
|||||||
refreshLogProtection(requestUnlock = hasWindowFocus())
|
refreshLogProtection(requestUnlock = hasWindowFocus())
|
||||||
syncDrawerSelection(itemId)
|
syncDrawerSelection(itemId)
|
||||||
val page = Page.fromMenuItem(itemId)
|
val page = Page.fromMenuItem(itemId)
|
||||||
|
supportFragmentManager.popBackStackImmediate(
|
||||||
|
null,
|
||||||
|
androidx.fragment.app.FragmentManager.POP_BACK_STACK_INCLUSIVE,
|
||||||
|
)
|
||||||
supportFragmentManager.commit {
|
supportFragmentManager.commit {
|
||||||
replace(
|
replace(
|
||||||
R.id.content_frame,
|
R.id.content_frame,
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:pathData="M6,6L18,18M18,6L6,18"
|
||||||
|
android:strokeColor="@color/visibility_hidden_cross"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:strokeWidth="2.5" />
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M7,4h3v3H7zM14,4h3v3h-3zM7,10.5h3v3H7zM14,10.5h3v3h-3zM7,17h3v3H7zM14,17h3v3h-3z" />
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34a0.996,0.996 0,0 0,-1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z" />
|
||||||
|
</vector>
|
||||||
@@ -5,10 +5,18 @@
|
|||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="@dimen/page_padding">
|
android:padding="@dimen/page_padding">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/return_to_list"
|
||||||
|
style="?attr/materialButtonOutlinedStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Return to list" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/app_name"
|
android:id="@+id/app_name"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
android:textAppearance="?attr/textAppearanceHeadline6"
|
android:textAppearance="?attr/textAppearanceHeadline6"
|
||||||
android:textStyle="bold" />
|
android:textStyle="bold" />
|
||||||
|
|
||||||
@@ -22,52 +30,45 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="20dp"
|
android:layout_marginTop="20dp"
|
||||||
android:text="Hide by default"
|
android:text="Default visibility"
|
||||||
android:textStyle="bold" />
|
android:textAppearance="?attr/textAppearanceHeadline6" />
|
||||||
|
|
||||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
android:id="@+id/hide_aod"
|
android:id="@+id/show_aod"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Always-on display" />
|
android:text="Always-on display" />
|
||||||
|
|
||||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
android:id="@+id/hide_lockscreen"
|
android:id="@+id/show_lockscreen"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Collapsed lockscreen" />
|
android:text="Collapsed lockscreen" />
|
||||||
|
|
||||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
android:id="@+id/hide_unlocked"
|
android:id="@+id/show_unlocked"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Unlocked status bar" />
|
android:text="Unlocked status bar" />
|
||||||
|
|
||||||
<LinearLayout
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="20dp"
|
android:layout_marginTop="20dp"
|
||||||
android:gravity="center_vertical"
|
android:text="Exceptions based on text contents"
|
||||||
android:orientation="horizontal">
|
android:textAppearance="?attr/textAppearanceHeadline6" />
|
||||||
|
|
||||||
<TextView
|
<com.google.android.material.button.MaterialButton
|
||||||
android:layout_width="0dp"
|
android:id="@+id/add_exception"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_height="wrap_content"
|
||||||
android:text="Ordered text exceptions"
|
android:layout_marginTop="4dp"
|
||||||
android:textStyle="bold" />
|
android:text="Add exception" />
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/add_exception"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Add" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="The first matching expression replaces the defaults above. Drag to reorder."
|
android:text="The first matching expression stops evaluating and replaces default visibility. Drag to reorder."
|
||||||
android:textAppearance="?attr/textAppearanceBody2" />
|
android:textAppearance="?attr/textAppearanceBody2" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:text="Tap an app icon to hide or show it on AOD, the lockscreen, or the unlocked status bar. Tap the app name for text exceptions."
|
android:text="Icons represent AOD, Lockscreen and Unlocked, respectively. Tap to toggle visibility. Tap the app for more advanced options."
|
||||||
android:textAppearance="?attr/textAppearanceCaption" />
|
android:textAppearance="?attr/textAppearanceCaption" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
|
|||||||
@@ -0,0 +1,139 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:minHeight="64dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingTop="6dp"
|
||||||
|
android:paddingBottom="6dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/drag_handle"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:contentDescription="Drag to reorder"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:src="@drawable/ic_drag_dots"
|
||||||
|
app:tint="?android:attr/textColorSecondary" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/pattern"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:textAppearance="?attr/textAppearanceBody1" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/aod_cell"
|
||||||
|
android:layout_width="34dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:foreground="?attr/selectableItemBackgroundBorderless">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/aod_icon"
|
||||||
|
android:layout_width="26dp"
|
||||||
|
android:layout_height="26dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:contentDescription="AOD visibility"
|
||||||
|
android:scaleType="fitCenter" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/aod_cross"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="✕"
|
||||||
|
android:textColor="@color/visibility_hidden_cross"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:visibility="gone" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/lockscreen_cell"
|
||||||
|
android:layout_width="34dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:foreground="?attr/selectableItemBackgroundBorderless">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/lockscreen_icon"
|
||||||
|
android:layout_width="26dp"
|
||||||
|
android:layout_height="26dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:contentDescription="Lockscreen visibility"
|
||||||
|
android:scaleType="fitCenter" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/lockscreen_cross"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="✕"
|
||||||
|
android:textColor="@color/visibility_hidden_cross"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:visibility="gone" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/unlocked_cell"
|
||||||
|
android:layout_width="34dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:foreground="?attr/selectableItemBackgroundBorderless">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/unlocked_icon"
|
||||||
|
android:layout_width="26dp"
|
||||||
|
android:layout_height="26dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:contentDescription="Unlocked status-bar visibility"
|
||||||
|
android:scaleType="fitCenter" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/unlocked_cross"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="✕"
|
||||||
|
android:textColor="@color/visibility_hidden_cross"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:visibility="gone" />
|
||||||
|
</FrameLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/edit"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:contentDescription="Edit expression"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:src="@drawable/ic_edit"
|
||||||
|
app:tint="?android:attr/textColorPrimary" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/delete"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:contentDescription="Delete expression"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:src="@drawable/ic_delete_cross" />
|
||||||
|
</LinearLayout>
|
||||||
Reference in New Issue
Block a user