From b0d0b7f1d82111ff2f6ea1c1b448d27b3746fe05 Mon Sep 17 00:00:00 2001 From: Tony Chen Date: Tue, 19 May 2026 00:46:24 +1000 Subject: [PATCH] Create keyvalue/key-value.ttl if it does not exist --- example/lib/utils/ensure_resource.dart | 103 +++++++++++++++++++++++++ example/lib/widgets/home_sections.dart | 29 ++++++- example/pubspec.yaml | 4 +- 3 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 example/lib/utils/ensure_resource.dart diff --git a/example/lib/utils/ensure_resource.dart b/example/lib/utils/ensure_resource.dart new file mode 100644 index 00000000..12c51bac --- /dev/null +++ b/example/lib/utils/ensure_resource.dart @@ -0,0 +1,103 @@ +/// Utility to ensure a Pod resource exists before performing actions on it. +/// +/// Copyright (C) 2026, Software Innovation Institute, ANU. +/// +/// Licensed under the GNU General Public License, Version 3 (the "License"). +/// +/// License: https://opensource.org/license/gpl-3-0. +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or (at your option) any later +// version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +// details. +// +// You should have received a copy of the GNU General Public License along with +// this program. If not, see . +/// +/// Authors: Tony Chen + +// ignore_for_file: use_build_context_synchronously + +library; + +import 'package:flutter/material.dart'; + +import 'package:solidpod/solidpod.dart' + show ResourceStatus, checkResourceStatus, filenameToResourceUrl, writePod; + +import 'package:demopod/dialogs/alert.dart'; + +/// Ensures the resource at [relativePath] exists in the user's Pod. +/// +/// The [relativePath] is interpreted relative to the app's data directory +/// (e.g. `keyvalue/key-value.ttl`). When the resource is missing on the Pod, +/// a new file is created using [defaultContent] (encrypted by default) so +/// downstream actions such as granting permissions do not fail. +/// +/// Returns `true` when the resource is available (already existed or was +/// just created), and `false` otherwise. + +Future ensurePodResourceExists( + BuildContext context, { + required String relativePath, + required String defaultContent, + bool encrypted = true, +}) async { + try { + final fileUrl = await filenameToResourceUrl(fileName: relativePath); + + final status = await checkResourceStatus(fileUrl); + + switch (status) { + case ResourceStatus.exist: + return true; + + case ResourceStatus.notExist: + await writePod(relativePath, defaultContent, encrypted: encrypted); + + if (context.mounted) { + await alert( + context, + 'The resource "$relativePath" did not exist on your Pod, ' + 'so a new file with placeholder content has been created ' + 'automatically.', + ); + } + return true; + + case ResourceStatus.forbidden: + if (context.mounted) { + await alert( + context, + 'Access to "$relativePath" is forbidden. Please check the ' + 'permissions on your Pod and try again.', + ); + } + return false; + + case ResourceStatus.unknown: + if (context.mounted) { + await alert( + context, + 'Unable to determine whether "$relativePath" exists on your Pod. ' + 'Please try again in a moment.', + ); + } + return false; + } + } on Object catch (e) { + debugPrint('ensurePodResourceExists() failed: $e'); + if (context.mounted) { + await alert( + context, + 'Failed to ensure "$relativePath" exists on your Pod: $e', + ); + } + return false; + } +} diff --git a/example/lib/widgets/home_sections.dart b/example/lib/widgets/home_sections.dart index b042e64a..835c48a7 100644 --- a/example/lib/widgets/home_sections.dart +++ b/example/lib/widgets/home_sections.dart @@ -43,6 +43,7 @@ import 'package:solidui/solidui.dart' import 'package:demopod/constants/app.dart'; import 'package:demopod/features/permission_callback_demo.dart'; import 'package:demopod/features/multiple_resource_sharing.dart'; +import 'package:demopod/utils/ensure_resource.dart'; /// Builds the login management section widgets. @@ -148,12 +149,25 @@ List buildPermissionSection( if (loggedIn) { await getKeyFromUserIfRequired(context, currentWidget); + // Ensure the target resource exists on the Pod before opening the + // grant permission UI. The button previously failed with a "not + // found" error when keyvalue/key-value.ttl had never been created. + + if (!context.mounted) return; + final ready = await ensurePodResourceExists( + context, + relativePath: dataFile, + defaultContent: createDemoTtlStr('key-value'), + ); + if (!ready) return; + + if (!context.mounted) return; Navigator.push( context, MaterialPageRoute( builder: (context) => GrantPermissionUi( backgroundColor: titleBackgroundColor, - resourceNames: ['keyvalue/key-value.ttl'], + resourceNames: [dataFile], // accessModeList: ['read', 'write'], // recipientTypeList: ['indi', 'group'], // isFile: false, @@ -253,6 +267,19 @@ List buildPermissionSection( if (loggedIn) { await getKeyFromUserIfRequired(context, currentWidget); + // Ensure the target resource exists on the Pod before opening the + // shared resources UI. The button previously failed with a "not + // found" error when keyvalue/key-value.ttl had never been created. + + if (!context.mounted) return; + final ready = await ensurePodResourceExists( + context, + relativePath: dataFile, + defaultContent: createDemoTtlStr('key-value'), + ); + if (!ready) return; + + if (!context.mounted) return; Navigator.push( context, MaterialPageRoute( diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 9eca0ad2..81854107 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -14,8 +14,8 @@ dependencies: intl: any markdown_tooltip: ^0.0.10 rdflib: ^0.2.12 - solidpod: ^0.12.5 - solidui: ^0.3.43 + solidpod: ^0.12.6 + solidui: ^0.3.45 universal_io: ^2.3.1 window_manager: ^0.5.1