diff --git a/app_petty_cash/lib/app/route.dart b/app_petty_cash/lib/app/route.dart index 40cbf2f..4e18eba 100644 --- a/app_petty_cash/lib/app/route.dart +++ b/app_petty_cash/lib/app/route.dart @@ -1,4 +1,5 @@ import 'package:app_petty_cash/screen/home/home_screen.dart'; +import 'package:app_petty_cash/screen/transaksi/transaksi_screen.dart'; import 'package:flutter/material.dart'; import '../screen/login/login_screen.dart'; @@ -8,6 +9,7 @@ const loginRoute = "/loginRoute"; const menuRoute = "/menuRoute"; const splashScreen = "/splashScreen"; const homeRoute = "/homeRoute"; +const transaksiRoute = "/transaksiRoute"; class AppRoute { static Route generateRoute(RouteSettings settings) { @@ -25,7 +27,7 @@ class AppRoute { } // home screen - if (settings.name == homeRoute) { + if (settings.name == homeRoute) { return MaterialPageRoute(builder: (context) { return MediaQuery( data: MediaQuery.of(context).copyWith( @@ -37,6 +39,19 @@ class AppRoute { }); } + // tansaksi screen + if (settings.name == transaksiRoute) { + return MaterialPageRoute(builder: (context) { + return MediaQuery( + data: MediaQuery.of(context).copyWith( + textScaleFactor: 1.0, + padding: EdgeInsets.all(0), + ), + child: TransaksiScreen(), + ); + }); + } + // default return MaterialPageRoute(builder: (context) { return MediaQuery( diff --git a/app_petty_cash/lib/main.dart b/app_petty_cash/lib/main.dart index 6413458..6a68a03 100644 --- a/app_petty_cash/lib/main.dart +++ b/app_petty_cash/lib/main.dart @@ -5,7 +5,9 @@ import 'app/route.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); - runApp(const ProviderScope(child: MyApp())); + runApp( + const ProviderScope(child: MyApp()), + ); } class MyApp extends StatelessWidget { @@ -28,8 +30,9 @@ class MyApp extends StatelessWidget { ), debugShowCheckedModeBanner: false, // initialRoute: loginRoute, - initialRoute: splashScreen, + // initialRoute: splashScreen, + initialRoute: transaksiRoute, onGenerateRoute: AppRoute.generateRoute, ); } -} \ No newline at end of file +} diff --git a/app_petty_cash/lib/screen/login/custom_text_field.dart b/app_petty_cash/lib/screen/login/custom_text_field.dart index 0422ca8..15cb401 100644 --- a/app_petty_cash/lib/screen/login/custom_text_field.dart +++ b/app_petty_cash/lib/screen/login/custom_text_field.dart @@ -132,6 +132,7 @@ class CustomTextField extends StatelessWidget { final bool isError; final bool isTextArea; final bool isReadOnly; + final bool isNumber; const CustomTextField( {Key? key, @@ -148,7 +149,9 @@ class CustomTextField extends StatelessWidget { this.isPrefix = false, this.isTextArea = false, this.isError = false, - this.isReadOnly = false}) + this.isReadOnly = false, + this.isNumber = false + }) : super(key: key); @override @@ -162,6 +165,7 @@ class CustomTextField extends StatelessWidget { onSubmitted: onSubmitted, focusNode: focusNode, maxLines: (isTextArea) ? 4 : 1, + keyboardType: (isNumber) ? TextInputType.number : TextInputType.text, decoration: InputDecoration( // focusedBorder: OutlineInputBorder( // borderSide: BorderSide(color: Constant.textGrey, width: 1), diff --git a/app_petty_cash/lib/screen/transaksi/transaksi_screen.dart b/app_petty_cash/lib/screen/transaksi/transaksi_screen.dart index 05eb5d5..1be8953 100644 --- a/app_petty_cash/lib/screen/transaksi/transaksi_screen.dart +++ b/app_petty_cash/lib/screen/transaksi/transaksi_screen.dart @@ -1,10 +1,304 @@ +import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; -class TransaksiScreen extends StatelessWidget { +import '../../app/constant.dart'; +import '../login/custom_text_field.dart'; + +class DummyDropdownTipe { + final String options; + final int id; + + DummyDropdownTipe( + this.options, + this.id, + ); +} + +class DummyRadioTipe { + final String text; + final int id; + + DummyRadioTipe(this.text, this.id); +} + +class TransaksiScreen extends HookConsumerWidget { const TransaksiScreen({super.key}); @override - Widget build(BuildContext context) { - return const Placeholder(); + Widget build(BuildContext context, WidgetRef ref) { + final ctrlJumlah = useTextEditingController(text: ""); + final ctrlCatatan = useTextEditingController(text: ""); + + final selectedDropdownKategori = useState( + DummyDropdownTipe( + "", + 0, + ), + ); + final dropdownItemsKategori = useState>( + List.empty( + growable: true, + ), + ); + + final radioButtonItems = + useState>(List.empty(growable: true)); + final selectedRadio = useState(DummyRadioTipe("", 0)); + + useEffect(() { + dropdownItemsKategori.value = [ + DummyDropdownTipe("Pengantaran Hasil", 1), + DummyDropdownTipe("Pengambilan Bahan", 2), + DummyDropdownTipe("Lain-lain", 3), + ]; + + // selectedDropdownKategori.value = dropdownItemsKategori.value[input]; + selectedDropdownKategori.value = dropdownItemsKategori.value[0]; + radioButtonItems.value = [ + DummyRadioTipe( + "Debit", + 1, + ), + DummyRadioTipe( + "Kredit", + 2, + ), + ]; + + selectedRadio.value = radioButtonItems.value[0]; + }, []); + + final isMounted = useIsMounted(); + + return Scaffold( + appBar: AppBar( + title: Text('Transaksi'), + ), + body: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.all(20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Kategori', + style: Constant.body1(context: context).copyWith( + fontWeight: FontWeight.w600, color: Constant.textBlack), + ), + SizedBox( + height: Constant.getActualYPhone(context: context, y: 10), + ), + // Dropdown kategori + SizedBox( + width: Constant.getActualXPhone(context: context, x: 390), + child: DropdownButtonHideUnderline( + child: DropdownButton2( + isExpanded: true, + hint: Row( + children: [ + Expanded( + child: Text( + 'Select Item', + style: Constant.body1(context: context).copyWith( + fontWeight: FontWeight.w600, + color: Constant.textBlack), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + items: dropdownItemsKategori.value + .map((DummyDropdownTipe option) { + return DropdownMenuItem( + value: option, + child: Text( + option.options, + style: Constant.body1(context: context).copyWith( + color: Constant.textBlack, + fontWeight: FontWeight.w600), + ), + ); + }).toList(), + value: selectedDropdownKategori.value, + onChanged: (DummyDropdownTipe? newValue) { + // if (newValue) { + selectedDropdownKategori.value = newValue!; + print(selectedDropdownKategori.value.id); + // } + }, + buttonStyleData: ButtonStyleData( + height: Constant.getActualY(context: context, y: 56), + width: Constant.getActualX(context: context, x: 320), + padding: EdgeInsets.only( + left: Constant.getActualX(context: context, x: 10), + right: Constant.getActualX(context: context, x: 10), + ), + decoration: BoxDecoration( + color: Constant.white, + border: Border.all(color: Constant.textBlack, width: 1), + borderRadius: BorderRadius.circular(8), + ), + elevation: 2, + ), + iconStyleData: IconStyleData( + icon: Icon( + Icons.keyboard_arrow_down_outlined, + ), + iconSize: 24, + iconEnabledColor: Constant.textBlack, + iconDisabledColor: Colors.grey, + ), + dropdownStyleData: DropdownStyleData( + maxHeight: Constant.getActualY(context: context, y: 200), + // width: Constant.getActualX(context: context, x: 320), + padding: EdgeInsets.only( + top: Constant.getActualY(context: context, y: 10), + left: Constant.getActualX(context: context, x: 10), + right: Constant.getActualX(context: context, x: 10), + bottom: Constant.getActualY(context: context, y: 10), + ), + decoration: BoxDecoration( + color: Constant.white, + borderRadius: BorderRadius.circular(8), + boxShadow: [ + BoxShadow( + color: Colors.grey, + blurRadius: 20.0, + spreadRadius: 2.0, + offset: Offset(0.0, 0.0), + ), + ], + ), + elevation: 8, + offset: const Offset(0, -10), + scrollbarTheme: ScrollbarThemeData( + radius: const Radius.circular(40), + thickness: MaterialStateProperty.all(6), + thumbVisibility: MaterialStateProperty.all(true), + ), + ), + menuItemStyleData: MenuItemStyleData( + height: Constant.getActualY(context: context, y: 56), + padding: EdgeInsets.only( + top: Constant.getActualY(context: context, y: 10), + left: Constant.getActualX(context: context, x: 10), + right: Constant.getActualX(context: context, x: 10), + ), + ), + ), + ), + ), + + SizedBox( + height: Constant.getActualYPhone(context: context, y: 20), + ), + + // jenis + Text( + 'Jenis', + style: Constant.body1(context: context).copyWith( + fontWeight: FontWeight.w600, color: Constant.textBlack), + ), + SizedBox( + height: Constant.getActualYPhone(context: context, y: 10), + ), + SizedBox( + width: Constant.getActualXPhone(context: context, x: 340), + height: Constant.getActualYPhone(context: context, y: 36), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + if (radioButtonItems.value.isEmpty) + Text('Radio Button Empty') + else + for (var i = 0; i < radioButtonItems.value.length; i++) + Padding( + padding: const EdgeInsets.only(right: 20), + child: Row( + children: [ + Radio( + activeColor: Constant.confirmed, + value: radioButtonItems.value[i], + groupValue: selectedRadio.value, + onChanged: (DummyRadioTipe? index) { + if (isMounted()) { + selectedRadio.value = index!; + } else { + return; + } + }, + ), + Text( + radioButtonItems.value[i].text, + style: + Constant.body1(context: context).copyWith( + color: Constant.textBlack, + fontWeight: FontWeight.w400, + ), + ), + ], + ), + ), + ], + ), + ), + + SizedBox( + height: Constant.getActualYPhone(context: context, y: 20), + ), + + // jumlah + Text( + 'Jumlah', + style: Constant.body1(context: context).copyWith( + fontWeight: FontWeight.w600, color: Constant.textBlack), + ), + SizedBox( + height: Constant.getActualYPhone(context: context, y: 20), + ), + CustomTextField( + isNumber: true, + isReadOnly: false, + ctrl: ctrlJumlah, + isPassword: false, + isMaxLine: false, + hintText: "Jumlah", + labelText: "Jumlah", + // onChange: (String searchResult) {}, + isPrefix: false, + ), + + SizedBox( + height: Constant.getActualYPhone(context: context, y: 20), + ), + + // catatan + Text( + 'Catatan', + style: Constant.body1(context: context).copyWith( + fontWeight: FontWeight.w600, color: Constant.textBlack), + ), + SizedBox( + height: Constant.getActualYPhone(context: context, y: 20), + ), + CustomTextField( + isNumber: false, + isReadOnly: false, + ctrl: ctrlCatatan, + isPassword: false, + isMaxLine: true, + isTextArea: true, + hintText: "Catatan", + labelText: "Catatan", + // onChange: (String searchResult) {}, + isPrefix: false, + ), + ], + ), + ), + ), + ); } -} \ No newline at end of file +} diff --git a/app_petty_cash/pubspec.lock b/app_petty_cash/pubspec.lock index 567d0f8..bdfc21c 100644 --- a/app_petty_cash/pubspec.lock +++ b/app_petty_cash/pubspec.lock @@ -57,6 +57,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.6" + dropdown_button2: + dependency: "direct main" + description: + name: dropdown_button2 + sha256: b0fe8d49a030315e9eef6c7ac84ca964250155a6224d491c1365061bc974a9e1 + url: "https://pub.dev" + source: hosted + version: "2.3.9" equatable: dependency: "direct main" description: @@ -97,6 +105,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + file_picker: + dependency: "direct main" + description: + name: file_picker + sha256: "4e42aacde3b993c5947467ab640882c56947d9d27342a5b6f2895b23956954a6" + url: "https://pub.dev" + source: hosted + version: "6.1.1" flutter: dependency: "direct main" description: flutter @@ -118,6 +134,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da + url: "https://pub.dev" + source: hosted + version: "2.0.17" flutter_riverpod: dependency: "direct main" description: diff --git a/app_petty_cash/pubspec.yaml b/app_petty_cash/pubspec.yaml index 77c1dbf..8c96efa 100644 --- a/app_petty_cash/pubspec.yaml +++ b/app_petty_cash/pubspec.yaml @@ -44,6 +44,8 @@ dependencies: fancy_bottom_navigation_2: ^0.3.5 intl: ^0.17.0 permission_handler: ^10.2.0 + dropdown_button2: ^2.1.3 + file_picker: ^6.1.1 dev_dependencies: flutter_test: