Skip to content

Commit 15e1554

Browse files
authored
Merge pull request #3 from dvd-bnc/master
Initial implementation of native FS methods
2 parents 805f10a + 1ebfe97 commit 15e1554

28 files changed

+1874
-353
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,6 @@ app.*.map.json
4444
/android/app/debug
4545
/android/app/profile
4646
/android/app/release
47+
48+
**/zig-out
49+
**/.zig-cache

.vscode/launch.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
8+
{
9+
"name": "files",
10+
"request": "launch",
11+
"type": "dart",
12+
"args": ["--enable-experiment=native-assets"]
13+
},
14+
{
15+
"name": "files (profile mode)",
16+
"request": "launch",
17+
"type": "dart",
18+
"flutterMode": "profile",
19+
"args": ["--enable-experiment=native-assets"]
20+
},
21+
{
22+
"name": "files (release mode)",
23+
"request": "launch",
24+
"type": "dart",
25+
"flutterMode": "release",
26+
"args": ["--enable-experiment=native-assets"]
27+
}
28+
]
29+
}

devtools_options.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
description: This file stores settings for Dart & Flutter DevTools.
2+
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
3+
extensions:

hook/build.dart

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import 'package:code_assets/code_assets.dart';
2+
import 'package:hooks/hooks.dart';
3+
4+
void main(List<String> args) async {
5+
await build(args, (input, output) async {
6+
final targetOS = input.config.code.targetOS;
7+
if (targetOS != OS.linux) return;
8+
9+
output.assets.code.add(
10+
CodeAsset(
11+
package: input.packageName,
12+
name: 'libfs.dart',
13+
linkMode: DynamicLoadingSystem(Uri.file('src/zig-out/lib/libfs.so')),
14+
),
15+
);
16+
});
17+
}

lib/backend/database/helper.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import 'dart:io';
2-
31
import 'package:files/backend/database/model.dart';
2+
import 'package:files/backend/fs.dart' as fs;
43
import 'package:files/backend/providers.dart';
54
import 'package:isar_community/isar.dart';
65

@@ -9,7 +8,8 @@ class EntityStatCacheHelper {
98
final stat = isar.entityStats.where().pathEqualTo(path).findFirstSync();
109

1110
if (stat == null) {
12-
final fetchedStat = EntityStat.fromStat(path, await FileStat.stat(path));
11+
final file = fs.File.fromPath(path);
12+
final fetchedStat = EntityStat.fromFileInfo(path, await file.queryInfo().result);
1313
await set(fetchedStat);
1414
return fetchedStat;
1515
}

lib/backend/database/model.dart

Lines changed: 69 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,52 @@
1-
import 'dart:io';
2-
1+
import 'package:files/backend/fs.dart' as fs;
32
import 'package:files/backend/providers.dart';
43
import 'package:flutter/foundation.dart';
54
import 'package:isar_community/isar.dart';
65

76
part 'model.g.dart';
87

8+
typedef _FileInfoSnapshot = ({
9+
DateTime changed,
10+
DateTime modified,
11+
DateTime accessed,
12+
EntityType type,
13+
int mode,
14+
int size,
15+
});
16+
17+
_FileInfoSnapshot _getSnapshotForInfo(fs.FileInfo info) {
18+
final attributes = info.listAttributes()!;
19+
20+
assert(attributes.contains('standard::type'));
21+
// assert(attributes.contains('time::modified'));
22+
// assert(attributes.contains('time::access'));
23+
// assert(attributes.contains('time::created'));
24+
assert(attributes.contains('standard::size'));
25+
26+
final defaultTime = DateTime.fromMillisecondsSinceEpoch(0);
27+
28+
return (
29+
changed: info.getCreationTime() ?? defaultTime,
30+
modified: info.getModificationTime() ?? defaultTime,
31+
accessed: info.getAccessTime() ?? defaultTime,
32+
type: switch (info.getFileType()) {
33+
1 || 4 || 5 => EntityType.file,
34+
2 || 6 => EntityType.directory,
35+
3 => EntityType.link,
36+
final t => throw ArgumentError.value(t),
37+
},
38+
mode: 0, // TODO
39+
size: info.getSize(),
40+
);
41+
}
42+
943
@Collection()
1044
class EntityStat with ChangeNotifier {
1145
EntityStat();
1246

1347
EntityStat.fastInit({
1448
required this.path,
49+
required this.info,
1550
required this.changed,
1651
required this.modified,
1752
required this.accessed,
@@ -20,21 +55,29 @@ class EntityStat with ChangeNotifier {
2055
required this.size,
2156
});
2257

23-
EntityStat.fromStat(String path, FileStat stat)
24-
: this.fastInit(
25-
path: path,
26-
changed: stat.changed,
27-
modified: stat.modified,
28-
accessed: stat.accessed,
29-
type: EntityType.fromDartIo(stat.type),
30-
mode: stat.mode,
31-
size: stat.size,
32-
);
58+
factory EntityStat.fromFileInfo(String path, fs.FileInfo info) {
59+
final snapshot = _getSnapshotForInfo(info);
60+
61+
return EntityStat.fastInit(
62+
path: path,
63+
info: info,
64+
changed: snapshot.changed,
65+
modified: snapshot.modified,
66+
accessed: snapshot.accessed,
67+
type: snapshot.type,
68+
mode: snapshot.mode,
69+
size: snapshot.size,
70+
);
71+
}
72+
3373
Id? id;
3474

3575
@Index(unique: true, type: IndexType.hash)
3676
late String path;
3777

78+
@Ignore()
79+
late fs.FileInfo info;
80+
3881
late DateTime changed;
3982
late DateTime modified;
4083
late DateTime accessed;
@@ -45,60 +88,30 @@ class EntityStat with ChangeNotifier {
4588
late int size;
4689

4790
Future<void> fetchUpdate() async {
48-
final ioStat = await FileStat.stat(path);
49-
50-
if (!_statIdentical(ioStat)) {
51-
changed = ioStat.changed;
52-
modified = ioStat.modified;
53-
accessed = ioStat.accessed;
54-
type = EntityType.fromDartIo(ioStat.type);
55-
mode = ioStat.mode;
56-
size = ioStat.size;
91+
final file = fs.File.fromPath(path);
92+
final info = await file.queryInfo().result;
93+
final snapshot = _getSnapshotForInfo(info);
94+
95+
if (!_infoIdentical(snapshot)) {
96+
changed = snapshot.changed;
97+
modified = snapshot.modified;
98+
accessed = snapshot.accessed;
99+
type = snapshot.type;
100+
mode = snapshot.mode;
101+
size = snapshot.size;
57102
await helper.set(this);
58103
notifyListeners();
59104
}
60105
}
61106

62-
bool _statIdentical(FileStat other) {
107+
bool _infoIdentical(_FileInfoSnapshot other) {
63108
return changed == other.changed &&
64109
modified == other.modified &&
65110
accessed == other.accessed &&
66-
type == EntityType.fromDartIo(other.type) &&
111+
type == other.type &&
67112
mode == other.mode &&
68113
size == other.size;
69114
}
70115
}
71116

72-
enum EntityType {
73-
file,
74-
directory,
75-
link,
76-
notFound;
77-
78-
static EntityType fromDartIo(FileSystemEntityType type) {
79-
switch (type) {
80-
case FileSystemEntityType.file:
81-
return EntityType.file;
82-
case FileSystemEntityType.directory:
83-
return EntityType.directory;
84-
case FileSystemEntityType.link:
85-
return EntityType.link;
86-
case FileSystemEntityType.notFound:
87-
default:
88-
return EntityType.notFound;
89-
}
90-
}
91-
92-
FileSystemEntityType get toDartIo {
93-
switch (this) {
94-
case EntityType.file:
95-
return FileSystemEntityType.file;
96-
case EntityType.directory:
97-
return FileSystemEntityType.directory;
98-
case EntityType.link:
99-
return FileSystemEntityType.link;
100-
case EntityType.notFound:
101-
return FileSystemEntityType.notFound;
102-
}
103-
}
104-
}
117+
enum EntityType { file, directory, link, notFound }

lib/backend/drive_provider.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class DriveProvider with ChangeNotifier {
1515

1616
List<UDisksBlockDevice> get blockDevices => List.of(_blockDevices);
1717
List<UDisksDrive> get drives => List.of(_drives);
18+
List<String> get supportedFilesystems => List.of(_client.supportedFilesystems);
1819

1920
Future<void> init() async {
2021
await _client.connect();

lib/backend/entity_info.dart

Lines changed: 10 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,22 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
import 'dart:io';
18-
1917
import 'package:files/backend/database/model.dart';
18+
import 'package:files/backend/fs.dart' as fs;
2019
import 'package:flutter/foundation.dart';
2120

2221
@immutable
2322
class EntityInfo {
24-
const EntityInfo._(this._entity, this.stat, this.entityType);
23+
const EntityInfo(this.file, this.stat, this.entityType);
2524

26-
final FileSystemEntity _entity;
25+
final fs.File file;
2726
final EntityStat stat;
2827
final EntityType entityType;
2928

30-
String get path => _entity.path;
31-
32-
FileSystemEntity get entity => _entity;
29+
String get path => file.path;
3330

3431
bool _equals(EntityInfo other) {
35-
return entity.path == other.entity.path &&
32+
return file.path == other.file.path &&
3633
stat.accessed == other.stat.accessed &&
3734
stat.changed == other.stat.changed &&
3835
stat.mode == other.stat.mode &&
@@ -52,7 +49,7 @@ class EntityInfo {
5249

5350
@override
5451
int get hashCode => Object.hash(
55-
entity.path,
52+
file.path,
5653
stat.accessed,
5754
stat.changed,
5855
stat.mode,
@@ -63,77 +60,12 @@ class EntityInfo {
6360
);
6461
}
6562

66-
class FileEntityInfo extends EntityInfo {
67-
const FileEntityInfo({required File entity, required EntityStat stat})
68-
: super._(entity, stat, EntityType.file);
69-
70-
@override
71-
File get entity => _entity as File;
72-
}
73-
74-
class DirectoryEntityInfo extends EntityInfo {
75-
const DirectoryEntityInfo({required Directory entity, required EntityStat stat})
76-
: super._(entity, stat, EntityType.directory);
77-
78-
@override
79-
Directory get entity => _entity as Directory;
80-
}
81-
82-
enum EntityType { file, directory }
83-
8463
extension EntityInfoHelpers on EntityInfo {
85-
FileEntityInfo get asFile => this as FileEntityInfo;
86-
DirectoryEntityInfo get asDirectory => this as DirectoryEntityInfo;
87-
88-
bool get isFile => this is FileEntityInfo;
89-
bool get isDirectory => this is DirectoryEntityInfo;
64+
bool get isFile => stat.type == EntityType.file || stat.type == EntityType.link;
65+
bool get isDirectory => stat.type == EntityType.directory;
9066
}
9167

9268
extension EntityInfoListHelpers on List<EntityInfo> {
93-
List<FileEntityInfo> get files => whereType<FileEntityInfo>().toList();
94-
List<DirectoryEntityInfo> get directories => whereType<DirectoryEntityInfo>().toList();
69+
List<EntityInfo> get files => where((e) => e.isFile).toList();
70+
List<EntityInfo> get directories => where((e) => e.isDirectory).toList();
9571
}
96-
97-
/* class EntityStat implements Insertable<EntityStat> {
98-
final String path;
99-
final DateTime changed;
100-
final DateTime modified;
101-
final DateTime accessed;
102-
final FileSystemEntityType type;
103-
final int mode;
104-
final int size;
105-
106-
const EntityStat({
107-
required this.path,
108-
required this.changed,
109-
required this.modified,
110-
required this.accessed,
111-
required this.type,
112-
required this.mode,
113-
required this.size,
114-
});
115-
116-
EntityStat.fromStat(String path, FileStat stat)
117-
: this(
118-
path: path,
119-
changed: stat.changed,
120-
modified: stat.modified,
121-
accessed: stat.accessed,
122-
type: stat.type,
123-
mode: stat.mode,
124-
size: stat.size,
125-
);
126-
127-
@override
128-
Map<String, Expression> toColumns(bool nullToAbsent) {
129-
return FileStatCachesCompanion(
130-
path: Value(path),
131-
changed: Value(changed),
132-
modified: Value(modified),
133-
accessed: Value(accessed),
134-
type: Value(type),
135-
mode: Value(mode),
136-
size: Value(size),
137-
).toColumns(nullToAbsent);
138-
}
139-
} */

0 commit comments

Comments
 (0)