bug fixes + radar podcasts

This commit is contained in:
MohammadTaha Basiri 2022-12-03 09:26:47 +03:30
parent 931c268c25
commit b1ce815c66
20 changed files with 433 additions and 265 deletions

View File

@ -32,7 +32,7 @@ if (keystorePropertiesFile.exists()) {
}
android {
compileSdkVersion 31
compileSdkVersion 33
compileOptions {

View File

@ -3,57 +3,56 @@ import 'package:flutter/cupertino.dart';
class Assets {
static const String _basePath = 'lib/assets';
static const String _baseImagesPath = _basePath + '/images';
static const String _baseCategoriesPath = _baseImagesPath + '/categories';
static const String _baseThemesPath = _baseImagesPath + '/themes';
static const String _baseEmptyStatesPath = _baseImagesPath + '/empty_states';
static const String _baseAnimationsPath = _basePath + '/animations';
static const String _baseRecordsPath = _baseImagesPath + '/records';
static const String _baseLogosPath = _baseImagesPath + '/logos';
static const String _baseImagesPath = '$_basePath/images';
static const String _baseCategoriesPath = '$_baseImagesPath/categories';
static const String _baseThemesPath = '$_baseImagesPath/themes';
static const String _baseEmptyStatesPath = '$_baseImagesPath/empty_states';
static const String _baseAnimationsPath = '$_basePath/animations';
static const String _baseRecordsPath = '$_baseImagesPath/records';
static const String _baseLogosPath = '$_baseImagesPath/logos';
static String get verticalLogoWithText =>
_baseLogosPath + '/logo-vertical-$_themeSuffix.svg';
'$_baseLogosPath/logo-vertical-$_themeSuffix.svg';
static String get horizontalLogoWithText =>
_baseLogosPath + '/logo-horizontal-$_themeSuffix.svg';
static String get studioLogo => _baseLogosPath + '/studio-$_themeSuffix.svg';
'$_baseLogosPath/logo-horizontal-$_themeSuffix.svg';
static String get studioLogo => '$_baseLogosPath/studio-$_themeSuffix.svg';
static String get logoLoadingAnimation =>
_baseAnimationsPath + '/indicator-$_themeSuffix.riv';
'$_baseAnimationsPath/indicator-$_themeSuffix.riv';
static String get businessCategoryIcon =>
_baseCategoriesPath + '/business-$_themeSuffix.svg';
'$_baseCategoriesPath/business-$_themeSuffix.svg';
static String get economicCategoryIcon =>
_baseCategoriesPath + '/economic-$_themeSuffix.svg';
'$_baseCategoriesPath/economic-$_themeSuffix.svg';
static String get enviromentalCategoryIcon =>
_baseCategoriesPath + '/enviromental-$_themeSuffix.svg';
'$_baseCategoriesPath/enviromental-$_themeSuffix.svg';
static String get politicalCategoryIcon =>
_baseCategoriesPath + '/political-$_themeSuffix.svg';
'$_baseCategoriesPath/political-$_themeSuffix.svg';
static String get socialCategoryIcon =>
_baseCategoriesPath + '/social-$_themeSuffix.svg';
'$_baseCategoriesPath/social-$_themeSuffix.svg';
static String get techCategoryIcon =>
_baseCategoriesPath + '/tech-$_themeSuffix.svg';
'$_baseCategoriesPath/tech-$_themeSuffix.svg';
static String get steelCategoryIcon =>
_baseCategoriesPath + '/steel-$_themeSuffix.svg';
'$_baseCategoriesPath/steel-$_themeSuffix.svg';
static String get stockCategoryIcon =>
_baseCategoriesPath + '/stock-$_themeSuffix.svg';
'$_baseCategoriesPath/stock-$_themeSuffix.svg';
static String get globCategoryIcon =>
_baseCategoriesPath + '/glob-$_themeSuffix.svg';
'$_baseCategoriesPath/glob-$_themeSuffix.svg';
static String get emptyBookmark =>
_baseEmptyStatesPath + '/bookmark-$_themeSuffix.svg';
'$_baseEmptyStatesPath/bookmark-$_themeSuffix.svg';
static String get emptyChart =>
_baseEmptyStatesPath + '/chart-$_themeSuffix.svg';
static String get emptyChat =>
_baseEmptyStatesPath + '/chat-$_themeSuffix.svg';
'$_baseEmptyStatesPath/chart-$_themeSuffix.svg';
static String get emptyChat => '$_baseEmptyStatesPath/chat-$_themeSuffix.svg';
static String get emptyConnection =>
_baseEmptyStatesPath + '/connection-$_themeSuffix.svg';
'$_baseEmptyStatesPath/connection-$_themeSuffix.svg';
static String get emptyResult =>
_baseEmptyStatesPath + '/result-$_themeSuffix.svg';
'$_baseEmptyStatesPath/result-$_themeSuffix.svg';
static const String lightTheme = _baseThemesPath + '/theme-light.svg';
static const String darkTheme = _baseThemesPath + '/theme-dark.svg';
static const String lightTheme = '$_baseThemesPath/theme-light.svg';
static const String darkTheme = '$_baseThemesPath/theme-dark.svg';
static String get record => _baseRecordsPath + '/record-$_themeSuffix.svg';
static String get record => '$_baseRecordsPath/record-$_themeSuffix.svg';
static String get _themeSuffix =>
DesignConfig.brightness == Brightness.dark ? 'dark' : 'light';

View File

@ -14,6 +14,7 @@ class NewsDetailsData {
final List<Tag> tags;
final List<Content> contents;
final List<OverviewData> relatedContents = [];
bool relatedContentsIsEmpty;
NewsDetailsData({
required this.id,
@ -26,6 +27,7 @@ class NewsDetailsData {
required this.tags,
required this.contents,
required this.order,
this.relatedContentsIsEmpty = false,
});
factory NewsDetailsData.fromJson(Map<String, dynamic> json) {

View File

@ -11,6 +11,7 @@ class RadarDetailsData {
final int timeToRead;
final String createdAt;
final String? podcast;
final int? duration;
final bool forManagers;
final bool marked;
int comments;
@ -19,6 +20,7 @@ class RadarDetailsData {
final List<CategoryData> categories;
final int order;
final List<OverviewData> relatedContents = [];
bool relatedContentsIsEmpty;
RadarDetailsData({
required this.id,
@ -34,6 +36,8 @@ class RadarDetailsData {
required this.contents,
required this.categories,
required this.order,
required this.duration,
this.relatedContentsIsEmpty = false,
});
factory RadarDetailsData.fromJson(Map<String, dynamic> json) {
@ -59,6 +63,7 @@ class RadarDetailsData {
(cat) => CategoryData.fromJson(cat),
),
),
duration: json['duration'],
);
}

View File

@ -11,6 +11,7 @@ class StudioDetailsData {
final String? iframe;
final String createdAt;
final int order;
bool relatedContentsIsEmpty;
bool marked;
int comments;
final List<Tag> tags;
@ -29,6 +30,7 @@ class StudioDetailsData {
required this.marked,
required this.comments,
required this.tags,
this.relatedContentsIsEmpty = false,
});
factory StudioDetailsData.fromJson(Map<String, dynamic> json) {

View File

@ -25,9 +25,10 @@ class MediaService {
void Function(bool isNext)? onTrackChanged,
}) async {
String tag;
tag = '${isVoiceMessage ? 'message' : 'podcast'}-$id';
tag =
'${currentPodcast?.description == 'radar' ? 'radar' : isVoiceMessage ? 'message' : 'podcast'}-$id';
if (!isVoiceMessage && MediaProvider.downloadedItemIds.contains(id)) {
audioSource = StorageService.appDocsDir + '/podcasts/podcast-$id.mp3';
audioSource = '${StorageService.appDocsDir}/podcasts/podcast-$id.mp3';
isNetworkAudio = false;
}
if (audioPlayerTag == tag) {
@ -52,7 +53,7 @@ class MediaService {
? null
: Metas(
artist: 'استودیو دیدوان',
title: currentPodcast!.title,
title: currentPodcast?.title ?? '',
),
);
} else {
@ -62,7 +63,7 @@ class MediaService {
? null
: Metas(
artist: 'استودیو دیدوان',
title: currentPodcast!.title,
title: currentPodcast?.title ?? '',
),
);
}

View File

@ -4,44 +4,41 @@ import 'package:didvan/models/requests/studio.dart';
class RequestHelper {
static const String baseUrl = 'https://api.didvan.app';
static const String _baseUserUrl = baseUrl + '/user';
static const String _baseRadarUrl = baseUrl + '/radar';
static const String _baseNewsUrl = baseUrl + '/news';
static const String _baseStudioUrl = baseUrl + '/studio';
static const String _baseStatisticUrl = baseUrl + '/statistic';
static const String _baseDirectUrl = _baseUserUrl + '/direct';
static const String _baseUserUrl = '$baseUrl/user';
static const String _baseRadarUrl = '$baseUrl/radar';
static const String _baseNewsUrl = '$baseUrl/news';
static const String _baseStudioUrl = '$baseUrl/studio';
static const String _baseStatisticUrl = '$baseUrl/statistic';
static const String _baseDirectUrl = '$_baseUserUrl/direct';
static const String confirmUsername = _baseUserUrl + '/confirmUsername';
static const String changePassword = _baseUserUrl + '/changePassword';
static const String login = _baseUserUrl + '/login';
static const String directs = _baseUserUrl + '/direct';
static const String userInfo = _baseUserUrl + '/info';
static const String firebaseToken = _baseUserUrl + '/firebaseToken';
static const String silenceInterval = _baseUserUrl + '/silenceInterval';
static const String updateProfilePhoto = _baseUserUrl + '/profile/photo';
static const String checkUsername = _baseUserUrl + '/CheckUsername';
static const String updateProfile = _baseUserUrl + '/profile/edit';
static const String otp = _baseUserUrl + '/otp';
static const String confirmUsername = '$_baseUserUrl/confirmUsername';
static const String changePassword = '$_baseUserUrl/changePassword';
static const String login = '$_baseUserUrl/login';
static const String directs = '$_baseUserUrl/direct';
static const String userInfo = '$_baseUserUrl/info';
static const String firebaseToken = '$_baseUserUrl/firebaseToken';
static const String silenceInterval = '$_baseUserUrl/silenceInterval';
static const String updateProfilePhoto = '$_baseUserUrl/profile/photo';
static const String checkUsername = '$_baseUserUrl/CheckUsername';
static const String updateProfile = '$_baseUserUrl/profile/edit';
static const String otp = '$_baseUserUrl/otp';
static String bookmarks({
required int page,
String? search,
String? type,
String? studioType,
}) =>
_baseUserUrl +
'/marked/${type ?? ''}' +
_urlConcatGenerator([
'$_baseUserUrl/marked/${type ?? ''}${_urlConcatGenerator([
MapEntry('page', page),
MapEntry('type', studioType),
MapEntry('search', search),
]);
])}';
static const String directTypes = baseUrl + '/direct/types';
static String direct(int id) => _baseDirectUrl + '/$id';
static String sendDirectMessage(int id) =>
_baseDirectUrl + '/$id/sendMessage';
static const String directTypes = '$baseUrl/direct/types';
static String direct(int id) => '$_baseDirectUrl/$id';
static String sendDirectMessage(int id) => '$_baseDirectUrl/$id/sendMessage';
static String deleteDirect(int id, int messageId) =>
_baseDirectUrl + '/$id/message/$messageId';
'$_baseDirectUrl/$id/message/$messageId';
static String tag({
required List<int> ids,
String? type,
@ -49,26 +46,22 @@ class RequestHelper {
int? page,
int? limit,
}) =>
baseUrl +
'/tag' +
_urlConcatGenerator([
'$baseUrl/tag${_urlConcatGenerator([
MapEntry('page', page),
MapEntry('limit', limit ?? '3'),
MapEntry('type', type),
MapEntry('id', itemId ?? '1'),
MapEntry('tags', _urlListConcatGenerator(ids)),
]);
])}';
static String radarDetails(int id, RadarRequestArgs args) =>
_baseRadarUrl +
'/$id' +
_urlConcatGenerator([
'$_baseRadarUrl/$id${_urlConcatGenerator([
MapEntry('page', args.page),
MapEntry('start', args.startDate),
MapEntry('end', args.endDate),
MapEntry('search', args.search),
MapEntry('categories', _urlListConcatGenerator(args.categories)),
]);
])}';
static String radarOverviews({required RadarRequestArgs args}) =>
_baseRadarUrl +
_urlConcatGenerator([
@ -80,14 +73,12 @@ class RequestHelper {
]);
static String newsDetails(int id, NewsRequestArgs args) =>
_baseNewsUrl +
'/$id' +
_urlConcatGenerator([
'$_baseNewsUrl/$id${_urlConcatGenerator([
MapEntry('page', args.page),
MapEntry('start', args.startDate),
MapEntry('end', args.endDate),
MapEntry('search', args.search),
]);
])}';
static String newsOverviews({required NewsRequestArgs args}) =>
_baseNewsUrl +
_urlConcatGenerator([
@ -98,19 +89,15 @@ class RequestHelper {
]);
static String studioSlider(String type) =>
_baseStudioUrl +
'/slider' +
_urlConcatGenerator([MapEntry('type', type)]);
'$_baseStudioUrl/slider${_urlConcatGenerator([MapEntry('type', type)])}';
static String studioDetails(int id, StudioRequestArgs args) =>
_baseStudioUrl +
'/$id' +
_urlConcatGenerator([
'$_baseStudioUrl/$id${_urlConcatGenerator([
MapEntry('page', args.page),
MapEntry('type', args.type),
MapEntry('order', args.order),
MapEntry('search', args.search),
MapEntry('asc', args.asc),
]);
])}';
static String studioOverviews({required StudioRequestArgs args}) =>
_baseStudioUrl +
_urlConcatGenerator([
@ -130,23 +117,19 @@ class RequestHelper {
String label,
String period,
) =>
_baseStatisticUrl +
'/$label' +
_urlConcatGenerator([
'$_baseStatisticUrl/$label${_urlConcatGenerator([
MapEntry('period', period),
]);
])}';
static String mark(int id, String type) => baseUrl + '/$type/$id/mark';
static String tracking(int id, String type) =>
baseUrl + '/$type/$id/tracking';
static String comments(int id, String type) =>
baseUrl + '/$type/$id/comments';
static String mark(int id, String type) => '$baseUrl/$type/$id/mark';
static String tracking(int id, String type) => '$baseUrl/$type/$id/tracking';
static String comments(int id, String type) => '$baseUrl/$type/$id/comments';
static String feedback(int id, int commentId, String type) =>
baseUrl + '/$type/$id/comments/$commentId/feedback';
'$baseUrl/$type/$id/comments/$commentId/feedback';
static String addComment(int id, String type) =>
baseUrl + '/$type/$id/comments/add';
static String deleteComment(int id) => baseUrl + '/comment/$id';
static String reportComment(int id) => baseUrl + '/comment/$id/report';
'$baseUrl/$type/$id/comments/add';
static String deleteComment(int id) => '$baseUrl/comment/$id';
static String reportComment(int id) => '$baseUrl/comment/$id/report';
static String _urlConcatGenerator(List<MapEntry<String, dynamic>> additions) {
String result = '';
@ -156,7 +139,7 @@ class RequestHelper {
if (additions.isNotEmpty) {
result += '?';
for (var i = 0; i < additions.length; i++) {
result += (additions[i].key + '=' + additions[i].value!.toString());
result += ('${additions[i].key}=${additions[i].value!}');
if (i != additions.length - 1) {
result += '&';
}

View File

@ -1,7 +1,9 @@
import 'dart:io';
import 'package:assets_audio_player/assets_audio_player.dart';
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/models/studio_details_data.dart';
import 'package:didvan/services/media/media.dart';
import 'package:didvan/views/home/widgets/audio/audio_slider.dart';
import 'package:didvan/views/widgets/didvan/icon_button.dart';
@ -11,11 +13,13 @@ class AudioWidget extends StatelessWidget {
final String? audioUrl;
final File? audioFile;
final int id;
final StudioDetailsData? audioMetaData;
const AudioWidget({
Key? key,
this.audioUrl,
this.audioFile,
required this.id,
this.audioMetaData,
}) : super(key: key);
@override
@ -24,16 +28,20 @@ class AudioWidget extends StatelessWidget {
stream: MediaService.audioPlayer.isPlaying,
builder: (context, snapshot) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: AudioSlider(
tag: 'message-$id',
tag: audioMetaData != null ? 'radar-$id' : 'message-$id',
duration: audioMetaData?.duration,
showTimer: true,
),
),
_AudioControllerButton(
audioFile: audioFile,
audioUrl: audioUrl,
id: id,
audioMetaData: audioMetaData,
),
],
);
@ -46,28 +54,46 @@ class _AudioControllerButton extends StatelessWidget {
final String? audioUrl;
final File? audioFile;
final int id;
final StudioDetailsData? audioMetaData;
const _AudioControllerButton(
{Key? key, this.audioUrl, this.audioFile, required this.id})
: super(key: key);
const _AudioControllerButton({
Key? key,
this.audioUrl,
this.audioFile,
required this.id,
this.audioMetaData,
}) : super(key: key);
bool get _nowPlaying => MediaService.audioPlayerTag == 'message-$id';
bool get _nowPlaying =>
MediaService.audioPlayerTag ==
(audioMetaData != null ? 'radar-$id' : 'message-$id');
@override
Widget build(BuildContext context) {
return StreamBuilder<PlayingAudio?>(
stream: MediaService.audioPlayer.onReadyToPlay,
builder: (context, snapshot) {
return DidvanIconButton(
icon: MediaService.audioPlayer.isPlaying.value && _nowPlaying
? DidvanIcons.pause_circle_solid
: DidvanIcons.play_circle_solid,
gestureSize: 36,
color: Theme.of(context).colorScheme.focusedBorder,
onPressed: () {
onPressed: () async {
if (snapshot.data == null && _nowPlaying) {
return;
}
if (audioMetaData != null) {
MediaService.currentPodcast = audioMetaData;
}
MediaService.handleAudioPlayback(
audioSource: audioFile?.path ?? audioUrl,
id: id,
isNetworkAudio: audioFile == null,
isVoiceMessage: true,
isVoiceMessage: audioMetaData == null,
);
},
);
});
}
}

View File

@ -72,6 +72,9 @@ class NewsDetailsState extends CoreProvier {
_currentIndex--;
}
isFetchingNewItem = false;
if (currentNews.contents.length == 1) {
getRelatedContents();
}
appState = AppState.idle;
return;
}
@ -108,7 +111,10 @@ class NewsDetailsState extends CoreProvier {
}
Future<void> getRelatedContents() async {
if (currentNews.relatedContents.isNotEmpty) return;
if (currentNews.relatedContents.isNotEmpty &&
currentNews.relatedContentsIsEmpty) {
return;
}
relatedQueue.add(currentNews.id);
final service = RequestService(RequestHelper.tag(
ids: currentNews.tags.map((tag) => tag.id).toList(),
@ -125,8 +131,19 @@ class NewsDetailsState extends CoreProvier {
.relatedContents
.add(OverviewData.fromJson(relateds[i]));
}
notifyListeners();
if (relateds.isEmpty) {
news
.where((element) => element != null)
.firstWhere((element) => element!.id == currentNews.id)
?.relatedContentsIsEmpty = true;
}
} else {
news
.where((element) => element != null)
.firstWhere((element) => element!.id == currentNews.id)
?.relatedContentsIsEmpty = true;
}
notifyListeners();
}
@override

View File

@ -1,3 +1,4 @@
import 'package:didvan/models/enums.dart';
import 'package:didvan/models/requests/radar.dart';
import 'package:didvan/views/home/radar/radar_details/radar_details_state.dart';
import 'package:didvan/views/home/widgets/floating_navigation_bar.dart';

View File

@ -81,6 +81,9 @@ class RadarDetailsState extends CoreProvier {
_currentIndex--;
}
isFetchingNewItem = false;
if (currentRadar.contents.length == 1) {
getRelatedContents();
}
appState = AppState.idle;
return;
}
@ -91,7 +94,10 @@ class RadarDetailsState extends CoreProvier {
}
Future<void> getRelatedContents() async {
if (currentRadar.relatedContents.isNotEmpty) return;
if (currentRadar.relatedContents.isNotEmpty &&
currentRadar.relatedContentsIsEmpty) {
return;
}
relatedQueue.add(currentRadar.id);
final service = RequestService(RequestHelper.tag(
ids: currentRadar.tags.map((tag) => tag.id).toList(),
@ -108,8 +114,19 @@ class RadarDetailsState extends CoreProvier {
.relatedContents
.add(OverviewData.fromJson(relateds[i]));
}
notifyListeners();
if (relateds.isEmpty) {
radars
.where((element) => element != null)
.firstWhere((element) => element!.id == currentRadar.id)
?.relatedContentsIsEmpty = true;
}
} else {
radars
.where((element) => element != null)
.firstWhere((element) => element!.id == currentRadar.id)
?.relatedContentsIsEmpty = true;
}
notifyListeners();
}
bool exists(RadarDetailsData? radar) =>

View File

@ -138,17 +138,19 @@ class _ProfilePhotoState extends State<ProfilePhoto> {
return;
}
final pickedFile = await MediaService.pickImage(source: source);
File? file;
dynamic file;
if (pickedFile != null && !kIsWeb) {
file = await ImageCropper().cropImage(
sourcePath: pickedFile.path,
aspectRatio: const CropAspectRatio(ratioX: 1, ratioY: 1),
iosUiSettings: const IOSUiSettings(
uiSettings: [
IOSUiSettings(
title: 'برش تصویر',
doneButtonTitle: 'تایید',
cancelButtonTitle: 'بازگشت',
),
androidUiSettings: const AndroidUiSettings(toolbarTitle: 'برش تصویر'),
AndroidUiSettings(toolbarTitle: 'برش تصویر')
],
compressQuality: 30,
);
if (file == null) return;

View File

@ -126,7 +126,7 @@ class _StudioState extends State<Studio> {
emptyState: EmptyResult(
onNewSearch: () => _focusNode.requestFocus(),
),
centerEmptyState: true,
centerEmptyState: false,
enableEmptyState: state.studios.isEmpty,
placeholder: state.videosSelected
? VideoOverview.placeHolder

View File

@ -14,7 +14,7 @@ class StudioDetailsState extends CoreProvier {
StudioDetailsData? nextStudio;
StudioDetailsData? prevStudio;
late int initialIndex;
late StudioRequestArgs args;
StudioRequestArgs? args;
StudioRequestArgs? podcastArgs;
final List<int> relatedQueue = [];
bool _positionListenerActivated = false;
@ -45,11 +45,11 @@ class StudioDetailsState extends CoreProvier {
if (args != null) {
this.args = args;
}
if (this.args.type == 'podcast') {
if (this.args?.type == 'podcast') {
podcastArgs = this.args;
}
if (MediaService.currentPodcast?.id == id &&
this.args.type == 'podcast' &&
this.args?.type == 'podcast' &&
!fetchOnly) {
return;
}
@ -68,7 +68,7 @@ class StudioDetailsState extends CoreProvier {
_handlePodcastPlayback(studio);
}
if (isForward == null) {
if (this.args.type == 'podcast') {
if (this.args?.type == 'podcast') {
MediaService.audioPlayerTag =
'podcast-${MediaService.currentPodcast?.id ?? ''}';
}
@ -77,7 +77,12 @@ class StudioDetailsState extends CoreProvier {
alongSideState = AppState.busy;
notifyListeners();
}
final service = RequestService(RequestHelper.studioDetails(id, this.args));
final service = RequestService(
RequestHelper.studioDetails(
id,
this.args ?? const StudioRequestArgs(page: 0),
),
);
await service.httpGet();
nextStudio = null;
prevStudio = null;
@ -91,10 +96,10 @@ class StudioDetailsState extends CoreProvier {
}
final result = service.result;
studio = StudioDetailsData.fromJson(result['studio']);
if (result['nextStudio'].isNotEmpty && this.args.page != 0) {
if (result['nextStudio'].isNotEmpty && this.args?.page != 0) {
nextStudio = StudioDetailsData.fromJson(result['nextStudio']);
}
if (result['prevStudio'].isNotEmpty && this.args.page != 0) {
if (result['prevStudio'].isNotEmpty && this.args?.page != 0) {
prevStudio = StudioDetailsData.fromJson(result['prevStudio']);
}
if (isForward == null && !fetchOnly) {
@ -113,7 +118,7 @@ class StudioDetailsState extends CoreProvier {
}
Future<void> _handlePodcastPlayback(StudioDetailsData studio) async {
if (args.type == 'podcast') {
if (args?.type == 'podcast') {
MediaService.currentPodcast = studio;
MediaService.podcastPlaylistArgs = args;
await MediaService.handleAudioPlayback(
@ -156,7 +161,7 @@ class StudioDetailsState extends CoreProvier {
final service = RequestService(RequestHelper.tag(
ids: studio.tags.map((tag) => tag.id).toList(),
itemId: studio.id,
type: args.type,
type: args?.type,
));
await service.httpGet();
if (service.isSuccess) {
@ -164,8 +169,13 @@ class StudioDetailsState extends CoreProvier {
for (var i = 0; i < relateds.length; i++) {
studio.relatedContents.add(OverviewData.fromJson(relateds[i]));
}
notifyListeners();
if (relateds.isEmpty) {
studio.relatedContentsIsEmpty = true;
}
} else {
studio.relatedContentsIsEmpty = true;
}
notifyListeners();
}
void onCommentsChanged(int count) {

View File

@ -71,7 +71,7 @@ class StudioDetailsWidget extends StatelessWidget {
direction: TextDirection.rtl,
textAlign: TextAlign.right,
lineHeight: LineHeight.percent(135),
margin: EdgeInsets.zero,
margin: const Margins(),
padding: EdgeInsets.zero,
),
},
@ -144,7 +144,8 @@ class StudioDetailsWidget extends StatelessWidget {
}
return Column(
children: [
if (state.studio.relatedContents.isEmpty)
if (state.studio.relatedContents.isEmpty &&
!state.studio.relatedContentsIsEmpty)
for (var i = 0; i < 3; i++)
Padding(
padding: const EdgeInsets.only(

View File

@ -112,7 +112,8 @@ class _PlayerNavBar extends StatelessWidget {
return StreamBuilder<bool>(
stream: MediaService.audioPlayer.isPlaying,
builder: (context, snapshot) => GestureDetector(
onTap: () => MediaService.currentPodcast == null
onTap: () => MediaService.currentPodcast == null ||
MediaService.currentPodcast?.description == 'radar'
? null
: _showPlayerBottomSheet(context),
child: Consumer<StudioDetailsState>(
@ -203,7 +204,9 @@ class _PlayerNavBar extends StatelessWidget {
stream: MediaService.audioPlayer.onReadyToPlay,
builder: (context, snapshot) {
if (snapshot.data == null ||
state.appState == AppState.busy) {
state.appState == AppState.busy &&
MediaService.currentPodcast?.description !=
'radar') {
return Padding(
padding: const EdgeInsets.only(
top: 4,
@ -226,7 +229,8 @@ class _PlayerNavBar extends StatelessWidget {
},
),
if (state.appState != AppState.busy &&
snapshot.data != null)
snapshot.data != null ||
MediaService.currentPodcast?.description == 'radar')
Padding(
padding: const EdgeInsets.only(
left: 12,
@ -241,7 +245,7 @@ class _PlayerNavBar extends StatelessWidget {
? DidvanIcons.pause_solid
: DidvanIcons.play_solid,
onPressed: () {
if (state.args.type == 'video') {
if (state.args?.type == 'video') {
state.getStudioDetails(
MediaService.currentPodcast!.id,
args: state.podcastArgs,
@ -270,7 +274,7 @@ class _PlayerNavBar extends StatelessWidget {
final sheetKey = GlobalKey<ExpandableBottomSheetState>();
bool isExpanded = false;
final detailsState = context.read<StudioDetailsState>();
if (detailsState.args.type == 'video') {
if (detailsState.args?.type == 'video') {
detailsState.getStudioDetails(
MediaService.currentPodcast!.id,
args: detailsState.podcastArgs,

View File

@ -4,9 +4,12 @@ import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/models/requests/news.dart';
import 'package:didvan/models/requests/radar.dart';
import 'package:didvan/models/studio_details_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/home/direct/widgets/audio_widget.dart';
import 'package:didvan/views/home/widgets/audio/audio_slider.dart';
import 'package:didvan/views/home/widgets/overview/multitype.dart';
import 'package:didvan/views/home/widgets/tag_item.dart';
import 'package:didvan/views/widgets/animated_visibility.dart';
@ -108,6 +111,44 @@ class _DidvanPageViewState extends State<DidvanPageView> {
const EdgeInsets.symmetric(horizontal: 16),
child: _subtitle(item),
),
if (widget.isRadar && item.podcast != null)
Container(
padding: const EdgeInsets.all(12)
.copyWith(left: 0, bottom: 4),
margin: const EdgeInsets.all(12),
decoration: BoxDecoration(
border: Border.all(
color: Theme.of(context).colorScheme.hint,
),
borderRadius: DesignConfig.lowBorderRadius,
color: Theme.of(context).backgroundColor,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const DidvanText('این مطلب را بشنوید:'),
const SizedBox(height: 8),
AudioWidget(
id: item.id,
audioUrl: item.podcast,
audioMetaData: StudioDetailsData(
id: item.id,
link: item.podcast,
createdAt: item.createdAt,
order: 0,
marked: item.marked,
comments: 0,
tags: [],
iframe: '',
duration: item.duration,
title: item.title,
image: item.image,
description: 'radar',
),
),
],
),
),
for (var i = 0; i < item.contents.length; i++)
Padding(
padding: const EdgeInsets.symmetric(
@ -146,7 +187,8 @@ class _DidvanPageViewState extends State<DidvanPageView> {
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: ItemTitle(title: 'مطالب مشابه'),
),
if (item.relatedContents.isEmpty)
if (item.relatedContents.isEmpty &&
!item.relatedContentsIsEmpty)
for (var i = 0; i < 3; i++)
Padding(
padding: const EdgeInsets.only(
@ -178,9 +220,9 @@ class _DidvanPageViewState extends State<DidvanPageView> {
),
),
Positioned(
child: _BackButton(scrollController: widget.scrollController),
right: 24,
top: 24 + deviceTopPadding,
child: _BackButton(scrollController: widget.scrollController),
),
],
);
@ -272,7 +314,7 @@ class _DidvanPageViewState extends State<DidvanPageView> {
direction: TextDirection.rtl,
textAlign: TextAlign.right,
lineHeight: LineHeight.percent(135),
margin: EdgeInsets.zero,
margin: const Margins(),
padding: EdgeInsets.zero,
),
'a': Style(

View File

@ -16,7 +16,7 @@ class DidvanSwitch extends StatefulWidget {
}) : super(key: key);
@override
_DidvanSwitchState createState() => _DidvanSwitchState();
State<DidvanSwitch> createState() => _DidvanSwitchState();
}
class _DidvanSwitchState extends State<DidvanSwitch> {

View File

@ -1,34 +1,41 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_flutterfire_internals:
dependency: transitive
description:
name: _flutterfire_internals
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.9"
assets_audio_player:
dependency: "direct main"
description:
name: assets_audio_player
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.5"
version: "3.0.6"
assets_audio_player_web:
dependency: transitive
description:
name: assets_audio_player_web
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.5"
version: "3.0.6"
async:
dependency: transitive
description:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.2"
version: "2.9.0"
audio_video_progress_bar:
dependency: "direct main"
description:
name: audio_video_progress_bar
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.0"
version: "0.11.0"
better_player:
dependency: "direct main"
description:
@ -56,21 +63,21 @@ packages:
name: cached_network_image
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.1"
version: "3.2.3"
cached_network_image_platform_interface:
dependency: transitive
description:
name: cached_network_image_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
version: "2.0.0"
cached_network_image_web:
dependency: transitive
description:
name: cached_network_image_web
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
version: "1.0.2"
carousel_slider:
dependency: "direct main"
description:
@ -84,7 +91,7 @@ packages:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "1.2.1"
charcode:
dependency: transitive
description:
@ -98,7 +105,21 @@ packages:
name: clock
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.1.1"
cloud_firestore_platform_interface:
dependency: transitive
description:
name: cloud_firestore_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "5.9.0"
cloud_firestore_web:
dependency: transitive
description:
name: cloud_firestore_web
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
collection:
dependency: transitive
description:
@ -112,7 +133,7 @@ packages:
name: cross_file
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.3+1"
version: "0.3.3+2"
crypto:
dependency: transitive
description:
@ -140,14 +161,14 @@ packages:
name: day_night_time_picker
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.2"
version: "1.1.3"
equatable:
dependency: transitive
description:
name: equatable
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
version: "2.0.5"
expandable_bottom_sheet:
dependency: "direct main"
description:
@ -161,7 +182,7 @@ packages:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
version: "1.3.1"
ffi:
dependency: transitive
description:
@ -175,56 +196,56 @@ packages:
name: file
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.2"
version: "6.1.4"
firebase_core:
dependency: "direct main"
description:
name: firebase_core
url: "https://pub.dartlang.org"
source: hosted
version: "1.19.2"
version: "2.3.0"
firebase_core_platform_interface:
dependency: transitive
description:
name: firebase_core_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "4.4.3"
version: "4.5.2"
firebase_core_web:
dependency: transitive
description:
name: firebase_core_web
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.0"
version: "2.0.1"
firebase_messaging:
dependency: "direct main"
description:
name: firebase_messaging
url: "https://pub.dartlang.org"
source: hosted
version: "11.4.4"
version: "14.1.3"
firebase_messaging_platform_interface:
dependency: transitive
description:
name: firebase_messaging_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "3.5.4"
version: "4.2.7"
firebase_messaging_web:
dependency: transitive
description:
name: firebase_messaging_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.4.4"
version: "3.2.8"
fl_chart:
dependency: "direct main"
description:
name: fl_chart
url: "https://pub.dartlang.org"
source: hosted
version: "0.50.6"
version: "0.55.2"
flutter:
dependency: "direct main"
description: flutter
@ -250,14 +271,14 @@ packages:
name: flutter_html
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0-alpha.5"
version: "3.0.0-alpha.6"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
version: "2.0.1"
flutter_localizations:
dependency: "direct main"
description: flutter
@ -276,42 +297,42 @@ packages:
name: flutter_secure_storage
url: "https://pub.dartlang.org"
source: hosted
version: "5.0.2"
version: "6.1.0"
flutter_secure_storage_linux:
dependency: transitive
description:
name: flutter_secure_storage_linux
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.1.2"
flutter_secure_storage_macos:
dependency: transitive
description:
name: flutter_secure_storage_macos
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.1.2"
flutter_secure_storage_platform_interface:
dependency: transitive
description:
name: flutter_secure_storage_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
version: "1.0.1"
flutter_secure_storage_web:
dependency: transitive
description:
name: flutter_secure_storage_web
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
version: "1.1.1"
flutter_secure_storage_windows:
dependency: transitive
description:
name: flutter_secure_storage_windows
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.2"
version: "1.1.3"
flutter_spinkit:
dependency: "direct main"
description:
@ -325,7 +346,7 @@ packages:
name: flutter_svg
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1+1"
version: "1.1.6"
flutter_test:
dependency: "direct dev"
description: flutter
@ -356,77 +377,91 @@ packages:
name: fwfh_text_style
url: "https://pub.dartlang.org"
source: hosted
version: "2.7.3+2"
version: "2.22.08+1"
graphs:
dependency: transitive
description:
name: graphs
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.2.0"
html:
dependency: transitive
description:
name: html
url: "https://pub.dartlang.org"
source: hosted
version: "0.15.0"
version: "0.15.1"
http:
dependency: transitive
description:
name: http
url: "https://pub.dartlang.org"
source: hosted
version: "0.13.4"
version: "0.13.5"
http_parser:
dependency: transitive
description:
name: http_parser
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.1"
version: "4.0.2"
image_cropper:
dependency: "direct main"
description:
name: image_cropper
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.1"
version: "3.0.1"
image_cropper_for_web:
dependency: transitive
description:
name: image_cropper_for_web
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
image_cropper_platform_interface:
dependency: transitive
description:
name: image_cropper_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.3"
image_picker:
dependency: "direct main"
description:
name: image_picker
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.5+3"
version: "0.8.6"
image_picker_android:
dependency: transitive
description:
name: image_picker_android
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.5+1"
version: "0.8.5+3"
image_picker_for_web:
dependency: transitive
description:
name: image_picker_for_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.8"
version: "2.1.10"
image_picker_ios:
dependency: transitive
description:
name: image_picker_ios
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.5+6"
version: "0.8.6+1"
image_picker_platform_interface:
dependency: transitive
description:
name: image_picker_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.5.0"
version: "2.6.2"
intl:
dependency: transitive
description:
@ -447,28 +482,28 @@ packages:
name: lints
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
version: "2.0.1"
matcher:
dependency: transitive
description:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.11"
version: "0.12.12"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.4"
version: "0.1.5"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.0"
version: "1.8.0"
nested:
dependency: transitive
description:
@ -482,7 +517,7 @@ packages:
name: numerus
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
version: "2.0.0"
octo_image:
dependency: transitive
description:
@ -496,21 +531,21 @@ packages:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.1"
version: "1.8.2"
path_drawing:
dependency: transitive
description:
name: path_drawing
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
version: "1.0.1"
path_parsing:
dependency: transitive
description:
name: path_parsing
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
version: "1.0.1"
path_provider:
dependency: "direct main"
description:
@ -524,14 +559,14 @@ packages:
name: path_provider_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.16"
version: "2.0.22"
path_provider_ios:
dependency: transitive
description:
name: path_provider_ios
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.10"
version: "2.0.11"
path_provider_linux:
dependency: transitive
description:
@ -552,14 +587,14 @@ packages:
name: path_provider_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
version: "2.0.5"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.1.3"
pedantic:
dependency: transitive
description:
@ -573,35 +608,35 @@ packages:
name: permission_handler
url: "https://pub.dartlang.org"
source: hosted
version: "9.2.0"
version: "10.2.0"
permission_handler_android:
dependency: transitive
description:
name: permission_handler_android
url: "https://pub.dartlang.org"
source: hosted
version: "9.0.2+1"
version: "10.2.0"
permission_handler_apple:
dependency: transitive
description:
name: permission_handler_apple
url: "https://pub.dartlang.org"
source: hosted
version: "9.0.4"
version: "9.0.7"
permission_handler_platform_interface:
dependency: transitive
description:
name: permission_handler_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "3.7.0"
version: "3.9.0"
permission_handler_windows:
dependency: transitive
description:
name: permission_handler_windows
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0"
version: "0.1.2"
persian_datetime_picker:
dependency: "direct main"
description:
@ -622,7 +657,7 @@ packages:
name: petitparser
url: "https://pub.dartlang.org"
source: hosted
version: "5.0.0"
version: "5.1.0"
pin_code_fields:
dependency: "direct main"
description:
@ -643,7 +678,7 @@ packages:
name: plugin_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
version: "2.1.3"
process:
dependency: transitive
description:
@ -657,42 +692,63 @@ packages:
name: provider
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.3"
version: "6.0.4"
record:
dependency: "direct main"
description:
name: record
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.4"
version: "4.4.3"
record_linux:
dependency: transitive
description:
name: record_linux
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.4"
record_macos:
dependency: transitive
description:
name: record_macos
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.2"
record_platform_interface:
dependency: transitive
description:
name: record_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
version: "0.5.0"
record_web:
dependency: "direct main"
description:
name: record_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.1"
version: "0.5.0"
record_windows:
dependency: transitive
description:
name: record_windows
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.2"
rive:
dependency: "direct main"
description:
name: rive
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.33"
version: "0.9.1"
rxdart:
dependency: transitive
description:
name: rxdart
url: "https://pub.dartlang.org"
source: hosted
version: "0.27.5"
version: "0.27.7"
skeleton_text:
dependency: "direct main"
description:
@ -711,21 +767,21 @@ packages:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.2"
version: "1.9.0"
sqflite:
dependency: transitive
description:
name: sqflite
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
version: "2.2.1"
sqflite_common:
dependency: transitive
description:
name: sqflite_common
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1+1"
version: "2.4.0+2"
stack_trace:
dependency: transitive
description:
@ -746,28 +802,28 @@ packages:
name: string_scanner
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.1.1"
synchronized:
dependency: transitive
description:
name: synchronized
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0+2"
version: "3.0.0+3"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "1.2.1"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.9"
version: "0.4.12"
typed_data:
dependency: transitive
description:
@ -795,14 +851,14 @@ packages:
name: url_launcher
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.5"
version: "6.1.7"
url_launcher_android:
dependency: transitive
description:
name: url_launcher_android
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.17"
version: "6.0.22"
url_launcher_ios:
dependency: transitive
description:
@ -830,14 +886,14 @@ packages:
name: url_launcher_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.1.1"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.12"
version: "2.0.13"
url_launcher_windows:
dependency: transitive
description:
@ -851,7 +907,7 @@ packages:
name: uuid
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.6"
version: "3.0.7"
vector_math:
dependency: transitive
description:
@ -900,7 +956,7 @@ packages:
name: wakelock_windows
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
version: "0.2.1"
webview_flutter:
dependency: "direct main"
description:
@ -914,35 +970,35 @@ packages:
name: webview_flutter_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.14"
version: "2.10.4"
webview_flutter_platform_interface:
dependency: transitive
description:
name: webview_flutter_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.9.1"
version: "1.9.5"
webview_flutter_wkwebview:
dependency: transitive
description:
name: webview_flutter_wkwebview
url: "https://pub.dartlang.org"
source: hosted
version: "2.9.1"
version: "2.9.5"
win32:
dependency: transitive
description:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "2.7.0"
version: "3.1.2"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0+1"
version: "0.2.0+2"
xml:
dependency: transitive
description:
@ -951,5 +1007,5 @@ packages:
source: hosted
version: "6.1.0"
sdks:
dart: ">=2.17.0 <3.0.0"
flutter: ">=3.0.0"
dart: ">=2.18.0 <3.0.0"
flutter: ">=3.3.0"

View File

@ -37,7 +37,7 @@ dependencies:
cupertino_icons: ^1.0.2
provider: ^6.0.1
pin_code_fields: ^7.3.0
rive: ^0.7.33
rive: ^0.9.1
image_picker: ^0.8.4+4
day_night_time_picker: ^1.0.5
path_provider: ^2.0.8
@ -48,24 +48,24 @@ dependencies:
carousel_slider: ^4.0.0
flutter_vibrate: ^1.3.0
universal_html: ^2.0.8
record: ^3.0.2
record_web: ^0.2.1
record: ^4.4.3
record_web: ^0.5.0
persian_datetime_picker: ^2.4.0
persian_number_utility: ^1.1.1
bot_toast: ^4.0.1
flutter_secure_storage: ^5.0.2
flutter_secure_storage: ^6.1.0
flutter_html: ^3.0.0-alpha.2
url_launcher: ^6.0.18
audio_video_progress_bar: ^0.10.0
image_cropper: ^1.5.0
firebase_messaging: ^11.2.8
firebase_core: ^1.13.1
audio_video_progress_bar: ^0.11.0
image_cropper: ^3.0.1
firebase_messaging: ^14.1.3
firebase_core: ^2.3.0
webview_flutter: ^3.0.1
expandable_bottom_sheet: ^1.1.1+1
permission_handler: ^9.2.0
permission_handler: ^10.2.0
better_player: ^0.0.81
assets_audio_player: ^3.0.4+1
fl_chart: ^0.50.1
fl_chart: ^0.55.2
dev_dependencies:
flutter_test:
@ -76,7 +76,7 @@ dev_dependencies:
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^1.0.0
flutter_lints: ^2.0.1
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec