3 Commits

Author SHA1 Message Date
f3de0bc165 centered file preview, made text copyable 2025-06-24 15:09:37 +02:00
8000475c1f aligned text to the left 2025-06-16 16:07:04 +02:00
da772f17cc changed file messages to show their text or their file name 2025-06-10 21:35:12 +02:00
7 changed files with 60 additions and 74 deletions

View File

@ -18,7 +18,7 @@ class AutocompleteResponseObject {
String label; String label;
String? icon; String? icon;
String? source; String? source;
String? status; List<String>? status;
String? subline; String? subline;
String? shareWithDisplayNameUniqe; String? shareWithDisplayNameUniqe;

View File

@ -28,7 +28,7 @@ AutocompleteResponseObject _$AutocompleteResponseObjectFromJson(
json['label'] as String, json['label'] as String,
json['icon'] as String?, json['icon'] as String?,
json['source'] as String?, json['source'] as String?,
json['status'] as String?, (json['status'] as List<dynamic>?)?.map((e) => e as String).toList(),
json['subline'] as String?, json['subline'] as String?,
json['shareWithDisplayNameUniqe'] as String?, json['shareWithDisplayNameUniqe'] as String?,
); );

View File

@ -55,15 +55,12 @@ class GetParticipantsResponseObject {
} }
enum GetParticipantsResponseObjectParticipantType { enum GetParticipantsResponseObjectParticipantType {
@JsonValue(1) owner('Besitzer'), @JsonValue(1) owner,
@JsonValue(2) moderator('Moderator'), @JsonValue(2) moderator,
@JsonValue(3) user('Benutzer'), @JsonValue(3) user,
@JsonValue(4) guest('Gast'), @JsonValue(4) guest,
@JsonValue(5) userFollowingPublicLink('Link Nutzer'), @JsonValue(5) userFollowingPublicLink,
@JsonValue(6) guestWithModeratorPermissions('Gast Moderator'); @JsonValue(6) guestWithModeratorPermissions
const GetParticipantsResponseObjectParticipantType(this.prettyName);
final String prettyName;
} }
enum GetParticipantsResponseObjectParticipantsInCallFlags { enum GetParticipantsResponseObjectParticipantsInCallFlags {

View File

@ -1,52 +1,28 @@
import 'package:collection/collection.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../../../api/marianumcloud/talk/getParticipants/getParticipantsResponse.dart'; import '../../../../../api/marianumcloud/talk/getParticipants/getParticipantsResponse.dart';
import '../../../../../widget/userAvatar.dart'; import '../../../../../widget/userAvatar.dart';
class ParticipantsListView extends StatelessWidget { class ParticipantsListView extends StatefulWidget {
final GetParticipantsResponse participantsResponse; final GetParticipantsResponse participantsResponse;
const ParticipantsListView(this.participantsResponse, {super.key}); const ParticipantsListView(this.participantsResponse, {super.key});
@override @override
Widget build(BuildContext context) { State<ParticipantsListView> createState() => _ParticipantsListViewState();
// final participants = participantsResponse.data.map((participant) => ListTile( }
// leading: UserAvatar(id: participant.actorId),
// title: Text(participant.displayName),
// subtitle: participant.statusMessage != null ? Text(participant.statusMessage!) : null,
// )).toList();
lastname(participant) => participant.displayName.toString().split(' ').last; class _ParticipantsListViewState extends State<ParticipantsListView> {
@override
final participants = participantsResponse.data Widget build(BuildContext context) => Scaffold(
.sorted((a, b) => lastname(a).compareTo(lastname(b)))
.sorted((a, b) => a.participantType.index.compareTo(b.participantType.index));
var groupedParticipants = participants.groupListsBy((participant) => participant.participantType);
// Map<GetParticipantsResponseObjectParticipantType, List<GetParticipantsResponseObject>>
return Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text('Teilnehmende'), title: const Text('Teilnehmende'),
), ),
body: ListView( body: ListView(
children: [ children: widget.participantsResponse.data.map((participant) => ListTile(
...groupedParticipants.entries.map((entry) => Column( leading: UserAvatar(id: participant.actorId),
children: [ title: Text(participant.displayName),
ListTile( subtitle: participant.statusMessage != null ? Text(participant.statusMessage!) : null,
title: Text(entry.key.prettyName), )).toList(),
titleTextStyle: TextStyle(fontWeight: FontWeight.bold), ),
),
...entry.value.map((participant) => ListTile(
leading: UserAvatar(id: participant.actorId),
title: Text(participant.displayName),
subtitle: participant.statusMessage != null ? Text(participant.statusMessage!) : null,
)),
Divider(),
],
))
],
)
); );
}
} }

View File

@ -206,7 +206,7 @@ class _ChatBubbleState extends State<ChatBubble> with SingleTickerProviderStateM
), ),
), ),
Visibility( Visibility(
visible: !message.containsFile, visible: widget.bubbleData.message != '{file}',
child: ListTile( child: ListTile(
leading: const Icon(Icons.copy), leading: const Icon(Icons.copy),
title: const Text('Nachricht kopieren'), title: const Text('Nachricht kopieren'),

View File

@ -21,39 +21,53 @@ class ChatMessage {
ChatMessage({required this.originalMessage, this.originalData}) { ChatMessage({required this.originalMessage, this.originalData}) {
if(originalData?.containsKey('file') ?? false) { if(originalData?.containsKey('file') ?? false) {
file = originalData?['file']; file = originalData?['file'];
content = file?.name ?? 'Datei';
} else {
content = RichObjectStringProcessor.parseToString(originalMessage, originalData);
} }
content = RichObjectStringProcessor.parseToString(originalMessage, originalData);
} }
Widget getWidget() { Widget getWidget() {
if(file == null) { var contentWidget = Linkify(
return Linkify( text: content,
text: content, onOpen: onOpen,
onOpen: onOpen, );
);
}
return Padding(padding: const EdgeInsets.only(top: 5), child: CachedNetworkImage( if(file == null) return contentWidget;
errorWidget: (context, url, error) => Row(
mainAxisSize: MainAxisSize.min, return Padding(
crossAxisAlignment: CrossAxisAlignment.center, padding: const EdgeInsets.only(top: 5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const Icon(Icons.file_open_outlined, size: 35), Row(
const SizedBox(width: 10), mainAxisSize: MainAxisSize.max,
Flexible(child: Text(file!.name, maxLines: 2, overflow: TextOverflow.ellipsis, style: const TextStyle(fontWeight: FontWeight.bold))), mainAxisAlignment: MainAxisAlignment.center,
const SizedBox(width: 10), children: [
CachedNetworkImage(
errorWidget: (context, url, error) => Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Icon(Icons.file_open_outlined, size: 35),
const SizedBox(width: 10),
Flexible(child: Text(file!.name, maxLines: 2, overflow: TextOverflow.ellipsis, style: const TextStyle(fontWeight: FontWeight.bold))),
const SizedBox(width: 10),
],
),
alignment: Alignment.center,
placeholder: (context, url) => const Padding(padding: EdgeInsets.all(15), child: SizedBox(width: 50, child: LinearProgressIndicator())),
fadeInDuration: Duration.zero,
fadeOutDuration: Duration.zero,
errorListener: (value) {},
imageUrl: 'https://${AccountData().buildHttpAuthString()}@${EndpointData().nextcloud().full()}/index.php/core/preview?fileId=${file!.id}&x=100&y=-1&a=1',
)
],
),
SizedBox(height: 5),
contentWidget
], ],
), )
alignment: Alignment.center, );
placeholder: (context, url) => const Padding(padding: EdgeInsets.all(15), child: SizedBox(width: 50, child: LinearProgressIndicator())),
fadeInDuration: Duration.zero,
fadeOutDuration: Duration.zero,
errorListener: (value) {},
imageUrl: 'https://${AccountData().buildHttpAuthString()}@${EndpointData().nextcloud().full()}/index.php/core/preview?fileId=${file!.id}&x=100&y=-1&a=1',
));
} }
Future<void> onOpen(LinkableElement link) async { Future<void> onOpen(LinkableElement link) async {

View File

@ -101,7 +101,6 @@ dependencies:
time_range_picker: ^2.3.0 time_range_picker: ^2.3.0
url_launcher: ^6.3.1 url_launcher: ^6.3.1
uuid: ^4.5.1 uuid: ^4.5.1
collection: ^1.19.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: