finish caleg, area and tim survei page

This commit is contained in:
kicap
2023-10-26 16:05:01 +08:00
parent 364bee3120
commit 85be29e7ce
24 changed files with 1100 additions and 228 deletions

View File

@ -1,8 +1,8 @@
import 'package:cek_suara/app/themes/app_text.dart';
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import '../../../../app/themes/app_colors.dart';
import '../../../../app/themes/app_text.dart';
import '../../../widgets/top_container.dart';
import './halaman_caleg_view_model.dart';
@ -71,40 +71,58 @@ class HalamanCalegView extends StatelessWidget {
),
if (!model.isBusy &&
model.listCalegModel.isNotEmpty)
Expanded(
child: SingleChildScrollView(
child: Column(
children: [
for (var i = 0;
i < model.jumlahCaleg;
i++)
Card(
child: ListTile(
leading: Text('${i + 1}'),
title: Text(
model
.listCalegModel[i].namaCaleg!,
style: boldTextStyle,
),
subtitle: Text(
'No. Urut: ${model.listCalegModel[i].nomorUrutCaleg!}',
style: italicTextStyle,
),
trailing: IconButton(
icon: const Icon(Icons.edit,
color: mainColor),
onPressed: () {},
),
SingleChildScrollView(
child: Column(
children: [
for (var i = 0; i < model.jumlahCaleg; i++)
Card(
child: ListTile(
leading: Text('${i + 1}'),
title: Text(
model.listCalegModel[i].namaCaleg!,
style: boldTextStyle,
),
subtitle: Text(
'No. Urut: ${model.listCalegModel[i].nomorUrutCaleg!}',
style: italicTextStyle,
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(
Icons.info_outline,
color: mainColor,
),
onPressed: () {
model.showDetailCaleg(
model.listCalegModel[i]);
},
),
IconButton(
icon: const Icon(
// trash
Icons.delete_outline,
color: dangerColor,
),
onPressed: () {
model.deleteCaleg(
model.listCalegModel[i]);
},
),
],
),
),
],
),
),
],
),
),
if (!model.isBusy && model.listCalegModel.isEmpty)
const Center(
Center(
child: Text(
'Tidak ada data caleg diinput sebelumnya',
model.status == true
? 'Tidak ada data caleg diinput sebelumnya'
: 'Gagal mengambil data caleg',
style: italicTextStyle,
textAlign: TextAlign.center,
),

View File

@ -1,3 +1,5 @@
import 'package:cek_suara/app/themes/app_colors.dart';
import '../../../../app/app.dialogs.dart';
import '../../../../app/app.logger.dart';
import '../../../../app/core/custom_base_view_model.dart';
@ -10,6 +12,7 @@ class HalamanCalegViewModel extends CustomBaseViewModel {
// variabel
List<CalegModel> listCalegModel = [];
int jumlahCaleg = 0;
bool status = false;
Future<void> init() async {
globalVar.backPressed = 'exitApp';
@ -31,8 +34,10 @@ class HalamanCalegViewModel extends CustomBaseViewModel {
log.i('listCalegModel: $listCalegModel');
log.i('jumlahCaleg: $jumlahCaleg');
status = true;
} catch (e) {
log.e(e);
status = false;
} finally {
globalVar.backPressed = 'exitApp';
setBusy(false);
@ -43,11 +48,64 @@ class HalamanCalegViewModel extends CustomBaseViewModel {
// log.i('addCaleg');
var res = await dialogService.showCustomDialog(
variant: DialogType.tambahEditCalegView,
data: {
'title': 'Tambah Caleg',
},
title: 'Tambah Caleg',
);
log.i(res?.confirmed);
if (res!.confirmed) {
snackbarService.showSnackbar(
message: 'Caleg berhasil ditambahkan',
title: 'Berhasil',
duration: const Duration(seconds: 3),
);
await getData();
}
}
deleteCaleg(CalegModel calegModel) {
dialogService
.showDialog(
title: 'Hapus Caleg',
description:
'Apakah anda yakin ingin menghapus caleg ${calegModel.namaCaleg} ?',
buttonTitle: 'Hapus',
cancelTitle: 'Batal',
buttonTitleColor: dangerColor,
cancelTitleColor: mainColor,
)
.then((value) async {
if (value!.confirmed) {
setBusy(true);
easyLoading.customLoading('Menghapus Caleg...');
try {
var response =
await httpService.delete('caleg/${calegModel.idCaleg}');
log.i(response.data);
await getData();
snackbarService.showSnackbar(
message: 'Caleg berhasil dihapus',
title: 'Berhasil',
duration: const Duration(seconds: 3),
);
} catch (e) {
log.e(e);
} finally {
easyLoading.dismissLoading();
setBusy(false);
}
}
});
}
showDetailCaleg(CalegModel calegModel) async {
var res = await dialogService.showCustomDialog(
variant: DialogType.tambahEditCalegView,
title: 'Detail Caleg',
data: calegModel,
);
// log.i('res ini: ${res!.confirmed}');
if (res!.confirmed) {
await deleteCaleg(calegModel);
}
}
}

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
import 'package:validatorless/validatorless.dart';
@ -10,13 +11,13 @@ import '../../../../widgets/my_textformfield.dart';
import './tambah_edit_caleg_view_model.dart';
class TambahEditCalegView extends StatelessWidget {
final DialogRequest? request;
final Function(DialogResponse)? completer;
final DialogRequest request;
final Function(DialogResponse) completer;
const TambahEditCalegView({
Key? key,
this.request,
this.completer,
required this.request,
required this.completer,
}) : super(key: key);
@override
@ -24,7 +25,7 @@ class TambahEditCalegView extends StatelessWidget {
return ViewModelBuilder<TambahEditCalegViewModel>.reactive(
viewModelBuilder: () => TambahEditCalegViewModel(),
onViewModelReady: (TambahEditCalegViewModel model) async {
await model.init();
await model.init(request.data);
},
builder: (
BuildContext context,
@ -45,73 +46,113 @@ class TambahEditCalegView extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
Text(
request?.data['title'] ?? '',
request.title ?? '',
),
const SizedBox(height: 10),
Stack(
children: [
CircleAvatar(
radius: 50,
backgroundColor: fontParagraphColor,
child: model.imageBytes == null
? const Icon(
Icons.person,
size: 50,
color: Colors.white,
)
: ClipRRect(
borderRadius: BorderRadius.circular(50),
child: Image.memory(
model.imageBytes!,
width: 100,
height: 100,
fit: BoxFit.cover,
if (model.calegModel == null)
Stack(
children: [
CircleAvatar(
radius: 50,
backgroundColor: fontParagraphColor,
child: model.imageBytes == null
? const Icon(
Icons.person,
size: 50,
color: Colors.white,
)
: ClipRRect(
borderRadius: BorderRadius.circular(50),
child: Image.memory(
model.imageBytes!,
width: 100,
height: 100,
fit: BoxFit.cover,
),
),
),
),
Positioned(
bottom: 0,
right: 0,
child: CircleAvatar(
radius: 15,
backgroundColor: warningColor,
child: IconButton(
onPressed: () {
model.addImage();
},
icon: const Icon(
Icons.add,
color: fontColor,
size: 15,
)),
),
Positioned(
bottom: 0,
right: 0,
child: CircleAvatar(
radius: 15,
backgroundColor: warningColor,
child: IconButton(
onPressed: () {
model.addImage();
},
icon: const Icon(
Icons.add,
color: fontColor,
size: 15,
)),
),
),
],
),
if (model.calegModel != null)
CircleAvatar(
radius: 50,
backgroundColor: fontParagraphColor,
child: ClipRRect(
borderRadius: BorderRadius.circular(50),
child: Image.network(
'${dotenv.env['api_url']}assets/caleg/${model.calegModel!.idCaleg}/${model.calegModel!.foto}',
width: 100,
height: 100,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return const Icon(
Icons.person,
size: 50,
color: greyBlueColor,
);
},
),
),
],
),
),
const SizedBox(height: 10),
MyTextFormField(
hintText: 'Masukan Nama Caleg',
labelText: 'Nama Caleg',
controller: model.namaController,
readOnly: model.calegModel != null,
validator: Validatorless.required(
'Nama Caleg tidak boleh kosong'),
),
const SizedBox(height: 10),
MyTextFormField(
hintText: 'Area',
labelText: 'Pencarian Area',
controller: model.cariAreaController,
suffixIcon: GestureDetector(
onTap: () {
// remove keyboard focus
FocusScope.of(context).unfocus();
model.cariArea();
},
child: const Icon(Icons.search),
hintText: 'Masukan Nomor Urut',
labelText: 'Nomor Urut',
controller: model.nomorUrutController,
readOnly: model.calegModel != null,
keyboardType: TextInputType.number,
validator: Validatorless.multiple(
// numbers only
[
Validatorless.required(
'Nomor Urut tidak boleh kosong'),
Validatorless.number('Nomor Urut harus berupa angka'),
],
),
// controller: model.partaiController,
),
if (model.calegModel == null) const SizedBox(height: 10),
if (model.calegModel == null)
MyTextFormField(
hintText: 'Area',
labelText: 'Pencarian Area',
controller: model.cariAreaController,
suffixIcon: GestureDetector(
onTap: () {
// remove keyboard focus
FocusScope.of(context).unfocus();
model.cariArea();
},
child: const Icon(Icons.search),
),
// controller: model.partaiController,
),
const SizedBox(height: 10),
SizedBox(
height: MediaQuery.of(context).size.height * 0.3,
@ -137,6 +178,7 @@ class TambahEditCalegView extends StatelessWidget {
value: model.listAreaId.contains(
model.listAreaModel[index].idArea!),
onChanged: (value) {
if (model.calegModel != null) return;
model.tambahHapusArea(
model.listAreaModel[index].idArea!,
);
@ -175,35 +217,111 @@ class TambahEditCalegView extends StatelessWidget {
),
),
const SizedBox(height: 10),
SizedBox(
width: 250,
child: MyButton(
text: 'Tambah Caleg',
onPressed: () async {
if (model.listAreaId.isEmpty) {
model.snackbarService.showSnackbar(
message:
'Pilih Area Calon Legislatif terlebih dahulu',
duration: const Duration(seconds: 2),
);
return;
}
if (model.calegModel == null)
SizedBox(
width: 250,
child: MyButton(
text: 'Tambah Caleg',
onPressed: () async {
if (model.listAreaId.isEmpty) {
model.snackbarService.showSnackbar(
message:
'Pilih Area Calon Legislatif terlebih dahulu',
duration: const Duration(seconds: 2),
);
return;
}
if (model.imageBytes == null) {
model.snackbarService.showSnackbar(
message:
'Pilih Foto Calon Legislatif terlebih dahulu',
duration: const Duration(seconds: 2),
);
return;
}
if (model.imageBytes == null) {
model.snackbarService.showSnackbar(
message:
'Pilih Foto Calon Legislatif terlebih dahulu',
duration: const Duration(seconds: 2),
);
return;
}
if (model.formKey.currentState!.validate()) {
model.addCaleg();
}
},
if (model.formKey.currentState!.validate()) {
// remove keyboard focus
FocusScope.of(context).unfocus();
model.dialogService
.showDialog(
title: 'Tambah Caleg',
description:
'Apakah anda yakin ingin menambah caleg ${model.namaController.text} ?',
buttonTitle: 'Ya',
cancelTitle: 'Batal',
)
.then((value) async {
if (value!.confirmed) {
bool res = await model.addCaleg();
model.log
.i('ini di res bagian dalamnya: $res');
if (res) {
// ignore: use_build_context_synchronously
// Navigator.of(context).pop();
completer(DialogResponse(confirmed: true));
}
// if (res.confirmed) {
// await model.addCaleg(completer!);
// completer!(DialogResponse(confirmed: true));
}
});
// bool res = await model.addCaleg();
// model.log.i('ini di res bagian dalamnya: $res');
// if (res) {
// // ignore: use_build_context_synchronously
// Navigator.of(context).pop();
// completer(DialogResponse(confirmed: true));
// }
// if (res.confirmed) {
// await model.addCaleg(completer!);
// completer!(DialogResponse(confirmed: true));
}
},
),
),
),
if (model.calegModel != null)
Row(
mainAxisSize: MainAxisSize.min,
children: [
// create rounde icon with one is delete and one is info
Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: mainColor.withOpacity(0.5),
borderRadius: BorderRadius.circular(50),
),
child: IconButton(
onPressed: () {},
icon: const Icon(
Icons.info,
color: Colors.white,
),
),
),
const SizedBox(width: 20),
Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: dangerColor,
borderRadius: BorderRadius.circular(50),
),
child: IconButton(
onPressed: () async {
completer(DialogResponse(confirmed: true));
},
icon: const Icon(
Icons.delete,
color: Colors.white,
),
),
),
],
)
],
),
),

View File

@ -11,6 +11,7 @@ import '../../../../../app/core/custom_base_view_model.dart';
import 'package:image_picker/image_picker.dart';
import '../../../../../model/area_model.dart';
import '../../../../../model/caleg_model.dart';
import '../../../../../model/my_response.model.dart';
class TambahEditCalegViewModel extends CustomBaseViewModel {
@ -24,6 +25,7 @@ class TambahEditCalegViewModel extends CustomBaseViewModel {
final formKey = GlobalKey<FormState>();
TextEditingController namaController = TextEditingController();
TextEditingController cariAreaController = TextEditingController();
TextEditingController nomorUrutController = TextEditingController();
List<int> listAreaId = [];
// image picker
@ -32,9 +34,49 @@ class TambahEditCalegViewModel extends CustomBaseViewModel {
XFile? imageFile;
Uint8List? imageBytes;
Future<void> init() async {
CalegModel? calegModel;
Future<void> init(data) async {
globalVar.backPressed = 'exitApp';
await getData();
calegModel = data;
if (calegModel != null) {
namaController.text = calegModel!.namaCaleg!;
nomorUrutController.text = calegModel!.nomorUrutCaleg!.toString();
getAreaList(calegModel!.idCaleg!);
// listAreaId = calegModel!.area!.map((e) => e.id!).toList();
}
log.i(data);
}
getAreaList(int idCaleg) async {
log.i('getAreaList');
setBusy(true);
globalVar.backPressed = 'cantBack';
try {
var response = await httpService.get('caleg/relasi_area/$idCaleg');
log.i(response.data);
MyResponseModel myResponseModel = MyResponseModel.fromJson(response.data);
var data = myResponseModel.data['area'];
for (var item in data) {
listAreaId.add(item['id_area']);
}
listAreaModel = [];
for (var item in allListAreaModel) {
if (listAreaId.contains(item.idArea)) {
listAreaModel.add(item);
}
}
log.i('listAreaModel: $listAreaModel');
// log.i('jumlahArea: $jumlahArea');
} catch (e) {
log.e(e);
} finally {
globalVar.backPressed = 'exitApp';
setBusy(false);
}
}
getData() async {
@ -105,61 +147,47 @@ class TambahEditCalegViewModel extends CustomBaseViewModel {
notifyListeners();
}
addCaleg() async {
dialogService
.showDialog(
title: 'Tambah Caleg',
description:
'Apakah anda yakin ingin menambahkan Caleg ${namaController.text}?',
buttonTitle: 'Ya',
cancelTitle: 'Tidak',
)
.then((value) async {
if (value!.confirmed) {
log.i('addCaleg');
setBusy(true);
globalVar.backPressed = 'cantBack';
easyLoading.customLoading('Tambah Caleg..');
Future<bool> addCaleg() async {
log.i('addCaleg');
setBusy(true);
globalVar.backPressed = 'cantBack';
easyLoading.customLoading('Tambah Caleg..');
var formData = FormData.fromMap({
'nama': namaController.text,
'area': const JsonEncoder().convert(listAreaId),
'foto': await MultipartFile.fromFile(
imageFile!.path,
filename: imageFile!.name,
contentType: MediaType('image', 'jpeg'),
)
});
try {
var response = await httpService.postWithFormData('caleg', formData);
log.i(response.data);
await getData();
navigationService.back();
// navigationService.back();
snackbarService.showSnackbar(
message: 'Berhasil menambahkan Caleg',
duration: const Duration(seconds: 2),
);
// navigationService.popRepeated(2);
} catch (e) {
log.e(e);
// navigationService.back();
snackbarService.showSnackbar(
message: 'Gagal menambahkan Caleg, ${e.toString()}',
duration: const Duration(seconds: 2),
);
} finally {
easyLoading.dismissLoading();
globalVar.backPressed = 'exitApp';
setBusy(false);
// navigationService.back();
// Navigator.of(context!).pop();
// remove all dialog
}
}
var formData = FormData.fromMap({
'nama': namaController.text,
'nomor_urut': nomorUrutController.text,
'area': const JsonEncoder().convert(listAreaId),
'foto': await MultipartFile.fromFile(
imageFile!.path,
filename: imageFile!.name,
contentType: MediaType('image', 'jpeg'),
)
});
try {
var response = await httpService.postWithFormData('caleg', formData);
log.i(response.data);
// await getData();
// navigationService.back();
// navigationService.back();
// snackbarService.showSnackbar(
// message: 'Berhasil menambahkan Caleg',
// duration: const Duration(seconds: 2),
// );
// completer(DialogResponse(confirmed: true));
return true;
// navigationService.popRepeated(2);
} catch (e) {
log.e(e);
return false;
} finally {
easyLoading.dismissLoading();
globalVar.backPressed = 'exitApp';
setBusy(false);
// navigationService.back();
// Navigator.of(context!).pop();
// remove all dialog
}
}
}