D1APP-99 preparing...

This commit is contained in:
MohammadTaha Basiri 2022-03-06 14:59:12 +03:30
parent ef5fd0524b
commit 3091c5d915
7 changed files with 325 additions and 106 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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