diff --git a/lib/screens/account/profile_page.dart b/lib/screens/account/profile_page.dart index 4381168..a5dc470 100644 --- a/lib/screens/account/profile_page.dart +++ b/lib/screens/account/profile_page.dart @@ -1,11 +1,16 @@ +import 'dart:math'; + +import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; import 'package:gap/gap.dart'; import 'package:get/get.dart'; import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; +import 'package:intl/intl.dart'; import 'package:solian/controllers/post_list_controller.dart'; import 'package:solian/exts.dart'; import 'package:solian/models/account.dart'; import 'package:solian/models/attachment.dart'; +import 'package:solian/models/daily_sign.dart'; import 'package:solian/models/pagination.dart'; import 'package:solian/models/post.dart'; import 'package:solian/models/subscription.dart'; @@ -18,6 +23,7 @@ import 'package:solian/widgets/account/account_avatar.dart'; import 'package:solian/widgets/account/account_heading.dart'; import 'package:solian/widgets/app_bar_leading.dart'; import 'package:solian/widgets/attachments/attachment_list.dart'; +import 'package:solian/widgets/daily_sign/history_chart.dart'; import 'package:solian/widgets/posts/post_list.dart'; import 'package:solian/widgets/posts/post_warped_list.dart'; import 'package:solian/widgets/sized_container.dart'; @@ -45,6 +51,7 @@ class _AccountProfilePageState extends State { Account? _userinfo; Subscription? _subscription; List _pinnedPosts = List.empty(); + List _dailySignRecords = List.empty(); int _totalUpvote = 0, _totalDownvote = 0; Future _getSubscription() async { @@ -57,7 +64,7 @@ class _AccountProfilePageState extends State { Future _getUserinfo() async { setState(() => _isBusy = true); - var client = await ServiceFinder.configureClient('auth'); + var client = await ServiceFinder.configureClient('id'); var resp = await client.get('/users/${widget.name}'); if (resp.statusCode != 200) { context.showErrorDialog(resp.bodyString).then((_) { @@ -67,7 +74,7 @@ class _AccountProfilePageState extends State { _userinfo = Account.fromJson(resp.body); } - client = await ServiceFinder.configureClient('interactive'); + client = await ServiceFinder.configureClient('co'); resp = await client.get('/users/${widget.name}'); if (resp.statusCode != 200) { context.showErrorDialog(resp.bodyString).then((_) { @@ -82,7 +89,7 @@ class _AccountProfilePageState extends State { } Future _getPinnedPosts() async { - final client = await ServiceFinder.configureClient('interactive'); + final client = await ServiceFinder.configureClient('co'); final resp = await client.get('/users/${widget.name}/pin'); if (resp.statusCode != 200) { context.showErrorDialog(resp.bodyString).then((_) { @@ -96,6 +103,23 @@ class _AccountProfilePageState extends State { } } + Future _getDailySignRecords() async { + final client = await ServiceFinder.configureClient('id'); + final resp = await client.get('/users/${widget.name}/daily?take=14'); + if (resp.statusCode != 200) { + context.showErrorDialog(resp.bodyString).then((_) { + Navigator.pop(context); + }); + } else { + final result = PaginationResult.fromJson(resp.body); + setState(() { + _dailySignRecords = List.from( + result.data?.map((x) => DailySignRecord.fromJson(x)) ?? [], + ); + }); + } + } + int get _userSocialCreditPoints { return _totalUpvote * 2 - _totalDownvote + _postController.postTotal.value; } @@ -129,6 +153,7 @@ class _AccountProfilePageState extends State { _getUserinfo().then((_) { _getSubscription(); _getPinnedPosts(); + _getDailySignRecords(); }); } @@ -285,7 +310,114 @@ class _AccountProfilePageState extends State { .getSomeoneStatus(_userinfo!.name), detail: _userinfo, profile: _userinfo!.profile, - extraWidgets: const [], + extraWidgets: [ + if (_dailySignRecords.isNotEmpty) + Card( + child: SizedBox( + height: 180, + width: max(640, MediaQuery.of(context).size.width), + child: LineChart( + LineChartData( + lineBarsData: [ + LineChartBarData( + isCurved: true, + isStrokeCapRound: true, + isStrokeJoinRound: true, + color: + Theme.of(context).colorScheme.primary, + belowBarData: BarAreaData( + show: true, + gradient: LinearGradient( + colors: List.filled( + _dailySignRecords.length, + Theme.of(context) + .colorScheme + .primary + .withOpacity(0.3), + ).toList(), + ), + ), + spots: _dailySignRecords + .map( + (x) => FlSpot( + x.createdAt + .copyWith( + hour: 0, + minute: 0, + second: 0, + millisecond: 0, + microsecond: 0, + ) + .millisecondsSinceEpoch + .toDouble(), + x.resultTier.toDouble(), + ), + ) + .toList(), + ) + ], + lineTouchData: LineTouchData( + touchTooltipData: LineTouchTooltipData( + getTooltipItems: (spots) => spots + .map((spot) => LineTooltipItem( + '${DailySignHistoryChartDialog.signSymbols[spot.y.toInt()]}\n${DateFormat('MM/dd').format(DateTime.fromMillisecondsSinceEpoch(spot.x.toInt()))}', + TextStyle( + color: Theme.of(context) + .colorScheme + .onSurface, + ), + )) + .toList(), + getTooltipColor: (_) => Theme.of(context) + .colorScheme + .surfaceContainerHigh, + ), + ), + titlesData: FlTitlesData( + topTitles: const AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + rightTitles: const AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + leftTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + reservedSize: 40, + interval: 1, + getTitlesWidget: (value, _) => Align( + alignment: Alignment.centerRight, + child: Text( + DailySignHistoryChartDialog + .signSymbols[value.toInt()], + textAlign: TextAlign.right, + ).paddingOnly(right: 8), + ), + ), + ), + bottomTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + reservedSize: 28, + interval: 86400000, + getTitlesWidget: (value, _) => Text( + DateFormat('dd').format( + DateTime.fromMillisecondsSinceEpoch( + value.toInt(), + ), + ), + textAlign: TextAlign.center, + ).paddingOnly(top: 8), + ), + ), + ), + gridData: const FlGridData(show: false), + borderData: FlBorderData(show: false), + ), + ), + ).marginOnly(right: 24, left: 12, bottom: 8, top: 24), + ) + ], ), ], ), @@ -373,8 +505,9 @@ class _AccountProfilePageState extends State { ), CenteredContainer( child: RefreshIndicator( - onRefresh: () => - Future.sync(() => _albumPagingController.refresh()), + onRefresh: () => Future.sync( + () => _albumPagingController.refresh(), + ), child: PagedGridView( padding: EdgeInsets.zero, pagingController: _albumPagingController, diff --git a/lib/screens/dashboard.dart b/lib/screens/dashboard.dart index 282b102..c0debf2 100644 --- a/lib/screens/dashboard.dart +++ b/lib/screens/dashboard.dart @@ -103,7 +103,7 @@ class _DashboardScreenState extends State { try { _signRecord = await _dailySign.signToday(); - _dailySign.listLastRecord(30).then((value) { + _dailySign.listLastRecord(14).then((value) { setState(() => _signRecordHistory = value); }); } catch (e) { diff --git a/lib/widgets/daily_sign/history_chart.dart b/lib/widgets/daily_sign/history_chart.dart index 3e3c1ee..2cf85f2 100644 --- a/lib/widgets/daily_sign/history_chart.dart +++ b/lib/widgets/daily_sign/history_chart.dart @@ -12,7 +12,7 @@ class DailySignHistoryChartDialog extends StatelessWidget { const DailySignHistoryChartDialog({super.key, required this.data}); - static List signSymbols = ['大凶', '凶', '中平', '吉', '大吉']; + static final List signSymbols = ['大凶', '凶', '中平', '吉', '大吉']; DateTime? get _firstRecordDate => data?.map((x) => x.createdAt).reduce( (a, b) => DateTime.fromMillisecondsSinceEpoch( @@ -93,19 +93,22 @@ class DailySignHistoryChartDialog extends StatelessWidget { ) ], lineTouchData: LineTouchData( - touchTooltipData: LineTouchTooltipData( - getTooltipItems: (spots) => spots - .map((spot) => LineTooltipItem( - '${signSymbols[spot.y.toInt()]}\n${DateFormat('MM/dd').format(DateTime.fromMillisecondsSinceEpoch(spot.x.toInt()))}', - TextStyle( - color: - Theme.of(context).colorScheme.onSurface, - ), - )) - .toList(), - getTooltipColor: (_) => - Theme.of(context).colorScheme.surfaceContainerHigh, - )), + touchTooltipData: LineTouchTooltipData( + getTooltipItems: (spots) => spots + .map((spot) => LineTooltipItem( + '${signSymbols[spot.y.toInt()]}\n${DateFormat('MM/dd').format(DateTime.fromMillisecondsSinceEpoch(spot.x.toInt()))}', + TextStyle( + color: Theme.of(context) + .colorScheme + .onSurface, + ), + )) + .toList(), + getTooltipColor: (_) => Theme.of(context) + .colorScheme + .surfaceContainerHigh, + ), + ), titlesData: FlTitlesData( topTitles: const AxisTitles( sideTitles: SideTitles(showTitles: false),