Compare commits
3 Commits
a20c2598fc
...
594ac39e3d
Author | SHA1 | Date | |
---|---|---|---|
594ac39e3d | |||
23321171f3 | |||
ee72d79c93 |
@ -375,7 +375,9 @@
|
||||
"postContent": "Content",
|
||||
"postSettings": "Settings",
|
||||
"postPublisherUnselected": "Publisher Unspecified",
|
||||
"postVisibility": "Visibility",
|
||||
"postType": "Post Type",
|
||||
"articleAttachmentHint": "Attachments must be uploaded and inserted into the article body to be visible.",
|
||||
"postVisibility": "Post Visibility",
|
||||
"postVisibilityPublic": "Public",
|
||||
"postVisibilityFriends": "Friends Only",
|
||||
"postVisibilityUnlisted": "Unlisted",
|
||||
|
@ -321,8 +321,15 @@ class ArticleComposeScreen extends HookConsumerWidget {
|
||||
builder: (context, attachments, _) {
|
||||
if (attachments.isEmpty) return const SizedBox.shrink();
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Gap(16),
|
||||
Text(
|
||||
'articleAttachmentHint'.tr(),
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
).padding(bottom: 8),
|
||||
ValueListenableBuilder<Map<int, double>>(
|
||||
valueListenable: state.attachmentProgress,
|
||||
builder: (context, progressMap, _) {
|
||||
@ -332,8 +339,8 @@ class ArticleComposeScreen extends HookConsumerWidget {
|
||||
children: [
|
||||
for (var idx = 0; idx < attachments.length; idx++)
|
||||
SizedBox(
|
||||
width: 120,
|
||||
height: 120,
|
||||
width: 280,
|
||||
height: 280,
|
||||
child: AttachmentPreview(
|
||||
item: attachments[idx],
|
||||
progress: progressMap[idx],
|
||||
@ -358,6 +365,12 @@ class ArticleComposeScreen extends HookConsumerWidget {
|
||||
delta,
|
||||
);
|
||||
},
|
||||
onInsert:
|
||||
() => ComposeLogic.insertAttachment(
|
||||
ref,
|
||||
state,
|
||||
idx,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -15,6 +15,7 @@ class AttachmentPreview extends StatelessWidget {
|
||||
final double? progress;
|
||||
final Function(int)? onMove;
|
||||
final Function? onDelete;
|
||||
final Function? onInsert;
|
||||
final Function? onRequestUpload;
|
||||
const AttachmentPreview({
|
||||
super.key,
|
||||
@ -23,6 +24,7 @@ class AttachmentPreview extends StatelessWidget {
|
||||
this.onRequestUpload,
|
||||
this.onMove,
|
||||
this.onDelete,
|
||||
this.onInsert,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -104,7 +106,11 @@ class AttachmentPreview extends StatelessWidget {
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
Gap(6),
|
||||
Center(child: LinearProgressIndicator(value: progress)),
|
||||
Center(
|
||||
child: LinearProgressIndicator(
|
||||
value: progress != null ? progress! / 100.0 : null,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -166,6 +172,18 @@ class AttachmentPreview extends StatelessWidget {
|
||||
onMove?.call(1);
|
||||
},
|
||||
),
|
||||
if (onInsert != null)
|
||||
InkWell(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: const Icon(
|
||||
Symbols.add,
|
||||
size: 14,
|
||||
color: Colors.white,
|
||||
).padding(horizontal: 8, vertical: 6),
|
||||
onTap: () {
|
||||
onInsert?.call();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
@ -6,11 +7,14 @@ import 'package:flutter_highlight/themes/a11y-dark.dart';
|
||||
import 'package:flutter_highlight/themes/a11y-light.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/file.dart';
|
||||
import 'package:island/pods/config.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/content/cloud_files.dart';
|
||||
import 'package:island/widgets/content/markdown_latex.dart';
|
||||
import 'package:markdown/markdown.dart' as markdown;
|
||||
import 'package:markdown_widget/markdown_widget.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import 'image.dart';
|
||||
@ -23,6 +27,7 @@ class MarkdownTextContent extends HookConsumerWidget {
|
||||
final TextStyle? linkStyle;
|
||||
final EdgeInsets? linesMargin;
|
||||
final bool isSelectable;
|
||||
final List<SnCloudFile>? attachments;
|
||||
|
||||
const MarkdownTextContent({
|
||||
super.key,
|
||||
@ -33,6 +38,7 @@ class MarkdownTextContent extends HookConsumerWidget {
|
||||
this.linkStyle,
|
||||
this.isSelectable = false,
|
||||
this.linesMargin,
|
||||
this.attachments,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -109,6 +115,29 @@ class MarkdownTextContent extends HookConsumerWidget {
|
||||
final uri = Uri.parse(url);
|
||||
if (uri.scheme == 'solian') {
|
||||
switch (uri.host) {
|
||||
case 'files':
|
||||
final file = attachments?.firstWhereOrNull(
|
||||
(file) => file.id == uri.pathSegments[0],
|
||||
);
|
||||
if (file == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(8),
|
||||
),
|
||||
),
|
||||
child: CloudFileWidget(
|
||||
item: file,
|
||||
fit: BoxFit.cover,
|
||||
).clipRRect(all: 8),
|
||||
),
|
||||
);
|
||||
case 'stickers':
|
||||
final size = doesEnlargeSticker ? 96.0 : 24.0;
|
||||
return ClipRRect(
|
||||
@ -132,9 +161,9 @@ class MarkdownTextContent extends HookConsumerWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
final content = UniversalImage(
|
||||
uri: uri.toString(),
|
||||
fit: BoxFit.cover,
|
||||
final content = ConstrainedBox(
|
||||
constraints: BoxConstraints(maxHeight: 360),
|
||||
child: UniversalImage(uri: uri.toString(), fit: BoxFit.contain),
|
||||
);
|
||||
return content;
|
||||
},
|
||||
|
@ -474,6 +474,23 @@ class ComposeLogic {
|
||||
state.attachments.value = clone;
|
||||
}
|
||||
|
||||
static void insertAttachment(WidgetRef ref, ComposeState state, int index) {
|
||||
final attachment = state.attachments.value[index];
|
||||
if (!attachment.isOnCloud) {
|
||||
return;
|
||||
}
|
||||
final cloudFile = attachment.data as SnCloudFile;
|
||||
final markdown = '';
|
||||
final controller = state.contentController;
|
||||
final text = controller.text;
|
||||
final selection = controller.selection;
|
||||
final newText = text.replaceRange(selection.start, selection.end, markdown);
|
||||
controller.text = newText;
|
||||
controller.selection = TextSelection.fromPosition(
|
||||
TextPosition(offset: selection.start + markdown.length),
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> performAction(
|
||||
WidgetRef ref,
|
||||
ComposeState state,
|
||||
|
@ -163,7 +163,7 @@ class PostItem extends HookConsumerWidget {
|
||||
if ((item.repliedPost != null || item.forwardedPost != null) &&
|
||||
showReferencePost)
|
||||
_buildReferencePost(context, item),
|
||||
if (item.attachments.isNotEmpty)
|
||||
if (item.attachments.isNotEmpty && item.type != 1)
|
||||
CloudFileList(
|
||||
files: item.attachments,
|
||||
maxWidth: math.min(
|
||||
@ -331,6 +331,7 @@ class PostItem extends HookConsumerWidget {
|
||||
item.type == 0
|
||||
? EdgeInsets.only(bottom: 8)
|
||||
: null,
|
||||
attachments: item.attachments,
|
||||
),
|
||||
],
|
||||
// Render tags and categories if they exist
|
||||
@ -389,7 +390,7 @@ class PostItem extends HookConsumerWidget {
|
||||
item.forwardedPost != null) &&
|
||||
showReferencePost)
|
||||
_buildReferencePost(context, item),
|
||||
if (item.attachments.isNotEmpty)
|
||||
if (item.attachments.isNotEmpty && item.type != 1)
|
||||
CloudFileList(
|
||||
files: item.attachments,
|
||||
maxWidth: math.min(
|
||||
@ -689,6 +690,7 @@ Widget _buildReferencePost(BuildContext context, SnPost item) {
|
||||
referencePost.type == 0
|
||||
? EdgeInsets.only(bottom: 4)
|
||||
: null,
|
||||
attachments: item.attachments,
|
||||
).padding(bottom: 4),
|
||||
// Truncation hint for referenced post
|
||||
if (referencePost.isTruncated)
|
||||
@ -696,7 +698,8 @@ Widget _buildReferencePost(BuildContext context, SnPost item) {
|
||||
isCompact: true,
|
||||
margin: const EdgeInsets.only(top: 4, bottom: 8),
|
||||
),
|
||||
if (referencePost.attachments.isNotEmpty)
|
||||
if (referencePost.attachments.isNotEmpty &&
|
||||
referencePost.type != 1)
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
@ -1030,6 +1033,7 @@ class _ArticlePostDisplay extends StatelessWidget {
|
||||
MarkdownTextContent(
|
||||
content: item.content!,
|
||||
textStyle: Theme.of(context).textTheme.bodyLarge,
|
||||
attachments: item.attachments,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/post.dart';
|
||||
import 'package:island/pods/userinfo.dart';
|
||||
import 'package:island/widgets/content/sheet.dart';
|
||||
import 'package:island/widgets/post/post_replies.dart';
|
||||
import 'package:island/widgets/post/post_quick_reply.dart';
|
||||
@ -14,6 +15,8 @@ class PostRepliesSheet extends HookConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final user = ref.watch(userInfoProvider);
|
||||
|
||||
return SheetScaffold(
|
||||
titleText: 'repliesCount'.plural(post.repliesCount),
|
||||
child: Column(
|
||||
@ -21,13 +24,16 @@ class PostRepliesSheet extends HookConsumerWidget {
|
||||
// Replies list
|
||||
Expanded(
|
||||
child: CustomScrollView(
|
||||
slivers: [PostRepliesList(
|
||||
slivers: [
|
||||
PostRepliesList(
|
||||
postId: post.id.toString(),
|
||||
backgroundColor: Colors.transparent,
|
||||
)],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Quick reply section
|
||||
if (user.value != null)
|
||||
Material(
|
||||
elevation: 2,
|
||||
child: PostQuickReply(
|
||||
|
Loading…
x
Reference in New Issue
Block a user