feat(ui): M3E restyle for settings, auth, and profile screens

This commit is contained in:
edde746
2026-07-02 11:47:43 +02:00
parent 074f92d144
commit 5f49dddb4d
62 changed files with 1415 additions and 874 deletions
+36 -37
View File
@@ -144,18 +144,18 @@ class _SettingsScreenState extends State<SettingsScreen> with FocusableTab, Moun
ExcludeFocus(child: CustomAppBar(title: Text(t.settings.title), pinned: true)),
SliverList(
delegate: SliverChildListDelegate([
if (DonationService.isEnabled) _buildDonateTile(),
_buildAppearanceTile(),
_buildPlaybackTile(),
_buildTrackersTile(),
const SizedBox(height: 8),
SettingsGroup(
children: [
if (DonationService.isEnabled) _buildDonateTile(),
_buildAppearanceTile(),
_buildPlaybackTile(),
_buildTrackersTile(),
],
),
_buildConnectionsSection(),
_buildProfilesSection(),
if (!PlatformDetector.isAppleTV()) _buildDownloadsSection(),
if (_keyboardShortcutsSupported) ...[_buildKeyboardShortcutsSection()],
@@ -166,12 +166,17 @@ class _SettingsScreenState extends State<SettingsScreen> with FocusableTab, Moun
if (!PlatformDetector.isTV()) _buildBackupSection(),
SettingNavigationTile(
focusNode: _focusTracker.get(_kAbout),
icon: Symbols.info_rounded,
title: t.settings.about,
subtitle: t.settings.aboutDescription,
destinationBuilder: (context) => const AboutScreen(),
const SizedBox(height: 24),
SettingsGroup(
children: [
SettingNavigationTile(
focusNode: _focusTracker.get(_kAbout),
icon: Symbols.info_rounded,
title: t.settings.about,
subtitle: t.settings.aboutDescription,
destinationBuilder: (context) => const AboutScreen(),
),
],
),
const SizedBox(height: 24),
]),
@@ -253,10 +258,9 @@ class _SettingsScreenState extends State<SettingsScreen> with FocusableTab, Moun
? t.connections.addConnectionSubtitleNoProfile
: t.connections.addConnectionSubtitleScoped(displayName: active.displayName);
return Column(
crossAxisAlignment: .start,
return SettingsGroup(
title: t.connections.sectionTitle,
children: [
SettingsSectionHeader(t.connections.sectionTitle),
// Connections are managed per-profile (via the Profiles section
// and each profile's detail screen). The shortcut here just opens
// the picker scoped to the active profile so users can add a Plex
@@ -270,11 +274,12 @@ class _SettingsScreenState extends State<SettingsScreen> with FocusableTab, Moun
Navigator.push(context, MaterialPageRoute(builder: (_) => AddConnectionScreen(targetProfile: active)));
},
),
_buildProfilesTile(),
],
);
}
Widget _buildProfilesSection() {
Widget _buildProfilesTile() {
// ActiveProfileProvider already merges local rows with virtual Plex
// Home profiles — counting only the local DB rows made every Plex Home
// household read as a single profile here. `context.select` keeps
@@ -302,10 +307,9 @@ class _SettingsScreenState extends State<SettingsScreen> with FocusableTab, Moun
final storageService = DownloadStorageService.instance;
final isCustom = storageService.isUsingCustomPath();
return Column(
crossAxisAlignment: .start,
return SettingsGroup(
title: t.settings.downloads,
children: [
SettingsSectionHeader(t.settings.downloads),
if (!Platform.isIOS)
FutureBuilder<String>(
future: storageService.getCurrentDownloadPathDisplay(),
@@ -342,10 +346,9 @@ class _SettingsScreenState extends State<SettingsScreen> with FocusableTab, Moun
Widget _buildKeyboardShortcutsSection() {
if (_keyboardService == null) return const SizedBox.shrink();
return Column(
crossAxisAlignment: .start,
return SettingsGroup(
title: t.settings.keyboardShortcuts,
children: [
SettingsSectionHeader(t.settings.keyboardShortcuts),
SettingNavigationTile(
focusNode: _focusTracker.get(_kVideoPlayerControls),
icon: Symbols.keyboard_rounded,
@@ -370,10 +373,9 @@ class _SettingsScreenState extends State<SettingsScreen> with FocusableTab, Moun
}
Widget _buildAdvancedSection() {
return Column(
crossAxisAlignment: .start,
return SettingsGroup(
title: t.settings.advanced,
children: [
SettingsSectionHeader(t.settings.advanced),
ListTile(
focusNode: _focusTracker.get(_kWatchTogetherRelay),
leading: const AppIcon(Symbols.dns_rounded, fill: 1),
@@ -446,10 +448,9 @@ class _SettingsScreenState extends State<SettingsScreen> with FocusableTab, Moun
}
Widget _buildBackupSection() {
return Column(
crossAxisAlignment: .start,
return SettingsGroup(
title: t.settings.backup,
children: [
SettingsSectionHeader(t.settings.backup),
ListTile(
focusNode: _focusTracker.get(_kExportSettings),
leading: const AppIcon(Symbols.upload_rounded, fill: 1),
@@ -480,10 +481,9 @@ class _SettingsScreenState extends State<SettingsScreen> with FocusableTab, Moun
Widget _buildUpdateSection() {
if (UpdateService.useNativeUpdater) {
return Column(
crossAxisAlignment: .start,
return SettingsGroup(
title: t.settings.updates,
children: [
SettingsSectionHeader(t.settings.updates),
ListTile(
focusNode: _focusTracker.get(_kCheckForUpdates),
leading: const AppIcon(Symbols.system_update_rounded, fill: 1),
@@ -498,10 +498,9 @@ class _SettingsScreenState extends State<SettingsScreen> with FocusableTab, Moun
final hasUpdate = _updateInfo != null && _updateInfo!['hasUpdate'] == true;
return Column(
crossAxisAlignment: .start,
return SettingsGroup(
title: t.settings.updates,
children: [
SettingsSectionHeader(t.settings.updates),
ListTile(
focusNode: _focusTracker.get(_kCheckForUpdates),
leading: AppIcon(