feat : button , outlined button

fab button , fab outlined button ,
input , pagination widget's
This commit is contained in:
2025-04-06 15:39:00 +03:30
parent 822e22d541
commit 50cc84461e
34 changed files with 3150 additions and 27 deletions

8
assets/icons/add.svg Normal file
View File

@@ -0,0 +1,8 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="vuesax/outline/add">
<g id="add">
<path id="Vector" d="M30 21.25H10C9.31667 21.25 8.75 20.6833 8.75 20C8.75 19.3167 9.31667 18.75 10 18.75H30C30.6833 18.75 31.25 19.3167 31.25 20C31.25 20.6833 30.6833 21.25 30 21.25Z" fill="white"/>
<path id="Vector_2" d="M20 31.25C19.3167 31.25 18.75 30.6833 18.75 30V10C18.75 9.31667 19.3167 8.75 20 8.75C20.6833 8.75 21.25 9.31667 21.25 10V30C21.25 30.6833 20.6833 31.25 20 31.25Z" fill="white"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 554 B

View File

@@ -0,0 +1,7 @@
<svg width="34" height="34" viewBox="0 0 34 34" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Arrow - Right">
<g id="Arrow - Right 2">
<path id="Stroke 1" d="M21.8999 26.8L12.0999 17L21.8999 7.19998" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 307 B

View File

@@ -0,0 +1,7 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Arrow - Right">
<g id="Arrow - Right 2">
<path id="Stroke 1" d="M8.5 5L15.5 12L8.5 19" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 288 B

10
assets/icons/download.svg Normal file
View File

@@ -0,0 +1,10 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="vuesax/outline/document-download">
<g id="document-download">
<path id="Vector" d="M9 17.75C8.9 17.75 8.81 17.73 8.71 17.69C8.43 17.58 8.25 17.3 8.25 17V11C8.25 10.59 8.59 10.25 9 10.25C9.41 10.25 9.75 10.59 9.75 11V15.19L10.47 14.47C10.76 14.18 11.24 14.18 11.53 14.47C11.82 14.76 11.82 15.24 11.53 15.53L9.53 17.53C9.39 17.67 9.19 17.75 9 17.75Z" fill="white"/>
<path id="Vector_2" d="M8.99994 17.75C8.80994 17.75 8.61994 17.68 8.46994 17.53L6.46994 15.53C6.17994 15.24 6.17994 14.76 6.46994 14.47C6.75994 14.18 7.23994 14.18 7.52994 14.47L9.52994 16.47C9.81994 16.76 9.81994 17.24 9.52994 17.53C9.37994 17.68 9.18994 17.75 8.99994 17.75Z" fill="white"/>
<path id="Vector_3" d="M15 22.75H9C3.57 22.75 1.25 20.43 1.25 15V9C1.25 3.57 3.57 1.25 9 1.25H14C14.41 1.25 14.75 1.59 14.75 2C14.75 2.41 14.41 2.75 14 2.75H9C4.39 2.75 2.75 4.39 2.75 9V15C2.75 19.61 4.39 21.25 9 21.25H15C19.61 21.25 21.25 19.61 21.25 15V10C21.25 9.59 21.59 9.25 22 9.25C22.41 9.25 22.75 9.59 22.75 10V15C22.75 20.43 20.43 22.75 15 22.75Z" fill="white"/>
<path id="Vector_4" d="M22 10.75H18C14.58 10.75 13.25 9.41999 13.25 5.99999V1.99999C13.25 1.69999 13.43 1.41999 13.71 1.30999C13.99 1.18999 14.31 1.25999 14.53 1.46999L22.53 9.46999C22.74 9.67999 22.81 10.01 22.69 10.29C22.57 10.57 22.3 10.75 22 10.75ZM14.75 3.80999V5.99999C14.75 8.57999 15.42 9.24999 18 9.24999H20.19L14.75 3.80999Z" fill="white"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

9
assets/icons/edit.svg Normal file
View File

@@ -0,0 +1,9 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="vuesax/outline/edit-2">
<g id="edit-2">
<path id="Vector" d="M5.53999 19.52C4.92999 19.52 4.35999 19.31 3.94999 18.92C3.42999 18.43 3.17999 17.69 3.26999 16.89L3.63999 13.65C3.70999 13.04 4.07999 12.23 4.50999 11.79L12.72 3.09999C14.77 0.929988 16.91 0.869988 19.08 2.91999C21.25 4.96999 21.31 7.10999 19.26 9.27999L11.05 17.97C10.63 18.42 9.84999 18.84 9.23999 18.94L6.01999 19.49C5.84999 19.5 5.69999 19.52 5.53999 19.52ZM15.93 2.90999C15.16 2.90999 14.49 3.38999 13.81 4.10999L5.59999 12.81C5.39999 13.02 5.16999 13.52 5.12999 13.81L4.75999 17.05C4.71999 17.38 4.79999 17.65 4.97999 17.82C5.15999 17.99 5.42999 18.05 5.75999 18L8.97999 17.45C9.26999 17.4 9.74999 17.14 9.94999 16.93L18.16 8.23999C19.4 6.91999 19.85 5.69999 18.04 3.99999C17.24 3.22999 16.55 2.90999 15.93 2.90999Z" fill="white"/>
<path id="Vector_2" d="M17.3404 10.95C17.3204 10.95 17.2904 10.95 17.2704 10.95C14.1504 10.64 11.6404 8.26997 11.1604 5.16997C11.1004 4.75997 11.3804 4.37997 11.7904 4.30997C12.2004 4.24997 12.5804 4.52997 12.6504 4.93997C13.0304 7.35997 14.9904 9.21997 17.4304 9.45997C17.8404 9.49997 18.1404 9.86997 18.1004 10.28C18.0504 10.66 17.7204 10.95 17.3404 10.95Z" fill="white"/>
<path id="Vector_3" d="M21 22.75H3C2.59 22.75 2.25 22.41 2.25 22C2.25 21.59 2.59 21.25 3 21.25H21C21.41 21.25 21.75 21.59 21.75 22C21.75 22.41 21.41 22.75 21 22.75Z" fill="white"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

8
assets/icons/filter.svg Normal file
View File

@@ -0,0 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="vuesax/outline/filter">
<g id="filter">
<path id="Vector" d="M10.9399 22.65C10.4599 22.65 9.9899 22.53 9.5499 22.29C8.6699 21.8 8.1399 20.91 8.1399 19.91V14.61C8.1399 14.11 7.8099 13.36 7.4999 12.98L3.7599 9.02001C3.1299 8.39001 2.6499 7.31001 2.6499 6.50001V4.20001C2.6499 2.60001 3.8599 1.35001 5.3999 1.35001H18.5999C20.1199 1.35001 21.3499 2.58001 21.3499 4.10001V6.30001C21.3499 7.35001 20.7199 8.54001 20.1299 9.13001L15.7999 12.96C15.3799 13.31 15.0499 14.08 15.0499 14.7V19C15.0499 19.89 14.4899 20.92 13.7899 21.34L12.4099 22.23C11.9599 22.51 11.4499 22.65 10.9399 22.65ZM5.3999 2.85001C4.6999 2.85001 4.1499 3.44001 4.1499 4.20001V6.50001C4.1499 6.87001 4.4499 7.59001 4.8299 7.97001L8.6399 11.98C9.1499 12.61 9.6499 13.66 9.6499 14.6V19.9C9.6499 20.55 10.0999 20.87 10.2899 20.97C10.7099 21.2 11.2199 21.2 11.6099 20.96L12.9999 20.07C13.2799 19.9 13.5599 19.36 13.5599 19V14.7C13.5599 13.63 14.0799 12.45 14.8299 11.82L19.1099 8.03001C19.4499 7.69001 19.8599 6.88001 19.8599 6.29001V4.10001C19.8599 3.41001 19.2999 2.85001 18.6099 2.85001H5.3999Z" fill="white"/>
<path id="Vector_2" d="M6.00017 10.75C5.86017 10.75 5.73017 10.71 5.60017 10.64C5.25017 10.42 5.14017 9.94999 5.36017 9.59999L10.2902 1.69999C10.5102 1.34999 10.9702 1.23999 11.3202 1.45999C11.6702 1.67999 11.7802 2.13999 11.5602 2.48999L6.63017 10.39C6.49017 10.62 6.25017 10.75 6.00017 10.75Z" fill="white"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

14
assets/icons/scan.svg Normal file
View File

@@ -0,0 +1,14 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="vuesax/outline/scan-barcode">
<g id="scan-barcode">
<path id="Vector" d="M2 9.75C1.59 9.75 1.25 9.41 1.25 9V6.5C1.25 3.6 3.61 1.25 6.5 1.25H9C9.41 1.25 9.75 1.59 9.75 2C9.75 2.41 9.41 2.75 9 2.75H6.5C4.43 2.75 2.75 4.43 2.75 6.5V9C2.75 9.41 2.41 9.75 2 9.75Z" fill="white"/>
<path id="Vector_2" d="M22 9.75C21.59 9.75 21.25 9.41 21.25 9V6.5C21.25 4.43 19.57 2.75 17.5 2.75H15C14.59 2.75 14.25 2.41 14.25 2C14.25 1.59 14.59 1.25 15 1.25H17.5C20.39 1.25 22.75 3.6 22.75 6.5V9C22.75 9.41 22.41 9.75 22 9.75Z" fill="white"/>
<path id="Vector_3" d="M17.5 22.75H16C15.59 22.75 15.25 22.41 15.25 22C15.25 21.59 15.59 21.25 16 21.25H17.5C19.57 21.25 21.25 19.57 21.25 17.5V16C21.25 15.59 21.59 15.25 22 15.25C22.41 15.25 22.75 15.59 22.75 16V17.5C22.75 20.4 20.39 22.75 17.5 22.75Z" fill="white"/>
<path id="Vector_4" d="M9 22.75H6.5C3.61 22.75 1.25 20.4 1.25 17.5V15C1.25 14.59 1.59 14.25 2 14.25C2.41 14.25 2.75 14.59 2.75 15V17.5C2.75 19.57 4.43 21.25 6.5 21.25H9C9.41 21.25 9.75 21.59 9.75 22C9.75 22.41 9.41 22.75 9 22.75Z" fill="white"/>
<path id="Vector_5" d="M9 11.25H7C5.59 11.25 4.75 10.41 4.75 9V7C4.75 5.59 5.59 4.75 7 4.75H9C10.41 4.75 11.25 5.59 11.25 7V9C11.25 10.41 10.41 11.25 9 11.25ZM7 6.25C6.41 6.25 6.25 6.41 6.25 7V9C6.25 9.59 6.41 9.75 7 9.75H9C9.59 9.75 9.75 9.59 9.75 9V7C9.75 6.41 9.59 6.25 9 6.25H7Z" fill="white"/>
<path id="Vector_6" d="M17 11.25H15C13.59 11.25 12.75 10.41 12.75 9V7C12.75 5.59 13.59 4.75 15 4.75H17C18.41 4.75 19.25 5.59 19.25 7V9C19.25 10.41 18.41 11.25 17 11.25ZM15 6.25C14.41 6.25 14.25 6.41 14.25 7V9C14.25 9.59 14.41 9.75 15 9.75H17C17.59 9.75 17.75 9.59 17.75 9V7C17.75 6.41 17.59 6.25 17 6.25H15Z" fill="white"/>
<path id="Vector_7" d="M9 19.25H7C5.59 19.25 4.75 18.41 4.75 17V15C4.75 13.59 5.59 12.75 7 12.75H9C10.41 12.75 11.25 13.59 11.25 15V17C11.25 18.41 10.41 19.25 9 19.25ZM7 14.25C6.41 14.25 6.25 14.41 6.25 15V17C6.25 17.59 6.41 17.75 7 17.75H9C9.59 17.75 9.75 17.59 9.75 17V15C9.75 14.41 9.59 14.25 9 14.25H7Z" fill="white"/>
<path id="Vector_8" d="M17 19.25H15C13.59 19.25 12.75 18.41 12.75 17V15C12.75 13.59 13.59 12.75 15 12.75H17C18.41 12.75 19.25 13.59 19.25 15V17C19.25 18.41 18.41 19.25 17 19.25ZM15 14.25C14.41 14.25 14.25 14.41 14.25 15V17C14.25 17.59 14.41 17.75 15 17.75H17C17.59 17.75 17.75 17.59 17.75 17V15C17.75 14.41 17.59 14.25 17 14.25H15Z" fill="white"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

11
assets/icons/trash.svg Normal file
View File

@@ -0,0 +1,11 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="vuesax/outline/trash">
<g id="trash">
<path id="Vector" d="M20.9997 6.72998C20.9797 6.72998 20.9497 6.72998 20.9197 6.72998C15.6297 6.19998 10.3497 5.99998 5.11967 6.52998L3.07967 6.72998C2.65967 6.76998 2.28967 6.46998 2.24967 6.04998C2.20967 5.62998 2.50967 5.26998 2.91967 5.22998L4.95967 5.02998C10.2797 4.48998 15.6697 4.69998 21.0697 5.22998C21.4797 5.26998 21.7797 5.63998 21.7397 6.04998C21.7097 6.43998 21.3797 6.72998 20.9997 6.72998Z" fill="white"/>
<path id="Vector_2" d="M8.49977 5.72C8.45977 5.72 8.41977 5.72 8.36977 5.71C7.96977 5.64 7.68977 5.25 7.75977 4.85L7.97977 3.54C8.13977 2.58 8.35977 1.25 10.6898 1.25H13.3098C15.6498 1.25 15.8698 2.63 16.0198 3.55L16.2398 4.85C16.3098 5.26 16.0298 5.65 15.6298 5.71C15.2198 5.78 14.8298 5.5 14.7698 5.1L14.5498 3.8C14.4098 2.93 14.3798 2.76 13.3198 2.76H10.6998C9.63977 2.76 9.61977 2.9 9.46977 3.79L9.23977 5.09C9.17977 5.46 8.85977 5.72 8.49977 5.72Z" fill="white"/>
<path id="Vector_3" d="M15.2104 22.75H8.79039C5.30039 22.75 5.16039 20.82 5.05039 19.26L4.40039 9.19001C4.37039 8.78001 4.69039 8.42001 5.10039 8.39001C5.52039 8.37001 5.87039 8.68001 5.90039 9.09001L6.55039 19.16C6.66039 20.68 6.70039 21.25 8.79039 21.25H15.2104C17.3104 21.25 17.3504 20.68 17.4504 19.16L18.1004 9.09001C18.1304 8.68001 18.4904 8.37001 18.9004 8.39001C19.3104 8.42001 19.6304 8.77001 19.6004 9.19001L18.9504 19.26C18.8404 20.82 18.7004 22.75 15.2104 22.75Z" fill="white"/>
<path id="Vector_4" d="M13.6601 17.25H10.3301C9.92008 17.25 9.58008 16.91 9.58008 16.5C9.58008 16.09 9.92008 15.75 10.3301 15.75H13.6601C14.0701 15.75 14.4101 16.09 14.4101 16.5C14.4101 16.91 14.0701 17.25 13.6601 17.25Z" fill="white"/>
<path id="Vector_5" d="M14.5 13.25H9.5C9.09 13.25 8.75 12.91 8.75 12.5C8.75 12.09 9.09 11.75 9.5 11.75H14.5C14.91 11.75 15.25 12.09 15.25 12.5C15.25 12.91 14.91 13.25 14.5 13.25Z" fill="white"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
assets/vec/add.svg.vec Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
assets/vec/download.svg.vec Normal file

Binary file not shown.

BIN
assets/vec/edit.svg.vec Normal file

Binary file not shown.

BIN
assets/vec/filter.svg.vec Normal file

Binary file not shown.

BIN
assets/vec/scan.svg.vec Normal file

Binary file not shown.

BIN
assets/vec/trash.svg.vec Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -1,7 +1,20 @@
import 'package:flutter/material.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 '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() { void main() {
runApp(const MyApp()); runApp(MyApp());
} }
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {
@@ -14,7 +27,259 @@ class MyApp extends StatelessWidget {
theme: ThemeData( theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
), ),
home: Home(),
); );
} }
} }
class Home extends StatefulWidget {
const Home({super.key});
@override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
List<bool> _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),
],
),
);
}
}

View File

@@ -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,
);
}

View File

@@ -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';
}

View File

@@ -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);
}
}

View File

@@ -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<RElevated> createState() => _RElevatedState();
}
class _RElevatedState extends State<RElevated> {
@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),
);
}
}

View File

@@ -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<RFab> 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<RFab> {
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: widget.onPressed,
style: ButtonStyle(
side: WidgetStateProperty.all(BorderSide.none),
backgroundColor: WidgetStateProperty.resolveWith<Color?>((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<Color?>((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,
);
}
}

View File

@@ -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<RFabOutlined> 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<RFabOutlined> {
bool isOnPressed =false;
@override
Widget build(BuildContext context) {
return OutlinedButton(
onPressed:widget.onPressed ,
style: ButtonStyle(
side: WidgetStateProperty.resolveWith<BorderSide?>((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<Color?>((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<Color?>((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
);
}
}

View File

@@ -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<ROutlinedElevated> createState() => _ROutlinedElevatedState();
}
class _ROutlinedElevatedState extends State<ROutlinedElevated> {
@override
Widget build(BuildContext context) {
return OutlinedButton(
onPressed: widget.onPressed,
style: ButtonStyle(
side: WidgetStateProperty.resolveWith<BorderSide?>((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<Color?>((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<Color?>((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),
);
}
}

View File

@@ -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<RTextButton> createState() => _RTextButtonState();
}
class _RTextButtonState extends State<RTextButton> {
@override
Widget build(BuildContext context) {
return TextButton(
style: ButtonStyle(
side: WidgetStatePropertyAll(BorderSide.none),
backgroundColor: WidgetStateProperty.resolveWith<Color?>((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<Color?>((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),
);
}
}

View File

@@ -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<RTextField> createState() => _RTextFieldState();
}
class _RTextFieldState extends State<RTextField> {
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),
));
}
}

View File

@@ -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<PaginationFromUntil> createState() => _PaginationFromUntilState();
}
class _PaginationFromUntilState extends State<PaginationFromUntil> {
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,
),
),
),
],
);
}
}

View File

@@ -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<RShowMore> createState() => _RShowMoreState();
}
class _RShowMoreState extends State<RShowMore>
with SingleTickerProviderStateMixin {
bool _toggled = false;
late final AnimationController _controller;
late final Animation<double> _iconRotation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 500),
);
_iconRotation = Tween<double>(
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,)
],
),
);
}
}

View File

@@ -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<T extends Object> 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 <Never>{},
}) : 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<T, Widget> 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<T> 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<T> disabledChildren;
@override
State<NewCupertinoSegmentedControl<T>> createState() =>
_SegmentedControlState<T>();
}
class _SegmentedControlState<T extends Object>
extends State<NewCupertinoSegmentedControl<T>>
with TickerProviderStateMixin<NewCupertinoSegmentedControl<T>> {
T? _pressedKey;
final List<AnimationController> _selectionControllers =
<AnimationController>[];
final List<ColorTween> _childTweens = <ColorTween>[];
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<T> 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<Widget> gestureChildren = <Widget>[];
final List<Color> backgroundColors = <Color>[];
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<T>(
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<T> 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<Color> backgroundColors;
final Color borderColor;
@override
RenderObject createRenderObject(BuildContext context) {
return _RenderSegmentedControl<T>(
textDirection: Directionality.of(context),
selectedIndex: selectedIndex,
pressedIndex: pressedIndex,
backgroundColors: backgroundColors,
borderColor: borderColor,
);
}
@override
void updateRenderObject(
BuildContext context,
_RenderSegmentedControl<T> renderObject,
) {
renderObject
..textDirection = Directionality.of(context)
..selectedIndex = selectedIndex
..pressedIndex = pressedIndex
..backgroundColors = backgroundColors
..borderColor = borderColor;
}
}
class _SegmentedControlContainerBoxParentData
extends ContainerBoxParentData<RenderBox> {
RRect? surroundingRect;
}
typedef _NextChild = RenderBox? Function(RenderBox child);
class _RenderSegmentedControl<T> extends RenderBox
with
ContainerRenderObjectMixin<
RenderBox,
ContainerBoxParentData<RenderBox>
>,
RenderBoxContainerDefaultsMixin<
RenderBox,
ContainerBoxParentData<RenderBox>
> {
_RenderSegmentedControl({
required int? selectedIndex,
required int? pressedIndex,
required TextDirection textDirection,
required List<Color> 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<Color> get backgroundColors => _backgroundColors;
List<Color> _backgroundColors;
set backgroundColors(List<Color> 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;
}
}

View File

@@ -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<CupertinoSegmentedControlDemo> createState() =>
_CupertinoSegmentedControlDemoState();
}
class _CupertinoSegmentedControlDemoState
extends State<CupertinoSegmentedControlDemo> {
int _selectedSegment = 0;
// The data for the segments
final Map<int, Widget> _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<int>(
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<CupertinoSegmentedControlDemo2> createState() =>
_CupertinoSegmentedControlDemoState2();
}
class _CupertinoSegmentedControlDemoState2
extends State<CupertinoSegmentedControlDemo2> {
int _selectedSegment = 0;
// The data for the segments
final Map<int, Widget> _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<int>(
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),
),
],
),
);
}
}

View File

@@ -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<Color?>((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,
),
);
}

View File

@@ -58,34 +58,14 @@ dev_dependencies:
flutter: flutter:
uses-material-design: true uses-material-design: true
# To add assets to your application, add an assets section, like this:
assets: assets:
- assets/icons/ - assets/icons/
- assets/images/ - assets/images/
- assets/logos/ - assets/logos/
- assets/vec/
# An image asset can refer to one or more resolution-specific "variants", see fonts:
# https://flutter.dev/to/resolution-aware-images - family: yekan
fonts:
# For details regarding adding assets from package dependencies, see - asset: fonts/iranyekanregularfanum.ttf
# 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

33
vecGeneratoe.sh Normal file
View File

@@ -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