diff --git a/assets/fonts/Courier/CourierPrime-Regular.ttf b/assets/fonts/Courier/CourierPrime-Regular.ttf new file mode 100644 index 00000000..4af1ff54 Binary files /dev/null and b/assets/fonts/Courier/CourierPrime-Regular.ttf differ diff --git a/lib/constants/app_constants.dart b/lib/constants/app_constants.dart index cfd05aa1..36a1cd57 100644 --- a/lib/constants/app_constants.dart +++ b/lib/constants/app_constants.dart @@ -43,6 +43,8 @@ const String FILE_SENT = 'File sent'; const String SECONDS = 'Seconds'; const String MINUTES = 'Minutes'; const String MINUTE = 'Minute'; +const String SEE_DETAILS = 'See details'; +const String UNKNOWN_ERROR = 'Unknown error'; const String X = 'X'; const String THREE_DOTS = '...'; const String WAITING_FOR_RECEIVER = @@ -147,12 +149,12 @@ const String ANDROID_DOWNLOADS_FOLDER_PATH = '/storage/emulated/0/Download'; const String WINDOW_TITLE = "Destiny"; -const String ERR_WRONG_CODE_RECEIVER = """Oops..\n -If you’re sure this is the right code: Either the sender is no longer connected, or the code was already used.\n +const String ERR_WRONG_CODE_RECEIVER = """Oops.. +If you’re sure this is the right code: Either the sender is no longer connected, or the code was already used. Please ask the sender for a new code and for them to stay connected until you get the file."""; -const String ERR_WRONG_CODE_SENDER = """Oops..\n -The receiver has entered the wrong code.\n +const String ERR_WRONG_CODE_SENDER = """Oops.. +The receiver has entered the wrong code. Please try sending the file again"""; const String ERR_INTERRUPTION_CANCELLATION_RECEIVER = diff --git a/lib/constants/asset_path.dart b/lib/constants/asset_path.dart index c785c90e..e991ab00 100644 --- a/lib/constants/asset_path.dart +++ b/lib/constants/asset_path.dart @@ -6,7 +6,7 @@ const String MONTSERRAT_SEMI_BOLD = 'MontserratSemiBold'; const String MONTSERRAT_EXTRA_BOLD = 'MontserratExtraBold'; const String MONTSERRAT_MEDIUM = 'MontserratMedium'; const String MONTSERRAT_LIGHT_ITALIC = 'MontserratLightItalic'; - +const String COURIER = 'Courier'; //images const String LOGO = 'assets/images/logo.png'; const String DEVICE_TO_DEVICE_IMG = 'assets/images/Device2Device.png'; diff --git a/lib/views/desktop/receive/receive.dart b/lib/views/desktop/receive/receive.dart index c14a852d..8492f215 100644 --- a/lib/views/desktop/receive/receive.dart +++ b/lib/views/desktop/receive/receive.dart @@ -86,7 +86,9 @@ class ReceiveScreen extends StatelessWidget { Widget receiveError() { return Consumer(builder: (context, state, _) { return DTErrorUI( - text: state.errorMessage ?? "Unknown error", + errorTitle: state.errorTitle, + error: '', + errorMessage: state.errorMessage ?? UNKNOWN_ERROR, onPressed: () { state.reset(); }, @@ -115,8 +117,9 @@ class ReceiveScreen extends StatelessWidget { Widget transferCancelled() { return Consumer(builder: (context, state, _) { return DTErrorUI( - text: ERR_INTERRUPTION_CANCELLATION_RECEIVER, - subText: 'Please try again.', + errorTitle: ERR_INTERRUPTION_CANCELLATION_RECEIVER, + error: state.error != null ? state.error : '', + errorMessage: state.errorMessage ?? UNKNOWN_ERROR, onPressed: () { state.reset(); }, @@ -127,7 +130,9 @@ class ReceiveScreen extends StatelessWidget { Widget transferRejected() { return Consumer(builder: (context, state, _) { return DTErrorUI( - text: 'The transfer was cancelled by the receiver.', + errorTitle: 'The transfer was cancelled by the receiver.', + error: state.error != null ? state.error : '', + errorMessage: state.errorMessage, onPressed: () { state.reset(); }, diff --git a/lib/views/desktop/send/send.dart b/lib/views/desktop/send/send.dart index ca94491a..ee6b1279 100644 --- a/lib/views/desktop/send/send.dart +++ b/lib/views/desktop/send/send.dart @@ -80,7 +80,9 @@ class SendScreen extends StatelessWidget { return Consumer(builder: (context, state, _) { return DTErrorUI( paddingTop: 80.0.h, - text: state.errorMessage ?? "Unknown error", + errorTitle: 'Please try again.', + error: state.error != null ? state.error?.error : '', + errorMessage: state.errorMessage ?? UNKNOWN_ERROR, showBoxDecoration: true, onPressed: () { state.reset(); @@ -94,8 +96,9 @@ class SendScreen extends StatelessWidget { return DTErrorUI( paddingTop: 80.0.h, showBoxDecoration: true, - text: ERR_INTERRUPTION_CANCELLATION_SENDER, - subText: 'Please try again.', + errorTitle: 'Please try again.', + error: state.error != null ? state.error?.error : '', + errorMessage: state.errorMessage, onPressed: () { state.reset(); }, @@ -108,7 +111,9 @@ class SendScreen extends StatelessWidget { return DTErrorUI( paddingTop: 80.0.h, showBoxDecoration: true, - text: 'The transfer was cancelled by the receiver.', + errorTitle: 'The transfer was cancelled by the receiver.', + error: state.error != null ? state.error?.error : '', + errorMessage: state.errorMessage, onPressed: () { state.reset(); }, diff --git a/lib/views/desktop/send/widgets/DTErrorUI.dart b/lib/views/desktop/send/widgets/DTErrorUI.dart index 57bb32d6..9467876c 100644 --- a/lib/views/desktop/send/widgets/DTErrorUI.dart +++ b/lib/views/desktop/send/widgets/DTErrorUI.dart @@ -2,23 +2,29 @@ import 'package:dart_wormhole_gui/config/theme/colors.dart'; import 'package:dart_wormhole_gui/views/desktop/widgets/DTButtonWithBackground.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import '../../../shared/util.dart'; +import '../../../../constants/app_constants.dart'; +import '../../../../constants/asset_path.dart'; +import '../../../../widgets/ExpandableTextBox.dart'; +import '../../../widgets/Heading.dart'; void doNothing() { print("Doing nothing with error UI button"); } class DTErrorUI extends StatelessWidget { - final String text; - final String subText; + final String? errorTitle; + final String? error; + final String? errorMessage; + final String buttonTitle; final double paddingTop; final void Function() onPressed; final bool? showBoxDecoration; DTErrorUI( - {this.text = '', - this.subText = '', + {this.errorTitle = '', + this.error = '', + this.errorMessage = '', this.showBoxDecoration = false, this.onPressed = doNothing, this.buttonTitle = '', @@ -37,15 +43,30 @@ class DTErrorUI extends StatelessWidget { : null, padding: EdgeInsets.only(left: 8.0.w, right: 8.0.w, top: paddingTop), child: Column(children: [ - ...convertErrorMessageIntoParagraphs(text, - Theme.of(context).textTheme.headline1, TextAlign.center, context), - Text( - subText, - style: Theme.of(context).textTheme.headline1, + Heading( + title: errorTitle, textAlign: TextAlign.center, + textStyle: TextStyle( + fontFamily: MONTSERRAT_MEDIUM, + fontSize: Theme.of(context).textTheme.headline1?.fontSize, + color: Theme.of(context).textTheme.headline1?.color), + ), + Heading( + marginTop: 20, + title: error, + isVisible: error != '', + textAlign: TextAlign.center, + textStyle: TextStyle( + fontSize: 20.0.sp, + fontFamily: Theme.of(context).textTheme.headline1?.fontFamily, + color: Theme.of(context).textTheme.headline1?.color, + )), + ExtensiveDesktopErrorExpandable( + error: this.error, + errorMessage: this.errorMessage, ), SizedBox( - height: 100.0.h, + height: this.error != '' ? 100.0.h : 16.0.h, ), DTButtonWithBackground( onPressed: onPressed, @@ -56,3 +77,52 @@ class DTErrorUI extends StatelessWidget { ])); } } + +class ExtensiveDesktopErrorExpandable extends StatelessWidget { + final String? error; + final String? errorMessage; + ExtensiveDesktopErrorExpandable({ + Key? key, + required this.error, + required this.errorMessage, + }) : super(key: key); + @override + Widget build(BuildContext context) { + if (error == '') + return Column( + children: [ + SizedBox( + height: 30.0.h, + ), + Heading( + title: SEE_DETAILS, + textStyle: TextStyle( + color: Theme.of(context).primaryColor, + fontSize: Theme.of(context).textTheme.subtitle1?.fontSize, + fontFamily: COURIER, + ), + ), + SizedBox(height: 4.0), + Row( + children: [ + Expanded(flex: 1, child: Container()), + Expanded( + flex: 10, + child: Container( + padding: EdgeInsets.fromLTRB(16.0, 0, 16.0, 0), + child: ExpandableTextBox( + showBorders: true, + errorMessage: errorMessage, + height: MediaQuery.of(context).size.height - 530.0.h, + fontSize: 17.0, + ), + )), + Expanded(flex: 1, child: Container()), + ], + ) + ], + ); + + return Container(); + } +} diff --git a/lib/views/mobile/receive/receive.dart b/lib/views/mobile/receive/receive.dart index e5fd3340..e5840651 100644 --- a/lib/views/mobile/receive/receive.dart +++ b/lib/views/mobile/receive/receive.dart @@ -83,7 +83,7 @@ class ReceiveScreen extends StatelessWidget { return Consumer(builder: (context, state, _) { return ErrorUI( errorTitle: state.errorTitle, - errorMessage: state.errorMessage ?? "Unknown error", + errorMessage: state.errorMessage ?? UNKNOWN_ERROR, error: state.error, actionText: "Receive a file", onPressed: () { diff --git a/lib/views/mobile/send/send.dart b/lib/views/mobile/send/send.dart index 6bfb5ec6..538e37af 100644 --- a/lib/views/mobile/send/send.dart +++ b/lib/views/mobile/send/send.dart @@ -59,8 +59,8 @@ class SendScreen extends StatelessWidget { return Consumer(builder: (context, state, _) { return ErrorUI( errorTitle: state.errorTitle, - errorMessage: state.errorMessage ?? "Unknown error", - error: state.error.toString(), + errorMessage: state.errorMessage ?? UNKNOWN_ERROR, + error: state.error != null ? state.error?.error : '', actionText: "Send a file", onPressed: () { state.reset(); diff --git a/lib/views/mobile/widgets/ErrorUI.dart b/lib/views/mobile/widgets/ErrorUI.dart index c7f6fedc..80a6a08e 100644 --- a/lib/views/mobile/widgets/ErrorUI.dart +++ b/lib/views/mobile/widgets/ErrorUI.dart @@ -1,7 +1,9 @@ +import 'package:dart_wormhole_gui/views/widgets/Heading.dart'; +import 'package:dart_wormhole_gui/widgets/ExpandableTextBox.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import '../../../constants/app_constants.dart'; import '../../../constants/asset_path.dart'; -import '../../shared/util.dart'; import 'buttons/ButtonWithBackground.dart'; class ErrorUI extends StatelessWidget { @@ -12,8 +14,8 @@ class ErrorUI extends StatelessWidget { final void Function() onPressed; ErrorUI( - {this.errorTitle, - this.error, + {this.errorTitle = "", + this.error = "", this.errorMessage, this.actionText = "", required this.onPressed, @@ -21,24 +23,76 @@ class ErrorUI extends StatelessWidget { : super(key: key); @override Widget build(BuildContext context) { - return Column(children: [ - ...convertErrorMessageIntoParagraphs( - errorMessage, - TextStyle( - fontSize: Theme.of(context).textTheme.headline6?.fontSize, - fontFamily: MONTSERRAT_LIGHT, - color: Theme.of(context).colorScheme.secondary, + return Column(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Column( + children: [ + Heading( + title: errorTitle ?? errorTitle.toString(), + textAlign: TextAlign.left, + textStyle: Theme.of(context).textTheme.subtitle1, ), - TextAlign.left, - context), - ButtonWithBackground( - width: 200.0.w, - height: 60.0.h, - title: actionText, - handleClicked: () { - onPressed(); - }, - fontSize: 18.0.sp), + Heading( + marginTop: 20, + title: error ?? error.toString(), + textAlign: TextAlign.center, + isVisible: error != '', + textStyle: TextStyle( + fontSize: 14.0.sp, + fontFamily: Theme.of(context).textTheme.subtitle2?.fontFamily, + color: Theme.of(context).textTheme.subtitle2?.color, + )), + SizedBox(height: 10.0), + ExtensiveMobileErrorExpandable( + error: this.error, + errorMessage: this.errorMessage, + ), + ], + ), + Container( + margin: EdgeInsets.only(bottom: 70.0.h), + child: ButtonWithBackground( + width: 200.0.w, + height: 60.0.h, + title: actionText, + handleClicked: () { + onPressed(); + }, + fontSize: 18.0.sp), + ) ]); } } + +class ExtensiveMobileErrorExpandable extends StatelessWidget { + final String? error; + final String? errorMessage; + ExtensiveMobileErrorExpandable({ + Key? key, + required this.error, + required this.errorMessage, + }) : super(key: key); + @override + Widget build(BuildContext context) { + if (error == '') + return Column( + children: [ + Heading( + title: SEE_DETAILS, + textStyle: TextStyle( + color: Theme.of(context).primaryColor, + fontSize: Theme.of(context).textTheme.subtitle1?.fontSize, + fontFamily: MONTSERRAT_THIN, + ), + ), + SizedBox(height: 4.0), + ExpandableTextBox( + showBorders: false, + errorMessage: errorMessage, + fontSize: 12.0, + ) + ], + ); + + return Container(); + } +} diff --git a/lib/views/widgets/Heading.dart b/lib/views/widgets/Heading.dart index 969c8e73..1d47cce0 100644 --- a/lib/views/widgets/Heading.dart +++ b/lib/views/widgets/Heading.dart @@ -7,6 +7,7 @@ class Heading extends StatelessWidget { final TextAlign textAlign; final double marginTop; final TextStyle? textStyle; + final bool? isVisible; Heading( {Key? key, this.title, @@ -14,10 +15,12 @@ class Heading extends StatelessWidget { this.path = '', this.textAlign = TextAlign.center, this.marginTop = 0, - this.textStyle}) + this.textStyle, + this.isVisible = true}) : super(key: key); @override Widget build(BuildContext context) { + if (isVisible == false) return Container(); if (subTitle == null) return Container( width: double.infinity, @@ -36,7 +39,6 @@ class Heading extends StatelessWidget { ], ), )); - return Row( children: [ Container( diff --git a/lib/widgets/ExpandableTextBox.dart b/lib/widgets/ExpandableTextBox.dart new file mode 100644 index 00000000..54e5b093 --- /dev/null +++ b/lib/widgets/ExpandableTextBox.dart @@ -0,0 +1,46 @@ +import 'package:dart_wormhole_gui/views/widgets/Heading.dart'; +import 'package:expand_widget/expand_widget.dart'; +import 'package:flutter/material.dart'; +import '../constants/asset_path.dart'; + +class ExpandableTextBox extends StatelessWidget { + final String? error; + final String? errorMessage; + final bool? showBorders; + final double? height; + final double? fontSize; + + ExpandableTextBox({ + Key? key, + this.error = '', + this.errorMessage = '', + this.showBorders = false, + this.height, + this.fontSize, + }) : super(key: key); + @override + Widget build(BuildContext context) { + return ExpandChild( + showBorders: showBorders, + expandedBGColor: Color(0xff1A1C2E), + arrowColor: Theme.of(context).primaryColor, + arrowSize: 40.0, + child: Container( + padding: EdgeInsets.all(16.0), + child: Container( + height: height, + child: SingleChildScrollView( + child: Column( + children: [ + Heading( + title: errorMessage ?? errorMessage.toString(), + textStyle: TextStyle( + color: Theme.of(context).textTheme.headline1?.color, + fontSize: fontSize, + fontFamily: COURIER, + ), + textAlign: TextAlign.left), + ], + ))))); + } +} diff --git a/pubspec.lock b/pubspec.lock index 44e8bb0b..a8224216 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -34,10 +34,10 @@ packages: description: path: "." ref: HEAD - resolved-ref: "6b1822cd01510f8a12e22376e2bdf49b31b8c8bd" + resolved-ref: "9dda94bfdbffe6fa0efc4453c075659ac2e3ac7f" url: "https://github.com/Ephenodrom/Dart-Basic-Utils" source: git - version: "4.2.2" + version: "4.3.0" boolean_selector: dependency: transitive description: @@ -121,7 +121,7 @@ packages: name: dart_console url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.1.1" dart_wormhole_william: dependency: "direct main" description: @@ -185,6 +185,15 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.0+2" + expand_widget: + dependency: "direct main" + description: + path: "." + ref: HEAD + resolved-ref: "0345379dd6d8cd89563074b0c9df47d93b53c5aa" + url: "https://github.com/shareef-dweikat/expand_widget" + source: git + version: "2.1.0" fake_async: dependency: transitive description: @@ -236,7 +245,7 @@ packages: name: flutter_plugin_android_lifecycle url: "https://pub.dartlang.org" source: hosted - version: "2.0.6" + version: "2.0.7" flutter_screenutil: dependency: "direct main" description: @@ -299,12 +308,19 @@ packages: description: flutter source: sdk version: "0.0.0" + intl: + dependency: transitive + description: + name: intl + url: "https://pub.dartlang.org" + source: hosted + version: "0.17.0" intro_slider: dependency: "direct main" description: path: "." ref: HEAD - resolved-ref: "483ee6aaea66e5993c22e28c3110a033a2f07299" + resolved-ref: "23a25d41fcb13f4971ceedef88e6755631d00cb2" url: "https://github.com/shareef-dweikat/flutter-intro-slider" source: git version: "3.0.2" @@ -321,7 +337,7 @@ packages: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.5.0" + version: "4.6.0" logging: dependency: transitive description: @@ -419,7 +435,7 @@ packages: name: path_provider_android url: "https://pub.dartlang.org" source: hosted - version: "2.0.15" + version: "2.0.16" path_provider_ios: dependency: transitive description: @@ -696,7 +712,7 @@ packages: description: path: "plugins/window_size" ref: HEAD - resolved-ref: "5c51870ced62a00e809ba4b81a846a052d241c9f" + resolved-ref: "12decbe0f592e14e03223f6f2c0c7e0e2dbd70a1" url: "https://github.com/google/flutter-desktop-embedding.git" source: git version: "0.1.0" diff --git a/pubspec.yaml b/pubspec.yaml index dcad2d25..c32e569b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,6 +36,9 @@ dependencies: intro_slider: git: url: https://github.com/shareef-dweikat/flutter-intro-slider + expand_widget: + git: + url: https://github.com/shareef-dweikat/expand_widget flutter: sdk: flutter @@ -107,6 +110,9 @@ flutter: - family: Lato fonts: - asset: assets/fonts/Lato/Lato-Regular.ttf + - family: Courier + fonts: + - asset: assets/fonts/Courier/CourierPrime-Regular.ttf # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class.