feat: phase1 UI prep — 设备ID系统传递 + 国家本地化展示 + 继续观看直进播放页
设备标识: Android SSAID/ iOS IDFV 原生通道 → Dart DeviceIdProvider 国家解析: 注册/登录从后端 IP → 国家/语言/时区/币种 自动落库 账号资料: 全部本地化展示 (account_display.dart) 我的页: 继续观看卡片点击直接进播放页
This commit is contained in:
1 parent
1b19513efb
commit
a3f3481f4f
15 files changed
+468
-25
No files matched your search
@@ -8,6 +8,7 @@ import 'package:provider/provider.dart';
|
||||
import '../../core/data/models/account_profile.dart';
|
||||
import '../../core/data/repositories/account_repository.dart';
|
||||
import '../../core/data/services/auth_controller.dart';
|
||||
import '../../core/formatting/account_display.dart';
|
||||
import '../../core/formatting/error_text.dart';
|
||||
import '../../core/formatting/localized_date_time.dart';
|
||||
import '../../core/theme/app_colors.dart';
|
||||
@@ -225,6 +226,7 @@ class _AccountProfilePageState extends State<AccountProfilePage> {
|
||||
);
|
||||
|
||||
Widget _readOnlyCard(AccountProfile profile, AppLocalizations l10n) {
|
||||
final localeName = Localizations.localeOf(context).languageCode;
|
||||
return _AccountCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -238,13 +240,34 @@ class _AccountProfilePageState extends State<AccountProfilePage> {
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
_info(l10n.accountMaskedAccount, profile.maskedTarget),
|
||||
_info(l10n.accountCountry, profile.countryCode),
|
||||
_info(
|
||||
l10n.accountCountry,
|
||||
countryName(profile.countryCode, localeName),
|
||||
),
|
||||
_info(l10n.accountCurrency, profile.currency),
|
||||
_info(l10n.accountStatus, profile.status),
|
||||
_info(l10n.accountLanguage, profile.language),
|
||||
_info(l10n.accountTimezone, profile.timezone),
|
||||
_info(l10n.accountRegion, profile.regionCode),
|
||||
_info(l10n.accountVipLevel, '${profile.vipLevel}'),
|
||||
_info(
|
||||
l10n.accountStatus,
|
||||
accountStatusText(profile.status, localeName),
|
||||
),
|
||||
_info(
|
||||
l10n.accountLanguage,
|
||||
languageName(profile.language, localeName),
|
||||
),
|
||||
_info(
|
||||
l10n.accountTimezone,
|
||||
timezoneName(profile.timezone, localeName),
|
||||
),
|
||||
// region 与 country 后端写的是同一个值,重复时不再单列一行
|
||||
if (profile.regionCode.isNotEmpty &&
|
||||
profile.regionCode != profile.countryCode)
|
||||
_info(
|
||||
l10n.accountRegion,
|
||||
countryName(profile.regionCode, localeName),
|
||||
),
|
||||
_info(
|
||||
l10n.accountVipLevel,
|
||||
vipLevelText(profile.vipLevel, localeName),
|
||||
),
|
||||
if (profile.createdAt != null)
|
||||
_info(
|
||||
l10n.accountCreatedAt,
|
||||
@@ -275,7 +298,7 @@ class _AccountProfilePageState extends State<AccountProfilePage> {
|
||||
),
|
||||
Flexible(
|
||||
child: Text(
|
||||
value.isEmpty ? '-' : value,
|
||||
value.isEmpty ? '—' : value,
|
||||
textAlign: TextAlign.right,
|
||||
style: const TextStyle(fontSize: AppDimens.body),
|
||||
),
|
||||
|
||||
@@ -6,8 +6,11 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../core/data/models/drama.dart';
|
||||
import '../../core/data/models/watch_progress.dart';
|
||||
import '../../core/data/repositories/watch_history_repository.dart';
|
||||
import '../../core/data/services/auth_controller.dart';
|
||||
import '../../core/data/services/catalog_controller.dart';
|
||||
import '../../core/data/services/favorite_controller.dart';
|
||||
import '../../core/data/services/locale_controller.dart';
|
||||
import '../../core/data/services/wallet_controller.dart';
|
||||
@@ -22,6 +25,7 @@ import '../downloads/downloads_page.dart';
|
||||
import '../account/account_profile_page.dart';
|
||||
import '../filter/filter_page.dart';
|
||||
import '../notices/notices_page.dart';
|
||||
import '../player/open_player.dart';
|
||||
import '../settings/settings_page.dart';
|
||||
import '../store/vip_page.dart';
|
||||
import '../wallet/wallet_page.dart';
|
||||
@@ -222,6 +226,7 @@ class _MyPageState extends State<MyPage> {
|
||||
const SizedBox(height: AppDimens.mineSectionGap),
|
||||
MineContinueWatching(
|
||||
records: continueWatching,
|
||||
onOpenRecord: _openContinueRecord,
|
||||
onOpenAll: _openHistoryTab,
|
||||
),
|
||||
],
|
||||
@@ -294,6 +299,36 @@ class _MyPageState extends State<MyPage> {
|
||||
unawaited(_openHistoryPage());
|
||||
}
|
||||
|
||||
/// 继续观看卡片:补齐剧集后直接进全屏播放页,播放器自己会定位到记录的秒数。
|
||||
Future<void> _openContinueRecord(WatchProgress record) async {
|
||||
final catalog = context.read<CatalogController>();
|
||||
// 续看记录只有剧的概要信息,先拼一个占位对象让目录去取完整详情
|
||||
final summary = Drama(
|
||||
id: record.dramaId,
|
||||
title: record.dramaTitle ?? '',
|
||||
synopsis: '',
|
||||
posterUrl: record.dramaCover ?? '',
|
||||
);
|
||||
Drama drama;
|
||||
try {
|
||||
drama = await catalog.requireDetail(summary);
|
||||
} catch (_) {
|
||||
if (!mounted) return;
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(SnackBar(content: Text(l10n.detailLoadFailed)));
|
||||
return;
|
||||
}
|
||||
if (!mounted) return;
|
||||
await playDramaFromCatalog(
|
||||
context,
|
||||
drama,
|
||||
episodeId: record.episodeId.isEmpty ? null : record.episodeId,
|
||||
);
|
||||
if (mounted) unawaited(logic.refreshRecent());
|
||||
}
|
||||
|
||||
Future<void> _openHistoryPage() async {
|
||||
await _push(const WatchRecordsPage());
|
||||
if (mounted) unawaited(logic.refreshRecent());
|
||||
|
||||
@@ -12,10 +12,14 @@ class MineContinueWatching extends StatelessWidget {
|
||||
const MineContinueWatching({
|
||||
super.key,
|
||||
required this.records,
|
||||
required this.onOpenRecord,
|
||||
required this.onOpenAll,
|
||||
});
|
||||
|
||||
final List<WatchProgress> records;
|
||||
|
||||
/// 单张卡片:直接进入该剧的播放页,并定位到记录的集。
|
||||
final ValueChanged<WatchProgress> onOpenRecord;
|
||||
final VoidCallback onOpenAll;
|
||||
|
||||
@override
|
||||
@@ -94,7 +98,11 @@ class MineContinueWatching extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _card(AppLocalizations l10n, WatchProgress record, String languageCode) {
|
||||
Widget _card(
|
||||
AppLocalizations l10n,
|
||||
WatchProgress record,
|
||||
String languageCode,
|
||||
) {
|
||||
final title = record.localizedTitle(languageCode).trim();
|
||||
final episode = record.episodeNumber;
|
||||
final hasProgress = record.duration > Duration.zero;
|
||||
@@ -103,7 +111,7 @@ class MineContinueWatching extends StatelessWidget {
|
||||
child: InkWell(
|
||||
key: Key('mine-continue-${record.dramaId}'),
|
||||
borderRadius: BorderRadius.circular(AppDimens.homeCardRadius),
|
||||
onTap: onOpenAll,
|
||||
onTap: () => onOpenRecord(record),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
||||
Reference in new issue
Block a user