"Updated AndroidManifest.xml, added FlutterDownloader dependency, and modified various Dart files for UI and functionality changes."

This commit is contained in:
OkaykOrhmn 2024-10-05 14:08:53 +03:30
parent 4aebc144fa
commit 7c74587785
15 changed files with 255 additions and 193 deletions

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.didvan.didvanapp"> package="com.didvan.didvanapp">
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
@ -39,6 +40,40 @@
<service android:name="es.antonborri.home_widget.HomeWidgetBackgroundService" <service android:name="es.antonborri.home_widget.HomeWidgetBackgroundService"
android:permission="android.permission.BIND_JOB_SERVICE" android:exported="true" /> android:permission="android.permission.BIND_JOB_SERVICE" android:exported="true" />
<provider
android:name="vn.hunghd.flutterdownloader.DownloadedFileProvider"
android:authorities="${applicationId}.flutter_downloader.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
<!-- Begin FlutterDownloader customization -->
<!-- disable default Initializer -->
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />
</provider>
<!-- declare customized Initializer -->
<provider
android:name="vn.hunghd.flutterdownloader.FlutterDownloaderInitializer"
android:authorities="${applicationId}.flutter-downloader-init"
android:exported="false">
<!-- changes this number to configure the maximum number of concurrent tasks -->
<meta-data
android:name="vn.hunghd.flutterdownloader.MAX_CONCURRENT_TASKS"
android:value="5" />
</provider>
<!-- End FlutterDownloader customization -->
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"

View File

@ -26,6 +26,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:home_widget/home_widget.dart'; import 'package:home_widget/home_widget.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_downloader/flutter_downloader.dart';
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
@ -66,6 +67,12 @@ void main() async {
HomeWidget.registerBackgroundCallback(_backgroundCallbackHomeWidget); HomeWidget.registerBackgroundCallback(_backgroundCallbackHomeWidget);
HomeWidget.registerInteractivityCallback(_backgroundCallbackHomeWidget); HomeWidget.registerInteractivityCallback(_backgroundCallbackHomeWidget);
await NotificationService.initializeNotification(); await NotificationService.initializeNotification();
await FlutterDownloader.initialize(
debug:
true, // optional: set to false to disable printing logs to console (default: true)
ignoreSsl:
true // option: set to false to disable working with http links (default: false)
);
} }
// FirebaseMessaging.onBackgroundMessage(_initPushNotification); // FirebaseMessaging.onBackgroundMessage(_initPushNotification);

View File

@ -11,13 +11,14 @@ import 'package:didvan/services/storage/storage.dart';
import 'package:didvan/utils/action_sheet.dart'; import 'package:didvan/utils/action_sheet.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_downloader/flutter_downloader.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:just_audio/just_audio.dart'; import 'package:just_audio/just_audio.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:http/http.dart' as http; import 'package:permission_handler/permission_handler.dart';
import 'package:universal_html/html.dart' as html; import 'package:universal_html/html.dart' as html;
class MediaService { class MediaService {
@ -148,8 +149,8 @@ class MediaService {
} }
} }
static Future<String?> downloadFile(String url) async { static Future<String?> downloadFile(String url, {final String? name}) async {
final basename = p.basename(url).split('?accessToken=').first; final basename = name ?? p.basename(url).split('?accessToken=').first;
Directory? dir; Directory? dir;
try { try {
if (Platform.isIOS) { if (Platform.isIOS) {
@ -163,20 +164,26 @@ class MediaService {
print("Cannot get download folder path $err"); print("Cannot get download folder path $err");
} }
} }
String path = "${dir?.path}${Platform.isIOS ? '/' : ''}$basename"; String path = "${dir?.path}${Platform.isIOS ? '/' : ''}";
final status = await Permission.storage.request();
File file = File(path); if (status.isGranted) {
try { try {
final http.Response audioResponse = await http.get(Uri.parse(url)); await FlutterDownloader.enqueue(
final bytes = audioResponse.bodyBytes; url: url,
file.writeAsBytes(bytes); savedDir: path,
fileName: basename,
showNotification: true,
openFileFromNotification: true,
);
} catch (e) { } catch (e) {
if (kDebugMode) { if (kDebugMode) {
print("Exception$e"); print("Exception$e");
} }
return null; return null;
} }
} else {
return null;
}
return path; return path;
} }

View File

@ -261,7 +261,7 @@ class _AiState extends State<Ai> {
const Padding( const Padding(
padding: EdgeInsets.fromLTRB(8, 8, 8, 4), padding: EdgeInsets.fromLTRB(8, 8, 8, 4),
child: DidvanText( child: DidvanText(
'مدل‌های هوش مصنوعی می‌توانند اشتباه کنند، صحت اطلاعات مهم را بررسی کنید و از وارد کردن اطلاعات حساس بپرهیزید.', 'مدل‌های هوش مصنوعی می‌توانند اشتباه کنند، صحت اطلاعات مهم را بررسی کنید.',
fontSize: 12, fontSize: 12,
), ),
) )

View File

@ -261,8 +261,6 @@ class _AiChatPageState extends State<AiChatPage> {
style: style:
ButtonStyleMode.primary, ButtonStyleMode.primary,
onPressed: () async { onPressed: () async {
final state = context
.read<AiChatState>();
await state await state
.changePlaceHolder( .changePlaceHolder(
placeholder.text); placeholder.text);
@ -688,25 +686,12 @@ class _AiChatPageState extends State<AiChatPage> {
onTap: () async { onTap: () async {
final url = final url =
'${RequestHelper.baseUrl + message.file.toString()}?accessToken=${RequestService.token}'; '${RequestHelper.baseUrl + message.file.toString()}?accessToken=${RequestService.token}';
final download = kIsWeb kIsWeb
? MediaService ? MediaService
.downloadFileFromWeb(url) .downloadFileFromWeb(url)
: await MediaService.downloadFile( : await MediaService.downloadFile(
url); url,
AlertData alertData = AlertData( name: message.fileName);
message: 'دانلود موفقیت آمیز بود',
aLertType: ALertType.success);
if (download == null) {
alertData = AlertData(
message:
'دانلود موفقیت آمیز نبود',
aLertType: ALertType.error);
}
Future.delayed(
Duration.zero,
() => ActionSheetUtils(context)
.showAlert(alertData),
);
}, },
child: Icon( child: Icon(
DidvanIcons.download_solid, DidvanIcons.download_solid,

View File

@ -3,6 +3,7 @@
import 'dart:async'; import 'dart:async';
import 'package:cached_network_image/cached_network_image.dart'; import 'package:cached_network_image/cached_network_image.dart';
import 'package:didvan/config/design_config.dart';
import 'package:didvan/config/theme_data.dart'; import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart'; import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/constants/assets.dart'; import 'package:didvan/constants/assets.dart';
@ -184,14 +185,21 @@ class _HistoryAiChatPageState extends State<HistoryAiChatPage> {
style: TextStyle( style: TextStyle(
color: Theme.of(context) color: Theme.of(context)
.colorScheme .colorScheme
.text), .text,
fontFamily:
DesignConfig.fontFamily),
children: [ children: [
TextSpan( TextSpan(
text: "\"${chat.title}\"", text: "\"${chat.title}\"",
style: const TextStyle( style: TextStyle(
fontFamily: DesignConfig
.fontFamily,
fontWeight: fontWeight:
FontWeight.bold)), FontWeight.bold)),
const TextSpan( TextSpan(
style: TextStyle(
fontFamily: DesignConfig
.fontFamily),
text: text:
' با هوشان اطمینان دارید؟ '), ' با هوشان اطمینان دارید؟ '),
]), ]),
@ -371,6 +379,9 @@ class _HistoryAiChatPageState extends State<HistoryAiChatPage> {
// fontWeight: FontWeight.bold, // fontWeight: FontWeight.bold,
// fontSize: 16, // fontSize: 16,
), ),
if (chat.prompts != null &&
chat.prompts!.isNotEmpty &&
chat.prompts![0].text != null)
DidvanText( DidvanText(
chat.prompts![0].text.toString(), chat.prompts![0].text.toString(),
maxLines: 1, maxLines: 1,

View File

@ -296,7 +296,7 @@ class _AiMessageBarState extends State<AiMessageBar> {
? const Padding( ? const Padding(
padding: EdgeInsets.fromLTRB(8, 8, 8, 4), padding: EdgeInsets.fromLTRB(8, 8, 8, 4),
child: DidvanText( child: DidvanText(
'مدل‌های هوش مصنوعی می‌توانند اشتباه کنند، صحت اطلاعات مهم را بررسی کنید و از وارد کردن اطلاعات حساس بپرهیزید.', 'مدل‌های هوش مصنوعی می‌توانند اشتباه کنند، صحت اطلاعات مهم را بررسی کنید.',
fontSize: 12, fontSize: 12,
), ),
) )
@ -680,10 +680,11 @@ class _AiMessageBarState extends State<AiMessageBar> {
MediaService.onLoadingPickFile(context); MediaService.onLoadingPickFile(context);
FilePickerResult? result = await MediaService.pickPdfFile(); FilePickerResult? result = await MediaService.pickPdfFile();
if (result != null) { if (result != null) {
String? name = result.files.first.name;
if (kIsWeb) { if (kIsWeb) {
Uint8List? bytes = Uint8List? bytes =
result.files.first.bytes; // Access the bytes property result.files.first.bytes; // Access the bytes property
String? name = result.files.first.name;
// Store bytes and file name directly in your state or model // Store bytes and file name directly in your state or model
state.file = FilesModel( state.file = FilesModel(
@ -695,7 +696,7 @@ class _AiMessageBarState extends State<AiMessageBar> {
); );
} else { } else {
state.file = FilesModel(result.files.single.path!, state.file = FilesModel(result.files.single.path!,
audio: false, image: false); audio: false, image: false, name: name);
} }
} }
Future.delayed( Future.delayed(
@ -752,7 +753,8 @@ class _AiMessageBarState extends State<AiMessageBar> {
state.file = kIsWeb state.file = kIsWeb
? FilesModel(pickedFile.path, ? FilesModel(pickedFile.path,
name: pickedFile.name, image: true, audio: false) name: pickedFile.name, image: true, audio: false)
: FilesModel(file!.path, image: true, audio: false); : FilesModel(file!.path,
name: pickedFile.name, image: true, audio: false);
await Future.delayed( await Future.delayed(
Duration.zero, Duration.zero,
() => ActionSheetUtils(context).pop(), () => ActionSheetUtils(context).pop(),
@ -773,10 +775,11 @@ class _AiMessageBarState extends State<AiMessageBar> {
FilePickerResult? result = await MediaService.pickAudioFile(); FilePickerResult? result = await MediaService.pickAudioFile();
if (result != null) { if (result != null) {
String? name = result.files.first.name;
if (kIsWeb) { if (kIsWeb) {
Uint8List? bytes = Uint8List? bytes =
result.files.first.bytes; // Access the bytes property result.files.first.bytes; // Access the bytes property
String? name = result.files.first.name;
final blob = html.Blob([bytes]); final blob = html.Blob([bytes]);
final blobUrl = html.Url.createObjectUrlFromBlob(blob); final blobUrl = html.Url.createObjectUrlFromBlob(blob);
@ -790,7 +793,7 @@ class _AiMessageBarState extends State<AiMessageBar> {
); );
} else { } else {
state.file = FilesModel(result.files.single.path!, state.file = FilesModel(result.files.single.path!,
audio: true, image: false); name: name, audio: true, image: false);
} }
} }
await Future.delayed( await Future.delayed(

View File

@ -561,7 +561,7 @@ class _AiMessageBarIOSState extends State<AiMessageBarIOS> {
? const Padding( ? const Padding(
padding: EdgeInsets.fromLTRB(8, 8, 8, 4), padding: EdgeInsets.fromLTRB(8, 8, 8, 4),
child: DidvanText( child: DidvanText(
'مدل‌های هوش مصنوعی می‌توانند اشتباه کنند، صحت اطلاعات مهم را بررسی کنید و از وارد کردن اطلاعات حساس بپرهیزید.', 'مدل‌های هوش مصنوعی می‌توانند اشتباه کنند، صحت اطلاعات مهم را بررسی کنید.',
fontSize: 12, fontSize: 12,
), ),
) )

View File

@ -1,4 +1,3 @@
import 'package:didvan/services/app_initalizer.dart';
import 'package:didvan/views/authentication/authentication_state.dart'; import 'package:didvan/views/authentication/authentication_state.dart';
import 'package:didvan/views/authentication/widgets/authentication_layout.dart'; import 'package:didvan/views/authentication/widgets/authentication_layout.dart';
import 'package:didvan/views/widgets/didvan/button.dart'; import 'package:didvan/views/widgets/didvan/button.dart';
@ -7,6 +6,7 @@ import 'package:didvan/views/widgets/didvan/text_field.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher_string.dart';
// import 'package:url_launcher/url_launcher.dart'; // import 'package:url_launcher/url_launcher.dart';
class UsernameInput extends StatefulWidget { class UsernameInput extends StatefulWidget {
@ -79,10 +79,9 @@ class _UsernameInputState extends State<UsernameInput> {
.bodySmall! .bodySmall!
.copyWith(color: Theme.of(context).colorScheme.primary), .copyWith(color: Theme.of(context).colorScheme.primary),
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = () => AppInitializer.openWebLink( ..onTap = () => launchUrlString(
context,
'https://didvan.com/terms-of-use#conditions', 'https://didvan.com/terms-of-use#conditions',
), mode: LaunchMode.inAppWebView),
), ),
const TextSpan(text: 'و\n'), const TextSpan(text: 'و\n'),
TextSpan( TextSpan(
@ -92,10 +91,9 @@ class _UsernameInputState extends State<UsernameInput> {
.bodySmall! .bodySmall!
.copyWith(color: Theme.of(context).colorScheme.primary), .copyWith(color: Theme.of(context).colorScheme.primary),
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = () => AppInitializer.openWebLink( ..onTap = () => launchUrlString(
context,
'https://didvan.com/terms-of-use#privacy', 'https://didvan.com/terms-of-use#privacy',
), mode: LaunchMode.inAppWebView),
), ),
const TextSpan(text: 'را می‌پذیرم'), const TextSpan(text: 'را می‌پذیرم'),
], ],

View File

@ -259,8 +259,7 @@ class DirectState extends CoreProvier {
} }
text = null; text = null;
replyRadar = null;
replyNews = null;
notifyListeners(); notifyListeners();
final service = final service =
@ -271,7 +270,11 @@ class DirectState extends CoreProvier {
if (service.isSuccess) { if (service.isSuccess) {
final message = service.result['message']; final message = service.result['message'];
messages.insert(0, MessageData.fromJson(message));
messages.insert(
0,
MessageData.fromJson(message)
.copyWith(news: replyNews, radar: replyRadar));
dailyMessages.clear(); dailyMessages.clear();
@ -303,8 +306,10 @@ class DirectState extends CoreProvier {
_addToDailyGrouped(messages[i]); _addToDailyGrouped(messages[i]);
} }
} }
path = null;
} }
path = null;
replyRadar = null;
replyNews = null;
notifyListeners(); notifyListeners();
} }
} }

View File

@ -315,43 +315,19 @@ class _HomeState extends State<Home>
// height: 12, // height: 12,
// ), // ),
Expanded( Expanded(
child: state.chats.isEmpty child: state.loadingdeleteAll ||
? Padding( state.appState == AppState.busy
padding:
const EdgeInsets.all(12.0),
child: Column(
children: [
SvgPicture.asset(
Assets.emptyResult,
height: MediaQuery.sizeOf(
context)
.height /
10,
),
const DidvanText(
'لیست خالی است',
fontSize: 14,
fontWeight: FontWeight.bold,
)
],
),
)
: state.loadingdeleteAll ||
state.appState ==
AppState.busy
? ListView.builder( ? ListView.builder(
shrinkWrap: true, shrinkWrap: true,
itemCount: 10, itemCount: 10,
padding: const EdgeInsets padding:
.symmetric( const EdgeInsets.symmetric(
horizontal: 12), horizontal: 12),
physics: physics:
const NeverScrollableScrollPhysics(), const NeverScrollableScrollPhysics(),
itemBuilder: itemBuilder: (context, index) {
(context, index) {
return const Padding( return const Padding(
padding: padding: EdgeInsets.symmetric(
EdgeInsets.symmetric(
vertical: 12.0), vertical: 12.0),
child: Row( child: Row(
crossAxisAlignment: crossAxisAlignment:
@ -387,6 +363,29 @@ class _HomeState extends State<Home>
); );
}, },
) )
: state.chats.isEmpty
? Padding(
padding: const EdgeInsets.all(
12.0),
child: Column(
children: [
SvgPicture.asset(
Assets.emptyResult,
height:
MediaQuery.sizeOf(
context)
.height /
10,
),
const DidvanText(
'لیست خالی است',
fontSize: 14,
fontWeight:
FontWeight.bold,
)
],
),
)
: ListView.builder( : ListView.builder(
shrinkWrap: true, shrinkWrap: true,
itemCount: state.chats.length, itemCount: state.chats.length,
@ -542,19 +541,7 @@ class _HomeState extends State<Home>
width: 12, width: 12,
), ),
Expanded( Expanded(
child: chat.isEditing != null && chat.isEditing! child: Text(
? TextFormField(
controller: title,
style: const TextStyle(fontSize: 12),
textAlignVertical: TextAlignVertical.bottom,
maxLines: 1,
decoration: const InputDecoration(
isDense: true,
contentPadding:
EdgeInsets.symmetric(vertical: 5, horizontal: 10),
border: OutlineInputBorder(),
))
: Text(
chat.title.toString(), chat.title.toString(),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 1, maxLines: 1,
@ -565,15 +552,25 @@ class _HomeState extends State<Home>
), ),
Row( Row(
children: [ children: [
chat.isEditing != null && InkWell(
chat.isEditing! &&
state.loadingchangeTitle
? const SizedBox(
width: 12,
height: 12,
child: CircularProgressIndicator())
: InkWell(
onTap: () async { onTap: () async {
ActionSheetUtils(context).openDialog(
data: ActionSheetData(
content: Center(
child: TextFormField(
controller: title,
style: const TextStyle(fontSize: 12),
textAlignVertical: TextAlignVertical.bottom,
maxLines: 3,
decoration: const InputDecoration(
isDense: true,
contentPadding: EdgeInsets.symmetric(
vertical: 5, horizontal: 10),
border: OutlineInputBorder(),
)),
),
title: 'تغییر نام',
onConfirmed: () async {
if (title.text.isNotEmpty) { if (title.text.isNotEmpty) {
await state.changeNameChat( await state.changeNameChat(
chat.id!, index, title.text, chat.id!, index, title.text,
@ -585,19 +582,21 @@ class _HomeState extends State<Home>
state.update(); state.update();
return; return;
} }
chat.isEditing = true;
state.update(); state.update();
}, },
));
},
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Icon( child: Icon(
chat.isEditing != null && chat.isEditing! Icons.edit_outlined,
? Icons.save size: 20,
: Icons.edit_outlined, ),
size: 18,
), ),
), ),
const SizedBox( const SizedBox(
width: 8, width: 4,
), ),
PopupMenuButton( PopupMenuButton(
onSelected: (value) async { onSelected: (value) async {
@ -621,22 +620,25 @@ class _HomeState extends State<Home>
value: 'حذف پیام', value: 'حذف پیام',
icon: DidvanIcons.trash_regular, icon: DidvanIcons.trash_regular,
color: Theme.of(context).colorScheme.error, color: Theme.of(context).colorScheme.error,
height: 24, height: 32,
size: 12), size: 16),
ActionSheetUtils.popUpBtns( ActionSheetUtils.popUpBtns(
value: 'آرشیو', value: 'آرشیو',
icon: Icons.folder_copy, icon: Icons.folder_copy,
height: 24, height: 32,
size: 12, size: 16,
), ),
]; ];
}, },
offset: const Offset(0, 0), offset: const Offset(0, 0),
position: PopupMenuPosition.under, position: PopupMenuPosition.under,
useRootNavigator: true, useRootNavigator: true,
child: const Icon( child: const Padding(
padding: EdgeInsets.all(8.0),
child: Icon(
Icons.more_vert, Icons.more_vert,
size: 18, size: 20,
),
), ),
), ),
], ],

View File

@ -93,7 +93,7 @@ class _EditProfileState extends State<EditProfile> {
Padding( Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0), padding: const EdgeInsets.symmetric(vertical: 8.0),
child: DidvanText( child: DidvanText(
'نام کاربری می‌تواند شامل کاراکترهای کوچک و بزرگ انگلیسی و اعداد باشد.', 'نام کاربری می‌تواند شامل کاراکترهای انگلیسی و اعداد باشد.',
style: Theme.of(context).textTheme.labelSmall, style: Theme.of(context).textTheme.labelSmall,
), ),
), ),

View File

@ -7,7 +7,6 @@ import 'package:didvan/models/view/app_bar_data.dart';
import 'package:didvan/providers/theme.dart'; import 'package:didvan/providers/theme.dart';
import 'package:didvan/providers/user.dart'; import 'package:didvan/providers/user.dart';
import 'package:didvan/routes/routes.dart'; import 'package:didvan/routes/routes.dart';
import 'package:didvan/services/app_initalizer.dart';
import 'package:didvan/services/storage/storage.dart'; import 'package:didvan/services/storage/storage.dart';
import 'package:didvan/utils/action_sheet.dart'; import 'package:didvan/utils/action_sheet.dart';
import 'package:didvan/views/profile/general_settings/settings_state.dart'; import 'package:didvan/views/profile/general_settings/settings_state.dart';
@ -23,6 +22,7 @@ import 'package:didvan/views/widgets/state_handlers/state_handler.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher_string.dart';
class ProfilePage extends StatefulWidget { class ProfilePage extends StatefulWidget {
const ProfilePage({Key? key}) : super(key: key); const ProfilePage({Key? key}) : super(key: key);
@ -221,8 +221,9 @@ class _ProfilePageState extends State<ProfilePage> {
MenuOption( MenuOption(
icon: DidvanIcons.info_circle_regular, icon: DidvanIcons.info_circle_regular,
title: 'معرفی دیدوان', title: 'معرفی دیدوان',
onTap: () => AppInitializer.openWebLink( onTap: () => launchUrlString(
context, 'https://didvan.com/#info'), 'https://didvan.com/#info',
mode: LaunchMode.inAppWebView),
), ),
const DidvanDivider(), const DidvanDivider(),
MenuOption( MenuOption(
@ -338,10 +339,9 @@ class _ProfilePageState extends State<ProfilePage> {
MenuOption( MenuOption(
icon: DidvanIcons.alert_regular, icon: DidvanIcons.alert_regular,
title: 'حریم خصوصی', title: 'حریم خصوصی',
onTap: () => AppInitializer.openWebLink( onTap: () => launchUrlString(
context,
'https://didvan.com/terms-of-use#privacy', 'https://didvan.com/terms-of-use#privacy',
), mode: LaunchMode.inAppWebView),
), ),
], ],
), ),

View File

@ -406,6 +406,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.3.1" version: "3.3.1"
flutter_downloader:
dependency: "direct main"
description:
name: flutter_downloader
sha256: b6da5495b6258aa7c243d0f0a5281e3430b385bccac11cc508f981e653b25aa6
url: "https://pub.dev"
source: hosted
version: "1.11.8"
flutter_html: flutter_html:
dependency: "direct main" dependency: "direct main"
description: description:

View File

@ -103,6 +103,7 @@ dependencies:
js: any js: any
flutter_sound_platform_interface: any flutter_sound_platform_interface: any
flutter_downloader: ^1.11.8
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter