diff --git a/assets/icons/MDS-Public-TW-Button.svg b/assets/icons/MDS-Public-TW-Button.svg new file mode 100644 index 0000000..e8f85f6 --- /dev/null +++ b/assets/icons/MDS-Public-TW-Button.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icons/calendar-tick 2.svg b/assets/icons/calendar-tick 2.svg new file mode 100644 index 0000000..032df26 --- /dev/null +++ b/assets/icons/calendar-tick 2.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/icons/calendar-tick.svg b/assets/icons/calendar-tick.svg new file mode 100644 index 0000000..1a40cd0 --- /dev/null +++ b/assets/icons/calendar-tick.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/icons/clock.svg b/assets/icons/clock.svg new file mode 100644 index 0000000..baf3724 --- /dev/null +++ b/assets/icons/clock.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icons/dislike.svg b/assets/icons/dislike.svg new file mode 100644 index 0000000..9296e56 --- /dev/null +++ b/assets/icons/dislike.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icons/favorite.svg b/assets/icons/favorite.svg new file mode 100644 index 0000000..9d38161 --- /dev/null +++ b/assets/icons/favorite.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icons/game 2.svg b/assets/icons/game 2.svg new file mode 100644 index 0000000..083e3ee --- /dev/null +++ b/assets/icons/game 2.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/assets/icons/game.svg b/assets/icons/game.svg new file mode 100644 index 0000000..135a362 --- /dev/null +++ b/assets/icons/game.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/assets/icons/like.svg b/assets/icons/like.svg new file mode 100644 index 0000000..8fa0663 --- /dev/null +++ b/assets/icons/like.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icons/nearby.svg b/assets/icons/nearby.svg new file mode 100644 index 0000000..430b2d7 --- /dev/null +++ b/assets/icons/nearby.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assets/icons/nearby2.svg b/assets/icons/nearby2.svg new file mode 100644 index 0000000..e9a9fa2 --- /dev/null +++ b/assets/icons/nearby2.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assets/icons/profile 2.svg b/assets/icons/profile 2.svg new file mode 100644 index 0000000..24fa30e --- /dev/null +++ b/assets/icons/profile 2.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icons/profile.svg b/assets/icons/profile.svg new file mode 100644 index 0000000..2b6b434 --- /dev/null +++ b/assets/icons/profile.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icons/receipt-discount 2.svg b/assets/icons/receipt-discount 2.svg new file mode 100644 index 0000000..a7e8180 --- /dev/null +++ b/assets/icons/receipt-discount 2.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assets/icons/receipt-discount.svg b/assets/icons/receipt-discount.svg new file mode 100644 index 0000000..b83165f --- /dev/null +++ b/assets/icons/receipt-discount.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assets/icons/routing-2.svg b/assets/icons/routing-2.svg new file mode 100644 index 0000000..8199083 --- /dev/null +++ b/assets/icons/routing-2.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assets/icons/star fill.svg b/assets/icons/star fill.svg new file mode 100644 index 0000000..7ec9167 --- /dev/null +++ b/assets/icons/star fill.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/star half.svg b/assets/icons/star half.svg new file mode 100644 index 0000000..86f760e --- /dev/null +++ b/assets/icons/star half.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icons/tick.svg b/assets/icons/tick.svg new file mode 100644 index 0000000..41550c0 --- /dev/null +++ b/assets/icons/tick.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/wp1929534-fast-food-wallpapers 1.png b/assets/images/wp1929534-fast-food-wallpapers 1.png new file mode 100644 index 0000000..bb51853 Binary files /dev/null and b/assets/images/wp1929534-fast-food-wallpapers 1.png differ diff --git a/lib/data/model/workingHours.dart b/lib/data/model/workingHours.dart new file mode 100644 index 0000000..c85a4de --- /dev/null +++ b/lib/data/model/workingHours.dart @@ -0,0 +1,49 @@ +class WorkingHours { + final String day; + final List shifts; + + WorkingHours({ + required this.day, + required this.shifts, + }); + + factory WorkingHours.fromJson(Map json) { + return WorkingHours( + day: json['day'], + shifts: (json['shifts'] as List) + .map((shift) => Shift.fromJson(shift)) + .toList(), + ); + } + + Map toJson() { + return { + 'day': day, + 'shifts': shifts.map((shift) => shift.toJson()).toList(), + }; + } +} + +class Shift { + final String openAt; + final String closeAt; + + Shift({ + required this.openAt, + required this.closeAt, + }); + + factory Shift.fromJson(Map json) { + return Shift( + openAt: json['open_at'], + closeAt: json['close_at'], + ); + } + + Map toJson() { + return { + 'open_at': openAt, + 'close_at': closeAt, + }; + } +} diff --git a/lib/gen/assets.gen.dart b/lib/gen/assets.gen.dart index a3338aa..dc393c6 100644 --- a/lib/gen/assets.gen.dart +++ b/lib/gen/assets.gen.dart @@ -21,6 +21,10 @@ class $AssetsIconsGen { /// File path: assets/icons/Line 4.svg SvgGenImage get line4 => const SvgGenImage('assets/icons/Line 4.svg'); + /// File path: assets/icons/MDS-Public-TW-Button.svg + SvgGenImage get mDSPublicTWButton => + const SvgGenImage('assets/icons/MDS-Public-TW-Button.svg'); + /// File path: assets/icons/MDS-Public-TW-Tag.svg SvgGenImage get mDSPublicTWTag => const SvgGenImage('assets/icons/MDS-Public-TW-Tag.svg'); @@ -55,6 +59,14 @@ class $AssetsIconsGen { /// File path: assets/icons/back.svg SvgGenImage get back => const SvgGenImage('assets/icons/back.svg'); + /// File path: assets/icons/calendar-tick 2.svg + SvgGenImage get calendarTick2 => + const SvgGenImage('assets/icons/calendar-tick 2.svg'); + + /// File path: assets/icons/calendar-tick.svg + SvgGenImage get calendarTick => + const SvgGenImage('assets/icons/calendar-tick.svg'); + /// File path: assets/icons/card-pos.svg SvgGenImage get cardPos => const SvgGenImage('assets/icons/card-pos.svg'); @@ -64,9 +76,15 @@ class $AssetsIconsGen { /// File path: assets/icons/clander.svg SvgGenImage get clander => const SvgGenImage('assets/icons/clander.svg'); + /// File path: assets/icons/clock.svg + SvgGenImage get clock => const SvgGenImage('assets/icons/clock.svg'); + /// File path: assets/icons/coin.svg SvgGenImage get coin => const SvgGenImage('assets/icons/coin.svg'); + /// File path: assets/icons/dislike.svg + SvgGenImage get dislike => const SvgGenImage('assets/icons/dislike.svg'); + /// File path: assets/icons/down.svg SvgGenImage get down => const SvgGenImage('assets/icons/down.svg'); @@ -74,10 +92,19 @@ class $AssetsIconsGen { SvgGenImage get elementEqual => const SvgGenImage('assets/icons/element-equal.svg'); + /// File path: assets/icons/favorite.svg + SvgGenImage get favorite => const SvgGenImage('assets/icons/favorite.svg'); + /// File path: assets/icons/fluent-color_location-ripple-16.svg SvgGenImage get fluentColorLocationRipple16 => const SvgGenImage('assets/icons/fluent-color_location-ripple-16.svg'); + /// File path: assets/icons/game 2.svg + SvgGenImage get game2 => const SvgGenImage('assets/icons/game 2.svg'); + + /// File path: assets/icons/game.svg + SvgGenImage get game => const SvgGenImage('assets/icons/game.svg'); + /// File path: assets/icons/ic_round-local-offer.svg SvgGenImage get icRoundLocalOffer => const SvgGenImage('assets/icons/ic_round-local-offer.svg'); @@ -85,6 +112,9 @@ class $AssetsIconsGen { /// File path: assets/icons/infoPic.svg SvgGenImage get infoPic => const SvgGenImage('assets/icons/infoPic.svg'); + /// File path: assets/icons/like.svg + SvgGenImage get like => const SvgGenImage('assets/icons/like.svg'); + /// File path: assets/icons/list.svg SvgGenImage get list => const SvgGenImage('assets/icons/list.svg'); @@ -126,12 +156,32 @@ class $AssetsIconsGen { SvgGenImage get materialSymbolsLocationWork => const SvgGenImage('assets/icons/material-symbols_location-work.svg'); + /// File path: assets/icons/nearby.svg + SvgGenImage get nearby => const SvgGenImage('assets/icons/nearby.svg'); + + /// File path: assets/icons/nearby2.svg + SvgGenImage get nearby2 => const SvgGenImage('assets/icons/nearby2.svg'); + /// File path: assets/icons/next.svg SvgGenImage get next => const SvgGenImage('assets/icons/next.svg'); /// File path: assets/icons/ph_cheese.svg SvgGenImage get phCheese => const SvgGenImage('assets/icons/ph_cheese.svg'); + /// File path: assets/icons/profile 2.svg + SvgGenImage get profile2 => const SvgGenImage('assets/icons/profile 2.svg'); + + /// File path: assets/icons/profile.svg + SvgGenImage get profile => const SvgGenImage('assets/icons/profile.svg'); + + /// File path: assets/icons/receipt-discount 2.svg + SvgGenImage get receiptDiscount2 => + const SvgGenImage('assets/icons/receipt-discount 2.svg'); + + /// File path: assets/icons/receipt-discount.svg + SvgGenImage get receiptDiscount => + const SvgGenImage('assets/icons/receipt-discount.svg'); + /// File path: assets/icons/recenter.svg SvgGenImage get recenter => const SvgGenImage('assets/icons/recenter.svg'); @@ -139,6 +189,9 @@ class $AssetsIconsGen { SvgGenImage get riSearch2Line => const SvgGenImage('assets/icons/ri_search-2-line.svg'); + /// File path: assets/icons/routing-2.svg + SvgGenImage get routing2 => const SvgGenImage('assets/icons/routing-2.svg'); + /// File path: assets/icons/routing.svg SvgGenImage get routing => const SvgGenImage('assets/icons/routing.svg'); @@ -162,9 +215,18 @@ class $AssetsIconsGen { /// File path: assets/icons/sort.svg SvgGenImage get sort => const SvgGenImage('assets/icons/sort.svg'); + /// File path: assets/icons/star fill.svg + SvgGenImage get starFill => const SvgGenImage('assets/icons/star fill.svg'); + + /// File path: assets/icons/star half.svg + SvgGenImage get starHalf => const SvgGenImage('assets/icons/star half.svg'); + /// File path: assets/icons/star.svg SvgGenImage get star => const SvgGenImage('assets/icons/star.svg'); + /// File path: assets/icons/tick.svg + SvgGenImage get tick => const SvgGenImage('assets/icons/tick.svg'); + /// File path: assets/icons/timer-pause.svg SvgGenImage get timerPause => const SvgGenImage('assets/icons/timer-pause.svg'); @@ -180,6 +242,7 @@ class $AssetsIconsGen { List get values => [ line1, line4, + mDSPublicTWButton, mDSPublicTWTag, nextButton, rectangleOff, @@ -190,15 +253,23 @@ class $AssetsIconsGen { arrowDown, arrowLeft, back, + calendarTick2, + calendarTick, cardPos, category2, clander, + clock, coin, + dislike, down, elementEqual, + favorite, fluentColorLocationRipple16, + game2, + game, icRoundLocalOffer, infoPic, + like, list, location, mapSelected, @@ -210,10 +281,17 @@ class $AssetsIconsGen { materialSymbolsLocationOn, materialSymbolsLocationOnn, materialSymbolsLocationWork, + nearby, + nearby2, next, phCheese, + profile2, + profile, + receiptDiscount2, + receiptDiscount, recenter, riSearch2Line, + routing2, routing, selectedList, shoppingCart, @@ -221,7 +299,10 @@ class $AssetsIconsGen { slide3, slides1, sort, + starFill, + starHalf, star, + tick, timerPause, timerStart, timer, @@ -265,6 +346,10 @@ class $AssetsImagesGen { /// File path: assets/images/userinfo.svg SvgGenImage get userinfo => const SvgGenImage('assets/images/userinfo.svg'); + /// File path: assets/images/wp1929534-fast-food-wallpapers 1.png + AssetGenImage get wp1929534FastFoodWallpapers1 => + const AssetGenImage('assets/images/wp1929534-fast-food-wallpapers 1.png'); + /// List of all assets List get values => [ frame, @@ -277,6 +362,7 @@ class $AssetsImagesGen { topDealsAndStores, usa, userinfo, + wp1929534FastFoodWallpapers1, ]; } diff --git a/lib/main.dart b/lib/main.dart index d99099c..a900be3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -32,6 +32,11 @@ class MyApp extends StatelessWidget { dialogTheme: DialogTheme( backgroundColor: Colors.white, ), + dropdownMenuTheme: DropdownMenuThemeData( + menuStyle: MenuStyle( + backgroundColor: MaterialStatePropertyAll(Colors.white), + ), + ), inputDecorationTheme: const InputDecorationTheme( labelStyle: TextStyle(color: Colors.black), hintStyle: TextStyle(color: Colors.grey), diff --git a/lib/res/colors.dart b/lib/res/colors.dart index 6e20551..f9ac123 100644 --- a/lib/res/colors.dart +++ b/lib/res/colors.dart @@ -13,4 +13,8 @@ class LightAppColors{ static const confirmPopup = Color.fromARGB(255, 23, 107,173); static const nearbyPopup = Color.fromARGB(255, 233, 245,254); static const nearbyPopuphint = Color.fromARGB(255, 112, 112, 110); + static const productDetailDivider = Color.fromARGB(255, 112, 112, 110); + static const fillOrder = Color.fromARGB(255, 200, 230, 201); + static const fillOrderText = Color.fromARGB(255, 32, 74, 34); + static const allReviewOpener = Color.fromARGB(255, 183, 28, 28); } \ No newline at end of file diff --git a/lib/screens/auth/cubit/auth_cubit.dart b/lib/screens/auth/cubit/auth_cubit.dart index 4a87173..9194249 100644 --- a/lib/screens/auth/cubit/auth_cubit.dart +++ b/lib/screens/auth/cubit/auth_cubit.dart @@ -1,6 +1,4 @@ import 'package:bloc/bloc.dart'; -import 'package:dio/dio.dart'; -import 'package:meta/meta.dart'; part 'auth_state.dart'; @@ -10,40 +8,20 @@ class AuthCubit extends Cubit { String _timeStamp = ""; String _timeDue = ""; - final Dio _dio = Dio(BaseOptions( - connectTimeout: const Duration(seconds: 30), - receiveTimeout: const Duration(seconds: 30), - )); - String get timeStamp => _timeStamp; String get timeDue => _timeDue; Future sendOTP(String phoneNumber) async { emit(AuthLoading()); - try { - final response = await _dio.post( - 'https://api-gateway.liara.run/auth/otp/generate', - data: {'userId': phoneNumber}, - ); - print(response.toString()); - - if (response.statusCode == 200 || response.statusCode == 201) { - if (response.data['success'] == true) { - _timeStamp = response.data['timestamp'].toString(); - _timeDue = response.data['due'].toString(); - emit(AuthSuccess(phoneNumber: phoneNumber)); - print(response.data.toString()); - } else { - emit(AuthError('Failed to send OTP')); - } - } else { - emit(AuthError('Server error: \${response.statusCode}')); - } - } on DioException catch (e) { - emit(AuthError('Connection error: \${e.message}')); - } catch (e) { - emit(AuthError('Unexpected error occurred')); - } + + // Simulate API delay + await Future.delayed(const Duration(seconds: 1)); + + // Mock data for development + _timeStamp = DateTime.now().millisecondsSinceEpoch.toString(); + _timeDue = DateTime.now().add(const Duration(minutes: 2)).millisecondsSinceEpoch.toString(); + + emit(AuthSuccess(phoneNumber: phoneNumber)); } void verifyOTP(String otpCode) {} diff --git a/lib/screens/auth/onboarding.dart b/lib/screens/auth/onboarding.dart index b5d4694..062e2f7 100644 --- a/lib/screens/auth/onboarding.dart +++ b/lib/screens/auth/onboarding.dart @@ -85,7 +85,7 @@ class _OnboardingScreenState extends State { ), ), Padding( - padding: EdgeInsets.fromLTRB(width / 15, 0, width / 15, width/30), + padding: EdgeInsets.fromLTRB(width / 15, 0, width / 15, width / 30), child: Text( '"Join the app to discover exclusive discounts and special offers in specific areas around you for a smarter shopping experience!"', style: TextStyle(fontWeight: FontWeight.w500, color: LightAppColors.hint, fontSize: 15), @@ -98,8 +98,7 @@ class _OnboardingScreenState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ AnimatedSwitcher( - duration: Duration(milliseconds: 300), - transitionBuilder: (child, animation) => FadeTransition(opacity: animation, child: child), + duration: Duration(milliseconds: 200), child: SvgPicture.asset( slides[currentIndex], key: ValueKey(slides[currentIndex]), diff --git a/lib/screens/auth/userInfo.dart b/lib/screens/auth/userInfo.dart index 4c296c9..dbb32d2 100644 --- a/lib/screens/auth/userInfo.dart +++ b/lib/screens/auth/userInfo.dart @@ -3,7 +3,8 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:lba/extension/screenSize.dart'; import 'package:lba/gen/assets.gen.dart'; import 'package:lba/res/colors.dart'; -import 'package:lba/screens/nearby/nearby.dart'; +import 'package:lba/screens/mains/navigation/navigation.dart'; +import 'package:lba/screens/mains/nearby/mainNearby/nearby.dart'; import 'package:lba/widgets/button.dart'; import 'package:lba/widgets/datePicker.dart'; @@ -37,18 +38,21 @@ class _UserInfoState extends State { ], ), Padding( - padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 24), + padding: const EdgeInsets.symmetric( + horizontal: 0, + vertical: 24, + ), child: Center( child: Padding( padding: const EdgeInsets.only(top: 0), child: SvgPicture.asset( Assets.images.userinfo.path, - height: height /2.9, + height: height / 2.9, ), ), ), ), - SizedBox(height: height/20), + SizedBox(height: height / 20), const Padding( padding: EdgeInsets.fromLTRB(25, 0, 25, 20), child: Text( @@ -66,13 +70,16 @@ class _UserInfoState extends State { counterText: '', hintText: "Enter here...", hintStyle: TextStyle( - fontWeight: FontWeight.normal, color: Colors.grey), + fontWeight: FontWeight.normal, + color: Colors.grey, + ), filled: true, fillColor: Color.fromARGB(255, 250, 250, 250), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(12)), - borderSide: - BorderSide(color: Color.fromARGB(255, 14, 63, 102)), + borderSide: BorderSide( + color: Color.fromARGB(255, 14, 63, 102), + ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(12)), @@ -95,66 +102,98 @@ class _UserInfoState extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 25), child: Wrap( - spacing: 5, + spacing: 3, + alignment: WrapAlignment.start, + runSpacing: 2, + runAlignment: WrapAlignment.start, children: [ - Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Text("Prefer not to say", + Directionality( + textDirection: TextDirection.rtl, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Radio( + value: "Prefer not to say", + groupValue: selectedGender, + activeColor: Colors.blue, + visualDensity: VisualDensity.compact, + materialTapTargetSize: + MaterialTapTargetSize.shrinkWrap, + onChanged: (value) { + setState(() { + selectedGender = value!; + }); + }, + ), + const Text( + "Prefer not to say", style: TextStyle( - color: Color.fromARGB(255, 112, 112, 110))), - Radio( - value: "Prefer not to say", - groupValue: selectedGender, - activeColor: Colors.blue, - onChanged: (value) { - setState(() { - selectedGender = value!; - }); - }, - ), - ], + color: Color.fromARGB(255, 112, 112, 110), + ), + ), + ], + ), ), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Text("Male", + SizedBox(width: 5,), + Directionality( + textDirection: TextDirection.rtl, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Radio( + value: "Male", + groupValue: selectedGender, + activeColor: Colors.blue, + visualDensity: VisualDensity.compact, + materialTapTargetSize: + MaterialTapTargetSize.shrinkWrap, + onChanged: (value) { + setState(() { + selectedGender = value!; + }); + }, + ), + const Text( + "Male", style: TextStyle( - color: Color.fromARGB(255, 112, 112, 110))), - Radio( - value: "Male", - groupValue: selectedGender, - activeColor: Colors.blue, - onChanged: (value) { - setState(() { - selectedGender = value!; - }); - }, - ), - ], + color: Color.fromARGB(255, 112, 112, 110), + ), + ), + ], + ), ), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Text("Female", + SizedBox(width: 5,), + Directionality( + textDirection: TextDirection.rtl, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Radio( + value: "Female", + groupValue: selectedGender, + activeColor: Colors.blue, + visualDensity: VisualDensity.compact, + materialTapTargetSize: + MaterialTapTargetSize.shrinkWrap, + onChanged: (value) { + setState(() { + selectedGender = value!; + }); + }, + ), + const Text( + "Female", style: TextStyle( - color: Color.fromARGB(255, 112, 112, 110))), - Radio( - value: "Female", - groupValue: selectedGender, - activeColor: Colors.blue, - onChanged: (value) { - setState(() { - selectedGender = value!; - }); - }, - ), - ], + color: Color.fromARGB(255, 112, 112, 110), + ), + ), + ], + ), ), ], ), ), - SizedBox(height: height/12), + SizedBox(height: height / 8), // const Padding( // padding: EdgeInsets.fromLTRB(25, 0, 25, 15), // child: Text( @@ -225,16 +264,19 @@ class _UserInfoState extends State { // const SizedBox(height: 30), Center( child: SizedBox( - width: width*0.9, + width: width * 0.9, child: Button( text: "Submit", onPressed: () { Navigator.pushAndRemoveUntil( context, - MaterialPageRoute(builder: (context) => const Nearby()), + MaterialPageRoute( + builder: (context) => const MainScreen(), + ), (route) => false, ); - }, color: const Color.fromARGB(255, 30, 137, 221), + }, + color: const Color.fromARGB(255, 30, 137, 221), ), ), ), @@ -242,7 +284,7 @@ class _UserInfoState extends State { onTap: () { Navigator.pushAndRemoveUntil( context, - MaterialPageRoute(builder: (context) => const Nearby()), + MaterialPageRoute(builder: (context) => const MainScreen()), (route) => false, ); }, @@ -253,18 +295,19 @@ class _UserInfoState extends State { child: Text( "Skip", style: TextStyle( - color: LightAppColors.primary, - fontWeight: FontWeight.bold, - fontSize: 16), + color: LightAppColors.primary, + fontWeight: FontWeight.bold, + fontSize: 16, + ), ), ), ), ), - ) + ), ], ), ), ), ); } -} \ No newline at end of file +} diff --git a/lib/screens/mains/discover/discover.dart b/lib/screens/mains/discover/discover.dart new file mode 100644 index 0000000..8ccf133 --- /dev/null +++ b/lib/screens/mains/discover/discover.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +class Discover extends StatelessWidget { + const Discover({super.key}); + + @override + Widget build(BuildContext context) { + return const Placeholder(); + } +} \ No newline at end of file diff --git a/lib/screens/mains/hunt/hunt.dart b/lib/screens/mains/hunt/hunt.dart new file mode 100644 index 0000000..b126df1 --- /dev/null +++ b/lib/screens/mains/hunt/hunt.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +class Hunt extends StatelessWidget { + const Hunt({super.key}); + + @override + Widget build(BuildContext context) { + return const Placeholder(); + } +} \ No newline at end of file diff --git a/lib/screens/mains/navigation/navigation.dart b/lib/screens/mains/navigation/navigation.dart new file mode 100644 index 0000000..eb12e0a --- /dev/null +++ b/lib/screens/mains/navigation/navigation.dart @@ -0,0 +1,151 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:lba/gen/assets.gen.dart'; +import 'package:lba/res/colors.dart'; +import 'package:lba/screens/mains/discover/discover.dart'; +import 'package:lba/screens/mains/hunt/hunt.dart'; +import 'package:lba/screens/mains/nearby/mainNearby/nearby.dart'; +import 'package:lba/screens/mains/planner/planner.dart'; +import 'package:lba/screens/mains/profile/profile.dart'; + +class MainScreen extends StatefulWidget { + const MainScreen({super.key}); + + @override + State createState() => _MainScreenState(); +} + +class _MainScreenState extends State { + int _currentIndex = 0; + + final List _screens = [ + Nearby(), + Discover(), + Hunt(), + Planner(), + Profile(), + ]; + + @override + Widget build(BuildContext context) { + return Scaffold( + extendBody: true, + body: AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: _screens[_currentIndex], + ), + bottomNavigationBar: CustomBottomNavigationBar( + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + currentIndex: _currentIndex, + ), + ); + } +} + +class CustomBottomNavigationBar extends StatefulWidget { + final Function(int) onTap; + final int currentIndex; + + const CustomBottomNavigationBar({ + super.key, + required this.onTap, + required this.currentIndex, + }); + + @override + State createState() => _CustomBottomNavigationBarState(); +} + +class _CustomBottomNavigationBarState extends State + with SingleTickerProviderStateMixin { + final List<_NavItem> items = [ + _NavItem('Nearby', Assets.icons.nearby.path, Assets.icons.nearby2.path), + _NavItem('Discover', Assets.icons.receiptDiscount.path, Assets.icons.receiptDiscount2.path), + _NavItem('Hunt', Assets.icons.game.path, Assets.icons.game2.path), + _NavItem('Planner', Assets.icons.calendarTick.path, Assets.icons.calendarTick2.path), + _NavItem('Profile', Assets.icons.profile.path, Assets.icons.profile2.path), + ]; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16), + child: Container( + height: 70, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.15), + blurRadius: 20, + offset: const Offset(0, 10), + ), + ], + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: List.generate(items.length, (index) { + final item = items[index]; + final bool isSelected = index == widget.currentIndex; + return GestureDetector( + onTap: () => widget.onTap(index), + child: AnimatedContainer( + duration: const Duration(milliseconds: 300), + curve: Curves.easeOutQuint, + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + decoration: BoxDecoration( + color: isSelected ? const Color(0xFFE3F2FD) : Colors.transparent, + borderRadius: BorderRadius.circular(15), + ), + child: Row( + children: [ + AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: SvgPicture.asset( + isSelected ? item.selectedIconPath : item.iconPath, + key: ValueKey(isSelected), + width: 24, + height: 24, + ), + ), + AnimatedSize( + duration: const Duration(milliseconds: 300), + curve: Curves.easeOut, + child: isSelected + ? Row( + children: [ + const SizedBox(width: 8), + Text( + item.label, + style: const TextStyle( + color: LightAppColors.primary, + fontWeight: FontWeight.w600, + ), + ), + ], + ) + : const SizedBox(), + ), + ], + ), + ), + ); + }), + ), + ), + ); + } +} + +class _NavItem { + final String label; + final String iconPath; + final String selectedIconPath; + + _NavItem(this.label, this.iconPath, this.selectedIconPath); +} diff --git a/lib/screens/nearby/bestNearby.dart b/lib/screens/mains/nearby/bestNearby.dart similarity index 90% rename from lib/screens/nearby/bestNearby.dart rename to lib/screens/mains/nearby/bestNearby.dart index fe3681b..2e1a98e 100644 --- a/lib/screens/nearby/bestNearby.dart +++ b/lib/screens/mains/nearby/bestNearby.dart @@ -46,21 +46,7 @@ class NearbyItems extends StatelessWidget { padding: const EdgeInsets.all(8.0), child: Column( children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - children: [ - Text( - detailsType==0?"Highest Discount Areas":detailsType==1?"Highest Discount Areas":detailsType==2?"Best Deal, Don't Miss":"", - style: TextStyle(fontSize: 15), - ), - const SizedBox(width: 8), - const Expanded( - child: Divider(color: Colors.grey, thickness: 2), - ), - ], - ), - ), + DividerTitle(detailsType: detailsType), SizedBox( height: detailsType==0?180:detailsType==1?240:detailsType==2?240:200, child: ListView.builder( @@ -184,3 +170,31 @@ class NearbyItems extends StatelessWidget { ); } } + +class DividerTitle extends StatelessWidget { + const DividerTitle({ + super.key, + required this.detailsType, + }); + + final int detailsType; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Text( + detailsType==0?"Highest Discount Areas":detailsType==1?"Highest Discount Areas":detailsType==2?"Best Deal, Don't Miss":"", + style: TextStyle(fontSize: 15), + ), + const SizedBox(width: 8), + const Expanded( + child: Divider(color: Colors.grey, thickness: 2), + ), + ], + ), + ); + } +} diff --git a/lib/screens/mains/nearby/mainNearby/listScreen.dart b/lib/screens/mains/nearby/mainNearby/listScreen.dart new file mode 100644 index 0000000..dcfee9d --- /dev/null +++ b/lib/screens/mains/nearby/mainNearby/listScreen.dart @@ -0,0 +1,270 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:lba/extension/screenSize.dart'; +import 'package:lba/gen/assets.gen.dart'; +import 'package:lba/widgets/orderType.dart'; +import 'package:lba/widgets/remainingTime.dart'; + +class ListScreen extends StatefulWidget { + final bool delivery; + final bool pickup; + int initialTimerStatus; + final String expiryTimeString; + final VoidCallback? ontap; + + ListScreen({ + super.key, + required this.delivery, + required this.pickup, + this.initialTimerStatus=3, + required this.expiryTimeString, + this.ontap, + }); + + @override + State createState() => _ListScreenState(); +} + +class _ListScreenState extends State { + late RemainingTime _timer; + late ValueNotifier _timerStatus; + + @override + void initState() { + super.initState(); + _timer = RemainingTime(); + _timerStatus = ValueNotifier(widget.initialTimerStatus); + _timer.initializeFromExpiry(expiryTimeString: widget.expiryTimeString); + + _timer.remainingSeconds.addListener(() { + if (_timer.remainingSeconds.value <= 0) { + _timerStatus.value = 3; + } else if (_timer.remainingSeconds.value < 18000) { + _timerStatus.value = 1; + } else if (_timer.remainingSeconds.value > 18000) { + _timerStatus.value = 2; + } + }); + } + + @override + void dispose() { + _timer.dispose(); + _timerStatus.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final width = context.screenWidth; + final height = context.screenHeight; + return + GestureDetector( + onTap: widget.ontap, + child: Padding( + padding: const EdgeInsets.only(bottom: 16), + child: Stack( + children: [ + Container( + margin: const EdgeInsets.only(top: 60), + padding: const EdgeInsets.only(top: 80), + decoration: BoxDecoration( + color: const Color.fromARGB(255, 242, 242, 241), + borderRadius: BorderRadius.circular(10), + ), + child: Padding( + padding: EdgeInsets.fromLTRB(12, 0, width/50, 15), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Row( + children: [ + SvgPicture.asset(Assets.icons.phCheese.path), + const SizedBox(width: 5), + const Text( + "Amul Cheese Slices", + style: TextStyle(fontWeight: FontWeight.bold), + ), + ], + ), + const SizedBox(height: 10), + Row( + children: [ + SvgPicture.asset( + Assets.icons.location.path, + color: const Color.fromARGB(255, 157, 157, 155), + width: 14, + ), + const SizedBox(width: 5), + const Text("Sharjah (750m away)",style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500 + ),), + ], + ), + const SizedBox(height: 10), + Row( + children: [ + SvgPicture.asset( + Assets.icons.coin.path, + width: 14, + ), + const SizedBox(width: 5), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: const [ + Text( + "18.15 AED", + style: TextStyle( + color: Color.fromARGB(255, 157, 157, 155), + fontSize: 10, + decoration: TextDecoration.lineThrough, + ), + ), + SizedBox(height: 0), + Row( + children: [ + Text("15.84 AED",style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500 + ),), + SizedBox(width: 4), + Text( + "(13% off)", + style: TextStyle( + color: Color.fromARGB(255, 76, 175, 80), + fontSize: 10, + fontWeight: FontWeight.w500 + ), + ), + ], + ), + ], + ), + ], + ), + ], + ), + ), + Padding( + padding: EdgeInsets.fromLTRB(0, 35, widget.delivery == false || widget.pickup == false ? width/5 : width/60, 0), + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SvgPicture.asset( + Assets.icons.star.path, + width: 14, + ), + const SizedBox(width: 2), + const Text( + "4.8", + style: TextStyle( + color: Color.fromARGB(255, 112, 112, 110), + ), + ), + ], + ), + const SizedBox(height: 10), + Row( + children: [ + if (widget.delivery) + OrderType( + icon: Assets.icons.cardPos.path, + typename: "Delivery", + fill: false, + ), + if (widget.delivery) const SizedBox(width: 5), + if (widget.pickup) + OrderType( + icon: Assets.icons.shoppingCart.path, + typename: "Pickup", + fill: false, + ), + ], + ), + ], + ), + ), + ], + ), + ), + ), + ClipRRect( + borderRadius: const BorderRadius.only( + topRight: Radius.circular(10), + topLeft: Radius.circular(10), + ), + child: Image.asset( + Assets.images.media.path, + width: double.infinity, + height: 130, + fit: BoxFit.cover, + ), + ), + Positioned( + top: 10, + left: 10, + child: ValueListenableBuilder( + valueListenable: _timerStatus, + builder: (context, timerStatus, child) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 6), + height: 20, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(6), + color: timerStatus == 1 + ? const Color.fromARGB(255, 255, 193, 7) + : timerStatus == 2 + ? const Color.fromARGB(255, 76, 175, 80) + : timerStatus == 3 + ? const Color.fromARGB(255, 244, 67, 54) + : const Color.fromARGB(255, 244, 67, 54), + ), + child: Row( + children: [ + SvgPicture.asset( + timerStatus == 1 + ? Assets.icons.timer.path + : timerStatus == 2 + ? Assets.icons.timerStart.path + : Assets.icons.timerPause.path, + width: 12, + height: 12, + ), + const SizedBox(width: 5), + ValueListenableBuilder( + valueListenable: _timer.remainingSeconds, + builder: (context, seconds, child) { + return Text( + timerStatus==3? "Unavailable":"${_timer.formatTime()} left", + style: const TextStyle( + color: Colors.white, + fontSize: 12, + fontWeight: FontWeight.w400, + ), + ); + }, + ), + ], + ), + ); + }, + ), + ), + ], + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/screens/nearby/map.dart b/lib/screens/mains/nearby/mainNearby/map.dart similarity index 63% rename from lib/screens/nearby/map.dart rename to lib/screens/mains/nearby/mainNearby/map.dart index 2ab4685..20b48c9 100644 --- a/lib/screens/nearby/map.dart +++ b/lib/screens/mains/nearby/mainNearby/map.dart @@ -3,7 +3,8 @@ import 'package:flutter_map/flutter_map.dart'; import 'package:latlong2/latlong.dart'; import 'package:lba/gen/assets.gen.dart'; import 'package:lba/res/colors.dart'; -import 'package:lba/screens/nearby/bestNearby.dart'; +import 'package:lba/screens/mains/nearby/bestNearby.dart'; +import 'package:lba/screens/product/productdetail.dart'; import 'package:location/location.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -87,7 +88,6 @@ class _CustomMapState extends State _initializeMarkers(); _checkLocationServices(); - // Initialize AnimationController _animationController = AnimationController( duration: const Duration(milliseconds: 500), vsync: this, @@ -206,7 +206,6 @@ class _CustomMapState extends State right: 0, child: Column( children: [ - // Recenter Button Padding( padding: const EdgeInsets.all(8.0), child: Row( @@ -248,162 +247,98 @@ class _CustomMapState extends State ], ), ), - // Marker Details if (_selectedMarkerIndex == null) Container( - height: 190, + height: 245, width: double.infinity, - padding: const EdgeInsets.only(bottom: 25,left: 8), + padding: const EdgeInsets.only(bottom: 90,left: 0), child: Center( child: ListView.builder( scrollDirection: Axis.horizontal, itemCount: _manualMarkers.length, itemBuilder: (context, index) { final marker = _manualMarkers[index]; - return Container( - margin: const EdgeInsets.symmetric(horizontal: 5), - padding: const EdgeInsets.all(8.0), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - color: LightAppColors.nearbyPopup, - border: Border.all(color: Colors.white, width: 2.0), - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Center( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(11), - ), - child: Image.asset(Assets.images.image.path), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - marker.name, - style: TextStyle(color: Colors.black), - ), - SizedBox(height: 5), - Text( - "${marker.place} ${marker.distance}", - style: TextStyle( - color: LightAppColors.nearbyPopuphint, - ), - ), - SizedBox(height: 5), - Text( - marker.description, - style: TextStyle( - color: LightAppColors.nearbyPopuphint, - fontSize: 10, - ), - ), - ], - ), - ), - ], - ), - SizedBox(height: 10), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - SvgPicture.asset( - Assets.icons.mDSPublicTWTag.path, - ), - SizedBox(width: 10), - Text( - "(15%) 43 - 36.55 AED ", - style: TextStyle(fontWeight: FontWeight.bold), - ), - ], - ), - ], - ), - ), - ), + return GestureDetector( + onTap: () { + Navigator.of(context).push(MaterialPageRoute(builder: (context) => Productdetail(),)); + }, + child: CustomCard(marker: marker), ); }, ), ), ) else - Container( - margin: const EdgeInsets.symmetric(horizontal: 5), - padding: const EdgeInsets.all(8.0).copyWith(bottom: 15), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - color: LightAppColors.nearbyPopup, - border: Border.all(color: Colors.white, width: 2.0), - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Center( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(11), + Padding( + padding: const EdgeInsets.only(bottom: 90,right: 8,left: 8,), + child: Container( + margin: const EdgeInsets.symmetric(horizontal: 5), + padding: const EdgeInsets.all(8.0).copyWith(bottom: 15), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: LightAppColors.nearbyPopup, + border: Border.all(color: Colors.white, width: 4.0), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Center( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(11), + ), + child: Image.asset(Assets.images.image.path), ), - child: Image.asset(Assets.images.image.path), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - _manualMarkers[_selectedMarkerIndex!].name, - style: TextStyle(color: Colors.black), - ), - SizedBox(height: 5), - Text( - "${_manualMarkers[_selectedMarkerIndex!].place} ${_manualMarkers[_selectedMarkerIndex!].distance}", - style: TextStyle( - color: LightAppColors.nearbyPopuphint, + Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + _manualMarkers[_selectedMarkerIndex!].name, + style: TextStyle(color: Colors.black), ), - ), - SizedBox(height: 5), - Text( - _manualMarkers[_selectedMarkerIndex!] - .description, - style: TextStyle( - color: LightAppColors.nearbyPopuphint, - fontSize: 10, + SizedBox(height: 5), + Text( + "${_manualMarkers[_selectedMarkerIndex!].place} ${_manualMarkers[_selectedMarkerIndex!].distance}", + style: TextStyle( + color: LightAppColors.nearbyPopuphint, + ), ), - ), - ], + SizedBox(height: 5), + Text( + _manualMarkers[_selectedMarkerIndex!] + .description, + style: TextStyle( + color: LightAppColors.nearbyPopuphint, + fontSize: 10, + ), + ), + ], + ), ), - ), - ], - ), - SizedBox(height: 10), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - SvgPicture.asset(Assets.icons.mDSPublicTWTag.path), - SizedBox(width: 10), - Text( - "(15%) 43 - 36.55 AED ", - style: TextStyle(fontWeight: FontWeight.bold), - ), - ], - ), - ], + ], + ), + SizedBox(height: 10), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SvgPicture.asset(Assets.icons.mDSPublicTWTag.path), + SizedBox(width: 10), + Text( + "(15%) 43 - 36.55 AED ", + style: TextStyle(fontWeight: FontWeight.bold), + ), + ], + ), + ], + ), ), ), ), @@ -455,7 +390,94 @@ class _CustomMapState extends State } } -// Helper class for animating LatLng +class CustomCard extends StatelessWidget { + const CustomCard({ + super.key, + required this.marker, + }); + + final MarkerData marker; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(left: 8), + child: Container( + margin: const EdgeInsets.symmetric(horizontal: 5), + padding: const EdgeInsets.all(8.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: LightAppColors.nearbyPopup, + border: Border.all(color: Colors.white, width: 4.0), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Center( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(11), + ), + child: Image.asset(Assets.images.image.path), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + marker.name, + style: TextStyle(color: Colors.black), + ), + SizedBox(height: 5), + Text( + "${marker.place} ${marker.distance}", + style: TextStyle( + color: LightAppColors.nearbyPopuphint, + ), + ), + SizedBox(height: 5), + Text( + marker.description, + style: TextStyle( + color: LightAppColors.nearbyPopuphint, + fontSize: 10, + ), + ), + ], + ), + ), + ], + ), + SizedBox(height: 10), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SvgPicture.asset( + Assets.icons.mDSPublicTWTag.path, + ), + SizedBox(width: 10), + Text( + "(15%) 43 - 36.55 AED ", + style: TextStyle(fontWeight: FontWeight.bold), + ), + ], + ), + ], + ), + ), + ), + ), + ); + } +} + class LatLngTween extends Tween { LatLngTween({required LatLng begin, required LatLng end}) : super(begin: begin, end: end); diff --git a/lib/screens/nearby/nearby.dart b/lib/screens/mains/nearby/mainNearby/nearby.dart similarity index 65% rename from lib/screens/nearby/nearby.dart rename to lib/screens/mains/nearby/mainNearby/nearby.dart index a4f2f0e..d564ef6 100644 --- a/lib/screens/nearby/nearby.dart +++ b/lib/screens/mains/nearby/mainNearby/nearby.dart @@ -1,8 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:lba/gen/assets.gen.dart'; -import 'package:lba/screens/nearby/listScreen.dart'; -import 'package:lba/screens/nearby/map.dart'; +import 'package:lba/screens/mains/nearby/mainNearby/listScreen.dart'; +import 'package:lba/screens/mains/nearby/mainNearby/map.dart'; +import 'package:lba/screens/product/productdetail.dart'; import 'package:lba/widgets/customBottomSheet.dart'; import 'package:lba/widgets/gpsPopup.dart'; @@ -36,7 +37,6 @@ class _NearbyState extends State { @override Widget build(BuildContext context) { - return Scaffold( appBar: AppBar( toolbarHeight: 70, @@ -114,8 +114,7 @@ class _NearbyState extends State { ), backgroundColor: Colors.white, ), - body: - Column( + body: Column( children: [ _buildToggleButtons(), Container( @@ -124,9 +123,7 @@ class _NearbyState extends State { color: const Color.fromARGB(255, 14, 63, 102), ), Expanded( - child: selectedIndex == 1 - ? _buildListContent() - : CustomMap(), + child: selectedIndex == 1 ? _buildListContent() : CustomMap(), ), // ElevatedButton( // onPressed: () => showGPSDialog(context), @@ -180,33 +177,39 @@ class _NearbyState extends State { Positioned( left: 0, child: _buildToggleButton( - color: selectedIndex == 1 - ? const Color.fromARGB(255, 10, 69, 117) - : const Color.fromARGB(100, 177, 177, 177), + color: + selectedIndex == 1 + ? const Color.fromARGB(255, 10, 69, 117) + : const Color.fromARGB(100, 177, 177, 177), icon: Assets.icons.elementEqual.path, - iconColor: selectedIndex == 1 - ? const Color.fromARGB(255, 234, 245, 254) - : const Color.fromARGB(255, 157, 157, 155), + iconColor: + selectedIndex == 1 + ? const Color.fromARGB(255, 234, 245, 254) + : const Color.fromARGB(255, 157, 157, 155), text: 'list', isSelected: selectedIndex == 1, onTap: () => setState(() => selectedIndex = 1), borderRadius: BorderRadius.only( topLeft: Radius.circular(12), bottomLeft: Radius.circular(12), - topRight: selectedIndex==1? Radius.circular(12):Radius.zero, - bottomRight: selectedIndex==1? Radius.circular(12):Radius.zero, + topRight: + selectedIndex == 1 ? Radius.circular(12) : Radius.zero, + bottomRight: + selectedIndex == 1 ? Radius.circular(12) : Radius.zero, ), ), ), Positioned( right: 0, child: _buildToggleButton( - color: selectedIndex == 0 - ? const Color.fromARGB(255, 10, 69, 117) - : const Color.fromARGB(100, 177, 177, 177), - iconColor: selectedIndex == 0 - ? const Color.fromARGB(255, 234, 245, 254) - : const Color.fromARGB(255, 157, 157, 155), + color: + selectedIndex == 0 + ? const Color.fromARGB(255, 10, 69, 117) + : const Color.fromARGB(100, 177, 177, 177), + iconColor: + selectedIndex == 0 + ? const Color.fromARGB(255, 234, 245, 254) + : const Color.fromARGB(255, 157, 157, 155), icon: Assets.icons.mapSelected.path, text: 'map', isSelected: selectedIndex == 0, @@ -214,8 +217,10 @@ class _NearbyState extends State { borderRadius: BorderRadius.only( topRight: Radius.circular(12), bottomRight: Radius.circular(12), - bottomLeft: selectedIndex==0? Radius.circular(12):Radius.zero, - topLeft: selectedIndex==0? Radius.circular(12):Radius.zero, + bottomLeft: + selectedIndex == 0 ? Radius.circular(12) : Radius.zero, + topLeft: + selectedIndex == 0 ? Radius.circular(12) : Radius.zero, ), ), ), @@ -245,6 +250,8 @@ class _NearbyState extends State { child: SvgPicture.asset(Assets.icons.arrowDown.path), ), elevation: 16, + dropdownColor: + Colors.white, style: const TextStyle( color: Color.fromARGB(255, 33, 150, 243), fontWeight: FontWeight.w500, @@ -255,12 +262,13 @@ class _NearbyState extends State { selectedOption = newValue!; }); }, - items: options.map>((String value) { - return DropdownMenuItem( - value: value, - child: Text(value), - ); - }).toList(), + items: + options.map>((String value) { + return DropdownMenuItem( + value: value, + child: Text(value), + ); + }).toList(), ), ], ), @@ -268,7 +276,12 @@ class _NearbyState extends State { ListScreen( delivery: true, pickup: false, - expiryTimeString: "2025-05-17T13:20:49.623619357Z", + expiryTimeString: "2025-05-19T13:30:49.623619357Z", + ontap: () { + Navigator.of(context).push( + MaterialPageRoute(builder: (context) => Productdetail()), + ); + }, ), ListScreen( delivery: false, @@ -280,6 +293,7 @@ class _NearbyState extends State { pickup: true, expiryTimeString: "2025-05-12T13:20:37.435249520Z", ), + const SizedBox(height: 90), ], ), ), @@ -287,76 +301,77 @@ class _NearbyState extends State { } Widget _buildToggleButton({ - required String text, - required bool isSelected, - required VoidCallback onTap, - required BorderRadius borderRadius, - required Color color, - required String icon, - required Color iconColor, -}) { - return GestureDetector( - onTap: onTap, - child: Stack( - children: [ - Container( - width: 170, - height: 50, - decoration: BoxDecoration( - borderRadius: borderRadius, - color: isSelected - ? const Color.fromARGB(255, 14, 63, 102) - : const Color.fromARGB(255, 234, 234, 233), - boxShadow: isSelected - ? [ - BoxShadow( - color: Colors.black.withOpacity(0.2), - spreadRadius: 1, - blurRadius: 4, - offset: const Offset(0, 2), + required String text, + required bool isSelected, + required VoidCallback onTap, + required BorderRadius borderRadius, + required Color color, + required String icon, + required Color iconColor, + }) { + return GestureDetector( + onTap: onTap, + child: Stack( + children: [ + Container( + width: 170, + height: 50, + decoration: BoxDecoration( + borderRadius: borderRadius, + color: + isSelected + ? const Color.fromARGB(255, 14, 63, 102) + : const Color.fromARGB(255, 234, 234, 233), + boxShadow: + isSelected + ? [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + spreadRadius: 1, + blurRadius: 4, + offset: const Offset(0, 2), + ), + ] + : null, + ), + alignment: Alignment.center, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: 30, + height: 30, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: color, + ), + child: Padding( + padding: const EdgeInsets.all(1.0), + child: Center( + child: SvgPicture.asset(icon, color: iconColor), ), - ] - : null, - ), - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: 30, - height: 30, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: color, + ), ), - child: Padding( - padding: const EdgeInsets.all(1.0), - child: Center(child: SvgPicture.asset(icon, color: iconColor)), + const SizedBox(width: 10), + Text( + text, + style: TextStyle( + color: isSelected ? Colors.white : Colors.black87, + fontWeight: FontWeight.bold, + ), ), - ), - const SizedBox(width: 10), - Text( - text, - style: TextStyle( - color: isSelected ? Colors.white : Colors.black87, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - ), - if (isSelected) - Positioned( - bottom: 0, - left: 0, - right: 0, - child: SvgPicture.asset( - Assets.icons.shape.path, - height: 4, + ], ), ), - ], - ), - ); + if (isSelected) + Positioned( + bottom: 0, + left: 0, + right: 0, + child: SvgPicture.asset(Assets.icons.shape.path, height: 4), + ), + ], + ), + ); + } } -} \ No newline at end of file diff --git a/lib/screens/mains/planner/planner.dart b/lib/screens/mains/planner/planner.dart new file mode 100644 index 0000000..c4de6ed --- /dev/null +++ b/lib/screens/mains/planner/planner.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +class Planner extends StatelessWidget { + const Planner({super.key}); + + @override + Widget build(BuildContext context) { + return const Placeholder(); + } +} \ No newline at end of file diff --git a/lib/screens/mains/profile/profile.dart b/lib/screens/mains/profile/profile.dart new file mode 100644 index 0000000..21872e4 --- /dev/null +++ b/lib/screens/mains/profile/profile.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +class Profile extends StatelessWidget { + const Profile({super.key}); + + @override + Widget build(BuildContext context) { + return const Placeholder(); + } +} \ No newline at end of file diff --git a/lib/screens/nearby/listScreen.dart b/lib/screens/nearby/listScreen.dart deleted file mode 100644 index f107ab3..0000000 --- a/lib/screens/nearby/listScreen.dart +++ /dev/null @@ -1,263 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:lba/extension/screenSize.dart'; -import 'package:lba/gen/assets.gen.dart'; -import 'package:lba/widgets/orderType.dart'; -import 'package:lba/widgets/remainingTime.dart'; - -class ListScreen extends StatefulWidget { - final bool delivery; - final bool pickup; - int initialTimerStatus; - final String expiryTimeString; - - ListScreen({ - super.key, - required this.delivery, - required this.pickup, - this.initialTimerStatus=3, - required this.expiryTimeString, - }); - - @override - State createState() => _ListScreenState(); -} - -class _ListScreenState extends State { - late RemainingTime _timer; - late ValueNotifier _timerStatus; - - @override - void initState() { - super.initState(); - _timer = RemainingTime(); - _timerStatus = ValueNotifier(widget.initialTimerStatus); - _timer.initializeFromExpiry(expiryTimeString: widget.expiryTimeString); - - _timer.remainingSeconds.addListener(() { - if (_timer.remainingSeconds.value <= 0) { - _timerStatus.value = 3; - } else if (_timer.remainingSeconds.value < 18000) { - _timerStatus.value = 1; - } else if (_timer.remainingSeconds.value > 18000) { - _timerStatus.value = 2; - } - }); - } - - @override - void dispose() { - _timer.dispose(); - _timerStatus.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - final width = context.screenWidth; - final height = context.screenHeight; - return - Padding( - padding: const EdgeInsets.only(bottom: 16), - child: Stack( - children: [ - Container( - margin: const EdgeInsets.only(top: 60), - padding: const EdgeInsets.only(top: 80), - decoration: BoxDecoration( - color: const Color.fromARGB(255, 242, 242, 241), - borderRadius: BorderRadius.circular(10), - ), - child: Padding( - padding: EdgeInsets.fromLTRB(12, 0, width/50, 15), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Row( - children: [ - SvgPicture.asset(Assets.icons.phCheese.path), - const SizedBox(width: 5), - const Text( - "Amul Cheese Slices", - style: TextStyle(fontWeight: FontWeight.bold), - ), - ], - ), - const SizedBox(height: 10), - Row( - children: [ - SvgPicture.asset( - Assets.icons.location.path, - color: const Color.fromARGB(255, 157, 157, 155), - width: 14, - ), - const SizedBox(width: 5), - const Text("Sharjah (750m away)",style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500 - ),), - ], - ), - const SizedBox(height: 10), - Row( - children: [ - SvgPicture.asset( - Assets.icons.coin.path, - width: 14, - ), - const SizedBox(width: 5), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: const [ - Text( - "18.15 AED", - style: TextStyle( - color: Color.fromARGB(255, 157, 157, 155), - fontSize: 10, - decoration: TextDecoration.lineThrough, - ), - ), - SizedBox(height: 0), - Row( - children: [ - Text("15.84 AED",style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500 - ),), - SizedBox(width: 4), - Text( - "(13% off)", - style: TextStyle( - color: Color.fromARGB(255, 76, 175, 80), - fontSize: 10, - fontWeight: FontWeight.w500 - ), - ), - ], - ), - ], - ), - ], - ), - ], - ), - ), - Padding( - padding: EdgeInsets.fromLTRB(0, 35, widget.delivery == false || widget.pickup == false ? width/5 : width/60, 0), - child: Column( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SvgPicture.asset( - Assets.icons.star.path, - width: 14, - ), - const SizedBox(width: 2), - const Text( - "4.8", - style: TextStyle( - color: Color.fromARGB(255, 112, 112, 110), - ), - ), - ], - ), - const SizedBox(height: 10), - Row( - children: [ - if (widget.delivery) - OrderType( - icon: Assets.icons.cardPos.path, - typename: "Delivery", - ), - if (widget.delivery) const SizedBox(width: 5), - if (widget.pickup) - OrderType( - icon: Assets.icons.shoppingCart.path, - typename: "Pickup", - ), - ], - ), - ], - ), - ), - ], - ), - ), - ), - ClipRRect( - borderRadius: const BorderRadius.only( - topRight: Radius.circular(10), - topLeft: Radius.circular(10), - ), - child: Image.asset( - Assets.images.media.path, - width: double.infinity, - height: 130, - fit: BoxFit.cover, - ), - ), - Positioned( - top: 10, - left: 10, - child: ValueListenableBuilder( - valueListenable: _timerStatus, - builder: (context, timerStatus, child) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 6), - height: 20, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(6), - color: timerStatus == 1 - ? const Color.fromARGB(255, 255, 193, 7) - : timerStatus == 2 - ? const Color.fromARGB(255, 76, 175, 80) - : timerStatus == 3 - ? const Color.fromARGB(255, 244, 67, 54) - : const Color.fromARGB(255, 244, 67, 54), - ), - child: Row( - children: [ - SvgPicture.asset( - timerStatus == 1 - ? Assets.icons.timer.path - : timerStatus == 2 - ? Assets.icons.timerStart.path - : Assets.icons.timerPause.path, - width: 12, - height: 12, - ), - const SizedBox(width: 5), - ValueListenableBuilder( - valueListenable: _timer.remainingSeconds, - builder: (context, seconds, child) { - return Text( - timerStatus==3? "Unavailable":"${_timer.formatTime()} left", - style: const TextStyle( - color: Colors.white, - fontSize: 12, - fontWeight: FontWeight.w400, - ), - ); - }, - ), - ], - ), - ); - }, - ), - ), - ], - ), - ); - } -} \ No newline at end of file diff --git a/lib/screens/product/item.dart b/lib/screens/product/item.dart new file mode 100644 index 0000000..f8c8e32 --- /dev/null +++ b/lib/screens/product/item.dart @@ -0,0 +1,221 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:lba/gen/assets.gen.dart'; +import 'package:lba/res/colors.dart'; +import 'package:lba/widgets/buildWarpedInfo.dart'; +import 'package:lba/widgets/orderType.dart'; +import 'package:lba/widgets/rate.dart'; +import 'package:lba/widgets/reviews.dart'; + +class Item extends StatefulWidget { + String title; + String brand; + String dimensions; + String colour; + String material; + String description; + + Item({ + super.key, + required this.title, + required this.brand, + required this.dimensions, + required this.colour, + required this.material, + required this.description, + }); + + @override + State createState() => _ItemState(); +} + +class _ItemState extends State with TickerProviderStateMixin { + bool showAllReviews = false; + final GlobalKey _listKey = GlobalKey(); + + final List> reviews = [ + { + "name": "Sara M", + "comment": + '"Super happy with my new sofa from Chattels & More! 🙻✨ Great quality, smooth delivery, and helpful staff. Totally worth it!" 😍👌', + "rate": 5.0, + "yesCount": 2, + "noCount": 0, + "date": "Jun 09, 2025", + }, + { + "name": "Khalid A", + "comment": + '"Nice design but poor delivery experience 😕🕐 Had to wait extra days and deal with missing parts. Expected better for the price." 👎💸', + "rate": 1.0, + "yesCount": 5, + "noCount": 10, + "date": "Dec 26, 2024", + }, + { + "name": "Khalid A", + "comment": + '"Nice design but poor delivery experience 😕🕐 Had to wait extra days and deal with missing parts. Expected better for the price." 👎💸', + "rate": 3.0, + "yesCount": 5, + "noCount": 10, + "date": "Dec 26, 2024", + }, + { + "name": "Sara M", + "comment": + '"Super happy with my new sofa from Chattels & More! 🙻✨ Great quality, smooth delivery, and helpful staff. Totally worth it!" 😍👌', + "rate": 4.0, + "yesCount": 2, + "noCount": 0, + "date": "Jun 09, 2025", + }, + ]; + + List> displayedReviews = []; + + @override + void initState() { + super.initState(); + displayedReviews = reviews.length > 2 ? reviews.sublist(0, 2) : List.from(reviews); + } + + void _showAllReviewsWithAnimation() async { + final newItems = reviews.sublist(displayedReviews.length); + for (int i = 0; i < newItems.length; i++) { + await Future.delayed(Duration(milliseconds: 150)); + displayedReviews.add(newItems[i]); + _listKey.currentState?.insertItem(displayedReviews.length - 1); + setState(() {}); + } + setState(() { + showAllReviews = true; + }); + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(16.0), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Align( + alignment: Alignment.centerLeft, + child: Text( + widget.title, + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16), + ), + ), + SizedBox(height: 5), + Row( + children: [ + Text("Brand: "), + Expanded( + child: Text( + widget.brand, + style: TextStyle(color: LightAppColors.primary), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + SizedBox(height: 10), + Row( + children: [ + CustomStarRating(rating: 4.8), + SizedBox(width: 3), + Text( + "4.8", + style: TextStyle(color: LightAppColors.productDetailDivider), + ), + ], + ), + SizedBox(height: 15), + Row( + children: [ + OrderType( + icon: Assets.icons.cardPos.path, + typename: "Delivery", + fill: true, + ), + SizedBox(width: 7), + OrderType( + icon: Assets.icons.shoppingCart.path, + typename: "Pickup", + fill: true, + ), + ], + ), + SizedBox(height: 15), + buildWrappedInfo("Dimensions:", widget.dimensions), + buildWrappedInfo("Colour:", widget.colour), + buildWrappedInfo("Material:", widget.material), + buildWrappedInfo("Description:", widget.description), + SizedBox(height: 30), + Center( + child: Text( + "Top reviews from the United Arab Emirates", + style: TextStyle(fontWeight: FontWeight.bold), + ), + ), + SizedBox(height: 15), + + AnimatedList( + key: _listKey, + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + initialItemCount: displayedReviews.length, + itemBuilder: (context, index, animation) { + final review = displayedReviews[index]; + return SizeTransition( + sizeFactor: animation, + axisAlignment: -1, + child: Reviews( + name: review['name'], + comment: review['comment'], + rate: review['rate'], + yesCount: review['yesCount'], + noCount: review['noCount'], + date: review['date'], + ), + ); + }, + ), + + if (!showAllReviews && reviews.length > 2) + Column( + children: [ + Center( + child: InkWell( + onTap: _showAllReviewsWithAnimation, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "See all reviews", + style: TextStyle( + color: LightAppColors.allReviewOpener, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + SizedBox(width: 10), + SvgPicture.asset( + Assets.icons.arrowDown.path, + color: LightAppColors.allReviewOpener, + ), + ], + ), + ), + ), + SizedBox(height: 50,) + ], + ), + ], + ), + ), + ); + } +} diff --git a/lib/screens/product/productdetail.dart b/lib/screens/product/productdetail.dart new file mode 100644 index 0000000..31c77ee --- /dev/null +++ b/lib/screens/product/productdetail.dart @@ -0,0 +1,307 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:lba/data/model/workingHours.dart'; +import 'package:lba/gen/assets.gen.dart'; +import 'package:lba/res/colors.dart'; +import 'package:lba/screens/product/item.dart'; +import 'package:lba/screens/product/shop.dart'; + +class Productdetail extends StatefulWidget { + const Productdetail({super.key}); + + @override + State createState() => _ProductdetailState(); +} + +class _ProductdetailState extends State + with SingleTickerProviderStateMixin { + String selectedImage = Assets.images.media.path; + int selectedIndex = 0; + + final List imageList = [ + Assets.images.media.path, + Assets.images.topDealsAndStores.path, + Assets.images.image.path, + Assets.images.topDealsAndStores.path, + ]; + + late AnimationController _controller; + late Animation _fadeAnimation; + + @override + void initState() { + super.initState(); + _controller = AnimationController( + vsync: this, + duration: const Duration(milliseconds: 300), + ); + _fadeAnimation = CurvedAnimation( + parent: _controller, + curve: Curves.easeInOut, + ); + _controller.forward(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + void _onToggleTap(int index) { + setState(() { + selectedIndex = index; + _controller.forward(from: 0); + }); + } + + + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SingleChildScrollView( + child: Column( + children: [ + Stack( + children: [ + SizedBox( + height: 400, + width: double.infinity, + child: Stack( + children: [ + AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: Image.asset( + selectedImage, + key: ValueKey(selectedImage), + fit: BoxFit.cover, + height: 350, + width: double.infinity, + ), + ), + Positioned( + top: 40, + left: 16, + child: IconButton( + icon: SvgPicture.asset( + Assets.icons.mDSPublicTWButton.path, + ), + onPressed: () => Navigator.pop(context), + ), + ), + Positioned( + top: 40, + right: 16, + child: IconButton( + icon: SvgPicture.asset(Assets.icons.favorite.path), + onPressed: () {}, + ), + ), + Positioned( + bottom: 0, + left: 0, + right: 0, + child: Container( + height: 105, + padding: const EdgeInsets.symmetric(vertical: 8), + decoration: BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + blurRadius: 10, + offset: const Offset(0, -2), + ), + ], + ), + child: ListView.separated( + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.symmetric(horizontal: 16), + itemCount: imageList.length, + separatorBuilder: + (_, __) => const SizedBox(width: 8), + itemBuilder: (context, index) { + final img = imageList[index]; + final isSelected = selectedImage == img; + return GestureDetector( + onTap: + () => setState(() => selectedImage = img), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: + isSelected + ? LightAppColors.confirmButton + : Colors.transparent, + width: 2, + ), + borderRadius: BorderRadius.circular(8), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: ColorFiltered( + colorFilter: + selectedIndex == 1 && + isSelected == false + ? ColorFilter.matrix([ + 0.2126, + 0.7152, + 0.0722, + 0, + 0, + 0.2126, + 0.7152, + 0.0722, + 0, + 0, + 0.2126, + 0.7152, + 0.0722, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + ]) + : ColorFilter.mode( + Colors.transparent, + BlendMode.dstOut, + ), + child: Image.asset( + img, + width: 100, + height: 100, + fit: BoxFit.cover, + ), + ), + ), + ), + ); + }, + ), + ), + ), + ], + ), + ), + ], + ), + const SizedBox(height: 20), + SizedBox( + width: 350, + height: 50, + child: Row( + children: [ + Expanded( + child: _buildToggleButton( + text: 'Item', + isSelected: selectedIndex == 0, + onTap: () => _onToggleTap(0), + ), + ), + Expanded( + child: _buildToggleButton( + text: 'Shop', + isSelected: selectedIndex == 1, + onTap: () => _onToggleTap(1), + ), + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: const Divider(thickness: 1.2, height: 2), + ), + FadeTransition( + opacity: _fadeAnimation, + child: + selectedIndex == 0 + ? Item( + title: "Bosse Swivel Chair - Nature", + brand: "Papadatos", + dimensions: "L 59 cm | D 69 cm | H 89 cm", + colour: + "Navy Blue, Burnt Sienna, Mustard Yellow, Olive Green", + material: + " Cover: Polyester, Frame construction: Plywood Lacquered, Foot/Base: Oak Solid wood Lacquered, Upholstering: 28 kg/m³ Polyurethane", + description: + "A dining chair which swivels through 360 degrees offers a number of advantages. It allows easy movement and flexibility when sitting, which increases comfort and makes it easier to reach different areas around the table. A swivel chair in the dining room also makes it easier to sit down and get up, even where space is a little limited. This largely eliminates the hassle of moving dining chairs around. In addition, the swivel function encourages dynamic interaction during meals or conversations.", + ) + : Shop( + shopName: "Chattels & More", + star: 3.6, + place: "Mall of the Emirates، City Centre Mirdif", + branches: [ + "Mall of the Emirates، City Centre Mirdif", + "UEA", + ], + + workingHours: [ + WorkingHours( + day: 'mo', + shifts: [Shift(openAt: '01:00', closeAt: '23:00')], + ), + WorkingHours( + day: 'tu', + shifts: [Shift(openAt: '09:00', closeAt: '17:00')], + ), + WorkingHours( + day: 'fr', + shifts: [ + Shift(openAt: '09:00', closeAt: '12:00'), + Shift(openAt: '14:00', closeAt: '18:00'), + ], + ), + ], + facilities: "White Glove Delivery Service", + ), + ), + ], + ), + ), + ); + } + + Widget _buildToggleButton({ + required String text, + required bool isSelected, + required VoidCallback onTap, + }) { + return GestureDetector( + onTap: onTap, + child: Stack( + children: [ + Container( + height: 50, + color: Colors.white, + alignment: Alignment.center, + child: Text( + text, + style: TextStyle( + color: + isSelected + ? LightAppColors.primary + : LightAppColors.productDetailDivider, + fontWeight: FontWeight.bold, + ), + ), + ), + if (isSelected) + Positioned( + bottom: 0, + left: 0, + right: 0, + child: SvgPicture.asset( + Assets.icons.shape.path, + height: 5, + color: LightAppColors.primary, + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/product/shop.dart b/lib/screens/product/shop.dart new file mode 100644 index 0000000..9f3c67e --- /dev/null +++ b/lib/screens/product/shop.dart @@ -0,0 +1,286 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:lba/data/model/workingHours.dart'; +import 'package:lba/gen/assets.gen.dart'; +import 'package:lba/res/colors.dart'; +import 'package:lba/widgets/customCard.dart'; +import 'package:lba/widgets/dividerTitle.dart'; +import 'package:lba/widgets/openChecker.dart'; +import 'package:lba/widgets/rate.dart'; +import 'package:maps_launcher/maps_launcher.dart'; + +class Shop extends StatefulWidget { + final String shopName; + final double star; + final String place; + final List branches; + final List workingHours; + final String facilities; + + const Shop({ + super.key, + required this.shopName, + required this.star, + required this.place, + required this.branches, + required this.workingHours, + required this.facilities, + }); + + @override + State createState() => _ShopState(); +} + +class _ShopState extends State { + late String selectedPlace; + bool isActiveOffer = true; + + + @override + void initState() { + super.initState(); + selectedPlace = widget.place; + } + + @override + Widget build(BuildContext context) { + final now = DateTime.now(); + final schedule = IsOpenChecker.getTodaySchedule(widget.workingHours); + final isOpen = IsOpenChecker.isOpenNow(widget.workingHours); + + String timeRange = ''; + if (isOpen && schedule.shifts.isNotEmpty) { + for (final shift in schedule.shifts) { + timeRange += + '${formatTime12Hour(shift.openAt)} - ${formatTime12Hour(shift.closeAt)} '; + } + } + + return SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + SvgPicture.asset( + Assets.icons.shop.path, + color: Colors.black, + height: 25, + ), + SizedBox(width: 10), + Text( + widget.shopName, + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 17), + ), + ], + ), + SizedBox(height: 15), + Row( + children: [ + CustomStarRating(rating: widget.star), + SizedBox(width: 5), + Text( + widget.star.toString(), + style: TextStyle(color: LightAppColors.productDetailDivider), + ), + ], + ), + SizedBox(height: 5), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + SvgPicture.asset( + Assets.icons.location.path, + color: Colors.black, + ), + SizedBox(width: 5), + Text( + selectedPlace, + style: TextStyle( + color: LightAppColors.productDetailDivider, + ), + ), + ], + ), + PopupMenuButton( + color: Colors.white, + icon: SvgPicture.asset( + Assets.icons.arrowDown.path, + color: Colors.black, + height: 20, + ), + onSelected: (String newPlace) { + setState(() { + selectedPlace = newPlace; + }); + }, + itemBuilder: (BuildContext context) { + return widget.branches.map((String branch) { + return PopupMenuItem( + value: branch, + child: Text(branch), + ); + }).toList(); + }, + ), + ], + ), + SizedBox(height: 5), + Row( + children: [ + SvgPicture.asset(Assets.icons.clock.path), + SizedBox(width: 5), + Text( + isOpen ? 'Open Now' : 'Closed', + style: TextStyle(color: isOpen ? Colors.green : Colors.red), + ), + SizedBox(width: 5), + Container( + color: LightAppColors.productDetailDivider, + width: 1, + height: 13, + ), + SizedBox(width: 5), + Text( + timeRange, + style: TextStyle(color: LightAppColors.productDetailDivider), + ), + ], + ), + SizedBox(height: 15), + DividerTitleWidget(title: "Facilities"), + SizedBox( + height: 50, + child: ListView.builder( + physics: NeverScrollableScrollPhysics(), + itemCount: 1, + itemBuilder: (context, index) { + return Row( + children: [ + SvgPicture.asset(Assets.icons.tick.path), + SizedBox(width: 5), + Text( + widget.facilities, + style: TextStyle( + color: LightAppColors.productDetailDivider, + ), + ), + ], + ); + }, + ), + ), + SizedBox(height: 20), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: LightAppColors.confirmButton, + minimumSize: const Size(double.infinity, 48), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + ), + ), + onPressed: () { + MapsLauncher.launchCoordinates(25.2399, 55.2744); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SvgPicture.asset( + Assets.icons.routing2.path, + color: Colors.black, + ), + SizedBox(width: 5), + Text( + "Direction", + style: const TextStyle( + color: Colors.black, + fontSize: 16, + ), + ), + ], + ), + ), + SizedBox(height: 30), + Text( + "List of offers", + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + SizedBox(height: 15), + Container( + height: 45, + width: 150, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: const Color.fromARGB(17, 77, 77, 77), + ), + child: Row( + children: [ + GestureDetector( + onTap: () { + setState(() { + isActiveOffer = true; + }); + }, + child: Padding( + padding: const EdgeInsets.all(5.0), + child: Container( + height: 35, + width: 70, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: isActiveOffer ? Colors.white : Colors.transparent, + ), + child: Center(child: Text("Active")), + ), + ), + ), + GestureDetector( + onTap: () { + setState(() { + isActiveOffer = false; + }); + }, + child: Padding( + padding: const EdgeInsets.all(5.0), + child: Container( + height: 35, + width: 60, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: !isActiveOffer ? Colors.white : Colors.transparent, + ), + child: Center(child: Text("Old")), + ), + ), + ), + ], + ), + ), + SizedBox(height: 15), + SizedBox( + height: 160, + child: ListView.builder( + scrollDirection: Axis.horizontal, + shrinkWrap: true, + itemCount: 2, + itemBuilder: (context, index) { + return CustomCard( + title: "Calamaro Table Lamp", + description: "Elegant lighting with a modern twist.", + ); + }, + ), + ), + ], + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/widgets/buildWarpedInfo.dart b/lib/widgets/buildWarpedInfo.dart new file mode 100644 index 0000000..faa724c --- /dev/null +++ b/lib/widgets/buildWarpedInfo.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; +import 'package:lba/res/colors.dart'; + +Widget buildWrappedInfo(String label, String value) { + List lines = value.split('\n'); + return Padding( + padding: const EdgeInsets.only(bottom: 10.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + RichText( + text: TextSpan( + style: TextStyle(color: LightAppColors.productDetailDivider), + children: [ + TextSpan( + text: '$label ', + style: TextStyle(color: LightAppColors.confirmButton), + ), + TextSpan( + text: lines.first, + ), + ], + ), + ), + if (lines.length > 1) + Padding( + padding: const EdgeInsets.only(top: 4.0), + child: Text( + lines.skip(1).join('\n'), + style: TextStyle(color: LightAppColors.productDetailDivider), + ), + ), + ], + ), + ); + } + diff --git a/lib/widgets/customCard.dart b/lib/widgets/customCard.dart new file mode 100644 index 0000000..356376d --- /dev/null +++ b/lib/widgets/customCard.dart @@ -0,0 +1,100 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:lba/gen/assets.gen.dart'; +import 'package:lba/res/colors.dart'; + +class CustomCard extends StatelessWidget { + final String title; + final String description; + + const CustomCard({ + super.key, + required this.title, + required this.description, + }); + + @override + Widget build(BuildContext context) { + return Container( + width: 320, // عرض کمی افزایش یافت + margin: const EdgeInsets.symmetric(horizontal: 5), + padding: const EdgeInsets.all(8.0), + decoration: BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + offset: Offset(2, 2), + blurRadius: 6, + spreadRadius: 1, + ), + ], + borderRadius: BorderRadius.circular(12), + color: LightAppColors.nearbyPopup, + border: Border.all(color: Colors.white, width: 4.0), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(11), + ), + child: Image.asset( + Assets.images.image.path, + width: 80, + height: 80, + fit: BoxFit.cover, + ), + ), + SizedBox(width: 8), + Flexible( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: TextStyle(color: Colors.black), + overflow: TextOverflow.ellipsis, + ), + SizedBox(height: 5), + Text( + description, + style: TextStyle( + color: LightAppColors.nearbyPopuphint, + fontSize: 15, + ), + maxLines: 2, + softWrap: true, + ), + ], + ), + ), + ], + ), + SizedBox(height: 10), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SvgPicture.asset( + Assets.icons.mDSPublicTWTag.path, + ), + SizedBox(width: 10), + Text( + "(15%) 43 - 36.55 AED", + style: TextStyle(fontWeight: FontWeight.bold), + ), + ], + ), + ], + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/widgets/dividerTitle.dart b/lib/widgets/dividerTitle.dart new file mode 100644 index 0000000..dd1f2cc --- /dev/null +++ b/lib/widgets/dividerTitle.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; + +class DividerTitleWidget extends StatelessWidget { + + final String title; + + const DividerTitleWidget({ + super.key, + required this.title, + }); + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Text( + title, + style: TextStyle(fontSize: 15), + ), + const SizedBox(width: 8), + const Expanded( + child: Divider(color: Colors.grey, thickness: 2), + ), + ], + ); + } +} diff --git a/lib/widgets/openChecker.dart b/lib/widgets/openChecker.dart new file mode 100644 index 0000000..a22ba07 --- /dev/null +++ b/lib/widgets/openChecker.dart @@ -0,0 +1,83 @@ +import 'package:intl/intl.dart'; +import 'package:lba/data/model/workingHours.dart'; + +class IsOpenChecker { + static const Map _dayMap = { + 'monday': 'mo', + 'tuesday': 'tu', + 'wednesday': 'we', + 'thursday': 'th', + 'friday': 'fr', + 'saturday': 'sa', + 'sunday': 'su', + }; + + static bool isOpenNow(List workingHours) { + final now = DateTime.now(); + final todayKey = _dayMap[DateFormat('EEEE').format(now).toLowerCase()] ?? ''; + + final todaySchedule = workingHours.firstWhere( + (day) => day.day.toLowerCase() == todayKey, + orElse: () => WorkingHours(day: todayKey, shifts: []), + ); + + if (todaySchedule.shifts.isEmpty) return false; + + for (final shift in todaySchedule.shifts) { + if (_isTimeBetween(now, shift.openAt, shift.closeAt)) { + return true; + } + } + + return false; + } + + static WorkingHours getTodaySchedule(List workingHours) { + final now = DateTime.now(); + final todayKey = _dayMap[DateFormat('EEEE').format(now).toLowerCase()] ?? ''; + + return workingHours.firstWhere( + (day) => day.day.toLowerCase() == todayKey, + orElse: () => WorkingHours(day: todayKey, shifts: []), + ); + } + + static bool _isTimeBetween(DateTime now, String open, String close) { + try { + final openTime = _parseTime(open); + final closeTime = _parseTime(close); + final nowTime = Duration(hours: now.hour, minutes: now.minute); + + if (closeTime <= openTime) { + // شیفت شبانه (مثلاً 22:00 تا 02:00) + return nowTime >= openTime || nowTime <= closeTime; + } + + return nowTime >= openTime && nowTime <= closeTime; + } catch (_) { + return false; + } + } + + static Duration _parseTime(String time) { + final parts = time.split(':'); + final hour = int.parse(parts[0]); + final minute = int.parse(parts[1]); + return Duration(hours: hour, minutes: minute); + } +} + + +String formatTime12Hour(String time24) { + try { + final parts = time24.split(':'); + final hour = int.parse(parts[0]); + final minute = int.parse(parts[1]); + + final dateTime = DateTime(0, 1, 1, hour, minute); + final formatter = DateFormat('hh:mm a'); + return formatter.format(dateTime); + } catch (_) { + return time24; + } +} \ No newline at end of file diff --git a/lib/widgets/orderType.dart b/lib/widgets/orderType.dart index 198405e..dcf2664 100644 --- a/lib/widgets/orderType.dart +++ b/lib/widgets/orderType.dart @@ -1,11 +1,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:lba/res/colors.dart'; class OrderType extends StatelessWidget { String icon; String typename; + bool fill; - OrderType({super.key, required this.icon, required this.typename}); + OrderType({super.key, required this.icon, required this.typename,required this.fill}); @override Widget build(BuildContext context) { @@ -13,6 +15,7 @@ class OrderType extends StatelessWidget { decoration: BoxDecoration( borderRadius: BorderRadius.circular(25), border: Border.all(color: Color.fromARGB(255, 76, 175, 80), width: 1.0), + color: fill==false?Colors.transparent:LightAppColors.fillOrder ), child: Padding( padding: const EdgeInsets.fromLTRB(6, 2, 6, 2), @@ -20,14 +23,14 @@ class OrderType extends StatelessWidget { children: [ SvgPicture.asset( icon, - color: Color.fromARGB(255, 95, 95, 95), + color: fill==false? Color.fromARGB(255, 95, 95, 95):LightAppColors.fillOrderText, height: 17, ), SizedBox(width: 2), Text( typename, style: TextStyle( - color: Color.fromARGB(255, 95, 95, 95), + color: fill==false? Color.fromARGB(255, 95, 95, 95):LightAppColors.fillOrderText, fontWeight: FontWeight.w500, fontSize: 12 ), diff --git a/lib/widgets/rate.dart b/lib/widgets/rate.dart new file mode 100644 index 0000000..a4c2603 --- /dev/null +++ b/lib/widgets/rate.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:lba/gen/assets.gen.dart'; + +class CustomStarRating extends StatelessWidget { + final double rating; + final int starCount; + final double size; + + const CustomStarRating({ + super.key, + required this.rating, + this.starCount = 5, + this.size = 20.0, + }); + + @override + Widget build(BuildContext context) { + List stars = []; + + double remaining = rating; + + for (int i = 0; i < starCount; i++) { + if (remaining >= 1) { + stars.add(_buildStar(Assets.icons.starFill.path)); + remaining -= 1; + } else if (remaining >= 0.5) { + stars.add(_buildStar(Assets.icons.starHalf.path)); + remaining = 0; + } else { + stars.add(_buildStar(Assets.icons.star.path)); + } + } + + return Row( + mainAxisSize: MainAxisSize.min, + children: stars, + ); + } + + Widget _buildStar(String asset) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 2), + child: SvgPicture.asset( + asset, + width: size, + height: size, + ), + ); + } +} diff --git a/lib/widgets/reviews.dart b/lib/widgets/reviews.dart new file mode 100644 index 0000000..32b9135 --- /dev/null +++ b/lib/widgets/reviews.dart @@ -0,0 +1,102 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:lba/gen/assets.gen.dart'; +import 'package:lba/res/colors.dart'; +import 'package:lba/widgets/buildWarpedInfo.dart'; +import 'package:lba/widgets/rate.dart'; + +class Reviews extends StatelessWidget { + + final String name; + final String comment; + final double rate; + final int yesCount; + final int noCount; + final String date; + + const Reviews({ + super.key, + required this.name, + required this.comment, + required this.rate, + required this.yesCount, + required this.noCount, + required this.date, + }); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text(name), + SizedBox(width: 2), + Image.asset(Assets.images.usa.path), + ], + ), + Text( + "Verified Buyer", + style: TextStyle(color: LightAppColors.confirmButton), + ), + ], + ), + CustomStarRating(rating: rate), + ], + ), + SizedBox(height: 7), + buildWrappedInfo( + "", + comment, + ), + SizedBox(height: 10,), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + InkWell( + child: Row( + children: [ + SvgPicture.asset(Assets.icons.like.path), + SizedBox(width: 1,), + Text("Yes (${yesCount.toString()})",style: TextStyle( + color: LightAppColors.hint, + ),), + ], + ), + ), + SizedBox(width: 10,), + InkWell( + child: Row( + children: [ + SvgPicture.asset(Assets.icons.dislike.path), + SizedBox(width: 1,), + Text("No (${noCount.toString()})",style: TextStyle( + color: LightAppColors.hint, + ),), + ], + ), + ), + ], + ), + Text(date,style: TextStyle( + color: LightAppColors.hint + ),) + ], + ), + SizedBox(height: 5,), + Divider(thickness: 1.2, height: 2), + ], + ), + ); + } +} diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index e71a16d..dbec55e 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,6 +6,14 @@ #include "generated_plugin_registrant.h" +#include +#include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) maps_launcher_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "MapsLauncherPlugin"); + maps_launcher_plugin_register_with_registrar(maps_launcher_registrar); + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); } diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 2e1de87..6c56d5b 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,6 +3,8 @@ # list(APPEND FLUTTER_PLUGIN_LIST + maps_launcher + url_launcher_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 4bda447..98bc016 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -7,10 +7,14 @@ import Foundation import geolocator_apple import location +import maps_launcher import shared_preferences_foundation +import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) LocationPlugin.register(with: registry.registrar(forPlugin: "LocationPlugin")) + MapsLauncherPlugin.register(with: registry.registrar(forPlugin: "MapsLauncherPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 15b74d5..53627da 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -568,6 +568,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + maps_launcher: + dependency: "direct main" + description: + name: maps_launcher + sha256: dac4c609720211fa6336b5903d917fe45e545c6b5665978efc3db2a3f436b1ae + url: "https://pub.dev" + source: hosted + version: "3.0.0+1" matcher: dependency: transitive description: @@ -917,6 +925,70 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.1" + url_launcher: + dependency: transitive + description: + name: url_launcher + sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" + url: "https://pub.dev" + source: hosted + version: "6.3.1" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: "8582d7f6fe14d2652b4c45c9b6c14c0b678c2af2d083a11b604caeba51930d79" + url: "https://pub.dev" + source: hosted + version: "6.3.16" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb" + url: "https://pub.dev" + source: hosted + version: "6.3.3" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" + url: "https://pub.dev" + source: hosted + version: "3.2.2" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" + url: "https://pub.dev" + source: hosted + version: "3.1.4" uuid: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 82315d5..e2745f6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,6 +46,7 @@ dependencies: flutter_map: ^8.1.1 latlong2: ^0.9.1 location: ^8.0.0 + maps_launcher: ^3.0.0+1 dev_dependencies: flutter_test: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 1ece8f2..9a6f8bb 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -7,8 +7,14 @@ #include "generated_plugin_registrant.h" #include +#include +#include void RegisterPlugins(flutter::PluginRegistry* registry) { GeolocatorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("GeolocatorWindows")); + MapsLauncherPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("MapsLauncherPlugin")); + UrlLauncherWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 7f101a7..ae10e3f 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -4,6 +4,8 @@ list(APPEND FLUTTER_PLUGIN_LIST geolocator_windows + maps_launcher + url_launcher_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST