repair add makanan page, addes socket io client for real time update data, added table status change page

This commit is contained in:
kicap
2023-08-25 04:22:48 +08:00
parent 24cc3d3bd7
commit b3781eb831
33 changed files with 1233 additions and 349 deletions

View File

@ -0,0 +1,96 @@
import 'package:flutter/material.dart';
import 'package:reza_admin/app/themes/app_text.dart';
import 'package:reza_admin/ui/widgets/my_textformfield.dart';
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
import './add_edit_makanan_text_form_dialog_view_model.dart';
class AddEditMakananTextFormDialogView extends StatelessWidget {
final DialogRequest? request;
final Function(DialogResponse)? completer;
const AddEditMakananTextFormDialogView({
Key? key,
this.request,
this.completer,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ViewModelBuilder<AddEditMakananTextFormDialogViewModel>.reactive(
viewModelBuilder: () => AddEditMakananTextFormDialogViewModel(),
onViewModelReady: (AddEditMakananTextFormDialogViewModel model) async {
await model.init(request!.data);
},
builder: (
BuildContext context,
AddEditMakananTextFormDialogViewModel model,
Widget? child,
) {
return Dialog(
child: Container(
padding: const EdgeInsets.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
model.title,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 20),
MyTextFormField(
hintText: model.description,
maxLines: model.maxLines,
controller: model.textEditingController,
keyboardType: model.keyboardType
? TextInputType.number
: TextInputType.text,
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
completer!(DialogResponse(confirmed: false));
},
child: Text(
'Cancel',
style: boldTextStyle.copyWith(color: Colors.red),
),
),
TextButton(
onPressed: () {
if (model.textEditingController.text.isNotEmpty) {
completer!(DialogResponse(
confirmed: true,
data: model.textEditingController.text,
));
} else {
model.snackbarService.showSnackbar(
message: 'Please fill the form',
title: 'Error',
);
}
// completer!(DialogResponse(
// confirmed: true,
// responseData: model.status,
// ));
},
child: const Text('Save'),
),
],
),
],
),
),
);
},
);
}
}

View File

@ -0,0 +1,23 @@
import 'package:flutter/material.dart';
import '../../../../../../app/app.logger.dart';
import '../../../../../../app/core/custom_base_view_model.dart';
class AddEditMakananTextFormDialogViewModel extends CustomBaseViewModel {
final log = getLogger('AddEditMakananTextFormDialogViewModel');
late String title;
late String description;
late int maxLines;
late bool keyboardType;
TextEditingController textEditingController = TextEditingController();
Future<void> init(data) async {
log.i(data);
title = data['title'];
description = data['description'];
maxLines = data['maxLines'];
keyboardType = data['keyboardType'];
}
}

View File

@ -35,159 +35,187 @@ class AddEditMakananView extends HookWidget {
return true;
},
child: Scaffold(
backgroundColor: backgroundColor,
body: SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Stack(
children: [
ListView.builder(
controller: scrollController,
itemCount: 1,
itemBuilder: (context, index) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: MediaQuery.of(context).padding.top,
),
const TopMenuWidget(),
const SecondWidget(),
const SizedBox(
height: 10,
),
MyWhiteContainer(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: RichText(
text: TextSpan(
children: [
TextSpan(
text: 'Ongkos Kirim',
style: boldTextStyle.copyWith(
fontSize: 14,
),
backgroundColor: backgroundColor,
body: SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Stack(
children: [
ListView.builder(
controller: scrollController,
itemCount: 1,
itemBuilder: (context, index) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: MediaQuery.of(context).padding.top,
),
const TopMenuWidget(),
const SecondWidget(),
const SizedBox(
height: 10,
),
MyWhiteContainer(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: RichText(
text: TextSpan(
children: [
TextSpan(
text: 'Ongkos Kirim',
style: boldTextStyle.copyWith(
fontSize: 14,
),
TextSpan(
text: ' Harga Ongkir Di Sini',
style: boldTextStyle.copyWith(
fontSize: 14,
color: dangerColor,
fontStyle: FontStyle.italic,
),
),
TextSpan(
text: ' Rp. 10.000',
style: boldTextStyle.copyWith(
fontSize: 14,
color: dangerColor,
fontStyle: FontStyle.italic,
),
],
),
),
],
),
),
const SizedBox(
width: 10,
),
IconButton(
onPressed: () {},
icon: const Icon(
Icons.edit,
color: dangerColor,
),
iconSize: 20,
),
const SizedBox(
width: 10,
),
],
),
const SizedBox(
height: 10,
),
Text(
"Bisa Dibayar COD sekitar Parepare",
style: regularTextStyle.copyWith(
fontSize: 13,
color: fontGrey,
),
const SizedBox(
width: 10,
),
// IconButton(
// onPressed: () async {
// String? data =
// await model.addEditDialog(
// title: 'Ongkos Kirim',
// description: 'Harga Ongkir Di Sini',
// keyboardType: true,
// maxLines: 1,
// );
// // model.log.i('data: $data');
// model.hargaOngkir = data;
// model.notifyListeners();
// },
// icon: const Icon(
// Icons.edit,
// color: dangerColor,
// ),
// iconSize: 20,
// ),
const SizedBox(
width: 10,
),
],
),
const SizedBox(
height: 10,
),
Text(
"Bisa Dibayar COD sekitar Parepare",
style: regularTextStyle.copyWith(
fontSize: 13,
color: fontGrey,
),
],
),
),
],
),
),
const SizedBox(
height: 10,
),
MyWhiteContainer(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
"Deskripsi",
style: boldTextStyle.copyWith(
fontSize: 15,
),
),
const SizedBox(
height: 10,
),
MyWhiteContainer(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
"Deskripsi",
style: boldTextStyle.copyWith(
fontSize: 15,
),
),
const SizedBox(
width: 10,
),
IconButton(
onPressed: () {},
icon: const Icon(
Icons.edit,
color: mainGrey,
),
iconSize: 20,
),
const SizedBox(
width: 10,
),
],
),
const SizedBox(
height: 10,
),
// bikin dummy text tentang nasi goreng
Text(
"Deskripsi Makanan Di Sini",
style: regularTextStyle.copyWith(
fontSize: 13,
color: fontGrey,
fontStyle: FontStyle.italic,
),
textAlign: TextAlign.justify,
const SizedBox(
width: 10,
),
IconButton(
onPressed: () async {
String? data =
await model.addEditDialog(
title: 'Deskripsi',
description:
'Deskripsi Makanan Di Sini',
maxLines: 5);
// model.log.i('data: $data');
model.deskripsi = data;
model.notifyListeners();
},
icon: const Icon(
Icons.edit,
color: mainGrey,
),
iconSize: 20,
),
const SizedBox(
width: 10,
),
],
),
const SizedBox(
height: 10,
),
// bikin dummy text tentang nasi goreng
Text(
model.deskripsi ??
"Deskripsi Makanan Di Sini",
style: regularTextStyle.copyWith(
fontSize: 13,
color: fontGrey,
fontStyle: FontStyle.italic,
),
],
),
textAlign: TextAlign.justify,
),
],
),
),
const SizedBox(
height: 20,
),
],
);
},
),
TopBarWidget(opacity: opacity),
],
),
),
const SizedBox(
height: 20,
),
],
);
},
),
TopBarWidget(opacity: opacity),
],
),
bottomNavigationBar: Container(
),
bottomNavigationBar: GestureDetector(
onTap: () {
model.tambahEditMakanan();
},
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
@ -220,7 +248,9 @@ class AddEditMakananView extends HookWidget {
),
),
),
)),
),
),
),
);
},
);
@ -351,7 +381,7 @@ class SecondWidget extends ViewModelWidget<AddEditMakananViewModel> {
children: [
Expanded(
child: Text(
"Nama Makanan Di Sini",
viewModel.namaMakanan ?? 'Nama Makanan Di Sini',
style: regularTextStyle.copyWith(
fontSize: 17,
fontStyle: FontStyle.italic,
@ -362,7 +392,16 @@ class SecondWidget extends ViewModelWidget<AddEditMakananViewModel> {
width: 10,
),
IconButton(
onPressed: () {},
onPressed: () async {
String? data = await viewModel.addEditDialog(
title: 'Nama Makanan',
description: 'Nama Makanan Di Sini',
);
// viewModel.log.i('data: $data');
viewModel.namaMakanan = data;
viewModel.notifyListeners();
},
icon: const Icon(
Icons.edit,
color: mainGrey,
@ -392,7 +431,18 @@ class SecondWidget extends ViewModelWidget<AddEditMakananViewModel> {
width: 10,
),
IconButton(
onPressed: () {},
onPressed: () async {
String? data = await viewModel.addEditDialog(
title: 'Harga Makanan',
description: 'Harga Makanan Di Sini',
keyboardType: true,
maxLines: 1,
);
// viewModel.log.i('data: $data');
viewModel.hargaMakanan = data;
viewModel.notifyListeners();
},
icon: const Icon(
Icons.edit,
color: dangerColor,
@ -432,14 +482,19 @@ class TopMenuWidget extends ViewModelWidget<AddEditMakananViewModel> {
// 'https://a.cdn-hotels.com/gdcs/production0/d1513/35c1c89e-408c-4449-9abe-f109068f40c0.jpg?impolicy=fcrop&w=800&h=533&q=medium',
// fit: BoxFit.cover,
// ),
child: Center(
child: Text(
'Add Image',
style: boldTextStyle.copyWith(
fontSize: 20,
),
),
),
child: viewModel.imageBytes != null
? Image.memory(
viewModel.imageBytes!,
fit: BoxFit.cover,
)
: Center(
child: Text(
'Add Image',
style: boldTextStyle.copyWith(
fontSize: 20,
),
),
),
),
// Positioned(
// bottom: 10,
@ -468,21 +523,24 @@ class TopMenuWidget extends ViewModelWidget<AddEditMakananViewModel> {
Positioned(
bottom: 20,
right: 20,
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 5,
),
width: 50,
height: 50,
decoration: BoxDecoration(
color: mainColor,
borderRadius: BorderRadius.circular(10),
),
child: const Center(
child: Icon(
Icons.camera_alt_outlined,
color: Colors.white,
size: 30,
child: GestureDetector(
onTap: () => viewModel.addImage(),
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 5,
),
width: 50,
height: 50,
decoration: BoxDecoration(
color: mainColor,
borderRadius: BorderRadius.circular(10),
),
child: const Center(
child: Icon(
Icons.camera_alt_outlined,
color: Colors.white,
size: 30,
),
),
),
),

View File

@ -1,9 +1,105 @@
import 'dart:typed_data';
import 'package:dio/dio.dart';
import 'package:image_picker/image_picker.dart';
import '../../../../../app/app.dialogs.dart';
import '../../../../../app/app.logger.dart';
import '../../../../../app/core/custom_base_view_model.dart';
class AddEditMakananViewModel extends CustomBaseViewModel {
final log = getLogger('AddMakananViewModel');
String? namaMakanan;
String? hargaMakanan;
// String? hargaOngkir;
String? deskripsi;
String? _imagePath;
final ImagePicker _picker = ImagePicker();
XFile? imageFile;
Uint8List? imageBytes;
Future<void> init() async {
globalVar.backPressed = 'backNormal';
}
void addImage() async {
try {
final XFile? image = await _picker.pickImage(source: ImageSource.gallery);
if (image != null) {
imageFile = image;
_imagePath = image.path;
imageBytes = await image.readAsBytes();
log.i('image path: $_imagePath');
notifyListeners();
}
} catch (e) {
log.e(e);
}
}
Future<String?> addEditDialog(
{required String title,
required String description,
int maxLines = 2,
bool keyboardType = false}) async {
var res = await dialogService.showCustomDialog(
variant: DialogType.addEditMakananTextFormDialogView,
data: {
'title': title,
'description': description,
'maxLines': maxLines,
'keyboardType': keyboardType,
},
);
if (res!.confirmed) {
return res.data;
} else {
return null;
}
}
tambahEditMakanan() async {
if (namaMakanan == null ||
hargaMakanan == null ||
// hargaOngkir == null ||
deskripsi == null ||
imageFile == null) {
await dialogService.showDialog(
title: 'Error',
description: 'Semua field harus diisi',
);
} else {
easyLoading.customLoading('Tambah Makanan');
setBusy(true);
try {
var formData = FormData.fromMap({
'nama_makanan': namaMakanan,
'harga_makanan': hargaMakanan,
// 'harga_ongkir': hargaOngkir,
'deskripsi_makanan': deskripsi,
'image': await MultipartFile.fromFile(_imagePath!),
});
var res = await httpService.postWithFormData('table/makanan', formData);
log.i(res.data);
setBusy(false);
easyLoading.dismiss();
dialogService.showDialog(
title: 'Berhasil',
description: 'Makanan berhasil ditambahkan',
);
globalVar.backPressed = 'exitApp';
navigationService.back();
navigationService.back();
} catch (e) {
log.e(e);
} finally {
setBusy(false);
easyLoading.dismiss();
}
}
}
}

View File

@ -371,8 +371,8 @@ class TopMenuWidget extends ViewModelWidget<DetailMakananViewModel> {
SizedBox(
width: double.infinity,
height: MediaQuery.of(context).size.height * 0.35,
child: Image.network(
'https://a.cdn-hotels.com/gdcs/production0/d1513/35c1c89e-408c-4449-9abe-f109068f40c0.jpg?impolicy=fcrop&w=800&h=533&q=medium',
child: Image.asset(
'assets/nasi_goreng.jpg',
fit: BoxFit.cover,
),
),

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:reza_admin/app/app.router.dart';
import 'package:stacked/stacked.dart';
@ -141,66 +142,94 @@ class MakananListView extends StatelessWidget {
height: 10,
),
Expanded(
child: Center(
child: SingleChildScrollView(
child: Wrap(
spacing: 10,
runSpacing: 10,
children: [
for (var i = 0; i < 10; i++)
GestureDetector(
onTap: () => model.goToDetailMakanan(),
child: Container(
width: MediaQuery.of(context).size.width * 0.46,
color: Colors.white,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
'https://a.cdn-hotels.com/gdcs/production0/d1513/35c1c89e-408c-4449-9abe-f109068f40c0.jpg?impolicy=fcrop&w=800&h=533&q=medium',
height: 150,
width: double.infinity,
fit: BoxFit.fill,
),
const SizedBox(
height: 5,
),
const Padding(
padding: EdgeInsets.only(
left: 5,
),
child: Text(
'Product Name',
style: TextStyle(
fontWeight: FontWeight.bold,
child: model.isBusy
? const Center(
child: CircularProgressIndicator(),
)
: (model.listMakanan.isEmpty
? const Center(
child: Text('Data Kosong'),
)
: SingleChildScrollView(
child: Wrap(
spacing: 5,
runSpacing: 10,
// alignment: WrapAlignment.spaceAround,
// crossAxisAlignment: WrapCrossAlignment.center,
children: [
for (var i = 0;
i < model.listMakanan.length;
i++)
GestureDetector(
onTap: () => model.goToDetailMakanan(),
child: Padding(
padding: const EdgeInsets.only(
left: 10,
// right: 5,
),
child: Container(
width: MediaQuery.of(context)
.size
.width *
0.46,
color: Colors.white,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Image.network(
'${dotenv.env['url']}assets/makanan/${model.listMakanan[i].imgUrl}',
height: 150,
width: double.infinity,
fit: BoxFit.fill,
),
// Image.asset(
// 'assets/nasi_goreng.jpg',
// height: 150,
// width: double.infinity,
// fit: BoxFit.fill,
// ),
const SizedBox(
height: 5,
),
Padding(
padding: const EdgeInsets.only(
left: 5,
),
child: Text(
model.listMakanan[i]
.namaMakanan!,
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(
height: 5,
),
Padding(
padding: const EdgeInsets.only(
left: 5,
),
child: Text(
model.listMakanan[i]
.deskripsiMakanan!,
style: const TextStyle(
color: Colors.grey,
),
),
),
const SizedBox(
height: 5,
),
],
),
),
),
),
const SizedBox(
height: 5,
),
const Padding(
padding: EdgeInsets.only(
left: 5,
),
child: Text(
'Rp. 100.000',
style: TextStyle(
color: Colors.grey,
),
),
),
const SizedBox(
height: 5,
),
],
),
],
),
),
],
),
),
),
)),
),
],
),

View File

@ -1,11 +1,46 @@
import 'package:reza_admin/model/makanan_model.dart';
import 'package:reza_admin/model/my_model.dart';
import '../../../../app/app.locator.dart';
import '../../../../app/app.logger.dart';
import '../../../../app/app.router.dart';
import '../../../../app/core/custom_base_view_model.dart';
import '../../../../services/my_socket_io_client.dart';
class MakananListViewModel extends CustomBaseViewModel {
final log = getLogger('MakananListViewModel');
final socketIoClient = locator<MySocketIoClient>();
List<MakananModel> listMakanan = [];
Future<void> init() async {
globalVar.backPressed = 'exitApp';
getData();
socketIoClient.on('makanan_user', (data) {
log.i('data : $data');
listMakanan.clear();
getData();
// webViewController!.reload();
});
}
getData() async {
setBusy(true);
easyLoading.showLoading();
try {
var res = await httpService.get('table/makanan');
MyModel myModel = MyModel.fromJson(res.data);
if (myModel.data.length > 0) {
for (var item in myModel.data) {
listMakanan.add(MakananModel.fromJson(item));
}
}
log.i(listMakanan);
} catch (e) {
log.e(e.toString());
} finally {
easyLoading.dismiss();
setBusy(false);
}
}
goToDetailMakanan() {