Ad and purchases enabled (still need actual testing)

This commit is contained in:
Courtney Arnold 2026-08-16 18:27:56 -05:00
parent 2fcc6dcab7
commit faf319322a
35 changed files with 1676 additions and 34 deletions

View file

@ -95,6 +95,16 @@ abstract class CloudStorageSession {
/// if none exists. If duplicates exist, the earliest-created one wins.
Future<String> findOrCreateFolder({required String parentId, required String name});
/// Relocates the existing folder [folderId] to be a child of
/// [newParentId] instead of wherever it currently lives, preserving its
/// contents and (name/subtree) intact. Used when the user picks a
/// different location for the app's already-existing folder (see
/// [CloudSyncService.selectAppFolder]), so its synced data and receipts
/// move with it instead of being abandoned in place while a fresh, empty
/// folder is created at the new location. Returns the folder's
/// (possibly new, for a path-addressed provider) id.
Future<String> moveFolder({required String folderId, required String newParentId});
/// Looks up a file's ID + versionTag by name within [folderId] without
/// downloading its content, or null if no such file exists yet.
Future<CloudFileInfo?> findFile({required String folderId, required String name});

View file

@ -244,6 +244,17 @@ class DropboxSession implements CloudStorageSession {
return childPath;
}
@override
Future<String> moveFolder({required String folderId, required String newParentId}) async {
final name = folderId.substring(folderId.lastIndexOf('/') + 1);
final toPath = _childPath(newParentId, name);
if (toPath == folderId) return folderId;
final json = await _post('/2/files/move_v2', {'from_path': folderId, 'to_path': toPath});
final metadata = json['metadata'] as Map<String, dynamic>?;
return metadata?['path_display'] as String? ?? toPath;
}
@override
Future<CloudFileInfo?> findFile({required String folderId, required String name}) async {
final filePath = _childPath(folderId, name);

View file

@ -157,6 +157,20 @@ class GoogleDriveSession implements CloudStorageSession {
return created.id!;
}
@override
Future<String> moveFolder({required String folderId, required String newParentId}) async {
final current = await _api.files.get(folderId, $fields: 'parents') as drive.File;
final oldParents = (current.parents ?? []).join(',');
final updated = await _api.files.update(
drive.File(),
folderId,
addParents: newParentId,
removeParents: oldParents.isEmpty ? null : oldParents,
$fields: 'id',
);
return updated.id ?? folderId;
}
@override
Future<CloudFileInfo?> findFile({required String folderId, required String name}) async {
final result = await _api.files.list(

View file

@ -245,6 +245,22 @@ class OneDriveSession implements CloudStorageSession {
return created['id'] as String;
}
@override
Future<String> moveFolder({required String folderId, required String newParentId}) async {
final response = await http.patch(
_graph('/me/drive/${_itemSegment(folderId)}'),
headers: {...await _authHeader(), 'Content-Type': 'application/json'},
body: jsonEncode({
'parentReference': {'id': newParentId},
}),
);
if (response.statusCode != 200) {
throw StateError('OneDrive API error (moveFolder): ${response.statusCode} ${response.body}');
}
final json = jsonDecode(response.body) as Map<String, dynamic>;
return json['id'] as String? ?? folderId;
}
@override
Future<CloudFileInfo?> findFile({required String folderId, required String name}) async {
final uri = _graph('/me/drive/${_itemSegment(folderId)}:/$name');

View file

@ -282,6 +282,22 @@ class WebDavSession implements CloudStorageSession {
return childUri.path;
}
@override
Future<String> moveFolder({required String folderId, required String newParentId}) async {
final name = _nameFromPath(folderId);
final destination = _childUri(_uriFor(newParentId), name);
final response = await _send('MOVE', _uriFor(folderId), headers: {
'Authorization': _provider._authHeader,
'Destination': destination.toString(),
'Overwrite': 'F',
});
if (response.statusCode != 201 && response.statusCode != 204) {
throw StateError('WebDAV MOVE failed: ${response.statusCode} ${response.body}');
}
return destination.path;
}
@override
Future<CloudFileInfo?> findFile({required String folderId, required String name}) async {
final fileUri = _childUri(_uriFor(folderId), name);