Add mention view
This commit is contained in:
parent
c1edb1c019
commit
4c369c8588
|
|
@ -0,0 +1,31 @@
|
||||||
|
class MentionData {
|
||||||
|
final int id;
|
||||||
|
final String fullName;
|
||||||
|
final String text;
|
||||||
|
final String createdAt;
|
||||||
|
final List<String> mentions;
|
||||||
|
|
||||||
|
MentionData(
|
||||||
|
{required this.id,
|
||||||
|
required this.text,
|
||||||
|
required this.createdAt,
|
||||||
|
required this.fullName,
|
||||||
|
required this.mentions});
|
||||||
|
|
||||||
|
factory MentionData.fromJson(Map<String, dynamic> json, bool private) =>
|
||||||
|
MentionData(
|
||||||
|
id: json['id'],
|
||||||
|
text: json['text'],
|
||||||
|
createdAt: json['createdAt'],
|
||||||
|
fullName: json['fullName'],
|
||||||
|
mentions: json['mentions'],
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'id': id,
|
||||||
|
'text': text,
|
||||||
|
'createdAt': createdAt,
|
||||||
|
'fullName': fullName,
|
||||||
|
'mentions': mentions,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -18,6 +18,8 @@ import 'package:didvan/views/home/new_statistic/statistics_details/stat_cats_gen
|
||||||
import 'package:didvan/views/home/new_statistic/statistics_details/stat_cats_general_state.dart';
|
import 'package:didvan/views/home/new_statistic/statistics_details/stat_cats_general_state.dart';
|
||||||
import 'package:didvan/views/home/new_statistic/stock/newStock_state.dart';
|
import 'package:didvan/views/home/new_statistic/stock/newStock_state.dart';
|
||||||
import 'package:didvan/views/home/new_statistic/stock/new_stock.dart';
|
import 'package:didvan/views/home/new_statistic/stock/new_stock.dart';
|
||||||
|
import 'package:didvan/views/mentions/mentions.dart';
|
||||||
|
import 'package:didvan/views/mentions/mentions_state.dart';
|
||||||
import 'package:didvan/views/news/news.dart';
|
import 'package:didvan/views/news/news.dart';
|
||||||
import 'package:didvan/views/news/news_details/news_details.dart';
|
import 'package:didvan/views/news/news_details/news_details.dart';
|
||||||
import 'package:didvan/views/news/news_details/news_details_state.dart';
|
import 'package:didvan/views/news/news_details/news_details_state.dart';
|
||||||
|
|
@ -55,7 +57,6 @@ import '../views/customize_category/notification_status_step.dart';
|
||||||
import '../views/notification_time/notification_time.dart';
|
import '../views/notification_time/notification_time.dart';
|
||||||
|
|
||||||
class RouteGenerator {
|
class RouteGenerator {
|
||||||
|
|
||||||
static Route<dynamic> generateRoute(RouteSettings settings) {
|
static Route<dynamic> generateRoute(RouteSettings settings) {
|
||||||
HomeWidget.saveWidgetData("cRoute", settings.name!);
|
HomeWidget.saveWidgetData("cRoute", settings.name!);
|
||||||
switch (settings.name) {
|
switch (settings.name) {
|
||||||
|
|
@ -242,6 +243,15 @@ class RouteGenerator {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
case Routes.mentions:
|
||||||
|
return _createRoute(
|
||||||
|
ChangeNotifierProvider<MentionsState>(
|
||||||
|
create: (context) => MentionsState(),
|
||||||
|
child: Mentions(
|
||||||
|
pageData: settings.arguments as Map<String, dynamic>,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
case Routes.bookmarks:
|
case Routes.bookmarks:
|
||||||
return _createRoute(
|
return _createRoute(
|
||||||
ChangeNotifierProvider<BookmarksState>(
|
ChangeNotifierProvider<BookmarksState>(
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ class Routes {
|
||||||
static const String directList = '/direct-list';
|
static const String directList = '/direct-list';
|
||||||
static const String direct = '/direct';
|
static const String direct = '/direct';
|
||||||
static const String comments = '/comments';
|
static const String comments = '/comments';
|
||||||
|
static const String mentions = '/mentions';
|
||||||
static const String bookmarks = '/bookmarks';
|
static const String bookmarks = '/bookmarks';
|
||||||
static const String filteredBookmarks = '/filtered-bookmarks';
|
static const String filteredBookmarks = '/filtered-bookmarks';
|
||||||
static const String imageCropper = '/image-cropper';
|
static const String imageCropper = '/image-cropper';
|
||||||
|
|
|
||||||
|
|
@ -186,16 +186,18 @@ class RequestHelper {
|
||||||
|
|
||||||
static String mark(int id, String type) => '$baseUrl/$type/$id/mark';
|
static String mark(int id, String type) => '$baseUrl/$type/$id/mark';
|
||||||
static String tracking(int id, String type) => '$baseUrl/$type/$id/tracking';
|
static String tracking(int id, String type) => '$baseUrl/$type/$id/tracking';
|
||||||
static String comments(int id, String type) => '$baseUrl/$type/$id/comments/v2';
|
static String comments(int id, String type) => '$baseUrl/$type/$id/comments';
|
||||||
|
static String mention(int id, String type) => '$baseUrl/$type/$id/mention';
|
||||||
static String favourites() => '$baseUrl/user/favorites';
|
static String favourites() => '$baseUrl/user/favorites';
|
||||||
static String notificationStatus() => '$baseUrl/user/notification/status';
|
static String notificationStatus() => '$baseUrl/user/notification/status';
|
||||||
static String notificationTime() => '$baseUrl/user/notification/time';
|
static String notificationTime() => '$baseUrl/user/notification/time';
|
||||||
static String usersMentions(String search) => '$baseUrl/comment/user?search=$search';
|
static String usersMentions(String search) =>
|
||||||
|
'$baseUrl/comment/user?search=$search';
|
||||||
static String feedback(int id, int commentId, String type) =>
|
static String feedback(int id, int commentId, String type) =>
|
||||||
'$baseUrl/$type/$id/comments/$commentId/feedback/v2';
|
'$baseUrl/$type/$id/comments/$commentId/feedback';
|
||||||
static String addComment(int id, String type) =>
|
static String addComment(int id, String type) =>
|
||||||
'$baseUrl/$type/$id/comments/add';
|
'$baseUrl/$type/$id/comments/add';
|
||||||
static String deleteComment(int id) => '$baseUrl/comment/$id/v2';
|
static String deleteComment(int id) => '$baseUrl/comment/$id';
|
||||||
static String reportComment(int id) => '$baseUrl/comment/$id/report';
|
static String reportComment(int id) => '$baseUrl/comment/$id/report';
|
||||||
static String widgetNews() => '$baseUrl/user/widget';
|
static String widgetNews() => '$baseUrl/user/widget';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,12 @@ 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/tag.dart';
|
import 'package:didvan/models/tag.dart';
|
||||||
|
import 'package:didvan/routes/routes.dart';
|
||||||
import 'package:didvan/views/widgets/animated_visibility.dart';
|
import 'package:didvan/views/widgets/animated_visibility.dart';
|
||||||
import 'package:didvan/views/widgets/bookmark_button.dart';
|
import 'package:didvan/views/widgets/bookmark_button.dart';
|
||||||
import 'package:didvan/views/widgets/didvan/card.dart';
|
import 'package:didvan/views/widgets/didvan/card.dart';
|
||||||
import 'package:didvan/views/widgets/didvan/divider.dart';
|
import 'package:didvan/views/widgets/didvan/divider.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/infography_tag.dart';
|
import 'package:didvan/views/widgets/infography_tag.dart';
|
||||||
import 'package:didvan/views/widgets/ink_wrapper.dart';
|
import 'package:didvan/views/widgets/ink_wrapper.dart';
|
||||||
|
|
@ -108,7 +110,6 @@ class InfographyItem extends StatelessWidget {
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
|
|
@ -137,12 +138,30 @@ class InfographyItem extends StatelessWidget {
|
||||||
),
|
),
|
||||||
const DidvanDivider(),
|
const DidvanDivider(),
|
||||||
Row(
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
InfoCat(
|
InfoCat(
|
||||||
category: category,
|
category: category,
|
||||||
createdAt: createdAt,
|
createdAt: createdAt,
|
||||||
),
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
DidvanIconButton(
|
||||||
|
gestureSize: 32,
|
||||||
|
onPressed: () => Navigator.of(context).pushNamed(
|
||||||
|
Routes.mentions,
|
||||||
|
arguments: {
|
||||||
|
'id': id,
|
||||||
|
'type': 'infography',
|
||||||
|
'title': title,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
icon: DidvanIcons.chats_light,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 8.0,
|
||||||
|
),
|
||||||
BookmarkButton(
|
BookmarkButton(
|
||||||
itemId: id,
|
itemId: id,
|
||||||
type: 'infography',
|
type: 'infography',
|
||||||
|
|
@ -151,6 +170,8 @@ class InfographyItem extends StatelessWidget {
|
||||||
onMarkChanged: (value) => onMarkChanged(id, value, true),
|
onMarkChanged: (value) => onMarkChanged(id, value, true),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,555 @@
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:didvan/config/design_config.dart';
|
||||||
|
import 'package:didvan/config/theme_data.dart';
|
||||||
|
import 'package:didvan/constants/app_icons.dart';
|
||||||
|
import 'package:didvan/constants/assets.dart';
|
||||||
|
import 'package:didvan/models/users_mention.dart';
|
||||||
|
import 'package:didvan/models/view/app_bar_data.dart';
|
||||||
|
import 'package:didvan/views/comments/widgets/comment.dart';
|
||||||
|
import 'package:didvan/views/mentions/mentions_state.dart';
|
||||||
|
import 'package:didvan/views/widgets/animated_visibility.dart';
|
||||||
|
import 'package:didvan/views/widgets/didvan/checkbox.dart';
|
||||||
|
import 'package:didvan/views/widgets/didvan/icon_button.dart';
|
||||||
|
import 'package:didvan/views/widgets/didvan/scaffold.dart';
|
||||||
|
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||||
|
import 'package:didvan/views/widgets/shimmer_placeholder.dart';
|
||||||
|
import 'package:didvan/views/widgets/state_handlers/empty_state.dart';
|
||||||
|
import 'package:didvan/views/widgets/state_handlers/sliver_state_handler.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../widgets/didvan/didvan_title_divider.dart';
|
||||||
|
import '../widgets/user_mention.dart';
|
||||||
|
|
||||||
|
class Mentions extends StatefulWidget {
|
||||||
|
final Map<String, dynamic> pageData;
|
||||||
|
|
||||||
|
const Mentions({
|
||||||
|
Key? key,
|
||||||
|
required this.pageData,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<Mentions> createState() => _MentionsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MentionsState extends State<Mentions> {
|
||||||
|
final _focusNode = FocusNode();
|
||||||
|
double _bottomPadding = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
final state = context.read<MentionsState>();
|
||||||
|
state.itemId = widget.pageData['id'];
|
||||||
|
state.type = widget.pageData['type'];
|
||||||
|
|
||||||
|
Future.delayed(
|
||||||
|
Duration.zero,
|
||||||
|
() => state.getComments(),
|
||||||
|
);
|
||||||
|
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get _isPage => widget.pageData['isPage'] != false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final commentsState = context.watch<MentionsState>();
|
||||||
|
|
||||||
|
final bottomViewInset = MediaQuery.of(context).viewInsets.bottom;
|
||||||
|
if (bottomViewInset == 0) {
|
||||||
|
if (_bottomPadding != 0) {
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
_bottomPadding = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_bottomPadding = bottomViewInset;
|
||||||
|
return Material(
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
DidvanScaffold(
|
||||||
|
hidePlayer: true,
|
||||||
|
physics: const BouncingScrollPhysics(),
|
||||||
|
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||||
|
appBarData: _isPage
|
||||||
|
? AppBarData(
|
||||||
|
hasBack: true,
|
||||||
|
title: 'فراخوانیها',
|
||||||
|
subtitle: widget.pageData['title'],
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 92),
|
||||||
|
showSliversFirst: false,
|
||||||
|
slivers: [
|
||||||
|
Consumer<MentionsState>(
|
||||||
|
builder: (context, state, child) =>
|
||||||
|
SliverStateHandler<MentionsState>(
|
||||||
|
onRetry: state.getComments,
|
||||||
|
state: state,
|
||||||
|
itemPadding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
childCount: state.comments.length,
|
||||||
|
placeholder: const _CommentPlaceholder(),
|
||||||
|
centerEmptyState: _isPage,
|
||||||
|
enableEmptyState:
|
||||||
|
state.comments.isEmpty && state.privateComments.isEmpty,
|
||||||
|
emptyState: EmptyState(
|
||||||
|
asset: Assets.emptyChat,
|
||||||
|
title: 'دوستان خود را فراخوانی کنید'),
|
||||||
|
builder: (context, state, index) => Comment(
|
||||||
|
key: ValueKey(
|
||||||
|
state.comments[index].id.toString() +
|
||||||
|
state.comments[index].text,
|
||||||
|
),
|
||||||
|
focusNode: _focusNode,
|
||||||
|
comment: state.comments[index],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
children: commentsState.privateComments.isNotEmpty
|
||||||
|
? [
|
||||||
|
const SizedBox(
|
||||||
|
height: 6,
|
||||||
|
),
|
||||||
|
DidvanTitleDivider(
|
||||||
|
title: "نظرات پنهان شده",
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
icon: Icon(
|
||||||
|
commentsState.showPrivates
|
||||||
|
? DidvanIcons.angle_up_regular
|
||||||
|
: DidvanIcons.angle_down_regular,
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
),
|
||||||
|
onClick: () {
|
||||||
|
commentsState.showPrivates =
|
||||||
|
!commentsState.showPrivates;
|
||||||
|
commentsState.update();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
AnimatedVisibility(
|
||||||
|
duration: DesignConfig.lowAnimationDuration,
|
||||||
|
isVisible: commentsState.showPrivates,
|
||||||
|
child: _buildPrivateComments(commentsState),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
const DidvanTitleDivider(
|
||||||
|
title: "سایر نظرات",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
AnimatedVisibility(
|
||||||
|
duration: DesignConfig.lowAnimationDuration,
|
||||||
|
isVisible: commentsState.showUsersForMentionsLayout,
|
||||||
|
child: BackdropFilter(
|
||||||
|
filter: ImageFilter.blur(sigmaX: 8.0, sigmaY: 8.0),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.focused.withOpacity(0.5)),
|
||||||
|
child: DidvanScaffold(
|
||||||
|
appBarData: null,
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
left: 16, right: 16, top: 16, bottom: 92),
|
||||||
|
backgroundColor: Colors.white.withOpacity(0.0),
|
||||||
|
slivers: [
|
||||||
|
Consumer<MentionsState>(
|
||||||
|
builder: (context, state, child) =>
|
||||||
|
SliverStateHandler<MentionsState>(
|
||||||
|
onRetry: state.getUsersMention,
|
||||||
|
state: state,
|
||||||
|
itemPadding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
childCount: state.usersMention.length,
|
||||||
|
placeholder: const _UsersPlaceholder(),
|
||||||
|
centerEmptyState: _isPage,
|
||||||
|
enableEmptyState: state.usersMention.isEmpty,
|
||||||
|
emptyState: EmptyState(
|
||||||
|
asset: Assets.emptyBookmark,
|
||||||
|
title: 'لیست خالی است',
|
||||||
|
),
|
||||||
|
builder: (context, state, index) {
|
||||||
|
return UserMention(
|
||||||
|
user: state.usersMention[index],
|
||||||
|
index: index,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: MediaQuery.of(context).viewInsets.bottom,
|
||||||
|
child: _MessageBox(focusNode: _focusNode),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView _buildPrivateComments(MentionsState commentsState) {
|
||||||
|
return ListView.builder(
|
||||||
|
physics: const BouncingScrollPhysics(),
|
||||||
|
itemCount: commentsState.privateComments.length,
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return Comment(
|
||||||
|
key: ValueKey(
|
||||||
|
commentsState.privateComments[index].id.toString() +
|
||||||
|
commentsState.privateComments[index].text,
|
||||||
|
),
|
||||||
|
focusNode: _focusNode,
|
||||||
|
comment: commentsState.privateComments[index],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MessageBox extends StatefulWidget {
|
||||||
|
final FocusNode focusNode;
|
||||||
|
|
||||||
|
const _MessageBox({Key? key, required this.focusNode}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_MessageBox> createState() => _MessageBoxState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MessageBoxState extends State<_MessageBox> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final state = context.watch<MentionsState>();
|
||||||
|
|
||||||
|
void onCheckBoxChange(bool b) {
|
||||||
|
state.hideMentionedUser = b;
|
||||||
|
state.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
AnimatedVisibility(
|
||||||
|
duration: DesignConfig.lowAnimationDuration,
|
||||||
|
isVisible: state.showReplyBox,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).colorScheme.secondCTA,
|
||||||
|
borderRadius: const BorderRadius.only(
|
||||||
|
topRight: Radius.circular(16),
|
||||||
|
topLeft: Radius.circular(16)),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.title
|
||||||
|
.withOpacity(0.2),
|
||||||
|
offset: const Offset(
|
||||||
|
5.0,
|
||||||
|
5.0,
|
||||||
|
),
|
||||||
|
blurRadius: 10.0,
|
||||||
|
spreadRadius: 2.0,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
// border: Border(
|
||||||
|
// top: BorderSide(
|
||||||
|
// color: Theme.of(context).colorScheme.border,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
if (state.replyingTo != null)
|
||||||
|
DidvanText(
|
||||||
|
'پاسخ به ${state.replyingTo!.fullName}:',
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
DidvanIconButton(
|
||||||
|
gestureSize: 24,
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
icon: DidvanIcons.close_regular,
|
||||||
|
onPressed: () {
|
||||||
|
state.commentId = null;
|
||||||
|
state.replyingTo = null;
|
||||||
|
state.showReplyBox = false;
|
||||||
|
state.update();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
color: Theme.of(context).colorScheme.secondCTA,
|
||||||
|
padding: const EdgeInsets.fromLTRB(16, 8, 16, 8),
|
||||||
|
child: Divider(
|
||||||
|
height: 2,
|
||||||
|
color: Theme.of(context).colorScheme.border,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
AnimatedVisibility(
|
||||||
|
duration: DesignConfig.lowAnimationDuration,
|
||||||
|
isVisible: state.usersMentioned.name != null,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).colorScheme.secondCTA,
|
||||||
|
borderRadius: !state.showReplyBox
|
||||||
|
? const BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(16),
|
||||||
|
topRight: Radius.circular(16))
|
||||||
|
: null),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
width: 2,
|
||||||
|
height: 40,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 8,
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
DidvanText(
|
||||||
|
"اشاره به",
|
||||||
|
color: Theme.of(context).colorScheme.text,
|
||||||
|
style: Theme.of(context).textTheme.labelSmall,
|
||||||
|
),
|
||||||
|
DidvanText(
|
||||||
|
state.usersMentioned.name.toString(),
|
||||||
|
color: Theme.of(context).colorScheme.text,
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
DidvanIconButton(
|
||||||
|
gestureSize: 24,
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
icon: DidvanIcons.close_regular,
|
||||||
|
onPressed: () {
|
||||||
|
state.usersMentioned = UsersMention();
|
||||||
|
state.update();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
!state.showReplyBox
|
||||||
|
? DidvanCheckbox(
|
||||||
|
title: "پنهان کردن فراخوانی",
|
||||||
|
value: state.hideMentionedUser,
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
onChanged: onCheckBoxChange,
|
||||||
|
size: 12,
|
||||||
|
)
|
||||||
|
: const SizedBox(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
boxShadow: state.showReplyBox && state.usersMentioned.name == null
|
||||||
|
? null
|
||||||
|
: [
|
||||||
|
BoxShadow(
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.title.withOpacity(0.2),
|
||||||
|
offset: const Offset(
|
||||||
|
5.0,
|
||||||
|
5.0,
|
||||||
|
),
|
||||||
|
blurRadius: 10.0,
|
||||||
|
spreadRadius: 2.0,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
color: state.showReplyBox && state.usersMentioned.name == null
|
||||||
|
? Theme.of(context).colorScheme.secondCTA
|
||||||
|
: Theme.of(context).colorScheme.surface,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
DidvanIconButton(
|
||||||
|
onPressed: () => _onSend(state),
|
||||||
|
icon: DidvanIcons.send_solid,
|
||||||
|
size: 24,
|
||||||
|
color: Theme.of(context).colorScheme.focusedBorder,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: TextField(
|
||||||
|
focusNode: widget.focusNode,
|
||||||
|
controller: state.commentTextFieldController,
|
||||||
|
keyboardType: TextInputType.multiline,
|
||||||
|
textInputAction: TextInputAction.send,
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
onEditingComplete: () {},
|
||||||
|
onSubmitted: (value) => _onSend(state),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: InputBorder.none,
|
||||||
|
hintText: 'پیام خود را ارسال کنید',
|
||||||
|
hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
|
color: Theme.of(context).colorScheme.disabledText),
|
||||||
|
),
|
||||||
|
onChanged: (value) => _onChange(state, value),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onSend(MentionsState state) {
|
||||||
|
if (state.commentTextFieldController.text.replaceAll(' ', '').isNotEmpty) {
|
||||||
|
state.addComment();
|
||||||
|
state.commentTextFieldController.text = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onChange(MentionsState state, value) {
|
||||||
|
state.commentTextFieldController.text = value;
|
||||||
|
if (state.usersMentioned.name == null) {
|
||||||
|
if (state.commentTextFieldController.text.contains("@")) {
|
||||||
|
int index = state.commentTextFieldController.text.indexOf("@");
|
||||||
|
if (state.commentTextFieldController.text.length > index + 1) {
|
||||||
|
if (state.commentTextFieldController.text
|
||||||
|
.substring(index)
|
||||||
|
.contains(" ")) {
|
||||||
|
state.showUsersForMentionsLayout = false;
|
||||||
|
} else {
|
||||||
|
state.mentionedText =
|
||||||
|
state.commentTextFieldController.text.substring(index);
|
||||||
|
state.getUsersMention();
|
||||||
|
state.showUsersForMentionsLayout = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state.showUsersForMentionsLayout = false;
|
||||||
|
}
|
||||||
|
state.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CommentPlaceholder extends StatelessWidget {
|
||||||
|
const _CommentPlaceholder({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return const Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
ShimmerPlaceholder(
|
||||||
|
height: 24,
|
||||||
|
width: 24,
|
||||||
|
borderRadius: DesignConfig.highBorderRadius,
|
||||||
|
),
|
||||||
|
SizedBox(width: 16),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
ShimmerPlaceholder(
|
||||||
|
height: 20,
|
||||||
|
width: 100,
|
||||||
|
),
|
||||||
|
ShimmerPlaceholder(
|
||||||
|
height: 14,
|
||||||
|
width: 100,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 12),
|
||||||
|
ShimmerPlaceholder(
|
||||||
|
height: 16,
|
||||||
|
width: double.infinity,
|
||||||
|
),
|
||||||
|
SizedBox(height: 8),
|
||||||
|
ShimmerPlaceholder(
|
||||||
|
height: 16,
|
||||||
|
width: 200,
|
||||||
|
),
|
||||||
|
SizedBox(height: 8),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
ShimmerPlaceholder(
|
||||||
|
height: 24,
|
||||||
|
width: 48,
|
||||||
|
),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
ShimmerPlaceholder(
|
||||||
|
height: 24,
|
||||||
|
width: 48,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _UsersPlaceholder extends StatelessWidget {
|
||||||
|
const _UsersPlaceholder({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return const Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
ShimmerPlaceholder(
|
||||||
|
height: 40,
|
||||||
|
width: 40,
|
||||||
|
borderRadius: DesignConfig.highBorderRadius,
|
||||||
|
),
|
||||||
|
SizedBox(width: 16),
|
||||||
|
Expanded(
|
||||||
|
child: ShimmerPlaceholder(
|
||||||
|
borderRadius: DesignConfig.highBorderRadius,
|
||||||
|
height: 40,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,250 @@
|
||||||
|
import 'package:didvan/config/design_config.dart';
|
||||||
|
import 'package:didvan/models/comment/comment.dart';
|
||||||
|
import 'package:didvan/models/comment/feedback.dart';
|
||||||
|
import 'package:didvan/models/comment/reply.dart';
|
||||||
|
import 'package:didvan/models/comment/user.dart';
|
||||||
|
import 'package:didvan/models/enums.dart';
|
||||||
|
import 'package:didvan/models/users_mention.dart';
|
||||||
|
import 'package:didvan/models/view/alert_data.dart';
|
||||||
|
import 'package:didvan/providers/core.dart';
|
||||||
|
import 'package:didvan/providers/user.dart';
|
||||||
|
import 'package:didvan/services/network/request.dart';
|
||||||
|
import 'package:didvan/services/network/request_helper.dart';
|
||||||
|
import 'package:didvan/utils/action_sheet.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class MentionsState extends CoreProvier {
|
||||||
|
TextEditingController commentTextFieldController = TextEditingController();
|
||||||
|
UsersMention usersMentioned = UsersMention();
|
||||||
|
String mentionedText = '';
|
||||||
|
int? commentId;
|
||||||
|
UserOverview? replyingTo;
|
||||||
|
bool showReplyBox = false;
|
||||||
|
bool showUsersForMentionsLayout = false;
|
||||||
|
bool showPrivates = false;
|
||||||
|
bool hideMentionedUser = false;
|
||||||
|
int _count = 0;
|
||||||
|
late String type;
|
||||||
|
|
||||||
|
final List<CommentData> comments = [];
|
||||||
|
final List<CommentData> privateComments = [];
|
||||||
|
final List<UsersMention> usersMention = [];
|
||||||
|
final Map<int, MapEntry<bool, bool>> _feedbackQueue = {};
|
||||||
|
|
||||||
|
int itemId = 0;
|
||||||
|
|
||||||
|
Future<void> getComments() async {
|
||||||
|
final service = RequestService(
|
||||||
|
RequestHelper.comments(itemId, type),
|
||||||
|
);
|
||||||
|
await service.httpGet();
|
||||||
|
if (service.isSuccess) {
|
||||||
|
comments.clear();
|
||||||
|
final messagesPublic = service.result['comments']['public'];
|
||||||
|
for (var i = 0; i < messagesPublic.length; i++) {
|
||||||
|
comments.add(CommentData.fromJson(messagesPublic[i], false));
|
||||||
|
_count++;
|
||||||
|
for (var j = 0; j < messagesPublic[i]['replies'].length; j++) {
|
||||||
|
_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final messagesPrivate = service.result['comments']['private'];
|
||||||
|
for (var i = 0; i < messagesPrivate.length; i++) {
|
||||||
|
privateComments.add(CommentData.fromJson(messagesPrivate[i], true));
|
||||||
|
_count++;
|
||||||
|
for (var j = 0; j < messagesPrivate[i]['replies'].length; j++) {
|
||||||
|
_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
appState = AppState.idle;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
appState = AppState.failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getUsersMention() async {
|
||||||
|
final service = RequestService(
|
||||||
|
RequestHelper.usersMentions(mentionedText.replaceAll("@", "")),
|
||||||
|
);
|
||||||
|
await service.httpGet();
|
||||||
|
if (service.isSuccess) {
|
||||||
|
usersMention.clear();
|
||||||
|
final List<dynamic> users = service.data('users');
|
||||||
|
usersMention
|
||||||
|
.addAll(users.map((users) => UsersMention.fromJson(users)).toList());
|
||||||
|
|
||||||
|
appState = AppState.idle;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
appState = AppState.failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> feedback({
|
||||||
|
required int id,
|
||||||
|
required bool like,
|
||||||
|
required bool dislike,
|
||||||
|
required int likeCount,
|
||||||
|
required int dislikeCount,
|
||||||
|
int? replyId,
|
||||||
|
}) async {
|
||||||
|
_feedbackQueue.addAll({id: MapEntry(like, dislike)});
|
||||||
|
dynamic comment;
|
||||||
|
if (replyId == null) {
|
||||||
|
comment = comments.firstWhere((comment) => comment.id == id);
|
||||||
|
} else {
|
||||||
|
comment = comments
|
||||||
|
.firstWhere((comment) => comment.id == id)
|
||||||
|
.replies
|
||||||
|
.firstWhere((element) => element.id == replyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (comment != null) {
|
||||||
|
comment.feedback.like = likeCount;
|
||||||
|
comment.feedback.dislike = dislikeCount;
|
||||||
|
comment.disliked = dislike;
|
||||||
|
comment.liked = like;
|
||||||
|
}
|
||||||
|
Future.delayed(const Duration(milliseconds: 500), () async {
|
||||||
|
if (!_feedbackQueue.containsKey(id)) return;
|
||||||
|
final service = RequestService(
|
||||||
|
RequestHelper.feedback(itemId, id, type),
|
||||||
|
body: {
|
||||||
|
'like': _feedbackQueue[id]!.key,
|
||||||
|
'dislike': _feedbackQueue[id]!.value,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
await service.put();
|
||||||
|
_feedbackQueue.remove(id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> addComment() async {
|
||||||
|
late List<CommentData> cList =
|
||||||
|
hideMentionedUser ? privateComments : comments;
|
||||||
|
final user = DesignConfig.context!.read<UserProvider>().user;
|
||||||
|
if (replyingTo != null) {
|
||||||
|
comments.firstWhere((comment) => comment.id == commentId).replies.add(
|
||||||
|
Reply(
|
||||||
|
id: 0,
|
||||||
|
text: commentTextFieldController.text,
|
||||||
|
createdAt: DateTime.now().toString(),
|
||||||
|
liked: false,
|
||||||
|
disliked: false,
|
||||||
|
feedback: FeedbackData(like: 0, dislike: 0),
|
||||||
|
toUser: replyingTo!,
|
||||||
|
user: UserOverview(
|
||||||
|
id: user.id,
|
||||||
|
fullName: user.fullName,
|
||||||
|
photo: user.photo,
|
||||||
|
),
|
||||||
|
status: 2,
|
||||||
|
mention: usersMentioned.name,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
cList.insert(
|
||||||
|
0,
|
||||||
|
CommentData(
|
||||||
|
id: 0,
|
||||||
|
text: commentTextFieldController.text,
|
||||||
|
createdAt: DateTime.now().toString(),
|
||||||
|
liked: false,
|
||||||
|
disliked: false,
|
||||||
|
feedback: FeedbackData(like: 0, dislike: 0),
|
||||||
|
user: UserOverview(
|
||||||
|
id: user.id,
|
||||||
|
fullName: user.fullName,
|
||||||
|
photo: user.photo,
|
||||||
|
),
|
||||||
|
replies: [],
|
||||||
|
status: 2,
|
||||||
|
private: hideMentionedUser,
|
||||||
|
mention: usersMentioned.name,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final body = {};
|
||||||
|
|
||||||
|
if (commentId != null) {
|
||||||
|
body.addAll({'commentId': commentId});
|
||||||
|
}
|
||||||
|
if (replyingTo != null) {
|
||||||
|
body.addAll({'replyUserId': replyingTo!.id});
|
||||||
|
}
|
||||||
|
body.addAll({'status': 2});
|
||||||
|
|
||||||
|
showReplyBox = false;
|
||||||
|
// update();
|
||||||
|
body.addAll({
|
||||||
|
'text': commentTextFieldController.text,
|
||||||
|
"mention": usersMentioned.id,
|
||||||
|
"private": hideMentionedUser
|
||||||
|
});
|
||||||
|
final service = RequestService(
|
||||||
|
RequestHelper.addComment(itemId, type),
|
||||||
|
body: body,
|
||||||
|
);
|
||||||
|
|
||||||
|
await service.post();
|
||||||
|
if (service.isSuccess) {
|
||||||
|
if (replyingTo != null) {
|
||||||
|
cList
|
||||||
|
.firstWhere((comment) => comment.id == commentId)
|
||||||
|
.replies
|
||||||
|
.firstWhere((reply) => reply.id == 0)
|
||||||
|
.id = service.result['comment']['id'];
|
||||||
|
} else {
|
||||||
|
cList.firstWhere((comment) => comment.id == 0).id =
|
||||||
|
service.result['comment']['id'];
|
||||||
|
}
|
||||||
|
commentId = null;
|
||||||
|
replyingTo = null;
|
||||||
|
usersMentioned = UsersMention();
|
||||||
|
mentionedText = '';
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reportComment(int id) {
|
||||||
|
final service = RequestService(RequestHelper.reportComment(id));
|
||||||
|
service.post();
|
||||||
|
ActionSheetUtils.showAlert(
|
||||||
|
AlertData(
|
||||||
|
message: 'گزارش شما با موفقیت ثبت شد و به زودی بررسی میگردد.',
|
||||||
|
aLertType: ALertType.success,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteComment(int id, int status, int? rootId) async {
|
||||||
|
final service = RequestService(RequestHelper.deleteComment(id));
|
||||||
|
service.delete();
|
||||||
|
if (rootId == null) {
|
||||||
|
final comment = comments.firstWhere((element) => element.id == id);
|
||||||
|
if (comment.replies.isNotEmpty) {
|
||||||
|
_count = 0;
|
||||||
|
await getComments();
|
||||||
|
} else {
|
||||||
|
comments.remove(comment);
|
||||||
|
|
||||||
|
if (status != 2) {
|
||||||
|
_count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
comments
|
||||||
|
.firstWhere((element) => element.id == rootId)
|
||||||
|
.replies
|
||||||
|
.removeWhere((element) => element.id == id);
|
||||||
|
|
||||||
|
if (status != 2) {
|
||||||
|
_count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,139 @@
|
||||||
|
import 'package:didvan/config/design_config.dart';
|
||||||
|
import 'package:didvan/config/theme_data.dart';
|
||||||
|
import 'package:didvan/constants/app_icons.dart';
|
||||||
|
import 'package:didvan/models/comment/comment.dart';
|
||||||
|
import 'package:didvan/models/comment/reply.dart';
|
||||||
|
import 'package:didvan/models/mention/mention.dart';
|
||||||
|
import 'package:didvan/models/view/action_sheet_data.dart';
|
||||||
|
import 'package:didvan/providers/user.dart';
|
||||||
|
import 'package:didvan/utils/action_sheet.dart';
|
||||||
|
import 'package:didvan/utils/date_time.dart';
|
||||||
|
import 'package:didvan/views/comments/comments_state.dart';
|
||||||
|
import 'package:didvan/views/mentions/mentions_state.dart';
|
||||||
|
import 'package:didvan/views/widgets/menu_item.dart';
|
||||||
|
import 'package:didvan/views/widgets/animated_visibility.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';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class Mention extends StatefulWidget {
|
||||||
|
final FocusNode focusNode;
|
||||||
|
final MentionData comment;
|
||||||
|
|
||||||
|
const Mention({
|
||||||
|
Key? key,
|
||||||
|
required this.focusNode,
|
||||||
|
required this.comment,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<Mention> createState() => MentionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class MentionState extends State<Mention> {
|
||||||
|
late final MentionsState state;
|
||||||
|
|
||||||
|
MentionData get _comment => widget.comment;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
state = context.read<MentionsState>();
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [_commentBuilder(comment: _comment)],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _commentBuilder({required comment, bool isReply = false}) => Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
right: isReply
|
||||||
|
? BorderSide(color: Theme.of(context).colorScheme.caption)
|
||||||
|
: BorderSide.none,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
if (isReply) const SizedBox(width: 12),
|
||||||
|
if (comment.user.photo == null)
|
||||||
|
const Icon(DidvanIcons.avatar_light),
|
||||||
|
if (comment.user.photo != null)
|
||||||
|
SkeletonImage(
|
||||||
|
imageUrl: comment.user.photo,
|
||||||
|
height: 24,
|
||||||
|
width: 24,
|
||||||
|
borderRadius: DesignConfig.highBorderRadius,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
DidvanText(
|
||||||
|
comment.user.fullName,
|
||||||
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
DidvanText(
|
||||||
|
DateTimeUtils.momentGenerator(comment.createdAt),
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
color: Theme.of(context).colorScheme.caption,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
DidvanIconButton(
|
||||||
|
size: 18,
|
||||||
|
gestureSize: 24,
|
||||||
|
icon: DidvanIcons.menu_light,
|
||||||
|
onPressed: () => _showCommentActions(comment),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
DidvanText(
|
||||||
|
comment.mention.toString(),
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
style: Theme.of(context).textTheme.titleSmall,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<void> _showCommentActions(comment) async {
|
||||||
|
ActionSheetUtils.showBottomSheet(
|
||||||
|
data: ActionSheetData(
|
||||||
|
title: 'گزینههای نظر',
|
||||||
|
content: Column(
|
||||||
|
children: [
|
||||||
|
if (comment.user.id == context.read<UserProvider>().user.id)
|
||||||
|
MenuOption(
|
||||||
|
title: 'حذف نظر',
|
||||||
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
|
onTap: () {
|
||||||
|
state.deleteComment(
|
||||||
|
comment.id,
|
||||||
|
comment.status,
|
||||||
|
comment.runtimeType == Reply ? _comment.id : null,
|
||||||
|
);
|
||||||
|
ActionSheetUtils.pop();
|
||||||
|
},
|
||||||
|
icon: DidvanIcons.trash_solid,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
hasConfirmButton: false,
|
||||||
|
hasDismissButton: false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -27,29 +27,6 @@ class ProfilePage extends StatelessWidget {
|
||||||
DidvanCard(
|
DidvanCard(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
// Consumer<UserProvider>(
|
|
||||||
// child: Icon(
|
|
||||||
// DidvanIcons.angle_left_regular,
|
|
||||||
// size: 18,
|
|
||||||
// color: Theme.of(context).colorScheme.title,
|
|
||||||
// ),
|
|
||||||
// builder: (context, state, child) => MenuOption(
|
|
||||||
// title: 'پیامها',
|
|
||||||
// icon: DidvanIcons.message_regular,
|
|
||||||
// onTap: () =>
|
|
||||||
// Navigator.of(context).pushNamed(Routes.directList),
|
|
||||||
// trailing: Row(
|
|
||||||
// children: [
|
|
||||||
// if (state.unreadMessageCount != 0)
|
|
||||||
// DidvanBadge(
|
|
||||||
// text: state.unreadMessageCount.toString(),
|
|
||||||
// ),
|
|
||||||
// child!,
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// const DidvanDivider(),
|
|
||||||
MenuOption(
|
MenuOption(
|
||||||
title: 'ویرایش پروفایل',
|
title: 'ویرایش پروفایل',
|
||||||
icon: DidvanIcons.user_edit_regular,
|
icon: DidvanIcons.user_edit_regular,
|
||||||
|
|
@ -65,12 +42,6 @@ class ProfilePage extends StatelessWidget {
|
||||||
Navigator.of(context).pushNamed(Routes.generalSettings),
|
Navigator.of(context).pushNamed(Routes.generalSettings),
|
||||||
),
|
),
|
||||||
const DidvanDivider(),
|
const DidvanDivider(),
|
||||||
// MenuOption(
|
|
||||||
// title: 'نشان شدهها',
|
|
||||||
// icon: DidvanIcons.bookmark_regular,
|
|
||||||
// onTap: () => Navigator.of(context).pushNamed(Routes.bookmarks),
|
|
||||||
// ),
|
|
||||||
// const DidvanDivider(),
|
|
||||||
MenuOption(
|
MenuOption(
|
||||||
title: 'خروج از حساب کاربری',
|
title: 'خروج از حساب کاربری',
|
||||||
icon: DidvanIcons.sign_out_regular,
|
icon: DidvanIcons.sign_out_regular,
|
||||||
|
|
@ -122,7 +93,7 @@ class ProfilePage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
DidvanText(
|
DidvanText(
|
||||||
'نسخه نرمافزار: 3.1.1',
|
'نسخه نرمافزار: 3.2.0',
|
||||||
style: Theme.of(context).textTheme.bodySmall,
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -42,10 +42,12 @@ class FloatingNavigationBar extends StatefulWidget {
|
||||||
class _FloatingNavigationBarState extends State<FloatingNavigationBar> {
|
class _FloatingNavigationBarState extends State<FloatingNavigationBar> {
|
||||||
bool _isScrolled = false;
|
bool _isScrolled = false;
|
||||||
int _comments = 0;
|
int _comments = 0;
|
||||||
|
int _mentions = 0;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didUpdateWidget(covariant FloatingNavigationBar oldWidget) {
|
void didUpdateWidget(covariant FloatingNavigationBar oldWidget) {
|
||||||
_comments = widget.item.comments;
|
_comments = widget.item.comments;
|
||||||
|
|
||||||
if (widget.openComments) {
|
if (widget.openComments) {
|
||||||
Future.delayed(
|
Future.delayed(
|
||||||
const Duration(seconds: 1),
|
const Duration(seconds: 1),
|
||||||
|
|
@ -71,6 +73,7 @@ class _FloatingNavigationBarState extends State<FloatingNavigationBar> {
|
||||||
_handleScroll();
|
_handleScroll();
|
||||||
_isScrolled = false;
|
_isScrolled = false;
|
||||||
_comments = widget.item.comments;
|
_comments = widget.item.comments;
|
||||||
|
|
||||||
if (widget.openComments) {
|
if (widget.openComments) {
|
||||||
Future.delayed(
|
Future.delayed(
|
||||||
const Duration(seconds: 1),
|
const Duration(seconds: 1),
|
||||||
|
|
@ -85,6 +88,7 @@ class _FloatingNavigationBarState extends State<FloatingNavigationBar> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -134,6 +138,31 @@ class _FloatingNavigationBarState extends State<FloatingNavigationBar> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
|
SizedBox(
|
||||||
|
width: 60,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
if (_mentions != 0)
|
||||||
|
DidvanText(
|
||||||
|
_mentions.toString(),
|
||||||
|
color: foregroundColor,
|
||||||
|
),
|
||||||
|
DidvanIconButton(
|
||||||
|
gestureSize: 32,
|
||||||
|
onPressed: () => Navigator.of(context).pushNamed(
|
||||||
|
Routes.mentions,
|
||||||
|
arguments: {
|
||||||
|
'id': widget.item.id,
|
||||||
|
'type': widget.isRadar ? 'radar' : 'news',
|
||||||
|
'title': widget.item.title,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
icon: DidvanIcons.chart_light,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
BookmarkButton(
|
BookmarkButton(
|
||||||
itemId: widget.item.id,
|
itemId: widget.item.id,
|
||||||
type: widget.isRadar ? 'radar' : 'news',
|
type: widget.isRadar ? 'radar' : 'news',
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ 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';
|
||||||
import 'package:didvan/providers/media.dart';
|
import 'package:didvan/providers/media.dart';
|
||||||
|
import 'package:didvan/routes/routes.dart';
|
||||||
import 'package:didvan/views/podcasts/studio_details/studio_details_state.dart';
|
import 'package:didvan/views/podcasts/studio_details/studio_details_state.dart';
|
||||||
import 'package:didvan/views/widgets/bookmark_button.dart';
|
import 'package:didvan/views/widgets/bookmark_button.dart';
|
||||||
import 'package:didvan/views/widgets/duration_widget.dart';
|
import 'package:didvan/views/widgets/duration_widget.dart';
|
||||||
|
|
@ -109,8 +110,21 @@ class PodcastOverview extends StatelessWidget {
|
||||||
strokeWidth: 2,
|
strokeWidth: 2,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 8.0),
|
||||||
],
|
],
|
||||||
|
DidvanIconButton(
|
||||||
|
gestureSize: 32,
|
||||||
|
onPressed: () => Navigator.of(context).pushNamed(
|
||||||
|
Routes.mentions,
|
||||||
|
arguments: {
|
||||||
|
'id': podcast.id,
|
||||||
|
'type': 'studio',
|
||||||
|
'title': podcast.title,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
icon: DidvanIcons.chats_light,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8.0),
|
||||||
BookmarkButton(
|
BookmarkButton(
|
||||||
itemId: podcast.id,
|
itemId: podcast.id,
|
||||||
type: 'podcast',
|
type: 'podcast',
|
||||||
|
|
|
||||||
|
|
@ -118,10 +118,6 @@ class RadarOverview extends StatelessWidget {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// const SizedBox(width: 16),
|
|
||||||
// const DidvanText('10'),
|
|
||||||
// const SizedBox(width: 4),
|
|
||||||
// const Icon(DidvanIcons.evaluation_regular),
|
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
BookmarkButton(
|
BookmarkButton(
|
||||||
itemId: radar.id,
|
itemId: radar.id,
|
||||||
|
|
|
||||||
|
|
@ -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/views/widgets/bookmark_button.dart';
|
import 'package:didvan/views/widgets/bookmark_button.dart';
|
||||||
|
import 'package:didvan/views/widgets/didvan/icon_button.dart';
|
||||||
import 'package:didvan/views/widgets/duration_widget.dart';
|
import 'package:didvan/views/widgets/duration_widget.dart';
|
||||||
import 'package:didvan/views/widgets/didvan/card.dart';
|
import 'package:didvan/views/widgets/didvan/card.dart';
|
||||||
import 'package:didvan/views/widgets/didvan/divider.dart';
|
import 'package:didvan/views/widgets/didvan/divider.dart';
|
||||||
|
|
@ -94,13 +95,19 @@ class VideoOverview extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
DurationWidget(duration: video.duration!),
|
DurationWidget(duration: video.duration!),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
// DidvanIconButton(
|
DidvanIconButton(
|
||||||
// gestureSize: 28,
|
gestureSize: 32,
|
||||||
// icon: DidvanIcons.download_regular,
|
onPressed: () => Navigator.of(context).pushNamed(
|
||||||
// onPressed: () =>
|
Routes.mentions,
|
||||||
// context.read<StudioState>().download(video.media!),
|
arguments: {
|
||||||
// ),
|
'id': video.id,
|
||||||
// const SizedBox(width: 16),
|
'type': 'studio',
|
||||||
|
'title': video.title,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
icon: DidvanIcons.chats_light,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8.0),
|
||||||
BookmarkButton(
|
BookmarkButton(
|
||||||
itemId: video.id,
|
itemId: video.id,
|
||||||
type: 'video',
|
type: 'video',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue