Compare commits

...

8 Commits

Author SHA1 Message Date
6ac536412a 🚀 Launch 2.2.2+49 2025-01-06 22:05:20 +08:00
52f8ffe4e4 💄 Update the app bar color when in transparent mode 2025-01-06 21:57:50 +08:00
aca81431aa 🐛 Fix desktop share post as image do not include file extension name 2025-01-06 21:53:35 +08:00
1fadd850b7 💄 Optimize some styling 2025-01-06 21:46:21 +08:00
ed2a9a21b6 🐛 Fix chat username height difference 2025-01-06 19:18:23 +08:00
57279eb3e4 🚀 Launch 2.2.1+48 2025-01-05 13:41:38 +08:00
c403a2914a 💄 Optimized article attachments displaying strategy 2025-01-05 13:34:37 +08:00
bcb176344c 💄 Optimize some styling 2025-01-05 13:29:39 +08:00
10 changed files with 55 additions and 102 deletions

View File

@ -83,7 +83,6 @@ class ChatMessageController extends ChangeNotifier {
if (member.id == profile?.id) break; if (member.id == profile?.id) break;
if (!typingMembers.any((x) => x.id == member.id)) { if (!typingMembers.any((x) => x.id == member.id)) {
typingMembers.add(member); typingMembers.add(member);
print('Typing member: ${typingMembers.map((ele) => member.id)}');
notifyListeners(); notifyListeners();
} }
typingInactiveTimer[member.id]?.cancel(); typingInactiveTimer[member.id]?.cancel();

View File

@ -35,7 +35,7 @@ class WebSocketProvider extends ChangeNotifier {
Future<void> connect({noRetry = false}) async { Future<void> connect({noRetry = false}) async {
if (!_ua.isAuthorized) return; if (!_ua.isAuthorized) return;
if (isConnected) { if (isConnected || conn != null) {
disconnect(); disconnect();
} }
@ -97,7 +97,7 @@ class WebSocketProvider extends ChangeNotifier {
onError: (err) { onError: (err) {
isConnected = false; isConnected = false;
notifyListeners(); notifyListeners();
Future.delayed(const Duration(seconds: 11), () => connect()); Future.delayed(const Duration(seconds: 1), () => connect());
}, },
); );
} }

View File

@ -96,6 +96,8 @@ class _PostDetailScreenState extends State<PostDetailScreen> {
), ),
), ),
]), ]),
maxLines: 2,
overflow: TextOverflow.ellipsis,
) )
: Text('postDetail').tr(), : Text('postDetail').tr(),
), ),

View File

@ -48,7 +48,7 @@ Future<ThemeData> createAppTheme(
appBarTheme: AppBarTheme( appBarTheme: AppBarTheme(
centerTitle: true, centerTitle: true,
elevation: hasAppBarBlurry ? 0 : null, elevation: hasAppBarBlurry ? 0 : null,
backgroundColor: hasAppBarBlurry ? colorScheme.surfaceContainer.withAlpha(200) : colorScheme.primary, backgroundColor: hasAppBarBlurry ? colorScheme.primary.withOpacity(0.3) : colorScheme.primary,
foregroundColor: hasAppBarBlurry ? colorScheme.onSurface : colorScheme.onPrimary, foregroundColor: hasAppBarBlurry ? colorScheme.onSurface : colorScheme.onPrimary,
), ),
scaffoldBackgroundColor: Colors.transparent, scaffoldBackgroundColor: Colors.transparent,

View File

@ -124,7 +124,7 @@ class ChatMessage extends StatelessWidget {
dateFormatter.format(data.createdAt.toLocal()), dateFormatter.format(data.createdAt.toLocal()),
).fontSize(13), ).fontSize(13),
], ],
), ).height(21),
if (isCompact) const Gap(8), if (isCompact) const Gap(8),
if (data.preload?.quoteEvent != null) if (data.preload?.quoteEvent != null)
StyledWidget(Container( StyledWidget(Container(

View File

@ -1,5 +1,3 @@
import 'dart:ui';
import 'package:dismissible_page/dismissible_page.dart'; import 'package:dismissible_page/dismissible_page.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:flutter_markdown/flutter_markdown.dart';
@ -7,15 +5,12 @@ import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:markdown/markdown.dart' as markdown; import 'package:markdown/markdown.dart' as markdown;
import 'package:provider/provider.dart'; import 'package:provider/provider.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/sn_sticker.dart'; import 'package:surface/providers/sn_sticker.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_item.dart';
import 'package:surface/widgets/universal_image.dart'; import 'package:surface/widgets/universal_image.dart';
import 'package:syntax_highlight/syntax_highlight.dart';
import 'package:url_launcher/url_launcher_string.dart'; import 'package:url_launcher/url_launcher_string.dart';
import 'package:path/path.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
import 'attachment/attachment_zoom.dart'; import 'attachment/attachment_zoom.dart';
@ -47,32 +42,33 @@ class MarkdownTextContent extends StatelessWidget {
styleSheet: MarkdownStyleSheet.fromTheme( styleSheet: MarkdownStyleSheet.fromTheme(
Theme.of(context), Theme.of(context),
).copyWith( ).copyWith(
textScaler: textScaler, textScaler: textScaler,
blockquote: TextStyle( blockquote: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant, color: Theme.of(context).colorScheme.onSurfaceVariant,
), ),
blockquoteDecoration: BoxDecoration( blockquoteDecoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainerHigh, color: Theme.of(context).colorScheme.surfaceContainerHigh,
borderRadius: const BorderRadius.all(Radius.circular(4)), borderRadius: const BorderRadius.all(Radius.circular(4)),
), ),
horizontalRuleDecoration: BoxDecoration( horizontalRuleDecoration: BoxDecoration(
border: Border( border: Border(
top: BorderSide( top: BorderSide(
width: 1.0, width: 1.0,
color: Theme.of(context).dividerColor,
),
),
),
codeblockDecoration: BoxDecoration(
border: Border.all(
color: Theme.of(context).dividerColor, color: Theme.of(context).dividerColor,
width: 0.3,
), ),
borderRadius: const BorderRadius.all(Radius.circular(4)), ),
color: Theme.of(context).colorScheme.surface.withOpacity(0.5), ),
)), codeblockDecoration: BoxDecoration(
border: Border.all(
color: Theme.of(context).dividerColor,
width: 0.3,
),
borderRadius: const BorderRadius.all(Radius.circular(4)),
color: Theme.of(context).colorScheme.surface.withOpacity(0.5),
),
code: GoogleFonts.robotoMono(height: 1),
),
builders: { builders: {
'code': _MarkdownTextCodeElement(),
}, },
softLineBreak: true, softLineBreak: true,
extensionSet: markdown.ExtensionSet( extensionSet: markdown.ExtensionSet(
@ -253,46 +249,3 @@ class _CustomEmoteInlineSyntax extends markdown.InlineSyntax {
return true; return true;
} }
} }
class _MarkdownTextCodeElement extends MarkdownElementBuilder {
@override
Widget? visitElementAfter(
markdown.Element element,
TextStyle? preferredStyle,
) {
var language = '';
if (element.attributes['class'] != null) {
String lg = element.attributes['class'] as String;
language = lg.substring(9).trim();
}
return SizedBox(
child: FutureBuilder(
future: (() async {
final docPath = '../../../';
final highlightingPath = join(docPath, 'assets/highlighting', language);
await Highlighter.initialize([highlightingPath]);
return Highlighter(
language: highlightingPath,
theme: PlatformDispatcher.instance.platformBrightness == Brightness.light
? await HighlighterTheme.loadLightTheme()
: await HighlighterTheme.loadDarkTheme(),
);
})(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final highlighter = snapshot.data!;
return Text.rich(
highlighter.highlight(element.textContent.trim()),
style: GoogleFonts.robotoMono(),
);
}
return Text(
element.textContent.trim(),
style: GoogleFonts.robotoMono(),
);
},
),
).padding(all: 8);
}
}

View File

@ -20,6 +20,7 @@ import 'package:styled_widget/styled_widget.dart';
import 'package:surface/providers/config.dart'; import 'package:surface/providers/config.dart';
import 'package:surface/providers/sn_network.dart'; import 'package:surface/providers/sn_network.dart';
import 'package:surface/providers/userinfo.dart'; import 'package:surface/providers/userinfo.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';
import 'package:surface/widgets/account/account_image.dart'; import 'package:surface/widgets/account/account_image.dart';
@ -112,7 +113,7 @@ class PostItem extends StatelessWidget {
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size, sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
); );
} else { } else {
await FileSaver.instance.saveFile(name: 'Solar Network Post #${data.id}', file: imageFile); await FileSaver.instance.saveFile(name: 'Solar Network Post #${data.id}.png', file: imageFile);
} }
await imageFile.delete(); await imageFile.delete();
@ -198,6 +199,10 @@ class PostItem extends StatelessWidget {
).center(); ).center();
} }
final displayableAttachments = data.preload?.attachments
?.where((ele) => ele?.mediaType != SnMediaType.image || data.type != 'article')
.toList();
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
@ -247,9 +252,9 @@ class PostItem extends StatelessWidget {
], ],
), ),
), ),
if ((data.preload?.attachments?.isNotEmpty ?? false) && data.type != 'article') if (displayableAttachments?.isNotEmpty ?? false)
AttachmentList( AttachmentList(
data: data.preload!.attachments!, data: displayableAttachments!,
bordered: true, bordered: true,
gridded: true, gridded: true,
maxHeight: showFullPost ? null : 480, maxHeight: showFullPost ? null : 480,

View File

@ -55,17 +55,20 @@ class UniversalImage extends StatelessWidget {
? null ? null
: (BuildContext context, Widget child, ImageChunkEvent? loadingProgress) { : (BuildContext context, Widget child, ImageChunkEvent? loadingProgress) {
if (loadingProgress == null) return child; if (loadingProgress == null) return child;
return Center( return Container(
child: TweenAnimationBuilder( constraints: BoxConstraints(maxHeight: 80),
tween: Tween( child: Center(
begin: 0, child: TweenAnimationBuilder(
end: loadingProgress.expectedTotalBytes != null tween: Tween(
? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! begin: 0,
: 0, end: loadingProgress.expectedTotalBytes != null
), ? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes!
duration: const Duration(milliseconds: 300), : 0,
builder: (context, value, _) => CircularProgressIndicator( ),
value: loadingProgress.expectedTotalBytes != null ? value.toDouble() : null, duration: const Duration(milliseconds: 300),
builder: (context, value, _) => CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null ? value.toDouble() : null,
),
), ),
), ),
); );

View File

@ -700,10 +700,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_markdown name: flutter_markdown
sha256: "255b00afa1a7bad19727da6a7780cf3db6c3c12e68d302d85e0ff1fdf173db9e" sha256: e37f4c69a07b07bb92622ef6b131a53c9aae48f64b176340af9e8e5238718487
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.4+3" version: "0.7.5"
flutter_native_splash: flutter_native_splash:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -1863,14 +1863,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.3.0+3" version: "3.3.0+3"
syntax_highlight:
dependency: "direct main"
description:
name: syntax_highlight
sha256: ee33b6aa82cc722bb9b40152a792181dee222353b486c0255fde666a3e3a4997
url: "https://pub.dev"
source: hosted
version: "0.4.0"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:

View File

@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 2.2.1+47 version: 2.2.2+49
environment: environment:
sdk: ^3.5.4 sdk: ^3.5.4
@ -54,7 +54,6 @@ dependencies:
flutter_markdown: ^0.7.4+1 flutter_markdown: ^0.7.4+1
url_launcher: ^6.3.1 url_launcher: ^6.3.1
flutter_animate: ^4.5.0 flutter_animate: ^4.5.0
syntax_highlight: ^0.4.0
google_fonts: ^6.2.1 google_fonts: ^6.2.1
path: ^1.9.0 path: ^1.9.0
relative_time: ^5.0.0 relative_time: ^5.0.0