Houshan-Basa/lib/ui/widgets/components/purchase/purchase_card.dart

458 lines
25 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ignore_for_file: use_build_context_synchronously, deprecated_member_use_from_same_package
import 'dart:math';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hoshan/core/gen/assets.gen.dart';
import 'package:hoshan/data/model/plans_model.dart';
import 'package:hoshan/data/repository/paymant_repository.dart';
import 'package:hoshan/ui/theme/colors.dart';
import 'package:hoshan/ui/theme/cubit/theme_mode_cubit.dart';
import 'package:hoshan/ui/theme/text.dart';
import 'package:hoshan/ui/widgets/components/button/loading_button.dart';
import 'package:hoshan/ui/widgets/components/dialog/dialog_handler.dart';
import 'package:hoshan/ui/widgets/components/image/network_image.dart';
import 'package:hoshan/ui/widgets/components/purchase/cubit/discount_cubit.dart';
import 'package:hoshan/ui/widgets/components/shapes/vertical_ribbon.dart';
import 'package:hoshan/ui/widgets/components/snackbar/snackbar_manager.dart';
import 'package:persian_number_utility/persian_number_utility.dart';
import 'package:url_launcher/url_launcher.dart';
class PurchaseCard extends StatefulWidget {
final Plans plan;
final String? label;
final double? height;
final Widget Function()? button;
const PurchaseCard({
super.key,
required this.plan,
this.label,
this.height,
this.button,
});
@override
State<PurchaseCard> createState() => _PurchaseCardState();
}
class _PurchaseCardState extends State<PurchaseCard> {
ValueNotifier<bool> loading = ValueNotifier(false);
ValueNotifier<bool> showDiscount = ValueNotifier(false);
final TextEditingController discountTextEditingController =
TextEditingController();
String? discountCode;
late final pr = widget.plan;
@override
Widget build(BuildContext context) {
return BlocProvider<DiscountCubit>(
create: (context) => DiscountCubit(),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Stack(
children: [
Container(
height: widget.height,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Theme.of(context).colorScheme.surface),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(12),
child: ImageNetwork(
url: pr.image,
radius: 360,
width: 94,
height: 94,
),
),
const SizedBox(
height: 8,
),
Text(
widget.plan.title ?? '',
style: AppTextStyles.headline5.copyWith(
color: Theme.of(context).colorScheme.onSurface),
),
if (widget.plan.desc != null)
Column(
children: [
const SizedBox(
height: 4,
),
Text(
widget.plan.desc!,
style: AppTextStyles.body4.copyWith(
color: AppColors.gray[
context.read<ThemeModeCubit>().isDark()
? 600
: 900]),
),
const SizedBox(
height: 16,
),
],
),
const SizedBox(
height: 8,
),
if (pr.price != null)
Column(
children: [
Text(
'${pr.coins} سکه هوشان + ${pr.freeCoins} سکه رایگان',
style: AppTextStyles.body4.copyWith(
color: Theme.of(context).colorScheme.onSurface),
textAlign: TextAlign.center,
textDirection: TextDirection.rtl,
),
const SizedBox(
height: 12,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
textDirection: TextDirection.rtl,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(':مبلغ قابل پرداخت',
style: AppTextStyles.body3.copyWith(
color: Theme.of(context)
.colorScheme
.primary)),
],
),
Row(
children: [
if (pr.oldPrice != null)
Stack(
children: [
Text(
'${'${pr.oldPrice}'.seRagham()} تومان',
style: AppTextStyles.body4.copyWith(
color: AppColors
.gray.defaultShade)),
Positioned.fill(
child: Divider(
color: AppColors.gray.defaultShade,
thickness: 4,
))
],
),
if (pr.oldPrice != null)
Text(' - ',
style: AppTextStyles.body4.copyWith(
color:
AppColors.green.defaultShade)),
Text('${'${pr.price}'.seRagham()} تومان',
style: AppTextStyles.body4.copyWith(
color: AppColors.green.defaultShade)),
],
)
],
),
),
const SizedBox(
height: 32,
),
ValueListenableBuilder(
valueListenable: showDiscount,
builder: (context, show, _) {
return show
? BlocConsumer<DiscountCubit, DiscountState>(
listener: (context, state) {
if (state is DiscountSuccess) {
final p = pr.price! -
(state.discount.percent != null
? min(
(pr.price! *
state.discount
.percent!) ~/
100,
state.discount
.maxValue!)
: state.discount.value!)
.toInt();
pr.oldPrice = pr.price;
pr.price = p.round();
setState(() {
discountCode = state.code;
});
}
},
builder: (context, state) {
return Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Expanded(
flex: 1,
child: Row(
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
LoadingButton(
loading: state
is DiscountLoading,
onPressed: () {
if (discountTextEditingController
.text.isEmpty) {
return;
}
if (state
is DiscountSuccess) {
pr.price =
pr.oldPrice;
pr.oldPrice = null;
setState(() {
discountCode = null;
});
context
.read<
DiscountCubit>()
.refresh();
return;
}
context
.read<
DiscountCubit>()
.verifyDiscount(
discountTextEditingController
.text,
pr.id ?? '');
},
color: state
is DiscountSuccess
? AppColors
.red.defaultShade
: AppColors.green
.defaultShade,
child: Text(
state is DiscountSuccess
? 'حذف'
: 'اعمال',
style: AppTextStyles
.body4
.copyWith(
color: Colors
.white,
fontWeight:
FontWeight
.bold),
))
],
),
),
Expanded(
flex: 2,
child: Directionality(
textDirection:
TextDirection.rtl,
child: TextField(
controller:
discountTextEditingController,
maxLength: 8,
maxLines: 1,
style: TextStyle(
color: Theme.of(context)
.colorScheme
.onSurface),
enabled: state
is! DiscountSuccess &&
state is! DiscountLoading,
buildCounter: (context,
{required currentLength,
required isFocused,
required maxLength}) =>
const SizedBox.shrink(),
onChanged: (value) {
if (state
is! DiscountInitial) {
context
.read<DiscountCubit>()
.refresh();
}
},
decoration: InputDecoration(
error:
state is DiscountFail
? Text(
state.message ??
'مشکلی پیش آمده لحظاتی دیگر دوباره امتحان کنید',
style: AppTextStyles
.body5
.copyWith(
color: AppColors
.red
.defaultShade),
)
: null,
suffixIcon:
GestureDetector(
onTap: () async {
ClipboardData?
clipboardData =
await Clipboard
.getData(
'text/plain');
if (clipboardData !=
null &&
clipboardData
.text !=
null) {
discountTextEditingController
.text =
clipboardData
.text!;
}
},
child: const Icon(
Icons
.paste_rounded)),
hintText:
'کد تخفیف دارید؟',
hintStyle:
AppTextStyles.body4),
),
),
)
],
);
},
)
: GestureDetector(
onTap: () => showDiscount.value = !show,
child: Text(
'کد تخفیف دارید؟ اینجا کلیک کنید.',
textDirection: TextDirection.rtl,
style: AppTextStyles.body4.copyWith(
fontWeight: FontWeight.bold,
color: Theme.of(context)
.colorScheme
.primary),
),
);
}),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: ValueListenableBuilder(
valueListenable: loading,
builder: (context, load, _) {
return LoadingButton(
loading: load,
onPressed: context
.watch<DiscountCubit>()
.state is DiscountLoading
? null
: () async {
try {
loading.value = true;
final link =
await PaymantRepository
.getLinkPaymant(
pr.oldPrice ??
pr.price ??
0,
code: discountCode);
await launchUrl(Uri.parse(link),
mode: LaunchMode
.externalApplication)
.onError(
(error, stackTrace) {
if (kDebugMode) {
print(
'error open Link is: $error');
}
return false;
},
);
} on DioException catch (e) {
SnackBarManager(context,
id: 'error-bazar-paymant')
.show(
status:
SnackBarStatus.error,
message:
'پرداخت ناموفق بود');
if (kDebugMode) {
print("Dio Error is: $e");
}
}
loading.value = false;
},
radius: 360,
color: AppColors.primaryColor.defaultShade,
width: MediaQuery.sizeOf(context).width,
height: 48,
child: Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Text(
'خرید بسته ${pr.title ?? ''}',
style: AppTextStyles.body4
.copyWith(color: Colors.white),
),
const SizedBox(
width: 8,
),
Padding(
padding: const EdgeInsets.only(
bottom: 4.0),
child: Assets.icon.outline.crown.svg(
color: Colors.white,
width: 18,
),
),
],
));
}),
),
],
),
if (widget.button != null) widget.button!.call()
],
),
),
if (widget.label != null)
Positioned(
top: 0, left: 36, child: VerticalRibbon(text: widget.label!)),
if (pr.title != 'بسته ویژه سازمان‌ها')
Positioned(
top: 16,
right: 16,
child: GestureDetector(
onTap: () {
DialogHandler(context: context).showExtras();
},
child: Assets.icon.outline.infoCircle.svg(
color: AppColors.gray[
context.read<ThemeModeCubit>().isDark()
? 600
: 900],
width: 32,
height: 32),
))
],
),
),
);
}
}