Compare commits
No commits in common. "b5155ebc5f667e15d56f9a08caa4b2433bd2807e" and "f311c1898c968fb479c8d0a6202fc1c719e5c470" have entirely different histories.
b5155ebc5f
...
f311c1898c
@ -15,6 +15,7 @@ import 'package:surface/providers/websocket.dart';
|
|||||||
import 'package:surface/types/account.dart';
|
import 'package:surface/types/account.dart';
|
||||||
import 'package:surface/widgets/account/account_image.dart';
|
import 'package:surface/widgets/account/account_image.dart';
|
||||||
import 'package:surface/widgets/account/account_status.dart';
|
import 'package:surface/widgets/account/account_status.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/navigation/app_scaffold.dart';
|
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
||||||
import 'package:surface/widgets/universal_image.dart';
|
import 'package:surface/widgets/universal_image.dart';
|
||||||
@ -111,7 +112,7 @@ class AccountScreen extends StatelessWidget {
|
|||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
noBackground: ResponsiveScaffold.getIsExpand(context),
|
noBackground: ResponsiveScaffold.getIsExpand(context),
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: const PageBackButton(),
|
leading: AutoAppBarLeading(),
|
||||||
title: Text("screenAccount").tr(),
|
title: Text("screenAccount").tr(),
|
||||||
flexibleSpace: ua.user != null && ua.user!.banner.isNotEmpty
|
flexibleSpace: ua.user != null && ua.user!.banner.isNotEmpty
|
||||||
? Stack(
|
? Stack(
|
||||||
|
@ -1,21 +1,19 @@
|
|||||||
import 'package:dismissible_page/dismissible_page.dart';
|
import 'package:dismissible_page/dismissible_page.dart';
|
||||||
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:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.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:path/path.dart' show withoutExtension;
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:surface/providers/sn_network.dart';
|
import 'package:surface/providers/sn_network.dart';
|
||||||
import 'package:surface/providers/userinfo.dart';
|
|
||||||
import 'package:surface/types/attachment.dart';
|
import 'package:surface/types/attachment.dart';
|
||||||
import 'package:surface/widgets/attachment/attachment_item.dart';
|
|
||||||
import 'package:surface/widgets/attachment/attachment_zoom.dart';
|
import 'package:surface/widgets/attachment/attachment_zoom.dart';
|
||||||
|
import 'package:surface/widgets/attachment/attachment_item.dart';
|
||||||
import 'package:surface/widgets/dialog.dart';
|
import 'package:surface/widgets/dialog.dart';
|
||||||
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
import 'package:very_good_infinite_list/very_good_infinite_list.dart';
|
|
||||||
|
|
||||||
class AlbumScreen extends StatefulWidget {
|
class AlbumScreen extends StatefulWidget {
|
||||||
const AlbumScreen({super.key});
|
const AlbumScreen({super.key});
|
||||||
@ -50,8 +48,6 @@ class _AlbumScreenState extends State<AlbumScreen> {
|
|||||||
Future<void> _fetchAttachments() async {
|
Future<void> _fetchAttachments() async {
|
||||||
setState(() => _isBusy = true);
|
setState(() => _isBusy = true);
|
||||||
|
|
||||||
final ua = context.read<UserProvider>();
|
|
||||||
|
|
||||||
const uuid = Uuid();
|
const uuid = Uuid();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -59,11 +55,10 @@ class _AlbumScreenState extends State<AlbumScreen> {
|
|||||||
final resp = await sn.client.get('/cgi/uc/attachments', queryParameters: {
|
final resp = await sn.client.get('/cgi/uc/attachments', queryParameters: {
|
||||||
'take': 10,
|
'take': 10,
|
||||||
'offset': _attachments.length,
|
'offset': _attachments.length,
|
||||||
'author': ua.user?.name,
|
|
||||||
});
|
});
|
||||||
final attachments = List<SnAttachment>.from(
|
final attachments = List<SnAttachment>.from(
|
||||||
resp.data['data']?.map((e) => SnAttachment.fromJson(e)) ?? [],
|
resp.data['data']?.map((e) => SnAttachment.fromJson(e)) ?? [],
|
||||||
);
|
).where((e) => e.mimetype.startsWith('image')).toList();
|
||||||
_attachments.addAll(attachments);
|
_attachments.addAll(attachments);
|
||||||
_heroTags.addAll(_attachments.map((_) => uuid.v4()));
|
_heroTags.addAll(_attachments.map((_) => uuid.v4()));
|
||||||
|
|
||||||
@ -102,127 +97,94 @@ class _AlbumScreenState extends State<AlbumScreen> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
appBar: AppBar(
|
body: CustomScrollView(
|
||||||
leading: PageBackButton(),
|
controller: _scrollController,
|
||||||
title: Text('screenAlbum').tr(),
|
slivers: [
|
||||||
),
|
SliverAppBar(
|
||||||
body: Column(
|
leading: PageBackButton(),
|
||||||
children: [
|
title: Text('screenAlbum').tr(),
|
||||||
Card(
|
),
|
||||||
margin: EdgeInsets.zero,
|
SliverToBoxAdapter(
|
||||||
child: Row(
|
child: Card(
|
||||||
children: [
|
child: Row(
|
||||||
SizedBox(
|
children: [
|
||||||
width: 80,
|
SizedBox(
|
||||||
height: 80,
|
width: 80,
|
||||||
child: CircularProgressIndicator(
|
height: 80,
|
||||||
value: _billing?.includedRatio ?? 0,
|
child: CircularProgressIndicator(
|
||||||
strokeWidth: 8,
|
value: _billing?.includedRatio ?? 0,
|
||||||
backgroundColor:
|
strokeWidth: 8,
|
||||||
Theme.of(context).colorScheme.surfaceContainerHigh,
|
backgroundColor:
|
||||||
),
|
Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||||
).padding(all: 12),
|
|
||||||
const Gap(24),
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text('attachmentBillingUploaded').tr().bold(),
|
|
||||||
Text(
|
|
||||||
(_billing?.currentBytes ?? 0).formatBytes(decimals: 4),
|
|
||||||
style: GoogleFonts.robotoMono(),
|
|
||||||
),
|
|
||||||
Text('attachmentBillingDiscount').tr().bold(),
|
|
||||||
Text(
|
|
||||||
'${(_billing?.discountFileSize ?? 0).formatBytes(decimals: 2)} · ${((_billing?.includedRatio ?? 0) * 100).toStringAsFixed(2)}%',
|
|
||||||
style: GoogleFonts.robotoMono(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Tooltip(
|
|
||||||
message: 'attachmentBillingHint'.tr(),
|
|
||||||
child: IconButton(
|
|
||||||
icon: const Icon(Symbols.info),
|
|
||||||
onPressed: () {},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
).padding(horizontal: 24, vertical: 8),
|
|
||||||
).padding(horizontal: 8, top: 8),
|
|
||||||
Expanded(
|
|
||||||
child: InfiniteList(
|
|
||||||
padding: EdgeInsets.only(top: 8),
|
|
||||||
itemCount: _attachments.length,
|
|
||||||
isLoading: _isBusy,
|
|
||||||
hasReachedMax:
|
|
||||||
_totalCount != null && _attachments.length >= _totalCount!,
|
|
||||||
onFetchData: _fetchAttachments,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final ele = _attachments[index];
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
ClipRRect(
|
|
||||||
child: AspectRatio(
|
|
||||||
aspectRatio: (ele.data['ratio'] ?? 1).toDouble(),
|
|
||||||
child: AttachmentItem(
|
|
||||||
data: ele,
|
|
||||||
heroTag: _heroTags[index],
|
|
||||||
onZoom: () {
|
|
||||||
context.pushTransparentRoute(
|
|
||||||
AttachmentZoomView(
|
|
||||||
data: [ele],
|
|
||||||
),
|
|
||||||
backgroundColor: Colors.black.withOpacity(0.7),
|
|
||||||
rootNavigator: true,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Row(
|
).padding(all: 12),
|
||||||
|
const Gap(24),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Text('attachmentBillingUploaded').tr().bold(),
|
||||||
child: Column(
|
Text(
|
||||||
mainAxisSize: MainAxisSize.min,
|
(_billing?.currentBytes ?? 0)
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
.formatBytes(decimals: 4),
|
||||||
children: [
|
style: GoogleFonts.robotoMono(),
|
||||||
Text(ele.name),
|
|
||||||
if (ele.alt != withoutExtension(ele.name))
|
|
||||||
Text(ele.alt),
|
|
||||||
Text(DateFormat().format(ele.createdAt)),
|
|
||||||
const Gap(4),
|
|
||||||
Text(ele.size.formatBytes()).fontSize(12),
|
|
||||||
],
|
|
||||||
).padding(horizontal: 16, vertical: 12),
|
|
||||||
),
|
),
|
||||||
Padding(
|
Text('attachmentBillingDiscount').tr().bold(),
|
||||||
padding: EdgeInsets.only(left: 12, right: 12, top: 4),
|
Text(
|
||||||
child: IconButton(
|
'${(_billing?.discountFileSize ?? 0).formatBytes(decimals: 2)} · ${((_billing?.includedRatio ?? 0) * 100).toStringAsFixed(2)}%',
|
||||||
padding: EdgeInsets.zero,
|
style: GoogleFonts.robotoMono(),
|
||||||
visualDensity: VisualDensity.compact,
|
|
||||||
icon: const Icon(Symbols.info),
|
|
||||||
onPressed: () {
|
|
||||||
showModalBottomSheet(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => AttachmentZoomDetailPopup(
|
|
||||||
data: ele,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
);
|
Tooltip(
|
||||||
},
|
message: 'attachmentBillingHint'.tr(),
|
||||||
separatorBuilder: (_, __) => const Gap(8),
|
child: IconButton(
|
||||||
|
icon: const Icon(Symbols.info),
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).padding(horizontal: 24, vertical: 8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverMasonryGrid.extent(
|
||||||
|
childCount: _attachments.length,
|
||||||
|
maxCrossAxisExtent: 320,
|
||||||
|
mainAxisSpacing: 4,
|
||||||
|
crossAxisSpacing: 4,
|
||||||
|
itemBuilder: (context, idx) {
|
||||||
|
final attachment = _attachments[idx];
|
||||||
|
return GestureDetector(
|
||||||
|
child: ClipRRect(
|
||||||
|
child: AspectRatio(
|
||||||
|
aspectRatio: attachment.metadata['ratio']?.toDouble() ?? 1,
|
||||||
|
child: AttachmentItem(
|
||||||
|
data: attachment,
|
||||||
|
heroTag: _heroTags[idx],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
context.pushTransparentRoute(
|
||||||
|
AttachmentZoomView(
|
||||||
|
data: [attachment],
|
||||||
|
heroTags: [_heroTags[idx]],
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.black.withOpacity(0.7),
|
||||||
|
rootNavigator: true,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (_isBusy)
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(24),
|
||||||
|
child: const CircularProgressIndicator(),
|
||||||
|
).center(),
|
||||||
),
|
),
|
||||||
)
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -303,7 +303,6 @@ class _PostPublisherScreenState extends State<PostPublisherScreen>
|
|||||||
),
|
),
|
||||||
child: SliverAppBar(
|
child: SliverAppBar(
|
||||||
expandedHeight: _appBarHeight,
|
expandedHeight: _appBarHeight,
|
||||||
leading: const PageBackButton(),
|
|
||||||
title: _publisher == null
|
title: _publisher == null
|
||||||
? Text('loading').tr()
|
? Text('loading').tr()
|
||||||
: RichText(
|
: RichText(
|
||||||
|
@ -373,7 +373,7 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
|
|||||||
_showDetail = true;
|
_showDetail = true;
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => AttachmentZoomDetailPopup(
|
builder: (context) => _AttachmentZoomDetailPopup(
|
||||||
data: widget.data.elementAt(_page),
|
data: widget.data.elementAt(_page),
|
||||||
),
|
),
|
||||||
).then((_) {
|
).then((_) {
|
||||||
@ -403,7 +403,7 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
|
|||||||
_showDetail = true;
|
_showDetail = true;
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => AttachmentZoomDetailPopup(
|
builder: (context) => _AttachmentZoomDetailPopup(
|
||||||
data: widget.data.elementAt(_page),
|
data: widget.data.elementAt(_page),
|
||||||
),
|
),
|
||||||
).then((_) {
|
).then((_) {
|
||||||
@ -416,10 +416,10 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AttachmentZoomDetailPopup extends StatelessWidget {
|
class _AttachmentZoomDetailPopup extends StatelessWidget {
|
||||||
final SnAttachment data;
|
final SnAttachment data;
|
||||||
|
|
||||||
const AttachmentZoomDetailPopup({required this.data});
|
const _AttachmentZoomDetailPopup({required this.data});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -40,7 +40,6 @@ class UnauthorizedHint extends StatelessWidget {
|
|||||||
GoRouter.of(context).pushNamed('authLogin').then((value) {
|
GoRouter.of(context).pushNamed('authLogin').then((value) {
|
||||||
if (value == true && context.mounted) {
|
if (value == true && context.mounted) {
|
||||||
final ua = context.read<UserProvider>();
|
final ua = context.read<UserProvider>();
|
||||||
ua.refreshUser();
|
|
||||||
context.showSnackbar('loginSuccess'.tr(args: [
|
context.showSnackbar('loginSuccess'.tr(args: [
|
||||||
'@${ua.user?.name} (${ua.user?.nick})',
|
'@${ua.user?.name} (${ua.user?.nick})',
|
||||||
]));
|
]));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user