458 lines
25 KiB
Dart
458 lines
25 KiB
Dart
// 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),
|
||
))
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|