feat: implemenat refresh indicator
This commit is contained in:
parent
b951af1eec
commit
0cf104c5d9
|
@ -1,8 +1,13 @@
|
||||||
|
import 'dart:math' as math;
|
||||||
|
|
||||||
|
import 'package:custom_refresh_indicator/custom_refresh_indicator.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:iconsax_flutter/iconsax_flutter.dart';
|
import 'package:iconsax_flutter/iconsax_flutter.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:rijig_mobile/core/utils/guide.dart';
|
import 'package:rijig_mobile/core/utils/guide.dart';
|
||||||
import 'package:rijig_mobile/features/home/presentation/components/about_comp.dart';
|
import 'package:rijig_mobile/features/home/presentation/components/about_comp.dart';
|
||||||
|
import 'package:rijig_mobile/features/home/presentation/viewmodel/about_vmod.dart';
|
||||||
import 'package:rijig_mobile/widget/card_withicon.dart';
|
import 'package:rijig_mobile/widget/card_withicon.dart';
|
||||||
|
|
||||||
class HomeScreen extends StatefulWidget {
|
class HomeScreen extends StatefulWidget {
|
||||||
|
@ -17,10 +22,29 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: whiteColor,
|
backgroundColor: whiteColor,
|
||||||
body: SafeArea(
|
body: CustomMaterialIndicator(
|
||||||
child: SingleChildScrollView(
|
onRefresh: () async {
|
||||||
padding: PaddingCustom().paddingHorizontalVertical(16, 20),
|
await Provider.of<AboutViewModel>(
|
||||||
child: Column(
|
context,
|
||||||
|
listen: false,
|
||||||
|
).getAboutList();
|
||||||
|
},
|
||||||
|
backgroundColor: whiteColor,
|
||||||
|
indicatorBuilder: (context, controller) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(6.0),
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
color: primaryColor,
|
||||||
|
value:
|
||||||
|
controller.state.isLoading
|
||||||
|
? null
|
||||||
|
: math.min(controller.value, 1.0),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: SafeArea(
|
||||||
|
child: ListView(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
@ -72,7 +96,7 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Important!",
|
"Important!",
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
|
@ -80,7 +104,7 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const Gap(15),
|
Gap(15),
|
||||||
AboutComponent(),
|
AboutComponent(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -94,7 +118,7 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Artikel",
|
"Artikel",
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
|
@ -105,6 +129,7 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
Gap(20),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
import 'dart:math' as math;
|
||||||
|
|
||||||
|
import 'package:custom_refresh_indicator/custom_refresh_indicator.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
@ -6,63 +9,92 @@ import 'package:rijig_mobile/globaldata/trash/trash_viewmodel.dart';
|
||||||
import 'package:rijig_mobile/widget/appbar.dart';
|
import 'package:rijig_mobile/widget/appbar.dart';
|
||||||
import 'package:shimmer/shimmer.dart';
|
import 'package:shimmer/shimmer.dart';
|
||||||
|
|
||||||
class RequestPickScreen extends StatelessWidget {
|
class RequestPickScreen extends StatefulWidget {
|
||||||
const RequestPickScreen({super.key});
|
const RequestPickScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
RequestPickScreenState createState() => RequestPickScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class RequestPickScreenState extends State<RequestPickScreen> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
Provider.of<TrashViewModel>(context, listen: false).loadCategories();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Future.microtask(() {
|
|
||||||
// ignore: use_build_context_synchronously
|
|
||||||
Provider.of<TrashViewModel>(context, listen: false).loadCategories();
|
|
||||||
});
|
|
||||||
final String? baseUrl = dotenv.env["BASE_URL"];
|
final String? baseUrl = dotenv.env["BASE_URL"];
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: whiteColor,
|
backgroundColor: whiteColor,
|
||||||
appBar: CustomAppBar(judul: "Pilih sampah"),
|
appBar: CustomAppBar(judul: "Pilih sampah"),
|
||||||
body: Consumer<TrashViewModel>(
|
body: CustomMaterialIndicator(
|
||||||
builder: (context, viewModel, child) {
|
onRefresh: () async {
|
||||||
if (viewModel.isLoading) {
|
await Provider.of<TrashViewModel>(
|
||||||
return ListView.builder(
|
context,
|
||||||
itemCount: 5,
|
listen: false,
|
||||||
itemBuilder: (context, index) {
|
).loadCategories();
|
||||||
return SkeletonCard();
|
},
|
||||||
},
|
backgroundColor: Colors.white,
|
||||||
);
|
indicatorBuilder: (context, controller) {
|
||||||
}
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(6.0),
|
||||||
if (viewModel.errorMessage != null) {
|
child: CircularProgressIndicator(
|
||||||
return Center(child: Text(viewModel.errorMessage!));
|
color: primaryColor,
|
||||||
}
|
value:
|
||||||
|
controller.state.isLoading
|
||||||
return ListView.builder(
|
? null
|
||||||
itemCount: viewModel.trashCategoryResponse?.categories.length ?? 0,
|
: math.min(controller.value, 1.0),
|
||||||
itemBuilder: (context, index) {
|
),
|
||||||
final category =
|
|
||||||
viewModel.trashCategoryResponse!.categories[index];
|
|
||||||
return Card(
|
|
||||||
margin: const EdgeInsets.symmetric(
|
|
||||||
vertical: 10,
|
|
||||||
horizontal: 15,
|
|
||||||
),
|
|
||||||
elevation: 4,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
),
|
|
||||||
child: ListTile(
|
|
||||||
leading: Image.network(
|
|
||||||
"$baseUrl${category.icon}",
|
|
||||||
width: 50,
|
|
||||||
height: 50,
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
),
|
|
||||||
title: Text(category.name),
|
|
||||||
subtitle: Text("${category.price}"),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
child: Consumer<TrashViewModel>(
|
||||||
|
builder: (context, viewModel, child) {
|
||||||
|
if (viewModel.isLoading) {
|
||||||
|
return ListView.builder(
|
||||||
|
itemCount: 5,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return SkeletonCard();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viewModel.errorMessage != null) {
|
||||||
|
return Center(child: Text(viewModel.errorMessage!));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ListView.builder(
|
||||||
|
itemCount:
|
||||||
|
viewModel.trashCategoryResponse?.categories.length ?? 0,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final category =
|
||||||
|
viewModel.trashCategoryResponse!.categories[index];
|
||||||
|
return Card(
|
||||||
|
margin: const EdgeInsets.symmetric(
|
||||||
|
vertical: 10,
|
||||||
|
horizontal: 15,
|
||||||
|
),
|
||||||
|
elevation: 4,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
child: ListTile(
|
||||||
|
leading: Image.network(
|
||||||
|
"$baseUrl${category.icon}",
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
title: Text(category.name),
|
||||||
|
subtitle: Text("${category.price}"),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue