fixed story index bug

This commit is contained in:
mohamadmahdi jebeli 2025-07-12 15:30:37 +03:30
parent 283938d759
commit 5f02802ad1
35 changed files with 296 additions and 223 deletions

View File

@ -17,6 +17,7 @@
android:icon="@mipmap/ic_launcher"
android:label="Didvan"
android:requestLegacyExternalStorage="true"
android:usesCleartextTraffic="true">
<receiver
android:name=".FavWidget"

View File

@ -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'],
);

View File

@ -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'],
);

View File

@ -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,
};
}

View File

@ -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),

View File

@ -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';

View File

@ -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!;
}

View File

@ -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({

View File

@ -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 {

View File

@ -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';

View File

@ -1,3 +1,5 @@
// ignore_for_file: avoid_print
import 'package:flutter/services.dart';
class NativeWebViewLauncher {

View File

@ -20,6 +20,7 @@
const Ai({Key? key}) : super(key: key);
@override
// ignore: library_private_types_in_public_api
_AiState createState() => _AiState();
}

View File

@ -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(

View File

@ -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';

View File

@ -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';

View File

@ -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),

View File

@ -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();

View File

@ -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,
),
),
),

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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 = [];

View File

@ -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';

View File

@ -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) {

View File

@ -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,
},
);
},

View File

@ -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;

View File

@ -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>();

View File

@ -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;

View File

@ -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',

View File

@ -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),

View File

@ -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';

View File

@ -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(),
),
],
)
],

View File

@ -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"

View File

@ -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: