diff --git a/README.md b/README.md index 4cd160ba..74efc542 100644 --- a/README.md +++ b/README.md @@ -90,13 +90,13 @@ iOS Production ## VaahExtendedFlutter -### Central log library: +### → Central log library: Can be used for logging different details. All methods are static thus no instance of Console is required. Console.info() method will print info in blue color font, Console.success() method will print log in green color font, Console.warning() method will print log in yellow color font, and Console.danger() method will print log in red color font. The files reside in `lib/vaahextendflutter/log/` folder. -### Environment and Version Tag +### → Environment and Version Tag Panel -Environment and Version Tag can be seen on every page unless you set `showEnvAndVersionTag` for your Environment configuration in `env.dart` file. You can change color of tag by setting `envAndVersionTagColor` variable for your Environment configuration. +Environment and Version Tag can be seen on every page unless you set `showEnvAndVersionTag` to `false` for your Environment configuration in `env.dart` file. You can change color of tag by setting `envAndVersionTagColor` variable for your Environment configuration. NOTE: `Remember showEnvAndVersionTag for production should always be false in Environment configuration in `env.dart` file.` ```dart @@ -106,6 +106,60 @@ NOTE: `Remember showEnvAndVersionTag for production should always be false in En ), ``` -NOTE: Whenever you create a new screen/ page, wrap the body with `TagWrapper` class. +#### NOTE: You have to write below code in MaterialApp, and that will show tag panel on each screen. You don't have to wrap any other screen/ widget, or you don't have to extend any screen/ any widget with TagPanelHost. + +In file cotaining material app paste this code after imports +```dart +final _navigatorKey = GlobalKey(); +``` + In material app paste this code and panel will be visible on all pages. +```dart +builder: (BuildContext context, Widget? child) { + return TagPanelHost( + navigatorKey: _navigatorKey, + child: child!, + ); +}, +``` +This panel uses EnvController, thus dependens on env.dart file. + +### → Dynamic fontsize, dynamic width, dynamic height depending on device size + +To use it directly by importing `screen_util.dart` check Usage: comment in `screen_util.dart` file. + +Or for feasibility extend your Statelesswidgets with BaseStateless +```dart +class DemoPage extends BaseStateful { +} +``` + +And Statefull widgets with BaseStateful widgets +```dart +class _DemoPageState extends BaseStateful { +... +} +``` +After that you can use dynamic size in that extended widget. +```dart +SizedBox( + width: 300.wExt, // or swExt + height: 200.hExt, // or shExt + child: Text( + 'demo', + style: TextStyle( + fontSize: 20.spExt, + ), + ), +); +``` + +### → Base widgets +`vaahextendflutter/base` folder contains all the base classes/ widgets. + +BaseStateless and BaseStateful are used when dev wants to init/ add dependencies in many screens and don't want to write same logic in every file, so they write the logic in base files only. eg. internet connectivity checker, dynamic size dependency, etc. + +so base class implements those logics and other classes can extend the base classes. + +### → Helpers +Most common constants and styles used in whole app. -You can use alignment and margin properties for achieving desired results using TagWrapper. \ No newline at end of file diff --git a/lib/env.dart b/lib/env.dart index de594dfd..cfccabfc 100644 --- a/lib/env.dart +++ b/lib/env.dart @@ -15,13 +15,14 @@ EnvironmentConfig defaultConfig = const EnvironmentConfig( envType: 'default', version: version, build: build, - baseUrl: '', - apiBaseUrl: '', - analyticsId: '', + backendUrl: '', // base url or backend url + apiUrl: '', // api base url + firebaseId: '', // firebase id enableConsoleLogs: true, enableLocalLogs: true, showEnvAndVersionTag: true, - envAndVersionTagColor: Colors.red, + envAndVersionTagColor: Color( + 0xAA000000), // first 2 digit after 0x represents the opacity where CC being max and 00 being min ); // To add new configuration add new key, value pair in envConfigs @@ -73,9 +74,9 @@ class EnvironmentConfig { final String envType; final String version; final String build; - final String baseUrl; - final String apiBaseUrl; - final String analyticsId; + final String backendUrl; + final String apiUrl; + final String firebaseId; final bool enableConsoleLogs; final bool enableLocalLogs; final bool showEnvAndVersionTag; @@ -85,9 +86,9 @@ class EnvironmentConfig { required this.envType, required this.version, required this.build, - required this.baseUrl, - required this.apiBaseUrl, - required this.analyticsId, + required this.backendUrl, + required this.apiUrl, + required this.firebaseId, required this.enableConsoleLogs, required this.enableLocalLogs, required this.showEnvAndVersionTag, @@ -98,9 +99,9 @@ class EnvironmentConfig { String? envType, String? version, String? build, - String? baseUrl, - String? apiBaseUrl, - String? analyticsId, + String? backendUrl, + String? apiUrl, + String? firebaseId, bool? enableConsoleLogs, bool? enableLocalLogs, bool? showEnvAndVersionTag, @@ -110,9 +111,9 @@ class EnvironmentConfig { envType: envType ?? this.envType, version: version ?? this.version, build: build ?? this.build, - baseUrl: baseUrl ?? this.baseUrl, - apiBaseUrl: apiBaseUrl ?? this.apiBaseUrl, - analyticsId: analyticsId ?? this.analyticsId, + backendUrl: backendUrl ?? this.backendUrl, + apiUrl: apiUrl ?? this.apiUrl, + firebaseId: firebaseId ?? this.firebaseId, enableConsoleLogs: enableConsoleLogs ?? this.enableConsoleLogs, enableLocalLogs: enableLocalLogs ?? this.enableLocalLogs, showEnvAndVersionTag: showEnvAndVersionTag ?? this.showEnvAndVersionTag, diff --git a/lib/main.dart b/lib/main.dart index a97d41d6..b39cec71 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,9 +2,10 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'env.dart'; -import 'vaahextendflutter/log/console.dart'; import 'vaahextendflutter/base/base_stateful.dart'; -import 'vaahextendflutter/tag/tag.dart'; +import 'vaahextendflutter/helpers/constants.dart'; +import 'vaahextendflutter/log/console.dart'; +import 'vaahextendflutter/tag/tag_panel.dart'; void main() { WidgetsFlutterBinding.ensureInitialized(); @@ -22,6 +23,8 @@ void main() { runApp(const TeamApp()); } +final _navigatorKey = GlobalKey(); + class TeamApp extends StatelessWidget { const TeamApp({super.key}); @@ -30,14 +33,30 @@ class TeamApp extends StatelessWidget { return MaterialApp( title: 'WebReinvent Team', theme: ThemeData( - primarySwatch: Colors.blue, + primarySwatch: kPrimaryColor, ), - home: const TeamHomePage(), + onGenerateInitialRoutes: (String initialRoute) { + return [TeamHomePage.route()]; + }, + onGenerateRoute: onGenerateRoute, + builder: (BuildContext context, Widget? child) { + return TagPanelHost( + navigatorKey: _navigatorKey, + child: child!, + ); + }, ); } } class TeamHomePage extends StatefulWidget { + static Route route() { + return MaterialPageRoute( + settings: const RouteSettings(name: '/'), + builder: (_) => const TeamHomePage(), + ); + } + const TeamHomePage({super.key}); @override @@ -58,13 +77,16 @@ class _TeamHomePageState extends BaseStateful { super.build(context); return Scaffold( appBar: AppBar(), - body: const TagWrapper( - alignment: Alignment.topCenter, - margin: EdgeInsets.all(10), - child: Center( - child: Text('Webreinvent'), - ), + body: const Center( + child: Text('Webreinvent'), ), ); } } + +Route? onGenerateRoute(RouteSettings settings) { + if (settings.name == '/') { + return TeamHomePage.route(); + } + return null; +} diff --git a/lib/vaahextendflutter/base/base_stateless.dart b/lib/vaahextendflutter/base/base_stateless.dart index fb407dcb..e83c2e1d 100644 --- a/lib/vaahextendflutter/base/base_stateless.dart +++ b/lib/vaahextendflutter/base/base_stateless.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import '../services/screen_util.dart'; abstract class BaseStateless extends StatelessWidget with DynamicSize { diff --git a/lib/vaahextendflutter/helpers/constants.dart b/lib/vaahextendflutter/helpers/constants.dart new file mode 100644 index 00000000..50edaea9 --- /dev/null +++ b/lib/vaahextendflutter/helpers/constants.dart @@ -0,0 +1,118 @@ +import 'package:flutter/material.dart'; + +const double kDeafaultPadding = 16.0; +const double kDeafaultMargin = 16.0; + +const MaterialColor kPrimaryColor = Colors.amber; +const MaterialColor kSecondaryColor = Colors.amber; + +// Common Widgets +const emptyWidget = SizedBox(); +const emptyWidgetWide = SizedBox(width: double.infinity); +const emptyIconButton = SizedBox(width: kMinInteractiveDimension); + +// Layout Margins +const horizontalMargin4 = SizedBox(width: 4.0); +const horizontalMargin8 = SizedBox(width: 8.0); +const horizontalMargin12 = SizedBox(width: 12.0); +const horizontalMargin16 = SizedBox(width: 16.0); +const horizontalMargin24 = SizedBox(width: 24.0); +const horizontalMargin32 = SizedBox(width: 32.0); +const horizontalMargin48 = SizedBox(width: 48.0); + +const verticalMargin2 = SizedBox(height: 2.0); +const verticalMargin4 = SizedBox(height: 4.0); +const verticalMargin8 = SizedBox(height: 8.0); +const verticalMargin12 = SizedBox(height: 12.0); +const verticalMargin16 = SizedBox(height: 16.0); +const verticalMargin24 = SizedBox(height: 24.0); +const verticalMargin32 = SizedBox(height: 32.0); +const verticalMargin48 = SizedBox(height: 48.0); + +const sliverVerticalMargin4 = SliverToBoxAdapter(child: SizedBox(height: 4.0)); +const sliverVerticalMargin8 = SliverToBoxAdapter(child: SizedBox(height: 8.0)); +const sliverVerticalMargin12 = + SliverToBoxAdapter(child: SizedBox(height: 12.0)); +const sliverVerticalMargin16 = + SliverToBoxAdapter(child: SizedBox(height: 16.0)); +const sliverVerticalMargin24 = + SliverToBoxAdapter(child: SizedBox(height: 24.0)); +const sliverVerticalMargin32 = + SliverToBoxAdapter(child: SizedBox(height: 32.0)); +const sliverVerticalMargin48 = + SliverToBoxAdapter(child: SizedBox(height: 48.0)); + +// Layout Paddings +const horizontalPadding4 = EdgeInsets.symmetric(horizontal: 4.0); +const horizontalPadding8 = EdgeInsets.symmetric(horizontal: 8.0); +const horizontalPadding12 = EdgeInsets.symmetric(horizontal: 12.0); +const horizontalPadding16 = EdgeInsets.symmetric(horizontal: 16.0); +const horizontalPadding24 = EdgeInsets.symmetric(horizontal: 24.0); +const horizontalPadding32 = EdgeInsets.symmetric(horizontal: 32.0); +const horizontalPadding48 = EdgeInsets.symmetric(horizontal: 48.0); + +const verticalPadding2 = EdgeInsets.symmetric(vertical: 2.0); +const verticalPadding4 = EdgeInsets.symmetric(vertical: 4.0); +const verticalPadding8 = EdgeInsets.symmetric(vertical: 8.0); +const verticalPadding12 = EdgeInsets.symmetric(vertical: 12.0); +const verticalPadding16 = EdgeInsets.symmetric(vertical: 16.0); +const verticalPadding24 = EdgeInsets.symmetric(vertical: 24.0); +const verticalPadding32 = EdgeInsets.symmetric(vertical: 32.0); +const verticalPadding48 = EdgeInsets.symmetric(vertical: 48.0); + +const emptyPadding = EdgeInsets.zero; + +const allPadding4 = EdgeInsets.all(4.0); +const allPadding8 = EdgeInsets.all(8.0); +const allPadding12 = EdgeInsets.all(12.0); +const allPadding16 = EdgeInsets.all(16.0); +const allPadding24 = EdgeInsets.all(24.0); +const allPadding32 = EdgeInsets.all(32.0); +const allPadding48 = EdgeInsets.all(48.0); + +const leftPadding4 = EdgeInsets.only(left: 4.0); +const leftPadding8 = EdgeInsets.only(left: 8.0); +const leftPadding12 = EdgeInsets.only(left: 12.0); +const leftPadding16 = EdgeInsets.only(left: 16.0); +const leftPadding24 = EdgeInsets.only(left: 24.0); +const leftPadding32 = EdgeInsets.only(left: 32.0); +const leftPadding48 = EdgeInsets.only(left: 48.0); + +const topPadding1 = EdgeInsets.only(top: 1.0); +const topPadding2 = EdgeInsets.only(top: 2.0); +const topPadding4 = EdgeInsets.only(top: 4.0); +const topPadding8 = EdgeInsets.only(top: 8.0); +const topPadding12 = EdgeInsets.only(top: 12.0); +const topPadding16 = EdgeInsets.only(top: 16.0); +const topPadding24 = EdgeInsets.only(top: 24.0); +const topPadding32 = EdgeInsets.only(top: 32.0); +const topPadding48 = EdgeInsets.only(top: 48.0); + +const rightPadding4 = EdgeInsets.only(right: 4.0); +const rightPadding8 = EdgeInsets.only(right: 8.0); +const rightPadding12 = EdgeInsets.only(right: 12.0); +const rightPadding16 = EdgeInsets.only(right: 16.0); +const rightPadding24 = EdgeInsets.only(right: 24.0); +const rightPadding32 = EdgeInsets.only(right: 32.0); +const rightPadding48 = EdgeInsets.only(right: 48.0); + +const bottomPadding1 = EdgeInsets.only(bottom: 1.0); +const bottomPadding2 = EdgeInsets.only(bottom: 2.0); +const bottomPadding4 = EdgeInsets.only(bottom: 4.0); +const bottomPadding8 = EdgeInsets.only(bottom: 8.0); +const bottomPadding12 = EdgeInsets.only(bottom: 12.0); +const bottomPadding16 = EdgeInsets.only(bottom: 16.0); +const bottomPadding24 = EdgeInsets.only(bottom: 24.0); +const bottomPadding32 = EdgeInsets.only(bottom: 32.0); +const bottomPadding48 = EdgeInsets.only(bottom: 48.0); + +const duration250milli = + Duration(milliseconds: 250); // best suitable for animations +const duration300milli = Duration(milliseconds: 300); +const duration400milli = Duration(milliseconds: 400); +const duration500milli = Duration(milliseconds: 500); +const duration600milli = Duration(milliseconds: 600); +const duration700milli = Duration(milliseconds: 700); +const duration800milli = Duration(milliseconds: 800); +const duration900milli = Duration(milliseconds: 900); +const duration1000milli = Duration(milliseconds: 1000); diff --git a/lib/vaahextendflutter/helpers/styles.dart b/lib/vaahextendflutter/helpers/styles.dart new file mode 100644 index 00000000..87bced55 --- /dev/null +++ b/lib/vaahextendflutter/helpers/styles.dart @@ -0,0 +1,171 @@ +import 'package:flutter/material.dart'; +import '../services/screen_util.dart'; + +class TextStyles { + const TextStyles._(); + + // Regular + static final regular0 = _baseRegular[TextSize.size0]; + static final regular1 = _baseRegular[TextSize.size1]; + static final regular2 = _baseRegular[TextSize.size2]; + static final regular3 = _baseRegular[TextSize.size3]; + static final regular4 = _baseRegular[TextSize.size4]; + static final regular5 = _baseRegular[TextSize.size5]; + static final regular6 = _baseRegular[TextSize.size6]; + static final regular7 = _baseRegular[TextSize.size7]; + static final regular8 = _baseRegular[TextSize.size8]; + + // Semi-bold + static final semiBold0 = _baseSemiBold[TextSize.size0]; + static final semiBold1 = _baseSemiBold[TextSize.size1]; + static final semiBold2 = _baseSemiBold[TextSize.size2]; + static final semiBold3 = _baseSemiBold[TextSize.size3]; + static final semiBold4 = _baseSemiBold[TextSize.size4]; + static final semiBold5 = _baseSemiBold[TextSize.size5]; + static final semiBold6 = _baseSemiBold[TextSize.size6]; + static final semiBold7 = _baseSemiBold[TextSize.size7]; + static final semiBold8 = _baseSemiBold[TextSize.size8]; + + // Bold + static final bold0 = _baseBold[TextSize.size0]; + static final bold1 = _baseBold[TextSize.size1]; + static final bold2 = _baseBold[TextSize.size2]; + static final bold3 = _baseBold[TextSize.size3]; + static final bold4 = _baseBold[TextSize.size4]; + static final bold5 = _baseBold[TextSize.size5]; + static final bold6 = _baseBold[TextSize.size6]; + static final bold7 = _baseBold[TextSize.size7]; + static final bold8 = _baseBold[TextSize.size8]; + + // Bold Underlined + static final boldUnderlined0 = _baseBoldUnder[TextSize.size0]; + static final boldUnderlined1 = _baseBoldUnder[TextSize.size1]; + static final boldUnderlined2 = _baseBoldUnder[TextSize.size2]; + static final boldUnderlined3 = _baseBoldUnder[TextSize.size3]; + static final boldUnderlined4 = _baseBoldUnder[TextSize.size4]; + static final boldUnderlined5 = _baseBoldUnder[TextSize.size5]; + static final boldUnderlined6 = _baseBoldUnder[TextSize.size6]; + static final boldUnderlined7 = _baseBoldUnder[TextSize.size7]; + static final boldUnderlined8 = _baseBoldUnder[TextSize.size8]; + + // -------------------------------------------------------------------------- + + // static final _baseLight = { + // TextSize.size0: createBaseTextStyle(TextWeight.light, TextSize.size0), + // TextSize.size1: createBaseTextStyle(TextWeight.light, TextSize.size1), + // TextSize.size2: createBaseTextStyle(TextWeight.light, TextSize.size2), + // TextSize.size3: createBaseTextStyle(TextWeight.light, TextSize.size3), + // TextSize.size4: createBaseTextStyle(TextWeight.light, TextSize.size4), + // TextSize.size5: createBaseTextStyle(TextWeight.light, TextSize.size5), + // TextSize.size6: createBaseTextStyle(TextWeight.light, TextSize.size6), + // TextSize.size7: createBaseTextStyle(TextWeight.light, TextSize.size7), + // TextSize.size8: createBaseTextStyle(TextWeight.light, TextSize.size8), + // }; + + static final _baseRegular = { + TextSize.size0: createBaseTextStyle(TextWeight.regular, TextSize.size0), + TextSize.size1: createBaseTextStyle(TextWeight.regular, TextSize.size1), + TextSize.size2: createBaseTextStyle(TextWeight.regular, TextSize.size2), + TextSize.size3: createBaseTextStyle(TextWeight.regular, TextSize.size3), + TextSize.size4: createBaseTextStyle(TextWeight.regular, TextSize.size4), + TextSize.size5: createBaseTextStyle(TextWeight.regular, TextSize.size5), + TextSize.size6: createBaseTextStyle(TextWeight.regular, TextSize.size6), + TextSize.size7: createBaseTextStyle(TextWeight.regular, TextSize.size7), + TextSize.size8: createBaseTextStyle(TextWeight.regular, TextSize.size8), + }; + + static final _baseSemiBold = { + TextSize.size0: createBaseTextStyle(TextWeight.semiBold, TextSize.size0), + TextSize.size1: createBaseTextStyle(TextWeight.semiBold, TextSize.size1), + TextSize.size2: createBaseTextStyle(TextWeight.semiBold, TextSize.size2), + TextSize.size3: createBaseTextStyle(TextWeight.semiBold, TextSize.size3), + TextSize.size4: createBaseTextStyle(TextWeight.semiBold, TextSize.size4), + TextSize.size5: createBaseTextStyle(TextWeight.semiBold, TextSize.size5), + TextSize.size6: createBaseTextStyle(TextWeight.semiBold, TextSize.size6), + TextSize.size7: createBaseTextStyle(TextWeight.semiBold, TextSize.size7), + TextSize.size8: createBaseTextStyle(TextWeight.semiBold, TextSize.size8), + }; + + static final _baseBold = { + TextSize.size0: createBaseTextStyle(TextWeight.bold, TextSize.size0), + TextSize.size1: createBaseTextStyle(TextWeight.bold, TextSize.size1), + TextSize.size2: createBaseTextStyle(TextWeight.bold, TextSize.size2), + TextSize.size3: createBaseTextStyle(TextWeight.bold, TextSize.size3), + TextSize.size4: createBaseTextStyle(TextWeight.bold, TextSize.size4), + TextSize.size5: createBaseTextStyle(TextWeight.bold, TextSize.size5), + TextSize.size6: createBaseTextStyle(TextWeight.bold, TextSize.size6), + TextSize.size7: createBaseTextStyle(TextWeight.bold, TextSize.size7), + TextSize.size8: createBaseTextStyle(TextWeight.bold, TextSize.size8), + }; + + static final _baseBoldUnder = { + TextSize.size0: + createBaseTextStyle(TextWeight.bold, TextSize.size0, underline: true), + TextSize.size1: + createBaseTextStyle(TextWeight.bold, TextSize.size1, underline: true), + TextSize.size2: + createBaseTextStyle(TextWeight.bold, TextSize.size2, underline: true), + TextSize.size3: + createBaseTextStyle(TextWeight.bold, TextSize.size3, underline: true), + TextSize.size4: + createBaseTextStyle(TextWeight.bold, TextSize.size4, underline: true), + TextSize.size5: + createBaseTextStyle(TextWeight.bold, TextSize.size5, underline: true), + TextSize.size6: + createBaseTextStyle(TextWeight.bold, TextSize.size6, underline: true), + TextSize.size7: + createBaseTextStyle(TextWeight.bold, TextSize.size7, underline: true), + TextSize.size8: + createBaseTextStyle(TextWeight.bold, TextSize.size8, underline: true), + }; + + static TextStyle createBaseTextStyle(TextWeight weight, TextSize size, + {Color? color, double? lineHeight, bool underline = false}) { + final fontSize = _fontSizes[size]!; + return TextStyle( + fontWeight: _fontWeights[weight]!, + fontSize: fontSize, + decoration: underline ? TextDecoration.underline : null, + height: (lineHeight ?? _lineHeights[size]!) / fontSize, + ); + } + + static const _fontWeights = { + TextWeight.light: FontWeight.w300, + TextWeight.regular: FontWeight.w400, + TextWeight.semiBold: FontWeight.w600, + TextWeight.bold: FontWeight.w700, + }; + + static final _fontSizes = { + TextSize.size0: 10.0.spExt, + TextSize.size1: 12.0.spExt, + TextSize.size2: 14.0.spExt, + TextSize.size3: 15.0.spExt, + TextSize.size4: 16.0.spExt, + TextSize.size5: 18.0.spExt, + TextSize.size6: 21.0.spExt, + TextSize.size7: 24.0.spExt, + TextSize.size8: 27.0.spExt, + }; + + static final _lineHeights = { + TextSize.size0: 14.0.spExt, + TextSize.size1: 16.0.spExt, + TextSize.size2: 19.0.spExt, + TextSize.size3: 20.0.spExt, + TextSize.size4: 21.0.spExt, + TextSize.size5: 24.0.spExt, + TextSize.size6: 27.0.spExt, + TextSize.size7: 30.0.spExt, + TextSize.size8: 33.0.spExt, + }; +} + +enum TextSize { size0, size1, size2, size3, size4, size5, size6, size7, size8 } + +enum TextWeight { light, regular, semiBold, bold } + +extension TextStyleWithColor on TextStyle? { + TextStyle withColor(Color color) => this!.copyWith(color: color); +} diff --git a/lib/vaahextendflutter/helpers/theme.dart b/lib/vaahextendflutter/helpers/theme.dart new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/lib/vaahextendflutter/helpers/theme.dart @@ -0,0 +1 @@ + diff --git a/lib/vaahextendflutter/services/screen_util.dart b/lib/vaahextendflutter/services/screen_util.dart index ca094aeb..f30a2811 100644 --- a/lib/vaahextendflutter/services/screen_util.dart +++ b/lib/vaahextendflutter/services/screen_util.dart @@ -6,10 +6,31 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; // @override // Widget build(BuildContext context) { // initDynamicSize(context); -// return Container(); +// return SizedBox( +// width: 300.wExt, // or swExt +// height: 200.hExt, // or shExt +// child: Text( +// 'demo', +// style: TextStyle( +// fontSize: 20.spExt, +// ), +// ), +// ); // } // } +// ApplySize: +// SizedBox( +// width: 300.wExt, // or swExt +// height: 200.hExt, // or shExt +// child: Text( +// 'demo', +// style: TextStyle( +// fontSize: 20.spExt, +// ), +// ), +// ); + mixin DynamicSize { // check for logical size of the device https://www.ios-resolution.com/ void initDynamicSize(BuildContext context) { diff --git a/lib/vaahextendflutter/tag/tag.dart b/lib/vaahextendflutter/tag/tag.dart deleted file mode 100644 index 901fdf10..00000000 --- a/lib/vaahextendflutter/tag/tag.dart +++ /dev/null @@ -1,84 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; - -import '../../env.dart'; -import '../services/screen_util.dart'; - -class TagWrapper extends StatelessWidget { - final Widget child; - final EdgeInsets? margin; - final AlignmentGeometry? alignment; - - const TagWrapper({ - super.key, - required this.child, - this.margin, - this.alignment, - }); - - @override - Widget build(BuildContext context) { - bool showEnvAndVersionTag = false; - EnvController? envController; - bool envControllerExists = Get.isRegistered(); - if (envControllerExists) { - envController = Get.find(); - showEnvAndVersionTag = envController.config.showEnvAndVersionTag; - } - return showEnvAndVersionTag - ? Stack( - children: [ - child, - wrapAlignment( - alignment: alignment, - child: Container( - margin: margin, - child: tagWidget( - color: Colors.red, - envType: envController!.config.envType, - version: envController.config.version, - build: envController.config.build, - ), - ), - ), - ], - ) - : child; - } -} - -Widget tagWidget({ - required Color color, - required String envType, - required String version, - required String build, -}) { - return Container( - padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 4), - decoration: BoxDecoration( - border: Border.all( - color: Colors.red, - width: 2, - ), - borderRadius: BorderRadius.circular(20), - ), - child: Text( - '$envType $version +$build', - style: TextStyle( - fontSize: 12.spExt, - color: color, - fontWeight: FontWeight.bold, - ), - ), - ); -} - -Widget wrapAlignment({AlignmentGeometry? alignment, required Widget child}) { - if (alignment != null) { - return Align( - alignment: alignment, - child: child, - ); - } - return child; -} diff --git a/lib/vaahextendflutter/tag/tag_panel.dart b/lib/vaahextendflutter/tag/tag_panel.dart new file mode 100644 index 00000000..0b01df29 --- /dev/null +++ b/lib/vaahextendflutter/tag/tag_panel.dart @@ -0,0 +1,386 @@ +// ***************************************** +// Dev helper panel that comes from bottom +// example: https://img-v4.getdemo.dev/screenshot/qemu-system-x86_64_9g9eFWHZK5.mp4 + +// If you change any code in this file you'll probably have to restart the app +// HotReload won't work because most of the variables are constants and are +// assigned with some values when material app is build. +// ***************************************** + +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../env.dart'; +import '../helpers/constants.dart'; +import '../helpers/styles.dart'; + +const double constHandleWidth = 180.0; // tag handle width +const double constHandleHeight = 28.0; // tag handle height + +@immutable +class TagPanelHost extends StatefulWidget { + const TagPanelHost({ + Key? key, + required this.navigatorKey, + required this.child, + }) : super(key: key); + + final GlobalKey navigatorKey; + final Widget child; + + @override + TagPanelHostState createState() => TagPanelHostState(); + + static TagPanelHostState of(BuildContext context) { + return context.findAncestorStateOfType()!; + } +} + +class TagPanelHostState extends State + with SingleTickerProviderStateMixin { + final _drawerKey = GlobalKey(); + final _focusScopeNode = FocusScopeNode(); + final _handleHeight = constHandleHeight; + late AnimationController _controller; + + // To determine whether to show tag or not deending on env variable + EnvController? envController; + bool showEnvAndVersionTag = false; + + @override + void initState() { + super.initState(); + // check if envController Exists in app or not + bool envControllerExists = Get.isRegistered(); + if (envControllerExists) { + // get env controller and set variable showEnvAndVersionTag + envController = Get.find(); + showEnvAndVersionTag = + envController?.config.showEnvAndVersionTag ?? false; + } + // initialise AnimationController + _controller = AnimationController( + duration: duration250milli, + vsync: this, + ); + // addStatusListener to focus and unfocus the panel shown + _controller.addStatusListener( + (AnimationStatus status) { + if (status == AnimationStatus.dismissed) { + _focusScopeNode.unfocus(); + } + }, + ); + } + + NavigatorState get navigator => widget.navigatorKey.currentState!; + + // will open panel + void open() => _controller.fling(velocity: 1.0); + + // will close panel + void close() => _controller.fling(velocity: -1.0); + + // will open/ close panel based on if panel is half open or close + void toggle() { + if (_controller.value > 0.5) { + close(); + } else { + open(); + } + } + + @override + Widget build(BuildContext context) { + return showEnvAndVersionTag + ? LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + final height = constraints.maxHeight; + final minFactor = (_handleHeight / height); + return Stack( + fit: StackFit.expand, + children: [ + widget.child, + GestureDetector( + onVerticalDragDown: (DragDownDetails details) { + _controller.stop(); + }, + onVerticalDragUpdate: (DragUpdateDetails details) { + _controller.value += (-details.primaryDelta! / height); + }, + onVerticalDragEnd: (DragEndDetails details) { + if (_controller.isDismissed) { + return; + } + if (details.primaryVelocity!.abs() >= 365.0) { + final visualVelocity = + -details.primaryVelocity! / height; + _controller.fling(velocity: visualVelocity); + } else if (_controller.value < 0.5) { + close(); + } else { + open(); + } + }, + onVerticalDragCancel: () { + if (_controller.isDismissed || _controller.isAnimating) { + return; + } + if (_controller.value < 0.5) { + close(); + } else { + open(); + } + }, + excludeFromSemantics: true, + child: RepaintBoundary( + child: Align( + alignment: Alignment.bottomCenter, + child: AnimatedBuilder( + animation: _controller, + builder: (BuildContext context, Widget? child) { + return Align( + alignment: Alignment.topCenter, + heightFactor: _controller.value + minFactor, + child: child, + ); + }, + child: RepaintBoundary( + child: FocusScope( + key: _drawerKey, + node: _focusScopeNode, + child: _EnvPanel( + handleHeight: _handleHeight, + onHandlePressed: toggle, + config: envController!.config, + child: Builder( + builder: (BuildContext context) { + return ListView( + primary: false, + padding: EdgeInsets.only( + top: + MediaQuery.of(context).padding.top + + kDeafaultPadding + + _handleHeight, + bottom: kDeafaultPadding, + left: kDeafaultPadding, + right: kDeafaultPadding, + ), + children: [ + SelectableText( + envController!.config.envType, + style: TextStyles.regular3, + ), + verticalMargin4, + SelectableText( + 'Version: ${envController!.config.version}', + style: TextStyles.regular3, + ), + verticalMargin4, + SelectableText( + 'Build: ${envController!.config.build}', + style: TextStyles.regular3, + ), + verticalMargin16, + SelectableText( + 'Backend URL: ${envController!.config.backendUrl}', + style: TextStyles.regular3, + ), + verticalMargin8, + SelectableText( + 'API URL: ${envController!.config.apiUrl}', + style: TextStyles.regular3, + ), + verticalMargin8, + SelectableText( + 'Firebase Id: ${envController!.config.firebaseId}', + style: TextStyles.regular3, + ), + verticalMargin8, + SelectableText( + 'Console Logs Enabled: ${envController!.config.enableConsoleLogs}', + style: TextStyles.regular3, + ), + verticalMargin8, + SelectableText( + 'Local Logs Enabled: ${envController!.config.enableLocalLogs}', + style: TextStyles.regular3, + ), + verticalMargin8, + ], + ); + }, + ), + ), + ), + ), + ), + ), + ), + ), + ], + ); + }, + ) + : widget.child; + } +} + +@immutable +class _EnvPanel extends StatelessWidget { + const _EnvPanel({ + Key? key, + required this.handleHeight, + required this.onHandlePressed, + required this.config, + required this.child, + }) : super(key: key); + + final double handleHeight; + final VoidCallback onHandlePressed; + final EnvironmentConfig config; + final Widget child; + + @override + Widget build(BuildContext context) { + return Theme( + data: ThemeData( + primaryColor: config.envAndVersionTagColor, + colorScheme: ColorScheme.fromSwatch( + accentColor: config.envAndVersionTagColor, + brightness: Brightness.dark, + ), + ), + child: Material( + color: config.envAndVersionTagColor, + clipBehavior: Clip.antiAlias, + shape: const _PanelBorder(), + child: Stack( + fit: StackFit.expand, + children: [ + RepaintBoundary( + child: Overlay( + initialEntries: [ + OverlayEntry( + maintainState: true, + builder: (BuildContext context) => child, + ), + ], + ), + ), + RepaintBoundary( + child: Align( + alignment: Alignment.topCenter, + child: InkResponse( + onTap: onHandlePressed, + radius: constHandleWidth / 1.25, + child: RotatedBox( + quarterTurns: 0, + child: SizedBox( + width: constHandleWidth, + height: handleHeight, + child: FittedBox( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 2, + ), + child: Text( + '${config.envType} ${config.version}+${config.build}', + ), + ), + ), + ), + ), + ), + ), + ), + ], + ), + ), + ); + } +} + +class _PanelBorder extends ShapeBorder { + const _PanelBorder(); + + static const double handleWidth = constHandleWidth; + static const double handleHeight = constHandleHeight + + 4; // if you want a small width line visible with tag remove + 4 + + @override + EdgeInsetsGeometry get dimensions => EdgeInsets.zero; + + @override + ShapeBorder scale(double t) => const _PanelBorder(); + + @override + Path getInnerPath(Rect rect, {TextDirection? textDirection}) { + return Path()..addRect(rect); + } + + @override + Path getOuterPath(Rect rect, {TextDirection? textDirection}) { + const borderRadius = BorderRadius.all(Radius.circular(handleHeight / 2)); + + final width = ((rect.width - handleWidth) / 2); + final leftend = rect.left + width; + final rightend = rect.right - width; + return Path.combine( + PathOperation.union, + Path.combine( + PathOperation.difference, + Path() + ..addRect( + rect, + ), + Path() + ..addRRect( + borderRadius.toRRect( + Rect.fromLTRB( + rect.left - handleWidth, + -handleHeight, + leftend, + handleHeight - 4.0, + ), + ), + ) + ..addRRect( + borderRadius.toRRect( + Rect.fromLTRB( + rightend, + -handleHeight, + rect.right + handleHeight, + handleHeight - 4.0, + ), + ), + ) + ..addRect( + Rect.fromLTWH( + leftend, + 0, + handleWidth, + handleHeight / 2, + ), + ), + ), + Path() + ..addRRect( + borderRadius.toRRect( + Rect.fromLTWH( + leftend, + 0, + handleWidth, + handleHeight, + ), + ), + ), + ); + } + + @override + void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) { + // + } +}