implemented global user search integration for Talk chats with role-coded badges and direct chat creation logic

This commit is contained in:
2026-07-12 19:05:27 +02:00
parent 44e45c9b78
commit babc347b18
17 changed files with 580 additions and 82 deletions
@@ -0,0 +1,30 @@
import 'package:dio/dio.dart';
import '../../errors/marianumconnect_error.dart';
import '../../marianumconnect_api.dart';
import '../../marianumconnect_endpoint.dart';
import 'user_search_response.dart';
/// Searches active users (students, teachers, staff) via the MarianumConnect
/// mobile API. Returns each match's Nextcloud username plus role, so the Talk
/// search can start a direct chat and label results without hitting Nextcloud.
class UserSearch {
final Dio _dio;
UserSearch({Dio? dio}) : _dio = dio ?? MarianumConnectApi.dio();
Future<UserSearchResponse> run(String query) async {
try {
final response = await _dio.get<List<dynamic>>(
MarianumConnectEndpoint.resolve('users/search'),
queryParameters: {'q': query},
);
final list = response.data!
.map((e) => McUserSearchResult.fromJson(e as Map<String, dynamic>))
.toList();
return UserSearchResponse(result: list);
} on DioException catch (e) {
throw mapMarianumConnectError(e);
}
}
}
@@ -0,0 +1,40 @@
import 'package:json_annotation/json_annotation.dart';
import '../../../api_response.dart';
part 'user_search_response.g.dart';
@JsonSerializable(explicitToJson: true)
class McUserSearchResult {
/// Nextcloud-/Talk-Username — dient als `invite` beim Chat-Start.
final String username;
final String firstName;
final String lastName;
/// STUDENT, TEACHER oder STAFF.
final String userType;
final String? className;
McUserSearchResult({
required this.username,
required this.firstName,
required this.lastName,
required this.userType,
this.className,
});
factory McUserSearchResult.fromJson(Map<String, dynamic> json) =>
_$McUserSearchResultFromJson(json);
Map<String, dynamic> toJson() => _$McUserSearchResultToJson(this);
}
@JsonSerializable(explicitToJson: true)
class UserSearchResponse extends ApiResponse {
final List<McUserSearchResult> result;
UserSearchResponse({required this.result});
factory UserSearchResponse.fromJson(Map<String, dynamic> json) =>
_$UserSearchResponseFromJson(json);
Map<String, dynamic> toJson() => _$UserSearchResponseToJson(this);
}
@@ -0,0 +1,41 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user_search_response.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
McUserSearchResult _$McUserSearchResultFromJson(Map<String, dynamic> json) =>
McUserSearchResult(
username: json['username'] as String,
firstName: json['firstName'] as String,
lastName: json['lastName'] as String,
userType: json['userType'] as String,
className: json['className'] as String?,
);
Map<String, dynamic> _$McUserSearchResultToJson(McUserSearchResult instance) =>
<String, dynamic>{
'username': instance.username,
'firstName': instance.firstName,
'lastName': instance.lastName,
'userType': instance.userType,
'className': instance.className,
};
UserSearchResponse _$UserSearchResponseFromJson(Map<String, dynamic> json) =>
UserSearchResponse(
result: (json['result'] as List<dynamic>)
.map((e) => McUserSearchResult.fromJson(e as Map<String, dynamic>))
.toList(),
)
..headers = (json['headers'] as Map<String, dynamic>?)?.map(
(k, e) => MapEntry(k, e as String),
);
Map<String, dynamic> _$UserSearchResponseToJson(UserSearchResponse instance) =>
<String, dynamic>{
'headers': ?instance.headers,
'result': instance.result.map((e) => e.toJson()).toList(),
};