my_controller.dart
5.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import 'dart:async';
import 'dart:io';
import 'package:doublefeel_flutter/app/modules/watch_theme/models/watch_theme_models.dart';
import 'package:doublefeel_flutter/app/routes/app_pages.dart';
import 'package:doublefeel_flutter/core/constants/intent_keys.dart';
import 'package:doublefeel_flutter/core/logging/app_logger.dart';
import 'package:doublefeel_flutter/core/network/api/theme_api.dart';
import 'package:doublefeel_flutter/core/network/api/user_api.dart';
import 'package:doublefeel_flutter/core/network/api/vip_api.dart';
import 'package:doublefeel_flutter/core/platform/pigeon_api_facade.dart';
import 'package:doublefeel_flutter/core/result/app_result.dart';
import 'package:doublefeel_flutter/data/local/user_preferences_storage.dart';
import 'package:doublefeel_flutter/data/models/local/user_preferences.dart';
import 'package:doublefeel_flutter/data/models/user/user_models.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart';
class MyController extends GetxController {
MyController(this._userApi, this._vipApi, this._themeApi);
final UserApi _userApi;
final VipApi _vipApi;
final ThemeApi _themeApi;
final ImagePicker _picker = ImagePicker();
final watchThemeItems = <WatchThemeItem>[].obs;
final isLoadingWatchThemes = false.obs;
final AppPlatformHostApi _platformHostApi = AppPlatformHostApi();
List<WatchThemeItem> get officialWatchThemes =>
watchThemeItems.where((theme) => theme.isOfficialTheme).toList();
@override
void onInit() {
super.onInit();
unawaited(loadWatchThemes());
}
Future<void> loadWatchThemes() async {
isLoadingWatchThemes.value = true;
final result = await _themeApi.getThemeList(errorHandlingPolicy: null);
isLoadingWatchThemes.value = false;
if (result case AppSuccess<WatchThemeResponse>(data: final response)) {
watchThemeItems.assignAll(response.themes);
}
}
void updateNickname(String nickname) async {
final result = await _userApi.updateOwnerUserInfo(nickname: nickname);
if (result is AppSuccess<UserInfoResponse>) {
await Get.find<UserPreferencesStorage>().updateMeUserInfo(result.data);
}
}
/// 选择头像:支持拍照或从相册选取,选取后进入裁剪页
Future<void> pickAvatar({bool fromCamera = false}) async {
// 1. 用 image_picker 调起系统相机或相册
final XFile? picked = await _picker.pickImage(
source: fromCamera ? ImageSource.camera : ImageSource.gallery,
imageQuality: 90,
maxWidth: 1024,
maxHeight: 1024,
);
if (picked == null) return; // 用户取消
AppLogger.e(picked.path);
// OHOS 版 image_cropper 使用 Flutter 页面承载裁剪 UI,必须显式传入
// BuildContext(该插件目前通过 WebUiSettings 读取该参数)。
final isOhos = Platform.operatingSystem.toLowerCase() == 'ohos';
final cropperContext = Get.context ?? Get.overlayContext;
CroppedFile? cropped;
try {
cropped = await ImageCropper().cropImage(
sourcePath: picked.path,
aspectRatio: const CropAspectRatio(ratioX: 1, ratioY: 1),
uiSettings: [
AndroidUiSettings(
toolbarTitle: '裁剪头像',
lockAspectRatio: true,
),
IOSUiSettings(
title: '裁剪头像',
aspectRatioLockEnabled: true,
resetAspectRatioEnabled: false,
),
if (isOhos && cropperContext != null)
WebUiSettings(context: cropperContext),
],
);
} finally {
if (isOhos) {
// 等待 cropper 路由的退场动画结束,防止其 AppBar 覆盖恢复的样式。
await Future<void>.delayed(const Duration(milliseconds: 400));
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.dark,
statusBarBrightness: Brightness.light,
systemNavigationBarColor: Colors.transparent,
systemNavigationBarIconBrightness: Brightness.dark,
),
);
}
}
if (cropped == null) return; // 用户取消裁剪
final ossPath = await _platformHostApi.uploadFile(
cropped.path,
HResourceType.image,
);
final updateResult = await _userApi.updateOwnerUserInfo(avatar: ossPath);
if (updateResult is AppSuccess<UserInfoResponse>) {
await Get.find<UserPreferencesStorage>()
.updateMeUserInfo(updateResult.data);
}
}
Future<void> goWatchThemePage() async {
final hasCustomThemes = watchThemeItems.any((theme) => theme.isCustomTheme);
await Get.toNamed(
Routes.WATCH_THEME,
arguments: {
'isPremium': hasCustomThemes,
'hasCustomThemes': hasCustomThemes,
},
);
await loadWatchThemes();
}
Future<void> toPremiumPage() async {
await Get.toNamed(Routes.PURCHASE, arguments: {
IntentKeys.channelType: '我的页面会员入口',
});
final vipResult = await _vipApi.getVipInfo();
if (vipResult case AppSuccess(data: final vip)) {
try {
final vipPrefs = UserPreferencesVipInfo.fromVipInfo(vip);
await Get.find<UserPreferencesStorage>().updateVipInfo(vipPrefs);
} on Exception catch (e) {}
}
}
Future<void> refreshEmail() async {
final result = await _userApi.getUserInfo();
if (result case AppSuccess<UserInfoResponse>(data: final user)) {
await Get.find<UserPreferencesStorage>().updateMeUserInfo(user);
}
}
}