# 11 — Suche & Discovery --- ## Inhaltsverzeichnis - [Nachrichten in einem Raum suchen](#nachrichten-in-einem-raum-suchen) - [Globale Nachrichten-Suche](#globale-nachrichten-suche) - [User-Suche](#user-suche) - [Öffentliches Raumverzeichnis](#öffentliches-raumverzeichnis) - [Matrix-URI auflösen](#matrix-uri-auflösen) - [Raum per Alias finden](#raum-per-alias-finden) --- ## Nachrichten in einem Raum suchen ```dart // In der lokalen Timeline suchen (gecacht) final found = timeline.events .where((e) => e.type == EventTypes.Message && e.body.toLowerCase().contains(query.toLowerCase())) .toList(); // Auf dem Server suchen (Matrix-Suchendpoint) final result = await client.searchEvents( Categories( roomEvents: RoomEventsCriteria( searchTerm: 'suchbegriff', roomId: room.id, // optional: nur in einem Raum orderBy: SearchOrder.recent, // oder .rank keys: [SearchKey.contentBody], // oder .contentName, .contentTopic filter: RoomEventFilter( limit: 20, rooms: [room.id], notRooms: [], ), ), ), ); // Ergebnisse for (final result in result.roomEvents?.results ?? []) { print(result.result.body); print(result.result.originServerTs); print(result.result.senderId); } // Paginierung final nextToken = result.roomEvents?.nextBatch; if (nextToken != null) { final more = await client.searchEvents( /* gleiche Criteria */, nextBatch: nextToken, ); } ``` --- ## Globale Nachrichten-Suche ```dart // Über alle Räume suchen final result = await client.searchEvents( Categories( roomEvents: RoomEventsCriteria( searchTerm: 'flutter matrix', orderBy: SearchOrder.recent, includeState: false, groupings: Groupings( groupBy: [Group(key: GroupKey.roomId)], // Gruppiert nach Raum ), ), ), ); // Gruppen-Ergebnisse for (final entry in result.roomEvents?.groups?.entries ?? []) { final groupKey = entry.key; // 'room_id' for (final roomGroup in entry.value.entries) { final roomId = roomGroup.key; print('Treffer in $roomId: ${roomGroup.value.count}'); // roomGroup.value.results: List (Event-IDs) } } ``` --- ## User-Suche ```dart // User-Verzeichnis durchsuchen final response = await client.searchUserDirectory( 'alice', // Suchbegriff (Name oder MXID) limit: 20, ); for (final user in response.results) { print(user.userId); // @alice:server print(user.displayName); // Alice print(user.avatarUrl); // mxc://... // Avatar als HTTP-URL final avatarHttp = user.avatarUrl?.getThumbnail( client, width: 56, height: 56, method: ThumbnailMethod.crop, ); } print(response.limited); // true wenn weitere Ergebnisse vorhanden // MXID direkt laden (ohne Suche) final profile = await client.getProfileFromUserId('@alice:server'); print(profile.displayname); print(profile.avatarUrl); ``` --- ## Öffentliches Raumverzeichnis ```dart // Öffentliche Räume (des eigenen Servers) final result = await client.queryPublicRooms( limit: 50, ); // Mit Suchbegriff final searched = await client.queryPublicRooms( limit: 20, filter: PublicRoomQueryFilter( genericSearchTerm: 'flutter', ), ); // Anderen Server durchsuchen final remote = await client.queryPublicRooms( server: 'matrix.org', limit: 20, filter: PublicRoomQueryFilter(genericSearchTerm: 'linux'), ); // Paginierung var batch = await client.queryPublicRooms(limit: 50); while (batch.nextBatch != null) { batch = await client.queryPublicRooms( limit: 50, since: batch.nextBatch, ); } // Einzelnes Ergebnis for (final room in result.chunk) { print(room.roomId); print(room.name); print(room.topic); print(room.numJoinedMembers); print(room.worldReadable); print(room.guestCanJoin); print(room.avatarUrl); print(room.canonicalAlias); print(room.joinRule); // 'public' | 'knock' | etc. print(room.roomType); // 'm.space' | null } ``` --- ## Matrix-URI auflösen ```dart // Matrix-to URI parsen // https://matrix.to/#/@alice:server // https://matrix.to/#/!roomId:server // https://matrix.to/#/#alias:server // matrix:u/alice:server // matrix:r/alias:server // matrix:roomid/roomId:server import 'package:matrix/matrix.dart'; final uri = MatrixUri.parse('https://matrix.to/#/#kanal:example.org'); if (uri != null) { switch (uri.primaryType) { case MatrixUriType.room: // Raum-Alias case MatrixUriType.roomId: // Raum-ID case MatrixUriType.user: // User-MXID case MatrixUriType.event: // Event-Link } final identifier = uri.primaryIdentifier; // z.B. '#kanal:example.org' oder '!roomId:server' // Beitreten (bei Raum) if (uri.primaryType == MatrixUriType.room || uri.primaryType == MatrixUriType.roomId) { await client.joinRoomOrAlias( identifier, serverName: uri.viaServers, // föderierte Server ); } } // Matrix-URI generieren final roomUri = MatrixUri( primaryType: MatrixUriType.roomId, primaryIdentifier: room.id, viaServers: ['example.org'], ).toUri().toString(); // → matrix:roomid/roomId:server?via=example.org // Matrix.to Link generieren final matrixToLink = 'https://matrix.to/#/${Uri.encodeComponent(room.canonicalAlias ?? room.id)}'; ``` --- ## Raum per Alias finden ```dart // Alias → Raum-ID auflösen final result = await client.getRoomIdByAlias('#alias:server'); print(result.roomId); print(result.servers); // Via-Server für Beitritt // Direkt beitreten via Alias await client.joinRoomOrAlias('#alias:server'); // Lokal prüfen (gecacht) final localRoom = client.rooms.firstWhere( (r) => r.canonicalAlias == '#alias:server', orElse: () => throw Exception('Nicht gefunden'), ); ```