diff --git a/lib/customwidgets/datadisplay/bookshelf/legendBookshelf.dart b/lib/customwidgets/datadisplay/bookshelf/legendBookshelf.dart new file mode 100644 index 0000000..f489070 --- /dev/null +++ b/lib/customwidgets/datadisplay/bookshelf/legendBookshelf.dart @@ -0,0 +1,104 @@ +import 'package:flutter/material.dart'; +import 'package:webstore/customwidgets/datadisplay/carousel/legendCarouselItem.dart'; +import 'package:webstore/customwidgets/legendButton/legendButton.dart'; + +class LegendBookshelf extends StatefulWidget { + final double? height; + final List items; + final Duration? animationDuration; + + LegendBookshelf({ + Key? key, + this.height, + required this.items, + this.animationDuration, + }) : super(key: key); + + @override + _LegendBookshelfState createState() => _LegendBookshelfState(); +} + +class _LegendBookshelfState extends State { + late int selected; + late CrossFadeState state; + + @override + void initState() { + super.initState(); + selected = widget.items.indexOf(widget.items.first); + state = CrossFadeState.showFirst; + } +/* + List getItems(double width) { + List items = widget.items + .map( + (w) => LegendCarouselItem( + maxWidth: width, + item: w, + duration: widget.animationDuration ?? Duration(milliseconds: 250), + selected: selected == widget.items.indexOf(w), + ), + ) + .toList(); + + return items; + }*/ + + void changedSelected(bool right) { + int dir = right ? 1 : -1; + + if ((right && selected < widget.items.length - 1) || + (!right && selected > 0)) { + setState(() { + selected += dir; + }); + } + } + + @override + Widget build(BuildContext context) { + return LayoutBuilder(builder: (context, c) { + double w = c.maxWidth; + return Container( + height: widget.height, + width: MediaQuery.of(context).size.width, + color: Colors.transparent, + child: Stack( + children: [ + Align( + alignment: Alignment.center, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [], //getItems(w), + ), + ), + Align( + alignment: Alignment.centerRight, + child: SizedBox( + width: 100, + child: LegendButton( + text: Text("next"), + onPressed: () { + changedSelected(true); + }, + ), + ), + ), + Align( + alignment: Alignment.centerLeft, + child: Container( + width: 100, + child: LegendButton( + text: Text("back"), + onPressed: () { + changedSelected(false); + }, + ), + ), + ), + ], + ), + ); + }); + } +} diff --git a/lib/customwidgets/datadisplay/bookshelf/legendBookshelfItem.dart b/lib/customwidgets/datadisplay/bookshelf/legendBookshelfItem.dart new file mode 100644 index 0000000..dc6bb4d --- /dev/null +++ b/lib/customwidgets/datadisplay/bookshelf/legendBookshelfItem.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +class LegendBookshelfItem extends StatelessWidget { + final Widget item; + final Duration duration; + final bool selected; + final double maxWidth; + + LegendBookshelfItem({ + required this.item, + required this.duration, + required this.selected, + required this.maxWidth, + }); + + @override + Widget build(BuildContext context) { + return Container( + child: AnimatedCrossFade( + firstChild: SizedBox( + child: item, + width: maxWidth, + height: MediaQuery.of(context).size.height, + ), + secondChild: Container( + width: 0, + child: item, + height: MediaQuery.of(context).size.height, + ), + crossFadeState: + selected ? CrossFadeState.showFirst : CrossFadeState.showSecond, + duration: duration, + ), + ); + } +} diff --git a/lib/customwidgets/datadisplay/carousel/legendCarousel.dart b/lib/customwidgets/datadisplay/carousel/legendCarousel.dart new file mode 100644 index 0000000..cbdaa4f --- /dev/null +++ b/lib/customwidgets/datadisplay/carousel/legendCarousel.dart @@ -0,0 +1,133 @@ +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:webstore/customwidgets/datadisplay/carousel/legendCarouselItem.dart'; +import 'package:webstore/customwidgets/icons/legendAnimatedIcon.dart'; +import 'package:webstore/customwidgets/legendButton/legendButton.dart'; + +const Duration duration = const Duration(milliseconds: 360); +Curve curve = Curves.easeInOutSine; + +class LegendCarousel extends StatefulWidget { + final double? height; + final List items; + final Duration? animationDuration; + final EdgeInsetsGeometry? padding; + late bool isInfinite; + + LegendCarousel({ + required this.items, + this.height, + this.animationDuration, + this.padding, + bool? isInfinite, + }) { + this.isInfinite = isInfinite ?? false; + } + + @override + _LegendCarouselState createState() => _LegendCarouselState(); +} + +class _LegendCarouselState extends State { + late int selected; + late PageController _scrollController; + + @override + void initState() { + super.initState(); + selected = widget.items.indexOf(widget.items.first); + + _scrollController = PageController(initialPage: selected, keepPage: true) + ..addListener(_onScroll); + } + + void _onScroll() { + int page = _scrollController.page?.toInt() ?? -1; + print(page); + } + + void selectPage(int page) { + _scrollController.animateToPage(page, duration: duration, curve: curve); + } + + List getItems(double width) { + List items = widget.items + .map( + (w) => LegendCarouselItem( + maxWidth: width, + item: w, + duration: widget.animationDuration ?? Duration(milliseconds: 250), + ), + ) + .toList(); + + return items; + } + + void changedSelected(bool right) { + int toSelect = selected + (right ? 1 : -1); + + if (toSelect >= 0 && toSelect < widget.items.length) { + setState(() { + selected = toSelect; + }); + + selectPage(toSelect); + } + } + + @override + Widget build(BuildContext context) { + return LayoutBuilder(builder: (context, c) { + double width = MediaQuery.of(context).size.width; + List items = getItems(width); + return Container( + height: widget.height, + width: MediaQuery.of(context).size.width, + color: Colors.transparent, + child: Stack( + children: [ + Align( + alignment: Alignment.center, + child: PageView( + scrollDirection: Axis.horizontal, + physics: BouncingScrollPhysics(), + children: items, + pageSnapping: true, + controller: _scrollController, + ), + ), + Align( + alignment: Alignment.centerRight, + child: LegendAnimatedIcon( + icon: Icons.arrow_forward_ios, + theme: LegendAnimtedIconTheme( + enabled: Colors.black87, + disabled: Colors.black38, + ), + padding: EdgeInsets.all(32.0), + onPressed: () { + changedSelected(true); + }, + ), + ), + Align( + alignment: Alignment.centerLeft, + child: LegendAnimatedIcon( + icon: Icons.arrow_back_ios, + theme: LegendAnimtedIconTheme( + enabled: Colors.black87, + disabled: Colors.black38, + ), + padding: EdgeInsets.all(32.0), + onPressed: () { + changedSelected(false); + }, + ), + ), + ], + ), + ); + }); + } +} diff --git a/lib/customwidgets/datadisplay/carousel/legendCarouselItem.dart b/lib/customwidgets/datadisplay/carousel/legendCarouselItem.dart new file mode 100644 index 0000000..7a72da7 --- /dev/null +++ b/lib/customwidgets/datadisplay/carousel/legendCarouselItem.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +class LegendCarouselItem extends StatelessWidget { + final Widget item; + final Duration duration; + + final double maxWidth; + + LegendCarouselItem({ + required this.item, + required this.duration, + required this.maxWidth, + }); + + @override + Widget build(BuildContext context) { + return Container( + child: SizedBox( + child: item, + width: maxWidth, + height: MediaQuery.of(context).size.height, + ), + ); + } +} diff --git a/lib/customwidgets/datadisplay/table/legendTable.dart b/lib/customwidgets/datadisplay/table/legendTable.dart index 67958fb..5168ee2 100644 --- a/lib/customwidgets/datadisplay/table/legendTable.dart +++ b/lib/customwidgets/datadisplay/table/legendTable.dart @@ -5,7 +5,7 @@ import 'package:webstore/customwidgets/legendButton/legendButton.dart'; import 'package:webstore/customwidgets/legendButton/legendButtonStyle.dart'; import 'package:webstore/customwidgets/typography/legendText.dart'; import 'package:webstore/styles/sizeProvider.dart'; -import 'package:webstore/styles/typography.dart'; +import 'package:webstore/customwidgets/typography/typography.dart'; class LegendTable extends StatelessWidget { final double? height; diff --git a/lib/customwidgets/datadisplay/table/legendTableCell.dart b/lib/customwidgets/datadisplay/table/legendTableCell.dart index 321de2c..b5d2c25 100644 --- a/lib/customwidgets/datadisplay/table/legendTableCell.dart +++ b/lib/customwidgets/datadisplay/table/legendTableCell.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:webstore/customwidgets/legendButton/legendButton.dart'; import 'package:webstore/customwidgets/typography/legendText.dart'; -import 'package:webstore/styles/typography.dart'; +import 'package:webstore/customwidgets/typography/typography.dart'; enum LegendTableValueType { TEXT, diff --git a/lib/customwidgets/icons/legendAnimatedIcon.dart b/lib/customwidgets/icons/legendAnimatedIcon.dart new file mode 100644 index 0000000..55eb8c8 --- /dev/null +++ b/lib/customwidgets/icons/legendAnimatedIcon.dart @@ -0,0 +1,111 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +class LegendAnimatedIcon extends StatefulWidget { + final IconData icon; + final LegendAnimtedIconTheme theme; + final Function onPressed; + final EdgeInsetsGeometry? padding; + + LegendAnimatedIcon({ + required this.icon, + required this.theme, + required this.onPressed, + this.padding, + }); + + @override + _LegendAnimatedIconState createState() => _LegendAnimatedIconState(); +} + +class _LegendAnimatedIconState extends State + with SingleTickerProviderStateMixin { + late bool hovered; + late AnimationController _controller; + late Animation _animation; + late Color? color; + + @override + void initState() { + hovered = false; + color = widget.theme.disabled; + _controller = AnimationController( + duration: const Duration(milliseconds: 100), vsync: this); + _animation = + ColorTween(begin: widget.theme.disabled, end: widget.theme.enabled) + .animate(_controller) + ..addListener( + () { + setState(() { + color = _animation.value; + }); + }, + ); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Container( + padding: widget.padding, + child: InkWell( + splashFactory: NoSplash.splashFactory, + splashColor: Colors.transparent, + hoverColor: Colors.transparent, + highlightColor: Colors.transparent, + onTap: () => widget.onPressed(), + onHover: (value) { + if (value && !hovered) { + if (!_controller.isAnimating || !hovered) { + _controller.forward(); + hovered = true; + } + } else { + if (!_controller.isAnimating || hovered) { + _controller.reverse(); + hovered = false; + } + } + }, + child: Container( + decoration: BoxDecoration( + boxShadow: [widget.theme.getAnimatedShadow(color)], + ), + child: Icon( + widget.icon, + color: color, + ), + ), + ), + ); + } +} + +class LegendAnimtedIconTheme { + final Color enabled; + final Color disabled; + late BoxShadow enabledBoxShadow; + + LegendAnimtedIconTheme({ + required this.enabled, + required this.disabled, + BoxShadow? boxShadow, + }) { + this.enabledBoxShadow = boxShadow ?? + BoxShadow( + color: this.enabled.withOpacity(0.2), + spreadRadius: 2, + blurRadius: 16, + offset: Offset(0, 0), + ); + } + + BoxShadow getAnimatedShadow(Color? color) { + return BoxShadow( + color: color?.withOpacity(0.2) ?? Colors.transparent, + blurRadius: enabledBoxShadow.blurRadius, + offset: enabledBoxShadow.offset, + spreadRadius: enabledBoxShadow.spreadRadius, + ); + } +} diff --git a/lib/customwidgets/icons/legendGradientIcon.dart b/lib/customwidgets/icons/legendGradientIcon.dart new file mode 100644 index 0000000..f0e89eb --- /dev/null +++ b/lib/customwidgets/icons/legendGradientIcon.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; + +class GradientIcon extends StatelessWidget { + GradientIcon( + this.icon, + this.size, + this.gradient, + ); + + final IconData icon; + final double size; + final Gradient gradient; + + @override + Widget build(BuildContext context) { + return ShaderMask( + child: SizedBox( + width: size * 1.2, + height: size * 1.2, + child: Icon( + icon, + size: size, + color: Colors.white, + ), + ), + shaderCallback: (Rect bounds) { + final Rect rect = Rect.fromLTRB(0, 0, size, size); + return gradient.createShader(rect); + }, + ); + } +} diff --git a/lib/customwidgets/icons/legendIcon.dart b/lib/customwidgets/icons/legendIcon.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/customwidgets/input/dropdown.dart/legendDropdown.dart b/lib/customwidgets/input/dropdown.dart/legendDropdown.dart new file mode 100644 index 0000000..52000e0 --- /dev/null +++ b/lib/customwidgets/input/dropdown.dart/legendDropdown.dart @@ -0,0 +1,120 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:webstore/customwidgets/input/dropdown.dart/legendDropdownOption.dart'; +import 'package:webstore/styles/legendColorTheme.dart'; +import 'package:webstore/styles/legendSizingTheme.dart'; +import 'package:webstore/styles/legendTheme.dart'; + +class LegendDropdown extends StatefulWidget { + final List options; + final Function(PopupMenuOption selected) onSelected; + final Color? color; + final double? itemHeight; + final AnimatedIconData? buttonIcon; + + LegendDropdown({ + required this.options, + required this.onSelected, + this.color, + this.itemHeight, + this.buttonIcon, + }); + + @override + _LegendDropdownState createState() => _LegendDropdownState(); +} + +class _LegendDropdownState extends State + with SingleTickerProviderStateMixin { + late AnimationController _animationController; + + @override + initState() { + _animationController = new AnimationController( + vsync: this, + duration: Duration(milliseconds: 250), + reverseDuration: Duration(milliseconds: 250), + lowerBound: 0.0, + upperBound: 1.0, + animationBehavior: AnimationBehavior.preserve, + ); + + super.initState(); + } + + PopupMenuItem getDropDownMenuItem( + String option, IconData? icon, context, LegendColorTheme colors) { + return PopupMenuItem( + height: widget.itemHeight ?? 36, + value: option, + child: Row( + children: [ + Container( + child: icon != null + ? Padding( + child: Icon( + icon, + color: colors.primaryColor, + size: 24, + ), + padding: EdgeInsets.only(right: 16), + ) + : null, + ), + /* Expanded( + child: Text( + option, + style: GoogleFonts.nunito(color: widget.theme.textColor), + ), + ),*/ + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + LegendColorTheme colors = Provider.of(context).colors; + LegendSizing sizes = Provider.of(context).sizing; + + return Container( + height: 40, + child: PopupMenuButton( + icon: GestureDetector( + child: AnimatedIcon( + icon: widget.buttonIcon ?? AnimatedIcons.menu_close, + color: widget.color, + progress: _animationController, + ), + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8), + ), + ), + onSelected: (value) { + _animationController.reverse(); + widget + .onSelected(widget.options.singleWhere((e) => e.value == value)); + }, + // color: colors.backgroundColor, + // elevation: colors.elevation, + onCanceled: () { + _animationController.reverse(); + }, + enableFeedback: true, + iconSize: 12, + offset: Offset(0, (12 ?? 0) + 8.0), + itemBuilder: (BuildContext context) { + _animationController.forward(); + return widget.options + .map( + (opt) => + getDropDownMenuItem(opt.value, opt.icon, context, colors), + ) + .toList(); + }, + ), + ); + } +} diff --git a/lib/customwidgets/input/dropdown.dart/legendDropdownOption.dart b/lib/customwidgets/input/dropdown.dart/legendDropdownOption.dart new file mode 100644 index 0000000..3e3d381 --- /dev/null +++ b/lib/customwidgets/input/dropdown.dart/legendDropdownOption.dart @@ -0,0 +1,8 @@ +import 'package:flutter/material.dart'; + +class PopupMenuOption { + final String value; + final IconData? icon; + + PopupMenuOption({required this.value, this.icon}); +} diff --git a/lib/customwidgets/input/form/formfields.dart/legendDropdownField.dart b/lib/customwidgets/input/form/formfields.dart/legendDropdownField.dart new file mode 100644 index 0000000..c9d641f --- /dev/null +++ b/lib/customwidgets/input/form/formfields.dart/legendDropdownField.dart @@ -0,0 +1,23 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:webstore/customwidgets/input/dropdown.dart/legendDropdown.dart'; +import 'package:webstore/customwidgets/input/dropdown.dart/legendDropdownOption.dart'; + +class LegendDropDownField extends FormField { + final List options; + + LegendDropDownField({ + required this.options, + }) : super( + validator: (value) {}, + builder: (field) { + return LegendDropdown( + options: options, + onSelected: (selected) { + print(selected); + }, + ); + }, + ); +} diff --git a/lib/customwidgets/input/form/legendForm.dart b/lib/customwidgets/input/form/legendForm.dart new file mode 100644 index 0000000..11c6354 --- /dev/null +++ b/lib/customwidgets/input/form/legendForm.dart @@ -0,0 +1,168 @@ +import 'package:flutter/material.dart'; +import 'package:webstore/customwidgets/input/form/legendFormField.dart'; +import 'package:webstore/customwidgets/input/switch/legendSwitch.dart'; +import 'package:webstore/customwidgets/input/text/legendTextField.dart'; +import 'package:webstore/customwidgets/legendButton/legendButton.dart'; +import 'package:webstore/customwidgets/typography/legendText.dart'; +import 'package:webstore/customwidgets/typography/typography.dart'; + +class LegendForm extends StatefulWidget { + final List children; + late List fields; + late List layouts; + final bool? autovalidate; + final double? height; + + LegendForm({ + required this.children, + this.autovalidate, + this.height, + }) { + fields = children.whereType().toList(); + layouts = children.whereType().toList(); + } + + @override + _LegendFormState createState() => _LegendFormState(); +} + +class _LegendFormState extends State { + final _formKey = GlobalKey(); + + List getFields(BuildContext context) { + List widgets = []; + + for (var i = 0; i < widget.children.length; i++) { + dynamic item = widget.children[i]; + if (item is LegendFormField) { + LegendFormField field = item; + widgets.add(getFormfield(field, context, false)); + } else if (item is LegendFormRow) { + LegendFormRow row = item; + widgets.add(getFormRow(row, context)); + } + } + return widgets; + } + + Widget getFormRow(LegendFormRow row, BuildContext context) { + List children = + row.children.map((e) => getFormfield(e, context, true)).toList(); + return Row( + children: children, + mainAxisAlignment: row.alignment ?? MainAxisAlignment.start, + ); + } + + Widget getFormfield(LegendFormField field, BuildContext context, bool isRow) { + Widget formField = Container(); + double width = MediaQuery.of(context).size.width; + + switch (field.type) { + case LegendFormFieldType.BOOL: + formField = FormField( + builder: (f) { + print(f); + return LegendSwitch( + activeColor: f.hasError ? Colors.redAccent : Colors.tealAccent, + onChanged: field.onChanged != null + ? (value) { + field.onChanged!(value); + } + : null, + ); + }, + initialValue: field.initalValue, + autovalidateMode: AutovalidateMode.disabled, + onSaved: field.onSave != null + ? (value) { + field.onSave!(value); + } + : null, + ); + break; + + case LegendFormFieldType.TEXT: + formField = TextFormField( + validator: (value) { + if (field.isRequired) { + if (field.validator != null) { + field.validator!(value); + } else { + if (value == null || value.length == 0) { + return 'Field required'; + } + } + } else if (field.validator != null) { + field.validator!(value); + } + }, + decoration: field.textField?.decoration, + initialValue: field.initalValue, + // autovalidateMode: AutovalidateMode.disabled, + onChanged: field.onChanged != null + ? (value) { + field.onChanged!(value); + } + : null, + onSaved: field.onSave != null + ? (value) { + field.onSave!(value); + } + : null, + onFieldSubmitted: field.onSave != null + ? (value) { + field.onSave!(value); + } + : null, + ); + break; + case LegendFormFieldType.NUMBER: + break; + } + + Widget w = Container( + padding: EdgeInsets.only(bottom: 12), + width: isRow ? null : width, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (field.title != null) + LegendText( + text: field.title!, + textStyle: LegendTextStyle.formHeader(), + ), + formField, + ], + ), + ); + + if (isRow) w = Expanded(child: w); + + return w; + } + + @override + Widget build(BuildContext context) { + return Container( + height: widget.height, + child: Form( + key: _formKey, + child: Column( + children: getFields(context) + + [ + LegendButton( + text: LegendText(text: "Submit"), + onPressed: () { + _formKey.currentState?.validate(); + }, + ) + ], + ), + onChanged: () { + print("test"); + }, + ), + ); + } +} diff --git a/lib/customwidgets/input/form/legendFormField.dart b/lib/customwidgets/input/form/legendFormField.dart new file mode 100644 index 0000000..e84f60e --- /dev/null +++ b/lib/customwidgets/input/form/legendFormField.dart @@ -0,0 +1,74 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:webstore/customwidgets/input/text/legendTextField.dart'; + +enum LegendFormFieldType { + TEXT, + BOOL, + NUMBER, +} + +class LegendFormRow { + final List children; + final MainAxisAlignment? alignment; + + LegendFormRow({ + required this.children, + this.alignment, + }); +} + +class LegendFormField { + final LegendFormFieldType type; + final LegendTextField? textField; + final T? initalValue; + final Function(T value)? onChanged; + final Function(T value)? onSave; + final String? title; + final Function(T? val)? validator; + late bool isRequired; + + LegendFormField({ + required this.type, + this.textField, + this.initalValue, + this.onChanged, + this.onSave, + this.title, + this.validator, + bool? isRequired, + }) { + this.isRequired = isRequired ?? false; + } + factory LegendFormField.text({ + required LegendTextField text, + Function(T value)? onChanged, + Function(T value)? onSave, + bool? isRequired, + }) { + return LegendFormField( + type: LegendFormFieldType.TEXT, + textField: text, + onChanged: onChanged, + onSave: onSave, + isRequired: isRequired, + ); + } + + factory LegendFormField.boolean({ + Function(T value)? onChanged, + Function(T value)? onSave, + Function(T? value)? validator, + required String title, + bool? isRequired, + }) { + return LegendFormField( + type: LegendFormFieldType.BOOL, + onChanged: onChanged, + onSave: onSave, + title: title, + isRequired: isRequired, + validator: validator, + ); + } +} diff --git a/lib/customwidgets/input/selectBar/legendSelectBar.dart b/lib/customwidgets/input/selectBar/legendSelectBar.dart new file mode 100644 index 0000000..bb0e680 --- /dev/null +++ b/lib/customwidgets/input/selectBar/legendSelectBar.dart @@ -0,0 +1,95 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:webstore/customwidgets/icons/legendGradientIcon.dart'; +import 'package:webstore/customwidgets/input/selectBar/selectProvider.dart'; +import 'package:webstore/styles/legendColorTheme.dart'; +import 'package:webstore/styles/legendSizingTheme.dart'; +import 'package:webstore/styles/legendTheme.dart'; + +import 'legendSelectOption.dart'; +import 'legendselectButton.dart'; + +class LegendSelectBar extends StatelessWidget { + final List options; + final void Function(LegendSelectOption selected) onSelected; + final MainAxisAlignment? aligment; + final double? iconSize; + final bool? isCard; + final EdgeInsets? margin; + final double? width; + final double? height; + + LegendSelectBar({ + required this.options, + required this.onSelected, + required this.aligment, + this.iconSize, + this.isCard, + this.margin, + this.width, + this.height, + }); + + List getOptions(BuildContext context) { + List widgets = []; + + for (LegendSelectOption o in options) { + Widget w = new LegendSelectButton( + option: o, + size: iconSize ?? 24, + onClick: (selOption) { + Provider.of(context, listen: false) + .selectOption(o); + onSelected(selOption); + }, + ); + widgets.add(w); + } + + return widgets; + } + + @override + Widget build(BuildContext context) { + LegendColorTheme theme = Provider.of(context).colors; + LegendSizing sizing = Provider.of(context).sizing; + + return ListenableProvider( + create: (c) => new LegendSelectProvider(options.first), + builder: (context, snapshot) { + return Padding( + padding: margin ?? EdgeInsets.all(4.0), + child: Container( + width: width, + height: height, + padding: EdgeInsets.all(sizing.borderRadius.bottomLeft.x / 2), + decoration: isCard ?? false + ? BoxDecoration( + borderRadius: sizing.borderRadius, + color: LegendColorTheme.darken(theme.primaryColor, 0.08), + boxShadow: [ + BoxShadow( + color: Colors.black12, + blurRadius: 4, + spreadRadius: 2, + offset: Offset( + 0, + 1, + ), + ), + ], + ) + : null, + child: Row( + mainAxisAlignment: aligment ?? MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.center, + children: getOptions(context), + ), + ), + ); + }, + ); + } +} diff --git a/lib/customwidgets/input/selectBar/legendSelectOption.dart b/lib/customwidgets/input/selectBar/legendSelectOption.dart new file mode 100644 index 0000000..b450d13 --- /dev/null +++ b/lib/customwidgets/input/selectBar/legendSelectOption.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; + +class LegendSelectOption { + final IconData? icon; + final Color? color; + final Gradient? gradient; + final String name; + + LegendSelectOption({ + this.icon, + required this.name, + this.color, + this.gradient, + }); +} diff --git a/lib/customwidgets/input/selectBar/legendselectButton.dart b/lib/customwidgets/input/selectBar/legendselectButton.dart new file mode 100644 index 0000000..421c948 --- /dev/null +++ b/lib/customwidgets/input/selectBar/legendselectButton.dart @@ -0,0 +1,173 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:webstore/customwidgets/icons/legendGradientIcon.dart'; +import 'package:webstore/customwidgets/input/selectBar/selectProvider.dart'; +import 'package:webstore/styles/legendColorTheme.dart'; + +import 'legendSelectOption.dart'; + +class LegendSelectButton extends StatefulWidget { + final LegendSelectOption option; + final void Function(LegendSelectOption option) onClick; + final double size; + late BoxShadow shadow; + late Color? hoverColor; + late Color backgroundColor; + + Gradient? gradient; + + LegendSelectButton({ + required this.option, + required this.size, + required this.onClick, + }) { + backgroundColor = option.color ?? Colors.red; + gradient = option.gradient; + + if (gradient != null) { + backgroundColor = gradient!.colors.first; + } + + shadow = BoxShadow( + color: backgroundColor.withOpacity(0.2), + spreadRadius: 2, + blurRadius: 16, + offset: Offset(0, 3), + ); + hoverColor = LegendColorTheme.darken( + backgroundColor, + 0.1, + ); + } + + @override + _LegendSelectButtonState createState() => _LegendSelectButtonState(); +} + +class _LegendSelectButtonState extends State + with SingleTickerProviderStateMixin { + late bool hovered; + late Animation animation; + late Animation shadowAnimation; + late AnimationController controller; + late Color? color; + double shadow = 0.0; + late bool selected; + + @override + void initState() { + super.initState(); + hovered = false; + selected = false; + color = widget.option.color; + controller = AnimationController( + duration: const Duration(milliseconds: 100), vsync: this); + animation = + ColorTween(begin: widget.backgroundColor, end: widget.hoverColor) + .animate(controller) + ..addListener( + () { + setState(() { + color = animation.value; + }); + }, + ); + shadowAnimation = Tween(begin: 0.0, end: 1.0).animate(controller) + ..addListener( + () { + setState(() { + shadow = shadowAnimation.value; + }); + }, + ); + } + + Widget normalIcon() { + return Icon( + widget.option.icon!, + color: color, + size: widget.size, + ); + } + + Widget gradientIcon() { + return GradientIcon( + widget.option.icon!, + widget.size, + widget.gradient!, + ); + } + + BoxShadow getShadow(Color? color) { + BoxShadow old = widget.shadow; + return BoxShadow( + color: color?.withOpacity(0.2 + shadow * 0.02) ?? Colors.transparent, + blurRadius: old.blurRadius + shadow * 1, + offset: old.offset, + spreadRadius: old.spreadRadius + shadow * 1, + ); + } + + @override + Widget build(BuildContext context) { + return Consumer(builder: (context, sel, c) { + bool s = sel.selected.name == widget.option.name; + print(s); + if (s && !selected) { + controller.forward(); + selected = true; + } else if (!s && selected) { + controller.reverse(); + selected = false; + } + return InkWell( + splashFactory: NoSplash.splashFactory, + splashColor: Colors.transparent, + hoverColor: Colors.transparent, + highlightColor: Colors.transparent, + onTap: () { + widget.onClick(widget.option); + }, + borderRadius: BorderRadius.all( + Radius.circular(widget.size / 2), + ), + onHover: (value) { + if (selected == false) { + if (value && !hovered) { + if (!controller.isAnimating || !hovered) { + controller.forward(); + hovered = true; + } + } else { + if (!controller.isAnimating || hovered) { + controller.reverse(); + hovered = false; + } + } + } + }, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.all( + Radius.circular(widget.size / 2), + ), + boxShadow: [ + getShadow(color), + ], + ), + child: getIcon(), + ), + ); + }); + } + + Widget getIcon() { + if (widget.option.gradient != null) { + return gradientIcon(); + } else { + return normalIcon(); + } + } +} diff --git a/lib/customwidgets/input/selectBar/selectProvider.dart b/lib/customwidgets/input/selectBar/selectProvider.dart new file mode 100644 index 0000000..cece6b5 --- /dev/null +++ b/lib/customwidgets/input/selectBar/selectProvider.dart @@ -0,0 +1,16 @@ +import 'package:flutter/cupertino.dart'; +import 'package:webstore/customwidgets/input/selectBar/legendSelectOption.dart'; + +class LegendSelectProvider with ChangeNotifier { + late List options; + late LegendSelectOption selected; + + LegendSelectProvider( + this.selected, + ); + + selectOption(LegendSelectOption selectOption) { + selected = selectOption; + notifyListeners(); + } +} diff --git a/lib/customwidgets/input/switch/legendSwitch.dart b/lib/customwidgets/input/switch/legendSwitch.dart new file mode 100644 index 0000000..be0df20 --- /dev/null +++ b/lib/customwidgets/input/switch/legendSwitch.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; + +class LegendSwitch extends StatefulWidget { + final Function(bool value)? onChanged; + late bool initalValue; + final Color? activeColor; + final Color? disabledColor; + + LegendSwitch({ + this.onChanged, + bool? initalValue, + this.activeColor, + this.disabledColor, + }) { + this.initalValue = initalValue ?? false; + } + + @override + _LegendSwitchState createState() => _LegendSwitchState(); +} + +class _LegendSwitchState extends State { + late bool value; + + @override + void initState() { + value = widget.initalValue; + + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Container( + child: Switch( + value: value, + activeColor: widget.activeColor, + onChanged: (val) { + setState(() { + value = val; + }); + if (widget.onChanged != null) widget.onChanged!(value); + }, + ), + ); + } +} diff --git a/lib/customwidgets/input/text/legendInputDecoration.dart b/lib/customwidgets/input/text/legendInputDecoration.dart new file mode 100644 index 0000000..81dd71c --- /dev/null +++ b/lib/customwidgets/input/text/legendInputDecoration.dart @@ -0,0 +1,258 @@ +import 'package:flutter/material.dart'; +import 'package:webstore/styles/legendColorTheme.dart'; + +class LegendInputDecoration extends InputDecoration { + final Widget? icon; + + final String? labelText; + + final TextStyle? labelStyle; + + final String? helperText; + + final TextStyle? helperStyle; + + final int? helperMaxLines; + + final String? hintText; + + final TextStyle? hintStyle; + + final TextDirection? hintTextDirection; + + final int? hintMaxLines; + + final String? errorText; + + final TextStyle? errorStyle; + + final int? errorMaxLines; + + final FloatingLabelBehavior? floatingLabelBehavior; + + final bool? isDense; + + final EdgeInsetsGeometry? contentPadding; + + final bool isCollapsed; + + final Widget? prefixIcon; + + final BoxConstraints? prefixIconConstraints; + + final Widget? prefix; + + final String? prefixText; + + final TextStyle? prefixStyle; + + final Widget? suffixIcon; + + final Widget? suffix; + + final String? suffixText; + + final TextStyle? suffixStyle; + + final BoxConstraints? suffixIconConstraints; + + final String? counterText; + + final Widget? counter; + + final TextStyle? counterStyle; + + final bool? filled; + + final Color? fillColor; + + final Color? focusColor; + + final Color? hoverColor; + + final InputBorder? focusedBorder; + + final InputBorder? focusedErrorBorder; + + final InputBorder? errorBorder; + + final InputBorder? disabledBorder; + + final InputBorder? enabledBorder; + + final InputBorder? border; + + final bool enabled; + + final String? semanticCounterText; + + final bool? alignLabelWithHint; + + final Color? cursorColor; + + final Color? textColor; + + LegendInputDecoration({ + this.icon, + this.labelText, + this.labelStyle, + this.helperText, + this.helperStyle, + this.helperMaxLines, + this.hintText, + this.hintStyle, + this.hintTextDirection, + this.hintMaxLines, + this.errorText, + this.errorStyle, + this.errorBorder, + this.errorMaxLines, + this.floatingLabelBehavior, + this.isDense, + this.contentPadding, + required this.isCollapsed, + this.prefixIcon, + this.prefixIconConstraints, + this.prefix, + this.prefixText, + this.prefixStyle, + this.suffixIcon, + this.suffix, + this.suffixText, + this.suffixStyle, + this.suffixIconConstraints, + this.counterText, + this.counter, + this.counterStyle, + this.filled, + this.fillColor, + this.focusColor, + this.hoverColor, + this.focusedBorder, + this.focusedErrorBorder, + this.disabledBorder, + this.enabledBorder, + this.border, + required this.enabled, + this.semanticCounterText, + this.alignLabelWithHint, + this.cursorColor, + this.textColor, + }) : super( + alignLabelWithHint: alignLabelWithHint, + border: border, + contentPadding: contentPadding, + counter: counter, + counterStyle: counterStyle, + counterText: counterText, + disabledBorder: disabledBorder, + enabled: enabled, + enabledBorder: enabledBorder, + errorBorder: errorBorder, + errorMaxLines: errorMaxLines, + errorStyle: errorStyle, + errorText: errorText, + fillColor: fillColor, + filled: filled, + floatingLabelBehavior: floatingLabelBehavior, + focusColor: focusColor, + focusedBorder: focusedBorder, + focusedErrorBorder: focusedErrorBorder, + helperMaxLines: helperMaxLines, + helperStyle: helperStyle, + helperText: helperText, + hintMaxLines: hintMaxLines, + hintStyle: hintStyle, + hintText: hintText, + hintTextDirection: hintTextDirection, + hoverColor: hoverColor, + icon: icon, + isCollapsed: isCollapsed, + isDense: isDense, + labelStyle: labelStyle, + labelText: labelText, + prefix: prefix, + prefixIcon: prefixIcon, + prefixIconConstraints: prefixIconConstraints, + prefixStyle: prefixStyle, + prefixText: prefixText, + semanticCounterText: semanticCounterText, + suffix: suffix, + suffixIcon: suffixIcon, + suffixIconConstraints: suffixIconConstraints, + suffixStyle: suffixStyle, + suffixText: suffixText, + ); + + factory LegendInputDecoration.rounded({ + String? error, + String? hint, + Widget? leading, + Widget? trailling, + BorderRadius? radius, + MaterialColor? borderColor, + Color? textColor, + Color? focusColor, + Color? errorColor, + double? borderWidth, + }) { + if (borderColor == null) borderColor = Colors.grey; + if (textColor == null) textColor = Colors.grey; + + OutlineInputBorder border = OutlineInputBorder( + borderRadius: radius ?? BorderRadius.all(Radius.circular(8)), + ); + + return LegendInputDecoration( + isCollapsed: false, + enabled: true, + border: border, + enabledBorder: OutlineInputBorder( + borderRadius: radius ?? + BorderRadius.all( + Radius.circular(8), + ), + // gapPadding: + borderSide: BorderSide( + color: borderColor.shade400, + width: borderWidth ?? 1.0, + ), + ), + focusedBorder: border.copyWith( + borderSide: BorderSide( + color: focusColor ?? Colors.blueAccent, + width: borderWidth ?? 1.0, + ), + ), + errorBorder: border.copyWith( + borderSide: BorderSide( + color: errorColor ?? Colors.redAccent, + width: borderWidth ?? 1.2, + ), + ), + focusedErrorBorder: border.copyWith( + borderSide: BorderSide( + color: errorColor ?? LegendColorTheme.darken(Colors.redAccent, 0.2), + width: borderWidth ?? 1.2, + ), + ), + errorText: error, + focusColor: focusColor, + cursorColor: LegendColorTheme.lighten(textColor.withOpacity(1), 0.1), + textColor: textColor, + hintText: hint, + prefixIcon: leading != null + ? Padding( + padding: EdgeInsets.only(left: 6, right: 12), + child: leading, + ) + : null, + suffixIcon: trailling != null + ? Padding( + padding: EdgeInsets.only(left: 12, right: 6), + child: trailling, + ) + : null, + ); + } +} diff --git a/lib/customwidgets/input/text/legendTextField.dart b/lib/customwidgets/input/text/legendTextField.dart new file mode 100644 index 0000000..9db6028 --- /dev/null +++ b/lib/customwidgets/input/text/legendTextField.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; +import 'package:webstore/customwidgets/input/text/legendInputDecoration.dart'; +import 'package:webstore/customwidgets/typography/typography.dart'; + +class LegendTextField extends StatefulWidget { + final LegendInputDecoration decoration; + + LegendTextField({ + required this.decoration, + Key? key, + }) : super(key: key); + + @override + _LegendTextFieldState createState() => _LegendTextFieldState(); +} + +class _LegendTextFieldState extends State { + late TextEditingController ctrl; + + @override + void initState() { + super.initState(); + ctrl = TextEditingController(); + } + + @override + Widget build(BuildContext context) { + return Container( + child: TextField( + controller: ctrl, + decoration: widget.decoration, + cursorColor: widget.decoration.cursorColor, + textAlignVertical: TextAlignVertical.top, + onSubmitted: (value) {}, + onChanged: (value) {}, + style: + LegendTextStyle.textInput(textColor: widget.decoration.textColor), + toolbarOptions: + ToolbarOptions(copy: true, selectAll: true, paste: true, cut: true), + ), + ); + } +} diff --git a/lib/customwidgets/layout/drawers/drawerMenuTile.dart b/lib/customwidgets/layout/drawers/drawerMenuTile.dart index 291ba8a..cb17e97 100644 --- a/lib/customwidgets/layout/drawers/drawerMenuTile.dart +++ b/lib/customwidgets/layout/drawers/drawerMenuTile.dart @@ -1,6 +1,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:webstore/styles/typography.dart'; +import 'package:webstore/customwidgets/typography/typography.dart'; import '../../../router/routerProvider.dart'; import '../../typography/legendText.dart'; @@ -30,13 +30,13 @@ class _DrawerMenuTileState extends State late AnimationController controller; late bool _isClicked; late bool _isHovered; - late Color? color = Colors.white; + late Color? color; Color? borderColor; @override void initState() { _isClicked = false; _isHovered = false; - + color = Colors.black; controller = new AnimationController( vsync: this, duration: Duration(milliseconds: 250), diff --git a/lib/customwidgets/layout/drawers/siderMenuVerticalTile.dart b/lib/customwidgets/layout/drawers/siderMenuVerticalTile.dart index 5d233b0..059a3a7 100644 --- a/lib/customwidgets/layout/drawers/siderMenuVerticalTile.dart +++ b/lib/customwidgets/layout/drawers/siderMenuVerticalTile.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:webstore/customwidgets/typography/legendText.dart'; import 'package:webstore/styles/legendTheme.dart'; -import 'package:webstore/styles/typography.dart'; +import 'package:webstore/customwidgets/typography/typography.dart'; import '../../../router/routerProvider.dart'; class SiderMenuVerticalTile extends StatefulWidget { @@ -22,16 +22,17 @@ class _SiderMenuVerticalTileState extends State late AnimationController controller; late bool _isClicked; late bool _isHovered; - late Color? color = Colors.white; + late Color? color; Color? borderColor; @override void initState() { _isClicked = false; _isHovered = false; + color = Colors.black; controller = new AnimationController( vsync: this, - duration: Duration(milliseconds: 250), + duration: Duration(milliseconds: 360), ); banimation = ColorTween( begin: Colors.teal, @@ -39,7 +40,7 @@ class _SiderMenuVerticalTileState extends State ).animate(controller); animation = ColorTween( - begin: Colors.white, + begin: Colors.black, end: Colors.blueAccent, ).animate(controller); @@ -67,6 +68,7 @@ class _SiderMenuVerticalTileState extends State // TODO: implement build return Container( height: 64, + margin: EdgeInsets.only(bottom: 16), decoration: BoxDecoration( border: Border( left: BorderSide( @@ -113,8 +115,9 @@ class _SiderMenuVerticalTileState extends State ), ), LegendText( + textAlign: TextAlign.center, text: widget.title ?? "", - textStyle: LegendTextStyle.h5().copyWith( + textStyle: LegendTextStyle.siderMenuCollapsed().copyWith( color: color, ), ), diff --git a/lib/customwidgets/layout/fixed/appBar.dart/fixedAppBar.dart b/lib/customwidgets/layout/fixed/appBar.dart/fixedAppBar.dart new file mode 100644 index 0000000..84ff295 --- /dev/null +++ b/lib/customwidgets/layout/fixed/appBar.dart/fixedAppBar.dart @@ -0,0 +1,62 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; +import 'package:provider/provider.dart'; +import 'package:webstore/customwidgets/layout/fixed/appBar.dart/fixedMenu.dart'; +import 'package:webstore/customwidgets/typography/legendText.dart'; +import 'package:webstore/customwidgets/typography/typography.dart'; +import '../../../../objects/menuOption.dart'; +import '../../../../router/routerProvider.dart'; +import '../../../../styles/layoutType.dart'; +import '../../../../styles/sizeProvider.dart'; +import '../../../../styles/legendTheme.dart'; + +class FixedAppBar extends StatelessWidget { + final bool? showMenu; + final WidgetBuilder? builder; + final Widget? leading; + + FixedAppBar({ + this.showMenu, + this.builder, + this.leading, + }); + + @override + Widget build(BuildContext context) { + LegendTheme theme = Provider.of(context); + + return SliverAppBar( + backgroundColor: theme.colors.primaryColor, + actions: [ + Builder( + builder: builder ?? (c) => Container(), + ), + ], + title: Hero( + tag: ValueKey("appBarTitle"), + child: Material( + color: Colors.transparent, + child: Row( + children: [ + leading ?? + LegendText( + text: "Legend Design", + textStyle: LegendTextStyle.h1(), + ), + if (showMenu ?? true) + Expanded( + child: FixedMenu(context: context), + ), + ], + ), + ), + ), + expandedHeight: theme.sizing.appbarHeight, + collapsedHeight: theme.sizing.appbarHeight, + toolbarHeight: theme.sizing.appbarHeight, + pinned: true, + automaticallyImplyLeading: false, + ); + } +} diff --git a/lib/customwidgets/layout/fixed/appBar.dart/fixedMenu.dart b/lib/customwidgets/layout/fixed/appBar.dart/fixedMenu.dart new file mode 100644 index 0000000..058f9b7 --- /dev/null +++ b/lib/customwidgets/layout/fixed/appBar.dart/fixedMenu.dart @@ -0,0 +1,69 @@ +import 'package:flutter/material.dart'; +import 'package:webstore/objects/menuOption.dart'; +import 'package:webstore/router/routerProvider.dart'; +import 'package:webstore/styles/layoutType.dart'; +import 'package:webstore/styles/sizeProvider.dart'; + +class FixedMenu extends StatelessWidget { + const FixedMenu({ + Key? key, + required this.context, + }) : super(key: key); + + final BuildContext context; + + Widget getCollapsedMenu(BuildContext context) { + return Container( + alignment: Alignment.centerRight, + child: IconButton( + iconSize: 36, + onPressed: () { + Scaffold.of(context).openEndDrawer(); + }, + icon: Icon( + Icons.menu, + color: Colors.white, + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + List options = RouterProvider.of(context).menuOptions; + + double menuWidth; + + return Container( + margin: const EdgeInsets.only(left: 16.0), + height: 80, + child: LayoutBuilder( + builder: (context, constraints) { + menuWidth = constraints.maxWidth; + + if (menuWidth > 600) { + return Row( + children: [ + Expanded( + flex: 1, + child: Container(), + ), + Container( + child: Row( + children: options, + ), + ), + Expanded( + flex: 2, + child: Container(), + ), + ], + ); + } else { + return getCollapsedMenu(context); + } + }, + ), + ); + } +} diff --git a/lib/customwidgets/layout/fixed/fixedAppBar.dart b/lib/customwidgets/layout/fixed/fixedAppBar.dart deleted file mode 100644 index d9721a1..0000000 --- a/lib/customwidgets/layout/fixed/fixedAppBar.dart +++ /dev/null @@ -1,65 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:provider/provider.dart'; -import '../../../objects/menuOption.dart'; -import '../../../router/routerProvider.dart'; -import '../../../styles/layoutType.dart'; -import '../../../styles/sizeProvider.dart'; -import '../../../styles/legendTheme.dart'; - -class FixedAppBar extends StatelessWidget { - @override - Widget build(BuildContext context) { - LegendTheme theme = Provider.of(context); - return SliverAppBar( - backgroundColor: theme.colors.primaryColor, - leading: Hero( - tag: ValueKey("appBarLeading"), - child: Container( - width: 80, - height: 80, - child: Placeholder(), - ), - ), - actions: [Container()], - title: Hero( - tag: ValueKey("appBarTitle"), - child: Material(color: Colors.transparent, child: menu(context)), - ), - expandedHeight: theme.sizing.appbarHeight, - collapsedHeight: theme.sizing.appbarHeight, - toolbarHeight: theme.sizing.appbarHeight, - pinned: true, - automaticallyImplyLeading: false, - ); - } - - Widget menu(BuildContext context) { - List options = RouterProvider.of(context).menuOptions; - ScreenSize screenSize = SizeProvider.of(context).screenSize; - - if (screenSize != ScreenSize.Small) { - return Container( - margin: const EdgeInsets.only(left: 16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: options, - ), - ); - } else { - return Container( - alignment: Alignment.centerRight, - child: IconButton( - iconSize: 36, - onPressed: () { - Scaffold.of(context).openEndDrawer(); - }, - icon: Icon( - Icons.menu, - color: Colors.white, - ), - ), - ); - } - } -} diff --git a/lib/customwidgets/layout/fixed/fixedSider.dart b/lib/customwidgets/layout/fixed/fixedSider.dart index d000495..20f9098 100644 --- a/lib/customwidgets/layout/fixed/fixedSider.dart +++ b/lib/customwidgets/layout/fixed/fixedSider.dart @@ -1,6 +1,10 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:provider/provider.dart'; +import 'package:webstore/customwidgets/layout/sections/sectionTile.dart'; +import 'package:webstore/router/routes/sectionProvider.dart'; +import 'package:webstore/router/routes/sectionRouteInfo.dart'; import '../drawers/siderMenuVerticalTile.dart'; import '../../../objects/menuOption.dart'; import '../../../router/routerProvider.dart'; @@ -11,84 +15,205 @@ import '../../../styles/legendTheme.dart'; import '../drawers/drawerMenuTile.dart'; class FixedSider extends StatelessWidget { - final bool? showMenu; + late final bool showMenu; + late final bool showSectionMenu; + WidgetBuilder? builder; - FixedSider({this.showMenu}); + FixedSider({ + bool? showMenu, + bool? showSectionMenu, + this.builder, + }) { + this.showMenu = showMenu ?? true; + this.showSectionMenu = showSectionMenu ?? false; + } @override Widget build(BuildContext context) { ScreenSize screenSize = SizeProvider.of(context).screenSize; + bool showSider = + screenSize == ScreenSize.Large || screenSize == ScreenSize.XXL; return Hero( tag: ValueKey("sider"), child: Material( elevation: 20, - child: screenSize != ScreenSize.Small - ? sider(context) - : collapsedSider(context), + child: showSider + ? Sider( + showMenu: showMenu, + builder: builder, + context: context, + showSectionMenu: showSectionMenu, + ) + : CollapsedSider( + context: context, + showMenu: showMenu, + showSectionMenu: showSectionMenu, + ), ), ); } +} + +class CollapsedSider extends StatelessWidget { + final bool showMenu; + final bool showSectionMenu; - Widget sider(BuildContext context) { + const CollapsedSider({ + Key? key, + required this.context, + required this.showMenu, + required this.showSectionMenu, + }) : super(key: key); + + final BuildContext context; + + @override + Widget build(BuildContext context) { LegendTheme theme = Provider.of(context); List options = RouterProvider.of(context).menuOptions; - List tiles = List.of( + List tiles = List.of( options.map( - (option) => DrawerMenuTile( + (option) => SiderMenuVerticalTile( icon: option.icon, title: option.title, path: option.page, - backgroundColor: Colors.teal, - left: true, ), ), ); + List sections = + SectionProvider.of(context)?.sections ?? []; + List sectionTiles = List.of( + sections.map( + (option) => SectionTile( + name: option.name, + ), + ), + ); return Container( - width: 200, + width: 80, height: MediaQuery.of(context).size.height, color: theme.colors.primaryColor, child: Column( children: [ Container( child: Placeholder(), - height: 100, + height: 80, ), - showMenu ?? false - ? ListView( - shrinkWrap: true, - children: tiles, - ) - : Container() + if (showMenu) + ListView( + shrinkWrap: true, + children: tiles, + ), + if (showSectionMenu) + ListView( + children: sectionTiles, + shrinkWrap: true, + ) ], ), ); } +} + +class Sider extends StatelessWidget { + const Sider({ + Key? key, + required this.showMenu, + required this.builder, + required this.context, + required this.showSectionMenu, + }) : super(key: key); + + final bool? showMenu; + final bool? showSectionMenu; + final WidgetBuilder? builder; + final BuildContext context; - Widget collapsedSider(BuildContext context) { + @override + Widget build(BuildContext context) { LegendTheme theme = Provider.of(context); + + ScrollController scrollController = ScrollController( + initialScrollOffset: 80.0, + ); + scrollController + ..addListener(() { + if (scrollController.offset <= 80) { + scrollController.jumpTo(80); + } + }); + List options = RouterProvider.of(context).menuOptions; - List tiles = List.of( + List tiles = List.of( options.map( - (option) => SiderMenuVerticalTile( + (option) => DrawerMenuTile( icon: option.icon, title: option.title, path: option.page, + backgroundColor: Colors.teal, + left: true, + ), + ), + ); + + List sections = + SectionProvider.of(context)?.sections ?? []; + List sectionTiles = List.of( + sections.map( + (option) => SectionTile( + name: option.name, ), ), ); + + List children = []; + + if (showMenu ?? false) { + children.add(ListView( + shrinkWrap: true, + children: tiles, + )); + } + + if (showSectionMenu ?? false) { + children.add(ListView( + shrinkWrap: true, + children: sectionTiles, + )); + } + + if (builder != null) + children.add(Builder( + builder: (context) => builder!(context), + )); + + for (var i = 1; i < children.length; i += 2) { + children.insert(i, Padding(padding: EdgeInsets.only(top: 16))); + } + return Container( - width: 80, + width: 200, height: MediaQuery.of(context).size.height, color: theme.colors.primaryColor, - child: Column( - children: [ - ListView( - shrinkWrap: true, - children: tiles, - ) - ], + child: Expanded( + child: CustomScrollView( + shrinkWrap: true, + slivers: [ + SliverAppBar( + title: Container(), + backgroundColor: theme.colors.primaryColor, + actions: [Container()], + expandedHeight: theme.sizing.appbarHeight, + collapsedHeight: theme.sizing.appbarHeight, + toolbarHeight: theme.sizing.appbarHeight, + pinned: true, + automaticallyImplyLeading: false, + ), + SliverList(delegate: SliverChildListDelegate(children)) + ], + ), ), ); } diff --git a/lib/customwidgets/layout/grid/LegendSizeBox.dart b/lib/customwidgets/layout/grid/LegendSizeBox.dart new file mode 100644 index 0000000..71120f5 --- /dev/null +++ b/lib/customwidgets/layout/grid/LegendSizeBox.dart @@ -0,0 +1,12 @@ +import 'package:flutter/material.dart'; + +class LegendSizeBox extends StatelessWidget { + const LegendSizeBox({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + child: null, + ); + } +} diff --git a/lib/customwidgets/layout/grid/legendGrid.dart b/lib/customwidgets/layout/grid/legendGrid.dart index e60c9e0..45f3ad7 100644 --- a/lib/customwidgets/layout/grid/legendGrid.dart +++ b/lib/customwidgets/layout/grid/legendGrid.dart @@ -4,7 +4,7 @@ import 'package:webstore/customwidgets/layout/sections/sectionHeader.dart'; import 'package:webstore/customwidgets/typography/legendText.dart'; import 'package:webstore/styles/layoutType.dart'; import 'package:webstore/styles/sizeProvider.dart'; -import 'package:webstore/styles/typography.dart'; +import 'package:webstore/customwidgets/typography/typography.dart'; class LegendGrid extends StatelessWidget { final List children; @@ -22,30 +22,14 @@ class LegendGrid extends StatelessWidget { int crossAxisCount; ScreenSize ss = SizeProvider.of(context).screenSize; - LegendGridSizeInfo size; - switch (ss) { - case ScreenSize.Small: - size = sizes.small; - break; - case ScreenSize.Medium: - size = sizes.medium; - break; - case ScreenSize.Large: - size = sizes.large; - break; - case ScreenSize.XXL: - size = sizes.xxl; - break; - default: - size = sizes.small; - break; - } + LegendGridSizeInfo size = sizes.getSizeForSize(ss); return LayoutBuilder(builder: (context, constraints) { int count = size.count; - double height = size.height; + double singleChildWidth = constraints.maxWidth / count; int rows = (children.length / count).ceil(); + double height = size.height * rows; double aspectRatio = singleChildWidth / (height / rows); return Container( height: height, diff --git a/lib/customwidgets/layout/grid/legendGridSize.dart b/lib/customwidgets/layout/grid/legendGridSize.dart index 3e66232..f896903 100644 --- a/lib/customwidgets/layout/grid/legendGridSize.dart +++ b/lib/customwidgets/layout/grid/legendGridSize.dart @@ -1,15 +1,104 @@ +import 'package:webstore/styles/layoutType.dart'; +import 'package:webstore/styles/legendTheme.dart'; + +enum LegendGridSizeDirection { + UP, + DOWN, +} + class LegendGridSize { - final LegendGridSizeInfo small; - final LegendGridSizeInfo medium; - final LegendGridSizeInfo large; - final LegendGridSizeInfo xxl; + late LegendGridSizeInfo? small; + late LegendGridSizeInfo? medium; + late LegendGridSizeInfo? large; + late LegendGridSizeInfo? xxl; + late LegendGridSizeDirection? layoutDirection; + + final LegendGridSizeInfo def = LegendGridSizeInfo(1, 64); LegendGridSize({ - required this.small, - required this.medium, - required this.large, - required this.xxl, - }); + LegendGridSizeInfo? small, + LegendGridSizeInfo? medium, + LegendGridSizeInfo? large, + LegendGridSizeInfo? xxl, + this.layoutDirection, + }) { + this.layoutDirection = this.layoutDirection ?? LegendGridSizeDirection.DOWN; + + List infos = [ + small, + medium, + large, + xxl, + ]; + + for (var i = 0; i < infos.length; i++) { + LegendGridSizeInfo? inf = infos[i]; + + if (inf == null) { + if (layoutDirection == LegendGridSizeDirection.DOWN) { + for (var j = i - 1; j >= 0; j--) { + infos[i] = infos[j]; + if (infos[j] != null) { + break; + } + } + + if (infos[i] == null) { + for (var k = i + 1; k <= infos.length; k++) { + infos[i] = infos[k]; + if (infos[k] != null) { + break; + } + } + } + } else { + for (var k = i + 1; k < infos.length; k++) { + infos[i] = infos[k]; + if (infos[k] != null) { + break; + } + } + + if (infos[i] == null) { + for (var j = i - 1; j >= 0; j--) { + infos[i] = infos[j]; + if (infos[j] != null) { + break; + } + } + } + } + } + } + + this.small = infos[0] ?? def; + this.medium = infos[1] ?? def; + this.large = infos[2] ?? def; + this.xxl = infos[3] ?? def; + } + + bool checkIfNoSizing(List sizes) { + if (sizes.any((element) => element != null)) { + return false; + } + return true; + } + + LegendGridSizeInfo getSizeForSize(ScreenSize size) { + switch (size) { + case ScreenSize.Small: + return small!; + + case ScreenSize.Medium: + return medium!; + case ScreenSize.Large: + return large!; + case ScreenSize.XXL: + return xxl!; + default: + return def; + } + } } class LegendGridSizeInfo { diff --git a/lib/customwidgets/layout/legendScaffold.dart b/lib/customwidgets/layout/legendScaffold.dart index 825f644..55215d3 100644 --- a/lib/customwidgets/layout/legendScaffold.dart +++ b/lib/customwidgets/layout/legendScaffold.dart @@ -3,8 +3,16 @@ import 'dart:io'; import 'package:animations/animations.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:provider/provider.dart'; +import 'package:webstore/customwidgets/layout/sectionNavigation/sectionNavigation.dart'; +import 'package:webstore/customwidgets/layout/sections/section.dart'; +import 'package:webstore/router/routes/sectionProvider.dart'; +import 'package:webstore/router/routes/sectionRouteInfo.dart'; +import 'package:webstore/styles/legendColorTheme.dart'; +import 'package:webstore/styles/legendTheme.dart'; import 'drawers/drawerMenu.dart'; -import 'fixed/fixedAppBar.dart'; +import 'fixed/appBar.dart/fixedAppBar.dart'; import 'package:flutter/foundation.dart' show kIsWeb; import 'fixed/fixedFooter.dart'; import 'fixed/fixedSider.dart'; @@ -15,37 +23,75 @@ import '../../objects/menuOption.dart'; import '../../router/routerProvider.dart'; import '../../styles/layoutType.dart'; import '../../styles/sizeProvider.dart'; -import '../../styles/typography.dart'; +import '../typography/typography.dart'; class LegendScaffold extends StatelessWidget { final LayoutType? layoutType; final String pageName; final Function(BuildContext context)? onActionButtonPressed; - final WidgetBuilder contentBuilder; + final WidgetBuilder? siderBuilder; + final WidgetBuilder? appBarBuilder; + final bool? showSiderMenu; + final bool? showAppBarMenu; + late final bool singlePage; + late final List children; + late final WidgetBuilder contentBuilder; - const LegendScaffold({ - Key? key, - this.layoutType, + LegendScaffold({ required this.pageName, + this.layoutType, this.onActionButtonPressed, - required this.contentBuilder, - }) : super(key: key); + this.siderBuilder, + this.showSiderMenu, + this.showAppBarMenu, + this.appBarBuilder, + WidgetBuilder? contentBuilder, + List? children, + bool? singlePage, + Key? key, + }) : super(key: key) { + this.singlePage = singlePage ?? false; + this.children = children ?? []; + this.contentBuilder = contentBuilder ?? (f) => Container(); + } + + List? sections; @override Widget build(BuildContext context) { + sections = SectionProvider.of(context)?.sections; return SizeProvider( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, - child: Builder( - builder: (context) { - if (kIsWeb) { - return materialLayout(context); - } else if (Platform.isIOS || Platform.isMacOS) { - return cupertinoLayout(context); - } else { - return materialLayout(context); + child: SectionNavigation( + sections: sections, + onNavigate: (section) { + // Jump to Section + if (sections != null) { + SectionRouteInfo s = sections! + .singleWhere((element) => element.name == section.name); + if (s.key != null && s.key?.currentContext != null) { + Scrollable.ensureVisible( + s.key!.currentContext!, + curve: Curves.easeInOut, + duration: Duration( + milliseconds: 400, + ), + ); + } } }, + child: Builder( + builder: (context) { + if (kIsWeb) { + return materialLayout(context); + } else if (Platform.isIOS || Platform.isMacOS) { + return cupertinoLayout(context); + } else { + return materialLayout(context); + } + }, + ), ), ); } @@ -60,10 +106,15 @@ class LegendScaffold extends StatelessWidget { if (layoutType == LayoutType.FixedSider) { return FixedSider( showMenu: true, + builder: siderBuilder, ); } else if (layoutType == LayoutType.FixedHeaderSider && screenSize != ScreenSize.Small) { - return FixedSider(); + return FixedSider( + builder: siderBuilder, + showMenu: showSiderMenu, + showSectionMenu: true, + ); } else { return Container(); } @@ -74,22 +125,23 @@ class LegendScaffold extends StatelessWidget { } Widget getHeader() { - if (layoutType == LayoutType.FixedHeaderSider) { - return FixedAppBar(); - } else if (layoutType == LayoutType.FixedHeader) { - return FixedAppBar(); - } else { - return SliverToBoxAdapter( - child: Container(), - ); + switch (layoutType) { + case LayoutType.FixedHeaderSider: + return FixedAppBar( + showMenu: showAppBarMenu, + builder: appBarBuilder, + ); + case LayoutType.FixedHeader: + return FixedAppBar( + builder: appBarBuilder, + ); + default: + return SliverToBoxAdapter( + child: Container(), + ); } } - Widget getDrawer(BuildContext context) { - ScreenSize ss = SizeProvider.of(context).screenSize; - return ss == ScreenSize.Small ? DrawerMenu() : Container(); - } - Widget getActionButton(BuildContext context) { return FloatingActionButton( onPressed: () { @@ -111,8 +163,10 @@ class LegendScaffold extends StatelessWidget { var whitespace = 16 * 2 + 10; var footerHeight = 200; + LegendColorTheme colors = Provider.of(context).colors; + return Scaffold( - endDrawer: getDrawer(context), + endDrawer: DrawerMenu(), endDrawerEnableOpenDragGesture: false, floatingActionButton: onActionButtonPressed != null ? Builder( @@ -126,46 +180,40 @@ class LegendScaffold extends StatelessWidget { getSider(screenSize), Expanded( child: CustomScrollView( - /*/ headerSliverBuilder: (context, innerBoxIsScrolled) { - return [ - getHeader(), - ]; - },*/ slivers: [ getHeader(), - SliverToBoxAdapter( - child: LayoutBuilder(builder: (context, constraints) { - return Container( - constraints: BoxConstraints( - minHeight: MediaQuery.of(context).size.height - 80, - ), - color: Colors.black12, - padding: contentPadding, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: LegendText( - text: pageName, - textStyle: LegendTextStyle.h1(), + children.isEmpty + ? SliverToBoxAdapter( + child: LayoutBuilder(builder: (context, constraints) { + return Container( + constraints: BoxConstraints( + minHeight: + MediaQuery.of(context).size.height - 80, ), - padding: - const EdgeInsets.only(top: 8.0, bottom: 16.0), - ), - Container( - color: Colors.white, - // height: 1000, - width: constraints.maxWidth - - contentPadding.horizontal, - padding: const EdgeInsets.all(8.0), - child: Builder(builder: contentBuilder), + color: colors.scaffoldBackgroundColor, + padding: contentPadding, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: constraints.maxWidth - + contentPadding.horizontal, + padding: const EdgeInsets.all(8.0), + child: Builder(builder: contentBuilder), + ), + getFooter(), + ], + ), + ); + }), + ) + : SliverToBoxAdapter( + child: SingleChildScrollView( + child: Column( + children: getChildren(), ), - getFooter(), - ], - ), - ); - }), - ), + ), + ) ], ), ), @@ -173,4 +221,36 @@ class LegendScaffold extends StatelessWidget { ), ); } + + // Every Section Widget gets wrapped witch a Global Key for Section Navigation + List getChildren() { + List childs = []; + + this.children.forEach((element) { + Widget w; + if (element is Section) { + Section s = element; + GlobalKey key = new GlobalKey(); + if (sections != null) { + try { + SectionRouteInfo se = + sections!.singleWhere((element) => element.name == s.name); + int i = sections!.indexOf(se); + sections![i] = SectionRouteInfo(name: se.name, key: key); + } catch (e) { + print("No Section found!"); + } + } + w = Container( + key: key, + child: s, + ); + } else { + w = element; + } + childs.add(w); + }); + + return childs; + } } diff --git a/lib/customwidgets/layout/sectionNavigation/sectionNavigation.dart b/lib/customwidgets/layout/sectionNavigation/sectionNavigation.dart new file mode 100644 index 0000000..b9a72a3 --- /dev/null +++ b/lib/customwidgets/layout/sectionNavigation/sectionNavigation.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; +import 'package:webstore/router/routes/sectionRouteInfo.dart'; + +class SectionNavigation extends InheritedWidget { + SectionNavigation({ + Key? key, + required this.onNavigate, + required this.child, + List? sections, + }) : super(key: key, child: child) { + this.sections = sections ?? []; + } + + late final List sections; + final Widget child; + final void Function(SectionRouteInfo section) onNavigate; + + void navigateToSection(SectionRouteInfo section) { + onNavigate(section); + } + + static SectionNavigation? of(BuildContext context) { + final SectionNavigation? result = + context.dependOnInheritedWidgetOfExactType(); + assert(result != null, 'No SizeProvider found in context'); + return result!; + } + + @override + bool updateShouldNotify(SectionNavigation oldWidget) { + return true; + } +} diff --git a/lib/customwidgets/layout/sections/section.dart b/lib/customwidgets/layout/sections/section.dart index e04ca7c..7bf08a0 100644 --- a/lib/customwidgets/layout/sections/section.dart +++ b/lib/customwidgets/layout/sections/section.dart @@ -1,37 +1,73 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:webstore/customwidgets/layout/sections/sectionHeader.dart'; import 'package:webstore/customwidgets/typography/legendText.dart'; -import 'package:webstore/styles/typography.dart'; +import 'package:webstore/styles/legendColorTheme.dart'; +import 'package:webstore/styles/legendTheme.dart'; +import 'package:webstore/customwidgets/typography/typography.dart'; class Section extends StatelessWidget { + final String? name; final List children; final String header; final TextStyle? headerTextStyle; + final double? verticalSpacing; + final double? margin; Section({ required this.children, required this.header, + this.name, this.headerTextStyle, + this.verticalSpacing, + this.margin, }); - List getChildren() { - children.insert( - 0, + List getWidgets() { + List widgets = [ SectionHeader( text: header, textStyle: headerTextStyle, ), - ); - return children; + ]; + widgets.addAll(children); + if (verticalSpacing != null) { + for (var i = 1; i < widgets.length; i += 2) { + widgets.insert( + i, + Padding( + padding: EdgeInsets.only(top: verticalSpacing!), + ), + ); + } + } + return widgets; } @override Widget build(BuildContext context) { - return Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: getChildren(), - ), - ); + LegendColorTheme colors = Provider.of(context).colors; + + return LayoutBuilder(builder: (context, constraints) { + return Padding( + padding: EdgeInsets.all(margin ?? 12.0), + child: Container( + alignment: Alignment.centerLeft, + margin: EdgeInsets.only(bottom: 24), + padding: EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.06), + borderRadius: BorderRadius.all( + Radius.circular(4), + ), + ), + width: constraints.maxWidth, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: getWidgets(), + ), + ), + ); + }); } } diff --git a/lib/customwidgets/layout/sections/sectionHeader.dart b/lib/customwidgets/layout/sections/sectionHeader.dart index 73f3dac..5874e4e 100644 --- a/lib/customwidgets/layout/sections/sectionHeader.dart +++ b/lib/customwidgets/layout/sections/sectionHeader.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:webstore/customwidgets/typography/legendText.dart'; -import 'package:webstore/styles/typography.dart'; +import 'package:webstore/customwidgets/typography/typography.dart'; class SectionHeader extends StatelessWidget { final String text; @@ -11,7 +11,7 @@ class SectionHeader extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - padding: EdgeInsets.symmetric(vertical: 8.0), + padding: EdgeInsets.only(bottom: 4.0), child: LegendText( text: text, textStyle: textStyle ?? LegendTextStyle.sectionHeader(), diff --git a/lib/customwidgets/layout/sections/sectionTile.dart b/lib/customwidgets/layout/sections/sectionTile.dart new file mode 100644 index 0000000..b219fb2 --- /dev/null +++ b/lib/customwidgets/layout/sections/sectionTile.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:webstore/customwidgets/layout/sectionNavigation/sectionNavigation.dart'; +import 'package:webstore/customwidgets/legendButton/legendButton.dart'; +import 'package:webstore/customwidgets/typography/legendText.dart'; +import 'package:webstore/customwidgets/typography/typography.dart'; +import 'package:webstore/router/routes/sectionRouteInfo.dart'; + +extension StringExtension on String { + String capitalize() { + return "${this[0].toUpperCase()}${this.substring(1)}"; + } +} + +class SectionTile extends StatelessWidget { + late final String name; + late final String displayName; + + SectionTile({ + Key? key, + required String name, + }) : super(key: key) { + this.name = name; + this.displayName = name.replaceAll("/", "").capitalize(); + } + + @override + Widget build(BuildContext context) { + return ListTile( + contentPadding: EdgeInsets.all(8), + title: Container( + alignment: Alignment.center, + child: LegendText( + text: displayName, + textStyle: LegendTextStyle.sectionLink().copyWith( + fontSize: 16, + fontWeight: FontWeight.w400, + ), + ), + ), + onTap: () { + SectionNavigation.of(context) + ?.navigateToSection(SectionRouteInfo(name: name)); + }, + ); + } +} diff --git a/lib/customwidgets/legendButton/legendButton.dart b/lib/customwidgets/legendButton/legendButton.dart index b94449a..b813043 100644 --- a/lib/customwidgets/legendButton/legendButton.dart +++ b/lib/customwidgets/legendButton/legendButton.dart @@ -7,7 +7,6 @@ class LegendButton extends StatelessWidget { final Function onPressed; final EdgeInsetsGeometry? margin; final EdgeInsetsGeometry? padding; - final double? width; const LegendButton({ Key? key, @@ -16,37 +15,61 @@ class LegendButton extends StatelessWidget { required this.onPressed, this.margin, this.padding, - this.width, }) : super(key: key); @override Widget build(BuildContext context) { - return Padding( - padding: margin ?? const EdgeInsets.all(8.0), - child: TextButton( - onPressed: () => onPressed(), - child: Container( - width: width, - padding: padding ?? - const EdgeInsets.symmetric( - vertical: 8.0, - horizontal: 16.0, - ), - alignment: Alignment.center, - decoration: BoxDecoration( - borderRadius: - BorderRadius.all(style?.borderRadius ?? Radius.circular(0)), - gradient: style?.backgroundGradient, - boxShadow: style?.boxShadow == null - ? [] - : [ - style?.boxShadow ?? BoxShadow(), - ], + return LayoutBuilder(builder: (context, constraints) { + double? height = style?.height; + double? width = style?.width; + double? v; + double? w; + if (constraints.maxHeight == double.infinity) { + v = margin?.vertical ?? 8.0; + } else { + v = height != null ? (constraints.maxHeight - height) / 2 : null; + } + + w = width != null ? (constraints.maxWidth - width) / 2 : null; + + return Container( + height: constraints.maxHeight == double.infinity + ? null + : constraints.maxHeight, + width: constraints.maxWidth == double.infinity + ? null + : constraints.maxWidth, + constraints: height != null ? BoxConstraints(maxHeight: height) : null, + padding: EdgeInsets.symmetric( + vertical: v ?? 8.0, + horizontal: w ?? 8.0, + ), + child: TextButton( + onPressed: () => onPressed(), + child: Container( + width: width, + height: height, + padding: padding ?? + const EdgeInsets.symmetric( + vertical: 8.0, + horizontal: 16.0, + ), + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: + BorderRadius.all(style?.borderRadius ?? Radius.circular(0)), + gradient: style?.backgroundGradient, + boxShadow: style?.boxShadow == null + ? [] + : [ + style?.boxShadow ?? BoxShadow(), + ], + ), + child: text, ), - child: text, + style: style ?? ButtonStyle(), ), - style: style ?? ButtonStyle(), - ), - ); + ); + }); } } diff --git a/lib/customwidgets/legendButton/legendButtonStyle.dart b/lib/customwidgets/legendButton/legendButtonStyle.dart index c18f58a..ceda8fd 100644 --- a/lib/customwidgets/legendButton/legendButtonStyle.dart +++ b/lib/customwidgets/legendButton/legendButtonStyle.dart @@ -41,6 +41,8 @@ class LegendButtonStyle extends ButtonStyle { final Radius? borderRadius; final Gradient? backgroundGradient; final BoxShadow? boxShadow; + final double? height; + final double? width; LegendButtonStyle({ this.textStyle, @@ -63,6 +65,8 @@ class LegendButtonStyle extends ButtonStyle { this.borderRadius, this.backgroundGradient, this.boxShadow, + this.height, + this.width, }) : super( alignment: alignment, animationDuration: animationDuration, @@ -90,7 +94,8 @@ class LegendButtonStyle extends ButtonStyle { visualDensity: visualDensity, ); - factory LegendButtonStyle.gradient(List colors) { + factory LegendButtonStyle.gradient(List colors, + {double? height, double? width}) { return LegendButtonStyle( backgroundColor: MaterialStateProperty.resolveWith( (states) { @@ -100,7 +105,6 @@ class LegendButtonStyle extends ButtonStyle { foregroundColor: MaterialStateProperty.all(Colors.white), animationDuration: legendAnimationDuration, borderRadius: legendBorderRadius, - minimumSize: MaterialStateProperty.all(Size.zero), backgroundGradient: LinearGradient( colors: colors, ), @@ -115,10 +119,12 @@ class LegendButtonStyle extends ButtonStyle { legendBoxShadow.color.withOpacity(0.4), ), boxShadow: legendBoxShadow, + height: height, + width: width, ); } - factory LegendButtonStyle.danger() { + factory LegendButtonStyle.danger({double? height, double? width}) { return LegendButtonStyle( backgroundColor: MaterialStateProperty.resolveWith( (states) { @@ -129,12 +135,17 @@ class LegendButtonStyle extends ButtonStyle { } }, ), + minimumSize: width != null && height != null + ? MaterialStateProperty.all(Size(width, height)) + : null, foregroundColor: MaterialStateProperty.all(Colors.white), animationDuration: legendAnimationDuration, + height: height, + width: width, ); } - factory LegendButtonStyle.confirm() { + factory LegendButtonStyle.confirm({double? height, double? width}) { return LegendButtonStyle( backgroundColor: MaterialStateProperty.resolveWith( (states) { @@ -147,6 +158,9 @@ class LegendButtonStyle extends ButtonStyle { ), foregroundColor: MaterialStateProperty.all(Colors.white), animationDuration: legendAnimationDuration, + minimumSize: width != null && height != null + ? MaterialStateProperty.all(Size(width, height)) + : null, elevation: MaterialStateProperty.resolveWith( (states) { if (states.contains(MaterialState.hovered)) { @@ -157,10 +171,12 @@ class LegendButtonStyle extends ButtonStyle { }, ), borderRadius: legendBorderRadius, + height: height, + width: width, ); } - factory LegendButtonStyle.normal() { + factory LegendButtonStyle.normal({double? height, double? width}) { return LegendButtonStyle( backgroundColor: MaterialStateProperty.all(Colors.white), overlayColor: MaterialStateProperty.all(Colors.white), @@ -174,6 +190,9 @@ class LegendButtonStyle extends ButtonStyle { } }, ), + fixedSize: width != null && height != null + ? MaterialStateProperty.all(Size(width, height)) + : null, borderRadius: Radius.circular(4), side: MaterialStateProperty.resolveWith( (states) { @@ -188,6 +207,50 @@ class LegendButtonStyle extends ButtonStyle { } }, ), + height: height, + width: width, + ); + } + + @override + LegendButtonStyle copyWith({ + AlignmentGeometry? alignment, + Duration? animationDuration, + MaterialStateProperty? backgroundColor, + MaterialStateProperty? elevation, + bool? enableFeedback, + MaterialStateProperty? fixedSize, + MaterialStateProperty? foregroundColor, + MaterialStateProperty? minimumSize, + MaterialStateProperty? mouseCursor, + MaterialStateProperty? overlayColor, + MaterialStateProperty? padding, + MaterialStateProperty? shadowColor, + MaterialStateProperty? shape, + MaterialStateProperty? side, + InteractiveInkFeatureFactory? splashFactory, + MaterialTapTargetSize? tapTargetSize, + MaterialStateProperty? textStyle, + VisualDensity? visualDensity, + }) { + return LegendButtonStyle( + alignment: alignment, + animationDuration: animationDuration, + backgroundColor: backgroundColor, + elevation: elevation, + enableFeedback: enableFeedback, + fixedSize: fixedSize, + foregroundColor: foregroundColor, + minimumSize: minimumSize, + mouseCursor: mouseCursor, + overlayColor: overlayColor, + padding: padding, + shadowColor: shadowColor, + side: side, + splashFactory: splashFactory, + tapTargetSize: tapTargetSize, + textStyle: textStyle, + visualDensity: visualDensity, ); } } diff --git a/lib/customwidgets/modals/legendAlert.dart b/lib/customwidgets/modals/legendAlert.dart index d91a119..aa729ba 100644 --- a/lib/customwidgets/modals/legendAlert.dart +++ b/lib/customwidgets/modals/legendAlert.dart @@ -6,7 +6,7 @@ import 'package:webstore/customwidgets/legendButton/legendButton.dart'; import 'package:webstore/customwidgets/typography/legendText.dart'; import 'package:webstore/objects/assetInfo.dart'; import 'package:webstore/styles/legendTheme.dart'; -import 'package:webstore/styles/typography.dart'; +import 'package:webstore/customwidgets/typography/typography.dart'; class LegendAlert extends StatelessWidget { String? message; diff --git a/lib/customwidgets/modals/legendBottomSheet.dart b/lib/customwidgets/modals/legendBottomSheet.dart index 21d6a5a..11b3451 100644 --- a/lib/customwidgets/modals/legendBottomSheet.dart +++ b/lib/customwidgets/modals/legendBottomSheet.dart @@ -7,7 +7,7 @@ import '../typography/legendText.dart'; import '../../styles/layoutType.dart'; import '../../styles/sizeProvider.dart'; import '../../styles/legendTheme.dart'; -import '../../styles/typography.dart'; +import '../typography/typography.dart'; class LegendBottomSheet extends StatelessWidget { final String title; diff --git a/lib/customwidgets/typography/legendText.dart b/lib/customwidgets/typography/legendText.dart index d13b056..c70a3eb 100644 --- a/lib/customwidgets/typography/legendText.dart +++ b/lib/customwidgets/typography/legendText.dart @@ -5,25 +5,36 @@ class LegendText extends StatelessWidget { final String text; final TextStyle? textStyle; final bool? selectable; + final TextAlign? textAlign; LegendText({ required this.text, this.selectable, this.textStyle, + this.textAlign, }); @override Widget build(BuildContext context) { return Container( + height: textStyle?.height, child: kIsWeb && (selectable ?? true) ? webText() : normalText(), ); } webText() { - return SelectableText(text, style: textStyle); + return SelectableText( + text, + style: textStyle, + textAlign: textAlign, + ); } normalText() { - return Text(text, style: textStyle); + return Text( + text, + style: textStyle, + textAlign: textAlign, + ); } } diff --git a/lib/styles/typography.dart b/lib/customwidgets/typography/typography.dart similarity index 69% rename from lib/styles/typography.dart rename to lib/customwidgets/typography/typography.dart index 890567a..c285a71 100644 --- a/lib/styles/typography.dart +++ b/lib/customwidgets/typography/typography.dart @@ -25,17 +25,17 @@ class LegendTypography { this.h4 ?? LegendTextStyle.h4(); this.h5 ?? LegendTextStyle.h5(); this.h6 ?? LegendTextStyle.h6(); - this.h7 ?? LegendTextStyle.h7(); + this.h7 ?? LegendTextStyle.textInput(); } } class LegendTextStyle extends TextStyle { - final TextStyle? style; final Color textColor; final Color backgroundColor; final double fontSize; final FontWeight fontWeight; final String fontFamily; + final double? height; LegendTextStyle({ required this.textColor, @@ -43,7 +43,7 @@ class LegendTextStyle extends TextStyle { required this.fontSize, required this.fontWeight, required this.fontFamily, - this.style, + this.height, }) : super( color: textColor, backgroundColor: backgroundColor, @@ -56,9 +56,19 @@ class LegendTextStyle extends TextStyle { return LegendTextStyle( textColor: Colors.grey[850]!, backgroundColor: Colors.transparent, - fontSize: 22, - fontWeight: FontWeight.w200, - fontFamily: "Roboto", + fontSize: 28, + fontWeight: FontWeight.w300, + fontFamily: "sans serif", + ); + } + + factory LegendTextStyle.appBarMenuHeader() { + return LegendTextStyle( + textColor: Colors.grey[850]!, + backgroundColor: Colors.transparent, + fontSize: 14, + fontWeight: FontWeight.w300, + fontFamily: "sans serif", ); } @@ -102,6 +112,26 @@ class LegendTextStyle extends TextStyle { ); } + factory LegendTextStyle.siderMenuCollapsed() { + return LegendTextStyle( + textColor: Colors.black87, + backgroundColor: Colors.transparent, + fontSize: 10, + fontWeight: FontWeight.w200, + fontFamily: "Roboto", + ); + } + + factory LegendTextStyle.sectionLink() { + return LegendTextStyle( + textColor: Colors.black87, + backgroundColor: Colors.transparent, + fontSize: 16, + fontWeight: FontWeight.w300, + fontFamily: "Roboto", + ); + } + factory LegendTextStyle.h6() { return LegendTextStyle( textColor: Colors.white, @@ -112,12 +142,14 @@ class LegendTextStyle extends TextStyle { ); } - factory LegendTextStyle.h7() { + factory LegendTextStyle.textInput({ + Color? textColor, + }) { return LegendTextStyle( - textColor: Colors.black87, - backgroundColor: Colors.white, - fontSize: 12, - fontWeight: FontWeight.w600, + textColor: textColor ?? Colors.black87, + backgroundColor: Colors.transparent, + fontSize: 18, + fontWeight: FontWeight.w300, fontFamily: "sans serif", ); } @@ -131,4 +163,14 @@ class LegendTextStyle extends TextStyle { fontFamily: "sans serif", ); } + + factory LegendTextStyle.formHeader() { + return LegendTextStyle( + textColor: Colors.black87, + backgroundColor: Colors.transparent, + fontSize: 16.0, + fontWeight: FontWeight.w400, + fontFamily: "sans serif", + ); + } } diff --git a/lib/main.dart b/lib/main.dart index e889640..80a3bcf 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:webstore/router/routes/sectionRouteInfo.dart'; import 'package:webstore/styles/legendColorTheme.dart'; import 'objects/menuOption.dart'; @@ -8,10 +9,10 @@ import 'pages/home.dart'; import 'pages/products.dart'; import 'router/delegate.dart'; import 'router/parser.dart'; -import 'router/routeInfo.dart'; +import 'router/routes/routeInfo.dart'; import 'router/routerProvider.dart'; import 'styles/legendTheme.dart'; -import 'styles/typography.dart'; +import 'customwidgets/typography/typography.dart'; void main() { runApp( @@ -40,8 +41,16 @@ class MyApp extends StatelessWidget { page: ProductsPage(), ), RouteInfo( - name: "/widgetcomponents", + name: "/widgets", page: WidgetComponents(), + sections: [ + SectionRouteInfo(name: "/buttons"), + SectionRouteInfo(name: "/modals"), + SectionRouteInfo(name: "/selectbar"), + SectionRouteInfo(name: "/carousel"), + SectionRouteInfo(name: "/textfield"), + SectionRouteInfo(name: "/form"), + ], ), ], menuOptions: [ @@ -56,9 +65,9 @@ class MyApp extends StatelessWidget { icon: Icons.accessibility, ), MenuOptionHeader( - title: "Widget Components", - page: "/widgetcomponents", - icon: Icons.info_sharp, + title: "Widgets", + page: "/widgets", + icon: Icons.widgets, ), ], child: MaterialApp.router( diff --git a/lib/objects/menuOption.dart b/lib/objects/menuOption.dart index d71cd73..27e7dd3 100644 --- a/lib/objects/menuOption.dart +++ b/lib/objects/menuOption.dart @@ -4,7 +4,7 @@ import 'package:provider/provider.dart'; import 'package:webstore/customwidgets/typography/legendText.dart'; import 'package:webstore/styles/sizeProvider.dart'; import 'package:webstore/styles/legendTheme.dart'; -import 'package:webstore/styles/typography.dart'; +import 'package:webstore/customwidgets/typography/typography.dart'; import '../router/routerProvider.dart'; class MenuOptionHeader extends StatefulWidget { @@ -29,7 +29,7 @@ class _MenuOptionHeaderState extends State late AnimationController controller; late Animation animation; late Animation animation2; - late Color color = Colors.white; + late Color color = Colors.black87; late Color borderColor = Colors.transparent; @override @@ -41,11 +41,11 @@ class _MenuOptionHeaderState extends State controller = AnimationController( vsync: this, duration: Duration( - milliseconds: 200, + milliseconds: 260, ), ); animation = ColorTween( - begin: Colors.white, + begin: color, end: Colors.blueAccent, ).animate(controller); @@ -71,7 +71,7 @@ class _MenuOptionHeaderState extends State Widget build(BuildContext context) { LegendTheme theme = Provider.of(context); return Container( - margin: const EdgeInsets.only(left: 32.0), + margin: const EdgeInsets.only(left: 8.0), decoration: BoxDecoration( border: Border( top: BorderSide( @@ -113,14 +113,14 @@ class _MenuOptionHeaderState extends State focusColor: Colors.transparent, highlightColor: Colors.transparent, child: Container( - padding: const EdgeInsets.all(16.0), + padding: const EdgeInsets.all(12.0), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Icon( widget.icon, color: color, - size: theme.sizing.appbarHeight / 3, + size: theme.sizing.appbarHeight / 3.5, ), Padding(padding: const EdgeInsets.symmetric(horizontal: 4.0)), Padding( @@ -128,8 +128,7 @@ class _MenuOptionHeaderState extends State child: LegendText( text: widget.title, selectable: false, - textStyle: LegendTextStyle.h1().copyWith( - fontSize: theme.sizing.appbarHeight / 4.5, + textStyle: LegendTextStyle.appBarMenuHeader().copyWith( color: color, ), ), diff --git a/lib/pages/home.dart b/lib/pages/home.dart index ecc8747..a6dc2e5 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -2,6 +2,8 @@ import 'package:animations/animations.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:provider/provider.dart'; +import 'package:webstore/customwidgets/input/selectBar/legendSelectBar.dart'; +import 'package:webstore/customwidgets/input/selectBar/legendSelectOption.dart'; import 'package:webstore/customwidgets/legendButton/legendButtonStyle.dart'; import 'package:webstore/customwidgets/modals/legendAlert.dart'; import 'package:webstore/customwidgets/modals/legendPopups.dart'; @@ -12,7 +14,7 @@ import '../customwidgets/layout/legendScaffold.dart'; import '../customwidgets/modals/modal.dart'; import '../customwidgets/typography/legendText.dart'; import '../styles/layoutType.dart'; -import '../styles/typography.dart'; +import '../customwidgets/typography/typography.dart'; class Home extends StatelessWidget { @override @@ -24,22 +26,6 @@ class Home extends StatelessWidget { return Column( children: [ Text("Home"), - LegendButton( - text: Text("Change Theme to Dark"), - onPressed: () { - Provider.of(context, listen: false) - .changeColorTheme(LegendColorThemeType.DARK); - }, - style: LegendButtonStyle.confirm(), - ), - LegendButton( - text: Text("Change Theme to Light"), - onPressed: () { - Provider.of(context, listen: false) - .changeColorTheme(LegendColorThemeType.LIGHT); - }, - style: LegendButtonStyle.confirm(), - ), LegendButton( text: Text("Show Success Alert"), onPressed: () { @@ -54,7 +40,6 @@ class Home extends StatelessWidget { ), LegendButton( text: Text("Show Modal Bottom"), - width: 200, onPressed: () => { Scaffold.of(context).showBottomSheet( (context) { @@ -72,8 +57,8 @@ class Home extends StatelessWidget { clipBehavior: Clip.antiAlias, ), }, - style: LegendButtonStyle.confirm(), - ) + style: LegendButtonStyle.confirm(height: 100), + ), ], ); }, diff --git a/lib/pages/products.dart b/lib/pages/products.dart index 40dc663..66d1819 100644 --- a/lib/pages/products.dart +++ b/lib/pages/products.dart @@ -6,8 +6,8 @@ import 'package:webstore/customwidgets/datadisplay/table/legendTableCell.dart'; import 'package:webstore/customwidgets/legendButton/legendButtonStyle.dart'; import 'package:webstore/customwidgets/legendButton/legendButton.dart'; import 'package:webstore/customwidgets/typography/legendText.dart'; -import 'package:webstore/styles/typography.dart'; -import '../customwidgets/layout/fixed/fixedAppBar.dart'; +import 'package:webstore/customwidgets/typography/typography.dart'; +import '../customwidgets/layout/fixed/appBar.dart/fixedAppBar.dart'; import '../customwidgets/layout/legendScaffold.dart'; import '../styles/layoutType.dart'; diff --git a/lib/pages/widgetComponets.dart b/lib/pages/widgetComponets.dart index 664b80d..f72b3d5 100644 --- a/lib/pages/widgetComponets.dart +++ b/lib/pages/widgetComponets.dart @@ -1,16 +1,32 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_syntax_view/flutter_syntax_view.dart'; +import 'package:provider/provider.dart'; +import 'package:webstore/customwidgets/datadisplay/carousel/legendCarousel.dart'; import 'package:webstore/customwidgets/datadisplay/table/legendRowValue.dart'; import 'package:webstore/customwidgets/datadisplay/table/legendTable.dart'; import 'package:webstore/customwidgets/datadisplay/table/legendTableCell.dart'; +import 'package:webstore/customwidgets/input/form/legendForm.dart'; +import 'package:webstore/customwidgets/input/form/legendFormField.dart'; +import 'package:webstore/customwidgets/input/selectBar/legendSelectBar.dart'; +import 'package:webstore/customwidgets/input/selectBar/legendSelectOption.dart'; +import 'package:webstore/customwidgets/input/selectBar/legendselectButton.dart'; +import 'package:webstore/customwidgets/input/text/legendInputDecoration.dart'; +import 'package:webstore/customwidgets/input/text/legendTextField.dart'; import 'package:webstore/customwidgets/layout/grid/legendGridSize.dart'; import 'package:webstore/customwidgets/layout/grid/legendGrid.dart'; +import 'package:webstore/customwidgets/layout/sectionNavigation/sectionNavigation.dart'; import 'package:webstore/customwidgets/layout/sections/section.dart'; import 'package:webstore/customwidgets/legendButton/legendButton.dart'; import 'package:webstore/customwidgets/legendButton/legendButtonStyle.dart'; +import 'package:webstore/customwidgets/modals/legendAlert.dart'; +import 'package:webstore/customwidgets/modals/legendBottomSheet.dart'; +import 'package:webstore/customwidgets/modals/legendPopups.dart'; +import 'package:webstore/customwidgets/modals/modal.dart'; import 'package:webstore/customwidgets/typography/legendText.dart'; -import 'package:webstore/styles/typography.dart'; +import 'package:webstore/router/routes/sectionRouteInfo.dart'; +import 'package:webstore/styles/legendTheme.dart'; +import 'package:webstore/customwidgets/typography/typography.dart'; import '../customwidgets/layout/legendScaffold.dart'; import '../styles/layoutType.dart'; @@ -18,80 +34,370 @@ class WidgetComponents extends StatelessWidget { @override Widget build(BuildContext context) { return LegendScaffold( - contentBuilder: (context) { + showSiderMenu: false, + showAppBarMenu: true, + appBarBuilder: (context) { return Container( - child: Column( - children: [ - Section( - header: "Buttons", - children: [ - LegendText( - text: - "Buttons sind sehr cool!. Im Legend Design Pack gibt es mehere Arten von Buttons. "), - LegendGrid( - sizes: LegendGridSize( - small: LegendGridSizeInfo(1, 320), - medium: LegendGridSizeInfo(3, 160), - large: LegendGridSizeInfo(4, 80), - xxl: LegendGridSizeInfo(4, 80), - ), - children: [ - LegendButton( - margin: EdgeInsets.all(16), - text: LegendText( - text: "Alert", - ), - onPressed: () => {}, - style: LegendButtonStyle.danger(), + alignment: Alignment.center, + padding: EdgeInsets.symmetric(horizontal: 12), + child: LegendSelectBar( + margin: EdgeInsets.all(2), + width: 100, + height: 48, + isCard: true, + options: [ + LegendSelectOption( + color: Colors.grey, + icon: Icons.dark_mode, + name: "dark", + ), + LegendSelectOption( + color: Colors.purple[200], + icon: Icons.light_mode, + name: "light", + ), + ], + aligment: MainAxisAlignment.spaceBetween, + onSelected: (option) { + switch (option.name) { + case "dark": + Provider.of(context, listen: false) + .changeColorTheme(LegendColorThemeType.DARK); + break; + case "light": + Provider.of(context, listen: false) + .changeColorTheme(LegendColorThemeType.LIGHT); + break; + default: + break; + } + }, + iconSize: 26, + ), + ); + }, + children: [ + Section( + name: "/buttons", + verticalSpacing: 8, + header: "Buttons", + children: [ + LegendText( + text: + "Buttons sind sehr cool!. Im Legend Design Pack gibt es mehere Arten von Buttons. "), + LegendGrid( + sizes: LegendGridSize( + small: LegendGridSizeInfo(2, 64), + medium: LegendGridSizeInfo(3, 64), + large: LegendGridSizeInfo(4, 64), + xxl: LegendGridSizeInfo(4, 64), + ), + children: [ + LegendButton( + margin: EdgeInsets.all(16), + text: LegendText( + text: "Alert", + ), + onPressed: () => {}, + style: LegendButtonStyle.danger(), + ), + LegendButton( + margin: EdgeInsets.all(16), + text: LegendText( + text: "Sucess", + ), + onPressed: () => {}, + style: LegendButtonStyle.confirm(), + ), + LegendButton( + margin: EdgeInsets.all(16), + text: LegendText( + text: "Info", + ), + onPressed: () => {}, + style: LegendButtonStyle.normal( + // height: 48, ), - LegendButton( - margin: EdgeInsets.all(16), - text: LegendText( - text: "Sucess", - ), - onPressed: () => {}, - style: LegendButtonStyle.confirm(), + ), + LegendButton( + // margin: EdgeInsets.all(16), + text: LegendText(text: "Gradient"), + onPressed: () => {}, + style: LegendButtonStyle.gradient( + [ + Colors.red[200]!, + Colors.redAccent, + ], + width: 100, + ), + ), + ], + ), + Container( + height: 200, + child: SyntaxView( + code: + "LegendButton(\n margin: EdgeInsets.all(16),\n text: LegendText(text: \"Gradient\"),\n onPressed: () => {},\n style: LegendButtonStyle.gradient(\n [\n Colors.red[200]!,\n Colors.redAccent,\n ],\n ),\n ),", + syntax: Syntax.DART, + syntaxTheme: SyntaxTheme.standard(), + fontSize: 18.0, + withZoom: false, + withLinesCount: false, + expanded: false, + ), + ), + ], + ), + Section( + header: "Modals", + name: "/modals", + verticalSpacing: 12, + children: [ + LegendText( + text: + "Buttons sind sehr cool!. Im Legend Design Pack gibt es mehere Arten von Buttons. ", + ), + LegendGrid( + sizes: LegendGridSize( + small: LegendGridSizeInfo(1, 48), + medium: LegendGridSizeInfo(3, 48), + large: LegendGridSizeInfo(4, 48), + xxl: LegendGridSizeInfo(4, 48), + ), + children: [ + LegendButton( + text: Text("Show Success Alert"), + margin: EdgeInsets.all(16.0), + onPressed: () { + LegendPopups.showAlert( + context: context, + alert: LegendAlert.success( + message: "Ja geschafft du verdammta Trottlwichsa!", ), - LegendButton( - margin: EdgeInsets.all(16), - text: LegendText( - text: "Info", - ), - onPressed: () => {}, - style: LegendButtonStyle.normal(), + ); + }, + style: LegendButtonStyle.normal(), + ), + LegendButton( + text: Text("Show Modal Bottom"), + onPressed: () => { + Scaffold.of(context).showBottomSheet( + (context) { + return LegendBottomSheet( + title: "Cookies", + onCancel: () {}, + onConfirm: () {}, + content: LegendText( + text: "Bitte aktzeptieren Sie unsere Cookies! LIT", + textStyle: LegendTextStyle.h5(), + ), + ); + }, + backgroundColor: Colors.transparent, + clipBehavior: Clip.antiAlias, + ), + }, + style: LegendButtonStyle.normal(), + ), + LegendButton( + text: Text("Show Modal"), + onPressed: () => { + LegendPopups.showLegendModal( + context: context, + modal: Modal( + content: Text("test"), + onConfirm: () => {}, + onCancle: () => {}, + height: 400, + width: 400, ), - LegendButton( - margin: EdgeInsets.all(16), - text: LegendText(text: "Gradient"), - onPressed: () => {}, - style: LegendButtonStyle.gradient( - [ - Colors.red[200]!, - Colors.redAccent, - ], - ), + ), + }, + style: LegendButtonStyle.normal(), + ) + ], + ), + ], + ), + Section( + name: "/selectbar", + children: [ + LegendGrid( + sizes: LegendGridSize( + small: LegendGridSizeInfo(1, 80), + large: LegendGridSizeInfo(3, 80), + layoutDirection: LegendGridSizeDirection.DOWN, + ), + children: [ + LegendSelectBar( + options: [ + LegendSelectOption( + color: Colors.redAccent, + icon: Icons.credit_card, + name: "1", + ), + LegendSelectOption( + color: Colors.purpleAccent, + icon: Icons.wallet_giftcard, + name: "2", + ), + LegendSelectOption( + color: Colors.cyanAccent, + icon: Icons.money, + name: "3", + ), + ], + aligment: MainAxisAlignment.spaceAround, + onSelected: (a) { + print(a); + }, + iconSize: 36, + ), + LegendSelectBar( + options: [ + LegendSelectOption( + color: Colors.redAccent, + icon: Icons.credit_card, + name: "1"), + LegendSelectOption( + color: Colors.purpleAccent, + icon: Icons.wallet_giftcard, + name: "2"), + LegendSelectOption( + color: Colors.cyanAccent, + icon: Icons.money, + name: "3", + ), + ], + aligment: MainAxisAlignment.spaceAround, + onSelected: (a) { + print(a); + }, + iconSize: 36, + ), + LegendSelectBar( + options: [ + LegendSelectOption( + color: Colors.redAccent, + icon: Icons.credit_card, + name: "1"), + LegendSelectOption( + color: Colors.purpleAccent, + icon: Icons.wallet_giftcard, + name: "2"), + LegendSelectOption( + color: Colors.cyanAccent, + icon: Icons.money, + name: "3", + ), + ], + aligment: MainAxisAlignment.spaceAround, + onSelected: (a) { + print(a); + }, + isCard: true, + iconSize: 36, + ), + ], + ), + ], + header: "Select Button Bar", + ), + Section( + name: "/textfield", + children: [ + LegendTextField( + decoration: LegendInputDecoration.rounded( + focusColor: Colors.teal, + textColor: Colors.grey[800], + radius: BorderRadius.all(Radius.circular(2))), + ), + ], + header: "Textfield", + ), + Section( + name: "/carousel", + children: [ + LegendCarousel( + height: 200, + items: [ + Container(), + Container(), + Container( + color: Colors.orange, + ), + Container( + color: Colors.green, + ), + ], + ), + ], + header: "Carousel", + ), + Section( + name: "/form", + children: [ + LegendForm( + children: [ + LegendFormField.text( + text: LegendTextField( + decoration: LegendInputDecoration.rounded( + focusColor: Colors.teal, + textColor: Colors.grey[800], + radius: BorderRadius.all( + Radius.circular(2), ), - ], + ), ), - Container( - height: 200, - child: SyntaxView( - code: - "LegendButton(\n margin: EdgeInsets.all(16),\n text: LegendText(text: \"Gradient\"),\n onPressed: () => {},\n style: LegendButtonStyle.gradient(\n [\n Colors.red[200]!,\n Colors.redAccent,\n ],\n ),\n ),", - syntax: Syntax.DART, - syntaxTheme: SyntaxTheme.standard(), - fontSize: 18.0, - withZoom: false, - withLinesCount: false, - expanded: false, + onChanged: (value) { + print(value); + }, + onSave: (value) { + print("save $value"); + }, + ), + LegendFormField.text( + isRequired: true, + text: LegendTextField( + decoration: LegendInputDecoration.rounded( + focusColor: Colors.teal, + textColor: Colors.grey[800], + radius: BorderRadius.all( + Radius.circular(2), + ), ), ), - ], - ), - ], - ), - ); - }, + onChanged: (value) { + print(value); + }, + onSave: (value) { + print("save $value"); + }, + ), + LegendFormRow( + children: [ + LegendFormField.boolean( + title: "Test", + isRequired: true, + onChanged: (value) { + print(value); + }, + ), + LegendFormField.boolean( + isRequired: true, + title: "Test", + onChanged: (value) { + print(value); + }, + ), + ], + ), + ], + ) + ], + header: "Form", + ), + ], pageName: "Widget Components", layoutType: LayoutType.FixedHeaderSider, ); diff --git a/lib/router/delegate.dart b/lib/router/delegate.dart index e3f46a2..fd49781 100644 --- a/lib/router/delegate.dart +++ b/lib/router/delegate.dart @@ -2,7 +2,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import '../pages/home.dart'; import 'errorpages/notfound.dart'; -import 'routeInfo.dart'; +import 'routes/routeInfo.dart'; import 'routerProvider.dart'; class WebRouterDelegate extends RouterDelegate> diff --git a/lib/router/errorpages/notfound.dart b/lib/router/errorpages/notfound.dart index 124ba5f..5a54345 100644 --- a/lib/router/errorpages/notfound.dart +++ b/lib/router/errorpages/notfound.dart @@ -1,6 +1,5 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import '../../customwidgets/layout/fixed/fixedAppBar.dart'; import '../../customwidgets/layout/legendScaffold.dart'; class NotFoundPage extends StatelessWidget { diff --git a/lib/router/routerProvider.dart b/lib/router/routerProvider.dart index b3b055e..85505cd 100644 --- a/lib/router/routerProvider.dart +++ b/lib/router/routerProvider.dart @@ -6,9 +6,11 @@ import 'package:flutter/widgets.dart'; import '../objects/menuOption.dart'; import 'delegate.dart'; import 'errorpages/notfound.dart'; -import 'routeInfo.dart'; +import 'routes/routeInfo.dart'; import 'package:flutter/foundation.dart' show kIsWeb; +import 'routes/sectionProvider.dart'; + class RouterProvider extends InheritedWidget { final WebRouterDelegate routerDelegate; final Widget child; @@ -35,40 +37,46 @@ class RouterProvider extends InheritedWidget { this.routerDelegate.pushPage(p); } - static Widget getRouteWidget(RouteSettings s, List routes) { + static RouteInfo getRouteWidget(RouteSettings s, List routes) { if (routes == null || routes.isEmpty) { - return NotFoundPage(); + return RouteInfo(name: "Not Found", page: NotFoundPage()); } - Widget? w = routes.singleWhere( + RouteInfo? route = routes.singleWhere( (r) => r.name == s.name, orElse: () { return RouteInfo(name: "/notfound", page: NotFoundPage()); }, - ).page; + ); - return w; + return route; } - static Page createPage(RouteSettings s, Widget page) { + static Page createPage(RouteSettings s, RouteInfo route) { String now = DateTime.now().millisecondsSinceEpoch.toString(); + + // create full screen Page + if (kIsWeb) { return MaterialPage( - child: page, + child: route.page, key: ValueKey(s.name! + now), name: s.name, arguments: s.arguments, ); } else if (Platform.isIOS || Platform.isMacOS) { return CupertinoPage( - child: page, + child: route.page, key: ValueKey(s.name! + now), name: s.name, arguments: s.arguments, ); } else { return MaterialPage( - child: page, + child: SectionProvider( + sections: route.sections, + child: route.page, + ), key: ValueKey(s.name! + now), name: s.name, arguments: s.arguments, diff --git a/lib/router/routeInfo.dart b/lib/router/routes/routeInfo.dart similarity index 63% rename from lib/router/routeInfo.dart rename to lib/router/routes/routeInfo.dart index 1d05c6a..774ba5f 100644 --- a/lib/router/routeInfo.dart +++ b/lib/router/routes/routeInfo.dart @@ -1,13 +1,16 @@ import 'package:flutter/widgets.dart'; +import 'package:webstore/router/routes/sectionRouteInfo.dart'; class RouteInfo { final String name; final Widget page; final Object? arguments; + final List? sections; RouteInfo({ required this.name, required this.page, this.arguments, + this.sections, }); } diff --git a/lib/router/routes/sectionProvider.dart b/lib/router/routes/sectionProvider.dart new file mode 100644 index 0000000..ecab4f5 --- /dev/null +++ b/lib/router/routes/sectionProvider.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; +import 'package:webstore/router/routes/sectionRouteInfo.dart'; + +class SectionProvider extends InheritedWidget { + SectionProvider({ + Key? key, + required this.child, + required this.sections, + }) : super(key: key, child: child); + + final Widget child; + final List? sections; + + static SectionProvider? of(BuildContext context) { + return context.dependOnInheritedWidgetOfExactType(); + } + + @override + bool updateShouldNotify(SectionProvider oldWidget) { + return true; + } +} diff --git a/lib/router/routes/sectionRouteInfo.dart b/lib/router/routes/sectionRouteInfo.dart new file mode 100644 index 0000000..e39473b --- /dev/null +++ b/lib/router/routes/sectionRouteInfo.dart @@ -0,0 +1,8 @@ +import 'package:flutter/cupertino.dart'; + +class SectionRouteInfo { + final String name; + GlobalKey? key; + + SectionRouteInfo({required this.name, this.key}); +} diff --git a/lib/styles/extensions.dart b/lib/styles/extensions.dart new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/lib/styles/extensions.dart @@ -0,0 +1 @@ + diff --git a/lib/styles/legendColorTheme.dart b/lib/styles/legendColorTheme.dart index afbd1f9..ff6c69b 100644 --- a/lib/styles/legendColorTheme.dart +++ b/lib/styles/legendColorTheme.dart @@ -3,9 +3,32 @@ import 'package:flutter/material.dart'; class LegendColorTheme { final Color primaryColor; final Color secondaryColor; + final Color scaffoldBackgroundColor; LegendColorTheme({ required this.primaryColor, required this.secondaryColor, + required this.scaffoldBackgroundColor, }); + + // ranges from 0.0 to 1.0 + + static Color darken(Color color, [double amount = .1]) { + assert(amount >= 0 && amount <= 1); + + final hsl = HSLColor.fromColor(color); + final hslDark = hsl.withLightness((hsl.lightness - amount).clamp(0.0, 1.0)); + + return hslDark.toColor(); + } + + static Color lighten(Color color, [double amount = .1]) { + assert(amount >= 0 && amount <= 1); + + final hsl = HSLColor.fromColor(color); + final hslLight = + hsl.withLightness((hsl.lightness + amount).clamp(0.0, 1.0)); + + return hslLight.toColor(); + } } diff --git a/lib/styles/legendSizingTheme.dart b/lib/styles/legendSizingTheme.dart index 17f6ed1..983804b 100644 --- a/lib/styles/legendSizingTheme.dart +++ b/lib/styles/legendSizingTheme.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:webstore/styles/typography.dart'; +import 'package:webstore/customwidgets/typography/typography.dart'; class LegendSizing { final BorderRadius borderRadius; diff --git a/lib/styles/legendTheme.dart b/lib/styles/legendTheme.dart index a4d49dc..8f493ed 100644 --- a/lib/styles/legendTheme.dart +++ b/lib/styles/legendTheme.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:webstore/styles/legendColorTheme.dart'; import 'legendColorTheme.dart'; import 'legendSizingTheme.dart'; -import 'typography.dart'; +import '../customwidgets/typography/typography.dart'; enum LegendColorThemeType { LIGHT, @@ -23,10 +23,12 @@ class LegendTheme extends ChangeNotifier { LegendColorTheme lightColorTheme = LegendColorTheme( primaryColor: Colors.teal, secondaryColor: Colors.blueGrey, + scaffoldBackgroundColor: Colors.black.withOpacity(0.06), ); LegendColorTheme darkColorTheme = LegendColorTheme( - primaryColor: Colors.redAccent, - secondaryColor: Colors.blueGrey, + primaryColor: Colors.blueGrey, + secondaryColor: Colors.blueAccent, + scaffoldBackgroundColor: Colors.black.withOpacity(0.06), ); void changeColorTheme(LegendColorThemeType type) { diff --git a/lib/styles/sizeProvider.dart b/lib/styles/sizeProvider.dart index 2e04058..c6b0a1d 100644 --- a/lib/styles/sizeProvider.dart +++ b/lib/styles/sizeProvider.dart @@ -7,6 +7,14 @@ class SizeProvider extends InheritedWidget { late final ScreenSize screenSize; final double height; + // AppBar Menu Width + late double _menuWidth; + void setMenuWidth(double width) { + this._menuWidth = width; + } + + double get menuWidth => this._menuWidth; + SizeProvider({ required this.child, required this.width,