diff --git a/mobile/lib/api/review.dart b/mobile/lib/api/review.dart index 1bf406e..2cc18b1 100644 --- a/mobile/lib/api/review.dart +++ b/mobile/lib/api/review.dart @@ -64,7 +64,7 @@ Future createReview( if (e.response != null) { var response = e.response!; if (response.statusCode == 401) { - profile.setLoggedOut(); + await profile.setLoggedOut(); return Future.error("Session expired"); } if (response.statusCode == 400) { diff --git a/mobile/lib/api/tikum.dart b/mobile/lib/api/tikum.dart index 5ffce7d..ee3235a 100644 --- a/mobile/lib/api/tikum.dart +++ b/mobile/lib/api/tikum.dart @@ -31,7 +31,7 @@ Future> getMyTikum() async { ); if (response.statusCode == 401) { - profile.setLoggedOut(); + await profile.setLoggedOut(); return Future.error("Session expired"); } @@ -64,7 +64,7 @@ Future deleteMyTikum(int id) async { ); if (response.statusCode == 401) { - profile.setLoggedOut(); + await profile.setLoggedOut(); return Future.error("Session expired"); } @@ -106,7 +106,7 @@ Future createTikum({ if (e.response != null) { var response = e.response!; if (response.statusCode == 401) { - profile.setLoggedOut(); + await profile.setLoggedOut(); return Future.error("Session expired"); } if (response.statusCode == 400) { diff --git a/mobile/lib/api/user.dart b/mobile/lib/api/user.dart index 74b74e8..aa49bb7 100644 --- a/mobile/lib/api/user.dart +++ b/mobile/lib/api/user.dart @@ -20,7 +20,7 @@ Future loginUser(String email, String password) async { var id = decoded["user"]["id"]; var profile = await SecureProfile.getStorage(); - profile.setLoggedIn(id, token); + await profile.setLoggedIn(id, token); } else if (response.statusCode == 400) { return Future.error("Email atau password salah"); } else { @@ -59,7 +59,7 @@ Future> getMyReviewById() async { ); if (response.statusCode == 401) { - profile.setLoggedOut(); + await profile.setLoggedOut(); return Future.error("Session expired, please login again"); } @@ -88,7 +88,7 @@ Future getMyProfileById() async { ); if (response.statusCode == 401) { - profile.setLoggedOut(); + await profile.setLoggedOut(); return Future.error("Session expired, please login again"); } @@ -118,7 +118,7 @@ Future deleteMyReview(int id) async { ); if (response.statusCode == 401) { - profile.setLoggedOut(); + await profile.setLoggedOut(); return Future.error("Session expired, please login again"); } @@ -144,7 +144,7 @@ Future userLogout() async { ); if (res.statusCode == 401) { - profile.setLoggedOut(); + await profile.setLoggedOut(); return Future.error("Session expired, please login again"); } @@ -152,7 +152,7 @@ Future userLogout() async { return Future.error("Failed to logout"); } - profile.setLoggedOut(); + await profile.setLoggedOut(); } Future getUserProfileById(int id) async { diff --git a/mobile/lib/model/profile_secure.dart b/mobile/lib/model/profile_secure.dart index 375d869..a0a1ba4 100644 --- a/mobile/lib/model/profile_secure.dart +++ b/mobile/lib/model/profile_secure.dart @@ -63,13 +63,13 @@ class SecureProfile { return userId; } - void setLoggedIn(int userId, String apiKey) async { + Future setLoggedIn(int userId, String apiKey) async { await storage.setInt("user_id", userId); await storage.setString("api_key", apiKey); isLoggedIn = true; } - void setLoggedOut() async { + Future setLoggedOut() async { await storage.remove("api_key"); await storage.remove("user_id"); isLoggedIn = false; diff --git a/mobile/lib/screen/_global/components/profile_card.dart b/mobile/lib/screen/_global/components/profile_card.dart index 0baa665..cce218c 100644 --- a/mobile/lib/screen/_global/components/profile_card.dart +++ b/mobile/lib/screen/_global/components/profile_card.dart @@ -67,7 +67,7 @@ class ProfileCard extends StatelessWidget { // ignore: prefer_const_literals_to_create_immutables children: [ const Text("Rataan Rating"), - Text(data.avgRating.toString()), + Text(data.avgRating.toStringAsFixed(2)), ], ), ), diff --git a/mobile/lib/screen/form_login/login_screen.dart b/mobile/lib/screen/form_login/login_screen.dart index c09763e..e4ef1f6 100644 --- a/mobile/lib/screen/form_login/login_screen.dart +++ b/mobile/lib/screen/form_login/login_screen.dart @@ -5,7 +5,6 @@ import 'package:mobile/api/user.dart'; import 'package:mobile/screen/form_register/register_screen.dart'; import 'package:mobile/screen/home/home_screen.dart'; import 'package:mobile/utils/show_snackbar.dart'; -import 'package:mobile/model/profile_secure.dart'; class LoginScreenArguments { LoginScreenArguments(); diff --git a/mobile/lib/screen/form_review/form_review_screen.dart b/mobile/lib/screen/form_review/form_review_screen.dart index fc1d45b..3b494f4 100644 --- a/mobile/lib/screen/form_review/form_review_screen.dart +++ b/mobile/lib/screen/form_review/form_review_screen.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:geolocator/geolocator.dart'; diff --git a/mobile/lib/screen/home/components/profile/myprofile/card_profile.dart b/mobile/lib/screen/home/components/profile/myprofile/card_profile.dart index 60d3adf..1f7a91b 100644 --- a/mobile/lib/screen/home/components/profile/myprofile/card_profile.dart +++ b/mobile/lib/screen/home/components/profile/myprofile/card_profile.dart @@ -8,30 +8,59 @@ import 'package:mobile/screen/review_detail/review_detail_screen.dart'; import 'package:mobile/utils/show_snackbar.dart'; // final GlobalKey _navKey = GlobalKey(); -class TimelineCard extends StatefulWidget { - final ReviewProfile data; + +class MyReviewCard extends StatelessWidget { final int randomForProfile = math.Random().nextInt(1000); - TimelineCard({Key? key, required this.data, int? randomForProfile}) + final ReviewProfile data; + Function? refreshParent; + MyReviewCard({Key? key, required this.data, this.refreshParent}) : super(key: key); - @override - State createState() => _TimelineCardState(); -} - -class _TimelineCardState extends State { - @override - void initState() { - super.initState(); - } - @override Widget build(BuildContext context) { + void _handleDelete() async { + showDialog( + context: context, + builder: (BuildContext context) => AlertDialog( + title: const Text('Hapus Review'), + content: const Text( + 'Jika anda menghapus review ini akan hilang dari timeline umum dan profile anda!'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context, 'Cancel'), + child: const Text('Cancel'), + ), + TextButton( + onPressed: () async { + try { + await deleteMyReview(data.id); + ShowSnackBar(context, "Berhasil menghapus post"); + if (refreshParent != null) { + refreshParent!(); + } + } catch (err) { + ShowSnackBar(context, err.toString()); + } + Navigator.pop(context, "OK"); + }, + child: const Text( + 'OK', + style: TextStyle( + color: Colors.red, + ), + ), + ), + ], + ), + ); + } + return Container( margin: const EdgeInsets.only(bottom: 5), child: InkWell( onTap: () { Navigator.pushNamed(context, ReviewDetailScreen.routeName, - arguments: ReviewDetailScreenArguments(id: widget.data.id)); + arguments: ReviewDetailScreenArguments(id: data.id)); }, child: Column( children: [ @@ -45,64 +74,27 @@ class _TimelineCardState extends State { borderRadius: BorderRadius.circular(50), child: ImageNetworkWShimmer( link: - "https://www.thiswaifudoesnotexist.net/example-${widget.randomForProfile}.jpg", + "https://www.thiswaifudoesnotexist.net/example-$randomForProfile.jpg", width: 40, height: 40, ), ), const SizedBox(width: 10), - Text(widget.data.nameUser) + Text(data.nameUser) ]), TextButton( - child: const Icon( - Icons.delete, - color: Colors.red, - ), - onPressed: () => showDialog( - context: context, - builder: (BuildContext context) => AlertDialog( - title: const Text('Hapus Review'), - content: const Text( - 'Jika anda menghapus review ini akan hilang dari timeline umum dan profile anda!'), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context, 'Cancel'), - child: const Text('Cancel'), - ), - TextButton( - onPressed: () async { - try { - await deleteMyReview(widget.data.id); - ShowSnackBar(context, - "Berhasil menghapus post, harap pindah halaman untuk melihat perubahan"); - } catch (err) { - ShowSnackBar(context, err.toString()); - } - Navigator.pop(context, "OK"); - }, - child: const Text( - 'OK', - style: TextStyle( - color: Colors.red, - ), - ), - ), - ], + child: const Icon( + Icons.delete, + color: Colors.red, ), - ), - // onPressed: () async { - // setState(() { - // _futureStatus = deleteMyReview(widget.data.id); - // }); - // }, - ), + onPressed: _handleDelete), ], )), const SizedBox(height: 10), ImageNetworkWShimmer( - link: widget.data.photo[0] == "/" - ? "https://travelliu.yaudahlah.my.id${widget.data.photo}" - : widget.data.photo), + link: data.photo[0] == "/" + ? "https://travelliu.yaudahlah.my.id${data.photo}" + : data.photo), Container( margin: const EdgeInsets.only(left: 10, right: 10, bottom: 10), child: Column( @@ -112,12 +104,12 @@ class _TimelineCardState extends State { children: [ const Icon(Icons.star_border_outlined, color: Colors.yellow), - Text(widget.data.rating.toString()), + Text(data.rating.toString()), const SizedBox( width: 10, ), Text( - widget.data.namaTempat, + data.namaTempat, style: const TextStyle(fontWeight: FontWeight.bold), ), ], @@ -127,7 +119,7 @@ class _TimelineCardState extends State { children: [ Expanded( child: Text( - widget.data.review, + data.review, textAlign: TextAlign.left, )) ], diff --git a/mobile/lib/screen/home/components/profile/myprofile/my_profile.dart b/mobile/lib/screen/home/components/profile/myprofile/my_profile.dart index 1fb8ff7..9ce78ec 100644 --- a/mobile/lib/screen/home/components/profile/myprofile/my_profile.dart +++ b/mobile/lib/screen/home/components/profile/myprofile/my_profile.dart @@ -17,27 +17,21 @@ class MyProfile extends StatelessWidget { Widget build(BuildContext context) { return SingleChildScrollView( child: Column( - children: const [ - SizedBox( + children: [ + const SizedBox( height: 10, ), _ProfileSection(), - _ReviewSection(), + const _ReviewSection(), ], ), ); } } -class _ProfileSection extends StatefulWidget { - const _ProfileSection({Key? key}) : super(key: key); - - @override - State<_ProfileSection> createState() => _ProfileSectionState(); -} - -class _ProfileSectionState extends State<_ProfileSection> { - Future futureProfile = getMyProfileById(); +class _ProfileSection extends StatelessWidget { + final Future futureProfile = getMyProfileById(); + _ProfileSection({Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -101,7 +95,7 @@ class _ProfileSectionState extends State<_ProfileSection> { return SizedBox( height: MediaQuery.of(context).size.height * 0.4, - child: Center(child: ShimmerProfile()), + child: const Center(child: ShimmerProfile()), ); }, ), @@ -120,6 +114,12 @@ class _ReviewSection extends StatefulWidget { class __ReviewSectionState extends State<_ReviewSection> { Future> futureReview = getMyReviewById(); + void refreshList() { + setState(() { + futureReview = getMyReviewById(); + }); + } + @override Widget build(BuildContext context) { return FutureBuilder>( @@ -129,11 +129,29 @@ class __ReviewSectionState extends State<_ReviewSection> { return Center(child: Text(snapshot.error.toString())); } if (snapshot.hasData) { + if (snapshot.data!.isEmpty) { + return Center( + child: SizedBox( + width: 350, + child: Column( + children: const [ + Text( + "Oops.. kamu masih belum membagikan apapun", + textAlign: TextAlign.center, + ), + Text("Bagikan cerita perjalananmu sekarang!") + ], + ), + ), + ); + } + return Column( children: [ for (var data in snapshot.data!) - TimelineCard( + MyReviewCard( data: data, + refreshParent: refreshList, ) ], ); diff --git a/mobile/lib/screen/home/components/tikum/my_tikum.dart b/mobile/lib/screen/home/components/tikum/my_tikum.dart index e247afe..cdea926 100644 --- a/mobile/lib/screen/home/components/tikum/my_tikum.dart +++ b/mobile/lib/screen/home/components/tikum/my_tikum.dart @@ -31,10 +31,10 @@ class _MyTikumState extends State { builder: (context, snapshot) { if (snapshot.hasData) { if (snapshot.data!.getLoggedInStatus()) { - return MyTikumList(); + return const MyTikumList(); } } - return NotLoggedIn(); + return const NotLoggedIn(); }, ), ); @@ -42,7 +42,7 @@ class _MyTikumState extends State { } class MyTikumList extends StatefulWidget { - MyTikumList({Key? key}) : super(key: key); + const MyTikumList({Key? key}) : super(key: key); @override State createState() => _MyTikumListState(); @@ -50,22 +50,49 @@ class MyTikumList extends StatefulWidget { class _MyTikumListState extends State { late Future> futureTikumProfile; + + @override void initState() { futureTikumProfile = getMyTikum(); super.initState(); } + void refreshList() { + setState(() { + futureTikumProfile = getMyTikum(); + }); + } + @override Widget build(BuildContext context) { return FutureBuilder>( future: futureTikumProfile, builder: (context, snapshot) { if (snapshot.hasData) { + if (snapshot.data!.isEmpty) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: const [ + Text( + "Wah sepertinya kamu belum membuat \nTitik Kumpul", + textAlign: TextAlign.center, + ), + Text( + "Tikum", + style: TextStyle(fontWeight: FontWeight.bold), + ) + ], + ), + ); + } + return ListView( children: [ for (var data in snapshot.data!) MyTikumCard( tikum: data, + refreshParent: refreshList, ) ], ); diff --git a/mobile/lib/screen/home/components/tikum/mytikum_card.dart b/mobile/lib/screen/home/components/tikum/mytikum_card.dart index 5ce43a8..1bf1456 100644 --- a/mobile/lib/screen/home/components/tikum/mytikum_card.dart +++ b/mobile/lib/screen/home/components/tikum/mytikum_card.dart @@ -8,10 +8,49 @@ import 'package:mobile/api/tikum.dart'; class MyTikumCard extends StatelessWidget { final TikumProfile tikum; - const MyTikumCard({Key? key, required this.tikum}) : super(key: key); + Function? refreshParent; + MyTikumCard({Key? key, required this.tikum, this.refreshParent}) + : super(key: key); @override Widget build(BuildContext context) { + void _handleDelete() async { + showDialog( + context: context, + builder: (BuildContext context) => AlertDialog( + title: const Text('Hapus Titik Kumpul'), + content: const Text( + 'Jika anda menghapus titik kumpul ini akan hilang dari my tikum anda!'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context, 'Cancel'), + child: const Text('Cancel'), + ), + TextButton( + onPressed: () async { + try { + await deleteMyTikum(tikum.id); + ShowSnackBar(context, "Berhasil menghapus titik kumpul"); + if (refreshParent != null) { + refreshParent!(); + } + } catch (err) { + ShowSnackBar(context, err.toString()); + } + Navigator.pop(context, "OK"); + }, + child: const Text( + 'OK', + style: TextStyle( + color: Colors.red, + ), + ), + ), + ], + ), + ); + } + return Column(children: [ Container( padding: @@ -40,48 +79,11 @@ class MyTikumCard extends StatelessWidget { ], ), TextButton( - child: const Icon( - Icons.delete, - color: Colors.red, - ), - onPressed: () => showDialog( - context: context, - builder: (BuildContext context) => AlertDialog( - title: const Text('Hapus Titik Kumpul'), - content: const Text( - 'Jika anda menghapus titik kumpul ini akan hilang dari my tikum anda!'), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context, 'Cancel'), - child: const Text('Cancel'), - ), - TextButton( - onPressed: () async { - try { - await deleteMyTikum(tikum.id); - ShowSnackBar(context, - "Berhasil menghapus titik kumpul, harap pindah halaman untuk melihat perubahan"); - } catch (err) { - ShowSnackBar(context, err.toString()); - } - Navigator.pop(context, "OK"); - }, - child: const Text( - 'OK', - style: TextStyle( - color: Colors.red, - ), - ), - ), - ], + child: const Icon( + Icons.delete, + color: Colors.red, ), - ), - // onPressed: () async { - // setState(() { - // _futureStatus = deleteMyReview(widget.data.id); - // }); - // }, - ), + onPressed: _handleDelete), ], ), const SizedBox( diff --git a/mobile/lib/screen/home/components/tikum/tikum.dart b/mobile/lib/screen/home/components/tikum/tikum.dart index b90cdee..9df1d4f 100644 --- a/mobile/lib/screen/home/components/tikum/tikum.dart +++ b/mobile/lib/screen/home/components/tikum/tikum.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:mobile/model/profile_secure.dart'; import 'package:mobile/screen/form_tikum/form_tikum_screen.dart'; -import 'package:mobile/screen/test_screen/test_screen.dart'; import 'package:mobile/screen/home/components/tikum/global_tikum.dart'; import 'package:mobile/screen/home/components/tikum/my_tikum.dart'; @@ -11,29 +10,29 @@ class TikumLayout extends StatelessWidget { @override Widget build(BuildContext context) { return DefaultTabController( - length: 2, - child: Scaffold( + length: 2, + child: Scaffold( + backgroundColor: Colors.white, + floatingActionButton: const _FloatingActionButtonTikum(), + appBar: AppBar( backgroundColor: Colors.white, - floatingActionButton: const _FloatingActionButtonTikum(), - appBar: AppBar( - backgroundColor: Colors.white, - flexibleSpace: Column( - mainAxisAlignment: MainAxisAlignment.end, - children: const [ - TabBar(indicatorColor: Colors.black26, tabs: [ - Tab( - text: "Global Tikum", - ), - Tab( - text: "My Tikum", - ) - ]) - ], - ), + flexibleSpace: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: const [ + TabBar(indicatorColor: Colors.black26, tabs: [ + Tab( + text: "Global Tikum", + ), + Tab( + text: "My Tikum", + ) + ]) + ], ), - body: TabBarView(children: [GlobalTikum(), MyTikum()]), - )); - ; + ), + body: TabBarView(children: [GlobalTikum(), MyTikum()]), + ), + ); } } diff --git a/mobile/lib/screen/home/home_screen.dart b/mobile/lib/screen/home/home_screen.dart index 696e070..63a4074 100644 --- a/mobile/lib/screen/home/home_screen.dart +++ b/mobile/lib/screen/home/home_screen.dart @@ -19,7 +19,7 @@ class HomeScreen extends StatefulWidget { class _HomeScreenState extends State { final List section = [ const Timeline(), - TikumLayout(), + const TikumLayout(), ProfileSection() ]; var sectionidx = 0; @@ -34,7 +34,7 @@ class _HomeScreenState extends State { return Scaffold( appBar: AppBar( - actions: [Image(image: AssetImage("assets/Logos.png"))], + actions: const [Image(image: AssetImage("assets/Logos.png"))], title: const Text("Travelliu", style: TextStyle(fontWeight: FontWeight.bold)), backgroundColor: Colors.white, diff --git a/mobile/lib/screen/permission/permission_screen.dart b/mobile/lib/screen/permission/permission_screen.dart index 3a56f74..abf0857 100644 --- a/mobile/lib/screen/permission/permission_screen.dart +++ b/mobile/lib/screen/permission/permission_screen.dart @@ -106,7 +106,7 @@ class _PermissionScreenState extends State { return Scaffold( backgroundColor: Colors.white, body: Padding( - padding: EdgeInsets.all(20), + padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisAlignment: MainAxisAlignment.spaceBetween, diff --git a/mobile/lib/screen/profile_detail/profile_detail_screen.dart b/mobile/lib/screen/profile_detail/profile_detail_screen.dart index ddf306e..c675aa4 100644 --- a/mobile/lib/screen/profile_detail/profile_detail_screen.dart +++ b/mobile/lib/screen/profile_detail/profile_detail_screen.dart @@ -12,8 +12,8 @@ class ProfilePeopleScreenArguments { } class ProfilePeopleScreen extends StatefulWidget { - ProfilePeopleScreen({Key? key}) : super(key: key); - static String routeName = "/profile-detail"; + const ProfilePeopleScreen({Key? key}) : super(key: key); + static const String routeName = "/profile-detail"; @override State createState() => _ProfilePeopleScreenState(); }