Skip to content

Instantly share code, notes, and snippets.

@abdullahalamodi
Created August 14, 2022 08:22
Show Gist options
  • Save abdullahalamodi/a7c7208e52f73414afb49c837f04275d to your computer and use it in GitHub Desktop.
Save abdullahalamodi/a7c7208e52f73414afb49c837f04275d to your computer and use it in GitHub Desktop.
upload, download and show files from google drive
import 'dart:developer';
import 'dart:io';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:googleapis/drive/v3.dart' as g_drive;
import 'package:http/http.dart' as http;
import 'package:path_provider/path_provider.dart';
class GoogleAuthClient extends http.BaseClient {
final Map<String, String> _headers;
final _client = http.Client();
GoogleAuthClient(this._headers);
@override
Future<http.StreamedResponse> send(http.BaseRequest request) {
request.headers.addAll(_headers);
return _client.send(request);
}
}
extension FileNameEx on File {
String get nameWithEx => path.substring(path.lastIndexOf('/') + 1);
}
class GoogleDriveServices {
g_drive.DriveApi? driveApi;
final GoogleSignIn _googleSignIn = GoogleSignIn.standard(
scopes: [g_drive.DriveApi.driveScope],
);
Future<g_drive.DriveApi?> _getDriveApi(
GoogleSignInAccount? googleUser,
) async {
if (driveApi == null) {
final headers = await googleUser?.authHeaders;
if (headers == null) {
return null;
}
final client = GoogleAuthClient(headers);
driveApi = g_drive.DriveApi(client);
}
return driveApi;
}
Future<GoogleSignInAccount?> signIn({bool silently = false}) =>
silently ? _googleSignIn.signInSilently() : _googleSignIn.signIn();
Future<bool> isSignedIn() => _googleSignIn.isSignedIn();
Future<void> signOut() => _googleSignIn.disconnect();
// upload file to google drive
Future<void> uploadFile(
File file,
GoogleSignInAccount? googleUser,
) async {
final driveApi = await _getDriveApi(googleUser);
if (driveApi == null) return;
final appFolderId = await _getMyAppFolderId(driveApi);
if (appFolderId == null) {
log('backup: folderId == null, need sign in');
return;
}
// Create a folder
var folderInfo = g_drive.File();
folderInfo.name = DateTime.now().millisecondsSinceEpoch.toString();
folderInfo.mimeType = _mimeType;
folderInfo.parents = [appFolderId];
final backupfolder = await driveApi.files.create(folderInfo);
try {
final datInfo =
g_drive.File(name: file.nameWithEx, parents: [backupfolder.id!]);
final datRresponse = await driveApi.files.create(
datInfo,
uploadMedia: g_drive.Media(
file.openRead(),
file.lengthSync(),
),
);
log(datRresponse.toJson().toString());
} catch (e) {
//if not completed the backup (uplade the file) delete the folder
// so that no corrupted files remain
driveApi.files.delete(backupfolder.id!);
rethrow;
}
// when backup (uplade the file) successfuly delete others if exist
final fileList = await driveApi.files.list(
q: "'$appFolderId' in parents",
$fields: "files(id, name)",
);
final backupsList = fileList.files ?? [];
for (var item in backupsList) {
if (item.id != backupfolder.id!) {
await driveApi.files.delete(item.id!);
}
}
}
Future<g_drive.File?> _getFileByFolderId(
g_drive.DriveApi driveApi,
String folderId,
) async {
try {
final found = await driveApi.files.list(
q: "'$folderId' in parents",
$fields: "files(id, name)",
);
final files = found.files;
return files?.first;
} catch (e) {
log(e.toString());
return null;
}
}
Future<List<int>> futureFromStream(Stream<List<int>> stream) async {
List<int> sum = [];
await for (final value in stream) {
sum += value;
}
return sum;
}
// download file form google drive by folder id.
// I have one file in my folder so I get that file by query
// that folder this is what is suitable for my case
// 💡 you can search and query files as you want
// by follow this link https://developers.google.com/drive/api/guides/search-files
Future<File?> downloadFileByFolderId({
required final String folderId,
required final GoogleSignInAccount? googleUser,
final String fileNameWithEx = 'downloaded_file.txt',
}) async {
final driveApi = await _getDriveApi(googleUser);
if (driveApi == null) return null;
// query folder to get file
final driveFile = await _getFileByFolderId(driveApi, folderId);
if (driveFile == null) return null;
final directory = await getApplicationDocumentsDirectory();
//
final fileMedia = (await driveApi.files.get(driveFile.id!,
downloadOptions: g_drive.DownloadOptions.fullMedia)) as g_drive.Media;
// the palce you safe the file. 💡 you can pass it as parameter instead of file name with ex
File? newFile = File('${directory.path}/$fileNameWithEx');
List<int> dataStore = [];
dataStore = await futureFromStream(fileMedia.stream);
await newFile.writeAsBytes(dataStore);
// TODO for debug !!
log("lckFile: File saved at ${newFile.path}");
log("lckFile: File name: ${newFile.nameWithEx}");
return newFile;
}
// get all files in a spicific folder. ( ❗ the file "id and name" not the file media)
// you can desplay them as list
Future<List<g_drive.File>?> getFiles({
required final GoogleSignInAccount? googleUser,
}) async {
final driveApi = await _getDriveApi(googleUser);
if (driveApi == null) return null;
final appFolderId = await _getMyAppFolderId(driveApi);
final found = await driveApi.files.list(
q: "'$appFolderId' in parents",
$fields: "files(id, name)",
);
final files = found.files ?? [];
return files.isEmpty ? null : files;
}
// we assume that you will create folder
// for your app on google drive to store your data on
Future<String?> _getMyAppFolderId(
g_drive.DriveApi driveApi,
) async {
try {
// search for folder by name
final found = await driveApi.files.list(
q: "mimeType = '$_mimeType' and name = '$_folderName'",
$fields: "files(id, name)",
);
final files = found.files;
if (files == null) return null;
// Create a folder for first time
if (files.isEmpty) {
var folder = g_drive.File();
folder.name = _folderName;
folder.mimeType = _mimeType;
final folderCreation = await driveApi.files.create(folder);
log("Folder ID: ${folderCreation.id}");
return folderCreation.id;
} else {
return files.first.id;
}
} catch (e) {
log(e.toString());
return null;
}
}
static const _mimeType = "application/vnd.google-apps.folder";
static const _folderName = "myAppFolder";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment