first commit
This commit is contained in:
@ -0,0 +1,136 @@
|
||||
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 './first_page_view_model.dart';
|
||||
|
||||
class FirstPageView extends StatelessWidget {
|
||||
const FirstPageView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ViewModelBuilder<FirstPageViewModel>.reactive(
|
||||
viewModelBuilder: () => FirstPageViewModel(),
|
||||
onViewModelReady: (FirstPageViewModel model) async {
|
||||
await model.init();
|
||||
},
|
||||
builder: (
|
||||
BuildContext context,
|
||||
FirstPageViewModel 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: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TopContainer(
|
||||
title: 'Jumlah Pemilih',
|
||||
value: '${model.counter} Orang',
|
||||
icon: Icons.people_alt_outlined,
|
||||
background: blueColor,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
text: 'Selamat Datang, ',
|
||||
style: regularTextStyle,
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '${model.nama}\n\n',
|
||||
style: boldTextStyle,
|
||||
),
|
||||
const TextSpan(
|
||||
text: 'Silahkan tambahkan data ',
|
||||
style: regularTextStyle,
|
||||
),
|
||||
TextSpan(
|
||||
text: 'Pemilih ',
|
||||
style: boldTextStyle.copyWith(
|
||||
color: greenColor,
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
const TextSpan(
|
||||
text: 'dengan menekan menu ',
|
||||
style: regularTextStyle,
|
||||
),
|
||||
TextSpan(
|
||||
text: 'Survei ',
|
||||
style: boldTextStyle.copyWith(
|
||||
color: greenColor,
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
const TextSpan(
|
||||
text: 'di bawah sebelah kanan.\n\n',
|
||||
style: regularTextStyle,
|
||||
),
|
||||
const TextSpan(
|
||||
text: 'Menu ',
|
||||
style: regularTextStyle,
|
||||
),
|
||||
TextSpan(
|
||||
text: 'History ',
|
||||
style: boldTextStyle.copyWith(
|
||||
color: greenColor,
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
const TextSpan(
|
||||
text:
|
||||
'pada bawah tengah digunakan untuk melihat data yang sudah diinputkan.\n\n',
|
||||
style: regularTextStyle,
|
||||
),
|
||||
const TextSpan(
|
||||
text: 'Menu ',
|
||||
style: regularTextStyle,
|
||||
),
|
||||
TextSpan(
|
||||
text: 'Pengaturan ',
|
||||
style: boldTextStyle.copyWith(
|
||||
color: greenColor,
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
const TextSpan(
|
||||
text:
|
||||
'pada bawah debelah kanan digunakan untuk mengubah data diri anda.\n\nSekian dari Developer',
|
||||
style: regularTextStyle,
|
||||
),
|
||||
TextSpan(
|
||||
text: '\nKicap Karan ',
|
||||
style: boldTextStyle.copyWith(
|
||||
color: dangerColor,
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
import '../../../../app/app.logger.dart';
|
||||
import '../../../../app/core/custom_base_view_model.dart';
|
||||
import '../../../../model/my_response.model.dart';
|
||||
|
||||
class FirstPageViewModel extends CustomBaseViewModel {
|
||||
final log = getLogger('FirstPageViewModel');
|
||||
int counter = 0;
|
||||
String? nik;
|
||||
String? nama;
|
||||
Future<void> init() async {
|
||||
globalVar.backPressed = 'exitApp';
|
||||
nik = await mySharedPrefs.getString('nik');
|
||||
nama = await mySharedPrefs.getString('nama');
|
||||
await getData();
|
||||
}
|
||||
|
||||
getData() async {
|
||||
setBusy(true);
|
||||
|
||||
try {
|
||||
var response = await httpService.get('tim_survei/counter/$nik');
|
||||
MyResponseModel myResponseModel = MyResponseModel.fromJson(response.data);
|
||||
counter = myResponseModel.data;
|
||||
} catch (e) {
|
||||
log.e(e.toString());
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
|
||||
import '../../../../app/themes/app_colors.dart';
|
||||
import '../../../../app/themes/app_text.dart';
|
||||
import './halaman_history_view_model.dart';
|
||||
|
||||
class HalamanHistoryView extends StatelessWidget {
|
||||
const HalamanHistoryView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ViewModelBuilder<HalamanHistoryViewModel>.reactive(
|
||||
viewModelBuilder: () => HalamanHistoryViewModel(),
|
||||
onViewModelReady: (HalamanHistoryViewModel model) async {
|
||||
await model.init();
|
||||
},
|
||||
builder: (
|
||||
BuildContext context,
|
||||
HalamanHistoryViewModel 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: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(15),
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.grey),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
color: warningColor,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
"Caleg : ",
|
||||
style: italicTextStyle.copyWith(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Text(
|
||||
model.namaCaleg,
|
||||
style: boldTextStyle.copyWith(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Expanded(
|
||||
child: Container(
|
||||
alignment: model.isBusy
|
||||
? Alignment.center
|
||||
: model.status == true
|
||||
? model.counter > 0
|
||||
? Alignment.topCenter
|
||||
: Alignment.center
|
||||
: Alignment.center,
|
||||
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: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (model.isBusy)
|
||||
const Center(
|
||||
child: CircularProgressIndicator()),
|
||||
if (!model.isBusy &&
|
||||
model.status == true &&
|
||||
model.counter > 0)
|
||||
for (var i = 0; i < model.counter; i++)
|
||||
Card(
|
||||
child: ListTile(
|
||||
// leading is datetime dummy
|
||||
leading:
|
||||
Text(model.listPemilih[i].createdAt!),
|
||||
title: Text(
|
||||
model.listPemilih[i].namaPemilih!,
|
||||
style: boldTextStyle,
|
||||
),
|
||||
subtitle: Text(
|
||||
model.listPemilih[i].namaArea!,
|
||||
),
|
||||
trailing: IconButton(
|
||||
icon: const Icon(
|
||||
Icons.info_outline,
|
||||
color: mainColor,
|
||||
),
|
||||
onPressed: () {
|
||||
// model.showDetailCaleg(model.listCalegModel[i]);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!model.isBusy &&
|
||||
model.status == true &&
|
||||
model.counter == 0)
|
||||
const Center(
|
||||
child: Text(
|
||||
'Belum ada data',
|
||||
style: boldTextStyle,
|
||||
),
|
||||
),
|
||||
if (!model.isBusy && model.status == false)
|
||||
const Center(
|
||||
child: Text(
|
||||
'Error: Gagal mengambil data dari server',
|
||||
style: boldTextStyle,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
import 'package:cek_suara_app/model/my_response.model.dart';
|
||||
import 'package:cek_suara_app/model/pemilih_model.dart';
|
||||
|
||||
import '../../../../app/app.logger.dart';
|
||||
import '../../../../app/core/custom_base_view_model.dart';
|
||||
|
||||
class HalamanHistoryViewModel extends CustomBaseViewModel {
|
||||
final log = getLogger('HalamanHistoryViewModel');
|
||||
int counter = 0;
|
||||
List<PemilihModel> listPemilih = [];
|
||||
bool status = false;
|
||||
|
||||
String namaCaleg = '...';
|
||||
Future<void> init() async {
|
||||
await getData();
|
||||
}
|
||||
|
||||
getData() async {
|
||||
setBusy(true);
|
||||
|
||||
try {
|
||||
String? nik = await mySharedPrefs.getString('nik');
|
||||
var response = await httpService.get('tim_survei/$nik');
|
||||
MyResponseModel myResponseModel = MyResponseModel.fromJson(response.data);
|
||||
PemilihDetailModel pemilihDetailModel =
|
||||
PemilihDetailModel.fromJson(myResponseModel.data);
|
||||
listPemilih = pemilihDetailModel.pemilihModel!;
|
||||
log.i('listPemilih: $listPemilih');
|
||||
namaCaleg = listPemilih[0].namaCaleg!;
|
||||
counter = pemilihDetailModel.jumlah!;
|
||||
log.i('counter: $counter');
|
||||
status = true;
|
||||
} catch (e) {
|
||||
log.e(e.toString());
|
||||
status = false;
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
import 'package:cek_suara_app/ui/views/tim_survei_index_tracking/first_page/first_page_view.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
|
||||
import './halaman_pengaturan_view_model.dart';
|
||||
|
||||
class HalamanPengaturanView extends StatelessWidget {
|
||||
const HalamanPengaturanView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ViewModelBuilder<HalamanPengaturanViewModel>.reactive(
|
||||
viewModelBuilder: () => HalamanPengaturanViewModel(),
|
||||
onViewModelReady: (HalamanPengaturanViewModel model) async {
|
||||
await model.init();
|
||||
},
|
||||
builder: (
|
||||
BuildContext context,
|
||||
HalamanPengaturanViewModel model,
|
||||
Widget? child,
|
||||
) {
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
// model.log.i('backPressed: ${model.globalVar.backPressed}');
|
||||
if (model.globalVar.backPressed == 'exitApp') {
|
||||
// model.back();
|
||||
model.quitApp(context);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
child: const FirstPageView(),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
import '../../../../app/core/custom_base_view_model.dart';
|
||||
|
||||
class HalamanPengaturanViewModel extends CustomBaseViewModel {
|
||||
Future<void> init() async {
|
||||
globalVar.backPressed = 'exitApp';
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
import 'package:cek_suara_app/ui/widgets/my_textformfield.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:stacked_services/stacked_services.dart';
|
||||
|
||||
import './bottom_sheet_cari_area_view_model.dart';
|
||||
|
||||
class BottomSheetCariAreaView extends StatelessWidget {
|
||||
final SheetRequest request;
|
||||
final Function(SheetResponse)? completer;
|
||||
|
||||
const BottomSheetCariAreaView({
|
||||
Key? key,
|
||||
required this.request,
|
||||
this.completer,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ViewModelBuilder<BottomSheetCariAreaViewModel>.reactive(
|
||||
viewModelBuilder: () => BottomSheetCariAreaViewModel(),
|
||||
onViewModelReady: (BottomSheetCariAreaViewModel model) async {
|
||||
await model.init();
|
||||
},
|
||||
builder: (
|
||||
BuildContext context,
|
||||
BottomSheetCariAreaViewModel model,
|
||||
Widget? child,
|
||||
) {
|
||||
return SafeArea(
|
||||
child: Container(
|
||||
alignment: Alignment.topCenter,
|
||||
width: double.infinity,
|
||||
height: MediaQuery.of(context).size.height,
|
||||
margin: const EdgeInsets.all(25),
|
||||
padding: const EdgeInsets.all(25),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: MyTextFormField(
|
||||
hintText: 'Cari Area',
|
||||
labelText: 'Cari Area',
|
||||
controller: model.searchController,
|
||||
suffixIcon: IconButton(
|
||||
onPressed: () {
|
||||
completer!(
|
||||
SheetResponse(
|
||||
confirmed: true,
|
||||
data: model.searchController.text,
|
||||
),
|
||||
);
|
||||
},
|
||||
icon: const Icon(Icons.search),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../../../app/app.logger.dart';
|
||||
import '../../../../../app/core/custom_base_view_model.dart';
|
||||
|
||||
class BottomSheetCariAreaViewModel extends CustomBaseViewModel {
|
||||
final log = getLogger('BottomSheetCariAreaViewModel');
|
||||
|
||||
TextEditingController searchController = TextEditingController();
|
||||
|
||||
Future<void> init() async {}
|
||||
}
|
@ -0,0 +1,272 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:validatorless/validatorless.dart';
|
||||
|
||||
import '../../../../app/themes/app_colors.dart';
|
||||
import '../../../widgets/my_button.dart';
|
||||
import '../../../widgets/my_textformfield.dart';
|
||||
import './halaman_survei_view_model.dart';
|
||||
|
||||
class HalamanSurveiView extends StatelessWidget {
|
||||
const HalamanSurveiView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ViewModelBuilder<HalamanSurveiViewModel>.reactive(
|
||||
viewModelBuilder: () => HalamanSurveiViewModel(),
|
||||
onViewModelReady: (HalamanSurveiViewModel model) async {
|
||||
await model.init();
|
||||
},
|
||||
builder: (
|
||||
BuildContext context,
|
||||
HalamanSurveiViewModel 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: SingleChildScrollView(
|
||||
child: Form(
|
||||
key: model.formKey,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Center(child: Text('Foto KTP / Wajah Pemilih')),
|
||||
// create a rectangle container that later use to show image with child is KTP icon
|
||||
Center(
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
height: 100,
|
||||
width: 150,
|
||||
decoration: BoxDecoration(
|
||||
color: mainColor,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: model.imageBytes != null
|
||||
? Image.memory(
|
||||
model.imageBytes!,
|
||||
fit: BoxFit.fill,
|
||||
)
|
||||
: const Icon(
|
||||
Icons.credit_card_rounded,
|
||||
color: Colors.white,
|
||||
size: 50,
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
child: CircleAvatar(
|
||||
radius: 15,
|
||||
backgroundColor: sixthGrey,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
model.addImage();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.add,
|
||||
color: backgroundColor3,
|
||||
size: 15,
|
||||
)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
MyTextFormField(
|
||||
hintText: 'Masukkan KTP / No HP Pemilih',
|
||||
labelText: 'KTP / No HP Pemilih',
|
||||
maxLength: 16,
|
||||
suffixIcon: const Icon(Icons.add_card_rounded),
|
||||
controller: model.ktpController,
|
||||
keyboardType: TextInputType.number,
|
||||
validator: Validatorless.multiple(
|
||||
[
|
||||
Validatorless.required(
|
||||
'KTP / No HP Pemilih tidak boleh kosong'),
|
||||
Validatorless.number(
|
||||
'KTP / No HP Pemilih harus angka'),
|
||||
Validatorless.min(
|
||||
10, 'KTP / No HP Pemilih minimal 10 digit'),
|
||||
Validatorless.max(
|
||||
16, 'KTP / No HP Pemilih maksimal 16 digit'),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
MyTextFormField(
|
||||
hintText: 'Masukkan Nama Pemilih',
|
||||
labelText: 'Nama Pemilih',
|
||||
suffixIcon: const Icon(Icons.person),
|
||||
controller: model.namaController,
|
||||
validator: Validatorless.required(
|
||||
'Nama Pemilih tidak boleh kosong'),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const Text(
|
||||
' Pilih Area',
|
||||
),
|
||||
if (model.isBusy)
|
||||
const Center(child: CircularProgressIndicator()),
|
||||
if (!model.isBusy && model.selectedArea != null)
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 60,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(25),
|
||||
border: Border.all(
|
||||
color: sixthGrey,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
// icon search
|
||||
IconButton(
|
||||
onPressed: () async =>
|
||||
await model.searchArea(),
|
||||
icon: const Icon(
|
||||
Icons.search,
|
||||
color: sixthGrey,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButton<String>(
|
||||
isExpanded: true,
|
||||
value: model.selectedArea!,
|
||||
icon: const Icon(Icons.arrow_drop_down),
|
||||
iconSize: 24,
|
||||
elevation: 16,
|
||||
style: const TextStyle(
|
||||
color: Colors.black),
|
||||
onChanged: (String? newValue) {
|
||||
model.log.i(newValue);
|
||||
model.selectedArea = newValue!;
|
||||
// model.changeArea(newValue);
|
||||
model.notifyListeners();
|
||||
},
|
||||
items: model.listAreaString
|
||||
.map<DropdownMenuItem<String>>(
|
||||
(String value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value,
|
||||
child: Text(value,
|
||||
overflow:
|
||||
TextOverflow.ellipsis),
|
||||
);
|
||||
}).toList()),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// const SizedBox(height: 20),
|
||||
// const Text(
|
||||
// ' Pilih Caleg',
|
||||
// ),
|
||||
// if (model.isBusy)
|
||||
// const Center(child: CircularProgressIndicator()),
|
||||
// if (!model.isBusy)
|
||||
// Container(
|
||||
// width: double.infinity,
|
||||
// height: 60,
|
||||
// padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
// decoration: BoxDecoration(
|
||||
// borderRadius: BorderRadius.circular(25),
|
||||
// border: Border.all(
|
||||
// color: sixthGrey,
|
||||
// ),
|
||||
// ),
|
||||
// child: Expanded(
|
||||
// child: DropdownButtonHideUnderline(
|
||||
// child: DropdownButton<String>(
|
||||
// isExpanded: true,
|
||||
// value: model.selectedCaleg!,
|
||||
// icon: const Icon(Icons.arrow_drop_down),
|
||||
// iconSize: 24,
|
||||
// elevation: 16,
|
||||
// style: const TextStyle(color: Colors.black),
|
||||
// onChanged: (String? newValue) {
|
||||
// model.log.i(newValue);
|
||||
// model.selectedCaleg = newValue!;
|
||||
|
||||
// model.notifyListeners();
|
||||
// },
|
||||
// items: model.listCalegString
|
||||
// .map<DropdownMenuItem<String>>(
|
||||
// (String value) {
|
||||
// return DropdownMenuItem<String>(
|
||||
// value: value,
|
||||
// child: Text(value,
|
||||
// overflow: TextOverflow.ellipsis),
|
||||
// );
|
||||
// }).toList()),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
|
||||
const SizedBox(height: 20),
|
||||
Center(
|
||||
child: SizedBox(
|
||||
width: 200,
|
||||
child: MyButton(
|
||||
text: 'Upload Data',
|
||||
onPressed: () {
|
||||
if (model.imageBytes == null) {
|
||||
model.snackbarService.showSnackbar(
|
||||
message:
|
||||
'Foto KTP / Wajah Pemilih tidak boleh kosong',
|
||||
);
|
||||
model.addImage();
|
||||
return;
|
||||
}
|
||||
|
||||
if (model.formKey.currentState!.validate()) {
|
||||
// hide keyboard
|
||||
FocusScope.of(context).unfocus();
|
||||
model.dialogService
|
||||
.showDialog(
|
||||
title: 'Upload Data',
|
||||
description:
|
||||
'Apakah anda yakin ingin mengupload data?',
|
||||
buttonTitle: 'Ya',
|
||||
cancelTitle: 'Tidak',
|
||||
)
|
||||
.then((value) async {
|
||||
if (value!.confirmed) {
|
||||
await model.uploadData();
|
||||
}
|
||||
});
|
||||
// model.uploadData();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,212 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http_parser/http_parser.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import '../../../../app/app.bottomsheets.dart';
|
||||
import '../../../../app/app.logger.dart';
|
||||
import '../../../../app/core/custom_base_view_model.dart';
|
||||
import '../../../../model/area_model.dart';
|
||||
import '../../../../model/my_response.model.dart';
|
||||
|
||||
class HalamanSurveiViewModel extends CustomBaseViewModel {
|
||||
final log = getLogger('HalamanSurveiViewModel');
|
||||
|
||||
// form
|
||||
final formKey = GlobalKey<FormState>();
|
||||
TextEditingController ktpController = TextEditingController();
|
||||
TextEditingController namaController = TextEditingController();
|
||||
|
||||
// image picker
|
||||
String? _imagePath;
|
||||
final ImagePicker _picker = ImagePicker();
|
||||
XFile? imageFile;
|
||||
Uint8List? imageBytes;
|
||||
|
||||
// area
|
||||
List<AreaModel> listAreaModel = [];
|
||||
List<String> listAreaString = [];
|
||||
List<AreaModel> allListAreaModel = [];
|
||||
String? selectedArea;
|
||||
int areaIndex = 0;
|
||||
|
||||
// // caleg
|
||||
// List<CalegModel> listCalegModel = [];
|
||||
// List<String> listCalegString = [];
|
||||
// String? selectedCaleg;
|
||||
|
||||
// ini baru
|
||||
String? idCaleg;
|
||||
String? nik;
|
||||
|
||||
Future<void> init() async {
|
||||
globalVar.backPressed = 'exitApp';
|
||||
|
||||
String idCaleg = await mySharedPrefs.getString('id_caleg') ?? '';
|
||||
this.idCaleg = idCaleg;
|
||||
nik = await mySharedPrefs.getString('nik') ?? '';
|
||||
await getData();
|
||||
}
|
||||
|
||||
getData() async {
|
||||
log.i('getData');
|
||||
setBusy(true);
|
||||
globalVar.backPressed = 'cantBack';
|
||||
try {
|
||||
// this one is before
|
||||
// var response = await httpService.get('area');
|
||||
|
||||
// String? nik = await mySharedPrefs.getString('nik');
|
||||
var response = await httpService.get('area/cek_area/$nik');
|
||||
log.i(response.data);
|
||||
MyResponseModel myResponseModel = MyResponseModel.fromJson(response.data);
|
||||
AreaListModel areaListModel =
|
||||
AreaListModel.fromJson(myResponseModel.data);
|
||||
listAreaModel = areaListModel.area!;
|
||||
allListAreaModel = areaListModel.area!;
|
||||
for (var element in listAreaModel) {
|
||||
listAreaString.add(element.namaArea!);
|
||||
}
|
||||
selectedArea = listAreaString[0];
|
||||
// int idArea = listAreaModel[0].idArea!;
|
||||
// await getCaleg(idArea);
|
||||
|
||||
// getCaleg()
|
||||
} catch (e) {
|
||||
log.e(e);
|
||||
} finally {
|
||||
globalVar.backPressed = 'exitApp';
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
|
||||
// getCaleg(int idArea) async {
|
||||
// log.i('getCaleg');
|
||||
// log.i('idArea: $idArea');
|
||||
// selectedCaleg = null;
|
||||
// listCalegModel = [];
|
||||
// listCalegString = [];
|
||||
// setBusy(true);
|
||||
// try {
|
||||
// var response = await httpService.get('caleg/area/$idArea');
|
||||
// log.i(response.data);
|
||||
// MyResponseModel myResponseModel = MyResponseModel.fromJson(response.data);
|
||||
// // log.i(myResponseModel.data);
|
||||
// CalegListModel calegListModel =
|
||||
// CalegListModel.fromJson(myResponseModel.data);
|
||||
// listCalegModel = calegListModel.caleg!;
|
||||
// for (var element in listCalegModel) {
|
||||
// listCalegString.add(element.namaCaleg!);
|
||||
// }
|
||||
// selectedCaleg = listCalegString[0];
|
||||
// // log.i('listCalegModel: $listCalegModel');
|
||||
// // log.i('listCalegString: $listCalegString');
|
||||
// // log.i('selectedCaleg: $selectedCaleg');
|
||||
// } catch (e) {
|
||||
// log.e(e);
|
||||
// } finally {
|
||||
// setBusy(false);
|
||||
// }
|
||||
// }
|
||||
|
||||
// changeArea(String? value) async {
|
||||
// int idArea = listAreaModel[listAreaString.indexOf(value!)].idArea!;
|
||||
// // log.i('idArea: $idArea');
|
||||
// await getCaleg(idArea);
|
||||
// }
|
||||
|
||||
void addImage() async {
|
||||
try {
|
||||
final XFile? image = await _picker.pickImage(source: ImageSource.camera);
|
||||
if (image != null) {
|
||||
imageFile = image;
|
||||
_imagePath = image.path;
|
||||
imageBytes = await image.readAsBytes();
|
||||
|
||||
log.i('image path: $_imagePath');
|
||||
notifyListeners();
|
||||
}
|
||||
} catch (e) {
|
||||
log.e(e);
|
||||
}
|
||||
}
|
||||
|
||||
searchArea() async {
|
||||
var res = await bottomSheetService.showCustomSheet(
|
||||
variant: BottomSheetType.bottomSheetCariAreaView,
|
||||
ignoreSafeArea: false,
|
||||
isScrollControlled: true,
|
||||
);
|
||||
|
||||
if (res!.confirmed) {
|
||||
log.i('res.data: ${res.data}');
|
||||
|
||||
String area = res.data;
|
||||
if (area == '') {
|
||||
listAreaModel = allListAreaModel;
|
||||
} else {
|
||||
listAreaModel = [];
|
||||
for (var element in allListAreaModel) {
|
||||
if (element.namaArea!.toLowerCase().contains(area.toLowerCase())) {
|
||||
listAreaModel.add(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
listAreaString = [];
|
||||
for (var element in listAreaModel) {
|
||||
listAreaString.add(element.namaArea!);
|
||||
}
|
||||
selectedArea = listAreaString[0];
|
||||
// int idArea = listAreaModel[0].idArea!;
|
||||
// await getCaleg(idArea);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
uploadData() async {
|
||||
log.i('uploadData');
|
||||
setBusy(true);
|
||||
easyLoading.customLoading('Uploading data...');
|
||||
globalVar.backPressed = 'cantBack';
|
||||
try {
|
||||
String idArea = listAreaModel[listAreaString.indexOf(selectedArea!)]
|
||||
.idArea
|
||||
.toString();
|
||||
var fomData = FormData.fromMap(
|
||||
{
|
||||
'ktp': ktpController.text,
|
||||
'nama': namaController.text,
|
||||
'idCaleg': idCaleg,
|
||||
'foto': await MultipartFile.fromFile(
|
||||
_imagePath!,
|
||||
filename: imageFile!.name,
|
||||
contentType: MediaType('image', 'jpg'),
|
||||
),
|
||||
'idArea': idArea,
|
||||
'nik': nik,
|
||||
},
|
||||
);
|
||||
await httpService.postWithFormData('tim_survei', fomData);
|
||||
snackbarService.showSnackbar(
|
||||
message: 'Data berhasil diupload',
|
||||
title: 'Berhasil',
|
||||
duration: const Duration(milliseconds: 2500),
|
||||
);
|
||||
// clear data
|
||||
ktpController.clear();
|
||||
namaController.clear();
|
||||
_imagePath = null;
|
||||
imageFile = null;
|
||||
imageBytes = null;
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
log.e(e);
|
||||
} finally {
|
||||
easyLoading.dismissLoading();
|
||||
globalVar.backPressed = 'exitApp';
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:stacked_services/stacked_services.dart';
|
||||
import 'package:stylish_bottom_bar/model/bar_items.dart';
|
||||
import 'package:stylish_bottom_bar/stylish_bottom_bar.dart';
|
||||
|
||||
import '../../../app/app.router.dart';
|
||||
import '../../../app/themes/app_colors.dart';
|
||||
import '../../../app/themes/app_text.dart';
|
||||
import './tim_survei_index_tracking_view_model.dart';
|
||||
|
||||
class TimSurveiIndexTrackingView extends StatelessWidget {
|
||||
const TimSurveiIndexTrackingView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ViewModelBuilder<TimSurveiIndexTrackingViewModel>.reactive(
|
||||
viewModelBuilder: () => TimSurveiIndexTrackingViewModel(),
|
||||
onViewModelReady: (TimSurveiIndexTrackingViewModel model) async {
|
||||
await model.init();
|
||||
},
|
||||
builder: (
|
||||
BuildContext context,
|
||||
TimSurveiIndexTrackingViewModel model,
|
||||
Widget? child,
|
||||
) {
|
||||
return Scaffold(
|
||||
extendBody: false,
|
||||
body: ExtendedNavigator(
|
||||
router: TimSurveiIndexTrackingViewRouter(),
|
||||
navigatorKey: StackedService.nestedNavigationKey(5),
|
||||
),
|
||||
bottomNavigationBar: StylishBottomBar(
|
||||
items: [
|
||||
for (var item in model.bottomNavBarList)
|
||||
BottomBarItem(
|
||||
icon: Icon(item['icon'],
|
||||
color: model.currentIndex ==
|
||||
model.bottomNavBarList.indexOf(item)
|
||||
? warningColor
|
||||
: fontColor),
|
||||
title: Text(
|
||||
item['name'],
|
||||
style: regularTextStyle.copyWith(
|
||||
color: model.currentIndex ==
|
||||
model.bottomNavBarList.indexOf(item)
|
||||
? warningColor
|
||||
: fontColor,
|
||||
),
|
||||
// textAlign: TextAlign.l,
|
||||
),
|
||||
backgroundColor:
|
||||
model.currentIndex == model.bottomNavBarList.indexOf(item)
|
||||
? fontColor
|
||||
: fontColor,
|
||||
),
|
||||
],
|
||||
currentIndex: model.currentIndex,
|
||||
option: BubbleBarOptions(),
|
||||
hasNotch: true,
|
||||
backgroundColor: warningColor,
|
||||
onTap: (value) {
|
||||
model.handleNavigation(value);
|
||||
},
|
||||
// fabLocation: StylishBarFabLocation.center,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:stacked_services/stacked_services.dart';
|
||||
|
||||
import '../../../app/app.locator.dart';
|
||||
import '../../../app/app.logger.dart';
|
||||
import '../../../app/app.router.dart';
|
||||
import '../../../services/global_var.dart';
|
||||
import '../../../services/shared_prefs.dart';
|
||||
|
||||
class TimSurveiIndexTrackingViewModel extends IndexTrackingViewModel {
|
||||
final log = getLogger('TimSurveiIndexTrackingViewModel');
|
||||
final mySharedPrefs = locator<MySharedPrefs>();
|
||||
final navigationService = locator<NavigationService>();
|
||||
final snackbarService = locator<SnackbarService>();
|
||||
final globalVar = locator<GlobalVar>();
|
||||
|
||||
final _bottomNavBarList = [
|
||||
{
|
||||
'name': 'Survei',
|
||||
'icon': Icons.supervised_user_circle_outlined,
|
||||
'header': 'Halaman Survei',
|
||||
},
|
||||
{
|
||||
'name': 'History',
|
||||
'icon': Icons.history_edu_outlined,
|
||||
'header': 'History Survei',
|
||||
},
|
||||
{
|
||||
'name': 'Pengaturan',
|
||||
'icon': Icons.settings_outlined,
|
||||
'header': 'Pengaturan',
|
||||
},
|
||||
];
|
||||
|
||||
String header = 'Pengaturan';
|
||||
|
||||
List<Map<String, dynamic>> get bottomNavBarList => _bottomNavBarList;
|
||||
|
||||
final List<String> _views = [
|
||||
TimSurveiIndexTrackingViewRoutes.halamanSurveiView,
|
||||
TimSurveiIndexTrackingViewRoutes.halamanHistoryView,
|
||||
TimSurveiIndexTrackingViewRoutes.halamanPengaturanView,
|
||||
];
|
||||
|
||||
Future<void> init() async {
|
||||
if (await mySharedPrefs.getString('level') != 'tim_survei') {
|
||||
snackbarService.showSnackbar(
|
||||
message: 'Anda tidak memiliki akses',
|
||||
title: 'Akses Ditolak',
|
||||
duration: const Duration(milliseconds: 2500),
|
||||
);
|
||||
navigationService.clearStackAndShow(Routes.loginScreenView);
|
||||
}
|
||||
setIndex(2);
|
||||
}
|
||||
|
||||
void handleNavigation(int index) {
|
||||
// log.d("handleNavigation: $index");
|
||||
// log.d("currentIndex: $currentIndex");
|
||||
|
||||
// if (currentIndex == index) return;
|
||||
|
||||
setIndex(index);
|
||||
header = _bottomNavBarList[index]['header'] as String;
|
||||
navigationService.navigateTo(
|
||||
_views[index],
|
||||
id: 5,
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user