Compare commits
2 Commits
3ffe3cb50f
...
c1e10916ee
Author | SHA1 | Date | |
---|---|---|---|
c1e10916ee | |||
0a8c9fb208 |
@ -1,4 +1,6 @@
|
||||
{
|
||||
"nextVersionAlert": "Heavy Development Alert",
|
||||
"nextVersionNotice": "You are using Solian 2.0 Preview, which is the first version of Solian 2.0. The current stable branch (sn.solsynth.dev) is 1.4. This version is still under heavy development, some features may not be stable, and not all features are supported. You can roll back to 1.4.X version via TestFlight, or continue to experience the new version (sn-next.solsynth.dev).",
|
||||
"screen": "Screen",
|
||||
"screenHome": "Home",
|
||||
"screenExplore": "Explore",
|
||||
@ -32,6 +34,8 @@
|
||||
"loading": "Loading...",
|
||||
"delete": "Delete",
|
||||
"report": "Report",
|
||||
"repost": "Repost",
|
||||
"reply": "Reply",
|
||||
"fieldUsername": "Username",
|
||||
"fieldNickname": "Nickname",
|
||||
"fieldEmail": "Email address",
|
||||
@ -74,5 +78,7 @@
|
||||
"fieldPostTitle": "Title",
|
||||
"fieldPostDescription": "Description",
|
||||
"postPublish": "Publish",
|
||||
"postEditingNotice": "You're about to editing a post that posted {}."
|
||||
"postEditingNotice": "You're about to editing a post that posted {}.",
|
||||
"postReplyingNotice": "You're about to reply to a post that posted {}.",
|
||||
"postRepostingNotice": "You're about to repost a post that posted {}."
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
{
|
||||
"nextVersionAlert": "高强度开发提示",
|
||||
"nextVersionNotice": "您正在使用的是 Solian 2.0 的抢先体验版本,目前稳定分支(sn.solsynth.dev)版本为 1.4。该版本还在持续的开发中,部分功能可能不稳定,也并非所有功能都支持了。您可以通过 TestFlight 回滚到 1.4.X 或者继续体验新版本(sn-next.solsynth.dev)。",
|
||||
"screen": "页面",
|
||||
"screenHome": "首页",
|
||||
"screenExplore": "探索",
|
||||
@ -32,6 +34,8 @@
|
||||
"preview": "预览",
|
||||
"delete": "删除",
|
||||
"report": "检举",
|
||||
"repost": "转帖",
|
||||
"reply": "回贴",
|
||||
"fieldUsername": "用户名",
|
||||
"fieldNickname": "显示名",
|
||||
"fieldEmail": "电子邮箱地址",
|
||||
@ -74,5 +78,7 @@
|
||||
"fieldPostTitle": "标题",
|
||||
"fieldPostDescription": "描述",
|
||||
"postPublish": "发布",
|
||||
"postEditingNotice": "你正在修改由 {} 发布的帖子。"
|
||||
"postEditingNotice": "你正在修改由 {} 发布的帖子。",
|
||||
"postReplyingNotice": "你正在回复由 {} 发布的帖子。",
|
||||
"postRepostingNotice": "你正在转发由 {} 发布的帖子。"
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class HomeScreen extends StatefulWidget {
|
||||
const HomeScreen({super.key});
|
||||
@ -16,6 +18,23 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
appBar: AppBar(
|
||||
title: Text("screenHome").tr(),
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
MaterialBanner(
|
||||
leading: const Icon(Symbols.construction),
|
||||
content: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('nextVersionAlert').tr().bold(),
|
||||
Text('nextVersionNotice').tr(),
|
||||
],
|
||||
).padding(vertical: 16),
|
||||
actions: [
|
||||
const SizedBox(),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -191,6 +191,8 @@ class _PostEditorScreenState extends State<PostEditorScreen> {
|
||||
'title': _title,
|
||||
'description': _description,
|
||||
'attachments': _attachments.map((e) => e.rid).toList(),
|
||||
if (_replyingTo != null) 'reply_to': _replyingTo!.id,
|
||||
if (_repostingTo != null) 'repost_to': _repostingTo!.id,
|
||||
},
|
||||
onSendProgress: (count, total) {
|
||||
setState(() {
|
||||
@ -385,19 +387,58 @@ class _PostEditorScreenState extends State<PostEditorScreen> {
|
||||
const Divider(height: 1),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding: EdgeInsets.only(
|
||||
top: _editingOg == null ? 8 : 0,
|
||||
bottom: 8,
|
||||
),
|
||||
padding: EdgeInsets.only(bottom: 8),
|
||||
child: Column(
|
||||
children: [
|
||||
// Replying Notice
|
||||
if (_replyingTo != null)
|
||||
Column(
|
||||
children: [
|
||||
Theme(
|
||||
data: Theme.of(context).copyWith(
|
||||
dividerColor: Colors.transparent,
|
||||
),
|
||||
child: ExpansionTile(
|
||||
minTileHeight: 48,
|
||||
leading: const Icon(Symbols.reply).padding(left: 4),
|
||||
title: Text('postReplyingNotice')
|
||||
.fontSize(15)
|
||||
.tr(args: ['@${_replyingTo!.publisher.name}']),
|
||||
children: <Widget>[PostItem(data: _replyingTo!)],
|
||||
),
|
||||
),
|
||||
const Divider(height: 1),
|
||||
],
|
||||
),
|
||||
// Reposting Notice
|
||||
if (_repostingTo != null)
|
||||
Column(
|
||||
children: [
|
||||
Theme(
|
||||
data: Theme.of(context).copyWith(
|
||||
dividerColor: Colors.transparent,
|
||||
),
|
||||
child: ExpansionTile(
|
||||
minTileHeight: 48,
|
||||
leading:
|
||||
const Icon(Symbols.forward).padding(left: 4),
|
||||
title: Text('postRepostingNotice')
|
||||
.fontSize(15)
|
||||
.tr(args: ['@${_repostingTo!.publisher.name}']),
|
||||
children: <Widget>[PostItem(data: _repostingTo!)],
|
||||
),
|
||||
),
|
||||
const Divider(height: 1),
|
||||
],
|
||||
),
|
||||
// Editing Notice
|
||||
if (_editingOg != null)
|
||||
Column(
|
||||
children: [
|
||||
Theme(
|
||||
data: Theme.of(context)
|
||||
.copyWith(dividerColor: Colors.transparent),
|
||||
data: Theme.of(context).copyWith(
|
||||
dividerColor: Colors.transparent,
|
||||
),
|
||||
child: ExpansionTile(
|
||||
minTileHeight: 48,
|
||||
leading:
|
||||
@ -405,13 +446,10 @@ class _PostEditorScreenState extends State<PostEditorScreen> {
|
||||
title: Text('postEditingNotice')
|
||||
.fontSize(15)
|
||||
.tr(args: ['@${_editingOg!.publisher.name}']),
|
||||
children: <Widget>[
|
||||
PostItem(data: _editingOg!),
|
||||
],
|
||||
children: <Widget>[PostItem(data: _editingOg!)],
|
||||
),
|
||||
),
|
||||
const Divider(height: 1),
|
||||
const Gap(8)
|
||||
],
|
||||
),
|
||||
// Content Input Area
|
||||
@ -430,7 +468,8 @@ class _PostEditorScreenState extends State<PostEditorScreen> {
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
)
|
||||
],
|
||||
].expand((ele) => [ele, const Gap(8)]).toList()
|
||||
..removeLast(),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -448,7 +487,7 @@ class _PostEditorScreenState extends State<PostEditorScreen> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
LoadingIndicator(isActive: _isBusy),
|
||||
LoadingIndicator(isActive: _isLoading),
|
||||
if (_isBusy && _progress != null)
|
||||
TweenAnimationBuilder<double>(
|
||||
tween: Tween(begin: 0, end: 1),
|
||||
|
@ -33,7 +33,7 @@ class SnPost with _$SnPost {
|
||||
required DateTime? pinnedAt,
|
||||
required DateTime? lockedAt,
|
||||
required bool isDraft,
|
||||
required DateTime publishedAt,
|
||||
required DateTime? publishedAt,
|
||||
required dynamic publishedUntil,
|
||||
required int totalUpvote,
|
||||
required int totalDownvote,
|
||||
|
@ -44,7 +44,7 @@ mixin _$SnPost {
|
||||
DateTime? get pinnedAt => throw _privateConstructorUsedError;
|
||||
DateTime? get lockedAt => throw _privateConstructorUsedError;
|
||||
bool get isDraft => throw _privateConstructorUsedError;
|
||||
DateTime get publishedAt => throw _privateConstructorUsedError;
|
||||
DateTime? get publishedAt => throw _privateConstructorUsedError;
|
||||
dynamic get publishedUntil => throw _privateConstructorUsedError;
|
||||
int get totalUpvote => throw _privateConstructorUsedError;
|
||||
int get totalDownvote => throw _privateConstructorUsedError;
|
||||
@ -94,7 +94,7 @@ abstract class $SnPostCopyWith<$Res> {
|
||||
DateTime? pinnedAt,
|
||||
DateTime? lockedAt,
|
||||
bool isDraft,
|
||||
DateTime publishedAt,
|
||||
DateTime? publishedAt,
|
||||
dynamic publishedUntil,
|
||||
int totalUpvote,
|
||||
int totalDownvote,
|
||||
@ -149,7 +149,7 @@ class _$SnPostCopyWithImpl<$Res, $Val extends SnPost>
|
||||
Object? pinnedAt = freezed,
|
||||
Object? lockedAt = freezed,
|
||||
Object? isDraft = null,
|
||||
Object? publishedAt = null,
|
||||
Object? publishedAt = freezed,
|
||||
Object? publishedUntil = freezed,
|
||||
Object? totalUpvote = null,
|
||||
Object? totalDownvote = null,
|
||||
@ -257,10 +257,10 @@ class _$SnPostCopyWithImpl<$Res, $Val extends SnPost>
|
||||
? _value.isDraft
|
||||
: isDraft // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
publishedAt: null == publishedAt
|
||||
publishedAt: freezed == publishedAt
|
||||
? _value.publishedAt
|
||||
: publishedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
as DateTime?,
|
||||
publishedUntil: freezed == publishedUntil
|
||||
? _value.publishedUntil
|
||||
: publishedUntil // ignore: cast_nullable_to_non_nullable
|
||||
@ -367,7 +367,7 @@ abstract class _$$SnPostImplCopyWith<$Res> implements $SnPostCopyWith<$Res> {
|
||||
DateTime? pinnedAt,
|
||||
DateTime? lockedAt,
|
||||
bool isDraft,
|
||||
DateTime publishedAt,
|
||||
DateTime? publishedAt,
|
||||
dynamic publishedUntil,
|
||||
int totalUpvote,
|
||||
int totalDownvote,
|
||||
@ -423,7 +423,7 @@ class __$$SnPostImplCopyWithImpl<$Res>
|
||||
Object? pinnedAt = freezed,
|
||||
Object? lockedAt = freezed,
|
||||
Object? isDraft = null,
|
||||
Object? publishedAt = null,
|
||||
Object? publishedAt = freezed,
|
||||
Object? publishedUntil = freezed,
|
||||
Object? totalUpvote = null,
|
||||
Object? totalDownvote = null,
|
||||
@ -531,10 +531,10 @@ class __$$SnPostImplCopyWithImpl<$Res>
|
||||
? _value.isDraft
|
||||
: isDraft // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
publishedAt: null == publishedAt
|
||||
publishedAt: freezed == publishedAt
|
||||
? _value.publishedAt
|
||||
: publishedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
as DateTime?,
|
||||
publishedUntil: freezed == publishedUntil
|
||||
? _value.publishedUntil
|
||||
: publishedUntil // ignore: cast_nullable_to_non_nullable
|
||||
@ -688,7 +688,7 @@ class _$SnPostImpl extends _SnPost {
|
||||
@override
|
||||
final bool isDraft;
|
||||
@override
|
||||
final DateTime publishedAt;
|
||||
final DateTime? publishedAt;
|
||||
@override
|
||||
final dynamic publishedUntil;
|
||||
@override
|
||||
@ -854,7 +854,7 @@ abstract class _SnPost extends SnPost {
|
||||
required final DateTime? pinnedAt,
|
||||
required final DateTime? lockedAt,
|
||||
required final bool isDraft,
|
||||
required final DateTime publishedAt,
|
||||
required final DateTime? publishedAt,
|
||||
required final dynamic publishedUntil,
|
||||
required final int totalUpvote,
|
||||
required final int totalDownvote,
|
||||
@ -917,7 +917,7 @@ abstract class _SnPost extends SnPost {
|
||||
@override
|
||||
bool get isDraft;
|
||||
@override
|
||||
DateTime get publishedAt;
|
||||
DateTime? get publishedAt;
|
||||
@override
|
||||
dynamic get publishedUntil;
|
||||
@override
|
||||
|
@ -39,7 +39,9 @@ _$SnPostImpl _$$SnPostImplFromJson(Map<String, dynamic> json) => _$SnPostImpl(
|
||||
? null
|
||||
: DateTime.parse(json['locked_at'] as String),
|
||||
isDraft: json['is_draft'] as bool,
|
||||
publishedAt: DateTime.parse(json['published_at'] as String),
|
||||
publishedAt: json['published_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['published_at'] as String),
|
||||
publishedUntil: json['published_until'],
|
||||
totalUpvote: (json['total_upvote'] as num).toInt(),
|
||||
totalDownvote: (json['total_downvote'] as num).toInt(),
|
||||
@ -80,7 +82,7 @@ Map<String, dynamic> _$$SnPostImplToJson(_$SnPostImpl instance) =>
|
||||
'pinned_at': instance.pinnedAt?.toIso8601String(),
|
||||
'locked_at': instance.lockedAt?.toIso8601String(),
|
||||
'is_draft': instance.isDraft,
|
||||
'published_at': instance.publishedAt.toIso8601String(),
|
||||
'published_at': instance.publishedAt?.toIso8601String(),
|
||||
'published_until': instance.publishedUntil,
|
||||
'total_upvote': instance.totalUpvote,
|
||||
'total_downvote': instance.totalDownvote,
|
||||
|
@ -2,8 +2,10 @@ import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:relative_time/relative_time.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:surface/providers/userinfo.dart';
|
||||
import 'package:surface/types/post.dart';
|
||||
import 'package:surface/widgets/account/account_image.dart';
|
||||
import 'package:surface/widgets/attachment/attachment_list.dart';
|
||||
@ -34,6 +36,9 @@ class _PostContentHeader extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ua = context.read<UserProvider>();
|
||||
final isAuthor = ua.isAuthorized && data.publisher.accountId == ua.user!.id;
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
AccountImage(content: data.publisher.avatar),
|
||||
@ -47,8 +52,9 @@ class _PostContentHeader extends StatelessWidget {
|
||||
children: [
|
||||
Text('@${data.publisher.name}').fontSize(13),
|
||||
const Gap(4),
|
||||
Text(RelativeTime(context).format(data.publishedAt))
|
||||
.fontSize(13),
|
||||
Text(RelativeTime(context).format(
|
||||
data.publishedAt ?? data.createdAt,
|
||||
)).fontSize(13),
|
||||
],
|
||||
).opacity(0.8),
|
||||
],
|
||||
@ -60,6 +66,7 @@ class _PostContentHeader extends StatelessWidget {
|
||||
visualDensity: VisualDensity(horizontal: -4, vertical: -4),
|
||||
),
|
||||
itemBuilder: (BuildContext context) => <PopupMenuEntry>[
|
||||
if (isAuthor)
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
@ -76,6 +83,7 @@ class _PostContentHeader extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
if (isAuthor)
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
@ -85,6 +93,39 @@ class _PostContentHeader extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
if (isAuthor) const PopupMenuDivider(),
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Symbols.reply),
|
||||
const Gap(16),
|
||||
Text('reply').tr(),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
GoRouter.of(context).pushNamed(
|
||||
'postEditor',
|
||||
pathParameters: {'mode': data.typePlural},
|
||||
queryParameters: {'replying': data.id.toString()},
|
||||
);
|
||||
},
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Symbols.forward),
|
||||
const Gap(16),
|
||||
Text('repost').tr(),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
GoRouter.of(context).pushNamed(
|
||||
'postEditor',
|
||||
pathParameters: {'mode': data.typePlural},
|
||||
queryParameters: {'reposting': data.id.toString()},
|
||||
);
|
||||
},
|
||||
),
|
||||
const PopupMenuDivider(),
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
|
Loading…
x
Reference in New Issue
Block a user