654 lines
24 KiB
Python
654 lines
24 KiB
Python
"""
|
|
Android Preference 组件 — Preference, PreferenceScreen, PreferenceManager 等
|
|
方法签名完全对齐 Android SDK
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import json
|
|
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
|
|
|
|
from .._core import (
|
|
Stub, AndroidOnlyError, android_context,
|
|
resolve_android_path, to_android_path,
|
|
_sdcard_root, _app_data_dir, _package_name,
|
|
)
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# PreferenceChangeListener
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class PreferenceChangeListener(Stub):
|
|
"""OnPreferenceChangeListener — 偏好变化监听器"""
|
|
|
|
def onPreferenceChange(self, preference: "Preference", new_value: Any) -> bool:
|
|
return True
|
|
|
|
|
|
class PreferenceOnPreferenceClickListener(Stub):
|
|
"""OnPreferenceClickListener — 偏好点击监听器"""
|
|
|
|
def onPreferenceClick(self, preference: "Preference") -> bool:
|
|
return True
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# PreferenceManager
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class PreferenceManager(Stub):
|
|
"""PreferenceManager — 偏好管理器"""
|
|
|
|
KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values"
|
|
|
|
def __init__(self, context: Any):
|
|
super().__init__()
|
|
self._context = context
|
|
self._shared_prefs_name: str = f"{_package_name}_preferences"
|
|
self._shared_prefs_mode: int = 0
|
|
self._prefs_data: Dict[str, Any] = {}
|
|
self._prefs_path = os.path.join(_app_data_dir, "shared_prefs",
|
|
f"{self._shared_prefs_name}.json")
|
|
self._load()
|
|
|
|
def _load(self):
|
|
os.makedirs(os.path.dirname(self._prefs_path), exist_ok=True)
|
|
if os.path.exists(self._prefs_path):
|
|
try:
|
|
with open(self._prefs_path, "r") as f:
|
|
self._prefs_data = json.load(f)
|
|
except (json.JSONDecodeError, OSError):
|
|
self._prefs_data = {}
|
|
else:
|
|
self._prefs_data = {}
|
|
|
|
def _save(self):
|
|
os.makedirs(os.path.dirname(self._prefs_path), exist_ok=True)
|
|
with open(self._prefs_path, "w") as f:
|
|
json.dump(self._prefs_data, f)
|
|
|
|
def getSharedPreferences(self) -> Any:
|
|
return self._prefs_data
|
|
|
|
def setSharedPreferencesName(self, name: str):
|
|
self._shared_prefs_name = name
|
|
self._prefs_path = os.path.join(_app_data_dir, "shared_prefs",
|
|
f"{name}.json")
|
|
self._load()
|
|
|
|
def setSharedPreferencesMode(self, mode: int):
|
|
self._shared_prefs_mode = mode
|
|
|
|
@staticmethod
|
|
def getDefaultSharedPreferences(context: Any) -> Any:
|
|
mgr = PreferenceManager(context)
|
|
return mgr.getSharedPreferences()
|
|
|
|
@staticmethod
|
|
def setDefaultValues(context: Any, res_id: int, read_again: bool):
|
|
pass
|
|
|
|
@staticmethod
|
|
def setDefaultValues(context: Any, shared_prefs_name: str,
|
|
shared_prefs_mode: int, res_id: int,
|
|
read_again: bool):
|
|
pass
|
|
|
|
def getPreference(self, key: str, default: Any = None) -> Any:
|
|
return self._prefs_data.get(key, default)
|
|
|
|
def putPreference(self, key: str, value: Any):
|
|
self._prefs_data[key] = value
|
|
self._save()
|
|
|
|
def removePreference(self, key: str):
|
|
if key in self._prefs_data:
|
|
del self._prefs_data[key]
|
|
self._save()
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# Preference
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class Preference(Stub):
|
|
"""Preference — 偏好设置项基类"""
|
|
|
|
def __init__(self, context: Any = None, attrs: Any = None,
|
|
def_style_attr: int = 0):
|
|
super().__init__()
|
|
self._context = context
|
|
self._title: str = ""
|
|
self._summary: str = ""
|
|
self._key: Optional[str] = None
|
|
self._enabled: bool = True
|
|
self._default_value: Any = None
|
|
self._order: int = 0
|
|
self._persistent: bool = True
|
|
self._icon: Any = None
|
|
self._dependents: List["Preference"] = []
|
|
self._dependency_key: Optional[str] = None
|
|
self._preference_manager: Optional[PreferenceManager] = None
|
|
self._parent: Optional["PreferenceGroup"] = None
|
|
self._on_change_listener: Optional[PreferenceChangeListener] = None
|
|
self._on_click_listener: Optional[PreferenceOnPreferenceClickListener] = None
|
|
|
|
def setTitle(self, title: str):
|
|
self._title = title
|
|
|
|
def getTitle(self) -> str:
|
|
return self._title
|
|
|
|
def setSummary(self, summary: str):
|
|
self._summary = summary
|
|
|
|
def getSummary(self) -> str:
|
|
return self._summary
|
|
|
|
def setKey(self, key: str):
|
|
self._key = key
|
|
|
|
def getKey(self) -> Optional[str]:
|
|
return self._key
|
|
|
|
def setEnabled(self, enabled: bool):
|
|
self._enabled = enabled
|
|
|
|
def isEnabled(self) -> bool:
|
|
return self._enabled
|
|
|
|
def setDefaultValue(self, value: Any):
|
|
self._default_value = value
|
|
|
|
def setOnPreferenceClickListener(self, listener: PreferenceOnPreferenceClickListener):
|
|
self._on_click_listener = listener
|
|
|
|
def setOnPreferenceChangeListener(self, listener: PreferenceChangeListener):
|
|
self._on_change_listener = listener
|
|
|
|
def getSharedPreferences(self) -> Any:
|
|
if self._preference_manager:
|
|
return self._preference_manager.getSharedPreferences()
|
|
return {}
|
|
|
|
def getEditor(self) -> Any:
|
|
if self._preference_manager:
|
|
return self._preference_manager
|
|
return None
|
|
|
|
def shouldCommit(self) -> bool:
|
|
return True
|
|
|
|
def shouldPersist(self) -> bool:
|
|
return self._persistent and self._key is not None
|
|
|
|
def persistString(self, value: str) -> bool:
|
|
if self.shouldPersist() and self._preference_manager:
|
|
self._preference_manager.putPreference(self._key, value)
|
|
return True
|
|
return False
|
|
|
|
def persistInt(self, value: int) -> bool:
|
|
if self.shouldPersist() and self._preference_manager:
|
|
self._preference_manager.putPreference(self._key, value)
|
|
return True
|
|
return False
|
|
|
|
def persistBoolean(self, value: bool) -> bool:
|
|
if self.shouldPersist() and self._preference_manager:
|
|
self._preference_manager.putPreference(self._key, value)
|
|
return True
|
|
return False
|
|
|
|
def persistFloat(self, value: float) -> bool:
|
|
if self.shouldPersist() and self._preference_manager:
|
|
self._preference_manager.putPreference(self._key, value)
|
|
return True
|
|
return False
|
|
|
|
def persistLong(self, value: int) -> bool:
|
|
return self.persistInt(value)
|
|
|
|
def getPersistedString(self, default_return: Optional[str] = None) -> Optional[str]:
|
|
if self.shouldPersist() and self._preference_manager:
|
|
val = self._preference_manager.getPreference(self._key, default_return)
|
|
return str(val) if val is not None else default_return
|
|
return default_return
|
|
|
|
def getPersistedInt(self, default_return: int = 0) -> int:
|
|
if self.shouldPersist() and self._preference_manager:
|
|
return int(self._preference_manager.getPreference(self._key, default_return))
|
|
return default_return
|
|
|
|
def getPersistedBoolean(self, default_return: bool = False) -> bool:
|
|
if self.shouldPersist() and self._preference_manager:
|
|
val = self._preference_manager.getPreference(self._key, default_return)
|
|
if isinstance(val, bool):
|
|
return val
|
|
return str(val).lower() in ("true", "1", "yes")
|
|
return default_return
|
|
|
|
def getPersistedFloat(self, default_return: float = 0.0) -> float:
|
|
if self.shouldPersist() and self._preference_manager:
|
|
return float(self._preference_manager.getPreference(self._key, default_return))
|
|
return default_return
|
|
|
|
def getPersistedLong(self, default_return: int = 0) -> int:
|
|
return self.getPersistedInt(default_return)
|
|
|
|
def notifyChanged(self):
|
|
pass
|
|
|
|
def notifyHierarchyChanged(self):
|
|
pass
|
|
|
|
def onBindView(self, view: Any):
|
|
pass
|
|
|
|
def onClick(self):
|
|
if self._on_click_listener:
|
|
self._on_click_listener.onPreferenceClick(self)
|
|
|
|
def setOrder(self, order: int):
|
|
self._order = order
|
|
|
|
def getOrder(self) -> int:
|
|
return self._order
|
|
|
|
def setPersistent(self, persistent: bool):
|
|
self._persistent = persistent
|
|
|
|
def isPersistent(self) -> bool:
|
|
return self._persistent
|
|
|
|
def setDependency(self, dependency_key: str):
|
|
self._dependency_key = dependency_key
|
|
|
|
def getDependency(self) -> Optional[str]:
|
|
return self._dependency_key
|
|
|
|
def toString(self) -> str:
|
|
return f"Preference(key={self._key}, title={self._title})"
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self._key) & 0x7FFFFFFF if self._key else 0
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# PreferenceGroup
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class PreferenceGroup(Preference):
|
|
"""PreferenceGroup — 偏好组"""
|
|
|
|
def __init__(self, context: Any = None, attrs: Any = None):
|
|
super().__init__(context, attrs)
|
|
self._preferences: List[Preference] = []
|
|
|
|
def addPreference(self, preference: Preference) -> bool:
|
|
if preference not in self._preferences:
|
|
self._preferences.append(preference)
|
|
preference._parent = self
|
|
return True
|
|
return False
|
|
|
|
def removePreference(self, preference: Preference) -> bool:
|
|
if preference in self._preferences:
|
|
self._preferences.remove(preference)
|
|
preference._parent = None
|
|
return True
|
|
return False
|
|
|
|
def removeAll(self):
|
|
for p in self._preferences:
|
|
p._parent = None
|
|
self._preferences.clear()
|
|
|
|
def getPreference(self, index: int) -> Optional[Preference]:
|
|
if 0 <= index < len(self._preferences):
|
|
return self._preferences[index]
|
|
return None
|
|
|
|
def getPreferenceCount(self) -> int:
|
|
return len(self._preferences)
|
|
|
|
def findPreference(self, key: str) -> Optional[Preference]:
|
|
for p in self._preferences:
|
|
if p.getKey() == key:
|
|
return p
|
|
if isinstance(p, PreferenceGroup):
|
|
result = p.findPreference(key)
|
|
if result:
|
|
return result
|
|
return None
|
|
|
|
def toString(self) -> str:
|
|
return f"PreferenceGroup(count={len(self._preferences)})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# PreferenceScreen
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class PreferenceScreen(PreferenceGroup):
|
|
"""PreferenceScreen — 根偏好屏幕"""
|
|
|
|
def __init__(self, context: Any = None, attrs: Any = None):
|
|
super().__init__(context, attrs)
|
|
self._root: bool = True
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# PreferenceCategory
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class PreferenceCategory(PreferenceGroup):
|
|
"""PreferenceCategory — 偏好分类标题"""
|
|
|
|
def __init__(self, context: Any = None, attrs: Any = None):
|
|
super().__init__(context, attrs)
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# TwoStatePreference
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class TwoStatePreference(Preference):
|
|
"""TwoStatePreference — 双状态偏好基类"""
|
|
|
|
def __init__(self, context: Any = None, attrs: Any = None):
|
|
super().__init__(context, attrs)
|
|
self._checked: bool = False
|
|
self._summary_on: str = ""
|
|
self._summary_off: str = ""
|
|
self._disable_dependents_state: bool = False
|
|
|
|
def isChecked(self) -> bool:
|
|
return self._checked
|
|
|
|
def setChecked(self, checked: bool):
|
|
self._checked = checked
|
|
self.persistBoolean(checked)
|
|
|
|
def setSummaryOn(self, summary: str):
|
|
self._summary_on = summary
|
|
|
|
def setSummaryOff(self, summary: str):
|
|
self._summary_off = summary
|
|
|
|
def setDisableDependentsState(self, state: bool):
|
|
self._disable_dependents_state = state
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# CheckBoxPreference
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class CheckBoxPreference(TwoStatePreference):
|
|
"""CheckBoxPreference — 复选框偏好"""
|
|
|
|
def __init__(self, context: Any = None, attrs: Any = None):
|
|
super().__init__(context, attrs)
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# SwitchPreference
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class SwitchPreference(TwoStatePreference):
|
|
"""SwitchPreference — 开关偏好"""
|
|
|
|
def __init__(self, context: Any = None, attrs: Any = None):
|
|
super().__init__(context, attrs)
|
|
self._switch_text_on: str = ""
|
|
self._switch_text_off: str = ""
|
|
|
|
def setSwitchTextOn(self, text: str):
|
|
self._switch_text_on = text
|
|
|
|
def setSwitchTextOff(self, text: str):
|
|
self._switch_text_off = text
|
|
|
|
def getSwitchTextOn(self) -> str:
|
|
return self._switch_text_on
|
|
|
|
def getSwitchTextOff(self) -> str:
|
|
return self._switch_text_off
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# DialogPreference
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class DialogPreference(Preference):
|
|
"""DialogPreference — 对话框偏好基类"""
|
|
|
|
def __init__(self, context: Any = None, attrs: Any = None):
|
|
super().__init__(context, attrs)
|
|
self._dialog_title: str = ""
|
|
self._dialog_message: str = ""
|
|
self._dialog_icon: Any = None
|
|
self._positive_button_text: str = ""
|
|
self._negative_button_text: str = ""
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# EditTextPreference
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class EditTextPreference(DialogPreference):
|
|
"""EditTextPreference — 文本编辑偏好"""
|
|
|
|
def __init__(self, context: Any = None, attrs: Any = None):
|
|
super().__init__(context, attrs)
|
|
self._text: str = ""
|
|
|
|
def getText(self) -> str:
|
|
return self._text
|
|
|
|
def setText(self, text: str):
|
|
self._text = text
|
|
self.persistString(text)
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# ListPreference
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class ListPreference(DialogPreference):
|
|
"""ListPreference — 列表偏好"""
|
|
|
|
def __init__(self, context: Any = None, attrs: Any = None):
|
|
super().__init__(context, attrs)
|
|
self._entries: List[str] = []
|
|
self._entry_values: List[str] = []
|
|
self._value: str = ""
|
|
|
|
def getEntries(self) -> List[str]:
|
|
return list(self._entries)
|
|
|
|
def setEntries(self, entries: List[str]):
|
|
self._entries = list(entries)
|
|
|
|
def getEntryValues(self) -> List[str]:
|
|
return list(self._entry_values)
|
|
|
|
def setEntryValues(self, values: List[str]):
|
|
self._entry_values = list(values)
|
|
|
|
def getValue(self) -> str:
|
|
return self._value
|
|
|
|
def setValue(self, value: str):
|
|
self._value = value
|
|
self.persistString(value)
|
|
|
|
def getEntry(self) -> Optional[str]:
|
|
try:
|
|
idx = self._entry_values.index(self._value)
|
|
if 0 <= idx < len(self._entries):
|
|
return self._entries[idx]
|
|
except ValueError:
|
|
pass
|
|
return None
|
|
|
|
def getSummary(self) -> str:
|
|
entry = self.getEntry()
|
|
if entry:
|
|
return entry
|
|
return self._summary
|
|
|
|
def setDefaultValue(self, value: Any):
|
|
super().setDefaultValue(value)
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# MultiSelectListPreference
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class MultiSelectListPreference(DialogPreference):
|
|
"""MultiSelectListPreference — 多选列表偏好"""
|
|
|
|
def __init__(self, context: Any = None, attrs: Any = None):
|
|
super().__init__(context, attrs)
|
|
self._entries: List[str] = []
|
|
self._entry_values: List[str] = []
|
|
self._values: Set[str] = set()
|
|
|
|
def getEntries(self) -> List[str]:
|
|
return list(self._entries)
|
|
|
|
def setEntries(self, entries: List[str]):
|
|
self._entries = list(entries)
|
|
|
|
def getEntryValues(self) -> List[str]:
|
|
return list(self._entry_values)
|
|
|
|
def setEntryValues(self, values: List[str]):
|
|
self._entry_values = list(values)
|
|
|
|
def getValues(self) -> Set[str]:
|
|
return set(self._values)
|
|
|
|
def setValues(self, values: Set[str]):
|
|
self._values = set(values)
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# RingtonePreference / SeekBarPreference / DropDownPreference
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class RingtonePreference(Preference):
|
|
"""RingtonePreference — 铃声偏好"""
|
|
|
|
def __init__(self, context: Any = None, attrs: Any = None):
|
|
super().__init__(context, attrs)
|
|
self._ringtone_type: int = 1
|
|
self._show_default: bool = True
|
|
self._show_silent: bool = True
|
|
|
|
|
|
class SeekBarPreference(Preference):
|
|
"""SeekBarPreference — 滑块偏好"""
|
|
|
|
def __init__(self, context: Any = None, attrs: Any = None):
|
|
super().__init__(context, attrs)
|
|
self._min: int = 0
|
|
self._max: int = 100
|
|
self._current: int = 50
|
|
self._show_progress: bool = True
|
|
self._adjustable: bool = True
|
|
|
|
def getMin(self) -> int:
|
|
return self._min
|
|
|
|
def setMin(self, min_val: int):
|
|
self._min = min_val
|
|
|
|
def getMax(self) -> int:
|
|
return self._max
|
|
|
|
def setMax(self, max_val: int):
|
|
self._max = max_val
|
|
|
|
def getValue(self) -> int:
|
|
return self._current
|
|
|
|
def setValue(self, value: int):
|
|
self._current = value
|
|
self.persistInt(value)
|
|
|
|
|
|
class DropDownPreference(ListPreference):
|
|
"""DropDownPreference — 下拉列表偏好"""
|
|
|
|
def __init__(self, context: Any = None, attrs: Any = None):
|
|
super().__init__(context, attrs)
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# PreferenceFragment / PreferenceFragmentCompat
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class PreferenceFragment(Stub):
|
|
"""PreferenceFragment — 偏好片段"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._preference_manager: Optional[PreferenceManager] = None
|
|
|
|
def onCreate(self, savedInstanceState: Any):
|
|
pass
|
|
|
|
def onCreatePreferences(self, savedInstanceState: Any, root_key: Optional[str]):
|
|
pass
|
|
|
|
def addPreferencesFromResource(self, res_id: int):
|
|
pass
|
|
|
|
def setPreferenceScreen(self, screen: PreferenceScreen):
|
|
pass
|
|
|
|
def getPreferenceScreen(self) -> Optional[PreferenceScreen]:
|
|
return None
|
|
|
|
def findPreference(self, key: str) -> Optional[Preference]:
|
|
screen = self.getPreferenceScreen()
|
|
if screen:
|
|
return screen.findPreference(key)
|
|
return None
|
|
|
|
|
|
class PreferenceFragmentCompat(PreferenceFragment):
|
|
"""PreferenceFragmentCompat — 兼容偏好片段"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# __all__
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
__all__ = [
|
|
"Preference",
|
|
"PreferenceScreen",
|
|
"PreferenceCategory",
|
|
"PreferenceManager",
|
|
"CheckBoxPreference",
|
|
"SwitchPreference",
|
|
"ListPreference",
|
|
"EditTextPreference",
|
|
"MultiSelectListPreference",
|
|
"PreferenceFragment",
|
|
"PreferenceFragmentCompat",
|
|
"PreferenceGroup",
|
|
"PreferenceChangeListener",
|
|
"PreferenceOnPreferenceClickListener",
|
|
"TwoStatePreference",
|
|
"DialogPreference",
|
|
"RingtonePreference",
|
|
"SeekBarPreference",
|
|
"DropDownPreference",
|
|
] |