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
...@@ -6,4 +6,9 @@ ...@@ -6,4 +6,9 @@
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_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> </manifest>
...@@ -8,7 +8,13 @@ ...@@ -8,7 +8,13 @@
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_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 <application
android:requestLegacyExternalStorage="true"
android:name="io.flutter.app.FlutterApplication" android:name="io.flutter.app.FlutterApplication"
android:label="bisaGo" android:label="bisaGo"
android:icon="@mipmap/launcher_icon"> android:icon="@mipmap/launcher_icon">
......
...@@ -6,4 +6,9 @@ ...@@ -6,4 +6,9 @@
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_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> </manifest>
3.5.0: 3.5.1:
- Pengguna dapat mengganti foto profil - Pengguna dapat mengganti foto profil
- Pengguna dapat mengubah informasi kegiatan yang sudah ada
3.4.0: 3.4.0:
- Notifikasi pengguna untuk komentar baru - Notifikasi pengguna untuk komentar baru
...@@ -8,16 +9,11 @@ ...@@ -8,16 +9,11 @@
- Kegiatan disabilitas di suatu lokasi - Kegiatan disabilitas di suatu lokasi
- Perbaikan bugs - Perbaikan bugs
3.2.1:
- Perbaikan masalah update fasilitas
3.2.0: 3.2.0:
- Tersedia fitur membagikan informasi fasilitas/kegiatan disabilitas kepada orang lain - Tersedia fitur membagikan informasi fasilitas/kegiatan disabilitas kepada orang lain
3.1.2: 3.1.2:
- Perbaikan masuk dengan Google - Perbaikan masuk dengan Google
3.1.1:
- Tersedia fitur pencarian layanan - Tersedia fitur pencarian layanan
- Tersedia pilihan kamera ketika menambahkan gambar fasilitas - Tersedia pilihan kamera ketika menambahkan gambar fasilitas
- Tersedia fitur riwayat pencarian - Tersedia fitur riwayat pencarian
...@@ -36,14 +36,38 @@ class KegiatanBloc { ...@@ -36,14 +36,38 @@ class KegiatanBloc {
} }
Future<dynamic> addNewKegiatan( Future<dynamic> addNewKegiatan(
Map<String, dynamic> newKegiatanData, String placeId) async { Map<String, dynamic> newKegiatanData) async {
try { try {
return await _kegiatanRepository.createKegiatan(newKegiatanData, placeId); return await _kegiatanRepository.createKegiatan(newKegiatanData);
} catch (e) { } catch (e) {
return Response('Failed to register komentar', 400); return Response('Failed to register komentar', 400);
} }
} }
Future<dynamic> updateKegiatan(
Map<String, dynamic> newKegiatanData,
String placeId,
int id
) async {
try {
return await _kegiatanRepository.updateKegiatan(
newKegiatanData, placeId, id);
} catch (e) {
return {'response': 'FAILED'};
}
}
Future<KegiatanModel> fetchDetailKegiatan(String placeId, int kegiatanId) async {
try {
return await _kegiatanRepository.fetchDetailKegiatan(
placeId,
kegiatanId
);
} catch (e) {
return KegiatanModel();
}
}
void resetKegiatanList() { void resetKegiatanList() {
kegiatanListSink kegiatanListSink
.add(NetworkModel.completed(KegiatanList(allKegiatanFromApi))); .add(NetworkModel.completed(KegiatanList(allKegiatanFromApi)));
......
import 'package:bisaGo/config/styles.dart';
import 'package:bisaGo/flavor/flavor.dart'; import 'package:bisaGo/flavor/flavor.dart';
import 'package:cached_network_image/cached_network_image.dart'; import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:shimmer/shimmer.dart';
class ImageHolder extends StatelessWidget { class ImageHolder extends StatelessWidget {
final String url; final String url;
...@@ -76,10 +76,12 @@ class ImageHolder extends StatelessWidget { ...@@ -76,10 +76,12 @@ class ImageHolder extends StatelessWidget {
fit: BoxFit.cover, fit: BoxFit.cover,
)), )),
), ),
placeholder: (context, _) => const Center( placeholder: (context, _) => Container(
child: CircularProgressIndicator( child: Shimmer.fromColors(
valueColor: AlwaysStoppedAnimation<Color>(greenPrimary), baseColor: Colors.grey[300],
)), highlightColor: Colors.grey[100],
enabled: true,
child: Container())),
errorWidget: (context, url, error) => errorWidget: (context, url, error) =>
const Center(child: Icon(Icons.broken_image, color: Colors.black38)), const Center(child: Icon(Icons.broken_image, color: Colors.black38)),
); );
......
...@@ -2,6 +2,6 @@ import 'package:intl/intl.dart'; ...@@ -2,6 +2,6 @@ import 'package:intl/intl.dart';
class CustomSerializer { class CustomSerializer {
static DateTime stringToDateTime(String date) { static DateTime stringToDateTime(String date) {
return DateFormat('dd-MM-yyyy hh:mm').parse(date); return DateFormat('yyyy-MM-dd HH:mm').parse(date);
} }
} }
...@@ -99,6 +99,12 @@ const fasilitas = { ...@@ -99,6 +99,12 @@ const fasilitas = {
'TB': 'Tempat Parkir Biasa', 'TB': 'Tempat Parkir Biasa',
}; };
const zonaWaktu = [
'WIB',
'WITA',
'WIT',
];
String getTag(String tag) { String getTag(String tag) {
return tags[tag]; return tags[tag];
} }
...@@ -13,34 +13,45 @@ class KegiatanList { ...@@ -13,34 +13,45 @@ class KegiatanList {
class KegiatanModel { class KegiatanModel {
final int id; final int id;
@JsonKey(name: 'place_id') @JsonKey(name: 'place_id')
final String placeId; String placeId;
final String creator; String creator;
@JsonKey(name: 'creator_email')
final String creatorEmail;
@JsonKey(name: 'nama_kegiatan') @JsonKey(name: 'nama_kegiatan')
final String namaKegiatan; String namaKegiatan;
final String penyelenggara; @JsonKey(name: 'creator_email')
final String narahubung; String creatorEmail;
final String deskripsi; String penyelenggara;
String deskripsi;
@JsonKey(name: 'nama_kontak')
String namaKontak;
@JsonKey(name: 'nomor_kontak')
String nomorKontak;
String links;
@JsonKey(name: 'time_start', fromJson: CustomSerializer.stringToDateTime) @JsonKey(name: 'time_start', fromJson: CustomSerializer.stringToDateTime)
final DateTime timeStart; DateTime timeStart;
@JsonKey(name: 'time_end', fromJson: CustomSerializer.stringToDateTime) @JsonKey(name: 'time_end', fromJson: CustomSerializer.stringToDateTime)
final DateTime timeEnd; DateTime timeEnd;
List<String> image; @JsonKey(name: 'zona_waktu')
String zonaWaktu;
List<String> images;
KegiatanModel({ KegiatanModel(
{
this.id, this.id,
this.placeId, this.placeId,
this.creator, this.creator,
this.namaKegiatan, this.namaKegiatan,
this.creatorEmail,
this.penyelenggara, this.penyelenggara,
this.narahubung,
this.deskripsi, this.deskripsi,
this.namaKontak,
this.nomorKontak,
this.links,
this.timeStart, this.timeStart,
this.timeEnd, this.timeEnd,
this.image, this.zonaWaktu,
this.creatorEmail, this.images,
}); }
);
factory KegiatanModel.fromJson(Map<String, dynamic> json) => factory KegiatanModel.fromJson(Map<String, dynamic> json) =>
_$KegiatanModelFromJson(json); _$KegiatanModelFromJson(json);
......
...@@ -27,13 +27,16 @@ KegiatanModel _$KegiatanModelFromJson(Map<String, dynamic> json) { ...@@ -27,13 +27,16 @@ KegiatanModel _$KegiatanModelFromJson(Map<String, dynamic> json) {
placeId: json['place_id'] as String, placeId: json['place_id'] as String,
creator: json['creator'] as String, creator: json['creator'] as String,
namaKegiatan: json['nama_kegiatan'] as String, namaKegiatan: json['nama_kegiatan'] as String,
creatorEmail: json['creator_email'] as String,
penyelenggara: json['penyelenggara'] as String, penyelenggara: json['penyelenggara'] as String,
narahubung: json['narahubung'] as String,
deskripsi: json['deskripsi'] as String, deskripsi: json['deskripsi'] as String,
namaKontak: json['nama_kontak'] as String,
nomorKontak: json['nomor_kontak'] as String,
links: json['links'] as String,
timeStart: CustomSerializer.stringToDateTime(json['time_start'] as String), timeStart: CustomSerializer.stringToDateTime(json['time_start'] as String),
timeEnd: CustomSerializer.stringToDateTime(json['time_end'] as String), timeEnd: CustomSerializer.stringToDateTime(json['time_end'] as String),
image: (json['image'] as List)?.map((e) => e as String)?.toList(), zonaWaktu: json['zona_waktu'] as String,
creatorEmail: json['creator_email'] as String, images: (json['images'] as List)?.map((e) => e as String)?.toList(),
); );
} }
...@@ -42,12 +45,15 @@ Map<String, dynamic> _$KegiatanModelToJson(KegiatanModel instance) => ...@@ -42,12 +45,15 @@ Map<String, dynamic> _$KegiatanModelToJson(KegiatanModel instance) =>
'id': instance.id, 'id': instance.id,
'place_id': instance.placeId, 'place_id': instance.placeId,
'creator': instance.creator, 'creator': instance.creator,
'creator_email': instance.creatorEmail,
'nama_kegiatan': instance.namaKegiatan, 'nama_kegiatan': instance.namaKegiatan,
'creator_email': instance.creatorEmail,
'penyelenggara': instance.penyelenggara, 'penyelenggara': instance.penyelenggara,
'narahubung': instance.narahubung,
'deskripsi': instance.deskripsi, 'deskripsi': instance.deskripsi,
'nama_kontak': instance.namaKontak,
'nomor_kontak': instance.nomorKontak,
'links': instance.links,
'time_start': instance.timeStart?.toIso8601String(), 'time_start': instance.timeStart?.toIso8601String(),
'time_end': instance.timeEnd?.toIso8601String(), 'time_end': instance.timeEnd?.toIso8601String(),
'image': instance.image, 'zona_waktu': instance.zonaWaktu,
'images': instance.images,
}; };
import 'package:intl/intl.dart';
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
import 'package:bisaGo/config/custom_serializer.dart';
part 'komentar.g.dart'; part 'komentar.g.dart';
...@@ -16,7 +16,7 @@ class KomentarModel { ...@@ -16,7 +16,7 @@ class KomentarModel {
final String namaLokasi; final String namaLokasi;
final String deskripsi; final String deskripsi;
final String creator; final String creator;
@JsonKey(name: 'date_time', fromJson: CustomSerializer.stringToDateTime) @JsonKey(name: 'date_time', fromJson: _stringToDateTime)
final DateTime dateTime; final DateTime dateTime;
final String tag; final String tag;
final List<String> disabilitas; final List<String> disabilitas;
...@@ -48,3 +48,7 @@ class KomentarModel { ...@@ -48,3 +48,7 @@ class KomentarModel {
Map<String, dynamic> toJson() => _$KomentarModelToJson(this); Map<String, dynamic> toJson() => _$KomentarModelToJson(this);
} }
DateTime _stringToDateTime(String date) {
return DateFormat('dd-MM-yyyy hh:mm').parse(date);
}
...@@ -27,7 +27,7 @@ KomentarModel _$KomentarModelFromJson(Map<String, dynamic> json) { ...@@ -27,7 +27,7 @@ KomentarModel _$KomentarModelFromJson(Map<String, dynamic> json) {
namaLokasi: json['nama_lokasi'] as String, namaLokasi: json['nama_lokasi'] as String,
deskripsi: json['deskripsi'] as String, deskripsi: json['deskripsi'] as String,
creator: json['creator'] as String, creator: json['creator'] as String,
dateTime: CustomSerializer.stringToDateTime(json['date_time'] as String), dateTime: _stringToDateTime(json['date_time'] as String),
tag: json['tag'] as String, tag: json['tag'] as String,
disabilitas: disabilitas:
(json['disabilitas'] as List)?.map((e) => e as String)?.toList(), (json['disabilitas'] as List)?.map((e) => e as String)?.toList(),
......
import 'package:intl/intl.dart';
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
import 'package:bisaGo/config/custom_serializer.dart';
part 'komentar_posting.g.dart'; part 'komentar_posting.g.dart';
...@@ -18,7 +18,7 @@ class KomentarPostingModel { ...@@ -18,7 +18,7 @@ class KomentarPostingModel {
final String creatorEmail; final String creatorEmail;
@JsonKey(name: 'creator_picture') @JsonKey(name: 'creator_picture')
final String creatorPicture; final String creatorPicture;
@JsonKey(fromJson: CustomSerializer.stringToDateTime) @JsonKey(fromJson: _stringToDateTime)
final DateTime created; final DateTime created;
KomentarPostingModel({ KomentarPostingModel({
...@@ -35,3 +35,7 @@ class KomentarPostingModel { ...@@ -35,3 +35,7 @@ class KomentarPostingModel {
Map<String, dynamic> toJson() => _$KomentarPostingModelToJson(this); Map<String, dynamic> toJson() => _$KomentarPostingModelToJson(this);
} }
DateTime _stringToDateTime(String date) {
return DateFormat('dd-MM-yyyy hh:mm').parse(date);
}
...@@ -29,7 +29,7 @@ KomentarPostingModel _$KomentarPostingModelFromJson(Map<String, dynamic> json) { ...@@ -29,7 +29,7 @@ KomentarPostingModel _$KomentarPostingModelFromJson(Map<String, dynamic> json) {
creator: json['creator'] as String, creator: json['creator'] as String,
creatorEmail: json['creator_email'] as String, creatorEmail: json['creator_email'] as String,
creatorPicture: json['creator_picture'] as String, creatorPicture: json['creator_picture'] as String,
created: CustomSerializer.stringToDateTime(json['created'] as String), created: _stringToDateTime(json['created'] as String),
); );
} }
......
import 'package:intl/intl.dart'; import 'package:bisaGo/config/custom_serializer.dart';
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
part 'komentar_posting_kegiatan.g.dart'; part 'komentar_posting_kegiatan.g.dart';
...@@ -18,7 +18,7 @@ class KomentarPostingKegiatanModel { ...@@ -18,7 +18,7 @@ class KomentarPostingKegiatanModel {
@JsonKey(name: 'creator_picture') @JsonKey(name: 'creator_picture')
final String creatorPicture; final String creatorPicture;
final String deskripsi; final String deskripsi;
@JsonKey(name: 'created', fromJson: _stringToDateTime) @JsonKey(name: 'created', fromJson: CustomSerializer.stringToDateTime)
final DateTime created; final DateTime created;
KomentarPostingKegiatanModel({ KomentarPostingKegiatanModel({
...@@ -35,7 +35,3 @@ class KomentarPostingKegiatanModel { ...@@ -35,7 +35,3 @@ class KomentarPostingKegiatanModel {
Map<String, dynamic> toJson() => _$KomentarPostingKegiatanModelToJson(this); Map<String, dynamic> toJson() => _$KomentarPostingKegiatanModelToJson(this);
} }
DateTime _stringToDateTime(String date) {
return DateFormat('yyy-MM-dd hh:mm').parse(date);
}
...@@ -29,7 +29,7 @@ KomentarPostingKegiatanModel _$KomentarPostingKegiatanModelFromJson( ...@@ -29,7 +29,7 @@ KomentarPostingKegiatanModel _$KomentarPostingKegiatanModelFromJson(
id: json['id'] as int, id: json['id'] as int,
creator: json['creator'] as String, creator: json['creator'] as String,
deskripsi: json['deskripsi'] as String, deskripsi: json['deskripsi'] as String,
created: _stringToDateTime(json['created'] as String), created: CustomSerializer.stringToDateTime(json['created'] as String),
creatorEmail: json['creator_email'] as String, creatorEmail: json['creator_email'] as String,
creatorPicture: json['creator_picture'] as String, creatorPicture: json['creator_picture'] as String,
); );
......
...@@ -77,7 +77,7 @@ class NetworkInterface { ...@@ -77,7 +77,7 @@ class NetworkInterface {
} }
Future<void> setToken(bool isLogin) async { Future<void> setToken(bool isLogin) async {
if (isLogin) { if (isLogin == true) {
final sharedPreferences = await SharedPreferences.getInstance(); final sharedPreferences = await SharedPreferences.getInstance();
dio.options.headers['Authorization'] = dio.options.headers['Authorization'] =
'Token ${sharedPreferences.getString('token')}'; 'Token ${sharedPreferences.getString('token')}';
......
...@@ -422,7 +422,6 @@ class AddInformasiState extends State<AddInformasi> { ...@@ -422,7 +422,6 @@ class AddInformasiState extends State<AddInformasi> {
.asUint8List(); .asUint8List();
newKomentarData['image'] = newKomentarData['image'] =
MultipartFile.fromBytes(bytes, filename: 'kursiroda.jpg'); MultipartFile.fromBytes(bytes, filename: 'kursiroda.jpg');
print('Fasilitas null dalem addinfo adalah: ' + _jenisFasilitas);
break; break;
case 'LF': case 'LF':
var bytes = var bytes =
...@@ -520,12 +519,11 @@ class AddInformasiState extends State<AddInformasi> { ...@@ -520,12 +519,11 @@ class AddInformasiState extends State<AddInformasi> {
.asUint8List(); .asUint8List();
newKomentarData['image'] = newKomentarData['image'] =
MultipartFile.fromBytes(bytes, filename: 'defaultDisable.png'); MultipartFile.fromBytes(bytes, filename: 'defaultDisable.png');
print('Fasilitas null default addinfo adalah: ' + _jenisFasilitas);
break; break;
} }
} else { } else {
final fileName = _image.path.split('/').last; final fileName = _image.path.split('/').last;
newKomentarData['image'] = MultipartFile.fromFile( newKomentarData['image'] = await MultipartFile.fromFile(
_image.path, _image.path,
filename: fileName, filename: fileName,
); );
......
...@@ -26,6 +26,7 @@ import 'package:bisaGo/config/styles.dart'; ...@@ -26,6 +26,7 @@ import 'package:bisaGo/config/styles.dart';
import 'package:bisaGo/page/pencarian/pencarian.dart'; import 'package:bisaGo/page/pencarian/pencarian.dart';
import 'package:google_maps_webservice/places.dart'; import 'package:google_maps_webservice/places.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:shimmer/shimmer.dart';
import '../filter_fasilitas/postingan/detail_post.dart'; import '../filter_fasilitas/postingan/detail_post.dart';
...@@ -41,6 +42,7 @@ class DashboardState extends State<Dashboard> { ...@@ -41,6 +42,7 @@ class DashboardState extends State<Dashboard> {
Geolocator geolocator; Geolocator geolocator;
LatLng currentLocation; LatLng currentLocation;
Set<Marker> markers = {}; Set<Marker> markers = {};
bool _enabled = true;
LokasiResponseBloc bloc = LokasiResponseBloc(); LokasiResponseBloc bloc = LokasiResponseBloc();
KegiatanTerdekatBloc blocKegiatanTerdekat = KegiatanTerdekatBloc(); KegiatanTerdekatBloc blocKegiatanTerdekat = KegiatanTerdekatBloc();
...@@ -194,19 +196,18 @@ class DashboardState extends State<Dashboard> { ...@@ -194,19 +196,18 @@ class DashboardState extends State<Dashboard> {
if (snapshot.hasData) { if (snapshot.hasData) {
switch (snapshot.data.status) { switch (snapshot.data.status) {
case Status.loading: case Status.loading:
_enabled = true;
return Container( return Container(
child: const Center( child: _buildMockKegiatanTerdekatWidget());
child: LinearProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
greenPrimary),
)));
break; break;
case Status.completed: case Status.completed:
_enabled = false;
final kegiatanTerdekat = snapshot.data.data; final kegiatanTerdekat = snapshot.data.data;
return _buildKegiatanTerdekatWidget( return _buildKegiatanTerdekatWidget(
kegiatanTerdekat); kegiatanTerdekat);
break; break;
case Status.error: case Status.error:
_enabled = false;
return Container( return Container(
child: const Center( child: const Center(
child: Text( child: Text(
...@@ -286,21 +287,17 @@ class DashboardState extends State<Dashboard> { ...@@ -286,21 +287,17 @@ class DashboardState extends State<Dashboard> {
if (snapshot.hasData) { if (snapshot.hasData) {
switch (snapshot.data.status) { switch (snapshot.data.status) {
case Status.loading: case Status.loading:
_enabled = true;