diff --git a/README.md b/README.md index f2283dcf1..eadac2f62 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ ## feat +- [x] 搜索用户动态 - [x] 直播弹幕 - [x] 修改头像/用户名/签名/性别/生日 - [x] 创建/编辑/删除收藏夹 diff --git a/lib/main.dart b/lib/main.dart index a2f248681..cbced7254 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -160,12 +160,10 @@ class MyApp extends StatelessWidget { // showSemanticsDebugger: true, title: 'PiliPalaX', theme: _getThemeData( - context: context, colorScheme: lightColorScheme, isDynamic: lightDynamic != null && isDynamicColor, ), darkTheme: _getThemeData( - context: context, colorScheme: darkColorScheme, isDynamic: darkDynamic != null && isDynamicColor, ), @@ -201,7 +199,6 @@ class MyApp extends StatelessWidget { } ThemeData _getThemeData({ - required BuildContext context, required ColorScheme colorScheme, required bool isDynamic, }) { diff --git a/lib/pages/member_search/search_dynamic.dart b/lib/pages/member_search/search_dynamic.dart index 588586714..63893760c 100644 --- a/lib/pages/member_search/search_dynamic.dart +++ b/lib/pages/member_search/search_dynamic.dart @@ -1,14 +1,20 @@ +import 'dart:convert'; + import 'package:PiliPalaX/common/constants.dart'; import 'package:PiliPalaX/common/widgets/loading_widget.dart'; +import 'package:PiliPalaX/common/widgets/network_img_layer.dart'; import 'package:PiliPalaX/common/widgets/refresh_indicator.dart'; +import 'package:PiliPalaX/http/dynamics.dart'; import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/pages/member_search/controller.dart'; import 'package:PiliPalaX/utils/grid.dart'; +import 'package:PiliPalaX/utils/id_utils.dart'; import 'package:PiliPalaX/utils/storage.dart'; +import 'package:PiliPalaX/utils/utils.dart'; import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; -import 'package:get/get_state_manager/src/rx_flutter/rx_obx_widget.dart'; import 'package:waterfall_flow/waterfall_flow.dart'; class SearchDynamic extends StatelessWidget { @@ -58,7 +64,7 @@ class SearchDynamic extends StatelessWidget { : LastChildLayoutType.none; }, children: (loadingState.response as List) - .map((item) => _buildItem(item)) + .map((item) => _buildItem(context, item)) .toList(), ) : SliverCrossAxisGroup( @@ -78,6 +84,7 @@ class SearchDynamic extends StatelessWidget { }); } return _buildItem( + context, loadingState.response[index], ); }, @@ -109,28 +116,186 @@ class SearchDynamic extends StatelessWidget { }; } - Widget _buildItem(item) { - return switch (item['desc']['type']) { - 2 => ListTile( - dense: true, - onTap: () {}, - title: const Text('动态'), + _buildHeader({ + required BuildContext context, + required String face, + required String name, + required dynamic vip, + required dynamic pubTime, + }) { + return Row( + children: [ + NetworkImgLayer( + width: 40, + height: 40, + type: 'avatar', + src: face, ), - 4 => ListTile( - dense: true, - onTap: () {}, - title: const Text('动态'), + const SizedBox(width: 10), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + name, + style: TextStyle( + color: vip != null + ? (vip?['status'] ?? vip?['vipStatus']) > 0 && + (vip?['type'] ?? vip?['vipType']) == 2 + ? Utils.vipColor + : null + : null, + fontSize: Theme.of(context).textTheme.titleSmall!.fontSize, + ), + ), + ], + ), + if (pubTime != null) + Text( + Utils.dateFormat(pubTime), + style: TextStyle( + fontSize: 13, + color: Theme.of(context).colorScheme.outline, + ), + ), + ], ), - 8 => ListTile( - dense: true, - onTap: () {}, - title: const Text('视频'), + ], + ); + } + + Widget _buildItem(context, item) { + try { + dynamic json = jsonDecode('${item['card']}'); + return switch (item['desc']['type']) { + 1 => _buildDynamic( + context: context, + id: item['desc']['dynamic_id_str'], + face: json['user']['face'], + name: json['user']['uname'], + vip: item['desc']['user_profile']['vip'], + pubTime: item['desc']['timestamp'], + content: json['item']['content'], + ), + 2 => _buildDynamic( + context: context, + id: item['desc']['dynamic_id_str'], + face: json['user']['head_url'], + name: json['user']['name'], + vip: json['user']['vip'], + pubTime: json['item']['upload_time'], + content: json['item']['description'], + ), + 4 => _buildDynamic( + context: context, + id: item['desc']['dynamic_id_str'], + face: json['user']['face'], + name: json['user']['uname'], + vip: item['desc']['user_profile']['vip'], + pubTime: item['desc']['timestamp'], + content: json['item']['content'], + ), + 8 => _buildVideo(context, json), + _ => _buildDef(item), + }; + } catch (e) { + debugPrint('$e'); + return _buildDef(item); + } + } + + _buildDynamic({ + required dynamic id, + required BuildContext context, + required String face, + required String name, + required dynamic vip, + required dynamic pubTime, + required String content, + }) { + return InkWell( + onTap: () async { + SmartDialog.showLoading(); + dynamic res = await DynamicsHttp.dynamicDetail(id: id); + if (res['status']) { + SmartDialog.dismiss(); + Get.toNamed('/dynamicDetail', + arguments: {'item': res['data'], 'floor': 1, 'action': 'detail'}); + } else { + SmartDialog.dismiss(); + SmartDialog.showToast(res['msg']); + } + }, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildHeader( + context: context, + face: face, + name: name, + vip: vip, + pubTime: pubTime, + ), + const SizedBox(height: 5), + Text( + content, + style: TextStyle(fontSize: 15), + ) + ], ), - _ => ListTile( - dense: true, - onTap: () {}, - title: Text('TODO: type: ${item['desc']['type']}'), + ), + ); + } + + _buildVideo(context, json) { + return ListTile( + dense: true, + onTap: () { + Get.toNamed( + '/video?bvid=${IdUtils.av2bv(json['aid'])}&cid=${json['cid']}', + arguments: {'heroTag': Utils.makeHeroTag(json['aid'])}, + ); + }, + title: Text( + '${json['title']}', + maxLines: 20, + style: TextStyle(fontSize: 15), + ), + subtitle: Text( + '${Utils.dateFormat(json['pubdate'])} · ${Utils.numFormat(json['stat']['view'])}观看 · ${Utils.numFormat(json['stat']['danmaku'])}弹幕', + style: TextStyle( + fontSize: 13, + color: Theme.of(context).colorScheme.outline, ), - }; + ), + leading: (json['pic'] as String?)?.isNotEmpty == true + ? Container( + margin: const EdgeInsets.symmetric(vertical: 6), + child: LayoutBuilder( + builder: (_, constraints) { + return NetworkImgLayer( + radius: 6, + src: json['pic'], + width: constraints.maxHeight * StyleString.aspectRatio, + height: constraints.maxHeight, + ); + }, + ), + ) + : null, + ); } + + _buildDef(item) => ListTile( + dense: true, + onTap: () { + Utils.copyText(jsonEncode(item)); + }, + title: Text('$item'), + subtitle: Text('${item['desc']['type']}'), + ); }