step 5 : transaksi page

This commit is contained in:
sindhu
2024-01-12 17:22:15 +07:00
parent f323df9f0f
commit 81c9fc6034
6 changed files with 351 additions and 9 deletions

View File

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

View File

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

View File

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

View File

@@ -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>(
DummyDropdownTipe(
"",
0,
),
);
final dropdownItemsKategori = useState<List<DummyDropdownTipe>>(
List.empty(
growable: true,
),
);
final radioButtonItems =
useState<List<DummyRadioTipe>>(List.empty(growable: true));
final selectedRadio = useState<DummyRadioTipe>(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<DummyDropdownTipe>(
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<DummyDropdownTipe>(
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<double>(6),
thumbVisibility: MaterialStateProperty.all<bool>(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<DummyRadioTipe>(
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,
),
],
),
),
),
);
}
}
}

View File

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

View File

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