diff --git a/example/lib/home.dart b/example/lib/home.dart index fe9e3518..7c9fe9eb 100644 --- a/example/lib/home.dart +++ b/example/lib/home.dart @@ -32,6 +32,19 @@ 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 + InitialSetupScreenBody, + loginIfRequired, + logoutPopup, + getKeyFromUserIfRequired, + changeKeyPopup, + smallGapV, + largeGapV; + import 'package:demopod/constants/app.dart'; import 'package:demopod/dialogs/about.dart'; import 'package:demopod/dialogs/alert.dart'; @@ -43,16 +56,6 @@ 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:intl/intl.dart'; -import 'package:markdown_tooltip/markdown_tooltip.dart'; -import 'package:solidui/solidui.dart' - show - InitialSetupScreenBody, - loginIfRequired, - logoutPopup, - getKeyFromUserIfRequired; - -import 'package:solidpod/solidpod.dart'; /// A widget for the demonstration screen of the application. @@ -284,11 +287,6 @@ class HomeState extends State with SingleTickerProviderStateMixin { final dateStr = DateFormat('HH:mm:ss dd MMMM yyyy').format(DateTime.now()); - // Some vertical spacing for the widget. - - const smallGapV = SizedBox(height: 10.0); - const largeGapV = SizedBox(height: 40.0); - // A small horizontal spacing for the widget. const smallGapH = SizedBox(width: 10.0); diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 1aad89b1..880f3d3e 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -25,7 +25,7 @@ dependency_overrides: solidui: git: url: https://github.com/anusii/solidui - ref: dev + ref: tony/186_migration dev_dependencies: flutter_lints: ^6.0.0 diff --git a/lib/solidpod.dart b/lib/solidpod.dart index a68bf8a4..f759e189 100644 --- a/lib/solidpod.dart +++ b/lib/solidpod.dart @@ -32,13 +32,20 @@ library; /// Organized constants structure to avoid name conflicts. /// Use `SolidConstants.namespaces.foaf`, `SolidConstants.directories.data`, etc. + export 'src/solid/constants/solid_constants.dart'; // Legacy exports for backward compatibility (deprecated, use SolidConstants instead) + export 'src/solid/constants/common.dart' show foaf, terms, ResourceStatus; export 'src/solid/constants/schema.dart' show appsTerms; export 'src/solid/constants/path_type.dart' show PathType; +/// Common RDF predicates for Linked Data operations. +/// Includes predicates for RDF, FOAF, ACL, VCard, Dublin Core Terms, and XSD. + +export 'src/solid/constants/predicates.dart'; + /// Solid authentication function export 'src/solid/authenticate.dart' show solidAuthenticate; @@ -62,11 +69,6 @@ export 'src/solid/solid_func_call_status.dart' show SolidFunctionCallStatus; export 'src/solid/common_func.dart' show checkPodInitialization, deleteDataFileDialog; -/// Security UI constants including SecurityStrings, SecurityColors, etc. - -export 'src/solid/constants/ui.dart' - show SecurityStrings, SecurityColors, SecurityTextStyles, SecurityLayout; - /// Includes the AppInfo class which stores app specific information /// such as name, version, canonical name, package name, build number. @@ -135,14 +137,6 @@ export 'src/solid/utils/get_url_helper.dart' export 'src/solid/utils/init_helper.dart' show generateDefaultFolders, generateCustomFolders, generateDefaultFiles; -/// Change security key popup widget - -export 'src/widgets/change_key_dialog.dart'; - -/// Security key UI widget for prompting and displaying security key dialogs - -export 'src/widgets/security_key_ui.dart'; - /// Read encrypted/non-encrypted files stored in a POD export 'src/solid/read_pod.dart'; @@ -231,3 +225,6 @@ export 'src/solid/get_resources.dart'; /// 20250917 gjw Extras that were required for the example app! Not yet /// documented. + +export 'package:solidui/solidui.dart' + show SecurityKeyUI, SecurityStrings, changeKeyPopup; diff --git a/lib/src/solid/constants/ui.dart b/lib/src/solid/constants/ui.dart deleted file mode 100644 index c1a76900..00000000 --- a/lib/src/solid/constants/ui.dart +++ /dev/null @@ -1,635 +0,0 @@ -/// Constants used for UI elements across the package. -/// -/// Copyright (C) 2024, Software Innovation Institute, ANU. -/// -/// Licensed under the MIT License (the "License"). -/// -/// License: https://choosealicense.com/licenses/mit/. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -/// -/// Authors: Ashley Tang, Jess Moore - -library; - -import 'package:flutter/material.dart'; - -import 'package:solidpod/src/solid/utils/heading.dart'; - -/// Thresholds for window size -class WindowSize { - /// Small width threshold - static const double smallWidthLimit = 600; - - /// Small height threshold - static const double smallHeightLimit = 600; - - /// Boolean describing whether the parent widget - /// is narrow. Derived from the box constraints - /// found by LayoutBuilder(). - /// - /// Arguments: - /// - [constraints] - The box constraints of the parent widget where LayoutBuilder() called. - bool isNarrowWindow(BoxConstraints constraints) { - final bool isNarrow; - if (constraints.maxWidth < WindowSize.smallWidthLimit) { - isNarrow = true; - } else { - isNarrow = false; - } - - return isNarrow; - } -} - -/// Approximate size for grid items used for -/// displaying text in list item. - -class ListItemSize { - /// Approximate height of compressed item - /// in list - /// when list item text is line wrapped - /// in a narrow mobile phone size window. - /// (Where each of note title, created date time, - /// modified date time are line wrapped to - /// two lines.) - - static const double compressedItemHeight = - 260; // (4 row subtitle) 190; (wrapped 4 row subtitle) - - /// Approximate height of uncompressed item - /// in list - /// when list item text is not line wrapped. - - static const double uncompressedItemHeight = - 138; // (4 row subtitle) 108; (3 row subtitle) - - /// Calculate card aspect ratio to use for - /// gridview builder cards using the box - /// constraints found by LayoutBuilder(). - /// - /// Arguments: - /// - [constraints] - The box constraints of the parent widget - /// where LayoutBuilder() called. - - double calculateCardAspectRatio(BoxConstraints constraints) { - /// Aspect ratio (width / height) for gridview - /// cards to display note items - final double cardAspectRatio; - - // Derive card aspect ratio (width / height) - if (constraints.maxWidth < WindowSize.smallWidthLimit) { - cardAspectRatio = constraints.maxWidth / compressedItemHeight; - } else { - cardAspectRatio = constraints.maxWidth / uncompressedItemHeight; - } - return cardAspectRatio; - } -} - -/// Class for icon sizing in list items - -class ListIconSize { - static const double width = 50; - static const double height = 50; - static const double twoIconWidth = (width * 2) + gap; - static const double gap = 15; -} - -/// Icon shape decoration for list items -ShapeDecoration listIconShape = - const ShapeDecoration(color: Colors.grey, shape: CircleBorder()); - -// Standard colours for actions and results. - -class ActionColors { - /// Green colour used for success - - static const success = Colors.green; - - // Red colour used for error/failure - - static const error = Colors.red; - - // Colour used for warning - - static const warning = Color.fromARGB(255, 204, 99, 1); - - // Red colour used for delete action - - static const delete = Colors.red; -} - -/// Colours used across security dialogs and prompts. - -class SecurityColors { - /// Primary colour (Forest Green) used for headings and important elements. - - static const primary = Color(0xFF2E7D32); - - /// Primary colour for dark mode (lighter green for better contrast). - - static const primaryDark = Color(0xFF66BB6A); - - /// Accent colour (Lighter Green) used for dividers and secondary elements. - - static const accent = Color(0xFF4CAF50); - - /// Accent colour for dark mode. - - static const accentDark = Color(0xFF81C784); - - /// Background colour (Light Grey) used for dialog backgrounds. - - static const background = Color(0xFFF5F5F5); - - /// Background colour for dark mode. - - static const backgroundDark = Color(0xFF1E1E1E); - - /// Text colour (Dark Grey) used for main text content. - - static const text = Color(0xFF212121); - - /// Text colour for dark mode. - - static const textDark = Color(0xFFE0E0E0); - - /// Grey colour used for labels and secondary text. - - static const labelGrey = Colors.grey; - - /// Label colour for dark mode. - - static const labelGreyDark = Color(0xFF9E9E9E); - - /// Card background colour for light mode. - - static const cardBackground = Colors.white; - - /// Card background colour for dark mode. - - static const cardBackgroundDark = Color(0xFF2D2D2D); - - /// Separator colour for light mode. - - static const separator = Color(0xFFE0E0E0); - - /// Separator colour for dark mode. - - static const separatorDark = Color(0xFF424242); -} - -/// Helper class to obtain theme-aware colours for security UI components. -/// -/// This class provides methods that return appropriate colours based on the -/// current theme brightness (light or dark mode). - -class SecurityThemeColors { - /// Returns the primary colour based on the current theme. - - static Color primary(BuildContext context) { - final isDark = Theme.of(context).brightness == Brightness.dark; - return isDark ? SecurityColors.primaryDark : SecurityColors.primary; - } - - /// Returns the accent colour based on the current theme. - - static Color accent(BuildContext context) { - final isDark = Theme.of(context).brightness == Brightness.dark; - return isDark ? SecurityColors.accentDark : SecurityColors.accent; - } - - /// Returns the background colour based on the current theme. - - static Color background(BuildContext context) { - final isDark = Theme.of(context).brightness == Brightness.dark; - return isDark ? SecurityColors.backgroundDark : SecurityColors.background; - } - - /// Returns the text colour based on the current theme. - - static Color text(BuildContext context) { - final isDark = Theme.of(context).brightness == Brightness.dark; - return isDark ? SecurityColors.textDark : SecurityColors.text; - } - - /// Returns the label grey colour based on the current theme. - - static Color labelGrey(BuildContext context) { - final isDark = Theme.of(context).brightness == Brightness.dark; - return isDark ? SecurityColors.labelGreyDark : SecurityColors.labelGrey; - } - - /// Returns the card background colour based on the current theme. - - static Color cardBackground(BuildContext context) { - final isDark = Theme.of(context).brightness == Brightness.dark; - return isDark - ? SecurityColors.cardBackgroundDark - : SecurityColors.cardBackground; - } - - /// Returns the separator colour based on the current theme. - - static Color separator(BuildContext context) { - final isDark = Theme.of(context).brightness == Brightness.dark; - return isDark ? SecurityColors.separatorDark : SecurityColors.separator; - } -} - -/// Text styles used across security dialogs and prompts. - -class SecurityTextStyles { - /// Style for main headings (e.g. "Security Key"). - - static const heading = TextStyle( - fontSize: 22, - fontWeight: FontWeight.bold, - color: SecurityColors.primary, - ); - - /// Style for regular text content. - - static const body = TextStyle( - fontSize: 15, - color: SecurityColors.text, - ); - - /// Style for the WebID display. - - static const webId = TextStyle( - fontSize: 13, - fontWeight: FontWeight.w500, - ); - - /// Style for the "Currently logged in as:" label. - - static const label = TextStyle( - fontSize: 13, - color: SecurityColors.labelGrey, - ); - - /// Style for button text. - - static const button = TextStyle( - fontSize: 14, - color: Colors.white, - ); -} - -/// Helper class to obtain theme-aware text styles for security UI components. - -class SecurityThemeTextStyles { - /// Returns the heading style based on the current theme. - - static TextStyle heading(BuildContext context) { - return TextStyle( - fontSize: 22, - fontWeight: FontWeight.bold, - color: SecurityThemeColors.primary(context), - ); - } - - /// Returns the body text style based on the current theme. - - static TextStyle body(BuildContext context) { - return TextStyle( - fontSize: 15, - color: SecurityThemeColors.text(context), - ); - } - - /// Returns the WebID style based on the current theme. - - static TextStyle webId(BuildContext context, {bool isLoggedIn = true}) { - return TextStyle( - fontSize: 13, - fontWeight: FontWeight.w500, - color: isLoggedIn ? SecurityThemeColors.primary(context) : Colors.red, - ); - } - - /// Returns the label style based on the current theme. - - static TextStyle label(BuildContext context) { - return TextStyle( - fontSize: 13, - color: SecurityThemeColors.labelGrey(context), - ); - } - - /// Returns the button text style. - - static const button = TextStyle( - fontSize: 14, - color: Colors.white, - ); - - /// Returns the cancel button style based on the current theme. - - static TextStyle cancelButton(BuildContext context) { - return TextStyle( - fontSize: 14, - color: SecurityThemeColors.text(context), - ); - } -} - -/// Layout constants used across security dialogs and prompts. - -class SecurityLayout { - /// Horizontal gap between elements. - - static const horizontalGap = SizedBox(width: 16); - - /// Standard padding for dialog content. - - static const contentPadding = EdgeInsets.all(20); - - /// Padding for form sections. - - static const formPadding = EdgeInsets.fromLTRB(20, 20, 20, 8); - - /// Padding for button sections. - - static const buttonsPadding = EdgeInsets.fromLTRB(20, 8, 20, 20); - - /// Margin for green divider under heading. - - static const dividerMargin = EdgeInsets.only(top: 4, bottom: 14); - - /// Padding for WebID display. - - static const webIdPadding = EdgeInsets.only(top: 4, bottom: 20); - - /// Input field spacing. - - static const inputFieldSpacing = EdgeInsets.only(bottom: 16); - - /// Button padding. - - static const buttonPadding = - EdgeInsets.symmetric(horizontal: 16, vertical: 10); - - /// Standard width for security dialogs. - - static const dialogWidth = 480.0; - - /// Maximum width constraint for security dialogs. - - static const maxDialogWidth = 500.0; - - /// Border radius for cards and buttons. - - static const borderRadius = 8.0; - - /// Border radius for buttons. - - static const buttonRadius = 6.0; - - /// Height for divider lines. - - static const dividerHeight = 1.5; - - /// Height for separator lines. - - static const separatorHeight = 1.0; -} - -/// Common text strings used across security dialogs and prompts. - -class SecurityStrings { - /// Label for the WebID display. - - static const webIdLabel = 'Currently logged in as:'; - - /// Label for not logged in state. - - static const notLoggedIn = 'Not logged in'; - - /// Security key input prompt. - - static const securityKeyPrompt = - 'Please enter the security key you previously provided for securing your data.'; - - /// Submit button text. - - static const submit = 'Submit'; - - /// Cancel button text. - - static const cancel = 'Cancel'; -} - -/// Small vertical spacing for the widget. -const smallGapV = SizedBox(height: 10.0); - -/// Large vertical spacing for the widget. -const largeGapV = SizedBox(height: 40.0); - -/// Normal height for data loading screens -const double normalLoadingScreenHeight = 200.0; - -/// Text styles used for permission form - -class RecipientTextStyle { - /// Style for the label. - - static const label = TextStyle( - fontSize: 15, - fontWeight: FontWeight.w500, - ); - - /// Style for the WebID display. - - static const webId = TextStyle( - fontSize: 15, - fontWeight: FontWeight.w600, - // 20251008 gjw Choose blue rather than - // orange which looks red. The red looks - // like it is an error. Blue is more - // neutral. - color: Colors.blueAccent, - ); -} - -/// Layout constants for sub headings - -class SubHeadingStyle { - /// Fontsize - - static const double fontsize = 17.0; - - /// Font color - - static const Color fontcolor = Color.fromRGBO(96, 125, 139, 1); - - /// Font weight - - static const FontWeight fontweight = FontWeight.bold; - - /// Padding - - static const double padding = 8.0; -} - -/// Layout constants for sub headings - -class HeadingStyle { - /// Fontsize - - static const double fontsize = 22.0; - - /// Font color - - static const Color fontcolor = Color.fromRGBO(96, 125, 139, 1); - - /// Font weight - - static const FontWeight fontweight = FontWeight.bold; - - /// Padding - - static const double padding = 8.0; -} - -/// Make sub heading using SubHeadingStyle as default - -Widget makeSubHeading( - String text, { - bool bold = true, - bool addColor = true, - bool addPadding = true, -}) => - buildHeading( - text: text, - fontSize: SubHeadingStyle.fontsize, - fontWeight: (bold) ? SubHeadingStyle.fontweight : FontWeight.normal, - color: (addColor) ? SubHeadingStyle.fontcolor : Colors.black, - padding: (addPadding) ? SubHeadingStyle.padding : 0, - ); - -/// Make heading using HeadingStyle as default - -Widget makeHeading( - String text, { - bool bold = true, - bool addColor = true, - bool addPadding = true, -}) => - buildHeading( - text: text, - fontSize: HeadingStyle.fontsize, - fontWeight: (bold) ? HeadingStyle.fontweight : FontWeight.normal, - color: (addColor) ? HeadingStyle.fontcolor : Colors.black, - padding: (addPadding) ? HeadingStyle.padding : 0, - ); - -/// Layout constants for scrollbars. - -class ScrollbarLayout { - /// Vertical gap between edge widget and scrollbar to avoid - /// horizontal scrollbar overlapping bottom edge of wrapped - /// content. - - static const verticalGap = SizedBox(height: 30); - - /// Horizontal gap between edge widget and scrollbar to avoid - /// vertical scrollbar overlapping the right edge of wrapped - /// content - /// - static const horizontalGap = SizedBox(width: 10); -} - -/// Colours used across dropdown dialogs and prompts. - -class DropdownColors { - /// Primary colour (Forest Green) used for dropdown elements - - static const primary = Color(0xFF2E7D32); - - /// Accent colour (Lighter Green) used for dividers and secondary elements. - - static const accent = Color(0xFF4CAF50); -} - -/// Layout constants used for sharing page - -class SharingPageLayout { - /// Padding for dialog input sections - - static const inputPadding = EdgeInsets.all( - 8, - ); -} - -/// Layout constants used for WebId entry containers - -class WebIdLayout { - /// Standard padding for page content. - - static const contentPadding = EdgeInsets.symmetric(horizontal: 50); - - /// Height of dropdown suggestion box. - - static const dropdownHeight = 120.0; - - /// Elevation of dropdown suggestion cards. - - static double dropdownElevation = 5; - - /// Padding of dropdown suggestion list. - - static const listPadding = EdgeInsets.fromLTRB(0, 5, 0, 5); -} - -/// Layout constants used for Grant Permission Form Dialog - -class GrantPermFormLayout { - /// Vertical gap between paragraphs - - static const paraVertGap = SizedBox(height: 10); - - /// Standard padding for dialog content. - - static const contentPadding = EdgeInsets.symmetric(horizontal: 50); - - /// Padding for dialog input sections - - static const inputPadding = EdgeInsets.all( - 8, - ); - - /// Standard width for security dialogs. - - static const dialogWidth = 480.0; - - /// Height of dropdown suggestion box. - - static const dropdownHeight = 120.0; - - /// Elevation of dropdown suggestion cards. - - static double dropdownElevation = 5; - - /// Padding of dropdown suggestion list. - - static const listPadding = EdgeInsets.fromLTRB(0, 5, 0, 5); -} diff --git a/lib/src/solid/grant_permission_form.dart b/lib/src/solid/grant_permission_form.dart index 16d04df2..19dc32aa 100644 --- a/lib/src/solid/grant_permission_form.dart +++ b/lib/src/solid/grant_permission_form.dart @@ -32,7 +32,9 @@ library; import 'package:flutter/material.dart'; -import 'package:solidpod/src/solid/constants/ui.dart'; +import 'package:solidui/solidui.dart' + show ActionColors, GrantPermFormLayout, smallGapV, makeSubHeading; + import 'package:solidpod/src/solid/constants/web_acl.dart'; import 'package:solidpod/src/solid/grant_permission.dart'; import 'package:solidpod/src/solid/grant_permission_helper.dart'; diff --git a/lib/src/solid/grant_permission_helper.dart b/lib/src/solid/grant_permission_helper.dart index cb93f9a9..5f9619be 100644 --- a/lib/src/solid/grant_permission_helper.dart +++ b/lib/src/solid/grant_permission_helper.dart @@ -28,7 +28,8 @@ library; import 'package:flutter/material.dart'; -import 'package:solidpod/src/solid/constants/ui.dart'; +import 'package:solidui/solidui.dart' show SharingPageLayout; + import 'package:solidpod/src/solid/constants/web_acl.dart'; import 'package:solidpod/src/widgets/permission_checkbox.dart'; diff --git a/lib/src/solid/grant_permission_ui.dart b/lib/src/solid/grant_permission_ui.dart index fe480209..074e8129 100644 --- a/lib/src/solid/grant_permission_ui.dart +++ b/lib/src/solid/grant_permission_ui.dart @@ -32,8 +32,15 @@ library; import 'package:flutter/material.dart'; +import 'package:solidui/solidui.dart' + show + normalLoadingScreenHeight, + smallGapV, + largeGapV, + makeHeading, + makeSubHeading; + import 'package:solidpod/src/solid/chk_exists_and_has_acl.dart'; -import 'package:solidpod/src/solid/constants/ui.dart'; import 'package:solidpod/src/solid/constants/web_acl.dart'; import 'package:solidpod/src/solid/grant_permission_helper.dart'; import 'package:solidpod/src/solid/models/permission_details.dart'; diff --git a/lib/src/solid/permission_table.dart b/lib/src/solid/permission_table.dart index 58417ec1..2dc245bd 100644 --- a/lib/src/solid/permission_table.dart +++ b/lib/src/solid/permission_table.dart @@ -33,8 +33,9 @@ library; import 'package:flutter/material.dart'; import 'package:markdown_tooltip/markdown_tooltip.dart'; +import 'package:solidui/solidui.dart' + show WindowSize, ListItemSize, ListIconSize, listIconShape; -import 'package:solidpod/src/solid/constants/ui.dart'; import 'package:solidpod/src/solid/models/permission.dart'; import 'package:solidpod/src/solid/revoke_permission_button.dart'; import 'package:solidpod/src/solid/utils/permission_helper.dart'; diff --git a/lib/src/solid/share_resource_button.dart b/lib/src/solid/share_resource_button.dart index 72144211..1db3ac20 100644 --- a/lib/src/solid/share_resource_button.dart +++ b/lib/src/solid/share_resource_button.dart @@ -32,7 +32,8 @@ library; import 'package:flutter/material.dart'; -import 'package:solidpod/src/solid/constants/ui.dart'; +import 'package:solidui/solidui.dart' show SharingPageLayout; + import 'package:solidpod/src/solid/grant_permission_form.dart'; import 'package:solidpod/src/solid/utils/alert.dart'; diff --git a/lib/src/solid/shared_resources_ui.dart b/lib/src/solid/shared_resources_ui.dart index 065cd130..dce687ca 100644 --- a/lib/src/solid/shared_resources_ui.dart +++ b/lib/src/solid/shared_resources_ui.dart @@ -33,7 +33,14 @@ library; import 'package:flutter/material.dart'; -import 'package:solidpod/src/solid/constants/ui.dart'; +import 'package:solidui/solidui.dart' + show + normalLoadingScreenHeight, + smallGapV, + largeGapV, + makeHeading, + makeSubHeading; + import 'package:solidpod/src/solid/shared_resources.dart'; import 'package:solidpod/src/solid/solid_func_call_status.dart'; import 'package:solidpod/src/solid/utils/authdata_manager.dart'; diff --git a/lib/src/solid/show_selected_recipients.dart b/lib/src/solid/show_selected_recipients.dart index 6f67de17..82807a5d 100644 --- a/lib/src/solid/show_selected_recipients.dart +++ b/lib/src/solid/show_selected_recipients.dart @@ -32,7 +32,8 @@ library; import 'package:flutter/material.dart'; -import 'package:solidpod/src/solid/constants/ui.dart'; +import 'package:solidui/solidui.dart' show smallGapV, RecipientTextStyle; + import 'package:solidpod/src/solid/constants/web_acl.dart'; /// A [StatelessWidget] for showing selected recipients in the diff --git a/lib/src/solid/utils/heading.dart b/lib/src/solid/utils/heading.dart deleted file mode 100644 index a4ecd81e..00000000 --- a/lib/src/solid/utils/heading.dart +++ /dev/null @@ -1,61 +0,0 @@ -/// A customisable heading widget. -/// -// Time-stamp: -/// -/// Copyright (C) 2024, Software Innovation Institute, ANU. -/// -/// Licensed under the MIT License (the "License"). -/// -/// License: https://choosealicense.com/licenses/mit/. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -/// -/// Authors: Anushka Vidanage - -library; - -import 'package:flutter/material.dart'; - -/// Sub heading build function -Row buildHeading({ - required String text, - required double fontSize, - FontWeight? fontWeight, - Color? color, - double? padding, -}) { - return Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Flexible( - child: Padding( - padding: padding == null ? EdgeInsets.zero : EdgeInsets.all(padding), - child: Text( - text, - style: TextStyle( - fontSize: fontSize, - fontWeight: fontWeight ?? FontWeight.normal, - color: color ?? Colors.black, - ), - ), - ), - ), - ], - ); -} diff --git a/lib/src/widgets/change_key_dialog.dart b/lib/src/widgets/change_key_dialog.dart deleted file mode 100644 index 817b5249..00000000 --- a/lib/src/widgets/change_key_dialog.dart +++ /dev/null @@ -1,168 +0,0 @@ -/// Show a pop up widget to change the security key -/// -/// Copyright (C) 2024, Software Innovation Institute, ANU. -/// -/// Licensed under the MIT License (the "License"). -/// -/// License: https://choosealicense.com/licenses/mit/. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -/// -/// Authors: Kevin Wang, Dawei Chen - -library; - -import 'package:flutter/material.dart'; - -import 'package:flutter_form_builder/flutter_form_builder.dart'; - -import 'package:solidpod/src/solid/utils/exceptions.dart' - show NotLoggedInException; -import 'package:solidpod/src/solid/utils/key_helper.dart' - show verifySecurityKey; -import 'package:solidpod/src/solid/utils/key_manager.dart' show KeyManager; -import 'package:solidpod/src/solid/utils/misc.dart' - show isUserLoggedIn, getWebId; -import 'package:solidpod/src/solid/utils/snack_bar.dart'; -import 'package:solidpod/src/widgets/security_key_ui.dart'; - -/// Displays a dialog for changing the key -/// [context] is the BuildContext from which this function is called. - -Future changeKeyPopup(BuildContext context, Widget child) async { - if (!await isUserLoggedIn()) { - throw NotLoggedInException( - 'User must be logged in to change security key.', - ); - } else { - final verificationKey = await KeyManager.getVerificationKey(); - final webId = await getWebId(); - - const message = - 'Please enter the current security key, the new security key,' - ' and repeat the new security key.'; - const currentKeyStr = 'current_security_key'; - const newKeyStr = 'new_security_key'; - const newKeyRepeatStr = 'new_security_key_repeat'; - final formKey = GlobalKey(); - - String? validateCurrentKey(String key) => - verifySecurityKey(key, verificationKey) - ? null - : 'Incorrect security key.'; - - String? validateNewKey(String key) => - verifySecurityKey(key, verificationKey) - ? 'New security key is identical to current security key.' - : null; - - String? validateNewKeyRepeat(String key) { - final formData = formKey.currentState?.value as Map; - if (formData.containsKey(newKeyStr) && - formData.containsKey(newKeyRepeatStr) && - formData[newKeyStr].toString() != - formData[newKeyRepeatStr].toString()) { - return 'New security keys do not match.'; - } - return null; - } - - final outerContext = context; - - Future submitForm(Map formDataMap) async { - final currentKey = formDataMap[currentKeyStr].toString(); - final newKey = formDataMap[newKeyStr].toString(); - final newKeyRepeat = formDataMap[newKeyRepeatStr].toString(); - - if (validateCurrentKey(currentKey) != null || - validateNewKey(newKey) != null || - validateNewKeyRepeat(newKeyRepeat) != null) { - return; - } - - late Color bgColor; - late Duration duration; - late String msg; - - try { - await KeyManager.changeSecurityKey(currentKey, newKey); - - msg = 'Successfully changed the security key!'; - bgColor = Colors.green; - duration = const Duration(seconds: 4); - } on Exception catch (e) { - msg = 'Failed to change security key! $e'; - bgColor = Colors.red; - duration = const Duration(seconds: 7); - } finally { - if (context.mounted) { - Navigator.pop(context); - } - if (outerContext.mounted) { - showSnackBar(outerContext, msg, bgColor, duration: duration); - } - } - } - - final inputFields = [ - ( - fieldKey: currentKeyStr, - fieldLabel: 'Current Security Key', - validateFunc: (key) => validateCurrentKey(key as String), - ), - ( - fieldKey: newKeyStr, - fieldLabel: 'New Security Key', - validateFunc: (key) => validateNewKey(key as String), - ), - ( - fieldKey: newKeyRepeatStr, - fieldLabel: 'Repeat New Security Key', - validateFunc: (key) => validateNewKeyRepeat(key as String), - ), - ]; - - // Use the unified SecurityKeyUI widget in dialog mode. - - final changeKeyForm = SecurityKeyUI( - webId: webId, - title: 'Change Security Key', - message: message, - inputFields: inputFields, - formKey: formKey, - submitFunc: submitForm, - displayMode: SecurityKeyDisplayMode.dialog, - child: child, - ); - - if (context.mounted) { - await showDialog( - context: context, - builder: (context) => AlertDialog( - content: SingleChildScrollView( - child: changeKeyForm, - ), - contentPadding: EdgeInsets.zero, - backgroundColor: Colors.transparent, - elevation: 0, - ), - ); - } - } -} diff --git a/lib/src/widgets/file_explorer.dart b/lib/src/widgets/file_explorer.dart index 6cddf4f7..1e4675eb 100644 --- a/lib/src/widgets/file_explorer.dart +++ b/lib/src/widgets/file_explorer.dart @@ -31,8 +31,9 @@ library; import 'package:flutter/material.dart'; +import 'package:solidui/solidui.dart' show normalLoadingScreenHeight; + import 'package:solidpod/src/solid/api/rest_api.dart'; -import 'package:solidpod/src/solid/constants/ui.dart'; import 'package:solidpod/src/solid/read_external_pod.dart'; import 'package:solidpod/src/solid/utils/alert.dart'; import 'package:solidpod/src/solid/utils/exceptions.dart'; diff --git a/lib/src/widgets/group_webid_input.dart b/lib/src/widgets/group_webid_input.dart index 4efec215..3c31c255 100644 --- a/lib/src/widgets/group_webid_input.dart +++ b/lib/src/widgets/group_webid_input.dart @@ -34,10 +34,11 @@ library; import 'package:flutter/material.dart'; import 'package:markdown_tooltip/markdown_tooltip.dart'; +import 'package:solidui/solidui.dart' + show smallGapV, makeSubHeading, GrantPermFormLayout; import 'package:solidpod/src/solid/api/rest_api.dart'; import 'package:solidpod/src/solid/constants/common.dart'; -import 'package:solidpod/src/solid/constants/ui.dart'; import 'package:solidpod/src/solid/utils/alert.dart'; /// A [StatefulWidget] dialog for entering group of webIds. diff --git a/lib/src/widgets/ind_webid_input.dart b/lib/src/widgets/ind_webid_input.dart index 422a25e8..21aaa660 100644 --- a/lib/src/widgets/ind_webid_input.dart +++ b/lib/src/widgets/ind_webid_input.dart @@ -34,10 +34,16 @@ library; import 'package:flutter/material.dart'; import 'package:markdown_tooltip/markdown_tooltip.dart'; +import 'package:solidui/solidui.dart' + show + smallGapV, + makeSubHeading, + GrantPermFormLayout, + WebIdLayout, + DropdownColors; import 'package:solidpod/src/solid/api/rest_api.dart'; import 'package:solidpod/src/solid/constants/common.dart'; -import 'package:solidpod/src/solid/constants/ui.dart'; import 'package:solidpod/src/solid/utils/alert.dart'; /// A [StatefulWidget] dialog for adding an individual webId. @@ -234,7 +240,7 @@ class _IndWebIdTextInputState extends State { elevation: WebIdLayout.dropdownElevation, child: ListTile( title: Text(idList[index]), - focusColor: SecurityColors.primary, + focusColor: DropdownColors.primary, hoverColor: DropdownColors.accent, splashColor: DropdownColors.primary, onTap: () => setState(() { diff --git a/lib/src/widgets/ind_webid_input_screen.dart b/lib/src/widgets/ind_webid_input_screen.dart index 2a1cf0ea..ab194799 100644 --- a/lib/src/widgets/ind_webid_input_screen.dart +++ b/lib/src/widgets/ind_webid_input_screen.dart @@ -33,7 +33,8 @@ library; import 'package:flutter/material.dart'; -import 'package:solidpod/src/solid/constants/ui.dart'; +import 'package:solidui/solidui.dart' show normalLoadingScreenHeight; + import 'package:solidpod/src/solid/get_recipient_list.dart'; import 'package:solidpod/src/widgets/ind_webid_input.dart'; import 'package:solidpod/src/widgets/loading_screen.dart'; diff --git a/lib/src/widgets/secret_text_field.dart b/lib/src/widgets/secret_text_field.dart deleted file mode 100644 index 34648253..00000000 --- a/lib/src/widgets/secret_text_field.dart +++ /dev/null @@ -1,114 +0,0 @@ -/// A text field for inputting secret text (e.g. password, security key etc.) -/// -/// Copyright (C) 2024, Software Innovation Institute, ANU. -/// -/// Licensed under the MIT License (the "License"). -/// -/// License: https://choosealicense.com/licenses/mit/. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -/// -/// Authors: Dawei Chen - -library; - -import 'package:flutter/material.dart'; - -import 'package:flutter_form_builder/flutter_form_builder.dart'; -import 'package:form_builder_validators/form_builder_validators.dart'; - -import 'package:solidpod/src/solid/constants/ui.dart'; - -/// A [StatefulWidget] for user to enter a secret text. - -class SecretTextField extends StatefulWidget { - /// Constructor. - - const SecretTextField({ - required this.fieldKey, - required this.fieldLabel, - required this.validateFunc, - super.key, - }); - - /// The key of this text field (to be used in a form) - final String fieldKey; - - /// The label text - final String fieldLabel; - - /// The verification function - final String? Function(String) validateFunc; - - @override - State createState() => _SecretTextFieldState(); -} - -class _SecretTextFieldState extends State { - bool _showSecret = false; - - @override - Widget build(BuildContext context) { - // The label text style using theme-aware colour. - - final style = TextStyle( - color: SecurityThemeColors.labelGrey(context), - letterSpacing: 1.5, - fontSize: 13.0, - fontWeight: FontWeight.bold, - ); - - // The suffix icon with theme-aware colour. - - final iconColor = SecurityThemeColors.labelGrey(context); - final icon = IconButton( - icon: Icon( - _showSecret ? Icons.visibility : Icons.visibility_off, - color: iconColor, - ), - onPressed: () => setState(() { - // Toggle the state to show/hide the secret. - _showSecret = !_showSecret; - }), - // Does not participate in focus traversal (ignore TAB key). - focusNode: FocusNode(skipTraversal: true), - ); - - // The validator. - - final secretValidator = FormBuilderValidators.compose([ - FormBuilderValidators.required(), - (val) => widget.validateFunc(val as String), - ]); - - return FormBuilderTextField( - name: widget.fieldKey, - obscureText: !_showSecret, - autocorrect: false, - decoration: InputDecoration( - labelText: widget.fieldLabel.toUpperCase(), - labelStyle: style, - suffixIcon: icon, - ), - style: TextStyle(color: SecurityThemeColors.text(context)), - cursorColor: SecurityThemeColors.primary(context), - validator: secretValidator, - ); - } -} diff --git a/lib/src/widgets/security_key_ui.dart b/lib/src/widgets/security_key_ui.dart deleted file mode 100644 index d697ad4e..00000000 --- a/lib/src/widgets/security_key_ui.dart +++ /dev/null @@ -1,406 +0,0 @@ -/// A unified widget for security key prompts and dialogs with WebID displayed prominently. -/// -/// Copyright (C) 2024, Software Innovation Institute, ANU. -/// -/// Licensed under the MIT License (the "License"). -/// -/// License: https://choosealicense.com/licenses/mit/. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -/// -/// Authors: Ashley Tang - -library; - -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart' show LogicalKeyboardKey; - -import 'package:flutter_form_builder/flutter_form_builder.dart'; - -import 'package:solidpod/src/solid/constants/ui.dart'; -import 'package:solidpod/src/solid/utils/push_replacement.dart'; -import 'package:solidpod/src/widgets/secret_text_field.dart'; - -/// Display mode for the SecurityKeyUI widget. -/// -/// This enum determines whether the widget should be displayed as a fullscreen prompt -/// or as an embedded dialog component. - -enum SecurityKeyDisplayMode { - /// Display as a fullscreen prompt with a scaffold. - - fullscreen, - - /// Display as an embedded dialog component. - - dialog -} - -/// A flexible [StatefulWidget] for security key operations with improved UI and WebID display. -/// -/// This widget can be used for both simple security key prompts (single input field) -/// and more complex dialogs (multiple input fields) by providing different configurations. - -class SecurityKeyUI extends StatefulWidget { - /// Constructor for the SecurityKeyUI widget. - /// - /// For a simple security key prompt: - /// - Pass a single input field in [inputFields] list - /// - Provide a title like "Security Key" - /// - Use [displayMode] = SecurityKeyDisplayMode.fullscreen - /// - /// For a security key dialog with multiple fields: - /// - Pass multiple input fields in [inputFields] - /// - Set [displayMode] = SecurityKeyDisplayMode.dialog - - const SecurityKeyUI({ - required this.webId, - required this.title, - required this.message, - required this.inputFields, - required this.formKey, - required this.submitFunc, - required this.child, - this.displayMode = SecurityKeyDisplayMode.fullscreen, - super.key, - }); - - /// The WebID to display. - - final String? webId; - - /// Title of the UI component. - - final String title; - - /// Message to display. - - final String message; - - /// The input text fields. - /// For a simple prompt, provide a list with a single field. - /// For a dialog with multiple inputs, provide multiple fields. - - final List< - ({ - String fieldKey, - String fieldLabel, - String? Function(String?) validateFunc, - })> inputFields; - - /// Key of the form for data retrieval. - - final GlobalKey formKey; - - /// The submit function. - - final Future Function(Map formDataMap) submitFunc; - - /// The child widget (for navigation after cancel). - - final Widget child; - - /// Display mode (fullscreen prompt or embedded dialog component). - - final SecurityKeyDisplayMode displayMode; - - @override - State createState() => _SecurityKeyUIState(); -} - -class _SecurityKeyUIState extends State { - Map _verifiedMap = {}; - bool _canSubmit = false; - - @override - void initState() { - super.initState(); - assert(widget.inputFields.isNotEmpty); - final fieldKeys = {for (final f in widget.inputFields) f.fieldKey}; - assert(fieldKeys.length == widget.inputFields.length); - _verifiedMap = {for (final k in fieldKeys) k: false}; - } - - Future _submit(BuildContext context) async { - final formData = widget.formKey.currentState?.value as Map; - - if (!_canSubmit) { - return; - } - - for (final f in widget.inputFields) { - if (formData[f.fieldKey] == null) { - debugPrint('${f.fieldKey} is null'); - return; - } - } - - try { - await widget.submitFunc(formData); - } on Exception catch (e) { - debugPrint('$e'); - } - } - - @override - Widget build(BuildContext context) { - // Create the card content with the form. - - final cardContent = _buildCardContent(context); - - // Return based on display mode. - - if (widget.displayMode == SecurityKeyDisplayMode.fullscreen) { - return Scaffold( - backgroundColor: SecurityThemeColors.background(context), - body: Center( - child: SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: cardContent, - ), - ), - ); - } else { - return cardContent; - } - } - - /// Builds the card content including header, form fields, and buttons. - - Widget _buildCardContent(BuildContext context) { - return Container( - width: SecurityLayout.dialogWidth, - constraints: const BoxConstraints( - maxWidth: SecurityLayout.maxDialogWidth, - ), - decoration: BoxDecoration( - color: SecurityThemeColors.cardBackground(context), - borderRadius: BorderRadius.circular(SecurityLayout.borderRadius), - boxShadow: [ - BoxShadow( - color: Colors.black.withValues(alpha: 0.1), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Header section. - - _buildHeader(context), - - // Separator. - - Container( - height: SecurityLayout.separatorHeight, - color: SecurityThemeColors.separator(context), - ), - - // Form with input fields. - - Padding( - padding: SecurityLayout.formPadding, - child: _buildForm(), - ), - - // Buttons. - - Padding( - padding: SecurityLayout.buttonsPadding, - child: _buildButtons(context), - ), - ], - ), - ); - } - - /// Builds the header section with title, WebID, and message. - - Widget _buildHeader(BuildContext context) { - return Padding( - padding: SecurityLayout.contentPadding, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Title heading. - - Text( - widget.title, - style: SecurityThemeTextStyles.heading(context), - ), - - // Green divider under heading. - - Container( - height: SecurityLayout.dividerHeight, - color: SecurityThemeColors.accent(context), - margin: SecurityLayout.dividerMargin, - ), - - // "Currently logged in as:" label. - - Text( - SecurityStrings.webIdLabel, - style: SecurityThemeTextStyles.label(context), - ), - - // WebID on separate line. - - Padding( - padding: SecurityLayout.webIdPadding, - child: Text( - widget.webId ?? SecurityStrings.notLoggedIn, - style: SecurityThemeTextStyles.webId( - context, - isLoggedIn: widget.webId != null, - ), - ), - ), - - // Instructions text. - - Text( - widget.message, - style: SecurityThemeTextStyles.body(context), - ), - ], - ), - ); - } - - /// Builds the form with input fields. - - Widget _buildForm() { - // Create the input fields. - - final inputFieldWidgets = []; - - for (final f in widget.inputFields) { - inputFieldWidgets.add( - Padding( - padding: SecurityLayout.inputFieldSpacing, - child: StatefulBuilder( - builder: (context, setState) => SecretTextField( - fieldKey: f.fieldKey, - fieldLabel: f.fieldLabel, - validateFunc: (val) { - final r = f.validateFunc(val); - - setState(() { - _verifiedMap[f.fieldKey] = (r == null); - }); - - this.setState(() { - _canSubmit = !_verifiedMap.containsValue(false); - }); - - return r; - }, - ), - ), - ), - ); - } - - return FormBuilder( - key: widget.formKey, - onChanged: () { - // Save input and validate. - - widget.formKey.currentState!.save(); - widget.formKey.currentState!.validate( - focusOnInvalid: false, - ); - - // Update state. - - setState(() { - _canSubmit = !_verifiedMap.containsValue(false); - }); - }, - autovalidateMode: AutovalidateMode.disabled, - child: KeyboardListener( - focusNode: FocusNode(), - onKeyEvent: (event) async { - if (event.logicalKey == LogicalKeyboardKey.enter) { - await _submit(context); - } - }, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: inputFieldWidgets, - ), - ), - ); - } - - /// Builds the buttons for submit and cancel. - - Widget _buildButtons(BuildContext context) { - final submitButton = ElevatedButton( - onPressed: _canSubmit ? () async => _submit(context) : null, - style: ElevatedButton.styleFrom( - backgroundColor: SecurityThemeColors.primary(context), - padding: SecurityLayout.buttonPadding, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(SecurityLayout.buttonRadius), - ), - ), - child: const Text( - SecurityStrings.submit, - style: SecurityThemeTextStyles.button, - ), - ); - - final cancelButton = TextButton( - onPressed: () { - if (widget.displayMode == SecurityKeyDisplayMode.dialog) { - Navigator.pop(context); - } else { - pushReplacement(context, widget.child); - // Navigator.pushReplacement( - // context, - // MaterialPageRoute( - // builder: (context) => widget.child, - // ), - // ); - } - }, - style: TextButton.styleFrom( - padding: SecurityLayout.buttonPadding, - ), - child: Text( - SecurityStrings.cancel, - style: SecurityThemeTextStyles.cancelButton(context), - ), - ); - - return Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - cancelButton, - SecurityLayout.horizontalGap, - submitButton, - ], - ); - } -} diff --git a/pubspec.yaml b/pubspec.yaml index b2747df4..dd46b8ee 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -22,9 +22,7 @@ dependencies: crypto: ^3.0.7 encrypter_plus: ^5.1.0 fast_rsa: ^3.8.6 - flutter_form_builder: ^10.2.0 flutter_secure_storage: ^10.0.0 - form_builder_validators: ^11.2.0 http: ^1.6.0 intl: ^0.20.2 jwt_decoder: ^2.0.1 @@ -35,26 +33,27 @@ dependencies: pointycastle: ^4.0.0 rdflib: ^0.2.12 solid_auth: ^0.1.28 - web: ^1.1.0 + solidui: ^0.0.25 universal_io: ^2.3.1 dev_dependencies: build_runner: ^2.10.5 custom_lint: ^0.8.1 - # Keep dependency checker quiet. demopod: path: example editable: ^2.0.0 file_picker: ^10.3.10 flutter_lints: ^6.0.0 import_order_lint: ^0.2.2 - # Keep dependency checker quiet. - solidui: ^0.0.25 ubuntu_lints: ^0.4.1+1 window_manager: ^0.5.1 dependency_overrides: flutter_lints: ^5.0.0 + solidui: + git: + url: https://github.com/anusii/solidui + ref: tony/186_migration flutter: assets: