step 5 : transaksi page
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import 'package:app_petty_cash/screen/home/home_screen.dart';
|
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 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../screen/login/login_screen.dart';
|
import '../screen/login/login_screen.dart';
|
||||||
@@ -8,6 +9,7 @@ const loginRoute = "/loginRoute";
|
|||||||
const menuRoute = "/menuRoute";
|
const menuRoute = "/menuRoute";
|
||||||
const splashScreen = "/splashScreen";
|
const splashScreen = "/splashScreen";
|
||||||
const homeRoute = "/homeRoute";
|
const homeRoute = "/homeRoute";
|
||||||
|
const transaksiRoute = "/transaksiRoute";
|
||||||
|
|
||||||
class AppRoute {
|
class AppRoute {
|
||||||
static Route<dynamic> generateRoute(RouteSettings settings) {
|
static Route<dynamic> generateRoute(RouteSettings settings) {
|
||||||
@@ -25,7 +27,7 @@ class AppRoute {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// home screen
|
// home screen
|
||||||
if (settings.name == homeRoute) {
|
if (settings.name == homeRoute) {
|
||||||
return MaterialPageRoute(builder: (context) {
|
return MaterialPageRoute(builder: (context) {
|
||||||
return MediaQuery(
|
return MediaQuery(
|
||||||
data: MediaQuery.of(context).copyWith(
|
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
|
// default
|
||||||
return MaterialPageRoute(builder: (context) {
|
return MaterialPageRoute(builder: (context) {
|
||||||
return MediaQuery(
|
return MediaQuery(
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ import 'app/route.dart';
|
|||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
runApp(const ProviderScope(child: MyApp()));
|
runApp(
|
||||||
|
const ProviderScope(child: MyApp()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
@@ -28,8 +30,9 @@ class MyApp extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
// initialRoute: loginRoute,
|
// initialRoute: loginRoute,
|
||||||
initialRoute: splashScreen,
|
// initialRoute: splashScreen,
|
||||||
|
initialRoute: transaksiRoute,
|
||||||
onGenerateRoute: AppRoute.generateRoute,
|
onGenerateRoute: AppRoute.generateRoute,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ class CustomTextField extends StatelessWidget {
|
|||||||
final bool isError;
|
final bool isError;
|
||||||
final bool isTextArea;
|
final bool isTextArea;
|
||||||
final bool isReadOnly;
|
final bool isReadOnly;
|
||||||
|
final bool isNumber;
|
||||||
|
|
||||||
const CustomTextField(
|
const CustomTextField(
|
||||||
{Key? key,
|
{Key? key,
|
||||||
@@ -148,7 +149,9 @@ class CustomTextField extends StatelessWidget {
|
|||||||
this.isPrefix = false,
|
this.isPrefix = false,
|
||||||
this.isTextArea = false,
|
this.isTextArea = false,
|
||||||
this.isError = false,
|
this.isError = false,
|
||||||
this.isReadOnly = false})
|
this.isReadOnly = false,
|
||||||
|
this.isNumber = false
|
||||||
|
})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -162,6 +165,7 @@ class CustomTextField extends StatelessWidget {
|
|||||||
onSubmitted: onSubmitted,
|
onSubmitted: onSubmitted,
|
||||||
focusNode: focusNode,
|
focusNode: focusNode,
|
||||||
maxLines: (isTextArea) ? 4 : 1,
|
maxLines: (isTextArea) ? 4 : 1,
|
||||||
|
keyboardType: (isNumber) ? TextInputType.number : TextInputType.text,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
// focusedBorder: OutlineInputBorder(
|
// focusedBorder: OutlineInputBorder(
|
||||||
// borderSide: BorderSide(color: Constant.textGrey, width: 1),
|
// borderSide: BorderSide(color: Constant.textGrey, width: 1),
|
||||||
|
|||||||
@@ -1,10 +1,304 @@
|
|||||||
|
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||||
import 'package:flutter/material.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});
|
const TransaksiScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
return const Placeholder();
|
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,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.6"
|
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:
|
equatable:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -97,6 +105,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.0.0"
|
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:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -118,6 +134,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.3"
|
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:
|
flutter_riverpod:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ dependencies:
|
|||||||
fancy_bottom_navigation_2: ^0.3.5
|
fancy_bottom_navigation_2: ^0.3.5
|
||||||
intl: ^0.17.0
|
intl: ^0.17.0
|
||||||
permission_handler: ^10.2.0
|
permission_handler: ^10.2.0
|
||||||
|
dropdown_button2: ^2.1.3
|
||||||
|
file_picker: ^6.1.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
Reference in New Issue
Block a user