diff --git a/lib/core/utils/guide.dart b/lib/core/utils/guide.dart index 33eee63..0290a24 100644 --- a/lib/core/utils/guide.dart +++ b/lib/core/utils/guide.dart @@ -24,10 +24,10 @@ FontWeight superBold = FontWeight.w900; // =====================text behavior===================== class Tulisan { - static TextStyle heading({Color? color}) { + static TextStyle heading({Color? color, double? fontsize}) { return GoogleFonts.spaceGrotesk( - fontSize: 24.sp, - fontWeight: FontWeight.bold, + fontSize: fontsize?.sp ?? 24.sp, + fontWeight: extraBold, color: color ?? blackNavyColor, ); } @@ -35,7 +35,7 @@ class Tulisan { static TextStyle body({Color? color, double? fontsize}) { return GoogleFonts.spaceMono( fontSize: fontsize?.sp ?? 16.sp, - fontWeight: FontWeight.w400, + fontWeight: regular, color: color ?? blackNavyColor, ); } @@ -43,7 +43,7 @@ class Tulisan { static TextStyle subheading({Color? color, double? fontsize}) { return GoogleFonts.spaceGrotesk( fontSize: fontsize?.sp ?? 18.sp, - fontWeight: FontWeight.w500, + fontWeight: medium, color: color ?? blackNavyColor, ); } @@ -55,7 +55,7 @@ class Tulisan { }) { return GoogleFonts.spaceGrotesk( fontSize: fontsize?.sp ?? 16.sp, - fontWeight: fontWeight ?? FontWeight.w400, + fontWeight: fontWeight ?? regular, color: color ?? blackNavyColor, ); } diff --git a/lib/features/activity/presentation/screen/activity_screen.dart b/lib/features/activity/presentation/screen/activity_screen.dart index 61b476d..4ba52fd 100644 --- a/lib/features/activity/presentation/screen/activity_screen.dart +++ b/lib/features/activity/presentation/screen/activity_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:rijig_mobile/core/utils/guide.dart'; import 'package:rijig_mobile/widget/tabbar_custom.dart'; +import 'package:rijig_mobile/widget/unhope_handler.dart'; class ActivityScreen extends StatefulWidget { const ActivityScreen({super.key}); @@ -49,11 +50,11 @@ class _ActivityScreenState extends State { ), ), ), - body: const TabBarView( + body: TabBarView( children: [ - Center(child: Text('Proses Page')), - Center(child: Text('Gak Eroh Page')), - Center(child: Text('Dibatalkan Page')), + Center(child: InfoStateWidget(type: InfoStateType.emptyData)), + Center(child: InfoStateWidget(type: InfoStateType.emptyData)), + Center(child: InfoStateWidget(type: InfoStateType.emptyData)), ], ), ), diff --git a/lib/features/home/presentation/screen/home_screen.dart b/lib/features/home/presentation/screen/home_screen.dart index 8babd01..6985d0f 100644 --- a/lib/features/home/presentation/screen/home_screen.dart +++ b/lib/features/home/presentation/screen/home_screen.dart @@ -13,7 +13,9 @@ import 'package:rijig_mobile/features/home/presentation/components/about_comp.da import 'package:rijig_mobile/features/home/presentation/components/article_list.dart'; import 'package:rijig_mobile/globaldata/about/about_vmod.dart'; import 'package:rijig_mobile/globaldata/article/article_vmod.dart'; +import 'package:rijig_mobile/widget/buttoncard.dart'; import 'package:rijig_mobile/widget/card_withicon.dart'; +import 'package:rijig_mobile/widget/showmodal.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @@ -98,7 +100,40 @@ class _HomeScreenState extends State { icon: Iconsax.timer, text: 'Process', number: '1', - onTap: () {}, + onTap: () { + CustomModalDialog.show( + context: context, + variant: ModalVariant.textVersion, + title: 'Hapus Akun', + content: + 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.', + buttonCount: 2, + button1: CardButtonOne( + textButton: "Ya, Hapus", + onTap: () {}, + fontSized: 14, + colorText: whiteColor, + color: primaryColor, + borderRadius: 10, + horizontal: double.infinity, + vertical: 50, + loadingTrue: false, + usingRow: false, + ), + button2: CardButtonOne( + textButton: "Batal", + onTap: () => router.pop(), + fontSized: 14, + colorText: primaryColor, + color: Colors.transparent, + borderRadius: 10, + horizontal: double.infinity, + vertical: 50, + loadingTrue: false, + usingRow: false, + ), + ); + }, ), ], ), diff --git a/lib/features/profil/components/logout_button.dart b/lib/features/profil/components/logout_button.dart index cf10570..67e9dc3 100644 --- a/lib/features/profil/components/logout_button.dart +++ b/lib/features/profil/components/logout_button.dart @@ -6,6 +6,7 @@ import 'package:rijig_mobile/core/router.dart'; import 'package:rijig_mobile/core/utils/guide.dart'; import 'package:rijig_mobile/features/auth/presentation/viewmodel/logout_vmod.dart'; import 'package:rijig_mobile/widget/buttoncard.dart'; +import 'package:rijig_mobile/widget/custom_bottom_sheet.dart'; class ButtonLogout extends StatefulWidget { const ButtonLogout({super.key}); @@ -29,17 +30,54 @@ class _ButtonLogoutState extends State { borderRadius: 10, horizontal: double.infinity, vertical: 50, - onTap: () async { - await viewModel.logout(); + onTap: + () => CustomBottomSheet.show( + context: context, + title: "Logout Sekarang?", + content: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Yakin ingin logout dari akun ini?"), + // tambahan konten + ], + ), + button1: CardButtonOne( + textButton: "Logout", + onTap: () {}, + fontSized: 14, + colorText: Colors.white, + color: Colors.red, + borderRadius: 10, + horizontal: double.infinity, + vertical: 50, + loadingTrue: false, + usingRow: false, + ), + button2: CardButtonOne( + textButton: "Batal", + onTap: () => router.pop(), + fontSized: 14, + colorText: Colors.red, + color: Colors.white, + borderRadius: 10, + horizontal: double.infinity, + vertical: 50, + loadingTrue: false, + usingRow: false, + ), + ), - if (viewModel.errorMessage == null) { - router.go("/login"); - } else { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(viewModel.errorMessage!)), - ); - } - }, + // onTap: () async { + // await viewModel.logout(); + + // if (viewModel.errorMessage == null) { + // router.go("/login"); + // } else { + // ScaffoldMessenger.of(context).showSnackBar( + // SnackBar(content: Text(viewModel.errorMessage!)), + // ); + // } + // }, loadingTrue: viewModel.isLoading, usingRow: false, ), diff --git a/lib/widget/custom_bottom_sheet.dart b/lib/widget/custom_bottom_sheet.dart new file mode 100644 index 0000000..1d4c36e --- /dev/null +++ b/lib/widget/custom_bottom_sheet.dart @@ -0,0 +1,92 @@ +import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; +import 'package:rijig_mobile/core/router.dart'; +import 'package:rijig_mobile/core/utils/guide.dart'; + +class CustomBottomSheet extends StatelessWidget { + final String title; + final Widget content; + final Widget button1; + final Widget? button2; + + const CustomBottomSheet({ + super.key, + required this.title, + required this.content, + required this.button1, + this.button2, + }); + + static void show({ + required BuildContext context, + required String title, + required Widget content, + required Widget button1, + Widget? button2, + Duration duration = const Duration(milliseconds: 380), + }) { + showModalBottomSheet( + context: context, + isScrollControlled: true, + backgroundColor: Colors.transparent, + transitionAnimationController: AnimationController( + vsync: Navigator.of(context), + duration: duration, + ), + builder: (context) { + return CustomBottomSheet( + title: title, + content: content, + button1: button1, + button2: button2, + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + return Stack( + clipBehavior: Clip.none, + children: [ + Container( + padding: PaddingCustom().paddingAll(15), + margin: const EdgeInsets.only(top: 30), + decoration: BoxDecoration( + color: whiteColor, + borderRadius: const BorderRadius.vertical(top: Radius.circular(15)), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(title, style: Tulisan.subheading(fontsize: 20)), + const Gap(12), + content, + const Gap(24), + if (button2 != null) + Column(children: [button1, const Gap(12), button2!]) + else + button1, + ], + ), + ), + Positioned( + top: -25, + right: 5, + child: GestureDetector( + onTap: () => router.pop(), + child: Container( + padding: PaddingCustom().paddingAll(10), + decoration: BoxDecoration( + color: whiteColor, + shape: BoxShape.circle, + ), + child: const Icon(Icons.close, size: 25), + ), + ), + ), + ], + ); + } +} diff --git a/lib/widget/showmodal.dart b/lib/widget/showmodal.dart new file mode 100644 index 0000000..f0a491c --- /dev/null +++ b/lib/widget/showmodal.dart @@ -0,0 +1,140 @@ +import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; +import 'package:rijig_mobile/core/router.dart'; +import 'package:rijig_mobile/core/utils/guide.dart'; + +enum ModalVariant { textVersion, imageVersion } + +class CustomModalDialog extends StatelessWidget { + final ModalVariant variant; + + final String title; + final String content; + final String? imageAsset; + + final int buttonCount; + final Widget? button1; + final Widget? button2; + + const CustomModalDialog({ + super.key, + required this.variant, + required this.title, + required this.content, + this.imageAsset, + this.buttonCount = 0, + this.button1, + this.button2, + }); + + static void show({ + required BuildContext context, + required ModalVariant variant, + required String title, + required String content, + String? imageAsset, + int buttonCount = 0, + Widget? button1, + Widget? button2, + }) { + showGeneralDialog( + context: context, + barrierDismissible: true, + barrierLabel: 'Dismiss', + barrierColor: Colors.black54, + transitionDuration: const Duration(milliseconds: 190), + pageBuilder: (_, __, ___) => const SizedBox.shrink(), + transitionBuilder: (_, animation, __, child) { + return Transform.scale( + scale: animation.value, + child: Opacity( + opacity: animation.value, + child: Center( + child: Dialog( + backgroundColor: Colors.transparent, + insetPadding: const EdgeInsets.symmetric( + horizontal: 24, + vertical: 24, + ), + child: CustomModalDialog( + variant: variant, + title: title, + content: content, + imageAsset: imageAsset, + buttonCount: buttonCount, + button1: button1, + button2: button2, + ), + ), + ), + ), + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + final modalContent = Container( + padding: PaddingCustom().paddingHorizontalVertical(20, 24), + margin: const EdgeInsets.only(top: 30), + decoration: BoxDecoration( + color: whiteColor, + borderRadius: BorderRadius.circular(24), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (variant == ModalVariant.imageVersion && imageAsset != null) + Padding( + padding: PaddingCustom().paddingOnly(bottom: 20), + child: Image.asset( + imageAsset!, + width: MediaQuery.of(context).size.width * 0.6, + fit: BoxFit.contain, + ), + ), + Align( + alignment: Alignment.centerLeft, + child: Text(title, style: Tulisan.subheading(fontsize: 19)), + ), + Gap(8), + Align( + alignment: Alignment.centerLeft, + child: Text(content, style: Tulisan.customText(fontsize: 14)), + ), + Gap(24), + if (buttonCount == 1 && button1 != null) button1!, + if (buttonCount == 2 && button1 != null && button2 != null) + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Expanded(child: button2!), + Gap(16), + Expanded(child: button1!), + ], + ), + ], + ), + ); + + return Stack( + clipBehavior: Clip.none, + children: [ + modalContent, + Positioned( + top: -15, + right: 5, + child: GestureDetector( + onTap: () => router.pop(), + child: CircleAvatar( + radius: 18, + backgroundColor: whiteColor, + child: Icon(Icons.close, color: blackNavyColor), + ), + ), + ), + ], + ); + } +} diff --git a/lib/widget/unhope_handler.dart b/lib/widget/unhope_handler.dart new file mode 100644 index 0000000..6f6e01a --- /dev/null +++ b/lib/widget/unhope_handler.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; + +enum InfoStateType { dataNotFound, emptyData, comingSoon } + +class InfoStateWidget extends StatelessWidget { + final InfoStateType type; + final String? imageAsset; + final String? description; + + const InfoStateWidget({ + super.key, + required this.type, + this.imageAsset, + this.description, + }); + + String _getDefaultDescription() { + switch (type) { + case InfoStateType.dataNotFound: + return 'Data tidak ditemukan'; + case InfoStateType.emptyData: + return 'Belum ada data yang tersedia'; + case InfoStateType.comingSoon: + return 'Fitur ini segera hadir'; + } + } + + String _getDefaultImageAsset() { + switch (type) { + case InfoStateType.dataNotFound: + return 'assets/image/empty_data.png'; + case InfoStateType.emptyData: + return 'assets/image/empty_data.png'; + case InfoStateType.comingSoon: + return 'assets/image/empty_data.png'; + } + } + + @override + Widget build(BuildContext context) { + final screenWidth = MediaQuery.of(context).size.width; + final screenHeight = MediaQuery.of(context).size.height; + + return Center( + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Image.asset( + imageAsset ?? _getDefaultImageAsset(), + width: screenWidth * 0.5, + height: screenHeight * 0.3, + fit: BoxFit.contain, + ), + const SizedBox(height: 20), + Text( + description ?? _getDefaultDescription(), + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.bodyMedium, + ), + ], + ), + ), + ); + } +}