✨ User fortune history
This commit is contained in:
parent
67a29b4305
commit
3d15c0b9f9
@ -1,6 +1,7 @@
|
|||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:fl_chart/fl_chart.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
@ -14,6 +15,7 @@ import 'package:surface/providers/relationship.dart';
|
|||||||
import 'package:surface/providers/sn_network.dart';
|
import 'package:surface/providers/sn_network.dart';
|
||||||
import 'package:surface/screens/abuse_report.dart';
|
import 'package:surface/screens/abuse_report.dart';
|
||||||
import 'package:surface/types/account.dart';
|
import 'package:surface/types/account.dart';
|
||||||
|
import 'package:surface/types/check_in.dart';
|
||||||
import 'package:surface/types/post.dart';
|
import 'package:surface/types/post.dart';
|
||||||
import 'package:surface/widgets/account/account_image.dart';
|
import 'package:surface/widgets/account/account_image.dart';
|
||||||
import 'package:surface/widgets/dialog.dart';
|
import 'package:surface/widgets/dialog.dart';
|
||||||
@ -62,6 +64,19 @@ class _UserScreenState extends State<UserScreen> with SingleTickerProviderStateM
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<List<SnCheckInRecord>> _getCheckInRecords() async {
|
||||||
|
try {
|
||||||
|
final sn = context.read<SnNetworkProvider>();
|
||||||
|
final resp = await sn.client.get('/cgi/id/users/${widget.name}/check-in?take=14');
|
||||||
|
return List.from(
|
||||||
|
resp.data['data']?.map((x) => SnCheckInRecord.fromJson(x)) ?? [],
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
if (mounted) context.showErrorDialog(err);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SnAccountStatusInfo? _status;
|
SnAccountStatusInfo? _status;
|
||||||
|
|
||||||
Future<void> _fetchStatus() async {
|
Future<void> _fetchStatus() async {
|
||||||
@ -497,6 +512,27 @@ class _UserScreenState extends State<UserScreen> with SingleTickerProviderStateM
|
|||||||
),
|
),
|
||||||
SliverToBoxAdapter(child: const Divider()),
|
SliverToBoxAdapter(child: const Divider()),
|
||||||
const SliverGap(12),
|
const SliverGap(12),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: FutureBuilder<List<SnCheckInRecord>>(
|
||||||
|
future: _getCheckInRecords(),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (!snapshot.hasData) return const SizedBox.shrink();
|
||||||
|
final records = snapshot.data!;
|
||||||
|
return SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 240,
|
||||||
|
child: CheckInRecordChart(records: records),
|
||||||
|
).padding(
|
||||||
|
right: 24,
|
||||||
|
left: 16,
|
||||||
|
top: 12,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SliverGap(12),
|
||||||
|
SliverToBoxAdapter(child: const Divider()),
|
||||||
|
const SliverGap(12),
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -565,3 +601,105 @@ class _UserScreenState extends State<UserScreen> with SingleTickerProviderStateM
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CheckInRecordChart extends StatelessWidget {
|
||||||
|
const CheckInRecordChart({
|
||||||
|
super.key,
|
||||||
|
required this.records,
|
||||||
|
});
|
||||||
|
|
||||||
|
final List<SnCheckInRecord> records;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return LineChart(
|
||||||
|
LineChartData(
|
||||||
|
lineBarsData: [
|
||||||
|
LineChartBarData(
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
belowBarData: BarAreaData(
|
||||||
|
show: true,
|
||||||
|
gradient: LinearGradient(
|
||||||
|
colors: List.filled(
|
||||||
|
records.length,
|
||||||
|
Theme.of(context).colorScheme.primary.withOpacity(0.3),
|
||||||
|
).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
spots: records
|
||||||
|
.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(
|
||||||
|
'${kCheckInResultTierSymbols[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(
|
||||||
|
kCheckInResultTierSymbols[value.toInt()],
|
||||||
|
textAlign: TextAlign.right,
|
||||||
|
).padding(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,
|
||||||
|
).padding(top: 8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
gridData: const FlGridData(show: false),
|
||||||
|
borderData: FlBorderData(show: false),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -3,6 +3,8 @@ import 'package:freezed_annotation/freezed_annotation.dart';
|
|||||||
part 'check_in.freezed.dart';
|
part 'check_in.freezed.dart';
|
||||||
part 'check_in.g.dart';
|
part 'check_in.g.dart';
|
||||||
|
|
||||||
|
const List<String> kCheckInResultTierSymbols = ['大凶', '凶', '中平', '吉', '大吉'];
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class SnCheckInRecord with _$SnCheckInRecord {
|
class SnCheckInRecord with _$SnCheckInRecord {
|
||||||
const SnCheckInRecord._();
|
const SnCheckInRecord._();
|
||||||
@ -21,11 +23,5 @@ class SnCheckInRecord with _$SnCheckInRecord {
|
|||||||
factory SnCheckInRecord.fromJson(Map<String, dynamic> json) =>
|
factory SnCheckInRecord.fromJson(Map<String, dynamic> json) =>
|
||||||
_$SnCheckInRecordFromJson(json);
|
_$SnCheckInRecordFromJson(json);
|
||||||
|
|
||||||
String get symbol => switch (resultTier) {
|
String get symbol => kCheckInResultTierSymbols[resultTier];
|
||||||
0 => '大凶',
|
|
||||||
1 => '凶',
|
|
||||||
2 => '中平',
|
|
||||||
3 => '吉',
|
|
||||||
_ => '大吉',
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
10
pubspec.lock
10
pubspec.lock
@ -614,6 +614,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.1.1"
|
||||||
|
fl_chart:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: fl_chart
|
||||||
|
sha256: c724234b05e378383e958f3e82ca84a3e1e3c06a0898462044dd8a24b1ee9864
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.70.0"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -2145,4 +2153,4 @@ packages:
|
|||||||
version: "3.1.3"
|
version: "3.1.3"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.6.0 <4.0.0"
|
dart: ">=3.6.0 <4.0.0"
|
||||||
flutter: ">=3.24.0"
|
flutter: ">=3.27.0"
|
||||||
|
@ -112,6 +112,7 @@ dependencies:
|
|||||||
in_app_review: ^2.0.10
|
in_app_review: ^2.0.10
|
||||||
version: ^3.0.2
|
version: ^3.0.2
|
||||||
flutter_colorpicker: ^1.1.0
|
flutter_colorpicker: ^1.1.0
|
||||||
|
fl_chart: ^0.70.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
Reference in New Issue
Block a user