diff --git a/assets/icons/add.svg b/assets/icons/add.svg new file mode 100644 index 0000000..2d74577 --- /dev/null +++ b/assets/icons/add.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/icons/arrow_left.svg b/assets/icons/arrow_left.svg new file mode 100644 index 0000000..2db56f6 --- /dev/null +++ b/assets/icons/arrow_left.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assets/icons/arrow_right.svg b/assets/icons/arrow_right.svg new file mode 100644 index 0000000..dfc8100 --- /dev/null +++ b/assets/icons/arrow_right.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assets/icons/download.svg b/assets/icons/download.svg new file mode 100644 index 0000000..0e8dd4d --- /dev/null +++ b/assets/icons/download.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/icons/edit.svg b/assets/icons/edit.svg new file mode 100644 index 0000000..632a118 --- /dev/null +++ b/assets/icons/edit.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/icons/filter.svg b/assets/icons/filter.svg new file mode 100644 index 0000000..52500e7 --- /dev/null +++ b/assets/icons/filter.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/icons/scan.svg b/assets/icons/scan.svg new file mode 100644 index 0000000..071b59b --- /dev/null +++ b/assets/icons/scan.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/assets/icons/trash.svg b/assets/icons/trash.svg new file mode 100644 index 0000000..6c9b5a1 --- /dev/null +++ b/assets/icons/trash.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/vec/add.svg.vec b/assets/vec/add.svg.vec new file mode 100644 index 0000000..0e0727a Binary files /dev/null and b/assets/vec/add.svg.vec differ diff --git a/assets/vec/arrow_left.svg.vec b/assets/vec/arrow_left.svg.vec new file mode 100644 index 0000000..010f8fd Binary files /dev/null and b/assets/vec/arrow_left.svg.vec differ diff --git a/assets/vec/arrow_right.svg.vec b/assets/vec/arrow_right.svg.vec new file mode 100644 index 0000000..432f905 Binary files /dev/null and b/assets/vec/arrow_right.svg.vec differ diff --git a/assets/vec/download.svg.vec b/assets/vec/download.svg.vec new file mode 100644 index 0000000..cf531fa Binary files /dev/null and b/assets/vec/download.svg.vec differ diff --git a/assets/vec/edit.svg.vec b/assets/vec/edit.svg.vec new file mode 100644 index 0000000..e22f172 Binary files /dev/null and b/assets/vec/edit.svg.vec differ diff --git a/assets/vec/filter.svg.vec b/assets/vec/filter.svg.vec new file mode 100644 index 0000000..6c190a3 Binary files /dev/null and b/assets/vec/filter.svg.vec differ diff --git a/assets/vec/scan.svg.vec b/assets/vec/scan.svg.vec new file mode 100644 index 0000000..e8a6953 Binary files /dev/null and b/assets/vec/scan.svg.vec differ diff --git a/assets/vec/trash.svg.vec b/assets/vec/trash.svg.vec new file mode 100644 index 0000000..7d8c954 Binary files /dev/null and b/assets/vec/trash.svg.vec differ diff --git a/fonts/iranyekanregularfanum.ttf b/fonts/iranyekanregularfanum.ttf new file mode 100644 index 0000000..72d5808 Binary files /dev/null and b/fonts/iranyekanregularfanum.ttf differ diff --git a/lib/main.dart b/lib/main.dart index 616f2cc..787cc7e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,7 +1,20 @@ import 'package:flutter/material.dart'; +import 'package:rasadyar_app/presentation/common/app_color.dart'; +import 'package:rasadyar_app/presentation/common/app_fonts.dart'; +import 'package:rasadyar_app/presentation/utils/color_utils.dart'; +import 'package:rasadyar_app/presentation/widget/buttons/elevated.dart'; +import 'package:rasadyar_app/presentation/widget/buttons/fab_outlined.dart'; +import 'package:rasadyar_app/presentation/widget/buttons/outline_elevated.dart'; +import 'package:rasadyar_app/presentation/widget/buttons/text_button.dart'; +import 'package:rasadyar_app/presentation/widget/inputs/r_input.dart'; +import 'package:rasadyar_app/presentation/widget/pagination/pagination_from_until.dart'; +import 'package:rasadyar_app/presentation/widget/pagination/show_more.dart'; +import 'package:rasadyar_app/presentation/widget/tabs/tab.dart'; + +import 'presentation/widget/buttons/fab.dart'; void main() { - runApp(const MyApp()); + runApp(MyApp()); } class MyApp extends StatelessWidget { @@ -14,7 +27,259 @@ class MyApp extends StatelessWidget { theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), ), + home: Home(), ); } } +class Home extends StatefulWidget { + const Home({super.key}); + + @override + State createState() => _HomeState(); +} + +class _HomeState extends State { + List _isOpen = [false, false, false, false, false, false]; + + void _handleAdd() { + print("Add FAB pressed"); + } + + void _handleEdit() { + print("Edit FAB pressed"); + } + + void _handleDelete() { + print("Delete FAB pressed"); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text("System design"), centerTitle: true), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: ExpansionPanelList( + expansionCallback: (panelIndex, isExpanded) { + setState(() { + _isOpen[panelIndex] = isExpanded; + }); + }, + children: [ + buttonWidget(), + fabWidget(), + outlinedFabWidget(), + paginationWidget(), + tabWidget(), + inputsWidget(), + ], + ), + ), + ), + ); + } + + ExpansionPanel inputsWidget() { + return ExpansionPanel( + isExpanded: _isOpen[5], + headerBuilder: (context, isExpanded) { + return ListTile( + title: Text( + "inputs", + style: AppFonts.yekan20Regular.copyWith(color: Colors.red), + ), + ); + }, + body: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + spacing: 14, + children: [ + RTextField( + hintText: 'حجم کشتار را در روز به قطعه وارد کنید', + hintStyle: AppFonts.yekan13Regular, + ), + RTextField( + label: 'تلفن مرغداری', + labelStyle: AppFonts.yekan10Regular, + ), + ], + ), + ), + ); + } + + ExpansionPanel tabWidget() { + return ExpansionPanel( + isExpanded: _isOpen[4], + headerBuilder: (context, isExpanded) { + return ListTile( + title: Text( + "tab", + style: AppFonts.yekan20Regular.copyWith(color: Colors.red), + ), + ); + }, + body: Column( + spacing: 14, + children: [ + CupertinoSegmentedControlDemo(), + CupertinoSegmentedControlDemo2(), + ], + ), + ); + } + + ExpansionPanel paginationWidget() { + return ExpansionPanel( + isExpanded: _isOpen[3], + headerBuilder: (context, isExpanded) { + return ListTile( + title: Text( + "پیجینیشن", + style: AppFonts.yekan20Regular.copyWith(color: Colors.red), + ), + ); + }, + body: Column(spacing: 14, children: [RShowMore(), PaginationFromUntil()]), + ); + } + + ExpansionPanel outlinedFabWidget() { + return ExpansionPanel( + isExpanded: _isOpen[2], + headerBuilder: (context, isExpanded) { + return ListTile( + title: Text( + "Outlined Fab ", + style: AppFonts.yekan20Regular.copyWith(color: Colors.green), + ), + ); + }, + body: Column( + spacing: 14, + children: [ + Row(), + + RFabOutlined.smallAdd(onPressed: () {}), + RFabOutlined.smallAdd(onPressed: null), + + RFabOutlined.smallAddNoBorder(onPressed: () {}), + RFabOutlined.smallAddNoBorder(onPressed: null), + + RFabOutlined.add(onPressed: () {}), + RFabOutlined.add(onPressed: null), + + RFabOutlined.addNoBorder(onPressed: () {}), + RFabOutlined.addNoBorder(onPressed: null), + ], + ), + ); + } + + ExpansionPanel fabWidget() { + return ExpansionPanel( + isExpanded: _isOpen[1], + headerBuilder: (context, isExpanded) { + return ListTile( + title: Text( + "Fab", + style: AppFonts.yekan20Regular.copyWith(color: Colors.green), + ), + ); + }, + body: Column( + spacing: 14, + children: [ + Row(), + + RFab.smallAdd(onPressed: () {}), + RFab.smallAdd(onPressed: null), + + RFab.add(onPressed: () {}), + RFab.add(onPressed: null), + + RFab.smallEdit(onPressed: null), + RFab.smallEdit(onPressed: () {}), + + RFab.edit(onPressed: () {}), + RFab.edit(onPressed: null), + + RFab.smallDelete(onPressed: () {}), + RFab.smallDelete(onPressed: null), + + RFab.delete(onPressed: () {}), + RFab.delete(onPressed: null), + + RFab.smallAction(onPressed: () {}), + RFab.smallAction(onPressed: null), + + RFab.action(onPressed: () {}), + RFab.action(onPressed: null), + + RFab.smallFilter(onPressed: () {}), + RFab.smallFilter(onPressed: null), + + RFab.filter(onPressed: () {}), + RFab.filter(onPressed: null), + + RFab.smallDownload(onPressed: () {}), + RFab.smallDownload(onPressed: null), + + RFab.download(onPressed: () {}), + RFab.download(onPressed: null), + + RFab.smallExcel(onPressed: () {}), + RFab.smallExcel(onPressed: null), + + RFab.excel(onPressed: () {}), + RFab.excel(onPressed: null), + + RFab.smallBack(onPressed: () {}), + RFab.smallBack(onPressed: null), + + RFab.back(onPressed: () {}), + RFab.back(onPressed: null), + ], + ), + ); + } + + ExpansionPanel buttonWidget() { + return ExpansionPanel( + isExpanded: _isOpen[0], + headerBuilder: (context, isExpanded) { + return ListTile( + title: Text( + "دکمه ها", + style: AppFonts.yekan20Regular.copyWith(color: Colors.green), + ), + ); + }, + body: Column( + spacing: 14, + children: [ + Row(), + + RElevated(text: 'ثبت', onPressed: () {}), + + RElevated(text: 'ثبت', onPressed: null), + + ROutlinedElevated(text: 'ثبت', onPressed: () {}), + ROutlinedElevated( + text: 'ثبتwwww', + onPressed: () {}, + backgroundColor: AppColor.blueNormal.disabledColor, + pressedBackgroundColor: AppColor.blueNormal, + ), + ROutlinedElevated(text: 'ثبت', onPressed: null), + + RTextButton(text: 'ثبت', onPressed: () {}), + RTextButton(text: 'ثبت', onPressed: null), + ], + ), + ); + } +} diff --git a/lib/presentation/common/app_fonts.dart b/lib/presentation/common/app_fonts.dart new file mode 100644 index 0000000..70b06fe --- /dev/null +++ b/lib/presentation/common/app_fonts.dart @@ -0,0 +1,155 @@ +import 'package:flutter/material.dart'; + +class AppFonts { + AppFonts._(); // Private constructor to prevent instantiation + + // --- Font Families --- + static const String yekan = 'yekan'; + + // --- Font Weights --- + static const FontWeight regular = FontWeight.w400; + static const FontWeight bold = FontWeight.w600; + static const double _height = 1.20; + + static const TextStyle yekan61Regular = TextStyle( + fontFamily: yekan, + fontWeight: regular, + fontSize: 61, + height: _height, + ); + + static const TextStyle yekan49Regular = TextStyle( + fontFamily: yekan, + fontWeight: regular, + fontSize: 48, + height: _height, + ); + + static const TextStyle yekan39Regular = TextStyle( + fontFamily: yekan, + fontWeight: regular, + fontSize: 39, + height: _height, + ); + + static const TextStyle yekan31Regular = TextStyle( + fontFamily: yekan, + fontWeight: regular, + fontSize: 31, + height: _height, + ); + + static const TextStyle yekan25Regular = TextStyle( + fontFamily: yekan, + fontWeight: regular, + fontSize: 25, + height: _height, + ); + + static const TextStyle yekan24Regular = TextStyle( + fontFamily: yekan, + fontWeight: regular, + fontSize: 24, + height: _height, + ); + + static const TextStyle yekan20Regular = TextStyle( + fontFamily: yekan, + fontWeight: regular, + fontSize: 20, + height: _height, + ); + + static const TextStyle yekan16Regular = TextStyle( + fontFamily: yekan, + fontWeight: regular, + fontSize: 16, + height: _height, + ); + + static const TextStyle yekan13Regular = TextStyle( + fontFamily: yekan, + fontWeight: regular, + fontSize: 13, + height: _height, + ); + + static const TextStyle yekan10Regular = TextStyle( + // Rounded from 10.24 + fontFamily: yekan, + fontWeight: regular, + fontSize: 10, + height: _height, + ); + + static const TextStyle yekan61Bold = TextStyle( + fontFamily: yekan, + fontWeight: bold, // Use bold weight + fontSize: 61, + height: _height, + ); + + static const TextStyle yekan49Bold = TextStyle( + fontFamily: yekan, + fontWeight: bold, // Use bold weight + fontSize: 48, + height: _height, + ); + + static const TextStyle yekan39Bold = TextStyle( + fontFamily: yekan, + fontWeight: bold, // Use bold weight + fontSize: 39, + height: _height, + ); + + static const TextStyle yekan31Bold = TextStyle( + fontFamily: yekan, + fontWeight: bold, // Use bold weight + fontSize: 31, + height: _height, + ); + + static const TextStyle yekan25Bold = TextStyle( + fontFamily: yekan, + fontWeight: bold, // Use bold weight + fontSize: 25, + height: _height, + ); + + static const TextStyle yekan24Bold = TextStyle( + fontFamily: yekan, + fontWeight: bold, // Use bold weight + fontSize: 24, + height: _height, + ); + + static const TextStyle yekan20Bold = TextStyle( + fontFamily: yekan, + fontWeight: bold, // Use bold weight + fontSize: 20, + height: _height, + ); + + static const TextStyle yekan16Bold = TextStyle( + // Base size bold + fontFamily: yekan, + fontWeight: bold, // Use bold weight + fontSize: 16, + height: _height, + ); + + static const TextStyle yekan13Bold = TextStyle( + fontFamily: yekan, + fontWeight: bold, // Use bold weight + fontSize: 13, + height: _height, + ); + + static const TextStyle yekan10Bold = TextStyle( + fontFamily: yekan, + fontWeight: bold, // Use bold weight + fontSize: 10, + height: _height, + ); +} diff --git a/lib/presentation/common/assets.dart b/lib/presentation/common/assets.dart new file mode 100644 index 0000000..185d647 --- /dev/null +++ b/lib/presentation/common/assets.dart @@ -0,0 +1,24 @@ +///This file is automatically generated. DO NOT EDIT, all your changes would be lost. +class Assets { + Assets._(); + + static const String iconsAdd = 'assets/icons/add.svg'; + static const String iconsArrowLeft = 'assets/icons/arrow_left.svg'; + static const String iconsArrowRight = 'assets/icons/arrow_right.svg'; + static const String iconsDownload = 'assets/icons/download.svg'; + static const String iconsEdit = 'assets/icons/edit.svg'; + static const String iconsFilter = 'assets/icons/filter.svg'; + static const String iconsScan = 'assets/icons/scan.svg'; + static const String iconsTrash = 'assets/icons/trash.svg'; + static const String imagesInnerSplash = 'assets/images/inner_splash.webp'; + static const String imagesOutterSplash = 'assets/images/outter_splash.webp'; + static const String vecAddSvg = 'assets/vec/add.svg.vec'; + static const String vecArrowLeftSvg = 'assets/vec/arrow_left.svg.vec'; + static const String vecArrowRightSvg = 'assets/vec/arrow_right.svg.vec'; + static const String vecDownloadSvg = 'assets/vec/download.svg.vec'; + static const String vecEditSvg = 'assets/vec/edit.svg.vec'; + static const String vecFilterSvg = 'assets/vec/filter.svg.vec'; + static const String vecScanSvg = 'assets/vec/scan.svg.vec'; + static const String vecTrashSvg = 'assets/vec/trash.svg.vec'; + +} diff --git a/lib/presentation/utils/color_utils.dart b/lib/presentation/utils/color_utils.dart new file mode 100644 index 0000000..46f9bb8 --- /dev/null +++ b/lib/presentation/utils/color_utils.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; + +extension ColorUtils on Color { + Color _darken([double amount = 0.1]) { + assert(amount >= 0 && amount <= 1, 'مقدار تیرگی باید بین 0 و 1 باشد'); + final hslColor = HSLColor.fromColor(this); + final newLightness = (hslColor.lightness - amount).clamp(0.0, 1.0); + final hslDarkerColor = hslColor.withLightness(newLightness); + return hslDarkerColor.toColor(); + } + + get disabledColor{ + return withAlpha(38); + } + + get hoverColor{ + return _darken(0.5); + } + + get pressedColor{ + return _darken(0.10); + } + +} diff --git a/lib/presentation/widget/buttons/elevated.dart b/lib/presentation/widget/buttons/elevated.dart new file mode 100644 index 0000000..c03bc2e --- /dev/null +++ b/lib/presentation/widget/buttons/elevated.dart @@ -0,0 +1,58 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_app/presentation/common/app_color.dart'; +import 'package:rasadyar_app/presentation/common/app_fonts.dart'; + +class RElevated extends StatefulWidget { + RElevated({ + super.key, + required this.text, + required this.onPressed, + foregroundColor, + backgroundColor, + disabledBackgroundColor, + disabledForegroundColor, + radius, + textStyle, + this.width = 150.0, + this.height = 56.0, + }); + + final String text; + final VoidCallback? onPressed; + final double width; + final double height; + Color? foregroundColor; + Color? backgroundColor; + Color? disabledForegroundColor; + Color? disabledBackgroundColor; + double? radius; + TextStyle? textStyle; + + @override + State createState() => _RElevatedState(); +} + +class _RElevatedState extends State { + @override + Widget build(BuildContext context) { + return ElevatedButton( + onPressed: () { + setState(() {}); + }, + style: ElevatedButton.styleFrom( + backgroundColor: widget.backgroundColor ?? AppColor.blueNormal, + foregroundColor: widget.foregroundColor ?? Colors.white, + disabledBackgroundColor: + widget.disabledBackgroundColor ?? AppColor.blueNormal.withAlpha(38), + disabledForegroundColor: widget.disabledForegroundColor ?? Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(widget.radius ?? 8), + ), + fixedSize: Size(widget.width, widget.height), + padding: EdgeInsets.zero, + textStyle: widget.textStyle ?? AppFonts.yekan24Regular, + ), + child: Text(widget.text), + ); + } +} diff --git a/lib/presentation/widget/buttons/fab.dart b/lib/presentation/widget/buttons/fab.dart new file mode 100644 index 0000000..84a4e8b --- /dev/null +++ b/lib/presentation/widget/buttons/fab.dart @@ -0,0 +1,232 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_app/presentation/common/app_color.dart'; +import 'package:rasadyar_app/presentation/common/assets.dart'; +import 'package:rasadyar_app/presentation/utils/color_utils.dart'; +import 'package:rasadyar_app/presentation/widget/vec_widget.dart'; + +class RFab extends StatefulWidget { + + + final VoidCallback? onPressed; + Color? foregroundColor; + Color? backgroundColor; + Color? disabledForegroundColor; + Color? disabledBackgroundColor; + double? radius; + ShapeBorder? shapeBorder; + Widget? icon; + + @override + State createState() => _RFabState(); + + //region Add + RFab.smallAdd({required VoidCallback? onPressed, Key? key}) + : this.small( + onPressed: onPressed, + icon: vecWidget(Assets.vecAddSvg), + backgroundColor: AppColor.greenNormal, + key: key, + ); + + RFab.add({required VoidCallback? onPressed, Key? key}) + : this( + onPressed: onPressed, + icon: vecWidget(Assets.vecAddSvg), + backgroundColor: AppColor.greenNormal, + key: key, + ); + + //endregion + + //region Edit + RFab.smallEdit({required VoidCallback? onPressed, Key? key}) + : this.small( + onPressed: onPressed, + icon: vecWidget(Assets.vecEditSvg), + backgroundColor: AppColor.blueNormal, + key: key, + ); + + RFab.edit({required VoidCallback? onPressed, Key? key}) + : this( + onPressed: onPressed, + icon: vecWidget(Assets.vecEditSvg), + backgroundColor: AppColor.blueNormal, + key: key, + ); + + //endregion + + //region delete + RFab.smallDelete({required VoidCallback? onPressed, Key? key}) + : this.small( + onPressed: onPressed, + icon: vecWidget(Assets.vecTrashSvg), + backgroundColor: AppColor.redNormal, + key: key, + ); + + RFab.delete({required VoidCallback? onPressed, Key? key}) + : this( + onPressed: onPressed, + icon: vecWidget(Assets.vecTrashSvg), + backgroundColor: AppColor.redNormal, + key: key, + ); + + //endregion + + //region action + RFab.smallAction({required VoidCallback? onPressed, Key? key}) + : this.small( + onPressed: onPressed, + icon: vecWidget(Assets.vecScanSvg), + backgroundColor: AppColor.blueNormal, + key: key, + ); + + RFab.action({required VoidCallback? onPressed, Key? key}) + : this( + onPressed: onPressed, + icon: vecWidget(Assets.vecScanSvg), + backgroundColor: AppColor.blueNormal, + key: key, + ); + + //endregion + + //region filter + RFab.smallFilter({required VoidCallback? onPressed, Key? key}) + : this.small( + onPressed: onPressed, + icon: vecWidget(Assets.vecFilterSvg), + backgroundColor: AppColor.blueNormal, + key: key, + ); + + RFab.filter({required VoidCallback? onPressed, Key? key}) + : this( + onPressed: onPressed, + icon: vecWidget(Assets.vecFilterSvg), + backgroundColor: AppColor.blueNormal, + key: key, + ); + + //endregion + + //region download + RFab.smallDownload({required VoidCallback? onPressed, Key? key}) + : this.small( + onPressed: onPressed, + icon: vecWidget(Assets.vecDownloadSvg), + backgroundColor: AppColor.blueNormal, + key: key, + ); + + RFab.download({required VoidCallback? onPressed, Key? key}) + : this( + onPressed: onPressed, + icon: vecWidget(Assets.vecDownloadSvg), + backgroundColor: AppColor.blueNormal, + key: key, + ); + + //endregion + + //region Excel + RFab.smallExcel({required VoidCallback? onPressed, Key? key}) + : this.small( + onPressed: onPressed, + icon: vecWidget(Assets.vecDownloadSvg), + backgroundColor: AppColor.greenDark, + key: key, + ); + + RFab.excel({required VoidCallback? onPressed, Key? key}) + : this( + onPressed: onPressed, + icon: vecWidget(Assets.vecDownloadSvg), + backgroundColor: AppColor.greenDark, + key: key, + ); + + //endregion + + //region Back + RFab.smallBack({required VoidCallback? onPressed, Key? key}) + : this.small( + onPressed: onPressed, + icon: vecWidget(Assets.vecArrowLeftSvg), + backgroundColor: AppColor.blueNormal, + key: key, + ); + + RFab.back({required VoidCallback? onPressed, Key? key}) + : this( + onPressed: onPressed, + icon: vecWidget(Assets.vecArrowLeftSvg), + backgroundColor: AppColor.blueNormal, + key: key, + ); + + //endregion + + //region General + RFab.small({ + required this.onPressed, + required this.icon, + required this.backgroundColor, + super.key, + }) : radius = 40.0, + foregroundColor = Colors.white; + + RFab({ + required this.onPressed, + required this.icon, + required this.backgroundColor, + super.key, + }) : radius = 56.0, + foregroundColor = Colors.white; + + //endregion +} + +class _RFabState extends State { + @override + Widget build(BuildContext context) { + return ElevatedButton( + onPressed: widget.onPressed, + style: ButtonStyle( + side: WidgetStateProperty.all(BorderSide.none), + backgroundColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.pressed)) { + return widget.backgroundColor?.pressedColor ?? + AppColor.blueNormalActive; + } else if (states.contains(WidgetState.hovered)) { + return widget.backgroundColor?.hoverColor ?? + AppColor.blueNormalHover; + } else if (states.contains(WidgetState.disabled)) { + return widget.backgroundColor?.disabledColor ?? + AppColor.blueNormal.disabledColor; + } + return widget.backgroundColor ?? AppColor.blueNormal; + }), + foregroundColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.disabled)) { + return widget.foregroundColor?.disabledColor; + } + return widget.foregroundColor; + }), + + shape: WidgetStatePropertyAll( + CircleBorder(side: BorderSide(width: 1, color: Colors.transparent)), + ), + fixedSize: WidgetStatePropertyAll( + Size(widget.radius ?? 56, widget.radius ?? 56), + ), + padding: WidgetStatePropertyAll(EdgeInsets.zero), + ), + child: widget.icon, + ); + } +} diff --git a/lib/presentation/widget/buttons/fab_outlined.dart b/lib/presentation/widget/buttons/fab_outlined.dart new file mode 100644 index 0000000..ecd9ea1 --- /dev/null +++ b/lib/presentation/widget/buttons/fab_outlined.dart @@ -0,0 +1,605 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_app/presentation/common/app_color.dart'; +import 'package:rasadyar_app/presentation/common/assets.dart'; +import 'package:rasadyar_app/presentation/utils/color_utils.dart'; +import 'package:rasadyar_app/presentation/widget/vec_widget.dart'; + +class RFabOutlined extends StatefulWidget { + final Widget icon; + VoidCallback? onPressed; + final Color backgroundColor; + final Color? borderColor; + final double? radius; + OutlinedBorder? shapeBorder; + + @override + State createState() => _RFabOutlinedState(); + + //region General + RFabOutlined({ + required this.icon, + required this.onPressed, + required this.backgroundColor, + required this.borderColor, + this.radius = 56.0, + super.key, + }) : shapeBorder = CircleBorder( + side: BorderSide(color: borderColor ?? Colors.transparent), + ); + + RFabOutlined.noBorder({ + required this.icon, + required this.onPressed, + required this.backgroundColor, + super.key, + }) : borderColor = Colors.transparent, + radius = 56.0, + shapeBorder = CircleBorder( + side: BorderSide(color: Colors.transparent, width: 1), + ); + + RFabOutlined.small({ + required this.icon, + required this.onPressed, + required this.backgroundColor, + required this.borderColor, + super.key, + }) : radius = 40.0, + shapeBorder = CircleBorder( + side: BorderSide(color: borderColor ?? Colors.transparent, width: 1), + ); + + RFabOutlined.smallNoBorder({ + required this.icon, + required this.onPressed, + required this.backgroundColor, + super.key, + }) : borderColor = Colors.transparent, + radius = 40.0, + shapeBorder = CircleBorder( + side: BorderSide(color: Colors.transparent, width: 1), + ); + + //endregion + + //region Add + RFabOutlined.smallAdd({VoidCallback? onPressed, Key? key}) + : this.small( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.greenNormal, + borderColor: AppColor.greenNormal, + icon: vecWidget2( + Assets.vecAddSvg, + + color: AppColor.greenNormal, + ), + ); + + RFabOutlined.smallAddNoBorder({VoidCallback? onPressed, Key? key}) + : this.smallNoBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.greenNormal, + icon: vecWidget( + Assets.vecAddSvg, + color: + onPressed != null + ? AppColor.greenNormal + : AppColor.greenNormal.disabledColor, + ), + ); + + RFabOutlined.add({VoidCallback? onPressed, Key? key}) + : this( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.greenNormal, + borderColor: AppColor.greenNormal, + icon: vecWidget( + Assets.vecAddSvg, + color: + onPressed != null + ? AppColor.greenNormal + : AppColor.greenNormal.disabledColor, + ), + ); + + RFabOutlined.addNoBorder({VoidCallback? onPressed, Key? key}) + : this.noBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.greenNormal, + icon: vecWidget( + Assets.vecAddSvg, + color: + onPressed != null + ? AppColor.greenNormal + : AppColor.greenNormal.disabledColor, + ), + ); + + //endregion + + //region Edit + RFabOutlined.smallEdit({VoidCallback? onPressed, Key? key}) + : this.small( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + borderColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecEditSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.smallEditNoBorder({VoidCallback? onPressed, Key? key}) + : this.smallNoBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecEditSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.edit({VoidCallback? onPressed, Key? key}) + : this( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + borderColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecEditSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.editNoBorder({VoidCallback? onPressed, Key? key}) + : this.noBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecEditSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + //endregion + + //region Delete + RFabOutlined.smallDelete({VoidCallback? onPressed, Key? key}) + : this.small( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.redNormal, + borderColor: AppColor.redNormal, + icon: vecWidget( + Assets.vecTrashSvg, + color: + onPressed != null + ? AppColor.redNormal + : AppColor.redNormal.disabledColor, + ), + ); + + RFabOutlined.smallDeleteNoBorder({VoidCallback? onPressed, Key? key}) + : this.smallNoBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.redNormal, + icon: vecWidget( + Assets.vecTrashSvg, + color: + onPressed != null + ? AppColor.redNormal + : AppColor.redNormal.disabledColor, + ), + ); + + RFabOutlined.delete({VoidCallback? onPressed, Key? key}) + : this( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.redNormal, + borderColor: AppColor.redNormal, + icon: vecWidget( + Assets.vecTrashSvg, + color: + onPressed != null + ? AppColor.redNormal + : AppColor.redNormal.disabledColor, + ), + ); + + RFabOutlined.deleteNoBorder({VoidCallback? onPressed, Key? key}) + : this.noBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.redNormal, + icon: vecWidget( + Assets.vecTrashSvg, + color: + onPressed != null + ? AppColor.redNormal + : AppColor.redNormal.disabledColor, + ), + ); + + //endregion + + //region Action + RFabOutlined.smallAction({VoidCallback? onPressed, Key? key}) + : this.small( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + borderColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecScanSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.smallActionNoBorder({VoidCallback? onPressed, Key? key}) + : this.smallNoBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecScanSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.action({VoidCallback? onPressed, Key? key}) + : this( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + borderColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecScanSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.actionNoBorder({VoidCallback? onPressed, Key? key}) + : this.noBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecScanSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + //endregion + + //region Filter + RFabOutlined.smallFilter({VoidCallback? onPressed, Key? key}) + : this.small( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + borderColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecFilterSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.smallFilterNoBorder({VoidCallback? onPressed, Key? key}) + : this.smallNoBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecFilterSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.filter({VoidCallback? onPressed, Key? key}) + : this( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + borderColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecFilterSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.filterNoBorder({VoidCallback? onPressed, Key? key}) + : this.noBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecFilterSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + //endregion + + //region Download + RFabOutlined.smallDownload({VoidCallback? onPressed, Key? key}) + : this.small( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + borderColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecDownloadSvg, + color: + onPressed != null + ? AppColor.greenDark + : AppColor.greenDark.disabledColor, + ), + ); + + RFabOutlined.smallDownloadNoBorder({VoidCallback? onPressed, Key? key}) + : this.smallNoBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecDownloadSvg, + color: + onPressed != null + ? AppColor.greenDark + : AppColor.greenDark.disabledColor, + ), + ); + + RFabOutlined.download({VoidCallback? onPressed, Key? key}) + : this( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + borderColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecDownloadSvg, + color: + onPressed != null + ? AppColor.greenDark + : AppColor.greenDark.disabledColor, + ), + ); + + RFabOutlined.downloadNoBorder({VoidCallback? onPressed, Key? key}) + : this.noBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecDownloadSvg, + color: + onPressed != null + ? AppColor.greenDark + : AppColor.greenDark.disabledColor, + ), + ); + + //endregion + + //region Excel + RFabOutlined.smallExcel({VoidCallback? onPressed, Key? key}) + : this.small( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.greenDark, + borderColor: AppColor.greenDark, + icon: vecWidget( + Assets.vecDownloadSvg, + color: + onPressed != null + ? AppColor.greenDark + : AppColor.greenDark.disabledColor, + ), + ); + + RFabOutlined.smallExcelNoBorder({VoidCallback? onPressed, Key? key}) + : this.noBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.greenDark, + icon: vecWidget( + Assets.vecDownloadSvg, + color: + onPressed != null + ? AppColor.greenDark + : AppColor.greenDark.disabledColor, + ), + ); + + RFabOutlined.excel({VoidCallback? onPressed, Key? key}) + : this( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.greenDark, + borderColor: AppColor.greenDark, + icon: vecWidget( + Assets.vecDownloadSvg, + color: + onPressed != null + ? AppColor.greenDark + : AppColor.greenDark.disabledColor, + ), + ); + + RFabOutlined.excelNoBorder({VoidCallback? onPressed, Key? key}) + : this.noBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.greenDark, + icon: vecWidget( + Assets.vecDownloadSvg, + color: + onPressed != null + ? AppColor.greenDark + : AppColor.greenDark.disabledColor, + ), + ); + + //endregion + + //region Back + RFabOutlined.smallBack({VoidCallback? onPressed, Key? key}) + : this.small( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + borderColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecArrowLeftSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.smallBackNoBorder({VoidCallback? onPressed, Key? key}) + : this.smallNoBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecArrowLeftSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.back({VoidCallback? onPressed, Key? key}) + : this( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + borderColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecArrowLeftSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + RFabOutlined.backNoBorder({VoidCallback? onPressed, Key? key}) + : this.noBorder( + key: key, + onPressed: onPressed, + backgroundColor: AppColor.blueNormal, + icon: vecWidget( + Assets.vecArrowLeftSvg, + color: + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + ), + ); + + //endregion +} + +class _RFabOutlinedState extends State { + bool isOnPressed =false; + @override + Widget build(BuildContext context) { + return OutlinedButton( + onPressed:widget.onPressed , + style: ButtonStyle( + side: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.disabled)) { + return BorderSide( + color: + widget.borderColor?.disabledColor ?? + AppColor.blueNormal.disabledColor, + width: 2, + ); + } + return BorderSide( + color: widget.borderColor ?? AppColor.blueNormal, + width: 2, + ); + }), + backgroundColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.pressed)) { + return widget.backgroundColor; + } else if (states.contains(WidgetState.hovered)) { + return widget.backgroundColor.hoverColor ?? + AppColor.blueNormal.hoverColor; + } else if (states.contains(WidgetState.disabled)) { + return widget.backgroundColor.disabledColor ?? + AppColor.blueNormal.disabledColor; + } + return Colors.transparent; + }), + foregroundColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.pressed)) { + return Colors.white; + } else if (states.contains(WidgetState.disabled)) { + return widget.backgroundColor.disabledColor ?? + AppColor.blueNormal.disabledColor; + } + return widget.backgroundColor; + }), + + shape: WidgetStatePropertyAll(widget.shapeBorder), + fixedSize: WidgetStatePropertyAll( + Size(widget.radius ?? 56, widget.radius ?? 56), + ), + padding: WidgetStatePropertyAll(EdgeInsets.zero), + ), + child: widget.icon + ); + } +} + diff --git a/lib/presentation/widget/buttons/outline_elevated.dart b/lib/presentation/widget/buttons/outline_elevated.dart new file mode 100644 index 0000000..23272bf --- /dev/null +++ b/lib/presentation/widget/buttons/outline_elevated.dart @@ -0,0 +1,101 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_app/presentation/common/app_color.dart'; +import 'package:rasadyar_app/presentation/common/app_fonts.dart'; +import 'package:rasadyar_app/presentation/utils/color_utils.dart'; + +class ROutlinedElevated extends StatefulWidget { + ROutlinedElevated({ + super.key, + required this.text, + required this.onPressed, + this.foregroundColor, + this.backgroundColor, + this.borderColor, + this.disabledBackgroundColor, + this.pressedBackgroundColor, + this.radius, + this.textStyle, + this.width = 150.0, + this.height = 56.0, + }); + + final String text; + final VoidCallback? onPressed; + final double width; + final double height; + Color? foregroundColor; + Color? backgroundColor; + + Color? borderColor; + + Color? disabledBackgroundColor; + Color? pressedBackgroundColor; + double? radius; + TextStyle? textStyle; + + @override + State createState() => _ROutlinedElevatedState(); +} + +class _ROutlinedElevatedState extends State { + @override + Widget build(BuildContext context) { + return OutlinedButton( + onPressed: widget.onPressed, + style: ButtonStyle( + side: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.pressed)) { + return BorderSide( + color: widget.borderColor ?? AppColor.blueNormal, + width: 2, + ); + } else if (states.contains(WidgetState.disabled)) { + return BorderSide( + color: widget.borderColor ?? AppColor.blueNormal.withAlpha(38), + width: 2, + ); + } + return BorderSide( + color: widget.borderColor ?? AppColor.blueNormal, + width: 2, + ); + }), + backgroundColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.pressed)) { + if (widget.pressedBackgroundColor != null) { + return widget.pressedBackgroundColor; + } + return widget.backgroundColor?.pressedColor ?? AppColor.blueNormal; + } else if (states.contains(WidgetState.hovered)) { + return widget.backgroundColor?.hoverColor ?? + AppColor.blueNormal.hoverColor; + } else if (states.contains(WidgetState.disabled)) { + return widget.backgroundColor?.disabledColor ?? Colors.transparent; + } + return widget.backgroundColor; + }), + foregroundColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.pressed)) { + return Colors.white; + } else if (states.contains(WidgetState.disabled)) { + return AppColor.blueNormal.withAlpha(38); + } + return AppColor.blueNormal; + }), + + shape: WidgetStatePropertyAll( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(widget.radius ?? 8), + ), + ), + fixedSize: WidgetStatePropertyAll(Size(widget.width, widget.height)), + padding: WidgetStatePropertyAll(EdgeInsets.zero), + textStyle: WidgetStatePropertyAll( + widget.textStyle ?? + AppFonts.yekan24Regular.copyWith(color: AppColor.blueNormal), + ), + ), + child: Text(widget.text), + ); + } +} diff --git a/lib/presentation/widget/buttons/text_button.dart b/lib/presentation/widget/buttons/text_button.dart new file mode 100644 index 0000000..40fb3a4 --- /dev/null +++ b/lib/presentation/widget/buttons/text_button.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_app/presentation/common/app_color.dart'; +import 'package:rasadyar_app/presentation/common/app_fonts.dart'; + +class RTextButton extends StatefulWidget { + RTextButton({ + super.key, + required this.text, + required this.onPressed, + foregroundColor, + backgroundColor, + borderColor, + disabledBackgroundColor, + radius, + textStyle, + this.width = 150.0, + this.height = 56.0, + }); + + final String text; + final VoidCallback? onPressed; + final double width; + final double height; + Color? foregroundColor; + Color? backgroundColor; + Color? borderColor; + + Color? disabledBackgroundColor; + double? radius; + TextStyle? textStyle; + + @override + State createState() => _RTextButtonState(); +} + +class _RTextButtonState extends State { + @override + Widget build(BuildContext context) { + return TextButton( + style: ButtonStyle( + side: WidgetStatePropertyAll(BorderSide.none), + backgroundColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.pressed)) { + return widget.backgroundColor ?? AppColor.blueNormal; + } else if (states.contains(WidgetState.hovered)) { + return widget.backgroundColor?.withAlpha(38) ?? AppColor.blueNormal.withAlpha(38); + } else if (states.contains(WidgetState.disabled)) { + return widget.disabledBackgroundColor ?? Colors.transparent; + } + return Colors.transparent; + }), + foregroundColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.pressed)) { + return Colors.white; + } else if (states.contains(WidgetState.disabled)) { + return AppColor.blueNormal.withAlpha(38); + } + return AppColor.blueNormal; + }), + + shape: WidgetStatePropertyAll( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(widget.radius ?? 8), + ), + ), + fixedSize: WidgetStatePropertyAll(Size(widget.width, widget.height)), + padding: WidgetStatePropertyAll(EdgeInsets.zero), + textStyle: WidgetStatePropertyAll( + widget.textStyle ?? + AppFonts.yekan24Regular.copyWith(color: AppColor.blueNormal), + ), + ), + onPressed:widget.onPressed, + child: Text(widget.text), + ); + } +} diff --git a/lib/presentation/widget/inputs/r_input.dart b/lib/presentation/widget/inputs/r_input.dart new file mode 100644 index 0000000..07edc2b --- /dev/null +++ b/lib/presentation/widget/inputs/r_input.dart @@ -0,0 +1,216 @@ + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +@immutable +class RTextField extends StatefulWidget { + RTextField( + {super.key, + this.maxLines, + this.maxLength, + this.hintText, + this.padding, + this.onChanged, + this.onSubmitted, + this.keyboardType, + this.showCounter = false, + this.isDense, + this.initText, + this.isForNumber = false, + this.style, + this.hintStyle, + this.suffixIcon, + this.prefixIcon, + this.validator, + this.readonly = false, + this.boxConstraints, + this.minLines, + this.radius, + this.filled, + this.enabled, + this.errorStyle, + this.labelStyle, + this.label}) { + filled = filled ?? false; + obscure = false; + _inputBorder = OutlineInputBorder( + borderSide: BorderSide(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(radius ?? 16)); + } + + RTextField.noBorder( + {super.key, + this.maxLines, + this.maxLength, + this.hintText, + this.padding, + this.onChanged, + this.onSubmitted, + this.keyboardType, + this.showCounter = false, + this.isDense, + this.initText, + this.style, + this.hintStyle, + this.suffixIcon, + this.radius, + this.validator, + this.boxConstraints, + this.minLines, + this.isForNumber = false, + this.readonly = false, + this.label, + this.filled, + this.errorStyle, + this.labelStyle, + this.enabled}) { + _inputBorder = OutlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.circular(radius ?? 16)); + obscure = false; + filled = filled ?? true; + } + + RTextField.password( + {super.key, + this.maxLines = 1, + this.maxLength, + this.hintText, + this.padding, + this.onChanged, + this.onSubmitted, + this.keyboardType, + this.showCounter = false, + this.isDense, + this.initText, + this.style, + this.hintStyle, + this.suffixIcon, + this.prefixIcon, + this.radius, + this.validator, + this.boxConstraints, + this.minLines, + this.isForNumber = false, + this.readonly = false, + this.label, + this.filled, + this.errorStyle, + this.labelStyle, + this.enabled}) { + _inputBorder = OutlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.circular(radius ?? 16)); + filled = filled ?? true; + obscure = true; + _isPassword = true; + prefixIcon = prefixIcon ?? const Icon(CupertinoIcons.person); + } + + final int? maxLines; + final int? minLines; + final int? maxLength; + final String? hintText; + final String? label; + final EdgeInsets? padding; + final TextStyle? style; + final TextStyle? errorStyle; + final TextStyle? hintStyle; + final TextStyle? labelStyle; + final bool showCounter; + final bool? isDense; + final bool? isForNumber; + final bool readonly; + bool? obscure; + final bool? enabled; + final double? radius; + final TextInputType? keyboardType; + final Function(String)? onChanged; + final Function(String)? onSubmitted; + final FormFieldValidator? validator; + final String? initText; + Widget? suffixIcon; + Widget? prefixIcon; + bool? filled; + bool _isPassword = false; + + final BoxConstraints? boxConstraints; + late final InputBorder? _inputBorder; + + @override + State createState() => _RTextFieldState(); +} + +class _RTextFieldState extends State { + final TextEditingController _controller = TextEditingController(); + bool? obscure; + + @override + void initState() { + super.initState(); + if (widget.initText != null) { + _controller.text = widget.initText!; + } + obscure = widget.obscure; + } + + @override + void didUpdateWidget(covariant RTextField oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.initText != oldWidget.initText) { + _controller.text = widget.initText ?? ''; + } + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: widget.padding ?? const EdgeInsets.symmetric(vertical: 6.0), + child: TextFormField( + controller: _controller, + readOnly: widget.readonly, + minLines: widget.minLines, + maxLines: widget.maxLines, + onChanged: widget.onChanged, + validator: widget.validator, + enabled: widget.enabled, + obscureText: obscure ?? false, + onTapOutside: (event) { + FocusScope.of(context).unfocus(); + }, + onFieldSubmitted: widget.onSubmitted, + maxLength: widget.maxLength, + textDirection: TextDirection.rtl, + style: widget.style , + keyboardType: widget.keyboardType, + decoration: InputDecoration( + errorStyle: widget.errorStyle, + errorMaxLines: 1, + isDense: widget.isDense, + suffixIcon: widget.suffixIcon ?? + (widget._isPassword + ? IconButton( + onPressed: () { + setState(() { + obscure = !obscure!; + }); + }, + icon: Icon(!obscure! + ? CupertinoIcons.eye_slash + : CupertinoIcons.eye)) + : null), + suffixIconConstraints: widget.boxConstraints, + prefixIcon: widget.prefixIcon, + prefixIconConstraints: widget.boxConstraints, + hintText: widget.hintText, + labelText: widget.label, + labelStyle: widget.labelStyle, + filled: widget.filled, + counter: widget.showCounter ? null : const SizedBox(), + hintStyle: widget.hintStyle, + enabledBorder: widget._inputBorder, + focusedBorder: widget._inputBorder, + border: widget._inputBorder), + )); + } +} \ No newline at end of file diff --git a/lib/presentation/widget/pagination/pagination_from_until.dart b/lib/presentation/widget/pagination/pagination_from_until.dart new file mode 100644 index 0000000..53f1203 --- /dev/null +++ b/lib/presentation/widget/pagination/pagination_from_until.dart @@ -0,0 +1,255 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:rasadyar_app/presentation/common/app_color.dart'; +import 'package:rasadyar_app/presentation/common/app_fonts.dart'; + +class PaginationFromUntil extends StatefulWidget { + const PaginationFromUntil({super.key}); + + @override + State createState() => _PaginationFromUntilState(); +} + +class _PaginationFromUntilState extends State { + int current = 1; + int total = 10; + + @override + Widget build(BuildContext context) { + return Container( + width: 164, + height: 47, + clipBehavior: Clip.antiAlias, + decoration: ShapeDecoration( + color: const Color(0xFFEAEFFF), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(50)), + ), + child: Row( + children: [ + FloatingActionButton.small( + onPressed: () { + if(current>1){ + setState(() { + current--; + }); + } + + }, + shape: CircleBorder(), + elevation: 0, + backgroundColor: Colors.white, + child: Icon(CupertinoIcons.arrow_left, color: AppColor.blueNormal), + ), + Expanded( + child: Text( + '$current از $total', + textAlign: TextAlign.center, + textDirection: TextDirection.rtl, + style: AppFonts.yekan16Regular.copyWith( + color: AppColor.blueNormal, + ), + ), + ), + FloatingActionButton.small( + + onPressed:() { + if (current < total) { + setState(() { + current++; + }); + } + }, + shape: CircleBorder(), + elevation: 0, + backgroundColor: AppColor.blueNormal, + child: Icon(CupertinoIcons.arrow_right, color: Colors.white), + ), + ], + ), + ); + } + + Stack buildStack() { + return Stack( + children: [ + Positioned( + left: 4, + top: 4, + child: Container( + width: 40, + height: 40, + child: Stack( + children: [ + Positioned( + left: 40, + top: 40, + child: Container( + transform: + Matrix4.identity() + ..translate(0.0, 0.0) + ..rotateZ(-3.14), + width: 40, + height: 40, + child: Stack( + children: [ + Positioned( + left: 0, + top: 0, + child: Container( + width: 40, + height: 40, + child: Stack( + children: [ + Positioned( + left: 0, + top: 0, + child: Container( + width: 40, + height: 40, + child: Stack( + children: [ + Positioned( + left: 0, + top: 0, + child: Container( + width: 40, + height: 40, + clipBehavior: Clip.antiAlias, + decoration: ShapeDecoration( + color: + Colors.white /* Secondary */, + shape: RoundedRectangleBorder( + side: BorderSide( + width: 1, + color: + Colors + .white /* Secondary */, + ), + borderRadius: + BorderRadius.circular(50), + ), + ), + child: Stack(), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + Positioned( + left: 8, + top: 8, + child: Container(width: 24, height: 24, child: Stack()), + ), + ], + ), + ), + ), + Positioned( + left: 120, + top: 3, + child: Container( + width: 40, + height: 40, + child: Stack( + children: [ + Positioned( + left: 40, + top: 40, + child: Container( + transform: + Matrix4.identity() + ..translate(0.0, 0.0) + ..rotateZ(-3.14), + width: 40, + height: 40, + child: Stack( + children: [ + Positioned( + left: 0, + top: 0, + child: Container( + width: 40, + height: 40, + child: Stack( + children: [ + Positioned( + left: 0, + top: 0, + child: Container( + width: 40, + height: 40, + child: Stack( + children: [ + Positioned( + left: 0, + top: 0, + child: Container( + width: 40, + height: 40, + clipBehavior: Clip.antiAlias, + decoration: ShapeDecoration( + color: const Color( + 0xFF2D5FFF, + ) /* Primary */, + shape: RoundedRectangleBorder( + side: BorderSide( + width: 1, + color: const Color( + 0xFF2D5FFF, + ) /* Primary */, + ), + borderRadius: + BorderRadius.circular(50), + ), + ), + child: Stack(), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + Positioned( + left: 8, + top: 8, + child: Container(width: 24, height: 24, child: Stack()), + ), + ], + ), + ), + ), + Positioned( + left: 63, + top: 9, + child: Text( + '1 از 17', + style: TextStyle( + color: const Color(0xFF2D5FFF) /* Primary */, + fontSize: 16, + fontFamily: 'IRANYekanFN', + fontWeight: FontWeight.w400, + height: 1.75, + ), + ), + ), + ], + ); + } +} diff --git a/lib/presentation/widget/pagination/show_more.dart b/lib/presentation/widget/pagination/show_more.dart new file mode 100644 index 0000000..36fb207 --- /dev/null +++ b/lib/presentation/widget/pagination/show_more.dart @@ -0,0 +1,78 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:rasadyar_app/presentation/common/app_color.dart'; +import 'package:rasadyar_app/presentation/common/app_fonts.dart'; + +class RShowMore extends StatefulWidget { + const RShowMore({super.key}); + + @override + State createState() => _RShowMoreState(); +} + +class _RShowMoreState extends State + with SingleTickerProviderStateMixin { + bool _toggled = false; + late final AnimationController _controller; + late final Animation _iconRotation; + + @override + void initState() { + super.initState(); + + _controller = AnimationController( + vsync: this, + duration: const Duration(milliseconds: 500), + ); + _iconRotation = Tween( + begin: 0, + end: 0.50, + ) // 90 degrees (quarter turn) + .animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOut)); + } + + void _toggle() { + setState(() => _toggled = !_toggled); + _toggled ? _controller.forward() : _controller.reverse(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: _toggle, + behavior: HitTestBehavior.opaque, + child: Row( + mainAxisSize: MainAxisSize.min, + spacing: 8, + children: [ + RotationTransition( + turns: _iconRotation, + child: const Icon(CupertinoIcons.chevron_down, size: 12,color:AppColor.blueNormal ,), + ), + + AnimatedSwitcher( + duration: const Duration(milliseconds: 500), + transitionBuilder: + (child, animation) => + FadeTransition(opacity: animation, child: child), + child: Text( + _toggled ? 'کمتر' : 'مشاهده بیشتر', + key: ValueKey(_toggled), + style: AppFonts.yekan10Regular.copyWith(color: AppColor.blueNormal), + ), + ), + SizedBox(height: 50,) + ], + + + + ), + ); + } +} diff --git a/lib/presentation/widget/tabs/new_tab.dart b/lib/presentation/widget/tabs/new_tab.dart new file mode 100644 index 0000000..c6e73c4 --- /dev/null +++ b/lib/presentation/widget/tabs/new_tab.dart @@ -0,0 +1,784 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// @docImport 'switch.dart'; +library; + +import 'dart:collection'; +import 'dart:math' as math; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/rendering.dart'; + +// Minimum padding from edges of the segmented control to edges of +// encompassing widget. +const EdgeInsetsGeometry _kHorizontalItemPadding = EdgeInsets.symmetric( + horizontal: 16.0, +); + +// Minimum height of the segmented control. +const double _kMinSegmentedControlHeight = 28.0; + +// The default color used for the text of the disabled segment. +const Color _kDisableTextColor = Color.fromARGB(115, 122, 122, 122); + +// The duration of the fade animation used to transition when a new widget +// is selected. +const Duration _kFadeDuration = Duration(milliseconds: 165); + +class NewCupertinoSegmentedControl extends StatefulWidget { + /// Creates an iOS-style segmented control bar. + /// + /// The [children] argument must be an ordered [Map] such as a + /// [LinkedHashMap]. Further, the length of the [children] list must be + /// greater than one. + /// + /// Each widget value in the map of [children] must have an associated key + /// that uniquely identifies this widget. This key is what will be returned + /// in the [onValueChanged] callback when a new value from the [children] map + /// is selected. + /// + /// The [groupValue] is the currently selected value for the segmented control. + /// If no [groupValue] is provided, or the [groupValue] is null, no widget will + /// appear as selected. The [groupValue] must be either null or one of the keys + /// in the [children] map. + NewCupertinoSegmentedControl({ + super.key, + required this.children, + required this.onValueChanged, + this.groupValue, + this.unselectedColor, + this.selectedColor, + this.borderColor, + this.pressedColor, + this.disabledColor, + this.disabledTextColor, + this.padding, + this.disabledChildren = const {}, + }) : assert(children.length >= 2), + assert( + groupValue == null || + children.keys.any((T child) => child == groupValue), + 'The groupValue must be either null or one of the keys in the children map.', + ); + + /// The identifying keys and corresponding widget values in the + /// segmented control. + /// + /// The map must have more than one entry. + /// This attribute must be an ordered [Map] such as a [LinkedHashMap]. + final Map children; + + /// The identifier of the widget that is currently selected. + /// + /// This must be one of the keys in the [Map] of [children]. + /// If this attribute is null, no widget will be initially selected. + final T? groupValue; + + /// The callback that is called when a new option is tapped. + /// + /// The segmented control passes the newly selected widget's associated key + /// to the callback but does not actually change state until the parent + /// widget rebuilds the segmented control with the new [groupValue]. + final ValueChanged onValueChanged; + + /// The color used to fill the backgrounds of unselected widgets and as the + /// text color of the selected widget. + /// + /// Defaults to [CupertinoTheme]'s `primaryContrastingColor` if null. + final Color? unselectedColor; + + /// The color used to fill the background of the selected widget and as the text + /// color of unselected widgets. + /// + /// Defaults to [CupertinoTheme]'s `primaryColor` if null. + final Color? selectedColor; + + /// The color used as the border around each widget. + /// + /// Defaults to [CupertinoTheme]'s `primaryColor` if null. + final Color? borderColor; + + /// The color used to fill the background of the widget the user is + /// temporarily interacting with through a long press or drag. + /// + /// Defaults to the selectedColor at 20% opacity if null. + final Color? pressedColor; + + /// The color used to fill the background of the segment when it is disabled. + /// + /// If null, this color will be 50% opacity of the [selectedColor] when + /// the segment is selected. If the segment is unselected, this color will be + /// set to [unselectedColor]. + final Color? disabledColor; + + /// The color used for the text of the segment when it is disabled. + final Color? disabledTextColor; + + /// The CupertinoSegmentedControl will be placed inside this padding. + /// + /// Defaults to EdgeInsets.symmetric(horizontal: 16.0) + final EdgeInsetsGeometry? padding; + + /// The set of identifying keys that correspond to the segments that should be disabled. + /// + /// All segments are enabled by default. + final Set disabledChildren; + + @override + State> createState() => + _SegmentedControlState(); +} + +class _SegmentedControlState + extends State> + with TickerProviderStateMixin> { + T? _pressedKey; + + final List _selectionControllers = + []; + final List _childTweens = []; + + late ColorTween _forwardBackgroundColorTween; + late ColorTween _reverseBackgroundColorTween; + late ColorTween _textColorTween; + + Color? _selectedColor; + Color? _unselectedColor; + Color? _borderColor; + Color? _pressedColor; + Color? _selectedDisabledColor; + Color? _unselectedDisabledColor; + Color? _disabledTextColor; + + AnimationController createAnimationController() { + return AnimationController(duration: _kFadeDuration, vsync: this) + ..addListener(() { + setState(() { + // State of background/text colors has changed + }); + }); + } + + bool _updateColors() { + assert(mounted, 'This should only be called after didUpdateDependencies'); + bool changed = false; + final Color disabledTextColor = + widget.disabledTextColor ?? _kDisableTextColor; + if (_disabledTextColor != disabledTextColor) { + changed = true; + _disabledTextColor = disabledTextColor; + } + final Color selectedColor = + widget.selectedColor ?? CupertinoTheme.of(context).primaryColor; + if (_selectedColor != selectedColor) { + changed = true; + _selectedColor = selectedColor; + } + final Color unselectedColor = + widget.unselectedColor ?? + CupertinoTheme.of(context).primaryContrastingColor; + if (_unselectedColor != unselectedColor) { + changed = true; + _unselectedColor = unselectedColor; + } + final Color selectedDisabledColor = + widget.disabledColor ?? selectedColor.withOpacity(0.5); + final Color unselectedDisabledColor = + widget.disabledColor ?? unselectedColor; + if (_selectedDisabledColor != selectedDisabledColor || + _unselectedDisabledColor != unselectedDisabledColor) { + changed = true; + _selectedDisabledColor = selectedDisabledColor; + _unselectedDisabledColor = unselectedDisabledColor; + } + final Color borderColor = + widget.borderColor ?? CupertinoTheme.of(context).primaryColor; + if (_borderColor != borderColor) { + changed = true; + _borderColor = borderColor; + } + final Color pressedColor = + widget.pressedColor ?? + CupertinoTheme.of(context).primaryColor.withOpacity(0.2); + if (_pressedColor != pressedColor) { + changed = true; + _pressedColor = pressedColor; + } + + _forwardBackgroundColorTween = ColorTween( + begin: _pressedColor, + end: _selectedColor, + ); + _reverseBackgroundColorTween = ColorTween( + begin: _unselectedColor, + end: _selectedColor, + ); + _textColorTween = ColorTween(begin: _selectedColor, end: _unselectedColor); + return changed; + } + + void _updateAnimationControllers() { + assert(mounted, 'This should only be called after didUpdateDependencies'); + for (final AnimationController controller in _selectionControllers) { + controller.dispose(); + } + _selectionControllers.clear(); + _childTweens.clear(); + + for (final T key in widget.children.keys) { + final AnimationController animationController = + createAnimationController(); + if (widget.groupValue == key) { + _childTweens.add(_reverseBackgroundColorTween); + animationController.value = 1.0; + } else { + _childTweens.add(_forwardBackgroundColorTween); + } + _selectionControllers.add(animationController); + } + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + + if (_updateColors()) { + _updateAnimationControllers(); + } + } + + @override + void didUpdateWidget(NewCupertinoSegmentedControl oldWidget) { + super.didUpdateWidget(oldWidget); + + if (_updateColors() || + oldWidget.children.length != widget.children.length) { + _updateAnimationControllers(); + } + + if (oldWidget.groupValue != widget.groupValue) { + int index = 0; + for (final T key in widget.children.keys) { + if (widget.groupValue == key) { + _childTweens[index] = _forwardBackgroundColorTween; + _selectionControllers[index].forward(); + } else { + _childTweens[index] = _reverseBackgroundColorTween; + _selectionControllers[index].reverse(); + } + index += 1; + } + } + } + + @override + void dispose() { + for (final AnimationController animationController + in _selectionControllers) { + animationController.dispose(); + } + super.dispose(); + } + + void _onTapDown(T currentKey) { + if (_pressedKey == null && currentKey != widget.groupValue) { + setState(() { + _pressedKey = currentKey; + }); + } + } + + void _onTapCancel() { + setState(() { + _pressedKey = null; + }); + } + + void _onTap(T currentKey) { + if (currentKey != _pressedKey) { + return; + } + if (!widget.disabledChildren.contains(currentKey)) { + if (currentKey != widget.groupValue) { + widget.onValueChanged(currentKey); + } + } + _pressedKey = null; + } + + Color? getTextColor(int index, T currentKey) { + if (widget.disabledChildren.contains(currentKey)) { + return _disabledTextColor; + } + if (_selectionControllers[index].isAnimating) { + return _textColorTween.evaluate(_selectionControllers[index]); + } + if (widget.groupValue == currentKey) { + return _unselectedColor; + } + return _selectedColor; + } + + Color? getBackgroundColor(int index, T currentKey) { + if (widget.disabledChildren.contains(currentKey)) { + return widget.groupValue == currentKey + ? _selectedDisabledColor + : _unselectedDisabledColor; + } + if (_selectionControllers[index].isAnimating) { + return _childTweens[index].evaluate(_selectionControllers[index]); + } + if (widget.groupValue == currentKey) { + return _selectedColor; + } + if (_pressedKey == currentKey) { + return _pressedColor; + } + return _unselectedColor; + } + + @override + Widget build(BuildContext context) { + final List gestureChildren = []; + final List backgroundColors = []; + int index = 0; + int? selectedIndex; + int? pressedIndex; + for (final T currentKey in widget.children.keys) { + selectedIndex = (widget.groupValue == currentKey) ? index : selectedIndex; + pressedIndex = (_pressedKey == currentKey) ? index : pressedIndex; + + final TextStyle textStyle = DefaultTextStyle.of( + context, + ).style.copyWith(color: getTextColor(index, currentKey)); + final IconThemeData iconTheme = IconThemeData( + color: getTextColor(index, currentKey), + ); + + Widget child = Center(child: widget.children[currentKey]); + + child = MouseRegion( + cursor: kIsWeb ? SystemMouseCursors.click : MouseCursor.defer, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTapDown: + widget.disabledChildren.contains(currentKey) + ? null + : (TapDownDetails event) { + _onTapDown(currentKey); + }, + onTapCancel: + widget.disabledChildren.contains(currentKey) + ? null + : _onTapCancel, + onTap: () { + _onTap(currentKey); + }, + child: IconTheme( + data: iconTheme, + child: DefaultTextStyle( + style: textStyle, + child: Semantics( + button: true, + inMutuallyExclusiveGroup: true, + selected: widget.groupValue == currentKey, + child: child, + ), + ), + ), + ), + ); + + backgroundColors.add(getBackgroundColor(index, currentKey)!); + gestureChildren.add(child); + index += 1; + } + + final Widget box = _SegmentedControlRenderWidget( + selectedIndex: selectedIndex, + pressedIndex: pressedIndex, + backgroundColors: backgroundColors, + borderColor: _borderColor!, + children: gestureChildren, + ); + + return Padding( + padding: widget.padding ?? _kHorizontalItemPadding, + child: UnconstrainedBox(constrainedAxis: Axis.horizontal, child: box), + ); + } +} + +class _SegmentedControlRenderWidget extends MultiChildRenderObjectWidget { + const _SegmentedControlRenderWidget({ + super.key, + super.children, + required this.selectedIndex, + required this.pressedIndex, + required this.backgroundColors, + required this.borderColor, + }); + + final int? selectedIndex; + final int? pressedIndex; + final List backgroundColors; + final Color borderColor; + + @override + RenderObject createRenderObject(BuildContext context) { + return _RenderSegmentedControl( + textDirection: Directionality.of(context), + selectedIndex: selectedIndex, + pressedIndex: pressedIndex, + backgroundColors: backgroundColors, + borderColor: borderColor, + ); + } + + @override + void updateRenderObject( + BuildContext context, + _RenderSegmentedControl renderObject, + ) { + renderObject + ..textDirection = Directionality.of(context) + ..selectedIndex = selectedIndex + ..pressedIndex = pressedIndex + ..backgroundColors = backgroundColors + ..borderColor = borderColor; + } +} + +class _SegmentedControlContainerBoxParentData + extends ContainerBoxParentData { + RRect? surroundingRect; +} + +typedef _NextChild = RenderBox? Function(RenderBox child); + +class _RenderSegmentedControl extends RenderBox + with + ContainerRenderObjectMixin< + RenderBox, + ContainerBoxParentData + >, + RenderBoxContainerDefaultsMixin< + RenderBox, + ContainerBoxParentData + > { + _RenderSegmentedControl({ + required int? selectedIndex, + required int? pressedIndex, + required TextDirection textDirection, + required List backgroundColors, + required Color borderColor, + }) : _textDirection = textDirection, + _selectedIndex = selectedIndex, + _pressedIndex = pressedIndex, + _backgroundColors = backgroundColors, + _borderColor = borderColor; + + int? get selectedIndex => _selectedIndex; + int? _selectedIndex; + + set selectedIndex(int? value) { + if (_selectedIndex == value) { + return; + } + _selectedIndex = value; + markNeedsPaint(); + } + + int? get pressedIndex => _pressedIndex; + int? _pressedIndex; + + set pressedIndex(int? value) { + if (_pressedIndex == value) { + return; + } + _pressedIndex = value; + markNeedsPaint(); + } + + TextDirection get textDirection => _textDirection; + TextDirection _textDirection; + + set textDirection(TextDirection value) { + if (_textDirection == value) { + return; + } + _textDirection = value; + markNeedsLayout(); + } + + List get backgroundColors => _backgroundColors; + List _backgroundColors; + + set backgroundColors(List value) { + if (_backgroundColors == value) { + return; + } + _backgroundColors = value; + markNeedsPaint(); + } + + Color get borderColor => _borderColor; + Color _borderColor; + + set borderColor(Color value) { + if (_borderColor == value) { + return; + } + _borderColor = value; + markNeedsPaint(); + } + + @override + double computeMinIntrinsicWidth(double height) { + RenderBox? child = firstChild; + double minWidth = 0.0; + while (child != null) { + final _SegmentedControlContainerBoxParentData childParentData = + child.parentData! as _SegmentedControlContainerBoxParentData; + final double childWidth = child.getMinIntrinsicWidth(height); + minWidth = math.max(minWidth, childWidth); + child = childParentData.nextSibling; + } + return minWidth * childCount; + } + + @override + double computeMaxIntrinsicWidth(double height) { + RenderBox? child = firstChild; + double maxWidth = 0.0; + while (child != null) { + final _SegmentedControlContainerBoxParentData childParentData = + child.parentData! as _SegmentedControlContainerBoxParentData; + final double childWidth = child.getMaxIntrinsicWidth(height); + maxWidth = math.max(maxWidth, childWidth); + child = childParentData.nextSibling; + } + return maxWidth * childCount; + } + + @override + double computeMinIntrinsicHeight(double width) { + RenderBox? child = firstChild; + double minHeight = 0.0; + while (child != null) { + final _SegmentedControlContainerBoxParentData childParentData = + child.parentData! as _SegmentedControlContainerBoxParentData; + final double childHeight = child.getMinIntrinsicHeight(width); + minHeight = math.max(minHeight, childHeight); + child = childParentData.nextSibling; + } + return minHeight; + } + + @override + double computeMaxIntrinsicHeight(double width) { + RenderBox? child = firstChild; + double maxHeight = 0.0; + while (child != null) { + final _SegmentedControlContainerBoxParentData childParentData = + child.parentData! as _SegmentedControlContainerBoxParentData; + final double childHeight = child.getMaxIntrinsicHeight(width); + maxHeight = math.max(maxHeight, childHeight); + child = childParentData.nextSibling; + } + return maxHeight; + } + + @override + double? computeDistanceToActualBaseline(TextBaseline baseline) { + return defaultComputeDistanceToHighestActualBaseline(baseline); + } + + @override + void setupParentData(RenderBox child) { + if (child.parentData is! _SegmentedControlContainerBoxParentData) { + child.parentData = _SegmentedControlContainerBoxParentData(); + } + } + + void _layoutRects( + _NextChild nextChild, + RenderBox? leftChild, + RenderBox? rightChild, + ) { + RenderBox? child = leftChild; + double start = 0.0; + while (child != null) { + final _SegmentedControlContainerBoxParentData childParentData = + child.parentData! as _SegmentedControlContainerBoxParentData; + final Offset childOffset = Offset(start, 0.0); + childParentData.offset = childOffset; + final Rect childRect = Rect.fromLTWH( + start, + 0.0, + child.size.width, + child.size.height, + ); + final RRect rChildRect; + if (child == leftChild) { + rChildRect = RRect.fromRectAndCorners( + childRect, + topLeft: const Radius.circular(10.0), + bottomLeft: const Radius.circular(10.0), + ); + } else if (child == rightChild) { + rChildRect = RRect.fromRectAndCorners( + childRect, + topRight: const Radius.circular(10.0), + bottomRight: const Radius.circular(10.0), + ); + } else { + rChildRect = RRect.fromRectAndCorners(childRect); + } + childParentData.surroundingRect = rChildRect; + start += child.size.width; + child = nextChild(child); + } + } + + Size _calculateChildSize(BoxConstraints constraints) { + double maxHeight = _kMinSegmentedControlHeight; + double childWidth = constraints.minWidth / childCount; + RenderBox? child = firstChild; + while (child != null) { + childWidth = math.max( + childWidth, + child.getMaxIntrinsicWidth(double.infinity), + ); + child = childAfter(child); + } + childWidth = math.min(childWidth, constraints.maxWidth / childCount); + child = firstChild; + while (child != null) { + final double boxHeight = child.getMaxIntrinsicHeight(childWidth); + maxHeight = math.max(maxHeight, boxHeight); + child = childAfter(child); + } + return Size(childWidth, maxHeight); + } + + Size _computeOverallSizeFromChildSize(Size childSize) { + return constraints.constrain( + Size(childSize.width * childCount, childSize.height), + ); + } + + @override + double? computeDryBaseline( + covariant BoxConstraints constraints, + TextBaseline baseline, + ) { + final Size childSize = _calculateChildSize(constraints); + final BoxConstraints childConstraints = BoxConstraints.tight(childSize); + + BaselineOffset baselineOffset = BaselineOffset.noBaseline; + for ( + RenderBox? child = firstChild; + child != null; + child = childAfter(child) + ) { + baselineOffset = baselineOffset.minOf( + BaselineOffset(child.getDryBaseline(childConstraints, baseline)), + ); + } + return baselineOffset.offset; + } + + @override + Size computeDryLayout(BoxConstraints constraints) { + final Size childSize = _calculateChildSize(constraints); + return _computeOverallSizeFromChildSize(childSize); + } + + @override + void performLayout() { + final BoxConstraints constraints = this.constraints; + final Size childSize = _calculateChildSize(constraints); + + final BoxConstraints childConstraints = BoxConstraints.tightFor( + width: childSize.width, + height: childSize.height, + ); + + RenderBox? child = firstChild; + while (child != null) { + child.layout(childConstraints, parentUsesSize: true); + child = childAfter(child); + } + + switch (textDirection) { + case TextDirection.rtl: + _layoutRects(childBefore, lastChild, firstChild); + case TextDirection.ltr: + _layoutRects(childAfter, firstChild, lastChild); + } + + size = _computeOverallSizeFromChildSize(childSize); + } + + @override + void paint(PaintingContext context, Offset offset) { + RenderBox? child = firstChild; + int index = 0; + while (child != null) { + _paintChild(context, offset, child, index); + child = childAfter(child); + index += 1; + } + } + + void _paintChild( + PaintingContext context, + Offset offset, + RenderBox child, + int childIndex, + ) { + final _SegmentedControlContainerBoxParentData childParentData = + child.parentData! as _SegmentedControlContainerBoxParentData; + + context.canvas.drawRRect( + childParentData.surroundingRect!.shift(offset), + Paint() + ..color = backgroundColors[childIndex] + ..style = PaintingStyle.fill, + ); + context.canvas.drawRRect( + childParentData.surroundingRect!.shift(offset), + Paint() + ..color = borderColor + ..strokeWidth = 1.0 + ..style = PaintingStyle.stroke, + ); + + context.paintChild(child, childParentData.offset + offset); + } + + @override + bool hitTestChildren(BoxHitTestResult result, {required Offset position}) { + RenderBox? child = lastChild; + while (child != null) { + final _SegmentedControlContainerBoxParentData childParentData = + child.parentData! as _SegmentedControlContainerBoxParentData; + if (childParentData.surroundingRect!.contains(position)) { + return result.addWithPaintOffset( + offset: childParentData.offset, + position: position, + hitTest: (BoxHitTestResult result, Offset localOffset) { + assert(localOffset == position - childParentData.offset); + return child!.hitTest(result, position: localOffset); + }, + ); + } + child = childParentData.previousSibling; + } + return false; + } +} diff --git a/lib/presentation/widget/tabs/tab.dart b/lib/presentation/widget/tabs/tab.dart new file mode 100644 index 0000000..ac2f735 --- /dev/null +++ b/lib/presentation/widget/tabs/tab.dart @@ -0,0 +1,115 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:rasadyar_app/presentation/common/app_color.dart'; +import 'package:rasadyar_app/presentation/common/app_fonts.dart'; + +import 'new_tab.dart'; + +class CupertinoSegmentedControlDemo extends StatefulWidget { + const CupertinoSegmentedControlDemo({super.key}); + + @override + State createState() => + _CupertinoSegmentedControlDemoState(); +} + +class _CupertinoSegmentedControlDemoState + extends State { + int _selectedSegment = 0; + + // The data for the segments + final Map _segments = const { + 0: Text('Segment 1'), + 1: Text('Segment 2'), + 2: Text('Segment 3'), + }; + + @override + Widget build(BuildContext context) { + return SafeArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + CupertinoSlidingSegmentedControl( + children: _segments, + groupValue: _selectedSegment, + + onValueChanged: (int? value) { + setState(() { + _selectedSegment = value!; + }); + }, + ), + const SizedBox(height: 20), + Text( + 'Selected Segment: ${_selectedSegment + 1}', + style: const TextStyle(fontSize: 24), + ), + ], + ), + ); + } +} + +class CupertinoSegmentedControlDemo2 extends StatefulWidget { + const CupertinoSegmentedControlDemo2({super.key}); + + @override + State createState() => + _CupertinoSegmentedControlDemoState2(); +} + +class _CupertinoSegmentedControlDemoState2 + extends State { + int _selectedSegment = 0; + + // The data for the segments + final Map _segments = { + 0:Container( + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50) + ), + child: Text('لاشه', style: AppFonts.yekan13Regular), + ), + 1: Container( + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50) + ), + child: Text('زنده', style: AppFonts.yekan13Regular), + ), + }; + + @override + Widget build(BuildContext context) { + return SafeArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + NewCupertinoSegmentedControl( + padding: EdgeInsetsDirectional.symmetric( + horizontal: 20, + vertical: 10, + ), + children: _segments, + groupValue: _selectedSegment, + selectedColor: AppColor.blueNormal, + unselectedColor: Colors.white, + borderColor: Colors.grey.shade300, + onValueChanged: (int value) { + setState(() { + _selectedSegment = value; + }); + }, + ), + const SizedBox(height: 20), + Text( + 'Selected Segment: ${_selectedSegment + 1}', + style: const TextStyle(fontSize: 24), + ), + ], + ), + ); + } +} diff --git a/lib/presentation/widget/vec_widget.dart b/lib/presentation/widget/vec_widget.dart new file mode 100644 index 0000000..8f76b40 --- /dev/null +++ b/lib/presentation/widget/vec_widget.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:vector_graphics/vector_graphics.dart'; + +SvgPicture vecWidget( + String assets, { + double? width, + double? height, + BoxFit? fit, + Color? color, +}) { + return SvgPicture( + AssetBytesLoader(assets), + width: width, + height: height, + fit: fit ?? BoxFit.contain, + colorFilter: + color != null ? ColorFilter.mode(color, BlendMode.srcIn) : null, + ); +} +Widget vecWidget2( + String assets, { + double? width, + double? height, + BoxFit? fit, + Color? color, + }) { + final resolvedColor = WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.pressed)) { + return Colors.white; + } + return color; + }).resolve({}); // You can pass actual states if needed + + return IconTheme( + data: IconThemeData(color: resolvedColor), + child: SvgPicture( + AssetBytesLoader(assets), + width: width, + height: height, + fit: fit ?? BoxFit.contain, + colorFilter: resolvedColor != null + ? ColorFilter.mode(resolvedColor, BlendMode.srcIn) + : null, + ), + ); +} diff --git a/pubspec.yaml b/pubspec.yaml index bb74dfd..52bb4ec 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -58,34 +58,14 @@ dev_dependencies: flutter: uses-material-design: true - # To add assets to your application, add an assets section, like this: + assets: - assets/icons/ - assets/images/ - assets/logos/ + - assets/vec/ - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/to/resolution-aware-images - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/to/asset-from-package - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/to/font-from-package + fonts: + - family: yekan + fonts: + - asset: fonts/iranyekanregularfanum.ttf diff --git a/vecGeneratoe.sh b/vecGeneratoe.sh new file mode 100644 index 0000000..4f92558 --- /dev/null +++ b/vecGeneratoe.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# Directory to read files from +sourcePath="assets/icons" +targetPath="assets/vec" + + +if [ ! -e "$targetPath" ]; then + echo "📁 Directory does not exist. Creating: $targetPath" + mkdir -p "$targetPath" +fi + + +# Loop and delete old vec file +for file in "$targetPath"/* +do + if [ -f "$file" ]; then + + echo "Delete old ===> $file" + rm "$file" + fi +done +# Loop through all files in the directory +for file in "$sourcePath"/* +do + if [ -f "$file" ]; then + echo "Generate Vec file ===> $file" + fileName=$(basename -- "$file") + echo "Generate Vec file ===> $fileName" + dart run vector_graphics_compiler -i "$file" -o "$targetPath/$fileName.vec" + git add . + fi +done \ No newline at end of file