Skip to content

Commit ef3f748

Browse files
feat: Add includeHiddenAssets option (#1288)
Signed-off-by: Caijinglong <cjl_spy@163.com> Co-authored-by: Alex Li <github@alexv525.com>
1 parent 636e70e commit ef3f748

File tree

10 files changed

+154
-11
lines changed

10 files changed

+154
-11
lines changed

example/lib/model/photo_provider.dart

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ class PhotoProvider extends ChangeNotifier {
5757
notifyListeners();
5858
}
5959

60+
bool _includeHiddenAssets = false;
61+
62+
bool get includeHiddenAssets => _includeHiddenAssets;
63+
64+
set includeHiddenAssets(bool value) {
65+
_includeHiddenAssets = value;
66+
notifyListeners();
67+
}
68+
6069
DateTime _startDt = DateTime(2005); // Default Before 8 years
6170

6271
DateTime get startDt => _startDt;
@@ -168,6 +177,13 @@ class PhotoProvider extends ChangeNotifier {
168177
containsPathModified = value;
169178
}
170179

180+
void changeIncludeHiddenAssets(bool? value) {
181+
if (value == null) {
182+
return;
183+
}
184+
includeHiddenAssets = value;
185+
}
186+
171187
void reset() {
172188
list.clear();
173189
}
@@ -191,13 +207,13 @@ class PhotoProvider extends ChangeNotifier {
191207
}
192208

193209
FilterOptionGroup makeOption() {
194-
final FilterOption option = FilterOption(
210+
final FilterOption filterOption = FilterOption(
195211
sizeConstraint: SizeConstraint(
196212
minWidth: int.tryParse(minWidth) ?? 0,
197213
maxWidth: int.tryParse(maxWidth) ?? 100000,
198214
minHeight: int.tryParse(minHeight) ?? 0,
199215
maxHeight: int.tryParse(maxHeight) ?? 100000,
200-
ignoreSize: ignoreSize,
216+
ignoreSize: _ignoreSize,
201217
),
202218
durationConstraint: DurationConstraint(
203219
min: minDuration,
@@ -211,15 +227,19 @@ class PhotoProvider extends ChangeNotifier {
211227
max: endDt,
212228
);
213229

214-
return FilterOptionGroup()
215-
..setOption(AssetType.video, option)
216-
..setOption(AssetType.image, option)
217-
..setOption(AssetType.audio, option)
218-
..createTimeCond = createDtCond
219-
..containsPathModified = _containsPathModified
230+
final FilterOptionGroup optionGroup = FilterOptionGroup(
231+
imageOption: filterOption,
232+
videoOption: filterOption,
233+
audioOption: filterOption,
234+
containsPathModified: containsPathModified,
220235
// ignore: deprecated_member_use
221-
..containsLivePhotos = _containsLivePhotos
222-
..onlyLivePhotos = onlyLivePhotos;
236+
containsLivePhotos: containsLivePhotos,
237+
onlyLivePhotos: onlyLivePhotos,
238+
createTimeCond: createDtCond,
239+
includeHiddenAssets: includeHiddenAssets, // iOS 平台特有
240+
);
241+
242+
return optionGroup;
223243
}
224244

225245
Future<void> refreshAllGalleryProperties() async {
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:photo_manager/photo_manager.dart';
3+
4+
class IncludeHiddenTestPage extends StatefulWidget {
5+
const IncludeHiddenTestPage({super.key});
6+
7+
@override
8+
State<IncludeHiddenTestPage> createState() => _IncludeHiddenTestPageState();
9+
}
10+
11+
class _IncludeHiddenTestPageState extends State<IncludeHiddenTestPage> {
12+
final List<String> _logs = [];
13+
14+
Future<void> _test() async {
15+
final option = CustomFilter.sql(where: '');
16+
final count = await PhotoManager.getAssetCount(filterOption: option);
17+
18+
setState(() {
19+
_logs.add('Not include hidden count: $count');
20+
});
21+
22+
final option2 = CustomFilter.sql(where: '');
23+
option2.includeHiddenAssets = true;
24+
final count2 = await PhotoManager.getAssetCount(filterOption: option2);
25+
26+
setState(() {
27+
_logs.add('Include hidden count: $count2');
28+
});
29+
}
30+
31+
@override
32+
Widget build(BuildContext context) {
33+
return Scaffold(
34+
appBar: AppBar(
35+
title: const Text('Include Hidden Test'),
36+
),
37+
body: Column(
38+
children: [
39+
ElevatedButton(
40+
onPressed: _test,
41+
child: const Text('Test the count of hidden and not hidden'),
42+
),
43+
Expanded(
44+
child: ListView(
45+
children: [
46+
..._logs.reversed.map((e) => ListTile(title: Text(e))),
47+
],
48+
),
49+
),
50+
],
51+
),
52+
);
53+
}
54+
}

example/lib/page/custom_filter_example_page.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import 'dart:io';
2+
13
import 'package:flutter/material.dart';
24
import 'package:photo_manager/photo_manager.dart';
35
import 'package:photo_manager_example/page/custom_filter/path_list.dart';
@@ -6,6 +8,7 @@ import 'custom_filter/advance_filter_page.dart';
68
import 'custom_filter/custom_filter_sql_gif_image.dart';
79
import 'custom_filter/custom_filter_sql_page.dart';
810
import 'custom_filter/filter_assets_page.dart';
11+
import 'custom_filter/include_hidden_test_page.dart';
912

1013
class CustomFilterExamplePage extends StatelessWidget {
1114
const CustomFilterExamplePage({super.key});
@@ -69,6 +72,11 @@ class CustomFilterExamplePage extends StatelessWidget {
6972
},
7073
),
7174
),
75+
if (Platform.isIOS || Platform.isMacOS)
76+
buildItem(
77+
'Include hidden test',
78+
const IncludeHiddenTestPage(),
79+
),
7280
],
7381
),
7482
),

example/lib/page/filter_option_page.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class _FilterOptionPageState extends State<FilterOptionPage> {
3434
}),
3535
buildIgnoreSize(provider),
3636
buildNeedTitleCheck(provider),
37+
buildIncludeHiddenAssetsCheck(provider),
3738
buildDurationWidget(
3839
provider,
3940
'minDuration',
@@ -204,6 +205,27 @@ class _FilterOptionPageState extends State<FilterOptionPage> {
204205
},
205206
);
206207
}
208+
209+
/// 构建包含隐藏资源的复选框
210+
///
211+
/// 此选项仅在 iOS 平台上有效
212+
Widget buildIncludeHiddenAssetsCheck(PhotoProvider provider) {
213+
return AnimatedBuilder(
214+
animation: provider,
215+
builder: (BuildContext context, Widget? snapshot) {
216+
return CheckboxListTile(
217+
title: const Text('Include hidden assets (iOS only)'),
218+
subtitle: const Text('包含隐藏的资源(仅 iOS 平台有效)'),
219+
onChanged: (bool? value) {
220+
if (value != null) {
221+
provider.includeHiddenAssets = value;
222+
}
223+
},
224+
value: provider.includeHiddenAssets,
225+
);
226+
},
227+
);
228+
}
207229
}
208230

209231
class DarwinPathFilterPage extends StatefulWidget {

example/lib/page/home_page.dart

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ class _NewHomePageState extends State<NewHomePage> {
6464
_buildContainsLivePhotos(),
6565
_buildOnlyLivePhotos(),
6666
_buildPathContainsModifiedDateCheck(),
67+
if (Platform.isIOS || Platform.isMacOS)
68+
_buildIncludeHiddenAssetsCheck(),
6769
_buildPngCheck(),
6870
_buildNotifyCheck(),
6971
_buildFilterOption(watchProvider),
@@ -210,7 +212,17 @@ class _NewHomePageState extends State<NewHomePage> {
210212
onChanged: (bool? value) {
211213
readProvider.changeContainsPathModified(value);
212214
},
213-
title: const Text('contains path modified date'),
215+
title: const Text('Contains path modified date'),
216+
);
217+
}
218+
219+
Widget _buildIncludeHiddenAssetsCheck() {
220+
return CheckboxListTile(
221+
value: watchProvider.includeHiddenAssets,
222+
onChanged: (bool? value) {
223+
readProvider.changeIncludeHiddenAssets(value);
224+
},
225+
title: const Text('Include hidden assets'),
214226
);
215227
}
216228

ios/Classes/core/PMConvertUtils.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ + (NSDictionary *)convertPMAssetToMap:(PMAssetEntity *)asset
133133
container.containsModified = [map[@"containsPathModified"] boolValue];
134134
container.containsLivePhotos = [map[@"containsLivePhotos"] boolValue];
135135
container.onlyLivePhotos = [map[@"onlyLivePhotos"] boolValue];
136+
container.includeHiddenAssets = [map[@"includeHiddenAssets"] boolValue];
136137

137138
NSArray *sortArray = map[@"orders"];
138139
[container injectSortArray:sortArray];

ios/Classes/core/PMFilterOption.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ typedef struct PMDurationConstraint {
5858
@property(nonatomic, assign) BOOL containsLivePhotos;
5959
@property(nonatomic, assign) BOOL onlyLivePhotos;
6060
@property(nonatomic, assign) BOOL containsModified;
61+
@property(nonatomic, assign) BOOL includeHiddenAssets;
6162
@property(nonatomic, strong) NSArray<NSSortDescriptor *> *sortArray;
6263

6364
- (NSArray<NSSortDescriptor *> *)sortCond;

ios/Classes/core/PMFilterOption.m

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ - (PHFetchOptions *)getFetchOptions:(int)type {
5252

5353
PHFetchOptions *options = [PHFetchOptions new];
5454
options.sortDescriptors = [optionGroup sortCond];
55+
56+
// 获取 includeHiddenAssets 属性
57+
options.includeHiddenAssets = optionGroup.includeHiddenAssets;
5558

5659
NSMutableString *cond = [NSMutableString new];
5760
NSMutableArray *args = [NSMutableArray new];
@@ -255,6 +258,9 @@ - (NSString *)where {
255258

256259
- (PHFetchOptions *)getFetchOptions:(int)type {
257260
PHFetchOptions *options = [PHFetchOptions new];
261+
262+
// 从 params 中获取 includeHiddenAssets 属性
263+
options.includeHiddenAssets = self.params[@"includeHiddenAssets"] ? [self.params[@"includeHiddenAssets"] boolValue] : NO;
258264

259265
BOOL containsImage = [PMRequestTypeUtils containsImage:type];
260266
BOOL containsVideo = [PMRequestTypeUtils containsVideo:type];

lib/src/filter/base_filter.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ abstract class PMFilter {
3838
/// Construct a default filter.
3939
factory PMFilter.defaultValue({
4040
bool containsPathModified = false,
41+
bool includeHiddenAssets = false,
4142
}) {
4243
return CustomFilter.sql(
4344
where: '',
@@ -58,6 +59,17 @@ abstract class PMFilter {
5859
/// * [AssetPathEntity.lastModified].
5960
bool containsPathModified = false;
6061

62+
/// Whether to include hidden assets in the results.
63+
///
64+
/// This option only takes effect on iOS.
65+
/// Beginning with iOS 16, users can require authentication to view the
66+
/// hidden album, and the user setting is true by default. When true,
67+
/// the system doesn’t return hidden assets even if the option is true.
68+
///
69+
/// See also:
70+
/// * [PHFetchOptions.includeHiddenAssets](https://developer.apple.com/documentation/photos/phfetchoptions/includehiddenassets).
71+
bool includeHiddenAssets = false;
72+
6173
/// The type of the filter.
6274
BaseFilterType get type;
6375

@@ -83,6 +95,7 @@ abstract class PMFilter {
8395
Map<String, dynamic> _paramMap() {
8496
return <String, dynamic>{
8597
'containsPathModified': containsPathModified,
98+
'includeHiddenAssets': includeHiddenAssets,
8699
};
87100
}
88101
}

lib/src/filter/classical/filter_option_group.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@ class FilterOptionGroup extends PMFilter {
4747
DateTimeCond? createTimeCond,
4848
DateTimeCond? updateTimeCond,
4949
List<OrderOption> orders = const <OrderOption>[],
50+
bool includeHiddenAssets = false,
5051
}) {
5152
super.containsPathModified = containsPathModified;
53+
super.includeHiddenAssets = includeHiddenAssets;
5254
_map[AssetType.image] = imageOption;
5355
_map[AssetType.video] = videoOption;
5456
_map[AssetType.audio] = audioOption;
@@ -140,6 +142,7 @@ class FilterOptionGroup extends PMFilter {
140142
}
141143
containsPathModified = other.containsPathModified;
142144
containsLivePhotos = other.containsLivePhotos;
145+
includeHiddenAssets = other.includeHiddenAssets;
143146
onlyLivePhotos = other.onlyLivePhotos;
144147
createTimeCond = other.createTimeCond;
145148
updateTimeCond = other.updateTimeCond;
@@ -197,6 +200,7 @@ class FilterOptionGroup extends PMFilter {
197200
FilterOption? videoOption,
198201
FilterOption? audioOption,
199202
bool? containsPathModified,
203+
bool? includeHiddenAssets,
200204
@Deprecated(
201205
'The option will be enabled by default. '
202206
'This will be removed in v4.0.0',
@@ -216,12 +220,14 @@ class FilterOptionGroup extends PMFilter {
216220
createTimeCond ??= this.createTimeCond;
217221
updateTimeCond ??= this.updateTimeCond;
218222
orders ??= this.orders;
223+
includeHiddenAssets ??= this.includeHiddenAssets;
219224

220225
final FilterOptionGroup result = FilterOptionGroup()
221226
..setOption(AssetType.image, imageOption!)
222227
..setOption(AssetType.video, videoOption!)
223228
..setOption(AssetType.audio, audioOption!)
224229
..containsPathModified = containsPathModified
230+
..includeHiddenAssets = includeHiddenAssets
225231
..containsLivePhotos = containsLivePhotos
226232
..onlyLivePhotos = onlyLivePhotos
227233
..createTimeCond = createTimeCond

0 commit comments

Comments
 (0)