Files
xianyan/lib/core/utils/device_detection.dart
Developer 7564e8893d chore: 完成多平台适配与代码优化
此提交包含多项变更:
1. 新增鸿蒙平台支持,完善设备检测与数据库适配
2. 替换旧版分享插件API为SharePlus
3. 批量迁移StateNotifier到Notifier以适配新版Riverpod
4. 修复zip编码判断、图表API参数等bug
5. 更新应用图标、启动页资源与多尺寸适配图标
6. 调整Android最小SDK版本与应用名称
7. 优化日志打印与正则表达式使用
8. 修正编辑器画布样式初始化与配置逻辑
9. 更新依赖与CI插件配置
2026-05-17 07:17:07 +08:00

270 lines
8.7 KiB
Dart

// ============================================================
// 闲言APP — 跨平台设备检测 + 屏幕适配
// 创建时间: 2026-04-20
// 更新时间: 2026-04-23
// 作用: 检测平台/设备类型/屏幕方向/响应式断点,支持全局引用
// 上次更新: 增加横屏优先适配 + 响应式断点 + 全局引用入口
// ============================================================
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/widgets.dart';
import 'platform_utils.dart' as pu;
// ============================================================
// 设备类型枚举
// ============================================================
enum DeviceType {
android('Android', true, false),
ios('iOS', true, false),
harmony('HarmonyOS', true, false),
windows('Windows', false, true),
macos('macOS', false, true),
linux('Linux', false, true),
web('Web', false, false),
unknown('Unknown', false, false);
const DeviceType(this.label, this.isMobile, this.isDesktop);
final String label;
final bool isMobile;
final bool isDesktop;
}
// ============================================================
// 屏幕方向枚举
// ============================================================
enum ScreenOrientation {
portrait,
landscape,
square;
bool get isLandscape => this == ScreenOrientation.landscape;
bool get isPortrait => this == ScreenOrientation.portrait;
}
// ============================================================
// 响应式断点 (与 design-rules.md 统一)
// ============================================================
class Breakpoints {
Breakpoints._();
static const double mobile = 640;
static const double tablet = 768;
static const double desktop = 1024;
static const double ultraWide = 1920;
static const double foldableMin = 600;
static const double foldableMax = 900;
}
// ============================================================
// 屏幕尺寸分类
// ============================================================
enum ScreenSizeClass {
compact('手机'),
foldable('折叠屏'),
medium('平板'),
expanded('桌面'),
ultraWide('大屏');
const ScreenSizeClass(this.label);
final String label;
bool get isCompact => this == ScreenSizeClass.compact;
bool get isFoldable => this == ScreenSizeClass.foldable;
bool get isMedium => this == ScreenSizeClass.medium;
bool get isExpanded => this == ScreenSizeClass.expanded;
bool get isUltraWide => this == ScreenSizeClass.ultraWide;
int get layoutColumns {
switch (this) {
case ScreenSizeClass.compact:
return 1;
case ScreenSizeClass.foldable:
return 2;
case ScreenSizeClass.medium:
return 2;
case ScreenSizeClass.expanded:
return 3;
case ScreenSizeClass.ultraWide:
return 4;
}
}
}
// ============================================================
// 设备检测工具类 — 全局引用入口
// ============================================================
class DeviceDetection {
DeviceDetection._();
static DeviceType get deviceType {
if (kIsWeb) return DeviceType.web;
try {
if (_isHarmonyOS()) return DeviceType.harmony;
if (pu.isAndroid) return DeviceType.android;
if (pu.isIOS) return DeviceType.ios;
if (pu.isWindows) return DeviceType.windows;
if (pu.isMacOS) return DeviceType.macos;
if (pu.isLinux) return DeviceType.linux;
} catch (_) {}
return DeviceType.unknown;
}
static bool get isMobile => deviceType.isMobile;
static bool get isDesktop => deviceType.isDesktop;
static bool get isAndroid => deviceType == DeviceType.android;
static bool get isIOS => deviceType == DeviceType.ios;
static bool get isHarmony => deviceType == DeviceType.harmony;
static bool get isWindows => deviceType == DeviceType.windows;
static bool get isMacOS => deviceType == DeviceType.macos;
static bool get isLinux => deviceType == DeviceType.linux;
static bool get isWeb => deviceType == DeviceType.web;
static String get platformName => deviceType.label;
static bool _isHarmonyOS() {
try {
if (pu.isWeb) return false;
return pu.isOhos;
} catch (_) {
return false;
}
}
/// 从 BuildContext 获取屏幕方向
static ScreenOrientation orientation(BuildContext context) {
final size = MediaQuery.sizeOf(context);
if (size.width > size.height) return ScreenOrientation.landscape;
if (size.width < size.height) return ScreenOrientation.portrait;
return ScreenOrientation.square;
}
/// 从 BuildContext 获取屏幕尺寸分类
static ScreenSizeClass sizeClass(BuildContext context) {
final width = MediaQuery.sizeOf(context).width;
return sizeClassFromWidth(width);
}
/// 从宽度值获取屏幕尺寸分类
static ScreenSizeClass sizeClassFromWidth(double width) {
if (width >= Breakpoints.ultraWide) return ScreenSizeClass.ultraWide;
if (width >= Breakpoints.desktop) return ScreenSizeClass.expanded;
if (width >= Breakpoints.tablet) return ScreenSizeClass.medium;
if (width >= Breakpoints.foldableMin && width <= Breakpoints.foldableMax) {
return ScreenSizeClass.foldable;
}
return ScreenSizeClass.compact;
}
/// 当前是否横屏
static bool isLandscape(BuildContext context) =>
orientation(context).isLandscape;
/// 当前是否竖屏
static bool isPortrait(BuildContext context) =>
orientation(context).isPortrait;
/// 当前是否折叠屏
static bool isFoldable(BuildContext context) => sizeClass(context).isFoldable;
/// 获取布局列数
static int layoutColumns(BuildContext context) =>
sizeClass(context).layoutColumns;
/// 横屏优先 — 获取主内容区最大宽度
static double contentMaxWidth(BuildContext context) {
final sizeClass = DeviceDetection.sizeClass(context);
switch (sizeClass) {
case ScreenSizeClass.compact:
return double.infinity;
case ScreenSizeClass.foldable:
return 900;
case ScreenSizeClass.medium:
return 1024;
case ScreenSizeClass.expanded:
return 1200;
case ScreenSizeClass.ultraWide:
return 1600;
}
}
/// 获取平台图标 emoji
static String get platformEmoji {
switch (deviceType) {
case DeviceType.android:
return '🤖';
case DeviceType.ios:
return '🍎';
case DeviceType.harmony:
return '🔴';
case DeviceType.windows:
return '🪟';
case DeviceType.macos:
return '💻';
case DeviceType.linux:
return '🐧';
case DeviceType.web:
return '🌐';
case DeviceType.unknown:
return '';
}
}
}
// ============================================================
// 全局引用快捷方式 — 可在任何地方使用
// ============================================================
/// 全局设备检测快捷引用
/// 用法: `AppDevice.isIOS`, `AppDevice.isLandscape(context)`
class AppDevice {
AppDevice._();
static bool get isMobile => DeviceDetection.isMobile;
static bool get isDesktop => DeviceDetection.isDesktop;
static bool get isAndroid => DeviceDetection.isAndroid;
static bool get isIOS => DeviceDetection.isIOS;
static bool get isHarmony => DeviceDetection.isHarmony;
static bool get isWindows => DeviceDetection.isWindows;
static bool get isMacOS => DeviceDetection.isMacOS;
static bool get isLinux => DeviceDetection.isLinux;
static bool get isWeb => DeviceDetection.isWeb;
static String get platformName => DeviceDetection.platformName;
static String get platformEmoji => DeviceDetection.platformEmoji;
static DeviceType get platform => DeviceDetection.deviceType;
static ScreenOrientation orientation(BuildContext context) =>
DeviceDetection.orientation(context);
static ScreenSizeClass sizeClass(BuildContext context) =>
DeviceDetection.sizeClass(context);
static bool isLandscape(BuildContext context) =>
DeviceDetection.isLandscape(context);
static bool isPortrait(BuildContext context) =>
DeviceDetection.isPortrait(context);
static bool isFoldable(BuildContext context) =>
DeviceDetection.isFoldable(context);
static int layoutColumns(BuildContext context) =>
DeviceDetection.layoutColumns(context);
static double contentMaxWidth(BuildContext context) =>
DeviceDetection.contentMaxWidth(context);
}
/// 全局断点快捷引用
/// 用法: `AppBreakpoints.mobile`, `AppBreakpoints.desktop`
class AppBreakpoints {
AppBreakpoints._();
static const double mobile = Breakpoints.mobile;
static const double tablet = Breakpoints.tablet;
static const double desktop = Breakpoints.desktop;
static const double ultraWide = Breakpoints.ultraWide;
static const double foldableMin = Breakpoints.foldableMin;
static const double foldableMax = Breakpoints.foldableMax;
}