Skip to content

Commit

Permalink
комментарии к статьям
Browse files Browse the repository at this point in the history
дефолтный язык: русский

даты с учетом локальной таймзоны
  • Loading branch information
iska9der committed Sep 4, 2022
1 parent cc79e80 commit 5fe20c4
Show file tree
Hide file tree
Showing 27 changed files with 798 additions and 86 deletions.
25 changes: 25 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "flabr",
"request": "launch",
"type": "dart"
},
{
"name": "flabr (profile mode)",
"request": "launch",
"type": "dart",
"flutterMode": "profile"
},
{
"name": "flabr (release mode)",
"request": "launch",
"type": "dart",
"flutterMode": "release"
}
]
}
24 changes: 14 additions & 10 deletions lib/common/model/network/params.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,45 @@ import 'package:equatable/equatable.dart';

class Params extends Equatable {
const Params({
this.fl = 'ru',
this.hl = 'ru',
this.langArticles = 'ru',
this.langUI = 'ru',
this.page = '',
});

/// Язык постов
///
/// `fl` на хабре
///
/// перечисляется через запятую
final String fl;
final String langArticles;

/// Язык интерфейса
final String hl;
///
/// `hl` на хабре
final String langUI;

final String page;

Map<String, dynamic> toMap() {
return {
'fl': fl,
'hl': hl,
'fl': langArticles,
'hl': langUI,
'page': page,
};
}

factory Params.fromMap(map) {
return Params(
fl: map['fl'] ?? 'ru',
hl: map['hl'] ?? 'ru',
langArticles: map['fl'] ?? 'ru',
langUI: map['hl'] ?? 'ru',
page: map['page'] ?? '',
);
}

String toQueryString() {
return 'fl=$fl&hl=$hl&page=$page';
return 'fl=$langArticles&hl=$langUI&page=$page';
}

@override
List<Object?> get props => [fl, hl, page];
List<Object?> get props => [langArticles, langUI, page];
}
10 changes: 10 additions & 0 deletions lib/component/router/app_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import '../../feature/article/page/article_detail_page.dart';
import '../../feature/article/page/article_list_page.dart';
import '../../feature/article/page/news_detail_page.dart';
import '../../feature/article/page/news_list_page.dart';
import '../../feature/comment/page/comment_list_page.dart';
import '../../feature/hub/page/hub_dashboard_page.dart';
import '../../feature/hub/page/hub_detail_page.dart';
import '../../feature/hub/page/hub_list_page.dart';
Expand Down Expand Up @@ -46,6 +47,11 @@ part 'app_router.gr.dart';
name: ArticleDetailPage.routeName,
page: ArticleDetailPage,
),
AutoRoute(
path: CommentListPage.routePath,
name: CommentListPage.routeName,
page: CommentListPage,
),
],
),

Expand Down Expand Up @@ -173,6 +179,10 @@ part 'app_router.gr.dart';
path: '*/post/:id',
redirectTo: 'articles/details/:id',
),
RedirectRoute(
path: '*/post/:id/comments',
redirectTo: 'articles/comments/:id',
),

/// Статьи из блогов
/// todo: пока через вкладку "статьи"
Expand Down
45 changes: 44 additions & 1 deletion lib/component/router/app_router.gr.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ class _$AppRouter extends RootStackRouter {
routeData: routeData,
child: ArticleDetailPage(key: args.key, id: args.id));
},
ArticleCommentListRoute.name: (routeData) {
final pathParams = routeData.inheritedPathParams;
final args = routeData.argsAs<ArticleCommentListRouteArgs>(
orElse: () => ArticleCommentListRouteArgs(
articleId: pathParams.getString('articleId')));
return MaterialPageX<dynamic>(
routeData: routeData,
child: CommentListPage(key: args.key, articleId: args.articleId));
},
NewsListRoute.name: (routeData) {
final pathParams = routeData.inheritedPathParams;
final args = routeData.argsAs<NewsListRouteArgs>(
Expand Down Expand Up @@ -134,7 +143,10 @@ class _$AppRouter extends RootStackRouter {
RouteConfig(ArticleListRoute.name,
path: 'flows/:flow', parent: ArticlesEmptyRoute.name),
RouteConfig(ArticleDetailRoute.name,
path: 'details/:id', parent: ArticlesEmptyRoute.name)
path: 'details/:id', parent: ArticlesEmptyRoute.name),
RouteConfig(ArticleCommentListRoute.name,
path: 'comments/:articleId',
parent: ArticlesEmptyRoute.name)
]),
RouteConfig(NewsEmptyRoute.name,
path: 'news',
Expand Down Expand Up @@ -204,6 +216,11 @@ class _$AppRouter extends RootStackRouter {
parent: DashboardRoute.name,
redirectTo: 'articles/details/:id',
fullMatch: true),
RouteConfig('*/post/:id/comments#redirect',
path: '*/post/:id/comments',
parent: DashboardRoute.name,
redirectTo: 'articles/comments/:id',
fullMatch: true),
RouteConfig('*/company/*/blog/:id#redirect',
path: '*/company/*/blog/:id',
parent: DashboardRoute.name,
Expand Down Expand Up @@ -344,6 +361,32 @@ class ArticleDetailRouteArgs {
}
}

/// generated route for
/// [CommentListPage]
class ArticleCommentListRoute
extends PageRouteInfo<ArticleCommentListRouteArgs> {
ArticleCommentListRoute({Key? key, required String articleId})
: super(ArticleCommentListRoute.name,
path: 'comments/:articleId',
args: ArticleCommentListRouteArgs(key: key, articleId: articleId),
rawPathParams: {'articleId': articleId});

static const String name = 'ArticleCommentListRoute';
}

class ArticleCommentListRouteArgs {
const ArticleCommentListRouteArgs({this.key, required this.articleId});

final Key? key;

final String articleId;

@override
String toString() {
return 'ArticleCommentListRouteArgs{key: $key, articleId: $articleId}';
}
}

/// generated route for
/// [NewsListPage]
class NewsListRoute extends PageRouteInfo<NewsListRouteArgs> {
Expand Down
2 changes: 1 addition & 1 deletion lib/feature/article/model/article_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class ArticleModel extends Equatable {
final ArticleType type;

final String timePublished;
DateTime get publishedAt => DateTime.parse(timePublished);
DateTime get publishedAt => DateTime.parse(timePublished).toLocal();

/// Заголовок
final String titleHtml;
Expand Down
29 changes: 7 additions & 22 deletions lib/feature/article/model/network/article_list_params.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import '../../../../common/model/network/params.dart';

class ArticleListParams extends Params {
const ArticleListParams({
super.fl = 'ru',
super.hl = 'ru',
super.langArticles = 'ru',
super.langUI = 'ru',
this.news = false,
this.flow,
this.custom,
Expand All @@ -25,8 +25,8 @@ class ArticleListParams extends Params {
@override
Map<String, dynamic> toMap() {
return {
'fl': fl,
'hl': hl,
'fl': langArticles,
'hl': langUI,
'news': news,
'flow': flow,
'custom': custom,
Expand All @@ -37,21 +37,6 @@ class ArticleListParams extends Params {
};
}

@override
factory ArticleListParams.fromMap(Map<String, dynamic> map) {
return ArticleListParams(
fl: map['fl'] as String,
hl: map['hl'] as String,
news: map['news'] ? map['news'] == 'true' : false,
flow: map['flow'] as String,
custom: map['custom'] as String,
page: map['page'] as String,
sort: map['sort'] as String,
period: map['period'] as String,
score: map['score'] as String,
);
}

@override
String toQueryString() {
String? lSort = sort != null ? '&sort=$sort' : '';
Expand All @@ -70,13 +55,13 @@ class ArticleListParams extends Params {
String? lPeriod = period != null ? '&period=$period' : '';
String? lScore = score != null ? '&score=$score' : '';

return 'fl=$fl&hl=$hl$lFlow$lNews$lSort$lPeriod$lScore&page=$page';
return 'fl=$langArticles&hl=$langUI$lFlow$lNews$lSort$lPeriod$lScore&page=$page';
}

@override
List<Object?> get props => [
fl,
hl,
langArticles,
langUI,
news,
flow,
custom,
Expand Down
3 changes: 2 additions & 1 deletion lib/feature/article/page/article_detail_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,10 @@ class _FloatingStatistics extends StatelessWidget {
curve: Curves.easeInOutCubicEmphasized,
offset: isVisible ? const Offset(0, 0) : const Offset(0, 10),
child: Container(
height: 26,
height: 36,
color: Theme.of(context).colorScheme.surface.withOpacity(.95),
child: ArticleStatisticsWidget(
articleId: state.id,
statistics: stats,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
),
Expand Down
37 changes: 31 additions & 6 deletions lib/feature/article/repository/article_repository.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import '../../../common/exception/displayable_exception.dart';
import '../../../common/exception/fetch_exception.dart';
import '../../../component/http/http_client.dart';
import '../../comment/model/network/comment_list_params.dart';
import '../../comment/model/network/comment_list_response.dart';
import '../model/article_type.dart';
import '../model/flow_enum.dart';
import '../model/network/article_list_params.dart';
Expand Down Expand Up @@ -41,8 +43,8 @@ class ArticleRepository {
}) async {
try {
final params = ArticleListParams(
fl: langArticles,
hl: langUI,
langArticles: langArticles,
langUI: langUI,
flow: flow == FlowEnum.all ? null : flow.name,
news: type == ArticleType.news,

Expand Down Expand Up @@ -78,8 +80,8 @@ class ArticleRepository {
}) async {
try {
final params = ArticleListParams(
fl: langArticles,
hl: langUI,
langArticles: langArticles,
langUI: langUI,
sort: 'all',
period: sort == SortEnum.byBest ? period.name : null,
score: sort == SortEnum.byNew ? score : null,
Expand Down Expand Up @@ -110,8 +112,8 @@ class ArticleRepository {
}) async {
try {
final params = ArticleListParams(
fl: langArticles,
hl: langUI,
langArticles: langArticles,
langUI: langUI,
page: page,
);

Expand All @@ -127,4 +129,27 @@ class ArticleRepository {
throw FetchException();
}
}

Future<CommentListResponse> fetchComments({
required String articleId,
required String langUI,
required String langArticles,
}) async {
try {
final params = CommentListParams(
articleId: articleId,
langArticles: langArticles,
langUI: langUI,
);

final queryString = params.toQueryString();
final response = await _baseClient.get(queryString);

return CommentListResponse.fromMap(response.data);
} on DisplayableException {
rethrow;
} catch (e) {
throw FetchException();
}
}
}
17 changes: 17 additions & 0 deletions lib/feature/article/service/article_service.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import '../../../component/language.dart';
import '../../comment/model/network/comment_list_response.dart';
import '../model/article_model.dart';
import '../model/article_type.dart';
import '../model/flow_enum.dart';
Expand Down Expand Up @@ -125,4 +126,20 @@ class ArticleService {

return cached;
}

Future<CommentListResponse> fetchComments({
required String articleId,
required LanguageEnum langUI,
required List<LanguageEnum> langArticles,
}) async {
final listResponse = await repository.fetchComments(
articleId: articleId,
langUI: langUI.name,
langArticles: encodeLangs(langArticles),
);

final structurizedComments = listResponse.structurize();

return listResponse.copyWith(comments: structurizedComments);
}
}
10 changes: 5 additions & 5 deletions lib/feature/article/widget/article_card_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ class ArticleCardWidget extends StatelessWidget {
],
),
const SizedBox(height: 30),
ArticleStatisticsWidget(statistics: article.statistics),
ArticleStatisticsWidget(
articleId: article.id,
statistics: article.statistics,
),
],
),
);
Expand All @@ -67,15 +70,12 @@ class ArticleInfoWidget extends StatelessWidget {

@override
Widget build(BuildContext context) {
final timePub =
'${DateFormat.yMMMMd().format(article.publishedAt)}, ${DateFormat.Hm().format(article.publishedAt)}';

return Row(
children: [
ArticleAuthorWidget(article.author),
const SizedBox(width: 4),
Text(
timePub,
DateFormat.yMMMMd().add_jm().format(article.publishedAt),
style: Theme.of(context).textTheme.caption,
),
],
Expand Down
Loading

0 comments on commit 5fe20c4

Please sign in to comment.