implemented an E2E-encrypted Nextcloud push-v2 notification system with support for RSA decryption and signature verification; introduced an iOS Notification Service Extension and native AppDelegate handlers for Talk actions (inline reply and mark-as-read); replaced the legacy notification registration with a new lifecycle managing app passwords and secure keypair storage; added background message handling with tray synchronization and a test notification utility in the settings.
This commit is contained in:
1 parent
32f7c311bc
commit
74a2ddd17f
56 files changed
+2987
-285
No files matched your search
@@ -13,6 +13,8 @@ class CapabilitiesCubit extends HydratedCubit<CapabilitiesState> {
|
||||
|
||||
bool get canViewForeignTimetables => state.viewForeignTimetables;
|
||||
|
||||
bool get canReceivePushNotifications => state.pushNotifications;
|
||||
|
||||
/// Refreshes capabilities from the server. On any failure (endpoint not yet
|
||||
/// live, network error, 4xx) the previously hydrated flags are kept but the
|
||||
/// state is marked `loaded` — a failed fetch never silently grants a
|
||||
@@ -23,6 +25,7 @@ class CapabilitiesCubit extends HydratedCubit<CapabilitiesState> {
|
||||
emit(
|
||||
CapabilitiesState(
|
||||
viewForeignTimetables: response.viewForeignTimetables,
|
||||
pushNotifications: response.pushNotifications,
|
||||
loaded: true,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@ part 'capabilities_state.g.dart';
|
||||
abstract class CapabilitiesState with _$CapabilitiesState {
|
||||
const factory CapabilitiesState({
|
||||
@Default(false) bool viewForeignTimetables,
|
||||
@Default(false) bool pushNotifications,
|
||||
// Whether a capability response (or a definitive failure) has been
|
||||
// observed at least once this session. Lets the UI distinguish "still
|
||||
// unknown" from "confirmed not allowed".
|
||||
|
||||
@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$CapabilitiesState {
|
||||
|
||||
bool get viewForeignTimetables;// Whether a capability response (or a definitive failure) has been
|
||||
bool get viewForeignTimetables; bool get pushNotifications;// Whether a capability response (or a definitive failure) has been
|
||||
// observed at least once this session. Lets the UI distinguish "still
|
||||
// unknown" from "confirmed not allowed".
|
||||
bool get loaded;
|
||||
@@ -31,16 +31,16 @@ $CapabilitiesStateCopyWith<CapabilitiesState> get copyWith => _$CapabilitiesStat
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is CapabilitiesState&&(identical(other.viewForeignTimetables, viewForeignTimetables) || other.viewForeignTimetables == viewForeignTimetables)&&(identical(other.loaded, loaded) || other.loaded == loaded));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is CapabilitiesState&&(identical(other.viewForeignTimetables, viewForeignTimetables) || other.viewForeignTimetables == viewForeignTimetables)&&(identical(other.pushNotifications, pushNotifications) || other.pushNotifications == pushNotifications)&&(identical(other.loaded, loaded) || other.loaded == loaded));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,viewForeignTimetables,loaded);
|
||||
int get hashCode => Object.hash(runtimeType,viewForeignTimetables,pushNotifications,loaded);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CapabilitiesState(viewForeignTimetables: $viewForeignTimetables, loaded: $loaded)';
|
||||
return 'CapabilitiesState(viewForeignTimetables: $viewForeignTimetables, pushNotifications: $pushNotifications, loaded: $loaded)';
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ abstract mixin class $CapabilitiesStateCopyWith<$Res> {
|
||||
factory $CapabilitiesStateCopyWith(CapabilitiesState value, $Res Function(CapabilitiesState) _then) = _$CapabilitiesStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
bool viewForeignTimetables, bool loaded
|
||||
bool viewForeignTimetables, bool pushNotifications, bool loaded
|
||||
});
|
||||
|
||||
|
||||
@@ -68,9 +68,10 @@ class _$CapabilitiesStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of CapabilitiesState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? viewForeignTimetables = null,Object? loaded = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? viewForeignTimetables = null,Object? pushNotifications = null,Object? loaded = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
viewForeignTimetables: null == viewForeignTimetables ? _self.viewForeignTimetables : viewForeignTimetables // ignore: cast_nullable_to_non_nullable
|
||||
as bool,pushNotifications: null == pushNotifications ? _self.pushNotifications : pushNotifications // ignore: cast_nullable_to_non_nullable
|
||||
as bool,loaded: null == loaded ? _self.loaded : loaded // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
@@ -157,10 +158,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool viewForeignTimetables, bool loaded)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool viewForeignTimetables, bool pushNotifications, bool loaded)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _CapabilitiesState() when $default != null:
|
||||
return $default(_that.viewForeignTimetables,_that.loaded);case _:
|
||||
return $default(_that.viewForeignTimetables,_that.pushNotifications,_that.loaded);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -178,10 +179,10 @@ return $default(_that.viewForeignTimetables,_that.loaded);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool viewForeignTimetables, bool loaded) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool viewForeignTimetables, bool pushNotifications, bool loaded) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _CapabilitiesState():
|
||||
return $default(_that.viewForeignTimetables,_that.loaded);case _:
|
||||
return $default(_that.viewForeignTimetables,_that.pushNotifications,_that.loaded);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
@@ -198,10 +199,10 @@ return $default(_that.viewForeignTimetables,_that.loaded);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool viewForeignTimetables, bool loaded)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool viewForeignTimetables, bool pushNotifications, bool loaded)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _CapabilitiesState() when $default != null:
|
||||
return $default(_that.viewForeignTimetables,_that.loaded);case _:
|
||||
return $default(_that.viewForeignTimetables,_that.pushNotifications,_that.loaded);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -213,10 +214,11 @@ return $default(_that.viewForeignTimetables,_that.loaded);case _:
|
||||
@JsonSerializable()
|
||||
|
||||
class _CapabilitiesState implements CapabilitiesState {
|
||||
const _CapabilitiesState({this.viewForeignTimetables = false, this.loaded = false});
|
||||
const _CapabilitiesState({this.viewForeignTimetables = false, this.pushNotifications = false, this.loaded = false});
|
||||
factory _CapabilitiesState.fromJson(Map<String, dynamic> json) => _$CapabilitiesStateFromJson(json);
|
||||
|
||||
@override@JsonKey() final bool viewForeignTimetables;
|
||||
@override@JsonKey() final bool pushNotifications;
|
||||
// Whether a capability response (or a definitive failure) has been
|
||||
// observed at least once this session. Lets the UI distinguish "still
|
||||
// unknown" from "confirmed not allowed".
|
||||
@@ -235,16 +237,16 @@ Map<String, dynamic> toJson() {
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CapabilitiesState&&(identical(other.viewForeignTimetables, viewForeignTimetables) || other.viewForeignTimetables == viewForeignTimetables)&&(identical(other.loaded, loaded) || other.loaded == loaded));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CapabilitiesState&&(identical(other.viewForeignTimetables, viewForeignTimetables) || other.viewForeignTimetables == viewForeignTimetables)&&(identical(other.pushNotifications, pushNotifications) || other.pushNotifications == pushNotifications)&&(identical(other.loaded, loaded) || other.loaded == loaded));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,viewForeignTimetables,loaded);
|
||||
int get hashCode => Object.hash(runtimeType,viewForeignTimetables,pushNotifications,loaded);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CapabilitiesState(viewForeignTimetables: $viewForeignTimetables, loaded: $loaded)';
|
||||
return 'CapabilitiesState(viewForeignTimetables: $viewForeignTimetables, pushNotifications: $pushNotifications, loaded: $loaded)';
|
||||
}
|
||||
|
||||
|
||||
@@ -255,7 +257,7 @@ abstract mixin class _$CapabilitiesStateCopyWith<$Res> implements $CapabilitiesS
|
||||
factory _$CapabilitiesStateCopyWith(_CapabilitiesState value, $Res Function(_CapabilitiesState) _then) = __$CapabilitiesStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
bool viewForeignTimetables, bool loaded
|
||||
bool viewForeignTimetables, bool pushNotifications, bool loaded
|
||||
});
|
||||
|
||||
|
||||
@@ -272,9 +274,10 @@ class __$CapabilitiesStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of CapabilitiesState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? viewForeignTimetables = null,Object? loaded = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? viewForeignTimetables = null,Object? pushNotifications = null,Object? loaded = null,}) {
|
||||
return _then(_CapabilitiesState(
|
||||
viewForeignTimetables: null == viewForeignTimetables ? _self.viewForeignTimetables : viewForeignTimetables // ignore: cast_nullable_to_non_nullable
|
||||
as bool,pushNotifications: null == pushNotifications ? _self.pushNotifications : pushNotifications // ignore: cast_nullable_to_non_nullable
|
||||
as bool,loaded: null == loaded ? _self.loaded : loaded // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
|
||||
@@ -9,11 +9,13 @@ part of 'capabilities_state.dart';
|
||||
_CapabilitiesState _$CapabilitiesStateFromJson(Map<String, dynamic> json) =>
|
||||
_CapabilitiesState(
|
||||
viewForeignTimetables: json['viewForeignTimetables'] as bool? ?? false,
|
||||
pushNotifications: json['pushNotifications'] as bool? ?? false,
|
||||
loaded: json['loaded'] as bool? ?? false,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$CapabilitiesStateToJson(_CapabilitiesState instance) =>
|
||||
<String, dynamic>{
|
||||
'viewForeignTimetables': instance.viewForeignTimetables,
|
||||
'pushNotifications': instance.pushNotifications,
|
||||
'loaded': instance.loaded,
|
||||
};
|
||||
Reference in new issue
Block a user