From f53b80b520eabc267d3806f55d642d0905f3668c Mon Sep 17 00:00:00 2001 From: Tony Chen Date: Thu, 19 Mar 2026 16:20:05 +1100 Subject: [PATCH 1/3] Lint --- dart_dependency_validator.yaml | 3 +++ example/lib/features/create_acl_inherited_file.dart | 4 ++-- example/lib/features/edit_keyvalue.dart | 8 ++++---- example/lib/features/file_service.dart | 4 ++-- example/lib/features/view_keys.dart | 4 ++-- example/lib/main.dart | 5 +++-- example/lib/utils/rdf.dart | 1 - example/pubspec.yaml | 1 + example/support/flutter.mk | 2 +- pubspec.yaml | 1 + support/flutter.mk | 2 +- 11 files changed, 20 insertions(+), 15 deletions(-) diff --git a/dart_dependency_validator.yaml b/dart_dependency_validator.yaml index db9a30b8..ae00a763 100644 --- a/dart_dependency_validator.yaml +++ b/dart_dependency_validator.yaml @@ -1,2 +1,5 @@ +exclude: + - "example/**" + ignore: - cupertino_icons # An asset repository. diff --git a/example/lib/features/create_acl_inherited_file.dart b/example/lib/features/create_acl_inherited_file.dart index 61c996ac..24d687cd 100644 --- a/example/lib/features/create_acl_inherited_file.dart +++ b/example/lib/features/create_acl_inherited_file.dart @@ -25,10 +25,10 @@ library; import 'package:flutter/material.dart'; -import 'package:demopod/constants/app.dart'; - import 'package:solidpod/solidpod.dart' show writePod, setInheritKeyDir; +import 'package:demopod/constants/app.dart'; + // A widget to create a resource with inherited ACL. // // The resource will be created inside a parent directory and the ACL of that diff --git a/example/lib/features/edit_keyvalue.dart b/example/lib/features/edit_keyvalue.dart index ba406fa0..02bdb119 100644 --- a/example/lib/features/edit_keyvalue.dart +++ b/example/lib/features/edit_keyvalue.dart @@ -27,13 +27,13 @@ library; import 'package:flutter/material.dart'; -import 'package:demopod/constants/app.dart'; -import 'package:demopod/dialogs/alert.dart'; -import 'package:demopod/utils/rdf.dart'; import 'package:editable/editable.dart'; +import 'package:solidpod/solidpod.dart' show isUserLoggedIn, writePod; import 'package:solidui/solidui.dart' show getKeyFromUserIfRequired; -import 'package:solidpod/solidpod.dart' show isUserLoggedIn, writePod; +import 'package:demopod/constants/app.dart'; +import 'package:demopod/dialogs/alert.dart'; +import 'package:demopod/utils/rdf.dart'; class KeyValueEdit extends StatefulWidget { /// Constructor diff --git a/example/lib/features/file_service.dart b/example/lib/features/file_service.dart index 8147eb27..593728b3 100644 --- a/example/lib/features/file_service.dart +++ b/example/lib/features/file_service.dart @@ -25,11 +25,11 @@ library; import 'package:flutter/material.dart'; -import 'package:demopod/dialogs/alert.dart'; import 'package:file_picker/file_picker.dart'; - import 'package:solidpod/solidpod.dart'; +import 'package:demopod/dialogs/alert.dart'; + class FileService extends StatefulWidget { const FileService({required this.child, required this.webId, super.key}); final String webId; diff --git a/example/lib/features/view_keys.dart b/example/lib/features/view_keys.dart index bb0a88d8..03a9ba76 100644 --- a/example/lib/features/view_keys.dart +++ b/example/lib/features/view_keys.dart @@ -27,11 +27,11 @@ library; import 'package:flutter/material.dart'; +import 'package:solidpod/solidpod.dart' show KeyManager; + import 'package:demopod/constants/app.dart'; import 'package:demopod/utils/rdf.dart' show getEncKeyContent; -import 'package:solidpod/solidpod.dart' show KeyManager; - /// A widget to show the user all the encryption keys stored in their Solid Pod. class ViewKeys extends StatefulWidget { diff --git a/example/lib/main.dart b/example/lib/main.dart index 46935571..9346ef00 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -27,11 +27,12 @@ library; import 'package:flutter/material.dart'; -import 'package:demopod/home.dart'; -import 'package:demopod/utils/is_desktop.dart'; import 'package:solidui/solidui.dart' show SolidLogin, InfoButtonStyle; import 'package:window_manager/window_manager.dart'; +import 'package:demopod/home.dart'; +import 'package:demopod/utils/is_desktop.dart'; + void main() async { // Remove [debugPrint] messages from production code. diff --git a/example/lib/utils/rdf.dart b/example/lib/utils/rdf.dart index 08d27523..0c8dedb1 100644 --- a/example/lib/utils/rdf.dart +++ b/example/lib/utils/rdf.dart @@ -25,7 +25,6 @@ library; import 'package:rdflib/rdflib.dart'; - import 'package:solidpod/solidpod.dart' show getWebId; // Namespace for keys diff --git a/example/pubspec.yaml b/example/pubspec.yaml index d16aff7d..fafcd772 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -28,6 +28,7 @@ dependency_overrides: ref: dev dev_dependencies: + dependency_validator: ^5.0.4 flutter_lints: ^6.0.0 flutter: diff --git a/example/support/flutter.mk b/example/support/flutter.mk index e8d2168f..7e7cf942 100644 --- a/example/support/flutter.mk +++ b/example/support/flutter.mk @@ -174,7 +174,7 @@ analyze: .PHONY: depend depend: @echo "Review pubspec.yaml dependencies." - -dependency_validator + -dart run dependency_validator @echo $(SEPARATOR) .PHONY: ignore diff --git a/pubspec.yaml b/pubspec.yaml index 487ff81d..7b7b005c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,6 +38,7 @@ dependencies: dev_dependencies: build_runner: ^2.10.5 custom_lint: ^0.8.1 + dependency_validator: ^5.0.4 flutter_lints: ^6.0.0 import_order_lint: ^0.2.2 diff --git a/support/flutter.mk b/support/flutter.mk index 5768fdea..ec907b92 100644 --- a/support/flutter.mk +++ b/support/flutter.mk @@ -213,7 +213,7 @@ analyze: .PHONY: depend depend: @echo "Dart: REVIEW DEPENDENCIES." - -dependency_validator + -dart run dependency_validator @echo $(SEPARATOR) # Check and fail if any files exceed limit. From 2d75a52d0000d86f22578ba527b8ea6143aea196 Mon Sep 17 00:00:00 2001 From: Tony Chen Date: Thu, 19 Mar 2026 16:44:29 +1100 Subject: [PATCH 2/3] Fix the locmax issues --- example/lib/dialogs/file_metadata.dart | 80 ++++ example/lib/features/file_service.dart | 255 ++----------- .../features/permission_callback_demo.dart | 92 +---- example/lib/home.dart | 350 +----------------- .../lib/widgets/file_service_sections.dart | 284 ++++++++++++++ example/lib/widgets/home_sections.dart | 347 +++++++++++++++++ .../lib/widgets/permission_demo_widgets.dart | 114 ++++++ 7 files changed, 884 insertions(+), 638 deletions(-) create mode 100644 example/lib/dialogs/file_metadata.dart create mode 100644 example/lib/widgets/file_service_sections.dart create mode 100644 example/lib/widgets/home_sections.dart create mode 100644 example/lib/widgets/permission_demo_widgets.dart diff --git a/example/lib/dialogs/file_metadata.dart b/example/lib/dialogs/file_metadata.dart new file mode 100644 index 00000000..cb3dfd7e --- /dev/null +++ b/example/lib/dialogs/file_metadata.dart @@ -0,0 +1,80 @@ +/// A dialog to display file metadata information. +/// +/// Copyright (C) 2024, 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: Dawei Chen + +library; + +import 'package:flutter/material.dart'; + +/// Shows a dialog displaying file metadata. + +void showFileMetadataDialog({ + required BuildContext context, + required String fileName, + required String contentLength, + required String lastModified, + required String contentType, + required String allowdAccess, +}) { + showDialog( + context: context, + builder: (_) => AlertDialog( + title: const Text('File Information'), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _infoRow('File name', fileName), + _infoRow('Last modified', lastModified), + _infoRow('Content length', contentLength), + _infoRow('Content type', contentType), + _infoRow('Allowed operations', allowdAccess), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Close'), + ), + ], + ), + ); +} + +Widget _infoRow(String label, String value) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 120, + child: Text( + '$label:', + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ), + Expanded(child: Text(value)), + ], + ), + ); +} diff --git a/example/lib/features/file_service.dart b/example/lib/features/file_service.dart index 593728b3..ea7927d1 100644 --- a/example/lib/features/file_service.dart +++ b/example/lib/features/file_service.dart @@ -29,6 +29,7 @@ import 'package:file_picker/file_picker.dart'; import 'package:solidpod/solidpod.dart'; import 'package:demopod/dialogs/alert.dart'; +import 'package:demopod/widgets/file_service_sections.dart'; class FileService extends StatefulWidget { const FileService({required this.child, required this.webId, super.key}); @@ -76,37 +77,6 @@ class _FileServiceState extends State { return folder.isNotEmpty ? folder : null; } - Widget getProgressBar(String message, bool isDone, double percent) { - const textStyle = TextStyle( - color: Colors.green, - fontWeight: FontWeight.bold, - ); - - final prefix = Text(message, style: textStyle); - final suffix = Text('${(percent * 100).toInt()}%', style: textStyle); - final progress = SizedBox( - width: 300, - height: 10, - child: LinearProgressIndicator( - value: percent, - minHeight: 2, - backgroundColor: Colors.black12, - color: Colors.greenAccent, - ), - ); - - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - prefix, - smallGapH, - progress, - smallGapH, - suffix, - ], - ); - } - @override void initState() { super.initState(); @@ -363,199 +333,44 @@ class _FileServiceState extends State { // Widgets of the file upload section - final uploadSection = [ - Text( - 'Upload a local large file and save it as "$defaultRemoteFileName" in POD', - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - smallGapV, - Table( - columnWidths: const { - 0: FixedColumnWidth(450), - // 1: FixedColumnWidth(50), - // 1: FlexColumnWidth(), - }, - children: [ - TableRow( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - uploadFile ?? - 'Click the Browse button to choose a local file', - style: TextStyle( - color: uploadFile == null ? Colors.red : Colors.blue, - fontStyle: FontStyle.italic, - fontSize: 16, - ), - ), - smallGapH, - if (uploadDone) const Icon(Icons.done, color: Colors.green), - ], - ), - ], - ), - TableRow( - children: [ - TextFormField( - controller: remoteFolderController, - enabled: !(uploadInProgress || uploadDone), - decoration: const InputDecoration( - // labelText: 'Remote Folder', - // border: OutlineInputBorder(), - hintText: '(Optional) save to folder in POD, e.g. dir1/dir2/', - hintStyle: TextStyle( - color: Colors.brown, - fontStyle: FontStyle.italic, - fontSize: 15, - ), - ), - // validator: (value) { - // if (value != null || value!.trim().isNotEmpty) { - // if (!value.endsWith('/')) { - // return 'Folder path must ends with /'; - // } - // } - // return null; - // }, - ), - ], - ), - TableRow(children: [ - TextFormField( - controller: keyRefFolderController, - enabled: !(uploadInProgress || uploadDone), - decoration: const InputDecoration( - hintText: - '(Optional) Inherit encryption key of folder in POD, e.g. dir1/', - hintStyle: TextStyle( - color: Colors.brown, - fontStyle: FontStyle.italic, - fontSize: 15, - ), - ), - ), - ]), - ], - ), - smallGapV, - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - browseButton, - smallGapH, - uploadButton, - ], - ), - ]; + final uploadSection = buildUploadSectionUI( + defaultRemoteFileName: defaultRemoteFileName, + uploadFile: uploadFile, + uploadDone: uploadDone, + uploadInProgress: uploadInProgress, + remoteFolderController: remoteFolderController, + keyRefFolderController: keyRefFolderController, + browseButton: browseButton, + uploadButton: uploadButton, + ); // Widgets of the file download section - final downloadSection = [ - Text( - 'Download the "$defaultRemoteFileName" from POD', - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - smallGapV, - if (downloadFile != null) - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text('Save file'), - smallGapH, - Text( - downloadFile!, - style: const TextStyle(color: Colors.blue), - ), - smallGapH, - if (downloadDone) const Icon(Icons.done, color: Colors.green), - ], - ), - smallGapV, - downloadButton, - ]; + final downloadSection = buildDownloadSectionUI( + defaultRemoteFileName: defaultRemoteFileName, + downloadFile: downloadFile, + downloadDone: downloadDone, + downloadButton: downloadButton, + ); // Widgets of the shared file download section - // Widgets of the file download section - final downloadSharedSection = [ - Text( - 'Download a shared large file from an external POD', - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - smallGapV, - SizedBox( - width: 550, - child: TextFormField( - controller: sharedUrlController, - enabled: !(downloadSharedInProgress || downloadSharedDone), - decoration: const InputDecoration( - hintText: 'URL of shared large file in external POD', - hintStyle: TextStyle( - color: Colors.brown, - fontStyle: FontStyle.italic, - fontSize: 15, - ), - ), - ), - ), - smallGapV, - if (downloadSharedFile != null) - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text('Save file'), - smallGapH, - Text( - downloadSharedFile!, - style: const TextStyle(color: Colors.blue), - ), - smallGapH, - if (downloadSharedDone) const Icon(Icons.done, color: Colors.green), - ], - ), - smallGapV, - downloadSharedButton, - ]; + final downloadSharedSection = buildDownloadSharedSectionUI( + downloadSharedFile: downloadSharedFile, + downloadSharedDone: downloadSharedDone, + downloadSharedInProgress: downloadSharedInProgress, + sharedUrlController: sharedUrlController, + downloadSharedButton: downloadSharedButton, + ); // Widgets of the file delete section - final deleteSection = [ - Text( - 'Delete the "$defaultRemoteFileName" from POD', - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - smallGapV, - if (deleteInProgress || deleteDone) - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text('Delete remote file'), - smallGapH, - Text( - defaultRemoteFileName, - style: const TextStyle(color: Colors.blue), - ), - smallGapH, - if (deleteDone) const Icon(Icons.done, color: Colors.green), - ], - ), - smallGapV, - deleteButton, - ]; + final deleteSection = buildDeleteSectionUI( + defaultRemoteFileName: defaultRemoteFileName, + deleteInProgress: deleteInProgress, + deleteDone: deleteDone, + deleteButton: deleteButton, + ); return Scaffold( body: Padding( @@ -599,7 +414,8 @@ class _FileServiceState extends State { top: 20, left: 0, right: 0, - child: getProgressBar('Uploading:', uploadDone, uploadPercent), + child: buildProgressBar( + 'Uploading:', uploadDone, uploadPercent), ), // Downloading progress bar @@ -609,7 +425,7 @@ class _FileServiceState extends State { top: 20, left: 0, right: 0, - child: getProgressBar( + child: buildProgressBar( 'Downloading:', downloadDone, downloadPercent), ), @@ -620,7 +436,7 @@ class _FileServiceState extends State { top: 20, left: 0, right: 0, - child: getProgressBar( + child: buildProgressBar( 'Downloading:', downloadSharedDone, downloadSharedPercent), ), @@ -631,7 +447,8 @@ class _FileServiceState extends State { top: 20, left: 0, right: 0, - child: getProgressBar('Deleting:', deleteDone, deletePercent), + child: buildProgressBar( + 'Deleting:', deleteDone, deletePercent), ), // Navigate back to demo page diff --git a/example/lib/features/permission_callback_demo.dart b/example/lib/features/permission_callback_demo.dart index 5c48d4e1..008bcc34 100644 --- a/example/lib/features/permission_callback_demo.dart +++ b/example/lib/features/permission_callback_demo.dart @@ -28,6 +28,8 @@ import 'package:flutter/material.dart'; import 'package:solidpod/solidpod.dart'; import 'package:solidui/solidui.dart' show GrantPermissionUi; +import 'package:demopod/widgets/permission_demo_widgets.dart'; + /// A widget demonstrating the onPermissionGranted callback functionality. class PermissionCallbackDemo extends StatefulWidget { @@ -297,39 +299,7 @@ demo:exampleData$fileNumber children: [ // Header section. - Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: Colors.blue[50], - borderRadius: BorderRadius.circular(12), - border: Border.all(color: Colors.blue[200]!), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(Icons.lightbulb_outline, - color: Colors.blue[700], size: 28), - const SizedBox(width: 12), - const Text( - 'Why Use onPermissionGranted Callback?', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.black87, - ), - ), - ], - ), - const SizedBox(height: 12), - const Text( - 'The onPermissionGranted callback allows your app to automatically continue workflows after users grant permissions. This demo creates sample files automatically and shows how to share multiple files sequentially without manual navigation.', - style: TextStyle(fontSize: 16, height: 1.4), - ), - ], - ), - ), + buildDemoHeaderSection(), const SizedBox(height: 24), @@ -365,13 +335,13 @@ demo:exampleData$fileNumber Row( children: [ - _buildStepIndicator(1, 'Start', _currentStep >= 1), - _buildConnector(_currentStep >= 2), - _buildStepIndicator(2, 'Grant', _currentStep >= 2), - _buildConnector(_currentStep >= 3), - _buildStepIndicator(3, 'Process', _currentStep >= 3), - _buildConnector(_currentStep >= 4), - _buildStepIndicator(4, 'Complete', _currentStep >= 4), + buildStepIndicator(1, 'Start', _currentStep >= 1), + buildStepConnector(_currentStep >= 2), + buildStepIndicator(2, 'Grant', _currentStep >= 2), + buildStepConnector(_currentStep >= 3), + buildStepIndicator(3, 'Process', _currentStep >= 3), + buildStepConnector(_currentStep >= 4), + buildStepIndicator(4, 'Complete', _currentStep >= 4), ], ), @@ -582,46 +552,4 @@ demo:exampleData$fileNumber ); } - Widget _buildStepIndicator(int step, String label, bool isActive) { - return Column( - children: [ - Container( - width: 32, - height: 32, - decoration: BoxDecoration( - color: isActive ? Colors.blue[600] : Colors.grey[300], - shape: BoxShape.circle, - ), - child: Center( - child: Text( - step.toString(), - style: TextStyle( - color: isActive ? Colors.white : Colors.grey[600], - fontWeight: FontWeight.bold, - fontSize: 14, - ), - ), - ), - ), - const SizedBox(height: 4), - Text( - label, - style: TextStyle( - fontSize: 12, - color: isActive ? Colors.blue[600] : Colors.grey[600], - fontWeight: isActive ? FontWeight.w600 : FontWeight.normal, - ), - ), - ], - ); - } - - Widget _buildConnector(bool isActive) { - return Container( - width: 24, - height: 2, - margin: const EdgeInsets.only(bottom: 20), - color: isActive ? Colors.blue[600] : Colors.grey[300], - ); - } } diff --git a/example/lib/home.dart b/example/lib/home.dart index aec5ed3f..75b4d05d 100644 --- a/example/lib/home.dart +++ b/example/lib/home.dart @@ -33,31 +33,27 @@ library; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:markdown_tooltip/markdown_tooltip.dart'; import 'package:solidpod/solidpod.dart'; import 'package:solidui/solidui.dart' show - GrantPermissionUi, - InitialSetupScreenBody, - SharedResourcesUi, changeKeyPopup, getKeyFromUserIfRequired, largeGapV, loginIfRequired, - logoutPopup, smallGapV; import 'package:demopod/constants/app.dart'; import 'package:demopod/dialogs/about.dart'; import 'package:demopod/dialogs/alert.dart'; +import 'package:demopod/dialogs/file_metadata.dart'; import 'package:demopod/features/create_acl_inherited_file.dart'; import 'package:demopod/features/edit_keyvalue.dart'; import 'package:demopod/features/file_service.dart'; -import 'package:demopod/features/permission_callback_demo.dart'; import 'package:demopod/features/read_acl_inherited_file.dart'; import 'package:demopod/features/view_keys.dart'; import 'package:demopod/main.dart'; import 'package:demopod/utils/rdf.dart'; +import 'package:demopod/widgets/home_sections.dart'; /// A widget for the demonstration screen of the application. @@ -230,58 +226,6 @@ class HomeState extends State with SingleTickerProviderStateMixin { } } - void showFileMetadataDialog({ - required BuildContext context, - required String fileName, - required String contentLength, - required String lastModified, - required String contentType, - required String allowdAccess, - }) { - showDialog( - context: context, - builder: (_) => AlertDialog( - title: const Text('File Information'), - content: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _infoRow('File name', fileName), - _infoRow('Last modified', lastModified), - _infoRow('Content length', contentLength), - _infoRow('Content type', contentType), - _infoRow('Allowed operations', allowdAccess), - ], - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('Close'), - ), - ], - ), - ); - } - - Widget _infoRow(String label, String value) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 4), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - width: 120, - child: Text( - '$label:', - style: const TextStyle(fontWeight: FontWeight.bold), - ), - ), - Expanded(child: Text(value)), - ], - ), - ); - } - Widget _build(BuildContext context, String title) { // Build the widget. @@ -584,288 +528,20 @@ class HomeState extends State with SingleTickerProviderStateMixin { ); }, ), - largeGapV, - const Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Solid Server Login Management', - style: TextStyle( - fontSize: 22, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - MarkdownTooltip( - message: - 'This will remove from our local device\'s memory the ' - 'solid pod login information so that the next time you ' - 'start up the app you will need to login to your solid ' - 'server hosting your pod.', - child: ElevatedButton( - child: - const Text('Forget Remote Solid Server Login'), - onPressed: () async { - final deleteRes = await deleteLogIn(); - - var deleteMsg = ''; - - if (deleteRes) { - deleteMsg = - 'Successfully forgot remote solid server login info'; - } else { - deleteMsg = - 'Failed to forget login info. Try again in a while'; - } - - await showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('Notice'), - content: Text(deleteMsg), - actions: [ - ElevatedButton( - onPressed: () { - Navigator.pop(context); - }, - child: const Text('OK')) - ], - ), - ); - - _resetWebId(); - }, - ), - ), - smallGapV, - MarkdownTooltip( - message: - 'This will send a request through the browser to the ' - 'remote solid server to log you out of your Pod.', - child: ElevatedButton( - onPressed: () async { - await logoutPopup(context, const DemoPod()); - }, - child: - const Text('Logout From Remote Solid Server'), - ), - ), - largeGapV, - const Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Resource Permission Management', - style: TextStyle( - fontSize: 22, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - ElevatedButton( - child: const Text( - 'Add/Delete Permissions from a Specific Resource (key-value.ttl)'), - onPressed: () async { - final loggedIn = await loginIfRequired( - context, - ); - - if (loggedIn) { - await getKeyFromUserIfRequired(context, widget); - - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const GrantPermissionUi( - backgroundColor: titleBackgroundColor, - resourceName: 'keyvalue/key-value.ttl', - // accessModeList: ['read', 'write'], - // recipientTypeList: ['indi', 'group'], - // isFile: false, - child: Home(), - ), - ), - ); - } - }, - ), - smallGapV, - ElevatedButton( - child: const Text('Permission Callback Demo'), - onPressed: () async { - final loggedIn = await loginIfRequired( - context, - ); - - if (loggedIn) { - await getKeyFromUserIfRequired(context, widget); - - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - const PermissionCallbackDemo( - child: Home(), - ), - ), - ); - } - }, - ), - smallGapV, - ElevatedButton( - child: const Text( - 'Add/Delete Permissions from any Resource'), - onPressed: () async { - final loggedIn = await loginIfRequired( - context, - ); - - if (loggedIn) { - await getKeyFromUserIfRequired(context, widget); - - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const GrantPermissionUi( - backgroundColor: titleBackgroundColor, - child: Home(), - ), - ), - ); - } - }, - ), - largeGapV, - const Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Manage External Resources with Access', - style: TextStyle( - fontSize: 22, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - ElevatedButton( - child: const Text( - 'View specific resource (key-value.ttl) your WebID has access to'), - onPressed: () async { - final loggedIn = await loginIfRequired( - context, - ); - - if (loggedIn) { - await getKeyFromUserIfRequired(context, widget); - - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const SharedResourcesUi( - backgroundColor: titleBackgroundColor, - fileName: 'key-value.ttl', - child: Home(), - ), - ), - ); - } - }, - ), - smallGapV, - ElevatedButton( - child: const Text( - 'View ALL Resources your WebID has access to'), - onPressed: () async { - final loggedIn = await loginIfRequired( - context, - ); - - if (loggedIn) { - await getKeyFromUserIfRequired(context, widget); - - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const SharedResourcesUi( - backgroundColor: titleBackgroundColor, - child: Home(), - ), - ), - ); - } - }, + ...buildLoginManagementSection( + context, + _resetWebId, + () => const DemoPod(), ), - smallGapV, - largeGapV, - const Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Setup Wizard Demo', - style: TextStyle( - fontSize: 22, - fontWeight: FontWeight.bold, - ), - ), - ], + ...buildPermissionSection( + context, + widget, + () => const Home(), ), - smallGapV, - ElevatedButton( - onPressed: () async { - // Now that the back button issue is fixed in InitialSetupScreenBody, - // we can use it directly without any custom wrapper. - - final loggedIn = await loginIfRequired(context); - - if (!loggedIn) { - debugPrint('Please login to run the demo'); - return; - } - - final webId = await getWebId(); - if (webId == null) { - debugPrint('web ID is not available'); - return; - } - - final sampleDirUrl = await getDirUrl([ - await getDataDirPath(), - 'setup_wizard_demo', - ].join('/')); - final sampleFileName = 'setup_wizard_demo.ttl'; - final sampleFileUrl = await getFileUrl([ - await getDataDirPath(), - 'sampleFileName', - ].join('/')); - - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => Scaffold( - body: SafeArea( - child: InitialSetupScreenBody( - // Sample resources that would need to be created. - - resNeedToCreate: { - 'folders': [sampleDirUrl], - 'files': [sampleFileUrl], - 'fileNames': [sampleFileName], - }, - child: const Home(), - ), - ), - ), - ), - ); - }, - child: const Text( - 'Show Solid Pod Setup Wizard (Using Real Component)'), + ...buildSetupWizardSection( + context, + () => const Home(), ), - smallGapV, ], ), ), diff --git a/example/lib/widgets/file_service_sections.dart b/example/lib/widgets/file_service_sections.dart new file mode 100644 index 00000000..302155e1 --- /dev/null +++ b/example/lib/widgets/file_service_sections.dart @@ -0,0 +1,284 @@ +/// Extracted UI sections for the FileService screen. +/// +/// Copyright (C) 2024, 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: Dawei Chen + +library; + +import 'package:flutter/material.dart'; + +/// Builds a progress bar showing operation status. + +Widget buildProgressBar(String message, bool isDone, double percent) { + const smallGapH = SizedBox(width: 10); + const textStyle = TextStyle( + color: Colors.green, + fontWeight: FontWeight.bold, + ); + + final prefix = Text(message, style: textStyle); + final suffix = Text('${(percent * 100).toInt()}%', style: textStyle); + final progress = SizedBox( + width: 300, + height: 10, + child: LinearProgressIndicator( + value: percent, + minHeight: 2, + backgroundColor: Colors.black12, + color: Colors.greenAccent, + ), + ); + + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [prefix, smallGapH, progress, smallGapH, suffix], + ); +} + +/// Builds the upload section UI. + +List buildUploadSectionUI({ + required String defaultRemoteFileName, + required String? uploadFile, + required bool uploadDone, + required bool uploadInProgress, + required TextEditingController remoteFolderController, + required TextEditingController keyRefFolderController, + required Widget browseButton, + required Widget uploadButton, +}) { + const smallGapH = SizedBox(width: 10); + const smallGapV = SizedBox(height: 10); + + return [ + Text( + 'Upload a local large file and save it as "$defaultRemoteFileName" in POD', + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + smallGapV, + Table( + columnWidths: const { + 0: FixedColumnWidth(450), + }, + children: [ + TableRow( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + uploadFile ?? + 'Click the Browse button to choose a local file', + style: TextStyle( + color: uploadFile == null ? Colors.red : Colors.blue, + fontStyle: FontStyle.italic, + fontSize: 16, + ), + ), + smallGapH, + if (uploadDone) const Icon(Icons.done, color: Colors.green), + ], + ), + ], + ), + TableRow( + children: [ + TextFormField( + controller: remoteFolderController, + enabled: !(uploadInProgress || uploadDone), + decoration: const InputDecoration( + hintText: + '(Optional) save to folder in POD, e.g. dir1/dir2/', + hintStyle: TextStyle( + color: Colors.brown, + fontStyle: FontStyle.italic, + fontSize: 15, + ), + ), + ), + ], + ), + TableRow(children: [ + TextFormField( + controller: keyRefFolderController, + enabled: !(uploadInProgress || uploadDone), + decoration: const InputDecoration( + hintText: + '(Optional) Inherit encryption key of folder in POD, e.g. dir1/', + hintStyle: TextStyle( + color: Colors.brown, + fontStyle: FontStyle.italic, + fontSize: 15, + ), + ), + ), + ]), + ], + ), + smallGapV, + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + browseButton, + smallGapH, + uploadButton, + ], + ), + ]; +} + +/// Builds the download section UI. + +List buildDownloadSectionUI({ + required String defaultRemoteFileName, + required String? downloadFile, + required bool downloadDone, + required Widget downloadButton, +}) { + const smallGapH = SizedBox(width: 10); + const smallGapV = SizedBox(height: 10); + + return [ + Text( + 'Download the "$defaultRemoteFileName" from POD', + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + smallGapV, + if (downloadFile != null) + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Save file'), + smallGapH, + Text( + downloadFile, + style: const TextStyle(color: Colors.blue), + ), + smallGapH, + if (downloadDone) const Icon(Icons.done, color: Colors.green), + ], + ), + smallGapV, + downloadButton, + ]; +} + +/// Builds the delete section UI. + +List buildDeleteSectionUI({ + required String defaultRemoteFileName, + required bool deleteInProgress, + required bool deleteDone, + required Widget deleteButton, +}) { + const smallGapH = SizedBox(width: 10); + const smallGapV = SizedBox(height: 10); + + return [ + Text( + 'Delete the "$defaultRemoteFileName" from POD', + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + smallGapV, + if (deleteInProgress || deleteDone) + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Delete remote file'), + smallGapH, + Text( + defaultRemoteFileName, + style: const TextStyle(color: Colors.blue), + ), + smallGapH, + if (deleteDone) const Icon(Icons.done, color: Colors.green), + ], + ), + smallGapV, + deleteButton, + ]; +} + +/// Builds the download shared file section UI. + +List buildDownloadSharedSectionUI({ + required String? downloadSharedFile, + required bool downloadSharedDone, + required bool downloadSharedInProgress, + required TextEditingController sharedUrlController, + required Widget downloadSharedButton, +}) { + const smallGapH = SizedBox(width: 10); + const smallGapV = SizedBox(height: 10); + + return [ + const Text( + 'Download a shared large file from an external POD', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + smallGapV, + SizedBox( + width: 550, + child: TextFormField( + controller: sharedUrlController, + enabled: !(downloadSharedInProgress || downloadSharedDone), + decoration: const InputDecoration( + hintText: 'URL of shared large file in external POD', + hintStyle: TextStyle( + color: Colors.brown, + fontStyle: FontStyle.italic, + fontSize: 15, + ), + ), + ), + ), + smallGapV, + if (downloadSharedFile != null) + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Save file'), + smallGapH, + Text( + downloadSharedFile, + style: const TextStyle(color: Colors.blue), + ), + smallGapH, + if (downloadSharedDone) + const Icon(Icons.done, color: Colors.green), + ], + ), + smallGapV, + downloadSharedButton, + ]; +} diff --git a/example/lib/widgets/home_sections.dart b/example/lib/widgets/home_sections.dart new file mode 100644 index 00000000..46b1a80f --- /dev/null +++ b/example/lib/widgets/home_sections.dart @@ -0,0 +1,347 @@ +/// Extracted section widgets for the Home screen. +/// +/// Copyright (C) 2024, 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: Dawei Chen + +// ignore_for_file: use_build_context_synchronously + +library; + +import 'package:flutter/material.dart'; + +import 'package:markdown_tooltip/markdown_tooltip.dart'; +import 'package:solidpod/solidpod.dart'; +import 'package:solidui/solidui.dart' + show + GrantPermissionUi, + InitialSetupScreenBody, + SharedResourcesUi, + getKeyFromUserIfRequired, + loginIfRequired, + logoutPopup, + largeGapV, + smallGapV; + +import 'package:demopod/constants/app.dart'; +import 'package:demopod/features/permission_callback_demo.dart'; + +/// Builds the login management section widgets. + +List buildLoginManagementSection( + BuildContext context, + VoidCallback onResetWebId, + Widget Function() createDemoPod, +) { + return [ + largeGapV, + const Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Solid Server Login Management', + style: TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + MarkdownTooltip( + message: 'This will remove from our local device\'s memory the ' + 'solid pod login information so that the next time you ' + 'start up the app you will need to login to your solid ' + 'server hosting your pod.', + child: ElevatedButton( + child: const Text('Forget Remote Solid Server Login'), + onPressed: () async { + final deleteRes = await deleteLogIn(); + + var deleteMsg = ''; + + if (deleteRes) { + deleteMsg = + 'Successfully forgot remote solid server login info'; + } else { + deleteMsg = + 'Failed to forget login info. Try again in a while'; + } + + await showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Notice'), + content: Text(deleteMsg), + actions: [ + ElevatedButton( + onPressed: () { + Navigator.pop(context); + }, + child: const Text('OK')) + ], + ), + ); + + onResetWebId(); + }, + ), + ), + smallGapV, + MarkdownTooltip( + message: 'This will send a request through the browser to the ' + 'remote solid server to log you out of your Pod.', + child: ElevatedButton( + onPressed: () async { + await logoutPopup(context, createDemoPod()); + }, + child: const Text('Logout From Remote Solid Server'), + ), + ), + ]; +} + +/// Builds the permission management and external resources section widgets. + +List buildPermissionSection( + BuildContext context, + Widget currentWidget, + Widget Function() createHomeWidget, +) { + return [ + largeGapV, + const Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Resource Permission Management', + style: TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ElevatedButton( + child: const Text( + 'Add/Delete Permissions from a Specific Resource (key-value.ttl)'), + onPressed: () async { + final loggedIn = await loginIfRequired( + context, + ); + + if (loggedIn) { + await getKeyFromUserIfRequired(context, currentWidget); + + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => GrantPermissionUi( + backgroundColor: titleBackgroundColor, + resourceName: 'keyvalue/key-value.ttl', + // accessModeList: ['read', 'write'], + // recipientTypeList: ['indi', 'group'], + // isFile: false, + child: createHomeWidget(), + ), + ), + ); + } + }, + ), + smallGapV, + ElevatedButton( + child: const Text('Permission Callback Demo'), + onPressed: () async { + final loggedIn = await loginIfRequired( + context, + ); + + if (loggedIn) { + await getKeyFromUserIfRequired(context, currentWidget); + + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + PermissionCallbackDemo(child: createHomeWidget()), + ), + ); + } + }, + ), + smallGapV, + ElevatedButton( + child: const Text( + 'Add/Delete Permissions from any Resource'), + onPressed: () async { + final loggedIn = await loginIfRequired( + context, + ); + + if (loggedIn) { + await getKeyFromUserIfRequired(context, currentWidget); + + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => GrantPermissionUi( + backgroundColor: titleBackgroundColor, + child: createHomeWidget(), + ), + ), + ); + } + }, + ), + largeGapV, + const Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Manage External Resources with Access', + style: TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ElevatedButton( + child: const Text( + 'View specific resource (key-value.ttl) your WebID has access to'), + onPressed: () async { + final loggedIn = await loginIfRequired( + context, + ); + + if (loggedIn) { + await getKeyFromUserIfRequired(context, currentWidget); + + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SharedResourcesUi( + backgroundColor: titleBackgroundColor, + fileName: 'key-value.ttl', + child: createHomeWidget(), + ), + ), + ); + } + }, + ), + smallGapV, + ElevatedButton( + child: const Text( + 'View ALL Resources your WebID has access to'), + onPressed: () async { + final loggedIn = await loginIfRequired( + context, + ); + + if (loggedIn) { + await getKeyFromUserIfRequired(context, currentWidget); + + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SharedResourcesUi( + backgroundColor: titleBackgroundColor, + child: createHomeWidget(), + ), + ), + ); + } + }, + ), + smallGapV, + ]; +} + +/// Builds the setup wizard section widgets. + +List buildSetupWizardSection( + BuildContext context, + Widget Function() createHomeWidget, +) { + return [ + largeGapV, + const Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Setup Wizard Demo', + style: TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + smallGapV, + ElevatedButton( + onPressed: () async { + final loggedIn = await loginIfRequired(context); + + if (!loggedIn) { + debugPrint('Please login to run the demo'); + return; + } + + final webId = await getWebId(); + if (webId == null) { + debugPrint('web ID is not available'); + return; + } + + final sampleDirUrl = await getDirUrl([ + await getDataDirPath(), + 'setup_wizard_demo', + ].join('/')); + final sampleFileName = 'setup_wizard_demo.ttl'; + final sampleFileUrl = await getFileUrl([ + await getDataDirPath(), + 'sampleFileName', + ].join('/')); + + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => Scaffold( + body: SafeArea( + child: InitialSetupScreenBody( + resNeedToCreate: { + 'folders': [sampleDirUrl], + 'files': [sampleFileUrl], + 'fileNames': [sampleFileName], + }, + child: createHomeWidget(), + ), + ), + ), + ), + ); + }, + child: const Text( + 'Show Solid Pod Setup Wizard (Using Real Component)'), + ), + smallGapV, + ]; +} diff --git a/example/lib/widgets/permission_demo_widgets.dart b/example/lib/widgets/permission_demo_widgets.dart new file mode 100644 index 00000000..c176c0ff --- /dev/null +++ b/example/lib/widgets/permission_demo_widgets.dart @@ -0,0 +1,114 @@ +/// Extracted widgets for the Permission Callback Demo screen. +/// +/// Copyright (C) 2025, 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: Dawei Chen + +library; + +import 'package:flutter/material.dart'; + +/// Builds a step indicator for the workflow progress display. + +Widget buildStepIndicator(int step, String label, bool isActive) { + return Column( + children: [ + Container( + width: 32, + height: 32, + decoration: BoxDecoration( + color: isActive ? Colors.blue[600] : Colors.grey[300], + shape: BoxShape.circle, + ), + child: Center( + child: Text( + step.toString(), + style: TextStyle( + color: isActive ? Colors.white : Colors.grey[600], + fontWeight: FontWeight.bold, + fontSize: 14, + ), + ), + ), + ), + const SizedBox(height: 4), + Text( + label, + style: TextStyle( + fontSize: 12, + color: isActive ? Colors.blue[600] : Colors.grey[600], + fontWeight: isActive ? FontWeight.w600 : FontWeight.normal, + ), + ), + ], + ); +} + +/// Builds a connector line between step indicators. + +Widget buildStepConnector(bool isActive) { + return Container( + width: 24, + height: 2, + margin: const EdgeInsets.only(bottom: 20), + color: isActive ? Colors.blue[600] : Colors.grey[300], + ); +} + +/// Builds the header section explaining the demo purpose. + +Widget buildDemoHeaderSection() { + return Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: Colors.blue[50], + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.blue[200]!), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon(Icons.lightbulb_outline, + color: Colors.blue[700], size: 28), + const SizedBox(width: 12), + const Text( + 'Why Use onPermissionGranted Callback?', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), + ), + ], + ), + const SizedBox(height: 12), + const Text( + 'The onPermissionGranted callback allows your app to automatically ' + 'continue workflows after users grant permissions. This demo creates ' + 'sample files automatically and shows how to share multiple files ' + 'sequentially without manual navigation.', + style: TextStyle(fontSize: 16, height: 1.4), + ), + ], + ), + ); +} From 9f3c0722b44be4e117e6e14e5b2a58ab8ab89cf1 Mon Sep 17 00:00:00 2001 From: Tony Chen Date: Thu, 19 Mar 2026 16:45:00 +1100 Subject: [PATCH 3/3] Lint --- example/lib/features/file_service.dart | 7 +++---- .../lib/features/permission_callback_demo.dart | 1 - example/lib/widgets/file_service_sections.dart | 6 ++---- example/lib/widgets/home_sections.dart | 15 +++++---------- example/lib/widgets/permission_demo_widgets.dart | 3 +-- 5 files changed, 11 insertions(+), 21 deletions(-) diff --git a/example/lib/features/file_service.dart b/example/lib/features/file_service.dart index ea7927d1..1b3143cd 100644 --- a/example/lib/features/file_service.dart +++ b/example/lib/features/file_service.dart @@ -414,8 +414,8 @@ class _FileServiceState extends State { top: 20, left: 0, right: 0, - child: buildProgressBar( - 'Uploading:', uploadDone, uploadPercent), + child: + buildProgressBar('Uploading:', uploadDone, uploadPercent), ), // Downloading progress bar @@ -447,8 +447,7 @@ class _FileServiceState extends State { top: 20, left: 0, right: 0, - child: buildProgressBar( - 'Deleting:', deleteDone, deletePercent), + child: buildProgressBar('Deleting:', deleteDone, deletePercent), ), // Navigate back to demo page diff --git a/example/lib/features/permission_callback_demo.dart b/example/lib/features/permission_callback_demo.dart index 008bcc34..5acd816a 100644 --- a/example/lib/features/permission_callback_demo.dart +++ b/example/lib/features/permission_callback_demo.dart @@ -551,5 +551,4 @@ demo:exampleData$fileNumber ), ); } - } diff --git a/example/lib/widgets/file_service_sections.dart b/example/lib/widgets/file_service_sections.dart index 302155e1..b3ee937a 100644 --- a/example/lib/widgets/file_service_sections.dart +++ b/example/lib/widgets/file_service_sections.dart @@ -108,8 +108,7 @@ List buildUploadSectionUI({ controller: remoteFolderController, enabled: !(uploadInProgress || uploadDone), decoration: const InputDecoration( - hintText: - '(Optional) save to folder in POD, e.g. dir1/dir2/', + hintText: '(Optional) save to folder in POD, e.g. dir1/dir2/', hintStyle: TextStyle( color: Colors.brown, fontStyle: FontStyle.italic, @@ -274,8 +273,7 @@ List buildDownloadSharedSectionUI({ style: const TextStyle(color: Colors.blue), ), smallGapH, - if (downloadSharedDone) - const Icon(Icons.done, color: Colors.green), + if (downloadSharedDone) const Icon(Icons.done, color: Colors.green), ], ), smallGapV, diff --git a/example/lib/widgets/home_sections.dart b/example/lib/widgets/home_sections.dart index 46b1a80f..1c42fc3c 100644 --- a/example/lib/widgets/home_sections.dart +++ b/example/lib/widgets/home_sections.dart @@ -77,11 +77,9 @@ List buildLoginManagementSection( var deleteMsg = ''; if (deleteRes) { - deleteMsg = - 'Successfully forgot remote solid server login info'; + deleteMsg = 'Successfully forgot remote solid server login info'; } else { - deleteMsg = - 'Failed to forget login info. Try again in a while'; + deleteMsg = 'Failed to forget login info. Try again in a while'; } await showDialog( @@ -188,8 +186,7 @@ List buildPermissionSection( ), smallGapV, ElevatedButton( - child: const Text( - 'Add/Delete Permissions from any Resource'), + child: const Text('Add/Delete Permissions from any Resource'), onPressed: () async { final loggedIn = await loginIfRequired( context, @@ -249,8 +246,7 @@ List buildPermissionSection( ), smallGapV, ElevatedButton( - child: const Text( - 'View ALL Resources your WebID has access to'), + child: const Text('View ALL Resources your WebID has access to'), onPressed: () async { final loggedIn = await loginIfRequired( context, @@ -339,8 +335,7 @@ List buildSetupWizardSection( ), ); }, - child: const Text( - 'Show Solid Pod Setup Wizard (Using Real Component)'), + child: const Text('Show Solid Pod Setup Wizard (Using Real Component)'), ), smallGapV, ]; diff --git a/example/lib/widgets/permission_demo_widgets.dart b/example/lib/widgets/permission_demo_widgets.dart index c176c0ff..517b549d 100644 --- a/example/lib/widgets/permission_demo_widgets.dart +++ b/example/lib/widgets/permission_demo_widgets.dart @@ -87,8 +87,7 @@ Widget buildDemoHeaderSection() { children: [ Row( children: [ - Icon(Icons.lightbulb_outline, - color: Colors.blue[700], size: 28), + Icon(Icons.lightbulb_outline, color: Colors.blue[700], size: 28), const SizedBox(width: 12), const Text( 'Why Use onPermissionGranted Callback?',