From d04a72c4626515492f68c64ae400ff51846f57a3 Mon Sep 17 00:00:00 2001 From: bggRGjQaUbCoE Date: Sat, 19 Oct 2024 10:38:29 +0800 Subject: [PATCH] feat: show member article --- lib/http/api.dart | 3 + lib/http/member.dart | 49 ++++++++ lib/models/space/data.dart | 3 +- lib/models/space/data.g.dart | 2 +- lib/models/space_article/author.dart | 36 ++++++ lib/models/space_article/author.g.dart | 36 ++++++ lib/models/space_article/category.dart | 19 ++++ lib/models/space_article/category.g.dart | 19 ++++ lib/models/space_article/data.dart | 21 ++++ lib/models/space_article/data.g.dart | 25 ++++ lib/models/space_article/item.dart | 107 ++++++++++++++++++ lib/models/space_article/item.g.dart | 101 +++++++++++++++++ lib/models/space_article/label.dart | 17 +++ lib/models/space_article/label.g.dart | 19 ++++ lib/models/space_article/list.dart | 44 +++++++ lib/models/space_article/list.g.dart | 37 ++++++ lib/models/space_article/media.dart | 33 ++++++ lib/models/space_article/media.g.dart | 29 +++++ lib/models/space_article/nameplate.dart | 29 +++++ lib/models/space_article/nameplate.g.dart | 25 ++++ lib/models/space_article/official_verify.dart | 17 +++ .../space_article/official_verify.g.dart | 19 ++++ lib/models/space_article/pendant.dart | 19 ++++ lib/models/space_article/pendant.g.dart | 21 ++++ lib/models/space_article/space_article.dart | 21 ++++ lib/models/space_article/space_article.g.dart | 24 ++++ lib/models/space_article/stats.dart | 30 +++++ lib/models/space_article/stats.g.dart | 29 +++++ lib/models/space_article/vip.dart | 37 ++++++ lib/models/space_article/vip.g.dart | 31 +++++ .../content/article/member_article.dart | 96 +++++++++++++++- .../content/article/member_article_ctr.dart | 50 ++++++++ .../member_contribute/member_contribute.dart | 5 +- .../new/content/member_home/member_home.dart | 53 ++++++++- 34 files changed, 1098 insertions(+), 8 deletions(-) create mode 100644 lib/models/space_article/author.dart create mode 100644 lib/models/space_article/author.g.dart create mode 100644 lib/models/space_article/category.dart create mode 100644 lib/models/space_article/category.g.dart create mode 100644 lib/models/space_article/data.dart create mode 100644 lib/models/space_article/data.g.dart create mode 100644 lib/models/space_article/item.dart create mode 100644 lib/models/space_article/item.g.dart create mode 100644 lib/models/space_article/label.dart create mode 100644 lib/models/space_article/label.g.dart create mode 100644 lib/models/space_article/list.dart create mode 100644 lib/models/space_article/list.g.dart create mode 100644 lib/models/space_article/media.dart create mode 100644 lib/models/space_article/media.g.dart create mode 100644 lib/models/space_article/nameplate.dart create mode 100644 lib/models/space_article/nameplate.g.dart create mode 100644 lib/models/space_article/official_verify.dart create mode 100644 lib/models/space_article/official_verify.g.dart create mode 100644 lib/models/space_article/pendant.dart create mode 100644 lib/models/space_article/pendant.g.dart create mode 100644 lib/models/space_article/space_article.dart create mode 100644 lib/models/space_article/space_article.g.dart create mode 100644 lib/models/space_article/stats.dart create mode 100644 lib/models/space_article/stats.g.dart create mode 100644 lib/models/space_article/vip.dart create mode 100644 lib/models/space_article/vip.g.dart create mode 100644 lib/pages/member/new/content/member_contribute/content/article/member_article_ctr.dart diff --git a/lib/http/api.dart b/lib/http/api.dart index 6261b951..e3c36457 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -300,6 +300,9 @@ class Api { static const String spaceBangumi = '${HttpString.appBaseUrl}/x/v2/space/bangumi'; + static const String spaceArticle = + '${HttpString.appBaseUrl}/x/v2/space/article'; + static const String spaceFav = '/x/v3/fav/folder/space'; // 用户名片信息 diff --git a/lib/http/member.dart b/lib/http/member.dart index e3c0fc8b..db4a0f86 100644 --- a/lib/http/member.dart +++ b/lib/http/member.dart @@ -20,6 +20,7 @@ import '../models/member/info.dart'; import '../models/member/seasons.dart'; import '../models/member/tags.dart'; import '../models/space_archive/data.dart' as archive; +import '../models/space_article/data.dart' as article; import '../utils/utils.dart'; import '../utils/wbi_sign.dart'; import 'index.dart'; @@ -60,6 +61,54 @@ class MemberHttp { } } + static Future spaceArticle({ + required int mid, + required int page, + }) async { + String? accessKey = GStorage.localCache + .get(LocalCacheKey.accessKey, defaultValue: {})['value']; + Map data = { + if (accessKey != null) 'access_key': accessKey, + 'appkey': Constants.appKey, + 'build': '1462100', + 'c_locale': 'zh_CN', + 'channel': 'yingyongbao', + 'mobi_app': 'android_hd', + 'platform': 'android', + 'pn': '$page', + 'ps': '10', + 's_locale': 'zh_CN', + 'statistics': Constants.statistics, + 'ts': (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(), + 'vmid': mid.toString(), + }; + String sign = Utils.appSign( + data, + Constants.appKey, + Constants.appSec, + ); + data['sign'] = sign; + int? _mid = GStorage.userInfo.get('userInfoCache')?.mid; + dynamic res = await Request().get( + Api.spaceArticle, + data: data, + options: Options( + headers: { + 'env': 'prod', + 'app-key': 'android_hd', + 'x-bili-mid': _mid, + 'bili-http-engine': 'cronet', + 'user-agent': Constants.userAgent, + }, + ), + ); + if (res.data['code'] == 0) { + return LoadingState.success(article.Data.fromJson(res.data['data'])); + } else { + return LoadingState.error(res.data['message']); + } + } + static Future spaceFav({ required int mid, }) async { diff --git a/lib/models/space/data.dart b/lib/models/space/data.dart index 029a5521..8d334bfa 100644 --- a/lib/models/space/data.dart +++ b/lib/models/space/data.dart @@ -15,6 +15,7 @@ import 'series.dart'; import 'setting.dart'; import 'tab.dart'; import 'tab2.dart'; +import 'package:PiliPalaX/models/space_article/data.dart' as space; part 'data.g.dart'; @@ -35,7 +36,7 @@ class Data { Images? images; Archive? archive; Series? series; - Article? article; + space.Data? article; Season? season; @JsonKey(name: 'coin_archive') CoinArchive? coinArchive; diff --git a/lib/models/space/data.g.dart b/lib/models/space/data.g.dart index 0765da58..07d4279f 100644 --- a/lib/models/space/data.g.dart +++ b/lib/models/space/data.g.dart @@ -32,7 +32,7 @@ Data _$DataFromJson(Map json) => Data( : Series.fromJson(json['series'] as Map), article: json['article'] == null ? null - : Article.fromJson(json['article'] as Map), + : space.Data.fromJson(json['article'] as Map), season: json['season'] == null ? null : Season.fromJson(json['season'] as Map), diff --git a/lib/models/space_article/author.dart b/lib/models/space_article/author.dart new file mode 100644 index 00000000..77f18f0f --- /dev/null +++ b/lib/models/space_article/author.dart @@ -0,0 +1,36 @@ +import 'package:json_annotation/json_annotation.dart'; + +import 'nameplate.dart'; +import 'official_verify.dart'; +import 'pendant.dart'; +import 'vip.dart'; + +part 'author.g.dart'; + +@JsonSerializable() +class Author { + int? mid; + String? name; + String? face; + Pendant? pendant; + @JsonKey(name: 'official_verify') + OfficialVerify? officialVerify; + Nameplate? nameplate; + Vip? vip; + + Author({ + this.mid, + this.name, + this.face, + this.pendant, + this.officialVerify, + this.nameplate, + this.vip, + }); + + factory Author.fromJson(Map json) { + return _$AuthorFromJson(json); + } + + Map toJson() => _$AuthorToJson(this); +} diff --git a/lib/models/space_article/author.g.dart b/lib/models/space_article/author.g.dart new file mode 100644 index 00000000..349368dc --- /dev/null +++ b/lib/models/space_article/author.g.dart @@ -0,0 +1,36 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'author.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Author _$AuthorFromJson(Map json) => Author( + mid: (json['mid'] as num?)?.toInt(), + name: json['name'] as String?, + face: json['face'] as String?, + pendant: json['pendant'] == null + ? null + : Pendant.fromJson(json['pendant'] as Map), + officialVerify: json['official_verify'] == null + ? null + : OfficialVerify.fromJson( + json['official_verify'] as Map), + nameplate: json['nameplate'] == null + ? null + : Nameplate.fromJson(json['nameplate'] as Map), + vip: json['vip'] == null + ? null + : Vip.fromJson(json['vip'] as Map), + ); + +Map _$AuthorToJson(Author instance) => { + 'mid': instance.mid, + 'name': instance.name, + 'face': instance.face, + 'pendant': instance.pendant, + 'official_verify': instance.officialVerify, + 'nameplate': instance.nameplate, + 'vip': instance.vip, + }; diff --git a/lib/models/space_article/category.dart b/lib/models/space_article/category.dart new file mode 100644 index 00000000..98916bb2 --- /dev/null +++ b/lib/models/space_article/category.dart @@ -0,0 +1,19 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'category.g.dart'; + +@JsonSerializable() +class Category { + int? id; + @JsonKey(name: 'parent_id') + int? parentId; + String? name; + + Category({this.id, this.parentId, this.name}); + + factory Category.fromJson(Map json) { + return _$CategoryFromJson(json); + } + + Map toJson() => _$CategoryToJson(this); +} diff --git a/lib/models/space_article/category.g.dart b/lib/models/space_article/category.g.dart new file mode 100644 index 00000000..5f52c7d4 --- /dev/null +++ b/lib/models/space_article/category.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'category.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Category _$CategoryFromJson(Map json) => Category( + id: (json['id'] as num?)?.toInt(), + parentId: (json['parent_id'] as num?)?.toInt(), + name: json['name'] as String?, + ); + +Map _$CategoryToJson(Category instance) => { + 'id': instance.id, + 'parent_id': instance.parentId, + 'name': instance.name, + }; diff --git a/lib/models/space_article/data.dart b/lib/models/space_article/data.dart new file mode 100644 index 00000000..698540cb --- /dev/null +++ b/lib/models/space_article/data.dart @@ -0,0 +1,21 @@ +import 'package:json_annotation/json_annotation.dart'; + +import 'item.dart'; +import 'list.dart'; + +part 'data.g.dart'; + +@JsonSerializable() +class Data { + int? count; + List? item; + @JsonKey(name: 'lists_count') + int? listsCount; + List? lists; + + Data({this.count, this.item, this.listsCount, this.lists}); + + factory Data.fromJson(Map json) => _$DataFromJson(json); + + Map toJson() => _$DataToJson(this); +} diff --git a/lib/models/space_article/data.g.dart b/lib/models/space_article/data.g.dart new file mode 100644 index 00000000..161edccd --- /dev/null +++ b/lib/models/space_article/data.g.dart @@ -0,0 +1,25 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'data.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Data _$DataFromJson(Map json) => Data( + count: (json['count'] as num?)?.toInt(), + item: (json['item'] as List?) + ?.map((item) => Item.fromJson(item)) + .toList(), + listsCount: (json['lists_count'] as num?)?.toInt(), + lists: (json['lists'] as List?) + ?.map((item) => ArticleList.fromJson(item)) + .toList(), + ); + +Map _$DataToJson(Data instance) => { + 'count': instance.count, + 'item': instance.item, + 'lists_count': instance.listsCount, + 'lists': instance.lists, + }; diff --git a/lib/models/space_article/item.dart b/lib/models/space_article/item.dart new file mode 100644 index 00000000..e261f611 --- /dev/null +++ b/lib/models/space_article/item.dart @@ -0,0 +1,107 @@ +import 'package:json_annotation/json_annotation.dart'; + +import 'author.dart'; +import 'category.dart'; +import 'media.dart'; +import 'stats.dart'; + +part 'item.g.dart'; + +@JsonSerializable() +class Item { + int? id; + Category? category; + List? categories; + String? title; + String? summary; + @JsonKey(name: 'banner_url') + String? bannerUrl; + @JsonKey(name: 'template_id') + int? templateId; + int? state; + Author? author; + int? reprint; + @JsonKey(name: 'image_urls') + List? imageUrls; + @JsonKey(name: 'publish_time') + int? publishTime; + int? ctime; + int? mtime; + Stats? stats; + int? attributes; + int? words; + @JsonKey(name: 'origin_image_urls') + List? originImageUrls; + dynamic list; + @JsonKey(name: 'is_like') + bool? isLike; + Media? media; + @JsonKey(name: 'apply_time') + String? applyTime; + @JsonKey(name: 'check_time') + String? checkTime; + int? original; + @JsonKey(name: 'act_id') + int? actId; + dynamic dispute; + dynamic authenMark; + @JsonKey(name: 'cover_avid') + int? coverAvid; + @JsonKey(name: 'top_video_info') + dynamic topVideoInfo; + int? type; + @JsonKey(name: 'check_state') + int? checkState; + @JsonKey(name: 'origin_template_id') + int? originTemplateId; + String? uri; + String? param; + String? goto; + @JsonKey(name: 'publish_time_text') + String? publishTimeText; + String? dyn; + + Item({ + this.id, + this.category, + this.categories, + this.title, + this.summary, + this.bannerUrl, + this.templateId, + this.state, + this.author, + this.reprint, + this.imageUrls, + this.publishTime, + this.ctime, + this.mtime, + this.stats, + this.attributes, + this.words, + this.originImageUrls, + this.list, + this.isLike, + this.media, + this.applyTime, + this.checkTime, + this.original, + this.actId, + this.dispute, + this.authenMark, + this.coverAvid, + this.topVideoInfo, + this.type, + this.checkState, + this.originTemplateId, + this.uri, + this.param, + this.goto, + this.publishTimeText, + this.dyn, + }); + + factory Item.fromJson(Map json) => _$ItemFromJson(json); + + Map toJson() => _$ItemToJson(this); +} diff --git a/lib/models/space_article/item.g.dart b/lib/models/space_article/item.g.dart new file mode 100644 index 00000000..988487a4 --- /dev/null +++ b/lib/models/space_article/item.g.dart @@ -0,0 +1,101 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'item.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Item _$ItemFromJson(Map json) => Item( + id: (json['id'] as num?)?.toInt(), + category: json['category'] == null + ? null + : Category.fromJson(json['category'] as Map), + categories: (json['categories'] as List?) + ?.map((e) => Category.fromJson(e as Map)) + .toList(), + title: json['title'] as String?, + summary: json['summary'] as String?, + bannerUrl: json['banner_url'] as String?, + templateId: (json['template_id'] as num?)?.toInt(), + state: (json['state'] as num?)?.toInt(), + author: json['author'] == null + ? null + : Author.fromJson(json['author'] as Map), + reprint: (json['reprint'] as num?)?.toInt(), + imageUrls: (json['image_urls'] as List?) + ?.map((e) => e as String) + .toList(), + publishTime: (json['publish_time'] as num?)?.toInt(), + ctime: (json['ctime'] as num?)?.toInt(), + mtime: (json['mtime'] as num?)?.toInt(), + stats: json['stats'] == null + ? null + : Stats.fromJson(json['stats'] as Map), + attributes: (json['attributes'] as num?)?.toInt(), + words: (json['words'] as num?)?.toInt(), + originImageUrls: (json['origin_image_urls'] as List?) + ?.map((e) => e as String) + .toList(), + list: json['list'], + isLike: json['is_like'] as bool?, + media: json['media'] == null + ? null + : Media.fromJson(json['media'] as Map), + applyTime: json['apply_time'] as String?, + checkTime: json['check_time'] as String?, + original: (json['original'] as num?)?.toInt(), + actId: (json['act_id'] as num?)?.toInt(), + dispute: json['dispute'], + authenMark: json['authenMark'], + coverAvid: (json['cover_avid'] as num?)?.toInt(), + topVideoInfo: json['top_video_info'], + type: (json['type'] as num?)?.toInt(), + checkState: (json['check_state'] as num?)?.toInt(), + originTemplateId: (json['origin_template_id'] as num?)?.toInt(), + uri: json['uri'] as String?, + param: json['param'] as String?, + goto: json['goto'] as String?, + publishTimeText: json['publish_time_text'] as String?, + dyn: json['dynamic'] as String?, + ); + +Map _$ItemToJson(Item instance) => { + 'id': instance.id, + 'category': instance.category, + 'categories': instance.categories, + 'title': instance.title, + 'summary': instance.summary, + 'banner_url': instance.bannerUrl, + 'template_id': instance.templateId, + 'state': instance.state, + 'author': instance.author, + 'reprint': instance.reprint, + 'image_urls': instance.imageUrls, + 'publish_time': instance.publishTime, + 'ctime': instance.ctime, + 'mtime': instance.mtime, + 'stats': instance.stats, + 'attributes': instance.attributes, + 'words': instance.words, + 'origin_image_urls': instance.originImageUrls, + 'list': instance.list, + 'is_like': instance.isLike, + 'media': instance.media, + 'apply_time': instance.applyTime, + 'check_time': instance.checkTime, + 'original': instance.original, + 'act_id': instance.actId, + 'dispute': instance.dispute, + 'authenMark': instance.authenMark, + 'cover_avid': instance.coverAvid, + 'top_video_info': instance.topVideoInfo, + 'type': instance.type, + 'check_state': instance.checkState, + 'origin_template_id': instance.originTemplateId, + 'uri': instance.uri, + 'param': instance.param, + 'goto': instance.goto, + 'publish_time_text': instance.publishTimeText, + 'dynamic': instance.dyn, + }; diff --git a/lib/models/space_article/label.dart b/lib/models/space_article/label.dart new file mode 100644 index 00000000..e517c679 --- /dev/null +++ b/lib/models/space_article/label.dart @@ -0,0 +1,17 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'label.g.dart'; + +@JsonSerializable() +class Label { + String? path; + String? text; + @JsonKey(name: 'label_theme') + String? labelTheme; + + Label({this.path, this.text, this.labelTheme}); + + factory Label.fromJson(Map json) => _$LabelFromJson(json); + + Map toJson() => _$LabelToJson(this); +} diff --git a/lib/models/space_article/label.g.dart b/lib/models/space_article/label.g.dart new file mode 100644 index 00000000..b127e6b4 --- /dev/null +++ b/lib/models/space_article/label.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'label.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Label _$LabelFromJson(Map json) => Label( + path: json['path'] as String?, + text: json['text'] as String?, + labelTheme: json['label_theme'] as String?, + ); + +Map _$LabelToJson(Label instance) => { + 'path': instance.path, + 'text': instance.text, + 'label_theme': instance.labelTheme, + }; diff --git a/lib/models/space_article/list.dart b/lib/models/space_article/list.dart new file mode 100644 index 00000000..e02ea80c --- /dev/null +++ b/lib/models/space_article/list.dart @@ -0,0 +1,44 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'list.g.dart'; + +@JsonSerializable() +class ArticleList { + int? id; + int? mid; + String? name; + @JsonKey(name: 'image_url') + String? imageUrl; + @JsonKey(name: 'update_time') + int? updateTime; + int? ctime; + @JsonKey(name: 'publish_time') + int? publishTime; + String? summary; + int? words; + int? read; + @JsonKey(name: 'articles_count') + int? articlesCount; + @JsonKey(name: 'update_time_text') + String? updateTimeText; + + ArticleList({ + this.id, + this.mid, + this.name, + this.imageUrl, + this.updateTime, + this.ctime, + this.publishTime, + this.summary, + this.words, + this.read, + this.articlesCount, + this.updateTimeText, + }); + + factory ArticleList.fromJson(Map json) => + _$ListFromJson(json); + + Map toJson() => _$ListToJson(this); +} diff --git a/lib/models/space_article/list.g.dart b/lib/models/space_article/list.g.dart new file mode 100644 index 00000000..09791d06 --- /dev/null +++ b/lib/models/space_article/list.g.dart @@ -0,0 +1,37 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'list.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ArticleList _$ListFromJson(Map json) => ArticleList( + id: (json['id'] as num?)?.toInt(), + mid: (json['mid'] as num?)?.toInt(), + name: json['name'] as String?, + imageUrl: json['image_url'] as String?, + updateTime: (json['update_time'] as num?)?.toInt(), + ctime: (json['ctime'] as num?)?.toInt(), + publishTime: (json['publish_time'] as num?)?.toInt(), + summary: json['summary'] as String?, + words: (json['words'] as num?)?.toInt(), + read: (json['read'] as num?)?.toInt(), + articlesCount: (json['articles_count'] as num?)?.toInt(), + updateTimeText: json['update_time_text'] as String?, + ); + +Map _$ListToJson(ArticleList instance) => { + 'id': instance.id, + 'mid': instance.mid, + 'name': instance.name, + 'image_url': instance.imageUrl, + 'update_time': instance.updateTime, + 'ctime': instance.ctime, + 'publish_time': instance.publishTime, + 'summary': instance.summary, + 'words': instance.words, + 'read': instance.read, + 'articles_count': instance.articlesCount, + 'update_time_text': instance.updateTimeText, + }; diff --git a/lib/models/space_article/media.dart b/lib/models/space_article/media.dart new file mode 100644 index 00000000..ba440358 --- /dev/null +++ b/lib/models/space_article/media.dart @@ -0,0 +1,33 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'media.g.dart'; + +@JsonSerializable() +class Media { + int? score; + @JsonKey(name: 'media_id') + int? mediaId; + String? title; + String? cover; + String? area; + @JsonKey(name: 'type_id') + int? typeId; + @JsonKey(name: 'type_name') + String? typeName; + int? spoiler; + + Media({ + this.score, + this.mediaId, + this.title, + this.cover, + this.area, + this.typeId, + this.typeName, + this.spoiler, + }); + + factory Media.fromJson(Map json) => _$MediaFromJson(json); + + Map toJson() => _$MediaToJson(this); +} diff --git a/lib/models/space_article/media.g.dart b/lib/models/space_article/media.g.dart new file mode 100644 index 00000000..2fe823ed --- /dev/null +++ b/lib/models/space_article/media.g.dart @@ -0,0 +1,29 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'media.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Media _$MediaFromJson(Map json) => Media( + score: (json['score'] as num?)?.toInt(), + mediaId: (json['media_id'] as num?)?.toInt(), + title: json['title'] as String?, + cover: json['cover'] as String?, + area: json['area'] as String?, + typeId: (json['type_id'] as num?)?.toInt(), + typeName: json['type_name'] as String?, + spoiler: (json['spoiler'] as num?)?.toInt(), + ); + +Map _$MediaToJson(Media instance) => { + 'score': instance.score, + 'media_id': instance.mediaId, + 'title': instance.title, + 'cover': instance.cover, + 'area': instance.area, + 'type_id': instance.typeId, + 'type_name': instance.typeName, + 'spoiler': instance.spoiler, + }; diff --git a/lib/models/space_article/nameplate.dart b/lib/models/space_article/nameplate.dart new file mode 100644 index 00000000..e0ce7118 --- /dev/null +++ b/lib/models/space_article/nameplate.dart @@ -0,0 +1,29 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'nameplate.g.dart'; + +@JsonSerializable() +class Nameplate { + int? nid; + String? name; + String? image; + @JsonKey(name: 'image_small') + String? imageSmall; + String? level; + String? condition; + + Nameplate({ + this.nid, + this.name, + this.image, + this.imageSmall, + this.level, + this.condition, + }); + + factory Nameplate.fromJson(Map json) { + return _$NameplateFromJson(json); + } + + Map toJson() => _$NameplateToJson(this); +} diff --git a/lib/models/space_article/nameplate.g.dart b/lib/models/space_article/nameplate.g.dart new file mode 100644 index 00000000..8e0bc567 --- /dev/null +++ b/lib/models/space_article/nameplate.g.dart @@ -0,0 +1,25 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'nameplate.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Nameplate _$NameplateFromJson(Map json) => Nameplate( + nid: (json['nid'] as num?)?.toInt(), + name: json['name'] as String?, + image: json['image'] as String?, + imageSmall: json['image_small'] as String?, + level: json['level'] as String?, + condition: json['condition'] as String?, + ); + +Map _$NameplateToJson(Nameplate instance) => { + 'nid': instance.nid, + 'name': instance.name, + 'image': instance.image, + 'image_small': instance.imageSmall, + 'level': instance.level, + 'condition': instance.condition, + }; diff --git a/lib/models/space_article/official_verify.dart b/lib/models/space_article/official_verify.dart new file mode 100644 index 00000000..875a2868 --- /dev/null +++ b/lib/models/space_article/official_verify.dart @@ -0,0 +1,17 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'official_verify.g.dart'; + +@JsonSerializable() +class OfficialVerify { + int? type; + String? desc; + + OfficialVerify({this.type, this.desc}); + + factory OfficialVerify.fromJson(Map json) { + return _$OfficialVerifyFromJson(json); + } + + Map toJson() => _$OfficialVerifyToJson(this); +} diff --git a/lib/models/space_article/official_verify.g.dart b/lib/models/space_article/official_verify.g.dart new file mode 100644 index 00000000..d6c9bb4a --- /dev/null +++ b/lib/models/space_article/official_verify.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'official_verify.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +OfficialVerify _$OfficialVerifyFromJson(Map json) => + OfficialVerify( + type: (json['type'] as num?)?.toInt(), + desc: json['desc'] as String?, + ); + +Map _$OfficialVerifyToJson(OfficialVerify instance) => + { + 'type': instance.type, + 'desc': instance.desc, + }; diff --git a/lib/models/space_article/pendant.dart b/lib/models/space_article/pendant.dart new file mode 100644 index 00000000..f73fb229 --- /dev/null +++ b/lib/models/space_article/pendant.dart @@ -0,0 +1,19 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'pendant.g.dart'; + +@JsonSerializable() +class Pendant { + int? pid; + String? name; + String? image; + int? expire; + + Pendant({this.pid, this.name, this.image, this.expire}); + + factory Pendant.fromJson(Map json) { + return _$PendantFromJson(json); + } + + Map toJson() => _$PendantToJson(this); +} diff --git a/lib/models/space_article/pendant.g.dart b/lib/models/space_article/pendant.g.dart new file mode 100644 index 00000000..c23bc587 --- /dev/null +++ b/lib/models/space_article/pendant.g.dart @@ -0,0 +1,21 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'pendant.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Pendant _$PendantFromJson(Map json) => Pendant( + pid: (json['pid'] as num?)?.toInt(), + name: json['name'] as String?, + image: json['image'] as String?, + expire: (json['expire'] as num?)?.toInt(), + ); + +Map _$PendantToJson(Pendant instance) => { + 'pid': instance.pid, + 'name': instance.name, + 'image': instance.image, + 'expire': instance.expire, + }; diff --git a/lib/models/space_article/space_article.dart b/lib/models/space_article/space_article.dart new file mode 100644 index 00000000..5e9a0fd4 --- /dev/null +++ b/lib/models/space_article/space_article.dart @@ -0,0 +1,21 @@ +import 'package:json_annotation/json_annotation.dart'; + +import 'data.dart'; + +part 'space_article.g.dart'; + +@JsonSerializable() +class SpaceArticle { + int? code; + String? message; + int? ttl; + Data? data; + + SpaceArticle({this.code, this.message, this.ttl, this.data}); + + factory SpaceArticle.fromJson(Map json) { + return _$SpaceArticleFromJson(json); + } + + Map toJson() => _$SpaceArticleToJson(this); +} diff --git a/lib/models/space_article/space_article.g.dart b/lib/models/space_article/space_article.g.dart new file mode 100644 index 00000000..0d4f4a33 --- /dev/null +++ b/lib/models/space_article/space_article.g.dart @@ -0,0 +1,24 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'space_article.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +SpaceArticle _$SpaceArticleFromJson(Map json) => SpaceArticle( + code: (json['code'] as num?)?.toInt(), + message: json['message'] as String?, + ttl: (json['ttl'] as num?)?.toInt(), + data: json['data'] == null + ? null + : Data.fromJson(json['data'] as Map), + ); + +Map _$SpaceArticleToJson(SpaceArticle instance) => + { + 'code': instance.code, + 'message': instance.message, + 'ttl': instance.ttl, + 'data': instance.data, + }; diff --git a/lib/models/space_article/stats.dart b/lib/models/space_article/stats.dart new file mode 100644 index 00000000..0834c749 --- /dev/null +++ b/lib/models/space_article/stats.dart @@ -0,0 +1,30 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'stats.g.dart'; + +@JsonSerializable() +class Stats { + int? view; + int? favorite; + int? like; + int? dislike; + int? reply; + int? share; + int? coin; + int? dyn; + + Stats({ + this.view, + this.favorite, + this.like, + this.dislike, + this.reply, + this.share, + this.coin, + this.dyn, + }); + + factory Stats.fromJson(Map json) => _$StatsFromJson(json); + + Map toJson() => _$StatsToJson(this); +} diff --git a/lib/models/space_article/stats.g.dart b/lib/models/space_article/stats.g.dart new file mode 100644 index 00000000..80329e16 --- /dev/null +++ b/lib/models/space_article/stats.g.dart @@ -0,0 +1,29 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'stats.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Stats _$StatsFromJson(Map json) => Stats( + view: (json['view'] as num?)?.toInt(), + favorite: (json['favorite'] as num?)?.toInt(), + like: (json['like'] as num?)?.toInt(), + dislike: (json['dislike'] as num?)?.toInt(), + reply: (json['reply'] as num?)?.toInt(), + share: (json['share'] as num?)?.toInt(), + coin: (json['coin'] as num?)?.toInt(), + dyn: (json['dynamic'] as num?)?.toInt(), + ); + +Map _$StatsToJson(Stats instance) => { + 'view': instance.view, + 'favorite': instance.favorite, + 'like': instance.like, + 'dislike': instance.dislike, + 'reply': instance.reply, + 'share': instance.share, + 'coin': instance.coin, + 'dynamic': instance.dyn, + }; diff --git a/lib/models/space_article/vip.dart b/lib/models/space_article/vip.dart new file mode 100644 index 00000000..7959e0ba --- /dev/null +++ b/lib/models/space_article/vip.dart @@ -0,0 +1,37 @@ +import 'package:json_annotation/json_annotation.dart'; + +import 'label.dart'; + +part 'vip.g.dart'; + +@JsonSerializable() +class Vip { + int? type; + int? status; + @JsonKey(name: 'due_date') + int? dueDate; + @JsonKey(name: 'vip_pay_type') + int? vipPayType; + @JsonKey(name: 'theme_type') + int? themeType; + Label? label; + @JsonKey(name: 'avatar_subscript') + int? avatarSubscript; + @JsonKey(name: 'nickname_color') + String? nicknameColor; + + Vip({ + this.type, + this.status, + this.dueDate, + this.vipPayType, + this.themeType, + this.label, + this.avatarSubscript, + this.nicknameColor, + }); + + factory Vip.fromJson(Map json) => _$VipFromJson(json); + + Map toJson() => _$VipToJson(this); +} diff --git a/lib/models/space_article/vip.g.dart b/lib/models/space_article/vip.g.dart new file mode 100644 index 00000000..5f95aa41 --- /dev/null +++ b/lib/models/space_article/vip.g.dart @@ -0,0 +1,31 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'vip.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Vip _$VipFromJson(Map json) => Vip( + type: (json['type'] as num?)?.toInt(), + status: (json['status'] as num?)?.toInt(), + dueDate: (json['due_date'] as num?)?.toInt(), + vipPayType: (json['vip_pay_type'] as num?)?.toInt(), + themeType: (json['theme_type'] as num?)?.toInt(), + label: json['label'] == null + ? null + : Label.fromJson(json['label'] as Map), + avatarSubscript: (json['avatar_subscript'] as num?)?.toInt(), + nicknameColor: json['nickname_color'] as String?, + ); + +Map _$VipToJson(Vip instance) => { + 'type': instance.type, + 'status': instance.status, + 'due_date': instance.dueDate, + 'vip_pay_type': instance.vipPayType, + 'theme_type': instance.themeType, + 'label': instance.label, + 'avatar_subscript': instance.avatarSubscript, + 'nickname_color': instance.nicknameColor, + }; diff --git a/lib/pages/member/new/content/member_contribute/content/article/member_article.dart b/lib/pages/member/new/content/member_contribute/content/article/member_article.dart index bde226f4..8465cdb7 100644 --- a/lib/pages/member/new/content/member_contribute/content/article/member_article.dart +++ b/lib/pages/member/new/content/member_contribute/content/article/member_article.dart @@ -1,12 +1,22 @@ +import 'package:PiliPalaX/common/constants.dart'; +import 'package:PiliPalaX/common/widgets/http_error.dart'; +import 'package:PiliPalaX/common/widgets/network_img_layer.dart'; +import 'package:PiliPalaX/http/loading_state.dart'; +import 'package:PiliPalaX/models/space_article/item.dart'; +import 'package:PiliPalaX/pages/member/new/content/member_contribute/content/article/member_article_ctr.dart'; +import 'package:PiliPalaX/utils/app_scheme.dart'; import 'package:flutter/material.dart'; +import 'package:get/get.dart'; class MemberArticle extends StatefulWidget { const MemberArticle({ super.key, required this.heroTag, + required this.mid, }); final String? heroTag; + final int mid; @override State createState() => _MemberArticleState(); @@ -17,11 +27,91 @@ class _MemberArticleState extends State @override bool get wantKeepAlive => true; + late final _controller = Get.put( + MemberArticleCtr(mid: widget.mid), + tag: widget.heroTag, + ); + @override Widget build(BuildContext context) { super.build(context); - return Center( - child: Text('Article'), - ); + return Obx(() => _buildBody(_controller.loadingState.value)); + } + + _buildBody(LoadingState loadingState) { + return loadingState is Success + ? MediaQuery.removePadding( + context: context, + removeTop: true, + child: RefreshIndicator( + onRefresh: () async { + await _controller.onRefresh(); + }, + child: ListView.separated( + itemCount: loadingState.response.length, + itemBuilder: (_, index) { + if (index == loadingState.response.length - 1) { + _controller.onLoadMore(); + } + Item item = loadingState.response[index]; + return ListTile( + dense: true, + onTap: () { + PiliScheme.routePush(Uri.parse(item.uri ?? '')); + }, + leading: item.originImageUrls?.isNotEmpty == true + ? Container( + margin: const EdgeInsets.symmetric(vertical: 6), + child: LayoutBuilder( + builder: (_, constraints) { + return NetworkImgLayer( + radius: 6, + src: item.originImageUrls!.first, + width: constraints.maxHeight * + StyleString.aspectRatio, + height: constraints.maxHeight, + ); + }, + ), + ) + : null, + title: Text( + item.title ?? '', + style: TextStyle( + fontSize: 15, + ), + ), + subtitle: item.summary?.isNotEmpty == true + ? Text( + item.summary!, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 13, + color: Theme.of(context).colorScheme.outline, + ), + ) + : null, + ); + }, + separatorBuilder: (_, index) => Divider(height: 1), + ), + ), + ) + : loadingState is Error + ? Center( + child: CustomScrollView( + shrinkWrap: true, + slivers: [ + HttpError( + errMsg: loadingState.errMsg, + fn: _controller.onReload, + ), + ], + ), + ) + : Center( + child: CircularProgressIndicator(), + ); } } diff --git a/lib/pages/member/new/content/member_contribute/content/article/member_article_ctr.dart b/lib/pages/member/new/content/member_contribute/content/article/member_article_ctr.dart new file mode 100644 index 00000000..bd89919d --- /dev/null +++ b/lib/pages/member/new/content/member_contribute/content/article/member_article_ctr.dart @@ -0,0 +1,50 @@ +import 'package:PiliPalaX/http/loading_state.dart'; +import 'package:PiliPalaX/http/member.dart'; +import 'package:PiliPalaX/models/space_article/data.dart'; +import 'package:PiliPalaX/pages/common/common_controller.dart'; + +class MemberArticleCtr extends CommonController { + MemberArticleCtr({ + required this.mid, + }); + + final int mid; + + bool isEnd = false; + int count = -1; + + @override + void onInit() { + super.onInit(); + queryData(); + } + + @override + Future onRefresh() async { + isEnd = false; + return super.onRefresh(); + } + + @override + Future queryData([bool isRefresh = true]) { + if (isEnd) return Future.value(); + return super.queryData(isRefresh); + } + + @override + bool customHandleResponse(Success response) { + Data data = response.response; + if (currentPage == 1) { + count = data.count ?? -1; + } else if (loadingState.value is Success) { + data.item?.insertAll(0, (loadingState.value as Success).response); + } + isEnd = (data.item?.length ?? -1) >= count; + loadingState.value = LoadingState.success(data.item); + return true; + } + + @override + Future customGetData() => + MemberHttp.spaceArticle(mid: mid, page: currentPage); +} diff --git a/lib/pages/member/new/content/member_contribute/member_contribute.dart b/lib/pages/member/new/content/member_contribute/member_contribute.dart index 136658db..73e5d5d3 100644 --- a/lib/pages/member/new/content/member_contribute/member_contribute.dart +++ b/lib/pages/member/new/content/member_contribute/member_contribute.dart @@ -89,7 +89,10 @@ class _MemberContributeState extends State heroTag: widget.heroTag, mid: widget.mid, ), - 'article' => MemberArticle(heroTag: widget.heroTag), + 'article' => MemberArticle( + heroTag: widget.heroTag, + mid: widget.mid, + ), 'audio' => MemberAudio(heroTag: widget.heroTag), 'season_video' => MemberVideo( type: ContributeType.season, diff --git a/lib/pages/member/new/content/member_home/member_home.dart b/lib/pages/member/new/content/member_home/member_home.dart index 13018e0a..01166941 100644 --- a/lib/pages/member/new/content/member_home/member_home.dart +++ b/lib/pages/member/new/content/member_home/member_home.dart @@ -1,6 +1,7 @@ import 'dart:math'; import 'package:PiliPalaX/common/constants.dart'; +import 'package:PiliPalaX/common/widgets/network_img_layer.dart'; import 'package:PiliPalaX/common/widgets/video_card_v_member_home.dart'; import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/models/space/data.dart'; @@ -13,6 +14,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; +import '../../../../../utils/app_scheme.dart'; + class MemberHome extends StatefulWidget { const MemberHome({super.key, this.heroTag}); @@ -93,7 +96,7 @@ class _MemberHomeState extends State true) ...[ _videoHeader( title: '最近点赞的视频', - param: 'coinArchive', + param: 'likeArchive', count: loadingState.response.likeArchive.count, ), // TODO @@ -105,7 +108,53 @@ class _MemberHomeState extends State param1: 'article', count: loadingState.response.article.count, ), - // TODO + SliverToBoxAdapter( + child: ListTile( + dense: true, + onTap: () { + PiliScheme.routePush(Uri.parse( + loadingState.response.article.item.first.uri ?? '')); + }, + leading: loadingState.response.article.item.first + .originImageUrls?.isNotEmpty == + true + ? Container( + margin: const EdgeInsets.symmetric(vertical: 6), + child: LayoutBuilder( + builder: (_, constraints) { + return NetworkImgLayer( + radius: 6, + src: loadingState.response.article.item.first + .originImageUrls!.first, + width: constraints.maxHeight * + StyleString.aspectRatio, + height: constraints.maxHeight, + ); + }, + ), + ) + : null, + title: Text( + loadingState.response.article.item.first.title ?? '', + style: TextStyle( + fontSize: 15, + ), + ), + subtitle: loadingState.response.article.item.first.summary + ?.isNotEmpty == + true + ? Text( + loadingState.response.article.item.first.summary!, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 13, + color: Theme.of(context).colorScheme.outline, + ), + ) + : null, + ), + ), ], if (loadingState.response?.audios?.item?.isNotEmpty == true) ...[ _videoHeader(