Compare commits

...

5 Commits

Author SHA1 Message Date
3b1e918117 🐛 Fix side nav cause render error 2025-01-20 01:43:11 +08:00
ed7981fdaf 🧪 Post max width 2025-01-19 17:20:24 +08:00
9698ca53e4 Swipe up to view attachment details 2025-01-19 11:44:14 +08:00
ddc1dc7daf 💄 Optimize attachment zoom page 2025-01-19 01:00:00 +08:00
1625a957f8 👔 Use material design 3 by default 2025-01-19 00:39:47 +08:00
9 changed files with 378 additions and 215 deletions

View File

@ -17,6 +17,7 @@
android:label="Solian"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
android:enableOnBackInvokedCallback="true"
android:requestLegacyExternalStorage="true">
<activity
android:name=".MainActivity"

View File

@ -294,6 +294,7 @@
"addAttachmentFromCameraPhoto": "Take photo",
"addAttachmentFromCameraVideo": "Take video",
"addAttachmentFromRandomId": "Link via RID",
"attachmentDetailInfo": "Attachment details",
"attachmentPastedImage": "Pasted Image",
"attachmentInsertLink": "Insert Link",
"attachmentSetAsPostThumbnail": "Set as post thumbnail",

View File

@ -292,6 +292,7 @@
"addAttachmentFromCameraPhoto": "拍摄照片",
"addAttachmentFromCameraVideo": "拍摄视频",
"addAttachmentFromRandomId": "通过访问 ID 链接",
"attachmentDetailInfo": "附件详细信息",
"attachmentPastedImage": "粘贴的图片",
"attachmentInsertLink": "插入连接",
"attachmentSetAsPostThumbnail": "设置为帖子缩略图",

View File

@ -217,7 +217,24 @@ class _ExploreScreenState extends State<ExploreScreen> {
hasReachedMax: _postCount != null && _posts.length >= _postCount!,
onFetchData: _fetchPosts,
itemBuilder: (context, idx) {
return GestureDetector(
return Center(
child: Container(
decoration: BoxDecoration(
border: Border(
left: BorderSide(
color: Theme.of(context).dividerColor,
width: 1 / MediaQuery.of(context).devicePixelRatio,
),
right: BorderSide(
color: Theme.of(context).dividerColor,
width: 1 / MediaQuery.of(context).devicePixelRatio,
),
),
),
constraints: const BoxConstraints(maxWidth: 640),
child: Column(
children: [
GestureDetector(
child: PostItem(
data: _posts[idx],
maxWidth: 640,
@ -235,9 +252,13 @@ class _ExploreScreenState extends State<ExploreScreen> {
extra: _posts[idx],
);
},
),
const Divider(height: 1),
],
),
),
);
},
separatorBuilder: (context, index) => const Divider(height: 1),
),
],
),

View File

@ -120,7 +120,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
subtitle: Text('settingsThemeMaterial3Description').tr(),
contentPadding: const EdgeInsets.only(left: 24, right: 17),
secondary: const Icon(Symbols.new_releases),
value: _prefs.getBool(kMaterialYouToggleStoreKey) ?? false,
value: _prefs.getBool(kMaterialYouToggleStoreKey) ?? true,
onChanged: (value) {
setState(() {
_prefs.setBool(

View File

@ -36,7 +36,7 @@ Future<ThemeData> createAppTheme(
final hasAppBarBlurry = prefs.getBool(kAppbarTransparentStoreKey) ?? false;
return ThemeData(
useMaterial3: useMaterial3 ?? (prefs.getBool(kMaterialYouToggleStoreKey) ?? false),
useMaterial3: useMaterial3 ?? (prefs.getBool(kMaterialYouToggleStoreKey) ?? true),
colorScheme: colorScheme,
brightness: brightness,
iconTheme: IconThemeData(
@ -52,5 +52,15 @@ Future<ThemeData> createAppTheme(
foregroundColor: hasAppBarBlurry ? colorScheme.onSurface : colorScheme.onPrimary,
),
scaffoldBackgroundColor: Colors.transparent,
pageTransitionsTheme: PageTransitionsTheme(
builders: {
TargetPlatform.android: PredictiveBackPageTransitionsBuilder(),
TargetPlatform.iOS: ZoomPageTransitionsBuilder(),
TargetPlatform.macOS: ZoomPageTransitionsBuilder(),
TargetPlatform.fuchsia: ZoomPageTransitionsBuilder(),
TargetPlatform.linux: ZoomPageTransitionsBuilder(),
TargetPlatform.windows: ZoomPageTransitionsBuilder(),
},
),
);
}

View File

@ -10,7 +10,6 @@ import 'package:surface/providers/experience.dart';
import 'package:surface/providers/sn_network.dart';
import 'package:surface/screens/account/profile_page.dart';
import 'package:surface/types/account.dart';
import 'package:surface/types/post.dart';
import 'package:surface/widgets/account/account_image.dart';
import 'package:surface/widgets/universal_image.dart';

View File

@ -129,6 +129,8 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
Color get _unFocusColor => Theme.of(context).colorScheme.onSurface.withOpacity(0.75);
bool _showDetail = false;
@override
Widget build(BuildContext context) {
final sn = context.read<SnNetworkProvider>();
@ -144,9 +146,11 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
onDismissed: () {
Navigator.of(context).pop();
},
direction: DismissiblePageDismissDirection.down,
direction: DismissiblePageDismissDirection.none,
backgroundColor: Colors.transparent,
isFullScreen: true,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
child: Scaffold(
body: Stack(
children: [
@ -264,7 +268,8 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
borderRadius: const BorderRadius.all(Radius.circular(16)),
onTap: _isDownloading
? null
: () => _saveToAlbum(widget.data.length > 1 ? _pageController.page?.round() ?? 0 : 0),
: () =>
_saveToAlbum(widget.data.length > 1 ? _pageController.page?.round() ?? 0 : 0),
child: Container(
padding: const EdgeInsets.all(6),
child: !_isDownloading
@ -322,7 +327,8 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
'f/${item.metadata['exif']?['Aperture']}',
style: metaTextStyle,
).padding(right: 2),
if (item.metadata['exif']?['Megapixels'] != null && item.metadata['exif']?['Model'] != null)
if (item.metadata['exif']?['Megapixels'] != null &&
item.metadata['exif']?['Model'] != null)
Text(
'${item.metadata['exif']?['Megapixels']}MP',
style: metaTextStyle,
@ -357,6 +363,132 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
],
),
),
onVerticalDragUpdate: (details) {
if (_showDetail) return;
if (details.delta.dy < 0) {
_showDetail = true;
showModalBottomSheet(
context: context,
builder: (context) => _AttachmentZoomDetailPopup(
data: widget.data.elementAt(widget.data.length > 1 ? _pageController.page?.round() ?? 0 : 0),
),
).then((_) {
_showDetail = false;
});
}
},
onTap: () {
Navigator.of(context).pop();
},
),
);
}
}
class _AttachmentZoomDetailPopup extends StatelessWidget {
final SnAttachment data;
const _AttachmentZoomDetailPopup({required this.data});
@override
Widget build(BuildContext context) {
final ud = context.read<UserDirectoryProvider>();
final account = ud.getAccountFromCache(data.accountId);
const tableGap = TableRow(
children: [
TableCell(child: SizedBox(height: 16)),
TableCell(child: SizedBox(height: 16)),
],
);
return SizedBox(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Icon(Symbols.info, size: 24),
const Gap(16),
Text('attachmentDetailInfo').tr().textStyle(Theme.of(context).textTheme.titleLarge!),
],
).padding(horizontal: 20, top: 16, bottom: 12),
Expanded(
child: Table(
columnWidths: {
0: IntrinsicColumnWidth(),
1: FlexColumnWidth(),
},
children: [
TableRow(
children: [
TableCell(
child: Text('attachmentUploadBy').tr().padding(right: 16),
),
TableCell(
child: Row(
children: [
if (data.accountId > 0)
AccountImage(
content: account?.avatar,
radius: 8,
),
const Gap(8),
Text(data.accountId > 0 ? account?.nick ?? 'unknown'.tr() : 'unknown'.tr()),
const Gap(8),
Text('#${data.accountId}', style: GoogleFonts.robotoMono()).opacity(0.75),
],
),
),
],
),
tableGap,
TableRow(
children: [
TableCell(child: Text('Mimetype').padding(right: 16)),
TableCell(child: Text(data.mimetype)),
],
),
TableRow(
children: [
TableCell(child: Text('Size').padding(right: 16)),
TableCell(
child: Row(
children: [
Text(data.size.formatBytes()),
const Gap(12),
Text('${data.size} Bytes', style: GoogleFonts.robotoMono()).opacity(0.75),
],
)),
],
),
TableRow(
children: [
TableCell(child: Text('Name').padding(right: 16)),
TableCell(child: Text(data.name)),
],
),
if (data.hash.isNotEmpty)
TableRow(
children: [
TableCell(child: Text('Hash').padding(right: 16)),
TableCell(child: Text(data.hash, style: GoogleFonts.robotoMono(fontSize: 11)).opacity(0.9)),
],
),
tableGap,
...(data.metadata['exif']?.keys.map((k) => TableRow(
children: [
TableCell(child: Text(k).padding(right: 16)),
TableCell(child: Text(data.metadata['exif'][k].toString())),
],
)) ??
[]),
],
).padding(horizontal: 20, vertical: 8),
),
],
),
);
}
}

View File

@ -18,9 +18,7 @@ class _AppRailNavigationState extends State<AppRailNavigation> {
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
context
.read<NavigationProvider>()
.autoDetectIndex(GoRouter.maybeOf(context));
context.read<NavigationProvider>().autoDetectIndex(GoRouter.maybeOf(context));
});
}
@ -31,11 +29,11 @@ class _AppRailNavigationState extends State<AppRailNavigation> {
return ListenableBuilder(
listenable: nav,
builder: (context, _) {
final destinations =
nav.destinations.where((ele) => ele.isPinned).toList();
final destinations = nav.destinations.where((ele) => ele.isPinned).toList();
return NavigationRail(
selectedIndex: nav.currentIndex,
selectedIndex:
nav.currentIndex != null && nav.currentIndex! < nav.pinnedDestinationCount ? nav.currentIndex : null,
destinations: [
...destinations.where((ele) => ele.isPinned).map((ele) {
return NavigationRailDestination(