98 lines
3.2 KiB
Dart
98 lines
3.2 KiB
Dart
|
|
import 'package:flutter/material.dart';
|
|||
|
|
import 'package:flutter/services.dart';
|
|||
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|||
|
|
|
|||
|
|
/// 显示方向偏好:跟随系统 / 竖屏 / 横屏。
|
|||
|
|
///
|
|||
|
|
/// 与主题、语言并列,作为「我的」页可手动切换的显示设置;切换后通过
|
|||
|
|
/// [SystemChrome.setPreferredOrientations] 实时生效,并重渲染界面(横屏沿用
|
|||
|
|
/// NavigationRail 布局,竖屏沿用 NavigationBar 布局,二者共用同一套橙白主题,
|
|||
|
|
/// 视觉风格保持一致)。
|
|||
|
|
enum DisplayOrientation {
|
|||
|
|
/// 跟随系统(默认):允许全部四个方向,由设备物理朝向决定。
|
|||
|
|
system,
|
|||
|
|
|
|||
|
|
/// 仅竖屏。
|
|||
|
|
portrait,
|
|||
|
|
|
|||
|
|
/// 仅横屏。
|
|||
|
|
landscape,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const String _kDisplayOrientation = 'display_orientation';
|
|||
|
|
|
|||
|
|
/// 将偏好映射为 [SystemChrome] 需要的设备方向列表。
|
|||
|
|
List<DeviceOrientation> deviceOrientationsFor(DisplayOrientation mode) {
|
|||
|
|
switch (mode) {
|
|||
|
|
case DisplayOrientation.portrait:
|
|||
|
|
return const [DeviceOrientation.portraitUp];
|
|||
|
|
case DisplayOrientation.landscape:
|
|||
|
|
return const [DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight];
|
|||
|
|
case DisplayOrientation.system:
|
|||
|
|
return const [
|
|||
|
|
DeviceOrientation.portraitUp,
|
|||
|
|
DeviceOrientation.portraitDown,
|
|||
|
|
DeviceOrientation.landscapeLeft,
|
|||
|
|
DeviceOrientation.landscapeRight,
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// 立即应用显示方向(调用 [SystemChrome.setPreferredOrientations])。
|
|||
|
|
void applyDisplayOrientation(DisplayOrientation mode) {
|
|||
|
|
SystemChrome.setPreferredOrientations(deviceOrientationsFor(mode));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// 从持久化读取已保存偏好;异常或无记录时返回 [DisplayOrientation.system]。
|
|||
|
|
Future<DisplayOrientation> loadSavedOrientation() async {
|
|||
|
|
try {
|
|||
|
|
final prefs = await SharedPreferences.getInstance();
|
|||
|
|
final v = prefs.getString(_kDisplayOrientation);
|
|||
|
|
if (v != null) {
|
|||
|
|
for (final e in DisplayOrientation.values) {
|
|||
|
|
if (e.name == v) return e;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} catch (_) {
|
|||
|
|
// 忽略:SharedPreferences 不可用时退化为系统。
|
|||
|
|
}
|
|||
|
|
return DisplayOrientation.system;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// 显示方向偏好管理(持久化 + 实时生效)。
|
|||
|
|
class DisplayOrientationNotifier extends Notifier<DisplayOrientation> {
|
|||
|
|
@override
|
|||
|
|
DisplayOrientation build() {
|
|||
|
|
// 首选项在 main 启动期已应用;这里异步回读以保证 UI 选中态与持久值一致。
|
|||
|
|
_load();
|
|||
|
|
return DisplayOrientation.system;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Future<void> _load() async {
|
|||
|
|
final saved = await loadSavedOrientation();
|
|||
|
|
if (saved != state) {
|
|||
|
|
state = saved;
|
|||
|
|
applyDisplayOrientation(saved);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// 切换显示方向:更新状态、即时生效并持久化。
|
|||
|
|
Future<void> set(DisplayOrientation mode) async {
|
|||
|
|
state = mode;
|
|||
|
|
applyDisplayOrientation(mode);
|
|||
|
|
try {
|
|||
|
|
final prefs = await SharedPreferences.getInstance();
|
|||
|
|
await prefs.setString(_kDisplayOrientation, mode.name);
|
|||
|
|
} catch (_) {
|
|||
|
|
// 忽略持久化失败,运行时仍生效。
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// 显示方向偏好提供者。
|
|||
|
|
final displayOrientationProvider =
|
|||
|
|
NotifierProvider<DisplayOrientationNotifier, DisplayOrientation>(
|
|||
|
|
DisplayOrientationNotifier.new,
|
|||
|
|
);
|