Fakultas Ilmu Komputer UI

Commit fd26348b authored by Jovi Handono Hutama's avatar Jovi Handono Hutama
Browse files

Merge branch 'dev-jovi' into 'PBI-12-info_kegiatan'

Dev jovi

See merge request !55
parents 46226868 3676b365
Pipeline #81151 passed with stages
in 13 minutes and 26 seconds
......@@ -6,4 +6,9 @@
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
</manifest>
......@@ -8,7 +8,13 @@
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:requestLegacyExternalStorage="true"
android:name="io.flutter.app.FlutterApplication"
android:label="bisaGo"
android:icon="@mipmap/launcher_icon">
......
......@@ -6,4 +6,9 @@
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
</manifest>
......@@ -36,9 +36,9 @@ class KegiatanBloc {
}
Future<dynamic> addNewKegiatan(
Map<String, dynamic> newKegiatanData, String placeId) async {
Map<String, dynamic> newKegiatanData) async {
try {
return await _kegiatanRepository.createKegiatan(newKegiatanData, placeId);
return await _kegiatanRepository.createKegiatan(newKegiatanData);
} catch (e) {
return Response('Failed to register komentar', 400);
}
......
import 'dart:async';
import 'dart:io';
// import 'dart:io';
import 'package:bisaGo/bloc/kegiatan_bloc.dart';
import 'package:bisaGo/component/bisago_appbar.dart';
......@@ -15,6 +15,7 @@ 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:http_parser/http_parser.dart';
import 'package:image_picker/image_picker.dart';
import 'package:intl/intl.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
......@@ -49,6 +50,7 @@ class _AddKegiatanState extends State<AddKegiatan> {
'${DateFormat('yyyy-MM-ddTHH:mm').format(DateTime.now())}';
List<Asset> images = <Asset>[];
bool permissionGranted = false;
@override
Widget build(BuildContext context) {
......@@ -104,12 +106,6 @@ class _AddKegiatanState extends State<AddKegiatan> {
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,
......@@ -123,14 +119,29 @@ class _AddKegiatanState extends State<AddKegiatan> {
),
);
final newKegiatanData = newKegiatan.toJson();
newKegiatanData['images'] = _imageFile;
var newKegiatanData = newKegiatan.toJson();
var multipartImageList = <MultipartFile>[];
newKegiatanData['place_id'] = widget.placeId;
newKegiatanData['zona_waktu'] = 'WIB';
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'] ??= [''];
final _bloc = KegiatanBloc(widget.placeId);
await _bloc.addNewKegiatan(
newKegiatanData,
widget.placeId,
);
await _bloc.addNewKegiatan(newKegiatanData);
successDialog(context);
Timer(const Duration(seconds: 2), () {
......@@ -173,52 +184,72 @@ class _AddKegiatanState extends State<AddKegiatan> {
}
final picker = ImagePicker();
File _image;
// File _image;
Future _getCameraImage() async {
final image =
await picker.getImage(source: ImageSource.camera, imageQuality: 50);
return File(image.path);
}
// Future _getCameraImage() async {
// final image =
// await picker.getImage(source: ImageSource.camera, imageQuality: 50);
// return File(image.path);
// }
Future<void> pickImages() async {
var resultList = <Asset>[];
// var status = await Permission.camera.status;
await _getStoragePermission();
await _getCameraPermission();
try {
// if (status.isGranted) {
// }
resultList = await MultiImagePicker.pickImages(
maxImages: 300,
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);
}
}
setState(() {
images = resultList;
});
Future _getStoragePermission() async {
if (await Permission.storage.request().isGranted) {
setState(() {
permissionGranted = true;
});
} else if (await Permission.storage.request().isPermanentlyDenied) {
await openAppSettings();
} else if (await Permission.storage.request().isDenied) {
setState(() {
permissionGranted = false;
});
}
}
// Future<bool> checkAndRequestCameraPermissions() async {
// PermissionStatus permission =
// await PermissionHandler().checkPermissionStatus(PermissionGroup.camera);
// if (permission != PermissionStatus.granted) {
// Map<PermissionGroup, PermissionStatus> permissions =
// await PermissionHandler().requestPermissions([PermissionGroup.camera]);
// return permissions[PermissionGroup.camera] == PermissionStatus.granted;
// } else {
// return true;
// }
// }
Future _getCameraPermission() async {
if (await Permission.camera.request().isGranted) {
setState(() {
permissionGranted = true;
});
} else if (await Permission.camera.request().isPermanentlyDenied) {
await openAppSettings();
} else if (await Permission.camera.request().isDenied) {
setState(() {
permissionGranted = false;
});
}
}
Widget namaLokasi() {
return Padding(
......@@ -337,9 +368,8 @@ class _AddKegiatanState extends State<AddKegiatan> {
return CustomTextField(
title: 'Link Kegiatan',
hint: 'Masukkan link kegiatan (jika ada)',
required: true,
required: false,
key: const Key('Text Field Link Kegiatan'),
validator: FieldValidator.validateName,
controller: linkController,
);
}
......@@ -348,7 +378,7 @@ class _AddKegiatanState extends State<AddKegiatan> {
return Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Padding(
padding: const EdgeInsets.fromLTRB(0,0,20,10),
......@@ -406,10 +436,13 @@ class _AddKegiatanState extends State<AddKegiatan> {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'Foto',
style: TextStyle(fontSize: 18),
textAlign: TextAlign.left,
Padding(
padding: const EdgeInsets.only(right: doubleSpace),
child: const Text(
'Foto',
style: TextStyle(fontSize: 18),
textAlign: TextAlign.left,
),
),
TextButton(
key: const Key('Button Input Foto Gallery'),
......@@ -419,7 +452,7 @@ class _AddKegiatanState extends State<AddKegiatan> {
},
child: Container(
width: MediaQuery.of(context).size.width * 0.35,
// width: MediaQuery.of(context).size.width * 0.35,
padding: const EdgeInsets.all(9.0),
alignment: Alignment.centerLeft,
decoration: BoxDecoration(
......@@ -435,7 +468,7 @@ class _AddKegiatanState extends State<AddKegiatan> {
),
const SizedBox(width: regularSpace),
const Text(
'Dari Gallery',
'Tambah foto ',
style: TextStyle(
color: Colors.white, fontSize: 14.0),
),
......@@ -443,40 +476,6 @@ class _AddKegiatanState extends State<AddKegiatan> {
),
),
),
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),
),
],
),
),
)
],
),
);
......
......@@ -6,7 +6,7 @@ abstract class BaseKegiatanRepository {
Future<KegiatanList> fetchKegiatan(String placeId);
Future<List<String>> fetchImages(String placeId, int id);
Future<dynamic> createKegiatan(
Map<String, dynamic> newKegiatanData, String placeId);
Map<String, dynamic> newKegiatanData);
Future<KegiatanModel> fetchDetailKegiatan(String placeId, int kegiatanId);
}
......@@ -47,10 +47,9 @@ class KegiatanRepository implements BaseKegiatanRepository {
@override
Future<dynamic> createKegiatan(
Map<String, dynamic> newKegiatanData,
String placeId,
) async {
final response = await _network.post(
url: '/informasi-fasilitas/lokasi/add-kegiatan/$placeId/',
url: '/informasi-fasilitas/lokasi/add-kegiatan/${newKegiatanData['place_id']}/',
bodyParams: newKegiatanData,
);
return response;
......
......@@ -60,6 +60,7 @@ dependencies:
photo_view: ^0.11.1
multi_image_picker: ^4.8.1
permission_handler: ^5.1.0+2
http_parser: ^3.1.4
dev_dependencies:
flutter_test:
......
import 'dart:async';
import 'package:bisaGo/model/kegiatan.dart';
import 'package:bisaGo/model/lokasi.dart';
import 'package:bisaGo/page/filter_fasilitas/add_kegiatan.dart';
import 'package:bisaGo/page/filter_fasilitas/fasilitas.dart';
import 'package:bisaGo/repository/kegiatan_repository.dart';
import 'package:bisaGo/repository/komentar_posting_repository.dart';
import 'package:bisaGo/repository/komentar_repository.dart';
import 'package:bisaGo/repository/lokasi_repository.dart';
import 'package:bisaGo/utils/custom_text_field.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:get_it/get_it.dart';
import 'package:mockito/mockito.dart';
import 'package:network_image_mock/network_image_mock.dart';
class MockKomentarRepository extends Fake implements KomentarRepository {}
class MockLokasiRepository extends Fake implements LokasiRepository {
final mockLokasi = {
'placeId': 'lKHBIUnKLJnKjnKLN',
'name': 'Margo City',
'alamat':
'Jl. Margonda Raya No.358, Kemiri Muka, Kecamatan Beji, Kota Depok, Jawa Barat 16423',
'image': 'static/img/2669211407.jpg',
'no_telp': '02178870888',
'counter': 69,
};
@override
Future<LokasiListResponse> fetchLokasi() async {
return Future.value(LokasiListResponse([Lokasi.fromJson(mockLokasi)]));
}
}
class MockKomentarPostingRepository extends Fake
implements KomentarPostingRepository {}
class MockKegiatanRepository extends Fake implements KegiatanRepository {
final mockKegiatan = {
'id': 1,
'place_id': 'asdfghjkl',
'creator': 'Jovi',
'nama_kegiatan': 'Jalan Sehat',
'penyelenggara': 'Gubernur',
'narahubung': 'Rafif (088012341234)',
'deskripsi': 'Jalan sehat keliling kota',
'time_start': '16-05-2021 06:00:00',
'time_end': '',
'image': '',
};
@override
Future<KegiatanList> fetchKegiatan(String placeId) {
return Future.value(KegiatanList([KegiatanModel.fromJson(mockKegiatan)]));
}
}
void main() {
final mockLokasi = {
'name': 'Margo City',
'alamat':
'Jl. Margonda Raya No.358, Kemiri Muka, Kecamatan Beji, Kota Depok, Jawa Barat 16423',
'image': 'static/img/2669211407.jpg',
'no_telp': '02178870888',
'counter': 69,
};
final mockKegiatan = {
'id': 1,
'place_id': 'asdfghjkl',
'creator': 'Jovi',
'nama_kegiatan': 'Jalan Sehat',
'penyelenggara': 'Gubernur',
'narahubung': 'Rafif (0880123456123456)',
'deskripsi': 'Jalan sehat keliling kota',
'time_start': '2021-05-15 06:00:00',
'time_end': '2021-05-15 10:00:00',
'image': ['a', 'b', 'c'],
};
setUpAll(() {
final _getIt = GetIt.instance;
_getIt.registerLazySingleton<BaseKomentarRepository>(
() => MockKomentarRepository());
_getIt.registerLazySingleton<BaseKomentarPostingRepository>(
() => MockKomentarPostingRepository());
_getIt.registerLazySingleton<BaseLokasiRepository>(
() => MockLokasiRepository());
_getIt.registerLazySingleton<BaseKegiatanRepository>(
() => MockKegiatanRepository());
});
testWidgets('Test Tambah Kegiatan Page',
(WidgetTester tester) async {
await mockNetworkImagesFor(() => tester.pumpWidget(
MaterialApp(
home: Fasilitas(
lokasi: Lokasi.fromJson(mockLokasi),
kegiatan: KegiatanModel.fromJson(mockKegiatan),
)
)
));
await tester.pump();
expect(find.text('Margo City'), findsOneWidget);
expect(find.text('Kegiatan'), findsOneWidget);
await tester.drag(find.text('Tambah Informasi'), Offset(-500, 0));
await tester.pump();
await tester.tap(find.text('Tambah Kegiatan'));
await tester.pump();
}
);
testWidgets('Test Form Tambah Kegiatan',
(WidgetTester tester) async {
await mockNetworkImagesFor(
() => tester.pumpWidget(
StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return MaterialApp(
home: Material(
child: AddKegiatan(nama: 'Margo City', placeId: 'asdfghjkl'),
)
);
},
)
)
);
expect(find.byType(CustomTextField), findsWidgets);
expect(find.byType(ElevatedButton), findsOneWidget);
}
);
}
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