D1APP-99 preparing...
This commit is contained in:
parent
ef5fd0524b
commit
3091c5d915
|
|
@ -7,6 +7,8 @@ import 'package:just_audio/just_audio.dart';
|
|||
class MediaService {
|
||||
static final AudioPlayer audioPlayer = AudioPlayer();
|
||||
static String? audioPlayerTag;
|
||||
static String? audioPlayerTitle;
|
||||
static String? audioPlayerCover;
|
||||
|
||||
static void init() {
|
||||
audioPlayer.positionStream.listen((event) {
|
||||
|
|
@ -54,6 +56,11 @@ class MediaService {
|
|||
}
|
||||
}
|
||||
|
||||
static Future<void> resetAudioPlayer() async {
|
||||
audioPlayerTag = null;
|
||||
MediaService.audioPlayer.stop();
|
||||
}
|
||||
|
||||
static Future<XFile?> pickImage({required ImageSource source}) async {
|
||||
final imagePicker = ImagePicker();
|
||||
final XFile? pickedFile = await imagePicker.pickImage(source: source);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:didvan/models/enums.dart';
|
||||
import 'package:didvan/models/view/app_bar_data.dart';
|
||||
import 'package:didvan/providers/server_data_provider.dart';
|
||||
import 'package:didvan/services/media/media.dart';
|
||||
import 'package:didvan/views/home/direct/direct_state.dart';
|
||||
import 'package:didvan/views/home/direct/widgets/message.dart';
|
||||
import 'package:didvan/views/home/direct/widgets/message_box.dart';
|
||||
|
|
@ -35,59 +36,65 @@ class _DirectState extends State<Direct> {
|
|||
Widget build(BuildContext context) {
|
||||
final state = context.watch<DirectState>();
|
||||
final d = MediaQuery.of(context);
|
||||
return Material(
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
top: 0,
|
||||
bottom: 56,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: DidvanScaffold(
|
||||
reverse: true,
|
||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||
appBarData: AppBarData(
|
||||
hasBack: true,
|
||||
subtitle: 'ارتباط با سردبیر',
|
||||
title: widget.pageData['type'] ?? 'پشتیبانی اپلیکیشن',
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
MediaService.resetAudioPlayer();
|
||||
return true;
|
||||
},
|
||||
child: Material(
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
top: 0,
|
||||
bottom: 56,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: DidvanScaffold(
|
||||
reverse: true,
|
||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||
appBarData: AppBarData(
|
||||
hasBack: true,
|
||||
subtitle: 'ارتباط با سردبیر',
|
||||
title: widget.pageData['type'] ?? 'پشتیبانی اپلیکیشن',
|
||||
),
|
||||
slivers: [
|
||||
if (state.appState != AppState.busy)
|
||||
SliverPadding(
|
||||
padding: state.replyRadar == null
|
||||
? EdgeInsets.zero
|
||||
: const EdgeInsets.only(bottom: 68),
|
||||
sliver: SliverStateHandler<DirectState>(
|
||||
itemPadding: const EdgeInsets.only(bottom: 12),
|
||||
state: state,
|
||||
builder: (context, state, index) => Message(
|
||||
message: state.messages[index],
|
||||
),
|
||||
childCount: state.messages.length,
|
||||
onRetry: state.getMessages,
|
||||
),
|
||||
),
|
||||
],
|
||||
children: [
|
||||
if (state.appState == AppState.busy)
|
||||
SizedBox(
|
||||
height: d.size.height - kToolbarHeight - d.padding.top,
|
||||
child: Center(
|
||||
child: SpinKitSpinningLines(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
slivers: [
|
||||
if (state.appState != AppState.busy)
|
||||
SliverPadding(
|
||||
padding: state.replyRadar == null
|
||||
? EdgeInsets.zero
|
||||
: const EdgeInsets.only(bottom: 68),
|
||||
sliver: SliverStateHandler<DirectState>(
|
||||
itemPadding: const EdgeInsets.only(bottom: 12),
|
||||
state: state,
|
||||
builder: (context, state, index) => Message(
|
||||
message: state.messages[index],
|
||||
),
|
||||
childCount: state.messages.length,
|
||||
onRetry: state.getMessages,
|
||||
),
|
||||
),
|
||||
],
|
||||
children: [
|
||||
if (state.appState == AppState.busy)
|
||||
SizedBox(
|
||||
height: d.size.height - kToolbarHeight - d.padding.top,
|
||||
child: Center(
|
||||
child: SpinKitSpinningLines(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: d.viewInsets.bottom,
|
||||
right: 0,
|
||||
left: 0,
|
||||
child: const MessageBox(),
|
||||
),
|
||||
],
|
||||
Positioned(
|
||||
bottom: d.viewInsets.bottom,
|
||||
right: 0,
|
||||
left: 0,
|
||||
child: const MessageBox(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class PodcastDetails extends StatelessWidget {
|
||||
const PodcastDetails({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Material(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(8)),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/app_icons.dart';
|
||||
import 'package:didvan/views/home/studio/studio_state.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class StudioTabBar extends StatelessWidget {
|
||||
const StudioTabBar({
|
||||
|
|
@ -11,11 +13,16 @@ class StudioTabBar extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final state = context.watch<StudioState>();
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16),
|
||||
padding: const EdgeInsets.all(4),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Theme.of(context).colorScheme.border),
|
||||
border: Border.all(
|
||||
color: state.videosSelected
|
||||
? Theme.of(context).colorScheme.secondary
|
||||
: Theme.of(context).primaryColor,
|
||||
),
|
||||
borderRadius: DesignConfig.lowBorderRadius,
|
||||
),
|
||||
child: Row(
|
||||
|
|
@ -26,7 +33,7 @@ class StudioTabBar extends StatelessWidget {
|
|||
selectedColor: Theme.of(context).colorScheme.secondary,
|
||||
title: 'ویدئو',
|
||||
onTap: () {},
|
||||
isSelected: true,
|
||||
isSelected: state.videosSelected,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
|
|
@ -40,7 +47,7 @@ class StudioTabBar extends StatelessWidget {
|
|||
selectedColor: Theme.of(context).colorScheme.focusedBorder,
|
||||
title: 'پادکست',
|
||||
onTap: () {},
|
||||
isSelected: true,
|
||||
isSelected: !state.videosSelected,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
@ -64,7 +71,8 @@ class _StudioTypeButton extends StatelessWidget {
|
|||
required this.isSelected,
|
||||
}) : super(key: key);
|
||||
|
||||
Color? get _color => isSelected ? selectedColor : null;
|
||||
Color? _color(context) =>
|
||||
isSelected ? selectedColor : Theme.of(context).colorScheme.hint;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -77,20 +85,20 @@ class _StudioTypeButton extends StatelessWidget {
|
|||
Icon(
|
||||
icon,
|
||||
size: 32,
|
||||
color: _color,
|
||||
color: _color(context),
|
||||
),
|
||||
if (!isSelected) const SizedBox(height: 18),
|
||||
if (isSelected)
|
||||
Container(
|
||||
width: 88,
|
||||
height: 1,
|
||||
color: _color,
|
||||
color: _color(context),
|
||||
),
|
||||
if (isSelected)
|
||||
DidvanText(
|
||||
title,
|
||||
style: Theme.of(context).textTheme.overline,
|
||||
color: _color,
|
||||
color: _color(context),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/app_icons.dart';
|
||||
import 'package:didvan/services/media/media.dart';
|
||||
import 'package:didvan/views/widgets/didvan/icon_button.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:didvan/views/widgets/skeleton_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class DidvanBNB extends StatelessWidget {
|
||||
|
|
@ -14,54 +17,93 @@ class DidvanBNB extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: 72,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(16)),
|
||||
boxShadow: DesignConfig.defaultShadow,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
_NavBarItem(
|
||||
isSelected: currentTabIndex == 0,
|
||||
title: 'اخبار',
|
||||
selectedIcon: DidvanIcons.news_solid,
|
||||
unselectedIcon: DidvanIcons.news_light,
|
||||
onTap: () => onTabChanged(0),
|
||||
),
|
||||
_NavBarItem(
|
||||
isSelected: currentTabIndex == 1,
|
||||
title: 'آمار',
|
||||
selectedIcon: DidvanIcons.chart_solid,
|
||||
unselectedIcon: DidvanIcons.chart_light,
|
||||
onTap: () => onTabChanged(1),
|
||||
),
|
||||
_NavBarItem(
|
||||
isSelected: currentTabIndex == 2,
|
||||
title: 'رادار',
|
||||
selectedIcon: DidvanIcons.radar_solid,
|
||||
unselectedIcon: DidvanIcons.radar_light,
|
||||
onTap: () => onTabChanged(2),
|
||||
),
|
||||
_NavBarItem(
|
||||
isSelected: currentTabIndex == 3,
|
||||
title: 'استودیو',
|
||||
selectedIcon: DidvanIcons.play_circle_solid,
|
||||
unselectedIcon: DidvanIcons.play_circle_light,
|
||||
onTap: () => onTabChanged(3),
|
||||
),
|
||||
_NavBarItem(
|
||||
isSelected: currentTabIndex == 4,
|
||||
title: 'تنظیمات',
|
||||
selectedIcon: DidvanIcons.setting_solid,
|
||||
unselectedIcon: DidvanIcons.setting_light,
|
||||
onTap: () => onTabChanged(4),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
return StreamBuilder<bool>(
|
||||
stream: MediaService.audioPlayer.playingStream,
|
||||
builder: (context, snapshot) {
|
||||
return Stack(
|
||||
children: [
|
||||
AnimatedContainer(
|
||||
duration: DesignConfig.lowAnimationDuration,
|
||||
height: snapshot.data == true ? 120 : 72,
|
||||
decoration: BoxDecoration(
|
||||
color: DesignConfig.isDark
|
||||
? Theme.of(context).colorScheme.focused
|
||||
: Theme.of(context).colorScheme.navigation,
|
||||
borderRadius: const BorderRadius.vertical(
|
||||
top: Radius.circular(16),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const DidvanIconButton(
|
||||
icon: DidvanIcons.close_regular,
|
||||
gestureSize: 24,
|
||||
onPressed: MediaService.resetAudioPlayer,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
if (MediaService.audioPlayerCover != null)
|
||||
SkeletonImage(imageUrl: MediaService.audioPlayerCover!),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
height: 72,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
borderRadius:
|
||||
const BorderRadius.vertical(top: Radius.circular(16)),
|
||||
boxShadow: DesignConfig.defaultShadow,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
_NavBarItem(
|
||||
isSelected: currentTabIndex == 0,
|
||||
title: 'اخبار',
|
||||
selectedIcon: DidvanIcons.news_solid,
|
||||
unselectedIcon: DidvanIcons.news_light,
|
||||
onTap: () => onTabChanged(0),
|
||||
),
|
||||
_NavBarItem(
|
||||
isSelected: currentTabIndex == 1,
|
||||
title: 'آمار',
|
||||
selectedIcon: DidvanIcons.chart_solid,
|
||||
unselectedIcon: DidvanIcons.chart_light,
|
||||
onTap: () => onTabChanged(1),
|
||||
),
|
||||
_NavBarItem(
|
||||
isSelected: currentTabIndex == 2,
|
||||
title: 'رادار',
|
||||
selectedIcon: DidvanIcons.radar_solid,
|
||||
unselectedIcon: DidvanIcons.radar_light,
|
||||
onTap: () => onTabChanged(2),
|
||||
),
|
||||
_NavBarItem(
|
||||
isSelected: currentTabIndex == 3,
|
||||
title: 'استودیو',
|
||||
selectedIcon: DidvanIcons.play_circle_solid,
|
||||
unselectedIcon: DidvanIcons.play_circle_light,
|
||||
onTap: () => onTabChanged(3),
|
||||
),
|
||||
_NavBarItem(
|
||||
isSelected: currentTabIndex == 4,
|
||||
title: 'تنظیمات',
|
||||
selectedIcon: DidvanIcons.setting_solid,
|
||||
unselectedIcon: DidvanIcons.setting_light,
|
||||
onTap: () => onTabChanged(4),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,138 @@
|
|||
import 'package:didvan/models/overview_data.dart';
|
||||
import 'package:didvan/models/requests/news.dart';
|
||||
import 'package:didvan/routes/routes.dart';
|
||||
import 'package:didvan/utils/date_time.dart';
|
||||
import 'package:didvan/views/home/widgets/bookmark_button.dart';
|
||||
import 'package:didvan/views/widgets/didvan/card.dart';
|
||||
import 'package:didvan/views/widgets/didvan/divider.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:didvan/views/widgets/shimmer_placeholder.dart';
|
||||
import 'package:didvan/views/widgets/skeleton_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class PodcastOverview extends StatelessWidget {
|
||||
final OverviewData news;
|
||||
final NewsRequestArgs? newsRequestArgs;
|
||||
final void Function(int id, bool value) onMarkChanged;
|
||||
final bool hasUnmarkConfirmation;
|
||||
const PodcastOverview({
|
||||
Key? key,
|
||||
required this.news,
|
||||
required this.onMarkChanged,
|
||||
this.newsRequestArgs,
|
||||
this.hasUnmarkConfirmation = false,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DidvanCard(
|
||||
onTap: () => Navigator.of(context).pushNamed(
|
||||
Routes.newsDetails,
|
||||
arguments: {
|
||||
'onMarkChanged': onMarkChanged,
|
||||
'id': news.id,
|
||||
'args': newsRequestArgs,
|
||||
'hasUnmarkConfirmation': hasUnmarkConfirmation,
|
||||
},
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
SkeletonImage(
|
||||
imageUrl: news.image,
|
||||
width: 64,
|
||||
height: 64,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 64,
|
||||
child: DidvanText(
|
||||
news.title,
|
||||
style: Theme.of(context).textTheme.bodyText1,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
DidvanText(
|
||||
news.description,
|
||||
maxLines: 3,
|
||||
),
|
||||
const DidvanDivider(verticalPadding: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
DidvanText(
|
||||
news.reference!,
|
||||
style: Theme.of(context).textTheme.caption,
|
||||
),
|
||||
DidvanText(
|
||||
' - ' + DateTimeUtils.momentGenerator(news.createdAt),
|
||||
style: Theme.of(context).textTheme.caption,
|
||||
),
|
||||
],
|
||||
),
|
||||
BookmarkButton(
|
||||
value: news.marked,
|
||||
onMarkChanged: (value) => onMarkChanged(news.id, value),
|
||||
askForConfirmation: hasUnmarkConfirmation,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static Widget get placeholder => DidvanCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const ShimmerPlaceholder(height: 64, width: 64),
|
||||
const SizedBox(width: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: const [
|
||||
ShimmerPlaceholder(height: 18, width: 200),
|
||||
SizedBox(height: 8),
|
||||
ShimmerPlaceholder(height: 18, width: 100),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const ShimmerPlaceholder(
|
||||
height: 16,
|
||||
width: double.infinity,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const ShimmerPlaceholder(
|
||||
height: 16,
|
||||
width: double.infinity,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const ShimmerPlaceholder(
|
||||
height: 16,
|
||||
width: 100,
|
||||
),
|
||||
const DidvanDivider(verticalPadding: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: const [
|
||||
ShimmerPlaceholder(height: 12, width: 150),
|
||||
ShimmerPlaceholder(height: 24, width: 24),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue