mirror of
https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation.git
synced 2026-08-09 15:19:11 +02:00
refactor: move theme to uad-gui; drop core gui deps; mark PmCommand must-use
This commit is contained in:
parent
da7482601e
commit
02ba6e2cca
14 changed files with 205 additions and 309 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -4558,10 +4558,8 @@ version = "1.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"csv",
|
"csv",
|
||||||
"dark-light",
|
|
||||||
"dirs",
|
"dirs",
|
||||||
"flate2",
|
"flate2",
|
||||||
"iced",
|
|
||||||
"log",
|
"log",
|
||||||
"retry",
|
"retry",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,6 @@ format_push_string = "warn"
|
||||||
large_include_file = "warn"
|
large_include_file = "warn"
|
||||||
shadow_unrelated = "warn"
|
shadow_unrelated = "warn"
|
||||||
struct_field_names = "allow" # annoying
|
struct_field_names = "allow" # annoying
|
||||||
module_name_repetitions = "allow" # annoying
|
|
||||||
|
|
||||||
disallowed_types = "deny"
|
disallowed_types = "deny"
|
||||||
disallowed_methods = "deny"
|
disallowed_methods = "deny"
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,7 @@ uad completions powershell > uad.ps1
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
### Remove all Facebook packages
|
### Remove Facebook packages
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
uad list --search facebook
|
uad list --search facebook
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ edition.workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
gui = ["dep:iced", "dep:dark-light"]
|
|
||||||
self-update = ["dep:flate2", "dep:tar"]
|
self-update = ["dep:flate2", "dep:tar"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
@ -25,8 +24,6 @@ dirs.workspace = true
|
||||||
ureq.workspace = true
|
ureq.workspace = true
|
||||||
retry.workspace = true
|
retry.workspace = true
|
||||||
csv.workspace = true
|
csv.workspace = true
|
||||||
iced = { workspace = true, optional = true }
|
|
||||||
dark-light = { workspace = true, optional = true }
|
|
||||||
flate2 = { workspace = true, optional = true }
|
flate2 = { workspace = true, optional = true }
|
||||||
tar = { workspace = true, optional = true }
|
tar = { workspace = true, optional = true }
|
||||||
|
|
||||||
|
|
@ -47,7 +44,6 @@ format_push_string = "warn"
|
||||||
large_include_file = "warn"
|
large_include_file = "warn"
|
||||||
shadow_unrelated = "warn"
|
shadow_unrelated = "warn"
|
||||||
struct_field_names = "allow" # annoying
|
struct_field_names = "allow" # annoying
|
||||||
module_name_repetitions = "allow" # annoying
|
|
||||||
|
|
||||||
disallowed_types = "deny"
|
disallowed_types = "deny"
|
||||||
disallowed_methods = "deny"
|
disallowed_methods = "deny"
|
||||||
|
|
|
||||||
|
|
@ -229,7 +229,6 @@ impl Default for ACommand {
|
||||||
pub struct ShellCommand(ACommand);
|
pub struct ShellCommand(ACommand);
|
||||||
impl ShellCommand {
|
impl ShellCommand {
|
||||||
/// `pm` command builder
|
/// `pm` command builder
|
||||||
#[must_use]
|
|
||||||
pub fn pm(mut self) -> PmCommand {
|
pub fn pm(mut self) -> PmCommand {
|
||||||
self.0.0.arg("pm");
|
self.0.0.arg("pm");
|
||||||
PmCommand(self)
|
PmCommand(self)
|
||||||
|
|
@ -335,6 +334,7 @@ pub const PM_CLEAR_PACK: &str = "pm clear";
|
||||||
/// Builder object for an Android Package Manager command.
|
/// Builder object for an Android Package Manager command.
|
||||||
/// <https://developer.android.com/tools/adb#pm>
|
/// <https://developer.android.com/tools/adb#pm>
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
#[must_use]
|
||||||
pub struct PmCommand(ShellCommand);
|
pub struct PmCommand(ShellCommand);
|
||||||
impl PmCommand {
|
impl PmCommand {
|
||||||
/// `list packages -s` sub-command, [`PACK_PREFIX`] stripped.
|
/// `list packages -s` sub-command, [`PACK_PREFIX`] stripped.
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,15 @@
|
||||||
use crate::CACHE_DIR;
|
use crate::CACHE_DIR;
|
||||||
use crate::CONFIG_DIR;
|
use crate::CONFIG_DIR;
|
||||||
|
use crate::sync::User;
|
||||||
use crate::utils::DisplayablePath;
|
use crate::utils::DisplayablePath;
|
||||||
use crate::{sync::User, theme::Theme};
|
|
||||||
use log::error;
|
use log::error;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
|
const DEFAULT_THEME: &str = "Auto (follow system theme)";
|
||||||
|
|
||||||
#[derive(Default, Debug, Serialize, Deserialize, Clone)]
|
#[derive(Default, Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub general: GeneralSettings,
|
pub general: GeneralSettings,
|
||||||
|
|
@ -44,7 +46,7 @@ pub struct DeviceSettings {
|
||||||
impl Default for GeneralSettings {
|
impl Default for GeneralSettings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
theme: Theme::default().to_string(),
|
theme: DEFAULT_THEME.to_string(),
|
||||||
expert_mode: false,
|
expert_mode: false,
|
||||||
backup_folder: CACHE_DIR.join("backups"),
|
backup_folder: CACHE_DIR.join("backups"),
|
||||||
}
|
}
|
||||||
|
|
@ -114,7 +116,7 @@ mod tests {
|
||||||
let config = Config::load_configuration_file();
|
let config = Config::load_configuration_file();
|
||||||
// non-deterministic
|
// non-deterministic
|
||||||
//assert_eq!(config.devices.len(), 0);
|
//assert_eq!(config.devices.len(), 0);
|
||||||
assert_eq!(config.general.theme, Theme::default().to_string());
|
assert_eq!(config.general.theme, DEFAULT_THEME);
|
||||||
assert!(!config.general.expert_mode);
|
assert!(!config.general.expert_mode);
|
||||||
assert_eq!(config.general.backup_folder, CACHE_DIR.join("backups"));
|
assert_eq!(config.general.backup_folder, CACHE_DIR.join("backups"));
|
||||||
}
|
}
|
||||||
|
|
@ -136,7 +138,7 @@ mod tests {
|
||||||
fn test_default_config() {
|
fn test_default_config() {
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
assert_eq!(config.devices.len(), 0);
|
assert_eq!(config.devices.len(), 0);
|
||||||
assert_eq!(config.general.theme, Theme::default().to_string());
|
assert_eq!(config.general.theme, DEFAULT_THEME);
|
||||||
assert!(!config.general.expert_mode);
|
assert!(!config.general.expert_mode);
|
||||||
assert_eq!(config.general.backup_folder, CACHE_DIR.join("backups"));
|
assert_eq!(config.general.backup_folder, CACHE_DIR.join("backups"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ pub mod adb;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod save;
|
pub mod save;
|
||||||
pub mod sync;
|
pub mod sync;
|
||||||
pub mod theme;
|
|
||||||
pub mod uad_lists;
|
pub mod uad_lists;
|
||||||
pub mod update;
|
pub mod update;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
|
||||||
|
|
@ -1,231 +0,0 @@
|
||||||
#[cfg(feature = "gui")]
|
|
||||||
use dark_light;
|
|
||||||
#[cfg(feature = "gui")]
|
|
||||||
use iced::theme::{self, Mode, Palette, Style};
|
|
||||||
#[cfg(feature = "gui")]
|
|
||||||
use iced::{Color, color};
|
|
||||||
#[cfg(feature = "gui")]
|
|
||||||
use std::sync::LazyLock;
|
|
||||||
|
|
||||||
/*
|
|
||||||
In-memory caching.
|
|
||||||
This fixes the perf bug
|
|
||||||
caused by Iced repeatedly calling `palette`.
|
|
||||||
|
|
||||||
Coincidentally, this also ensures consistent colors across the GUI,
|
|
||||||
at the cost of requiring a restart to update the palette.
|
|
||||||
(this is just a patch, not a fix)
|
|
||||||
*/
|
|
||||||
#[cfg(feature = "gui")]
|
|
||||||
pub static OS_COLOR_SCHEME: LazyLock<dark_light::Mode> =
|
|
||||||
LazyLock::new(|| dark_light::detect().unwrap_or(dark_light::Mode::Unspecified));
|
|
||||||
|
|
||||||
#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)]
|
|
||||||
/// Color scheme
|
|
||||||
pub enum Theme {
|
|
||||||
#[default]
|
|
||||||
/// `Dark` or `Light`, according to `dark_light`
|
|
||||||
Auto,
|
|
||||||
/// `Dark`-ish and purple
|
|
||||||
Lupin,
|
|
||||||
/// white on black
|
|
||||||
Dark,
|
|
||||||
/// black on white
|
|
||||||
Light,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "gui")]
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct BaseColors {
|
|
||||||
pub background: Color,
|
|
||||||
pub foreground: Color,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "gui")]
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct NormalColors {
|
|
||||||
pub primary: Color,
|
|
||||||
#[allow(dead_code, reason = "Reserved for future palette updates")]
|
|
||||||
pub secondary: Color,
|
|
||||||
pub surface: Color,
|
|
||||||
pub error: Color,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "gui")]
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct BrightColors {
|
|
||||||
pub primary: Color,
|
|
||||||
pub secondary: Color,
|
|
||||||
pub surface: Color,
|
|
||||||
pub error: Color,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "gui")]
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct ColorPalette {
|
|
||||||
pub base: BaseColors,
|
|
||||||
pub normal: NormalColors,
|
|
||||||
pub bright: BrightColors,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Theme {
|
|
||||||
pub const ALL: [Self; 4] = [Self::Auto, Self::Lupin, Self::Dark, Self::Light];
|
|
||||||
|
|
||||||
#[allow(
|
|
||||||
clippy::unreadable_literal,
|
|
||||||
reason = "https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/pull/578#discussion_r1759653408"
|
|
||||||
)]
|
|
||||||
/// This `fn` _could_ be `const`,
|
|
||||||
/// but `deref`ing a lazy-`static` is non-`const`.
|
|
||||||
#[must_use]
|
|
||||||
#[cfg(feature = "gui")]
|
|
||||||
pub fn palette(self) -> ColorPalette {
|
|
||||||
const DARK: ColorPalette = ColorPalette {
|
|
||||||
base: BaseColors {
|
|
||||||
background: color!(0x111111),
|
|
||||||
foreground: color!(0x1C1C1C),
|
|
||||||
},
|
|
||||||
normal: NormalColors {
|
|
||||||
primary: color!(0x5E4266),
|
|
||||||
secondary: color!(0x386E50),
|
|
||||||
surface: color!(0x828282),
|
|
||||||
error: color!(0x992B2B),
|
|
||||||
},
|
|
||||||
bright: BrightColors {
|
|
||||||
primary: color!(0xBA84FC),
|
|
||||||
secondary: color!(0x49EB7A),
|
|
||||||
surface: color!(0xE0E0E0),
|
|
||||||
error: color!(0xC13047),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const LIGHT: ColorPalette = ColorPalette {
|
|
||||||
base: BaseColors {
|
|
||||||
background: color!(0xEEEEEE),
|
|
||||||
foreground: color!(0xE0E0E0),
|
|
||||||
},
|
|
||||||
normal: NormalColors {
|
|
||||||
primary: color!(0x818181),
|
|
||||||
secondary: color!(0xF9D659),
|
|
||||||
surface: color!(0x818181),
|
|
||||||
error: color!(0x992B2B),
|
|
||||||
},
|
|
||||||
bright: BrightColors {
|
|
||||||
primary: color!(0x673AB7),
|
|
||||||
secondary: color!(0x3797A4),
|
|
||||||
surface: color!(0x000000),
|
|
||||||
error: color!(0xC13047),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const LUPIN: ColorPalette = ColorPalette {
|
|
||||||
base: BaseColors {
|
|
||||||
background: color!(0x282A36),
|
|
||||||
foreground: color!(0x353746),
|
|
||||||
},
|
|
||||||
normal: NormalColors {
|
|
||||||
primary: color!(0x58406F),
|
|
||||||
secondary: color!(0x386E50),
|
|
||||||
surface: color!(0xA2A4A3),
|
|
||||||
error: color!(0xA13034),
|
|
||||||
},
|
|
||||||
bright: BrightColors {
|
|
||||||
primary: color!(0xBD94F9),
|
|
||||||
secondary: color!(0x49EB7A),
|
|
||||||
surface: color!(0xF4F8F3),
|
|
||||||
error: color!(0xE63E6D),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
match self {
|
|
||||||
Self::Dark => DARK,
|
|
||||||
Self::Light => LIGHT,
|
|
||||||
Self::Lupin => LUPIN,
|
|
||||||
Self::Auto => match *OS_COLOR_SCHEME {
|
|
||||||
dark_light::Mode::Light => LIGHT,
|
|
||||||
dark_light::Mode::Dark | dark_light::Mode::Unspecified => DARK,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for Theme {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{}",
|
|
||||||
match self {
|
|
||||||
Self::Dark => "Dark",
|
|
||||||
Self::Light => "Light",
|
|
||||||
Self::Lupin => "Lupin",
|
|
||||||
Self::Auto => "Auto (follow system theme)",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts a string to the GUI's Theme type
|
|
||||||
#[must_use]
|
|
||||||
pub fn string_to_theme(theme: &str) -> Theme {
|
|
||||||
match theme {
|
|
||||||
"Lupin" => Theme::Lupin,
|
|
||||||
"Dark" => Theme::Dark,
|
|
||||||
"Light" => Theme::Light,
|
|
||||||
_ => Theme::Auto,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "gui")]
|
|
||||||
impl theme::Base for Theme {
|
|
||||||
fn default(preference: Mode) -> Self {
|
|
||||||
match preference {
|
|
||||||
Mode::Light => Self::Light,
|
|
||||||
Mode::Dark => Self::Dark,
|
|
||||||
Mode::None => match *OS_COLOR_SCHEME {
|
|
||||||
dark_light::Mode::Light => Self::Light,
|
|
||||||
dark_light::Mode::Dark | dark_light::Mode::Unspecified => Self::Dark,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mode(&self) -> Mode {
|
|
||||||
let resolved = match self {
|
|
||||||
Self::Auto => match *OS_COLOR_SCHEME {
|
|
||||||
dark_light::Mode::Light => Self::Light,
|
|
||||||
dark_light::Mode::Dark | dark_light::Mode::Unspecified => Self::Dark,
|
|
||||||
},
|
|
||||||
other => *other,
|
|
||||||
};
|
|
||||||
|
|
||||||
match resolved {
|
|
||||||
Self::Light => Mode::Light,
|
|
||||||
_ => Mode::Dark,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn base(&self) -> Style {
|
|
||||||
let p = Self::palette(*self);
|
|
||||||
Style {
|
|
||||||
background_color: p.base.background,
|
|
||||||
text_color: p.bright.surface,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn palette(&self) -> Option<Palette> {
|
|
||||||
let p = Self::palette(*self);
|
|
||||||
Some(Palette {
|
|
||||||
background: p.base.background,
|
|
||||||
text: p.bright.surface,
|
|
||||||
primary: p.normal.primary,
|
|
||||||
success: p.bright.secondary,
|
|
||||||
warning: p.normal.surface,
|
|
||||||
danger: p.normal.error,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
Self::Dark => "Dark",
|
|
||||||
Self::Light => "Light",
|
|
||||||
Self::Lupin => "Lupin",
|
|
||||||
Self::Auto => "Auto",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
adb::{ACommand as AdbCommand, PmListPacksFlag},
|
adb::{ACommand as AdbCommand, PmListPacksFlag},
|
||||||
sync::{CorePackage, User},
|
sync::{CorePackage, User},
|
||||||
theme::Theme,
|
|
||||||
uad_lists::{PackageHashMap, PackageState, Removal, UadList},
|
uad_lists::{PackageHashMap, PackageState, Removal, UadList},
|
||||||
};
|
};
|
||||||
use chrono::{DateTime, offset::Utc};
|
use chrono::{DateTime, offset::Utc};
|
||||||
|
|
@ -128,22 +127,10 @@ pub fn fetch_packages(
|
||||||
};
|
};
|
||||||
user_package.push(package);
|
user_package.push(package);
|
||||||
}
|
}
|
||||||
user_package.sort_by_key(|a| a.name.to_lowercase());
|
user_package.sort_by_key(|package| package.name.to_lowercase());
|
||||||
user_package
|
user_package
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn string_to_theme(theme: &str) -> Theme {
|
|
||||||
match theme {
|
|
||||||
"Dark" => Theme::Dark,
|
|
||||||
"Light" => Theme::Light,
|
|
||||||
"Lupin" => Theme::Lupin,
|
|
||||||
// Auto uses `Display`, so it doesn't have a canonical repr
|
|
||||||
t if t.starts_with("Auto") => Theme::Auto,
|
|
||||||
_ => Theme::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn setup_uad_dir(dir: &Path) -> PathBuf {
|
pub fn setup_uad_dir(dir: &Path) -> PathBuf {
|
||||||
let dir = dir.join("uad");
|
let dir = dir.join("uad");
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ no-self-update = []
|
||||||
img = ["image", "iced/image"]
|
img = ["image", "iced/image"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
uad-core = { path = "../uad-core", features = ["gui", "self-update"] }
|
uad-core = { path = "../uad-core", features = ["self-update"] }
|
||||||
iced.workspace = true
|
iced.workspace = true
|
||||||
image = { workspace = true, optional = true }
|
image = { workspace = true, optional = true }
|
||||||
rfd.workspace = true
|
rfd.workspace = true
|
||||||
|
|
@ -54,7 +54,6 @@ format_push_string = "warn"
|
||||||
large_include_file = "warn"
|
large_include_file = "warn"
|
||||||
shadow_unrelated = "warn"
|
shadow_unrelated = "warn"
|
||||||
struct_field_names = "allow" # annoying
|
struct_field_names = "allow" # annoying
|
||||||
module_name_repetitions = "allow" # annoying
|
|
||||||
|
|
||||||
disallowed_types = "deny"
|
disallowed_types = "deny"
|
||||||
disallowed_methods = "deny"
|
disallowed_methods = "deny"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::theme::string_to_theme;
|
|
||||||
#[cfg(feature = "img")]
|
#[cfg(feature = "img")]
|
||||||
use crate::theme::OS_COLOR_SCHEME;
|
use crate::theme::OS_COLOR_SCHEME;
|
||||||
use crate::theme::Theme;
|
use crate::theme::Theme;
|
||||||
|
use crate::theme::string_to_theme;
|
||||||
use crate::views::about::{About as AboutView, Message as AboutMessage};
|
use crate::views::about::{About as AboutView, Message as AboutMessage};
|
||||||
use crate::views::list::{
|
use crate::views::list::{
|
||||||
List as AppsView, LoadingState as ListLoadingState, Message as AppsMessage,
|
List as AppsView, LoadingState as ListLoadingState, Message as AppsMessage,
|
||||||
|
|
@ -9,13 +9,13 @@ use crate::views::list::{
|
||||||
use crate::views::settings::{Message as SettingsMessage, Settings as SettingsView};
|
use crate::views::settings::{Message as SettingsMessage, Settings as SettingsView};
|
||||||
use crate::widgets::navigation_menu::nav_menu;
|
use crate::widgets::navigation_menu::nav_menu;
|
||||||
use iced::font;
|
use iced::font;
|
||||||
|
use iced::widget::column;
|
||||||
#[cfg(feature = "img")]
|
#[cfg(feature = "img")]
|
||||||
use iced::window::icon;
|
use iced::window::icon;
|
||||||
#[cfg(feature = "img")]
|
|
||||||
use image::ImageFormat;
|
|
||||||
use iced::widget::column;
|
|
||||||
use iced::{Alignment, Element, Length, Settings, Task, window::Settings as Window};
|
use iced::{Alignment, Element, Length, Settings, Task, window::Settings as Window};
|
||||||
use iced::{Subscription, event, keyboard};
|
use iced::{Subscription, event, keyboard};
|
||||||
|
#[cfg(feature = "img")]
|
||||||
|
use image::ImageFormat;
|
||||||
use log::{debug, error, info};
|
use log::{debug, error, info};
|
||||||
#[cfg(feature = "self-update")]
|
#[cfg(feature = "self-update")]
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
@ -434,7 +434,7 @@ impl UadGui {
|
||||||
pub fn start() -> iced::Result {
|
pub fn start() -> iced::Result {
|
||||||
#[cfg(feature = "img")]
|
#[cfg(feature = "img")]
|
||||||
let logo: &[u8] = match *OS_COLOR_SCHEME {
|
let logo: &[u8] = match *OS_COLOR_SCHEME {
|
||||||
// remember to keep `Unspecified` in sync with `src/core/theme`
|
// remember to keep `Unspecified` in sync with `src/theme`
|
||||||
dark_light::Mode::Dark | dark_light::Mode::Unspecified => {
|
dark_light::Mode::Dark | dark_light::Mode::Unspecified => {
|
||||||
include_bytes!("../../../resources/assets/logo-dark.png")
|
include_bytes!("../../../resources/assets/logo-dark.png")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,72 +1,219 @@
|
||||||
use iced::theme::{self, Mode, Palette, Style};
|
use iced::theme::{self, Mode, Palette, Style};
|
||||||
|
use iced::{Color, color};
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
pub use uad_core::theme::{BaseColors, BrightColors, ColorPalette, NormalColors, OS_COLOR_SCHEME};
|
/*
|
||||||
|
In-memory caching.
|
||||||
|
This fixes the perf bug
|
||||||
|
caused by Iced repeatedly calling `palette`.
|
||||||
|
|
||||||
/// GUI-local wrapper around the core Theme to satisfy orphan rules for
|
Coincidentally, this also ensures consistent colors across the GUI,
|
||||||
/// iced's Catalog traits.
|
at the cost of requiring a restart to update the palette.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
(this is just a patch, not a fix)
|
||||||
pub struct Theme(pub uad_core::theme::Theme);
|
*/
|
||||||
|
pub static OS_COLOR_SCHEME: LazyLock<dark_light::Mode> =
|
||||||
|
LazyLock::new(|| dark_light::detect().unwrap_or(dark_light::Mode::Unspecified));
|
||||||
|
|
||||||
|
#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
/// Color scheme
|
||||||
|
pub enum Theme {
|
||||||
|
#[default]
|
||||||
|
/// `Dark` or `Light`, according to `dark_light`
|
||||||
|
Auto,
|
||||||
|
/// `Dark`-ish and purple
|
||||||
|
Lupin,
|
||||||
|
/// white on black
|
||||||
|
Dark,
|
||||||
|
/// black on white
|
||||||
|
Light,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct BaseColors {
|
||||||
|
pub background: Color,
|
||||||
|
pub foreground: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct NormalColors {
|
||||||
|
pub primary: Color,
|
||||||
|
#[allow(dead_code, reason = "Reserved for future palette updates")]
|
||||||
|
pub secondary: Color,
|
||||||
|
pub surface: Color,
|
||||||
|
pub error: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct BrightColors {
|
||||||
|
pub primary: Color,
|
||||||
|
pub secondary: Color,
|
||||||
|
pub surface: Color,
|
||||||
|
pub error: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct ColorPalette {
|
||||||
|
pub base: BaseColors,
|
||||||
|
pub normal: NormalColors,
|
||||||
|
pub bright: BrightColors,
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(
|
|
||||||
non_upper_case_globals,
|
|
||||||
reason = "Keep variant-like names matching core Theme"
|
|
||||||
)]
|
|
||||||
impl Theme {
|
impl Theme {
|
||||||
pub const Auto: Self = Self(uad_core::theme::Theme::Auto);
|
|
||||||
pub const Lupin: Self = Self(uad_core::theme::Theme::Lupin);
|
|
||||||
pub const Dark: Self = Self(uad_core::theme::Theme::Dark);
|
|
||||||
pub const Light: Self = Self(uad_core::theme::Theme::Light);
|
|
||||||
|
|
||||||
pub const ALL: [Self; 4] = [Self::Auto, Self::Lupin, Self::Dark, Self::Light];
|
pub const ALL: [Self; 4] = [Self::Auto, Self::Lupin, Self::Dark, Self::Light];
|
||||||
|
|
||||||
|
#[allow(
|
||||||
|
clippy::unreadable_literal,
|
||||||
|
reason = "https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/pull/578#discussion_r1759653408"
|
||||||
|
)]
|
||||||
|
/// This `fn` _could_ be `const`,
|
||||||
|
/// but `deref`ing a lazy-`static` is non-`const`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn palette(self) -> ColorPalette {
|
pub fn palette(self) -> ColorPalette {
|
||||||
self.0.palette()
|
const DARK: ColorPalette = ColorPalette {
|
||||||
|
base: BaseColors {
|
||||||
|
background: color!(0x111111),
|
||||||
|
foreground: color!(0x1C1C1C),
|
||||||
|
},
|
||||||
|
normal: NormalColors {
|
||||||
|
primary: color!(0x5E4266),
|
||||||
|
secondary: color!(0x386E50),
|
||||||
|
surface: color!(0x828282),
|
||||||
|
error: color!(0x992B2B),
|
||||||
|
},
|
||||||
|
bright: BrightColors {
|
||||||
|
primary: color!(0xBA84FC),
|
||||||
|
secondary: color!(0x49EB7A),
|
||||||
|
surface: color!(0xE0E0E0),
|
||||||
|
error: color!(0xC13047),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const LIGHT: ColorPalette = ColorPalette {
|
||||||
|
base: BaseColors {
|
||||||
|
background: color!(0xEEEEEE),
|
||||||
|
foreground: color!(0xE0E0E0),
|
||||||
|
},
|
||||||
|
normal: NormalColors {
|
||||||
|
primary: color!(0x818181),
|
||||||
|
secondary: color!(0xF9D659),
|
||||||
|
surface: color!(0x818181),
|
||||||
|
error: color!(0x992B2B),
|
||||||
|
},
|
||||||
|
bright: BrightColors {
|
||||||
|
primary: color!(0x673AB7),
|
||||||
|
secondary: color!(0x3797A4),
|
||||||
|
surface: color!(0x000000),
|
||||||
|
error: color!(0xC13047),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const LUPIN: ColorPalette = ColorPalette {
|
||||||
|
base: BaseColors {
|
||||||
|
background: color!(0x282A36),
|
||||||
|
foreground: color!(0x353746),
|
||||||
|
},
|
||||||
|
normal: NormalColors {
|
||||||
|
primary: color!(0x58406F),
|
||||||
|
secondary: color!(0x386E50),
|
||||||
|
surface: color!(0xA2A4A3),
|
||||||
|
error: color!(0xA13034),
|
||||||
|
},
|
||||||
|
bright: BrightColors {
|
||||||
|
primary: color!(0xBD94F9),
|
||||||
|
secondary: color!(0x49EB7A),
|
||||||
|
surface: color!(0xF4F8F3),
|
||||||
|
error: color!(0xE63E6D),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
match self {
|
||||||
|
Self::Dark => DARK,
|
||||||
|
Self::Light => LIGHT,
|
||||||
|
Self::Lupin => LUPIN,
|
||||||
|
Self::Auto => match *OS_COLOR_SCHEME {
|
||||||
|
dark_light::Mode::Light => LIGHT,
|
||||||
|
dark_light::Mode::Dark | dark_light::Mode::Unspecified => DARK,
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<uad_core::theme::Theme> for Theme {
|
impl std::fmt::Display for Theme {
|
||||||
fn from(value: uad_core::theme::Theme) -> Self {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
Self(value)
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
match self {
|
||||||
|
Self::Dark => "Dark",
|
||||||
|
Self::Light => "Light",
|
||||||
|
Self::Lupin => "Lupin",
|
||||||
|
Self::Auto => "Auto (follow system theme)",
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
|
|
||||||
impl From<Theme> for uad_core::theme::Theme {
|
|
||||||
fn from(value: Theme) -> Self {
|
|
||||||
value.0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts a string to the GUI's Theme type
|
/// Converts a string to the GUI's Theme type
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn string_to_theme(theme: &str) -> Theme {
|
pub fn string_to_theme(theme: &str) -> Theme {
|
||||||
Theme(uad_core::theme::string_to_theme(theme))
|
match theme {
|
||||||
|
"Lupin" => Theme::Lupin,
|
||||||
|
"Dark" => Theme::Dark,
|
||||||
|
"Light" => Theme::Light,
|
||||||
|
_ => Theme::Auto,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl theme::Base for Theme {
|
impl theme::Base for Theme {
|
||||||
fn default(preference: Mode) -> Self {
|
fn default(preference: Mode) -> Self {
|
||||||
Self(<uad_core::theme::Theme as theme::Base>::default(preference))
|
match preference {
|
||||||
|
Mode::Light => Self::Light,
|
||||||
|
Mode::Dark => Self::Dark,
|
||||||
|
Mode::None => match *OS_COLOR_SCHEME {
|
||||||
|
dark_light::Mode::Light => Self::Light,
|
||||||
|
dark_light::Mode::Dark | dark_light::Mode::Unspecified => Self::Dark,
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mode(&self) -> Mode {
|
fn mode(&self) -> Mode {
|
||||||
<uad_core::theme::Theme as theme::Base>::mode(&self.0)
|
let resolved = match self {
|
||||||
|
Self::Auto => match *OS_COLOR_SCHEME {
|
||||||
|
dark_light::Mode::Light => Self::Light,
|
||||||
|
dark_light::Mode::Dark | dark_light::Mode::Unspecified => Self::Dark,
|
||||||
|
},
|
||||||
|
other => *other,
|
||||||
|
};
|
||||||
|
|
||||||
|
match resolved {
|
||||||
|
Self::Light => Mode::Light,
|
||||||
|
_ => Mode::Dark,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn base(&self) -> Style {
|
fn base(&self) -> Style {
|
||||||
<uad_core::theme::Theme as theme::Base>::base(&self.0)
|
let p = Self::palette(*self);
|
||||||
|
Style {
|
||||||
|
background_color: p.base.background,
|
||||||
|
text_color: p.bright.surface,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn palette(&self) -> Option<Palette> {
|
fn palette(&self) -> Option<Palette> {
|
||||||
<uad_core::theme::Theme as theme::Base>::palette(&self.0)
|
let p = Self::palette(*self);
|
||||||
|
Some(Palette {
|
||||||
|
background: p.base.background,
|
||||||
|
text: p.bright.surface,
|
||||||
|
primary: p.normal.primary,
|
||||||
|
success: p.bright.secondary,
|
||||||
|
warning: p.normal.surface,
|
||||||
|
danger: p.normal.error,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
<uad_core::theme::Theme as theme::Base>::name(&self.0)
|
match self {
|
||||||
}
|
Self::Dark => "Dark",
|
||||||
}
|
Self::Light => "Light",
|
||||||
|
Self::Lupin => "Lupin",
|
||||||
impl std::fmt::Display for Theme {
|
Self::Auto => "Auto",
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
}
|
||||||
std::fmt::Display::fmt(&self.0, f)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
6
flake.lock
generated
6
flake.lock
generated
|
|
@ -2,11 +2,11 @@
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1765270179,
|
"lastModified": 1776949667,
|
||||||
"narHash": "sha256-g2a4MhRKu4ymR4xwo+I+auTknXt/+j37Lnf0Mvfl1rE=",
|
"narHash": "sha256-GMSVw35Q+294GlrTUKlx087E31z7KurReQ1YHSKp5iw=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "677fbe97984e7af3175b6c121f3c39ee5c8d62c9",
|
"rev": "01fbdeef22b76df85ea168fbfe1bfd9e63681b30",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,10 @@
|
||||||
with pkgs;
|
with pkgs;
|
||||||
[
|
[
|
||||||
libglvnd
|
libglvnd
|
||||||
xorg.libX11
|
libX11
|
||||||
xorg.libXcursor
|
libXcursor
|
||||||
xorg.libXi
|
libXi
|
||||||
xorg.libXrandr
|
libXrandr
|
||||||
libxkbcommon
|
libxkbcommon
|
||||||
wayland
|
wayland
|
||||||
]
|
]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue