Modernize settings UI with Material Components, DayNight theme, and app icon
The screen was built entirely from raw android.widget.* views with no theme applied at all, so it never had a chance to follow system dark/light mode and looked dated regardless. Adds AppCompat + Material Components, switches SettingsActivity to AppCompatActivity with a Theme.Material3. DayNight theme, and rebuilds the screen with Material widgets (cards, chips for the hidden-packages list, proper text fields). Also adds a launcher icon (previously none): a vector adaptive icon, a moon-like disc partially eclipsed by a diagonal veil in the background color — no image tool involved, just XML. Also renames the per-app "Remove" button to "Apply defaults (hide everything)" — "Remove" read as removing the app from the list, not resetting it to defaults, which is all it actually does. Co-Authored-By: agent <agent@bdeshi.space>
This commit is contained in:
1 parent
c21dd6fbcd
commit
e3c69eb161
8 files changed
+160
-99
No files matched your search
@@ -2,6 +2,9 @@
|
||||
|
||||
<application
|
||||
android:label="@string/app_name"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:theme="@style/Theme.Veil"
|
||||
android:allowBackup="false"
|
||||
android:hasCode="true">
|
||||
|
||||
@@ -18,7 +21,8 @@
|
||||
<activity
|
||||
android:name=".SettingsActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name">
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Veil">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package space.bdeshi.veil
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Typeface
|
||||
@@ -8,12 +7,17 @@ import android.os.Bundle
|
||||
import android.text.InputType
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.CheckBox
|
||||
import android.widget.EditText
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.ScrollView
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.google.android.material.checkbox.MaterialCheckBox
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.google.android.material.chip.ChipGroup
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import java.io.File
|
||||
|
||||
private val HELP_TIPS: List<Pair<String, String>> = listOf(
|
||||
@@ -35,19 +39,19 @@ private val HELP_TIPS: List<Pair<String, String>> = listOf(
|
||||
"the target app. No log lines from Veil there usually means it never got injected " +
|
||||
"(see the DenyList tip above), not a bug in this module.",
|
||||
"Forgot what an unconfigured app does?" to
|
||||
"Any app not in the list above gets every feature applied by default — check here " +
|
||||
"Any app not in the list below gets every feature applied by default — check here " +
|
||||
"first if something's being hidden that you didn't expect.",
|
||||
)
|
||||
|
||||
class SettingsActivity : Activity() {
|
||||
class SettingsActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var prefs: SharedPreferences
|
||||
private lateinit var appListContainer: LinearLayout
|
||||
private lateinit var hiddenPackagesContainer: LinearLayout
|
||||
private lateinit var helpContainer: LinearLayout
|
||||
private lateinit var helpToggle: Button
|
||||
private lateinit var packageInput: EditText
|
||||
private lateinit var hiddenPackageInput: EditText
|
||||
private lateinit var hiddenPackagesChips: ChipGroup
|
||||
private lateinit var helpContainer: View
|
||||
private lateinit var helpToggle: MaterialButton
|
||||
private lateinit var packageInput: TextInputEditText
|
||||
private lateinit var hiddenPackageInput: TextInputEditText
|
||||
private var helpVisible = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@@ -62,11 +66,17 @@ class SettingsActivity : Activity() {
|
||||
|
||||
root.addView(TextView(this).apply {
|
||||
text = "Veil"
|
||||
textSize = 20f
|
||||
textSize = 26f
|
||||
setTypeface(typeface, Typeface.BOLD)
|
||||
})
|
||||
root.addView(TextView(this).apply {
|
||||
text = "Hide device state from specific apps, per app."
|
||||
textSize = 14f
|
||||
alpha = 0.7f
|
||||
setPadding(0, dp(2), 0, dp(16))
|
||||
})
|
||||
|
||||
helpToggle = Button(this).apply {
|
||||
helpToggle = MaterialButton(this).apply {
|
||||
text = "Help & troubleshooting ▾"
|
||||
setOnClickListener {
|
||||
helpVisible = !helpVisible
|
||||
@@ -76,36 +86,34 @@ class SettingsActivity : Activity() {
|
||||
}
|
||||
root.addView(helpToggle)
|
||||
|
||||
helpContainer = LinearLayout(this).apply {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
setPadding(0, dp(8), 0, dp(8))
|
||||
visibility = View.GONE
|
||||
for ((title, body) in HELP_TIPS) {
|
||||
addView(TextView(this@SettingsActivity).apply {
|
||||
text = title
|
||||
setTypeface(typeface, Typeface.BOLD)
|
||||
setPadding(0, dp(8), 0, dp(2))
|
||||
})
|
||||
addView(TextView(this@SettingsActivity).apply {
|
||||
text = body
|
||||
textSize = 13f
|
||||
})
|
||||
}
|
||||
val (helpCard, helpContent) = card()
|
||||
helpCard.visibility = View.GONE
|
||||
helpContainer = helpCard
|
||||
for ((title, body) in HELP_TIPS) {
|
||||
helpContent.addView(TextView(this).apply {
|
||||
text = title
|
||||
setTypeface(typeface, Typeface.BOLD)
|
||||
setPadding(0, dp(8), 0, dp(2))
|
||||
})
|
||||
helpContent.addView(TextView(this).apply {
|
||||
text = body
|
||||
textSize = 13f
|
||||
alpha = 0.85f
|
||||
})
|
||||
}
|
||||
root.addView(helpContainer)
|
||||
root.addView(helpCard, marginTop(dp(8)))
|
||||
|
||||
root.addView(sectionTitle("Apps"))
|
||||
root.addView(TextView(this).apply {
|
||||
text = "Add the package name of an app you've scoped this module to in LSPosed, " +
|
||||
"then choose which checks to hide from it. Apps you haven't added here get " +
|
||||
"everything hidden by default (matches this module's original behavior)."
|
||||
setPadding(0, dp(8), 0, dp(16))
|
||||
"or just scope it in LSPosed and open the target app once — Veil picks it up " +
|
||||
"automatically. Apps not listed here get everything hidden by default."
|
||||
textSize = 13f
|
||||
alpha = 0.8f
|
||||
setPadding(0, dp(4), 0, dp(8))
|
||||
})
|
||||
|
||||
packageInput = EditText(this).apply {
|
||||
hint = "e.g. com.example.targetapp"
|
||||
inputType = InputType.TYPE_CLASS_TEXT
|
||||
layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f)
|
||||
}
|
||||
packageInput = textInput("e.g. com.example.targetapp")
|
||||
root.addView(addRow(packageInput) {
|
||||
val pkg = packageInput.text.toString().trim()
|
||||
if (pkg.isNotEmpty() && pkg.contains(".")) {
|
||||
@@ -118,28 +126,20 @@ class SettingsActivity : Activity() {
|
||||
|
||||
appListContainer = LinearLayout(this).apply {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
setPadding(0, dp(16), 0, 0)
|
||||
setPadding(0, dp(8), 0, 0)
|
||||
}
|
||||
root.addView(appListContainer)
|
||||
|
||||
root.addView(sectionTitle("Packages hidden from PackageManager"), marginTop(dp(24)))
|
||||
root.addView(TextView(this).apply {
|
||||
text = "Packages hidden from PackageManager"
|
||||
textSize = 18f
|
||||
setTypeface(typeface, Typeface.BOLD)
|
||||
setPadding(0, dp(24), 0, dp(4))
|
||||
})
|
||||
root.addView(TextView(this).apply {
|
||||
text = "Used by the \"Hide root / manager apps\" checkbox above — apps in this list " +
|
||||
"become invisible to PackageManager lookups for any target app with that box " +
|
||||
"checked."
|
||||
setPadding(0, 0, 0, dp(8))
|
||||
text = "Used by the \"Hide root / manager apps\" checkbox above — apps here become " +
|
||||
"invisible to PackageManager lookups for any target app with that box checked."
|
||||
textSize = 13f
|
||||
alpha = 0.8f
|
||||
setPadding(0, dp(4), 0, dp(8))
|
||||
})
|
||||
|
||||
hiddenPackageInput = EditText(this).apply {
|
||||
hint = "e.g. me.weishu.kernelsu"
|
||||
inputType = InputType.TYPE_CLASS_TEXT
|
||||
layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f)
|
||||
}
|
||||
hiddenPackageInput = textInput("e.g. me.weishu.kernelsu")
|
||||
root.addView(addRow(hiddenPackageInput) {
|
||||
val pkg = hiddenPackageInput.text.toString().trim()
|
||||
if (pkg.isNotEmpty() && pkg.contains(".")) {
|
||||
@@ -152,29 +152,69 @@ class SettingsActivity : Activity() {
|
||||
}
|
||||
})
|
||||
|
||||
hiddenPackagesContainer = LinearLayout(this).apply {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
hiddenPackagesChips = ChipGroup(this).apply {
|
||||
setPadding(0, dp(8), 0, 0)
|
||||
}
|
||||
root.addView(hiddenPackagesContainer)
|
||||
root.addView(hiddenPackagesChips)
|
||||
|
||||
setContentView(ScrollView(this).apply { addView(root) })
|
||||
refreshAppList()
|
||||
refreshHiddenPackages()
|
||||
}
|
||||
|
||||
private fun addRow(input: EditText, onAdd: () -> Unit): View {
|
||||
private fun sectionTitle(text: String): TextView = TextView(this).apply {
|
||||
this.text = text
|
||||
textSize = 18f
|
||||
setTypeface(typeface, Typeface.BOLD)
|
||||
}
|
||||
|
||||
private fun marginTop(px: Int): LinearLayout.LayoutParams =
|
||||
LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply {
|
||||
topMargin = px
|
||||
}
|
||||
|
||||
private fun textInput(hintText: String): TextInputEditText {
|
||||
val editText = TextInputEditText(this).apply {
|
||||
hint = hintText
|
||||
inputType = InputType.TYPE_CLASS_TEXT
|
||||
}
|
||||
return editText
|
||||
}
|
||||
|
||||
private fun addRow(input: TextInputEditText, onAdd: () -> Unit): View {
|
||||
val layout = TextInputLayout(this).apply {
|
||||
layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f)
|
||||
addView(input)
|
||||
}
|
||||
return LinearLayout(this).apply {
|
||||
orientation = LinearLayout.HORIZONTAL
|
||||
gravity = Gravity.CENTER_VERTICAL
|
||||
addView(input)
|
||||
addView(Button(this@SettingsActivity).apply {
|
||||
addView(layout)
|
||||
addView(MaterialButton(this@SettingsActivity).apply {
|
||||
text = "Add"
|
||||
setOnClickListener { onAdd() }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/** A MaterialCardView with an inner padded vertical container, added to root with bottom margin. */
|
||||
private fun card(): Pair<MaterialCardView, LinearLayout> {
|
||||
val content = LinearLayout(this).apply {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
setPadding(dp(16), dp(16), dp(16), dp(16))
|
||||
}
|
||||
val cardView = MaterialCardView(this).apply {
|
||||
radius = dp(12).toFloat()
|
||||
cardElevation = dp(1).toFloat()
|
||||
layoutParams = LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
).apply { bottomMargin = dp(12) }
|
||||
addView(content)
|
||||
}
|
||||
return cardView to content
|
||||
}
|
||||
|
||||
private fun hiddenPackages(): Set<String> =
|
||||
prefs.getStringSet(Features.HIDDEN_PACKAGES_KEY, Features.DEFAULT_HIDDEN_PACKAGES) ?: Features.DEFAULT_HIDDEN_PACKAGES
|
||||
|
||||
@@ -193,6 +233,8 @@ class SettingsActivity : Activity() {
|
||||
appListContainer.addView(TextView(this).apply {
|
||||
text = "No apps yet — scope Veil to a target app in LSPosed Manager and open " +
|
||||
"it once, or add a package name above."
|
||||
textSize = 13f
|
||||
alpha = 0.8f
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -204,11 +246,8 @@ class SettingsActivity : Activity() {
|
||||
|
||||
private fun buildPackageCard(pkg: String, isDiscoveredOnly: Boolean): View {
|
||||
val enabled = prefs.getStringSet(Features.keyFor(pkg), Features.ALL) ?: Features.ALL
|
||||
val (cardView, content) = card()
|
||||
|
||||
val card = LinearLayout(this).apply {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
setPadding(0, dp(12), 0, dp(12))
|
||||
}
|
||||
val titleRow = LinearLayout(this).apply {
|
||||
orientation = LinearLayout.HORIZONTAL
|
||||
gravity = Gravity.CENTER_VERTICAL
|
||||
@@ -217,22 +256,27 @@ class SettingsActivity : Activity() {
|
||||
text = pkg
|
||||
textSize = 16f
|
||||
setTypeface(typeface, Typeface.BOLD)
|
||||
layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f)
|
||||
})
|
||||
if (isDiscoveredOnly) {
|
||||
titleRow.addView(TextView(this).apply {
|
||||
text = " (auto-detected)"
|
||||
textSize = 13f
|
||||
titleRow.addView(Chip(this).apply {
|
||||
text = "Auto-detected"
|
||||
isClickable = false
|
||||
isCheckable = false
|
||||
})
|
||||
}
|
||||
card.addView(titleRow)
|
||||
card.addView(TextView(this).apply {
|
||||
text = "Checking a box below hides that thing from this app specifically — it stays " +
|
||||
"on for every other app."
|
||||
setPadding(0, 0, 0, dp(8))
|
||||
content.addView(titleRow)
|
||||
|
||||
content.addView(TextView(this).apply {
|
||||
text = "Checking a box below hides that thing from this app specifically — it " +
|
||||
"stays on for every other app."
|
||||
textSize = 12f
|
||||
alpha = 0.7f
|
||||
setPadding(0, dp(2), 0, dp(8))
|
||||
})
|
||||
|
||||
for ((id, info) in Features.INFO) {
|
||||
card.addView(CheckBox(this).apply {
|
||||
content.addView(MaterialCheckBox(this).apply {
|
||||
text = info.label
|
||||
isChecked = id in enabled
|
||||
setOnCheckedChangeListener { _, isChecked ->
|
||||
@@ -242,15 +286,16 @@ class SettingsActivity : Activity() {
|
||||
fixPermissions()
|
||||
}
|
||||
})
|
||||
card.addView(TextView(this).apply {
|
||||
content.addView(TextView(this).apply {
|
||||
text = info.description
|
||||
textSize = 13f
|
||||
alpha = 0.7f
|
||||
setPadding(dp(32), 0, 0, dp(8))
|
||||
})
|
||||
}
|
||||
|
||||
card.addView(Button(this).apply {
|
||||
text = "Remove (revert to default: hide everything)"
|
||||
content.addView(MaterialButton(this).apply {
|
||||
text = "Apply defaults (hide everything)"
|
||||
setOnClickListener {
|
||||
prefs.edit().remove(Features.keyFor(pkg)).apply()
|
||||
fixPermissions()
|
||||
@@ -258,32 +303,16 @@ class SettingsActivity : Activity() {
|
||||
}
|
||||
})
|
||||
|
||||
return card
|
||||
return cardView
|
||||
}
|
||||
|
||||
private fun refreshHiddenPackages() {
|
||||
hiddenPackagesContainer.removeAllViews()
|
||||
val packages = hiddenPackages().sorted()
|
||||
|
||||
if (packages.isEmpty()) {
|
||||
hiddenPackagesContainer.addView(TextView(this).apply {
|
||||
text = "None configured."
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
for (pkg in packages) {
|
||||
val row = LinearLayout(this).apply {
|
||||
orientation = LinearLayout.HORIZONTAL
|
||||
gravity = Gravity.CENTER_VERTICAL
|
||||
}
|
||||
row.addView(TextView(this).apply {
|
||||
hiddenPackagesChips.removeAllViews()
|
||||
for (pkg in hiddenPackages().sorted()) {
|
||||
hiddenPackagesChips.addView(Chip(this).apply {
|
||||
text = pkg
|
||||
layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f)
|
||||
})
|
||||
row.addView(Button(this).apply {
|
||||
text = "Remove"
|
||||
setOnClickListener {
|
||||
isCloseIconVisible = true
|
||||
setOnCloseIconClickListener {
|
||||
val current = hiddenPackages().toMutableSet()
|
||||
current.remove(pkg)
|
||||
prefs.edit().putStringSet(Features.HIDDEN_PACKAGES_KEY, current).apply()
|
||||
@@ -291,7 +320,6 @@ class SettingsActivity : Activity() {
|
||||
refreshHiddenPackages()
|
||||
}
|
||||
})
|
||||
hiddenPackagesContainer.addView(row)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<!-- A moon-like disc, partially eclipsed by a diagonal veil (cut in the background color) -->
|
||||
<path
|
||||
android:fillColor="#F2EDE4"
|
||||
android:pathData="M28,54 A26,26 0 1,1 80,54 A26,26 0 1,1 28,54 Z" />
|
||||
<path
|
||||
android:fillColor="#1B1B3A"
|
||||
android:pathData="M12,68 L36,92 L96,32 L72,8 Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,4 @@
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,4 @@
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#1B1B3A</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<style name="Theme.Veil" parent="Theme.Material3.DayNight.NoActionBar" />
|
||||
</resources>
|
||||
Reference in new issue
Block a user