D1APP-99 studio
This commit is contained in:
parent
00e00b0ec5
commit
d869f54338
|
|
@ -3,10 +3,14 @@
|
||||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<application
|
<application
|
||||||
android:label="Didvan"
|
android:label="Didvan"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:usesCleartextTraffic="true">
|
android:usesCleartextTraffic="true"
|
||||||
|
android:requestLegacyExternalStorage="true">
|
||||||
|
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
|
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
import 'dart:io';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:http_parser/http_parser.dart' as parser;
|
import 'package:http_parser/http_parser.dart' as parser;
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
|
||||||
class RequestService {
|
class RequestService {
|
||||||
static late String token;
|
static late String token;
|
||||||
|
|
@ -162,6 +164,13 @@ class RequestService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> download() async {
|
||||||
|
Permission.manageExternalStorage.request();
|
||||||
|
final response = await http.get(Uri.parse(url));
|
||||||
|
final file = await File('/storage/emulated/0/Download/file.mp3').create();
|
||||||
|
await file.writeAsBytes(response.bodyBytes);
|
||||||
|
}
|
||||||
|
|
||||||
void _handleResponse(http.Response? response) {
|
void _handleResponse(http.Response? response) {
|
||||||
statusCode = response?.statusCode;
|
statusCode = response?.statusCode;
|
||||||
if (_handleError(response)) {
|
if (_handleError(response)) {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import 'package:didvan/views/home/radar/radar.dart';
|
||||||
import 'package:didvan/views/home/settings/settings.dart';
|
import 'package:didvan/views/home/settings/settings.dart';
|
||||||
import 'package:didvan/views/home/statistics/statistics.dart';
|
import 'package:didvan/views/home/statistics/statistics.dart';
|
||||||
import 'package:didvan/views/home/studio/studio.dart';
|
import 'package:didvan/views/home/studio/studio.dart';
|
||||||
import 'package:didvan/views/home/widgets/bnb.dart';
|
import 'package:didvan/views/widgets/didvan/bnb.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,10 @@ class _StudioState extends State<Studio> {
|
||||||
icon: DidvanIcons.bookmark_regular,
|
icon: DidvanIcons.bookmark_regular,
|
||||||
onPressed: () => Navigator.of(context).pushNamed(
|
onPressed: () => Navigator.of(context).pushNamed(
|
||||||
Routes.filteredBookmarks,
|
Routes.filteredBookmarks,
|
||||||
arguments: context.read<StudioState>().type,
|
arguments: {
|
||||||
|
'type': context.read<StudioState>().type,
|
||||||
|
'onDeleted': (_) {}
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -84,9 +84,11 @@ class _StudioDetailsState extends State<StudioDetails> {
|
||||||
return Consumer<StudioDetailsState>(
|
return Consumer<StudioDetailsState>(
|
||||||
builder: (context, state, child) => StateHandler<StudioDetailsState>(
|
builder: (context, state, child) => StateHandler<StudioDetailsState>(
|
||||||
state: state,
|
state: state,
|
||||||
onRetry: () => state.getStudioDetails(state.currentStudio.id),
|
onRetry: () => state.getStudioDetails(state.studio.id),
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state.studios.isEmpty) {
|
if (state.prevStudio == null &&
|
||||||
|
state.nextStudio == null &&
|
||||||
|
state.args.page != 0) {
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
return WillPopScope(
|
return WillPopScope(
|
||||||
|
|
@ -105,7 +107,7 @@ class _StudioDetailsState extends State<StudioDetails> {
|
||||||
? null
|
? null
|
||||||
: AppBarData(
|
: AppBarData(
|
||||||
isSmall: true,
|
isSmall: true,
|
||||||
title: state.currentStudio.title,
|
title: state.studio.title,
|
||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
|
|
@ -146,7 +148,7 @@ class _StudioDetailsState extends State<StudioDetails> {
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
${state.currentStudio.media}
|
${state.studio.media}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
''',
|
''',
|
||||||
|
|
@ -171,12 +173,15 @@ class _StudioDetailsState extends State<StudioDetails> {
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
StudioDetailsWidget(
|
StudioDetailsWidget(
|
||||||
onCommentsTabSelected: () => _scrollController.animateTo(
|
onCommentsTabSelected: () => Future.delayed(
|
||||||
_scrollController.position.maxScrollExtent,
|
const Duration(milliseconds: 100),
|
||||||
duration: DesignConfig.lowAnimationDuration,
|
() => _scrollController.animateTo(
|
||||||
curve: Curves.easeIn,
|
_scrollController.position.maxScrollExtent,
|
||||||
|
duration: DesignConfig.lowAnimationDuration,
|
||||||
|
curve: Curves.easeIn,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
studio: state.currentStudio,
|
studio: state.studio,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -86,25 +86,25 @@ class _StudioDetailsState extends State<StudioDetails> {
|
||||||
return Consumer<StudioDetailsState>(
|
return Consumer<StudioDetailsState>(
|
||||||
builder: (context, state, child) => StateHandler<StudioDetailsState>(
|
builder: (context, state, child) => StateHandler<StudioDetailsState>(
|
||||||
state: state,
|
state: state,
|
||||||
onRetry: () => state.getStudioDetails(state.currentStudio.id),
|
onRetry: () => state.getStudioDetails(state.studio.id),
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state.studios.isEmpty) {
|
if (state.prevStudio == null &&
|
||||||
|
state.nextStudio == null &&
|
||||||
|
state.args.page != 0) {
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
if (kIsWeb) {
|
// ignore: undefined_prefixed_name
|
||||||
// ignore: undefined_prefixed_name
|
ui.platformViewRegistry.registerViewFactory(
|
||||||
ui.platformViewRegistry.registerViewFactory(
|
"video",
|
||||||
"video",
|
(int viewId) => html.IFrameElement()
|
||||||
(int viewId) => html.IFrameElement()
|
..allowFullscreen = true
|
||||||
..allowFullscreen = true
|
..src = Uri.dataFromString(
|
||||||
..src = Uri.dataFromString(
|
'<style>*{padding: 0 ; margin: 0; background: black;}</style>' +
|
||||||
'<style>*{padding: 0 ; margin: 0; background: black;}</style>' +
|
state.studio.media,
|
||||||
state.currentStudio.media,
|
mimeType: 'text/html',
|
||||||
mimeType: 'text/html',
|
).toString()
|
||||||
).toString()
|
..style.border = 'none',
|
||||||
..style.border = 'none',
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
return WillPopScope(
|
return WillPopScope(
|
||||||
onWillPop: () async {
|
onWillPop: () async {
|
||||||
if (_isFullScreen) {
|
if (_isFullScreen) {
|
||||||
|
|
@ -120,7 +120,7 @@ class _StudioDetailsState extends State<StudioDetails> {
|
||||||
? null
|
? null
|
||||||
: AppBarData(
|
: AppBarData(
|
||||||
isSmall: true,
|
isSmall: true,
|
||||||
title: state.currentStudio.title,
|
title: state.studio.title,
|
||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
if (kIsWeb)
|
if (kIsWeb)
|
||||||
|
|
@ -167,7 +167,7 @@ class _StudioDetailsState extends State<StudioDetails> {
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
${state.currentStudio.media}
|
${state.studio.media}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
''',
|
''',
|
||||||
|
|
@ -193,12 +193,15 @@ class _StudioDetailsState extends State<StudioDetails> {
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
StudioDetailsWidget(
|
StudioDetailsWidget(
|
||||||
onCommentsTabSelected: () => _scrollController.animateTo(
|
onCommentsTabSelected: () => Future.delayed(
|
||||||
_scrollController.position.maxScrollExtent,
|
const Duration(milliseconds: 100),
|
||||||
duration: DesignConfig.lowAnimationDuration,
|
() => _scrollController.animateTo(
|
||||||
curve: Curves.easeIn,
|
_scrollController.position.maxScrollExtent,
|
||||||
|
duration: DesignConfig.lowAnimationDuration,
|
||||||
|
curve: Curves.easeIn,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
studio: state.currentStudio,
|
studio: state.studio,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:math';
|
|
||||||
|
|
||||||
import 'package:didvan/models/enums.dart';
|
import 'package:didvan/models/enums.dart';
|
||||||
import 'package:didvan/models/overview_data.dart';
|
import 'package:didvan/models/overview_data.dart';
|
||||||
|
|
@ -11,16 +10,17 @@ import 'package:didvan/services/network/request.dart';
|
||||||
import 'package:didvan/services/network/request_helper.dart';
|
import 'package:didvan/services/network/request_helper.dart';
|
||||||
|
|
||||||
class StudioDetailsState extends CoreProvier {
|
class StudioDetailsState extends CoreProvier {
|
||||||
final List<StudioDetailsData?> studios = [];
|
late StudioDetailsData studio;
|
||||||
|
StudioDetailsData? nextStudio;
|
||||||
|
StudioDetailsData? prevStudio;
|
||||||
late int initialIndex;
|
late int initialIndex;
|
||||||
late StudioRequestArgs args;
|
late StudioRequestArgs args;
|
||||||
int _selectedDetailsIndex = 0;
|
|
||||||
bool isFetchingNewItem = false;
|
|
||||||
final List<int> relatedQueue = [];
|
final List<int> relatedQueue = [];
|
||||||
bool currentTypeIsVideo = true;
|
bool _positionListenerActivated = false;
|
||||||
|
|
||||||
int _currentIndex = 0;
|
int _selectedDetailsIndex = 0;
|
||||||
int get currentIndex => _currentIndex;
|
Timer? timer;
|
||||||
|
int timerValue = 10;
|
||||||
|
|
||||||
int get selectedDetailsIndex => _selectedDetailsIndex;
|
int get selectedDetailsIndex => _selectedDetailsIndex;
|
||||||
set selectedDetailsIndex(int value) {
|
set selectedDetailsIndex(int value) {
|
||||||
|
|
@ -31,83 +31,49 @@ class StudioDetailsState extends CoreProvier {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioDetailsData get currentStudio {
|
|
||||||
try {
|
|
||||||
return studios[_currentIndex]!;
|
|
||||||
} catch (e) {
|
|
||||||
return studios[_currentIndex + 1]!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> getStudioDetails(
|
Future<void> getStudioDetails(
|
||||||
int id, {
|
int id, {
|
||||||
bool? isForward,
|
|
||||||
StudioRequestArgs? args,
|
StudioRequestArgs? args,
|
||||||
|
bool? isForward,
|
||||||
}) async {
|
}) async {
|
||||||
if (args != null) {
|
if (args != null) {
|
||||||
this.args = args;
|
this.args = args;
|
||||||
}
|
}
|
||||||
if (isForward == null) {
|
if (MediaService.currentPodcast?.id == id && this.args.type == 'podcast') {
|
||||||
_selectedDetailsIndex = 0;
|
return;
|
||||||
appState = AppState.busy;
|
|
||||||
} else {
|
|
||||||
isFetchingNewItem = true;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
}
|
||||||
|
_selectedDetailsIndex = 0;
|
||||||
|
if (isForward != null) {
|
||||||
|
if (isForward) {
|
||||||
|
prevStudio = studio;
|
||||||
|
studio = nextStudio!;
|
||||||
|
nextStudio = null;
|
||||||
|
} else {
|
||||||
|
nextStudio = studio;
|
||||||
|
studio = prevStudio!;
|
||||||
|
prevStudio = null;
|
||||||
|
}
|
||||||
|
_handlePodcastPlayback(studio);
|
||||||
|
}
|
||||||
|
appState = AppState.busy;
|
||||||
final service = RequestService(RequestHelper.studioDetails(id, this.args));
|
final service = RequestService(RequestHelper.studioDetails(id, this.args));
|
||||||
await service.httpGet();
|
await service.httpGet();
|
||||||
if (service.isSuccess) {
|
if (service.isSuccess) {
|
||||||
studios.clear();
|
|
||||||
final result = service.result;
|
final result = service.result;
|
||||||
final studio = StudioDetailsData.fromJson(result['studio']);
|
studio = StudioDetailsData.fromJson(result['studio']);
|
||||||
await _handlePodcastPlayback(studio);
|
if (result['nextStudio'].isNotEmpty && this.args.page != 0) {
|
||||||
if (this.args.page == 0) {
|
|
||||||
studios.add(studio);
|
|
||||||
initialIndex = 0;
|
|
||||||
appState = AppState.idle;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
StudioDetailsData? prevStudio;
|
|
||||||
if (result['prevStudio'].isNotEmpty) {
|
|
||||||
prevStudio = StudioDetailsData.fromJson(result['prevStudio']);
|
|
||||||
}
|
|
||||||
|
|
||||||
StudioDetailsData? nextStudio;
|
|
||||||
if (result['nextStudio'].isNotEmpty) {
|
|
||||||
nextStudio = StudioDetailsData.fromJson(result['nextStudio']);
|
nextStudio = StudioDetailsData.fromJson(result['nextStudio']);
|
||||||
}
|
}
|
||||||
|
if (result['prevStudio'].isNotEmpty && this.args.page != 0) {
|
||||||
if (isForward == null) {
|
prevStudio = StudioDetailsData.fromJson(result['prevStudio']);
|
||||||
studios
|
}
|
||||||
.addAll(List.generate(max(studio.order - 2, 0), (index) => null));
|
if (isForward == null) {
|
||||||
if (prevStudio != null) {
|
await _handlePodcastPlayback(studio);
|
||||||
studios.add(prevStudio);
|
|
||||||
}
|
|
||||||
studios.add(studio);
|
|
||||||
if (nextStudio != null) {
|
|
||||||
studios.add(nextStudio);
|
|
||||||
}
|
|
||||||
_currentIndex = initialIndex = studio.order - 1;
|
|
||||||
} else if (isForward) {
|
|
||||||
if (!exists(nextStudio) && nextStudio != null) {
|
|
||||||
studios.add(nextStudio);
|
|
||||||
}
|
|
||||||
_currentIndex++;
|
|
||||||
} else if (!isForward) {
|
|
||||||
if (!exists(prevStudio) && prevStudio != null) {
|
|
||||||
studios[_currentIndex - 2] = prevStudio;
|
|
||||||
}
|
|
||||||
_currentIndex--;
|
|
||||||
}
|
}
|
||||||
isFetchingNewItem = false;
|
|
||||||
appState = AppState.idle;
|
appState = AppState.idle;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//why? total page state shouldn't die!
|
appState = AppState.failed;
|
||||||
if (isForward == null) {
|
|
||||||
appState = AppState.failed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _handlePodcastPlayback(StudioDetailsData studio) async {
|
Future<void> _handlePodcastPlayback(StudioDetailsData studio) async {
|
||||||
|
|
@ -118,37 +84,39 @@ class StudioDetailsState extends CoreProvier {
|
||||||
audioSource: studio.media,
|
audioSource: studio.media,
|
||||||
isVoiceMessage: false,
|
isVoiceMessage: false,
|
||||||
);
|
);
|
||||||
|
if (nextStudio != null && !_positionListenerActivated) {
|
||||||
|
_positionListenerActivated = true;
|
||||||
|
MediaService.audioPlayer.positionStream.listen((event) {
|
||||||
|
final duration = MediaService.audioPlayer.duration ??
|
||||||
|
Duration(seconds: studio.duration);
|
||||||
|
if (event.compareTo(duration) > 0 && nextStudio != null) {
|
||||||
|
getStudioDetails(nextStudio!.id, isForward: true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> getRelatedContents() async {
|
Future<void> getRelatedContents() async {
|
||||||
if (currentStudio.relatedContents.isNotEmpty) return;
|
if (studio.relatedContents.isNotEmpty) return;
|
||||||
relatedQueue.add(currentStudio.id);
|
relatedQueue.add(studio.id);
|
||||||
final service = RequestService(RequestHelper.tag(
|
final service = RequestService(RequestHelper.tag(
|
||||||
ids: currentStudio.tags.map((tag) => tag.id).toList(),
|
ids: studio.tags.map((tag) => tag.id).toList(),
|
||||||
itemId: currentStudio.id,
|
itemId: studio.id,
|
||||||
type: currentStudio.media.contains('iframe') ? 'video' : 'podcast',
|
type: studio.media.contains('iframe') ? 'video' : 'podcast',
|
||||||
));
|
));
|
||||||
await service.httpGet();
|
await service.httpGet();
|
||||||
if (service.isSuccess) {
|
if (service.isSuccess) {
|
||||||
final relateds = service.result['contents'];
|
final relateds = service.result['contents'];
|
||||||
for (var i = 0; i < relateds.length; i++) {
|
for (var i = 0; i < relateds.length; i++) {
|
||||||
studios
|
studio.relatedContents.add(OverviewData.fromJson(relateds[i]));
|
||||||
.where((element) => element != null)
|
|
||||||
.firstWhere((element) => element!.id == currentStudio.id)!
|
|
||||||
.relatedContents
|
|
||||||
.add(OverviewData.fromJson(relateds[i]));
|
|
||||||
}
|
}
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool exists(StudioDetailsData? studio) =>
|
|
||||||
studios.any((r) => studio != null && r != null && r.id == studio.id);
|
|
||||||
|
|
||||||
void onCommentsChanged(int count) {
|
void onCommentsChanged(int count) {
|
||||||
studios.firstWhere((studio) => studio?.id == currentStudio.id)!.comments =
|
studio.comments = count;
|
||||||
count;
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ class StudioDetailsWidget extends StatelessWidget {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
DidvanText(state.currentStudio.description),
|
DidvanText(state.studio.description),
|
||||||
if (studio.tags.isNotEmpty) const SizedBox(height: 20),
|
if (studio.tags.isNotEmpty) const SizedBox(height: 20),
|
||||||
Wrap(
|
Wrap(
|
||||||
spacing: 8,
|
spacing: 8,
|
||||||
|
|
@ -90,15 +90,15 @@ class StudioDetailsWidget extends StatelessWidget {
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(),
|
const SizedBox(),
|
||||||
if (state.studios.length != state.currentIndex + 1)
|
if (state.nextStudio != null)
|
||||||
_StudioPreview(
|
_StudioPreview(
|
||||||
isNext: true,
|
isNext: true,
|
||||||
studio: state.studios[state.currentIndex + 1]!,
|
studio: state.nextStudio!,
|
||||||
),
|
),
|
||||||
if (state.currentIndex != 0)
|
if (state.prevStudio != null)
|
||||||
_StudioPreview(
|
_StudioPreview(
|
||||||
isNext: false,
|
isNext: false,
|
||||||
studio: state.studios[state.currentIndex - 1]!,
|
studio: state.prevStudio!,
|
||||||
),
|
),
|
||||||
const SizedBox(),
|
const SizedBox(),
|
||||||
],
|
],
|
||||||
|
|
@ -234,7 +234,11 @@ class _StudioPreview extends StatelessWidget {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
final state = context.read<StudioDetailsState>();
|
final state = context.read<StudioDetailsState>();
|
||||||
state.getStudioDetails(studio.id, args: state.args);
|
state.getStudioDetails(
|
||||||
|
isNext ? state.nextStudio!.id : state.prevStudio!.id,
|
||||||
|
args: state.args,
|
||||||
|
isForward: isNext,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 88,
|
width: 88,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:didvan/models/enums.dart';
|
import 'package:didvan/models/enums.dart';
|
||||||
import 'package:didvan/models/overview_data.dart';
|
import 'package:didvan/models/overview_data.dart';
|
||||||
import 'package:didvan/models/requests/studio.dart';
|
import 'package:didvan/models/requests/studio.dart';
|
||||||
|
|
@ -117,4 +119,9 @@ class StudioState extends CoreProvier {
|
||||||
studios.firstWhere((radar) => radar.id == id).comments = count;
|
studios.firstWhere((radar) => radar.id == id).comments = count;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void download(String url) {
|
||||||
|
final service = RequestService(url);
|
||||||
|
service.download();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@ import 'package:carousel_slider/carousel_slider.dart';
|
||||||
import 'package:didvan/config/design_config.dart';
|
import 'package:didvan/config/design_config.dart';
|
||||||
import 'package:didvan/config/theme_data.dart';
|
import 'package:didvan/config/theme_data.dart';
|
||||||
import 'package:didvan/models/enums.dart';
|
import 'package:didvan/models/enums.dart';
|
||||||
|
import 'package:didvan/models/requests/studio.dart';
|
||||||
|
import 'package:didvan/routes/routes.dart';
|
||||||
|
import 'package:didvan/views/home/studio/studio_details/studio_details_state.dart';
|
||||||
import 'package:didvan/views/home/studio/studio_state.dart';
|
import 'package:didvan/views/home/studio/studio_state.dart';
|
||||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||||
import 'package:didvan/views/widgets/shimmer_placeholder.dart';
|
import 'package:didvan/views/widgets/shimmer_placeholder.dart';
|
||||||
|
|
@ -26,48 +29,75 @@ class _StudioSliderState extends State<StudioSlider> {
|
||||||
children: [
|
children: [
|
||||||
CarouselSlider(
|
CarouselSlider(
|
||||||
items: [
|
items: [
|
||||||
for (var i = 0; i < state.sliders.length; i++)
|
if (state.appState == AppState.busy)
|
||||||
Padding(
|
const Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
padding: EdgeInsets.symmetric(horizontal: 4),
|
||||||
child: state.appState == AppState.busy
|
child: ShimmerPlaceholder(),
|
||||||
? const ShimmerPlaceholder()
|
),
|
||||||
: Stack(
|
if (state.appState == AppState.idle)
|
||||||
children: [
|
for (var i = 0; i < state.sliders.length; i++)
|
||||||
SkeletonImage(
|
Padding(
|
||||||
borderRadius: DesignConfig.mediumBorderRadius,
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||||
imageUrl: state.sliders[i].image,
|
child: GestureDetector(
|
||||||
width: double.infinity,
|
onTap: () {
|
||||||
),
|
if (state.videosSelected) {
|
||||||
Positioned(
|
Navigator.of(context)
|
||||||
bottom: 0,
|
.pushNamed(Routes.studioDetails, arguments: {
|
||||||
left: 0,
|
'onMarkChanged': state.changeMark,
|
||||||
right: 0,
|
'id': state.sliders[i].id,
|
||||||
child: Container(
|
'args':
|
||||||
padding: const EdgeInsets.symmetric(
|
const StudioRequestArgs(page: 0, type: 'video'),
|
||||||
vertical: 4,
|
'hasUnmarkConfirmation': false,
|
||||||
horizontal: 8,
|
'isVideo': true,
|
||||||
),
|
});
|
||||||
decoration: BoxDecoration(
|
return;
|
||||||
color: (state.videosSelected
|
}
|
||||||
? Theme.of(context)
|
context.read<StudioDetailsState>().getStudioDetails(
|
||||||
.colorScheme
|
state.sliders[i].id,
|
||||||
.secondaryDisabled
|
args: const StudioRequestArgs(
|
||||||
: Theme.of(context).colorScheme.focused)
|
page: 0,
|
||||||
.withOpacity(0.9),
|
type: 'podcast',
|
||||||
borderRadius: const BorderRadius.vertical(
|
),
|
||||||
bottom: Radius.circular(10),
|
);
|
||||||
),
|
},
|
||||||
),
|
child: Stack(
|
||||||
child: DidvanText(
|
children: [
|
||||||
state.sliders[i].title,
|
SkeletonImage(
|
||||||
color: Theme.of(context).colorScheme.title,
|
borderRadius: DesignConfig.mediumBorderRadius,
|
||||||
style: Theme.of(context).textTheme.caption,
|
imageUrl: state.sliders[i].image,
|
||||||
|
width: double.infinity,
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 4,
|
||||||
|
horizontal: 8,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: (state.videosSelected
|
||||||
|
? Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.secondaryDisabled
|
||||||
|
: Theme.of(context).colorScheme.focused)
|
||||||
|
.withOpacity(0.9),
|
||||||
|
borderRadius: const BorderRadius.vertical(
|
||||||
|
bottom: Radius.circular(10),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
child: DidvanText(
|
||||||
|
state.sliders[i].title,
|
||||||
|
color: Theme.of(context).colorScheme.title,
|
||||||
|
style: Theme.of(context).textTheme.caption,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options: CarouselOptions(
|
options: CarouselOptions(
|
||||||
onPageChanged: (index, reason) => setState(
|
onPageChanged: (index, reason) => setState(
|
||||||
|
|
@ -75,7 +105,7 @@ class _StudioSliderState extends State<StudioSlider> {
|
||||||
),
|
),
|
||||||
viewportFraction: 0.94,
|
viewportFraction: 0.94,
|
||||||
aspectRatio: 16 / 9,
|
aspectRatio: 16 / 9,
|
||||||
autoPlay: true,
|
autoPlay: state.appState == AppState.idle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,21 @@
|
||||||
|
import 'dart:async';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:didvan/config/design_config.dart';
|
import 'package:didvan/config/design_config.dart';
|
||||||
import 'package:didvan/config/theme_data.dart';
|
import 'package:didvan/config/theme_data.dart';
|
||||||
import 'package:didvan/constants/app_icons.dart';
|
import 'package:didvan/constants/app_icons.dart';
|
||||||
import 'package:didvan/models/studio_details_data.dart';
|
import 'package:didvan/models/studio_details_data.dart';
|
||||||
|
import 'package:didvan/models/view/action_sheet_data.dart';
|
||||||
import 'package:didvan/services/media/media.dart';
|
import 'package:didvan/services/media/media.dart';
|
||||||
|
import 'package:didvan/utils/action_sheet.dart';
|
||||||
|
import 'package:didvan/views/home/studio/studio_details/studio_details_state.dart';
|
||||||
import 'package:didvan/views/home/studio/studio_state.dart';
|
import 'package:didvan/views/home/studio/studio_state.dart';
|
||||||
import 'package:didvan/views/home/widgets/audio/audio_slider.dart';
|
import 'package:didvan/views/home/widgets/audio/audio_slider.dart';
|
||||||
import 'package:didvan/views/home/widgets/bookmark_button.dart';
|
import 'package:didvan/views/home/widgets/bookmark_button.dart';
|
||||||
import 'package:didvan/views/widgets/didvan/icon_button.dart';
|
import 'package:didvan/views/widgets/didvan/icon_button.dart';
|
||||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||||
import 'package:didvan/views/widgets/ink_wrapper.dart';
|
import 'package:didvan/views/widgets/ink_wrapper.dart';
|
||||||
|
import 'package:didvan/views/widgets/item_title.dart';
|
||||||
import 'package:didvan/views/widgets/skeleton_image.dart';
|
import 'package:didvan/views/widgets/skeleton_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
@ -21,6 +26,7 @@ class AudioPlayerWidget extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final state = context.read<StudioDetailsState>();
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(8)),
|
borderRadius: const BorderRadius.vertical(top: Radius.circular(8)),
|
||||||
|
|
@ -60,13 +66,34 @@ class AudioPlayerWidget extends StatelessWidget {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
DidvanIconButton(
|
const SizedBox(),
|
||||||
icon: DidvanIcons.sleep_timer_regular,
|
StatefulBuilder(
|
||||||
onPressed: () {},
|
builder: (context, setState) => Column(
|
||||||
|
children: [
|
||||||
|
DidvanIconButton(
|
||||||
|
icon: state.timer == null
|
||||||
|
? DidvanIcons.sleep_timer_regular
|
||||||
|
: DidvanIcons.sleep_enabled_regular,
|
||||||
|
color: Theme.of(context).colorScheme.title,
|
||||||
|
onPressed: () => _showSleepTimer(
|
||||||
|
state,
|
||||||
|
() => setState(() {}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (state.timer != null)
|
||||||
|
DidvanText(
|
||||||
|
state.timerValue.toString() + '\'',
|
||||||
|
isEnglishFont: true,
|
||||||
|
style: Theme.of(context).textTheme.overline,
|
||||||
|
color: Theme.of(context).colorScheme.caption,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
DidvanIconButton(
|
DidvanIconButton(
|
||||||
|
color: Theme.of(context).colorScheme.title,
|
||||||
size: 32,
|
size: 32,
|
||||||
icon: DidvanIcons.media_forward_solid,
|
icon: DidvanIcons.media_forward_solid,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
|
@ -78,7 +105,11 @@ class AudioPlayerWidget extends StatelessWidget {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const DidvanText('30', isEnglishFont: true),
|
DidvanText(
|
||||||
|
'30',
|
||||||
|
isEnglishFont: true,
|
||||||
|
color: Theme.of(context).colorScheme.title,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
StreamBuilder<bool>(
|
StreamBuilder<bool>(
|
||||||
|
|
@ -94,6 +125,7 @@ class AudioPlayerWidget extends StatelessWidget {
|
||||||
DidvanIconButton(
|
DidvanIconButton(
|
||||||
size: 32,
|
size: 32,
|
||||||
icon: DidvanIcons.media_backward_solid,
|
icon: DidvanIcons.media_backward_solid,
|
||||||
|
color: Theme.of(context).colorScheme.title,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
MediaService.audioPlayer.seek(
|
MediaService.audioPlayer.seek(
|
||||||
Duration(
|
Duration(
|
||||||
|
|
@ -105,21 +137,104 @@ class AudioPlayerWidget extends StatelessWidget {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const DidvanText('10', isEnglishFont: true),
|
DidvanText(
|
||||||
|
'10',
|
||||||
|
isEnglishFont: true,
|
||||||
|
color: Theme.of(context).colorScheme.title,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
BookmarkButton(
|
BookmarkButton(
|
||||||
gestureSize: 48,
|
gestureSize: 48,
|
||||||
|
color: Theme.of(context).colorScheme.title,
|
||||||
value: podcast.marked,
|
value: podcast.marked,
|
||||||
onMarkChanged: (value) =>
|
onMarkChanged: (value) =>
|
||||||
context.read<StudioState>().changeMark(podcast.id, value),
|
context.read<StudioState>().changeMark(podcast.id, value),
|
||||||
),
|
),
|
||||||
|
const SizedBox(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _showSleepTimer(StudioDetailsState state, update) async {
|
||||||
|
int timerValue = 10;
|
||||||
|
final controller = FixedExtentScrollController();
|
||||||
|
Future.delayed(
|
||||||
|
const Duration(milliseconds: 100),
|
||||||
|
() => controller.animateTo(
|
||||||
|
50 * (state.timerValue / 5 - 2),
|
||||||
|
duration: DesignConfig.lowAnimationDuration,
|
||||||
|
curve: Curves.easeIn,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await ActionSheetUtils.showBottomSheet(
|
||||||
|
data: ActionSheetData(
|
||||||
|
content: StatefulBuilder(
|
||||||
|
builder: (context, setState) => Column(
|
||||||
|
children: [
|
||||||
|
const ItemTitle(
|
||||||
|
title: 'زمان خواب',
|
||||||
|
icon: DidvanIcons.sleep_timer_regular,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
DidvanText(
|
||||||
|
timerValue.toString() + ' دقیقه',
|
||||||
|
style: Theme.of(context).textTheme.headline3,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
const Icon(DidvanIcons.caret_down_solid),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
SizedBox(
|
||||||
|
height: 50,
|
||||||
|
child: RotatedBox(
|
||||||
|
quarterTurns: 3,
|
||||||
|
child: ListWheelScrollView(
|
||||||
|
controller: controller,
|
||||||
|
physics: const FixedExtentScrollPhysics(),
|
||||||
|
itemExtent: 48,
|
||||||
|
onSelectedItemChanged: (index) {
|
||||||
|
final minutes = (index + 2) * 5;
|
||||||
|
timerValue = minutes;
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
for (var i = 0; i < 9; i++)
|
||||||
|
Center(
|
||||||
|
child: Container(
|
||||||
|
color: Theme.of(context).colorScheme.text,
|
||||||
|
width: 50,
|
||||||
|
height: 3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onConfirmed: () {
|
||||||
|
state.timer = Timer(
|
||||||
|
Duration(minutes: timerValue),
|
||||||
|
MediaService.audioPlayer.stop,
|
||||||
|
);
|
||||||
|
state.timerValue = timerValue;
|
||||||
|
update();
|
||||||
|
},
|
||||||
|
dismissTitle: 'لغو',
|
||||||
|
onDismissed: () {
|
||||||
|
state.timer?.cancel();
|
||||||
|
state.timer = null;
|
||||||
|
state.timerValue = 10;
|
||||||
|
update();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
controller.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PlayPouseAnimatedIcon extends StatefulWidget {
|
class _PlayPouseAnimatedIcon extends StatefulWidget {
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ class AudioSlider extends StatelessWidget {
|
||||||
timeLabelTextStyle: TextStyle(
|
timeLabelTextStyle: TextStyle(
|
||||||
fontSize: showTimer ? null : 0,
|
fontSize: showTimer ? null : 0,
|
||||||
height: showTimer ? 3 : 0,
|
height: showTimer ? 3 : 0,
|
||||||
|
color: Theme.of(context).colorScheme.text,
|
||||||
fontFamily: DesignConfig.fontFamily.replaceAll(
|
fontFamily: DesignConfig.fontFamily.replaceAll(
|
||||||
'-FA',
|
'-FA',
|
||||||
'',
|
'',
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class BookmarkButton extends StatefulWidget {
|
class BookmarkButton extends StatefulWidget {
|
||||||
final bool value;
|
final bool value;
|
||||||
|
final Color? color;
|
||||||
final void Function(bool value) onMarkChanged;
|
final void Function(bool value) onMarkChanged;
|
||||||
final bool askForConfirmation;
|
final bool askForConfirmation;
|
||||||
final double gestureSize;
|
final double gestureSize;
|
||||||
|
|
@ -16,6 +17,7 @@ class BookmarkButton extends StatefulWidget {
|
||||||
required this.onMarkChanged,
|
required this.onMarkChanged,
|
||||||
this.askForConfirmation = false,
|
this.askForConfirmation = false,
|
||||||
required this.gestureSize,
|
required this.gestureSize,
|
||||||
|
this.color,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -41,6 +43,7 @@ class _BookmarkButtonState extends State<BookmarkButton> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return DidvanIconButton(
|
return DidvanIconButton(
|
||||||
gestureSize: widget.gestureSize,
|
gestureSize: widget.gestureSize,
|
||||||
|
color: widget.color,
|
||||||
icon: _value ? DidvanIcons.bookmark_solid : DidvanIcons.bookmark_regular,
|
icon: _value ? DidvanIcons.bookmark_solid : DidvanIcons.bookmark_regular,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
bool confirm = false;
|
bool confirm = false;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import 'package:didvan/models/overview_data.dart';
|
||||||
import 'package:didvan/models/requests/studio.dart';
|
import 'package:didvan/models/requests/studio.dart';
|
||||||
import 'package:didvan/utils/date_time.dart';
|
import 'package:didvan/utils/date_time.dart';
|
||||||
import 'package:didvan/views/home/studio/studio_details/studio_details_state.dart';
|
import 'package:didvan/views/home/studio/studio_details/studio_details_state.dart';
|
||||||
|
import 'package:didvan/views/home/studio/studio_state.dart';
|
||||||
import 'package:didvan/views/home/widgets/bookmark_button.dart';
|
import 'package:didvan/views/home/widgets/bookmark_button.dart';
|
||||||
import 'package:didvan/views/home/widgets/duration_widget.dart';
|
import 'package:didvan/views/home/widgets/duration_widget.dart';
|
||||||
import 'package:didvan/views/widgets/didvan/card.dart';
|
import 'package:didvan/views/widgets/didvan/card.dart';
|
||||||
|
|
@ -77,12 +78,13 @@ class PodcastOverview extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
DurationWidget(duration: podcast.duration!),
|
DurationWidget(duration: podcast.duration!),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
DidvanIconButton(
|
// DidvanIconButton(
|
||||||
gestureSize: 28,
|
// gestureSize: 28,
|
||||||
icon: DidvanIcons.download_regular,
|
// icon: DidvanIcons.download_regular,
|
||||||
onPressed: () {},
|
// onPressed: () =>
|
||||||
),
|
// context.read<StudioState>().download(podcast.media!),
|
||||||
const SizedBox(width: 16),
|
// ),
|
||||||
|
// const SizedBox(width: 16),
|
||||||
BookmarkButton(
|
BookmarkButton(
|
||||||
askForConfirmation: hasUnmarkConfirmation,
|
askForConfirmation: hasUnmarkConfirmation,
|
||||||
gestureSize: 24,
|
gestureSize: 24,
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import 'package:didvan/models/overview_data.dart';
|
||||||
import 'package:didvan/models/requests/studio.dart';
|
import 'package:didvan/models/requests/studio.dart';
|
||||||
import 'package:didvan/routes/routes.dart';
|
import 'package:didvan/routes/routes.dart';
|
||||||
import 'package:didvan/utils/date_time.dart';
|
import 'package:didvan/utils/date_time.dart';
|
||||||
|
import 'package:didvan/views/home/studio/studio_state.dart';
|
||||||
import 'package:didvan/views/home/widgets/bookmark_button.dart';
|
import 'package:didvan/views/home/widgets/bookmark_button.dart';
|
||||||
import 'package:didvan/views/home/widgets/duration_widget.dart';
|
import 'package:didvan/views/home/widgets/duration_widget.dart';
|
||||||
import 'package:didvan/views/widgets/didvan/card.dart';
|
import 'package:didvan/views/widgets/didvan/card.dart';
|
||||||
|
|
@ -13,6 +14,7 @@ import 'package:didvan/views/widgets/didvan/text.dart';
|
||||||
import 'package:didvan/views/widgets/shimmer_placeholder.dart';
|
import 'package:didvan/views/widgets/shimmer_placeholder.dart';
|
||||||
import 'package:didvan/views/widgets/skeleton_image.dart';
|
import 'package:didvan/views/widgets/skeleton_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class VideoOverview extends StatelessWidget {
|
class VideoOverview extends StatelessWidget {
|
||||||
final OverviewData video;
|
final OverviewData video;
|
||||||
|
|
@ -99,12 +101,13 @@ class VideoOverview extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
DurationWidget(duration: video.duration!),
|
DurationWidget(duration: video.duration!),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
DidvanIconButton(
|
// DidvanIconButton(
|
||||||
gestureSize: 28,
|
// gestureSize: 28,
|
||||||
icon: DidvanIcons.download_regular,
|
// icon: DidvanIcons.download_regular,
|
||||||
onPressed: () {},
|
// onPressed: () =>
|
||||||
),
|
// context.read<StudioState>().download(video.media!),
|
||||||
const SizedBox(width: 16),
|
// ),
|
||||||
|
// const SizedBox(width: 16),
|
||||||
BookmarkButton(
|
BookmarkButton(
|
||||||
gestureSize: 24,
|
gestureSize: 24,
|
||||||
value: video.marked,
|
value: video.marked,
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,7 @@ class DidvanBNB extends StatelessWidget {
|
||||||
expandableContent: state.appState == AppState.busy
|
expandableContent: state.appState == AppState.busy
|
||||||
? const SizedBox()
|
? const SizedBox()
|
||||||
: StudioDetailsWidget(
|
: StudioDetailsWidget(
|
||||||
studio: detailsState.currentStudio,
|
studio: detailsState.studio,
|
||||||
onCommentsTabSelected: () {
|
onCommentsTabSelected: () {
|
||||||
Future.delayed(
|
Future.delayed(
|
||||||
const Duration(milliseconds: 100),
|
const Duration(milliseconds: 100),
|
||||||
37
pubspec.lock
37
pubspec.lock
|
|
@ -532,6 +532,41 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.11.1"
|
version: "1.11.1"
|
||||||
|
permission_handler:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: permission_handler
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "9.2.0"
|
||||||
|
permission_handler_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_android
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "9.0.2+1"
|
||||||
|
permission_handler_apple:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_apple
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "9.0.3"
|
||||||
|
permission_handler_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_platform_interface
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.7.0"
|
||||||
|
permission_handler_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_windows
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.0"
|
||||||
persian_datetime_picker:
|
persian_datetime_picker:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -840,4 +875,4 @@ packages:
|
||||||
version: "5.3.1"
|
version: "5.3.1"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.16.0 <3.0.0"
|
dart: ">=2.16.0 <3.0.0"
|
||||||
flutter: ">=2.5.0"
|
flutter: ">=2.8.0"
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ dependencies:
|
||||||
firebase_core: ^1.13.1
|
firebase_core: ^1.13.1
|
||||||
webview_flutter: ^3.0.1
|
webview_flutter: ^3.0.1
|
||||||
expandable_bottom_sheet: ^1.1.1+1
|
expandable_bottom_sheet: ^1.1.1+1
|
||||||
|
permission_handler: ^9.2.0
|
||||||
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue