changed theme to green
This commit is contained in:
parent
f281eb5b50
commit
8c3493b792
@ -19,14 +19,19 @@ enum ContentThemeColor {
|
|||||||
pink,
|
pink,
|
||||||
green,
|
green,
|
||||||
red,
|
red,
|
||||||
brandRed;
|
brandRed,
|
||||||
|
brandGreen;
|
||||||
|
|
||||||
Color get color {
|
Color get color {
|
||||||
return (AdminTheme.theme.contentTheme.getMappedIntoThemeColor[this]?['color']) ?? Colors.black;
|
return (AdminTheme.theme.contentTheme.getMappedIntoThemeColor[this]
|
||||||
|
?['color']) ??
|
||||||
|
Colors.black;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color get onColor {
|
Color get onColor {
|
||||||
return (AdminTheme.theme.contentTheme.getMappedIntoThemeColor[this]?['onColor']) ?? Colors.white;
|
return (AdminTheme.theme.contentTheme.getMappedIntoThemeColor[this]
|
||||||
|
?['onColor']) ??
|
||||||
|
Colors.white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +82,9 @@ class TopBarTheme {
|
|||||||
|
|
||||||
static final TopBarTheme lightTopBarTheme = TopBarTheme();
|
static final TopBarTheme lightTopBarTheme = TopBarTheme();
|
||||||
|
|
||||||
static final TopBarTheme darkTopBarTheme = TopBarTheme(background: const Color(0xff2c3036), onBackground: const Color(0xffdcdcdc));
|
static final TopBarTheme darkTopBarTheme = TopBarTheme(
|
||||||
|
background: const Color(0xff2c3036),
|
||||||
|
onBackground: const Color(0xffdcdcdc));
|
||||||
}
|
}
|
||||||
|
|
||||||
class RightBarTheme {
|
class RightBarTheme {
|
||||||
@ -121,6 +128,7 @@ class ContentTheme {
|
|||||||
final Color pink, onPink;
|
final Color pink, onPink;
|
||||||
final Color red, onRed;
|
final Color red, onRed;
|
||||||
final Color brandRed, onBrandRed;
|
final Color brandRed, onBrandRed;
|
||||||
|
final Color brandGreen, onBrandGreen;
|
||||||
|
|
||||||
final Color cardBackground, cardShadow, cardBorder, cardText, cardTextMuted;
|
final Color cardBackground, cardShadow, cardBorder, cardText, cardTextMuted;
|
||||||
final Color title;
|
final Color title;
|
||||||
@ -130,7 +138,10 @@ class ContentTheme {
|
|||||||
var c = AdminTheme.theme.contentTheme;
|
var c = AdminTheme.theme.contentTheme;
|
||||||
return {
|
return {
|
||||||
ContentThemeColor.primary: {'color': c.primary, 'onColor': c.onPrimary},
|
ContentThemeColor.primary: {'color': c.primary, 'onColor': c.onPrimary},
|
||||||
ContentThemeColor.secondary: {'color': c.secondary, 'onColor': c.onSecondary},
|
ContentThemeColor.secondary: {
|
||||||
|
'color': c.secondary,
|
||||||
|
'onColor': c.onSecondary
|
||||||
|
},
|
||||||
ContentThemeColor.success: {'color': c.success, 'onColor': c.onSuccess},
|
ContentThemeColor.success: {'color': c.success, 'onColor': c.onSuccess},
|
||||||
ContentThemeColor.info: {'color': c.info, 'onColor': c.onInfo},
|
ContentThemeColor.info: {'color': c.info, 'onColor': c.onInfo},
|
||||||
ContentThemeColor.warning: {'color': c.warning, 'onColor': c.onWarning},
|
ContentThemeColor.warning: {'color': c.warning, 'onColor': c.onWarning},
|
||||||
@ -139,14 +150,21 @@ class ContentTheme {
|
|||||||
ContentThemeColor.dark: {'color': c.dark, 'onColor': c.onDark},
|
ContentThemeColor.dark: {'color': c.dark, 'onColor': c.onDark},
|
||||||
ContentThemeColor.pink: {'color': c.pink, 'onColor': c.onPink},
|
ContentThemeColor.pink: {'color': c.pink, 'onColor': c.onPink},
|
||||||
ContentThemeColor.red: {'color': c.red, 'onColor': c.onRed},
|
ContentThemeColor.red: {'color': c.red, 'onColor': c.onRed},
|
||||||
ContentThemeColor.brandRed: {'color': c.brandRed, 'onColor': c.onBrandRed},
|
ContentThemeColor.brandRed: {
|
||||||
|
'color': c.brandRed,
|
||||||
|
'onColor': c.onBrandRed
|
||||||
|
},
|
||||||
|
ContentThemeColor.green: {
|
||||||
|
'color': c.brandGreen,
|
||||||
|
'onColor': c.onBrandGreen
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentTheme({
|
ContentTheme({
|
||||||
this.background = const Color(0xfffafbfe),
|
this.background = const Color(0xfffafbfe),
|
||||||
this.onBackground = const Color(0xffF1F1F2),
|
this.onBackground = const Color(0xffF1F1F2),
|
||||||
this.primary = const Color(0xff663399),
|
this.primary = const Color(0xFF49BF3C),
|
||||||
this.onPrimary = const Color(0xffffffff),
|
this.onPrimary = const Color(0xffffffff),
|
||||||
this.secondary = const Color(0xff6c757d),
|
this.secondary = const Color(0xff6c757d),
|
||||||
this.onSecondary = const Color(0xffffffff),
|
this.onSecondary = const Color(0xffffffff),
|
||||||
@ -178,12 +196,12 @@ class ContentTheme {
|
|||||||
this.title = const Color(0xff6c757d),
|
this.title = const Color(0xff6c757d),
|
||||||
this.disabled = const Color(0xffffffff),
|
this.disabled = const Color(0xffffffff),
|
||||||
this.onDisabled = const Color(0xffffffff),
|
this.onDisabled = const Color(0xffffffff),
|
||||||
|
this.brandGreen = const Color(0xFF49BF3C),
|
||||||
|
this.onBrandGreen = const Color(0xFFFFFFFF),
|
||||||
});
|
});
|
||||||
|
|
||||||
//-------------------------------------- Left Bar Theme ----------------------------------------//
|
|
||||||
|
|
||||||
static final ContentTheme lightContentTheme = ContentTheme(
|
static final ContentTheme lightContentTheme = ContentTheme(
|
||||||
primary: Color(0xff663399),
|
primary: Color(0xFF49BF3C),
|
||||||
background: const Color(0xfffafbfe),
|
background: const Color(0xfffafbfe),
|
||||||
onBackground: const Color(0xff313a46),
|
onBackground: const Color(0xff313a46),
|
||||||
cardBorder: const Color(0xffe8ecf1),
|
cardBorder: const Color(0xffe8ecf1),
|
||||||
@ -197,7 +215,7 @@ class ContentTheme {
|
|||||||
);
|
);
|
||||||
|
|
||||||
static final ContentTheme darkContentTheme = ContentTheme(
|
static final ContentTheme darkContentTheme = ContentTheme(
|
||||||
primary: Color(0xff32BFAE),
|
primary: Color(0xFF49BF3C),
|
||||||
background: const Color(0xff343a40),
|
background: const Color(0xff343a40),
|
||||||
onBackground: const Color(0xffF1F1F2),
|
onBackground: const Color(0xffF1F1F2),
|
||||||
disabled: const Color(0xff444d57),
|
disabled: const Color(0xff444d57),
|
||||||
@ -236,9 +254,17 @@ class AdminTheme {
|
|||||||
|
|
||||||
static void setTheme() {
|
static void setTheme() {
|
||||||
theme = AdminTheme(
|
theme = AdminTheme(
|
||||||
leftBarTheme: ThemeCustomizer.instance.theme == ThemeMode.dark ? LeftBarTheme.darkLeftBarTheme : LeftBarTheme.lightLeftBarTheme,
|
leftBarTheme: ThemeCustomizer.instance.theme == ThemeMode.dark
|
||||||
topBarTheme: ThemeCustomizer.instance.theme == ThemeMode.dark ? TopBarTheme.darkTopBarTheme : TopBarTheme.lightTopBarTheme,
|
? LeftBarTheme.darkLeftBarTheme
|
||||||
rightBarTheme: ThemeCustomizer.instance.theme == ThemeMode.dark ? RightBarTheme.darkRightBarTheme : RightBarTheme.lightRightBarTheme,
|
: LeftBarTheme.lightLeftBarTheme,
|
||||||
contentTheme: ThemeCustomizer.instance.theme == ThemeMode.dark ? ContentTheme.darkContentTheme : ContentTheme.lightContentTheme);
|
topBarTheme: ThemeCustomizer.instance.theme == ThemeMode.dark
|
||||||
|
? TopBarTheme.darkTopBarTheme
|
||||||
|
: TopBarTheme.lightTopBarTheme,
|
||||||
|
rightBarTheme: ThemeCustomizer.instance.theme == ThemeMode.dark
|
||||||
|
? RightBarTheme.darkRightBarTheme
|
||||||
|
: RightBarTheme.lightRightBarTheme,
|
||||||
|
contentTheme: ThemeCustomizer.instance.theme == ThemeMode.dark
|
||||||
|
? ContentTheme.darkContentTheme
|
||||||
|
: ContentTheme.lightContentTheme);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:marco/helpers/widgets/my_spacing.dart';
|
import 'package:marco/helpers/widgets/my_spacing.dart';
|
||||||
import 'package:marco/helpers/widgets/my_text.dart';
|
import 'package:marco/helpers/widgets/my_text.dart';
|
||||||
|
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
|
||||||
|
|
||||||
class BaseBottomSheet extends StatelessWidget {
|
class BaseBottomSheet extends StatefulWidget {
|
||||||
final String title;
|
final String title;
|
||||||
final String? subtitle;
|
final String? subtitle;
|
||||||
final Widget child;
|
final Widget child;
|
||||||
@ -10,7 +11,7 @@ class BaseBottomSheet extends StatelessWidget {
|
|||||||
final VoidCallback onSubmit;
|
final VoidCallback onSubmit;
|
||||||
final bool isSubmitting;
|
final bool isSubmitting;
|
||||||
final String submitText;
|
final String submitText;
|
||||||
final Color submitColor;
|
final Color? submitColor;
|
||||||
final IconData submitIcon;
|
final IconData submitIcon;
|
||||||
final bool showButtons;
|
final bool showButtons;
|
||||||
final Widget? bottomContent;
|
final Widget? bottomContent;
|
||||||
@ -24,16 +25,23 @@ class BaseBottomSheet extends StatelessWidget {
|
|||||||
this.subtitle,
|
this.subtitle,
|
||||||
this.isSubmitting = false,
|
this.isSubmitting = false,
|
||||||
this.submitText = 'Submit',
|
this.submitText = 'Submit',
|
||||||
this.submitColor = Colors.indigo,
|
this.submitColor,
|
||||||
this.submitIcon = Icons.check_circle_outline,
|
this.submitIcon = Icons.check_circle_outline,
|
||||||
this.showButtons = true,
|
this.showButtons = true,
|
||||||
this.bottomContent,
|
this.bottomContent,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<BaseBottomSheet> createState() => _BaseBottomSheetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BaseBottomSheetState extends State<BaseBottomSheet> with UIMixin {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final mediaQuery = MediaQuery.of(context);
|
final mediaQuery = MediaQuery.of(context);
|
||||||
|
final effectiveSubmitColor =
|
||||||
|
widget.submitColor ?? contentTheme.primary;
|
||||||
|
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
padding: mediaQuery.viewInsets,
|
padding: mediaQuery.viewInsets,
|
||||||
@ -71,35 +79,31 @@ class BaseBottomSheet extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
MySpacing.height(12),
|
MySpacing.height(12),
|
||||||
|
|
||||||
// ✅ Centered title
|
|
||||||
Center(
|
Center(
|
||||||
child: MyText.titleLarge(
|
child: MyText.titleLarge(
|
||||||
title,
|
widget.title,
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (widget.subtitle != null &&
|
||||||
// ✅ Subtitle shown just below header if provided
|
widget.subtitle!.isNotEmpty) ...[
|
||||||
if (subtitle != null && subtitle!.isNotEmpty) ...[
|
|
||||||
MySpacing.height(4),
|
MySpacing.height(4),
|
||||||
MyText.bodySmall(
|
MyText.bodySmall(
|
||||||
subtitle!,
|
widget.subtitle!,
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
color: Colors.grey[700],
|
color: Colors.grey[700],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
||||||
MySpacing.height(12),
|
MySpacing.height(12),
|
||||||
child,
|
widget.child,
|
||||||
MySpacing.height(12),
|
MySpacing.height(12),
|
||||||
if (showButtons) ...[
|
if (widget.showButtons) ...[
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ElevatedButton.icon(
|
child: ElevatedButton.icon(
|
||||||
onPressed: onCancel,
|
onPressed: widget.onCancel,
|
||||||
icon: const Icon(Icons.close, color: Colors.white),
|
icon: const Icon(Icons.close, color: Colors.white),
|
||||||
label: MyText.bodyMedium(
|
label: MyText.bodyMedium(
|
||||||
"Cancel",
|
"Cancel",
|
||||||
@ -111,34 +115,40 @@ class BaseBottomSheet extends StatelessWidget {
|
|||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
padding:
|
||||||
|
const EdgeInsets.symmetric(vertical: 8),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ElevatedButton.icon(
|
child: ElevatedButton.icon(
|
||||||
onPressed: isSubmitting ? null : onSubmit,
|
onPressed:
|
||||||
icon: Icon(submitIcon, color: Colors.white),
|
widget.isSubmitting ? null : widget.onSubmit,
|
||||||
|
icon:
|
||||||
|
Icon(widget.submitIcon, color: Colors.white),
|
||||||
label: MyText.bodyMedium(
|
label: MyText.bodyMedium(
|
||||||
isSubmitting ? "Submitting..." : submitText,
|
widget.isSubmitting
|
||||||
|
? "Submitting..."
|
||||||
|
: widget.submitText,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
),
|
),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: submitColor,
|
backgroundColor: effectiveSubmitColor,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
padding:
|
||||||
|
const EdgeInsets.symmetric(vertical: 8),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (bottomContent != null) ...[
|
if (widget.bottomContent != null) ...[
|
||||||
MySpacing.height(12),
|
MySpacing.height(12),
|
||||||
bottomContent!,
|
widget.bottomContent!,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -9,6 +9,7 @@ import 'package:marco/helpers/widgets/my_text.dart';
|
|||||||
import 'package:marco/model/expense/expense_list_model.dart';
|
import 'package:marco/model/expense/expense_list_model.dart';
|
||||||
import 'package:marco/view/expense/expense_detail_screen.dart';
|
import 'package:marco/view/expense/expense_detail_screen.dart';
|
||||||
import 'package:marco/helpers/widgets/my_confirmation_dialog.dart';
|
import 'package:marco/helpers/widgets/my_confirmation_dialog.dart';
|
||||||
|
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
|
||||||
|
|
||||||
class ExpenseAppBar extends StatelessWidget implements PreferredSizeWidget {
|
class ExpenseAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||||
final ProjectController projectController;
|
final ProjectController projectController;
|
||||||
@ -72,7 +73,7 @@ class ExpenseAppBar extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SearchAndFilter extends StatelessWidget {
|
class SearchAndFilter extends StatefulWidget {
|
||||||
final TextEditingController controller;
|
final TextEditingController controller;
|
||||||
final ValueChanged<String> onChanged;
|
final ValueChanged<String> onChanged;
|
||||||
final VoidCallback onFilterTap;
|
final VoidCallback onFilterTap;
|
||||||
@ -86,6 +87,11 @@ class SearchAndFilter extends StatelessWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SearchAndFilter> createState() => _SearchAndFilterState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SearchAndFilterState extends State<SearchAndFilter> with UIMixin {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Padding(
|
return Padding(
|
||||||
@ -96,8 +102,8 @@ class SearchAndFilter extends StatelessWidget {
|
|||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 35,
|
height: 35,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
controller: controller,
|
controller: widget.controller,
|
||||||
onChanged: onChanged,
|
onChanged: widget.onChanged,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 12),
|
contentPadding: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
prefixIcon:
|
prefixIcon:
|
||||||
@ -109,6 +115,11 @@ class SearchAndFilter extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||||
),
|
),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(5),
|
||||||
|
borderSide:
|
||||||
|
BorderSide(color: contentTheme.primary, width: 1.5),
|
||||||
|
),
|
||||||
enabledBorder: OutlineInputBorder(
|
enabledBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
borderSide: BorderSide(color: Colors.grey.shade300),
|
borderSide: BorderSide(color: Colors.grey.shade300),
|
||||||
@ -124,7 +135,7 @@ class SearchAndFilter extends StatelessWidget {
|
|||||||
clipBehavior: Clip.none,
|
clipBehavior: Clip.none,
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.tune, color: Colors.black),
|
const Icon(Icons.tune, color: Colors.black),
|
||||||
if (expenseController.isFilterApplied)
|
if (widget.expenseController.isFilterApplied)
|
||||||
Positioned(
|
Positioned(
|
||||||
top: -1,
|
top: -1,
|
||||||
right: -1,
|
right: -1,
|
||||||
@ -140,7 +151,7 @@ class SearchAndFilter extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
onPressed: onFilterTap,
|
onPressed: widget.onFilterTap,
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
66
lib/helpers/widgets/wave_background.dart
Normal file
66
lib/helpers/widgets/wave_background.dart
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class WaveBackground extends StatelessWidget {
|
||||||
|
final Color color;
|
||||||
|
final double heightFactor;
|
||||||
|
|
||||||
|
const WaveBackground({
|
||||||
|
super.key,
|
||||||
|
required this.color,
|
||||||
|
this.heightFactor = 0.2,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return CustomPaint(
|
||||||
|
painter: _WavePainter(color, heightFactor),
|
||||||
|
size: Size.infinite,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _WavePainter extends CustomPainter {
|
||||||
|
final Color color;
|
||||||
|
final double heightFactor;
|
||||||
|
|
||||||
|
_WavePainter(this.color, this.heightFactor);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void paint(Canvas canvas, Size size) {
|
||||||
|
final paint1 = Paint()
|
||||||
|
..shader = LinearGradient(
|
||||||
|
colors: [
|
||||||
|
const Color(0xFF49BF3C),
|
||||||
|
const Color(0xFF81C784),
|
||||||
|
],
|
||||||
|
begin: Alignment.topLeft,
|
||||||
|
end: Alignment.bottomRight,
|
||||||
|
).createShader(Rect.fromLTWH(0, 0, size.width, size.height));
|
||||||
|
|
||||||
|
final path1 = Path()
|
||||||
|
..moveTo(0, size.height * heightFactor)
|
||||||
|
..quadraticBezierTo(
|
||||||
|
size.width * 0.25, size.height * 0.05, size.width * 0.5, size.height * 0.15)
|
||||||
|
..quadraticBezierTo(
|
||||||
|
size.width * 0.75, size.height * 0.25, size.width, size.height * 0.1)
|
||||||
|
..lineTo(size.width, 0)
|
||||||
|
..lineTo(0, 0)
|
||||||
|
..close();
|
||||||
|
|
||||||
|
canvas.drawPath(path1, paint1);
|
||||||
|
|
||||||
|
// Secondary wave (overlay) with same green but lighter opacity
|
||||||
|
final paint2 = Paint()..color = const Color(0xFF49BF3C).withOpacity(0.15);
|
||||||
|
final path2 = Path()
|
||||||
|
..moveTo(0, size.height * (heightFactor + 0.05))
|
||||||
|
..quadraticBezierTo(size.width * 0.4, size.height * 0.1, size.width, size.height * 0.2)
|
||||||
|
..lineTo(size.width, 0)
|
||||||
|
..lineTo(0, 0)
|
||||||
|
..close();
|
||||||
|
|
||||||
|
canvas.drawPath(path2, paint2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldRepaint(CustomPainter oldDelegate) => false;
|
||||||
|
}
|
@ -94,7 +94,7 @@ class _EmailLoginFormState extends State<EmailLoginForm> with UIMixin {
|
|||||||
MaterialStateProperty.resolveWith<Color>(
|
MaterialStateProperty.resolveWith<Color>(
|
||||||
(states) =>
|
(states) =>
|
||||||
states.contains(WidgetState.selected)
|
states.contains(WidgetState.selected)
|
||||||
? contentTheme.brandRed
|
? contentTheme.primary
|
||||||
: Colors.white,
|
: Colors.white,
|
||||||
),
|
),
|
||||||
checkColor: contentTheme.onPrimary,
|
checkColor: contentTheme.onPrimary,
|
||||||
@ -128,7 +128,7 @@ class _EmailLoginFormState extends State<EmailLoginForm> with UIMixin {
|
|||||||
elevation: 2,
|
elevation: 2,
|
||||||
padding: MySpacing.xy(80, 16),
|
padding: MySpacing.xy(80, 16),
|
||||||
borderRadiusAll: 10,
|
borderRadiusAll: 10,
|
||||||
backgroundColor: contentTheme.brandRed,
|
backgroundColor: contentTheme.primary,
|
||||||
child: MyText.labelLarge(
|
child: MyText.labelLarge(
|
||||||
'Login',
|
'Login',
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
|
@ -8,6 +8,7 @@ import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
|
|||||||
import 'package:marco/helpers/widgets/my_button.dart';
|
import 'package:marco/helpers/widgets/my_button.dart';
|
||||||
import 'package:marco/helpers/widgets/my_text.dart';
|
import 'package:marco/helpers/widgets/my_text.dart';
|
||||||
import 'package:marco/images.dart';
|
import 'package:marco/images.dart';
|
||||||
|
import 'package:marco/helpers/widgets/wave_background.dart';
|
||||||
|
|
||||||
class ForgotPasswordScreen extends StatefulWidget {
|
class ForgotPasswordScreen extends StatefulWidget {
|
||||||
const ForgotPasswordScreen({super.key});
|
const ForgotPasswordScreen({super.key});
|
||||||
@ -59,7 +60,7 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen>
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Stack(
|
body: Stack(
|
||||||
children: [
|
children: [
|
||||||
_RedWaveBackground(brandRed: contentTheme.brandRed),
|
WaveBackground(color: contentTheme.brandRed),
|
||||||
SafeArea(
|
SafeArea(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -230,8 +231,8 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen>
|
|||||||
padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 16),
|
||||||
borderRadiusAll: 10,
|
borderRadiusAll: 10,
|
||||||
backgroundColor: _isLoading
|
backgroundColor: _isLoading
|
||||||
? contentTheme.brandRed.withOpacity(0.6)
|
? contentTheme.primary.withOpacity(0.6)
|
||||||
: contentTheme.brandRed,
|
: contentTheme.primary,
|
||||||
child: _isLoading
|
child: _isLoading
|
||||||
? const SizedBox(
|
? const SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
@ -253,68 +254,13 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen>
|
|||||||
Widget _buildBackButton() {
|
Widget _buildBackButton() {
|
||||||
return TextButton.icon(
|
return TextButton.icon(
|
||||||
onPressed: () async => await LocalStorage.logout(),
|
onPressed: () async => await LocalStorage.logout(),
|
||||||
icon: const Icon(Icons.arrow_back, size: 18, color: Colors.redAccent),
|
icon: Icon(Icons.arrow_back, size: 18, color: contentTheme.primary),
|
||||||
label: MyText.bodyMedium(
|
label: MyText.bodyMedium(
|
||||||
'Back to Login',
|
'Back to Login',
|
||||||
color: contentTheme.brandRed,
|
color: contentTheme.primary,
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _RedWaveBackground extends StatelessWidget {
|
|
||||||
final Color brandRed;
|
|
||||||
const _RedWaveBackground({required this.brandRed});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return CustomPaint(
|
|
||||||
painter: _WavePainter(brandRed),
|
|
||||||
size: Size.infinite,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _WavePainter extends CustomPainter {
|
|
||||||
final Color brandRed;
|
|
||||||
|
|
||||||
_WavePainter(this.brandRed);
|
|
||||||
|
|
||||||
@override
|
|
||||||
void paint(Canvas canvas, Size size) {
|
|
||||||
final paint1 = Paint()
|
|
||||||
..shader = LinearGradient(
|
|
||||||
colors: [brandRed, const Color.fromARGB(255, 97, 22, 22)],
|
|
||||||
begin: Alignment.topLeft,
|
|
||||||
end: Alignment.bottomRight,
|
|
||||||
).createShader(Rect.fromLTWH(0, 0, size.width, size.height));
|
|
||||||
|
|
||||||
final path1 = Path()
|
|
||||||
..moveTo(0, size.height * 0.2)
|
|
||||||
..quadraticBezierTo(size.width * 0.25, size.height * 0.05,
|
|
||||||
size.width * 0.5, size.height * 0.15)
|
|
||||||
..quadraticBezierTo(
|
|
||||||
size.width * 0.75, size.height * 0.25, size.width, size.height * 0.1)
|
|
||||||
..lineTo(size.width, 0)
|
|
||||||
..lineTo(0, 0)
|
|
||||||
..close();
|
|
||||||
|
|
||||||
canvas.drawPath(path1, paint1);
|
|
||||||
|
|
||||||
final paint2 = Paint()..color = Colors.redAccent.withOpacity(0.15);
|
|
||||||
final path2 = Path()
|
|
||||||
..moveTo(0, size.height * 0.25)
|
|
||||||
..quadraticBezierTo(
|
|
||||||
size.width * 0.4, size.height * 0.1, size.width, size.height * 0.2)
|
|
||||||
..lineTo(size.width, 0)
|
|
||||||
..lineTo(0, 0)
|
|
||||||
..close();
|
|
||||||
|
|
||||||
canvas.drawPath(path2, paint2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool shouldRepaint(CustomPainter oldDelegate) => false;
|
|
||||||
}
|
|
||||||
|
@ -7,6 +7,7 @@ import 'package:marco/view/auth/otp_login_form.dart';
|
|||||||
import 'package:marco/helpers/services/api_endpoints.dart';
|
import 'package:marco/helpers/services/api_endpoints.dart';
|
||||||
import 'package:marco/view/auth/request_demo_bottom_sheet.dart';
|
import 'package:marco/view/auth/request_demo_bottom_sheet.dart';
|
||||||
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
|
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
|
||||||
|
import 'package:marco/helpers/widgets/wave_background.dart';
|
||||||
|
|
||||||
enum LoginOption { email, otp }
|
enum LoginOption { email, otp }
|
||||||
|
|
||||||
@ -83,7 +84,7 @@ class _WelcomeScreenState extends State<WelcomeScreen>
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
option == LoginOption.email
|
option == LoginOption.email
|
||||||
? EmailLoginForm()
|
? EmailLoginForm()
|
||||||
: const OTPLoginScreen(),
|
: const OTPLoginScreen(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -101,13 +102,14 @@ class _WelcomeScreenState extends State<WelcomeScreen>
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Stack(
|
body: Stack(
|
||||||
children: [
|
children: [
|
||||||
_RedWaveBackground(brandRed: contentTheme.brandRed),
|
WaveBackground(color: contentTheme.brandRed),
|
||||||
SafeArea(
|
SafeArea(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.all(24),
|
padding: const EdgeInsets.all(24),
|
||||||
child: ConstrainedBox(
|
child: ConstrainedBox(
|
||||||
constraints: BoxConstraints(maxWidth: isNarrow ? double.infinity : 420),
|
constraints: BoxConstraints(
|
||||||
|
maxWidth: isNarrow ? double.infinity : 420),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
@ -166,7 +168,10 @@ class _WelcomeScreenState extends State<WelcomeScreen>
|
|||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 10, offset: Offset(0, 4))],
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black12, blurRadius: 10, offset: Offset(0, 4))
|
||||||
|
],
|
||||||
),
|
),
|
||||||
child: Image.asset(Images.logoDark),
|
child: Image.asset(Images.logoDark),
|
||||||
),
|
),
|
||||||
@ -230,7 +235,7 @@ class _WelcomeScreenState extends State<WelcomeScreen>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: contentTheme.brandRed,
|
backgroundColor: contentTheme.brandGreen,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
|
||||||
elevation: 4,
|
elevation: 4,
|
||||||
@ -247,55 +252,3 @@ class _WelcomeScreenState extends State<WelcomeScreen>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Red wave background painter
|
|
||||||
class _RedWaveBackground extends StatelessWidget {
|
|
||||||
final Color brandRed;
|
|
||||||
const _RedWaveBackground({required this.brandRed});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return CustomPaint(
|
|
||||||
painter: _WavePainter(brandRed),
|
|
||||||
size: Size.infinite,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _WavePainter extends CustomPainter {
|
|
||||||
final Color brandRed;
|
|
||||||
_WavePainter(this.brandRed);
|
|
||||||
|
|
||||||
@override
|
|
||||||
void paint(Canvas canvas, Size size) {
|
|
||||||
final paint1 = Paint()
|
|
||||||
..shader = LinearGradient(
|
|
||||||
colors: [brandRed, const Color.fromARGB(255, 97, 22, 22)],
|
|
||||||
begin: Alignment.topLeft,
|
|
||||||
end: Alignment.bottomRight,
|
|
||||||
).createShader(Rect.fromLTWH(0, 0, size.width, size.height));
|
|
||||||
|
|
||||||
final path1 = Path()
|
|
||||||
..moveTo(0, size.height * 0.2)
|
|
||||||
..quadraticBezierTo(size.width * 0.25, size.height * 0.05, size.width * 0.5, size.height * 0.15)
|
|
||||||
..quadraticBezierTo(size.width * 0.75, size.height * 0.25, size.width, size.height * 0.1)
|
|
||||||
..lineTo(size.width, 0)
|
|
||||||
..lineTo(0, 0)
|
|
||||||
..close();
|
|
||||||
|
|
||||||
canvas.drawPath(path1, paint1);
|
|
||||||
|
|
||||||
final paint2 = Paint()..color = Colors.redAccent.withOpacity(0.15);
|
|
||||||
final path2 = Path()
|
|
||||||
..moveTo(0, size.height * 0.25)
|
|
||||||
..quadraticBezierTo(size.width * 0.4, size.height * 0.1, size.width, size.height * 0.2)
|
|
||||||
..lineTo(size.width, 0)
|
|
||||||
..lineTo(0, 0)
|
|
||||||
..close();
|
|
||||||
|
|
||||||
canvas.drawPath(path2, paint2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool shouldRepaint(CustomPainter oldDelegate) => false;
|
|
||||||
}
|
|
||||||
|
@ -193,7 +193,7 @@ class _LoginScreenState extends State<LoginScreen> with UIMixin {
|
|||||||
elevation: 2,
|
elevation: 2,
|
||||||
padding: MySpacing.xy(24, 16),
|
padding: MySpacing.xy(24, 16),
|
||||||
borderRadiusAll: 5,
|
borderRadiusAll: 5,
|
||||||
backgroundColor: Colors.blueAccent,
|
backgroundColor:contentTheme.brandGreen,
|
||||||
child: MyText.labelMedium(
|
child: MyText.labelMedium(
|
||||||
'Login',
|
'Login',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
|
@ -8,6 +8,7 @@ import 'package:marco/images.dart';
|
|||||||
import 'package:marco/helpers/services/storage/local_storage.dart';
|
import 'package:marco/helpers/services/storage/local_storage.dart';
|
||||||
import 'package:marco/helpers/services/api_endpoints.dart';
|
import 'package:marco/helpers/services/api_endpoints.dart';
|
||||||
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
|
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
|
||||||
|
import 'package:marco/helpers/widgets/wave_background.dart';
|
||||||
|
|
||||||
class MPINAuthScreen extends StatefulWidget {
|
class MPINAuthScreen extends StatefulWidget {
|
||||||
const MPINAuthScreen({super.key});
|
const MPINAuthScreen({super.key});
|
||||||
@ -51,7 +52,7 @@ class _MPINAuthScreenState extends State<MPINAuthScreen>
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Stack(
|
body: Stack(
|
||||||
children: [
|
children: [
|
||||||
_RedWaveBackground(brandRed: contentTheme.brandRed),
|
WaveBackground(color: contentTheme.brandRed),
|
||||||
SafeArea(
|
SafeArea(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -281,8 +282,8 @@ class _MPINAuthScreenState extends State<MPINAuthScreen>
|
|||||||
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16),
|
||||||
borderRadiusAll: 5,
|
borderRadiusAll: 5,
|
||||||
backgroundColor: controller.isLoading.value
|
backgroundColor: controller.isLoading.value
|
||||||
? contentTheme.brandRed.withOpacity(0.6)
|
? contentTheme.primary.withOpacity(0.6)
|
||||||
: contentTheme.brandRed,
|
: contentTheme.primary,
|
||||||
child: controller.isLoading.value
|
child: controller.isLoading.value
|
||||||
? const SizedBox(
|
? const SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
@ -341,57 +342,3 @@ class _MPINAuthScreenState extends State<MPINAuthScreen>
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _RedWaveBackground extends StatelessWidget {
|
|
||||||
final Color brandRed;
|
|
||||||
const _RedWaveBackground({required this.brandRed});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return CustomPaint(
|
|
||||||
painter: _WavePainter(brandRed),
|
|
||||||
size: Size.infinite,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _WavePainter extends CustomPainter {
|
|
||||||
final Color brandRed;
|
|
||||||
const _WavePainter(this.brandRed);
|
|
||||||
|
|
||||||
@override
|
|
||||||
void paint(Canvas canvas, Size size) {
|
|
||||||
final paint1 = Paint()
|
|
||||||
..shader = LinearGradient(
|
|
||||||
colors: [brandRed, const Color.fromARGB(255, 97, 22, 22)],
|
|
||||||
begin: Alignment.topLeft,
|
|
||||||
end: Alignment.bottomRight,
|
|
||||||
).createShader(Rect.fromLTWH(0, 0, size.width, size.height));
|
|
||||||
|
|
||||||
final path1 = Path()
|
|
||||||
..moveTo(0, size.height * 0.2)
|
|
||||||
..quadraticBezierTo(size.width * 0.25, size.height * 0.05,
|
|
||||||
size.width * 0.5, size.height * 0.15)
|
|
||||||
..quadraticBezierTo(
|
|
||||||
size.width * 0.75, size.height * 0.25, size.width, size.height * 0.1)
|
|
||||||
..lineTo(size.width, 0)
|
|
||||||
..lineTo(0, 0)
|
|
||||||
..close();
|
|
||||||
|
|
||||||
canvas.drawPath(path1, paint1);
|
|
||||||
|
|
||||||
final paint2 = Paint()..color = Colors.redAccent.withOpacity(0.15);
|
|
||||||
final path2 = Path()
|
|
||||||
..moveTo(0, size.height * 0.25)
|
|
||||||
..quadraticBezierTo(
|
|
||||||
size.width * 0.4, size.height * 0.1, size.width, size.height * 0.2)
|
|
||||||
..lineTo(size.width, 0)
|
|
||||||
..lineTo(0, 0)
|
|
||||||
..close();
|
|
||||||
|
|
||||||
canvas.drawPath(path2, paint2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool shouldRepaint(CustomPainter oldDelegate) => false;
|
|
||||||
}
|
|
||||||
|
@ -81,7 +81,7 @@ class _OTPLoginScreenState extends State<OTPLoginScreen> with UIMixin {
|
|||||||
elevation: 2,
|
elevation: 2,
|
||||||
padding: MySpacing.xy(24, 16),
|
padding: MySpacing.xy(24, 16),
|
||||||
borderRadiusAll: 10,
|
borderRadiusAll: 10,
|
||||||
backgroundColor: isDisabled ? Colors.grey : contentTheme.brandRed,
|
backgroundColor: isDisabled ? Colors.grey : contentTheme.primary,
|
||||||
child: controller.isSending.value
|
child: controller.isSending.value
|
||||||
? SizedBox(
|
? SizedBox(
|
||||||
width: 20,
|
width: 20,
|
||||||
|
@ -166,10 +166,9 @@ class _OrganizationFormState extends State<_OrganizationForm> with UIMixin {
|
|||||||
onChanged: (val) => setState(() => _agreed = val ?? false),
|
onChanged: (val) => setState(() => _agreed = val ?? false),
|
||||||
fillColor: MaterialStateProperty.resolveWith((states) =>
|
fillColor: MaterialStateProperty.resolveWith((states) =>
|
||||||
states.contains(MaterialState.selected)
|
states.contains(MaterialState.selected)
|
||||||
? contentTheme.brandRed
|
? contentTheme.primary
|
||||||
: Colors.white),
|
: Colors.white),
|
||||||
checkColor: Colors.white,
|
checkColor: Colors.white,
|
||||||
side: const BorderSide(color: Colors.red, width: 2),
|
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
@ -179,7 +178,7 @@ class _OrganizationFormState extends State<_OrganizationForm> with UIMixin {
|
|||||||
),
|
),
|
||||||
MyText(
|
MyText(
|
||||||
'privacy policy & terms',
|
'privacy policy & terms',
|
||||||
color: contentTheme.brandRed,
|
color: contentTheme.primary,
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -188,44 +187,44 @@ class _OrganizationFormState extends State<_OrganizationForm> with UIMixin {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
||||||
children: [
|
children: [
|
||||||
OutlinedButton.icon(
|
Expanded(
|
||||||
onPressed: () => Navigator.pop(context),
|
child: ElevatedButton.icon(
|
||||||
icon: const Icon(Icons.arrow_back, color: Colors.red),
|
onPressed: () => Navigator.pop(context),
|
||||||
label: MyText.bodyMedium("Back", color: Colors.red),
|
icon: const Icon(Icons.close, color: Colors.white),
|
||||||
style: OutlinedButton.styleFrom(
|
label: MyText.bodyMedium(
|
||||||
side: const BorderSide(color: Colors.red),
|
"Cancel",
|
||||||
shape: RoundedRectangleBorder(
|
color: Colors.white,
|
||||||
borderRadius: BorderRadius.circular(5),
|
fontWeight: 600,
|
||||||
|
),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: Colors.grey,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 28, vertical: 5),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ElevatedButton.icon(
|
const SizedBox(width: 12),
|
||||||
onPressed: _loading ? null : _submitForm,
|
Expanded(
|
||||||
icon: _loading
|
child: ElevatedButton.icon(
|
||||||
? const SizedBox(
|
onPressed: _loading ? null : _submitForm,
|
||||||
width: 18,
|
icon:
|
||||||
height: 18,
|
Icon(Icons.check_circle_outline, color: Colors.white),
|
||||||
child: CircularProgressIndicator(
|
label: MyText.bodyMedium(
|
||||||
color: Colors.white,
|
_loading ? "Submitting..." : "Submit",
|
||||||
strokeWidth: 2,
|
color: Colors.white,
|
||||||
),
|
fontWeight: 600,
|
||||||
)
|
),
|
||||||
: const Icon(Icons.check_circle_outline,
|
style: ElevatedButton.styleFrom(
|
||||||
color: Colors.white),
|
backgroundColor: contentTheme
|
||||||
label: _loading
|
.primary,
|
||||||
? const SizedBox.shrink()
|
shape: RoundedRectangleBorder(
|
||||||
: MyText.bodyMedium("Submit", color: Colors.white),
|
borderRadius: BorderRadius.circular(12),
|
||||||
style: ElevatedButton.styleFrom(
|
),
|
||||||
backgroundColor: Colors.indigo,
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(5),
|
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 28, vertical: 5),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -235,11 +234,11 @@ class _OrganizationFormState extends State<_OrganizationForm> with UIMixin {
|
|||||||
child: TextButton.icon(
|
child: TextButton.icon(
|
||||||
onPressed: () => Navigator.pop(context),
|
onPressed: () => Navigator.pop(context),
|
||||||
icon:
|
icon:
|
||||||
const Icon(Icons.arrow_back, size: 18, color: Colors.red),
|
Icon(Icons.arrow_back, size: 18, color: contentTheme.primary),
|
||||||
label: MyText.bodySmall(
|
label: MyText.bodySmall(
|
||||||
'Back to log in',
|
'Back to log in',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
color: contentTheme.brandRed,
|
color: contentTheme.primary,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -16,6 +16,7 @@ import 'package:marco/helpers/utils/date_time_utils.dart';
|
|||||||
import 'package:marco/model/directory/add_contact_bottom_sheet.dart';
|
import 'package:marco/model/directory/add_contact_bottom_sheet.dart';
|
||||||
import 'package:marco/helpers/widgets/my_refresh_indicator.dart';
|
import 'package:marco/helpers/widgets/my_refresh_indicator.dart';
|
||||||
import 'package:marco/helpers/widgets/my_confirmation_dialog.dart';
|
import 'package:marco/helpers/widgets/my_confirmation_dialog.dart';
|
||||||
|
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
|
||||||
|
|
||||||
// HELPER: Delta to HTML conversion
|
// HELPER: Delta to HTML conversion
|
||||||
String _convertDeltaToHtml(dynamic delta) {
|
String _convertDeltaToHtml(dynamic delta) {
|
||||||
@ -68,7 +69,7 @@ class ContactDetailScreen extends StatefulWidget {
|
|||||||
State<ContactDetailScreen> createState() => _ContactDetailScreenState();
|
State<ContactDetailScreen> createState() => _ContactDetailScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ContactDetailScreenState extends State<ContactDetailScreen> {
|
class _ContactDetailScreenState extends State<ContactDetailScreen> with UIMixin{
|
||||||
late final DirectoryController directoryController;
|
late final DirectoryController directoryController;
|
||||||
late final ProjectController projectController;
|
late final ProjectController projectController;
|
||||||
|
|
||||||
@ -191,7 +192,7 @@ class _ContactDetailScreenState extends State<ContactDetailScreen> {
|
|||||||
TabBar(
|
TabBar(
|
||||||
labelColor: Colors.black,
|
labelColor: Colors.black,
|
||||||
unselectedLabelColor: Colors.grey,
|
unselectedLabelColor: Colors.grey,
|
||||||
indicatorColor: Colors.red,
|
indicatorColor: contentTheme.primary,
|
||||||
tabs: const [
|
tabs: const [
|
||||||
Tab(text: "Details"),
|
Tab(text: "Details"),
|
||||||
Tab(text: "Notes"),
|
Tab(text: "Notes"),
|
||||||
@ -308,7 +309,7 @@ class _ContactDetailScreenState extends State<ContactDetailScreen> {
|
|||||||
bottom: 20,
|
bottom: 20,
|
||||||
right: 20,
|
right: 20,
|
||||||
child: FloatingActionButton.extended(
|
child: FloatingActionButton.extended(
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: contentTheme.primary,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final result = await Get.bottomSheet(
|
final result = await Get.bottomSheet(
|
||||||
AddContactBottomSheet(existingContact: contact),
|
AddContactBottomSheet(existingContact: contact),
|
||||||
@ -383,7 +384,7 @@ class _ContactDetailScreenState extends State<ContactDetailScreen> {
|
|||||||
bottom: 20,
|
bottom: 20,
|
||||||
right: 20,
|
right: 20,
|
||||||
child: FloatingActionButton.extended(
|
child: FloatingActionButton.extended(
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: contentTheme.primary,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final result = await Get.bottomSheet(
|
final result = await Get.bottomSheet(
|
||||||
AddCommentBottomSheet(contactId: contactId),
|
AddCommentBottomSheet(contactId: contactId),
|
||||||
|
@ -17,13 +17,15 @@ import 'package:marco/view/directory/contact_detail_screen.dart';
|
|||||||
import 'package:marco/view/directory/manage_bucket_screen.dart';
|
import 'package:marco/view/directory/manage_bucket_screen.dart';
|
||||||
import 'package:marco/controller/permission_controller.dart';
|
import 'package:marco/controller/permission_controller.dart';
|
||||||
import 'package:marco/helpers/utils/permission_constants.dart';
|
import 'package:marco/helpers/utils/permission_constants.dart';
|
||||||
|
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
|
||||||
|
|
||||||
|
|
||||||
class DirectoryView extends StatefulWidget {
|
class DirectoryView extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
State<DirectoryView> createState() => _DirectoryViewState();
|
State<DirectoryView> createState() => _DirectoryViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DirectoryViewState extends State<DirectoryView> {
|
class _DirectoryViewState extends State<DirectoryView> with UIMixin {
|
||||||
final DirectoryController controller = Get.find();
|
final DirectoryController controller = Get.find();
|
||||||
final TextEditingController searchController = TextEditingController();
|
final TextEditingController searchController = TextEditingController();
|
||||||
final PermissionController permissionController =
|
final PermissionController permissionController =
|
||||||
@ -126,7 +128,7 @@ class _DirectoryViewState extends State<DirectoryView> {
|
|||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () => Navigator.pop(context, true),
|
onPressed: () => Navigator.pop(context, true),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.indigo,
|
backgroundColor: contentTheme.primary,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
@ -172,7 +174,7 @@ class _DirectoryViewState extends State<DirectoryView> {
|
|||||||
backgroundColor: Colors.grey[100],
|
backgroundColor: Colors.grey[100],
|
||||||
floatingActionButton: FloatingActionButton.extended(
|
floatingActionButton: FloatingActionButton.extended(
|
||||||
heroTag: 'createContact',
|
heroTag: 'createContact',
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: contentTheme.primary,
|
||||||
onPressed: _handleCreateContact,
|
onPressed: _handleCreateContact,
|
||||||
icon: const Icon(Icons.person_add_alt_1, color: Colors.white),
|
icon: const Icon(Icons.person_add_alt_1, color: Colors.white),
|
||||||
label: const Text("Add Contact", style: TextStyle(color: Colors.white)),
|
label: const Text("Add Contact", style: TextStyle(color: Colors.white)),
|
||||||
@ -246,7 +248,7 @@ class _DirectoryViewState extends State<DirectoryView> {
|
|||||||
icon: Icon(Icons.tune,
|
icon: Icon(Icons.tune,
|
||||||
size: 20,
|
size: 20,
|
||||||
color: isFilterActive
|
color: isFilterActive
|
||||||
? Colors.indigo
|
? contentTheme.primary
|
||||||
: Colors.black87),
|
: Colors.black87),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
@ -323,13 +325,13 @@ class _DirectoryViewState extends State<DirectoryView> {
|
|||||||
PopupMenuItem<int>(
|
PopupMenuItem<int>(
|
||||||
value: 2,
|
value: 2,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: const [
|
children: [
|
||||||
Icon(Icons.add_box_outlined,
|
Icon(Icons.add_box_outlined,
|
||||||
size: 20, color: Colors.black87),
|
size: 20, color: Colors.black87),
|
||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
Expanded(child: Text("Create Bucket")),
|
Expanded(child: Text("Create Bucket")),
|
||||||
Icon(Icons.chevron_right,
|
Icon(Icons.chevron_right,
|
||||||
size: 20, color: Colors.red),
|
size: 20, color: contentTheme.primary),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@ -356,13 +358,13 @@ class _DirectoryViewState extends State<DirectoryView> {
|
|||||||
PopupMenuItem<int>(
|
PopupMenuItem<int>(
|
||||||
value: 1,
|
value: 1,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: const [
|
children: [
|
||||||
Icon(Icons.label_outline,
|
Icon(Icons.label_outline,
|
||||||
size: 20, color: Colors.black87),
|
size: 20, color: Colors.black87),
|
||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
Expanded(child: Text("Manage Buckets")),
|
Expanded(child: Text("Manage Buckets")),
|
||||||
Icon(Icons.chevron_right,
|
Icon(Icons.chevron_right,
|
||||||
size: 20, color: Colors.red),
|
size: 20, color: contentTheme.primary),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@ -401,7 +403,7 @@ class _DirectoryViewState extends State<DirectoryView> {
|
|||||||
const Expanded(child: Text('Show Deleted Contacts')),
|
const Expanded(child: Text('Show Deleted Contacts')),
|
||||||
Switch.adaptive(
|
Switch.adaptive(
|
||||||
value: !controller.isActive.value,
|
value: !controller.isActive.value,
|
||||||
activeColor: Colors.indigo,
|
activeColor: contentTheme.primary ,
|
||||||
onChanged: (val) {
|
onChanged: (val) {
|
||||||
controller.isActive.value = !val;
|
controller.isActive.value = !val;
|
||||||
controller.fetchContacts(active: !val);
|
controller.fetchContacts(active: !val);
|
||||||
@ -424,7 +426,7 @@ class _DirectoryViewState extends State<DirectoryView> {
|
|||||||
child: Obx(() {
|
child: Obx(() {
|
||||||
return MyRefreshIndicator(
|
return MyRefreshIndicator(
|
||||||
onRefresh: _refreshDirectory,
|
onRefresh: _refreshDirectory,
|
||||||
backgroundColor: Colors.indigo,
|
backgroundColor: contentTheme.primary,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
child: controller.isLoading.value
|
child: controller.isLoading.value
|
||||||
? ListView.separated(
|
? ListView.separated(
|
||||||
|
@ -12,6 +12,8 @@ import 'package:marco/helpers/widgets/avatar.dart';
|
|||||||
import 'package:marco/helpers/utils/date_time_utils.dart';
|
import 'package:marco/helpers/utils/date_time_utils.dart';
|
||||||
import 'package:marco/helpers/widgets/Directory/comment_editor_card.dart';
|
import 'package:marco/helpers/widgets/Directory/comment_editor_card.dart';
|
||||||
import 'package:marco/helpers/widgets/my_confirmation_dialog.dart';
|
import 'package:marco/helpers/widgets/my_confirmation_dialog.dart';
|
||||||
|
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
|
||||||
|
|
||||||
|
|
||||||
class NotesView extends StatelessWidget {
|
class NotesView extends StatelessWidget {
|
||||||
final NotesController controller = Get.find();
|
final NotesController controller = Get.find();
|
||||||
|
@ -13,6 +13,7 @@ import 'package:marco/helpers/widgets/my_snackbar.dart';
|
|||||||
import 'package:marco/model/document/document_edit_bottom_sheet.dart';
|
import 'package:marco/model/document/document_edit_bottom_sheet.dart';
|
||||||
import 'package:marco/controller/permission_controller.dart';
|
import 'package:marco/controller/permission_controller.dart';
|
||||||
import 'package:marco/helpers/utils/permission_constants.dart';
|
import 'package:marco/helpers/utils/permission_constants.dart';
|
||||||
|
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
|
||||||
|
|
||||||
class DocumentDetailsPage extends StatefulWidget {
|
class DocumentDetailsPage extends StatefulWidget {
|
||||||
final String documentId;
|
final String documentId;
|
||||||
@ -23,7 +24,7 @@ class DocumentDetailsPage extends StatefulWidget {
|
|||||||
State<DocumentDetailsPage> createState() => _DocumentDetailsPageState();
|
State<DocumentDetailsPage> createState() => _DocumentDetailsPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
class _DocumentDetailsPageState extends State<DocumentDetailsPage> with UIMixin {
|
||||||
final DocumentDetailsController controller =
|
final DocumentDetailsController controller =
|
||||||
Get.find<DocumentDetailsController>();
|
Get.find<DocumentDetailsController>();
|
||||||
|
|
||||||
@ -155,7 +156,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
|||||||
if (permissionController
|
if (permissionController
|
||||||
.hasPermission(Permissions.modifyDocument))
|
.hasPermission(Permissions.modifyDocument))
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.edit, color: Colors.red),
|
icon: Icon(Icons.edit, color: contentTheme.primary),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
// existing bottom sheet flow
|
// existing bottom sheet flow
|
||||||
await controller
|
await controller
|
||||||
|
@ -19,6 +19,7 @@ import 'package:marco/helpers/widgets/my_snackbar.dart';
|
|||||||
import 'package:marco/controller/permission_controller.dart';
|
import 'package:marco/controller/permission_controller.dart';
|
||||||
import 'package:marco/controller/document/document_details_controller.dart';
|
import 'package:marco/controller/document/document_details_controller.dart';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
|
||||||
|
|
||||||
class UserDocumentsPage extends StatefulWidget {
|
class UserDocumentsPage extends StatefulWidget {
|
||||||
final String? entityId;
|
final String? entityId;
|
||||||
@ -34,7 +35,7 @@ class UserDocumentsPage extends StatefulWidget {
|
|||||||
State<UserDocumentsPage> createState() => _UserDocumentsPageState();
|
State<UserDocumentsPage> createState() => _UserDocumentsPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _UserDocumentsPageState extends State<UserDocumentsPage> {
|
class _UserDocumentsPageState extends State<UserDocumentsPage> with UIMixin {
|
||||||
final DocumentController docController = Get.put(DocumentController());
|
final DocumentController docController = Get.put(DocumentController());
|
||||||
final PermissionController permissionController =
|
final PermissionController permissionController =
|
||||||
Get.find<PermissionController>();
|
Get.find<PermissionController>();
|
||||||
@ -304,6 +305,11 @@ class _UserDocumentsPageState extends State<UserDocumentsPage> {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(5),
|
||||||
|
borderSide:
|
||||||
|
BorderSide(color: contentTheme.primary, width: 1.5),
|
||||||
|
),
|
||||||
hintText: 'Search documents...',
|
hintText: 'Search documents...',
|
||||||
filled: true,
|
filled: true,
|
||||||
fillColor: Colors.white,
|
fillColor: Colors.white,
|
||||||
@ -415,7 +421,7 @@ class _UserDocumentsPageState extends State<UserDocumentsPage> {
|
|||||||
const Expanded(child: Text('Show Deleted Documents')),
|
const Expanded(child: Text('Show Deleted Documents')),
|
||||||
Switch.adaptive(
|
Switch.adaptive(
|
||||||
value: docController.showInactive.value,
|
value: docController.showInactive.value,
|
||||||
activeColor: Colors.indigo,
|
activeColor: contentTheme.primary,
|
||||||
onChanged: (val) {
|
onChanged: (val) {
|
||||||
docController.showInactive.value = val;
|
docController.showInactive.value = val;
|
||||||
docController.fetchDocuments(
|
docController.fetchDocuments(
|
||||||
@ -640,7 +646,7 @@ class _UserDocumentsPageState extends State<UserDocumentsPage> {
|
|||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
),
|
),
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: contentTheme.primary,
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
|
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
|
||||||
|
@ -9,6 +9,8 @@ import 'package:marco/helpers/widgets/my_text.dart';
|
|||||||
import 'package:marco/helpers/utils/launcher_utils.dart';
|
import 'package:marco/helpers/utils/launcher_utils.dart';
|
||||||
import 'package:marco/helpers/widgets/my_refresh_indicator.dart';
|
import 'package:marco/helpers/widgets/my_refresh_indicator.dart';
|
||||||
import 'package:marco/model/employees/add_employee_bottom_sheet.dart';
|
import 'package:marco/model/employees/add_employee_bottom_sheet.dart';
|
||||||
|
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
|
||||||
|
|
||||||
|
|
||||||
class EmployeeDetailPage extends StatefulWidget {
|
class EmployeeDetailPage extends StatefulWidget {
|
||||||
final String employeeId;
|
final String employeeId;
|
||||||
@ -24,7 +26,7 @@ class EmployeeDetailPage extends StatefulWidget {
|
|||||||
State<EmployeeDetailPage> createState() => _EmployeeDetailPageState();
|
State<EmployeeDetailPage> createState() => _EmployeeDetailPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _EmployeeDetailPageState extends State<EmployeeDetailPage> {
|
class _EmployeeDetailPageState extends State<EmployeeDetailPage> with UIMixin {
|
||||||
final EmployeesScreenController controller =
|
final EmployeesScreenController controller =
|
||||||
Get.put(EmployeesScreenController());
|
Get.put(EmployeesScreenController());
|
||||||
|
|
||||||
@ -87,7 +89,7 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> {
|
|||||||
value,
|
value,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.normal,
|
fontWeight: FontWeight.normal,
|
||||||
color: (isEmail || isPhone) ? Colors.indigo : Colors.black54,
|
color: (isEmail || isPhone) ? contentTheme.primary : Colors.black54,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
decoration: (isEmail || isPhone)
|
decoration: (isEmail || isPhone)
|
||||||
? TextDecoration.underline
|
? TextDecoration.underline
|
||||||
@ -248,7 +250,7 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> {
|
|||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon:
|
icon:
|
||||||
const Icon(Icons.edit, size: 24, color: Colors.red),
|
Icon(Icons.edit, size: 24, color: contentTheme.primary),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final result =
|
final result =
|
||||||
await showModalBottomSheet<Map<String, dynamic>>(
|
await showModalBottomSheet<Map<String, dynamic>>(
|
||||||
|
@ -16,6 +16,7 @@ import 'package:marco/helpers/utils/permission_constants.dart';
|
|||||||
import 'package:marco/helpers/widgets/my_refresh_indicator.dart';
|
import 'package:marco/helpers/widgets/my_refresh_indicator.dart';
|
||||||
import 'package:marco/view/employees/employee_profile_screen.dart';
|
import 'package:marco/view/employees/employee_profile_screen.dart';
|
||||||
|
|
||||||
|
|
||||||
class EmployeesScreen extends StatefulWidget {
|
class EmployeesScreen extends StatefulWidget {
|
||||||
const EmployeesScreen({super.key});
|
const EmployeesScreen({super.key});
|
||||||
|
|
||||||
@ -209,14 +210,14 @@ class _EmployeesScreenState extends State<EmployeesScreen> with UIMixin {
|
|||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.red,
|
color: contentTheme.primary,
|
||||||
borderRadius: BorderRadius.circular(28),
|
borderRadius: BorderRadius.circular(28),
|
||||||
boxShadow: const [
|
boxShadow: const [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: Colors.black26, blurRadius: 6, offset: Offset(0, 3))
|
color: Colors.black26, blurRadius: 6, offset: Offset(0, 3))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: const Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.add, color: Colors.white),
|
Icon(Icons.add, color: Colors.white),
|
||||||
@ -262,6 +263,11 @@ class _EmployeesScreenState extends State<EmployeesScreen> with UIMixin {
|
|||||||
hintStyle: const TextStyle(fontSize: 13, color: Colors.grey),
|
hintStyle: const TextStyle(fontSize: 13, color: Colors.grey),
|
||||||
filled: true,
|
filled: true,
|
||||||
fillColor: Colors.white,
|
fillColor: Colors.white,
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(5),
|
||||||
|
borderSide:
|
||||||
|
BorderSide(color: contentTheme.primary, width: 1.5),
|
||||||
|
),
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
borderSide: BorderSide(color: Colors.grey.shade300, width: 1),
|
borderSide: BorderSide(color: Colors.grey.shade300, width: 1),
|
||||||
|
@ -12,7 +12,6 @@ import 'package:marco/helpers/widgets/expense/expense_main_components.dart';
|
|||||||
import 'package:marco/helpers/utils/permission_constants.dart';
|
import 'package:marco/helpers/utils/permission_constants.dart';
|
||||||
import 'package:marco/helpers/widgets/my_refresh_indicator.dart';
|
import 'package:marco/helpers/widgets/my_refresh_indicator.dart';
|
||||||
|
|
||||||
|
|
||||||
class ExpenseMainScreen extends StatefulWidget {
|
class ExpenseMainScreen extends StatefulWidget {
|
||||||
const ExpenseMainScreen({super.key});
|
const ExpenseMainScreen({super.key});
|
||||||
|
|
||||||
@ -82,72 +81,75 @@ class _ExpenseMainScreenState extends State<ExpenseMainScreen>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
appBar: ExpenseAppBar(projectController: projectController),
|
appBar: ExpenseAppBar(projectController: projectController),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
// ---------------- TabBar ----------------
|
// ---------------- TabBar ----------------
|
||||||
Container(
|
Container(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
child: TabBar(
|
child: TabBar(
|
||||||
controller: _tabController,
|
controller: _tabController,
|
||||||
labelColor: Colors.black,
|
labelColor: Colors.black,
|
||||||
unselectedLabelColor: Colors.grey,
|
unselectedLabelColor: Colors.grey,
|
||||||
indicatorColor: Colors.red,
|
indicatorColor: Colors.red,
|
||||||
tabs: const [
|
tabs: const [
|
||||||
Tab(text: "Current Month"),
|
Tab(text: "Current Month"),
|
||||||
Tab(text: "History"),
|
Tab(text: "History"),
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
// ---------------- Gray background for rest ----------------
|
|
||||||
Expanded(
|
|
||||||
child: Container(
|
|
||||||
color: Colors.grey[100], // Light gray background
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
// ---------------- Search ----------------
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 0),
|
|
||||||
child: SearchAndFilter(
|
|
||||||
controller: searchController,
|
|
||||||
onChanged: (_) => setState(() {}),
|
|
||||||
onFilterTap: _openFilterBottomSheet,
|
|
||||||
expenseController: expenseController,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
// ---------------- TabBarView ----------------
|
|
||||||
Expanded(
|
|
||||||
child: TabBarView(
|
|
||||||
controller: _tabController,
|
|
||||||
children: [
|
|
||||||
_buildExpenseList(isHistory: false),
|
|
||||||
_buildExpenseList(isHistory: true),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
|
|
||||||
floatingActionButton:
|
// ---------------- Gray background for rest ----------------
|
||||||
permissionController.hasPermission(Permissions.expenseUpload)
|
Expanded(
|
||||||
? FloatingActionButton(
|
child: Container(
|
||||||
backgroundColor: Colors.red,
|
color: Colors.grey[100], // Light gray background
|
||||||
onPressed: showAddExpenseBottomSheet,
|
child: Column(
|
||||||
child: const Icon(Icons.add, color: Colors.white),
|
children: [
|
||||||
)
|
// ---------------- Search ----------------
|
||||||
: null,
|
Padding(
|
||||||
);
|
padding:
|
||||||
}
|
const EdgeInsets.symmetric(horizontal: 0, vertical: 0),
|
||||||
|
child: SearchAndFilter(
|
||||||
|
controller: searchController,
|
||||||
|
onChanged: (_) => setState(() {}),
|
||||||
|
onFilterTap: _openFilterBottomSheet,
|
||||||
|
expenseController: expenseController,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// ---------------- TabBarView ----------------
|
||||||
|
Expanded(
|
||||||
|
child: TabBarView(
|
||||||
|
controller: _tabController,
|
||||||
|
children: [
|
||||||
|
_buildExpenseList(isHistory: false),
|
||||||
|
_buildExpenseList(isHistory: true),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
floatingActionButton:
|
||||||
|
permissionController.hasPermission(Permissions.expenseUpload)
|
||||||
|
? FloatingActionButton.extended(
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
onPressed: showAddExpenseBottomSheet,
|
||||||
|
icon: const Icon(Icons.add, color: Colors.white),
|
||||||
|
label: const Text(
|
||||||
|
"Create New Expense",
|
||||||
|
style: TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildExpenseList({required bool isHistory}) {
|
Widget _buildExpenseList({required bool isHistory}) {
|
||||||
return Obx(() {
|
return Obx(() {
|
||||||
@ -197,4 +199,3 @@ Widget build(BuildContext context) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,8 +194,8 @@ class _UserProfileBarState extends State<UserProfileBar>
|
|||||||
_menuItemRow(
|
_menuItemRow(
|
||||||
icon: LucideIcons.lock,
|
icon: LucideIcons.lock,
|
||||||
label: hasMpin ? 'Change MPIN' : 'Set MPIN',
|
label: hasMpin ? 'Change MPIN' : 'Set MPIN',
|
||||||
iconColor: Colors.redAccent,
|
iconColor: contentTheme.primary,
|
||||||
textColor: Colors.redAccent,
|
textColor: contentTheme.primary,
|
||||||
onTap: _onMpinTap,
|
onTap: _onMpinTap,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -281,8 +281,8 @@ class _UserProfileBarState extends State<UserProfileBar>
|
|||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
shadowColor: Colors.red.shade200,
|
shadowColor: Colors.red.shade200,
|
||||||
padding: EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
vertical: condensed ? 14 : 18,
|
vertical: condensed ? 9 : 12,
|
||||||
horizontal: condensed ? 14 : 22,
|
horizontal: condensed ? 6 : 16,
|
||||||
),
|
),
|
||||||
shape:
|
shape:
|
||||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
|
RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user