Compare commits
No commits in common. "a1c4e5eca04cef112f096a66953fbafcab12457f" and "f78d3f4fd5452f00f866c859947fcf34fa07f437" have entirely different histories.
a1c4e5eca0
...
f78d3f4fd5
@ -60,6 +60,11 @@ class NavigationProvider extends ChangeNotifier {
|
|||||||
screen: 'chat',
|
screen: 'chat',
|
||||||
label: 'screenChat',
|
label: 'screenChat',
|
||||||
),
|
),
|
||||||
|
AppNavDestination(
|
||||||
|
icon: Icon(Symbols.account_circle, weight: 400, opticalSize: 20),
|
||||||
|
screen: 'account',
|
||||||
|
label: 'screenAccount',
|
||||||
|
),
|
||||||
AppNavDestination(
|
AppNavDestination(
|
||||||
icon: Icon(Symbols.group, weight: 400, opticalSize: 20),
|
icon: Icon(Symbols.group, weight: 400, opticalSize: 20),
|
||||||
screen: 'realm',
|
screen: 'realm',
|
||||||
@ -70,11 +75,6 @@ class NavigationProvider extends ChangeNotifier {
|
|||||||
screen: 'news',
|
screen: 'news',
|
||||||
label: 'screenNews',
|
label: 'screenNews',
|
||||||
),
|
),
|
||||||
AppNavDestination(
|
|
||||||
icon: Icon(Symbols.settings, weight: 400, opticalSize: 20),
|
|
||||||
screen: 'settings',
|
|
||||||
label: 'screenSettings',
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
static const List<String> kDefaultPinnedDestination = [
|
static const List<String> kDefaultPinnedDestination = [
|
||||||
'home',
|
'home',
|
||||||
|
304
lib/router.dart
304
lib/router.dart
@ -72,8 +72,8 @@ final _appRoutes = [
|
|||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/posts',
|
path: '/posts',
|
||||||
name: 'posts',
|
name: 'explore',
|
||||||
builder: (_, __) => const SizedBox.shrink(),
|
builder: (context, state) => const ExploreScreen(),
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/draft',
|
path: '/draft',
|
||||||
@ -111,195 +111,157 @@ final _appRoutes = [
|
|||||||
state.uri.queryParameters['categories']?.split(','),
|
state.uri.queryParameters['categories']?.split(','),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
|
||||||
ShellRoute(
|
|
||||||
builder: (context, state, child) => ResponsiveScaffold(
|
|
||||||
asideFlex: 2,
|
|
||||||
contentFlex: 3,
|
|
||||||
aside: const ExploreScreen(),
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
routes: [
|
|
||||||
GoRoute(
|
|
||||||
path: '/explore',
|
|
||||||
name: 'explore',
|
|
||||||
builder: (context, state) => const ResponsiveScaffoldLanding(
|
|
||||||
child: ExploreScreen(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
GoRoute(
|
|
||||||
path: '/posts/:slug',
|
|
||||||
name: 'postDetail',
|
|
||||||
builder: (context, state) => PostDetailScreen(
|
|
||||||
key: ValueKey(state.pathParameters['slug']!),
|
|
||||||
slug: state.pathParameters['slug']!,
|
|
||||||
preload: state.extra as SnPost?,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/publishers/:name',
|
path: '/publishers/:name',
|
||||||
name: 'postPublisher',
|
name: 'postPublisher',
|
||||||
builder: (context, state) =>
|
builder: (context, state) =>
|
||||||
PostPublisherScreen(name: state.pathParameters['name']!),
|
PostPublisherScreen(name: state.pathParameters['name']!),
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
|
||||||
ShellRoute(
|
|
||||||
builder: (context, state, child) => ResponsiveScaffold(
|
|
||||||
aside: const AccountScreen(),
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
routes: [
|
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/account',
|
path: '/:slug',
|
||||||
name: 'account',
|
name: 'postDetail',
|
||||||
builder: (context, state) =>
|
builder: (context, state) => PostDetailScreen(
|
||||||
const ResponsiveScaffoldLanding(child: AccountScreen()),
|
slug: state.pathParameters['slug']!,
|
||||||
routes: [
|
preload: state.extra as SnPost?,
|
||||||
GoRoute(
|
),
|
||||||
path: '/punishments',
|
|
||||||
name: 'accountPunishments',
|
|
||||||
builder: (context, state) => const PunishmentsScreen(),
|
|
||||||
),
|
|
||||||
GoRoute(
|
|
||||||
path: '/programs',
|
|
||||||
name: 'accountProgram',
|
|
||||||
builder: (context, state) => const AccountProgramScreen(),
|
|
||||||
),
|
|
||||||
GoRoute(
|
|
||||||
path: '/contacts',
|
|
||||||
name: 'accountContactMethods',
|
|
||||||
builder: (context, state) => const AccountContactMethod(),
|
|
||||||
),
|
|
||||||
GoRoute(
|
|
||||||
path: '/events',
|
|
||||||
name: 'accountActionEvents',
|
|
||||||
builder: (context, state) => const ActionEventScreen(),
|
|
||||||
),
|
|
||||||
GoRoute(
|
|
||||||
path: '/tickets',
|
|
||||||
name: 'accountAuthTickets',
|
|
||||||
builder: (context, state) => const AccountAuthTicket(),
|
|
||||||
),
|
|
||||||
GoRoute(
|
|
||||||
path: '/badges',
|
|
||||||
name: 'accountBadges',
|
|
||||||
builder: (context, state) => const AccountBadgesScreen(),
|
|
||||||
),
|
|
||||||
GoRoute(
|
|
||||||
path: '/wallet',
|
|
||||||
name: 'accountWallet',
|
|
||||||
builder: (context, state) => const WalletScreen(),
|
|
||||||
),
|
|
||||||
GoRoute(
|
|
||||||
path: '/keypairs',
|
|
||||||
name: 'accountKeyPairs',
|
|
||||||
builder: (context, state) => const KeyPairScreen(),
|
|
||||||
),
|
|
||||||
GoRoute(
|
|
||||||
path: '/settings',
|
|
||||||
name: 'accountSettings',
|
|
||||||
builder: (context, state) => AccountSettingsScreen(),
|
|
||||||
routes: [
|
|
||||||
GoRoute(
|
|
||||||
path: '/notify',
|
|
||||||
name: 'accountSettingsNotify',
|
|
||||||
builder: (context, state) => const AccountNotifyPrefsScreen(),
|
|
||||||
),
|
|
||||||
GoRoute(
|
|
||||||
path: '/auth',
|
|
||||||
name: 'accountSettingsSecurity',
|
|
||||||
builder: (context, state) => const AccountSecurityPrefsScreen(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
GoRoute(
|
|
||||||
path: '/settings/factors',
|
|
||||||
name: 'factorSettings',
|
|
||||||
builder: (context, state) => FactorSettingsScreen(),
|
|
||||||
),
|
|
||||||
GoRoute(
|
|
||||||
path: '/profile/edit',
|
|
||||||
name: 'accountProfileEdit',
|
|
||||||
builder: (context, state) => ProfileEditScreen(),
|
|
||||||
),
|
|
||||||
GoRoute(
|
|
||||||
path: '/publishers',
|
|
||||||
name: 'accountPublishers',
|
|
||||||
builder: (context, state) => PublisherScreen(),
|
|
||||||
),
|
|
||||||
GoRoute(
|
|
||||||
path: '/publishers/new',
|
|
||||||
name: 'accountPublisherNew',
|
|
||||||
builder: (context, state) => AccountPublisherNewScreen(),
|
|
||||||
),
|
|
||||||
GoRoute(
|
|
||||||
path: '/publishers/edit/:name',
|
|
||||||
name: 'accountPublisherEdit',
|
|
||||||
builder: (context, state) => AccountPublisherEditScreen(
|
|
||||||
name: state.pathParameters['name']!,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/accounts/:name',
|
path: '/account',
|
||||||
name: 'accountProfilePage',
|
name: 'account',
|
||||||
pageBuilder: (context, state) => NoTransitionPage(
|
builder: (context, state) => const AccountScreen(),
|
||||||
child: UserScreen(name: state.pathParameters['name']!),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
ShellRoute(
|
|
||||||
builder: (context, state, child) =>
|
|
||||||
ResponsiveScaffold(aside: const ChatScreen(), child: child),
|
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/chat',
|
path: '/punishments',
|
||||||
name: 'chat',
|
name: 'accountPunishments',
|
||||||
builder: (context, state) => const ResponsiveScaffoldLanding(
|
builder: (context, state) => const PunishmentsScreen(),
|
||||||
child: ChatScreen(),
|
),
|
||||||
),
|
GoRoute(
|
||||||
|
path: '/programs',
|
||||||
|
name: 'accountProgram',
|
||||||
|
builder: (context, state) => const AccountProgramScreen(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/contacts',
|
||||||
|
name: 'accountContactMethods',
|
||||||
|
builder: (context, state) => const AccountContactMethod(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/events',
|
||||||
|
name: 'accountActionEvents',
|
||||||
|
builder: (context, state) => const ActionEventScreen(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/tickets',
|
||||||
|
name: 'accountAuthTickets',
|
||||||
|
builder: (context, state) => const AccountAuthTicket(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/badges',
|
||||||
|
name: 'accountBadges',
|
||||||
|
builder: (context, state) => const AccountBadgesScreen(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/wallet',
|
||||||
|
name: 'accountWallet',
|
||||||
|
builder: (context, state) => const WalletScreen(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/keypairs',
|
||||||
|
name: 'accountKeyPairs',
|
||||||
|
builder: (context, state) => const KeyPairScreen(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/settings',
|
||||||
|
name: 'accountSettings',
|
||||||
|
builder: (context, state) => AccountSettingsScreen(),
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/:scope/:alias',
|
path: '/notify',
|
||||||
name: 'chatRoom',
|
name: 'accountSettingsNotify',
|
||||||
builder: (context, state) => ChatRoomScreen(
|
builder: (context, state) => const AccountNotifyPrefsScreen(),
|
||||||
key: ValueKey(
|
|
||||||
'${state.pathParameters['scope']!}:${state.pathParameters['alias']!}',
|
|
||||||
),
|
|
||||||
scope: state.pathParameters['scope']!,
|
|
||||||
alias: state.pathParameters['alias']!,
|
|
||||||
extra: state.extra as ChatRoomScreenExtra?,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/:scope/:alias/call',
|
path: '/auth',
|
||||||
name: 'chatCallRoom',
|
name: 'accountSettingsSecurity',
|
||||||
builder: (context, state) => CallRoomScreen(
|
builder: (context, state) => const AccountSecurityPrefsScreen(),
|
||||||
scope: state.pathParameters['scope']!,
|
|
||||||
alias: state.pathParameters['alias']!,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
GoRoute(
|
|
||||||
path: '/:scope/:alias/detail',
|
|
||||||
name: 'channelDetail',
|
|
||||||
builder: (context, state) => ChannelDetailScreen(
|
|
||||||
scope: state.pathParameters['scope']!,
|
|
||||||
alias: state.pathParameters['alias']!,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
GoRoute(
|
|
||||||
path: '/manage',
|
|
||||||
name: 'chatManage',
|
|
||||||
builder: (context, state) => ChatManageScreen(
|
|
||||||
editingChannelAlias: state.uri.queryParameters['editing'],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/settings/factors',
|
||||||
|
name: 'factorSettings',
|
||||||
|
builder: (context, state) => FactorSettingsScreen(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/profile/edit',
|
||||||
|
name: 'accountProfileEdit',
|
||||||
|
builder: (context, state) => ProfileEditScreen(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/publishers',
|
||||||
|
name: 'accountPublishers',
|
||||||
|
builder: (context, state) => PublisherScreen(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/publishers/new',
|
||||||
|
name: 'accountPublisherNew',
|
||||||
|
builder: (context, state) => AccountPublisherNewScreen(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/publishers/edit/:name',
|
||||||
|
name: 'accountPublisherEdit',
|
||||||
|
builder: (context, state) => AccountPublisherEditScreen(
|
||||||
|
name: state.pathParameters['name']!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/profile/:name',
|
||||||
|
name: 'accountProfilePage',
|
||||||
|
pageBuilder: (context, state) => NoTransitionPage(
|
||||||
|
child: UserScreen(name: state.pathParameters['name']!),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/chat',
|
||||||
|
name: 'chat',
|
||||||
|
builder: (context, state) => const ChatScreen(),
|
||||||
|
routes: [
|
||||||
|
GoRoute(
|
||||||
|
path: '/:scope/:alias',
|
||||||
|
name: 'chatRoom',
|
||||||
|
builder: (context, state) => ChatRoomScreen(
|
||||||
|
scope: state.pathParameters['scope']!,
|
||||||
|
alias: state.pathParameters['alias']!,
|
||||||
|
extra: state.extra as ChatRoomScreenExtra?,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/:scope/:alias/call',
|
||||||
|
name: 'chatCallRoom',
|
||||||
|
builder: (context, state) => CallRoomScreen(
|
||||||
|
scope: state.pathParameters['scope']!,
|
||||||
|
alias: state.pathParameters['alias']!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/:scope/:alias/detail',
|
||||||
|
name: 'channelDetail',
|
||||||
|
builder: (context, state) => ChannelDetailScreen(
|
||||||
|
scope: state.pathParameters['scope']!,
|
||||||
|
alias: state.pathParameters['alias']!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/manage',
|
||||||
|
name: 'chatManage',
|
||||||
|
builder: (context, state) => ChatManageScreen(
|
||||||
|
editingChannelAlias: state.uri.queryParameters['editing'],
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
|
@ -110,7 +110,6 @@ class AccountScreen extends StatelessWidget {
|
|||||||
final sn = context.read<SnNetworkProvider>();
|
final sn = context.read<SnNetworkProvider>();
|
||||||
|
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: AutoAppBarLeading(),
|
leading: AutoAppBarLeading(),
|
||||||
title: Text("screenAccount").tr(),
|
title: Text("screenAccount").tr(),
|
||||||
@ -142,6 +141,15 @@ class AccountScreen extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Symbols.settings, fill: 1),
|
||||||
|
onPressed: () {
|
||||||
|
GoRouter.of(context).pushNamed('settings');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const Gap(8),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
body: SingleChildScrollView(
|
body: SingleChildScrollView(
|
||||||
child: ua.isAuthorized
|
child: ua.isAuthorized
|
||||||
|
@ -59,7 +59,6 @@ class _ActionEventScreenState extends State<ActionEventScreen> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: const PageBackButton(),
|
leading: const PageBackButton(),
|
||||||
title: Text('accountActionEvent').tr(),
|
title: Text('accountActionEvent').tr(),
|
||||||
|
@ -91,7 +91,6 @@ class _AccountAuthTicketState extends State<AccountAuthTicket> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: const PageBackButton(),
|
leading: const PageBackButton(),
|
||||||
title: Text('accountAuthTickets').tr(),
|
title: Text('accountAuthTickets').tr(),
|
||||||
|
@ -70,7 +70,6 @@ class _AccountBadgesScreenState extends State<AccountBadgesScreen> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('screenAccountBadges').tr(),
|
title: Text('screenAccountBadges').tr(),
|
||||||
),
|
),
|
||||||
|
@ -69,7 +69,6 @@ class _AccountContactMethodState extends State<AccountContactMethod> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: const PageBackButton(),
|
leading: const PageBackButton(),
|
||||||
title: Text('accountContactMethods').tr(),
|
title: Text('accountContactMethods').tr(),
|
||||||
|
@ -16,11 +16,7 @@ final Map<int, (String, String, IconData)> kFactorTypes = {
|
|||||||
0: ('authFactorPassword', 'authFactorPasswordDescription', Symbols.password),
|
0: ('authFactorPassword', 'authFactorPasswordDescription', Symbols.password),
|
||||||
1: ('authFactorEmail', 'authFactorEmailDescription', Symbols.email),
|
1: ('authFactorEmail', 'authFactorEmailDescription', Symbols.email),
|
||||||
2: ('authFactorTOTP', 'authFactorTOTPDescription', Symbols.timer),
|
2: ('authFactorTOTP', 'authFactorTOTPDescription', Symbols.timer),
|
||||||
3: (
|
3: ('authFactorInAppNotify', 'authFactorInAppNotifyDescription', Symbols.notifications_active),
|
||||||
'authFactorInAppNotify',
|
|
||||||
'authFactorInAppNotifyDescription',
|
|
||||||
Symbols.notifications_active
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class FactorSettingsScreen extends StatefulWidget {
|
class FactorSettingsScreen extends StatefulWidget {
|
||||||
@ -40,10 +36,7 @@ class _FactorSettingsScreenState extends State<FactorSettingsScreen> {
|
|||||||
final sn = context.read<SnNetworkProvider>();
|
final sn = context.read<SnNetworkProvider>();
|
||||||
final resp = await sn.client.get('/cgi/id/users/me/factors');
|
final resp = await sn.client.get('/cgi/id/users/me/factors');
|
||||||
_factors = List<SnAuthFactor>.from(
|
_factors = List<SnAuthFactor>.from(
|
||||||
resp.data
|
resp.data?.map((e) => SnAuthFactor.fromJson(e as Map<String, dynamic>)).toList() ?? [],
|
||||||
?.map((e) => SnAuthFactor.fromJson(e as Map<String, dynamic>))
|
|
||||||
.toList() ??
|
|
||||||
[],
|
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
@ -62,7 +55,6 @@ class _FactorSettingsScreenState extends State<FactorSettingsScreen> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: PageBackButton(),
|
leading: PageBackButton(),
|
||||||
title: Text('screenFactorSettings').tr(),
|
title: Text('screenFactorSettings').tr(),
|
||||||
@ -104,8 +96,7 @@ class _FactorSettingsScreenState extends State<FactorSettingsScreen> {
|
|||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(kFactorTypes[ele.type]!.$1).tr(),
|
title: Text(kFactorTypes[ele.type]!.$1).tr(),
|
||||||
subtitle: Text(kFactorTypes[ele.type]!.$2).tr(),
|
subtitle: Text(kFactorTypes[ele.type]!.$2).tr(),
|
||||||
contentPadding:
|
contentPadding: const EdgeInsets.only(left: 24, right: 12),
|
||||||
const EdgeInsets.only(left: 24, right: 12),
|
|
||||||
leading: Icon(kFactorTypes[ele.type]!.$3),
|
leading: Icon(kFactorTypes[ele.type]!.$3),
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
icon: const Icon(Symbols.close),
|
icon: const Icon(Symbols.close),
|
||||||
@ -114,17 +105,14 @@ class _FactorSettingsScreenState extends State<FactorSettingsScreen> {
|
|||||||
context
|
context
|
||||||
.showConfirmDialog(
|
.showConfirmDialog(
|
||||||
'authFactorDelete'.tr(),
|
'authFactorDelete'.tr(),
|
||||||
'authFactorDeleteDescription'.tr(
|
'authFactorDeleteDescription'.tr(args: [kFactorTypes[ele.type]!.$1.tr()]),
|
||||||
args: [kFactorTypes[ele.type]!.$1.tr()]),
|
|
||||||
)
|
)
|
||||||
.then((val) async {
|
.then((val) async {
|
||||||
if (!val) return;
|
if (!val) return;
|
||||||
try {
|
try {
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
final sn =
|
final sn = context.read<SnNetworkProvider>();
|
||||||
context.read<SnNetworkProvider>();
|
await sn.client.delete('/cgi/id/users/me/factors/${ele.id}');
|
||||||
await sn.client.delete(
|
|
||||||
'/cgi/id/users/me/factors/${ele.id}');
|
|
||||||
_fetchFactors();
|
_fetchFactors();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
@ -203,9 +191,7 @@ class _FactorNewDialogState extends State<_FactorNewDialog> {
|
|||||||
value: _factorType,
|
value: _factorType,
|
||||||
items: kFactorTypes.entries.map(
|
items: kFactorTypes.entries.map(
|
||||||
(ele) {
|
(ele) {
|
||||||
final contains = widget.currentlyHave
|
final contains = widget.currentlyHave.map((ele) => ele.type).contains(ele.key);
|
||||||
.map((ele) => ele.type)
|
|
||||||
.contains(ele.key);
|
|
||||||
return DropdownMenuItem<int>(
|
return DropdownMenuItem<int>(
|
||||||
enabled: !contains,
|
enabled: !contains,
|
||||||
value: ele.key,
|
value: ele.key,
|
||||||
|
@ -37,7 +37,6 @@ class _KeyPairScreenState extends State<KeyPairScreen> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('screenKeyPairs').tr(),
|
title: Text('screenKeyPairs').tr(),
|
||||||
),
|
),
|
||||||
|
@ -75,7 +75,6 @@ class _AccountNotifyPrefsScreenState extends State<AccountNotifyPrefsScreen> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: const PageBackButton(),
|
leading: const PageBackButton(),
|
||||||
title: Text('accountSettingsNotify').tr(),
|
title: Text('accountSettingsNotify').tr(),
|
||||||
|
@ -70,7 +70,6 @@ class _AccountSecurityPrefsScreenState
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: const PageBackButton(),
|
leading: const PageBackButton(),
|
||||||
title: Text('accountSettingsSecurity').tr(),
|
title: Text('accountSettingsSecurity').tr(),
|
||||||
|
@ -66,40 +66,37 @@ class _ProfileEditScreenState extends State<ProfileEditScreen> {
|
|||||||
_locationController.text = prof.profile!.location;
|
_locationController.text = prof.profile!.location;
|
||||||
_avatar = prof.avatar;
|
_avatar = prof.avatar;
|
||||||
_banner = prof.banner;
|
_banner = prof.banner;
|
||||||
_links =
|
_links = prof.profile!.links.entries.map((ele) => (ele.key, ele.value)).toList();
|
||||||
prof.profile!.links.entries.map((ele) => (ele.key, ele.value)).toList();
|
|
||||||
_birthday = prof.profile!.birthday?.toLocal();
|
_birthday = prof.profile!.birthday?.toLocal();
|
||||||
if (_birthday != null) {
|
if (_birthday != null) {
|
||||||
_birthdayController.text =
|
_birthdayController.text = DateFormat(_kDateFormat).format(prof.profile!.birthday!.toLocal());
|
||||||
DateFormat(_kDateFormat).format(prof.profile!.birthday!.toLocal());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _selectBirthday() async {
|
void _selectBirthday() async {
|
||||||
await showCupertinoModalPopup<DateTime?>(
|
await showCupertinoModalPopup<DateTime?>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) => Container(
|
builder:
|
||||||
height: 216,
|
(BuildContext context) => Container(
|
||||||
padding: const EdgeInsets.only(top: 6.0),
|
height: 216,
|
||||||
margin:
|
padding: const EdgeInsets.only(top: 6.0),
|
||||||
EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
|
margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
|
||||||
color: Theme.of(context).colorScheme.surface,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
top: false,
|
top: false,
|
||||||
child: CupertinoDatePicker(
|
child: CupertinoDatePicker(
|
||||||
initialDateTime: _birthday?.toLocal(),
|
initialDateTime: _birthday?.toLocal(),
|
||||||
mode: CupertinoDatePickerMode.date,
|
mode: CupertinoDatePickerMode.date,
|
||||||
use24hFormat: true,
|
use24hFormat: true,
|
||||||
onDateTimeChanged: (DateTime newDate) {
|
onDateTimeChanged: (DateTime newDate) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_birthday = newDate;
|
_birthday = newDate;
|
||||||
_birthdayController.text =
|
_birthdayController.text = DateFormat(_kDateFormat).format(_birthday!);
|
||||||
DateFormat(_kDateFormat).format(_birthday!);
|
});
|
||||||
});
|
},
|
||||||
},
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,32 +109,29 @@ class _ProfileEditScreenState extends State<ProfileEditScreen> {
|
|||||||
|
|
||||||
Uint8List? rawBytes;
|
Uint8List? rawBytes;
|
||||||
if (!skipCrop) {
|
if (!skipCrop) {
|
||||||
final ImageProvider imageProvider =
|
final ImageProvider imageProvider = kIsWeb ? NetworkImage(image.path) : FileImage(File(image.path));
|
||||||
kIsWeb ? NetworkImage(image.path) : FileImage(File(image.path));
|
final aspectRatios =
|
||||||
final aspectRatios = place == 'banner'
|
place == 'banner' ? [CropAspectRatio(width: 16, height: 7)] : [CropAspectRatio(width: 1, height: 1)];
|
||||||
? [CropAspectRatio(width: 16, height: 7)]
|
final result =
|
||||||
: [CropAspectRatio(width: 1, height: 1)];
|
(!kIsWeb && (Platform.isIOS || Platform.isMacOS))
|
||||||
final result = (!kIsWeb && (Platform.isIOS || Platform.isMacOS))
|
? await showCupertinoImageCropper(
|
||||||
? await showCupertinoImageCropper(
|
// ignore: use_build_context_synchronously
|
||||||
// ignore: use_build_context_synchronously
|
context,
|
||||||
context,
|
allowedAspectRatios: aspectRatios,
|
||||||
allowedAspectRatios: aspectRatios,
|
imageProvider: imageProvider,
|
||||||
imageProvider: imageProvider,
|
)
|
||||||
)
|
: await showMaterialImageCropper(
|
||||||
: await showMaterialImageCropper(
|
// ignore: use_build_context_synchronously
|
||||||
// ignore: use_build_context_synchronously
|
context,
|
||||||
context,
|
allowedAspectRatios: aspectRatios,
|
||||||
allowedAspectRatios: aspectRatios,
|
imageProvider: imageProvider,
|
||||||
imageProvider: imageProvider,
|
);
|
||||||
);
|
|
||||||
|
|
||||||
if (result == null) return;
|
if (result == null) return;
|
||||||
|
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
setState(() => _isBusy = true);
|
setState(() => _isBusy = true);
|
||||||
rawBytes = (await result.uiImage.toByteData(format: ImageByteFormat.png))!
|
rawBytes = (await result.uiImage.toByteData(format: ImageByteFormat.png))!.buffer.asUint8List();
|
||||||
.buffer
|
|
||||||
.asUint8List();
|
|
||||||
} else {
|
} else {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
setState(() => _isBusy = true);
|
setState(() => _isBusy = true);
|
||||||
@ -158,8 +152,7 @@ class _ProfileEditScreenState extends State<ProfileEditScreen> {
|
|||||||
|
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
final sn = context.read<SnNetworkProvider>();
|
final sn = context.read<SnNetworkProvider>();
|
||||||
await sn.client
|
await sn.client.put('/cgi/id/users/me/$place', data: {'attachment': attachment.rid});
|
||||||
.put('/cgi/id/users/me/$place', data: {'attachment': attachment.rid});
|
|
||||||
|
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
final ua = context.read<UserProvider>();
|
final ua = context.read<UserProvider>();
|
||||||
@ -195,9 +188,7 @@ class _ProfileEditScreenState extends State<ProfileEditScreen> {
|
|||||||
'location': _locationController.value.text,
|
'location': _locationController.value.text,
|
||||||
'birthday': _birthday?.toUtc().toIso8601String(),
|
'birthday': _birthday?.toUtc().toIso8601String(),
|
||||||
'links': {
|
'links': {
|
||||||
for (final link in _links!
|
for (final link in _links!.where((ele) => ele.$1.isNotEmpty && ele.$2.isNotEmpty)) link.$1: link.$2,
|
||||||
.where((ele) => ele.$1.isNotEmpty && ele.$2.isNotEmpty))
|
|
||||||
link.$1: link.$2,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -244,10 +235,7 @@ class _ProfileEditScreenState extends State<ProfileEditScreen> {
|
|||||||
final sn = context.read<SnNetworkProvider>();
|
final sn = context.read<SnNetworkProvider>();
|
||||||
|
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
appBar: AppBar(leading: const PageBackButton(), title: Text('screenAccountProfileEdit').tr()),
|
||||||
appBar: AppBar(
|
|
||||||
leading: const PageBackButton(),
|
|
||||||
title: Text('screenAccountProfileEdit').tr()),
|
|
||||||
body: SingleChildScrollView(
|
body: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -265,14 +253,11 @@ class _ProfileEditScreenState extends State<ProfileEditScreen> {
|
|||||||
child: AspectRatio(
|
child: AspectRatio(
|
||||||
aspectRatio: 16 / 9,
|
aspectRatio: 16 / 9,
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Theme.of(context)
|
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||||
.colorScheme
|
child:
|
||||||
.surfaceContainerHigh,
|
_banner != null
|
||||||
child: _banner != null
|
? AutoResizeUniversalImage(sn.getAttachmentUrl(_banner!), fit: BoxFit.cover)
|
||||||
? AutoResizeUniversalImage(
|
: const SizedBox.shrink(),
|
||||||
sn.getAttachmentUrl(_banner!),
|
|
||||||
fit: BoxFit.cover)
|
|
||||||
: const SizedBox.shrink(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -309,16 +294,12 @@ class _ProfileEditScreenState extends State<ProfileEditScreen> {
|
|||||||
labelText: 'fieldUsername'.tr(),
|
labelText: 'fieldUsername'.tr(),
|
||||||
helperText: 'fieldUsernameCannotEditHint'.tr(),
|
helperText: 'fieldUsernameCannotEditHint'.tr(),
|
||||||
),
|
),
|
||||||
onTapOutside: (_) =>
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
FocusManager.instance.primaryFocus?.unfocus(),
|
|
||||||
),
|
),
|
||||||
TextField(
|
TextField(
|
||||||
controller: _nicknameController,
|
controller: _nicknameController,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(border: const UnderlineInputBorder(), labelText: 'fieldNickname'.tr()),
|
||||||
border: const UnderlineInputBorder(),
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
labelText: 'fieldNickname'.tr()),
|
|
||||||
onTapOutside: (_) =>
|
|
||||||
FocusManager.instance.primaryFocus?.unfocus(),
|
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
@ -330,8 +311,7 @@ class _ProfileEditScreenState extends State<ProfileEditScreen> {
|
|||||||
border: const UnderlineInputBorder(),
|
border: const UnderlineInputBorder(),
|
||||||
labelText: 'fieldFirstName'.tr(),
|
labelText: 'fieldFirstName'.tr(),
|
||||||
),
|
),
|
||||||
onTapOutside: (_) =>
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
FocusManager.instance.primaryFocus?.unfocus(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
@ -343,8 +323,7 @@ class _ProfileEditScreenState extends State<ProfileEditScreen> {
|
|||||||
border: const UnderlineInputBorder(),
|
border: const UnderlineInputBorder(),
|
||||||
labelText: 'fieldLastName'.tr(),
|
labelText: 'fieldLastName'.tr(),
|
||||||
),
|
),
|
||||||
onTapOutside: (_) =>
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
FocusManager.instance.primaryFocus?.unfocus(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -359,8 +338,7 @@ class _ProfileEditScreenState extends State<ProfileEditScreen> {
|
|||||||
border: const UnderlineInputBorder(),
|
border: const UnderlineInputBorder(),
|
||||||
labelText: 'fieldGender'.tr(),
|
labelText: 'fieldGender'.tr(),
|
||||||
),
|
),
|
||||||
onTapOutside: (_) =>
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
FocusManager.instance.primaryFocus?.unfocus(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Gap(4),
|
const Gap(4),
|
||||||
@ -372,8 +350,7 @@ class _ProfileEditScreenState extends State<ProfileEditScreen> {
|
|||||||
border: const UnderlineInputBorder(),
|
border: const UnderlineInputBorder(),
|
||||||
labelText: 'fieldPronouns'.tr(),
|
labelText: 'fieldPronouns'.tr(),
|
||||||
),
|
),
|
||||||
onTapOutside: (_) =>
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
FocusManager.instance.primaryFocus?.unfocus(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -383,11 +360,8 @@ class _ProfileEditScreenState extends State<ProfileEditScreen> {
|
|||||||
keyboardType: TextInputType.multiline,
|
keyboardType: TextInputType.multiline,
|
||||||
maxLines: null,
|
maxLines: null,
|
||||||
minLines: 3,
|
minLines: 3,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(border: const UnderlineInputBorder(), labelText: 'fieldDescription'.tr()),
|
||||||
border: const UnderlineInputBorder(),
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
labelText: 'fieldDescription'.tr()),
|
|
||||||
onTapOutside: (_) =>
|
|
||||||
FocusManager.instance.primaryFocus?.unfocus(),
|
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
@ -399,21 +373,18 @@ class _ProfileEditScreenState extends State<ProfileEditScreen> {
|
|||||||
border: const UnderlineInputBorder(),
|
border: const UnderlineInputBorder(),
|
||||||
labelText: 'fieldTimeZone'.tr(),
|
labelText: 'fieldTimeZone'.tr(),
|
||||||
),
|
),
|
||||||
onTapOutside: (_) =>
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
FocusManager.instance.primaryFocus?.unfocus(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Gap(4),
|
const Gap(4),
|
||||||
StyledWidget(
|
StyledWidget(
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Symbols.calendar_month),
|
icon: const Icon(Symbols.calendar_month),
|
||||||
visualDensity:
|
visualDensity: VisualDensity(horizontal: -4, vertical: -4),
|
||||||
VisualDensity(horizontal: -4, vertical: -4),
|
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
constraints: const BoxConstraints(),
|
constraints: const BoxConstraints(),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
_timezoneController.text =
|
_timezoneController.text = await FlutterTimezone.getLocalTimezone();
|
||||||
await FlutterTimezone.getLocalTimezone();
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
).padding(top: 6),
|
).padding(top: 6),
|
||||||
@ -421,8 +392,7 @@ class _ProfileEditScreenState extends State<ProfileEditScreen> {
|
|||||||
StyledWidget(
|
StyledWidget(
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Symbols.clear),
|
icon: const Icon(Symbols.clear),
|
||||||
visualDensity:
|
visualDensity: VisualDensity(horizontal: -4, vertical: -4),
|
||||||
VisualDensity(horizontal: -4, vertical: -4),
|
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
constraints: const BoxConstraints(),
|
constraints: const BoxConstraints(),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@ -434,18 +404,13 @@ class _ProfileEditScreenState extends State<ProfileEditScreen> {
|
|||||||
),
|
),
|
||||||
TextField(
|
TextField(
|
||||||
controller: _locationController,
|
controller: _locationController,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(border: const UnderlineInputBorder(), labelText: 'fieldLocation'.tr()),
|
||||||
border: const UnderlineInputBorder(),
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
labelText: 'fieldLocation'.tr()),
|
|
||||||
onTapOutside: (_) =>
|
|
||||||
FocusManager.instance.primaryFocus?.unfocus(),
|
|
||||||
),
|
),
|
||||||
TextField(
|
TextField(
|
||||||
controller: _birthdayController,
|
controller: _birthdayController,
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(border: const UnderlineInputBorder(), labelText: 'fieldBirthday'.tr()),
|
||||||
border: const UnderlineInputBorder(),
|
|
||||||
labelText: 'fieldBirthday'.tr()),
|
|
||||||
onTap: () => _selectBirthday(),
|
onTap: () => _selectBirthday(),
|
||||||
),
|
),
|
||||||
if (_links != null)
|
if (_links != null)
|
||||||
@ -453,8 +418,7 @@ class _ProfileEditScreenState extends State<ProfileEditScreen> {
|
|||||||
margin: const EdgeInsets.only(top: 16, bottom: 4),
|
margin: const EdgeInsets.only(top: 16, bottom: 4),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||||
horizontal: 16, vertical: 8),
|
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -463,17 +427,13 @@ class _ProfileEditScreenState extends State<ProfileEditScreen> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
'fieldLinks'.tr(),
|
'fieldLinks'.tr(),
|
||||||
style: Theme.of(context)
|
style: Theme.of(context).textTheme.titleMedium!.copyWith(fontSize: 17),
|
||||||
.textTheme
|
|
||||||
.titleMedium!
|
|
||||||
.copyWith(fontSize: 17),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
constraints: const BoxConstraints(),
|
constraints: const BoxConstraints(),
|
||||||
visualDensity:
|
visualDensity: VisualDensity(horizontal: -4, vertical: -4),
|
||||||
VisualDensity(horizontal: -4, vertical: -4),
|
|
||||||
icon: const Icon(Symbols.add),
|
icon: const Icon(Symbols.add),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() => _links!.add(('', '')));
|
setState(() => _links!.add(('', '')));
|
||||||
@ -497,9 +457,7 @@ class _ProfileEditScreenState extends State<ProfileEditScreen> {
|
|||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
_links![idx] = (value, _links![idx].$2);
|
_links![idx] = (value, _links![idx].$2);
|
||||||
},
|
},
|
||||||
onTapOutside: (_) => FocusManager
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
.instance.primaryFocus
|
|
||||||
?.unfocus(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
@ -515,9 +473,7 @@ class _ProfileEditScreenState extends State<ProfileEditScreen> {
|
|||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
_links![idx] = (_links![idx].$1, value);
|
_links![idx] = (_links![idx].$1, value);
|
||||||
},
|
},
|
||||||
onTapOutside: (_) => FocusManager
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
.instance.primaryFocus
|
|
||||||
?.unfocus(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -70,7 +70,6 @@ class _AccountProgramScreenState extends State<AccountProgramScreen> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('accountProgram').tr(),
|
title: Text('accountProgram').tr(),
|
||||||
),
|
),
|
||||||
|
@ -27,12 +27,10 @@ class AccountPublisherEditScreen extends StatefulWidget {
|
|||||||
const AccountPublisherEditScreen({super.key, required this.name});
|
const AccountPublisherEditScreen({super.key, required this.name});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AccountPublisherEditScreen> createState() =>
|
State<AccountPublisherEditScreen> createState() => _AccountPublisherEditScreenState();
|
||||||
_AccountPublisherEditScreenState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AccountPublisherEditScreenState
|
class _AccountPublisherEditScreenState extends State<AccountPublisherEditScreen> {
|
||||||
extends State<AccountPublisherEditScreen> {
|
|
||||||
bool _isBusy = false;
|
bool _isBusy = false;
|
||||||
|
|
||||||
SnPublisher? _publisher;
|
SnPublisher? _publisher;
|
||||||
@ -117,32 +115,29 @@ class _AccountPublisherEditScreenState
|
|||||||
|
|
||||||
Uint8List? rawBytes;
|
Uint8List? rawBytes;
|
||||||
if (!skipCrop) {
|
if (!skipCrop) {
|
||||||
final ImageProvider imageProvider =
|
final ImageProvider imageProvider = kIsWeb ? NetworkImage(image.path) : FileImage(File(image.path));
|
||||||
kIsWeb ? NetworkImage(image.path) : FileImage(File(image.path));
|
final aspectRatios =
|
||||||
final aspectRatios = place == 'banner'
|
place == 'banner' ? [CropAspectRatio(width: 16, height: 7)] : [CropAspectRatio(width: 1, height: 1)];
|
||||||
? [CropAspectRatio(width: 16, height: 7)]
|
final result =
|
||||||
: [CropAspectRatio(width: 1, height: 1)];
|
(!kIsWeb && (Platform.isIOS || Platform.isMacOS))
|
||||||
final result = (!kIsWeb && (Platform.isIOS || Platform.isMacOS))
|
? await showCupertinoImageCropper(
|
||||||
? await showCupertinoImageCropper(
|
// ignore: use_build_context_synchronously
|
||||||
// ignore: use_build_context_synchronously
|
context,
|
||||||
context,
|
allowedAspectRatios: aspectRatios,
|
||||||
allowedAspectRatios: aspectRatios,
|
imageProvider: imageProvider,
|
||||||
imageProvider: imageProvider,
|
)
|
||||||
)
|
: await showMaterialImageCropper(
|
||||||
: await showMaterialImageCropper(
|
// ignore: use_build_context_synchronously
|
||||||
// ignore: use_build_context_synchronously
|
context,
|
||||||
context,
|
allowedAspectRatios: aspectRatios,
|
||||||
allowedAspectRatios: aspectRatios,
|
imageProvider: imageProvider,
|
||||||
imageProvider: imageProvider,
|
);
|
||||||
);
|
|
||||||
|
|
||||||
if (result == null) return;
|
if (result == null) return;
|
||||||
|
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
setState(() => _isBusy = true);
|
setState(() => _isBusy = true);
|
||||||
rawBytes = (await result.uiImage.toByteData(format: ImageByteFormat.png))!
|
rawBytes = (await result.uiImage.toByteData(format: ImageByteFormat.png))!.buffer.asUint8List();
|
||||||
.buffer
|
|
||||||
.asUint8List();
|
|
||||||
} else {
|
} else {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
setState(() => _isBusy = true);
|
setState(() => _isBusy = true);
|
||||||
@ -196,10 +191,7 @@ class _AccountPublisherEditScreenState
|
|||||||
final sn = context.read<SnNetworkProvider>();
|
final sn = context.read<SnNetworkProvider>();
|
||||||
|
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
appBar: AppBar(leading: PageBackButton(), title: Text('screenAccountPublisherEdit').tr()),
|
||||||
appBar: AppBar(
|
|
||||||
leading: PageBackButton(),
|
|
||||||
title: Text('screenAccountPublisherEdit').tr()),
|
|
||||||
body: SingleChildScrollView(
|
body: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
@ -216,14 +208,11 @@ class _AccountPublisherEditScreenState
|
|||||||
child: AspectRatio(
|
child: AspectRatio(
|
||||||
aspectRatio: 16 / 9,
|
aspectRatio: 16 / 9,
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Theme.of(context)
|
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||||
.colorScheme
|
child:
|
||||||
.surfaceContainerHigh,
|
_banner != null
|
||||||
child: _banner != null
|
? AutoResizeUniversalImage(sn.getAttachmentUrl(_banner!), fit: BoxFit.cover)
|
||||||
? AutoResizeUniversalImage(
|
: const SizedBox.shrink(),
|
||||||
sn.getAttachmentUrl(_banner!),
|
|
||||||
fit: BoxFit.cover)
|
|
||||||
: const SizedBox.shrink(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -256,15 +245,13 @@ class _AccountPublisherEditScreenState
|
|||||||
labelText: 'fieldUsername'.tr(),
|
labelText: 'fieldUsername'.tr(),
|
||||||
helperText: 'fieldUsernameCannotEditHint'.tr(),
|
helperText: 'fieldUsernameCannotEditHint'.tr(),
|
||||||
),
|
),
|
||||||
onTapOutside: (_) =>
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
FocusManager.instance.primaryFocus?.unfocus(),
|
|
||||||
),
|
),
|
||||||
const Gap(4),
|
const Gap(4),
|
||||||
TextField(
|
TextField(
|
||||||
controller: _nickController,
|
controller: _nickController,
|
||||||
decoration: InputDecoration(labelText: 'fieldNickname'.tr()),
|
decoration: InputDecoration(labelText: 'fieldNickname'.tr()),
|
||||||
onTapOutside: (_) =>
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
FocusManager.instance.primaryFocus?.unfocus(),
|
|
||||||
),
|
),
|
||||||
const Gap(4),
|
const Gap(4),
|
||||||
TextField(
|
TextField(
|
||||||
@ -272,8 +259,7 @@ class _AccountPublisherEditScreenState
|
|||||||
maxLines: null,
|
maxLines: null,
|
||||||
minLines: 3,
|
minLines: 3,
|
||||||
decoration: InputDecoration(labelText: 'fieldDescription'.tr()),
|
decoration: InputDecoration(labelText: 'fieldDescription'.tr()),
|
||||||
onTapOutside: (_) =>
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
FocusManager.instance.primaryFocus?.unfocus(),
|
|
||||||
),
|
),
|
||||||
const Gap(12),
|
const Gap(12),
|
||||||
Row(
|
Row(
|
||||||
|
@ -25,8 +25,7 @@ class _AccountPublisherNewScreenState extends State<AccountPublisherNewScreen> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: const PageBackButton(),
|
leading: const PageBackButton(),
|
||||||
title: Text('screenAccountPublisherNew').tr(),
|
title: Text('screenAccountPublisherNew').tr(),
|
||||||
|
@ -33,8 +33,7 @@ class _PublisherScreenState extends State<PublisherScreen> {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
final resp = await sn.client.get('/cgi/co/publishers/me');
|
final resp = await sn.client.get('/cgi/co/publishers/me');
|
||||||
final List<SnPublisher> out = List<SnPublisher>.from(
|
final List<SnPublisher> out = List<SnPublisher>.from(resp.data?.map((e) => SnPublisher.fromJson(e)) ?? []);
|
||||||
resp.data?.map((e) => SnPublisher.fromJson(e)) ?? []);
|
|
||||||
|
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
|
|
||||||
@ -82,7 +81,6 @@ class _PublisherScreenState extends State<PublisherScreen> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: const PageBackButton(),
|
leading: const PageBackButton(),
|
||||||
title: Text('screenAccountPublishers').tr(),
|
title: Text('screenAccountPublishers').tr(),
|
||||||
@ -95,9 +93,7 @@ class _PublisherScreenState extends State<PublisherScreen> {
|
|||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
leading: const Icon(Symbols.add_circle),
|
leading: const Icon(Symbols.add_circle),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
GoRouter.of(context)
|
GoRouter.of(context).pushNamed('accountPublisherNew').then((value) {
|
||||||
.pushNamed('accountPublisherNew')
|
|
||||||
.then((value) {
|
|
||||||
if (value == true) {
|
if (value == true) {
|
||||||
_publishers.clear();
|
_publishers.clear();
|
||||||
_fetchPublishers();
|
_fetchPublishers();
|
||||||
@ -123,8 +119,7 @@ class _PublisherScreenState extends State<PublisherScreen> {
|
|||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(publisher.nick),
|
title: Text(publisher.nick),
|
||||||
subtitle: Text('@${publisher.name}'),
|
subtitle: Text('@${publisher.name}'),
|
||||||
contentPadding:
|
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
const EdgeInsets.symmetric(horizontal: 16),
|
|
||||||
leading: AccountImage(content: publisher.avatar),
|
leading: AccountImage(content: publisher.avatar),
|
||||||
trailing: PopupMenuButton(
|
trailing: PopupMenuButton(
|
||||||
itemBuilder: (BuildContext context) => [
|
itemBuilder: (BuildContext context) => [
|
||||||
|
@ -55,7 +55,6 @@ class _PunishmentsScreenState extends State<PunishmentsScreen> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('accountPunishments').tr(),
|
title: Text('accountPunishments').tr(),
|
||||||
leading: PageBackButton(),
|
leading: PageBackButton(),
|
||||||
|
@ -37,7 +37,6 @@ class AccountSettingsScreen extends StatelessWidget {
|
|||||||
final ua = context.watch<UserProvider>();
|
final ua = context.watch<UserProvider>();
|
||||||
|
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: PageBackButton(),
|
leading: PageBackButton(),
|
||||||
title: Text('screenAccountSettings').tr(),
|
title: Text('screenAccountSettings').tr(),
|
||||||
|
@ -6,16 +6,19 @@ import 'package:go_router/go_router.dart';
|
|||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:responsive_framework/responsive_framework.dart';
|
||||||
import 'package:surface/providers/channel.dart';
|
import 'package:surface/providers/channel.dart';
|
||||||
import 'package:surface/providers/sn_network.dart';
|
import 'package:surface/providers/sn_network.dart';
|
||||||
import 'package:surface/providers/user_directory.dart';
|
import 'package:surface/providers/user_directory.dart';
|
||||||
import 'package:surface/providers/userinfo.dart';
|
import 'package:surface/providers/userinfo.dart';
|
||||||
|
import 'package:surface/screens/chat/room.dart';
|
||||||
import 'package:surface/types/chat.dart';
|
import 'package:surface/types/chat.dart';
|
||||||
import 'package:surface/widgets/account/account_image.dart';
|
import 'package:surface/widgets/account/account_image.dart';
|
||||||
import 'package:surface/widgets/account/account_select.dart';
|
import 'package:surface/widgets/account/account_select.dart';
|
||||||
import 'package:surface/widgets/app_bar_leading.dart';
|
import 'package:surface/widgets/app_bar_leading.dart';
|
||||||
import 'package:surface/widgets/dialog.dart';
|
import 'package:surface/widgets/dialog.dart';
|
||||||
import 'package:surface/widgets/loading_indicator.dart';
|
import 'package:surface/widgets/loading_indicator.dart';
|
||||||
|
import 'package:surface/widgets/navigation/app_background.dart';
|
||||||
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
||||||
import 'package:surface/widgets/unauthorized_hint.dart';
|
import 'package:surface/widgets/unauthorized_hint.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
@ -127,6 +130,8 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SnChannel? _focusChannel;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -135,8 +140,13 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _onTapChannel(SnChannel channel) {
|
void _onTapChannel(SnChannel channel) {
|
||||||
setState(() => _unreadCounts?[channel.id] = 0);
|
final doExpand = ResponsiveBreakpoints.of(context).largerOrEqualTo(DESKTOP);
|
||||||
GoRouter.of(context).pushReplacementNamed(
|
|
||||||
|
if (doExpand) {
|
||||||
|
setState(() => _focusChannel = channel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GoRouter.of(context).pushNamed(
|
||||||
'chatRoom',
|
'chatRoom',
|
||||||
pathParameters: {
|
pathParameters: {
|
||||||
'scope': channel.realm?.alias ?? 'global',
|
'scope': channel.realm?.alias ?? 'global',
|
||||||
@ -144,6 +154,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
},
|
},
|
||||||
).then((value) {
|
).then((value) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
|
_unreadCounts?[channel.id] = 0;
|
||||||
setState(() => _unreadCounts?[channel.id] = 0);
|
setState(() => _unreadCounts?[channel.id] = 0);
|
||||||
_refreshChannels(noRemote: true);
|
_refreshChannels(noRemote: true);
|
||||||
}
|
}
|
||||||
@ -166,8 +177,10 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return AppScaffold(
|
final doExpand = ResponsiveBreakpoints.of(context).largerOrEqualTo(DESKTOP);
|
||||||
noBackground: true,
|
|
||||||
|
final chatList = AppScaffold(
|
||||||
|
noBackground: doExpand,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: AutoAppBarLeading(),
|
leading: AutoAppBarLeading(),
|
||||||
title: Text('screenChat').tr(),
|
title: Text('screenChat').tr(),
|
||||||
@ -255,6 +268,11 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
lastMessage: lastMessage,
|
lastMessage: lastMessage,
|
||||||
unreadCount: _unreadCounts?[channel.id],
|
unreadCount: _unreadCounts?[channel.id],
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
if (doExpand) {
|
||||||
|
_unreadCounts?[channel.id] = 0;
|
||||||
|
setState(() => _focusChannel = channel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
_onTapChannel(channel);
|
_onTapChannel(channel);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -266,6 +284,28 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (doExpand) {
|
||||||
|
return AppBackground(
|
||||||
|
isRoot: true,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(width: 340, child: chatList),
|
||||||
|
const VerticalDivider(width: 1),
|
||||||
|
if (_focusChannel != null)
|
||||||
|
Expanded(
|
||||||
|
child: ChatRoomScreen(
|
||||||
|
key: ValueKey(_focusChannel!.id),
|
||||||
|
scope: _focusChannel!.realm?.alias ?? 'global',
|
||||||
|
alias: _focusChannel!.alias,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return chatList;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,8 +37,7 @@ class _CallRoomScreenState extends State<CallRoomScreen> {
|
|||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
color:
|
color: Theme.of(context).colorScheme.surfaceContainer.withOpacity(0.75),
|
||||||
Theme.of(context).colorScheme.surfaceContainer.withOpacity(0.75),
|
|
||||||
child: call.focusTrack != null
|
child: call.focusTrack != null
|
||||||
? InteractiveParticipantWidget(
|
? InteractiveParticipantWidget(
|
||||||
isFixedAvatar: false,
|
isFixedAvatar: false,
|
||||||
@ -73,8 +72,7 @@ class _CallRoomScreenState extends State<CallRoomScreen> {
|
|||||||
color: Theme.of(context).cardColor,
|
color: Theme.of(context).cardColor,
|
||||||
participant: track,
|
participant: track,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (track.participant.sid !=
|
if (track.participant.sid != call.focusTrack?.participant.sid) {
|
||||||
call.focusTrack?.participant.sid) {
|
|
||||||
call.setFocusTrack(track);
|
call.setFocusTrack(track);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -116,14 +114,10 @@ class _CallRoomScreenState extends State<CallRoomScreen> {
|
|||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||||
child: InteractiveParticipantWidget(
|
child: InteractiveParticipantWidget(
|
||||||
color: Theme.of(context)
|
color: Theme.of(context).colorScheme.surfaceContainerHigh.withOpacity(0.75),
|
||||||
.colorScheme
|
|
||||||
.surfaceContainerHigh
|
|
||||||
.withOpacity(0.75),
|
|
||||||
participant: track,
|
participant: track,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (track.participant.sid !=
|
if (track.participant.sid != call.focusTrack?.participant.sid) {
|
||||||
call.focusTrack?.participant.sid) {
|
|
||||||
call.setFocusTrack(track);
|
call.setFocusTrack(track);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -155,7 +149,6 @@ class _CallRoomScreenState extends State<CallRoomScreen> {
|
|||||||
listenable: call,
|
listenable: call,
|
||||||
builder: (context, _) {
|
builder: (context, _) {
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: RichText(
|
title: RichText(
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
@ -190,8 +183,7 @@ class _CallRoomScreenState extends State<CallRoomScreen> {
|
|||||||
Builder(builder: (context) {
|
Builder(builder: (context) {
|
||||||
final call = context.read<ChatCallProvider>();
|
final call = context.read<ChatCallProvider>();
|
||||||
final connectionQuality =
|
final connectionQuality =
|
||||||
call.room.localParticipant?.connectionQuality ??
|
call.room.localParticipant?.connectionQuality ?? livekit.ConnectionQuality.unknown;
|
||||||
livekit.ConnectionQuality.unknown;
|
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
@ -213,35 +205,24 @@ class _CallRoomScreenState extends State<CallRoomScreen> {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
{
|
{
|
||||||
livekit.ConnectionState.disconnected:
|
livekit.ConnectionState.disconnected: 'callStatusDisconnected'.tr(),
|
||||||
'callStatusDisconnected'.tr(),
|
livekit.ConnectionState.connected: 'callStatusConnected'.tr(),
|
||||||
livekit.ConnectionState.connected:
|
livekit.ConnectionState.connecting: 'callStatusConnecting'.tr(),
|
||||||
'callStatusConnected'.tr(),
|
livekit.ConnectionState.reconnecting: 'callStatusReconnecting'.tr(),
|
||||||
livekit.ConnectionState.connecting:
|
|
||||||
'callStatusConnecting'.tr(),
|
|
||||||
livekit.ConnectionState.reconnecting:
|
|
||||||
'callStatusReconnecting'.tr(),
|
|
||||||
}[call.room.connectionState]!,
|
}[call.room.connectionState]!,
|
||||||
),
|
),
|
||||||
const Gap(6),
|
const Gap(6),
|
||||||
if (connectionQuality !=
|
if (connectionQuality != livekit.ConnectionQuality.unknown)
|
||||||
livekit.ConnectionQuality.unknown)
|
|
||||||
Icon(
|
Icon(
|
||||||
{
|
{
|
||||||
livekit.ConnectionQuality.excellent:
|
livekit.ConnectionQuality.excellent: Icons.signal_cellular_alt,
|
||||||
Icons.signal_cellular_alt,
|
livekit.ConnectionQuality.good: Icons.signal_cellular_alt_2_bar,
|
||||||
livekit.ConnectionQuality.good:
|
livekit.ConnectionQuality.poor: Icons.signal_cellular_alt_1_bar,
|
||||||
Icons.signal_cellular_alt_2_bar,
|
|
||||||
livekit.ConnectionQuality.poor:
|
|
||||||
Icons.signal_cellular_alt_1_bar,
|
|
||||||
}[connectionQuality],
|
}[connectionQuality],
|
||||||
color: {
|
color: {
|
||||||
livekit.ConnectionQuality.excellent:
|
livekit.ConnectionQuality.excellent: Colors.green,
|
||||||
Colors.green,
|
livekit.ConnectionQuality.good: Colors.orange,
|
||||||
livekit.ConnectionQuality.good:
|
livekit.ConnectionQuality.poor: Colors.red,
|
||||||
Colors.orange,
|
|
||||||
livekit.ConnectionQuality.poor:
|
|
||||||
Colors.red,
|
|
||||||
}[connectionQuality],
|
}[connectionQuality],
|
||||||
size: 16,
|
size: 16,
|
||||||
)
|
)
|
||||||
@ -263,9 +244,7 @@ class _CallRoomScreenState extends State<CallRoomScreen> {
|
|||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: _layoutMode == 0
|
icon: _layoutMode == 0 ? const Icon(Icons.view_list) : const Icon(Icons.grid_view),
|
||||||
? const Icon(Icons.view_list)
|
|
||||||
: const Icon(Icons.grid_view),
|
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_switchLayout();
|
_switchLayout();
|
||||||
},
|
},
|
||||||
|
@ -220,7 +220,6 @@ class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
|
|||||||
final isOwned = ua.isAuthorized && _channel?.accountId == ua.user?.id;
|
final isOwned = ua.isAuthorized && _channel?.accountId == ua.user?.id;
|
||||||
|
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: _channel != null ? Text(_channel!.name) : Text('loading').tr(),
|
title: _channel != null ? Text(_channel!.name) : Text('loading').tr(),
|
||||||
),
|
),
|
||||||
|
@ -49,8 +49,7 @@ class _ChatManageScreenState extends State<ChatManageScreen> {
|
|||||||
resp.data?.map((e) => SnRealm.fromJson(e)) ?? [],
|
resp.data?.map((e) => SnRealm.fromJson(e)) ?? [],
|
||||||
);
|
);
|
||||||
if (_editingChannel != null) {
|
if (_editingChannel != null) {
|
||||||
_belongToRealm =
|
_belongToRealm = _realms?.firstWhereOrNull((e) => e.id == _editingChannel!.realmId);
|
||||||
_realms?.firstWhereOrNull((e) => e.id == _editingChannel!.realmId);
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (mounted) context.showErrorDialog(err);
|
if (mounted) context.showErrorDialog(err);
|
||||||
@ -98,8 +97,7 @@ class _ChatManageScreenState extends State<ChatManageScreen> {
|
|||||||
'is_community': _isCommunity,
|
'is_community': _isCommunity,
|
||||||
if (_editingChannel != null && _belongToRealm == null)
|
if (_editingChannel != null && _belongToRealm == null)
|
||||||
'new_belongs_realm': 'global'
|
'new_belongs_realm': 'global'
|
||||||
else if (_editingChannel != null &&
|
else if (_editingChannel != null && _belongToRealm?.id != _editingChannel?.realm?.id)
|
||||||
_belongToRealm?.id != _editingChannel?.realm?.id)
|
|
||||||
'new_belongs_realm': _belongToRealm!.alias,
|
'new_belongs_realm': _belongToRealm!.alias,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -141,11 +139,8 @@ class _ChatManageScreenState extends State<ChatManageScreen> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: widget.editingChannelAlias != null
|
title: widget.editingChannelAlias != null ? Text('screenChatManage').tr() : Text('screenChatNew').tr(),
|
||||||
? Text('screenChatManage').tr()
|
|
||||||
: Text('screenChatNew').tr(),
|
|
||||||
),
|
),
|
||||||
body: SingleChildScrollView(
|
body: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -157,8 +152,7 @@ class _ChatManageScreenState extends State<ChatManageScreen> {
|
|||||||
leadingPadding: const EdgeInsets.only(left: 10, right: 20),
|
leadingPadding: const EdgeInsets.only(left: 10, right: 20),
|
||||||
dividerColor: Colors.transparent,
|
dividerColor: Colors.transparent,
|
||||||
content: Text(
|
content: Text(
|
||||||
'channelEditingNotice'
|
'channelEditingNotice'.tr(args: ['#${_editingChannel!.alias}']),
|
||||||
.tr(args: ['#${_editingChannel!.alias}']),
|
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
@ -198,15 +192,12 @@ class _ChatManageScreenState extends State<ChatManageScreen> {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(item.name).textStyle(Theme.of(context)
|
Text(item.name).textStyle(Theme.of(context).textTheme.bodyMedium!),
|
||||||
.textTheme
|
|
||||||
.bodyMedium!),
|
|
||||||
Text(
|
Text(
|
||||||
item.description,
|
item.description,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
).textStyle(
|
).textStyle(Theme.of(context).textTheme.bodySmall!),
|
||||||
Theme.of(context).textTheme.bodySmall!),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -222,8 +213,7 @@ class _ChatManageScreenState extends State<ChatManageScreen> {
|
|||||||
CircleAvatar(
|
CircleAvatar(
|
||||||
radius: 16,
|
radius: 16,
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
foregroundColor:
|
foregroundColor: Theme.of(context).colorScheme.onSurface,
|
||||||
Theme.of(context).colorScheme.onSurface,
|
|
||||||
child: const Icon(Symbols.clear),
|
child: const Icon(Symbols.clear),
|
||||||
),
|
),
|
||||||
const Gap(12),
|
const Gap(12),
|
||||||
@ -232,9 +222,7 @@ class _ChatManageScreenState extends State<ChatManageScreen> {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text('fieldChatBelongToRealmUnset')
|
Text('fieldChatBelongToRealmUnset').tr().textStyle(
|
||||||
.tr()
|
|
||||||
.textStyle(
|
|
||||||
Theme.of(context).textTheme.bodyMedium!,
|
Theme.of(context).textTheme.bodyMedium!,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -269,8 +257,7 @@ class _ChatManageScreenState extends State<ChatManageScreen> {
|
|||||||
helperText: 'fieldChatAliasHint'.tr(),
|
helperText: 'fieldChatAliasHint'.tr(),
|
||||||
helperMaxLines: 2,
|
helperMaxLines: 2,
|
||||||
),
|
),
|
||||||
onTapOutside: (_) =>
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
FocusManager.instance.primaryFocus?.unfocus(),
|
|
||||||
),
|
),
|
||||||
const Gap(4),
|
const Gap(4),
|
||||||
TextField(
|
TextField(
|
||||||
@ -279,8 +266,7 @@ class _ChatManageScreenState extends State<ChatManageScreen> {
|
|||||||
border: const UnderlineInputBorder(),
|
border: const UnderlineInputBorder(),
|
||||||
labelText: 'fieldChatName'.tr(),
|
labelText: 'fieldChatName'.tr(),
|
||||||
),
|
),
|
||||||
onTapOutside: (_) =>
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
FocusManager.instance.primaryFocus?.unfocus(),
|
|
||||||
),
|
),
|
||||||
const Gap(4),
|
const Gap(4),
|
||||||
TextField(
|
TextField(
|
||||||
@ -291,8 +277,7 @@ class _ChatManageScreenState extends State<ChatManageScreen> {
|
|||||||
border: const UnderlineInputBorder(),
|
border: const UnderlineInputBorder(),
|
||||||
labelText: 'fieldChatDescription'.tr(),
|
labelText: 'fieldChatDescription'.tr(),
|
||||||
),
|
),
|
||||||
onTapOutside: (_) =>
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
FocusManager.instance.primaryFocus?.unfocus(),
|
|
||||||
),
|
),
|
||||||
const Gap(12),
|
const Gap(12),
|
||||||
CheckboxListTile(
|
CheckboxListTile(
|
||||||
|
@ -304,7 +304,6 @@ class _ChatRoomScreenState extends State<ChatRoomScreen> {
|
|||||||
final ud = context.read<UserDirectoryProvider>();
|
final ud = context.read<UserDirectoryProvider>();
|
||||||
|
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(
|
title: Text(
|
||||||
_channel?.type == 1
|
_channel?.type == 1
|
||||||
|
@ -157,7 +157,6 @@ class _ExploreScreenState extends State<ExploreScreen>
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final cfg = context.watch<ConfigProvider>();
|
final cfg = context.watch<ConfigProvider>();
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
|
||||||
floatingActionButtonLocation: ExpandableFab.location,
|
floatingActionButtonLocation: ExpandableFab.location,
|
||||||
floatingActionButton: ExpandableFab(
|
floatingActionButton: ExpandableFab(
|
||||||
key: _fabKey,
|
key: _fabKey,
|
||||||
@ -244,7 +243,6 @@ class _ExploreScreenState extends State<ExploreScreen>
|
|||||||
GoRouter.of(context).pushNamed('postShuffle');
|
GoRouter.of(context).pushNamed('postShuffle');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const Gap(48),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
@ -536,7 +534,6 @@ class _PostListWidgetState extends State<_PostListWidget> {
|
|||||||
switch (ele.type) {
|
switch (ele.type) {
|
||||||
case 'interactive.post':
|
case 'interactive.post':
|
||||||
return OpenablePostItem(
|
return OpenablePostItem(
|
||||||
useReplace: true,
|
|
||||||
data: SnPost.fromJson(ele.data),
|
data: SnPost.fromJson(ele.data),
|
||||||
maxWidth: 640,
|
maxWidth: 640,
|
||||||
onChanged: (data) {
|
onChanged: (data) {
|
||||||
|
@ -12,6 +12,7 @@ import 'package:surface/providers/userinfo.dart';
|
|||||||
import 'package:surface/types/post.dart';
|
import 'package:surface/types/post.dart';
|
||||||
import 'package:surface/widgets/dialog.dart';
|
import 'package:surface/widgets/dialog.dart';
|
||||||
import 'package:surface/widgets/loading_indicator.dart';
|
import 'package:surface/widgets/loading_indicator.dart';
|
||||||
|
import 'package:surface/widgets/navigation/app_background.dart';
|
||||||
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
||||||
import 'package:surface/widgets/post/post_comment_list.dart';
|
import 'package:surface/widgets/post/post_comment_list.dart';
|
||||||
import 'package:surface/widgets/post/post_item.dart';
|
import 'package:surface/widgets/post/post_item.dart';
|
||||||
@ -65,111 +66,115 @@ class _PostDetailScreenState extends State<PostDetailScreen> {
|
|||||||
|
|
||||||
final double maxWidth = _data?.type == 'video' ? double.infinity : 640;
|
final double maxWidth = _data?.type == 'video' ? double.infinity : 640;
|
||||||
|
|
||||||
return AppScaffold(
|
return AppBackground(
|
||||||
noBackground: true,
|
isRoot: widget.onBack != null,
|
||||||
appBar: AppBar(
|
child: AppScaffold(
|
||||||
leading: BackButton(
|
appBar: AppBar(
|
||||||
onPressed: () {
|
leading: BackButton(
|
||||||
if (widget.onBack != null) {
|
onPressed: () {
|
||||||
widget.onBack!.call();
|
if (widget.onBack != null) {
|
||||||
}
|
widget.onBack!.call();
|
||||||
if (GoRouter.of(context).canPop()) {
|
}
|
||||||
GoRouter.of(context).pop(context);
|
if (GoRouter.of(context).canPop()) {
|
||||||
return;
|
GoRouter.of(context).pop(context);
|
||||||
}
|
return;
|
||||||
GoRouter.of(context).replaceNamed('explore');
|
}
|
||||||
},
|
GoRouter.of(context).replaceNamed('explore');
|
||||||
),
|
},
|
||||||
title: _data?.body['title'] != null
|
|
||||||
? RichText(
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
text: TextSpan(children: [
|
|
||||||
TextSpan(
|
|
||||||
text: _data?.body['title'] ?? 'postNoun'.tr(),
|
|
||||||
style: Theme.of(context).textTheme.titleLarge!.copyWith(
|
|
||||||
color: Theme.of(context).appBarTheme.foregroundColor!,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const TextSpan(text: '\n'),
|
|
||||||
TextSpan(
|
|
||||||
text: 'postDetail'.tr(),
|
|
||||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
|
||||||
color: Theme.of(context).appBarTheme.foregroundColor!,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
maxLines: 2,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
)
|
|
||||||
: Text('postDetail').tr(),
|
|
||||||
),
|
|
||||||
body: CustomScrollView(
|
|
||||||
slivers: [
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: LoadingIndicator(isActive: _isBusy),
|
|
||||||
),
|
),
|
||||||
if (_data != null)
|
title: _data?.body['title'] != null
|
||||||
|
? RichText(
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
text: TextSpan(children: [
|
||||||
|
TextSpan(
|
||||||
|
text: _data?.body['title'] ?? 'postNoun'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.titleLarge!.copyWith(
|
||||||
|
color:
|
||||||
|
Theme.of(context).appBarTheme.foregroundColor!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const TextSpan(text: '\n'),
|
||||||
|
TextSpan(
|
||||||
|
text: 'postDetail'.tr(),
|
||||||
|
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
|
color:
|
||||||
|
Theme.of(context).appBarTheme.foregroundColor!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
)
|
||||||
|
: Text('postDetail').tr(),
|
||||||
|
),
|
||||||
|
body: CustomScrollView(
|
||||||
|
slivers: [
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: PostItem(
|
child: LoadingIndicator(isActive: _isBusy),
|
||||||
data: _data!,
|
),
|
||||||
maxWidth: maxWidth,
|
if (_data != null)
|
||||||
showComments: false,
|
SliverToBoxAdapter(
|
||||||
showFullPost: true,
|
child: PostItem(
|
||||||
onChanged: (data) {
|
data: _data!,
|
||||||
setState(() => _data = data);
|
maxWidth: maxWidth,
|
||||||
},
|
showComments: false,
|
||||||
onDeleted: () {
|
showFullPost: true,
|
||||||
Navigator.pop(context);
|
onChanged: (data) {
|
||||||
},
|
setState(() => _data = data);
|
||||||
|
},
|
||||||
|
onDeleted: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
if (_data != null)
|
||||||
if (_data != null)
|
SliverToBoxAdapter(
|
||||||
SliverToBoxAdapter(
|
child: Divider(height: 1).padding(top: 8),
|
||||||
child: Divider(height: 1).padding(top: 8),
|
|
||||||
),
|
|
||||||
if (_data != null)
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: Container(
|
|
||||||
constraints: BoxConstraints(maxWidth: maxWidth),
|
|
||||||
child: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
const Icon(Symbols.comment, size: 24),
|
|
||||||
const Gap(16),
|
|
||||||
Text('postCommentsDetailed')
|
|
||||||
.plural(_data!.metric.replyCount)
|
|
||||||
.textStyle(Theme.of(context).textTheme.titleLarge!),
|
|
||||||
],
|
|
||||||
).padding(horizontal: 20, vertical: 12).center(),
|
|
||||||
),
|
),
|
||||||
),
|
if (_data != null)
|
||||||
if (_data != null && ua.isAuthorized)
|
SliverToBoxAdapter(
|
||||||
SliverToBoxAdapter(
|
child: Container(
|
||||||
child: PostCommentQuickAction(
|
constraints: BoxConstraints(maxWidth: maxWidth),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const Icon(Symbols.comment, size: 24),
|
||||||
|
const Gap(16),
|
||||||
|
Text('postCommentsDetailed')
|
||||||
|
.plural(_data!.metric.replyCount)
|
||||||
|
.textStyle(Theme.of(context).textTheme.titleLarge!),
|
||||||
|
],
|
||||||
|
).padding(horizontal: 20, vertical: 12).center(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (_data != null && ua.isAuthorized)
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: PostCommentQuickAction(
|
||||||
|
parentPost: _data!,
|
||||||
|
maxWidth: maxWidth,
|
||||||
|
onPosted: () {
|
||||||
|
setState(() {
|
||||||
|
_data = _data!.copyWith(
|
||||||
|
metric: _data!.metric.copyWith(
|
||||||
|
replyCount: _data!.metric.replyCount + 1,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
_childListKey.currentState!.refresh();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (_data != null) SliverGap(8),
|
||||||
|
if (_data != null)
|
||||||
|
PostCommentSliverList(
|
||||||
|
key: _childListKey,
|
||||||
parentPost: _data!,
|
parentPost: _data!,
|
||||||
maxWidth: maxWidth,
|
maxWidth: maxWidth,
|
||||||
onPosted: () {
|
|
||||||
setState(() {
|
|
||||||
_data = _data!.copyWith(
|
|
||||||
metric: _data!.metric.copyWith(
|
|
||||||
replyCount: _data!.metric.replyCount + 1,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
_childListKey.currentState!.refresh();
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
if (_data != null)
|
||||||
if (_data != null) SliverGap(8),
|
SliverGap(math.max(MediaQuery.of(context).padding.bottom, 16)),
|
||||||
if (_data != null)
|
],
|
||||||
PostCommentSliverList(
|
),
|
||||||
key: _childListKey,
|
|
||||||
parentPost: _data!,
|
|
||||||
maxWidth: maxWidth,
|
|
||||||
),
|
|
||||||
if (_data != null)
|
|
||||||
SliverGap(math.max(MediaQuery.of(context).padding.bottom, 16)),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -286,7 +286,6 @@ class _PostPublisherScreenState extends State<PostPublisherScreen>
|
|||||||
final sn = context.read<SnNetworkProvider>();
|
final sn = context.read<SnNetworkProvider>();
|
||||||
|
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
|
||||||
body: NestedScrollView(
|
body: NestedScrollView(
|
||||||
controller: _scrollController,
|
controller: _scrollController,
|
||||||
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
|
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
|
||||||
|
@ -45,9 +45,7 @@ class _WalletScreenState extends State<WalletScreen> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: true,
|
appBar: AppBar(leading: PageBackButton(), title: Text('screenAccountWallet').tr()),
|
||||||
appBar: AppBar(
|
|
||||||
leading: PageBackButton(), title: Text('screenAccountWallet').tr()),
|
|
||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
LoadingIndicator(isActive: _isBusy),
|
LoadingIndicator(isActive: _isBusy),
|
||||||
@ -68,9 +66,7 @@ class _WalletScreenState extends State<WalletScreen> {
|
|||||||
SizedBox(width: double.infinity),
|
SizedBox(width: double.infinity),
|
||||||
Text(
|
Text(
|
||||||
NumberFormat.compactCurrency(
|
NumberFormat.compactCurrency(
|
||||||
locale: EasyLocalization.of(context)!
|
locale: EasyLocalization.of(context)!.currentLocale.toString(),
|
||||||
.currentLocale
|
|
||||||
.toString(),
|
|
||||||
symbol: '${'walletCurrencyShort'.tr()} ',
|
symbol: '${'walletCurrencyShort'.tr()} ',
|
||||||
decimalDigits: 2,
|
decimalDigits: 2,
|
||||||
).format(double.parse(_wallet!.balance)),
|
).format(double.parse(_wallet!.balance)),
|
||||||
@ -80,21 +76,17 @@ class _WalletScreenState extends State<WalletScreen> {
|
|||||||
const Gap(16),
|
const Gap(16),
|
||||||
Text(
|
Text(
|
||||||
NumberFormat.compactCurrency(
|
NumberFormat.compactCurrency(
|
||||||
locale: EasyLocalization.of(context)!
|
locale: EasyLocalization.of(context)!.currentLocale.toString(),
|
||||||
.currentLocale
|
|
||||||
.toString(),
|
|
||||||
symbol: '${'walletCurrencyGoldenShort'.tr()} ',
|
symbol: '${'walletCurrencyGoldenShort'.tr()} ',
|
||||||
decimalDigits: 2,
|
decimalDigits: 2,
|
||||||
).format(double.parse(_wallet!.goldenBalance)),
|
).format(double.parse(_wallet!.goldenBalance)),
|
||||||
style: Theme.of(context).textTheme.titleLarge,
|
style: Theme.of(context).textTheme.titleLarge,
|
||||||
),
|
),
|
||||||
Text('walletCurrencyGolden'
|
Text('walletCurrencyGolden'.plural(double.parse(_wallet!.goldenBalance))),
|
||||||
.plural(double.parse(_wallet!.goldenBalance))),
|
|
||||||
],
|
],
|
||||||
).padding(horizontal: 20, vertical: 24),
|
).padding(horizontal: 20, vertical: 24),
|
||||||
).padding(horizontal: 8, top: 16, bottom: 4),
|
).padding(horizontal: 8, top: 16, bottom: 4),
|
||||||
if (_wallet != null)
|
if (_wallet != null) Expanded(child: _WalletTransactionList(myself: _wallet!)),
|
||||||
Expanded(child: _WalletTransactionList(myself: _wallet!)),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -124,10 +116,7 @@ class _WalletTransactionListState extends State<_WalletTransactionList> {
|
|||||||
queryParameters: {'take': 10, 'offset': _transactions.length},
|
queryParameters: {'take': 10, 'offset': _transactions.length},
|
||||||
);
|
);
|
||||||
_totalCount = resp.data['count'];
|
_totalCount = resp.data['count'];
|
||||||
_transactions.addAll(resp.data['data']
|
_transactions.addAll(resp.data['data']?.map((e) => SnTransaction.fromJson(e)).cast<SnTransaction>() ?? []);
|
||||||
?.map((e) => SnTransaction.fromJson(e))
|
|
||||||
.cast<SnTransaction>() ??
|
|
||||||
[]);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
context.showErrorDialog(err);
|
context.showErrorDialog(err);
|
||||||
@ -152,8 +141,7 @@ class _WalletTransactionListState extends State<_WalletTransactionList> {
|
|||||||
child: InfiniteList(
|
child: InfiniteList(
|
||||||
itemCount: _transactions.length,
|
itemCount: _transactions.length,
|
||||||
isLoading: _isBusy,
|
isLoading: _isBusy,
|
||||||
hasReachedMax:
|
hasReachedMax: _totalCount != null && _transactions.length >= _totalCount!,
|
||||||
_totalCount != null && _transactions.length >= _totalCount!,
|
|
||||||
onFetchData: () {
|
onFetchData: () {
|
||||||
_fetchTransactions();
|
_fetchTransactions();
|
||||||
},
|
},
|
||||||
@ -161,9 +149,7 @@ class _WalletTransactionListState extends State<_WalletTransactionList> {
|
|||||||
final ele = _transactions[idx];
|
final ele = _transactions[idx];
|
||||||
final isIncoming = ele.payeeId == widget.myself.id;
|
final isIncoming = ele.payeeId == widget.myself.id;
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: isIncoming
|
leading: isIncoming ? const Icon(Symbols.call_received) : const Icon(Symbols.call_made),
|
||||||
? const Icon(Symbols.call_received)
|
|
||||||
: const Icon(Symbols.call_made),
|
|
||||||
title: Text(
|
title: Text(
|
||||||
'${isIncoming ? '+' : '-'}${ele.amount} ${'walletCurrencyShort'.tr()}',
|
'${isIncoming ? '+' : '-'}${ele.amount} ${'walletCurrencyShort'.tr()}',
|
||||||
style: TextStyle(color: isIncoming ? Colors.green : Colors.red),
|
style: TextStyle(color: isIncoming ? Colors.green : Colors.red),
|
||||||
@ -176,20 +162,12 @@ class _WalletTransactionListState extends State<_WalletTransactionList> {
|
|||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'walletTransactionType${ele.currency.capitalize()}'
|
'walletTransactionType${ele.currency.capitalize()}'.tr(),
|
||||||
.tr(),
|
|
||||||
style: Theme.of(context).textTheme.labelSmall,
|
style: Theme.of(context).textTheme.labelSmall,
|
||||||
),
|
),
|
||||||
Text(' · ')
|
Text(' · ').textStyle(Theme.of(context).textTheme.labelSmall!).padding(right: 4),
|
||||||
.textStyle(Theme.of(context).textTheme.labelSmall!)
|
|
||||||
.padding(right: 4),
|
|
||||||
Text(
|
Text(
|
||||||
DateFormat(
|
DateFormat(null, EasyLocalization.of(context)!.currentLocale.toString()).format(ele.createdAt),
|
||||||
null,
|
|
||||||
EasyLocalization.of(context)!
|
|
||||||
.currentLocale
|
|
||||||
.toString())
|
|
||||||
.format(ele.createdAt),
|
|
||||||
style: Theme.of(context).textTheme.labelSmall,
|
style: Theme.of(context).textTheme.labelSmall,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -221,34 +199,33 @@ class _CreateWalletWidgetState extends State<_CreateWalletWidget> {
|
|||||||
final TextEditingController passwordController = TextEditingController();
|
final TextEditingController passwordController = TextEditingController();
|
||||||
final password = await showDialog<String?>(
|
final password = await showDialog<String?>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (ctx) => AlertDialog(
|
builder:
|
||||||
title: Text('walletCreate').tr(),
|
(ctx) => AlertDialog(
|
||||||
content: Column(
|
title: Text('walletCreate').tr(),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
content: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
mainAxisSize: MainAxisSize.min,
|
||||||
Text('walletCreatePassword').tr(),
|
children: [
|
||||||
const Gap(8),
|
Text('walletCreatePassword').tr(),
|
||||||
TextField(
|
const Gap(8),
|
||||||
autofocus: true,
|
TextField(
|
||||||
obscureText: true,
|
autofocus: true,
|
||||||
controller: passwordController,
|
obscureText: true,
|
||||||
decoration: InputDecoration(labelText: 'fieldPassword'.tr()),
|
controller: passwordController,
|
||||||
|
decoration: InputDecoration(labelText: 'fieldPassword'.tr()),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
actions: [
|
||||||
),
|
TextButton(onPressed: () => Navigator.of(ctx).pop(), child: Text('cancel').tr()),
|
||||||
actions: [
|
TextButton(
|
||||||
TextButton(
|
onPressed: () {
|
||||||
onPressed: () => Navigator.of(ctx).pop(),
|
Navigator.of(ctx).pop(passwordController.text);
|
||||||
child: Text('cancel').tr()),
|
},
|
||||||
TextButton(
|
child: Text('next').tr(),
|
||||||
onPressed: () {
|
),
|
||||||
Navigator.of(ctx).pop(passwordController.text);
|
],
|
||||||
},
|
|
||||||
child: Text('next').tr(),
|
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
passwordController.dispose();
|
passwordController.dispose();
|
||||||
@ -280,18 +257,12 @@ class _CreateWalletWidgetState extends State<_CreateWalletWidget> {
|
|||||||
children: [
|
children: [
|
||||||
CircleAvatar(radius: 28, child: Icon(Symbols.add, size: 28)),
|
CircleAvatar(radius: 28, child: Icon(Symbols.add, size: 28)),
|
||||||
const Gap(12),
|
const Gap(12),
|
||||||
Text('walletCreate',
|
Text('walletCreate', style: Theme.of(context).textTheme.titleLarge).tr(),
|
||||||
style: Theme.of(context).textTheme.titleLarge)
|
Text('walletCreateSubtitle', style: Theme.of(context).textTheme.bodyMedium).tr(),
|
||||||
.tr(),
|
|
||||||
Text('walletCreateSubtitle',
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium)
|
|
||||||
.tr(),
|
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
Align(
|
Align(
|
||||||
alignment: Alignment.centerRight,
|
alignment: Alignment.centerRight,
|
||||||
child: TextButton(
|
child: TextButton(onPressed: _isBusy ? null : () => _createWallet(), child: Text('next').tr()),
|
||||||
onPressed: _isBusy ? null : () => _createWallet(),
|
|
||||||
child: Text('next').tr()),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
).padding(horizontal: 20, vertical: 24),
|
).padding(horizontal: 20, vertical: 24),
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gap/gap.dart';
|
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:surface/providers/navigation.dart';
|
import 'package:surface/providers/navigation.dart';
|
||||||
import 'package:surface/providers/userinfo.dart';
|
|
||||||
import 'package:surface/widgets/account/account_image.dart';
|
|
||||||
|
|
||||||
class AppRailNavigation extends StatefulWidget {
|
class AppRailNavigation extends StatefulWidget {
|
||||||
const AppRailNavigation({super.key});
|
const AppRailNavigation({super.key});
|
||||||
@ -20,59 +18,43 @@ class _AppRailNavigationState extends State<AppRailNavigation> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
context
|
context.read<NavigationProvider>().autoDetectIndex(GoRouter.maybeOf(context));
|
||||||
.read<NavigationProvider>()
|
|
||||||
.autoDetectIndex(GoRouter.maybeOf(context));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ua = context.watch<UserProvider>();
|
|
||||||
final nav = context.watch<NavigationProvider>();
|
final nav = context.watch<NavigationProvider>();
|
||||||
|
|
||||||
return ListenableBuilder(
|
return ListenableBuilder(
|
||||||
listenable: nav,
|
listenable: nav,
|
||||||
builder: (context, _) {
|
builder: (context, _) {
|
||||||
final destinations = nav.destinations.toList();
|
final destinations = nav.destinations.where((ele) => ele.isPinned).toList();
|
||||||
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: 80,
|
width: 80,
|
||||||
child: NavigationRail(
|
child: NavigationRail(
|
||||||
labelType: NavigationRailLabelType.selected,
|
selectedIndex:
|
||||||
backgroundColor: Theme.of(context)
|
nav.currentIndex != null && nav.currentIndex! < nav.pinnedDestinationCount ? nav.currentIndex : null,
|
||||||
.colorScheme
|
|
||||||
.surfaceContainerLow
|
|
||||||
.withOpacity(0.5),
|
|
||||||
selectedIndex: nav.currentIndex != null &&
|
|
||||||
nav.currentIndex! < nav.destinations.length
|
|
||||||
? nav.currentIndex
|
|
||||||
: null,
|
|
||||||
destinations: [
|
destinations: [
|
||||||
...destinations.map((ele) {
|
...destinations.where((ele) => ele.isPinned).map((ele) {
|
||||||
return NavigationRailDestination(
|
return NavigationRailDestination(
|
||||||
icon: ele.icon,
|
icon: ele.icon,
|
||||||
label: Text(ele.label).tr(),
|
label: Text(ele.label).tr(),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
leading: const Gap(4),
|
|
||||||
trailing: Expanded(
|
trailing: Expanded(
|
||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
child: Padding(
|
child: StyledWidget(
|
||||||
padding: EdgeInsets.only(bottom: 24),
|
IconButton(
|
||||||
child: GestureDetector(
|
icon: const Icon(Symbols.menu),
|
||||||
child: AccountImage(
|
onPressed: () {
|
||||||
content: ua.user?.avatar,
|
Scaffold.of(context).openDrawer();
|
||||||
fallbackWidget:
|
|
||||||
ua.isAuthorized ? null : const Icon(Symbols.login),
|
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
GoRouter.of(context).goNamed('account');
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
).padding(bottom: 16),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onDestinationSelected: (idx) {
|
onDestinationSelected: (idx) {
|
||||||
|
@ -13,6 +13,7 @@ import 'package:surface/providers/navigation.dart';
|
|||||||
import 'package:surface/widgets/connection_indicator.dart';
|
import 'package:surface/widgets/connection_indicator.dart';
|
||||||
import 'package:surface/widgets/navigation/app_background.dart';
|
import 'package:surface/widgets/navigation/app_background.dart';
|
||||||
import 'package:surface/widgets/navigation/app_bottom_navigation.dart';
|
import 'package:surface/widgets/navigation/app_bottom_navigation.dart';
|
||||||
|
import 'package:surface/widgets/navigation/app_drawer_navigation.dart';
|
||||||
import 'package:surface/widgets/navigation/app_rail_navigation.dart';
|
import 'package:surface/widgets/navigation/app_rail_navigation.dart';
|
||||||
import 'package:surface/widgets/notify_indicator.dart';
|
import 'package:surface/widgets/notify_indicator.dart';
|
||||||
|
|
||||||
@ -65,9 +66,7 @@ class AppScaffold extends StatelessWidget {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
extendBody: true,
|
extendBody: true,
|
||||||
extendBodyBehindAppBar: true,
|
extendBodyBehindAppBar: true,
|
||||||
backgroundColor: noBackground
|
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||||
? Colors.transparent
|
|
||||||
: Theme.of(context).scaffoldBackgroundColor,
|
|
||||||
body: SizedBox.expand(
|
body: SizedBox.expand(
|
||||||
child: noBackground
|
child: noBackground
|
||||||
? content
|
? content
|
||||||
@ -112,6 +111,7 @@ class AppRootScaffold extends StatelessWidget {
|
|||||||
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
|
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
|
||||||
|
|
||||||
final isCollapseDrawer = cfg.drawerIsCollapsed;
|
final isCollapseDrawer = cfg.drawerIsCollapsed;
|
||||||
|
final isExpandedDrawer = cfg.drawerIsExpanded;
|
||||||
|
|
||||||
final routeName = GoRouter.of(context)
|
final routeName = GoRouter.of(context)
|
||||||
.routerDelegate
|
.routerDelegate
|
||||||
@ -132,7 +132,19 @@ class AppRootScaffold extends StatelessWidget {
|
|||||||
? body
|
? body
|
||||||
: Row(
|
: Row(
|
||||||
children: [
|
children: [
|
||||||
AppRailNavigation(),
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
right: BorderSide(
|
||||||
|
color: Theme.of(context).dividerColor,
|
||||||
|
width: 1 / devicePixelRatio,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: isExpandedDrawer
|
||||||
|
? AppNavigationDrawer(elevation: 0)
|
||||||
|
: AppRailNavigation(),
|
||||||
|
),
|
||||||
Expanded(child: body),
|
Expanded(child: body),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -220,71 +232,10 @@ class AppRootScaffold extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
drawer: !isExpandedDrawer ? AppNavigationDrawer() : null,
|
||||||
drawerEdgeDragWidth: isPopable ? 0 : null,
|
drawerEdgeDragWidth: isPopable ? 0 : null,
|
||||||
bottomNavigationBar:
|
bottomNavigationBar:
|
||||||
isShowBottomNavigation ? AppBottomNavigationBar() : null,
|
isShowBottomNavigation ? AppBottomNavigationBar() : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResponsiveScaffold extends StatelessWidget {
|
|
||||||
final Widget aside;
|
|
||||||
final Widget? child;
|
|
||||||
final int asideFlex;
|
|
||||||
final int contentFlex;
|
|
||||||
const ResponsiveScaffold({
|
|
||||||
super.key,
|
|
||||||
required this.aside,
|
|
||||||
required this.child,
|
|
||||||
this.asideFlex = 1,
|
|
||||||
this.contentFlex = 2,
|
|
||||||
});
|
|
||||||
|
|
||||||
static bool getIsExpand(BuildContext context) {
|
|
||||||
return ResponsiveBreakpoints.of(context).largerOrEqualTo(TABLET);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
if (getIsExpand(context)) {
|
|
||||||
return AppBackground(
|
|
||||||
isRoot: true,
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Flexible(
|
|
||||||
flex: asideFlex,
|
|
||||||
child: aside,
|
|
||||||
),
|
|
||||||
VerticalDivider(width: 1),
|
|
||||||
if (child != null && child != aside)
|
|
||||||
Flexible(flex: contentFlex, child: child!)
|
|
||||||
else
|
|
||||||
Flexible(
|
|
||||||
flex: contentFlex,
|
|
||||||
child: ResponsiveScaffoldLanding(child: null),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return AppBackground(isRoot: true, child: child ?? aside);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ResponsiveScaffoldLanding extends StatelessWidget {
|
|
||||||
final Widget? child;
|
|
||||||
const ResponsiveScaffoldLanding({super.key, required this.child});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
if (ResponsiveScaffold.getIsExpand(context) || child == null) {
|
|
||||||
return AppScaffold(
|
|
||||||
noBackground: true,
|
|
||||||
appBar: AppBar(),
|
|
||||||
body: const SizedBox.shrink(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return child!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -4,6 +4,7 @@ import 'package:gap/gap.dart';
|
|||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:responsive_framework/responsive_framework.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:surface/providers/post.dart';
|
import 'package:surface/providers/post.dart';
|
||||||
import 'package:surface/providers/sn_network.dart';
|
import 'package:surface/providers/sn_network.dart';
|
||||||
@ -29,14 +30,24 @@ class PostCommentQuickAction extends StatelessWidget {
|
|||||||
return Container(
|
return Container(
|
||||||
height: 240,
|
height: 240,
|
||||||
constraints: BoxConstraints(maxWidth: maxWidth ?? double.infinity),
|
constraints: BoxConstraints(maxWidth: maxWidth ?? double.infinity),
|
||||||
|
margin: ResponsiveBreakpoints.of(context).largerThan(MOBILE)
|
||||||
|
? const EdgeInsets.symmetric(vertical: 8)
|
||||||
|
: EdgeInsets.zero,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.zero,
|
borderRadius: ResponsiveBreakpoints.of(context).largerThan(MOBILE)
|
||||||
border: Border.symmetric(
|
? const BorderRadius.all(Radius.circular(8))
|
||||||
horizontal: BorderSide(
|
: BorderRadius.zero,
|
||||||
color: Theme.of(context).dividerColor,
|
border: ResponsiveBreakpoints.of(context).largerThan(MOBILE)
|
||||||
width: 1 / devicePixelRatio,
|
? Border.all(
|
||||||
),
|
color: Theme.of(context).dividerColor,
|
||||||
),
|
width: 1 / devicePixelRatio,
|
||||||
|
)
|
||||||
|
: Border.symmetric(
|
||||||
|
horizontal: BorderSide(
|
||||||
|
color: Theme.of(context).dividerColor,
|
||||||
|
width: 1 / devicePixelRatio,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: PostMiniEditor(
|
child: PostMiniEditor(
|
||||||
postReplyId: parentPost.id,
|
postReplyId: parentPost.id,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
|
import 'package:animations/animations.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:file_saver/file_saver.dart';
|
import 'package:file_saver/file_saver.dart';
|
||||||
@ -25,6 +26,7 @@ import 'package:surface/providers/sn_network.dart';
|
|||||||
import 'package:surface/providers/translation.dart';
|
import 'package:surface/providers/translation.dart';
|
||||||
import 'package:surface/providers/user_directory.dart';
|
import 'package:surface/providers/user_directory.dart';
|
||||||
import 'package:surface/providers/userinfo.dart';
|
import 'package:surface/providers/userinfo.dart';
|
||||||
|
import 'package:surface/screens/post/post_detail.dart';
|
||||||
import 'package:surface/types/attachment.dart';
|
import 'package:surface/types/attachment.dart';
|
||||||
import 'package:surface/types/post.dart';
|
import 'package:surface/types/post.dart';
|
||||||
import 'package:surface/types/reaction.dart';
|
import 'package:surface/types/reaction.dart';
|
||||||
@ -51,7 +53,6 @@ class OpenablePostItem extends StatelessWidget {
|
|||||||
final bool showMenu;
|
final bool showMenu;
|
||||||
final bool showFullPost;
|
final bool showFullPost;
|
||||||
final bool showExpandableComments;
|
final bool showExpandableComments;
|
||||||
final bool useReplace;
|
|
||||||
final double? maxWidth;
|
final double? maxWidth;
|
||||||
final Function(SnPost data)? onChanged;
|
final Function(SnPost data)? onChanged;
|
||||||
final Function()? onDeleted;
|
final Function()? onDeleted;
|
||||||
@ -65,7 +66,6 @@ class OpenablePostItem extends StatelessWidget {
|
|||||||
this.showMenu = true,
|
this.showMenu = true,
|
||||||
this.showFullPost = false,
|
this.showFullPost = false,
|
||||||
this.showExpandableComments = false,
|
this.showExpandableComments = false,
|
||||||
this.useReplace = false,
|
|
||||||
this.maxWidth,
|
this.maxWidth,
|
||||||
this.onChanged,
|
this.onChanged,
|
||||||
this.onDeleted,
|
this.onDeleted,
|
||||||
@ -74,32 +74,40 @@ class OpenablePostItem extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final cfg = context.read<ConfigProvider>();
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
constraints: BoxConstraints(maxWidth: maxWidth ?? double.infinity),
|
constraints: BoxConstraints(maxWidth: maxWidth ?? double.infinity),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: GestureDetector(
|
child: OpenContainer(
|
||||||
child: PostItem(
|
closedBuilder: (_, __) => Container(
|
||||||
data: data,
|
constraints: BoxConstraints(maxWidth: maxWidth ?? double.infinity),
|
||||||
maxWidth: maxWidth,
|
child: PostItem(
|
||||||
showComments: showComments,
|
data: data,
|
||||||
showFullPost: showFullPost,
|
maxWidth: maxWidth,
|
||||||
showExpandableComments: showExpandableComments,
|
showComments: showComments,
|
||||||
onChanged: onChanged,
|
showFullPost: showFullPost,
|
||||||
onDeleted: onDeleted,
|
showExpandableComments: showExpandableComments,
|
||||||
onSelectAnswer: onSelectAnswer,
|
onChanged: onChanged,
|
||||||
|
onDeleted: onDeleted,
|
||||||
|
onSelectAnswer: onSelectAnswer,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
openBuilder: (_, close) => PostDetailScreen(
|
||||||
|
slug: data.id.toString(),
|
||||||
|
preload: data,
|
||||||
|
onBack: close,
|
||||||
|
),
|
||||||
|
openColor: Colors.transparent,
|
||||||
|
openElevation: 0,
|
||||||
|
transitionType: ContainerTransitionType.fade,
|
||||||
|
closedElevation: 0,
|
||||||
|
closedColor: Theme.of(context).colorScheme.surface.withOpacity(
|
||||||
|
cfg.prefs.getBool(kAppBackgroundStoreKey) == true ? 0 : 1,
|
||||||
|
),
|
||||||
|
closedShape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(16)),
|
||||||
),
|
),
|
||||||
onTap: () {
|
|
||||||
if (useReplace) {
|
|
||||||
GoRouter.of(context)
|
|
||||||
.pushReplacementNamed('postDetail', pathParameters: {
|
|
||||||
'slug': data.id.toString(),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
GoRouter.of(context).pushNamed('postDetail', pathParameters: {
|
|
||||||
'slug': data.id.toString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user