first commit
This commit is contained in:
@ -0,0 +1,131 @@
|
||||
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 '../../../widgets/top_container.dart';
|
||||
import './halaman_caleg_view_model.dart';
|
||||
|
||||
class HalamanCalegView extends StatelessWidget {
|
||||
const HalamanCalegView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ViewModelBuilder<HalamanCalegViewModel>.reactive(
|
||||
viewModelBuilder: () => HalamanCalegViewModel(),
|
||||
onViewModelReady: (HalamanCalegViewModel model) async {
|
||||
await model.init();
|
||||
},
|
||||
builder: (
|
||||
BuildContext context,
|
||||
HalamanCalegViewModel model,
|
||||
Widget? child,
|
||||
) {
|
||||
return Scaffold(
|
||||
body: WillPopScope(
|
||||
onWillPop: () async {
|
||||
// model.log.i('backPressed: ${model.globalVar.backPressed}');
|
||||
if (model.globalVar.backPressed == 'exitApp') {
|
||||
// model.back();
|
||||
model.quitApp(context);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
child: SafeArea(
|
||||
child: Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
children: [
|
||||
TopContainer(
|
||||
title: 'Jumlah Caleg',
|
||||
value: '${model.jumlahCaleg} Caleg',
|
||||
icon: Icons.co_present_outlined,
|
||||
background: greenColor,
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Expanded(
|
||||
// flex: 3,
|
||||
child: Container(
|
||||
height: double.infinity,
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.grey),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
color: warningColor,
|
||||
),
|
||||
child: Column(
|
||||
// mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: model.isBusy
|
||||
? MainAxisAlignment.center
|
||||
: (model.listCalegModel.isNotEmpty
|
||||
? MainAxisAlignment.start
|
||||
: MainAxisAlignment.center),
|
||||
children: [
|
||||
if (model.isBusy)
|
||||
const LinearProgressIndicator(
|
||||
minHeight: 5,
|
||||
color: mainColor,
|
||||
),
|
||||
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: () {},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!model.isBusy && model.listCalegModel.isEmpty)
|
||||
const Center(
|
||||
child: Text(
|
||||
'Tidak ada data caleg diinput sebelumnya',
|
||||
style: italicTextStyle,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () {
|
||||
model.addCaleg();
|
||||
},
|
||||
child: const Icon(Icons.add),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
import '../../../../app/app.dialogs.dart';
|
||||
import '../../../../app/app.logger.dart';
|
||||
import '../../../../app/core/custom_base_view_model.dart';
|
||||
import '../../../../model/caleg_model.dart';
|
||||
import '../../../../model/my_response.model.dart';
|
||||
|
||||
class HalamanCalegViewModel extends CustomBaseViewModel {
|
||||
final log = getLogger('HalamanCalegViewModel');
|
||||
|
||||
// variabel
|
||||
List<CalegModel> listCalegModel = [];
|
||||
int jumlahCaleg = 0;
|
||||
|
||||
Future<void> init() async {
|
||||
globalVar.backPressed = 'exitApp';
|
||||
await getData();
|
||||
}
|
||||
|
||||
getData() async {
|
||||
log.i('getData');
|
||||
setBusy(true);
|
||||
globalVar.backPressed = 'cantBack';
|
||||
try {
|
||||
var response = await httpService.get('caleg');
|
||||
log.i(response.data);
|
||||
MyResponseModel myResponseModel = MyResponseModel.fromJson(response.data);
|
||||
CalegListModel calegListModel =
|
||||
CalegListModel.fromJson(myResponseModel.data);
|
||||
listCalegModel = calegListModel.caleg!;
|
||||
jumlahCaleg = calegListModel.jumlah!;
|
||||
|
||||
log.i('listCalegModel: $listCalegModel');
|
||||
log.i('jumlahCaleg: $jumlahCaleg');
|
||||
} catch (e) {
|
||||
log.e(e);
|
||||
} finally {
|
||||
globalVar.backPressed = 'exitApp';
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
|
||||
addCaleg() async {
|
||||
// log.i('addCaleg');
|
||||
var res = await dialogService.showCustomDialog(
|
||||
variant: DialogType.tambahEditCalegView,
|
||||
data: {
|
||||
'title': 'Tambah Caleg',
|
||||
},
|
||||
);
|
||||
|
||||
log.i(res?.confirmed);
|
||||
}
|
||||
}
|
@ -0,0 +1,216 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:stacked_services/stacked_services.dart';
|
||||
import 'package:validatorless/validatorless.dart';
|
||||
|
||||
import '../../../../../app/themes/app_colors.dart';
|
||||
import '../../../../../app/themes/app_text.dart';
|
||||
import '../../../../widgets/my_button.dart';
|
||||
import '../../../../widgets/my_textformfield.dart';
|
||||
import './tambah_edit_caleg_view_model.dart';
|
||||
|
||||
class TambahEditCalegView extends StatelessWidget {
|
||||
final DialogRequest? request;
|
||||
final Function(DialogResponse)? completer;
|
||||
|
||||
const TambahEditCalegView({
|
||||
Key? key,
|
||||
this.request,
|
||||
this.completer,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ViewModelBuilder<TambahEditCalegViewModel>.reactive(
|
||||
viewModelBuilder: () => TambahEditCalegViewModel(),
|
||||
onViewModelReady: (TambahEditCalegViewModel model) async {
|
||||
await model.init();
|
||||
},
|
||||
builder: (
|
||||
BuildContext context,
|
||||
TambahEditCalegViewModel model,
|
||||
Widget? child,
|
||||
) {
|
||||
return Dialog(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(15),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
color: backgroundColor,
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
child: Form(
|
||||
key: model.formKey,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
request?.data['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,
|
||||
),
|
||||
),
|
||||
),
|
||||
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,
|
||||
)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
MyTextFormField(
|
||||
hintText: 'Masukan Nama Caleg',
|
||||
labelText: 'Nama Caleg',
|
||||
controller: model.namaController,
|
||||
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),
|
||||
),
|
||||
|
||||
// controller: model.partaiController,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.3,
|
||||
width: double.infinity,
|
||||
|
||||
// create 10 random checkbox
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (model.isBusy)
|
||||
const Center(child: CircularProgressIndicator()),
|
||||
if (!model.isBusy && model.listAreaModel.isNotEmpty)
|
||||
// FutureBuilder(future: , builder: builder)
|
||||
Wrap(
|
||||
spacing: 10,
|
||||
children: List.generate(
|
||||
model.listAreaModel.length,
|
||||
(index) => Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Checkbox(
|
||||
value: model.listAreaId.contains(
|
||||
model.listAreaModel[index].idArea!),
|
||||
onChanged: (value) {
|
||||
model.tambahHapusArea(
|
||||
model.listAreaModel[index].idArea!,
|
||||
);
|
||||
},
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
model.listAreaModel[index].namaArea!,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!model.isBusy && model.listAreaModel.isEmpty)
|
||||
Center(
|
||||
child: RichText(
|
||||
textAlign: TextAlign.center,
|
||||
text: TextSpan(
|
||||
text: 'Tidak ada pencarian area\n',
|
||||
style: regularTextStyle,
|
||||
children: [
|
||||
TextSpan(
|
||||
text:
|
||||
' ${model.cariAreaController.text}',
|
||||
style: boldTextStyle.copyWith(
|
||||
color: dangerColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
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.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();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,165 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http_parser/http_parser.dart';
|
||||
|
||||
import '../../../../../app/app.logger.dart';
|
||||
import '../../../../../app/core/custom_base_view_model.dart';
|
||||
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
|
||||
import '../../../../../model/area_model.dart';
|
||||
import '../../../../../model/my_response.model.dart';
|
||||
|
||||
class TambahEditCalegViewModel extends CustomBaseViewModel {
|
||||
final log = getLogger('TambahEditCalegViewModel');
|
||||
|
||||
// variabel list area
|
||||
List<AreaModel> listAreaModel = [];
|
||||
List<AreaModel> allListAreaModel = [];
|
||||
|
||||
// form variable
|
||||
final formKey = GlobalKey<FormState>();
|
||||
TextEditingController namaController = TextEditingController();
|
||||
TextEditingController cariAreaController = TextEditingController();
|
||||
List<int> listAreaId = [];
|
||||
|
||||
// image picker
|
||||
String? _imagePath;
|
||||
final ImagePicker _picker = ImagePicker();
|
||||
XFile? imageFile;
|
||||
Uint8List? imageBytes;
|
||||
|
||||
Future<void> init() async {
|
||||
globalVar.backPressed = 'exitApp';
|
||||
await getData();
|
||||
}
|
||||
|
||||
getData() async {
|
||||
log.i('getData');
|
||||
setBusy(true);
|
||||
globalVar.backPressed = 'cantBack';
|
||||
try {
|
||||
var response = await httpService.get('area');
|
||||
log.i(response.data);
|
||||
MyResponseModel myResponseModel = MyResponseModel.fromJson(response.data);
|
||||
AreaListModel areaListModel =
|
||||
AreaListModel.fromJson(myResponseModel.data);
|
||||
listAreaModel = areaListModel.area!;
|
||||
allListAreaModel = areaListModel.area!;
|
||||
// jumlahArea = areaListModel.jumlah!;
|
||||
|
||||
log.i('listAreaModel: $listAreaModel');
|
||||
// log.i('jumlahArea: $jumlahArea');
|
||||
} catch (e) {
|
||||
log.e(e);
|
||||
} finally {
|
||||
globalVar.backPressed = 'exitApp';
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
tambahHapusArea(int idArea) {
|
||||
log.i('tambahHapusArea');
|
||||
if (listAreaId.contains(idArea)) {
|
||||
listAreaId.remove(idArea);
|
||||
} else {
|
||||
listAreaId.add(idArea);
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
cariArea() {
|
||||
log.i('cariArea ${cariAreaController.text}');
|
||||
|
||||
if (cariAreaController.text.isEmpty) {
|
||||
listAreaModel = allListAreaModel;
|
||||
return;
|
||||
}
|
||||
|
||||
listAreaModel = allListAreaModel
|
||||
.where((element) => element.namaArea!
|
||||
.toLowerCase()
|
||||
.contains(cariAreaController.text.toLowerCase()))
|
||||
.toList();
|
||||
|
||||
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..');
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user