From 8e082b8debbc35055d3155d9329ac99778766766 Mon Sep 17 00:00:00 2001 From: Pratik-canopas Date: Fri, 20 Dec 2024 16:21:49 +0530 Subject: [PATCH 1/4] Use google apis for list --- data/.flutter-plugins-dependencies | 2 +- .../google_drive/google_drive_endpoint.dart | 71 +++++++ data/lib/services/google_drive_service.dart | 201 +++++++++--------- data/pubspec.yaml | 1 - 4 files changed, 168 insertions(+), 107 deletions(-) diff --git a/data/.flutter-plugins-dependencies b/data/.flutter-plugins-dependencies index 2e61f207..31138cb6 100644 --- a/data/.flutter-plugins-dependencies +++ b/data/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_local_notifications","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.8/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/package_info_plus-8.1.1/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"photo_manager","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/photo_manager-3.6.2/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.3/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"sqflite_darwin","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/sqflite_darwin-2.4.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/url_launcher_ios-6.3.2/","native_build":true,"dependencies":[]}],"android":[{"name":"flutter_local_notifications","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/","native_build":true,"dependencies":[]},{"name":"google_sign_in_android","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.33/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/package_info_plus-8.1.1/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/path_provider_android-2.2.12/","native_build":true,"dependencies":[]},{"name":"photo_manager","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/photo_manager-3.6.2/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/shared_preferences_android-2.3.3/","native_build":true,"dependencies":[]},{"name":"sqflite_android","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/sqflite_android-2.4.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.14/","native_build":true,"dependencies":[]}],"macos":[{"name":"flutter_local_notifications","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.8/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/package_info_plus-8.1.1/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"photo_manager","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/photo_manager-3.6.2/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.3/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"sqflite_darwin","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/sqflite_darwin-2.4.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/url_launcher_macos-3.2.2/","native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_local_notifications_linux","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/package_info_plus-8.1.1/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/","native_build":false,"dependencies":["path_provider_linux"]},{"name":"url_launcher_linux","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"package_info_plus","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/package_info_plus-8.1.1/","native_build":false,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[]},{"name":"shared_preferences_windows","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/","native_build":false,"dependencies":["path_provider_windows"]},{"name":"url_launcher_windows","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.3/","native_build":true,"dependencies":[]}],"web":[{"name":"google_sign_in_web","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.4+3/","dependencies":[]},{"name":"package_info_plus","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/package_info_plus-8.1.1/","dependencies":[]},{"name":"shared_preferences_web","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.2/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/url_launcher_web-2.3.3/","dependencies":[]}]},"dependencyGraph":[{"name":"flutter_local_notifications","dependencies":["flutter_local_notifications_linux"]},{"name":"flutter_local_notifications_linux","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"photo_manager","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]},{"name":"sqflite","dependencies":["sqflite_android","sqflite_darwin"]},{"name":"sqflite_android","dependencies":[]},{"name":"sqflite_darwin","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2024-12-17 10:29:49.780591","version":"3.27.0","swift_package_manager_enabled":false} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_local_notifications","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.8/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/package_info_plus-8.1.1/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"photo_manager","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/photo_manager-3.6.2/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.3/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"sqflite_darwin","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/sqflite_darwin-2.4.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/url_launcher_ios-6.3.2/","native_build":true,"dependencies":[]}],"android":[{"name":"flutter_local_notifications","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/","native_build":true,"dependencies":[]},{"name":"google_sign_in_android","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.33/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/package_info_plus-8.1.1/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/path_provider_android-2.2.12/","native_build":true,"dependencies":[]},{"name":"photo_manager","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/photo_manager-3.6.2/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/shared_preferences_android-2.3.3/","native_build":true,"dependencies":[]},{"name":"sqflite_android","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/sqflite_android-2.4.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.14/","native_build":true,"dependencies":[]}],"macos":[{"name":"flutter_local_notifications","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/","native_build":true,"dependencies":[]},{"name":"google_sign_in_ios","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.8/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/package_info_plus-8.1.1/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"photo_manager","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/photo_manager-3.6.2/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.3/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"sqflite_darwin","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/sqflite_darwin-2.4.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/url_launcher_macos-3.2.2/","native_build":true,"dependencies":[]}],"linux":[{"name":"flutter_local_notifications_linux","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/package_info_plus-8.1.1/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/","native_build":false,"dependencies":["path_provider_linux"]},{"name":"url_launcher_linux","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.1/","native_build":true,"dependencies":[]}],"windows":[{"name":"package_info_plus","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/package_info_plus-8.1.1/","native_build":false,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[]},{"name":"shared_preferences_windows","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/","native_build":false,"dependencies":["path_provider_windows"]},{"name":"url_launcher_windows","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.3/","native_build":true,"dependencies":[]}],"web":[{"name":"google_sign_in_web","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.4+3/","dependencies":[]},{"name":"package_info_plus","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/package_info_plus-8.1.1/","dependencies":[]},{"name":"shared_preferences_web","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.2/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/url_launcher_web-2.3.3/","dependencies":[]}]},"dependencyGraph":[{"name":"flutter_local_notifications","dependencies":["flutter_local_notifications_linux"]},{"name":"flutter_local_notifications_linux","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"photo_manager","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]},{"name":"sqflite","dependencies":["sqflite_android","sqflite_darwin"]},{"name":"sqflite_android","dependencies":[]},{"name":"sqflite_darwin","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2024-12-20 15:46:30.472884","version":"3.27.1","swift_package_manager_enabled":false} \ No newline at end of file diff --git a/data/lib/apis/google_drive/google_drive_endpoint.dart b/data/lib/apis/google_drive/google_drive_endpoint.dart index c5b7da72..6553bc26 100644 --- a/data/lib/apis/google_drive/google_drive_endpoint.dart +++ b/data/lib/apis/google_drive/google_drive_endpoint.dart @@ -7,6 +7,27 @@ import 'package:googleapis/drive/v3.dart' as drive; import 'package:http_parser/http_parser.dart'; import '../network/urls.dart'; +class GoogleDriveCreateFolderEndpoint extends Endpoint { + final String name; + + const GoogleDriveCreateFolderEndpoint({required this.name}); + + @override + String get baseUrl => BaseURL.googleDriveV3; + + @override + HttpMethod get method => HttpMethod.post; + + @override + Object? get data => { + 'name': name, + 'mimeType': 'application/vnd.google-apps.folder', + }; + + @override + String get path => '/files'; +} + class GoogleDriveUploadEndpoint extends Endpoint { final drive.File request; final AppMediaContent content; @@ -100,6 +121,56 @@ class GoogleDriveDownloadEndpoint extends DownloadEndpoint { String? get storePath => saveLocation; } +class GoogleDriveDeleteEndpoint extends Endpoint { + final String id; + + const GoogleDriveDeleteEndpoint({required this.id}); + + @override + String get baseUrl => BaseURL.googleDriveV3; + + @override + String get path => '/files/$id'; + + @override + HttpMethod get method => HttpMethod.delete; +} + +class GoogleDriveListEndpoint extends Endpoint { + final String? orderBy; + final String fields; + final String? q; + final int? pageSize; + final String? pageToken; + + const GoogleDriveListEndpoint({ + this.orderBy = 'createdTime desc', + this.pageSize, + this.pageToken, + this.q, + this.fields = + 'nextPageToken, files(id, name, description, mimeType, thumbnailLink, webContentLink, createdTime, modifiedTime, size, imageMediaMetadata, videoMediaMetadata, appProperties)', + }); + + @override + String get baseUrl => BaseURL.googleDriveV3; + + @override + String get path => '/files'; + + @override + HttpMethod get method => HttpMethod.get; + + @override + Map? get queryParameters => { + if (orderBy != null) 'orderBy': orderBy, + if (pageSize != null) 'pageSize': pageSize, + if (pageToken != null) 'pageToken': pageToken, + if (q != null) 'q': q, + 'fields': fields, + }; +} + class GoogleDriveUpdateAppPropertiesEndpoint extends Endpoint { final String id; final String localFileId; diff --git a/data/lib/services/google_drive_service.dart b/data/lib/services/google_drive_service.dart index 45033a33..521e74ad 100644 --- a/data/lib/services/google_drive_service.dart +++ b/data/lib/services/google_drive_service.dart @@ -6,99 +6,57 @@ import '../domain/config.dart'; import '../models/media/media.dart'; import '../models/media_content/media_content.dart'; import 'package:dio/dio.dart'; -import 'package:extension_google_sign_in_as_googleapis_auth/extension_google_sign_in_as_googleapis_auth.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:google_sign_in/google_sign_in.dart'; import 'package:googleapis/drive/v3.dart' as drive; import '../errors/app_error.dart'; -import 'auth_service.dart'; import 'base/cloud_provider_service.dart'; -final backUpFolderIdProvider = - StateNotifierProvider((ref) { - return BackUpFolderIdStateNotifier( - ref.read(authServiceProvider), - ref.read(googleDriveServiceProvider), - ); -}); - -class BackUpFolderIdStateNotifier extends StateNotifier { - final AuthService _authService; - final GoogleDriveService _googleDriveService; - StreamSubscription? _googleAccountSubscription; - - BackUpFolderIdStateNotifier(this._authService, this._googleDriveService) - : super(null) { - _googleAccountSubscription = - _authService.onGoogleAccountChange.listen((event) { - setBackUpFolderId(event); - }); - setBackUpFolderId(_authService.googleAccount); - } - - void setBackUpFolderId(GoogleSignInAccount? account) async { - state = - account == null ? null : await _googleDriveService.getBackUpFolderId(); - } - - @override - void dispose() { - _googleAccountSubscription?.cancel(); - super.dispose(); - } -} - final googleDriveServiceProvider = Provider( (ref) => GoogleDriveService( - ref.read(googleSignInProvider), ref.read(googleAuthenticatedDioProvider), ), ); class GoogleDriveService extends CloudProviderService { final Dio _client; - final GoogleSignIn _googleSignIn; - GoogleDriveService(this._googleSignIn, this._client); - - Future _getGoogleDriveAPI() async { - if (_googleSignIn.currentUser == null) { - throw const UserGoogleSignInAccountNotFound(); - } - final client = await _googleSignIn.authenticatedClient(); - final api = drive.DriveApi(client!); - client.close(); - return api; - } + GoogleDriveService(this._client); @override Future> getAllMedias({ required String folder, }) async { - final driveApi = await _getGoogleDriveAPI(); - bool hasMore = true; String? pageToken; final List medias = []; while (hasMore) { - final response = await driveApi.files.list( - q: "'$folder' in parents and trashed=false", - $fields: - "files(id, name, description, mimeType, thumbnailLink, webContentLink, createdTime, modifiedTime, size, imageMediaMetadata, videoMediaMetadata, appProperties)", - pageSize: 1000, - pageToken: pageToken, - orderBy: "createdTime desc", - ); - hasMore = response.nextPageToken != null; - pageToken = response.nextPageToken; - medias.addAll( - (response.files ?? []) - .map( - (e) => AppMedia.fromGoogleDriveFile(e), - ) - .toList(), + final res = await _client.req( + GoogleDriveListEndpoint( + q: "'$folder' in parents and trashed=false", + pageSize: 1000, + pageToken: pageToken, + ), ); + + if (res.statusCode == 200) { + final body = drive.FileList.fromJson(res.data); + hasMore = body.nextPageToken != null; + pageToken = body.nextPageToken; + medias.addAll( + body.files + ?.map( + (e) => AppMedia.fromGoogleDriveFile(e), + ) + .toList() ?? + [], + ); + } else { + throw SomethingWentWrongError( + statusCode: res.statusCode, + message: res.statusMessage, + ); + } } return medias; @@ -110,24 +68,30 @@ class GoogleDriveService extends CloudProviderService { String? nextPageToken, int pageSize = 30, }) async { - final driveApi = await _getGoogleDriveAPI(); - - final response = await driveApi.files.list( - q: "'$folder' in parents and trashed=false", - orderBy: "createdTime desc", - $fields: - "files(id, name, description, mimeType, thumbnailLink, webContentLink, createdTime, modifiedTime, size, imageMediaMetadata, videoMediaMetadata, appProperties)", - pageSize: pageSize, - pageToken: nextPageToken, + final res = await _client.req( + GoogleDriveListEndpoint( + q: "'$folder' in parents and trashed=false", + pageSize: pageSize, + pageToken: nextPageToken, + ), ); - return GetPaginatedMediasResponse( - nextPageToken: response.nextPageToken, - medias: (response.files ?? []) - .map( - (e) => AppMedia.fromGoogleDriveFile(e), - ) - .toList(), + if (res.statusCode == 200) { + final body = drive.FileList.fromJson(res.data); + return GetPaginatedMediasResponse( + nextPageToken: body.nextPageToken, + medias: body.files + ?.map( + (e) => AppMedia.fromGoogleDriveFile(e), + ) + .toList() ?? + [], + ); + } + + throw SomethingWentWrongError( + statusCode: res.statusCode, + message: res.statusMessage, ); } @@ -136,39 +100,66 @@ class GoogleDriveService extends CloudProviderService { required String id, CancelToken? cancelToken, }) async { - final driveApi = await _getGoogleDriveAPI(); - await driveApi.files.delete(id); + final res = await _client.req(GoogleDriveDeleteEndpoint(id: id)); + + if (res.statusCode == 200 || res.statusCode == 204) return; + + throw SomethingWentWrongError( + statusCode: res.statusCode, + message: res.statusMessage, + ); } Future getBackUpFolderId() async { - final driveApi = await _getGoogleDriveAPI(); - - final response = await driveApi.files.list( - q: "name='${ProviderConstants.backupFolderName}' and trashed=false and mimeType='application/vnd.google-apps.folder'", + final res = await _client.req( + GoogleDriveListEndpoint( + q: "name='${ProviderConstants.backupFolderName}' and trashed=false and mimeType='application/vnd.google-apps.folder'", + pageSize: 1, + ), ); - if (response.files?.isNotEmpty ?? false) { - return response.files?.first.id; - } else { - final folder = drive.File( - name: ProviderConstants.backupFolderName, - mimeType: 'application/vnd.google-apps.folder', - ); - final googleDriveFolder = await driveApi.files.create(folder); - return googleDriveFolder.id; + if (res.statusCode == 200) { + final body = drive.FileList.fromJson(res.data); + if (body.files?.isNotEmpty ?? false) { + return body.files?.first.id; + } else { + final createRes = await _client.req( + GoogleDriveCreateFolderEndpoint( + name: ProviderConstants.backupFolderName, + ), + ); + + if (createRes.statusCode == 200) { + return drive.File.fromJson(createRes.data).id; + } + + throw SomethingWentWrongError( + statusCode: createRes.statusCode, + message: createRes.statusMessage, + ); + } } + + throw SomethingWentWrongError( + statusCode: res.statusCode, + message: res.statusMessage, + ); } @override Future createFolder(String folderName) async { - final driveApi = await _getGoogleDriveAPI(); + final res = await _client.req( + GoogleDriveCreateFolderEndpoint(name: folderName), + ); - final folder = drive.File( - name: folderName, - mimeType: 'application/vnd.google-apps.folder', + if (res.statusCode == 200) { + return drive.File.fromJson(res.data).id; + } + + throw SomethingWentWrongError( + statusCode: res.statusCode, + message: res.statusMessage, ); - final googleDriveFolder = await driveApi.files.create(folder); - return googleDriveFolder.id; } @override diff --git a/data/pubspec.yaml b/data/pubspec.yaml index 805aea16..a7f5106a 100644 --- a/data/pubspec.yaml +++ b/data/pubspec.yaml @@ -22,7 +22,6 @@ dependencies: # authentication google_sign_in: ^6.2.2 - extension_google_sign_in_as_googleapis_auth: ^2.0.12 # notifications flutter_local_notifications: ^18.0.1 From af334ce4679fd9842774f32879139f7d9a625de6 Mon Sep 17 00:00:00 2001 From: Pratik-canopas Date: Fri, 20 Dec 2024 16:25:10 +0530 Subject: [PATCH 2/4] Use google apis for list --- .idea/libraries/Dart_Packages.xml | 16 -------- .idea/libraries/Flutter_Plugins.xml | 38 +++++++++---------- .../ui/flow/home/home_screen_view_model.dart | 9 ++--- app/pubspec.lock | 16 -------- app/pubspec.yaml | 1 + 5 files changed, 24 insertions(+), 56 deletions(-) diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index c0b294d9..18c0c921 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -324,13 +324,6 @@ - - - - - - @@ -613,13 +606,6 @@ - - - - - - @@ -1512,7 +1498,6 @@ - @@ -1551,7 +1536,6 @@ - diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 91306103..393d7ece 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -1,23 +1,37 @@ - - - - + + + + + + + + + + + + + + + + + + + - @@ -25,32 +39,18 @@ - - - - - - - - - - - - - - diff --git a/app/lib/ui/flow/home/home_screen_view_model.dart b/app/lib/ui/flow/home/home_screen_view_model.dart index 3c76afbe..95d0bf6b 100644 --- a/app/lib/ui/flow/home/home_screen_view_model.dart +++ b/app/lib/ui/flow/home/home_screen_view_model.dart @@ -93,7 +93,7 @@ class HomeViewStateNotifier extends StateNotifier void _listenUserGoogleAccount() { _googleAccountSubscription = _authService.onGoogleAccountChange.listen((event) async { - if (event != null) { + if (event != null && state.googleAccount?.id != event.id) { state = state.copyWith(googleAccount: event); try { _backUpFolderId = await _googleDriveService.getBackUpFolderId(); @@ -105,7 +105,7 @@ class HomeViewStateNotifier extends StateNotifier ); } loadMedias(reload: true); - } else { + } else if (event == null) { _backUpFolderId = null; state = state.copyWith( googleAccount: null, @@ -248,7 +248,7 @@ class HomeViewStateNotifier extends StateNotifier } } - // MEDIA OPERATIONS --------------------------------------------------------- + // MEDIA OPERATIONS ---------------------------------------------------------- /// Loads medias from local, google drive and dropbox. /// it append the medias to the existing medias if reload is false. @@ -316,9 +316,8 @@ class HomeViewStateNotifier extends StateNotifier // Load medias from google drive and separate the local ref medias and only cloud based medias. if (!_googleDriveMaxLoaded && state.googleAccount != null && + _backUpFolderId != null && hasInternet) { - _backUpFolderId ??= await _googleDriveService.getBackUpFolderId(); - final res = await _googleDriveService.getPaginatedMedias( folder: _backUpFolderId!, nextPageToken: _googleDrivePageToken, diff --git a/app/pubspec.lock b/app/pubspec.lock index 80b44df9..f5fa46a4 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -373,14 +373,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" - extension_google_sign_in_as_googleapis_auth: - dependency: transitive - description: - name: extension_google_sign_in_as_googleapis_auth - sha256: bcf4f8dedcc1e66ce5fe98fbd98cc86ed25ad7fce0511e8d6cdc46ccbf421e8e - url: "https://pub.dev" - source: hosted - version: "2.0.12" fake_async: dependency: transitive description: @@ -689,14 +681,6 @@ packages: url: "https://pub.dev" source: hosted version: "13.2.0" - googleapis_auth: - dependency: transitive - description: - name: googleapis_auth - sha256: befd71383a955535060acde8792e7efc11d2fccd03dd1d3ec434e85b68775938 - url: "https://pub.dev" - source: hosted - version: "1.6.0" graphs: dependency: transitive description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 76732ae1..24978351 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -54,6 +54,7 @@ dependencies: webview_flutter: ^4.10.0 app_links: ^6.3.2 + # file manager photo_manager: ^3.6.3 # storage From ba0b82228d4b08357de20208b4c44a35adc555ae Mon Sep 17 00:00:00 2001 From: Pratik-canopas Date: Fri, 20 Dec 2024 18:24:49 +0530 Subject: [PATCH 3/4] Fix preview --- app/lib/ui/flow/home/home_screen.dart | 182 +++++++++--------- .../ui/flow/home/home_screen_view_model.dart | 99 +++++----- .../components/local_media_image_preview.dart | 41 ++-- 3 files changed, 171 insertions(+), 151 deletions(-) diff --git a/app/lib/ui/flow/home/home_screen.dart b/app/lib/ui/flow/home/home_screen.dart index 3dcf564c..c47048ce 100644 --- a/app/lib/ui/flow/home/home_screen.dart +++ b/app/lib/ui/flow/home/home_screen.dart @@ -122,108 +122,104 @@ class _HomeScreenState extends ConsumerState { ), ); - return Scrollbar( + return ListView.builder( controller: _scrollController, - interactive: true, - child: ListView.builder( - controller: _scrollController, - itemCount: state.medias.length + 2, - itemBuilder: (context, index) { - if (index == 0) { - return Column( - children: [ - const HomeScreenHints(), - const NoInternetConnectionHint(), - ], - ); - } else if (index == state.medias.length + 1) { - return FadeInSwitcher( - child: state.loading - ? const Center( - child: Padding( - padding: EdgeInsets.all(16), - child: AppCircularProgressIndicator( - size: 20, - ), + itemCount: state.medias.length + 2, + itemBuilder: (context, index) { + if (index == 0) { + return Column( + children: [ + const HomeScreenHints(), + const NoInternetConnectionHint(), + ], + ); + } else if (index == state.medias.length + 1) { + return FadeInSwitcher( + child: state.loading + ? const Center( + child: Padding( + padding: EdgeInsets.all(16), + child: AppCircularProgressIndicator( + size: 20, ), - ) - : const SizedBox(), - ); - } else { - final gridEntry = state.medias.entries.elementAt(index - 1); - return Column( - children: [ - Container( - height: 45, - padding: const EdgeInsets.only(left: 16, top: 5), - margin: EdgeInsets.zero, - alignment: Alignment.centerLeft, - decoration: BoxDecoration( - color: context.colorScheme.surface, - ), - child: Text( - gridEntry.key.format(context, DateFormatType.relative), - style: AppTextStyles.subtitle1.copyWith( - color: context.colorScheme.textPrimary, ), - ), + ) + : const SizedBox(), + ); + } else { + final gridEntry = state.medias.entries.elementAt(index - 1); + return Column( + children: [ + Container( + height: 45, + padding: const EdgeInsets.only(left: 16, top: 5), + margin: EdgeInsets.zero, + alignment: Alignment.centerLeft, + decoration: BoxDecoration( + color: context.colorScheme.surface, ), - GridView.builder( - padding: const EdgeInsets.all(4), - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: context.mediaQuerySize.width > 600 - ? context.mediaQuerySize.width ~/ 180 - : context.mediaQuerySize.width ~/ 100, - crossAxisSpacing: 4, - mainAxisSpacing: 4, + child: Text( + gridEntry.key.format(context, DateFormatType.relative), + style: AppTextStyles.subtitle1.copyWith( + color: context.colorScheme.textPrimary, ), - itemCount: gridEntry.value.entries.length, - itemBuilder: (context, index) { - final media = - gridEntry.value.entries.elementAt(index).value; + ), + ), + GridView.builder( + padding: const EdgeInsets.all(4), + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: context.mediaQuerySize.width > 600 + ? context.mediaQuerySize.width ~/ 180 + : context.mediaQuerySize.width ~/ 100, + crossAxisSpacing: 4, + mainAxisSpacing: 4, + ), + itemCount: gridEntry.value.entries.length, + itemBuilder: (context, index) { + final media = + gridEntry.value.entries.elementAt(index).value; - if (media.id == state.lastLocalMediaId) { - runPostFrame(() { - _notifier.loadMedias(); - }); - } + if (media.id == state.lastLocalMediaId) { + runPostFrame(() { + _notifier.loadMedias(); + }); + } - return AppMediaItem( - key: ValueKey(media.id), - onTap: () async { - if (state.selectedMedias.isNotEmpty) { - _notifier.toggleMediaSelection(media); - HapticFeedback.lightImpact(); - } else { - await MediaPreviewRoute( - $extra: MediaPreviewRouteData( - medias: state.medias.values - .expand((element) => element.values) - .toList(), - startFrom: media.id, - ), - ).push(context); - } - }, - onLongTap: () { + return AppMediaItem( + key: ValueKey(media.id), + onTap: () async { + if (state.selectedMedias.isNotEmpty) { _notifier.toggleMediaSelection(media); HapticFeedback.lightImpact(); - }, - isSelected: state.selectedMedias.containsKey(media.id), - uploadMediaProcess: state.uploadMediaProcesses[media.id], - downloadMediaProcess: - state.downloadMediaProcesses[media.id], - media: media, - ); - }, - ), - ], - ); - } - }, - ), + } else { + await MediaPreviewRoute( + $extra: MediaPreviewRouteData( + medias: state.medias.values + .expand((element) => element.values) + .toList(), + startFrom: media.id, + ), + ).push(context); + } + }, + onLongTap: () { + _notifier.toggleMediaSelection(media); + HapticFeedback.lightImpact(); + }, + isSelected: state.selectedMedias.containsKey(media.id), + uploadMediaProcess: state.uploadMediaProcesses[media.id], + downloadMediaProcess: + state.downloadMediaProcesses[media.id], + media: media, + ); + }, + ), + ], + ); + } + }, ); } } diff --git a/app/lib/ui/flow/home/home_screen_view_model.dart b/app/lib/ui/flow/home/home_screen_view_model.dart index 95d0bf6b..19357bd0 100644 --- a/app/lib/ui/flow/home/home_screen_view_model.dart +++ b/app/lib/ui/flow/home/home_screen_view_model.dart @@ -27,21 +27,31 @@ final homeViewStateNotifier = ref.read(localMediaServiceProvider), ref.read(googleDriveServiceProvider), ref.read(dropboxServiceProvider), - ref.read(authServiceProvider), ref.read(mediaProcessRepoProvider), ref.read(loggerProvider), ref.read(connectivityHandlerProvider), ref.read(AppPreferences.dropboxCurrentUserAccount), + ref.read(googleUserAccountProvider), ); - ref.listen(AppPreferences.dropboxCurrentUserAccount, (previous, next) { + final dropboxAccountSubscription = + ref.listen(AppPreferences.dropboxCurrentUserAccount, (previous, next) { notifier.updateDropboxAccount(next); }); + final googleAccountSubscription = + ref.listen(googleUserAccountProvider, (previous, next) { + notifier.updateGoogleAccount(next); + }); + + ref.onDispose(() async { + dropboxAccountSubscription.close(); + googleAccountSubscription.close(); + }); + return notifier; }); class HomeViewStateNotifier extends StateNotifier with HomeViewModelHelperMixin { - final AuthService _authService; final Logger _logger; final GoogleDriveService _googleDriveService; final DropboxService _dropboxService; @@ -49,8 +59,6 @@ class HomeViewStateNotifier extends StateNotifier final MediaProcessRepo _mediaProcessRepo; final ConnectivityHandler _connectivityHandler; - StreamSubscription? _googleAccountSubscription; - // Local int _localMediaCount = 0; bool _localMaxLoaded = false; @@ -70,62 +78,62 @@ class HomeViewStateNotifier extends StateNotifier this._localMediaService, this._googleDriveService, this._dropboxService, - this._authService, this._mediaProcessRepo, this._logger, this._connectivityHandler, DropboxAccount? _dropboxAccount, + GoogleSignInAccount? _googleAccount, ) : super( HomeViewState( dropboxAccount: _dropboxAccount, - googleAccount: _authService.googleAccount, + googleAccount: _googleAccount, ), ) { + _init(); + } + + Future _init() async { _mediaProcessRepo.addListener(_mediaProcessObserve); - _listenUserGoogleAccount(); - loadMedias(reload: true); + await loadMedias(reload: true); _mediaProcessObserve(); } // ACCOUNT LISTENERS --------------------------------------------------------- /// Listen to google account changes and update the state accordingly. - void _listenUserGoogleAccount() { - _googleAccountSubscription = - _authService.onGoogleAccountChange.listen((event) async { - if (event != null && state.googleAccount?.id != event.id) { - state = state.copyWith(googleAccount: event); - try { - _backUpFolderId = await _googleDriveService.getBackUpFolderId(); - } catch (e, s) { - _logger.e( - "HomeViewStateNotifier: unable to get google drive back up folder id", - error: e, - stackTrace: s, - ); - } - loadMedias(reload: true); - } else if (event == null) { - _backUpFolderId = null; - state = state.copyWith( - googleAccount: null, - medias: mediaMapUpdate( - update: (media) { - if (media.driveMediaRefId != null && - media.sources.contains(AppMediaSource.googleDrive) && - media.sources.length > 1) { - return media.removeGoogleDriveRef(); - } else if (!media.sources.contains(AppMediaSource.googleDrive) && - media.driveMediaRefId == null) { - return media; - } - return null; - }, - medias: state.medias, - ), + Future updateGoogleAccount(GoogleSignInAccount? googleAccount) async { + if (googleAccount != null) { + state = state.copyWith(googleAccount: googleAccount); + try { + _backUpFolderId = await _googleDriveService.getBackUpFolderId(); + } catch (e, s) { + _logger.e( + "HomeViewStateNotifier: unable to get google drive back up folder id", + error: e, + stackTrace: s, ); } - }); + loadMedias(reload: true, force: true); + } else { + _backUpFolderId = null; + state = state.copyWith( + googleAccount: null, + medias: mediaMapUpdate( + update: (media) { + if (media.driveMediaRefId != null && + media.sources.contains(AppMediaSource.googleDrive) && + media.sources.length > 1) { + return media.removeGoogleDriveRef(); + } else if (!media.sources.contains(AppMediaSource.googleDrive) && + media.driveMediaRefId == null) { + return media; + } + return null; + }, + medias: state.medias, + ), + ); + } } /// Listen to dropbox account changes and update the state accordingly. @@ -252,8 +260,9 @@ class HomeViewStateNotifier extends StateNotifier /// Loads medias from local, google drive and dropbox. /// it append the medias to the existing medias if reload is false. - Future loadMedias({bool reload = false}) async { - if (state.loading || state.cloudLoading) return; + /// force will load media event its already loading + Future loadMedias({bool reload = false, bool force: false}) async { + if (state.cloudLoading && !force) return; state = state.copyWith(loading: true, cloudLoading: true, error: null); try { // Reset all the variables if reload is true diff --git a/app/lib/ui/flow/media_preview/components/local_media_image_preview.dart b/app/lib/ui/flow/media_preview/components/local_media_image_preview.dart index 9ae6a7e6..c41deb40 100644 --- a/app/lib/ui/flow/media_preview/components/local_media_image_preview.dart +++ b/app/lib/ui/flow/media_preview/components/local_media_image_preview.dart @@ -5,6 +5,7 @@ import '../../../../components/place_holder_screen.dart'; import '../../../../domain/extensions/context_extensions.dart'; import 'package:data/models/media/media.dart'; import 'package:flutter/material.dart'; +import '../../../../domain/image_providers/app_media_image_provider.dart'; class LocalMediaImagePreview extends StatelessWidget { final AppMedia media; @@ -43,21 +44,35 @@ class LocalMediaImagePreview extends StatelessWidget { frameBuilder: (context, child, frame, wasSynchronouslyLoaded) { if (wasSynchronouslyLoaded) { return child; - } else { - final width = context.mediaQuerySize.width; - double multiplier = 1; - if (media.displayWidth != null && media.displayWidth! > 0) { - multiplier = width / media.displayWidth!; - } - return SizedBox( - width: width, - height: - media.displayHeight != null && media.displayHeight! > 0 - ? media.displayHeight! * multiplier - : width, - child: child, + } + if (frame == null) { + return Image( + image: AppMediaImageProvider(media: media), + width: double.infinity, + height: double.infinity, + fit: BoxFit.contain, + errorBuilder: (context, error, stackTrace) { + return AppPage( + body: PlaceHolderScreen( + title: context.l10n.unable_to_load_media_error, + message: context.l10n.unable_to_load_media_message, + ), + ); + }, ); } + final width = context.mediaQuerySize.width; + double multiplier = 1; + if (media.displayWidth != null && media.displayWidth! > 0) { + multiplier = width / media.displayWidth!; + } + return SizedBox( + width: width, + height: media.displayHeight != null && media.displayHeight! > 0 + ? media.displayHeight! * multiplier + : width, + child: child, + ); }, ), ), From 102e89b81381d9d0c44057f285493523803c635c Mon Sep 17 00:00:00 2001 From: Pratik-canopas Date: Fri, 20 Dec 2024 18:26:14 +0530 Subject: [PATCH 4/4] Fix preview --- app/lib/ui/flow/home/home_screen.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/lib/ui/flow/home/home_screen.dart b/app/lib/ui/flow/home/home_screen.dart index c47048ce..3b39936f 100644 --- a/app/lib/ui/flow/home/home_screen.dart +++ b/app/lib/ui/flow/home/home_screen.dart @@ -178,8 +178,7 @@ class _HomeScreenState extends ConsumerState { ), itemCount: gridEntry.value.entries.length, itemBuilder: (context, index) { - final media = - gridEntry.value.entries.elementAt(index).value; + final media = gridEntry.value.entries.elementAt(index).value; if (media.id == state.lastLocalMediaId) { runPostFrame(() {