aves/lib/model/entry/dirs.dart
Thibault Deckers 5784607130 refactor
2023-03-14 20:31:18 +01:00

76 lines
2.4 KiB
Dart

import 'dart:async';
import 'dart:io';
import 'package:aves/services/common/services.dart';
import 'package:aves/utils/android_file_utils.dart';
import 'package:collection/collection.dart';
final entryDirRepo = EntryDirRepo._private();
class EntryDirRepo {
EntryDirRepo._private();
// mapping between the raw entry directory path to a resolvable directory
final Map<String?, EntryDir> _dirs = {};
final StreamController<EntryDir> _ambiguousDirStreamController = StreamController.broadcast();
Stream<EntryDir> get ambiguousDirStream => _ambiguousDirStreamController.stream;
// get a resolvable directory for a raw entry directory path
EntryDir getOrCreate(String? asIs) {
var entryDir = _dirs[asIs];
if (entryDir != null) return entryDir;
final asIsLower = asIs?.toLowerCase();
entryDir = _dirs.values.firstWhereOrNull((dir) => dir.asIsLower == asIsLower);
if (entryDir != null && !entryDir.ambiguous) {
entryDir.ambiguous = true;
_ambiguousDirStreamController.add(entryDir);
}
return _dirs.putIfAbsent(asIs, () => entryDir ?? EntryDir(asIs));
}
}
// Some directories are ambiguous because they use different cases,
// but the OS merge and present them as one directory.
// This class resolves ambiguous directories to get the directory path
// with the right case, as presented by the OS.
class EntryDir {
final String? asIs, asIsLower;
bool ambiguous = false;
String? _resolved;
EntryDir(this.asIs) : asIsLower = asIs?.toLowerCase();
String? get resolved {
if (!ambiguous) return asIs;
if (asIs == null) return null;
_resolved ??= _resolve();
return _resolved;
}
String? _resolve() {
final vrl = VolumeRelativeDirectory.fromPath(asIs!);
if (vrl == null || vrl.relativeDir.isEmpty) return asIs;
var resolved = vrl.volumePath;
final parts = pContext.split(vrl.relativeDir);
for (final part in parts) {
FileSystemEntity? found;
final dir = Directory(resolved);
if (dir.existsSync()) {
final partLower = part.toLowerCase();
try {
final childrenDirs = dir.listSync().where((v) => v.absolute is Directory).toSet();
found = childrenDirs.firstWhereOrNull((v) => pContext.basename(v.path).toLowerCase() == partLower);
} catch (error) {
// ignore, could be IO issue when listing directory
}
}
resolved = found?.path ?? '$resolved${pContext.separator}$part';
}
return resolved;
}
}