| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830 |
- import 'package:flutter/material.dart';
- import 'package:flutter/services.dart';
- import 'package:cached_network_image/cached_network_image.dart';
- import 'package:flutter_riverpod/flutter_riverpod.dart';
- import 'package:go_router/go_router.dart';
- import '../../../core/config/app_config.dart';
- import '../../../core/l10n/app_localizations.dart';
- import '../../../core/navigation/broker_navigation.dart';
- import '../../../core/theme/app_colors.dart';
- import '../../../providers/app_provider.dart';
- import '../../../providers/app_version_provider.dart';
- import '../../../providers/currency_provider.dart';
- import '../../../providers/customer_service_provider.dart';
- import '../../../providers/profile_provider.dart';
- import '../../widgets/common/update_dialog.dart';
- import '../../../core/utils/top_toast.dart';
- class ProfileScreen extends ConsumerWidget {
- const ProfileScreen({super.key});
- @override
- Widget build(BuildContext context, WidgetRef ref) {
- final l10n = AppLocalizations.of(context)!;
- final state = ref.watch(profileProvider);
- final isLoggedIn = state.user.isLoggedIn;
- return Scaffold(
- appBar: AppBar(
- title: Text(
- l10n.profile,
- style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
- ),
- centerTitle: true,
- ),
- body: ListView(
- children: [
- if (isLoggedIn) _UserCard(state: state) else const _GuestCard(),
- const SizedBox(height: 12),
- _SectionCard(
- title: l10n.quickFunctions,
- child: _QuickFunctions(l10n: l10n),
- ),
- const SizedBox(height: 12),
- _AppSettings(version: state.appVersion, isLoggedIn: isLoggedIn),
- if (isLoggedIn) ...[
- const SizedBox(height: 24),
- _LogoutButton(
- onTap: () => _showLogoutDialog(context, ref),
- ),
- ],
- const SizedBox(height: 40),
- ],
- ),
- );
- }
- void _showLogoutDialog(BuildContext context, WidgetRef ref) {
- final l10n = AppLocalizations.of(context)!;
- final cs = Theme.of(context).colorScheme;
- showDialog(
- context: context,
- builder: (ctx) => AlertDialog(
- backgroundColor: cs.surface,
- title: Text(
- l10n.logoutTitle,
- style: TextStyle(color: cs.onSurface),
- ),
- content: Text(
- l10n.logoutConfirm,
- style: TextStyle(color: cs.onSurface.withAlpha(153)),
- ),
- actions: [
- TextButton(
- onPressed: () => Navigator.of(ctx).pop(),
- child: Text(l10n.cancel,
- style: TextStyle(color: cs.onSurface.withAlpha(153))),
- ),
- TextButton(
- onPressed: () {
- Navigator.of(ctx).pop();
- ref.read(profileProvider.notifier).logout();
- },
- child: Text(l10n.confirm,
- style: const TextStyle(color: AppColors.brand)),
- ),
- ],
- ),
- );
- }
- }
- // ── 未登录:访客卡片 ──────────────────────────────────────────
- class _GuestCard extends StatelessWidget {
- const _GuestCard();
- @override
- Widget build(BuildContext context) {
- final l10n = AppLocalizations.of(context)!;
- final cs = Theme.of(context).colorScheme;
- final isDark = Theme.of(context).brightness == Brightness.dark;
- return Container(
- margin: const EdgeInsets.fromLTRB(16, 16, 16, 0),
- padding: const EdgeInsets.all(16),
- decoration: BoxDecoration(
- color: isDark ? AppColors.darkBgSecondary : AppColors.lightBgSecondary,
- borderRadius: BorderRadius.circular(12),
- ),
- child: Row(
- children: [
- Container(
- width: 56,
- height: 56,
- decoration: BoxDecoration(
- color: cs.outline.withAlpha(40),
- shape: BoxShape.circle,
- ),
- child: Icon(
- Icons.person_outline,
- color: cs.onSurface.withAlpha(153),
- size: 32,
- ),
- ),
- const SizedBox(width: 14),
- Expanded(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- l10n.guestGreeting,
- style: TextStyle(
- color: cs.onSurface,
- fontSize: 16,
- fontWeight: FontWeight.w600,
- ),
- ),
- const SizedBox(height: 10),
- SizedBox(
- height: 34,
- child: ElevatedButton(
- onPressed: () => context.push('/login'),
- style: ElevatedButton.styleFrom(
- backgroundColor: AppColors.brand,
- foregroundColor: Colors.black,
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(17),
- ),
- elevation: 0,
- padding: const EdgeInsets.symmetric(horizontal: 20),
- minimumSize: Size.zero,
- ),
- child: Text(
- l10n.loginRegister,
- style: const TextStyle(
- fontSize: 13,
- fontWeight: FontWeight.w600,
- ),
- ),
- ),
- ),
- ],
- ),
- ),
- ],
- ),
- );
- }
- }
- // ── 已登录:用户信息卡片 ─────────────────────────────────────────
- class _UserCard extends StatelessWidget {
- const _UserCard({required this.state});
- final ProfileState state;
- @override
- Widget build(BuildContext context) {
- final l10n = AppLocalizations.of(context)!;
- final user = state.user;
- final cs = Theme.of(context).colorScheme;
- final isDark = Theme.of(context).brightness == Brightness.dark;
- return Container(
- margin: const EdgeInsets.fromLTRB(16, 16, 16, 0),
- padding: const EdgeInsets.all(16),
- decoration: BoxDecoration(
- color: isDark ? AppColors.darkBgSecondary : AppColors.lightBgSecondary,
- borderRadius: BorderRadius.circular(12),
- ),
- child: Row(
- children: [
- Container(
- width: 56,
- height: 56,
- clipBehavior: Clip.antiAlias,
- decoration: const BoxDecoration(
- color: AppColors.brand,
- shape: BoxShape.circle,
- ),
- child: (user.avatarUrl != null && user.avatarUrl!.isNotEmpty)
- ? CachedNetworkImage(
- imageUrl: user.avatarUrl!,
- fit: BoxFit.cover,
- width: 56,
- height: 56,
- fadeInDuration: Duration.zero,
- errorWidget: (_, __, ___) => Center(
- child: Text(
- user.avatarLetter,
- style: const TextStyle(
- color: Colors.white,
- fontSize: 24,
- fontWeight: FontWeight.w700,
- ),
- ),
- ),
- )
- : Center(
- child: Text(
- user.avatarLetter,
- style: const TextStyle(
- color: Colors.white,
- fontSize: 24,
- fontWeight: FontWeight.w700,
- ),
- ),
- ),
- ),
- const SizedBox(width: 14),
- Expanded(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- user.email,
- style: TextStyle(
- color: cs.onSurface,
- fontSize: 16,
- fontWeight: FontWeight.w600,
- ),
- ),
- const SizedBox(height: 4),
- Row(
- children: [
- Text(
- 'UID: ${user.uid}',
- style: TextStyle(
- color: cs.onSurface.withAlpha(153),
- fontSize: 13,
- ),
- ),
- const SizedBox(width: 6),
- GestureDetector(
- onTap: () {
- Clipboard.setData(ClipboardData(text: user.uid));
- showTopToast(context,
- message: l10n.uidCopied,
- backgroundColor: AppColors.rise);
- },
- child: Icon(
- Icons.copy,
- size: 14,
- color: cs.onSurface.withAlpha(153),
- ),
- ),
- ],
- ),
- ],
- ),
- ),
- ],
- ),
- );
- }
- }
- // ── 卡片容器 ─────────────────────────────────────────────────
- class _SectionCard extends StatelessWidget {
- const _SectionCard({required this.title, required this.child});
- final String title;
- final Widget child;
- @override
- Widget build(BuildContext context) {
- final cs = Theme.of(context).colorScheme;
- final isDark = Theme.of(context).brightness == Brightness.dark;
- return Container(
- margin: const EdgeInsets.symmetric(horizontal: 16),
- decoration: BoxDecoration(
- color: isDark ? AppColors.darkBgSecondary : AppColors.lightBgSecondary,
- borderRadius: BorderRadius.circular(12),
- ),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Padding(
- padding: const EdgeInsets.fromLTRB(16, 14, 16, 10),
- child: Text(
- title,
- style: TextStyle(
- color: cs.onSurface.withAlpha(153),
- fontSize: 13,
- ),
- ),
- ),
- child,
- ],
- ),
- );
- }
- }
- // ── 常用功能 网格 ─────────────────────────────────────────────
- class _QuickFunctions extends StatelessWidget {
- final AppLocalizations l10n;
- const _QuickFunctions({required this.l10n});
- @override
- Widget build(BuildContext context) {
- final items = [
- (
- icon: Icons.language,
- label: l10n.languageSwitch,
- route: '/user/language'
- ),
- (
- icon: Icons.shield_outlined,
- label: l10n.security,
- route: '/user/security'
- ),
- (
- icon: Icons.notifications_outlined,
- label: l10n.announcements,
- route: '/user/messages'
- ),
- (icon: Icons.help_outline, label: l10n.helpCenter, route: '/user/help'),
- ];
- return Padding(
- padding: const EdgeInsets.fromLTRB(8, 0, 8, 16),
- child: Row(
- children: items
- .map((item) => Expanded(
- child: _QuickItemWidget(
- icon: item.icon, label: item.label, route: item.route)))
- .toList(),
- ),
- );
- }
- }
- class _QuickItemWidget extends StatelessWidget {
- const _QuickItemWidget(
- {required this.icon, required this.label, required this.route});
- final IconData icon;
- final String label;
- final String route;
- @override
- Widget build(BuildContext context) {
- final cs = Theme.of(context).colorScheme;
- return GestureDetector(
- onTap: () => context.push(route),
- child: Column(
- children: [
- Container(
- width: 52,
- height: 52,
- decoration: BoxDecoration(
- color: cs.outline.withAlpha(30),
- borderRadius: BorderRadius.circular(14),
- ),
- child: Icon(icon, color: cs.onSurface, size: 24),
- ),
- const SizedBox(height: 6),
- Text(
- label,
- maxLines: 1,
- overflow: TextOverflow.ellipsis,
- textAlign: TextAlign.center,
- style: TextStyle(
- color: cs.onSurface.withAlpha(153),
- fontSize: 12,
- ),
- ),
- ],
- ),
- );
- }
- }
- // ── APP 设置列表 ──────────────────────────────────────────────
- class _AppSettings extends ConsumerWidget {
- const _AppSettings({required this.version, required this.isLoggedIn});
- final String version;
- final bool isLoggedIn;
- @override
- Widget build(BuildContext context, WidgetRef ref) {
- final l10n = AppLocalizations.of(context)!;
- final cs = Theme.of(context).colorScheme;
- final isDark = Theme.of(context).brightness == Brightness.dark;
- final themeMode = ref.watch(themeProvider);
- final currencyState = ref.watch(currencyProvider);
- final selectedCurrency = currencyState.selected;
- return Container(
- margin: const EdgeInsets.symmetric(horizontal: 16),
- decoration: BoxDecoration(
- color: isDark ? AppColors.darkBgSecondary : AppColors.lightBgSecondary,
- borderRadius: BorderRadius.circular(12),
- ),
- child: Column(
- children: [
- if (isLoggedIn) ...[
- _SettingRow(
- label: l10n.broker,
- onTap: () => openBrokerEntry(context, ref),
- showTopRadius: true,
- ),
- Divider(
- height: 1,
- indent: 16,
- endIndent: 0,
- color: cs.outline.withAlpha(40)),
- ],
- _ThemeModeRow(themeMode: themeMode, ref: ref, l10n: l10n),
- Divider(
- height: 1,
- indent: 16,
- endIndent: 0,
- color: cs.outline.withAlpha(40)),
- _SettingRow(
- label: l10n.currency,
- trailing: Text(
- selectedCurrency != null
- ? '${selectedCurrency.currency} ${selectedCurrency.symbol}'
- : 'USD \$',
- style:
- TextStyle(color: cs.onSurface.withAlpha(153), fontSize: 13),
- ),
- onTap: () => _showCurrencyPicker(context, ref, currencyState, l10n),
- ),
- Divider(
- height: 1,
- indent: 16,
- endIndent: 0,
- color: cs.outline.withAlpha(40)),
- _SettingRow(
- label: l10n.stakingTitle,
- onTap: () => context.push('/finance/ido'),
- ),
- Divider(
- height: 1,
- indent: 16,
- endIndent: 0,
- color: cs.outline.withAlpha(40)),
- _SettingRow(
- label: l10n.serviceRoute,
- onTap: () => context.push('/user/service-route'),
- showTopRadius: false,
- ),
- Divider(
- height: 1,
- indent: 16,
- endIndent: 0,
- color: cs.outline.withAlpha(40)),
- _SettingRow(
- label: l10n.currentVersion,
- trailing: Text(
- version,
- style:
- TextStyle(color: cs.onSurface.withAlpha(153), fontSize: 13),
- ),
- onTap: () => _checkUpdate(context, ref, l10n),
- ),
- Divider(
- height: 1,
- indent: 16,
- endIndent: 0,
- color: cs.outline.withAlpha(40)),
- _SettingRow(
- label: l10n.clearCache,
- onTap: () => _confirmClearCache(context, ref, l10n),
- showBottomRadius: !AppConfig.customerServiceEnabled,
- ),
- if (AppConfig.customerServiceEnabled) ...[
- Column(children: [
- Divider(
- height: 1,
- indent: 16,
- endIndent: 0,
- color: cs.outline.withAlpha(40)),
- _SettingRow(
- label: l10n.customerService,
- onTap: () => openCustomerService(context, ref),
- showBottomRadius: true,
- ),
- ]),
- ],
- ],
- ),
- );
- }
- Future<void> _checkUpdate(
- BuildContext context, WidgetRef ref, AppLocalizations l10n) async {
- ref.invalidate(appVersionProvider);
- final result = await ref.read(appVersionProvider.future);
- if (!context.mounted) return;
- if (result != null && result.hasUpdate) {
- UpdateDialog.show(context, result);
- } else {
- showTopToast(context,
- message: l10n.alreadyLatestVersion, backgroundColor: AppColors.rise);
- }
- }
- void _showCurrencyPicker(BuildContext context, WidgetRef ref,
- CurrencyState currencyState, AppLocalizations l10n) {
- final cs = Theme.of(context).colorScheme;
- showModalBottomSheet<void>(
- context: context,
- useRootNavigator: true,
- isScrollControlled: true,
- backgroundColor: cs.surface,
- shape: const RoundedRectangleBorder(
- borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
- ),
- builder: (ctx) => Consumer(
- builder: (ctx, innerRef, _) {
- final live = innerRef.watch(currencyProvider);
- return SafeArea(
- child: ConstrainedBox(
- constraints: BoxConstraints(
- maxHeight: MediaQuery.of(ctx).size.height * 0.75,
- ),
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- const SizedBox(height: 12),
- Container(
- width: 36,
- height: 4,
- decoration: BoxDecoration(
- color: cs.outline.withAlpha(80),
- borderRadius: BorderRadius.circular(2),
- ),
- ),
- const SizedBox(height: 16),
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 16),
- child: Text(
- l10n.selectCurrency,
- style: TextStyle(
- color: cs.onSurface,
- fontSize: 16,
- fontWeight: FontWeight.w600),
- ),
- ),
- const SizedBox(height: 12),
- if (live.isLoading)
- Padding(
- padding: const EdgeInsets.symmetric(vertical: 24),
- child: CircularProgressIndicator(
- strokeWidth: 2, color: cs.onSurface),
- )
- else if (live.rates.isEmpty)
- Padding(
- padding: const EdgeInsets.symmetric(vertical: 24),
- child: Text(l10n.noCurrencyAvailable,
- style: TextStyle(color: cs.onSurface.withAlpha(153))),
- )
- else
- Flexible(
- child: SingleChildScrollView(
- child: Column(
- children: live.rates.map((rate) {
- final isSelected =
- rate.currency == live.selectedCode;
- return GestureDetector(
- behavior: HitTestBehavior.opaque,
- onTap: () {
- innerRef
- .read(currencyProvider.notifier)
- .selectCurrency(rate);
- Navigator.of(ctx).pop();
- },
- child: Padding(
- padding: const EdgeInsets.symmetric(
- horizontal: 16, vertical: 14),
- child: Row(
- children: [
- Text(
- rate.displayName,
- style: TextStyle(
- color: cs.onSurface,
- fontSize: 15,
- fontWeight: isSelected
- ? FontWeight.w600
- : FontWeight.w400,
- ),
- ),
- const Spacer(),
- if (isSelected)
- const Icon(Icons.check,
- color: AppColors.brand, size: 20),
- ],
- ),
- ),
- );
- }).toList(),
- ),
- ),
- ),
- const SizedBox(height: 8),
- ],
- ),
- ),
- );
- },
- ),
- );
- }
- Future<void> _confirmClearCache(
- BuildContext context, WidgetRef ref, AppLocalizations l10n) async {
- final cs = Theme.of(context).colorScheme;
- final confirmed = await showDialog<bool>(
- context: context,
- builder: (ctx) => AlertDialog(
- backgroundColor: cs.surface,
- title: Text(l10n.tips, style: TextStyle(color: cs.onSurface)),
- content: Text(
- l10n.confirmClearCache,
- style: TextStyle(color: cs.onSurface.withAlpha(153)),
- ),
- actions: [
- TextButton(
- onPressed: () => Navigator.of(ctx).pop(false),
- child: Text(l10n.cancel,
- style: TextStyle(color: cs.onSurface.withAlpha(153))),
- ),
- TextButton(
- onPressed: () => Navigator.of(ctx).pop(true),
- child: Text(l10n.confirm,
- style: const TextStyle(color: AppColors.brand)),
- ),
- ],
- ),
- );
- if (confirmed != true || !context.mounted) return;
- await ref.read(profileProvider.notifier).clearCache();
- if (!context.mounted) return;
- showTopToast(context,
- message: l10n.cacheCleared, duration: const Duration(seconds: 1));
- }
- }
- class _ThemeModeRow extends StatelessWidget {
- const _ThemeModeRow(
- {required this.themeMode, required this.ref, required this.l10n});
- final ThemeMode themeMode;
- final WidgetRef ref;
- final AppLocalizations l10n;
- @override
- Widget build(BuildContext context) {
- final cs = Theme.of(context).colorScheme;
- return Padding(
- padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
- child: Row(
- children: [
- Text(
- l10n.themeColor,
- style: TextStyle(color: cs.onSurface, fontSize: 14),
- ),
- const SizedBox(width: 16),
- Expanded(
- child: Row(
- mainAxisAlignment: MainAxisAlignment.end,
- children: [
- Flexible(
- child: _ThemeChip(
- label: l10n.lightMode,
- selected: themeMode == ThemeMode.light,
- onTap: () => ref
- .read(themeProvider.notifier)
- .setTheme(ThemeMode.light),
- ),
- ),
- const SizedBox(width: 6),
- Flexible(
- child: _ThemeChip(
- label: l10n.darkMode,
- selected: themeMode == ThemeMode.dark,
- onTap: () => ref
- .read(themeProvider.notifier)
- .setTheme(ThemeMode.dark),
- ),
- ),
- ],
- ),
- ),
- ],
- ),
- );
- }
- }
- class _ThemeChip extends StatelessWidget {
- const _ThemeChip(
- {required this.label, required this.selected, required this.onTap});
- final String label;
- final bool selected;
- final VoidCallback onTap;
- @override
- Widget build(BuildContext context) {
- final cs = Theme.of(context).colorScheme;
- return GestureDetector(
- onTap: onTap,
- child: Container(
- padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
- decoration: BoxDecoration(
- color: selected ? AppColors.brand : cs.outline.withAlpha(30),
- borderRadius: BorderRadius.circular(16),
- ),
- child: Text(
- label,
- maxLines: 1,
- overflow: TextOverflow.ellipsis,
- style: TextStyle(
- color: selected ? Colors.black : cs.onSurface.withAlpha(153),
- fontSize: 12,
- fontWeight: selected ? FontWeight.w600 : FontWeight.normal,
- ),
- ),
- ),
- );
- }
- }
- class _SettingRow extends StatelessWidget {
- const _SettingRow({
- required this.label,
- required this.onTap,
- this.trailing,
- this.showTopRadius = false,
- this.showBottomRadius = false,
- });
- final String label;
- final VoidCallback onTap;
- final Widget? trailing;
- final bool showTopRadius;
- final bool showBottomRadius;
- @override
- Widget build(BuildContext context) {
- final cs = Theme.of(context).colorScheme;
- return InkWell(
- onTap: onTap,
- borderRadius: BorderRadius.vertical(
- top: showTopRadius ? const Radius.circular(12) : Radius.zero,
- bottom: showBottomRadius ? const Radius.circular(12) : Radius.zero,
- ),
- child: Padding(
- padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
- child: Row(
- children: [
- Expanded(
- child: Text(
- label,
- style: TextStyle(
- color: cs.onSurface,
- fontSize: 14,
- ),
- ),
- ),
- if (trailing != null) trailing!,
- const SizedBox(width: 4),
- Icon(Icons.chevron_right,
- size: 18, color: cs.onSurface.withAlpha(102)),
- ],
- ),
- ),
- );
- }
- }
- // ── 退出登录按钮 ──────────────────────────────────────────────
- class _LogoutButton extends StatelessWidget {
- const _LogoutButton({required this.onTap});
- final VoidCallback onTap;
- @override
- Widget build(BuildContext context) {
- final l10n = AppLocalizations.of(context)!;
- final cs = Theme.of(context).colorScheme;
- final isDark = Theme.of(context).brightness == Brightness.dark;
- return Padding(
- padding: const EdgeInsets.symmetric(horizontal: 16),
- child: GestureDetector(
- onTap: onTap,
- child: Container(
- height: 48,
- decoration: BoxDecoration(
- color:
- isDark ? AppColors.darkBgSecondary : AppColors.lightBgSecondary,
- borderRadius: BorderRadius.circular(12),
- ),
- child: Center(
- child: Text(
- l10n.logoutButton,
- style: TextStyle(
- color: cs.onSurface,
- fontSize: 15,
- fontWeight: FontWeight.w500,
- ),
- ),
- ),
- ),
- ),
- );
- }
- }
|