Compare commits
No commits in common. "80a66136ce12622e5eec3178718d4cd5a8877009" and "b750cc3c6776046c2e2519d7d2748a7a3c47f68c" have entirely different histories.
80a66136ce
...
b750cc3c67
@ -444,6 +444,5 @@
|
|||||||
"postImageShareAds": "Explore posts on the Solar Network",
|
"postImageShareAds": "Explore posts on the Solar Network",
|
||||||
"postShare": "Share",
|
"postShare": "Share",
|
||||||
"postShareImage": "Share via Image",
|
"postShareImage": "Share via Image",
|
||||||
"appInitializing": "Initializing",
|
"appInitializing": "Initializing"
|
||||||
"poweredBy": "Powered by {}"
|
|
||||||
}
|
}
|
||||||
|
@ -442,6 +442,5 @@
|
|||||||
"postImageShareAds": "来 Solar Network 探索更多有趣帖子",
|
"postImageShareAds": "来 Solar Network 探索更多有趣帖子",
|
||||||
"postShare": "分享",
|
"postShare": "分享",
|
||||||
"postShareImage": "分享帖图",
|
"postShareImage": "分享帖图",
|
||||||
"appInitializing": "正在初始化",
|
"appInitializing": "正在初始化"
|
||||||
"poweredBy": "由 {} 提供支持"
|
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ import 'package:styled_widget/styled_widget.dart';
|
|||||||
import 'package:surface/firebase_options.dart';
|
import 'package:surface/firebase_options.dart';
|
||||||
import 'package:surface/providers/channel.dart';
|
import 'package:surface/providers/channel.dart';
|
||||||
import 'package:surface/providers/chat_call.dart';
|
import 'package:surface/providers/chat_call.dart';
|
||||||
import 'package:surface/providers/link_preview.dart';
|
|
||||||
import 'package:surface/providers/navigation.dart';
|
import 'package:surface/providers/navigation.dart';
|
||||||
import 'package:surface/providers/notification.dart';
|
import 'package:surface/providers/notification.dart';
|
||||||
import 'package:surface/providers/post.dart';
|
import 'package:surface/providers/post.dart';
|
||||||
@ -93,7 +92,6 @@ class SolianApp extends StatelessWidget {
|
|||||||
Provider(create: (ctx) => SnAttachmentProvider(ctx)),
|
Provider(create: (ctx) => SnAttachmentProvider(ctx)),
|
||||||
Provider(create: (ctx) => SnPostContentProvider(ctx)),
|
Provider(create: (ctx) => SnPostContentProvider(ctx)),
|
||||||
Provider(create: (ctx) => SnRelationshipProvider(ctx)),
|
Provider(create: (ctx) => SnRelationshipProvider(ctx)),
|
||||||
Provider(create: (ctx) => SnLinkPreviewProvider(ctx)),
|
|
||||||
ChangeNotifierProvider(create: (ctx) => UserProvider(ctx)),
|
ChangeNotifierProvider(create: (ctx) => UserProvider(ctx)),
|
||||||
ChangeNotifierProvider(create: (ctx) => WebSocketProvider(ctx)),
|
ChangeNotifierProvider(create: (ctx) => WebSocketProvider(ctx)),
|
||||||
ChangeNotifierProvider(create: (ctx) => NotificationProvider(ctx)),
|
ChangeNotifierProvider(create: (ctx) => NotificationProvider(ctx)),
|
||||||
@ -113,7 +111,7 @@ class SolianApp extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _AppDelegate extends StatelessWidget {
|
class _AppDelegate extends StatelessWidget {
|
||||||
const _AppDelegate();
|
const _AppDelegate({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -136,10 +134,7 @@ class _AppDelegate extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
routerConfig: appRouter,
|
routerConfig: appRouter,
|
||||||
builder: (context, child) {
|
builder: (context, child) {
|
||||||
return _AppSplashScreen(
|
return _AppSplashScreen(child: child!);
|
||||||
key: const Key('global-splash-screen'),
|
|
||||||
child: child!,
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
import 'dart:convert';
|
|
||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:surface/providers/sn_network.dart';
|
|
||||||
import 'package:surface/types/link.dart';
|
|
||||||
|
|
||||||
class SnLinkPreviewProvider {
|
|
||||||
late final SnNetworkProvider _sn;
|
|
||||||
|
|
||||||
final Map<String, SnLinkMeta> _cache = {};
|
|
||||||
|
|
||||||
SnLinkPreviewProvider(BuildContext context) {
|
|
||||||
_sn = context.read<SnNetworkProvider>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<SnLinkMeta?> getLinkMeta(String url) async {
|
|
||||||
final b64 = utf8.fuse(base64Url);
|
|
||||||
final target = b64.encode(url);
|
|
||||||
if (_cache.containsKey(target)) return _cache[target];
|
|
||||||
|
|
||||||
log('[LinkPreview] Fetching $url ($target)');
|
|
||||||
|
|
||||||
try {
|
|
||||||
final resp = await _sn.client.get('/cgi/re/link/$target');
|
|
||||||
final meta = SnLinkMeta.fromJson(resp.data);
|
|
||||||
_cache[url] = meta;
|
|
||||||
return meta;
|
|
||||||
} catch (err) {
|
|
||||||
log('[LinkPreview] Failed to fetch $url ($target)...');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -26,7 +26,6 @@ class WebSocketProvider extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> tryConnect() async {
|
Future<void> tryConnect() async {
|
||||||
if (isConnected) return;
|
|
||||||
if (!_ua.isAuthorized) return;
|
if (!_ua.isAuthorized) return;
|
||||||
|
|
||||||
log('[WebSocket] Connecting to the server...');
|
log('[WebSocket] Connecting to the server...');
|
||||||
@ -77,7 +76,6 @@ class WebSocketProvider extends ChangeNotifier {
|
|||||||
if (conn != null) {
|
if (conn != null) {
|
||||||
conn!.sink.close();
|
conn!.sink.close();
|
||||||
}
|
}
|
||||||
conn = null;
|
|
||||||
isConnected = false;
|
isConnected = false;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
||||||
|
|
||||||
part 'link.g.dart';
|
|
||||||
part 'link.freezed.dart';
|
|
||||||
|
|
||||||
@freezed
|
|
||||||
class SnLinkMeta with _$SnLinkMeta {
|
|
||||||
const SnLinkMeta._();
|
|
||||||
|
|
||||||
const factory SnLinkMeta({
|
|
||||||
required int id,
|
|
||||||
required DateTime createdAt,
|
|
||||||
required DateTime updatedAt,
|
|
||||||
required DateTime? deletedAt,
|
|
||||||
required String entryId,
|
|
||||||
required String? icon,
|
|
||||||
required String url,
|
|
||||||
required String? title,
|
|
||||||
required String? image,
|
|
||||||
required String? video,
|
|
||||||
required String? audio,
|
|
||||||
required String? description,
|
|
||||||
required String? siteName,
|
|
||||||
required String? type,
|
|
||||||
}) = _SnLinkMeta;
|
|
||||||
|
|
||||||
factory SnLinkMeta.fromJson(Map<String, dynamic> json) => _$SnLinkMetaFromJson(json);
|
|
||||||
}
|
|
@ -1,450 +0,0 @@
|
|||||||
// coverage:ignore-file
|
|
||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
|
||||||
|
|
||||||
part of 'link.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// FreezedGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
T _$identity<T>(T value) => value;
|
|
||||||
|
|
||||||
final _privateConstructorUsedError = UnsupportedError(
|
|
||||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
|
||||||
|
|
||||||
SnLinkMeta _$SnLinkMetaFromJson(Map<String, dynamic> json) {
|
|
||||||
return _SnLinkMeta.fromJson(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
mixin _$SnLinkMeta {
|
|
||||||
int get id => throw _privateConstructorUsedError;
|
|
||||||
DateTime get createdAt => throw _privateConstructorUsedError;
|
|
||||||
DateTime get updatedAt => throw _privateConstructorUsedError;
|
|
||||||
DateTime? get deletedAt => throw _privateConstructorUsedError;
|
|
||||||
String get entryId => throw _privateConstructorUsedError;
|
|
||||||
String? get icon => throw _privateConstructorUsedError;
|
|
||||||
String get url => throw _privateConstructorUsedError;
|
|
||||||
String? get title => throw _privateConstructorUsedError;
|
|
||||||
String? get image => throw _privateConstructorUsedError;
|
|
||||||
String? get video => throw _privateConstructorUsedError;
|
|
||||||
String? get audio => throw _privateConstructorUsedError;
|
|
||||||
String? get description => throw _privateConstructorUsedError;
|
|
||||||
String? get siteName => throw _privateConstructorUsedError;
|
|
||||||
String? get type => throw _privateConstructorUsedError;
|
|
||||||
|
|
||||||
/// Serializes this SnLinkMeta to a JSON map.
|
|
||||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
|
||||||
|
|
||||||
/// Create a copy of SnLinkMeta
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
$SnLinkMetaCopyWith<SnLinkMeta> get copyWith =>
|
|
||||||
throw _privateConstructorUsedError;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract class $SnLinkMetaCopyWith<$Res> {
|
|
||||||
factory $SnLinkMetaCopyWith(
|
|
||||||
SnLinkMeta value, $Res Function(SnLinkMeta) then) =
|
|
||||||
_$SnLinkMetaCopyWithImpl<$Res, SnLinkMeta>;
|
|
||||||
@useResult
|
|
||||||
$Res call(
|
|
||||||
{int id,
|
|
||||||
DateTime createdAt,
|
|
||||||
DateTime updatedAt,
|
|
||||||
DateTime? deletedAt,
|
|
||||||
String entryId,
|
|
||||||
String? icon,
|
|
||||||
String url,
|
|
||||||
String? title,
|
|
||||||
String? image,
|
|
||||||
String? video,
|
|
||||||
String? audio,
|
|
||||||
String? description,
|
|
||||||
String? siteName,
|
|
||||||
String? type});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
class _$SnLinkMetaCopyWithImpl<$Res, $Val extends SnLinkMeta>
|
|
||||||
implements $SnLinkMetaCopyWith<$Res> {
|
|
||||||
_$SnLinkMetaCopyWithImpl(this._value, this._then);
|
|
||||||
|
|
||||||
// ignore: unused_field
|
|
||||||
final $Val _value;
|
|
||||||
// ignore: unused_field
|
|
||||||
final $Res Function($Val) _then;
|
|
||||||
|
|
||||||
/// Create a copy of SnLinkMeta
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
@override
|
|
||||||
$Res call({
|
|
||||||
Object? id = null,
|
|
||||||
Object? createdAt = null,
|
|
||||||
Object? updatedAt = null,
|
|
||||||
Object? deletedAt = freezed,
|
|
||||||
Object? entryId = null,
|
|
||||||
Object? icon = freezed,
|
|
||||||
Object? url = null,
|
|
||||||
Object? title = freezed,
|
|
||||||
Object? image = freezed,
|
|
||||||
Object? video = freezed,
|
|
||||||
Object? audio = freezed,
|
|
||||||
Object? description = freezed,
|
|
||||||
Object? siteName = freezed,
|
|
||||||
Object? type = freezed,
|
|
||||||
}) {
|
|
||||||
return _then(_value.copyWith(
|
|
||||||
id: null == id
|
|
||||||
? _value.id
|
|
||||||
: id // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int,
|
|
||||||
createdAt: null == createdAt
|
|
||||||
? _value.createdAt
|
|
||||||
: createdAt // ignore: cast_nullable_to_non_nullable
|
|
||||||
as DateTime,
|
|
||||||
updatedAt: null == updatedAt
|
|
||||||
? _value.updatedAt
|
|
||||||
: updatedAt // ignore: cast_nullable_to_non_nullable
|
|
||||||
as DateTime,
|
|
||||||
deletedAt: freezed == deletedAt
|
|
||||||
? _value.deletedAt
|
|
||||||
: deletedAt // ignore: cast_nullable_to_non_nullable
|
|
||||||
as DateTime?,
|
|
||||||
entryId: null == entryId
|
|
||||||
? _value.entryId
|
|
||||||
: entryId // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,
|
|
||||||
icon: freezed == icon
|
|
||||||
? _value.icon
|
|
||||||
: icon // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,
|
|
||||||
url: null == url
|
|
||||||
? _value.url
|
|
||||||
: url // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,
|
|
||||||
title: freezed == title
|
|
||||||
? _value.title
|
|
||||||
: title // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,
|
|
||||||
image: freezed == image
|
|
||||||
? _value.image
|
|
||||||
: image // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,
|
|
||||||
video: freezed == video
|
|
||||||
? _value.video
|
|
||||||
: video // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,
|
|
||||||
audio: freezed == audio
|
|
||||||
? _value.audio
|
|
||||||
: audio // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,
|
|
||||||
description: freezed == description
|
|
||||||
? _value.description
|
|
||||||
: description // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,
|
|
||||||
siteName: freezed == siteName
|
|
||||||
? _value.siteName
|
|
||||||
: siteName // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,
|
|
||||||
type: freezed == type
|
|
||||||
? _value.type
|
|
||||||
: type // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,
|
|
||||||
) as $Val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract class _$$SnLinkMetaImplCopyWith<$Res>
|
|
||||||
implements $SnLinkMetaCopyWith<$Res> {
|
|
||||||
factory _$$SnLinkMetaImplCopyWith(
|
|
||||||
_$SnLinkMetaImpl value, $Res Function(_$SnLinkMetaImpl) then) =
|
|
||||||
__$$SnLinkMetaImplCopyWithImpl<$Res>;
|
|
||||||
@override
|
|
||||||
@useResult
|
|
||||||
$Res call(
|
|
||||||
{int id,
|
|
||||||
DateTime createdAt,
|
|
||||||
DateTime updatedAt,
|
|
||||||
DateTime? deletedAt,
|
|
||||||
String entryId,
|
|
||||||
String? icon,
|
|
||||||
String url,
|
|
||||||
String? title,
|
|
||||||
String? image,
|
|
||||||
String? video,
|
|
||||||
String? audio,
|
|
||||||
String? description,
|
|
||||||
String? siteName,
|
|
||||||
String? type});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
class __$$SnLinkMetaImplCopyWithImpl<$Res>
|
|
||||||
extends _$SnLinkMetaCopyWithImpl<$Res, _$SnLinkMetaImpl>
|
|
||||||
implements _$$SnLinkMetaImplCopyWith<$Res> {
|
|
||||||
__$$SnLinkMetaImplCopyWithImpl(
|
|
||||||
_$SnLinkMetaImpl _value, $Res Function(_$SnLinkMetaImpl) _then)
|
|
||||||
: super(_value, _then);
|
|
||||||
|
|
||||||
/// Create a copy of SnLinkMeta
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
@override
|
|
||||||
$Res call({
|
|
||||||
Object? id = null,
|
|
||||||
Object? createdAt = null,
|
|
||||||
Object? updatedAt = null,
|
|
||||||
Object? deletedAt = freezed,
|
|
||||||
Object? entryId = null,
|
|
||||||
Object? icon = freezed,
|
|
||||||
Object? url = null,
|
|
||||||
Object? title = freezed,
|
|
||||||
Object? image = freezed,
|
|
||||||
Object? video = freezed,
|
|
||||||
Object? audio = freezed,
|
|
||||||
Object? description = freezed,
|
|
||||||
Object? siteName = freezed,
|
|
||||||
Object? type = freezed,
|
|
||||||
}) {
|
|
||||||
return _then(_$SnLinkMetaImpl(
|
|
||||||
id: null == id
|
|
||||||
? _value.id
|
|
||||||
: id // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int,
|
|
||||||
createdAt: null == createdAt
|
|
||||||
? _value.createdAt
|
|
||||||
: createdAt // ignore: cast_nullable_to_non_nullable
|
|
||||||
as DateTime,
|
|
||||||
updatedAt: null == updatedAt
|
|
||||||
? _value.updatedAt
|
|
||||||
: updatedAt // ignore: cast_nullable_to_non_nullable
|
|
||||||
as DateTime,
|
|
||||||
deletedAt: freezed == deletedAt
|
|
||||||
? _value.deletedAt
|
|
||||||
: deletedAt // ignore: cast_nullable_to_non_nullable
|
|
||||||
as DateTime?,
|
|
||||||
entryId: null == entryId
|
|
||||||
? _value.entryId
|
|
||||||
: entryId // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,
|
|
||||||
icon: freezed == icon
|
|
||||||
? _value.icon
|
|
||||||
: icon // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,
|
|
||||||
url: null == url
|
|
||||||
? _value.url
|
|
||||||
: url // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String,
|
|
||||||
title: freezed == title
|
|
||||||
? _value.title
|
|
||||||
: title // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,
|
|
||||||
image: freezed == image
|
|
||||||
? _value.image
|
|
||||||
: image // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,
|
|
||||||
video: freezed == video
|
|
||||||
? _value.video
|
|
||||||
: video // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,
|
|
||||||
audio: freezed == audio
|
|
||||||
? _value.audio
|
|
||||||
: audio // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,
|
|
||||||
description: freezed == description
|
|
||||||
? _value.description
|
|
||||||
: description // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,
|
|
||||||
siteName: freezed == siteName
|
|
||||||
? _value.siteName
|
|
||||||
: siteName // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,
|
|
||||||
type: freezed == type
|
|
||||||
? _value.type
|
|
||||||
: type // ignore: cast_nullable_to_non_nullable
|
|
||||||
as String?,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
@JsonSerializable()
|
|
||||||
class _$SnLinkMetaImpl extends _SnLinkMeta {
|
|
||||||
const _$SnLinkMetaImpl(
|
|
||||||
{required this.id,
|
|
||||||
required this.createdAt,
|
|
||||||
required this.updatedAt,
|
|
||||||
required this.deletedAt,
|
|
||||||
required this.entryId,
|
|
||||||
required this.icon,
|
|
||||||
required this.url,
|
|
||||||
required this.title,
|
|
||||||
required this.image,
|
|
||||||
required this.video,
|
|
||||||
required this.audio,
|
|
||||||
required this.description,
|
|
||||||
required this.siteName,
|
|
||||||
required this.type})
|
|
||||||
: super._();
|
|
||||||
|
|
||||||
factory _$SnLinkMetaImpl.fromJson(Map<String, dynamic> json) =>
|
|
||||||
_$$SnLinkMetaImplFromJson(json);
|
|
||||||
|
|
||||||
@override
|
|
||||||
final int id;
|
|
||||||
@override
|
|
||||||
final DateTime createdAt;
|
|
||||||
@override
|
|
||||||
final DateTime updatedAt;
|
|
||||||
@override
|
|
||||||
final DateTime? deletedAt;
|
|
||||||
@override
|
|
||||||
final String entryId;
|
|
||||||
@override
|
|
||||||
final String? icon;
|
|
||||||
@override
|
|
||||||
final String url;
|
|
||||||
@override
|
|
||||||
final String? title;
|
|
||||||
@override
|
|
||||||
final String? image;
|
|
||||||
@override
|
|
||||||
final String? video;
|
|
||||||
@override
|
|
||||||
final String? audio;
|
|
||||||
@override
|
|
||||||
final String? description;
|
|
||||||
@override
|
|
||||||
final String? siteName;
|
|
||||||
@override
|
|
||||||
final String? type;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'SnLinkMeta(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, entryId: $entryId, icon: $icon, url: $url, title: $title, image: $image, video: $video, audio: $audio, description: $description, siteName: $siteName, type: $type)';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) ||
|
|
||||||
(other.runtimeType == runtimeType &&
|
|
||||||
other is _$SnLinkMetaImpl &&
|
|
||||||
(identical(other.id, id) || other.id == id) &&
|
|
||||||
(identical(other.createdAt, createdAt) ||
|
|
||||||
other.createdAt == createdAt) &&
|
|
||||||
(identical(other.updatedAt, updatedAt) ||
|
|
||||||
other.updatedAt == updatedAt) &&
|
|
||||||
(identical(other.deletedAt, deletedAt) ||
|
|
||||||
other.deletedAt == deletedAt) &&
|
|
||||||
(identical(other.entryId, entryId) || other.entryId == entryId) &&
|
|
||||||
(identical(other.icon, icon) || other.icon == icon) &&
|
|
||||||
(identical(other.url, url) || other.url == url) &&
|
|
||||||
(identical(other.title, title) || other.title == title) &&
|
|
||||||
(identical(other.image, image) || other.image == image) &&
|
|
||||||
(identical(other.video, video) || other.video == video) &&
|
|
||||||
(identical(other.audio, audio) || other.audio == audio) &&
|
|
||||||
(identical(other.description, description) ||
|
|
||||||
other.description == description) &&
|
|
||||||
(identical(other.siteName, siteName) ||
|
|
||||||
other.siteName == siteName) &&
|
|
||||||
(identical(other.type, type) || other.type == type));
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(
|
|
||||||
runtimeType,
|
|
||||||
id,
|
|
||||||
createdAt,
|
|
||||||
updatedAt,
|
|
||||||
deletedAt,
|
|
||||||
entryId,
|
|
||||||
icon,
|
|
||||||
url,
|
|
||||||
title,
|
|
||||||
image,
|
|
||||||
video,
|
|
||||||
audio,
|
|
||||||
description,
|
|
||||||
siteName,
|
|
||||||
type);
|
|
||||||
|
|
||||||
/// Create a copy of SnLinkMeta
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@override
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
_$$SnLinkMetaImplCopyWith<_$SnLinkMetaImpl> get copyWith =>
|
|
||||||
__$$SnLinkMetaImplCopyWithImpl<_$SnLinkMetaImpl>(this, _$identity);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Map<String, dynamic> toJson() {
|
|
||||||
return _$$SnLinkMetaImplToJson(
|
|
||||||
this,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class _SnLinkMeta extends SnLinkMeta {
|
|
||||||
const factory _SnLinkMeta(
|
|
||||||
{required final int id,
|
|
||||||
required final DateTime createdAt,
|
|
||||||
required final DateTime updatedAt,
|
|
||||||
required final DateTime? deletedAt,
|
|
||||||
required final String entryId,
|
|
||||||
required final String? icon,
|
|
||||||
required final String url,
|
|
||||||
required final String? title,
|
|
||||||
required final String? image,
|
|
||||||
required final String? video,
|
|
||||||
required final String? audio,
|
|
||||||
required final String? description,
|
|
||||||
required final String? siteName,
|
|
||||||
required final String? type}) = _$SnLinkMetaImpl;
|
|
||||||
const _SnLinkMeta._() : super._();
|
|
||||||
|
|
||||||
factory _SnLinkMeta.fromJson(Map<String, dynamic> json) =
|
|
||||||
_$SnLinkMetaImpl.fromJson;
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get id;
|
|
||||||
@override
|
|
||||||
DateTime get createdAt;
|
|
||||||
@override
|
|
||||||
DateTime get updatedAt;
|
|
||||||
@override
|
|
||||||
DateTime? get deletedAt;
|
|
||||||
@override
|
|
||||||
String get entryId;
|
|
||||||
@override
|
|
||||||
String? get icon;
|
|
||||||
@override
|
|
||||||
String get url;
|
|
||||||
@override
|
|
||||||
String? get title;
|
|
||||||
@override
|
|
||||||
String? get image;
|
|
||||||
@override
|
|
||||||
String? get video;
|
|
||||||
@override
|
|
||||||
String? get audio;
|
|
||||||
@override
|
|
||||||
String? get description;
|
|
||||||
@override
|
|
||||||
String? get siteName;
|
|
||||||
@override
|
|
||||||
String? get type;
|
|
||||||
|
|
||||||
/// Create a copy of SnLinkMeta
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@override
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
_$$SnLinkMetaImplCopyWith<_$SnLinkMetaImpl> get copyWith =>
|
|
||||||
throw _privateConstructorUsedError;
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'link.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// JsonSerializableGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
_$SnLinkMetaImpl _$$SnLinkMetaImplFromJson(Map<String, dynamic> json) =>
|
|
||||||
_$SnLinkMetaImpl(
|
|
||||||
id: (json['id'] as num).toInt(),
|
|
||||||
createdAt: DateTime.parse(json['created_at'] as String),
|
|
||||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
|
||||||
deletedAt: json['deleted_at'] == null
|
|
||||||
? null
|
|
||||||
: DateTime.parse(json['deleted_at'] as String),
|
|
||||||
entryId: json['entry_id'] as String,
|
|
||||||
icon: json['icon'] as String?,
|
|
||||||
url: json['url'] as String,
|
|
||||||
title: json['title'] as String?,
|
|
||||||
image: json['image'] as String?,
|
|
||||||
video: json['video'] as String?,
|
|
||||||
audio: json['audio'] as String?,
|
|
||||||
description: json['description'] as String?,
|
|
||||||
siteName: json['site_name'] as String?,
|
|
||||||
type: json['type'] as String?,
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> _$$SnLinkMetaImplToJson(_$SnLinkMetaImpl instance) =>
|
|
||||||
<String, dynamic>{
|
|
||||||
'id': instance.id,
|
|
||||||
'created_at': instance.createdAt.toIso8601String(),
|
|
||||||
'updated_at': instance.updatedAt.toIso8601String(),
|
|
||||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
|
||||||
'entry_id': instance.entryId,
|
|
||||||
'icon': instance.icon,
|
|
||||||
'url': instance.url,
|
|
||||||
'title': instance.title,
|
|
||||||
'image': instance.image,
|
|
||||||
'video': instance.video,
|
|
||||||
'audio': instance.audio,
|
|
||||||
'description': instance.description,
|
|
||||||
'site_name': instance.siteName,
|
|
||||||
'type': instance.type,
|
|
||||||
};
|
|
@ -10,7 +10,6 @@ import 'package:surface/providers/userinfo.dart';
|
|||||||
import 'package:surface/types/chat.dart';
|
import 'package:surface/types/chat.dart';
|
||||||
import 'package:surface/widgets/account/account_image.dart';
|
import 'package:surface/widgets/account/account_image.dart';
|
||||||
import 'package:surface/widgets/attachment/attachment_list.dart';
|
import 'package:surface/widgets/attachment/attachment_list.dart';
|
||||||
import 'package:surface/widgets/link_preview.dart';
|
|
||||||
import 'package:surface/widgets/markdown_content.dart';
|
import 'package:surface/widgets/markdown_content.dart';
|
||||||
import 'package:swipe_to/swipe_to.dart';
|
import 'package:swipe_to/swipe_to.dart';
|
||||||
|
|
||||||
@ -23,7 +22,6 @@ class ChatMessage extends StatelessWidget {
|
|||||||
final Function(SnChatMessage)? onReply;
|
final Function(SnChatMessage)? onReply;
|
||||||
final Function(SnChatMessage)? onEdit;
|
final Function(SnChatMessage)? onEdit;
|
||||||
final Function(SnChatMessage)? onDelete;
|
final Function(SnChatMessage)? onDelete;
|
||||||
|
|
||||||
const ChatMessage({
|
const ChatMessage({
|
||||||
super.key,
|
super.key,
|
||||||
required this.data,
|
required this.data,
|
||||||
@ -65,7 +63,7 @@ class ChatMessage extends StatelessWidget {
|
|||||||
onReply!(data);
|
onReply!(data);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (isOwner && data.type == 'messages.new' && onEdit != null)
|
if (isOwner && onEdit != null)
|
||||||
MenuItem(
|
MenuItem(
|
||||||
label: 'edit'.tr(),
|
label: 'edit'.tr(),
|
||||||
icon: Symbols.edit,
|
icon: Symbols.edit,
|
||||||
@ -73,7 +71,7 @@ class ChatMessage extends StatelessWidget {
|
|||||||
onEdit!(data);
|
onEdit!(data);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (isOwner && data.type == 'messages.new' && onDelete != null)
|
if (isOwner && onDelete != null)
|
||||||
MenuItem(
|
MenuItem(
|
||||||
label: 'delete'.tr(),
|
label: 'delete'.tr(),
|
||||||
icon: Symbols.delete,
|
icon: Symbols.delete,
|
||||||
@ -111,7 +109,9 @@ class ChatMessage extends StatelessWidget {
|
|||||||
radius: 12,
|
radius: 12,
|
||||||
).padding(right: 6),
|
).padding(right: 6),
|
||||||
Text(
|
Text(
|
||||||
(data.sender.nick?.isNotEmpty ?? false) ? data.sender.nick! : user?.nick ?? 'unknown',
|
(data.sender.nick?.isNotEmpty ?? false)
|
||||||
|
? data.sender.nick!
|
||||||
|
: user?.nick ?? 'unknown',
|
||||||
).bold(),
|
).bold(),
|
||||||
const Gap(6),
|
const Gap(6),
|
||||||
Text(
|
Text(
|
||||||
@ -123,7 +123,8 @@ class ChatMessage extends StatelessWidget {
|
|||||||
if (data.preload?.quoteEvent != null)
|
if (data.preload?.quoteEvent != null)
|
||||||
StyledWidget(Container(
|
StyledWidget(Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
borderRadius:
|
||||||
|
const BorderRadius.all(Radius.circular(8)),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: Theme.of(context).dividerColor,
|
color: Theme.of(context).dividerColor,
|
||||||
width: 1,
|
width: 1,
|
||||||
@ -152,8 +153,6 @@ class ChatMessage extends StatelessWidget {
|
|||||||
)
|
)
|
||||||
],
|
],
|
||||||
).opacity(isPending ? 0.5 : 1),
|
).opacity(isPending ? 0.5 : 1),
|
||||||
if (data.body['text'] != null && (data.body['text']?.isNotEmpty ?? false))
|
|
||||||
LinkPreviewWidget(text: data.body['text']!),
|
|
||||||
if (data.preload?.attachments?.isNotEmpty ?? false)
|
if (data.preload?.attachments?.isNotEmpty ?? false)
|
||||||
AttachmentList(
|
AttachmentList(
|
||||||
data: data.preload!.attachments!,
|
data: data.preload!.attachments!,
|
||||||
@ -162,7 +161,10 @@ class ChatMessage extends StatelessWidget {
|
|||||||
maxHeight: 520,
|
maxHeight: 520,
|
||||||
listPadding: const EdgeInsets.only(top: 8),
|
listPadding: const EdgeInsets.only(top: 8),
|
||||||
),
|
),
|
||||||
if (!hasMerged && !isCompact) const Gap(12) else if (!isCompact) const Gap(6),
|
if (!hasMerged && !isCompact)
|
||||||
|
const Gap(12)
|
||||||
|
else if (!isCompact)
|
||||||
|
const Gap(6),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -172,7 +174,6 @@ class ChatMessage extends StatelessWidget {
|
|||||||
|
|
||||||
class _ChatMessageText extends StatelessWidget {
|
class _ChatMessageText extends StatelessWidget {
|
||||||
final SnChatMessage data;
|
final SnChatMessage data;
|
||||||
|
|
||||||
const _ChatMessageText({super.key, required this.data});
|
const _ChatMessageText({super.key, required this.data});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -183,7 +184,6 @@ class _ChatMessageText extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
MarkdownTextContent(
|
MarkdownTextContent(
|
||||||
content: data.body['text'],
|
content: data.body['text'],
|
||||||
isSelectable: true,
|
|
||||||
isAutoWarp: true,
|
isAutoWarp: true,
|
||||||
),
|
),
|
||||||
if (data.updatedAt != data.createdAt)
|
if (data.updatedAt != data.createdAt)
|
||||||
@ -212,7 +212,6 @@ class _ChatMessageText extends StatelessWidget {
|
|||||||
|
|
||||||
class _ChatMessageSystemNotify extends StatelessWidget {
|
class _ChatMessageSystemNotify extends StatelessWidget {
|
||||||
final SnChatMessage data;
|
final SnChatMessage data;
|
||||||
|
|
||||||
const _ChatMessageSystemNotify({super.key, required this.data});
|
const _ChatMessageSystemNotify({super.key, required this.data});
|
||||||
|
|
||||||
String _formatDuration(Duration duration) {
|
String _formatDuration(Duration duration) {
|
||||||
|
@ -1,170 +0,0 @@
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
|
||||||
import 'package:gap/gap.dart';
|
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
|
||||||
import 'package:marquee/marquee.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:responsive_framework/responsive_framework.dart';
|
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
|
||||||
import 'package:surface/types/link.dart';
|
|
||||||
import 'package:surface/widgets/universal_image.dart';
|
|
||||||
import 'package:url_launcher/url_launcher_string.dart';
|
|
||||||
|
|
||||||
import '../providers/link_preview.dart';
|
|
||||||
|
|
||||||
class LinkPreviewWidget extends StatefulWidget {
|
|
||||||
final String text;
|
|
||||||
|
|
||||||
const LinkPreviewWidget({super.key, required this.text});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<LinkPreviewWidget> createState() => _LinkPreviewWidgetState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _LinkPreviewWidgetState extends State<LinkPreviewWidget> {
|
|
||||||
final List<SnLinkMeta> _links = List.empty(growable: true);
|
|
||||||
|
|
||||||
Future<void> _getLinkMeta() async {
|
|
||||||
final linkRegex = RegExp(r'https?:\/\/[^\s/$.?#].[^\s]*');
|
|
||||||
final links = linkRegex.allMatches(widget.text).map((e) => e.group(0)).toSet();
|
|
||||||
|
|
||||||
final lp = context.read<SnLinkPreviewProvider>();
|
|
||||||
|
|
||||||
final List<Future<SnLinkMeta?>> futures = links.where((e) => e != null).map((e) => lp.getLinkMeta(e!)).toList();
|
|
||||||
final results = await Future.wait(futures);
|
|
||||||
|
|
||||||
_links.addAll(results.where((e) => e != null).map((e) => e!).toList());
|
|
||||||
if (_links.isNotEmpty && mounted) setState(() {});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_getLinkMeta();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
if (_links.isEmpty) return const SizedBox.shrink();
|
|
||||||
|
|
||||||
return Wrap(
|
|
||||||
spacing: 8,
|
|
||||||
runSpacing: 8,
|
|
||||||
children: _links.map((e) => _LinkPreviewEntry(meta: e)).toList(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _LinkPreviewEntry extends StatelessWidget {
|
|
||||||
final SnLinkMeta meta;
|
|
||||||
|
|
||||||
const _LinkPreviewEntry({
|
|
||||||
super.key,
|
|
||||||
required this.meta,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
constraints: BoxConstraints(
|
|
||||||
maxWidth: ResponsiveBreakpoints.of(context).smallerOrEqualTo(MOBILE) ? double.infinity : 480,
|
|
||||||
),
|
|
||||||
child: GestureDetector(
|
|
||||||
child: Card(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
if (meta.image != null)
|
|
||||||
Container(
|
|
||||||
margin: const EdgeInsets.only(bottom: 4),
|
|
||||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
|
||||||
child: AspectRatio(
|
|
||||||
aspectRatio: 16 / 9,
|
|
||||||
child: ClipRRect(
|
|
||||||
child: AutoResizeUniversalImage(
|
|
||||||
meta.image!,
|
|
||||||
fit: BoxFit.contain,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 48,
|
|
||||||
child: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
if (meta.icon?.isNotEmpty ?? false)
|
|
||||||
StyledWidget(
|
|
||||||
meta.icon!.endsWith('.svg')
|
|
||||||
? SvgPicture.network(meta.icon!)
|
|
||||||
: UniversalImage(
|
|
||||||
meta.icon!,
|
|
||||||
width: 36,
|
|
||||||
height: 36,
|
|
||||||
cacheHeight: 36,
|
|
||||||
cacheWidth: 36,
|
|
||||||
),
|
|
||||||
).padding(all: 4, right: 16),
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
height: 24,
|
|
||||||
child: ((meta.title?.length ?? 0) > 40)
|
|
||||||
? Marquee(
|
|
||||||
text: meta.title ?? 'unknown'.tr(),
|
|
||||||
style: TextStyle(fontSize: 17, height: 1),
|
|
||||||
scrollAxis: Axis.horizontal,
|
|
||||||
showFadingOnlyWhenScrolling: true,
|
|
||||||
pauseAfterRound: const Duration(seconds: 3),
|
|
||||||
)
|
|
||||||
: Text(
|
|
||||||
meta.title ?? 'unknown'.tr(),
|
|
||||||
style: TextStyle(fontSize: 17, height: 1),
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (meta.siteName != null)
|
|
||||||
Text(
|
|
||||||
meta.siteName!,
|
|
||||||
style: TextStyle(fontSize: 13, height: 0.9),
|
|
||||||
).fontSize(11),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const Gap(6),
|
|
||||||
],
|
|
||||||
).padding(horizontal: 16),
|
|
||||||
),
|
|
||||||
if (meta.description != null)
|
|
||||||
Text(
|
|
||||||
meta.description!,
|
|
||||||
maxLines: 3,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
).padding(horizontal: 16, bottom: 8),
|
|
||||||
Text(
|
|
||||||
meta.url,
|
|
||||||
style: GoogleFonts.roboto(fontSize: 11, height: 0.9),
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
).opacity(0.75).padding(horizontal: 16),
|
|
||||||
const Gap(4),
|
|
||||||
Text(
|
|
||||||
'poweredBy'.tr(args: ['HyperNet.Reader']),
|
|
||||||
style: GoogleFonts.roboto(fontSize: 11, height: 0.9),
|
|
||||||
).opacity(0.75).padding(horizontal: 16),
|
|
||||||
const Gap(16),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
launchUrlString(meta.url, mode: LaunchMode.externalApplication);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -24,7 +24,6 @@ import 'package:surface/types/reaction.dart';
|
|||||||
import 'package:surface/widgets/account/account_image.dart';
|
import 'package:surface/widgets/account/account_image.dart';
|
||||||
import 'package:surface/widgets/attachment/attachment_list.dart';
|
import 'package:surface/widgets/attachment/attachment_list.dart';
|
||||||
import 'package:surface/widgets/dialog.dart';
|
import 'package:surface/widgets/dialog.dart';
|
||||||
import 'package:surface/widgets/link_preview.dart';
|
|
||||||
import 'package:surface/widgets/markdown_content.dart';
|
import 'package:surface/widgets/markdown_content.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:surface/widgets/post/post_comment_list.dart';
|
import 'package:surface/widgets/post/post_comment_list.dart';
|
||||||
@ -133,7 +132,6 @@ class PostItem extends StatelessWidget {
|
|||||||
_PostContentHeader(
|
_PostContentHeader(
|
||||||
data: data,
|
data: data,
|
||||||
isAuthor: isAuthor,
|
isAuthor: isAuthor,
|
||||||
isRelativeDate: !showFullPost,
|
|
||||||
onShare: () => _doShare(context),
|
onShare: () => _doShare(context),
|
||||||
onShareImage: () => _doShareViaPicture(context),
|
onShareImage: () => _doShareViaPicture(context),
|
||||||
onDeleted: () {
|
onDeleted: () {
|
||||||
@ -206,7 +204,6 @@ class PostItem extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
_PostContentHeader(
|
_PostContentHeader(
|
||||||
isAuthor: isAuthor,
|
isAuthor: isAuthor,
|
||||||
isRelativeDate: !showFullPost,
|
|
||||||
data: data,
|
data: data,
|
||||||
showMenu: showMenu,
|
showMenu: showMenu,
|
||||||
onShare: () => _doShare(context),
|
onShare: () => _doShare(context),
|
||||||
@ -220,10 +217,8 @@ class PostItem extends StatelessWidget {
|
|||||||
data: data,
|
data: data,
|
||||||
isEnlarge: data.type == 'article' && showFullPost,
|
isEnlarge: data.type == 'article' && showFullPost,
|
||||||
).padding(horizontal: 16, bottom: 8),
|
).padding(horizontal: 16, bottom: 8),
|
||||||
if (data.body['content']?.isNotEmpty ?? false)
|
|
||||||
_PostContentBody(
|
_PostContentBody(
|
||||||
data: data,
|
data: data,
|
||||||
isSelectable: showFullPost,
|
|
||||||
isEnlarge: data.type == 'article' && showFullPost,
|
isEnlarge: data.type == 'article' && showFullPost,
|
||||||
).padding(horizontal: 16, bottom: 6),
|
).padding(horizontal: 16, bottom: 6),
|
||||||
if (data.repostTo != null)
|
if (data.repostTo != null)
|
||||||
@ -252,10 +247,6 @@ class PostItem extends StatelessWidget {
|
|||||||
maxHeight: 560,
|
maxHeight: 560,
|
||||||
listPadding: const EdgeInsets.symmetric(horizontal: 12),
|
listPadding: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
),
|
),
|
||||||
if (data.body['content'] != null)
|
|
||||||
LinkPreviewWidget(
|
|
||||||
text: data.body['content'],
|
|
||||||
).padding(horizontal: 4),
|
|
||||||
Container(
|
Container(
|
||||||
constraints: BoxConstraints(maxWidth: maxWidth ?? double.infinity),
|
constraints: BoxConstraints(maxWidth: maxWidth ?? double.infinity),
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -321,7 +312,6 @@ class PostShareImageWidget extends StatelessWidget {
|
|||||||
data: data,
|
data: data,
|
||||||
isEnlarge: data.type == 'article',
|
isEnlarge: data.type == 'article',
|
||||||
).padding(horizontal: 16, bottom: 8),
|
).padding(horizontal: 16, bottom: 8),
|
||||||
if (data.body['content']?.isNotEmpty ?? false)
|
|
||||||
_PostContentBody(
|
_PostContentBody(
|
||||||
data: data,
|
data: data,
|
||||||
isEnlarge: data.type == 'article',
|
isEnlarge: data.type == 'article',
|
||||||
@ -337,10 +327,6 @@ class PostShareImageWidget extends StatelessWidget {
|
|||||||
data: data.preload!.attachments!,
|
data: data.preload!.attachments!,
|
||||||
isFlatted: true,
|
isFlatted: true,
|
||||||
).padding(horizontal: 16, bottom: 8),
|
).padding(horizontal: 16, bottom: 8),
|
||||||
if (data.body['content'] != null)
|
|
||||||
LinkPreviewWidget(
|
|
||||||
text: data.body['content'],
|
|
||||||
).padding(horizontal: 4),
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -864,19 +850,16 @@ class _PostContentHeader extends StatelessWidget {
|
|||||||
class _PostContentBody extends StatelessWidget {
|
class _PostContentBody extends StatelessWidget {
|
||||||
final SnPost data;
|
final SnPost data;
|
||||||
final bool isEnlarge;
|
final bool isEnlarge;
|
||||||
final bool isSelectable;
|
|
||||||
|
|
||||||
const _PostContentBody({
|
const _PostContentBody({
|
||||||
required this.data,
|
required this.data,
|
||||||
this.isEnlarge = false,
|
this.isEnlarge = false,
|
||||||
this.isSelectable = false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (data.body['content'] == null) return const SizedBox.shrink();
|
if (data.body['content'] == null) return const SizedBox.shrink();
|
||||||
return MarkdownTextContent(
|
return MarkdownTextContent(
|
||||||
isSelectable: isSelectable,
|
|
||||||
textScaler: isEnlarge ? TextScaler.linear(1.1) : null,
|
textScaler: isEnlarge ? TextScaler.linear(1.1) : null,
|
||||||
content: data.body['content'],
|
content: data.body['content'],
|
||||||
attachments: data.preload?.attachments,
|
attachments: data.preload?.attachments,
|
||||||
|
56
pubspec.lock
56
pubspec.lock
@ -454,14 +454,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.7"
|
version: "2.0.7"
|
||||||
fading_edge_scrollview:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: fading_edge_scrollview
|
|
||||||
sha256: "1f84fe3ea8e251d00d5735e27502a6a250e4aa3d3b330d3fdcb475af741464ef"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "4.1.1"
|
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -712,14 +704,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.0"
|
version: "0.7.0"
|
||||||
flutter_svg:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: flutter_svg
|
|
||||||
sha256: "54900a1a1243f3c4a5506d853a2b5c2dbc38d5f27e52a52618a8054401431123"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.16"
|
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -1066,14 +1050,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.2.2"
|
version: "7.2.2"
|
||||||
marquee:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: marquee
|
|
||||||
sha256: a87e7e80c5d21434f90ad92add9f820cf68be374b226404fe881d2bba7be0862
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.3.0"
|
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1250,14 +1226,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.0"
|
version: "1.9.0"
|
||||||
path_parsing:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: path_parsing
|
|
||||||
sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.0"
|
|
||||||
path_provider:
|
path_provider:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -1927,30 +1895,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.5.1"
|
version: "4.5.1"
|
||||||
vector_graphics:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: vector_graphics
|
|
||||||
sha256: "27d5fefe86fb9aace4a9f8375b56b3c292b64d8c04510df230f849850d912cb7"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.15"
|
|
||||||
vector_graphics_codec:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: vector_graphics_codec
|
|
||||||
sha256: "2430b973a4ca3c4dbc9999b62b8c719a160100dcbae5c819bae0cacce32c9cdb"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.12"
|
|
||||||
vector_graphics_compiler:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: vector_graphics_compiler
|
|
||||||
sha256: "1b4b9e706a10294258727674a340ae0d6e64a7231980f9f9a3d12e4b42407aad"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.16"
|
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -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.0.1+25
|
version: 2.0.1+24
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.5.4
|
sdk: ^3.5.4
|
||||||
@ -102,8 +102,6 @@ dependencies:
|
|||||||
qr_flutter: ^4.1.0
|
qr_flutter: ^4.1.0
|
||||||
file_saver: ^0.2.14
|
file_saver: ^0.2.14
|
||||||
device_info_plus: ^11.2.0
|
device_info_plus: ^11.2.0
|
||||||
marquee: ^2.3.0
|
|
||||||
flutter_svg: ^2.0.16
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user