fixed story index bug
This commit is contained in:
parent
283938d759
commit
5f02802ad1
|
|
@ -17,6 +17,7 @@
|
|||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="Didvan"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
|
||||
android:usesCleartextTraffic="true">
|
||||
<receiver
|
||||
android:name=".FavWidget"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ class MainPageBannerType {
|
|||
|
||||
factory MainPageBannerType.fromJson(Map<String, dynamic> json) {
|
||||
return MainPageBannerType(
|
||||
// fix if it null
|
||||
image: json['image'] ?? '',
|
||||
link: json['link'],
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
|
||||
class MainPageContentType {
|
||||
final int id;
|
||||
final String title;
|
||||
final String image;
|
||||
final String link;
|
||||
bool marked;
|
||||
bool isViewed;
|
||||
final List<String> subtitles;
|
||||
final int? duration;
|
||||
|
||||
|
|
@ -13,6 +15,7 @@ class MainPageContentType {
|
|||
required this.image,
|
||||
required this.link,
|
||||
required this.marked,
|
||||
required this.isViewed,
|
||||
required this.subtitles,
|
||||
this.duration,
|
||||
});
|
||||
|
|
@ -24,6 +27,7 @@ class MainPageContentType {
|
|||
image: json['image'],
|
||||
link: json['link'],
|
||||
marked: json['marked'],
|
||||
isViewed: json['isViewed'] ?? false,
|
||||
subtitles: List<String>.from(json['subtitles']),
|
||||
duration: json['duration'],
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
|
||||
class SliderData {
|
||||
final int id;
|
||||
final String title;
|
||||
final String image;
|
||||
final String link;
|
||||
|
||||
final bool isViewed;
|
||||
const SliderData({
|
||||
required this.id,
|
||||
required this.title,
|
||||
required this.image,
|
||||
required this.link,
|
||||
required this.isViewed,
|
||||
});
|
||||
|
||||
factory SliderData.fromJson(Map<String, dynamic> json) => SliderData(
|
||||
|
|
@ -16,11 +18,14 @@ class SliderData {
|
|||
title: json['title'],
|
||||
image: json['image'],
|
||||
link: json['link'],
|
||||
isViewed: json['isViewed'] ?? false,
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'title': title,
|
||||
'image': image,
|
||||
'link': link,
|
||||
'isViewed': isViewed,
|
||||
};
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
// ignore_for_file: avoid_print
|
||||
|
||||
import 'package:didvan/models/ai/ai_chat_args.dart';
|
||||
import 'package:didvan/models/story_model.dart';
|
||||
import 'package:didvan/views/ai/ai_chat_page.dart';
|
||||
|
|
@ -494,6 +496,7 @@ class RouteGenerator {
|
|||
textScaler: const TextScaler.linear(1.0),
|
||||
),
|
||||
child: Container(
|
||||
// ignore: deprecated_member_use
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
alignment: Alignment.center,
|
||||
child: AspectRatio(aspectRatio: 9 / 16, child: page),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// ignore_for_file: depend_on_referenced_packages, avoid_web_libraries_in_flutter
|
||||
// ignore_for_file: depend_on_referenced_packages, avoid_web_libraries_in_flutter, avoid_print
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:didvan/constants/assets.dart';
|
||||
import 'package:didvan/models/requests/studio.dart';
|
||||
import 'package:didvan/models/studio_details_data.dart';
|
||||
|
|
@ -9,7 +10,6 @@ import 'package:didvan/services/network/request.dart';
|
|||
import 'package:didvan/services/network/request_helper.dart';
|
||||
import 'package:didvan/services/storage/storage.dart';
|
||||
import 'package:didvan/utils/action_sheet.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_downloader/flutter_downloader.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
|
@ -90,17 +90,7 @@ class MediaService {
|
|||
}
|
||||
}
|
||||
await audioPlayer.play();
|
||||
// await audioPlayer.open(
|
||||
// audio,
|
||||
// showNotification: !isVoiceMessage,
|
||||
// notificationSettings: NotificationSettings(
|
||||
// customStopAction: (_) => resetAudioPlayer(),
|
||||
// customNextAction: (_) => onTrackChanged?.call(true),
|
||||
// customPrevAction: (_) => onTrackChanged?.call(false),
|
||||
// ),
|
||||
// );
|
||||
} catch (e) {
|
||||
// resetAudioPlayer();
|
||||
// rethrow;
|
||||
}
|
||||
}
|
||||
|
|
@ -133,7 +123,6 @@ class MediaService {
|
|||
return result;
|
||||
} catch (e) {
|
||||
e.printError(info: 'Pick PDF Fail');
|
||||
// navigatorKey.currentState!.pop();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -143,30 +132,11 @@ class MediaService {
|
|||
return await FilePicker.platform
|
||||
.pickFiles(
|
||||
type: FileType.any,
|
||||
// allowedExtensions: [
|
||||
// 'pdf',
|
||||
// 'doc',
|
||||
// 'docx',
|
||||
// 'xls',
|
||||
// 'xlsx',
|
||||
// 'ppt',
|
||||
// 'pptx',
|
||||
// 'txt',
|
||||
// 'mp3',
|
||||
// 'wav',
|
||||
// 'aac',
|
||||
// 'ogg',
|
||||
// 'flac'
|
||||
// ], // You can specify allowed extensions if needed
|
||||
allowMultiple: true,
|
||||
// Note: The maxFiles parameter is not directly supported by FilePicker.
|
||||
// You will need to handle the limit after selection if necessary.
|
||||
)
|
||||
.then((result) {
|
||||
if (result != null && result.files.length > 3) {
|
||||
// Handle the case where the selected files exceed the max limit
|
||||
// You can show an error message or return null
|
||||
return null; // or show a message to the user
|
||||
return null;
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
|
@ -189,47 +159,75 @@ class MediaService {
|
|||
}
|
||||
|
||||
static Future<String?> downloadFile(String url, {final String? name}) async {
|
||||
debugPrint("Attempting to download file from URL: $url");
|
||||
final basename = name ?? p.basename(url).split('?accessToken=').first;
|
||||
Directory? dir;
|
||||
try {
|
||||
if (Platform.isIOS) {
|
||||
dir = await getApplicationDocumentsDirectory(); // for iOS
|
||||
} else {
|
||||
dir = Directory('/storage/emulated/0/Download/'); // for android
|
||||
if (!await dir.exists()) dir = (await getExternalStorageDirectory())!;
|
||||
}
|
||||
} catch (err) {
|
||||
if (kDebugMode) {
|
||||
print("Cannot get download folder path $err");
|
||||
}
|
||||
}
|
||||
String path = "${dir?.path}${Platform.isIOS ? '/' : ''}";
|
||||
final status = await Permission.storage.request();
|
||||
if (status.isGranted) {
|
||||
try {
|
||||
await FlutterDownloader.enqueue(
|
||||
url: url,
|
||||
savedDir: path,
|
||||
fileName: basename,
|
||||
showNotification: true,
|
||||
openFileFromNotification: true,
|
||||
);
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
print("Exception$e");
|
||||
|
||||
PermissionStatus status;
|
||||
if (Platform.isAndroid) {
|
||||
final androidInfo = await DeviceInfoPlugin().androidInfo;
|
||||
if (androidInfo.version.sdkInt >= 33) {
|
||||
debugPrint("Android 13+ detected. Requesting Photos permission.");
|
||||
status = await Permission.photos.request();
|
||||
} else {
|
||||
debugPrint("Older Android version detected. Requesting Storage permission.");
|
||||
status = await Permission.storage.request();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
} else if (Platform.isIOS) {
|
||||
debugPrint("iOS detected. Requesting Photos permission.");
|
||||
status = await Permission.photos.request();
|
||||
} else {
|
||||
return null;
|
||||
status = PermissionStatus.granted;
|
||||
}
|
||||
|
||||
return path;
|
||||
debugPrint("Permission status after request: $status");
|
||||
|
||||
if (status.isGranted) {
|
||||
Directory? dir;
|
||||
try {
|
||||
if (Platform.isIOS) {
|
||||
dir = await getApplicationDocumentsDirectory();
|
||||
} else {
|
||||
dir = await getExternalStorageDirectory();
|
||||
}
|
||||
|
||||
if (dir == null) {
|
||||
debugPrint("Error: Could not determine download directory.");
|
||||
return null;
|
||||
}
|
||||
|
||||
final path = dir.path;
|
||||
debugPrint("Download directory determined: $path");
|
||||
|
||||
final taskId = await FlutterDownloader.enqueue(
|
||||
url: url,
|
||||
savedDir: path,
|
||||
fileName: basename,
|
||||
showNotification: true,
|
||||
openFileFromNotification: true,
|
||||
saveInPublicStorage: true,
|
||||
);
|
||||
debugPrint("Download successfully enqueued with taskId: $taskId");
|
||||
return path;
|
||||
|
||||
} catch (e) {
|
||||
debugPrint("Error during download process: $e");
|
||||
return null;
|
||||
}
|
||||
} else if (status.isPermanentlyDenied) {
|
||||
debugPrint("Storage permission is permanently denied. Opening app settings.");
|
||||
await openAppSettings();
|
||||
return null;
|
||||
} else {
|
||||
debugPrint("Storage permission was denied.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static String downloadFileFromWeb(String url) {
|
||||
final filename = url.split('/').last.split('?').first;
|
||||
html.AnchorElement anchorElement = html.AnchorElement(href: url);
|
||||
anchorElement.download = url;
|
||||
anchorElement.download = filename;
|
||||
anchorElement.click();
|
||||
return anchorElement.pathname!;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import 'package:didvan/models/requests/studio.dart';
|
|||
|
||||
class RequestHelper {
|
||||
static const String baseUrl = 'https://api.didvan.app';
|
||||
static const String baseUrl2 = 'http://opportunity-threat.didvan.com';
|
||||
static const String baseUrl2 = 'https://opportunity-threat.didvan.com';
|
||||
static const String storiesV1 = '$baseUrl2/api/v1/stories';
|
||||
static const String storyActivity = '$baseUrl2/api/v1/stories/activity';
|
||||
static const String _baseUserUrl = '$baseUrl/user';
|
||||
|
|
@ -20,7 +20,7 @@ class RequestHelper {
|
|||
static const String _baseHomeUrl = '$baseUrl/home';
|
||||
static const String _baseNewStats = '$baseUrl/home/statistic';
|
||||
static const String _baseNewStatsSearch = '$baseUrl/home/statistic/search';
|
||||
static const String checkHasPassword = '$_baseUserUrl/checkHasPassword';
|
||||
static const String checkHasPassword = '$_baseUserUrl/checkHasPassword';
|
||||
|
||||
static const String mainPageContent = _baseHomeUrl;
|
||||
static String searchAll({
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
// ignore_for_file: avoid_print
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:didvan/models/note.dart';
|
||||
import 'package:didvan/services/network/request.dart';
|
||||
import 'package:didvan/services/network/request_helper.dart';
|
||||
// ignore: library_prefixes
|
||||
import 'package:http/http.dart' as RequestServices;
|
||||
|
||||
class NoteService {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// ignore_for_file: avoid_print
|
||||
|
||||
import 'dart:convert';
|
||||
import 'package:didvan/models/home_page_content/swot.dart';
|
||||
import 'package:didvan/services/network/request.dart';
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// ignore_for_file: avoid_print
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class NativeWebViewLauncher {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
const Ai({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
// ignore: library_private_types_in_public_api
|
||||
_AiState createState() => _AiState();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
// lib/views/ai/ai_chat_page.dart
|
||||
|
||||
// ignore_for_file: library_private_types_in_public_api, deprecated_member_use, depend_on_referenced_packages, unnecessary_import
|
||||
|
||||
import 'dart:io' show Platform;
|
||||
import 'package:didvan/views/widgets/state_handlers/state_handler.dart';
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
|
||||
|
|
@ -599,27 +596,26 @@ class _AiChatPageState extends State<AiChatPage> {
|
|||
),
|
||||
),
|
||||
if (message.file != null && !kIsWeb)
|
||||
!Platform.isIOS
|
||||
? Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
final url =
|
||||
'${RequestHelper.baseUrl + message.file.toString()}?accessToken=${RequestService.token}';
|
||||
await MediaService.downloadFile(
|
||||
url,
|
||||
name: message.fileName);
|
||||
},
|
||||
child: Icon(
|
||||
DidvanIcons.download_solid,
|
||||
size: 18,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.focusedBorder,
|
||||
),
|
||||
),
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
debugPrint(
|
||||
"Download button tapped on iOS");
|
||||
final url =
|
||||
'${RequestHelper.baseUrl + message.file.toString()}?accessToken=${RequestService.token}';
|
||||
await MediaService.downloadFile(url,
|
||||
name: message.fileName);
|
||||
},
|
||||
child: Icon(
|
||||
DidvanIcons.download_solid,
|
||||
size: 18,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.focusedBorder,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (message.error != null && message.error!)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
|
|
@ -645,14 +641,7 @@ class _AiChatPageState extends State<AiChatPage> {
|
|||
),
|
||||
),
|
||||
),
|
||||
if (state.messages[mIndex].prompts[index]
|
||||
.text !=
|
||||
null ||
|
||||
(state.messages[mIndex].prompts[index]
|
||||
.text !=
|
||||
null &&
|
||||
state.messages[mIndex].prompts[index]
|
||||
.text!.isNotEmpty))
|
||||
if (message.text != null && message.text!.isNotEmpty && (file == null || !file.isImage()))
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: InkWell(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// ignore_for_file: body_might_complete_normally_catch_error
|
||||
// ignore_for_file: body_might_complete_normally_catch_error, avoid_print
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import 'package:didvan/models/view/action_sheet_data.dart';
|
|||
import 'package:didvan/models/view/alert_data.dart';
|
||||
import 'package:didvan/routes/routes.dart';
|
||||
import 'package:didvan/utils/action_sheet.dart';
|
||||
import 'package:didvan/utils/date_time.dart';
|
||||
import 'package:didvan/views/ai/history_ai_chat_state.dart';
|
||||
import 'package:didvan/views/widgets/didvan/divider.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// lib/views/ai_section/ai_section_page.dart
|
||||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/app_icons.dart';
|
||||
|
|
@ -185,15 +184,8 @@ class _AiSectionPageState extends State<AiSectionPage> {
|
|||
key: _aiSectionScaffoldKey,
|
||||
appBar: HoshanAppBar(
|
||||
onBack: () {
|
||||
if (aiState.isChatting) {
|
||||
aiState.endChat();
|
||||
setState(() {
|
||||
_currentTabIndex = 2;
|
||||
});
|
||||
} else {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
},
|
||||
withActions: true,
|
||||
),
|
||||
drawer: HoshanDrawer(scaffKey: _aiSectionScaffoldKey),
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import 'package:didvan/services/media/voice.dart';
|
|||
import 'package:didvan/services/network/request.dart';
|
||||
import 'package:didvan/services/network/request_helper.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_sound/public/flutter_sound_player.dart';
|
||||
import 'package:flutter_sound/public/flutter_sound_recorder.dart';
|
||||
import 'package:flutter_sound_platform_interface/flutter_sound_platform_interface.dart';
|
||||
|
|
@ -24,7 +25,7 @@ class DirectState extends CoreProvier {
|
|||
final Map<String, List<int>> dailyMessages = {};
|
||||
final List<int> deletionQueue = [];
|
||||
|
||||
String? text;
|
||||
final TextEditingController textController = TextEditingController();
|
||||
NewsAttachment? replyNews;
|
||||
RadarAttachment? replyRadar;
|
||||
int? audioDuration;
|
||||
|
|
@ -104,6 +105,7 @@ class DirectState extends CoreProvier {
|
|||
|
||||
@override
|
||||
void dispose() {
|
||||
textController.dispose();
|
||||
super.dispose();
|
||||
mPlayer!.closePlayer();
|
||||
mPlayer = null;
|
||||
|
|
@ -172,7 +174,7 @@ class DirectState extends CoreProvier {
|
|||
}
|
||||
|
||||
Future<void> startRecording() async {
|
||||
text = null;
|
||||
textController.text.isEmpty;
|
||||
// await _recorder.hasPermission();
|
||||
record();
|
||||
|
||||
|
|
@ -228,13 +230,14 @@ class DirectState extends CoreProvier {
|
|||
}
|
||||
|
||||
Future<void> sendMessage() async {
|
||||
if ((text == null || text!.isEmpty) && path == null) return;
|
||||
|
||||
if ((textController.text.isEmpty) && path == null) return;
|
||||
VoiceService.audioPlayer.stop();
|
||||
|
||||
final body = {};
|
||||
|
||||
if (text != null) {
|
||||
body.addAll({'text': text});
|
||||
if (textController.text.isNotEmpty) {
|
||||
body.addAll({'text': textController.text});
|
||||
}
|
||||
|
||||
if (replyRadar != null) {
|
||||
|
|
@ -253,7 +256,7 @@ class DirectState extends CoreProvier {
|
|||
body.addAll({'duration': countTimer.value.inSeconds.toString()});
|
||||
}
|
||||
|
||||
text = null;
|
||||
textController.clear();
|
||||
|
||||
notifyListeners();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/app_icons.dart';
|
||||
|
|
@ -9,54 +10,60 @@ import 'package:didvan/views/widgets/didvan/text.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class MessageBox extends StatelessWidget {
|
||||
class MessageBox extends StatefulWidget {
|
||||
const MessageBox({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<MessageBox> createState() => _MessageBoxState();
|
||||
}
|
||||
|
||||
class _MessageBoxState extends State<MessageBox> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Consumer<DirectState>(
|
||||
builder: (context, state, child) => state.replyRadar != null ||
|
||||
state.replyNews != null
|
||||
? _MessageBoxContainer(
|
||||
isMessage: false,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const DidvanText(
|
||||
'لینک به مطلب:',
|
||||
builder: (context, state, child) =>
|
||||
state.replyRadar != null || state.replyNews != null
|
||||
? _MessageBoxContainer(
|
||||
isMessage: false,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const DidvanText(
|
||||
'لینک به مطلب:',
|
||||
),
|
||||
DidvanText(
|
||||
state.replyRadar != null
|
||||
? state.replyRadar!.title
|
||||
: state.replyNews!.title,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
color:
|
||||
Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
],
|
||||
),
|
||||
DidvanText(
|
||||
state.replyRadar != null
|
||||
? state.replyRadar!.title
|
||||
: state.replyNews!.title,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
DidvanIconButton(
|
||||
icon: DidvanIcons.close_regular,
|
||||
gestureSize: 24,
|
||||
onPressed: () {
|
||||
state.replyRadar = null;
|
||||
state.replyNews = null;
|
||||
state.update();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
DidvanIconButton(
|
||||
icon: DidvanIcons.close_regular,
|
||||
gestureSize: 24,
|
||||
onPressed: () {
|
||||
state.replyRadar = null;
|
||||
state.replyNews = null;
|
||||
state.update();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
: const SizedBox(),
|
||||
),
|
||||
)
|
||||
: const SizedBox(),
|
||||
),
|
||||
_MessageBoxContainer(
|
||||
isMessage: true,
|
||||
|
|
@ -111,7 +118,21 @@ class _Typing extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _TypingState extends State<_Typing> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
context.read<DirectState>().textController.addListener(_rebuild);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
context.read<DirectState>().textController.removeListener(_rebuild);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _rebuild() {
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -126,13 +147,11 @@ class _TypingState extends State<_Typing> {
|
|||
scale: animation,
|
||||
child: child,
|
||||
),
|
||||
child: state.text != null && state.text!.isNotEmpty
|
||||
child: state.textController.text.isNotEmpty
|
||||
? DidvanIconButton(
|
||||
icon: DidvanIcons.send_solid,
|
||||
onPressed: () async {
|
||||
await state.sendMessage();
|
||||
state.update();
|
||||
_formKey.currentState!.reset();
|
||||
},
|
||||
size: 32,
|
||||
color: Theme.of(context).colorScheme.focusedBorder,
|
||||
|
|
@ -147,23 +166,17 @@ class _TypingState extends State<_Typing> {
|
|||
),
|
||||
Expanded(
|
||||
flex: 15,
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: TextFormField(
|
||||
textInputAction: TextInputAction.send,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
hintText: 'بنویسید یا پیام صوتی بگذارید...',
|
||||
hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
color: Theme.of(context).colorScheme.disabledText),
|
||||
),
|
||||
onChanged: (value) {
|
||||
if (value.length <= 1) {
|
||||
setState(() {});
|
||||
}
|
||||
state.text = value;
|
||||
},
|
||||
child: TextFormField(
|
||||
controller: state.textController,
|
||||
textInputAction: TextInputAction.send,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
hintText: 'بنویسید یا پیام صوتی بگذارید...',
|
||||
hintStyle: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(color: Theme.of(context).colorScheme.disabledText),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -227,7 +240,6 @@ class _RecordChecking extends StatelessWidget {
|
|||
child: AudioWave(
|
||||
file: state.path!,
|
||||
totalDuration: state.countTimer.value,
|
||||
// deleteClidk: () => state.deleteRecordedFile,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
// ignore_for_file: avoid_print
|
||||
|
||||
import 'dart:convert';
|
||||
import 'package:didvan/models/home_page_content/swot.dart';
|
||||
import 'package:didvan/services/network/request.dart';
|
||||
import 'package:didvan/services/network/request_helper.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:http/http.dart' as RequestServicess;
|
||||
|
||||
class BookmarkService {
|
||||
static Future<List<int>> fetchBookmarks() async {
|
||||
|
|
@ -69,7 +70,7 @@ class BookmarkService {
|
|||
}
|
||||
|
||||
static Future<List<SwotItem>> fetchBookmarkedSwotItems() async {
|
||||
final postIds = await fetchBookmarks(); // استفاده از همان لیست بوکمارکها
|
||||
final postIds = await fetchBookmarks();
|
||||
final List<SwotItem> items = [];
|
||||
|
||||
for (final postId in postIds) {
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ class _BookmarksState extends State<Bookmarks> {
|
|||
}
|
||||
|
||||
|
||||
// ignore: unused_element
|
||||
void _onSearchChanged(String value) {
|
||||
final state = context.read<BookmarksState>();
|
||||
if (value.length < 3 && value.isNotEmpty) {
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ class _HomeState extends State<Home>
|
|||
)
|
||||
.then((value) => ActionSheetUtils(context).openDialog(
|
||||
data: ActionSheetData(
|
||||
// ignore: deprecated_member_use
|
||||
backgroundColor: Theme.of(context).colorScheme.background,
|
||||
isBackgroundDropBlur: true,
|
||||
content: Stack(
|
||||
|
|
@ -208,6 +209,7 @@ class _HomeState extends State<Home>
|
|||
scaffKey: homeScaffKey,
|
||||
)
|
||||
: null,
|
||||
// ignore: deprecated_member_use
|
||||
body: WillPopScope(
|
||||
onWillPop: () async {
|
||||
if (context.read<HomeState>().tabController.index == 0) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import 'package:didvan/constants/app_icons.dart';
|
|||
import 'package:didvan/main.dart';
|
||||
import 'package:didvan/models/home_page_content/home_page_list.dart';
|
||||
import 'package:didvan/models/home_page_content/swot.dart';
|
||||
import 'package:didvan/services/swot_service.dart';
|
||||
import 'package:didvan/routes/routes.dart';
|
||||
import 'package:didvan/services/app_initalizer.dart';
|
||||
import 'package:didvan/views/home/main/main_page_state.dart';
|
||||
|
|
@ -48,10 +47,8 @@ class _MainPageState extends State<MainPage> {
|
|||
children: [
|
||||
if (state.stories.isNotEmpty) StorySection(stories: state.stories),
|
||||
const SizedBox(height: 12),
|
||||
// Main page content
|
||||
const MainPageMainContent(),
|
||||
|
||||
// START: MODIFIED SECTION
|
||||
Builder(builder: (context) {
|
||||
final List<Widget> pageContent = [];
|
||||
if (state.content != null && state.content!.lists.isNotEmpty) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:didvan/main.dart';
|
||||
import 'package:didvan/models/enums.dart';
|
||||
import 'package:didvan/models/home_page_content/content.dart';
|
||||
import 'package:didvan/models/home_page_content/home_page_content.dart';
|
||||
import 'package:didvan/models/home_page_content/swot.dart';
|
||||
import 'package:didvan/models/requests/infography.dart';
|
||||
|
|
@ -33,7 +34,12 @@ class MainPageState extends CoreProvier {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> _getSwotItems() async { // این متد را اضافه کنید
|
||||
int getStoryStartIndex(List<MainPageContentType> stories) {
|
||||
final firstUnreadIndex = stories.indexWhere((story) => !story.isViewed);
|
||||
return firstUnreadIndex != -1 ? firstUnreadIndex : 0;
|
||||
}
|
||||
|
||||
Future<void> _getSwotItems() async {
|
||||
try {
|
||||
swotItems = await SwotService.fetchSwotItems();
|
||||
} catch (e) {
|
||||
|
|
@ -44,6 +50,7 @@ class MainPageState extends CoreProvier {
|
|||
Future<void> _fetchStories() async {
|
||||
try {
|
||||
stories = await StoryService.getStories();
|
||||
// ignore: avoid_print
|
||||
print("Fetched ${stories.length} stories.");
|
||||
} catch (e) {
|
||||
stories = [];
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// ignore_for_file: avoid_print
|
||||
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/app_icons.dart';
|
||||
import 'package:didvan/views/home/bookmarks/bookmark_service.dart';
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ class _BookmarkedIconState extends State<BookmarkedIcon> {
|
|||
widget.onBookmarkChanged?.call(newBookmarkStatus);
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore: avoid_print
|
||||
print("Error toggling bookmark for post ${widget.postId}: $e");
|
||||
} finally {
|
||||
if (mounted) {
|
||||
|
|
|
|||
|
|
@ -23,11 +23,14 @@ class StorySection extends StatelessWidget {
|
|||
child: _StoryCircle(
|
||||
userStories: userStories,
|
||||
onTap: () {
|
||||
bool allStoriesViewed = stories.every((userStories) =>
|
||||
userStories.stories.every((story) => story.isViewed.value));
|
||||
|
||||
Navigator.of(context).pushNamed(
|
||||
Routes.storyViewer,
|
||||
arguments: {
|
||||
'stories': stories,
|
||||
'tappedIndex': index,
|
||||
'tappedIndex': allStoriesViewed ? 0 : index,
|
||||
},
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ class _SwotBookmark extends State<SwotBookmark> {
|
|||
}
|
||||
|
||||
void saveOrUpdateNote(String content) async {
|
||||
// ignore: avoid_print
|
||||
print('Processing note for PostId: ${widget.item.id}, Content: $content');
|
||||
setState(() {
|
||||
isLoading = true;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ class MainCategories extends StatelessWidget {
|
|||
'$link?accessToken=${RequestService.token}',
|
||||
mode: LaunchMode.inAppWebView,
|
||||
);
|
||||
// ignore: avoid_print
|
||||
print("your goddamn token is :${RequestService.token}");
|
||||
} else if (link.startsWith('tab-')) {
|
||||
final state = context.read<HomeState>();
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// ignore_for_file: unnecessary_this
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:didvan/models/enums.dart';
|
||||
|
|
@ -22,9 +24,7 @@ class StudioDetailsState extends CoreProvier {
|
|||
int _trackingTimerCounter = 0;
|
||||
Timer? _trackingTimer;
|
||||
|
||||
// BEGIN: ADD THIS LINE
|
||||
StreamSubscription? _positionSubscription;
|
||||
// END: ADD THIS LINE
|
||||
|
||||
int _selectedDetailsIndex = 0;
|
||||
Timer? timer;
|
||||
|
|
|
|||
|
|
@ -41,11 +41,18 @@ class _StudioSliderState extends State<StudioSlider> {
|
|||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
final firstUnreadIndex =
|
||||
state.sliders.indexWhere((story) => !story.isViewed);
|
||||
|
||||
final startId = (firstUnreadIndex == -1)
|
||||
? state.sliders.first.id
|
||||
: state.sliders[firstUnreadIndex].id;
|
||||
|
||||
if (state.videosSelected) {
|
||||
Navigator.of(context)
|
||||
.pushNamed(Routes.studioDetails, arguments: {
|
||||
'onMarkChanged': state.changeMark,
|
||||
'id': state.sliders[i].id,
|
||||
'id': startId,
|
||||
'args':
|
||||
const StudioRequestArgs(page: 0, type: 'video'),
|
||||
'hasUnmarkConfirmation': false,
|
||||
|
|
@ -54,7 +61,7 @@ class _StudioSliderState extends State<StudioSlider> {
|
|||
return;
|
||||
}
|
||||
context.read<StudioDetailsState>().getStudioDetails(
|
||||
state.sliders[i].id,
|
||||
startId,
|
||||
args: const StudioRequestArgs(
|
||||
page: 0,
|
||||
type: 'podcast',
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
// ignore_for_file: avoid_print
|
||||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:didvan/models/story_model.dart';
|
||||
import 'package:didvan/services/story_service.dart';
|
||||
import 'package:didvan/utils/date_time.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:didvan/views/widgets/shimmer_placeholder.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:video_player/video_player.dart';
|
||||
|
|
@ -92,7 +92,24 @@ class _UserStoryViewerState extends State<UserStoryViewer>
|
|||
void initState() {
|
||||
super.initState();
|
||||
_animationController = AnimationController(vsync: this);
|
||||
_loadStory(story: widget.userStories.stories.first);
|
||||
|
||||
final allStoriesInGroupViewed =
|
||||
widget.userStories.stories.every((story) => story.isViewed.value);
|
||||
|
||||
if (allStoriesInGroupViewed) {
|
||||
for (final story in widget.userStories.stories) {
|
||||
story.isViewed.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
_currentStoryIndex =
|
||||
widget.userStories.stories.indexWhere((story) => !story.isViewed.value);
|
||||
|
||||
if (_currentStoryIndex == -1) {
|
||||
_currentStoryIndex = 0;
|
||||
}
|
||||
|
||||
_loadStory(story: widget.userStories.stories[_currentStoryIndex]);
|
||||
|
||||
_animationController.addStatusListener((status) {
|
||||
if (status == AnimationStatus.completed) {
|
||||
|
|
@ -314,6 +331,7 @@ class _AnimatedBar extends StatelessWidget {
|
|||
decoration: BoxDecoration(
|
||||
color: position < currentIndex
|
||||
? Colors.white
|
||||
// ignore: deprecated_member_use
|
||||
: Colors.white.withOpacity(0.5),
|
||||
border: Border.all(color: Colors.black26, width: 0.8),
|
||||
borderRadius: BorderRadius.circular(30.0),
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// ignore_for_file: unused_element
|
||||
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:expandable_bottom_sheet/expandable_bottom_sheet.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
|
@ -7,8 +9,6 @@ import 'package:provider/provider.dart';
|
|||
import '../../../config/design_config.dart';
|
||||
import '../../../constants/app_icons.dart';
|
||||
import '../../../models/enums.dart';
|
||||
import '../../../models/requests/radar.dart';
|
||||
import '../../../routes/routes.dart';
|
||||
import '../../../services/media/media.dart';
|
||||
import '../../../utils/action_sheet.dart';
|
||||
import '../../podcasts/podcasts_state.dart';
|
||||
|
|
|
|||
|
|
@ -1,13 +1,8 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/app_icons.dart';
|
||||
import 'package:didvan/routes/routes.dart';
|
||||
import 'package:didvan/views/ai/ai_state.dart';
|
||||
import 'package:didvan/views/widgets/didvan/icon_button.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class HoshanAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
final Function()? onBack;
|
||||
|
|
@ -55,14 +50,14 @@ class HoshanAppBar extends StatelessWidget implements PreferredSizeWidget {
|
|||
),
|
||||
Row(
|
||||
children: [
|
||||
if (withInfo)
|
||||
DidvanIconButton(
|
||||
icon: DidvanIcons.info_circle_light,
|
||||
size: 32,
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(context, Routes.info);
|
||||
}),
|
||||
if (withActions)
|
||||
// if (withInfo)
|
||||
// DidvanIconButton(
|
||||
// icon: DidvanIcons.info_circle_light,
|
||||
// size: 32,
|
||||
// onPressed: () {
|
||||
// Navigator.pushNamed(context, Routes.info);
|
||||
// }),
|
||||
// if (withActions)
|
||||
// Stack(
|
||||
// children: [
|
||||
// DidvanIconButton(
|
||||
|
|
@ -81,15 +76,13 @@ class HoshanAppBar extends StatelessWidget implements PreferredSizeWidget {
|
|||
// )
|
||||
// ],
|
||||
// ),
|
||||
if (context.watch<AiState>().page != 0 || !withActions)
|
||||
Transform.rotate(
|
||||
angle: 180 * pi / 180,
|
||||
child: DidvanIconButton(
|
||||
icon: DidvanIcons.back_light,
|
||||
size: 32,
|
||||
onPressed: () => onBack?.call(),
|
||||
),
|
||||
if (withInfo)
|
||||
DidvanIconButton(
|
||||
icon: DidvanIcons.angle_left_light,
|
||||
size: 32,
|
||||
onPressed: () => onBack?.call(),
|
||||
),
|
||||
|
||||
],
|
||||
)
|
||||
],
|
||||
|
|
|
|||
26
pubspec.lock
26
pubspec.lock
|
|
@ -201,6 +201,22 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.11"
|
||||
device_info_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: device_info_plus
|
||||
sha256: "98f28b42168cc509abc92f88518882fd58061ea372d7999aecc424345c7bff6a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "11.5.0"
|
||||
device_info_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: device_info_plus_platform_interface
|
||||
sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.3"
|
||||
equatable:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -1650,6 +1666,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.12.0"
|
||||
win32_registry:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32_registry
|
||||
sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -1668,4 +1692,4 @@ packages:
|
|||
version: "6.5.0"
|
||||
sdks:
|
||||
dart: ">=3.7.0 <4.0.0"
|
||||
flutter: ">=3.27.0"
|
||||
flutter: ">=3.29.0"
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
|||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
version: 3.3.8+3380
|
||||
version: 4.0.1+4380
|
||||
|
||||
environment:
|
||||
sdk: ">=2.19.0 <3.0.0"
|
||||
|
|
@ -112,6 +112,8 @@ dependencies:
|
|||
flutter_inappwebview: ^6.1.5
|
||||
sms_autofill: ^2.4.1
|
||||
shimmer: ^3.0.0
|
||||
device_info_plus: ^11.5.0
|
||||
# image_gallery_saver: ^2.0.3
|
||||
# fading_edge_scrollview: ^4.1.1
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
|
|||
Loading…
Reference in New Issue