Skip to content

Commit

Permalink
feat(Skeletons): Add a user bookings skeleton loader
Browse files Browse the repository at this point in the history
Signed-off-by: arafaysaleem <a.rafaysaleem@gmail.com>
  • Loading branch information
arafaysaleem committed Jun 16, 2021
1 parent a2ca4be commit 74982f5
Show file tree
Hide file tree
Showing 4 changed files with 244 additions and 74 deletions.
4 changes: 2 additions & 2 deletions lib/views/screens/user_bookings_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import 'package:flutter/material.dart';
import '../../helper/extensions/context_extensions.dart';

//Widgets
import '../widgets/user_bookings/user_bookings_list.dart';
import '../widgets/user_bookings/user_bookings_history.dart';

class UserBookingsScreen extends StatelessWidget {
const UserBookingsScreen({Key? key}) : super(key: key);
Expand Down Expand Up @@ -54,7 +54,7 @@ class UserBookingsScreen extends StatelessWidget {
const Expanded(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 15),
child: UserBookingsList(),
child: UserBookingsHistory(),
),
),
],
Expand Down
147 changes: 147 additions & 0 deletions lib/views/skeletons/user_bookings_skeleton_loader.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import 'package:flutter/material.dart';

//Helpers
import '../../helper/utils/constants.dart';

//Widgets
import '../widgets/common/shimmer_loader.dart';

class UserBookingsSkeletonLoader extends StatelessWidget {
const UserBookingsSkeletonLoader();

@override
Widget build(BuildContext context) {
return ShimmerLoader(
child: ListView.separated(
itemCount: 4,
physics: const NeverScrollableScrollPhysics(),
separatorBuilder: (ctx,i) => const SizedBox(height: 20),
itemBuilder: (ctx,i) => const _UserBookingSkeleton(),
),
);
}
}

class _UserBookingSkeleton extends StatelessWidget {
const _UserBookingSkeleton({
Key? key,
}) : super(key: key);

@override
Widget build(BuildContext context) {
return SizedBox(
height: 140,
child: Stack(
alignment: Alignment.bottomCenter,
children: [
//Booking overview
SizedBox(
height: 120,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
//Booking details
_BookingDetailsSkeleton(),

//No of seats
SizedBox(
height: double.infinity,
width: 45,
child: DecoratedBox(
decoration: BoxDecoration(
color: Constants.darkSkeletonColor,
borderRadius: BorderRadius.only(
topRight: Radius.circular(15),
bottomRight: Radius.circular(15),
),
),
),
),
],
),
),

//Movie Image
const Positioned(
bottom: 13,
left: 13,
child: SizedBox(
height: 125,
width: 100,
child: DecoratedBox(
decoration: BoxDecoration(
color: Constants.darkSkeletonColor,
borderRadius: BorderRadius.all(Radius.circular(10)),
),
child: Center(
child: Icon(
Icons.movie_creation_rounded,
color: Constants.lightSkeletonColor,
size: 40,
),
),
),
),
),
],
),
);
}
}

class _BookingDetailsSkeleton extends StatelessWidget {
const _BookingDetailsSkeleton({
Key? key,
}) : super(key: key);

@override
Widget build(BuildContext context) {
return Expanded(
child: Container(
decoration: const BoxDecoration(
color: Constants.lightSkeletonColor,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(15),
bottomLeft: Radius.circular(15),
),
),
padding: const EdgeInsets.fromLTRB(125, 10, 10, 13),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
//Movie data
SizedBox(
height: 25,
width: double.infinity,
child: DecoratedBox(
decoration: BoxDecoration(
color: Constants.darkSkeletonColor,
borderRadius: BorderRadius.all(
Radius.circular(6),
),
),
),
),

SizedBox(height: 10),

//Show details
Expanded(
child: SizedBox(
width: double.infinity,
child: DecoratedBox(
decoration: BoxDecoration(
color: Constants.darkSkeletonColor,
borderRadius: BorderRadius.all(
Radius.circular(8),
),
),
),
),
),
],
),
),
);
}
}
48 changes: 48 additions & 0 deletions lib/views/widgets/user_bookings/user_bookings_history.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

//Helpers
import '../../../helper/extensions/context_extensions.dart';

//Providers
import '../../../providers/bookings_provider.dart';

//Services
import '../../../services/networking/network_exception.dart';

//Skeletons
import '../../skeletons/user_bookings_skeleton_loader.dart';

//Widgets
import '../common/custom_error_widget.dart';
import 'user_bookings_list.dart';

class UserBookingsHistory extends HookWidget {
const UserBookingsHistory();

@override
Widget build(BuildContext context) {
final userBookingsFuture = useProvider(userBookingsProvider);
return AnimatedSwitcher(
duration: const Duration(milliseconds: 600),
switchOutCurve: Curves.easeInBack,
child: userBookingsFuture.when(
data: (bookings) => UserBookingsList(bookings: bookings),
loading: () => const UserBookingsSkeletonLoader(),
error: (error, st) {
if (error is NetworkException) {
return CustomErrorWidget.dark(
error: error,
retryCallback: () => context.refresh(userBookingsProvider),
height: context.screenHeight * 0.5,
);
}
debugPrint(error.toString());
debugPrint(st.toString());
return const SizedBox.shrink();
},
),
);
}
}
119 changes: 47 additions & 72 deletions lib/views/widgets/user_bookings/user_bookings_list.dart
Original file line number Diff line number Diff line change
@@ -1,35 +1,27 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

//Helpers
import '../../../helper/extensions/context_extensions.dart';
import '../../../helper/utils/constants.dart';

//Providers
import '../../../providers/bookings_provider.dart';

//Models
import '../../../models/user_booking_model.dart';

//Services
import '../../../services/networking/network_exception.dart';

//Skeletons
import '../../skeletons/movie_poster_placeholder.dart';

//Widgets
import '../common/custom_error_widget.dart';
import '../common/custom_network_image.dart';
import 'booking_details_dialog.dart';
import 'booking_summary_row.dart';

class UserBookingsList extends HookWidget {
const UserBookingsList();
class UserBookingsList extends StatelessWidget {
const UserBookingsList({
Key? key,
required this.bookings,
}) : super(key: key);

static const movieSize = 100.0;
static const padding = 15.0;
final List<UserBookingModel> bookings;

void onTap(BuildContext context, UserBookingModel booking) {
showGeneralDialog(
Expand All @@ -39,7 +31,8 @@ class UserBookingsList extends HookWidget {
barrierLabel: '',
context: context,
transitionBuilder: (context, a1, a2, dialog) {
final curveValue = (1 - Curves.linearToEaseOut.transform(a1.value)) * 200;
final curveValue =
(1 - Curves.linearToEaseOut.transform(a1.value)) * 200;
return Transform(
transform: Matrix4.translationValues(curveValue, 0.0, 0.0),
child: Opacity(opacity: a1.value, child: dialog),
Expand All @@ -54,66 +47,48 @@ class UserBookingsList extends HookWidget {

@override
Widget build(BuildContext context) {
final userBookingsFuture = useProvider(userBookingsProvider);
return userBookingsFuture.when(
data: (bookings) => ListView.separated(
physics: const BouncingScrollPhysics(),
itemCount: bookings.length,
separatorBuilder: (_, i) => const SizedBox(height: 20),
itemBuilder: (_, i) {
final booking = bookings[i];
final total = booking.bookings.fold(0.0, (sum, seat) => seat.price);
final noOfSeats = booking.bookings.length;
return SizedBox(
height: 140,
child: GestureDetector(
onTap: () => onTap(context, booking),
child: Stack(
alignment: Alignment.bottomCenter,
children: [
//Booking overview
BookingSummaryRow(
total: total,
title: booking.title,
noOfSeats: noOfSeats,
showDateTime: booking.show.showDatetime,
showType: booking.show.showType,
),
return ListView.separated(
physics: const BouncingScrollPhysics(),
itemCount: bookings.length,
separatorBuilder: (_, i) => const SizedBox(height: 20),
itemBuilder: (_, i) {
final booking = bookings[i];
final total = booking.bookings.fold(0.0, (sum, seat) => seat.price);
final noOfSeats = booking.bookings.length;
return SizedBox(
height: 140,
child: GestureDetector(
onTap: () {},
child: Stack(
alignment: Alignment.bottomCenter,
children: [
//Booking overview
BookingSummaryRow(
total: total,
title: booking.title,
noOfSeats: noOfSeats,
showDateTime: booking.show.showDatetime,
showType: booking.show.showType,
),

//Movie Image
Positioned(
bottom: 13,
left: 13,
child: CustomNetworkImage(
imageUrl: booking.posterUrl,
fit: BoxFit.cover,
width: movieSize,
height: movieSize + 25,
borderRadius: const BorderRadius.all(Radius.circular(10)),
placeholder: const MoviePosterPlaceholder(),
errorWidget: const MoviePosterPlaceholder(),
),
//Movie Image
Positioned(
bottom: 13,
left: 13,
child: CustomNetworkImage(
imageUrl: booking.posterUrl,
fit: BoxFit.cover,
width: movieSize,
height: movieSize + 25,
borderRadius: const BorderRadius.all(Radius.circular(10)),
placeholder: const MoviePosterPlaceholder(iconSize: 40),
errorWidget: const MoviePosterPlaceholder(iconSize: 40),
),
],
),
),
],
),
);
},
),
loading: () => const SpinKitRing(color: Colors.red),
error: (error, st) {
if (error is NetworkException) {
return CustomErrorWidget.dark(
error: error,
retryCallback: () {
context.refresh(userBookingsProvider);
},
height: context.screenHeight * 0.5,
);
}
debugPrint(error.toString());
debugPrint(st.toString());
return const SizedBox.shrink();
),
);
},
);
}
Expand Down

0 comments on commit 74982f5

Please sign in to comment.