fixed auto album identification and naming
This commit is contained in:
parent
63c06c09fc
commit
685e3fe9b6
4 changed files with 44 additions and 10 deletions
|
@ -29,7 +29,8 @@ mixin AlbumMixin on SourceBase {
|
|||
void _notifyAlbumChange() => eventBus.fire(AlbumsChangedEvent());
|
||||
|
||||
String getAlbumDisplayName(BuildContext? context, String dirPath) {
|
||||
assert(!dirPath.endsWith(pContext.separator));
|
||||
final separator = pContext.separator;
|
||||
assert(!dirPath.endsWith(separator));
|
||||
|
||||
if (context != null) {
|
||||
final type = androidFileUtils.getAlbumType(dirPath);
|
||||
|
@ -52,8 +53,9 @@ mixin AlbumMixin on SourceBase {
|
|||
String unique(String dirPath, Set<String?> others) {
|
||||
final parts = pContext.split(dirPath);
|
||||
for (var i = parts.length - 1; i > 0; i--) {
|
||||
final testName = pContext.joinAll(['', ...parts.skip(i)]);
|
||||
if (others.every((item) => !item!.endsWith(testName))) return testName;
|
||||
final name = pContext.joinAll(['', ...parts.skip(i)]);
|
||||
final testName = '$separator$name';
|
||||
if (others.every((item) => !item!.endsWith(testName))) return name;
|
||||
}
|
||||
return dirPath;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import 'package:flutter/widgets.dart';
|
|||
final AndroidFileUtils androidFileUtils = AndroidFileUtils._private();
|
||||
|
||||
class AndroidFileUtils {
|
||||
late String primaryStorage, dcimPath, downloadPath, moviesPath, picturesPath, videoCapturesPath;
|
||||
late final String separator, primaryStorage, dcimPath, downloadPath, moviesPath, picturesPath, videoCapturesPath;
|
||||
Set<StorageVolume> storageVolumes = {};
|
||||
Set<Package> _packages = {};
|
||||
List<String> _potentialAppDirs = [];
|
||||
|
@ -22,9 +22,10 @@ class AndroidFileUtils {
|
|||
AndroidFileUtils._private();
|
||||
|
||||
Future<void> init() async {
|
||||
separator = pContext.separator;
|
||||
storageVolumes = await storageService.getStorageVolumes();
|
||||
// path_provider getExternalStorageDirectory() gives '/storage/emulated/0/Android/data/deckers.thibault.aves/files'
|
||||
primaryStorage = storageVolumes.firstWhereOrNull((volume) => volume.isPrimary)?.path ?? '/';
|
||||
primaryStorage = storageVolumes.firstWhereOrNull((volume) => volume.isPrimary)?.path ?? separator;
|
||||
// standard
|
||||
dcimPath = pContext.join(primaryStorage, 'DCIM');
|
||||
downloadPath = pContext.join(primaryStorage, 'Download');
|
||||
moviesPath = pContext.join(primaryStorage, 'Movies');
|
||||
|
@ -39,11 +40,11 @@ class AndroidFileUtils {
|
|||
appNameChangeNotifier.notifyListeners();
|
||||
}
|
||||
|
||||
bool isCameraPath(String path) => path.startsWith(dcimPath) && (path.endsWith('Camera') || path.endsWith('100ANDRO'));
|
||||
bool isCameraPath(String path) => path.startsWith(dcimPath) && (path.endsWith('${separator}Camera') || path.endsWith('${separator}100ANDRO'));
|
||||
|
||||
bool isScreenshotsPath(String path) => (path.startsWith(dcimPath) || path.startsWith(picturesPath)) && path.endsWith('Screenshots');
|
||||
bool isScreenshotsPath(String path) => (path.startsWith(dcimPath) || path.startsWith(picturesPath)) && path.endsWith('${separator}Screenshots');
|
||||
|
||||
bool isScreenRecordingsPath(String path) => (path.startsWith(dcimPath) || path.startsWith(moviesPath)) && (path.endsWith('Screen recordings') || path.endsWith('ScreenRecords'));
|
||||
bool isScreenRecordingsPath(String path) => (path.startsWith(dcimPath) || path.startsWith(moviesPath)) && (path.endsWith('${separator}Screen recordings') || path.endsWith('${separator}ScreenRecords'));
|
||||
|
||||
bool isVideoCapturesPath(String path) => path == videoCapturesPath;
|
||||
|
||||
|
@ -54,7 +55,7 @@ class AndroidFileUtils {
|
|||
final volume = storageVolumes.firstWhereOrNull((v) => path.startsWith(v.path));
|
||||
// storage volume path includes trailing '/', but argument path may or may not,
|
||||
// which is an issue when the path is at the root
|
||||
return volume != null || path.endsWith('/') ? volume : getStorageVolume('$path/');
|
||||
return volume != null || path.endsWith(separator) ? volume : getStorageVolume('$path$separator');
|
||||
}
|
||||
|
||||
bool isOnRemovableStorage(String path) => getStorageVolume(path)?.isRemovable ?? false;
|
||||
|
|
|
@ -259,6 +259,8 @@ void main() {
|
|||
FakeMediaStoreService.newImage('${FakeStorageService.primaryPath}Seneca', '1'),
|
||||
FakeMediaStoreService.newImage('${FakeStorageService.removablePath}Pictures/Cicero', '1'),
|
||||
FakeMediaStoreService.newImage('${FakeStorageService.removablePath}Marcus Aurelius', '1'),
|
||||
FakeMediaStoreService.newImage('${FakeStorageService.primaryPath}Pictures/Hannah Arendt', '1'),
|
||||
FakeMediaStoreService.newImage('${FakeStorageService.primaryPath}Pictures/Arendt', '1'),
|
||||
};
|
||||
|
||||
await androidFileUtils.init();
|
||||
|
@ -276,6 +278,8 @@ void main() {
|
|||
expect(source.getAlbumDisplayName(context, '${FakeStorageService.primaryPath}Seneca'), 'Seneca');
|
||||
expect(source.getAlbumDisplayName(context, '${FakeStorageService.removablePath}Pictures/Cicero'), 'Cicero');
|
||||
expect(source.getAlbumDisplayName(context, '${FakeStorageService.removablePath}Marcus Aurelius'), 'Marcus Aurelius');
|
||||
expect(source.getAlbumDisplayName(context, '${FakeStorageService.primaryPath}Pictures/Hannah Arendt'), 'Hannah Arendt');
|
||||
expect(source.getAlbumDisplayName(context, '${FakeStorageService.primaryPath}Pictures/Arendt'), 'Arendt');
|
||||
return const Placeholder();
|
||||
},
|
||||
),
|
||||
|
|
27
test/utils/android_file_utils.dart
Normal file
27
test/utils/android_file_utils.dart
Normal file
|
@ -0,0 +1,27 @@
|
|||
import 'package:aves/services/services.dart';
|
||||
import 'package:aves/services/storage_service.dart';
|
||||
import 'package:aves/utils/android_file_utils.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../fake/storage_service.dart';
|
||||
|
||||
void main() {
|
||||
setUp(() async {
|
||||
// specify Posix style path context for consistent behaviour when running tests on Windows
|
||||
getIt.registerLazySingleton<p.Context>(() => p.Context(style: p.Style.posix));
|
||||
|
||||
getIt.registerLazySingleton<StorageService>(() => FakeStorageService());
|
||||
|
||||
await androidFileUtils.init();
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
await getIt.reset();
|
||||
});
|
||||
|
||||
test('camera album identification', () {
|
||||
expect(androidFileUtils.isCameraPath('${FakeStorageService.primaryPath}DCIM/Camera'), true);
|
||||
expect(androidFileUtils.isCameraPath('${FakeStorageService.primaryPath}DCIM/YoloCamera'), false);
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue