Houshan-Basa/lib/ui/widgets/components/dialog/dialog_handler.dart

2045 lines
82 KiB
Dart

// ignore_for_file: deprecated_member_use_from_same_package, use_build_context_synchronously, deprecated_member_use
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:go_router/go_router.dart';
import 'package:hoshan/core/gen/assets.gen.dart';
import 'package:hoshan/core/routes/route_generator.dart';
import 'package:hoshan/core/services/firebase/firebase_api.dart';
import 'package:hoshan/data/model/ai/credit_model.dart';
import 'package:hoshan/data/model/chat_args.dart';
import 'package:hoshan/data/model/event_model.dart';
import 'package:hoshan/data/storage/shared_preferences_helper.dart';
import 'package:hoshan/ui/screens/main/home/bloc/bots_bloc.dart';
import 'package:hoshan/ui/screens/setting/cubit/settlement_cubit.dart';
import 'package:hoshan/ui/screens/splash/cubit/user_info_cubit.dart';
import 'package:hoshan/ui/theme/colors.dart';
import 'package:hoshan/ui/theme/cubit/theme_mode_cubit.dart';
import 'package:hoshan/ui/theme/responsive.dart';
import 'package:hoshan/ui/theme/text.dart';
import 'package:hoshan/ui/widgets/components/button/loading_button.dart';
import 'package:hoshan/ui/widgets/components/calender/persian_date_picker.dart';
import 'package:hoshan/ui/widgets/components/calender/shamsi_year_month_picker.dart';
import 'package:hoshan/ui/widgets/components/image/custome_image.dart';
import 'package:hoshan/ui/widgets/components/image/network_image.dart';
import 'package:hoshan/ui/widgets/components/snackbar/snackbar_manager.dart';
import 'package:hoshan/ui/widgets/components/text/auth_text_field.dart';
import 'package:hoshan/ui/widgets/components/video/video_player_widget.dart';
import 'package:hoshan/ui/widgets/sections/loading/default_placeholder.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:shamsi_date/shamsi_date.dart';
import 'package:string_validator/string_validator.dart';
import 'package:url_launcher/url_launcher.dart';
class DialogHandler {
final BuildContext context;
final double maxDialogWidthInDesktop = 600;
DialogHandler({required this.context});
Future loadingDialog({final String? text}) async {
await showDialog(
context: context,
barrierDismissible: false,
builder: (context) => Responsive(context).maxWidthInDesktop(
maxWidth: maxDialogWidthInDesktop,
child: (contxet, maxWidth) => Dialog(
shadowColor: Colors.white,
backgroundColor: Colors.white,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
child: AspectRatio(
aspectRatio: 1 / 1,
child: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: SpinKitThreeBounce(
size: 36,
color: AppColors.primaryColor.defaultShade,
),
),
),
),
),
),
);
}
Future<void> showDatePicker(
{final Function(List<Jalali>)? onConfirm,
final Function()? onDismise,
final int? dateCounts,
final List<Jalali>? selectedDates}) async {
await showDialog(
context: context,
builder: (context) {
return Responsive(context).maxWidthInDesktop(
maxWidth: maxDialogWidthInDesktop,
child: (contxet, maxWidth) => Dialog(
surfaceTintColor: Theme.of(context).colorScheme.surface,
backgroundColor: Theme.of(context).colorScheme.surface,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: MediaQuery.sizeOf(context).width,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(16),
),
child: PersianDatePicker(
selectedDates: selectedDates,
dateCounts: dateCounts,
onConfirm: (p0) {
onConfirm?.call(p0);
context.pop();
},
onDismise: () {
onDismise?.call();
context.pop();
},
),
),
],
)),
);
},
);
}
Future<bool> showExit() async {
bool exit = false;
await showDialog(
context: context,
builder: (context) {
return Responsive(context).maxWidthInDesktop(
maxWidth: maxDialogWidthInDesktop,
child: (contxet, maxWidth) => Dialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
margin: const EdgeInsets.all(16),
width: 120,
height: 120,
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
shape: BoxShape.circle, color: AppColors.red[50]),
child: Assets.icon.gif.exit.image()),
Text(
'خروج از برنامه',
style: AppTextStyles.headline6.copyWith(
color: Theme.of(context).colorScheme.onSurface),
textAlign: TextAlign.center,
),
const SizedBox(
height: 4,
),
Text(
'میخواهید از برنامه خارج شوید؟',
style: AppTextStyles.body4.copyWith(
color: Theme.of(context).colorScheme.onSurface),
textAlign: TextAlign.center,
),
const SizedBox(
height: 16,
),
Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: LoadingButton(
width: MediaQuery.sizeOf(context).width,
radius: 32,
isOutlined: true,
color: Theme.of(context).colorScheme.secondary,
backgroundColor:
Theme.of(context).dialogTheme.backgroundColor,
onPressed: () {
exit = true;
context.pop();
},
child: Text(
'بله',
style: AppTextStyles.body4.copyWith(
color: Theme.of(context).colorScheme.secondary),
),
),
)),
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: LoadingButton(
width: MediaQuery.sizeOf(context).width,
radius: 32,
color: Theme.of(context).colorScheme.secondary,
child: Text('خیر',
style: AppTextStyles.body4
.copyWith(color: Colors.white)),
onPressed: () {
context.pop();
},
),
)),
],
)
],
),
),
),
);
},
);
return exit;
}
Future<void> showLogOut() async {
await showDialog(
context: context,
builder: (context) {
return Responsive(context).maxWidthInDesktop(
maxWidth: maxDialogWidthInDesktop,
child: (contxet, maxWidth) => Dialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
margin: const EdgeInsets.all(16),
width: 120,
height: 120,
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
shape: BoxShape.circle, color: AppColors.red[50]),
child: Assets.icon.gif.exit.image()),
Text(
'!خروج از حساب کاربری',
style: AppTextStyles.headline6.copyWith(
color: Theme.of(context).colorScheme.onSurface),
textAlign: TextAlign.center,
),
const SizedBox(
height: 4,
),
Text(
'از خروج اطمینان دارید؟',
style: AppTextStyles.body4.copyWith(
color: Theme.of(context).colorScheme.onSurface),
textAlign: TextAlign.center,
),
const SizedBox(
height: 16,
),
Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: LoadingButton(
width: MediaQuery.sizeOf(context).width,
radius: 32,
isOutlined: true,
backgroundColor:
Theme.of(context).dialogTheme.backgroundColor,
color: Theme.of(context).colorScheme.secondary,
onPressed: () {
AuthTokenStorage.clearToken();
FirebasApi.deleteToken();
context.read<UserInfoCubit>().clearUser();
contxet.go(Routes.main, extra: false);
},
child: Text(
'بله',
style: AppTextStyles.body4.copyWith(
color: Theme.of(context).colorScheme.secondary),
),
),
)),
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: LoadingButton(
width: MediaQuery.sizeOf(context).width,
radius: 32,
color: Theme.of(context).colorScheme.secondary,
child: Text('خیر',
style: AppTextStyles.body4
.copyWith(color: Colors.white)),
onPressed: () {
context.pop();
},
),
)),
],
)
],
),
),
),
);
},
);
}
Future<void> showDeleteItem(
{final String? title,
final String? description,
final Function()? onConfirm}) async {
await showDialog(
context: context,
builder: (context) {
return Responsive(context).maxWidthInDesktop(
maxWidth: maxDialogWidthInDesktop,
child: (contxet, maxWidth) => Dialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
margin: const EdgeInsets.all(16),
width: 120,
height: 120,
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
shape: BoxShape.circle, color: AppColors.red[50]),
child: Assets.icon.gif.delete.image()),
if (title != null)
Text(
title,
style: AppTextStyles.headline6.copyWith(
color: Theme.of(context).colorScheme.onSurface),
textAlign: TextAlign.center,
textDirection: TextDirection.rtl,
),
const SizedBox(
height: 4,
),
if (description != null)
Text(
description,
style: AppTextStyles.body4.copyWith(
color: Theme.of(context).colorScheme.onSurface),
textAlign: TextAlign.center,
textDirection: TextDirection.rtl,
),
const SizedBox(
height: 16,
),
Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: LoadingButton(
width: MediaQuery.sizeOf(context).width,
radius: 32,
isOutlined: true,
backgroundColor:
Theme.of(context).dialogTheme.backgroundColor,
color: Theme.of(context).colorScheme.secondary,
onPressed: () {
onConfirm?.call();
context.pop();
},
child: Text(
'بله',
style: AppTextStyles.body4.copyWith(
color: Theme.of(context).colorScheme.secondary),
),
),
)),
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: LoadingButton(
width: MediaQuery.sizeOf(context).width,
radius: 32,
color: Theme.of(context).colorScheme.secondary,
child: Text('خیر',
style: AppTextStyles.body4
.copyWith(color: Colors.white)),
onPressed: () {
context.pop();
},
),
)),
],
)
],
),
),
),
);
},
);
}
Future<void> showImageHero(
{required final String image, final bool? isUrl}) async {
final TransformationController transformationController =
TransformationController();
await showDialog(
context: context,
builder: (context) {
return Responsive(context).maxWidthInDesktop(
maxWidth: maxDialogWidthInDesktop,
child: (contxet, maxWidth) => Dialog(
insetPadding: EdgeInsets.zero,
backgroundColor: Colors.transparent,
child: SizedBox(
width: double.infinity,
height: double.infinity,
child: GestureDetector(
onTap: () => context.pop(),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: InteractiveViewer(
transformationController: transformationController,
panEnabled: true,
minScale: 0.5,
maxScale: 4,
child: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: GestureDetector(
onTap: () {},
onDoubleTapDown: (details) {
final double currentScale = transformationController
.value
.getMaxScaleOnAxis();
final double newScale =
currentScale >= 4.0 ? 1 : currentScale * 2;
final Offset tapPosition = details.localPosition;
final Matrix4 newMatrix = Matrix4.identity()
..scale(newScale)
..translate(
(newScale == 1 ? 1 : tapPosition.dx) *
(1 - newScale / currentScale),
(newScale == 1 ? 1 : tapPosition.dy) *
(1 - newScale / currentScale),
);
transformationController.value = newMatrix;
},
child: Container(
constraints: BoxConstraints(
maxWidth: MediaQuery.sizeOf(context).width * 0.8,
maxHeight: MediaQuery.sizeOf(context).width * 0.8,
),
child: isUrl ?? image.isURL()
? ImageNetwork(
url: image,
radius: 4,
)
: ClipRRect(
borderRadius: BorderRadius.circular(4),
child: CustomeImage(
src: image,
)),
),
),
),
),
),
),
),
),
),
);
},
);
}
Future<void> showVideoHero(
{required final String url, final bool? isUrl}) async {
await showDialog(
context: context,
builder: (context) {
return Responsive(context).maxWidthInDesktop(
maxWidth: maxDialogWidthInDesktop,
child: (contxet, maxWidth) => Dialog(
insetPadding: EdgeInsets.zero,
backgroundColor: Colors.transparent,
child: Stack(
children: [
SizedBox(
width: double.infinity,
height: double.infinity,
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: VideoPlayerWidget(
url: url,
)),
),
Positioned(
top: 16,
left: 16,
child: GestureDetector(
onTap: () => context.pop(),
child: Container(
width: 24,
height: 24,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: Theme.of(context).colorScheme.onSurface,
)),
child: Icon(
CupertinoIcons.xmark,
size: 18,
color: Theme.of(context).colorScheme.onSurface,
),
),
))
],
),
),
);
},
);
}
void showUpgradeCredit() async {
await showAlertDialog(
title: 'اوه نه! اعتبارت تموم شد!',
imageGif: Assets.icon.gif.oneCoin.image(),
description:
'برای ادامه ماجراجویی‌هاتون با مدل‌های هوش مصنوعی حرفه‌ای، لطفاً اشتراکتون رو ارتقا بدین!',
onConfirmText: 'ارتقای اشتراک',
onConfirm: (c) async {
c.go(Routes.purchase);
},
);
}
void showInstagramFollow({
final Function()? onConfirm,
final Function()? onCancel,
}) async {
await showAlertDialog(
title: '!هوشانو دنبال کن',
imageGif: Assets.icon.gif.instagram.image(),
description:
'اگه دنبال آخرین اخبار، آموزش‌ها، کدهای تخفیف و کلی چیز خفن دیگه هستی، حتماً ما رو تو اینستاگرام فالو کن! تازه، 20 سکه هوشانی هم هدیه می‌گیری!',
onConfirmText: 'دنبال کردن',
onCancel: (c) => context.pop(),
onConfirm: (c) async {
await launchUrl(Uri.parse('https://www.instagram.com/Houshan.ai'),
mode: LaunchMode.externalApplication)
.onError(
(error, stackTrace) {
if (kDebugMode) {
print('error open Link is: $error');
}
return false;
},
);
},
);
}
void showHeart({
final Function()? onConfirm,
final Function()? onCancel,
}) async {
// Disabled by request: do nothing
return;
}
void showEdit({
final Function()? onConfirm,
final Function()? onCancel,
}) async {
await showAlertDialog(
title: '!هوشانی شو',
imageGif: Assets.icon.gif.write.image(),
description:
'با تکمیل اطلاعات حساب کاربریت، علاوه بر اینکه 20 سکه هوشانی هدیه می‌گیری، به شکل بهینه‌تری از هوشان استفاده می‌کنی.',
onConfirmText: 'دعوت از دوستان',
onCancel: (c) => c.pop(),
onConfirm: (c) async {},
);
}
void showGift({
required final String mesasge,
final Function()? onConfirm,
final Function()? onCancel,
}) async {
await showAlertDialog(
title: 'یک هدیه ویژه شما',
imageGif: Assets.icon.gif.gift.image(),
description: mesasge,
);
}
void showWellcome({
required final String mesasge,
final Function()? onConfirm,
final Function()? onCancel,
}) async {
await showAlertDialog(
imageGif: Assets.icon.gif.bell.image(),
description: mesasge,
);
}
void showCreateSuccess({
final Function()? onConfirm,
final Function()? onCancel,
}) async {
await showAlertDialog(
onConfirm: (c) async => c.pop(),
onConfirmText: 'تایید',
imageGif: Assets.icon.gif.clock.image(),
description:
'دستیار هوش مصنوعی شما با موفقیت ساخته شد.\nاین دستیار پس از تأیید در فهرست “دستیار‌های من” نمایش داده می‌شود.',
);
}
void showCoin({required final Function() onSuccess}) async {
await showAlertDialog(
title: 'تسویه حساب',
imageGif: Assets.icon.gif.coin.image(),
child: Padding(
padding: const EdgeInsets.only(top: 16),
child: BlocProvider<SettlementCubit>(
create: (context) => SettlementCubit(),
child: BlocConsumer<SettlementCubit, SettlementState>(
listener: (context, state) async {
if (state is SettlementSuccess) {
await context.read<UserInfoCubit>().getUserInfo();
context.read<UserInfoCubit>().changeCredit(CreditModel(
credit: UserInfoCubit.userInfoModel.credit,
freeCredit: UserInfoCubit.userInfoModel.freeCredit));
}
},
builder: (context, state) {
String msg = 'خطا لحظاتی دیگر دوباره تلاش کنید';
if (state is SettlementSuccess) {
msg = state.message;
onSuccess.call();
}
if (state is SettlementFail) {
if (state.message != null) {
msg = state.message!;
}
}
return state is SettlementInitial
? Column(
children: [
Text(
'شیوه دریافت درآمد خود را انتخاب کنید.',
style: AppTextStyles.body4.copyWith(
color: Theme.of(context).colorScheme.onSurface),
textDirection: TextDirection.rtl,
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: LoadingButton(
width: double.infinity,
color: AppColors.primaryColor.defaultShade,
onPressed: () async {
context.read<SettlementCubit>().init(false);
},
child: Text(
'سکه',
style: AppTextStyles.body3
.copyWith(color: Colors.white),
),
)),
const SizedBox(
width: 8,
),
Expanded(
child: LoadingButton(
width: double.infinity,
color: AppColors.primaryColor.defaultShade,
onPressed:
UserInfoCubit.userInfoModel.cardNumber ==
null
? null
: () {
context
.read<SettlementCubit>()
.init(true);
},
child: Text(
'ریالی',
style: AppTextStyles.body3.copyWith(
color: Colors.white,
fontWeight: FontWeight.bold),
),
)),
],
),
if (UserInfoCubit.userInfoModel.cardNumber == null)
Padding(
padding: const EdgeInsets.all(4),
child: Directionality(
textDirection: TextDirection.rtl,
child: Row(
children: [
Assets.icon.outline.warning2.svg(
color: AppColors.red.defaultShade,
width: 18,
height: 18),
const SizedBox(
width: 4,
),
Flexible(
child: Text(
'برای دریافت ریالی باید شماره کارت خود را در ویرایش پروفایل اضافه کنید',
textDirection: TextDirection.rtl,
style: AppTextStyles.body6.copyWith(
color: AppColors.red.defaultShade,
fontWeight: FontWeight.bold),
),
),
],
),
),
)
],
)
: state is SettlementLoading
? SpinKitThreeBounce(
color: AppColors.primaryColor.defaultShade,
size: 32,
)
: Text(
msg,
textDirection: TextDirection.rtl,
style: AppTextStyles.body4.copyWith(
fontWeight: FontWeight.bold,
color: state is SettlementSuccess
? AppColors.green.defaultShade
: AppColors.red.defaultShade),
);
},
),
),
));
}
void showExtras() async {
await showAlertDialog(
title: '',
imageGif: Assets.icon.gif.extras.image(),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
'قبل از هر چیز لازم است بدانید که:',
style: AppTextStyles.body5.copyWith(
fontWeight: FontWeight.bold,
color: AppColors.gray[
context.read<ThemeModeCubit>().isDark() ? 600 : 900]),
textDirection: TextDirection.rtl,
),
],
),
const SizedBox(
height: 8,
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 6.0),
child: Row(
textDirection: TextDirection.rtl,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Assets.icon.outline.verify.svg(),
const SizedBox(
width: 8,
),
Expanded(
child: Text(
'دسترسی شما تاریخ انقضاء ندارد',
style: AppTextStyles.body5.copyWith(
color: AppColors.gray[
context.read<ThemeModeCubit>().isDark()
? 600
: 900]),
textDirection: TextDirection.rtl,
),
),
const SizedBox(
width: 8,
),
Assets.icon.outline.tickSquare.svg(),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 6.0),
child: Row(
textDirection: TextDirection.rtl,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Assets.icon.outline.verify.svg(),
const SizedBox(
width: 8,
),
Expanded(
child: Text(
'به همه مدل‌ها و ابزارها دسترسی دارید',
style: AppTextStyles.body5.copyWith(
color: AppColors.gray[
context.read<ThemeModeCubit>().isDark()
? 600
: 900]),
textDirection: TextDirection.rtl,
),
),
const SizedBox(
width: 8,
),
Assets.icon.outline.tickSquare.svg(),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 6.0),
child: Row(
textDirection: TextDirection.rtl,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Assets.icon.outline.verify.svg(),
const SizedBox(
width: 8,
),
Expanded(
child: Text(
'پرداخت شما ارزان و بر اساس میزان استفاده شماست',
style: AppTextStyles.body5.copyWith(
color: AppColors.gray[
context.read<ThemeModeCubit>().isDark()
? 600
: 900]),
textDirection: TextDirection.rtl,
),
),
const SizedBox(
width: 8,
),
Assets.icon.outline.tickSquare.svg(),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 6.0),
child: Row(
textDirection: TextDirection.rtl,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Assets.icon.outline.verify.svg(),
const SizedBox(
width: 8,
),
Expanded(
child: Text(
'بسته‌ی انتخابی شما بلافاصله پس از پرداخت فعال می‌شود.',
style: AppTextStyles.body5.copyWith(
color: AppColors.gray[
context.read<ThemeModeCubit>().isDark()
? 600
: 900]),
textDirection: TextDirection.rtl,
),
),
const SizedBox(
width: 8,
),
Assets.icon.outline.tickSquare.svg(),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 6.0),
child: Row(
textDirection: TextDirection.rtl,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Assets.icon.outline.verify.svg(),
const SizedBox(
width: 8,
),
Expanded(
child: Text(
'حذف تبلیغات',
style: AppTextStyles.body5.copyWith(
color: AppColors.gray[
context.read<ThemeModeCubit>().isDark()
? 600
: 900]),
textDirection: TextDirection.rtl,
),
),
const SizedBox(
width: 8,
),
Assets.icon.outline.tickSquare.svg(),
],
),
),
],
));
}
Future showAlertDialog({
final String? title,
required final Image imageGif,
final String? description,
final Widget? child,
final bool barrierDismissible = true,
final String onConfirmText = '',
final String onCancelText = 'بازگشت',
final Future Function(BuildContext contxet)? onConfirm,
final Function(BuildContext contxet)? onCancel,
}) async {
await showDialog(
context: context,
barrierDismissible: barrierDismissible,
builder: (context) {
final ValueNotifier<bool> loading = ValueNotifier(false);
return Responsive(context).maxWidthInDesktop(
maxWidth: maxDialogWidthInDesktop,
child: (contxet, maxWidth) => PopScope(
canPop: barrierDismissible,
child: Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16)),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (barrierDismissible)
Row(
children: [
GestureDetector(
onTap: () => context.pop(),
child: Container(
width: 24,
height: 24,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color:
Theme.of(context).colorScheme.onSurface,
)),
child: Icon(
CupertinoIcons.xmark,
size: 18,
color: Theme.of(context).colorScheme.onSurface,
),
),
)
],
),
Container(
width: 94,
height: 94,
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: AppColors.secondryColor[50],
shape: BoxShape.circle),
child: imageGif,
),
const SizedBox(
height: 8,
),
if (title != null)
Text(
title,
style: AppTextStyles.body3.copyWith(
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.onSurface),
textDirection: TextDirection.rtl,
),
if (description != null)
Column(
children: [
const SizedBox(
height: 8,
),
Text(
description,
style: AppTextStyles.body4.copyWith(
color: Theme.of(context).colorScheme.onSurface),
textAlign: TextAlign.center,
textDirection: TextDirection.rtl,
),
],
),
if (child != null) child,
const SizedBox(
height: 16,
),
Row(
children: [
if (onConfirm != null)
Expanded(
flex: 6,
child: ValueListenableBuilder(
valueListenable: loading,
builder: (context, l, _) {
return LoadingButton(
width: double.infinity,
loading: l,
color:
AppColors.primaryColor.defaultShade,
onPressed: () async {
loading.value = true;
await onConfirm.call(contxet);
loading.value = false;
},
child: Text(
onConfirmText,
style: AppTextStyles.body5
.copyWith(color: Colors.white),
),
);
})),
if (onConfirm != null && onCancel != null)
const SizedBox(
width: 24,
),
if (onCancel != null)
Expanded(
flex: 4,
child: LoadingButton(
width: double.infinity,
color: Theme.of(context).colorScheme.secondary,
isOutlined: true,
backgroundColor: Theme.of(context)
.dialogTheme
.backgroundColor,
onPressed: () => onCancel.call(contxet),
child: Text(
onCancelText,
style: AppTextStyles.body5.copyWith(
color: Theme.of(context)
.colorScheme
.secondary,
fontWeight: FontWeight.bold),
),
)),
],
)
],
),
),
),
),
);
},
);
}
Future showPersonsAlert() async {
final TextEditingController textEditingController = TextEditingController();
await showDialog(
context: context,
builder: (context) => Responsive(context).maxWidthInDesktop(
maxWidth: maxDialogWidthInDesktop,
child: (contxet, maxWidth) => Dialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Directionality(
textDirection: TextDirection.rtl,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
title: Text(
'جای چه شخصیتی اینجا خالیه؟',
style: AppTextStyles.body3.copyWith(
color: Theme.of(context).colorScheme.onSurface),
),
),
const SizedBox(
height: 16,
),
AuthTextField(
controller: textEditingController,
hintText: 'دوست داری با چه کسی گپ بزنی؟',
label: 'نام شخصیت مد نظر',
),
const SizedBox(
height: 32,
),
Row(
children: [
Expanded(
flex: 5,
child: LoadingButton(
onPressed: () {
contxet.pop();
},
width: double.infinity,
isOutlined: true,
backgroundColor:
Theme.of(context).dialogTheme.backgroundColor,
color: Theme.of(context).colorScheme.primary,
child: Text(
'بازگشت',
style: AppTextStyles.body4.copyWith(
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.bold),
)),
),
const SizedBox(
width: 12,
),
Expanded(
flex: 6,
child: LoadingButton(
onPressed: () {},
width: double.infinity,
child: Text(
'تایید',
style: AppTextStyles.body4.copyWith(
color: Colors.white,
fontWeight: FontWeight.bold),
)),
),
],
)
],
),
),
),
),
),
);
}
/*
Future<void> showUpgradeCredit(
{final String? title, final Function()? onConfirm}) async {
final titleString = title == null ? '' : '" $title " ';
await showDialog(
context: context,
builder: (context) {
return Dialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: CircleIconBtn(
size: 48,
icon: Assets.icon.outline.crown,
color: AppColors.red[50],
iconColor: AppColors.red[100],
iconPadding: const EdgeInsets.all(12),
),
),
Text(
'شما به هوش مصنوعی $titleStringدسترسی ندارید',
style: AppTextStyles.headline6,
textAlign: TextAlign.center,
),
const SizedBox(
height: 4,
),
Text(
'برای دسترسی، اشتراک خود را ارتقا دهید ',
style: AppTextStyles.body4,
textAlign: TextAlign.center,
),
const SizedBox(
height: 16,
),
Row(
children: [
Flexible(
flex: 3,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: LoadingButton(
width: MediaQuery.sizeOf(context).width,
radius: 32,
color: AppColors.red.defaultShade,
child: Text('ارتقای اشتراک',
style: AppTextStyles.body4
.copyWith(color: Colors.white)),
onPressed: () {
onConfirm?.call();
context.pop();
},
),
)),
Flexible(
flex: 2,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: LoadingButton(
width: MediaQuery.sizeOf(context).width,
radius: 32,
isOutlined: true,
color: AppColors.red.defaultShade,
onPressed: () {
context.pop();
},
child: Text(
'بازگشت',
style: AppTextStyles.body4
.copyWith(color: AppColors.red.defaultShade),
),
),
)),
],
)
],
),
),
);
},
);
}
Future<void> showGiftCredit({final Function()? onConfirm}) async {
await showDialog(
context: context,
builder: (context) {
return Dialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
GestureDetector(
onTap: () => context.pop(),
child: Container(
width: 24,
height: 24,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(color: AppColors.gray[900])),
child: const Icon(
CupertinoIcons.xmark,
size: 16,
),
),
),
],
),
Padding(
padding: const EdgeInsets.all(16.0),
child: CircleIconBtn(
size: 86,
icon: Assets.icon.outline.coin,
color: AppColors.secondryColor[50],
iconColor: AppColors.secondryColor.defaultShade,
iconPadding: const EdgeInsets.all(12),
),
),
Text(
'بسته اعتبار هدیه',
style: AppTextStyles.headline6,
textAlign: TextAlign.center,
),
const SizedBox(
height: 4,
),
Text(
'100 / 100',
style:
AppTextStyles.body4.copyWith(fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 32.0, vertical: 16),
child: LoadingButton(
radius: 32,
color: AppColors.primaryColor.defaultShade,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('مشاهده همه بسته‌ها',
style: AppTextStyles.body4
.copyWith(color: Colors.white)),
const SizedBox(
width: 8,
),
Assets.icon.outline.crown.svg(color: Colors.white),
],
),
onPressed: () {
onConfirm?.call();
context.pop();
},
),
),
],
),
),
);
},
);
} */
Future showPurchStatus(
{required final bool success, required final String detail}) async {
final color =
success ? AppColors.green.defaultShade : AppColors.red.defaultShade;
await showDialog(
context: context,
builder: (context) => Responsive(context).maxWidthInDesktop(
maxWidth: maxDialogWidthInDesktop,
child: (contxet, maxWidth) => Dialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 94,
height: 94,
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: success ? AppColors.green[50] : AppColors.red[50],
shape: BoxShape.circle),
child: Icon(
success ? CupertinoIcons.check_mark : CupertinoIcons.xmark,
size: 80,
color: Colors.white,
),
),
const SizedBox(
height: 8,
),
Text(
'پرداخت ${success ? 'موفق' : 'ناموفق'}',
style: AppTextStyles.body3
.copyWith(fontWeight: FontWeight.bold, color: color),
),
Column(
children: [
const SizedBox(
height: 8,
),
Text(
detail,
style: AppTextStyles.body4,
textAlign: TextAlign.center,
textDirection: TextDirection.rtl,
),
],
),
const SizedBox(
height: 16,
),
],
),
),
),
),
);
}
Future showCustomeReport() async {
await showDialog(
context: context,
builder: (context) => Responsive(context).maxWidthInDesktop(
maxWidth: maxDialogWidthInDesktop,
child: (contxet, maxWidth) => Dialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Directionality(
textDirection: TextDirection.rtl,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
title: Text(
'گزارش اشکال',
style: AppTextStyles.body2.copyWith(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.bold),
),
),
const SizedBox(
height: 12,
),
const AuthTextField(
label: 'لطفاً توضیح دهید',
minLines: 6,
maxLines: 6,
),
const SizedBox(
height: 32,
),
Row(
children: [
Expanded(
child: LoadingButton(
width: double.infinity,
onPressed: () {
context.pop();
},
child: Text(
'بازگشت',
style: AppTextStyles.body4.copyWith(
fontWeight: FontWeight.bold,
color: Colors.white),
))),
const SizedBox(
width: 24,
),
Expanded(
child: LoadingButton(
width: double.infinity,
onPressed: () {
context.pop();
context.pop();
SnackBarManager(context, id: 'report-success')
.show(
status: SnackBarStatus.success,
message: 'گزارش با موفقیت ارسال شد');
},
isOutlined: true,
color: Theme.of(context).colorScheme.primary,
backgroundColor:
Theme.of(context).dialogTheme.backgroundColor,
child: Text(
'گزارش',
style: AppTextStyles.body4.copyWith(
fontWeight: FontWeight.bold,
color:
Theme.of(context).colorScheme.primary),
))),
],
)
],
),
),
),
),
),
);
}
Future showShamsiYearMonthPicker(
{required Jalali initailDate,
required dynamic Function(Jalali selectedDate) onDateSelected}) async {
await showDialog(
context: context,
builder: (context) => Responsive(context).maxWidthInDesktop(
maxWidth: maxDialogWidthInDesktop,
child: (contxet, maxWidth) => Dialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: ShamsiYearMonthPicker(
onDateSelected: onDateSelected,
initailDate: initailDate,
),
),
),
),
);
}
Future showPrivateBots() async {
await showDialog(
context: context,
builder: (context) => Responsive(context).maxWidthInDesktop(
maxWidth: maxDialogWidthInDesktop,
child: (context, maxWidth) => Center(
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.sizeOf(context).height * 0.5),
child: Dialog(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Directionality(
textDirection: TextDirection.rtl,
child: BlocBuilder<BotsBloc, BotsState>(
builder: (context, state) {
if (state is BotsFail) {
return const SizedBox.shrink();
}
if (state is BotsSuccess) {
final privateBots = state.privateBots;
if (privateBots.isEmpty) return const SizedBox.shrink();
return Scrollbar(
thumbVisibility: true,
interactive: true,
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Column(
children: [
ListTile(
title: Text(
'مدل‌های حرفه‌ای',
style: AppTextStyles.body3
.copyWith(fontWeight: FontWeight.bold),
),
leading: Assets.icon.outline.crown.svg(
color: Theme.of(context)
.colorScheme
.onSurface),
),
ListView.builder(
itemCount: privateBots.length,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.symmetric(
horizontal: 16),
itemBuilder: (context, index) {
final bot = privateBots[index];
return InkWell(
onTap: () {
context.push(Routes.chat,
extra: ChatArgs(bot: bot));
},
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 8),
decoration: BoxDecoration(
border: index !=
privateBots.length - 1
? Border(
bottom: BorderSide(
color: AppColors
.gray[context
.read<
ThemeModeCubit>()
.isDark()
? 600
: 900]))
: null),
child: Row(
children: [
ImageNetwork(
url: bot.image,
width: 32,
height: 32,
radius: 360,
color: bot.image != null &&
bot.image!
.contains('/llm')
? Theme.of(context)
.colorScheme
.onSurface
: null,
fit: BoxFit.cover,
),
const SizedBox(
width: 8,
),
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
bot.name ?? '',
maxLines: 1,
overflow:
TextOverflow.ellipsis,
style: AppTextStyles.body4
.copyWith(
color:
Theme.of(context)
.colorScheme
.onSurface,
fontWeight:
FontWeight.bold),
),
if (bot.description != null)
Text(bot.description!,
style: AppTextStyles.body5
.copyWith(
color: AppColors
.gray[context
.read<
ThemeModeCubit>()
.isDark()
? 600
: 900]))
],
)),
const SizedBox(
width: 8,
),
Container(
padding:
const EdgeInsets.symmetric(
horizontal: 8,
vertical: 4),
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.primary,
borderRadius:
BorderRadius.circular(
16)),
child: Center(
child: Text(
bot.cost == 0 ||
bot.cost == null
? 'رایگان'
: '${bot.cost} سکه',
style: AppTextStyles.body6
.copyWith(
color: Colors.white),
),
),
)
],
),
),
);
},
),
],
),
),
);
}
return Column(
children: [
DefaultPlaceHolder(
child: ListTile(
title: Text(
'مدل‌های هوش مصنوعی حرفه‌ای',
style: AppTextStyles.body4.copyWith(
fontWeight: FontWeight.bold,
color: Theme.of(context)
.colorScheme
.onSurface),
),
leading: Assets.icon.outline.crown.svg(
color:
Theme.of(context).colorScheme.onSurface),
),
),
ListView.builder(
padding: const EdgeInsets.symmetric(horizontal: 16),
itemCount: 10,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (context, index) {
return DefaultPlaceHolder(
child: Container(
height: 32,
margin: const EdgeInsets.symmetric(vertical: 8),
decoration:
const BoxDecoration(color: Colors.white),
));
},
),
const SizedBox(
height: 16,
)
],
);
},
),
),
),
),
),
),
),
);
}
void onMusicCreate({
final Function()? onConfirm,
final Function()? onCancel,
}) async {
// Disabled by request: do nothing
return;
}
void onVideoCreate({
final Function()? onConfirm,
final Function()? onCancel,
}) async {
// Disabled by request: do nothing
return;
}
void onPhotoCreated({
final Function()? onConfirm,
final Function()? onCancel,
}) async {
// Disabled by request: do nothing
return;
}
void conditionsForCmp({required final String awards}) async {
await showDialog(
context: context,
builder: (context) => Responsive(context).maxWidthInDesktop(
maxWidth: maxDialogWidthInDesktop,
child: (contxet, maxWidth) => Dialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Directionality(
textDirection: TextDirection.rtl,
child: ListTile(
contentPadding: EdgeInsets.zero,
title: Text(
'📑 شرایط شرکت در مسابقه',
style: AppTextStyles.headline6.copyWith(
color: Theme.of(context).colorScheme.onSurface),
),
),
),
const SizedBox(
height: 16,
),
Scrollbar(
thumbVisibility: true,
trackVisibility: true,
interactive: true,
child: Directionality(
textDirection: TextDirection.rtl,
child: Container(
margin: const EdgeInsets.only(right: 8),
constraints: BoxConstraints(
maxHeight: MediaQuery.sizeOf(context).height * 0.4),
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: Html(
data: awards,
shrinkWrap: true,
onLinkTap: (url, attributes, element) async {
try {
await launchUrl(Uri.parse(url!),
mode: LaunchMode.externalApplication)
.onError(
(error, stackTrace) {
if (kDebugMode) {
print('error open Link is: $error');
}
return false;
},
);
} catch (e) {
if (kDebugMode) {
print(e);
}
}
},
style: {
'p': Style(
fontFamily: AppTextStyles.defaultFontFamily,
color:
Theme.of(context).colorScheme.onSurface,
fontSize: FontSize(16))
}),
),
),
),
),
const SizedBox(
height: 16,
),
LoadingButton(
width: double.infinity,
onPressed: () {
contxet.pop();
},
color: Theme.of(context).colorScheme.primary,
child: Text(
'بازگشت',
style: AppTextStyles.body4.copyWith(color: Colors.white),
))
],
),
),
),
),
);
}
void rewardForCmp({required final String rewards}) async {
await showDialog(
context: context,
builder: (context) => Responsive(context).maxWidthInDesktop(
maxWidth: maxDialogWidthInDesktop,
child: (contxet, maxWidth) => Dialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Directionality(
textDirection: TextDirection.rtl,
child: ListTile(
contentPadding: EdgeInsets.zero,
title: Text(
'🏆 جوایز مسابقه',
style: AppTextStyles.headline6.copyWith(
color: Theme.of(context).colorScheme.onSurface),
),
),
),
const SizedBox(
height: 16,
),
Scrollbar(
thumbVisibility: true,
trackVisibility: true,
interactive: true,
child: Directionality(
textDirection: TextDirection.rtl,
child: Container(
margin: const EdgeInsets.only(right: 8),
constraints: BoxConstraints(
maxHeight: MediaQuery.sizeOf(context).height * 0.4),
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: Html(
data: rewards,
shrinkWrap: true,
onLinkTap: (url, attributes, element) async {
try {
await launchUrl(Uri.parse(url!),
mode: LaunchMode.externalApplication)
.onError(
(error, stackTrace) {
if (kDebugMode) {
print('error open Link is: $error');
}
return false;
},
);
} catch (e) {
if (kDebugMode) {
print(e);
}
}
},
style: {
'p': Style(
fontFamily: AppTextStyles.defaultFontFamily,
color:
Theme.of(context).colorScheme.onSurface,
fontSize: FontSize(16)),
}),
),
),
)),
const SizedBox(
height: 16,
),
LoadingButton(
width: double.infinity,
onPressed: () {
contxet.pop();
},
color: Theme.of(context).colorScheme.primary,
child: Text(
'بازگشت',
style: AppTextStyles.body4.copyWith(color: Colors.white),
))
],
),
),
),
),
);
}
void winnersForCmp({required final List<Winners> winners}) async {
await showDialog(
context: context,
builder: (context) => Responsive(context).maxWidthInDesktop(
maxWidth: maxDialogWidthInDesktop,
child: (contxet, maxWidth) => Dialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Directionality(
textDirection: TextDirection.rtl,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
contentPadding: EdgeInsets.zero,
title: Text(
'✌️ نفرات برتر مسابقه',
style: AppTextStyles.headline6.copyWith(
color: Theme.of(context).colorScheme.onSurface),
),
),
const SizedBox(
height: 16,
),
ListView.builder(
itemCount: winners.length,
shrinkWrap: true,
itemBuilder: (context, index) {
final winner = winners[index];
return ListTile(
leading: const CircleAvatar(),
title: Text('${winner.rank ?? 1}',
style: AppTextStyles.body3.copyWith(
color: Theme.of(context).colorScheme.onSurface,
)),
subtitle: Text.rich(
TextSpan(text: winner.username ?? '', children: [
TextSpan(
text: 'مشاهده اثر',
style: TextStyle(
color:
Theme.of(context).colorScheme.primary))
]),
style: AppTextStyles.body4.copyWith(
color: Theme.of(context).colorScheme.onSurface),
),
);
},
),
const SizedBox(
height: 16,
),
LoadingButton(
width: double.infinity,
onPressed: () {
contxet.pop();
},
color: Theme.of(context).colorScheme.primary,
child: Text(
'بازگشت',
style:
AppTextStyles.body4.copyWith(color: Colors.white),
))
],
),
),
),
),
),
);
}
Future updateAlert(
{required final String message,
required final bool force,
required final String version}) async {
final versionStyle = AppTextStyles.body4.copyWith(
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.onSurface);
await showAlertDialog(
barrierDismissible: !force,
imageGif: Assets.icon.gif.waveHand.image(),
title: 'به روزرسانی هوشان',
onConfirmText: 'به روزرسانی',
onCancelText: force ? '' : '!الان نه',
onCancel: force ? null : (c) => context.pop(),
onConfirm: (c) async {
await launchUrl(Uri.parse('https://api.houshan.ai/apk'),
mode: LaunchMode.externalApplication)
.onError(
(error, stackTrace) {
if (kDebugMode) {
print('error open Link is: $error');
}
return false;
},
);
},
child: Column(
children: [
SizedBox(
height: 8,
),
Text(message,
textDirection: TextDirection.rtl,
textAlign: TextAlign.justify,
style: AppTextStyles.body4
.copyWith(color: Theme.of(context).colorScheme.onSurface)),
SizedBox(
height: 16,
),
Row(
children: [
Expanded(
child: Center(
child: FutureBuilder<PackageInfo>(
future: PackageInfo.fromPlatform(),
builder: (context, snapshot) {
String version = '...';
if (snapshot.hasData && snapshot.data != null) {
version = snapshot.data!.version;
}
return Text(version, style: versionStyle);
}),
)),
Text('>>>', style: versionStyle),
Expanded(
child: Center(
child: Text(version, style: versionStyle),
)),
],
)
],
));
}
}