Merge branch 'wala_plus_with_dialog_removal' of http://34.17.182.140/Haroon6138/mohemm-flutter-app into wala_plus_with_dialog_removal
* 'wala_plus_with_dialog_removal' of http://34.17.182.140/Haroon6138/mohemm-flutter-app: Toast fixed # Conflicts: # lib/generated/codegen_loader.g.dart # lib/generated/locale_keys.g.dartwala_plus_with_dialog_removal
commit
bd6e9577e3
Binary file not shown.
|
Before Width: | Height: | Size: 778 KiB |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,386 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mohem_flutter_app/api/offers_and_discounts_api_client.dart';
|
||||
import 'package:mohem_flutter_app/app_state/app_state.dart';
|
||||
import 'package:mohem_flutter_app/classes/colors.dart';
|
||||
import 'package:mohem_flutter_app/classes/utils.dart';
|
||||
import 'package:mohem_flutter_app/config/routes.dart';
|
||||
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
|
||||
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
|
||||
import 'package:mohem_flutter_app/models/generic_response_model.dart';
|
||||
import 'package:mohem_flutter_app/models/offers_and_discounts/wala_plus_retailer_model.dart';
|
||||
import 'package:mohem_flutter_app/ui/mazaya/widgets/mazaya_bottom_nav.dart';
|
||||
import 'package:mohem_flutter_app/ui/mazaya/widgets/wala_plus_retailer_grid.dart';
|
||||
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
|
||||
|
||||
// Mazaya Saved tab - full-screen version of what was FavoriteMerchantsBottomSheet (a modal
|
||||
// bottom sheet). Same fetch/search/pagination/toggle-favorite logic, now its own pushed route
|
||||
// with the shared MazayaBottomNav instead of a dismissible sheet - matches Discover's "own
|
||||
// route, fetches fresh on mount" pattern.
|
||||
class SavedRetailersScreen extends StatefulWidget {
|
||||
const SavedRetailersScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<SavedRetailersScreen> createState() => _SavedRetailersScreenState();
|
||||
}
|
||||
|
||||
class _SavedRetailersScreenState extends State<SavedRetailersScreen> {
|
||||
List<WalaPlusRetailerModel> favoriteRetailers = <WalaPlusRetailerModel>[];
|
||||
bool isLoading = true;
|
||||
bool isLoadingMore = false;
|
||||
bool hasMore = true;
|
||||
bool _isFetchingPage = false;
|
||||
int currentPage = 1;
|
||||
int totalPages = 1;
|
||||
final int pageSize = 10;
|
||||
String searchQuery = "";
|
||||
Timer? _debounceTimer;
|
||||
final TextEditingController _searchController = TextEditingController();
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_scrollController.addListener(_scrollListener);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted) fetchFavorites();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_debounceTimer?.cancel();
|
||||
_scrollController.removeListener(_scrollListener);
|
||||
_scrollController.dispose();
|
||||
_searchController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _scrollListener() {
|
||||
if (!_scrollController.hasClients) return;
|
||||
double maxScroll = _scrollController.position.maxScrollExtent;
|
||||
double currentScroll = _scrollController.position.pixels;
|
||||
if (currentScroll >= maxScroll - 35) {
|
||||
if (!isLoading && !isLoadingMore && !_isFetchingPage && hasMore) {
|
||||
fetchNextPage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String? _getUserReferenceForFavorites() {
|
||||
String ref = OffersAndDiscountsApiClient().resolveUserReference();
|
||||
if (ref.trim().isNotEmpty) return ref.trim();
|
||||
String? userName = AppState().getUserName;
|
||||
if (userName != null && userName.trim().isNotEmpty) return userName.trim();
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<void> fetchFavorites({String? query}) async {
|
||||
if (query != null) searchQuery = query;
|
||||
setState(() {
|
||||
isLoading = true;
|
||||
currentPage = 1;
|
||||
hasMore = true;
|
||||
});
|
||||
try {
|
||||
String? queryParam =
|
||||
searchQuery.trim().isNotEmpty ? searchQuery.trim() : null;
|
||||
String? userRef = _getUserReferenceForFavorites();
|
||||
WalaPlusRetailersResponse? response = await OffersAndDiscountsApiClient()
|
||||
.getWalaPlusRetailers(
|
||||
categoryId: "",
|
||||
page: 1,
|
||||
perPage: pageSize,
|
||||
offerType: null,
|
||||
query: queryParam,
|
||||
sortBy: null,
|
||||
radius: null,
|
||||
minDiscount: null,
|
||||
context: null,
|
||||
userReference: userRef,
|
||||
);
|
||||
favoriteRetailers = response?.retailers ?? <WalaPlusRetailerModel>[];
|
||||
for (WalaPlusRetailerModel r in favoriteRetailers) {
|
||||
r.isFavorite = true;
|
||||
}
|
||||
currentPage = 1;
|
||||
totalPages = response?.pagesCount ?? 1;
|
||||
hasMore =
|
||||
currentPage < totalPages &&
|
||||
(response?.retailers?.isNotEmpty ?? false);
|
||||
} catch (e) {
|
||||
debugPrint("MazayaSavedScreen: error fetching favorites: $e");
|
||||
favoriteRetailers = <WalaPlusRetailerModel>[];
|
||||
} finally {
|
||||
if (mounted) setState(() => isLoading = false);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> fetchNextPage() async {
|
||||
if (isLoading || isLoadingMore || _isFetchingPage || !hasMore) return;
|
||||
_isFetchingPage = true;
|
||||
setState(() => isLoadingMore = true);
|
||||
try {
|
||||
int nextPage = currentPage + 1;
|
||||
String? queryParam =
|
||||
searchQuery.trim().isNotEmpty ? searchQuery.trim() : null;
|
||||
String? userRef = _getUserReferenceForFavorites();
|
||||
WalaPlusRetailersResponse? response = await OffersAndDiscountsApiClient()
|
||||
.getWalaPlusRetailers(
|
||||
categoryId: "",
|
||||
page: nextPage,
|
||||
perPage: pageSize,
|
||||
offerType: null,
|
||||
query: queryParam,
|
||||
sortBy: null,
|
||||
radius: null,
|
||||
minDiscount: null,
|
||||
context: null,
|
||||
userReference: userRef,
|
||||
);
|
||||
List<WalaPlusRetailerModel> newRetailers =
|
||||
response?.retailers ?? <WalaPlusRetailerModel>[];
|
||||
if (newRetailers.isNotEmpty) {
|
||||
for (WalaPlusRetailerModel r in newRetailers) {
|
||||
r.isFavorite = true;
|
||||
}
|
||||
currentPage = nextPage;
|
||||
totalPages = response?.pagesCount ?? totalPages;
|
||||
hasMore = currentPage < totalPages;
|
||||
favoriteRetailers.addAll(newRetailers);
|
||||
} else {
|
||||
hasMore = false;
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint("MazayaSavedScreen: error fetching next page: $e");
|
||||
} finally {
|
||||
_isFetchingPage = false;
|
||||
if (mounted) setState(() => isLoadingMore = false);
|
||||
}
|
||||
}
|
||||
|
||||
void _onSearchChanged(String query) {
|
||||
_debounceTimer?.cancel();
|
||||
searchQuery = query;
|
||||
if (query.trim().isEmpty) {
|
||||
fetchFavorites(query: "");
|
||||
} else {
|
||||
_debounceTimer = Timer(const Duration(milliseconds: 600), () {
|
||||
fetchFavorites(query: query.trim());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _toggleFavorite(WalaPlusRetailerModel item) async {
|
||||
String retailerId = item.id ?? "";
|
||||
if (retailerId.isEmpty) return;
|
||||
|
||||
bool currentFav = item.isFavorite ?? true;
|
||||
bool targetFav = !currentFav;
|
||||
|
||||
setState(() {
|
||||
item.isFavorite = targetFav;
|
||||
if (!targetFav) {
|
||||
favoriteRetailers.removeWhere(
|
||||
(WalaPlusRetailerModel r) => r.id == item.id,
|
||||
);
|
||||
}
|
||||
});
|
||||
Utils.showLoading(context);
|
||||
|
||||
try {
|
||||
GenericResponseModel? response;
|
||||
String? userRef = _getUserReferenceForFavorites();
|
||||
if (targetFav) {
|
||||
response = await OffersAndDiscountsApiClient().addWalaPlusFavorite(
|
||||
retailerId: retailerId,
|
||||
context: context,
|
||||
userReference: userRef,
|
||||
);
|
||||
} else {
|
||||
response = await OffersAndDiscountsApiClient().removeWalaPlusFavorite(
|
||||
retailerId: retailerId,
|
||||
context: context,
|
||||
userReference: userRef,
|
||||
);
|
||||
}
|
||||
|
||||
Utils.hideLoading(context);
|
||||
|
||||
if (response != null && response.errorMessage == null) {
|
||||
bool isAr = AppState().isArabic(context);
|
||||
String msg =
|
||||
isAr
|
||||
? (targetFav
|
||||
? LocaleKeys.favoriteAddedSuccess.tr()
|
||||
: LocaleKeys.favoriteRemovedSuccess.tr())
|
||||
: (response.wpFavoritesAddRemoveMessage ??
|
||||
(targetFav
|
||||
? LocaleKeys.favoriteAddedSuccess.tr()
|
||||
: LocaleKeys.favoriteRemovedSuccess.tr()));
|
||||
Utils.showToast(msg, isSuccess: true);
|
||||
} else {
|
||||
Utils.showToast(
|
||||
response?.errorEndUserMessage ??
|
||||
response?.errorMessage ??
|
||||
LocaleKeys.favoriteError.tr(),
|
||||
);
|
||||
await fetchFavorites(query: _searchController.text);
|
||||
}
|
||||
} catch (e) {
|
||||
Utils.hideLoading(context);
|
||||
debugPrint("MazayaSavedScreen: error toggling favorite: $e");
|
||||
Utils.showToast(LocaleKeys.favoriteError.tr());
|
||||
await fetchFavorites(query: _searchController.text);
|
||||
}
|
||||
}
|
||||
|
||||
void _openRetailer(WalaPlusRetailerModel item) async {
|
||||
await Navigator.pushNamed(
|
||||
context,
|
||||
AppRoutes.retailerDetailsScreen,
|
||||
arguments: item,
|
||||
);
|
||||
if (mounted) {
|
||||
await fetchFavorites(query: _searchController.text);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
bool isAr = AppState().isArabic(context);
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: AppBarWidget(
|
||||
context,
|
||||
title: LocaleKeys.favoriteOffers.tr(),
|
||||
showHomeButton: false,
|
||||
),
|
||||
bottomNavigationBar: const MazayaBottomNav(currentTab: MazayaTab.saved),
|
||||
body: Column(
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: 70,
|
||||
padding: const EdgeInsets.only(
|
||||
top: 14,
|
||||
right: 16,
|
||||
bottom: 14,
|
||||
left: 16,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(color: const Color(0xFFE8E8E8), width: 1.0),
|
||||
boxShadow: <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: const Color(0xFF000000).withOpacity(0.0314),
|
||||
offset: const Offset(0, 2),
|
||||
blurRadius: 5,
|
||||
spreadRadius: 0,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
LocaleKeys.search.tr().toText12(
|
||||
isBold: true,
|
||||
color: const Color(0xFF2A333C),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
TextField(
|
||||
controller: _searchController,
|
||||
onChanged: _onSearchChanged,
|
||||
onSubmitted: (String val) {
|
||||
_debounceTimer?.cancel();
|
||||
fetchFavorites(query: val.trim());
|
||||
},
|
||||
textInputAction: TextInputAction.search,
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
hintText: LocaleKeys.searchItems.tr(),
|
||||
hintStyle: const TextStyle(
|
||||
color: Color(0xFFACAFB1),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 1.2,
|
||||
),
|
||||
border: InputBorder.none,
|
||||
suffixIcon: ValueListenableBuilder<TextEditingValue>(
|
||||
valueListenable: _searchController,
|
||||
builder: (
|
||||
BuildContext context,
|
||||
TextEditingValue value,
|
||||
Widget? child,
|
||||
) {
|
||||
if (value.text.isEmpty)
|
||||
return const SizedBox.shrink();
|
||||
return InkWell(
|
||||
child: const Icon(
|
||||
Icons.clear,
|
||||
size: 18,
|
||||
color: Color(0xFF848486),
|
||||
),
|
||||
onTap: () {
|
||||
_searchController.clear();
|
||||
_onSearchChanged("");
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
suffixIconConstraints: const BoxConstraints(
|
||||
maxWidth: 24,
|
||||
maxHeight: 28,
|
||||
),
|
||||
),
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF2A333C),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: RefreshIndicator(
|
||||
onRefresh: () => fetchFavorites(query: _searchController.text),
|
||||
color: MyColors.textMixColor,
|
||||
child: SingleChildScrollView(
|
||||
controller: _scrollController,
|
||||
physics: const AlwaysScrollableScrollPhysics(
|
||||
parent: BouncingScrollPhysics(),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 8,
|
||||
),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
WalaPlusRetailerGrid(
|
||||
isLoading: isLoading,
|
||||
retailers: favoriteRetailers,
|
||||
isAr: isAr,
|
||||
isLoadingMore: isLoadingMore,
|
||||
onTapRetailer: _openRetailer,
|
||||
onFavoriteTap: _toggleFavorite,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
|
||||
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
|
||||
import 'package:mohem_flutter_app/ui/mazaya/mazaya_discover_screen.dart';
|
||||
import 'package:mohem_flutter_app/ui/mazaya/saved_retailers_screen.dart';
|
||||
import 'package:mohem_flutter_app/ui/profile/family_members.dart';
|
||||
|
||||
enum MazayaTab { discover, saved, myFamily }
|
||||
|
||||
// Shared bottom nav for the Mazaya module (Discover / Saved / My Family). Each tab is its own
|
||||
// screen, swapped in with zero-duration transition (see _onTabTapped) so switching tabs feels
|
||||
// instant rather than like a new screen opening - not an IndexedStack shell, since each tab still
|
||||
// needs to reload its own data fresh on every switch, not preserve state across tabs.
|
||||
class MazayaBottomNav extends StatelessWidget {
|
||||
final MazayaTab currentTab;
|
||||
|
||||
const MazayaBottomNav({Key? key, required this.currentTab}) : super(key: key);
|
||||
|
||||
static const Color _activeColor = Color(0xFF147D6B);
|
||||
static const Color _inactiveColor = Color(0xFF78817F);
|
||||
|
||||
void _onTabTapped(BuildContext context, MazayaTab tab) {
|
||||
if (tab == currentTab) return;
|
||||
Widget targetScreen;
|
||||
RouteSettings? settings;
|
||||
switch (tab) {
|
||||
case MazayaTab.discover:
|
||||
targetScreen = const MazayaDiscoverScreen();
|
||||
break;
|
||||
case MazayaTab.saved:
|
||||
targetScreen = const SavedRetailersScreen();
|
||||
break;
|
||||
case MazayaTab.myFamily:
|
||||
targetScreen = const FamilyMembers();
|
||||
settings = const RouteSettings(arguments: <String, dynamic>{'fromMazaya': true});
|
||||
break;
|
||||
}
|
||||
Navigator.pushReplacement(
|
||||
context,
|
||||
PageRouteBuilder<void>(
|
||||
settings: settings,
|
||||
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) => targetScreen,
|
||||
transitionDuration: Duration.zero,
|
||||
reverseTransitionDuration: Duration.zero,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildItem(BuildContext context, {required MazayaTab tab, required String svgAsset, required String label}) {
|
||||
bool isActive = tab == currentTab;
|
||||
return Expanded(
|
||||
child: InkWell(
|
||||
onTap: () => _onTabTapped(context, tab),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
SvgPicture.asset(svgAsset, width: 22, height: 22, colorFilter: ColorFilter.mode(isActive ? _activeColor : _inactiveColor, BlendMode.srcIn)),
|
||||
const SizedBox(height: 5),
|
||||
label.toText11(weight: isActive ? FontWeight.w600 : FontWeight.w400, color: isActive ? _activeColor : _inactiveColor),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SafeArea(
|
||||
top: false,
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(color: Colors.white, border: Border(top: BorderSide(color: Color(0xFFE8EAE4)))),
|
||||
padding: const EdgeInsets.only(top: 13, bottom: 9),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
_buildItem(context, tab: MazayaTab.discover, svgAsset: "assets/icons/mazaya_compass.svg", label: LocaleKeys.discover.tr()),
|
||||
_buildItem(context, tab: MazayaTab.saved, svgAsset: "assets/icons/mazaya_heart_outline.svg", label: LocaleKeys.saved.tr()),
|
||||
_buildItem(context, tab: MazayaTab.myFamily, svgAsset: "assets/icons/mazaya_user_round.svg", label: LocaleKeys.myFamily.tr()),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,97 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
|
||||
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
|
||||
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
|
||||
import 'package:mohem_flutter_app/main.dart';
|
||||
import 'package:mohem_flutter_app/models/offers_and_discounts/wala_plus_retailer_model.dart';
|
||||
import 'package:mohem_flutter_app/ui/mazaya/retailers_list_screen.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
|
||||
class WalaPlusRetailerGrid extends StatelessWidget {
|
||||
final bool isLoading;
|
||||
final List<WalaPlusRetailerModel> retailers;
|
||||
final bool isAr;
|
||||
final void Function(WalaPlusRetailerModel item) onTapRetailer;
|
||||
final void Function(WalaPlusRetailerModel item) onFavoriteTap;
|
||||
final bool isLoadingMore;
|
||||
final int shimmerItemCount;
|
||||
|
||||
const WalaPlusRetailerGrid({
|
||||
Key? key,
|
||||
required this.isLoading,
|
||||
required this.retailers,
|
||||
required this.isAr,
|
||||
required this.onTapRetailer,
|
||||
required this.onFavoriteTap,
|
||||
this.isLoadingMore = false,
|
||||
this.shimmerItemCount = 4,
|
||||
}) : super(key: key);
|
||||
|
||||
SliverGridDelegateWithFixedCrossAxisCount get _gridDelegate =>
|
||||
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: isTablet ? 4 : 2, mainAxisExtent: 235, crossAxisSpacing: 12, mainAxisSpacing: 16);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (isLoading) {
|
||||
return Shimmer.fromColors(
|
||||
baseColor: const Color(0xFFE2E8F0),
|
||||
highlightColor: const Color(0xFFF8FAFC),
|
||||
child: GridView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
gridDelegate: _gridDelegate,
|
||||
itemCount: shimmerItemCount,
|
||||
itemBuilder: (BuildContext _, int __) => _buildShimmerCard(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (retailers.isEmpty) {
|
||||
return Padding(padding: const EdgeInsets.only(top: 40), child: Center(child: LocaleKeys.noOffersAvailable.tr().toText14(color: const Color(0xFF64748B))));
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
GridView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
gridDelegate: _gridDelegate,
|
||||
itemCount: retailers.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return WalaPlusRetailerCard(item: retailers[index], isAr: isAr, onTap: () => onTapRetailer(retailers[index]), onFavoriteTap: () => onFavoriteTap(retailers[index]));
|
||||
},
|
||||
),
|
||||
if (isLoadingMore) ...<Widget>[
|
||||
16.height,
|
||||
Center(child: Padding(padding: const EdgeInsets.symmetric(vertical: 12), child: Image.asset("assets/images/logos/loading_mohemm_logo.gif", height: 48.0, width: 48.0))),
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildShimmerCard() {
|
||||
return Container(
|
||||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(20)),
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Container(height: 120, width: double.infinity, decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(14))),
|
||||
const SizedBox(height: 8),
|
||||
Container(height: 14, width: 110, decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(4))),
|
||||
const SizedBox(height: 6),
|
||||
Container(height: 14, width: 80, decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(4))),
|
||||
const SizedBox(height: 6),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Container(height: 28, width: 50, decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(6))),
|
||||
const SizedBox(width: 5),
|
||||
Container(height: 28, width: 45, decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(6))),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue