added cek suara bottom sheet and detail suara bottom sheet

This commit is contained in:
kicap
2023-11-04 05:58:20 +08:00
parent 283f793d29
commit 2f9e6703ef
17 changed files with 664 additions and 219 deletions

View File

@ -7,18 +7,23 @@
import 'package:stacked_services/stacked_services.dart';
import 'app.locator.dart';
import '../ui/views/admin_index_tracking/halaman_caleg/coba_bottom_sheet/coba_bottom_sheet_view.dart';
import '../ui/views/admin_index_tracking/detail_suara_bottom_sheet/detail_suara_bottom_sheet_view.dart';
import '../ui/views/admin_index_tracking/detail_suara_pemilih_bottom_sheet/detail_suara_pemilih_bottom_sheet_view.dart';
enum BottomSheetType {
cobaBottomSheetView,
detailSuaraBottomSheetView,
detailSuaraPemilihBottomSheetView,
}
void setupBottomSheetUi() {
final bottomsheetService = locator<BottomSheetService>();
final Map<BottomSheetType, SheetBuilder> builders = {
BottomSheetType.cobaBottomSheetView: (context, request, completer) =>
CobaBottomSheetView(request: request, completer: completer),
BottomSheetType.detailSuaraBottomSheetView: (context, request, completer) =>
DetailSuaraBottomSheetView(request: request, completer: completer),
BottomSheetType.detailSuaraPemilihBottomSheetView:
(context, request, completer) => DetailSuaraPemilihBottomSheetView(
request: request, completer: completer),
};
bottomsheetService.setCustomSheetBuilders(builders);

View File

@ -1,4 +1,4 @@
import 'package:cek_suara/ui/views/admin_index_tracking/halaman_caleg/coba_bottom_sheet/coba_bottom_sheet_view.dart';
import 'package:cek_suara/ui/views/admin_index_tracking/detail_suara_pemilih_bottom_sheet/detail_suara_pemilih_bottom_sheet_view.dart';
import 'package:stacked_services/stacked_services.dart';
import 'package:stacked/stacked_annotations.dart';
@ -8,6 +8,7 @@ import '../services/my_easyloading.dart';
import '../services/other_function.dart';
import '../ui/views/admin_index_tracking/admin_first_page/admin_first_page_view.dart';
import '../ui/views/admin_index_tracking/admin_index_tracking_view.dart';
import '../ui/views/admin_index_tracking/detail_suara_bottom_sheet/detail_suara_bottom_sheet_view.dart';
import '../ui/views/admin_index_tracking/halaman_area/halaman_area_view.dart';
import '../ui/views/admin_index_tracking/halaman_caleg/halaman_caleg_view.dart';
import '../ui/views/admin_index_tracking/halaman_caleg/tambah_edit_caleg/tambah_edit_caleg_view.dart';
@ -45,10 +46,11 @@ import '../ui/views/splash_screen/splash_screen_view.dart';
],
dialogs: [
StackedDialog(classType: TambahEditCalegView),
StackedDialog(classType: TambahDetailTimSurveiView)
StackedDialog(classType: TambahDetailTimSurveiView),
],
bottomsheets: [
StackedBottomsheet(classType: CobaBottomSheetView),
StackedBottomsheet(classType: DetailSuaraBottomSheetView),
StackedBottomsheet(classType: DetailSuaraPemilihBottomSheetView),
],
dependencies: [
LazySingleton(classType: NavigationService),

View File

@ -0,0 +1,75 @@
import '../app/app.locator.dart';
import '../services/other_function.dart';
class PemilihDetailModel {
List<PemilihModel>? pemilihModel;
int? jumlah;
PemilihDetailModel({this.pemilihModel, this.jumlah});
PemilihDetailModel.fromJson(Map<String, dynamic> json) {
if (json['data'] != null) {
pemilihModel = <PemilihModel>[];
json['data'].forEach((v) {
pemilihModel!.add(PemilihModel.fromJson(v));
});
}
jumlah = json['jumlah'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
if (pemilihModel != null) {
data['data'] = pemilihModel!.map((v) => v.toJson()).toList();
}
data['jumlah'] = jumlah;
return data;
}
}
class PemilihModel {
final myFunction = locator<MyFunction>();
String? nikNomorHp;
String? namaPemilih;
String? img;
String? nikTimSurvei;
String? namaTimSurvei;
String? namaCaleg;
String? namaArea;
String? createdAt;
PemilihModel(
{this.nikNomorHp,
this.namaPemilih,
this.img,
this.nikTimSurvei,
this.namaTimSurvei,
this.namaCaleg,
this.namaArea,
this.createdAt});
PemilihModel.fromJson(Map<String, dynamic> json) {
nikNomorHp = json['nik_nomor_hp'];
namaPemilih = json['nama_pemilih'];
img = json['img'];
nikTimSurvei = json['nik_tim_survei'];
namaTimSurvei = json['nama_tim_survei'];
namaCaleg = json['nama_caleg'];
namaArea = json['nama_area'];
createdAt = myFunction.convertDateTime(json['created_at']);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['nik_nomor_hp'] = nikNomorHp;
data['nama_pemilih'] = namaPemilih;
data['img'] = img;
data['nik_tim_survei'] = nikTimSurvei;
data['nama_tim_survei'] = namaTimSurvei;
data['nama_caleg'] = namaCaleg;
data['nama_area'] = namaArea;
data['created_at'] = createdAt;
return data;
}
}

View File

@ -7,4 +7,10 @@ class MyFunction {
DateFormat('dd-MM-yyyy | hh.mm.ss a').format(dateTime);
return formattedDateTime;
}
// chnage | to \n in string
String convertDateTime2(String input) {
input = input.replaceAll('| ', '\n');
return input;
}
}

View File

@ -24,7 +24,8 @@ class AdminIndexTrackingView extends StatelessWidget {
AdminIndexTrackingViewModel model,
Widget? child,
) {
return Scaffold(
return SafeArea(
child: Scaffold(
extendBody: false,
body: ExtendedNavigator(
router: AdminIndexTrackingViewRouter(),
@ -49,8 +50,8 @@ class AdminIndexTrackingView extends StatelessWidget {
),
// textAlign: TextAlign.l,
),
backgroundColor:
model.currentIndex == model.bottomNavBarList.indexOf(item)
backgroundColor: model.currentIndex ==
model.bottomNavBarList.indexOf(item)
? fontColor
: fontColor,
),
@ -64,6 +65,7 @@ class AdminIndexTrackingView extends StatelessWidget {
},
// fabLocation: StylishBarFabLocation.center,
),
),
);
},
);

View File

@ -0,0 +1,141 @@
import 'package:cek_suara/app/themes/app_colors.dart';
import 'package:cek_suara/app/themes/app_text.dart';
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
import './detail_suara_bottom_sheet_view_model.dart';
class DetailSuaraBottomSheetView extends StatelessWidget {
final SheetRequest? request;
final Function(SheetResponse)? completer;
const DetailSuaraBottomSheetView({
Key? key,
this.request,
this.completer,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ViewModelBuilder<DetailSuaraBottomSheetViewModel>.reactive(
viewModelBuilder: () => DetailSuaraBottomSheetViewModel(),
onViewModelReady: (DetailSuaraBottomSheetViewModel model) async {
await model.init(request!);
},
builder: (
BuildContext context,
DetailSuaraBottomSheetViewModel model,
Widget? child,
) {
return SafeArea(
child: Container(
width: MediaQuery.of(context).size.width,
padding: const EdgeInsets.all(20),
alignment: Alignment.topCenter,
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
child: Column(
children: [
Text(
request!.title!,
style: italicTextStyle.copyWith(
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 20),
Expanded(
child: Container(
padding: const EdgeInsets.all(15),
decoration: BoxDecoration(
color: warningColor,
borderRadius: BorderRadius.circular(10),
),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisSize: MainAxisSize.min,
children: [
Text(
'Jumlah Suara: ${model.counter}',
style: boldTextStyle,
),
const SizedBox(height: 10),
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.myFunction
.convertDateTime2(
model.listPemilih[i].createdAt!)),
title: Text(
model.listPemilih[i].namaPemilih!,
style: boldTextStyle,
),
subtitle: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
if (request!.description == 'Caleg')
Text(
model.listPemilih[i].namaTimSurvei!,
style: italicTextStyle,
),
Text(
model.listPemilih[i].namaArea!,
),
],
),
trailing: IconButton(
icon: const Icon(
Icons.info_outline,
color: mainColor,
),
onPressed: () {
model.showDetailPemilih(
model.listPemilih[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,
),
),
],
),
),
),
),
],
),
),
);
},
);
}
}

View File

@ -0,0 +1,50 @@
import 'package:cek_suara/model/pemilih_model.dart';
import '../../../../app/app.bottomsheets.dart';
import '../../../../app/app.logger.dart';
import '../../../../app/core/custom_base_view_model.dart';
import '../../../../model/my_response.model.dart';
class DetailSuaraBottomSheetViewModel extends CustomBaseViewModel {
final log = getLogger('DetailSuaraBottomSheetViewModel');
bool status = false;
List<PemilihModel> listPemilih = [];
int counter = 0;
Future<void> init(sheetRequest) async {
String id = sheetRequest.data.toString();
String status = sheetRequest.description;
await getData(id, status);
}
getData(String id, String status) async {
setBusy(true);
try {
var response = await httpService.get('caleg/suara/$id');
MyResponseModel myResponseModel = MyResponseModel.fromJson(response.data);
PemilihDetailModel pemilihDetailModel =
PemilihDetailModel.fromJson(myResponseModel.data);
listPemilih = pemilihDetailModel.pemilihModel!;
counter = pemilihDetailModel.jumlah!;
this.status = true;
} catch (e) {
this.status = false;
} finally {
setBusy(false);
}
}
showDetailPemilih(PemilihModel listPemilih) async {
await bottomSheetService.showCustomSheet(
variant: BottomSheetType.detailSuaraPemilihBottomSheetView,
title: 'Detail Suara Pemilih',
description: 'Detail Suara Pemilih',
// isScrollControlled: true,
data: listPemilih,
);
}
}

View File

@ -0,0 +1,157 @@
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 '../../../../../app/themes/app_colors.dart';
import '../../../../../app/themes/app_text.dart';
import './detail_suara_pemilih_bottom_sheet_view_model.dart';
class DetailSuaraPemilihBottomSheetView extends StatelessWidget {
final SheetRequest request;
final Function(SheetResponse)? completer;
const DetailSuaraPemilihBottomSheetView({
Key? key,
required this.request,
this.completer,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ViewModelBuilder<DetailSuaraPemilihBottomSheetViewModel>.reactive(
viewModelBuilder: () => DetailSuaraPemilihBottomSheetViewModel(),
onViewModelReady: (DetailSuaraPemilihBottomSheetViewModel model) async {
await model.init();
},
builder: (
BuildContext context,
DetailSuaraPemilihBottomSheetViewModel model,
Widget? child,
) {
return SafeArea(
child: Container(
width: MediaQuery.of(context).size.width,
padding: const EdgeInsets.all(20),
alignment: Alignment.topCenter,
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16.0),
topRight: Radius.circular(16.0),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
request.title!,
style: boldTextStyle.copyWith(
fontSize: 16,
color: fontColor,
),
),
const SizedBox(height: 15),
Container(
height: 100,
width: 150,
decoration: BoxDecoration(
color: mainColor,
borderRadius: BorderRadius.circular(10),
),
child: GestureDetector(
onTap: () {
model.showImage(
context,
dotenv.env['url']! + request.data!.img!,
);
},
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.network(
dotenv.env['url']! + request.data!.img!,
fit: BoxFit.fill,
errorBuilder: (context, error, stackTrace) {
return const Center(
child: Icon(
Icons.error,
color: backgroundColor,
size: 50,
),
);
},
),
),
),
),
_DetailChildWidget(
title: 'Nama',
value: request.data!.namaPemilih!,
),
_DetailChildWidget(
title: 'No KTP /\nNo HP',
value: request.data!.nikNomorHp!,
),
_DetailChildWidget(
title: 'Tanggal/\nWaktu',
value: request.data!.createdAt!,
),
],
),
),
);
},
);
}
}
class _DetailChildWidget extends StatelessWidget {
const _DetailChildWidget({
Key? key,
required this.title,
required this.value,
}) : super(key: key);
final String title;
final String value;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 15),
child: Row(
children: [
Expanded(
flex: 3,
child: Text(
title,
style: boldTextStyle.copyWith(
fontSize: 16,
color: fontColor,
),
),
),
Expanded(
flex: 1,
child: Text(
' : ',
style: boldTextStyle.copyWith(
fontSize: 16,
color: fontColor,
),
),
),
Expanded(
flex: 7,
child: Text(
value,
style: italicTextStyle.copyWith(
fontSize: 16,
color: fontColor,
),
),
),
],
),
);
}
}

View File

@ -0,0 +1,23 @@
import 'package:easy_image_viewer/easy_image_viewer.dart';
import 'package:flutter/material.dart';
import '../../../../../app/app.logger.dart';
import '../../../../../app/core/custom_base_view_model.dart';
class DetailSuaraPemilihBottomSheetViewModel extends CustomBaseViewModel {
final log = getLogger('DetailSuaraPemilihBottomSheetViewModel');
Future<void> init() async {}
showImage(BuildContext context, String? url) async {
log.i(url);
showImageViewer(
context,
Image.network(
url!,
fit: BoxFit.fill,
).image,
swipeDismissible: true,
doubleTapZoomable: true,
);
}
}

View File

@ -1,44 +0,0 @@
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
import './coba_bottom_sheet_view_model.dart';
class CobaBottomSheetView extends StatelessWidget {
final SheetRequest? request;
final Function(SheetResponse)? completer;
const CobaBottomSheetView({
Key? key,
this.request,
this.completer,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ViewModelBuilder<CobaBottomSheetViewModel>.reactive(
viewModelBuilder: () => CobaBottomSheetViewModel(),
onViewModelReady: (CobaBottomSheetViewModel model) async {
await model.init();
},
builder: (
BuildContext context,
CobaBottomSheetViewModel model,
Widget? child,
) {
return SafeArea(
child: Container(
padding: const EdgeInsets.all(20),
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
child: const Text('Coba Bottom Sheet'),
),
);
},
);
}
}

View File

@ -1,5 +0,0 @@
import 'package:cek_suara/app/core/custom_base_view_model.dart';
class CobaBottomSheetViewModel extends CustomBaseViewModel {
Future<void> init() async {}
}

View File

@ -55,6 +55,7 @@ class HalamanCalegView extends StatelessWidget {
borderRadius: BorderRadius.circular(10),
color: warningColor,
),
child: SingleChildScrollView(
child: Column(
// mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
@ -74,12 +75,15 @@ class HalamanCalegView extends StatelessWidget {
SingleChildScrollView(
child: Column(
children: [
for (var i = 0; i < model.jumlahCaleg; i++)
for (var i = 0;
i < model.jumlahCaleg;
i++)
Card(
child: ListTile(
leading: Text('${i + 1}'),
title: Text(
model.listCalegModel[i].namaCaleg!,
model
.listCalegModel[i].namaCaleg!,
style: boldTextStyle,
),
subtitle: Text(
@ -95,8 +99,8 @@ class HalamanCalegView extends StatelessWidget {
color: mainColor,
),
onPressed: () {
model.showDetailCaleg(
model.listCalegModel[i]);
model.showDetailCaleg(model
.listCalegModel[i]);
},
),
IconButton(
@ -106,8 +110,8 @@ class HalamanCalegView extends StatelessWidget {
color: dangerColor,
),
onPressed: () {
model.deleteCaleg(
model.listCalegModel[i]);
model.deleteCaleg(model
.listCalegModel[i]);
},
),
],
@ -131,6 +135,7 @@ class HalamanCalegView extends StatelessWidget {
),
),
),
),
],
),
),

View File

@ -217,7 +217,8 @@ class TambahEditCalegView extends StatelessWidget {
),
),
const SizedBox(height: 10),
if (model.calegModel == null)
if (model.calegModel == null &&
request.title == 'Tambah Caleg')
SizedBox(
width: 250,
child: MyButton(
@ -291,13 +292,15 @@ class TambahEditCalegView extends StatelessWidget {
width: 50,
height: 50,
decoration: BoxDecoration(
color: mainColor.withOpacity(0.5),
color: mainColor,
borderRadius: BorderRadius.circular(50),
),
child: IconButton(
onPressed: () {},
onPressed: () {
model.checkSuara(model.calegModel!);
},
icon: const Icon(
Icons.info,
Icons.list_alt,
color: Colors.white,
),
),

View File

@ -5,6 +5,7 @@ import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:http_parser/http_parser.dart';
import '../../../../../app/app.bottomsheets.dart';
import '../../../../../app/app.logger.dart';
import '../../../../../app/core/custom_base_view_model.dart';
@ -190,4 +191,17 @@ class TambahEditCalegViewModel extends CustomBaseViewModel {
// remove all dialog
}
}
checkSuara(CalegModel calegModel) async {
log.i('calegModel: ${calegModel.toJson()}');
await bottomSheetService.showCustomSheet(
data: calegModel.idCaleg,
barrierDismissible: true,
isScrollControlled: true,
title: 'Detail Suara Caleg ${calegModel.namaCaleg}',
description: 'Caleg',
ignoreSafeArea: false,
variant: BottomSheetType.detailSuaraBottomSheetView,
);
}
}

View File

@ -20,7 +20,8 @@ class SplashScreenView extends StatelessWidget {
SplashScreenViewModel model,
Widget? child,
) {
return Scaffold(
return SafeArea(
child: Scaffold(
backgroundColor: warningColor,
body: Center(
child: Column(
@ -83,6 +84,7 @@ class SplashScreenView extends StatelessWidget {
],
),
),
),
);
},
);

View File

@ -193,6 +193,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.3.3"
easy_image_viewer:
dependency: "direct main"
description:
name: easy_image_viewer
sha256: "8d11a4630e9beb7aacf043c98da2dd4b3bc3b47aa4073d2016ba696376161272"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
fake_async:
dependency: transitive
description:

View File

@ -51,6 +51,7 @@ dependencies:
validatorless: ^1.2.3
http_parser:
intl:
easy_image_viewer:
dev_dependencies: