Redesign notification visibility controls
This commit is contained in:
@@ -1,19 +1,23 @@
|
||||
package se.ajpanton.notificationsmaster
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.EditText
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.commit
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.switchmaterial.SwitchMaterial
|
||||
import se.ajpanton.notificationsmaster.databinding.FragmentAppVisibilityBinding
|
||||
import se.ajpanton.notificationsmaster.databinding.ItemVisibilityExceptionBinding
|
||||
import se.ajpanton.notificationsmaster.visibility.AppVisibilityPolicy
|
||||
import se.ajpanton.notificationsmaster.visibility.NotificationSurface
|
||||
import se.ajpanton.notificationsmaster.visibility.VisibilityExceptionRule
|
||||
@@ -24,7 +28,8 @@ class AppVisibilityFragment : Fragment(R.layout.fragment_app_visibility) {
|
||||
private var binding: FragmentAppVisibilityBinding? = null
|
||||
private lateinit var store: VisibilityPolicyStore
|
||||
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?) {
|
||||
binding = FragmentAppVisibilityBinding.bind(view)
|
||||
@@ -32,17 +37,29 @@ class AppVisibilityFragment : Fragment(R.layout.fragment_app_visibility) {
|
||||
packageName = requireArguments().getString(ARG_PACKAGE)!!
|
||||
binding!!.appName.text = InstalledApps.name(requireContext(), 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.adapter = adapter
|
||||
ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(UP or DOWN, 0) {
|
||||
override fun onMove(list: RecyclerView, from: RecyclerView.ViewHolder, to: RecyclerView.ViewHolder): Boolean {
|
||||
touchHelper = ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(UP or DOWN, 0) {
|
||||
override fun isLongPressDragEnabled() = false
|
||||
|
||||
override fun onMove(
|
||||
list: RecyclerView,
|
||||
from: RecyclerView.ViewHolder,
|
||||
to: RecyclerView.ViewHolder,
|
||||
): Boolean {
|
||||
adapter.move(from.bindingAdapterPosition, to.bindingAdapterPosition)
|
||||
saveApp { copy(exceptions = adapter.rules()) }
|
||||
saveExceptions(adapter.rules())
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onSwiped(holder: RecyclerView.ViewHolder, direction: Int) = Unit
|
||||
}).attachToRecyclerView(binding!!.exceptions)
|
||||
}).also { it.attachToRecyclerView(binding!!.exceptions) }
|
||||
binding!!.addException.setOnClickListener { showExceptionDialog(null) }
|
||||
bind()
|
||||
}
|
||||
@@ -57,21 +74,27 @@ class AppVisibilityFragment : Fragment(R.layout.fragment_app_visibility) {
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private fun returnToList(@Suppress("UNUSED_PARAMETER") view: View) {
|
||||
if (!parentFragmentManager.popBackStackImmediate()) {
|
||||
parentFragmentManager.commit { replace(R.id.content_frame, NotificationVisibilityFragment()) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun bind() {
|
||||
val policy = appPolicy()
|
||||
bindSurface(binding!!.hideUnlocked, NotificationSurface.UNLOCKED_STATUSBAR, policy)
|
||||
bindSurface(binding!!.hideLockscreen, NotificationSurface.LOCKSCREEN_COLLAPSED, policy)
|
||||
bindSurface(binding!!.hideAod, NotificationSurface.AOD, policy)
|
||||
bindSurface(binding!!.showAod, NotificationSurface.AOD, policy)
|
||||
bindSurface(binding!!.showLockscreen, NotificationSurface.LOCKSCREEN_COLLAPSED, policy)
|
||||
bindSurface(binding!!.showUnlocked, NotificationSurface.UNLOCKED_STATUSBAR, policy)
|
||||
adapter.submit(policy.exceptions)
|
||||
}
|
||||
|
||||
private fun bindSurface(toggle: SwitchMaterial, surface: NotificationSurface, policy: AppVisibilityPolicy) {
|
||||
toggle.setOnCheckedChangeListener(null)
|
||||
toggle.isChecked = surface in policy.blockedSurfaces
|
||||
toggle.setOnCheckedChangeListener { _, hidden ->
|
||||
toggle.isChecked = surface !in policy.blockedSurfaces
|
||||
toggle.setOnCheckedChangeListener { _, visible ->
|
||||
saveApp {
|
||||
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 deleteException(position: Int) {
|
||||
saveApp { copy(exceptions = exceptions.toMutableList().apply { removeAt(position) }) }
|
||||
bind()
|
||||
adapter.submit(adapter.rules().toMutableList().apply { removeAt(position) })
|
||||
saveExceptions(adapter.rules())
|
||||
}
|
||||
|
||||
private fun showExceptionDialog(position: Int?) {
|
||||
val existing = position?.let { appPolicy().exceptions[it] }
|
||||
val content = LinearLayout(requireContext()).apply {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
setPadding(dp(24), 0, dp(24), 0)
|
||||
}
|
||||
val existing = position?.let { adapter.rules().getOrNull(it) }
|
||||
val pattern = EditText(requireContext()).apply {
|
||||
hint = "Regular expression"
|
||||
setText(existing?.pattern)
|
||||
maxLines = 4
|
||||
}
|
||||
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)
|
||||
}
|
||||
setPadding(dp(24), 0, dp(24), 0)
|
||||
}
|
||||
val dialog = MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(if (existing == null) "Add text exception" else "Edit text exception")
|
||||
.setView(content)
|
||||
.setView(pattern)
|
||||
.setNegativeButton("Cancel", null)
|
||||
.setPositiveButton("Save", null)
|
||||
.create()
|
||||
dialog.setOnShowListener {
|
||||
dialog.getButton(android.app.AlertDialog.BUTTON_POSITIVE).setOnClickListener {
|
||||
val rule = runCatching {
|
||||
VisibilityExceptionRule(
|
||||
pattern.text.toString(),
|
||||
toggles.filterValues { it.isChecked }.keys,
|
||||
).also { require(it.hasValidPattern()) }
|
||||
}.getOrElse {
|
||||
val rule = VisibilityExceptionRule(
|
||||
pattern.text.toString(),
|
||||
existing?.blockedSurfaces ?: appPolicy().blockedSurfaces,
|
||||
)
|
||||
if (!rule.hasValidPattern()) {
|
||||
pattern.error = "Enter a valid, non-empty regular expression"
|
||||
return@setOnClickListener
|
||||
}
|
||||
saveApp {
|
||||
copy(exceptions = exceptions.toMutableList().apply {
|
||||
if (position == null) add(rule) else set(position, rule)
|
||||
})
|
||||
val rules = adapter.rules().toMutableList().apply {
|
||||
if (position == null) add(rule) else set(position, rule)
|
||||
}
|
||||
bind()
|
||||
adapter.submit(rules)
|
||||
saveExceptions(rules)
|
||||
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 class ExceptionAdapter(
|
||||
private val appIcon: Drawable,
|
||||
private val edit: (Int) -> Unit,
|
||||
private val delete: (Int) -> Unit,
|
||||
private val changed: (List<VisibilityExceptionRule>) -> Unit,
|
||||
private val startDrag: (ExceptionHolder) -> Unit,
|
||||
) : RecyclerView.Adapter<ExceptionHolder>() {
|
||||
private val items = mutableListOf<VisibilityExceptionRule>()
|
||||
|
||||
@@ -170,74 +183,72 @@ class AppVisibilityFragment : Fragment(R.layout.fragment_app_visibility) {
|
||||
|
||||
fun rules() = items.toList()
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ExceptionHolder {
|
||||
val row = LinearLayout(parent.context).apply {
|
||||
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 onCreateViewHolder(parent: ViewGroup, viewType: Int) = ExceptionHolder(
|
||||
ItemVisibilityExceptionBinding.inflate(LayoutInflater.from(parent.context), parent, false),
|
||||
)
|
||||
|
||||
override fun onBindViewHolder(holder: ExceptionHolder, position: Int) {
|
||||
val binding = holder.binding
|
||||
val rule = items[position]
|
||||
holder.pattern.text = rule.pattern
|
||||
holder.summary.text = surfaceSummary(rule.blockedSurfaces)
|
||||
holder.itemView.setOnClickListener {
|
||||
holder.bindingAdapterPosition.takeIf { it != RecyclerView.NO_POSITION }?.let(edit)
|
||||
binding.pattern.text = rule.pattern
|
||||
bindSurface(binding.aodIcon, binding.aodCross, rule, NotificationSurface.AOD)
|
||||
bindSurface(
|
||||
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 {
|
||||
holder.bindingAdapterPosition.takeIf { it != RecyclerView.NO_POSITION }?.let(delete)
|
||||
binding.unlockedCell.setOnClickListener {
|
||||
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
|
||||
|
||||
private fun surfaceSummary(surfaces: Set<NotificationSurface>): String {
|
||||
val names = listOf(
|
||||
NotificationSurface.UNLOCKED_STATUSBAR to "status bar",
|
||||
NotificationSurface.LOCKSCREEN_COLLAPSED to "lockscreen",
|
||||
NotificationSurface.AOD to "AOD",
|
||||
).filter { it.first in surfaces }.joinToString { it.second }
|
||||
return if (names.isEmpty()) "Show on all surfaces" else "Hide: $names"
|
||||
private fun toggle(holder: ExceptionHolder, surface: NotificationSurface) {
|
||||
val position = holder.positionOrNull() ?: return
|
||||
val current = items[position]
|
||||
items[position] = current.copy(blockedSurfaces = current.blockedSurfaces.toMutableSet().apply {
|
||||
if (surface in current.blockedSurfaces) remove(surface) else add(surface)
|
||||
})
|
||||
notifyItemChanged(position)
|
||||
changed(rules())
|
||||
}
|
||||
|
||||
private fun dp(parent: ViewGroup, value: Int) =
|
||||
(value * parent.resources.displayMetrics.density).toInt()
|
||||
private fun bindSurface(
|
||||
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(
|
||||
view: View,
|
||||
val pattern: TextView,
|
||||
val summary: TextView,
|
||||
val remove: Button,
|
||||
) : RecyclerView.ViewHolder(view)
|
||||
private class ExceptionHolder(val binding: ItemVisibilityExceptionBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
companion object {
|
||||
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
|
||||
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()
|
||||
syncDrawerToggle()
|
||||
}
|
||||
@@ -156,6 +164,10 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
||||
refreshLogProtection(requestUnlock = hasWindowFocus())
|
||||
syncDrawerSelection(itemId)
|
||||
val page = Page.fromMenuItem(itemId)
|
||||
supportFragmentManager.popBackStackImmediate(
|
||||
null,
|
||||
androidx.fragment.app.FragmentManager.POP_BACK_STACK_INCLUSIVE,
|
||||
)
|
||||
supportFragmentManager.commit {
|
||||
replace(
|
||||
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: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
|
||||
android:id="@+id/app_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textAppearance="?attr/textAppearanceHeadline6"
|
||||
android:textStyle="bold" />
|
||||
|
||||
@@ -22,52 +30,45 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:text="Hide by default"
|
||||
android:textStyle="bold" />
|
||||
android:text="Default visibility"
|
||||
android:textAppearance="?attr/textAppearanceHeadline6" />
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
android:id="@+id/hide_aod"
|
||||
android:id="@+id/show_aod"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Always-on display" />
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
android:id="@+id/hide_lockscreen"
|
||||
android:id="@+id/show_lockscreen"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Collapsed lockscreen" />
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
android:id="@+id/hide_unlocked"
|
||||
android:id="@+id/show_unlocked"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Unlocked status bar" />
|
||||
|
||||
<LinearLayout
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
android:text="Exceptions based on text contents"
|
||||
android:textAppearance="?attr/textAppearanceHeadline6" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Ordered text exceptions"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/add_exception"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Add" />
|
||||
</LinearLayout>
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/add_exception"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="Add exception" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
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" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
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" />
|
||||
|
||||
<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