Skip to content

Commit 9294fdf

Browse files
authored
♻️ Separate AssetPickerDelegate (#315)
1 parent a62a40b commit 9294fdf

File tree

4 files changed

+400
-217
lines changed

4 files changed

+400
-217
lines changed
Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
///
2+
/// [Author] Alex (https://github.com/AlexV525)
3+
/// [Date] 2022/05/05 11:25
4+
///
5+
// ignore_for_file: deprecated_member_use
6+
import 'package:flutter/material.dart';
7+
import 'package:flutter/services.dart';
8+
import 'package:photo_manager/photo_manager.dart';
9+
10+
import '../constants/config.dart';
11+
import '../constants/constants.dart';
12+
import '../internal/methods.dart';
13+
import '../internal/singleton.dart';
14+
import '../provider/asset_picker_provider.dart';
15+
import '../widget/asset_picker.dart';
16+
import '../widget/asset_picker_page_route.dart';
17+
import 'asset_picker_builder_delegate.dart';
18+
19+
class AssetPickerDelegate {
20+
const AssetPickerDelegate();
21+
22+
/// {@template wechat_assets_picker.delegates.AssetPickerDelegate.permissionCheck}
23+
/// Request the current [PermissionState] of required permissions.
24+
/// 请求所需权限的 [PermissionState]
25+
///
26+
/// Throws a [StateError] when the state is not [PermissionState.authorized]
27+
/// or [PermissionState.limited],
28+
/// which means the picker can not perform further actions.
29+
/// 当权限状态不是 [PermissionState.authorized][PermissionState.limited] 时,
30+
/// 将抛出 [StateError],此时选择器无法执行其他操作。
31+
///
32+
/// See also:
33+
/// * [PermissionState] which defined all states of required permissions.
34+
/// {@endtemplate}
35+
Future<PermissionState> permissionCheck() async {
36+
final PermissionState _ps = await PhotoManager.requestPermissionExtend();
37+
if (_ps != PermissionState.authorized && _ps != PermissionState.limited) {
38+
throw StateError('Permission state error with $_ps.');
39+
}
40+
return _ps;
41+
}
42+
43+
/// {@template wechat_assets_picker.delegates.AssetPickerDelegate.pickAssets}
44+
/// Pick assets with the given [pickerConfig].
45+
/// 根据给定的 [pickerConfig] 选择资源。
46+
///
47+
/// Set [useRootNavigator] to determine
48+
/// whether the picker route should use the root [Navigator].
49+
/// 使用 [useRootNavigator] 来控制选择器的路由是否使用最顶层的 [Navigator]
50+
///
51+
/// By extending the [AssetPickerPageRoute], users can customize the route
52+
/// and use it with the [pageRouteBuilder].
53+
/// 继承 [AssetPickerPageRoute] 可以自定义路由,
54+
/// 并且通过 [pageRouteBuilder] 进行使用。
55+
///
56+
/// See also:
57+
/// * [AssetPickerConfig] which holds all configurations for basic picking.
58+
/// * [DefaultAssetPickerProvider] which is the default provider that
59+
/// manages assets during the picking process.
60+
/// * [DefaultAssetPickerBuilderDelegate] which is the default builder that
61+
/// builds all widgets during the picking process.
62+
/// {@endtemplate}
63+
Future<List<AssetEntity>?> pickAssets(
64+
BuildContext context, {
65+
AssetPickerConfig pickerConfig = const AssetPickerConfig(),
66+
bool useRootNavigator = true,
67+
AssetPickerPageRouteBuilder<List<AssetEntity>>? pageRouteBuilder,
68+
}) async {
69+
final PermissionState _ps = await permissionCheck();
70+
final DefaultAssetPickerProvider provider = DefaultAssetPickerProvider(
71+
maxAssets: pickerConfig.maxAssets,
72+
pageSize: pickerConfig.pageSize,
73+
pathThumbnailSize: pickerConfig.pathThumbnailSize,
74+
selectedAssets: pickerConfig.selectedAssets,
75+
requestType: pickerConfig.requestType,
76+
sortPathDelegate: pickerConfig.sortPathDelegate,
77+
filterOptions: pickerConfig.filterOptions,
78+
);
79+
final Widget picker = AssetPicker<AssetEntity, AssetPathEntity>(
80+
key: Singleton.pickerKey,
81+
builder: DefaultAssetPickerBuilderDelegate(
82+
provider: provider,
83+
initialPermission: _ps,
84+
gridCount: pickerConfig.gridCount,
85+
pickerTheme: pickerConfig.pickerTheme,
86+
gridThumbnailSize: pickerConfig.gridThumbnailSize,
87+
previewThumbnailSize: pickerConfig.previewThumbnailSize,
88+
specialPickerType: pickerConfig.specialPickerType,
89+
specialItemPosition: pickerConfig.specialItemPosition,
90+
specialItemBuilder: pickerConfig.specialItemBuilder,
91+
loadingIndicatorBuilder: pickerConfig.loadingIndicatorBuilder,
92+
selectPredicate: pickerConfig.selectPredicate,
93+
shouldRevertGrid: pickerConfig.shouldRevertGrid,
94+
limitedPermissionOverlayPredicate:
95+
pickerConfig.limitedPermissionOverlayPredicate,
96+
pathNameBuilder: pickerConfig.pathNameBuilder,
97+
textDelegate: pickerConfig.textDelegate,
98+
themeColor: pickerConfig.themeColor,
99+
locale: Localizations.maybeLocaleOf(context),
100+
),
101+
);
102+
final List<AssetEntity>? result = await Navigator.of(
103+
context,
104+
rootNavigator: useRootNavigator,
105+
).push<List<AssetEntity>>(
106+
pageRouteBuilder?.call(picker) ??
107+
AssetPickerPageRoute<List<AssetEntity>>(builder: (_) => picker),
108+
);
109+
return result;
110+
}
111+
112+
/// {@template wechat_assets_picker.delegates.AssetPickerDelegate.pickAssetsWithDelegate}
113+
/// Pick assets with the given [delegate].
114+
/// 根据给定的 [delegate] 选择资源。
115+
///
116+
/// Set [useRootNavigator] to determine
117+
/// whether the picker route should use the root [Navigator].
118+
/// 使用 [useRootNavigator] 来控制选择器的路由是否使用最顶层的 [Navigator]
119+
///
120+
/// By extending the [AssetPickerPageRoute], users can customize the route
121+
/// and use it with the [pageRouteBuilder].
122+
/// 继承 [AssetPickerPageRoute] 可以自定义路由,
123+
/// 并且通过 [pageRouteBuilder] 进行使用。
124+
///
125+
/// See also:
126+
/// * [AssetPickerBuilderDelegate] for how to customize/override widgets
127+
/// during the picking process.
128+
/// {@endtemplate}
129+
Future<List<Asset>?> pickAssetsWithDelegate<Asset, Path,
130+
PickerProvider extends AssetPickerProvider<Asset, Path>>(
131+
BuildContext context, {
132+
required AssetPickerBuilderDelegate<Asset, Path> delegate,
133+
bool useRootNavigator = true,
134+
AssetPickerPageRouteBuilder<List<Asset>>? pageRouteBuilder,
135+
}) async {
136+
await permissionCheck();
137+
final Widget picker = AssetPicker<Asset, Path>(
138+
key: Singleton.pickerKey,
139+
builder: delegate,
140+
);
141+
final List<Asset>? result = await Navigator.of(
142+
context,
143+
rootNavigator: useRootNavigator,
144+
).push<List<Asset>>(
145+
pageRouteBuilder?.call(picker) ??
146+
AssetPickerPageRoute<List<Asset>>(builder: (_) => picker),
147+
);
148+
return result;
149+
}
150+
151+
/// {@template wechat_assets_picker.delegates.AssetPickerDelegate.registerObserve}
152+
/// Register observe callback with assets changes.
153+
/// 注册资源(图库)变化的监听回调
154+
/// @{endtemplate}
155+
void registerObserve([ValueChanged<MethodCall>? callback]) {
156+
if (callback == null) {
157+
return;
158+
}
159+
try {
160+
PhotoManager.addChangeCallback(callback);
161+
PhotoManager.startChangeNotify();
162+
} catch (e) {
163+
realDebugPrint('Error when registering assets callback: $e');
164+
}
165+
}
166+
167+
/// {@template wechat_assets_picker.delegates.AssetPickerDelegate.unregisterObserve}
168+
/// Unregister the observation callback with assets changes.
169+
/// 取消注册资源(图库)变化的监听回调
170+
/// @{endtemplate}
171+
void unregisterObserve([ValueChanged<MethodCall>? callback]) {
172+
if (callback == null) {
173+
return;
174+
}
175+
try {
176+
PhotoManager.removeChangeCallback(callback);
177+
PhotoManager.stopChangeNotify();
178+
} catch (e) {
179+
realDebugPrint('Error when unregistering assets callback: $e');
180+
}
181+
}
182+
183+
/// {@template wechat_assets_picker.delegates.AssetPickerDelegate.themeData}
184+
/// Build a [ThemeData] with the given [themeColor] for the picker.
185+
/// 为选择器构建基于 [themeColor][ThemeData]
186+
///
187+
/// If [themeColor] is null, the color will use the fallback
188+
/// [defaultThemeColorWeChat] which is the default color in the WeChat design.
189+
/// 如果 [themeColor] 为 null,主题色将回落使用 [defaultThemeColorWeChat]
190+
/// 即微信设计中的绿色主题色。
191+
///
192+
/// Set [light] to true if pickers require a light version of the theme.
193+
/// 设置 [light] 为 true 时可以获取浅色版本的主题。
194+
/// {@endtemplate}
195+
ThemeData themeData(Color? themeColor, {bool light = false}) {
196+
themeColor ??= defaultThemeColorWeChat;
197+
if (light) {
198+
return ThemeData.light().copyWith(
199+
primaryColor: Colors.grey[50],
200+
primaryColorLight: Colors.grey[50],
201+
primaryColorDark: Colors.grey[50],
202+
canvasColor: Colors.grey[100],
203+
scaffoldBackgroundColor: Colors.grey[50],
204+
bottomAppBarColor: Colors.grey[50],
205+
cardColor: Colors.grey[50],
206+
highlightColor: Colors.transparent,
207+
toggleableActiveColor: themeColor,
208+
textSelectionTheme: TextSelectionThemeData(
209+
cursorColor: themeColor,
210+
selectionColor: themeColor.withAlpha(100),
211+
selectionHandleColor: themeColor,
212+
),
213+
indicatorColor: themeColor,
214+
appBarTheme: const AppBarTheme(
215+
systemOverlayStyle: SystemUiOverlayStyle(
216+
statusBarBrightness: Brightness.light,
217+
statusBarIconBrightness: Brightness.dark,
218+
),
219+
elevation: 0,
220+
),
221+
buttonTheme: ButtonThemeData(buttonColor: themeColor),
222+
colorScheme: ColorScheme(
223+
primary: Colors.grey[50]!,
224+
primaryVariant: Colors.grey[50]!,
225+
secondary: themeColor,
226+
secondaryVariant: themeColor,
227+
background: Colors.grey[50]!,
228+
surface: Colors.grey[50]!,
229+
brightness: Brightness.light,
230+
error: const Color(0xffcf6679),
231+
onPrimary: Colors.white,
232+
onSecondary: Colors.white,
233+
onSurface: Colors.black,
234+
onBackground: Colors.black,
235+
onError: Colors.white,
236+
),
237+
);
238+
}
239+
return ThemeData.dark().copyWith(
240+
primaryColor: Colors.grey[900],
241+
primaryColorLight: Colors.grey[900],
242+
primaryColorDark: Colors.grey[900],
243+
canvasColor: Colors.grey[850],
244+
scaffoldBackgroundColor: Colors.grey[900],
245+
bottomAppBarColor: Colors.grey[900],
246+
cardColor: Colors.grey[900],
247+
highlightColor: Colors.transparent,
248+
toggleableActiveColor: themeColor,
249+
textSelectionTheme: TextSelectionThemeData(
250+
cursorColor: themeColor,
251+
selectionColor: themeColor.withAlpha(100),
252+
selectionHandleColor: themeColor,
253+
),
254+
indicatorColor: themeColor,
255+
appBarTheme: const AppBarTheme(
256+
systemOverlayStyle: SystemUiOverlayStyle(
257+
statusBarBrightness: Brightness.dark,
258+
statusBarIconBrightness: Brightness.light,
259+
),
260+
elevation: 0,
261+
),
262+
buttonTheme: ButtonThemeData(buttonColor: themeColor),
263+
colorScheme: ColorScheme(
264+
primary: Colors.grey[900]!,
265+
primaryVariant: Colors.grey[900]!,
266+
secondary: themeColor,
267+
secondaryVariant: themeColor,
268+
background: Colors.grey[900]!,
269+
surface: Colors.grey[900]!,
270+
brightness: Brightness.dark,
271+
error: const Color(0xffcf6679),
272+
onPrimary: Colors.black,
273+
onSecondary: Colors.black,
274+
onSurface: Colors.white,
275+
onBackground: Colors.white,
276+
onError: Colors.black,
277+
),
278+
);
279+
}
280+
}

0 commit comments

Comments
 (0)