Compare commits

..

No commits in common. "d5cf2478d8051fb93c006cba5c392f4aaf7207b3" and "a75083d916dd246ccc691142bb2408d66cf9ad1b" have entirely different histories.

12 changed files with 413 additions and 489 deletions

View File

@ -249,11 +249,8 @@ class SnNetworkProvider {
return null; return null;
} }
String getAttachmentUrl(String ky, {bool preview = true}) { String getAttachmentUrl(String ky) {
if (ky.startsWith("http")) return ky; if (ky.startsWith("http")) return ky;
if (!preview) {
return '${client.options.baseUrl}/cgi/uc/attachments/$ky?preview=false';
}
return '${client.options.baseUrl}/cgi/uc/attachments/$ky'; return '${client.options.baseUrl}/cgi/uc/attachments/$ky';
} }

View File

@ -15,7 +15,6 @@ import 'package:surface/providers/experience.dart';
import 'package:surface/providers/relationship.dart'; import 'package:surface/providers/relationship.dart';
import 'package:surface/providers/sn_network.dart'; import 'package:surface/providers/sn_network.dart';
import 'package:surface/screens/abuse_report.dart'; import 'package:surface/screens/abuse_report.dart';
import 'package:surface/screens/account/punishments.dart';
import 'package:surface/types/account.dart'; import 'package:surface/types/account.dart';
import 'package:surface/types/check_in.dart'; import 'package:surface/types/check_in.dart';
import 'package:surface/types/post.dart'; import 'package:surface/types/post.dart';
@ -458,7 +457,7 @@ class _UserScreenState extends State<UserScreen>
], ],
).padding(right: 8), ).padding(right: 8),
if (_account!.profile!.description.isNotEmpty) if (_account!.profile!.description.isNotEmpty)
const Gap(4) const Gap(12)
else else
const Gap(8), const Gap(8),
if (_account!.profile!.description.isNotEmpty) if (_account!.profile!.description.isNotEmpty)
@ -504,8 +503,7 @@ class _UserScreenState extends State<UserScreen>
], ],
).padding(vertical: 8, horizontal: 12), ).padding(vertical: 8, horizontal: 12),
), ),
if (_account!.badges.isNotEmpty) const Gap(8), const Gap(8),
if (_account!.badges.isNotEmpty)
Wrap( Wrap(
spacing: 4, spacing: 4,
runSpacing: 4, runSpacing: 4,
@ -621,17 +619,6 @@ class _UserScreenState extends State<UserScreen>
], ],
).padding(all: 16), ).padding(all: 16),
), ),
if (_account?.punishments.isNotEmpty ?? false)
SliverToBoxAdapter(child: const Divider()),
if (_account?.punishments.isNotEmpty ?? false)
SliverToBoxAdapter(
child: Column(
children: [
for (final ele in _account!.punishments)
PunishmentInfoCard(ele: ele),
],
),
),
if (_account?.profile?.links.isNotEmpty ?? false) if (_account?.profile?.links.isNotEmpty ?? false)
SliverToBoxAdapter(child: const Divider()), SliverToBoxAdapter(child: const Divider()),
if (_account?.profile?.links.isNotEmpty ?? false) if (_account?.profile?.links.isNotEmpty ?? false)

View File

@ -107,28 +107,6 @@ class _PunishmentsScreenState extends State<PunishmentsScreen> {
itemCount: _punishments?.length ?? 0, itemCount: _punishments?.length ?? 0,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final ele = _punishments![index]; final ele = _punishments![index];
return PunishmentInfoCard(ele: ele);
},
separatorBuilder: (_, __) => const Gap(8),
),
),
),
],
),
);
}
}
class PunishmentInfoCard extends StatelessWidget {
const PunishmentInfoCard({
super.key,
required this.ele,
});
final SnPunishment ele;
@override
Widget build(BuildContext context) {
return Card( return Card(
margin: EdgeInsets.symmetric(horizontal: 8), margin: EdgeInsets.symmetric(horizontal: 8),
child: Column( child: Column(
@ -139,8 +117,10 @@ class PunishmentInfoCard extends StatelessWidget {
Icon(kPunishmentIcons[ele.type], size: 20), Icon(kPunishmentIcons[ele.type], size: 20),
const Gap(6), const Gap(6),
Expanded( Expanded(
child: child: Text('punishmentType${ele.type}')
Text('punishmentType${ele.type}').tr().fontSize(16).bold(), .tr()
.fontSize(16)
.bold(),
), ),
], ],
), ),
@ -195,5 +175,13 @@ class PunishmentInfoCard extends StatelessWidget {
], ],
).padding(horizontal: 24, vertical: 16), ).padding(horizontal: 24, vertical: 16),
); );
},
separatorBuilder: (_, __) => const Gap(8),
),
),
),
],
),
);
} }
} }

View File

@ -22,7 +22,6 @@ abstract class SnAccount with _$SnAccount {
required String language, required String language,
required SnAccountProfile? profile, required SnAccountProfile? profile,
@Default([]) List<SnAccountBadge> badges, @Default([]) List<SnAccountBadge> badges,
@Default([]) List<SnPunishment> punishments,
required DateTime? suspendedAt, required DateTime? suspendedAt,
required int? affiliatedId, required int? affiliatedId,
required int? affiliatedTo, required int? affiliatedTo,

View File

@ -29,7 +29,6 @@ mixin _$SnAccount {
String get language; String get language;
SnAccountProfile? get profile; SnAccountProfile? get profile;
List<SnAccountBadge> get badges; List<SnAccountBadge> get badges;
List<SnPunishment> get punishments;
DateTime? get suspendedAt; DateTime? get suspendedAt;
int? get affiliatedId; int? get affiliatedId;
int? get affiliatedTo; int? get affiliatedTo;
@ -70,8 +69,6 @@ mixin _$SnAccount {
other.language == language) && other.language == language) &&
(identical(other.profile, profile) || other.profile == profile) && (identical(other.profile, profile) || other.profile == profile) &&
const DeepCollectionEquality().equals(other.badges, badges) && const DeepCollectionEquality().equals(other.badges, badges) &&
const DeepCollectionEquality()
.equals(other.punishments, punishments) &&
(identical(other.suspendedAt, suspendedAt) || (identical(other.suspendedAt, suspendedAt) ||
other.suspendedAt == suspendedAt) && other.suspendedAt == suspendedAt) &&
(identical(other.affiliatedId, affiliatedId) || (identical(other.affiliatedId, affiliatedId) ||
@ -102,7 +99,6 @@ mixin _$SnAccount {
language, language,
profile, profile,
const DeepCollectionEquality().hash(badges), const DeepCollectionEquality().hash(badges),
const DeepCollectionEquality().hash(punishments),
suspendedAt, suspendedAt,
affiliatedId, affiliatedId,
affiliatedTo, affiliatedTo,
@ -112,7 +108,7 @@ mixin _$SnAccount {
@override @override
String toString() { String toString() {
return 'SnAccount(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, confirmedAt: $confirmedAt, contacts: $contacts, avatar: $avatar, banner: $banner, name: $name, nick: $nick, permNodes: $permNodes, language: $language, profile: $profile, badges: $badges, punishments: $punishments, suspendedAt: $suspendedAt, affiliatedId: $affiliatedId, affiliatedTo: $affiliatedTo, automatedBy: $automatedBy, automatedId: $automatedId)'; return 'SnAccount(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, confirmedAt: $confirmedAt, contacts: $contacts, avatar: $avatar, banner: $banner, name: $name, nick: $nick, permNodes: $permNodes, language: $language, profile: $profile, badges: $badges, suspendedAt: $suspendedAt, affiliatedId: $affiliatedId, affiliatedTo: $affiliatedTo, automatedBy: $automatedBy, automatedId: $automatedId)';
} }
} }
@ -136,7 +132,6 @@ abstract mixin class $SnAccountCopyWith<$Res> {
String language, String language,
SnAccountProfile? profile, SnAccountProfile? profile,
List<SnAccountBadge> badges, List<SnAccountBadge> badges,
List<SnPunishment> punishments,
DateTime? suspendedAt, DateTime? suspendedAt,
int? affiliatedId, int? affiliatedId,
int? affiliatedTo, int? affiliatedTo,
@ -172,7 +167,6 @@ class _$SnAccountCopyWithImpl<$Res> implements $SnAccountCopyWith<$Res> {
Object? language = null, Object? language = null,
Object? profile = freezed, Object? profile = freezed,
Object? badges = null, Object? badges = null,
Object? punishments = null,
Object? suspendedAt = freezed, Object? suspendedAt = freezed,
Object? affiliatedId = freezed, Object? affiliatedId = freezed,
Object? affiliatedTo = freezed, Object? affiliatedTo = freezed,
@ -236,10 +230,6 @@ class _$SnAccountCopyWithImpl<$Res> implements $SnAccountCopyWith<$Res> {
? _self.badges ? _self.badges
: badges // ignore: cast_nullable_to_non_nullable : badges // ignore: cast_nullable_to_non_nullable
as List<SnAccountBadge>, as List<SnAccountBadge>,
punishments: null == punishments
? _self.punishments
: punishments // ignore: cast_nullable_to_non_nullable
as List<SnPunishment>,
suspendedAt: freezed == suspendedAt suspendedAt: freezed == suspendedAt
? _self.suspendedAt ? _self.suspendedAt
: suspendedAt // ignore: cast_nullable_to_non_nullable : suspendedAt // ignore: cast_nullable_to_non_nullable
@ -296,7 +286,6 @@ class _SnAccount extends SnAccount {
required this.language, required this.language,
required this.profile, required this.profile,
final List<SnAccountBadge> badges = const [], final List<SnAccountBadge> badges = const [],
final List<SnPunishment> punishments = const [],
required this.suspendedAt, required this.suspendedAt,
required this.affiliatedId, required this.affiliatedId,
required this.affiliatedTo, required this.affiliatedTo,
@ -305,7 +294,6 @@ class _SnAccount extends SnAccount {
: _contacts = contacts, : _contacts = contacts,
_permNodes = permNodes, _permNodes = permNodes,
_badges = badges, _badges = badges,
_punishments = punishments,
super._(); super._();
factory _SnAccount.fromJson(Map<String, dynamic> json) => factory _SnAccount.fromJson(Map<String, dynamic> json) =>
_$SnAccountFromJson(json); _$SnAccountFromJson(json);
@ -362,15 +350,6 @@ class _SnAccount extends SnAccount {
return EqualUnmodifiableListView(_badges); return EqualUnmodifiableListView(_badges);
} }
final List<SnPunishment> _punishments;
@override
@JsonKey()
List<SnPunishment> get punishments {
if (_punishments is EqualUnmodifiableListView) return _punishments;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_punishments);
}
@override @override
final DateTime? suspendedAt; final DateTime? suspendedAt;
@override @override
@ -422,8 +401,6 @@ class _SnAccount extends SnAccount {
other.language == language) && other.language == language) &&
(identical(other.profile, profile) || other.profile == profile) && (identical(other.profile, profile) || other.profile == profile) &&
const DeepCollectionEquality().equals(other._badges, _badges) && const DeepCollectionEquality().equals(other._badges, _badges) &&
const DeepCollectionEquality()
.equals(other._punishments, _punishments) &&
(identical(other.suspendedAt, suspendedAt) || (identical(other.suspendedAt, suspendedAt) ||
other.suspendedAt == suspendedAt) && other.suspendedAt == suspendedAt) &&
(identical(other.affiliatedId, affiliatedId) || (identical(other.affiliatedId, affiliatedId) ||
@ -454,7 +431,6 @@ class _SnAccount extends SnAccount {
language, language,
profile, profile,
const DeepCollectionEquality().hash(_badges), const DeepCollectionEquality().hash(_badges),
const DeepCollectionEquality().hash(_punishments),
suspendedAt, suspendedAt,
affiliatedId, affiliatedId,
affiliatedTo, affiliatedTo,
@ -464,7 +440,7 @@ class _SnAccount extends SnAccount {
@override @override
String toString() { String toString() {
return 'SnAccount(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, confirmedAt: $confirmedAt, contacts: $contacts, avatar: $avatar, banner: $banner, name: $name, nick: $nick, permNodes: $permNodes, language: $language, profile: $profile, badges: $badges, punishments: $punishments, suspendedAt: $suspendedAt, affiliatedId: $affiliatedId, affiliatedTo: $affiliatedTo, automatedBy: $automatedBy, automatedId: $automatedId)'; return 'SnAccount(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, confirmedAt: $confirmedAt, contacts: $contacts, avatar: $avatar, banner: $banner, name: $name, nick: $nick, permNodes: $permNodes, language: $language, profile: $profile, badges: $badges, suspendedAt: $suspendedAt, affiliatedId: $affiliatedId, affiliatedTo: $affiliatedTo, automatedBy: $automatedBy, automatedId: $automatedId)';
} }
} }
@ -491,7 +467,6 @@ abstract mixin class _$SnAccountCopyWith<$Res>
String language, String language,
SnAccountProfile? profile, SnAccountProfile? profile,
List<SnAccountBadge> badges, List<SnAccountBadge> badges,
List<SnPunishment> punishments,
DateTime? suspendedAt, DateTime? suspendedAt,
int? affiliatedId, int? affiliatedId,
int? affiliatedTo, int? affiliatedTo,
@ -528,7 +503,6 @@ class __$SnAccountCopyWithImpl<$Res> implements _$SnAccountCopyWith<$Res> {
Object? language = null, Object? language = null,
Object? profile = freezed, Object? profile = freezed,
Object? badges = null, Object? badges = null,
Object? punishments = null,
Object? suspendedAt = freezed, Object? suspendedAt = freezed,
Object? affiliatedId = freezed, Object? affiliatedId = freezed,
Object? affiliatedTo = freezed, Object? affiliatedTo = freezed,
@ -592,10 +566,6 @@ class __$SnAccountCopyWithImpl<$Res> implements _$SnAccountCopyWith<$Res> {
? _self._badges ? _self._badges
: badges // ignore: cast_nullable_to_non_nullable : badges // ignore: cast_nullable_to_non_nullable
as List<SnAccountBadge>, as List<SnAccountBadge>,
punishments: null == punishments
? _self._punishments
: punishments // ignore: cast_nullable_to_non_nullable
as List<SnPunishment>,
suspendedAt: freezed == suspendedAt suspendedAt: freezed == suspendedAt
? _self.suspendedAt ? _self.suspendedAt
: suspendedAt // ignore: cast_nullable_to_non_nullable : suspendedAt // ignore: cast_nullable_to_non_nullable

View File

@ -32,10 +32,6 @@ _SnAccount _$SnAccountFromJson(Map<String, dynamic> json) => _SnAccount(
?.map((e) => SnAccountBadge.fromJson(e as Map<String, dynamic>)) ?.map((e) => SnAccountBadge.fromJson(e as Map<String, dynamic>))
.toList() ?? .toList() ??
const [], const [],
punishments: (json['punishments'] as List<dynamic>?)
?.map((e) => SnPunishment.fromJson(e as Map<String, dynamic>))
.toList() ??
const [],
suspendedAt: json['suspended_at'] == null suspendedAt: json['suspended_at'] == null
? null ? null
: DateTime.parse(json['suspended_at'] as String), : DateTime.parse(json['suspended_at'] as String),
@ -61,7 +57,6 @@ Map<String, dynamic> _$SnAccountToJson(_SnAccount instance) =>
'language': instance.language, 'language': instance.language,
'profile': instance.profile?.toJson(), 'profile': instance.profile?.toJson(),
'badges': instance.badges.map((e) => e.toJson()).toList(), 'badges': instance.badges.map((e) => e.toJson()).toList(),
'punishments': instance.punishments.map((e) => e.toJson()).toList(),
'suspended_at': instance.suspendedAt?.toIso8601String(), 'suspended_at': instance.suspendedAt?.toIso8601String(),
'affiliated_id': instance.affiliatedId, 'affiliated_id': instance.affiliatedId,
'affiliated_to': instance.affiliatedTo, 'affiliated_to': instance.affiliatedTo,

View File

@ -22,14 +22,12 @@ class AccountPopoverCard extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final sn = context.read<SnNetworkProvider>(); final sn = context.read<SnNetworkProvider>();
return SingleChildScrollView( return Column(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [ children: [
if (data.banner.isNotEmpty) if (data.banner.isNotEmpty)
ClipRRect( Container(
borderRadius: BorderRadius.circular(16),
child: Container(
color: Theme.of(context).colorScheme.surfaceContainer, color: Theme.of(context).colorScheme.surfaceContainer,
child: AspectRatio( child: AspectRatio(
aspectRatio: 16 / 7, aspectRatio: 16 / 7,
@ -39,10 +37,8 @@ class AccountPopoverCard extends StatelessWidget {
), ),
), ),
), ),
).padding(all: 16)
else
const Gap(16),
// Top padding // Top padding
Gap(16),
Row( Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -71,8 +67,7 @@ class AccountPopoverCard extends StatelessWidget {
}, },
icon: const Icon(Symbols.chevron_right), icon: const Icon(Symbols.chevron_right),
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
visualDensity: visualDensity: const VisualDensity(horizontal: -4, vertical: -4),
const VisualDensity(horizontal: -4, vertical: -4),
), ),
const Gap(8) const Gap(8)
], ],
@ -91,9 +86,7 @@ class AccountPopoverCard extends StatelessWidget {
data.profile?.description ?? '', data.profile?.description ?? '',
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
).padding(horizontal: 26, bottom: 8) ).padding(horizontal: 26, bottom: 8),
else
const Gap(12),
Row( Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
@ -111,8 +104,7 @@ class AccountPopoverCard extends StatelessWidget {
child: LinearProgressIndicator( child: LinearProgressIndicator(
value: calcLevelUpProgress(data.profile?.experience ?? 0), value: calcLevelUpProgress(data.profile?.experience ?? 0),
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
backgroundColor: backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
Theme.of(context).colorScheme.surfaceContainer,
).alignment(Alignment.centerLeft), ).alignment(Alignment.centerLeft),
), ),
], ],
@ -164,9 +156,8 @@ class AccountPopoverCard extends StatelessWidget {
}, },
), ),
// Bottom padding // Bottom padding
const Gap(64), const Gap(16),
], ],
),
); );
} }
} }

View File

@ -170,7 +170,8 @@ class _AttachmentListState extends State<AttachmentList> {
child: Column( child: Column(
children: widget.data children: widget.data
.mapIndexed( .mapIndexed(
(idx, ele) => AspectRatio( (idx, ele) => GestureDetector(
child: AspectRatio(
aspectRatio: ele?.data['ratio']?.toDouble() ?? 1, aspectRatio: ele?.data['ratio']?.toDouble() ?? 1,
child: Container( child: Container(
constraints: constraints, constraints: constraints,
@ -179,21 +180,7 @@ class _AttachmentListState extends State<AttachmentList> {
heroTag: heroTags[idx], heroTag: heroTags[idx],
fit: BoxFit.cover, fit: BoxFit.cover,
filterQuality: widget.filterQuality, filterQuality: widget.filterQuality,
onZoom: () {
context.pushTransparentRoute(
AttachmentZoomView(
data: widget.data
.where((ele) =>
ele != null &&
ele.mediaType == SnMediaType.image)
.cast(),
initialIndex: idx,
heroTags: heroTags,
), ),
backgroundColor: Colors.black.withOpacity(0.7),
rootNavigator: true,
);
},
), ),
), ),
), ),
@ -224,6 +211,26 @@ class _AttachmentListState extends State<AttachmentList> {
child: AspectRatio( child: AspectRatio(
aspectRatio: aspectRatio:
(widget.data[idx]?.data['ratio'] ?? 1).toDouble(), (widget.data[idx]?.data['ratio'] ?? 1).toDouble(),
child: GestureDetector(
onTap: () {
if (widget.data[idx]?.mediaType !=
SnMediaType.image) {
return;
}
context.pushTransparentRoute(
AttachmentZoomView(
data: widget.data
.where((ele) =>
ele != null &&
ele.mediaType == SnMediaType.image)
.cast(),
initialIndex: idx,
heroTags: heroTags,
),
backgroundColor: Colors.black.withOpacity(0.7),
rootNavigator: true,
);
},
child: Stack( child: Stack(
fit: StackFit.expand, fit: StackFit.expand,
children: [ children: [
@ -242,23 +249,6 @@ class _AttachmentListState extends State<AttachmentList> {
data: widget.data[idx], data: widget.data[idx],
heroTag: heroTags[idx], heroTag: heroTags[idx],
filterQuality: widget.filterQuality, filterQuality: widget.filterQuality,
onZoom: () {
context.pushTransparentRoute(
AttachmentZoomView(
data: widget.data
.where((ele) =>
ele != null &&
ele.mediaType ==
SnMediaType.image)
.cast(),
initialIndex: idx,
heroTags: heroTags,
),
backgroundColor:
Colors.black.withOpacity(0.7),
rootNavigator: true,
);
},
), ),
), ),
), ),
@ -272,6 +262,7 @@ class _AttachmentListState extends State<AttachmentList> {
], ],
), ),
), ),
),
); );
}, },
separatorBuilder: (context, index) => const Gap(8), separatorBuilder: (context, index) => const Gap(8),

View File

@ -181,10 +181,7 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
scaleState == PhotoViewScaleState.initial); scaleState == PhotoViewScaleState.initial);
}, },
imageProvider: UniversalImage.provider( imageProvider: UniversalImage.provider(
sn.getAttachmentUrl( sn.getAttachmentUrl(widget.data.first.rid),
widget.data.first.rid,
preview: false,
),
), ),
), ),
); );
@ -202,10 +199,7 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
widget.heroTags?.elementAt(idx) ?? uuid.v4(); widget.heroTags?.elementAt(idx) ?? uuid.v4();
return PhotoViewGalleryPageOptions( return PhotoViewGalleryPageOptions(
imageProvider: UniversalImage.provider( imageProvider: UniversalImage.provider(
sn.getAttachmentUrl( sn.getAttachmentUrl(widget.data.elementAt(idx).rid),
widget.data.elementAt(idx).rid,
preview: false,
),
), ),
heroAttributes: PhotoViewHeroAttributes( heroAttributes: PhotoViewHeroAttributes(
tag: 'attachment-${widget.data.first.rid}-$heroTag', tag: 'attachment-${widget.data.first.rid}-$heroTag',

View File

@ -1,8 +1,11 @@
import 'dart:math' as math;
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_context_menu/flutter_context_menu.dart'; import 'package:flutter_context_menu/flutter_context_menu.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
import 'package:popover/popover.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'package:surface/providers/config.dart'; import 'package:surface/providers/config.dart';
@ -117,9 +120,20 @@ class ChatMessage extends StatelessWidget {
), ),
onTap: () { onTap: () {
if (user == null) return; if (user == null) return;
showModalBottomSheet( showPopover(
backgroundColor:
Theme.of(context).colorScheme.surface,
context: context, context: context,
builder: (context) => AccountPopoverCard(data: user), transition: PopoverTransition.other,
bodyBuilder: (context) => SizedBox(
width: math.min(
400, MediaQuery.of(context).size.width - 10),
child: AccountPopoverCard(data: user),
),
direction: PopoverDirection.bottom,
arrowHeight: 5,
arrowWidth: 15,
arrowDxOffset: -190,
); );
}, },
) )

View File

@ -12,6 +12,7 @@ import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:popover/popover.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:qr_flutter/qr_flutter.dart'; import 'package:qr_flutter/qr_flutter.dart';
import 'package:relative_time/relative_time.dart'; import 'package:relative_time/relative_time.dart';
@ -1273,11 +1274,20 @@ class _PostAvatar extends StatelessWidget {
), ),
), ),
onTap: () { onTap: () {
showModalBottomSheet( showPopover(
backgroundColor: Theme.of(context).colorScheme.surface,
context: context, context: context,
builder: (context) => PublisherPopoverCard( transition: PopoverTransition.other,
bodyBuilder: (context) => SizedBox(
width: math.min(400, MediaQuery.of(context).size.width - 10),
child: PublisherPopoverCard(
data: data.publisher, data: data.publisher,
), ),
),
direction: PopoverDirection.bottom,
arrowHeight: 5,
arrowWidth: 15,
arrowDxOffset: -190,
); );
}, },
); );

View File

@ -24,14 +24,12 @@ class PublisherPopoverCard extends StatelessWidget {
final user = data.type == 0 ? ud.getFromCache(data.accountId) : null; final user = data.type == 0 ? ud.getFromCache(data.accountId) : null;
return SingleChildScrollView( return Column(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [ children: [
if (data.banner.isNotEmpty) if (data.banner.isNotEmpty)
ClipRRect( Container(
borderRadius: BorderRadius.circular(16),
child: Container(
color: Theme.of(context).colorScheme.surfaceContainer, color: Theme.of(context).colorScheme.surfaceContainer,
child: AspectRatio( child: AspectRatio(
aspectRatio: 16 / 7, aspectRatio: 16 / 7,
@ -41,8 +39,6 @@ class PublisherPopoverCard extends StatelessWidget {
), ),
), ),
), ),
).padding(all: 16)
else
// Top padding // Top padding
Gap(16), Gap(16),
Row( Row(
@ -74,8 +70,7 @@ class PublisherPopoverCard extends StatelessWidget {
}, },
icon: const Icon(Symbols.chevron_right), icon: const Icon(Symbols.chevron_right),
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
visualDensity: visualDensity: const VisualDensity(horizontal: -4, vertical: -4),
const VisualDensity(horizontal: -4, vertical: -4),
), ),
const Gap(8) const Gap(8)
], ],
@ -103,10 +98,7 @@ class PublisherPopoverCard extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Text('publisherSocialPoint') Text('publisherSocialPoint').tr().fontSize(13).opacity(0.75),
.tr()
.fontSize(13)
.opacity(0.75),
Text((data.totalUpvote - data.totalDownvote).toString()), Text((data.totalUpvote - data.totalDownvote).toString()),
], ],
), ),
@ -122,10 +114,7 @@ class PublisherPopoverCard extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Text('publisherTotalUpvote') Text('publisherTotalUpvote').tr().fontSize(13).opacity(0.75),
.tr()
.fontSize(13)
.opacity(0.75),
Text(data.totalUpvote.toString()), Text(data.totalUpvote.toString()),
], ],
), ),
@ -152,9 +141,8 @@ class PublisherPopoverCard extends StatelessWidget {
], ],
).padding(horizontal: 16), ).padding(horizontal: 16),
// Bottom padding // Bottom padding
const Gap(64), const Gap(16),
], ],
),
); );
} }
} }