import 'package:comwell_key_app/.generated/assets/assets.gen.dart';
import 'package:comwell_key_app/presentation/screens/check_in/bloc/check_in_cubit.dart';
import 'package:comwell_key_app/presentation/screens/check_in/bloc/check_in_state.dart';
import 'package:comwell_key_app/common/components/comwell_card_component.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:comwell_key_app/utils/l10n_utils.dart';
import 'package:comwell_key_app/utils/lottie_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:lottie/lottie.dart';
class CheckInPage extends StatefulWidget {
const CheckInPage({super.key});
@override
State<CheckInPage> createState() => _CheckInPageState();
}
class _CheckInPageState extends State<CheckInPage> with SingleTickerProviderStateMixin {
LottieComposition? loadingComposition;
late final AnimationController animationController;
late final Widget loadingAnimation;
@override
void initState() {
animationController = AnimationController(vsync: this);
loadingAnimation = Lottie.asset(
Assets.animations.loadAnimation,
controller: animationController,
onLoaded: (composition) {
if (loadingComposition == null) {
loadingComposition = composition;
animationController.duration = composition.duration;
}
},
fit: BoxFit.cover,
width: 64,
height: 64,
);
super.initState();
}
@override
void dispose() {
animationController.dispose();
super.dispose();
}
void onAnimationEnd() {
playLoading();
}
void playLoading() {
loadingComposition?.playBetween(
animationController,
"spinner",
markerEnd: "success",
repeat: true,
);
}
void playError() {
loadingComposition?.playBetween(animationController, "error");
}
void playSuccess() {
loadingComposition?.playBetween(animationController, "success", markerEnd: "error");
}
double getCardPosition(BuildContext context) {
final mq = MediaQuery.of(context);
final cubit = context.read<CheckInCubit>();
final state = cubit.state;
final padding = mq.viewPadding;
final height = mq.size.height;
final startPosition = height - padding.bottom - padding.top - 100;
switch (state.cardState) {
case CheckInStatus.loading:
case CheckInStatus.error:
return height / 2 - 100;
case CheckInStatus.done:
return 100;
case _:
return startPosition;
}
}
Widget getCardContent(BuildContext context) {
final cubit = context.read<CheckInCubit>();
if (cubit.state.cardState == CheckInStatus.done) {
return Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(30)),
border: Border.all(color: colorBackground, width: 2),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"${context.strings.check_in_your_digital_card_room_prefix} ${(cubit.booking.roomNumber)}",
style: Theme.of(context).textTheme.headlineLarge?.copyWith(
color: colorBackground,
),
),
),
);
} else {
return loadingAnimation;
}
}
@override
Widget build(BuildContext context) {
final cubit = context.read<CheckInCubit>();
final theme = Theme.of(context);
return BlocConsumer<CheckInCubit, CheckInState>(
listener: (context, state) {
switch (state.cardState) {
case CheckInStatus.loading:
playLoading();
break;
case CheckInStatus.roomFound:
playSuccess();
break;
case CheckInStatus.error:
playError();
break;
default:
break;
}
},
builder: (context, state) {
return Scaffold(
body: SafeArea(
child: Builder(
builder: (context) {
final position = getCardPosition(context);
return Stack(
fit: StackFit.expand,
children: [
AnimatedPositioned(
duration: const Duration(milliseconds: 200),
top: position,
left: 16,
right: 16,
curve: Easing.linear,
onEnd: onAnimationEnd,
child: ComwellCard(content: getCardContent(context)),
),
if (state.cardState == CheckInStatus.error)
Align(
alignment: Alignment.bottomCenter,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 15),
Text(
context.strings.check_in_page_error_title,
textAlign: TextAlign.center,
style: theme.textTheme.headlineMedium?.copyWith(
color: colorHeadlineText,
),
),
const SizedBox(height: 15),
Text(
context.strings.check_in_page_error_subtitle,
textAlign: TextAlign.center,
style: theme.textTheme.bodySmall?.copyWith(color: colorHeadlineText),
),
const SizedBox(height: 15),
Text(state.subtitleStringId(context), style: theme.textTheme.bodySmall),
const SizedBox(height: 15),
const Divider(
color: colorDivider,
height: 0,
),
Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: ElevatedButton(
onPressed: () {
context.pop();
},
style: ButtonStyle(
backgroundColor: WidgetStatePropertyAll(sandColor[80]),
foregroundColor: const WidgetStatePropertyAll(
colorBackground,
),
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Text(context.strings.generic_continue),
),
),
),
),
],
),
],
),
),
if (state.cardState == CheckInStatus.done)
Align(
alignment: Alignment.bottomCenter,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
context.strings.check_in_your_digital_card_nb,
textAlign: TextAlign.center,
style: theme.textTheme.bodySmall?.copyWith(
color: colorHeadlineText,
),
),
),
const SizedBox(height: 15),
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
state.subtitleStringId(context),
style: theme.textTheme.bodySmall,
),
),
const SizedBox(height: 15),
const Divider(
color: colorDivider,
height: 0,
),
Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: ElevatedButton(
onPressed: () {
context.pop(true);
},
style: ButtonStyle(
backgroundColor: WidgetStatePropertyAll(sandColor[80]),
foregroundColor: const WidgetStatePropertyAll(
colorBackground,
),
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Text(context.strings.generic_done),
),
),
),
),
],
),
],
),
),
],
);
},
),
),
);
},
);
}
}