From f885790bf41d2b83e09cff091c3c93a7e2643d00 Mon Sep 17 00:00:00 2001 From: jld3103 Date: Thu, 1 Jun 2023 09:28:24 +0200 Subject: [PATCH 1/5] specs,nextcloud: private user status inherit public user status --- .../nextcloud/lib/src/nextcloud.openapi.dart | 158 ++++-- .../lib/src/nextcloud.openapi.g.dart | 452 +++++++++--------- .../nextcloud/lib/src/nextcloud.openapi.json | 68 ++- packages/nextcloud/test/user_status.dart | 96 ++-- specs/user_status.json | 68 ++- 5 files changed, 450 insertions(+), 392 deletions(-) diff --git a/packages/nextcloud/lib/src/nextcloud.openapi.dart b/packages/nextcloud/lib/src/nextcloud.openapi.dart index 0bf64f68..83bb5cd1 100644 --- a/packages/nextcloud/lib/src/nextcloud.openapi.dart +++ b/packages/nextcloud/lib/src/nextcloud.openapi.dart @@ -4664,85 +4664,74 @@ abstract class NextcloudUserStatusGetPublicStatus _$nextcloudUserStatusGetPublicStatusSerializer; } -abstract class NextcloudUserStatusStatus_ClearAt - implements Built { - factory NextcloudUserStatusStatus_ClearAt([final void Function(NextcloudUserStatusStatus_ClearAtBuilder)? b]) = - _$NextcloudUserStatusStatus_ClearAt; - const NextcloudUserStatusStatus_ClearAt._(); +abstract class NextcloudUserStatusStatus1 + implements Built { + factory NextcloudUserStatusStatus1([final void Function(NextcloudUserStatusStatus1Builder)? b]) = + _$NextcloudUserStatusStatus1; + const NextcloudUserStatusStatus1._(); - JsonObject get data; - NextcloudUserStatusClearAt? get userStatusClearAt; - - /// Time as unix timestamp - int? get $int; - static NextcloudUserStatusStatus_ClearAt fromJson(final Object json) => + factory NextcloudUserStatusStatus1.fromJson(final Map json) => jsonSerializers.deserializeWith(serializer, json)!; + + Map toJson() => jsonSerializers.serializeWith(serializer, this)! as Map; + String? get messageId; + bool get messageIsPredefined; + bool get statusIsUserDefined; + static Serializer get serializer => _$nextcloudUserStatusStatus1Serializer; +} + +abstract class NextcloudUserStatusStatus implements Built { + factory NextcloudUserStatusStatus([final void Function(NextcloudUserStatusStatusBuilder)? b]) = + _$NextcloudUserStatusStatus; + const NextcloudUserStatusStatus._(); + + JsonObject get data; + NextcloudUserStatusPublicStatus get userStatusPublicStatus; + NextcloudUserStatusStatus1 get userStatusStatus1; + static NextcloudUserStatusStatus fromJson(final Object json) => jsonSerializers.deserializeWith(serializer, json)!; Map toJson() => jsonSerializers.serializeWith(serializer, this)! as Map; @BuiltValueSerializer(custom: true) - static Serializer get serializer => - _$NextcloudUserStatusStatus_ClearAtSerializer(); + static Serializer get serializer => _$NextcloudUserStatusStatusSerializer(); } -class _$NextcloudUserStatusStatus_ClearAtSerializer implements PrimitiveSerializer { +class _$NextcloudUserStatusStatusSerializer implements PrimitiveSerializer { @override - final Iterable types = const [NextcloudUserStatusStatus_ClearAt, _$NextcloudUserStatusStatus_ClearAt]; + final Iterable types = const [NextcloudUserStatusStatus, _$NextcloudUserStatusStatus]; @override - final String wireName = 'NextcloudUserStatusStatus_ClearAt'; + final String wireName = 'NextcloudUserStatusStatus'; @override Object serialize( final Serializers serializers, - final NextcloudUserStatusStatus_ClearAt object, { + final NextcloudUserStatusStatus object, { final FullType specifiedType = FullType.unspecified, }) => object.data.value; @override - NextcloudUserStatusStatus_ClearAt deserialize( + NextcloudUserStatusStatus deserialize( final Serializers serializers, final Object data, { final FullType specifiedType = FullType.unspecified, }) { - final result = NextcloudUserStatusStatus_ClearAtBuilder()..data = JsonObject(data); - try { - result._userStatusClearAt = (jsonSerializers.deserialize( + final result = NextcloudUserStatusStatusBuilder()..data = JsonObject(data); + result.userStatusPublicStatus.replace( + jsonSerializers.deserialize( data, - specifiedType: const FullType(NextcloudUserStatusClearAt), - )! as NextcloudUserStatusClearAt) - .toBuilder(); - } catch (_) {} - try { - result._$int = data as int?; - } catch (_) {} - assert( - [result._userStatusClearAt, result._$int].where((final x) => x != null).isNotEmpty, - 'Need oneOf for ${result._data}', + specifiedType: const FullType(NextcloudUserStatusPublicStatus), + )! as NextcloudUserStatusPublicStatus, + ); + result.userStatusStatus1.replace( + jsonSerializers.deserialize( + data, + specifiedType: const FullType(NextcloudUserStatusStatus1), + )! as NextcloudUserStatusStatus1, ); return result.build(); } } -abstract class NextcloudUserStatusStatus implements Built { - factory NextcloudUserStatusStatus([final void Function(NextcloudUserStatusStatusBuilder)? b]) = - _$NextcloudUserStatusStatus; - const NextcloudUserStatusStatus._(); - - factory NextcloudUserStatusStatus.fromJson(final Map json) => - jsonSerializers.deserializeWith(serializer, json)!; - - Map toJson() => jsonSerializers.serializeWith(serializer, this)! as Map; - String get userId; - String? get message; - String? get messageId; - bool get messageIsPredefined; - String? get icon; - NextcloudUserStatusStatus_ClearAt? get clearAt; - NextcloudUserStatusType get status; - bool get statusIsUserDefined; - static Serializer get serializer => _$nextcloudUserStatusStatusSerializer; -} - abstract class NextcloudUserStatusGetStatus_Ocs_Data implements Built { factory NextcloudUserStatusGetStatus_Ocs_Data([ @@ -4950,6 +4939,69 @@ abstract class NextcloudUserStatusPredefinedStatuses _$nextcloudUserStatusPredefinedStatusesSerializer; } +abstract class NextcloudUserStatusHeartbeat_Ocs_Data + implements Built { + factory NextcloudUserStatusHeartbeat_Ocs_Data([ + final void Function(NextcloudUserStatusHeartbeat_Ocs_DataBuilder)? b, + ]) = _$NextcloudUserStatusHeartbeat_Ocs_Data; + const NextcloudUserStatusHeartbeat_Ocs_Data._(); + + JsonObject get data; + BuiltList? get builtListJsonObject; + NextcloudUserStatusStatus? get userStatusStatus; + static NextcloudUserStatusHeartbeat_Ocs_Data fromJson(final Object json) => + jsonSerializers.deserializeWith(serializer, json)!; + Map toJson() => jsonSerializers.serializeWith(serializer, this)! as Map; + @BuiltValueSerializer(custom: true) + static Serializer get serializer => + _$NextcloudUserStatusHeartbeat_Ocs_DataSerializer(); +} + +class _$NextcloudUserStatusHeartbeat_Ocs_DataSerializer + implements PrimitiveSerializer { + @override + final Iterable types = const [NextcloudUserStatusHeartbeat_Ocs_Data, _$NextcloudUserStatusHeartbeat_Ocs_Data]; + + @override + final String wireName = 'NextcloudUserStatusHeartbeat_Ocs_Data'; + + @override + Object serialize( + final Serializers serializers, + final NextcloudUserStatusHeartbeat_Ocs_Data object, { + final FullType specifiedType = FullType.unspecified, + }) => + object.data.value; + + @override + NextcloudUserStatusHeartbeat_Ocs_Data deserialize( + final Serializers serializers, + final Object data, { + final FullType specifiedType = FullType.unspecified, + }) { + final result = NextcloudUserStatusHeartbeat_Ocs_DataBuilder()..data = JsonObject(data); + try { + result._builtListJsonObject = (jsonSerializers.deserialize( + data, + specifiedType: const FullType(BuiltList, [FullType(JsonObject)]), + )! as BuiltList) + .toBuilder(); + } catch (_) {} + try { + result._userStatusStatus = (jsonSerializers.deserialize( + data, + specifiedType: const FullType(NextcloudUserStatusStatus), + )! as NextcloudUserStatusStatus) + .toBuilder(); + } catch (_) {} + assert( + [result._builtListJsonObject, result._userStatusStatus].where((final x) => x != null).isNotEmpty, + 'Need oneOf for ${result._data}', + ); + return result.build(); + } +} + abstract class NextcloudUserStatusHeartbeat_Ocs implements Built { factory NextcloudUserStatusHeartbeat_Ocs([final void Function(NextcloudUserStatusHeartbeat_OcsBuilder)? b]) = @@ -4961,7 +5013,7 @@ abstract class NextcloudUserStatusHeartbeat_Ocs Map toJson() => jsonSerializers.serializeWith(serializer, this)! as Map; NextcloudOCSMeta get meta; - NextcloudUserStatusStatus get data; + NextcloudUserStatusHeartbeat_Ocs_Data get data; static Serializer get serializer => _$nextcloudUserStatusHeartbeatOcsSerializer; } @@ -5112,7 +5164,7 @@ abstract class NextcloudNotificationsNotificationDecryptedSubject NextcloudUserStatusGetPublicStatus_Ocs, NextcloudUserStatusGetStatus, NextcloudUserStatusGetStatus_Ocs, - NextcloudUserStatusStatus, + NextcloudUserStatusStatus1, NextcloudUserStatusPredefinedStatuses, NextcloudUserStatusPredefinedStatuses_Ocs, NextcloudUserStatusPredefinedStatus, diff --git a/packages/nextcloud/lib/src/nextcloud.openapi.g.dart b/packages/nextcloud/lib/src/nextcloud.openapi.g.dart index 14ae1512..05f56271 100644 --- a/packages/nextcloud/lib/src/nextcloud.openapi.g.dart +++ b/packages/nextcloud/lib/src/nextcloud.openapi.g.dart @@ -225,6 +225,7 @@ Serializers _$serializers = (Serializers().toBuilder() ..add(NextcloudUserStatusGetStatus_Ocs_Data.serializer) ..add(NextcloudUserStatusHeartbeat.serializer) ..add(NextcloudUserStatusHeartbeat_Ocs.serializer) + ..add(NextcloudUserStatusHeartbeat_Ocs_Data.serializer) ..add(NextcloudUserStatusPredefinedStatus.serializer) ..add(NextcloudUserStatusPredefinedStatus_ClearAt.serializer) ..add(NextcloudUserStatusPredefinedStatuses.serializer) @@ -232,12 +233,13 @@ Serializers _$serializers = (Serializers().toBuilder() ..add(NextcloudUserStatusPublicStatus.serializer) ..add(NextcloudUserStatusPublicStatus_ClearAt.serializer) ..add(NextcloudUserStatusStatus.serializer) - ..add(NextcloudUserStatusStatus_ClearAt.serializer) + ..add(NextcloudUserStatusStatus1.serializer) ..add(NextcloudUserStatusType.serializer) ..addBuilderFactory(const FullType(BuiltList, [FullType(JsonObject)]), () => ListBuilder()) ..addBuilderFactory(const FullType(BuiltList, [FullType(JsonObject)]), () => ListBuilder()) ..addBuilderFactory(const FullType(BuiltList, [FullType(JsonObject)]), () => ListBuilder()) ..addBuilderFactory(const FullType(BuiltList, [FullType(JsonObject)]), () => ListBuilder()) + ..addBuilderFactory(const FullType(BuiltList, [FullType(JsonObject)]), () => ListBuilder()) ..addBuilderFactory(const FullType(BuiltList, [FullType(NextcloudCoreAutocompleteResult_Ocs_Data)]), () => ListBuilder()) ..addBuilderFactory(const FullType(BuiltList, [FullType(NextcloudCoreNavigationApps_Ocs_Data)]), @@ -548,7 +550,8 @@ Serializer _$nextcloudUserStatusGetPubli _$NextcloudUserStatusGetPublicStatus_OcsSerializer(); Serializer _$nextcloudUserStatusGetPublicStatusSerializer = _$NextcloudUserStatusGetPublicStatusSerializer(); -Serializer _$nextcloudUserStatusStatusSerializer = _$NextcloudUserStatusStatusSerializer(); +Serializer _$nextcloudUserStatusStatus1Serializer = + _$NextcloudUserStatusStatus1Serializer(); Serializer _$nextcloudUserStatusGetStatusOcsSerializer = _$NextcloudUserStatusGetStatus_OcsSerializer(); Serializer _$nextcloudUserStatusGetStatusSerializer = @@ -7380,57 +7383,35 @@ class _$NextcloudUserStatusGetPublicStatusSerializer } } -class _$NextcloudUserStatusStatusSerializer implements StructuredSerializer { +class _$NextcloudUserStatusStatus1Serializer implements StructuredSerializer { @override - final Iterable types = const [NextcloudUserStatusStatus, _$NextcloudUserStatusStatus]; + final Iterable types = const [NextcloudUserStatusStatus1, _$NextcloudUserStatusStatus1]; @override - final String wireName = 'NextcloudUserStatusStatus'; + final String wireName = 'NextcloudUserStatusStatus1'; @override - Iterable serialize(Serializers serializers, NextcloudUserStatusStatus object, + Iterable serialize(Serializers serializers, NextcloudUserStatusStatus1 object, {FullType specifiedType = FullType.unspecified}) { final result = [ - 'userId', - serializers.serialize(object.userId, specifiedType: const FullType(String)), 'messageIsPredefined', serializers.serialize(object.messageIsPredefined, specifiedType: const FullType(bool)), - 'status', - serializers.serialize(object.status, specifiedType: const FullType(NextcloudUserStatusType)), 'statusIsUserDefined', serializers.serialize(object.statusIsUserDefined, specifiedType: const FullType(bool)), ]; Object? value; - value = object.message; - if (value != null) { - result - ..add('message') - ..add(serializers.serialize(value, specifiedType: const FullType(String))); - } value = object.messageId; if (value != null) { result ..add('messageId') ..add(serializers.serialize(value, specifiedType: const FullType(String))); } - value = object.icon; - if (value != null) { - result - ..add('icon') - ..add(serializers.serialize(value, specifiedType: const FullType(String))); - } - value = object.clearAt; - if (value != null) { - result - ..add('clearAt') - ..add(serializers.serialize(value, specifiedType: const FullType(NextcloudUserStatusStatus_ClearAt))); - } return result; } @override - NextcloudUserStatusStatus deserialize(Serializers serializers, Iterable serialized, + NextcloudUserStatusStatus1 deserialize(Serializers serializers, Iterable serialized, {FullType specifiedType = FullType.unspecified}) { - final result = NextcloudUserStatusStatusBuilder(); + final result = NextcloudUserStatusStatus1Builder(); final iterator = serialized.iterator; while (iterator.moveNext()) { @@ -7438,29 +7419,12 @@ class _$NextcloudUserStatusStatusSerializer implements StructuredSerializer - (NextcloudUserStatusStatus_ClearAtBuilder()..update(updates))._build(); + factory _$NextcloudUserStatusStatus1([void Function(NextcloudUserStatusStatus1Builder)? updates]) => + (NextcloudUserStatusStatus1Builder()..update(updates))._build(); - _$NextcloudUserStatusStatus_ClearAt._({required this.data, this.userStatusClearAt, this.$int}) : super._() { - BuiltValueNullFieldError.checkNotNull(data, r'NextcloudUserStatusStatus_ClearAt', 'data'); + _$NextcloudUserStatusStatus1._({this.messageId, required this.messageIsPredefined, required this.statusIsUserDefined}) + : super._() { + BuiltValueNullFieldError.checkNotNull(messageIsPredefined, r'NextcloudUserStatusStatus1', 'messageIsPredefined'); + BuiltValueNullFieldError.checkNotNull(statusIsUserDefined, r'NextcloudUserStatusStatus1', 'statusIsUserDefined'); } @override - NextcloudUserStatusStatus_ClearAt rebuild(void Function(NextcloudUserStatusStatus_ClearAtBuilder) updates) => + NextcloudUserStatusStatus1 rebuild(void Function(NextcloudUserStatusStatus1Builder) updates) => (toBuilder()..update(updates)).build(); @override - NextcloudUserStatusStatus_ClearAtBuilder toBuilder() => NextcloudUserStatusStatus_ClearAtBuilder()..replace(this); + NextcloudUserStatusStatus1Builder toBuilder() => NextcloudUserStatusStatus1Builder()..replace(this); @override bool operator ==(Object other) { if (identical(other, this)) return true; - return other is NextcloudUserStatusStatus_ClearAt && - data == other.data && - userStatusClearAt == other.userStatusClearAt && - $int == other.$int; + return other is NextcloudUserStatusStatus1 && + messageId == other.messageId && + messageIsPredefined == other.messageIsPredefined && + statusIsUserDefined == other.statusIsUserDefined; } @override int get hashCode { var _$hash = 0; - _$hash = $jc(_$hash, data.hashCode); - _$hash = $jc(_$hash, userStatusClearAt.hashCode); - _$hash = $jc(_$hash, $int.hashCode); + _$hash = $jc(_$hash, messageId.hashCode); + _$hash = $jc(_$hash, messageIsPredefined.hashCode); + _$hash = $jc(_$hash, statusIsUserDefined.hashCode); _$hash = $jf(_$hash); return _$hash; } @override String toString() { - return (newBuiltValueToStringHelper(r'NextcloudUserStatusStatus_ClearAt') - ..add('data', data) - ..add('userStatusClearAt', userStatusClearAt) - ..add('\$int', $int)) + return (newBuiltValueToStringHelper(r'NextcloudUserStatusStatus1') + ..add('messageId', messageId) + ..add('messageIsPredefined', messageIsPredefined) + ..add('statusIsUserDefined', statusIsUserDefined)) .toString(); } } -class NextcloudUserStatusStatus_ClearAtBuilder - implements Builder { - _$NextcloudUserStatusStatus_ClearAt? _$v; +class NextcloudUserStatusStatus1Builder + implements Builder { + _$NextcloudUserStatusStatus1? _$v; - JsonObject? _data; - JsonObject? get data => _$this._data; - set data(JsonObject? data) => _$this._data = data; + String? _messageId; + String? get messageId => _$this._messageId; + set messageId(String? messageId) => _$this._messageId = messageId; - NextcloudUserStatusClearAtBuilder? _userStatusClearAt; - NextcloudUserStatusClearAtBuilder get userStatusClearAt => - _$this._userStatusClearAt ??= NextcloudUserStatusClearAtBuilder(); - set userStatusClearAt(NextcloudUserStatusClearAtBuilder? userStatusClearAt) => - _$this._userStatusClearAt = userStatusClearAt; + bool? _messageIsPredefined; + bool? get messageIsPredefined => _$this._messageIsPredefined; + set messageIsPredefined(bool? messageIsPredefined) => _$this._messageIsPredefined = messageIsPredefined; - int? _$int; - int? get $int => _$this._$int; - set $int(int? $int) => _$this._$int = $int; + bool? _statusIsUserDefined; + bool? get statusIsUserDefined => _$this._statusIsUserDefined; + set statusIsUserDefined(bool? statusIsUserDefined) => _$this._statusIsUserDefined = statusIsUserDefined; - NextcloudUserStatusStatus_ClearAtBuilder(); + NextcloudUserStatusStatus1Builder(); - NextcloudUserStatusStatus_ClearAtBuilder get _$this { + NextcloudUserStatusStatus1Builder get _$this { final $v = _$v; if ($v != null) { - _data = $v.data; - _userStatusClearAt = $v.userStatusClearAt?.toBuilder(); - _$int = $v.$int; + _messageId = $v.messageId; + _messageIsPredefined = $v.messageIsPredefined; + _statusIsUserDefined = $v.statusIsUserDefined; _$v = null; } return this; } @override - void replace(NextcloudUserStatusStatus_ClearAt other) { + void replace(NextcloudUserStatusStatus1 other) { ArgumentError.checkNotNull(other, 'other'); - _$v = other as _$NextcloudUserStatusStatus_ClearAt; + _$v = other as _$NextcloudUserStatusStatus1; } @override - void update(void Function(NextcloudUserStatusStatus_ClearAtBuilder)? updates) { + void update(void Function(NextcloudUserStatusStatus1Builder)? updates) { if (updates != null) updates(this); } @override - NextcloudUserStatusStatus_ClearAt build() => _build(); + NextcloudUserStatusStatus1 build() => _build(); - _$NextcloudUserStatusStatus_ClearAt _build() { - _$NextcloudUserStatusStatus_ClearAt _$result; - try { - _$result = _$v ?? - _$NextcloudUserStatusStatus_ClearAt._( - data: BuiltValueNullFieldError.checkNotNull(data, r'NextcloudUserStatusStatus_ClearAt', 'data'), - userStatusClearAt: _userStatusClearAt?.build(), - $int: $int); - } catch (_) { - late String _$failedField; - try { - _$failedField = 'userStatusClearAt'; - _userStatusClearAt?.build(); - } catch (e) { - throw BuiltValueNestedFieldError(r'NextcloudUserStatusStatus_ClearAt', _$failedField, e.toString()); - } - rethrow; - } + _$NextcloudUserStatusStatus1 _build() { + final _$result = _$v ?? + _$NextcloudUserStatusStatus1._( + messageId: messageId, + messageIsPredefined: BuiltValueNullFieldError.checkNotNull( + messageIsPredefined, r'NextcloudUserStatusStatus1', 'messageIsPredefined'), + statusIsUserDefined: BuiltValueNullFieldError.checkNotNull( + statusIsUserDefined, r'NextcloudUserStatusStatus1', 'statusIsUserDefined')); replace(_$result); return _$result; } @@ -21920,39 +21875,22 @@ class NextcloudUserStatusStatus_ClearAtBuilder class _$NextcloudUserStatusStatus extends NextcloudUserStatusStatus { @override - final String userId; - @override - final String? message; - @override - final String? messageId; - @override - final bool messageIsPredefined; - @override - final String? icon; + final JsonObject data; @override - final NextcloudUserStatusStatus_ClearAt? clearAt; + final NextcloudUserStatusPublicStatus userStatusPublicStatus; @override - final NextcloudUserStatusType status; - @override - final bool statusIsUserDefined; + final NextcloudUserStatusStatus1 userStatusStatus1; factory _$NextcloudUserStatusStatus([void Function(NextcloudUserStatusStatusBuilder)? updates]) => (NextcloudUserStatusStatusBuilder()..update(updates))._build(); _$NextcloudUserStatusStatus._( - {required this.userId, - this.message, - this.messageId, - required this.messageIsPredefined, - this.icon, - this.clearAt, - required this.status, - required this.statusIsUserDefined}) + {required this.data, required this.userStatusPublicStatus, required this.userStatusStatus1}) : super._() { - BuiltValueNullFieldError.checkNotNull(userId, r'NextcloudUserStatusStatus', 'userId'); - BuiltValueNullFieldError.checkNotNull(messageIsPredefined, r'NextcloudUserStatusStatus', 'messageIsPredefined'); - BuiltValueNullFieldError.checkNotNull(status, r'NextcloudUserStatusStatus', 'status'); - BuiltValueNullFieldError.checkNotNull(statusIsUserDefined, r'NextcloudUserStatusStatus', 'statusIsUserDefined'); + BuiltValueNullFieldError.checkNotNull(data, r'NextcloudUserStatusStatus', 'data'); + BuiltValueNullFieldError.checkNotNull( + userStatusPublicStatus, r'NextcloudUserStatusStatus', 'userStatusPublicStatus'); + BuiltValueNullFieldError.checkNotNull(userStatusStatus1, r'NextcloudUserStatusStatus', 'userStatusStatus1'); } @override @@ -21966,27 +21904,17 @@ class _$NextcloudUserStatusStatus extends NextcloudUserStatusStatus { bool operator ==(Object other) { if (identical(other, this)) return true; return other is NextcloudUserStatusStatus && - userId == other.userId && - message == other.message && - messageId == other.messageId && - messageIsPredefined == other.messageIsPredefined && - icon == other.icon && - clearAt == other.clearAt && - status == other.status && - statusIsUserDefined == other.statusIsUserDefined; + data == other.data && + userStatusPublicStatus == other.userStatusPublicStatus && + userStatusStatus1 == other.userStatusStatus1; } @override int get hashCode { var _$hash = 0; - _$hash = $jc(_$hash, userId.hashCode); - _$hash = $jc(_$hash, message.hashCode); - _$hash = $jc(_$hash, messageId.hashCode); - _$hash = $jc(_$hash, messageIsPredefined.hashCode); - _$hash = $jc(_$hash, icon.hashCode); - _$hash = $jc(_$hash, clearAt.hashCode); - _$hash = $jc(_$hash, status.hashCode); - _$hash = $jc(_$hash, statusIsUserDefined.hashCode); + _$hash = $jc(_$hash, data.hashCode); + _$hash = $jc(_$hash, userStatusPublicStatus.hashCode); + _$hash = $jc(_$hash, userStatusStatus1.hashCode); _$hash = $jf(_$hash); return _$hash; } @@ -21994,14 +21922,9 @@ class _$NextcloudUserStatusStatus extends NextcloudUserStatusStatus { @override String toString() { return (newBuiltValueToStringHelper(r'NextcloudUserStatusStatus') - ..add('userId', userId) - ..add('message', message) - ..add('messageId', messageId) - ..add('messageIsPredefined', messageIsPredefined) - ..add('icon', icon) - ..add('clearAt', clearAt) - ..add('status', status) - ..add('statusIsUserDefined', statusIsUserDefined)) + ..add('data', data) + ..add('userStatusPublicStatus', userStatusPublicStatus) + ..add('userStatusStatus1', userStatusStatus1)) .toString(); } } @@ -22009,52 +21932,30 @@ class _$NextcloudUserStatusStatus extends NextcloudUserStatusStatus { class NextcloudUserStatusStatusBuilder implements Builder { _$NextcloudUserStatusStatus? _$v; - String? _userId; - String? get userId => _$this._userId; - set userId(String? userId) => _$this._userId = userId; - - String? _message; - String? get message => _$this._message; - set message(String? message) => _$this._message = message; - - String? _messageId; - String? get messageId => _$this._messageId; - set messageId(String? messageId) => _$this._messageId = messageId; - - bool? _messageIsPredefined; - bool? get messageIsPredefined => _$this._messageIsPredefined; - set messageIsPredefined(bool? messageIsPredefined) => _$this._messageIsPredefined = messageIsPredefined; - - String? _icon; - String? get icon => _$this._icon; - set icon(String? icon) => _$this._icon = icon; - - NextcloudUserStatusStatus_ClearAtBuilder? _clearAt; - NextcloudUserStatusStatus_ClearAtBuilder get clearAt => - _$this._clearAt ??= NextcloudUserStatusStatus_ClearAtBuilder(); - set clearAt(NextcloudUserStatusStatus_ClearAtBuilder? clearAt) => _$this._clearAt = clearAt; + JsonObject? _data; + JsonObject? get data => _$this._data; + set data(JsonObject? data) => _$this._data = data; - NextcloudUserStatusType? _status; - NextcloudUserStatusType? get status => _$this._status; - set status(NextcloudUserStatusType? status) => _$this._status = status; + NextcloudUserStatusPublicStatusBuilder? _userStatusPublicStatus; + NextcloudUserStatusPublicStatusBuilder get userStatusPublicStatus => + _$this._userStatusPublicStatus ??= NextcloudUserStatusPublicStatusBuilder(); + set userStatusPublicStatus(NextcloudUserStatusPublicStatusBuilder? userStatusPublicStatus) => + _$this._userStatusPublicStatus = userStatusPublicStatus; - bool? _statusIsUserDefined; - bool? get statusIsUserDefined => _$this._statusIsUserDefined; - set statusIsUserDefined(bool? statusIsUserDefined) => _$this._statusIsUserDefined = statusIsUserDefined; + NextcloudUserStatusStatus1Builder? _userStatusStatus1; + NextcloudUserStatusStatus1Builder get userStatusStatus1 => + _$this._userStatusStatus1 ??= NextcloudUserStatusStatus1Builder(); + set userStatusStatus1(NextcloudUserStatusStatus1Builder? userStatusStatus1) => + _$this._userStatusStatus1 = userStatusStatus1; NextcloudUserStatusStatusBuilder(); NextcloudUserStatusStatusBuilder get _$this { final $v = _$v; if ($v != null) { - _userId = $v.userId; - _message = $v.message; - _messageId = $v.messageId; - _messageIsPredefined = $v.messageIsPredefined; - _icon = $v.icon; - _clearAt = $v.clearAt?.toBuilder(); - _status = $v.status; - _statusIsUserDefined = $v.statusIsUserDefined; + _data = $v.data; + _userStatusPublicStatus = $v.userStatusPublicStatus.toBuilder(); + _userStatusStatus1 = $v.userStatusStatus1.toBuilder(); _$v = null; } return this; @@ -22079,21 +21980,16 @@ class NextcloudUserStatusStatusBuilder implements Builder? builtListJsonObject; + @override + final NextcloudUserStatusStatus? userStatusStatus; + + factory _$NextcloudUserStatusHeartbeat_Ocs_Data( + [void Function(NextcloudUserStatusHeartbeat_Ocs_DataBuilder)? updates]) => + (NextcloudUserStatusHeartbeat_Ocs_DataBuilder()..update(updates))._build(); + + _$NextcloudUserStatusHeartbeat_Ocs_Data._({required this.data, this.builtListJsonObject, this.userStatusStatus}) + : super._() { + BuiltValueNullFieldError.checkNotNull(data, r'NextcloudUserStatusHeartbeat_Ocs_Data', 'data'); + } + + @override + NextcloudUserStatusHeartbeat_Ocs_Data rebuild(void Function(NextcloudUserStatusHeartbeat_Ocs_DataBuilder) updates) => + (toBuilder()..update(updates)).build(); + + @override + NextcloudUserStatusHeartbeat_Ocs_DataBuilder toBuilder() => + NextcloudUserStatusHeartbeat_Ocs_DataBuilder()..replace(this); + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is NextcloudUserStatusHeartbeat_Ocs_Data && + data == other.data && + builtListJsonObject == other.builtListJsonObject && + userStatusStatus == other.userStatusStatus; + } + + @override + int get hashCode { + var _$hash = 0; + _$hash = $jc(_$hash, data.hashCode); + _$hash = $jc(_$hash, builtListJsonObject.hashCode); + _$hash = $jc(_$hash, userStatusStatus.hashCode); + _$hash = $jf(_$hash); + return _$hash; + } + + @override + String toString() { + return (newBuiltValueToStringHelper(r'NextcloudUserStatusHeartbeat_Ocs_Data') + ..add('data', data) + ..add('builtListJsonObject', builtListJsonObject) + ..add('userStatusStatus', userStatusStatus)) + .toString(); + } +} + +class NextcloudUserStatusHeartbeat_Ocs_DataBuilder + implements Builder { + _$NextcloudUserStatusHeartbeat_Ocs_Data? _$v; + + JsonObject? _data; + JsonObject? get data => _$this._data; + set data(JsonObject? data) => _$this._data = data; + + ListBuilder? _builtListJsonObject; + ListBuilder get builtListJsonObject => _$this._builtListJsonObject ??= ListBuilder(); + set builtListJsonObject(ListBuilder? builtListJsonObject) => + _$this._builtListJsonObject = builtListJsonObject; + + NextcloudUserStatusStatusBuilder? _userStatusStatus; + NextcloudUserStatusStatusBuilder get userStatusStatus => + _$this._userStatusStatus ??= NextcloudUserStatusStatusBuilder(); + set userStatusStatus(NextcloudUserStatusStatusBuilder? userStatusStatus) => + _$this._userStatusStatus = userStatusStatus; + + NextcloudUserStatusHeartbeat_Ocs_DataBuilder(); + + NextcloudUserStatusHeartbeat_Ocs_DataBuilder get _$this { + final $v = _$v; + if ($v != null) { + _data = $v.data; + _builtListJsonObject = $v.builtListJsonObject?.toBuilder(); + _userStatusStatus = $v.userStatusStatus?.toBuilder(); + _$v = null; + } + return this; + } + + @override + void replace(NextcloudUserStatusHeartbeat_Ocs_Data other) { + ArgumentError.checkNotNull(other, 'other'); + _$v = other as _$NextcloudUserStatusHeartbeat_Ocs_Data; + } + + @override + void update(void Function(NextcloudUserStatusHeartbeat_Ocs_DataBuilder)? updates) { + if (updates != null) updates(this); + } + + @override + NextcloudUserStatusHeartbeat_Ocs_Data build() => _build(); + + _$NextcloudUserStatusHeartbeat_Ocs_Data _build() { + _$NextcloudUserStatusHeartbeat_Ocs_Data _$result; + try { + _$result = _$v ?? + _$NextcloudUserStatusHeartbeat_Ocs_Data._( + data: BuiltValueNullFieldError.checkNotNull(data, r'NextcloudUserStatusHeartbeat_Ocs_Data', 'data'), + builtListJsonObject: _builtListJsonObject?.build(), + userStatusStatus: _userStatusStatus?.build()); + } catch (_) { + late String _$failedField; + try { + _$failedField = 'builtListJsonObject'; + _builtListJsonObject?.build(); + _$failedField = 'userStatusStatus'; + _userStatusStatus?.build(); + } catch (e) { + throw BuiltValueNestedFieldError(r'NextcloudUserStatusHeartbeat_Ocs_Data', _$failedField, e.toString()); + } + rethrow; + } + replace(_$result); + return _$result; + } +} + class _$NextcloudUserStatusHeartbeat_Ocs extends NextcloudUserStatusHeartbeat_Ocs { @override final NextcloudOCSMeta meta; @override - final NextcloudUserStatusStatus data; + final NextcloudUserStatusHeartbeat_Ocs_Data data; factory _$NextcloudUserStatusHeartbeat_Ocs([void Function(NextcloudUserStatusHeartbeat_OcsBuilder)? updates]) => (NextcloudUserStatusHeartbeat_OcsBuilder()..update(updates))._build(); @@ -22934,9 +22955,10 @@ class NextcloudUserStatusHeartbeat_OcsBuilder NextcloudOCSMetaBuilder get meta => _$this._meta ??= NextcloudOCSMetaBuilder(); set meta(NextcloudOCSMetaBuilder? meta) => _$this._meta = meta; - NextcloudUserStatusStatusBuilder? _data; - NextcloudUserStatusStatusBuilder get data => _$this._data ??= NextcloudUserStatusStatusBuilder(); - set data(NextcloudUserStatusStatusBuilder? data) => _$this._data = data; + NextcloudUserStatusHeartbeat_Ocs_DataBuilder? _data; + NextcloudUserStatusHeartbeat_Ocs_DataBuilder get data => + _$this._data ??= NextcloudUserStatusHeartbeat_Ocs_DataBuilder(); + set data(NextcloudUserStatusHeartbeat_Ocs_DataBuilder? data) => _$this._data = data; NextcloudUserStatusHeartbeat_OcsBuilder(); diff --git a/packages/nextcloud/lib/src/nextcloud.openapi.json b/packages/nextcloud/lib/src/nextcloud.openapi.json index 3b7e4a4f..84b0224d 100644 --- a/packages/nextcloud/lib/src/nextcloud.openapi.json +++ b/packages/nextcloud/lib/src/nextcloud.openapi.json @@ -1894,47 +1894,29 @@ } }, "UserStatusStatus": { - "type": "object", - "required": [ - "userId", - "messageIsPredefined", - "status", - "statusIsUserDefined" - ], - "properties": { - "userId": { - "type": "string" - }, - "message": { - "type": "string" - }, - "messageId": { - "type": "string" - }, - "messageIsPredefined": { - "type": "boolean" - }, - "icon": { - "type": "string" + "allOf": [ + { + "$ref": "#/components/schemas/UserStatusPublicStatus" }, - "clearAt": { - "oneOf": [ - { - "$ref": "#/components/schemas/UserStatusClearAt" + { + "type": "object", + "required": [ + "messageIsPredefined", + "statusIsUserDefined" + ], + "properties": { + "messageId": { + "type": "string" }, - { - "type": "integer", - "description": "Time as unix timestamp" + "messageIsPredefined": { + "type": "boolean" + }, + "statusIsUserDefined": { + "type": "boolean" } - ] - }, - "status": { - "$ref": "#/components/schemas/UserStatusType" - }, - "statusIsUserDefined": { - "type": "boolean" + } } - } + ] }, "UserStatusPublicStatus": { "type": "object", @@ -1985,7 +1967,17 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "$ref": "#/components/schemas/UserStatusStatus" + "oneOf": [ + { + "type": "array", + "items": { + "type": "object" + } + }, + { + "$ref": "#/components/schemas/UserStatusStatus" + } + ] } } } diff --git a/packages/nextcloud/test/user_status.dart b/packages/nextcloud/test/user_status.dart index f432e2d3..e03ff6b1 100644 --- a/packages/nextcloud/test/user_status.dart +++ b/packages/nextcloud/test/user_status.dart @@ -51,14 +51,14 @@ Future run(final DockerImage image) async { test('Set status', () async { final response = await client.userStatus.setStatus(statusType: NextcloudUserStatusType.online); - expect(response.ocs.data.userStatusStatus!.userId, 'user1'); - expect(response.ocs.data.userStatusStatus!.message, null); - expect(response.ocs.data.userStatusStatus!.messageId, null); - expect(response.ocs.data.userStatusStatus!.messageIsPredefined, false); - expect(response.ocs.data.userStatusStatus!.icon, null); - expect(response.ocs.data.userStatusStatus!.clearAt, null); - expect(response.ocs.data.userStatusStatus!.status, NextcloudUserStatusType.online); - expect(response.ocs.data.userStatusStatus!.statusIsUserDefined, true); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.userId, 'user1'); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.message, null); + expect(response.ocs.data.userStatusStatus!.userStatusStatus1.messageId, null); + expect(response.ocs.data.userStatusStatus!.userStatusStatus1.messageIsPredefined, false); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.icon, null); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.clearAt, null); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.status, NextcloudUserStatusType.online); + expect(response.ocs.data.userStatusStatus!.userStatusStatus1.statusIsUserDefined, true); }); test('Get status', () async { @@ -67,14 +67,14 @@ Future run(final DockerImage image) async { await client.userStatus.setStatus(statusType: NextcloudUserStatusType.online); final response = await client.userStatus.getStatus(); - expect(response.ocs.data.userStatusStatus!.userId, 'user1'); - expect(response.ocs.data.userStatusStatus!.message, null); - expect(response.ocs.data.userStatusStatus!.messageId, null); - expect(response.ocs.data.userStatusStatus!.messageIsPredefined, false); - expect(response.ocs.data.userStatusStatus!.icon, null); - expect(response.ocs.data.userStatusStatus!.clearAt, null); - expect(response.ocs.data.userStatusStatus!.status, NextcloudUserStatusType.online); - expect(response.ocs.data.userStatusStatus!.statusIsUserDefined, true); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.userId, 'user1'); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.message, null); + expect(response.ocs.data.userStatusStatus!.userStatusStatus1.messageId, null); + expect(response.ocs.data.userStatusStatus!.userStatusStatus1.messageIsPredefined, false); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.icon, null); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.clearAt, null); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.status, NextcloudUserStatusType.online); + expect(response.ocs.data.userStatusStatus!.userStatusStatus1.statusIsUserDefined, true); }); test('Find all statuses', () async { @@ -110,14 +110,14 @@ Future run(final DockerImage image) async { messageId: 'meeting', clearAt: clearAt, ); - expect(response.ocs.data.userStatusStatus!.userId, 'user1'); - expect(response.ocs.data.userStatusStatus!.message, null); - expect(response.ocs.data.userStatusStatus!.messageId, 'meeting'); - expect(response.ocs.data.userStatusStatus!.messageIsPredefined, true); - expect(response.ocs.data.userStatusStatus!.icon, null); - expect(response.ocs.data.userStatusStatus!.clearAt!.$int, clearAt); - expect(response.ocs.data.userStatusStatus!.status, NextcloudUserStatusType.offline); - expect(response.ocs.data.userStatusStatus!.statusIsUserDefined, false); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.userId, 'user1'); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.message, null); + expect(response.ocs.data.userStatusStatus!.userStatusStatus1.messageId, 'meeting'); + expect(response.ocs.data.userStatusStatus!.userStatusStatus1.messageIsPredefined, true); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.icon, null); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.clearAt!.$int, clearAt); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.status, NextcloudUserStatusType.offline); + expect(response.ocs.data.userStatusStatus!.userStatusStatus1.statusIsUserDefined, false); }); test('Set custom message', () async { @@ -127,14 +127,14 @@ Future run(final DockerImage image) async { message: 'bla', clearAt: clearAt, ); - expect(response.ocs.data.userStatusStatus!.userId, 'user1'); - expect(response.ocs.data.userStatusStatus!.message, 'bla'); - expect(response.ocs.data.userStatusStatus!.messageId, null); - expect(response.ocs.data.userStatusStatus!.messageIsPredefined, false); - expect(response.ocs.data.userStatusStatus!.icon, '😀'); - expect(response.ocs.data.userStatusStatus!.clearAt!.$int, clearAt); - expect(response.ocs.data.userStatusStatus!.status, NextcloudUserStatusType.offline); - expect(response.ocs.data.userStatusStatus!.statusIsUserDefined, false); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.userId, 'user1'); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.message, 'bla'); + expect(response.ocs.data.userStatusStatus!.userStatusStatus1.messageId, null); + expect(response.ocs.data.userStatusStatus!.userStatusStatus1.messageIsPredefined, false); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.icon, '😀'); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.clearAt!.$int, clearAt); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.status, NextcloudUserStatusType.offline); + expect(response.ocs.data.userStatusStatus!.userStatusStatus1.statusIsUserDefined, false); }); test('Clear message', () async { @@ -147,26 +147,26 @@ Future run(final DockerImage image) async { await client.userStatus.clearMessage(); final response = await client.userStatus.getStatus(); - expect(response.ocs.data.userStatusStatus!.userId, 'user1'); - expect(response.ocs.data.userStatusStatus!.message, null); - expect(response.ocs.data.userStatusStatus!.messageId, null); - expect(response.ocs.data.userStatusStatus!.messageIsPredefined, false); - expect(response.ocs.data.userStatusStatus!.icon, null); - expect(response.ocs.data.userStatusStatus!.clearAt, null); - expect(response.ocs.data.userStatusStatus!.status, NextcloudUserStatusType.offline); - expect(response.ocs.data.userStatusStatus!.statusIsUserDefined, false); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.userId, 'user1'); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.message, null); + expect(response.ocs.data.userStatusStatus!.userStatusStatus1.messageId, null); + expect(response.ocs.data.userStatusStatus!.userStatusStatus1.messageIsPredefined, false); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.icon, null); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.clearAt, null); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.status, NextcloudUserStatusType.offline); + expect(response.ocs.data.userStatusStatus!.userStatusStatus1.statusIsUserDefined, false); }); test('Heartbeat', () async { final response = await client.userStatus.heartbeat(status: NextcloudUserStatusType.online); - expect(response.ocs.data.userId, 'user1'); - expect(response.ocs.data.message, null); - expect(response.ocs.data.messageId, null); - expect(response.ocs.data.messageIsPredefined, false); - expect(response.ocs.data.icon, null); - expect(response.ocs.data.clearAt, null); - expect(response.ocs.data.status, NextcloudUserStatusType.online); - expect(response.ocs.data.statusIsUserDefined, false); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.userId, 'user1'); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.message, null); + expect(response.ocs.data.userStatusStatus!.userStatusStatus1.messageId, null); + expect(response.ocs.data.userStatusStatus!.userStatusStatus1.messageIsPredefined, false); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.icon, null); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.clearAt, null); + expect(response.ocs.data.userStatusStatus!.userStatusPublicStatus.status, NextcloudUserStatusType.online); + expect(response.ocs.data.userStatusStatus!.userStatusStatus1.statusIsUserDefined, false); }); }); } diff --git a/specs/user_status.json b/specs/user_status.json index afa3595b..ac0a2206 100644 --- a/specs/user_status.json +++ b/specs/user_status.json @@ -267,47 +267,29 @@ } }, "Status": { - "type": "object", - "required": [ - "userId", - "messageIsPredefined", - "status", - "statusIsUserDefined" - ], - "properties": { - "userId": { - "type": "string" - }, - "message": { - "type": "string" - }, - "messageId": { - "type": "string" - }, - "messageIsPredefined": { - "type": "boolean" - }, - "icon": { - "type": "string" + "allOf": [ + { + "$ref": "#/components/schemas/PublicStatus" }, - "clearAt": { - "oneOf": [ - { - "$ref": "#/components/schemas/ClearAt" + { + "type": "object", + "required": [ + "messageIsPredefined", + "statusIsUserDefined" + ], + "properties": { + "messageId": { + "type": "string" }, - { - "type": "integer", - "description": "Time as unix timestamp" + "messageIsPredefined": { + "type": "boolean" + }, + "statusIsUserDefined": { + "type": "boolean" } - ] - }, - "status": { - "$ref": "#/components/schemas/Type" - }, - "statusIsUserDefined": { - "type": "boolean" + } } - } + ] }, "PublicStatus": { "type": "object", @@ -358,7 +340,17 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "$ref": "#/components/schemas/Status" + "oneOf": [ + { + "type": "array", + "items": { + "type": "object" + } + }, + { + "$ref": "#/components/schemas/Status" + } + ] } } } From bb694580d8a75008e4128f95fe74d927d2a94327 Mon Sep 17 00:00:00 2001 From: jld3103 Date: Wed, 31 May 2023 16:30:48 +0200 Subject: [PATCH 2/5] neon: Use Stream in ResultBuilder to allow any kind of Stream --- packages/neon/neon/lib/src/widgets/result_builder.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/neon/neon/lib/src/widgets/result_builder.dart b/packages/neon/neon/lib/src/widgets/result_builder.dart index c5d1dcee..d527287f 100644 --- a/packages/neon/neon/lib/src/widgets/result_builder.dart +++ b/packages/neon/neon/lib/src/widgets/result_builder.dart @@ -7,7 +7,7 @@ class ResultBuilder extends StatelessWidget { super.key, }); - final BehaviorSubject>? stream; + final Stream?>? stream; final Widget Function(BuildContext, Result) builder; From e8a48c786910daa7c219ac5909faa0ccd3d24bc9 Mon Sep 17 00:00:00 2001 From: jld3103 Date: Thu, 1 Jun 2023 17:23:46 +0200 Subject: [PATCH 3/5] neon: Implement TimerBloc --- .github/workflows/dart.yml | 38 ++++++++- packages/neon/neon/lib/neon.dart | 1 + packages/neon/neon/lib/src/blocs/timer.dart | 85 ++++++++++++++++++++ packages/neon/neon/mono_pkg.yaml | 1 + packages/neon/neon/pubspec.yaml | 1 + packages/neon/neon/test/timer_bloc_test.dart | 43 ++++++++++ tool/ci.sh | 6 +- 7 files changed, 171 insertions(+), 4 deletions(-) create mode 100644 packages/neon/neon/lib/src/blocs/timer.dart create mode 100644 packages/neon/neon/test/timer_bloc_test.dart diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index 9f8494bd..de6bf129 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -869,6 +869,38 @@ jobs: needs: - job_001 job_028: + name: "all; PKG: packages/neon/neon; `flutter test`" + runs-on: ubuntu-latest + steps: + - name: Cache Pub hosted dependencies + uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 + with: + path: "~/.pub-cache/hosted" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/neon/neon;commands:test_0" + restore-keys: | + os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/neon/neon + os:ubuntu-latest;pub-cache-hosted;sdk:stable + os:ubuntu-latest;pub-cache-hosted + os:ubuntu-latest + - name: Setup Flutter SDK + uses: subosito/flutter-action@48cafc24713cca54bbe03cdc3a423187d413aafa + with: + channel: stable + - id: checkout + name: Checkout repository + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab + - id: packages_neon_neon_pub_upgrade + name: packages/neon/neon; flutter pub upgrade + run: flutter pub upgrade + if: "always() && steps.checkout.conclusion == 'success'" + working-directory: packages/neon/neon + - name: packages/neon/neon; flutter test + run: flutter test + if: "always() && steps.packages_neon_neon_pub_upgrade.conclusion == 'success'" + working-directory: packages/neon/neon + needs: + - job_001 + job_029: name: "all; PKG: packages/nextcloud; `dart test`" runs-on: ubuntu-latest steps: @@ -876,7 +908,7 @@ jobs: uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/nextcloud;commands:test" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/nextcloud;commands:test_1" restore-keys: | os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/nextcloud os:ubuntu-latest;pub-cache-hosted;sdk:stable @@ -900,7 +932,7 @@ jobs: working-directory: packages/nextcloud needs: - job_001 - job_029: + job_030: name: "all; PKG: packages/sort_box; `dart test`" runs-on: ubuntu-latest steps: @@ -908,7 +940,7 @@ jobs: uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/sort_box;commands:test" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/sort_box;commands:test_1" restore-keys: | os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/sort_box os:ubuntu-latest;pub-cache-hosted;sdk:stable diff --git a/packages/neon/neon/lib/neon.dart b/packages/neon/neon/lib/neon.dart index b30ad6bb..2bc8e73f 100644 --- a/packages/neon/neon/lib/neon.dart +++ b/packages/neon/neon/lib/neon.dart @@ -56,6 +56,7 @@ part 'src/blocs/first_launch.dart'; part 'src/blocs/login.dart'; part 'src/blocs/next_push.dart'; part 'src/blocs/push_notifications.dart'; +part 'src/blocs/timer.dart'; part 'src/blocs/user_details.dart'; part 'src/blocs/user_status.dart'; part 'src/interfaces/notifications.dart'; diff --git a/packages/neon/neon/lib/src/blocs/timer.dart b/packages/neon/neon/lib/src/blocs/timer.dart new file mode 100644 index 00000000..c19f327c --- /dev/null +++ b/packages/neon/neon/lib/src/blocs/timer.dart @@ -0,0 +1,85 @@ +part of '../../neon.dart'; + +abstract class TimerBlocEvents { + /// Register a [callback] that will be called periodically. + /// The time between the executions is defined by the [duration]. + NeonTimer registerTimer(final Duration duration, final VoidCallback callback); + + /// Unregister a timer that has been previously registered with the bloc. + /// You can also use [NeonTimer.cancel]. + void unregisterTimer(final NeonTimer timer); +} + +abstract class TimerBlocStates {} + +/// Execute callbacks at defined periodic intervals. +/// Components can register their callbacks and everything with the same periodicity will be executed at the same time. +/// +/// The [TimerBloc] is a singleton. +/// Sub-second timers are not supported. +class TimerBloc extends Bloc implements TimerBlocEvents, TimerBlocStates { + factory TimerBloc() => instance ??= TimerBloc._(); + + @visibleForTesting + factory TimerBloc.mocked(final TimerBloc mock) => instance ??= mock; + + TimerBloc._(); + + @visibleForTesting + static TimerBloc? instance; + + final Map _timers = {}; + final Map> _callbacks = {}; + + @visibleForTesting + Map get timers => _timers; + + @visibleForTesting + Map> get callbacks => _callbacks; + + @override + void dispose() { + for (final timer in _timers.values) { + timer.cancel(); + } + _timers.clear(); + _callbacks.clear(); + TimerBloc.instance = null; + } + + @override + NeonTimer registerTimer(final Duration duration, final VoidCallback callback) { + if (_timers[duration.inSeconds] == null) { + _timers[duration.inSeconds] = Timer.periodic(duration, (final _) { + for (final callback in _callbacks[duration.inSeconds]!) { + callback(); + } + }); + _callbacks[duration.inSeconds] = {callback}; + } else { + _callbacks[duration.inSeconds]!.add(callback); + } + return NeonTimer(duration, callback); + } + + @override + void unregisterTimer(final NeonTimer timer) { + if (_timers[timer.duration.inSeconds] != null) { + _callbacks[timer.duration.inSeconds]!.remove(timer.callback); + } + } +} + +class NeonTimer { + NeonTimer( + this.duration, + this.callback, + ); + + final Duration duration; + final VoidCallback callback; + + void cancel() { + TimerBloc().unregisterTimer(this); + } +} diff --git a/packages/neon/neon/mono_pkg.yaml b/packages/neon/neon/mono_pkg.yaml index 60bc3bfd..a6c495b0 100644 --- a/packages/neon/neon/mono_pkg.yaml +++ b/packages/neon/neon/mono_pkg.yaml @@ -5,3 +5,4 @@ stages: - all: - analyze: --fatal-infos . - format: --output=none --set-exit-if-changed --line-length 120 . + - test diff --git a/packages/neon/neon/pubspec.yaml b/packages/neon/neon/pubspec.yaml index 5bca6d64..3cd0244e 100644 --- a/packages/neon/neon/pubspec.yaml +++ b/packages/neon/neon/pubspec.yaml @@ -64,6 +64,7 @@ dev_dependencies: git: url: https://github.com/stack11/dart_nit_picking ref: 0b2ee0d + test: ^1.24.3 dependency_overrides: wakelock_windows: # TODO: https://github.com/creativecreatorormaybenot/wakelock/pull/195 diff --git a/packages/neon/neon/test/timer_bloc_test.dart b/packages/neon/neon/test/timer_bloc_test.dart new file mode 100644 index 00000000..504e23df --- /dev/null +++ b/packages/neon/neon/test/timer_bloc_test.dart @@ -0,0 +1,43 @@ +import 'package:neon/neon.dart'; +import 'package:test/test.dart'; + +void main() { + group('TimerBloc', () { + tearDown(() { + TimerBloc().dispose(); + }); + + test('Register timer', () async { + const duration = Duration(milliseconds: 100); + + final stopwatch = Stopwatch()..start(); + final callback = stopwatch.stop; + TimerBloc().registerTimer(duration, callback); + await Future.delayed(duration); + + expect(stopwatch.elapsedMilliseconds, greaterThan(duration.inMilliseconds)); + expect(stopwatch.elapsedMilliseconds, lessThan(duration.inMilliseconds * 1.1)); + expect(TimerBloc().callbacks[duration.inSeconds], contains(callback)); + expect(TimerBloc().timers[duration.inSeconds], isNot(isNull)); + }); + + test('Unregister timer', () async { + const duration = Duration(milliseconds: 100); + final callback = neverCalled; + + TimerBloc().registerTimer(duration, callback).cancel(); + await Future.delayed(duration); + + expect(TimerBloc().callbacks[duration.inSeconds], isNot(contains(callback))); + }); + + test('dispose', () { + TimerBloc().registerTimer(const Duration(minutes: 1), () {}); + expect(TimerBloc().timers, hasLength(1)); + expect(TimerBloc().callbacks, hasLength(1)); + TimerBloc().dispose(); + expect(TimerBloc().timers, isEmpty); + expect(TimerBloc().callbacks, isEmpty); + }); + }); +} diff --git a/tool/ci.sh b/tool/ci.sh index 59aa55ff..b07eaafb 100755 --- a/tool/ci.sh +++ b/tool/ci.sh @@ -79,7 +79,11 @@ for PKG in ${PKGS}; do echo 'dart format --output=none --set-exit-if-changed --line-length 120 .' dart format --output=none --set-exit-if-changed --line-length 120 . || EXIT_CODE=$? ;; - test) + test_0) + echo 'flutter test' + flutter test || EXIT_CODE=$? + ;; + test_1) echo 'dart test' dart test || EXIT_CODE=$? ;; From 6bd19e32f18b80de1f5d40f7fe93228000f0a0b3 Mon Sep 17 00:00:00 2001 From: jld3103 Date: Wed, 31 May 2023 16:30:05 +0200 Subject: [PATCH 4/5] neon: Refactor UserStatusBloc into UserStatusesBloc --- packages/neon/neon/lib/neon.dart | 2 +- .../neon/neon/lib/src/blocs/accounts.dart | 12 +-- .../neon/neon/lib/src/blocs/user_status.dart | 61 ------------- .../neon/lib/src/blocs/user_statuses.dart | 85 +++++++++++++++++++ 4 files changed, 92 insertions(+), 68 deletions(-) delete mode 100644 packages/neon/neon/lib/src/blocs/user_status.dart create mode 100644 packages/neon/neon/lib/src/blocs/user_statuses.dart diff --git a/packages/neon/neon/lib/neon.dart b/packages/neon/neon/lib/neon.dart index 2bc8e73f..0de68ae2 100644 --- a/packages/neon/neon/lib/neon.dart +++ b/packages/neon/neon/lib/neon.dart @@ -58,7 +58,7 @@ part 'src/blocs/next_push.dart'; part 'src/blocs/push_notifications.dart'; part 'src/blocs/timer.dart'; part 'src/blocs/user_details.dart'; -part 'src/blocs/user_status.dart'; +part 'src/blocs/user_statuses.dart'; part 'src/interfaces/notifications.dart'; part 'src/pages/account_settings.dart'; part 'src/pages/home.dart'; diff --git a/packages/neon/neon/lib/src/blocs/accounts.dart b/packages/neon/neon/lib/src/blocs/accounts.dart index c1d8a16e..1fda9d6b 100644 --- a/packages/neon/neon/lib/src/blocs/accounts.dart +++ b/packages/neon/neon/lib/src/blocs/accounts.dart @@ -74,7 +74,7 @@ class AccountsBloc extends Bloc implements AccountsBlocEvents, AccountsBlocState final _appsBlocs = {}; final _capabilitiesBlocs = {}; final _userDetailsBlocs = {}; - final _userStatusBlocs = {}; + final _userStatusesBlocs = {}; @override void dispose() { @@ -83,7 +83,7 @@ class AccountsBloc extends Bloc implements AccountsBlocEvents, AccountsBlocState _appsBlocs.disposeAll(); _capabilitiesBlocs.disposeAll(); _userDetailsBlocs.disposeAll(); - _userStatusBlocs.disposeAll(); + _userStatusesBlocs.disposeAll(); for (final options in _accountsOptions.values) { options.dispose(); } @@ -190,12 +190,12 @@ class AccountsBloc extends Bloc implements AccountsBlocEvents, AccountsBlocState ); } - UserStatusBloc getUserStatusBloc(final Account account) { - if (_userStatusBlocs[account.id] != null) { - return _userStatusBlocs[account.id]!; + UserStatusesBloc getUserStatusesBloc(final Account account) { + if (_userStatusesBlocs[account.id] != null) { + return _userStatusesBlocs[account.id]!; } - return _userStatusBlocs[account.id] = UserStatusBloc( + return _userStatusesBlocs[account.id] = UserStatusesBloc( _platform, account, ); diff --git a/packages/neon/neon/lib/src/blocs/user_status.dart b/packages/neon/neon/lib/src/blocs/user_status.dart deleted file mode 100644 index 7704657e..00000000 --- a/packages/neon/neon/lib/src/blocs/user_status.dart +++ /dev/null @@ -1,61 +0,0 @@ -part of '../../neon.dart'; - -abstract class UserStatusBlocEvents {} - -abstract class UserStatusBlocStates { - BehaviorSubject> get userStatus; -} - -class UserStatusBloc extends InteractiveBloc implements UserStatusBlocEvents, UserStatusBlocStates { - UserStatusBloc( - this._platform, - this._account, - ) { - _timer = instantPeriodicTimer( - const Duration(minutes: 5), - (final _) async { - await refresh(); - }, - ); - } - - final NeonPlatform _platform; - final Account _account; - late Timer _timer; - - @override - void dispose() { - _timer.cancel(); - unawaited(userStatus.close()); - } - - @override - BehaviorSubject> userStatus = - BehaviorSubject>(); - - @override - Future refresh() async { - final isAway = - _platform.canUseWindowManager && (!(await windowManager.isFocused()) || !(await windowManager.isVisible())); - try { - final response = await _account.client.userStatus.heartbeat( - status: isAway ? NextcloudUserStatusType.away : NextcloudUserStatusType.online, - ); - userStatus.add(Result.success(response.ocs.data)); - } catch (e) { - if (e is NextcloudApiException && e.statusCode == 204) { - return; - } - userStatus.add(Result.error(e)); - } - } -} - -Timer instantPeriodicTimer( - final Duration duration, - final void Function(Timer timer) callback, -) { - final timer = Timer.periodic(duration, callback); - callback(timer); - return timer; -} diff --git a/packages/neon/neon/lib/src/blocs/user_statuses.dart b/packages/neon/neon/lib/src/blocs/user_statuses.dart new file mode 100644 index 00000000..21b8803f --- /dev/null +++ b/packages/neon/neon/lib/src/blocs/user_statuses.dart @@ -0,0 +1,85 @@ +part of '../../neon.dart'; + +abstract class UserStatusesBlocEvents { + void load(final String username, {final bool force = false}); +} + +abstract class UserStatusesBlocStates { + BehaviorSubject>> get statuses; +} + +class UserStatusesBloc extends InteractiveBloc implements UserStatusesBlocEvents, UserStatusesBlocStates { + UserStatusesBloc( + this._platform, + this._account, + ) { + unawaited(refresh()); + _timer = TimerBloc().registerTimer(const Duration(minutes: 5), refresh); + } + + final NeonPlatform _platform; + final Account _account; + late final NeonTimer _timer; + + @override + void dispose() { + _timer.cancel(); + unawaited(statuses.close()); + super.dispose(); + } + + @override + BehaviorSubject>> statuses = + BehaviorSubject>>(); + + @override + Future refresh() async { + for (final username in _statuses.keys) { + await load(username, force: true); + } + } + + @override + Future load(final String username, {final bool force = false}) async { + if (!force && _statuses.containsKey(username)) { + return; + } + + try { + _updateStatus(username, Result.loading()); + + NextcloudUserStatusPublicStatus? data; + if (_account.username == username) { + final isAway = + _platform.canUseWindowManager && (!(await windowManager.isFocused()) || !(await windowManager.isVisible())); + final response = await _account.client.userStatus.heartbeat( + status: isAway ? NextcloudUserStatusType.away : NextcloudUserStatusType.online, + ); + data = response.ocs.data.userStatusStatus?.userStatusPublicStatus; + } else { + final response = await _account.client.userStatus.getPublicStatus(userId: username); + data = response.ocs.data.userStatusPublicStatus; + } + + _updateStatus(username, Result.success(data)); + } catch (e, s) { + if (e is NextcloudApiException && (e.statusCode == 404 || e.statusCode == 204)) { + _updateStatus(username, Result.success(null)); + return; + } + debugPrint(e.toString()); + debugPrint(s.toString()); + _updateStatus(username, Result.error(e)); + } + } + + Map> get _statuses => + statuses.valueOrNull ?? >{}; + + void _updateStatus(final String username, final Result result) { + statuses.add({ + ..._statuses, + username: result, + }); + } +} From 8209dcd95f97e2e5c2e992e2c09ec333f57e1cae Mon Sep 17 00:00:00 2001 From: jld3103 Date: Wed, 31 May 2023 16:28:18 +0200 Subject: [PATCH 5/5] neon: Refactor AccountAvatar into UserAvatar --- packages/neon/neon/lib/neon.dart | 2 +- packages/neon/neon/lib/src/pages/home.dart | 4 +- .../neon/lib/src/widgets/account_avatar.dart | 103 -------------- .../neon/lib/src/widgets/account_tile.dart | 2 +- .../neon/lib/src/widgets/user_avatar.dart | 126 ++++++++++++++++++ 5 files changed, 130 insertions(+), 107 deletions(-) delete mode 100644 packages/neon/neon/lib/src/widgets/account_avatar.dart create mode 100644 packages/neon/neon/lib/src/widgets/user_avatar.dart diff --git a/packages/neon/neon/lib/neon.dart b/packages/neon/neon/lib/neon.dart index 0de68ae2..6992799e 100644 --- a/packages/neon/neon/lib/neon.dart +++ b/packages/neon/neon/lib/neon.dart @@ -93,7 +93,6 @@ part 'src/utils/storage.dart'; part 'src/utils/stream_listenable.dart'; part 'src/utils/theme.dart'; part 'src/utils/validators.dart'; -part 'src/widgets/account_avatar.dart'; part 'src/widgets/account_settings_tile.dart'; part 'src/widgets/account_tile.dart'; part 'src/widgets/app_implementation_icon.dart'; @@ -109,6 +108,7 @@ part 'src/widgets/nextcloud_logo.dart'; part 'src/widgets/relative_time.dart'; part 'src/widgets/result_builder.dart'; part 'src/widgets/text_settings_tile.dart'; +part 'src/widgets/user_avatar.dart'; Future runNeon({ required final WidgetsBinding binding, diff --git a/packages/neon/neon/lib/src/pages/home.dart b/packages/neon/neon/lib/src/pages/home.dart index a3cc9f7b..3e165ad7 100644 --- a/packages/neon/neon/lib/src/pages/home.dart +++ b/packages/neon/neon/lib/src/pages/home.dart @@ -225,7 +225,7 @@ class _HomePageState extends State { }, tooltip: account.client.humanReadableID, icon: IntrinsicHeight( - child: NeonAccountAvatar( + child: NeonUserAvatar( account: account, ), ), @@ -496,7 +496,7 @@ class _HomePageState extends State { }, tooltip: AppLocalizations.of(context).settingsAccount, icon: IntrinsicWidth( - child: NeonAccountAvatar( + child: NeonUserAvatar( account: account, ), ), diff --git a/packages/neon/neon/lib/src/widgets/account_avatar.dart b/packages/neon/neon/lib/src/widgets/account_avatar.dart deleted file mode 100644 index 4cbf95fe..00000000 --- a/packages/neon/neon/lib/src/widgets/account_avatar.dart +++ /dev/null @@ -1,103 +0,0 @@ -part of '../../neon.dart'; - -const kAvatarSize = 40.0; - -class NeonAccountAvatar extends StatelessWidget { - const NeonAccountAvatar({ - required this.account, - super.key, - }); - - final Account account; - - @override - Widget build(final BuildContext context) { - final isDark = Theme.of(context).brightness == Brightness.dark; - final size = (kAvatarSize * MediaQuery.of(context).devicePixelRatio).toInt(); - final userStatusBloc = Provider.of(context, listen: false).getUserStatusBloc(account); - return SizedBox.square( - dimension: kAvatarSize, - child: Stack( - alignment: Alignment.center, - children: [ - CircleAvatar( - child: ClipOval( - child: NeonCachedApiImage( - account: account, - cacheKey: 'avatar-${account.id}-${isDark ? 'dark' : 'light'}$size', - download: () async { - if (isDark) { - return account.client.core.getDarkAvatar( - userId: account.username, - size: size, - ); - } else { - return account.client.core.getAvatar( - userId: account.username, - size: size, - ); - } - }, - ), - ), - ), - ResultBuilder( - stream: userStatusBloc.userStatus, - builder: (final context, final userStatus) { - final hasEmoji = userStatus.data?.icon != null; - final factor = hasEmoji ? 2 : 3; - return Align( - alignment: Alignment.bottomRight, - child: Container( - height: kAvatarSize / factor, - width: kAvatarSize / factor, - decoration: userStatus.loading || userStatus.error != null || userStatus.data == null || hasEmoji - ? null - : BoxDecoration( - shape: BoxShape.circle, - color: _userStatusToColor(userStatus.data!), - ), - child: userStatus.loading - ? CircularProgressIndicator( - strokeWidth: 1.5, - color: Theme.of(context).colorScheme.onPrimary, - ) - : userStatus.error != null && - (userStatus.error is! NextcloudApiException || - (userStatus.error! as NextcloudApiException).statusCode != 404) - ? NeonException( - userStatus.error, - onRetry: userStatusBloc.refresh, - onlyIcon: true, - iconSize: kAvatarSize / factor, - ) - : hasEmoji - ? Text( - userStatus.data!.icon!, - style: const TextStyle( - fontSize: 16, - ), - ) - : null, - ), - ); - }, - ), - ], - ), - ); - } - - Color _userStatusToColor(final NextcloudUserStatusStatus userStatus) { - switch (userStatus.status) { - case NextcloudUserStatusType.online: - return const Color(0xFF49B382); - case NextcloudUserStatusType.away: - return const Color(0xFFF4A331); - case NextcloudUserStatusType.dnd: - return const Color(0xFFED484C); - default: - return Colors.transparent; - } - } -} diff --git a/packages/neon/neon/lib/src/widgets/account_tile.dart b/packages/neon/neon/lib/src/widgets/account_tile.dart index b93dacb9..4da61494 100644 --- a/packages/neon/neon/lib/src/widgets/account_tile.dart +++ b/packages/neon/neon/lib/src/widgets/account_tile.dart @@ -34,7 +34,7 @@ class NeonAccountTile extends StatelessWidget { ) : null, leading: IntrinsicWidth( - child: NeonAccountAvatar( + child: NeonUserAvatar( account: account, ), ), diff --git a/packages/neon/neon/lib/src/widgets/user_avatar.dart b/packages/neon/neon/lib/src/widgets/user_avatar.dart new file mode 100644 index 00000000..c19285bc --- /dev/null +++ b/packages/neon/neon/lib/src/widgets/user_avatar.dart @@ -0,0 +1,126 @@ +// ignore_for_file: use_late_for_private_fields_and_variables +// ^ This is a really strange false positive, it goes of at a very random place without any meaning. Hopefully fixed soon? + +part of '../../neon.dart'; + +const kAvatarSize = 40.0; + +class NeonUserAvatar extends StatefulWidget { + NeonUserAvatar({ + required this.account, + final String? username, + this.showStatus = true, + this.size = kAvatarSize, + super.key, + }) : username = username ?? account.client.username!; + + final Account account; + final String username; + final bool showStatus; + final double size; + + @override + State createState() => _UserAvatarState(); +} + +class _UserAvatarState extends State { + late final _userStatusBloc = Provider.of(context, listen: false).getUserStatusesBloc(widget.account); + + @override + void initState() { + super.initState(); + + unawaited(_userStatusBloc.load(widget.username)); + } + + @override + Widget build(final BuildContext context) { + final isDark = Theme.of(context).brightness == Brightness.dark; + final size = (widget.size * MediaQuery.of(context).devicePixelRatio).toInt(); + return Stack( + alignment: Alignment.center, + children: [ + CircleAvatar( + radius: widget.size / 2, + child: ClipOval( + child: NeonCachedApiImage( + account: widget.account, + cacheKey: 'avatar-${widget.username}-${isDark ? 'dark' : 'light'}$size', + download: () async { + if (isDark) { + return widget.account.client.core.getDarkAvatar( + userId: widget.username, + size: size, + ); + } else { + return widget.account.client.core.getAvatar( + userId: widget.username, + size: size, + ); + } + }, + ), + ), + ), + if (widget.showStatus) ...[ + ResultBuilder( + stream: _userStatusBloc.statuses.map((final statuses) => statuses[widget.username]), + builder: _userStatusIconBuilder, + ), + ], + ], + ); + } + + Widget _userStatusIconBuilder(final BuildContext context, final Result result) { + final hasEmoji = result.data?.icon != null; + final scaledSize = widget.size / (hasEmoji ? 2 : 3); + + Widget? child; + Decoration? decoration; + if (result.loading) { + child = CircularProgressIndicator( + strokeWidth: 1.5, + color: Theme.of(context).colorScheme.onPrimary, + ); + } else if (result.error != null) { + child = Icon( + Icons.error_outline, + size: scaledSize, + color: Theme.of(context).colorScheme.error, + ); + } else if (hasEmoji) { + child = Text( + result.data!.icon!, + style: const TextStyle( + fontSize: 16, + ), + ); + } else if (result.data != null) { + decoration = BoxDecoration( + shape: BoxShape.circle, + color: _userStatusToColor(result.data!.status), + ); + } + + return SizedBox.square( + dimension: widget.size, + child: Align( + alignment: Alignment.bottomRight, + child: Container( + width: scaledSize, + height: scaledSize, + decoration: decoration, + child: child, + ), + ), + ); + } + + Color? _userStatusToColor(final NextcloudUserStatusType userStatusType) => switch (userStatusType) { + NextcloudUserStatusType.online => const Color(0xFF49B382), + NextcloudUserStatusType.away => const Color(0xFFF4A331), + NextcloudUserStatusType.dnd => const Color(0xFFED484C), + _ => null, + }; +}