Flutter File/Folder search with Google Drive API

Dart and Flutter

I tried some file search queries to communicate with Google Drive. If you don’t know how to connect to Google Drive, check this post first.

The example code is in my repository but you have to follow the steps described in the article above because a necessary file google-services.json is not included in the repository.

https://github.com/yuto-yuto/flutter_samples/blob/main/lib/google_drive_search.dart
Sponsored links

Template code and my file list

All examples use the following code. We change only the query.

Widget _createButton(String title, Function(drive.DriveApi driveApi) query) {
  return ElevatedButton(
    onPressed: () async {
      final driveApi = await _getDriveApi();
      if (driveApi == null) {
        return;
      }

      final fileList = await query(driveApi);
      final files = fileList.files;
      if (files == null) {
        return showMessage(context, "Data not found", "");
      }
      await _showList(files);
    },
    child: Text(title),
  );
}

There are only 3 folders in my Google Drive. temp1 and temp2 folders have almost the same files.

To read folders and files without any limitations, we need to specify the following scope. Without this scope, the app can read the folders and files that are created by the app.

  final googleSignIn = GoogleSignIn.standard(scopes: [
    drive.DriveApi.driveReadonlyScope
  ]);

If you need to create a hidden directory, which is only for the app, this post might be helpful.

Sponsored links

Get All Files and Folders in the Drive

If we want to get all files, it’s very simple. We don’t have to specify any query for that.

Future<drive.FileList> _allFileList(drive.DriveApi driveApi) {
  return driveApi.files.list(
    spaces: 'drive',
  );
}

Check if the file is a folder

It shows an icon depending on the file type in the example above. To show the proper icon, we need to check the mimeType. Since the folder type is always "application/vnd.google-apps.folder", we can check if it is a folder by using it.

const _folderType = "application/vnd.google-apps.folder";

Future<void> _showList(List<drive.File> files) {
  return showDialog(
    context: context,
    builder: (BuildContext context) {
      return AlertDialog(
        title: Text("List"),
        content: Container(
          width: MediaQuery.of(context).size.height - 50,
          height: MediaQuery.of(context).size.height,
          child: ListView.builder(
            itemCount: files.length,
            itemBuilder: (context, index) {
              final isFolder = files[index].mimeType == _folderType;

              return ListTile(
                leading: Icon(isFolder
                    ? Icons.folder
                    : Icons.insert_drive_file_outlined),
                title: Text(files[index].name ?? "no-name"),
              );
            },
          ),
        ),
      );
    },
  );
}

Get files in the root folder

This is the code to get files under the root folder. Normally, we need to specify an ID of the folder but we can use "root" as the alias.

Future<drive.FileList> _root(drive.DriveApi driveApi) {
  return driveApi.files.list(
    spaces: 'drive',
    q: "'root' in parents",
  );
}

Get files in the specific folder

As I mentioned above, we need to specify a folder ID to get a file list in the folder. I couldn’t find a way to get the list with only one query.

Future<drive.FileList> _filesInFolder(drive.DriveApi driveApi) async {
  final folderId = await _getFolderId(driveApi, "temp1");
  return driveApi.files.list(
    spaces: 'drive',
    q: "'$folderId' in parents",
  );
}

Future<String?> _getFolderId(
  drive.DriveApi driveApi,
  String folderName,
) async {
  try {
    final found = await driveApi.files.list(
      q: "mimeType = '$_folderType' and name = '$folderName'",
      $fields: "files(id, name)",
    );
    final files = found.files;
    if (files == null) {
      return null;
    }

    if (files.isNotEmpty) {
      return files.first.id;
    }
  } catch (e) {
    print(e);
  }
  return null;
}

The code gets a file list in temp1 folder.

Get files that contains specific words

It seems not to be possible to use wildcards for the query. Therefore, we can write only simple conditions by using "contains" keyword.

Future<drive.FileList> _txt(drive.DriveApi driveApi) {
  return driveApi.files.list(
    spaces: 'drive',
    q: "name contains '.txt'",
  );
}

This query gets “.txt” files but if a file name is like “abc.txt.md”, it is also included in the result.

My folder doesn’t include such a file.

Get files that are owned by other users

Future<drive.FileList> _filesOwnedByOther(drive.DriveApi driveApi) async {
  return driveApi.files.list(
    spaces: 'drive',
    q: "not 'me' in owners",
  );
}

Get shared files

I couldn’t find a way to do this in a query. To get files that are shared with others, we need to check the "shared" property. It can be done only after we get the file list.

Future<drive.FileList> _sharedFiles(drive.DriveApi driveApi) async {
  final list = await driveApi.files.list(
    spaces: 'drive',
    q: "'me' in owners",
  );

  // remove non-shared files
  list.files?.removeWhere((element) => element.shared == false);
  return list;
}

It includes both folder and file. temp1 folder is shared with another user.

Comments

  1. Anonymous says:

    Is I can use the driveReadonlyScope without verification? When I add this scope and run app I select my google account and a pop-up appears that google has not verified this app when I select continue the another pop-up show that something went wrong why?

Copied title and URL