From 9bbfd4529aa13b2a98345dbbf085d40fda83f7fb Mon Sep 17 00:00:00 2001 From: pahmiudahgede Date: Thu, 15 May 2025 16:27:07 +0700 Subject: [PATCH] feat: add feature about detail and prepare repsponse --- lib/core/container/export_vmod.dart | 5 +- lib/core/container/injection_container.dart | 6 +- lib/core/router.dart | 8 + lib/core/utils/exportimportview.dart | 5 +- lib/core/utils/navigation.dart | 2 +- lib/features/home/home_screen.dart | 222 ------------------ lib/features/home/model/about_model.dart | 55 +++++ .../presentation/components/about_comp.dart | 147 ++++++++++++ .../components/about_detail_comp.dart | 62 +++++ .../components/product_card.dart | 0 .../home/presentation/screen/home_screen.dart | 118 ++++++++++ .../presentation/viewmodel/about_vmod.dart | 52 ++++ .../home/repositories/about_repository.dart | 21 ++ lib/features/home/service/about_service.dart | 24 ++ .../screen}/requestpickup_screen.dart | 4 +- lib/main.dart | 2 + pubspec.lock | 24 ++ pubspec.yaml | 3 + 18 files changed, 531 insertions(+), 229 deletions(-) delete mode 100644 lib/features/home/home_screen.dart create mode 100644 lib/features/home/model/about_model.dart create mode 100644 lib/features/home/presentation/components/about_comp.dart create mode 100644 lib/features/home/presentation/components/about_detail_comp.dart rename lib/features/home/{ => presentation}/components/product_card.dart (100%) create mode 100644 lib/features/home/presentation/screen/home_screen.dart create mode 100644 lib/features/home/presentation/viewmodel/about_vmod.dart create mode 100644 lib/features/home/repositories/about_repository.dart create mode 100644 lib/features/home/service/about_service.dart rename lib/features/requestpick/{ => presentation/screen}/requestpickup_screen.dart (96%) diff --git a/lib/core/container/export_vmod.dart b/lib/core/container/export_vmod.dart index 70b005b..a1c0a9e 100644 --- a/lib/core/container/export_vmod.dart +++ b/lib/core/container/export_vmod.dart @@ -10,4 +10,7 @@ export 'package:rijig_mobile/features/auth/service/logout_service.dart'; export 'package:rijig_mobile/features/auth/service/otp_service.dart'; export 'package:rijig_mobile/globaldata/trash/trash_repository.dart'; export 'package:rijig_mobile/globaldata/trash/trash_service.dart'; -export 'package:rijig_mobile/globaldata/trash/trash_viewmodel.dart'; \ No newline at end of file +export 'package:rijig_mobile/globaldata/trash/trash_viewmodel.dart'; +export 'package:rijig_mobile/features/home/presentation/viewmodel/about_vmod.dart'; +export 'package:rijig_mobile/features/home/repositories/about_repository.dart'; +export 'package:rijig_mobile/features/home/service/about_service.dart'; diff --git a/lib/core/container/injection_container.dart b/lib/core/container/injection_container.dart index 84887dd..dde20c8 100644 --- a/lib/core/container/injection_container.dart +++ b/lib/core/container/injection_container.dart @@ -7,5 +7,9 @@ void init() { sl.registerFactory(() => OtpViewModel(OtpService(OtpRepository()))); sl.registerFactory(() => LogoutViewModel(LogoutService(LogoutRepository()))); - sl.registerFactory(() => TrashViewModel(TrashCategoryService(TrashCategoryRepository()))); + sl.registerFactory( + () => TrashViewModel(TrashCategoryService(TrashCategoryRepository())), + ); + sl.registerFactory(() => AboutViewModel(AboutService(AboutRepository()))); + sl.registerFactory(() => AboutDetailViewModel(AboutService(AboutRepository()))); } diff --git a/lib/core/router.dart b/lib/core/router.dart index 14d85b3..c3b5f69 100644 --- a/lib/core/router.dart +++ b/lib/core/router.dart @@ -39,5 +39,13 @@ final router = GoRouter( ), GoRoute(path: '/cart', builder: (context, state) => CartScreen()), GoRoute(path: '/profil', builder: (context, state) => ProfilScreen()), + + GoRoute( + path: '/aboutdetail', + builder: (context, state) { + dynamic data = state.extra; + return AboutDetailScreenComp(data: data); + }, + ), ], ); diff --git a/lib/core/utils/exportimportview.dart b/lib/core/utils/exportimportview.dart index 6739d14..e1647a4 100644 --- a/lib/core/utils/exportimportview.dart +++ b/lib/core/utils/exportimportview.dart @@ -2,12 +2,13 @@ export 'package:go_router/go_router.dart'; export 'package:rijig_mobile/core/utils/navigation.dart'; export 'package:rijig_mobile/features/activity/activity_screen.dart'; export 'package:rijig_mobile/features/cart/cart_screen.dart'; -export 'package:rijig_mobile/features/home/home_screen.dart'; +export 'package:rijig_mobile/features/home/presentation/screen/home_screen.dart'; export 'package:rijig_mobile/features/profil/profil_screen.dart'; -export 'package:rijig_mobile/features/requestpick/requestpickup_screen.dart'; +export 'package:rijig_mobile/features/requestpick/presentation/screen/requestpickup_screen.dart'; export 'package:rijig_mobile/features/auth/presentation/screen/inputpin_screen.dart'; export 'package:rijig_mobile/features/auth/presentation/screen/login_screen.dart'; export 'package:rijig_mobile/features/auth/presentation/screen/otp_screen.dart'; export 'package:rijig_mobile/features/auth/presentation/screen/verifpin_screen.dart'; export 'package:rijig_mobile/features/launch/onboardingpage_screen.dart'; export 'package:rijig_mobile/features/launch/splash_screen.dart'; +export 'package:rijig_mobile/features/home/presentation/components/about_detail_comp.dart'; diff --git a/lib/core/utils/navigation.dart b/lib/core/utils/navigation.dart index 9c9c79a..3c17bcf 100644 --- a/lib/core/utils/navigation.dart +++ b/lib/core/utils/navigation.dart @@ -4,7 +4,7 @@ import 'package:rijig_mobile/core/utils/guide.dart'; import 'package:rijig_mobile/core/router.dart'; import 'package:rijig_mobile/features/activity/activity_screen.dart'; import 'package:rijig_mobile/features/cart/cart_screen.dart'; -import 'package:rijig_mobile/features/home/home_screen.dart'; +import 'package:rijig_mobile/features/home/presentation/screen/home_screen.dart'; import 'package:rijig_mobile/features/profil/profil_screen.dart'; import 'package:shared_preferences/shared_preferences.dart'; diff --git a/lib/features/home/home_screen.dart b/lib/features/home/home_screen.dart deleted file mode 100644 index 44f22b1..0000000 --- a/lib/features/home/home_screen.dart +++ /dev/null @@ -1,222 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:gap/gap.dart'; -import 'package:iconsax_flutter/iconsax_flutter.dart'; -import 'package:rijig_mobile/core/utils/guide.dart'; -import 'package:rijig_mobile/features/home/components/product_card.dart'; -import 'package:rijig_mobile/features/home/model/product.dart'; -import 'package:rijig_mobile/widget/card_withicon.dart'; - -class HomeScreen extends StatefulWidget { - const HomeScreen({super.key}); - - @override - State createState() => _HomeScreenState(); -} - -class _HomeScreenState extends State { - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: whiteColor, - body: SafeArea( - child: SingleChildScrollView( - padding: PaddingCustom().paddingHorizontalVertical(16, 20), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Rijig", - style: Tulisan.heading(color: primaryColor), - ), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Icon(Iconsax.notification), - Gap(10), - Icon(Iconsax.message_2), - ], - ), - ], - ), - ), - ], - ), - Gap(20), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - CardWithIcon( - icon: Icons.account_circle, - text: 'Users', - number: '245', - onTap: () {}, - ), - CardWithIcon( - icon: Icons.shopping_cart, - text: 'Orders', - number: '178', - onTap: () {}, - ), - ], - ), - Gap(20), - Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - "Important!", - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Colors.black, - ), - ), - ], - ), - const Gap(15), - SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - children: [ - SpecialOfferCard( - image: "assets/image/Image Banner 2.png", - category: "Smartphone", - numOfBrands: 18, - press: () {}, - ), - Gap(10), - SpecialOfferCard( - image: "assets/image/Image Banner 3.png", - category: "Fashion", - numOfBrands: 24, - press: () {}, - ), - ], - ), - ), - ], - ), - Gap(20), - Column( - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - "Artikel", - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Colors.black, - ), - ), - ], - ), - ), - SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - children: [ - ...List.generate(demoProducts.length, (index) { - if (demoProducts[index].isPopular) { - return Padding( - padding: const EdgeInsets.only(left: 20), - child: ProductCard( - product: demoProducts[index], - onPress: () {}, - ), - ); - } - return const SizedBox.shrink(); - }), - const SizedBox(width: 20), - ], - ), - ), - ], - ), - ], - ), - ), - ), - ); - } -} - -class SpecialOfferCard extends StatelessWidget { - const SpecialOfferCard({ - super.key, - required this.category, - required this.image, - required this.numOfBrands, - required this.press, - }); - - final String category, image; - final int numOfBrands; - final GestureTapCallback press; - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: press, - child: SizedBox( - width: 242, - height: 100, - child: ClipRRect( - borderRadius: BorderRadius.circular(20), - child: Stack( - children: [ - Image.asset(image, fit: BoxFit.cover), - Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Colors.black54, - Colors.black38, - Colors.black26, - Colors.transparent, - ], - ), - ), - ), - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 15, - vertical: 10, - ), - child: Text.rich( - TextSpan( - style: const TextStyle(color: Colors.white), - children: [ - TextSpan( - text: "$category\n", - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - TextSpan(text: "$numOfBrands Brands"), - ], - ), - ), - ), - ], - ), - ), - ), - ); - } -} diff --git a/lib/features/home/model/about_model.dart b/lib/features/home/model/about_model.dart new file mode 100644 index 0000000..e4abdd9 --- /dev/null +++ b/lib/features/home/model/about_model.dart @@ -0,0 +1,55 @@ +class AboutModel { + final String id; + final String title; + final String coverImage; + final String createdAt; + final String updatedAt; + + AboutModel({ + required this.id, + required this.title, + required this.coverImage, + required this.createdAt, + required this.updatedAt, + }); + + factory AboutModel.fromJson(Map json) { + return AboutModel( + id: json['id'], + title: json['title'], + coverImage: json['cover_image'], + createdAt: json['created_at'], + updatedAt: json['updated_at'], + ); + } +} + +class AboutDetailModel { + final String id; + final String aboutId; // nullable jika perlu + final String imageDetail; + final String description; + final String createdAt; + final String updatedAt; + + AboutDetailModel({ + required this.id, + required this.aboutId, + required this.imageDetail, + required this.description, + required this.createdAt, + required this.updatedAt, + }); + + factory AboutDetailModel.fromJson(Map json) { + return AboutDetailModel( + id: json['id'], + aboutId: json['about_id'] ?? '', // Use empty string or null as fallback + imageDetail: json['image_detail'], + description: json['description'], + createdAt: json['created_at'], + updatedAt: json['updated_at'], + ); + } +} + diff --git a/lib/features/home/presentation/components/about_comp.dart b/lib/features/home/presentation/components/about_comp.dart new file mode 100644 index 0000000..042571d --- /dev/null +++ b/lib/features/home/presentation/components/about_comp.dart @@ -0,0 +1,147 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:carousel_slider/carousel_slider.dart'; +import 'package:provider/provider.dart'; +import 'package:rijig_mobile/core/router.dart'; +import 'package:rijig_mobile/features/home/presentation/viewmodel/about_vmod.dart'; +import 'package:rijig_mobile/features/requestpick/presentation/screen/requestpickup_screen.dart'; + +class AboutComponent extends StatefulWidget { + const AboutComponent({super.key}); + + @override + AboutComponentState createState() => AboutComponentState(); +} + +class AboutComponentState extends State { + int _current = 0; + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + Provider.of(context, listen: false).getAboutList(); + }); + } + + @override + Widget build(BuildContext context) { + final String? baseUrl = dotenv.env["BASE_URL"]; + + return Consumer( + builder: (context, viewModel, child) { + if (viewModel.isLoading) { + return ListView.builder( + itemCount: 1, + itemBuilder: (context, index) { + return SkeletonCard(); + }, + ); + } + + if (viewModel.errorMessage != null) { + return Center(child: Text(viewModel.errorMessage!)); + } + + if (viewModel.aboutList == null || viewModel.aboutList!.isEmpty) { + return Center(child: Text("No data available")); + } + + List> imageSliders = + viewModel.aboutList!.map((about) { + return { + "iconPath": "$baseUrl${about.coverImage}", + "route": about.id, + "title": about.title, + }; + }).toList(); + + return Column( + children: [ + CarouselSlider( + items: + imageSliders.map((imageData) { + return InkWell( + child: Container( + height: 150, + decoration: BoxDecoration( + image: DecorationImage( + image: NetworkImage(imageData["iconPath"]), + fit: BoxFit.cover, + ), + borderRadius: const BorderRadius.all( + Radius.circular(20), + ), + ), + child: Stack( + children: [ + Positioned( + top: 10, + left: 10, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 12, + vertical: 6, + ), + color: Colors.black.withOpacity(0.5), + child: Text( + imageData["title"], + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ), + onTap: () { + debugPrint("Tapped on ${imageData['route']}"); + // imageData["route"]; + router.push("/aboutdetail", extra: imageData["route"]); + }, + ); + }).toList(), + options: CarouselOptions( + autoPlay: true, + autoPlayInterval: Duration(seconds: 8), + enlargeCenterPage: true, + height: 150, + onPageChanged: (index, reason) { + setState(() { + _current = index; + }); + }, + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: + imageSliders.asMap().entries.map((entry) { + return GestureDetector( + child: Container( + width: 8.0, + height: 8.0, + margin: const EdgeInsets.symmetric( + vertical: 8.0, + horizontal: 4.0, + ), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: (Theme.of(context).brightness == + Brightness.dark + ? Colors.blue + : Colors.blue) + .withOpacity(_current == entry.key ? 0.9 : 0.2), + ), + ), + ); + }).toList(), + ), + ], + ); + }, + ); + } +} diff --git a/lib/features/home/presentation/components/about_detail_comp.dart b/lib/features/home/presentation/components/about_detail_comp.dart new file mode 100644 index 0000000..e0aa2e2 --- /dev/null +++ b/lib/features/home/presentation/components/about_detail_comp.dart @@ -0,0 +1,62 @@ +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'; + +class AboutDetailScreenComp extends StatefulWidget { + final String data; + const AboutDetailScreenComp({super.key, required this.data}); + + @override + State createState() => _AboutDetailScreenCompState(); +} + +class _AboutDetailScreenCompState extends State { + @override + void initState() { + super.initState(); + context.read().getDetail(widget.data); + } + + @override + Widget build(BuildContext context) { + final String? baseurl = dotenv.env['BASE_URL']; + return Scaffold( + appBar: CustomAppBar(judul: "About Detail"), + body: Consumer( + builder: (context, vm, _) { + if (vm.isLoading) { + return ListView.builder( + itemCount: 2, + itemBuilder: (context, index) { + return SkeletonCard(); + }, + ); + } + if (vm.errorMessage != null) return Text(vm.errorMessage!); + return ListView.builder( + itemCount: vm.details.length, + itemBuilder: (context, index) { + final detail = vm.details[index]; + return Card( + margin: EdgeInsets.all(8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Image.network("$baseurl${detail.imageDetail}"), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text(detail.description), + ), + ], + ), + ); + }, + ); + }, + ), + ); + } +} diff --git a/lib/features/home/components/product_card.dart b/lib/features/home/presentation/components/product_card.dart similarity index 100% rename from lib/features/home/components/product_card.dart rename to lib/features/home/presentation/components/product_card.dart diff --git a/lib/features/home/presentation/screen/home_screen.dart b/lib/features/home/presentation/screen/home_screen.dart new file mode 100644 index 0000000..4d91912 --- /dev/null +++ b/lib/features/home/presentation/screen/home_screen.dart @@ -0,0 +1,118 @@ +import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; +import 'package:iconsax_flutter/iconsax_flutter.dart'; +import 'package:rijig_mobile/core/utils/guide.dart'; +import 'package:rijig_mobile/features/home/presentation/components/about_comp.dart'; +import 'package:rijig_mobile/widget/card_withicon.dart'; + +class HomeScreen extends StatefulWidget { + const HomeScreen({super.key}); + + @override + State createState() => _HomeScreenState(); +} + +class _HomeScreenState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: whiteColor, + body: SafeArea( + child: SingleChildScrollView( + padding: PaddingCustom().paddingHorizontalVertical(16, 20), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Rijig", + style: Tulisan.heading(color: primaryColor), + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Icon(Iconsax.notification), + Gap(10), + Icon(Iconsax.message_2), + ], + ), + ], + ), + ), + ], + ), + Gap(20), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + CardWithIcon( + icon: Icons.account_circle, + text: 'Users', + number: '245', + onTap: () {}, + ), + CardWithIcon( + icon: Icons.shopping_cart, + text: 'Orders', + number: '178', + onTap: () {}, + ), + ], + ), + Gap(20), + Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + "Important!", + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Colors.black, + ), + ), + ], + ), + const Gap(15), + Container( + height: + 250, // Tentukan tinggi yang sesuai untuk AboutComponent + child: AboutComponent(), + ), + ], + ), + Gap(20), + Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + "Artikel", + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Colors.black, + ), + ), + ], + ), + ), + ], + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/features/home/presentation/viewmodel/about_vmod.dart b/lib/features/home/presentation/viewmodel/about_vmod.dart new file mode 100644 index 0000000..ec97142 --- /dev/null +++ b/lib/features/home/presentation/viewmodel/about_vmod.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; +import 'package:rijig_mobile/features/home/service/about_service.dart'; +import 'package:rijig_mobile/features/home/model/about_model.dart'; + +class AboutViewModel extends ChangeNotifier { + final AboutService _aboutService; + + AboutViewModel(this._aboutService); + + bool isLoading = false; + String? errorMessage; + List? aboutList; + + Future getAboutList() async { + isLoading = true; + errorMessage = null; + notifyListeners(); + + try { + aboutList = await _aboutService.getAboutList(); + } catch (e) { + errorMessage = "Error: ${e.toString()}"; + } + + isLoading = false; + notifyListeners(); + } +} + +class AboutDetailViewModel extends ChangeNotifier { + final AboutService service; + + AboutDetailViewModel(this.service); + + bool isLoading = false; + String? errorMessage; + List details = []; + + Future getDetail(String aboutId) async { + isLoading = true; + notifyListeners(); + + try { + details = await service.getAboutDetail(aboutId); + } catch (e) { + errorMessage = "Failed to fetch: $e"; + } + + isLoading = false; + notifyListeners(); + } +} diff --git a/lib/features/home/repositories/about_repository.dart b/lib/features/home/repositories/about_repository.dart new file mode 100644 index 0000000..bfdf208 --- /dev/null +++ b/lib/features/home/repositories/about_repository.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'package:rijig_mobile/core/api/api_services.dart'; +import 'package:rijig_mobile/features/home/model/about_model.dart'; + +class AboutRepository { + final Https _https = Https(); + + Future> getAboutList() async { + final response = await _https.get('/about'); + debugPrint("response about: $response"); + final List data = response['data'] ?? []; + return data.map((e) => AboutModel.fromJson(e)).toList(); + } + + Future> getAboutDetail(String id) async { + final response = await _https.get('/about/$id'); + debugPrint("response about detail: $response"); + final List aboutDetail = response['data']['about_detail'] ?? []; + return aboutDetail.map((e) => AboutDetailModel.fromJson(e)).toList(); + } +} diff --git a/lib/features/home/service/about_service.dart b/lib/features/home/service/about_service.dart new file mode 100644 index 0000000..d52ff81 --- /dev/null +++ b/lib/features/home/service/about_service.dart @@ -0,0 +1,24 @@ +import 'package:rijig_mobile/features/home/repositories/about_repository.dart'; +import 'package:rijig_mobile/features/home/model/about_model.dart'; + +class AboutService { + final AboutRepository _aboutRepository; + + AboutService(this._aboutRepository); + + Future> getAboutList() async { + try { + return await _aboutRepository.getAboutList(); + } catch (e) { + throw Exception('Failed to load About list: $e'); + } + } + + Future> getAboutDetail(String id) async { + try { + return await _aboutRepository.getAboutDetail(id); + } catch (e) { + throw Exception('Failed to load About Detail: $e'); + } + } +} diff --git a/lib/features/requestpick/requestpickup_screen.dart b/lib/features/requestpick/presentation/screen/requestpickup_screen.dart similarity index 96% rename from lib/features/requestpick/requestpickup_screen.dart rename to lib/features/requestpick/presentation/screen/requestpickup_screen.dart index 0e0e59d..36b7ab8 100644 --- a/lib/features/requestpick/requestpickup_screen.dart +++ b/lib/features/requestpick/presentation/screen/requestpickup_screen.dart @@ -14,7 +14,7 @@ class RequestPickScreen extends StatelessWidget { // ignore: use_build_context_synchronously Provider.of(context, listen: false).loadCategories(); }); - final String? _baseUrl = dotenv.env["BASE_URL"]; + final String? baseUrl = dotenv.env["BASE_URL"]; return Scaffold( appBar: CustomAppBar(judul: "Pilih sampah"), @@ -49,7 +49,7 @@ class RequestPickScreen extends StatelessWidget { ), child: ListTile( leading: Image.network( - "$_baseUrl${category.icon}", + "$baseUrl${category.icon}", width: 50, height: 50, fit: BoxFit.cover, diff --git a/lib/main.dart b/lib/main.dart index 2ca682f..d127a7a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -31,6 +31,8 @@ class MyApp extends StatelessWidget { ChangeNotifierProvider(create: (_) => sl()), ChangeNotifierProvider(create: (_) => sl()), + ChangeNotifierProvider(create: (_) => sl()), + ChangeNotifierProvider(create: (_) => sl()), ], child: ScreenUtilInit( designSize: const Size(375, 812), diff --git a/pubspec.lock b/pubspec.lock index 7d15b36..7a774db 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -25,6 +25,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + carousel_slider: + dependency: "direct main" + description: + name: carousel_slider + sha256: "7b006ec356205054af5beaef62e2221160ea36b90fb70a35e4deacd49d0349ae" + url: "https://pub.dev" + source: hosted + version: "5.0.0" characters: dependency: transitive description: @@ -150,6 +158,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_carousel_widget: + dependency: "direct main" + description: + name: flutter_carousel_widget + sha256: "6473e6df04bfafea70efd58251fe5945d5aa8d19461575c1b9d83643f08e0c77" + url: "https://pub.dev" + source: hosted + version: "3.1.0" flutter_dotenv: dependency: "direct main" description: @@ -573,6 +589,14 @@ packages: description: flutter source: sdk version: "0.0.0" + smooth_page_indicator: + dependency: "direct main" + description: + name: smooth_page_indicator + sha256: b21ebb8bc39cf72d11c7cfd809162a48c3800668ced1c9da3aade13a32cf6c1c + url: "https://pub.dev" + source: hosted + version: "1.2.1" source_span: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index c18f374..1c59ce4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,12 +8,14 @@ environment: sdk: ^3.7.2 dependencies: + carousel_slider: ^5.0.0 concentric_transition: ^1.0.3 connectivity_plus: ^6.1.4 cupertino_icons: ^1.0.8 device_info_plus: ^11.4.0 flutter: sdk: flutter + flutter_carousel_widget: ^3.1.0 flutter_dotenv: ^5.2.1 flutter_screenutil: ^5.9.3 flutter_secure_storage: ^9.2.4 @@ -30,6 +32,7 @@ dependencies: provider: ^6.1.4 shared_preferences: ^2.3.3 shimmer: ^3.0.0 + smooth_page_indicator: ^1.2.1 uuid: ^4.5.1 dev_dependencies: