Fakultas Ilmu Komputer UI

Commit be04391b authored by Yoga Pratama's avatar Yoga Pratama
Browse files

[GREEN] Implement add kegiatan page

parent b9648864
Pipeline #77382 passed with stages
in 13 minutes and 15 seconds
...@@ -4,6 +4,7 @@ import 'package:bisaGo/model/kegiatan.dart'; ...@@ -4,6 +4,7 @@ import 'package:bisaGo/model/kegiatan.dart';
import 'package:bisaGo/network/data/network_model.dart'; import 'package:bisaGo/network/data/network_model.dart';
import 'package:bisaGo/repository/kegiatan_repository.dart'; import 'package:bisaGo/repository/kegiatan_repository.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
import 'package:http/http.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
class KegiatanBloc { class KegiatanBloc {
...@@ -12,9 +13,9 @@ class KegiatanBloc { ...@@ -12,9 +13,9 @@ class KegiatanBloc {
List<KegiatanModel> allKegiatanFromApi; List<KegiatanModel> allKegiatanFromApi;
StreamSink<NetworkModel<KegiatanList>> get kegiatanListSink => StreamSink<NetworkModel<KegiatanList>> get kegiatanListSink =>
_kegiatanListController.sink; _kegiatanListController.sink;
Stream<NetworkModel<KegiatanList>> get kegiatanListStream => Stream<NetworkModel<KegiatanList>> get kegiatanListStream =>
_kegiatanListController.stream; _kegiatanListController.stream;
KegiatanBloc(String placeId) { KegiatanBloc(String placeId) {
_kegiatanListController = BehaviorSubject<NetworkModel<KegiatanList>>(); _kegiatanListController = BehaviorSubject<NetworkModel<KegiatanList>>();
...@@ -25,8 +26,8 @@ class KegiatanBloc { ...@@ -25,8 +26,8 @@ class KegiatanBloc {
Future<void> fetchKegiatanList(String placeId) async { Future<void> fetchKegiatanList(String placeId) async {
kegiatanListSink.add(NetworkModel.loading('Getting Kegiatan')); kegiatanListSink.add(NetworkModel.loading('Getting Kegiatan'));
try { try {
final kegiatanListResponse = final kegiatanListResponse =
await _kegiatanRepository.fetchKegiatan(placeId); await _kegiatanRepository.fetchKegiatan(placeId);
allKegiatanFromApi = List.from(kegiatanListResponse.allKegiatan); allKegiatanFromApi = List.from(kegiatanListResponse.allKegiatan);
kegiatanListSink.add(NetworkModel.completed(kegiatanListResponse)); kegiatanListSink.add(NetworkModel.completed(kegiatanListResponse));
} catch (e) { } catch (e) {
...@@ -34,12 +35,21 @@ class KegiatanBloc { ...@@ -34,12 +35,21 @@ class KegiatanBloc {
} }
} }
Future<dynamic> addNewKegiatan(
Map<String, dynamic> newKegiatanData, String placeId) async {
try {
return await _kegiatanRepository.createKegiatan(newKegiatanData, placeId);
} catch (e) {
return Response('Failed to register komentar', 400);
}
}
void resetKegiatanList() { void resetKegiatanList() {
kegiatanListSink kegiatanListSink
.add(NetworkModel.completed(KegiatanList(allKegiatanFromApi))); .add(NetworkModel.completed(KegiatanList(allKegiatanFromApi)));
} }
void dispose() { void dispose() {
_kegiatanListController?.close(); _kegiatanListController?.close();
} }
} }
\ No newline at end of file
import 'dart:async';
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/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:dio/dio.dart';
import 'package:flutter/material.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:intl/intl.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
class AddKegiatan extends StatefulWidget {
AddKegiatan({
Key key,
@required this.nama,
@required this.placeId,
}) : super(key: key);
final String nama;
final String placeId;
@override
_AddKegiatanState createState() => _AddKegiatanState();
}
class _AddKegiatanState extends State<AddKegiatan> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
TextEditingController nameController = TextEditingController();
TextEditingController phoneController = TextEditingController();
TextEditingController penyelenggaraController = TextEditingController();
TextEditingController narahubungController = TextEditingController();
TextEditingController deskripsiController = TextEditingController();
String tanggalKegiatan =
'${DateFormat('yyyy-MM-dd hh:mm').format(DateTime.now())}';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(55),
child: BisaGoAppBar(
title: 'Tambah Kegiatan',
leading: InkWell(
onTap: () => Navigator.pop(context, 'Take me back'),
child: const Icon(Icons.arrow_back_ios),
),
),
),
body: SingleChildScrollView(
child: Form(
key: _formKey,
child: Stack(
children: <Widget>[
Container(
key: const Key('Body Add Kegiatan Page'),
alignment: Alignment.topCenter,
padding: EdgeInsets.only(
top: MediaQuery.of(context).size.height * .04,
left: tripleSpace,
right: tripleSpace,
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),
),
],
),
),
)
],
),
_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),
)),
],
),
),
],
),
),
),
);
}
Future<void> _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: nameController.text,
deskripsi: deskripsiController.text,
narahubung: narahubungController.text,
penyelenggara: penyelenggaraController.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
? 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;
});
}
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 _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);
}
}
...@@ -3,6 +3,7 @@ import 'package:bisaGo/bloc/lokasi_response_bloc.dart'; ...@@ -3,6 +3,7 @@ import 'package:bisaGo/bloc/lokasi_response_bloc.dart';
import 'package:bisaGo/component/image_holder.dart'; import 'package:bisaGo/component/image_holder.dart';
import 'package:bisaGo/model/kegiatan.dart'; import 'package:bisaGo/model/kegiatan.dart';
import 'package:bisaGo/model/lokasi.dart'; import 'package:bisaGo/model/lokasi.dart';
import 'package:bisaGo/page/filter_fasilitas/add_kegiatan.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:bisaGo/bloc/komentar_bloc.dart'; import 'package:bisaGo/bloc/komentar_bloc.dart';
import 'package:bisaGo/component/bisago_appbar.dart'; import 'package:bisaGo/component/bisago_appbar.dart';
...@@ -229,7 +230,7 @@ class _FasilitasState extends State<Fasilitas> { ...@@ -229,7 +230,7 @@ class _FasilitasState extends State<Fasilitas> {
color: Colors.transparent))), color: Colors.transparent))),
), ),
onPressed: () { onPressed: () {
checkLoginStatus(); checkLoginStatus('informasi');
}, },
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
...@@ -353,7 +354,7 @@ class _FasilitasState extends State<Fasilitas> { ...@@ -353,7 +354,7 @@ class _FasilitasState extends State<Fasilitas> {
color: Colors.transparent))), color: Colors.transparent))),
), ),
onPressed: () { onPressed: () {
checkLoginStatus(); checkLoginStatus('kegiatan');
}, },
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
...@@ -467,13 +468,13 @@ class _FasilitasState extends State<Fasilitas> { ...@@ -467,13 +468,13 @@ class _FasilitasState extends State<Fasilitas> {
super.dispose(); super.dispose();
} }
void checkLoginStatus() async { void checkLoginStatus(String type) async {
final sharedPreferences = await SharedPreferences.getInstance(); final sharedPreferences = await SharedPreferences.getInstance();
if (sharedPreferences.getString('token') == null) { if (sharedPreferences.getString('token') == null) {
await Navigator.of(context).pushAndRemoveUntil( await Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (BuildContext context) => const Login()), MaterialPageRoute(builder: (BuildContext context) => const Login()),
(Route<dynamic> route) => false); (Route<dynamic> route) => false);
} else { } else if (type == 'informasi') {
await Navigator.of(context) await Navigator.of(context)
.push(MaterialPageRoute( .push(MaterialPageRoute(
builder: (BuildContext context) => AddInformasi( builder: (BuildContext context) => AddInformasi(
...@@ -482,6 +483,18 @@ class _FasilitasState extends State<Fasilitas> { ...@@ -482,6 +483,18 @@ class _FasilitasState extends State<Fasilitas> {
))) )))
.then((value) => .then((value) =>
_komentarBloc.fetchKomentarList(widget.lokasi.placeId)); _komentarBloc.fetchKomentarList(widget.lokasi.placeId));
} else {
await Navigator.of(context)
.push(MaterialPageRoute(
builder: (BuildContext context) => AddKegiatan(
nama: widget.lokasi.name,
placeId: widget.lokasi.placeId,
)))
.then(
(value) => _kegiatanBloc.fetchKegiatanList(
widget.lokasi.placeId,
),
);
} }
} }
......
...@@ -5,6 +5,8 @@ import 'package:bisaGo/network/network_interface.dart'; ...@@ -5,6 +5,8 @@ import 'package:bisaGo/network/network_interface.dart';
abstract class BaseKegiatanRepository { abstract class BaseKegiatanRepository {
Future<KegiatanList> fetchKegiatan(String placeId); Future<KegiatanList> fetchKegiatan(String placeId);
Future<List<String>> fetchImages(String placeId, int id); Future<List<String>> fetchImages(String placeId, int id);
Future<dynamic> createKegiatan(
Map<String, dynamic> newKegiatanData, String placeId);
} }
class KegiatanRepository implements BaseKegiatanRepository { class KegiatanRepository implements BaseKegiatanRepository {
...@@ -32,11 +34,25 @@ class KegiatanRepository implements BaseKegiatanRepository { ...@@ -32,11 +34,25 @@ class KegiatanRepository implements BaseKegiatanRepository {
final response = await _network.get(url: url, isLogin: false); final response = await _network.get(url: url, isLogin: false);
var allImages = []; var allImages = [];
for (var _index=0; _index < response.length; _index++) { for (var _index = 0; _index < response.length; _index++) {
var fotoUrl = ApiFlavor.getBaseUrl() + response.values.toList()[_index]['foto']; var fotoUrl =
ApiFlavor.getBaseUrl() + response.values.toList()[_index]['foto'];
allImages.add(fotoUrl); allImages.add(fotoUrl);
} }
allImages = allImages.cast<String>(); allImages = allImages.cast<String>();
return allImages; return allImages;
} }
}
\ No newline at end of file @override
Future<dynamic> createKegiatan(
Map<String, dynamic> newKegiatanData,
String placeId,
) async {
print(newKegiatanData);
final response = await _network.post(
url: '/informasi-fasilitas/lokasi/add-kegiatan/$placeId/',
bodyParams: newKegiatanData,
);
return response;
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment