From 58357fe7b6553d619a7d953be61a7fcb330081f0 Mon Sep 17 00:00:00 2001 From: jovi_013 Date: Mon, 31 May 2021 14:39:24 +0700 Subject: [PATCH 1/2] [CHORES] Add dependencies --- pubspec.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pubspec.yaml b/pubspec.yaml index 9a7a51c..7273be9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -58,6 +58,8 @@ dependencies: carousel_slider: ^3.0.0 url_launcher: ^6.0.3 photo_view: ^0.11.1 + multi_image_picker: ^4.8.1 + permission_handler: ^5.1.0+2 dev_dependencies: flutter_test: -- GitLab From cc34d637ad4683008e891b6df43dec3c80855129 Mon Sep 17 00:00:00 2001 From: jovi_013 Date: Mon, 31 May 2021 14:41:15 +0700 Subject: [PATCH 2/2] [WIP] Multi image picker --- lib/page/filter_fasilitas/add_kegiatan.dart | 432 ++++++++++++-------- 1 file changed, 262 insertions(+), 170 deletions(-) diff --git a/lib/page/filter_fasilitas/add_kegiatan.dart b/lib/page/filter_fasilitas/add_kegiatan.dart index 45233ae..4aaefeb 100644 --- a/lib/page/filter_fasilitas/add_kegiatan.dart +++ b/lib/page/filter_fasilitas/add_kegiatan.dart @@ -3,7 +3,6 @@ import 'dart:io'; import 'package:bisaGo/bloc/kegiatan_bloc.dart'; import 'package:bisaGo/component/bisago_appbar.dart'; -import 'package:bisaGo/component/image_preview_holder.dart'; // import 'package:bisaGo/config/strings.dart'; import 'package:bisaGo/config/styles.dart'; import 'package:bisaGo/model/kegiatan.dart'; @@ -11,6 +10,7 @@ import 'package:bisaGo/utils/custom_button.dart'; // import 'package:bisaGo/utils/custom_dropdown.dart'; import 'package:bisaGo/utils/custom_text_field.dart'; import 'package:bisaGo/utils/validator.dart'; +import 'package:carousel_slider/carousel_slider.dart'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_datetime_picker/flutter_datetime_picker.dart'; @@ -18,6 +18,8 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:image_picker/image_picker.dart'; import 'package:intl/intl.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; +import 'package:multi_image_picker/multi_image_picker.dart'; +import 'package:permission_handler/permission_handler.dart'; class AddKegiatan extends StatefulWidget { AddKegiatan({ @@ -45,6 +47,8 @@ class _AddKegiatanState extends State { String tanggalKegiatan = '${DateFormat('yyyy-MM-ddTHH:mm').format(DateTime.now())}'; + + List images = []; @override Widget build(BuildContext context) { @@ -95,6 +99,127 @@ class _AddKegiatanState extends State { ); } + Future _submitData() async { + final form = _formKey.currentState; + if (_formKey.currentState.validate()) { + form.save(); + + final fileName = _image.path.split('/').last; + final _imageFile = await MultipartFile.fromFile( + _image.path, + filename: fileName, + ); + + final newKegiatan = KegiatanModel( + namaKegiatan: namaKegiatanController.text, + penyelenggara: penyelenggaraController.text, + deskripsi: deskripsiController.text, + namaKontak: namaKontakController.text, + nomorKontak: nomorKontakController.text, + links: linkController.text, + timeStart: DateTime.parse(tanggalKegiatan), + timeEnd: DateTime.parse(tanggalKegiatan).add( + Duration(days: 1), + ), + ); + + final newKegiatanData = newKegiatan.toJson(); + newKegiatanData['images'] = _imageFile; + + final _bloc = KegiatanBloc(widget.placeId); + await _bloc.addNewKegiatan( + newKegiatanData, + widget.placeId, + ); + + successDialog(context); + Timer(const Duration(seconds: 2), () { + Navigator.pop(context); + Navigator.pop(context); + }); + } else { + failedDialog(context, ''); + } + } + + void successDialog(BuildContext context) { + const alertDialog = AlertDialog( + title: Text('Tambah informasi berhasil'), + content: Icon(FontAwesomeIcons.checkCircle), + ); + showDialog( + context: context, + builder: (BuildContext context) { + return alertDialog; + }); + } + + void failedDialog(BuildContext context, String message) { + var newMessage = message; + if (message == 'default') { + newMessage = 'Gagal menambahkan informasi'; + } + final alertDialog = AlertDialog( + title: Text(newMessage), + content: const Icon( + FontAwesomeIcons.exclamationCircle, + ), + ); + showDialog( + context: context, + builder: (BuildContext context) { + return alertDialog; + }); + } + + final picker = ImagePicker(); + File _image; + + Future _getCameraImage() async { + final image = + await picker.getImage(source: ImageSource.camera, imageQuality: 50); + return File(image.path); + } + + Future pickImages() async { + var resultList = []; + // var status = await Permission.camera.status; + + try { + // if (status.isGranted) { + + // } + resultList = await MultiImagePicker.pickImages( + maxImages: 300, + enableCamera: true, + selectedAssets: images, + materialOptions: MaterialOptions( + actionBarTitle: widget.nama, + actionBarColor: '#ff3A903A', + useDetailsView: true, + ), + ); + } on Exception catch (e) { + print(e); + } + + setState(() { + images = resultList; + }); + } + +// Future checkAndRequestCameraPermissions() async { +// PermissionStatus permission = +// await PermissionHandler().checkPermissionStatus(PermissionGroup.camera); +// if (permission != PermissionStatus.granted) { +// Map permissions = +// await PermissionHandler().requestPermissions([PermissionGroup.camera]); +// return permissions[PermissionGroup.camera] == PermissionStatus.granted; +// } else { +// return true; +// } +// } + Widget namaLokasi() { return Padding( padding: const EdgeInsets.only(bottom: doubleSpace), @@ -276,196 +401,163 @@ class _AddKegiatanState extends State { } Widget fotoField() { - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Foto', - style: TextStyle(fontSize: 18), - textAlign: TextAlign.left, - ), - TextButton( - key: const Key('Button Input Foto Gallery'), - style: TextButton.styleFrom(padding: EdgeInsets.zero), - onPressed: () async { - final imageSelected = await _getImage(); - setState(() { - _image = imageSelected; - }); - }, - child: Container( - width: MediaQuery.of(context).size.width * 0.35, - padding: const EdgeInsets.all(9.0), - alignment: Alignment.centerLeft, - decoration: BoxDecoration( - boxShadow: regularShadow, - borderRadius: BorderRadius.circular(10.0), - color: greenPrimary), - child: Row( - children: [ - const Icon( - MdiIcons.imagePlus, - color: Colors.white, - size: 14.0, - ), - const SizedBox(width: regularSpace), - const Text( - 'Dari Gallery', - style: TextStyle( - color: Colors.white, fontSize: 14.0), - ), - ], - ), + return Padding( + padding: const EdgeInsets.only(bottom: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Foto', + style: TextStyle(fontSize: 18), + textAlign: TextAlign.left, ), - ), - TextButton( - key: const Key('Button Input Foto Camera'), - style: TextButton.styleFrom(padding: EdgeInsets.zero), - onPressed: () async { - final imageSelected = await _getCameraImage(); - setState(() { - _image = imageSelected; - }); - }, - child: Container( - width: MediaQuery.of(context).size.width * 0.35, - padding: const EdgeInsets.all(9.0), - alignment: Alignment.centerLeft, - decoration: BoxDecoration( - boxShadow: regularShadow, - borderRadius: BorderRadius.circular(10.0), - color: greenPrimary), - child: Row( - children: [ - const Icon( - MdiIcons.imagePlus, - color: Colors.white, - size: 14.0, - ), - const SizedBox(width: regularSpace), - const Text( - 'Dari Kamera', - style: TextStyle( - color: Colors.white, fontSize: 14.0), - ), - ], + TextButton( + key: const Key('Button Input Foto Gallery'), + style: TextButton.styleFrom(padding: EdgeInsets.zero), + onPressed: () async { + await pickImages(); + }, + + child: Container( + width: MediaQuery.of(context).size.width * 0.35, + padding: const EdgeInsets.all(9.0), + alignment: Alignment.centerLeft, + decoration: BoxDecoration( + boxShadow: regularShadow, + borderRadius: BorderRadius.circular(10.0), + color: greenPrimary), + child: Row( + children: [ + const Icon( + MdiIcons.imagePlus, + color: Colors.white, + size: 14.0, + ), + const SizedBox(width: regularSpace), + const Text( + 'Dari Gallery', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ], + ), ), ), - ) - ], + TextButton( + key: const Key('Button Input Foto Camera'), + style: TextButton.styleFrom(padding: EdgeInsets.zero), + onPressed: () async { + final imageSelected = await _getCameraImage(); + setState(() { + _image = imageSelected; + }); + }, + child: Container( + width: MediaQuery.of(context).size.width * 0.35, + padding: const EdgeInsets.all(9.0), + alignment: Alignment.centerLeft, + decoration: BoxDecoration( + boxShadow: regularShadow, + borderRadius: BorderRadius.circular(10.0), + color: greenPrimary), + child: Row( + children: [ + const Icon( + MdiIcons.imagePlus, + color: Colors.white, + size: 14.0, + ), + const SizedBox(width: regularSpace), + const Text( + 'Dari Kamera', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ], + ), + ), + ) + ], + ), ); } Widget simpanButton() { return Container( - margin: const EdgeInsets.only(top: tripleSpace), + margin: const EdgeInsets.only(top: doubleSpace), alignment: Alignment.center, child: ButtonTheme( key: const Key('Button Simpan'), minWidth: double.infinity, height: 40, - child: submitButton('Simpan', _validateLoginInput), + child: submitButton('Simpan', _submitData), ) ); } - Future _validateLoginInput() async { - final form = _formKey.currentState; - if (_formKey.currentState.validate()) { - form.save(); - - final fileName = _image.path.split('/').last; - final _imageFile = await MultipartFile.fromFile( - _image.path, - filename: fileName, - ); - - final newKegiatan = KegiatanModel( - namaKegiatan: namaKegiatanController.text, - penyelenggara: penyelenggaraController.text, - deskripsi: deskripsiController.text, - namaKontak: namaKontakController.text, - nomorKontak: nomorKontakController.text, - links: linkController.text, - timeStart: DateTime.parse(tanggalKegiatan), - timeEnd: DateTime.parse(tanggalKegiatan).add( - Duration(days: 1), - ), - ); - - final newKegiatanData = newKegiatan.toJson(); - newKegiatanData['images'] = _imageFile; - - final _bloc = KegiatanBloc(widget.placeId); - await _bloc.addNewKegiatan( - newKegiatanData, - widget.placeId, - ); - - successDialog(context); - Timer(const Duration(seconds: 2), () { - Navigator.pop(context); - Navigator.pop(context); - }); - } else { - failedDialog(context, ''); - } - } - Widget _showImagePreview() { - return _image == null + return images.isEmpty ? const SizedBox(height: 0) - : ImagePreviewHolder( - image: Image.file(_image), - onPressed: () async { - setState(() { - _image = null; - }); - }, - ); - } - - void successDialog(BuildContext context) { - const alertDialog = AlertDialog( - title: Text('Tambah informasi berhasil'), - content: Icon(FontAwesomeIcons.checkCircle), - ); - showDialog( - context: context, - builder: (BuildContext context) { - return alertDialog; - }); + : carousel(); } - void failedDialog(BuildContext context, String message) { - var newMessage = message; - if (message == 'default') { - newMessage = 'Gagal menambahkan informasi'; - } - final alertDialog = AlertDialog( - title: Text(newMessage), - content: const Icon( - FontAwesomeIcons.exclamationCircle, - ), + Widget carousel() { + return SizedBox( + width: MediaQuery.of(context).size.width, + height: 160, + child: CarouselSlider( + options: CarouselOptions( + aspectRatio: 1.0, + enlargeCenterPage: true, + enableInfiniteScroll: false, + initialPage: 0, + autoPlay: true, + ), + items: images.map((item) => Container( + child: ClipRRect( + borderRadius: BorderRadius.all(Radius.circular(20)), + child: Stack( + children: [ + AssetThumb( + asset: item, + width: MediaQuery.of(context).size.height.toInt(), + height: MediaQuery.of(context).size.width.toInt(), + ), + Positioned( + bottom: 0.0, + left: 0.0, + right: 0.0, + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + Color.fromARGB( + 200, 0, 0, 0), + Color.fromARGB(0, 0, 0, 0) + ], + begin: + Alignment.bottomCenter, + end: Alignment.topCenter, + ), + ), + padding: EdgeInsets.symmetric( + vertical: 10.0, + horizontal: 20.0), + child: Text( + '#${images.indexOf(item) + 1}', + style: TextStyle( + color: Colors.white, + fontSize: 20.0, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ) + ), + ), + ).toList()), ); - showDialog( - context: context, - builder: (BuildContext context) { - return alertDialog; - }); - } - - final picker = ImagePicker(); - File _image; - - Future _getImage() async { - final image = await picker.getImage(source: ImageSource.gallery); - return File(image.path); - } - - Future _getCameraImage() async { - final image = - await picker.getImage(source: ImageSource.camera, imageQuality: 50); - return File(image.path); } } -- GitLab