diff --git a/lib/page/filter_fasilitas/add_kegiatan.dart b/lib/page/filter_fasilitas/add_kegiatan.dart index c0b2fedfd37035829f2e7e805d2e8a3ac480fa0f..76145d90381eeefd753bd1b987032d077b1beb46 100644 --- a/lib/page/filter_fasilitas/add_kegiatan.dart +++ b/lib/page/filter_fasilitas/add_kegiatan.dart @@ -71,184 +71,15 @@ class _AddKegiatanState extends State { bottom: tripleSpace), child: ListBody( children: [ - 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, - ), - Wrap( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - 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(), + narahubungField(), + 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,6 +90,244 @@ class _AddKegiatanState extends State { ); } + 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', + required: true, + key: const Key('Text Field Nama'), + validator: FieldValidator.validateName, + controller: nameController, + ); + } + + Widget deskripsiField() { + return Container( + margin: const EdgeInsets.symmetric(vertical: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + 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: [ + 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: 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, + ), + ), + ), + ), + ] + ) + ); + } + + Widget penyelenggaraField() { + return CustomTextField( + title: 'Penyelenggara', + required: true, + key: const Key('Text Field Penyelenggara'), + validator: FieldValidator.validateName, + controller: penyelenggaraController, + ); + } + + Widget narahubungField() { + return CustomTextField( + title: 'Nomor Telepon Narahubung', + required: true, + key: const Key('Text Field Nomor Telepon Narahubung'), + validator: FieldValidator.validateName, + controller: narahubungController, + ); + } + + Widget tanggalKegiatanField() { + return Padding( + padding: const EdgeInsets.only(bottom: 16), + child: Wrap( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(0,0,20,10), + child: const Text( + 'Tanggal Kegiatan', + style: TextStyle(fontSize: 18), + textAlign: TextAlign.left, + ), + ), + 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), + ), + ), + ], + ), + ); + } + + 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), + ), + ], + ), + ), + ), + 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), + alignment: Alignment.center, + child: ButtonTheme( + key: const Key('Button Simpan'), + minWidth: double.infinity, + height: 40, + child: submitButton('Simpan', _validateLoginInput), + ) + ); + } + Future _validateLoginInput() async { final form = _formKey.currentState; if (_formKey.currentState.validate()) { diff --git a/lib/page/filter_fasilitas/fasilitas.dart b/lib/page/filter_fasilitas/fasilitas.dart index d21f585a385e5d1a52db954e6f0292b9ad0d8bcc..8f6e66fcd2d1824cd245c50fb09cb8cb5cdb075f 100644 --- a/lib/page/filter_fasilitas/fasilitas.dart +++ b/lib/page/filter_fasilitas/fasilitas.dart @@ -29,7 +29,8 @@ class Fasilitas extends StatefulWidget { _FasilitasState createState() => _FasilitasState(); } -class _FasilitasState extends State { +class _FasilitasState extends State + with AutomaticKeepAliveClientMixin { var kursiRodaVal = true; var liftVal = true; var toiletDisabilitasVal = true; @@ -64,6 +65,7 @@ class _FasilitasState extends State { @override Widget build(BuildContext context) { + super.build(context); return DefaultTabController( length: 2, child: Scaffold( @@ -506,4 +508,7 @@ class _FasilitasState extends State { await _lokasiBloc.postSearchHistory(widget.lokasi.placeId, token); } } + + @override + bool get wantKeepAlive => true; } diff --git a/lib/page/filter_fasilitas/kegiatan_image_view.dart b/lib/page/filter_fasilitas/kegiatan_image_view.dart new file mode 100644 index 0000000000000000000000000000000000000000..fa29496b1c2c709c503159b53965a8e920bb8092 --- /dev/null +++ b/lib/page/filter_fasilitas/kegiatan_image_view.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; +import 'package:photo_view/photo_view.dart'; + +class KegiatanImageView extends StatefulWidget { + final String url; + KegiatanImageView(this.url); + + @override + _KegiatanImageView createState() => _KegiatanImageView(url); +} + +class _KegiatanImageView extends State { + final String url; + _KegiatanImageView(this.url); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: PhotoView( + imageProvider: NetworkImage(url), + ) + ); + } +} \ No newline at end of file diff --git a/lib/page/filter_fasilitas/kegiatan_list_images.dart b/lib/page/filter_fasilitas/kegiatan_list_images.dart new file mode 100644 index 0000000000000000000000000000000000000000..f7f347cb5e638ce57f7982ccf54bd2adfd1283fb --- /dev/null +++ b/lib/page/filter_fasilitas/kegiatan_list_images.dart @@ -0,0 +1,55 @@ +import 'package:bisaGo/component/bisago_appbar.dart'; +import 'package:bisaGo/page/filter_fasilitas/kegiatan_image_view.dart'; +import 'package:flutter/material.dart'; + +class KegiatanListImages extends StatefulWidget { + final List urls; + final String namaKegiatan; + KegiatanListImages(this.urls, this.namaKegiatan); + + @override + _KegiatanListImages createState() => _KegiatanListImages(urls, namaKegiatan); +} + +class _KegiatanListImages extends State { + List urls; + String namaKegiatan; + _KegiatanListImages(this.urls, this.namaKegiatan); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: BisaGoAppBar( + title: namaKegiatan, + ), + body: Container( + padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 2.0), + child: GridView.count( + crossAxisCount: 2, + padding: EdgeInsets.all(3.0), + children: urls.map((url) => renderImage(url)).toList(), + ), + ), + ); + } + + Card renderImage(String imageUrl) { + return Card( + elevation: 1.0, + margin: EdgeInsets.all(5.0), + child: Container( + child: InkWell( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => KegiatanImageView(imageUrl), + ), + ); + }, + child: Image.network(imageUrl, fit: BoxFit.cover), + ), + ) + ); + } +} \ No newline at end of file diff --git a/lib/page/filter_fasilitas/postingan/detail_post_kegiatan.dart b/lib/page/filter_fasilitas/postingan/detail_post_kegiatan.dart index f34fb2834e111969af837a463d5902e8f0adddec..d7213f9b28a046af745c5e7cf014ec90523807cb 100644 --- a/lib/page/filter_fasilitas/postingan/detail_post_kegiatan.dart +++ b/lib/page/filter_fasilitas/postingan/detail_post_kegiatan.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:bisaGo/model/kegiatan.dart'; import 'package:bisaGo/model/lokasi.dart'; +import 'package:bisaGo/page/filter_fasilitas/kegiatan_list_images.dart'; import 'package:bisaGo/repository/dynamic_links_service_repository.dart'; import 'package:bisaGo/utils/share_utils.dart'; import 'package:bisaGo/utils/validator.dart'; @@ -166,9 +167,22 @@ class _DetailPostKegiatanPageState extends State { Radius.circular(20)), child: Stack( children: [ - Image.network(item, - fit: BoxFit.cover, - width: 1000.0), + GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: + (context) => + KegiatanListImages( + widget.kegiatan.image, + widget.kegiatan.namaKegiatan + ), + ) + ); + }, + child: Image.network(item, fit: BoxFit.cover, width: 1000.0), + ), Positioned( bottom: 0.0, left: 0.0, diff --git a/lib/utils/custom_text_field.dart b/lib/utils/custom_text_field.dart index 66172e9e8c7a8536eb2330f2656b2c45b69a4bf2..269435a9c127360c1714587b0f95ce740d01585a 100644 --- a/lib/utils/custom_text_field.dart +++ b/lib/utils/custom_text_field.dart @@ -34,21 +34,21 @@ class CustomTextField extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - RichText( - key: Key(title), - text: TextSpan( - text: title, - style: const TextStyle( - fontSize: 18, color: Colors.black, fontFamily: 'Muli'), - children: [ - if (required) - const TextSpan(text: '*', style: TextStyle(color: red)), - ], + Padding( + padding: const EdgeInsets.only(bottom: 10), + child: RichText( + key: Key(title), + text: TextSpan( + text: title, + style: const TextStyle( + fontSize: 18, color: Colors.black, fontFamily: 'Muli'), + children: [ + if (required) + const TextSpan(text: '*', style: TextStyle(color: red)), + ], + ), ), ), - const SizedBox( - height: 10, - ), TextFormField( readOnly: readOnly, onSaved: onSaved, diff --git a/pubspec.yaml b/pubspec.yaml index afecc95033783e520dd4b18bd435712fa920a387..9a7a51c25c286f60a731b532761e60b44ea84279 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -57,6 +57,7 @@ dependencies: firebase_dynamic_links: ^0.7.0+1 carousel_slider: ^3.0.0 url_launcher: ^6.0.3 + photo_view: ^0.11.1 dev_dependencies: flutter_test: diff --git a/test/kegiatan_image_view_test.dart b/test/kegiatan_image_view_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..d3e5f5bf9c5936dcfa50f52ae9ad1b3f60bfd510 --- /dev/null +++ b/test/kegiatan_image_view_test.dart @@ -0,0 +1,25 @@ +import 'package:bisaGo/page/filter_fasilitas/kegiatan_image_view.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:network_image_mock/network_image_mock.dart'; + +void main() { + testWidgets('Test Kegiatan Image View', + (WidgetTester tester) async { + await mockNetworkImagesFor( + () => tester.pumpWidget( + StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MaterialApp( + home: Material( + child: KegiatanImageView(''), + ) + ); + }, + ) + ) + ); + expect(find.byType(KegiatanImageView), findsOneWidget); + } + ); +} \ No newline at end of file diff --git a/test/kegiatan_list_images_test.dart b/test/kegiatan_list_images_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..c2b2c56a534b27b5549d61bda5a5344f76fbb88f --- /dev/null +++ b/test/kegiatan_list_images_test.dart @@ -0,0 +1,26 @@ +import 'package:bisaGo/page/filter_fasilitas/kegiatan_list_images.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:network_image_mock/network_image_mock.dart'; + +void main() { + testWidgets('Test Kegiatan List Images', + (WidgetTester tester) async { + await mockNetworkImagesFor( + () => tester.pumpWidget( + StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MaterialApp( + home: Material( + child: KegiatanListImages([''], 'Makan bersama'), + ) + ); + }, + ) + ) + ); + expect(find.byType(KegiatanListImages), findsWidgets); + expect(find.text('Makan bersama'), findsOneWidget); + } + ); +} \ No newline at end of file diff --git a/test/registrasi_informasi_layanan_disabilitas_test.dart b/test/registrasi_informasi_layanan_disabilitas_test.dart index c84ca84b281e26ff8bf0c104998c8a5c4236618e..fe308f65cb753ae3adb29db8339062886b6f1bd0 100644 --- a/test/registrasi_informasi_layanan_disabilitas_test.dart +++ b/test/registrasi_informasi_layanan_disabilitas_test.dart @@ -22,7 +22,7 @@ void main() { expect(find.byType(Icon), findsNWidgets(5)); expect(find.byType(Row), findsNWidgets(6)); expect(find.byType(Scaffold), findsOneWidget); - expect(find.byType(SizedBox), findsNWidgets(61)); + expect(find.byType(SizedBox), findsNWidgets(53)); expect(find.byType(TextButton), findsNWidgets(3)); //negative test