refact: refactoring code and style
This commit is contained in:
parent
4f84abfeee
commit
0d129218de
|
@ -47,5 +47,13 @@ final router = GoRouter(
|
|||
return AboutDetailScreenComp(data: data);
|
||||
},
|
||||
),
|
||||
|
||||
GoRoute(
|
||||
path: '/artikeldetail',
|
||||
builder: (context, state) {
|
||||
dynamic data = state.extra;
|
||||
return ArticleDetailScreen(data: data);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
|
@ -12,3 +12,4 @@ export 'package:rijig_mobile/features/auth/presentation/screen/verifpin_screen.d
|
|||
export 'package:rijig_mobile/features/launch/screen/onboardingpage_screen.dart';
|
||||
export 'package:rijig_mobile/features/launch/screen/splash_screen.dart';
|
||||
export 'package:rijig_mobile/features/home/presentation/components/about_detail_comp.dart';
|
||||
export 'package:rijig_mobile/features/home/presentation/components/article_content.dart';
|
||||
|
|
|
@ -52,7 +52,7 @@ class _NavigationPageState extends State<NavigationPage> {
|
|||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
extendBody: true,
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: whiteColor,
|
||||
body: IndexedStack(
|
||||
index: _selectedIndex,
|
||||
children: const [
|
||||
|
@ -151,7 +151,7 @@ class _NavigationPageState extends State<NavigationPage> {
|
|||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Iconsax.archive_2, color: Colors.white, size: 30),
|
||||
Icon(Iconsax.archive_2, color: whiteColor, size: 30),
|
||||
Text(
|
||||
"Mulai",
|
||||
style: Tulisan.customText(
|
||||
|
|
|
@ -5,7 +5,7 @@ import 'package:provider/provider.dart';
|
|||
import 'package:rijig_mobile/core/router.dart';
|
||||
import 'package:rijig_mobile/core/utils/guide.dart';
|
||||
import 'package:rijig_mobile/features/home/presentation/viewmodel/about_vmod.dart';
|
||||
import 'package:rijig_mobile/features/requestpick/presentation/screen/requestpickup_screen.dart';
|
||||
import 'package:rijig_mobile/widget/skeletonize.dart';
|
||||
|
||||
class AboutComponent extends StatefulWidget {
|
||||
const AboutComponent({super.key});
|
||||
|
@ -33,6 +33,7 @@ class AboutComponentState extends State<AboutComponent> {
|
|||
builder: (context, viewModel, child) {
|
||||
if (viewModel.isLoading) {
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: 1,
|
||||
itemBuilder: (context, index) {
|
||||
return SkeletonCard();
|
||||
|
@ -99,7 +100,6 @@ class AboutComponentState extends State<AboutComponent> {
|
|||
),
|
||||
onTap: () {
|
||||
debugPrint("Tapped on ${imageData['route']}");
|
||||
// imageData["route"];
|
||||
router.push("/aboutdetail", extra: imageData["route"]);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:rijig_mobile/features/home/presentation/viewmodel/about_vmod.dart';
|
||||
import 'package:rijig_mobile/features/requestpick/presentation/screen/requestpickup_screen.dart';
|
||||
import 'package:rijig_mobile/widget/appbar.dart';
|
||||
import 'package:rijig_mobile/widget/skeletonize.dart';
|
||||
|
||||
class AboutDetailScreenComp extends StatefulWidget {
|
||||
final String data;
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:rijig_mobile/core/utils/guide.dart';
|
||||
import 'package:rijig_mobile/globaldata/article/article_model.dart';
|
||||
import 'package:rijig_mobile/widget/appbar.dart';
|
||||
|
||||
class ArticleDetailScreen extends StatelessWidget {
|
||||
final ArticleModel data;
|
||||
|
||||
const ArticleDetailScreen({super.key, required this.data});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final String? baseUrl = dotenv.env["BASE_URL"];
|
||||
|
||||
return Scaffold(
|
||||
appBar: CustomAppBar(judul: "detail artikel"),
|
||||
body: SingleChildScrollView(
|
||||
padding: PaddingCustom().paddingAll(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(data.heading, style: Tulisan.heading()),
|
||||
Gap(8),
|
||||
Text(
|
||||
"Oleh ${data.author} • ${data.publishedAt}",
|
||||
style: TextStyle(
|
||||
fontSize: 13.sp,
|
||||
fontStyle: FontStyle.italic,
|
||||
color: greyAbsolutColor,
|
||||
),
|
||||
),
|
||||
Gap(30),
|
||||
if (data.coverImage.isNotEmpty)
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Image.network(
|
||||
"$baseUrl${data.coverImage}",
|
||||
width: double.infinity,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder:
|
||||
(context, error, stackTrace) =>
|
||||
const Icon(Icons.broken_image),
|
||||
),
|
||||
),
|
||||
Gap(10),
|
||||
Divider(thickness: 1.3, color: blackNavyColor),
|
||||
Gap(60),
|
||||
Text(data.content, style: Tulisan.customText()),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,11 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:rijig_mobile/core/router.dart';
|
||||
import 'package:rijig_mobile/core/utils/guide.dart';
|
||||
import 'package:rijig_mobile/globaldata/article/article_vmod.dart';
|
||||
import 'package:rijig_mobile/widget/skeletonize.dart';
|
||||
|
||||
class ArticleScreen extends StatefulWidget {
|
||||
const ArticleScreen({super.key});
|
||||
|
@ -14,7 +18,6 @@ class _ArticleScreenState extends State<ArticleScreen> {
|
|||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// Fetch data setelah frame build pertama
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
Provider.of<ArticleViewModel>(context, listen: false).loadArticles();
|
||||
});
|
||||
|
@ -27,7 +30,13 @@ class _ArticleScreenState extends State<ArticleScreen> {
|
|||
return Consumer<ArticleViewModel>(
|
||||
builder: (context, viewModel, child) {
|
||||
if (viewModel.isLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: 1,
|
||||
itemBuilder: (context, index) {
|
||||
return SkeletonCard();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (viewModel.errorMessage != null) {
|
||||
|
@ -38,49 +47,78 @@ class _ArticleScreenState extends State<ArticleScreen> {
|
|||
return const Center(child: Text("Tidak ada artikel ditemukan."));
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
itemCount: viewModel.articles.length,
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) {
|
||||
final article = viewModel.articles[index];
|
||||
return Card(
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
elevation: 3,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: ListTile(
|
||||
contentPadding: const EdgeInsets.all(12),
|
||||
leading: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Image.network(
|
||||
"$baseUrl${article.coverImage}",
|
||||
width: 60,
|
||||
height: 60,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder:
|
||||
(context, error, stackTrace) =>
|
||||
const Icon(Icons.image_not_supported),
|
||||
return SizedBox(
|
||||
height: 190,
|
||||
child: ListView.separated(
|
||||
scrollDirection: Axis.horizontal,
|
||||
clipBehavior: Clip.none,
|
||||
itemCount: viewModel.articles.length,
|
||||
separatorBuilder: (_, __) => Gap(12),
|
||||
itemBuilder: (context, index) {
|
||||
final article = viewModel.articles[index];
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
router.push("/artikeldetail", extra: article);
|
||||
},
|
||||
child: Container(
|
||||
padding: PaddingCustom().paddingAll(3),
|
||||
width: 180,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: greyColor),
|
||||
color: whiteColor,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(16),
|
||||
topRight: Radius.circular(16),
|
||||
),
|
||||
child: Image.network(
|
||||
"$baseUrl${article.coverImage}",
|
||||
width: double.infinity,
|
||||
height: 100,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder:
|
||||
(context, error, stackTrace) =>
|
||||
const Icon(Icons.image_not_supported),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: PaddingCustom().paddingAll(10),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
article.heading,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
"by ${article.author} • ${article.publishedAt}",
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
title: Text(
|
||||
article.heading,
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
subtitle: Text(
|
||||
"By ${article.author} • ${article.publishedAt}",
|
||||
style: const TextStyle(fontSize: 12),
|
||||
),
|
||||
onTap: () {
|
||||
// Navigasi ke detail (jika tersedia)
|
||||
// router.push('/article-detail', extra: article.articleId);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -122,21 +122,18 @@ class _HomeScreenState extends State<HomeScreen> {
|
|||
Gap(20),
|
||||
Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Artikel",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.black,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Artikel",
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.black,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Gap(15),
|
||||
ArticleScreen(),
|
||||
|
|
|
@ -7,7 +7,7 @@ import 'package:provider/provider.dart';
|
|||
import 'package:rijig_mobile/core/utils/guide.dart';
|
||||
import 'package:rijig_mobile/globaldata/trash/trash_viewmodel.dart';
|
||||
import 'package:rijig_mobile/widget/appbar.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
import 'package:rijig_mobile/widget/skeletonize.dart';
|
||||
|
||||
class RequestPickScreen extends StatefulWidget {
|
||||
const RequestPickScreen({super.key});
|
||||
|
@ -20,7 +20,9 @@ class RequestPickScreenState extends State<RequestPickScreen> {
|
|||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
Provider.of<TrashViewModel>(context, listen: false).loadCategories();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
Provider.of<TrashViewModel>(context, listen: false).loadCategories();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -37,10 +39,10 @@ class RequestPickScreenState extends State<RequestPickScreen> {
|
|||
listen: false,
|
||||
).loadCategories();
|
||||
},
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: whiteColor,
|
||||
indicatorBuilder: (context, controller) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(6.0),
|
||||
padding: PaddingCustom().paddingAll(6),
|
||||
child: CircularProgressIndicator(
|
||||
color: primaryColor,
|
||||
value:
|
||||
|
@ -54,6 +56,7 @@ class RequestPickScreenState extends State<RequestPickScreen> {
|
|||
builder: (context, viewModel, child) {
|
||||
if (viewModel.isLoading) {
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: 5,
|
||||
itemBuilder: (context, index) {
|
||||
return SkeletonCard();
|
||||
|
@ -99,25 +102,3 @@ class RequestPickScreenState extends State<RequestPickScreen> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SkeletonCard extends StatelessWidget {
|
||||
const SkeletonCard({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Shimmer.fromColors(
|
||||
baseColor: Colors.grey[300]!,
|
||||
highlightColor: Colors.grey[100]!,
|
||||
child: Card(
|
||||
margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
|
||||
elevation: 4,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
child: ListTile(
|
||||
leading: Container(width: 50, height: 50, color: Colors.white),
|
||||
title: Container(width: 100, height: 15, color: Colors.white),
|
||||
subtitle: Container(width: 150, height: 10, color: Colors.white),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
|
||||
class SkeletonCard extends StatelessWidget {
|
||||
const SkeletonCard({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Shimmer.fromColors(
|
||||
baseColor: Colors.grey[300]!,
|
||||
highlightColor: Colors.grey[100]!,
|
||||
child: Card(
|
||||
margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
|
||||
elevation: 4,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
child: ListTile(
|
||||
leading: Container(width: 50, height: 50, color: Colors.white),
|
||||
title: Container(width: 100, height: 15, color: Colors.white),
|
||||
subtitle: Container(width: 150, height: 10, color: Colors.white),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue