new video player complete version
This commit is contained in:
parent
00f108710a
commit
a7c0fcf6f0
|
|
@ -9,7 +9,8 @@ class OverviewData {
|
||||||
final int? timeToRead;
|
final int? timeToRead;
|
||||||
final int? duration;
|
final int? duration;
|
||||||
final String? reference;
|
final String? reference;
|
||||||
final String? media;
|
final String? link;
|
||||||
|
final String? iframe;
|
||||||
final bool forManagers;
|
final bool forManagers;
|
||||||
final String createdAt;
|
final String createdAt;
|
||||||
final String type;
|
final String type;
|
||||||
|
|
@ -27,7 +28,8 @@ class OverviewData {
|
||||||
required this.marked,
|
required this.marked,
|
||||||
required this.comments,
|
required this.comments,
|
||||||
required this.forManagers,
|
required this.forManagers,
|
||||||
this.media,
|
this.link,
|
||||||
|
this.iframe,
|
||||||
this.duration,
|
this.duration,
|
||||||
this.timeToRead,
|
this.timeToRead,
|
||||||
this.reference,
|
this.reference,
|
||||||
|
|
@ -51,7 +53,8 @@ class OverviewData {
|
||||||
duration: json['duration'],
|
duration: json['duration'],
|
||||||
type: json['type'] ?? '',
|
type: json['type'] ?? '',
|
||||||
marked: json['marked'] ?? true,
|
marked: json['marked'] ?? true,
|
||||||
media: json['media'],
|
link: json['link'],
|
||||||
|
iframe: json['iframe'],
|
||||||
categories: json['categories'] != null
|
categories: json['categories'] != null
|
||||||
? List<CategoryData>.from(
|
? List<CategoryData>.from(
|
||||||
json['categories'].map(
|
json['categories'].map(
|
||||||
|
|
|
||||||
|
|
@ -2,26 +2,25 @@ class SliderData {
|
||||||
final int id;
|
final int id;
|
||||||
final String title;
|
final String title;
|
||||||
final String image;
|
final String image;
|
||||||
final String media;
|
final String link;
|
||||||
|
|
||||||
const SliderData({
|
const SliderData({
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.title,
|
required this.title,
|
||||||
required this.image,
|
required this.image,
|
||||||
required this.media,
|
required this.link,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory SliderData.fromJson(Map<String, dynamic> json) => SliderData(
|
factory SliderData.fromJson(Map<String, dynamic> json) => SliderData(
|
||||||
id: json['id'],
|
id: json['id'],
|
||||||
title: json['title'],
|
title: json['title'],
|
||||||
image: json['image'],
|
image: json['image'],
|
||||||
media: json['media'],
|
link: json['link'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
'id': id,
|
'id': id,
|
||||||
'title': title,
|
'title': title,
|
||||||
'image': image,
|
'image': image,
|
||||||
'media': media,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ class StudioDetailsData {
|
||||||
final String title;
|
final String title;
|
||||||
final String description;
|
final String description;
|
||||||
final String image;
|
final String image;
|
||||||
final String media;
|
final String link;
|
||||||
|
final String? iframe;
|
||||||
final String createdAt;
|
final String createdAt;
|
||||||
final int order;
|
final int order;
|
||||||
bool marked;
|
bool marked;
|
||||||
|
|
@ -21,7 +22,8 @@ class StudioDetailsData {
|
||||||
required this.title,
|
required this.title,
|
||||||
required this.description,
|
required this.description,
|
||||||
required this.image,
|
required this.image,
|
||||||
required this.media,
|
required this.link,
|
||||||
|
required this.iframe,
|
||||||
required this.createdAt,
|
required this.createdAt,
|
||||||
required this.order,
|
required this.order,
|
||||||
required this.marked,
|
required this.marked,
|
||||||
|
|
@ -36,7 +38,8 @@ class StudioDetailsData {
|
||||||
title: json['title'],
|
title: json['title'],
|
||||||
description: json['description'],
|
description: json['description'],
|
||||||
image: json['image'],
|
image: json['image'],
|
||||||
media: json['media'],
|
link: json['link'],
|
||||||
|
iframe: json['iframe'],
|
||||||
createdAt: json['createdAt'],
|
createdAt: json['createdAt'],
|
||||||
order: json['order'],
|
order: json['order'],
|
||||||
marked: json['marked'],
|
marked: json['marked'],
|
||||||
|
|
@ -51,7 +54,6 @@ class StudioDetailsData {
|
||||||
'title': title,
|
'title': title,
|
||||||
'description': description,
|
'description': description,
|
||||||
'image': image,
|
'image': image,
|
||||||
'media': media,
|
|
||||||
'createdAt': createdAt,
|
'createdAt': createdAt,
|
||||||
'order': order,
|
'order': order,
|
||||||
'marked': marked,
|
'marked': marked,
|
||||||
|
|
|
||||||
|
|
@ -180,8 +180,15 @@ class RouteGenerator {
|
||||||
final shortestSide = MediaQuery.of(context).size.shortestSide;
|
final shortestSide = MediaQuery.of(context).size.shortestSide;
|
||||||
final bool useMobileLayout = shortestSide < 600;
|
final bool useMobileLayout = shortestSide < 600;
|
||||||
if (kIsWeb && !useMobileLayout) {
|
if (kIsWeb && !useMobileLayout) {
|
||||||
|
final deviceSize = MediaQuery.of(context).size;
|
||||||
return MediaQuery(
|
return MediaQuery(
|
||||||
data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
|
data: MediaQuery.of(context).copyWith(
|
||||||
|
textScaleFactor: 1.0,
|
||||||
|
size: Size(
|
||||||
|
deviceSize.width / 16 * 9,
|
||||||
|
deviceSize.height,
|
||||||
|
),
|
||||||
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.background,
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,9 @@ class ActionSheetUtils {
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => Container(
|
builder: (context) => Container(
|
||||||
padding: data.hasPadding ? const EdgeInsets.all(20) : EdgeInsets.zero,
|
padding: data.hasPadding
|
||||||
|
? const EdgeInsets.all(20).copyWith(top: 0)
|
||||||
|
: EdgeInsets.zero,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.surface,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
borderRadius: const BorderRadius.vertical(
|
borderRadius: const BorderRadius.vertical(
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ class _StudioState extends State<Studio> {
|
||||||
emptyState: EmptyResult(
|
emptyState: EmptyResult(
|
||||||
onNewSearch: () => _focusNode.requestFocus(),
|
onNewSearch: () => _focusNode.requestFocus(),
|
||||||
),
|
),
|
||||||
centerEmptyState: false,
|
centerEmptyState: true,
|
||||||
enableEmptyState: state.studios.isEmpty,
|
enableEmptyState: state.studios.isEmpty,
|
||||||
placeholder: state.videosSelected
|
placeholder: state.videosSelected
|
||||||
? VideoOverview.placeHolder
|
? VideoOverview.placeHolder
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:better_player/better_player.dart';
|
import 'package:better_player/better_player.dart';
|
||||||
import 'package:didvan/models/view/app_bar_data.dart';
|
import 'package:didvan/models/view/app_bar_data.dart';
|
||||||
import 'package:didvan/services/media/media.dart';
|
import 'package:didvan/services/media/media.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_details/widgets/details_tab_bar.dart';
|
|
||||||
import 'package:didvan/views/home/studio/studio_details/widgets/studio_details_widget.dart';
|
import 'package:didvan/views/home/studio/studio_details/widgets/studio_details_widget.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/app_bar.dart';
|
import 'package:didvan/views/widgets/didvan/app_bar.dart';
|
||||||
|
|
@ -12,8 +9,6 @@ import 'package:didvan/views/widgets/state_handlers/state_handler.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'package:webview_flutter/webview_flutter.dart';
|
|
||||||
|
|
||||||
class StudioDetails extends StatefulWidget {
|
class StudioDetails extends StatefulWidget {
|
||||||
final Map<String, dynamic> pageData;
|
final Map<String, dynamic> pageData;
|
||||||
|
|
||||||
|
|
@ -24,7 +19,8 @@ class StudioDetails extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _StudioDetailsState extends State<StudioDetails> {
|
class _StudioDetailsState extends State<StudioDetails> {
|
||||||
final _scrollController = ScrollController();
|
int _currentlyPlayingId = 0;
|
||||||
|
late BetterPlayerController _betterPlayerController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
|
@ -34,15 +30,12 @@ class _StudioDetailsState extends State<StudioDetails> {
|
||||||
Duration.zero,
|
Duration.zero,
|
||||||
() => state.getStudioDetails(widget.pageData['id']),
|
() => state.getStudioDetails(widget.pageData['id']),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (Platform.isAndroid) WebView.platform = AndroidWebView();
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final d = MediaQuery.of(context);
|
final d = MediaQuery.of(context);
|
||||||
|
|
||||||
return Consumer<StudioDetailsState>(
|
return Consumer<StudioDetailsState>(
|
||||||
builder: (context, state, child) => StateHandler<StudioDetailsState>(
|
builder: (context, state, child) => StateHandler<StudioDetailsState>(
|
||||||
state: state,
|
state: state,
|
||||||
|
|
@ -54,6 +47,32 @@ class _StudioDetailsState extends State<StudioDetails> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
|
if (_currentlyPlayingId != state.studio.id) {
|
||||||
|
BetterPlayerDataSource betterPlayerDataSource =
|
||||||
|
BetterPlayerDataSource(
|
||||||
|
BetterPlayerDataSourceType.network,
|
||||||
|
state.studio.link,
|
||||||
|
);
|
||||||
|
_betterPlayerController = BetterPlayerController(
|
||||||
|
BetterPlayerConfiguration(
|
||||||
|
aspectRatio: 16 / 9,
|
||||||
|
showPlaceholderUntilPlay: true,
|
||||||
|
controlsConfiguration: BetterPlayerControlsConfiguration(
|
||||||
|
enablePlaybackSpeed: false,
|
||||||
|
enableSubtitles: false,
|
||||||
|
enableAudioTracks: false,
|
||||||
|
progressBarPlayedColor:
|
||||||
|
Theme.of(context).colorScheme.secondary,
|
||||||
|
progressBarHandleColor:
|
||||||
|
Theme.of(context).colorScheme.secondary,
|
||||||
|
),
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
fullScreenAspectRatio: 16 / 9,
|
||||||
|
),
|
||||||
|
betterPlayerDataSource: betterPlayerDataSource,
|
||||||
|
);
|
||||||
|
_currentlyPlayingId = state.studio.id;
|
||||||
|
}
|
||||||
return WillPopScope(
|
return WillPopScope(
|
||||||
onWillPop: () async {
|
onWillPop: () async {
|
||||||
if (MediaService.currentPodcast != null) {
|
if (MediaService.currentPodcast != null) {
|
||||||
|
|
@ -63,7 +82,6 @@ class _StudioDetailsState extends State<StudioDetails> {
|
||||||
},
|
},
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
key: ValueKey(state.studio.id),
|
|
||||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||||
appBar: PreferredSize(
|
appBar: PreferredSize(
|
||||||
preferredSize: const Size.fromHeight(56),
|
preferredSize: const Size.fromHeight(56),
|
||||||
|
|
@ -84,43 +102,34 @@ class _StudioDetailsState extends State<StudioDetails> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: Column(
|
body: SingleChildScrollView(
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
child: SizedBox(
|
||||||
|
height: d.size.height - d.padding.top - 56,
|
||||||
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Directionality(
|
BetterPlayer(controller: _betterPlayerController),
|
||||||
textDirection: TextDirection.ltr,
|
|
||||||
child: BetterPlayer.network(
|
|
||||||
'https://studio-didvan.arvanvod.com/Vz01Bxq2bQ/nylPWJ4B63/h_,144_200,240_400,360_800,480_1215,720_1215,k.mp4.list/master.m3u8',
|
|
||||||
betterPlayerConfiguration:
|
|
||||||
const BetterPlayerConfiguration(
|
|
||||||
aspectRatio: 16 / 9,
|
|
||||||
controlsConfiguration:
|
|
||||||
BetterPlayerControlsConfiguration(
|
|
||||||
enablePlaybackSpeed: false,
|
|
||||||
enableSubtitles: false,
|
|
||||||
enableAudioTracks: false,
|
|
||||||
),
|
|
||||||
autoDetectFullscreenAspectRatio: true,
|
|
||||||
autoDetectFullscreenDeviceOrientation: true,
|
|
||||||
fullScreenAspectRatio: 16 / 9,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const DetailsTabBar(
|
|
||||||
isVideo: true,
|
|
||||||
),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: StudioDetailsWidget(
|
child: StudioDetailsWidget(
|
||||||
onMarkChanged: (id, value) =>
|
onMarkChanged: (id, value) => widget
|
||||||
widget.pageData['onMarkChanged'](id, value, true),
|
.pageData['onMarkChanged'](id, value, true),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// void dispose() {
|
||||||
|
// _betterPlayerController.dispose();
|
||||||
|
// super.dispose();
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,13 @@
|
||||||
import 'dart:ui' as ui;
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
import 'package:didvan/config/design_config.dart';
|
|
||||||
import 'package:didvan/models/view/app_bar_data.dart';
|
import 'package:didvan/models/view/app_bar_data.dart';
|
||||||
import 'package:didvan/services/media/media.dart';
|
import 'package:didvan/services/media/media.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_details/widgets/details_tab_bar.dart';
|
|
||||||
import 'package:didvan/views/home/studio/studio_details/widgets/studio_details_widget.dart';
|
import 'package:didvan/views/home/studio/studio_details/widgets/studio_details_widget.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/scaffold.dart';
|
import 'package:didvan/views/widgets/didvan/app_bar.dart';
|
||||||
import 'package:didvan/views/widgets/state_handlers/state_handler.dart';
|
import 'package:didvan/views/widgets/state_handlers/state_handler.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:universal_html/html.dart' as html;
|
import 'package:universal_html/html.dart' as html;
|
||||||
|
|
||||||
|
|
@ -24,8 +21,6 @@ class StudioDetails extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _StudioDetailsState extends State<StudioDetails> {
|
class _StudioDetailsState extends State<StudioDetails> {
|
||||||
bool _isFullScreen = false;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
final state = context.read<StudioDetailsState>();
|
final state = context.read<StudioDetailsState>();
|
||||||
|
|
@ -34,42 +29,12 @@ class _StudioDetailsState extends State<StudioDetails> {
|
||||||
Duration.zero,
|
Duration.zero,
|
||||||
() => state.getStudioDetails(widget.pageData['id']),
|
() => state.getStudioDetails(widget.pageData['id']),
|
||||||
);
|
);
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _changeFullSceen(bool value) async {
|
|
||||||
if (value) {
|
|
||||||
await SystemChrome.setEnabledSystemUIMode(
|
|
||||||
SystemUiMode.manual,
|
|
||||||
overlays: [],
|
|
||||||
);
|
|
||||||
SystemChrome.setSystemUIOverlayStyle(
|
|
||||||
const SystemUiOverlayStyle(
|
|
||||||
systemNavigationBarColor: Colors.black,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
await SystemChrome.setPreferredOrientations(
|
|
||||||
[DeviceOrientation.landscapeLeft],
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
await SystemChrome.setEnabledSystemUIMode(
|
|
||||||
SystemUiMode.manual,
|
|
||||||
overlays: [SystemUiOverlay.bottom, SystemUiOverlay.top],
|
|
||||||
);
|
|
||||||
await SystemChrome.setPreferredOrientations(
|
|
||||||
[DeviceOrientation.portraitUp],
|
|
||||||
);
|
|
||||||
DesignConfig.updateSystemUiOverlayStyle();
|
|
||||||
}
|
|
||||||
setState(() {
|
|
||||||
_isFullScreen = value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ds = MediaQuery.of(context).size;
|
final d = MediaQuery.of(context);
|
||||||
return Consumer<StudioDetailsState>(
|
return Consumer<StudioDetailsState>(
|
||||||
builder: (context, state, child) => StateHandler<StudioDetailsState>(
|
builder: (context, state, child) => StateHandler<StudioDetailsState>(
|
||||||
state: state,
|
state: state,
|
||||||
|
|
@ -82,66 +47,61 @@ class _StudioDetailsState extends State<StudioDetails> {
|
||||||
..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.studio.iframe!,
|
||||||
mimeType: 'text/html',
|
mimeType: 'text/html',
|
||||||
).toString()
|
).toString()
|
||||||
..style.border = 'none',
|
..style.border = 'none',
|
||||||
);
|
);
|
||||||
return WillPopScope(
|
return WillPopScope(
|
||||||
onWillPop: () async {
|
onWillPop: () async {
|
||||||
if (_isFullScreen) {
|
|
||||||
await _changeFullSceen(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (MediaService.currentPodcast != null) {
|
if (MediaService.currentPodcast != null) {
|
||||||
state.studio = MediaService.currentPodcast!;
|
state.studio = MediaService.currentPodcast!;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
child: DidvanScaffold(
|
child: SafeArea(
|
||||||
padding: EdgeInsets.zero,
|
child: Scaffold(
|
||||||
appBarData: _isFullScreen
|
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||||
? null
|
appBar: PreferredSize(
|
||||||
: AppBarData(
|
preferredSize: const Size.fromHeight(56),
|
||||||
isSmall: true,
|
child: DidvanAppBar(
|
||||||
title: state.studio.title,
|
appBarData: AppBarData(
|
||||||
trailing: BookmarkButton(
|
trailing: BookmarkButton(
|
||||||
itemId: state.studio.id,
|
itemId: state.studio.id,
|
||||||
type: 'video',
|
type: 'video',
|
||||||
value: state.studio.marked,
|
value: state.studio.marked,
|
||||||
onMarkChanged: (value) => widget
|
onMarkChanged: (value) {
|
||||||
.pageData['onMarkChanged'](state.studio.id, value),
|
widget.pageData['onMarkChanged'](
|
||||||
|
state.studio.id, value);
|
||||||
|
},
|
||||||
gestureSize: 48,
|
gestureSize: 48,
|
||||||
),
|
),
|
||||||
|
isSmall: true,
|
||||||
|
title: state.studio.title,
|
||||||
),
|
),
|
||||||
showSliversFirst: true,
|
),
|
||||||
slivers: [
|
),
|
||||||
SliverAppBar(
|
body: SingleChildScrollView(
|
||||||
automaticallyImplyLeading: false,
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
pinned: true,
|
child: SizedBox(
|
||||||
elevation: 0,
|
height: d.size.height - d.padding.top - 56,
|
||||||
toolbarHeight:
|
child: Column(
|
||||||
(_isFullScreen ? ds.height : ds.width * 9 / 16) +
|
children: [
|
||||||
72 -
|
const AspectRatio(
|
||||||
MediaQuery.of(context).padding.top,
|
|
||||||
flexibleSpace: Column(
|
|
||||||
children: const [
|
|
||||||
AspectRatio(
|
|
||||||
aspectRatio: 16 / 9,
|
aspectRatio: 16 / 9,
|
||||||
child: HtmlElementView(viewType: 'video'),
|
child: HtmlElementView(viewType: 'video'),
|
||||||
),
|
),
|
||||||
DetailsTabBar(
|
Expanded(
|
||||||
isVideo: true,
|
child: StudioDetailsWidget(
|
||||||
),
|
onMarkChanged: (id, value) => widget
|
||||||
],
|
.pageData['onMarkChanged'](id, value, true),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
children: [
|
|
||||||
StudioDetailsWidget(
|
|
||||||
onMarkChanged: widget.pageData['onMarkChanged'],
|
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ class StudioDetailsState extends CoreProvier {
|
||||||
MediaService.currentPodcast = studio;
|
MediaService.currentPodcast = studio;
|
||||||
MediaService.podcastPlaylistArgs = args;
|
MediaService.podcastPlaylistArgs = args;
|
||||||
await MediaService.handleAudioPlayback(
|
await MediaService.handleAudioPlayback(
|
||||||
audioSource: studio.media,
|
audioSource: studio.link,
|
||||||
id: studio.id,
|
id: studio.id,
|
||||||
isVoiceMessage: false,
|
isVoiceMessage: false,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ class DetailsTabBar extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final state = context.read<StudioDetailsState>();
|
final state = context.watch<StudioDetailsState>();
|
||||||
return WillPopScope(
|
return WillPopScope(
|
||||||
onWillPop: () async {
|
onWillPop: () async {
|
||||||
state.selectedDetailsIndex = 0;
|
state.selectedDetailsIndex = 0;
|
||||||
|
|
@ -35,10 +35,6 @@ class DetailsTabBar extends StatelessWidget {
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: FittedBox(
|
|
||||||
fit: BoxFit.scaleDown,
|
|
||||||
child: SizedBox(
|
|
||||||
width: MediaQuery.of(context).size.width,
|
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
_TabItem(
|
_TabItem(
|
||||||
|
|
@ -67,8 +63,6 @@ class DetailsTabBar extends StatelessWidget {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -106,6 +100,7 @@ class _TabItem extends StatelessWidget {
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: Column(
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Icon(
|
Icon(
|
||||||
icon,
|
icon,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:didvan/config/design_config.dart';
|
import 'dart:math';
|
||||||
|
|
||||||
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/enums.dart';
|
import 'package:didvan/models/enums.dart';
|
||||||
|
|
@ -28,38 +29,34 @@ class StudioDetailsWidget extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ds = MediaQuery.of(context).size;
|
final ds = MediaQuery.of(context).size;
|
||||||
|
|
||||||
return SafeArea(
|
return SafeArea(
|
||||||
bottom: true,
|
bottom: true,
|
||||||
child: Consumer<StudioDetailsState>(
|
child: Consumer<StudioDetailsState>(
|
||||||
builder: (context, state, child) {
|
builder: (context, state, child) {
|
||||||
bool isVideo = state.studio.media.contains('iframe');
|
bool isVideo = state.studio.iframe != null;
|
||||||
return Container(
|
return Container(
|
||||||
color: Theme.of(context).colorScheme.surface,
|
height: max(
|
||||||
child: Column(
|
ds.height -
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
if (!isVideo)
|
|
||||||
DetailsTabBar(
|
|
||||||
isVideo: isVideo,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
ConstrainedBox(
|
|
||||||
constraints: BoxConstraints(
|
|
||||||
maxHeight: isVideo
|
|
||||||
? double.infinity
|
|
||||||
: ds.height -
|
|
||||||
ds.width * 9 / 16 -
|
ds.width * 9 / 16 -
|
||||||
144 -
|
72 -
|
||||||
MediaQuery.of(context).padding.top,
|
MediaQuery.of(context).padding.top,
|
||||||
),
|
0),
|
||||||
|
color: Theme.of(context).colorScheme.surface,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Positioned(
|
||||||
|
top: 72,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
child: StateHandler<StudioDetailsState>(
|
child: StateHandler<StudioDetailsState>(
|
||||||
onRetry: () {},
|
onRetry: () {},
|
||||||
state: state,
|
state: state,
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state.selectedDetailsIndex == 0) {
|
if (state.selectedDetailsIndex == 0) {
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
physics: const BouncingScrollPhysics(),
|
padding: const EdgeInsets.all(16),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
|
@ -128,6 +125,11 @@ class StudioDetailsWidget extends StatelessWidget {
|
||||||
if (state.selectedDetailsIndex == 1) {
|
if (state.selectedDetailsIndex == 1) {
|
||||||
return ChangeNotifierProvider<CommentsState>(
|
return ChangeNotifierProvider<CommentsState>(
|
||||||
create: (context) => CommentsState(),
|
create: (context) => CommentsState(),
|
||||||
|
child: SizedBox(
|
||||||
|
height: ds.height -
|
||||||
|
ds.width * 9 / 16 -
|
||||||
|
172 -
|
||||||
|
MediaQuery.of(context).padding.top,
|
||||||
child: Comments(
|
child: Comments(
|
||||||
pageData: {
|
pageData: {
|
||||||
'id': state.studio.id,
|
'id': state.studio.id,
|
||||||
|
|
@ -137,10 +139,10 @@ class StudioDetailsWidget extends StatelessWidget {
|
||||||
'isPage': false,
|
'isPage': false,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return SingleChildScrollView(
|
return Column(
|
||||||
child: Column(
|
|
||||||
children: [
|
children: [
|
||||||
if (state.studio.relatedContents.isEmpty)
|
if (state.studio.relatedContents.isEmpty)
|
||||||
for (var i = 0; i < 3; i++)
|
for (var i = 0; i < 3; i++)
|
||||||
|
|
@ -167,11 +169,13 @@ class StudioDetailsWidget extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
DetailsTabBar(
|
||||||
|
isVideo: isVideo,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
@ -202,7 +206,7 @@ class _StudioPreview extends StatelessWidget {
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
String get _previewTitle {
|
String get _previewTitle {
|
||||||
if (studio.media.contains('iframe')) {
|
if (studio.iframe != null) {
|
||||||
return 'ویدئو ${isNext ? 'بعدی' : 'قبلی'} ';
|
return 'ویدئو ${isNext ? 'بعدی' : 'قبلی'} ';
|
||||||
}
|
}
|
||||||
return 'پادکست ${isNext ? 'بعدی' : 'قبلی'} ';
|
return 'پادکست ${isNext ? 'بعدی' : 'قبلی'} ';
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ class AudioPlayerWidget extends StatelessWidget {
|
||||||
stream: MediaService.audioPlayer.playingStream,
|
stream: MediaService.audioPlayer.playingStream,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
return _PlayPouseAnimatedIcon(
|
return _PlayPouseAnimatedIcon(
|
||||||
audioSource: podcast.media,
|
audioSource: podcast.link,
|
||||||
id: podcast.id,
|
id: podcast.id,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ class PodcastOverview extends StatelessWidget {
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
if (!kIsWeb) ...[
|
if (!kIsWeb) ...[
|
||||||
if (state.appState == AppState.idle ||
|
if (state.appState == AppState.idle ||
|
||||||
!state.downloadQueue.contains(podcast.media))
|
!state.downloadQueue.contains(podcast.link))
|
||||||
DidvanIconButton(
|
DidvanIconButton(
|
||||||
gestureSize: 28,
|
gestureSize: 28,
|
||||||
color: _isDownloaded
|
color: _isDownloaded
|
||||||
|
|
@ -97,11 +97,11 @@ class PodcastOverview extends StatelessWidget {
|
||||||
: () => state.download(
|
: () => state.download(
|
||||||
fileName: 'podcast-${podcast.id}.mp3',
|
fileName: 'podcast-${podcast.id}.mp3',
|
||||||
isVideo: false,
|
isVideo: false,
|
||||||
url: podcast.media!,
|
url: podcast.link!,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (state.appState == AppState.busy &&
|
if (state.appState == AppState.busy &&
|
||||||
state.downloadQueue.contains(podcast.media))
|
state.downloadQueue.contains(podcast.link))
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
width: 18,
|
width: 18,
|
||||||
height: 18,
|
height: 18,
|
||||||
|
|
|
||||||
|
|
@ -248,7 +248,7 @@ class _PlayerNavBar extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
MediaService.handleAudioPlayback(
|
MediaService.handleAudioPlayback(
|
||||||
audioSource: MediaService.currentPodcast!.media,
|
audioSource: MediaService.currentPodcast!.link,
|
||||||
id: MediaService.currentPodcast!.id,
|
id: MediaService.currentPodcast!.id,
|
||||||
isVoiceMessage: false,
|
isVoiceMessage: false,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue