Fakultas Ilmu Komputer UI

Commit 02b099bd authored by Ardian Ghifari's avatar Ardian Ghifari
Browse files

Merge branch 'dev-ardian' into 'PBI-15-redesign_menu'

Add shimmer loading effect

See merge request !77
parents 828e3da4 0ec4b120
Pipeline #82078 failed with stages
in 10 minutes and 48 seconds
import 'dart:async';
import 'dart:io';
// 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';
import 'package:bisaGo/utils/custom_button.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/widgets.dart';
import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:image_picker/image_picker.dart';
import 'package:http_parser/http_parser.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({
......@@ -34,14 +38,18 @@ class AddKegiatan extends StatefulWidget {
class _AddKegiatanState extends State<AddKegiatan> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
TextEditingController nameController = TextEditingController();
TextEditingController phoneController = TextEditingController();
TextEditingController namaKegiatanController = TextEditingController();
TextEditingController penyelenggaraController = TextEditingController();
TextEditingController narahubungController = TextEditingController();
TextEditingController deskripsiController = TextEditingController();
TextEditingController namaKontakController = TextEditingController();
TextEditingController nomorKontakController = TextEditingController();
TextEditingController linkController = TextEditingController();
String tanggalKegiatan =
'${DateFormat('yyyy-MM-dd hh:mm').format(DateTime.now())}';
'${DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now())}';
String zonaCurrent = 'WIB';
List<Asset> images = <Asset>[];
bool permissionGranted = false;
@override
Widget build(BuildContext context) {
......@@ -71,184 +79,17 @@ class _AddKegiatanState extends State<AddKegiatan> {
bottom: tripleSpace),
child: ListBody(
children: <Widget>[
CustomTextField(
title: 'Nama Kegiatan',
required: true,
key: const Key('Text Field Nama'),
validator: FieldValidator.validateName,
controller: nameController,
),
CustomTextField(
title: 'Penyelenggara',
required: true,
key: const Key('Text Field Penyelenggara'),
validator: FieldValidator.validateName,
controller: penyelenggaraController,
),
CustomTextField(
title: 'Nomor Telepon Narahubung',
required: true,
key: const Key('Text Field Nomor Telepon Narahubung'),
validator: FieldValidator.validateName,
controller: narahubungController,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
const Text(
'Tanggal Kegiatan',
style: TextStyle(fontSize: 18),
textAlign: TextAlign.left,
),
const SizedBox(height: 10.0),
TextButton(
key: const Key('Button Tanggal Kegiatan'),
style: TextButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0)),
padding: const EdgeInsets.all(13.0),
backgroundColor: greenPrimary,
),
onPressed: () {
DatePicker.showDateTimePicker(
context,
currentTime: DateTime.parse(tanggalKegiatan),
onChanged: (date) {
setState(() {
tanggalKegiatan =
'${DateFormat('yyyy-MM-dd hh:mm').format(date)}';
});
},
);
},
child: Text(
tanggalKegiatan,
style: const TextStyle(
fontSize: 15.0, color: Colors.white),
),
),
],
),
SizedBox(height: 16),
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),
),
],
),
),
),
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),
),
],
),
),
)
],
),
namaLokasi(),
namaKegiatanField(),
deskripsiField(),
penyelenggaraField(),
namaKontakField(),
nomorKontakField(),
linkField(),
tanggalKegiatanField(),
fotoField(),
_showImagePreview(),
SizedBox(height: 16),
TextFormField(
key: const Key('Text Field Deskripsi'),
keyboardType: TextInputType.multiline,
maxLines: null,
minLines: 3,
validator: FieldValidator.validateInfo,
controller: deskripsiController,
style: const TextStyle(
fontSize: 18,
),
decoration: InputDecoration(
hintStyle: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 15),
hintText: 'Tulis deskripsi...',
contentPadding: const EdgeInsets.all(8.0),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color: Theme.of(context).primaryColor,
),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color: Theme.of(context).primaryColor,
),
),
),
),
Container(
margin: const EdgeInsets.fromLTRB(
0, tripleSpace, 0, regularSpace),
alignment: Alignment.center,
child: ButtonTheme(
key: const Key('Button Simpan'),
minWidth: double.infinity,
height: 40,
child: submitButton('Simpan', _validateLoginInput),
)),
simpanButton(),
],
),
),
......@@ -259,36 +100,56 @@ class _AddKegiatanState extends State<AddKegiatan> {
);
}
Future<void> _validateLoginInput() async {
Future<void> _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: nameController.text,
deskripsi: deskripsiController.text,
narahubung: narahubungController.text,
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),
),
zonaWaktu: zonaCurrent,
);
final newKegiatanData = newKegiatan.toJson();
newKegiatanData['images'] = _imageFile;
var newKegiatanData = newKegiatan.toJson();
newKegiatanData['place_id'] = widget.placeId;
var multipartImageList = <MultipartFile>[];
if (images != null) {
for (var asset in images) {
var byteData = await asset.getByteData();
var imageData = byteData.buffer.asUint8List();
var multipartFile = MultipartFile.fromBytes(
imageData,
filename: asset.name,
contentType: MediaType('image', 'jpeg'),
);
multipartImageList.add(multipartFile);
}
newKegiatanData['images'] = multipartImageList;
}
newKegiatanData['images'] ??= [''];
if (newKegiatanData['zona_waktu'] == 'WIT') {
newKegiatanData['time_start'] = newKegiatanData['time_start']+'+0900';
}
else if (newKegiatanData['zona_waktu'] == 'WITA') {
newKegiatanData['time_start'] = newKegiatanData['time_start']+'+0800';
}
else {
newKegiatanData['time_start'] = newKegiatanData['time_start']+'+0700';
}
final _bloc = KegiatanBloc(widget.placeId);
await _bloc.addNewKegiatan(
newKegiatanData,
widget.placeId,
);
await _bloc.addNewKegiatan(newKegiatanData);
successDialog(context);
Timer(const Duration(seconds: 2), () {
......@@ -296,26 +157,13 @@ class _AddKegiatanState extends State<AddKegiatan> {
Navigator.pop(context);
});
} else {
failedDialog(context, '');
failedDialog(context, 'default');
}
}
Widget _showImagePreview() {
return _image == null
? 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'),
title: Text('Tambah kegiatan berhasil'),
content: Icon(FontAwesomeIcons.checkCircle),
);
showDialog(
......@@ -328,7 +176,7 @@ class _AddKegiatanState extends State<AddKegiatan> {
void failedDialog(BuildContext context, String message) {
var newMessage = message;
if (message == 'default') {
newMessage = 'Gagal menambahkan informasi';
newMessage = 'Gagal menambahkan kegiatan';
}
final alertDialog = AlertDialog(
title: Text(newMessage),
......@@ -343,17 +191,376 @@ class _AddKegiatanState extends State<AddKegiatan> {
});
}
final picker = ImagePicker();
File _image;
Future<void> pickImages() async {
var resultList = <Asset>[];
await _getPermission();
try {
if (permissionGranted) {
resultList = await MultiImagePicker.pickImages(
maxImages: 50,
enableCamera: true,
selectedAssets: images,
materialOptions: MaterialOptions(
actionBarTitle: widget.nama,
actionBarColor: '#ff3A903A',
statusBarColor: '#ff347D34',
useDetailsView: true,
startInAllView: true,
textOnNothingSelected: 'Tidak ada gambar yang dipilih',
),
);
setState(() {
images = resultList;
});
} else {
await openAppSettings();
}
} on Exception catch (e) {
print(e);
}
}
Future _getPermission() async {
var _camera = await Permission.storage.request();
var _storage = await Permission.camera.request();
if (_camera.isGranted && _storage.isGranted) {
setState(() {
permissionGranted = true;
});
} else if (_camera.isPermanentlyDenied || _storage.isPermanentlyDenied) {
await openAppSettings();
} else if (_camera.isDenied || _storage.isDenied) {
setState(() {
permissionGranted = false;
});
}
}
Widget namaLokasi() {
return Padding(
padding: const EdgeInsets.only(bottom: doubleSpace),
child: Text(
widget.nama,
style: const TextStyle(
fontSize: 28,
fontWeight: FontWeight.w800,
color: Colors.black,
fontFamily: 'Comfortaa',
),
),
);
}
Widget namaKegiatanField() {
return CustomTextField(
title: 'Nama Kegiatan',
hint: 'Masukkan nama kegiatan',
required: true,
key: const Key('Text Field Nama'),
validator: FieldValidator.validateName,
controller: namaKegiatanController,
);
}
Widget deskripsiField() {
return Container(
margin: const EdgeInsets.symmetric(vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: RichText(
key: Key('Deskripsi Kegiatan'),
text: TextSpan(
text: 'Deskripsi Kegiatan',
style: const TextStyle(
fontSize: 18, color: Colors.black, fontFamily: 'Muli'),
children: <TextSpan>[
const TextSpan(text: '*', style: TextStyle(color: red)),
],
),
),
),
TextFormField(
key: const Key('Text Field Deskripsi'),
keyboardType: TextInputType.multiline,
maxLines: null,
minLines: 3,
validator: FieldValidator.validateInfo,
controller: deskripsiController,
style: const TextStyle(
fontSize: 15,
),
decoration: InputDecoration(
hintStyle: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 15),
hintText: 'Tulis deskripsi...',
contentPadding: const EdgeInsets.all(8.0),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color: Theme.of(context).primaryColor,
),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color: Theme.of(context).primaryColor,
),
),
),
),
]));
}
Widget penyelenggaraField() {
return CustomTextField(
title: 'Penyelenggara',
hint: 'Masukkan nama penyelenggara',
required: true,
key: const Key('Text Field Penyelenggara'),
validator: FieldValidator.validateName,
controller: penyelenggaraController,
);
}
Widget namaKontakField() {
return CustomTextField(
title: 'Nama Narahubung',
hint: 'Masukkan nama narahubung',
required: false,
key: const Key('Text Field Nama Narahubung'),
controller: namaKontakController,
);
}
Widget nomorKontakField() {
return CustomTextField(
title: 'Nomor Telepon Narahubung',
hint: 'Masukkan nomor telepon narahubung',
required: true,
key: const Key('Text Field Nomor Telepon Narahubung'),
validator: FieldValidator.validateInfo,
controller: nomorKontakController,
);
}
Widget linkField() {
return CustomTextField(
title: 'Link Kegiatan',
hint: 'Masukkan link kegiatan (jika ada)',
required: false,
key: const Key('Text Field Link Kegiatan'),
controller: linkController,
);
}
Widget tanggalKegiatanField() {
return Container(
padding: const EdgeInsets.only(bottom: 16),
child: Column(
children: <Widget>[
SizedBox(height: 10.0),
Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 70, 10),
child: const Text(
'Tanggal & Waktu Kegiatan',
style: TextStyle(fontSize: 18),
textAlign: TextAlign.left,
),
),
Row(children: <Widget>[
// SizedBox(
// width: 186.0,
Expanded(
child: TextButton(
key: const Key('Button Tanggal & Waktu Kegiatan'),
style: TextButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0)),
padding: const EdgeInsets.all(13.0),
backgroundColor: Colors.transparent,
side: BorderSide(color: greenPrimary),
),
onPressed: () {
DatePicker.showDateTimePicker(
context,
currentTime: DateTime.parse(tanggalKegiatan),
onChanged: (date) {
setState(() {
tanggalKegiatan =
'${DateFormat('yyyy-MM-dd HH:mm').format(date)}';
});
},
);
},
child: Row(children: <Widget>[
Icon(
Icons.calendar_today,
size: 20,
color: Colors.green,
),
SizedBox(width: 10.0),
Text(
tanggalKegiatan,
style:
const TextStyle(fontSize: 15.0, color: Colors.black),
),
])
),
),
SizedBox(width: 15.0),
zonaWaktuChoice(),
]),
],
),
);
}
Widget zonaWaktuChoice() {
return DropdownButton<String>(
value: zonaCurrent,
underline: Container(
height: 1,
color: Colors.green,