From b5262137ad6c3f65cb1392dd47723f9d77e8f84c Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Thu, 4 Dec 2025 01:00:07 +0800 Subject: [PATCH] :lipstick: Better authorized device page --- assets/i18n/en-US.json | 3 +- lib/models/account.dart | 12 +- lib/models/account.freezed.dart | 130 ++++++++++----------- lib/models/account.g.dart | 16 +-- lib/models/auth.dart | 5 +- lib/models/auth.freezed.dart | 83 ++++++++----- lib/models/auth.g.dart | 11 +- lib/widgets/account/account_devices.dart | 70 ++++++----- lib/widgets/account/account_devices.g.dart | 6 +- lib/widgets/sites/file_item.dart | 2 +- lib/widgets/sites/info_row.dart | 36 +++--- 11 files changed, 216 insertions(+), 158 deletions(-) diff --git a/assets/i18n/en-US.json b/assets/i18n/en-US.json index 827986ad..8df879b7 100644 --- a/assets/i18n/en-US.json +++ b/assets/i18n/en-US.json @@ -1489,5 +1489,6 @@ "accountActivationAlert": "Remember to activate your account", "accountActivationAlertHint": "Unactivated account may leads to various of permission issues, activate your account by clicking the link we sent to your email inbox.", "accountActivationResendHint": "Didn't see it? Try click the button below to resend one. If you need to update your email while your account was unactivated, feel free to contact our customer service.", - "accountActivationResend": "Resend" + "accountActivationResend": "Resend", + "ipAddress": "IP Address" } diff --git a/lib/models/account.dart b/lib/models/account.dart index a99faab7..2a67ea9f 100644 --- a/lib/models/account.dart +++ b/lib/models/account.dart @@ -216,20 +216,20 @@ sealed class SnAuthDevice with _$SnAuthDevice { } @freezed -sealed class SnAuthDeviceWithChallenge with _$SnAuthDeviceWithChallenge { - const factory SnAuthDeviceWithChallenge({ +sealed class SnAuthDeviceWithSession with _$SnAuthDeviceWithSession { + const factory SnAuthDeviceWithSession({ required String id, required String deviceId, required String deviceName, required String? deviceLabel, required String accountId, required int platform, - required List challenges, + required List sessions, @Default(false) bool isCurrent, - }) = _SnAuthDeviceWithChallengee; + }) = _SnAuthDeviceWithSessione; - factory SnAuthDeviceWithChallenge.fromJson(Map json) => - _$SnAuthDeviceWithChallengeFromJson(json); + factory SnAuthDeviceWithSession.fromJson(Map json) => + _$SnAuthDeviceWithSessionFromJson(json); } @freezed diff --git a/lib/models/account.freezed.dart b/lib/models/account.freezed.dart index 70ace1be..6f70d1e4 100644 --- a/lib/models/account.freezed.dart +++ b/lib/models/account.freezed.dart @@ -3068,51 +3068,51 @@ as bool, } -SnAuthDeviceWithChallenge _$SnAuthDeviceWithChallengeFromJson( +SnAuthDeviceWithSession _$SnAuthDeviceWithSessionFromJson( Map json ) { - return _SnAuthDeviceWithChallengee.fromJson( + return _SnAuthDeviceWithSessione.fromJson( json ); } /// @nodoc -mixin _$SnAuthDeviceWithChallenge { +mixin _$SnAuthDeviceWithSession { - String get id; String get deviceId; String get deviceName; String? get deviceLabel; String get accountId; int get platform; List get challenges; bool get isCurrent; -/// Create a copy of SnAuthDeviceWithChallenge + String get id; String get deviceId; String get deviceName; String? get deviceLabel; String get accountId; int get platform; List get sessions; bool get isCurrent; +/// Create a copy of SnAuthDeviceWithSession /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @pragma('vm:prefer-inline') -$SnAuthDeviceWithChallengeCopyWith get copyWith => _$SnAuthDeviceWithChallengeCopyWithImpl(this as SnAuthDeviceWithChallenge, _$identity); +$SnAuthDeviceWithSessionCopyWith get copyWith => _$SnAuthDeviceWithSessionCopyWithImpl(this as SnAuthDeviceWithSession, _$identity); - /// Serializes this SnAuthDeviceWithChallenge to a JSON map. + /// Serializes this SnAuthDeviceWithSession to a JSON map. Map toJson(); @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAuthDeviceWithChallenge&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.deviceName, deviceName) || other.deviceName == deviceName)&&(identical(other.deviceLabel, deviceLabel) || other.deviceLabel == deviceLabel)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.platform, platform) || other.platform == platform)&&const DeepCollectionEquality().equals(other.challenges, challenges)&&(identical(other.isCurrent, isCurrent) || other.isCurrent == isCurrent)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAuthDeviceWithSession&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.deviceName, deviceName) || other.deviceName == deviceName)&&(identical(other.deviceLabel, deviceLabel) || other.deviceLabel == deviceLabel)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.platform, platform) || other.platform == platform)&&const DeepCollectionEquality().equals(other.sessions, sessions)&&(identical(other.isCurrent, isCurrent) || other.isCurrent == isCurrent)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,id,deviceId,deviceName,deviceLabel,accountId,platform,const DeepCollectionEquality().hash(challenges),isCurrent); +int get hashCode => Object.hash(runtimeType,id,deviceId,deviceName,deviceLabel,accountId,platform,const DeepCollectionEquality().hash(sessions),isCurrent); @override String toString() { - return 'SnAuthDeviceWithChallenge(id: $id, deviceId: $deviceId, deviceName: $deviceName, deviceLabel: $deviceLabel, accountId: $accountId, platform: $platform, challenges: $challenges, isCurrent: $isCurrent)'; + return 'SnAuthDeviceWithSession(id: $id, deviceId: $deviceId, deviceName: $deviceName, deviceLabel: $deviceLabel, accountId: $accountId, platform: $platform, sessions: $sessions, isCurrent: $isCurrent)'; } } /// @nodoc -abstract mixin class $SnAuthDeviceWithChallengeCopyWith<$Res> { - factory $SnAuthDeviceWithChallengeCopyWith(SnAuthDeviceWithChallenge value, $Res Function(SnAuthDeviceWithChallenge) _then) = _$SnAuthDeviceWithChallengeCopyWithImpl; +abstract mixin class $SnAuthDeviceWithSessionCopyWith<$Res> { + factory $SnAuthDeviceWithSessionCopyWith(SnAuthDeviceWithSession value, $Res Function(SnAuthDeviceWithSession) _then) = _$SnAuthDeviceWithSessionCopyWithImpl; @useResult $Res call({ - String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List challenges, bool isCurrent + String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List sessions, bool isCurrent }); @@ -3120,16 +3120,16 @@ $Res call({ } /// @nodoc -class _$SnAuthDeviceWithChallengeCopyWithImpl<$Res> - implements $SnAuthDeviceWithChallengeCopyWith<$Res> { - _$SnAuthDeviceWithChallengeCopyWithImpl(this._self, this._then); +class _$SnAuthDeviceWithSessionCopyWithImpl<$Res> + implements $SnAuthDeviceWithSessionCopyWith<$Res> { + _$SnAuthDeviceWithSessionCopyWithImpl(this._self, this._then); - final SnAuthDeviceWithChallenge _self; - final $Res Function(SnAuthDeviceWithChallenge) _then; + final SnAuthDeviceWithSession _self; + final $Res Function(SnAuthDeviceWithSession) _then; -/// Create a copy of SnAuthDeviceWithChallenge +/// Create a copy of SnAuthDeviceWithSession /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? deviceId = null,Object? deviceName = null,Object? deviceLabel = freezed,Object? accountId = null,Object? platform = null,Object? challenges = null,Object? isCurrent = null,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? deviceId = null,Object? deviceName = null,Object? deviceLabel = freezed,Object? accountId = null,Object? platform = null,Object? sessions = null,Object? isCurrent = null,}) { return _then(_self.copyWith( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable @@ -3137,8 +3137,8 @@ as String,deviceName: null == deviceName ? _self.deviceName : deviceName // igno as String,deviceLabel: freezed == deviceLabel ? _self.deviceLabel : deviceLabel // ignore: cast_nullable_to_non_nullable as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable as String,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable -as int,challenges: null == challenges ? _self.challenges : challenges // ignore: cast_nullable_to_non_nullable -as List,isCurrent: null == isCurrent ? _self.isCurrent : isCurrent // ignore: cast_nullable_to_non_nullable +as int,sessions: null == sessions ? _self.sessions : sessions // ignore: cast_nullable_to_non_nullable +as List,isCurrent: null == isCurrent ? _self.isCurrent : isCurrent // ignore: cast_nullable_to_non_nullable as bool, )); } @@ -3146,8 +3146,8 @@ as bool, } -/// Adds pattern-matching-related methods to [SnAuthDeviceWithChallenge]. -extension SnAuthDeviceWithChallengePatterns on SnAuthDeviceWithChallenge { +/// Adds pattern-matching-related methods to [SnAuthDeviceWithSession]. +extension SnAuthDeviceWithSessionPatterns on SnAuthDeviceWithSession { /// A variant of `map` that fallback to returning `orElse`. /// /// It is equivalent to doing: @@ -3160,10 +3160,10 @@ extension SnAuthDeviceWithChallengePatterns on SnAuthDeviceWithChallenge { /// } /// ``` -@optionalTypeArgs TResult maybeMap(TResult Function( _SnAuthDeviceWithChallengee value)? $default,{required TResult orElse(),}){ +@optionalTypeArgs TResult maybeMap(TResult Function( _SnAuthDeviceWithSessione value)? $default,{required TResult orElse(),}){ final _that = this; switch (_that) { -case _SnAuthDeviceWithChallengee() when $default != null: +case _SnAuthDeviceWithSessione() when $default != null: return $default(_that);case _: return orElse(); @@ -3182,10 +3182,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult map(TResult Function( _SnAuthDeviceWithChallengee value) $default,){ +@optionalTypeArgs TResult map(TResult Function( _SnAuthDeviceWithSessione value) $default,){ final _that = this; switch (_that) { -case _SnAuthDeviceWithChallengee(): +case _SnAuthDeviceWithSessione(): return $default(_that);} } /// A variant of `map` that fallback to returning `null`. @@ -3200,10 +3200,10 @@ return $default(_that);} /// } /// ``` -@optionalTypeArgs TResult? mapOrNull(TResult? Function( _SnAuthDeviceWithChallengee value)? $default,){ +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _SnAuthDeviceWithSessione value)? $default,){ final _that = this; switch (_that) { -case _SnAuthDeviceWithChallengee() when $default != null: +case _SnAuthDeviceWithSessione() when $default != null: return $default(_that);case _: return null; @@ -3221,10 +3221,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List challenges, bool isCurrent)? $default,{required TResult orElse(),}) {final _that = this; +@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List sessions, bool isCurrent)? $default,{required TResult orElse(),}) {final _that = this; switch (_that) { -case _SnAuthDeviceWithChallengee() when $default != null: -return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that.accountId,_that.platform,_that.challenges,_that.isCurrent);case _: +case _SnAuthDeviceWithSessione() when $default != null: +return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that.accountId,_that.platform,_that.sessions,_that.isCurrent);case _: return orElse(); } @@ -3242,10 +3242,10 @@ return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that /// } /// ``` -@optionalTypeArgs TResult when(TResult Function( String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List challenges, bool isCurrent) $default,) {final _that = this; +@optionalTypeArgs TResult when(TResult Function( String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List sessions, bool isCurrent) $default,) {final _that = this; switch (_that) { -case _SnAuthDeviceWithChallengee(): -return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that.accountId,_that.platform,_that.challenges,_that.isCurrent);} +case _SnAuthDeviceWithSessione(): +return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that.accountId,_that.platform,_that.sessions,_that.isCurrent);} } /// A variant of `when` that fallback to returning `null` /// @@ -3259,10 +3259,10 @@ return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that /// } /// ``` -@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List challenges, bool isCurrent)? $default,) {final _that = this; +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List sessions, bool isCurrent)? $default,) {final _that = this; switch (_that) { -case _SnAuthDeviceWithChallengee() when $default != null: -return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that.accountId,_that.platform,_that.challenges,_that.isCurrent);case _: +case _SnAuthDeviceWithSessione() when $default != null: +return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that.accountId,_that.platform,_that.sessions,_that.isCurrent);case _: return null; } @@ -3273,9 +3273,9 @@ return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that /// @nodoc @JsonSerializable() -class _SnAuthDeviceWithChallengee implements SnAuthDeviceWithChallenge { - const _SnAuthDeviceWithChallengee({required this.id, required this.deviceId, required this.deviceName, required this.deviceLabel, required this.accountId, required this.platform, required final List challenges, this.isCurrent = false}): _challenges = challenges; - factory _SnAuthDeviceWithChallengee.fromJson(Map json) => _$SnAuthDeviceWithChallengeeFromJson(json); +class _SnAuthDeviceWithSessione implements SnAuthDeviceWithSession { + const _SnAuthDeviceWithSessione({required this.id, required this.deviceId, required this.deviceName, required this.deviceLabel, required this.accountId, required this.platform, required final List sessions, this.isCurrent = false}): _sessions = sessions; + factory _SnAuthDeviceWithSessione.fromJson(Map json) => _$SnAuthDeviceWithSessioneFromJson(json); @override final String id; @override final String deviceId; @@ -3283,49 +3283,49 @@ class _SnAuthDeviceWithChallengee implements SnAuthDeviceWithChallenge { @override final String? deviceLabel; @override final String accountId; @override final int platform; - final List _challenges; -@override List get challenges { - if (_challenges is EqualUnmodifiableListView) return _challenges; + final List _sessions; +@override List get sessions { + if (_sessions is EqualUnmodifiableListView) return _sessions; // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_challenges); + return EqualUnmodifiableListView(_sessions); } @override@JsonKey() final bool isCurrent; -/// Create a copy of SnAuthDeviceWithChallenge +/// Create a copy of SnAuthDeviceWithSession /// with the given fields replaced by the non-null parameter values. @override @JsonKey(includeFromJson: false, includeToJson: false) @pragma('vm:prefer-inline') -_$SnAuthDeviceWithChallengeeCopyWith<_SnAuthDeviceWithChallengee> get copyWith => __$SnAuthDeviceWithChallengeeCopyWithImpl<_SnAuthDeviceWithChallengee>(this, _$identity); +_$SnAuthDeviceWithSessioneCopyWith<_SnAuthDeviceWithSessione> get copyWith => __$SnAuthDeviceWithSessioneCopyWithImpl<_SnAuthDeviceWithSessione>(this, _$identity); @override Map toJson() { - return _$SnAuthDeviceWithChallengeeToJson(this, ); + return _$SnAuthDeviceWithSessioneToJson(this, ); } @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAuthDeviceWithChallengee&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.deviceName, deviceName) || other.deviceName == deviceName)&&(identical(other.deviceLabel, deviceLabel) || other.deviceLabel == deviceLabel)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.platform, platform) || other.platform == platform)&&const DeepCollectionEquality().equals(other._challenges, _challenges)&&(identical(other.isCurrent, isCurrent) || other.isCurrent == isCurrent)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAuthDeviceWithSessione&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.deviceName, deviceName) || other.deviceName == deviceName)&&(identical(other.deviceLabel, deviceLabel) || other.deviceLabel == deviceLabel)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.platform, platform) || other.platform == platform)&&const DeepCollectionEquality().equals(other._sessions, _sessions)&&(identical(other.isCurrent, isCurrent) || other.isCurrent == isCurrent)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,id,deviceId,deviceName,deviceLabel,accountId,platform,const DeepCollectionEquality().hash(_challenges),isCurrent); +int get hashCode => Object.hash(runtimeType,id,deviceId,deviceName,deviceLabel,accountId,platform,const DeepCollectionEquality().hash(_sessions),isCurrent); @override String toString() { - return 'SnAuthDeviceWithChallenge(id: $id, deviceId: $deviceId, deviceName: $deviceName, deviceLabel: $deviceLabel, accountId: $accountId, platform: $platform, challenges: $challenges, isCurrent: $isCurrent)'; + return 'SnAuthDeviceWithSession(id: $id, deviceId: $deviceId, deviceName: $deviceName, deviceLabel: $deviceLabel, accountId: $accountId, platform: $platform, sessions: $sessions, isCurrent: $isCurrent)'; } } /// @nodoc -abstract mixin class _$SnAuthDeviceWithChallengeeCopyWith<$Res> implements $SnAuthDeviceWithChallengeCopyWith<$Res> { - factory _$SnAuthDeviceWithChallengeeCopyWith(_SnAuthDeviceWithChallengee value, $Res Function(_SnAuthDeviceWithChallengee) _then) = __$SnAuthDeviceWithChallengeeCopyWithImpl; +abstract mixin class _$SnAuthDeviceWithSessioneCopyWith<$Res> implements $SnAuthDeviceWithSessionCopyWith<$Res> { + factory _$SnAuthDeviceWithSessioneCopyWith(_SnAuthDeviceWithSessione value, $Res Function(_SnAuthDeviceWithSessione) _then) = __$SnAuthDeviceWithSessioneCopyWithImpl; @override @useResult $Res call({ - String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List challenges, bool isCurrent + String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List sessions, bool isCurrent }); @@ -3333,25 +3333,25 @@ $Res call({ } /// @nodoc -class __$SnAuthDeviceWithChallengeeCopyWithImpl<$Res> - implements _$SnAuthDeviceWithChallengeeCopyWith<$Res> { - __$SnAuthDeviceWithChallengeeCopyWithImpl(this._self, this._then); +class __$SnAuthDeviceWithSessioneCopyWithImpl<$Res> + implements _$SnAuthDeviceWithSessioneCopyWith<$Res> { + __$SnAuthDeviceWithSessioneCopyWithImpl(this._self, this._then); - final _SnAuthDeviceWithChallengee _self; - final $Res Function(_SnAuthDeviceWithChallengee) _then; + final _SnAuthDeviceWithSessione _self; + final $Res Function(_SnAuthDeviceWithSessione) _then; -/// Create a copy of SnAuthDeviceWithChallenge +/// Create a copy of SnAuthDeviceWithSession /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? deviceId = null,Object? deviceName = null,Object? deviceLabel = freezed,Object? accountId = null,Object? platform = null,Object? challenges = null,Object? isCurrent = null,}) { - return _then(_SnAuthDeviceWithChallengee( +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? deviceId = null,Object? deviceName = null,Object? deviceLabel = freezed,Object? accountId = null,Object? platform = null,Object? sessions = null,Object? isCurrent = null,}) { + return _then(_SnAuthDeviceWithSessione( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable as String,deviceName: null == deviceName ? _self.deviceName : deviceName // ignore: cast_nullable_to_non_nullable as String,deviceLabel: freezed == deviceLabel ? _self.deviceLabel : deviceLabel // ignore: cast_nullable_to_non_nullable as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable as String,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable -as int,challenges: null == challenges ? _self._challenges : challenges // ignore: cast_nullable_to_non_nullable -as List,isCurrent: null == isCurrent ? _self.isCurrent : isCurrent // ignore: cast_nullable_to_non_nullable +as int,sessions: null == sessions ? _self._sessions : sessions // ignore: cast_nullable_to_non_nullable +as List,isCurrent: null == isCurrent ? _self.isCurrent : isCurrent // ignore: cast_nullable_to_non_nullable as bool, )); } diff --git a/lib/models/account.g.dart b/lib/models/account.g.dart index d2bdca71..57307a19 100644 --- a/lib/models/account.g.dart +++ b/lib/models/account.g.dart @@ -367,24 +367,24 @@ Map _$SnAuthDeviceToJson(_SnAuthDevice instance) => 'is_current': instance.isCurrent, }; -_SnAuthDeviceWithChallengee _$SnAuthDeviceWithChallengeeFromJson( +_SnAuthDeviceWithSessione _$SnAuthDeviceWithSessioneFromJson( Map json, -) => _SnAuthDeviceWithChallengee( +) => _SnAuthDeviceWithSessione( id: json['id'] as String, deviceId: json['device_id'] as String, deviceName: json['device_name'] as String, deviceLabel: json['device_label'] as String?, accountId: json['account_id'] as String, platform: (json['platform'] as num).toInt(), - challenges: - (json['challenges'] as List) - .map((e) => SnAuthChallenge.fromJson(e as Map)) + sessions: + (json['sessions'] as List) + .map((e) => SnAuthSession.fromJson(e as Map)) .toList(), isCurrent: json['is_current'] as bool? ?? false, ); -Map _$SnAuthDeviceWithChallengeeToJson( - _SnAuthDeviceWithChallengee instance, +Map _$SnAuthDeviceWithSessioneToJson( + _SnAuthDeviceWithSessione instance, ) => { 'id': instance.id, 'device_id': instance.deviceId, @@ -392,7 +392,7 @@ Map _$SnAuthDeviceWithChallengeeToJson( 'device_label': instance.deviceLabel, 'account_id': instance.accountId, 'platform': instance.platform, - 'challenges': instance.challenges.map((e) => e.toJson()).toList(), + 'sessions': instance.sessions.map((e) => e.toJson()).toList(), 'is_current': instance.isCurrent, }; diff --git a/lib/models/auth.dart b/lib/models/auth.dart index e84437a4..f7e370f9 100644 --- a/lib/models/auth.dart +++ b/lib/models/auth.dart @@ -59,8 +59,9 @@ sealed class SnAuthSession with _$SnAuthSession { required DateTime? expiredAt, required List audiences, required List scopes, - required String ipAddress, - required String userAgent, + required String? ipAddress, + required String? userAgent, + required GeoIpLocation? location, required int type, required String accountId, required DateTime createdAt, diff --git a/lib/models/auth.freezed.dart b/lib/models/auth.freezed.dart index 18826e74..d13f0130 100644 --- a/lib/models/auth.freezed.dart +++ b/lib/models/auth.freezed.dart @@ -885,7 +885,7 @@ $GeoIpLocationCopyWith<$Res>? get location { /// @nodoc mixin _$SnAuthSession { - String get id; String? get label; DateTime get lastGrantedAt; DateTime? get expiredAt; List get audiences; List get scopes; String get ipAddress; String get userAgent; int get type; String get accountId; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; + String get id; String? get label; DateTime get lastGrantedAt; DateTime? get expiredAt; List get audiences; List get scopes; String? get ipAddress; String? get userAgent; GeoIpLocation? get location; int get type; String get accountId; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; /// Create a copy of SnAuthSession /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -898,16 +898,16 @@ $SnAuthSessionCopyWith get copyWith => _$SnAuthSessionCopyWithImp @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAuthSession&&(identical(other.id, id) || other.id == id)&&(identical(other.label, label) || other.label == label)&&(identical(other.lastGrantedAt, lastGrantedAt) || other.lastGrantedAt == lastGrantedAt)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&const DeepCollectionEquality().equals(other.audiences, audiences)&&const DeepCollectionEquality().equals(other.scopes, scopes)&&(identical(other.ipAddress, ipAddress) || other.ipAddress == ipAddress)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.type, type) || other.type == type)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAuthSession&&(identical(other.id, id) || other.id == id)&&(identical(other.label, label) || other.label == label)&&(identical(other.lastGrantedAt, lastGrantedAt) || other.lastGrantedAt == lastGrantedAt)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&const DeepCollectionEquality().equals(other.audiences, audiences)&&const DeepCollectionEquality().equals(other.scopes, scopes)&&(identical(other.ipAddress, ipAddress) || other.ipAddress == ipAddress)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.location, location) || other.location == location)&&(identical(other.type, type) || other.type == type)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,id,label,lastGrantedAt,expiredAt,const DeepCollectionEquality().hash(audiences),const DeepCollectionEquality().hash(scopes),ipAddress,userAgent,type,accountId,createdAt,updatedAt,deletedAt); +int get hashCode => Object.hash(runtimeType,id,label,lastGrantedAt,expiredAt,const DeepCollectionEquality().hash(audiences),const DeepCollectionEquality().hash(scopes),ipAddress,userAgent,location,type,accountId,createdAt,updatedAt,deletedAt); @override String toString() { - return 'SnAuthSession(id: $id, label: $label, lastGrantedAt: $lastGrantedAt, expiredAt: $expiredAt, audiences: $audiences, scopes: $scopes, ipAddress: $ipAddress, userAgent: $userAgent, type: $type, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; + return 'SnAuthSession(id: $id, label: $label, lastGrantedAt: $lastGrantedAt, expiredAt: $expiredAt, audiences: $audiences, scopes: $scopes, ipAddress: $ipAddress, userAgent: $userAgent, location: $location, type: $type, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; } @@ -918,11 +918,11 @@ abstract mixin class $SnAuthSessionCopyWith<$Res> { factory $SnAuthSessionCopyWith(SnAuthSession value, $Res Function(SnAuthSession) _then) = _$SnAuthSessionCopyWithImpl; @useResult $Res call({ - String id, String? label, DateTime lastGrantedAt, DateTime? expiredAt, List audiences, List scopes, String ipAddress, String userAgent, int type, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt + String id, String? label, DateTime lastGrantedAt, DateTime? expiredAt, List audiences, List scopes, String? ipAddress, String? userAgent, GeoIpLocation? location, int type, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt }); - +$GeoIpLocationCopyWith<$Res>? get location; } /// @nodoc @@ -935,7 +935,7 @@ class _$SnAuthSessionCopyWithImpl<$Res> /// Create a copy of SnAuthSession /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? label = freezed,Object? lastGrantedAt = null,Object? expiredAt = freezed,Object? audiences = null,Object? scopes = null,Object? ipAddress = null,Object? userAgent = null,Object? type = null,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? label = freezed,Object? lastGrantedAt = null,Object? expiredAt = freezed,Object? audiences = null,Object? scopes = null,Object? ipAddress = freezed,Object? userAgent = freezed,Object? location = freezed,Object? type = null,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { return _then(_self.copyWith( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as String,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable @@ -943,9 +943,10 @@ as String?,lastGrantedAt: null == lastGrantedAt ? _self.lastGrantedAt : lastGran as DateTime,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable as DateTime?,audiences: null == audiences ? _self.audiences : audiences // ignore: cast_nullable_to_non_nullable as List,scopes: null == scopes ? _self.scopes : scopes // ignore: cast_nullable_to_non_nullable -as List,ipAddress: null == ipAddress ? _self.ipAddress : ipAddress // ignore: cast_nullable_to_non_nullable -as String,userAgent: null == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable -as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable +as List,ipAddress: freezed == ipAddress ? _self.ipAddress : ipAddress // ignore: cast_nullable_to_non_nullable +as String?,userAgent: freezed == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable +as String?,location: freezed == location ? _self.location : location // ignore: cast_nullable_to_non_nullable +as GeoIpLocation?,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable as int,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable @@ -953,7 +954,19 @@ as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ign as DateTime?, )); } +/// Create a copy of SnAuthSession +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$GeoIpLocationCopyWith<$Res>? get location { + if (_self.location == null) { + return null; + } + return $GeoIpLocationCopyWith<$Res>(_self.location!, (value) { + return _then(_self.copyWith(location: value)); + }); +} } @@ -1032,10 +1045,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String? label, DateTime lastGrantedAt, DateTime? expiredAt, List audiences, List scopes, String ipAddress, String userAgent, int type, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this; +@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String? label, DateTime lastGrantedAt, DateTime? expiredAt, List audiences, List scopes, String? ipAddress, String? userAgent, GeoIpLocation? location, int type, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this; switch (_that) { case _SnAuthSession() when $default != null: -return $default(_that.id,_that.label,_that.lastGrantedAt,_that.expiredAt,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.type,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: +return $default(_that.id,_that.label,_that.lastGrantedAt,_that.expiredAt,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.location,_that.type,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: return orElse(); } @@ -1053,10 +1066,10 @@ return $default(_that.id,_that.label,_that.lastGrantedAt,_that.expiredAt,_that.a /// } /// ``` -@optionalTypeArgs TResult when(TResult Function( String id, String? label, DateTime lastGrantedAt, DateTime? expiredAt, List audiences, List scopes, String ipAddress, String userAgent, int type, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this; +@optionalTypeArgs TResult when(TResult Function( String id, String? label, DateTime lastGrantedAt, DateTime? expiredAt, List audiences, List scopes, String? ipAddress, String? userAgent, GeoIpLocation? location, int type, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this; switch (_that) { case _SnAuthSession(): -return $default(_that.id,_that.label,_that.lastGrantedAt,_that.expiredAt,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.type,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);} +return $default(_that.id,_that.label,_that.lastGrantedAt,_that.expiredAt,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.location,_that.type,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);} } /// A variant of `when` that fallback to returning `null` /// @@ -1070,10 +1083,10 @@ return $default(_that.id,_that.label,_that.lastGrantedAt,_that.expiredAt,_that.a /// } /// ``` -@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String? label, DateTime lastGrantedAt, DateTime? expiredAt, List audiences, List scopes, String ipAddress, String userAgent, int type, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this; +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String? label, DateTime lastGrantedAt, DateTime? expiredAt, List audiences, List scopes, String? ipAddress, String? userAgent, GeoIpLocation? location, int type, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this; switch (_that) { case _SnAuthSession() when $default != null: -return $default(_that.id,_that.label,_that.lastGrantedAt,_that.expiredAt,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.type,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: +return $default(_that.id,_that.label,_that.lastGrantedAt,_that.expiredAt,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.location,_that.type,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: return null; } @@ -1085,7 +1098,7 @@ return $default(_that.id,_that.label,_that.lastGrantedAt,_that.expiredAt,_that.a @JsonSerializable() class _SnAuthSession implements SnAuthSession { - const _SnAuthSession({required this.id, required this.label, required this.lastGrantedAt, required this.expiredAt, required final List audiences, required final List scopes, required this.ipAddress, required this.userAgent, required this.type, required this.accountId, required this.createdAt, required this.updatedAt, required this.deletedAt}): _audiences = audiences,_scopes = scopes; + const _SnAuthSession({required this.id, required this.label, required this.lastGrantedAt, required this.expiredAt, required final List audiences, required final List scopes, required this.ipAddress, required this.userAgent, required this.location, required this.type, required this.accountId, required this.createdAt, required this.updatedAt, required this.deletedAt}): _audiences = audiences,_scopes = scopes; factory _SnAuthSession.fromJson(Map json) => _$SnAuthSessionFromJson(json); @override final String id; @@ -1106,8 +1119,9 @@ class _SnAuthSession implements SnAuthSession { return EqualUnmodifiableListView(_scopes); } -@override final String ipAddress; -@override final String userAgent; +@override final String? ipAddress; +@override final String? userAgent; +@override final GeoIpLocation? location; @override final int type; @override final String accountId; @override final DateTime createdAt; @@ -1127,16 +1141,16 @@ Map toJson() { @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAuthSession&&(identical(other.id, id) || other.id == id)&&(identical(other.label, label) || other.label == label)&&(identical(other.lastGrantedAt, lastGrantedAt) || other.lastGrantedAt == lastGrantedAt)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&const DeepCollectionEquality().equals(other._audiences, _audiences)&&const DeepCollectionEquality().equals(other._scopes, _scopes)&&(identical(other.ipAddress, ipAddress) || other.ipAddress == ipAddress)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.type, type) || other.type == type)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAuthSession&&(identical(other.id, id) || other.id == id)&&(identical(other.label, label) || other.label == label)&&(identical(other.lastGrantedAt, lastGrantedAt) || other.lastGrantedAt == lastGrantedAt)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&const DeepCollectionEquality().equals(other._audiences, _audiences)&&const DeepCollectionEquality().equals(other._scopes, _scopes)&&(identical(other.ipAddress, ipAddress) || other.ipAddress == ipAddress)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.location, location) || other.location == location)&&(identical(other.type, type) || other.type == type)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,id,label,lastGrantedAt,expiredAt,const DeepCollectionEquality().hash(_audiences),const DeepCollectionEquality().hash(_scopes),ipAddress,userAgent,type,accountId,createdAt,updatedAt,deletedAt); +int get hashCode => Object.hash(runtimeType,id,label,lastGrantedAt,expiredAt,const DeepCollectionEquality().hash(_audiences),const DeepCollectionEquality().hash(_scopes),ipAddress,userAgent,location,type,accountId,createdAt,updatedAt,deletedAt); @override String toString() { - return 'SnAuthSession(id: $id, label: $label, lastGrantedAt: $lastGrantedAt, expiredAt: $expiredAt, audiences: $audiences, scopes: $scopes, ipAddress: $ipAddress, userAgent: $userAgent, type: $type, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; + return 'SnAuthSession(id: $id, label: $label, lastGrantedAt: $lastGrantedAt, expiredAt: $expiredAt, audiences: $audiences, scopes: $scopes, ipAddress: $ipAddress, userAgent: $userAgent, location: $location, type: $type, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; } @@ -1147,11 +1161,11 @@ abstract mixin class _$SnAuthSessionCopyWith<$Res> implements $SnAuthSessionCopy factory _$SnAuthSessionCopyWith(_SnAuthSession value, $Res Function(_SnAuthSession) _then) = __$SnAuthSessionCopyWithImpl; @override @useResult $Res call({ - String id, String? label, DateTime lastGrantedAt, DateTime? expiredAt, List audiences, List scopes, String ipAddress, String userAgent, int type, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt + String id, String? label, DateTime lastGrantedAt, DateTime? expiredAt, List audiences, List scopes, String? ipAddress, String? userAgent, GeoIpLocation? location, int type, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt }); - +@override $GeoIpLocationCopyWith<$Res>? get location; } /// @nodoc @@ -1164,7 +1178,7 @@ class __$SnAuthSessionCopyWithImpl<$Res> /// Create a copy of SnAuthSession /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? label = freezed,Object? lastGrantedAt = null,Object? expiredAt = freezed,Object? audiences = null,Object? scopes = null,Object? ipAddress = null,Object? userAgent = null,Object? type = null,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? label = freezed,Object? lastGrantedAt = null,Object? expiredAt = freezed,Object? audiences = null,Object? scopes = null,Object? ipAddress = freezed,Object? userAgent = freezed,Object? location = freezed,Object? type = null,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { return _then(_SnAuthSession( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as String,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable @@ -1172,9 +1186,10 @@ as String?,lastGrantedAt: null == lastGrantedAt ? _self.lastGrantedAt : lastGran as DateTime,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable as DateTime?,audiences: null == audiences ? _self._audiences : audiences // ignore: cast_nullable_to_non_nullable as List,scopes: null == scopes ? _self._scopes : scopes // ignore: cast_nullable_to_non_nullable -as List,ipAddress: null == ipAddress ? _self.ipAddress : ipAddress // ignore: cast_nullable_to_non_nullable -as String,userAgent: null == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable -as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable +as List,ipAddress: freezed == ipAddress ? _self.ipAddress : ipAddress // ignore: cast_nullable_to_non_nullable +as String?,userAgent: freezed == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable +as String?,location: freezed == location ? _self.location : location // ignore: cast_nullable_to_non_nullable +as GeoIpLocation?,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable as int,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable @@ -1183,7 +1198,19 @@ as DateTime?, )); } +/// Create a copy of SnAuthSession +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$GeoIpLocationCopyWith<$Res>? get location { + if (_self.location == null) { + return null; + } + return $GeoIpLocationCopyWith<$Res>(_self.location!, (value) { + return _then(_self.copyWith(location: value)); + }); +} } diff --git a/lib/models/auth.g.dart b/lib/models/auth.g.dart index b535ece2..0bdf5fa4 100644 --- a/lib/models/auth.g.dart +++ b/lib/models/auth.g.dart @@ -96,8 +96,14 @@ _SnAuthSession _$SnAuthSessionFromJson(Map json) => : DateTime.parse(json['expired_at'] as String), audiences: json['audiences'] as List, scopes: json['scopes'] as List, - ipAddress: json['ip_address'] as String, - userAgent: json['user_agent'] as String, + ipAddress: json['ip_address'] as String?, + userAgent: json['user_agent'] as String?, + location: + json['location'] == null + ? null + : GeoIpLocation.fromJson( + json['location'] as Map, + ), type: (json['type'] as num).toInt(), accountId: json['account_id'] as String, createdAt: DateTime.parse(json['created_at'] as String), @@ -118,6 +124,7 @@ Map _$SnAuthSessionToJson(_SnAuthSession instance) => 'scopes': instance.scopes, 'ip_address': instance.ipAddress, 'user_agent': instance.userAgent, + 'location': instance.location?.toJson(), 'type': instance.type, 'account_id': instance.accountId, 'created_at': instance.createdAt.toIso8601String(), diff --git a/lib/widgets/account/account_devices.dart b/lib/widgets/account/account_devices.dart index 4ed7289a..894d03c8 100644 --- a/lib/widgets/account/account_devices.dart +++ b/lib/widgets/account/account_devices.dart @@ -11,6 +11,7 @@ import 'package:island/services/udid.dart'; import 'package:island/widgets/alert.dart'; import 'package:island/widgets/content/sheet.dart'; import 'package:island/widgets/response.dart'; +import 'package:island/widgets/sites/info_row.dart'; import 'package:material_symbols_icons/symbols.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:styled_widget/styled_widget.dart'; @@ -19,21 +20,21 @@ import 'package:island/widgets/extended_refresh_indicator.dart'; part 'account_devices.g.dart'; @riverpod -Future> authDevices(Ref ref) async { +Future> authDevices(Ref ref) async { final resp = await ref .watch(apiClientProvider) .get('/pass/accounts/me/devices'); final currentId = await getUdid(); final data = - resp.data.map((e) { - final ele = SnAuthDeviceWithChallenge.fromJson(e); + resp.data.map((e) { + final ele = SnAuthDeviceWithSession.fromJson(e); return ele.copyWith(isCurrent: ele.deviceId == currentId); }).toList(); return data; } class _DeviceListTile extends StatelessWidget { - final SnAuthDeviceWithChallenge device; + final SnAuthDeviceWithSession device; final Function(String) updateDeviceLabel; final Function(String) logoutDevice; @@ -69,11 +70,12 @@ class _DeviceListTile extends StatelessWidget { subtitle: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Text( - 'lastActiveAt'.tr( - args: [device.challenges.first.createdAt.formatSystem()], + if (device.sessions.isNotEmpty) + Text( + 'lastActiveAt'.tr( + args: [device.sessions.first.createdAt.formatSystem()], + ), ), - ), ], ), leading: Icon(switch (device.platform) { @@ -114,26 +116,40 @@ class _DeviceListTile extends StatelessWidget { padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Text('authDeviceChallenges'.tr()), ), - for (final challenge in device.challenges) - ListTile( - minTileHeight: 48, - title: Text(DateFormat().format(challenge.createdAt.toLocal())), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Text(challenge.ipAddress), - if (challenge.location != null) - Row( - spacing: 4, - children: - [challenge.location?.city, challenge.location?.country] - .where((e) => e?.isNotEmpty ?? false) - .map((e) => Text(e!)) - .toList(), + ...device.sessions + .map( + (session) => Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 4, + children: [ + InfoRow( + label: 'createdAt'.tr( + args: [session.createdAt.toLocal().formatSystem()], + ), + icon: Symbols.join, ), - ], - ), - ), + InfoRow( + label: 'lastActiveAt'.tr( + args: [session.lastGrantedAt.toLocal().formatSystem()], + ), + icon: Symbols.refresh_rounded, + ), + InfoRow( + label: + '${'location'.tr()} ${session.location?.city ?? 'unknown'.tr()}', + icon: Symbols.pin_drop, + ), + InfoRow( + label: + '${'ipAddress'.tr()} ${session.ipAddress ?? 'unknown'.tr()}', + icon: Symbols.dns, + ), + ], + ).padding(horizontal: 20, vertical: 8), + ) + .expand((element) => [element, const Divider(height: 1)]) + .toList() + ..removeLast(), ], ); } diff --git a/lib/widgets/account/account_devices.g.dart b/lib/widgets/account/account_devices.g.dart index 8191cfcf..19d2141d 100644 --- a/lib/widgets/account/account_devices.g.dart +++ b/lib/widgets/account/account_devices.g.dart @@ -6,12 +6,12 @@ part of 'account_devices.dart'; // RiverpodGenerator // ************************************************************************** -String _$authDevicesHash() => r'35735af4ed75b73fe80c8942e53b3bc26a569c01'; +String _$authDevicesHash() => r'1af378149286020ec263be178c573ccc247a0cd1'; /// See also [authDevices]. @ProviderFor(authDevices) final authDevicesProvider = - AutoDisposeFutureProvider>.internal( + AutoDisposeFutureProvider>.internal( authDevices, name: r'authDevicesProvider', debugGetCreateSourceHash: @@ -25,6 +25,6 @@ final authDevicesProvider = @Deprecated('Will be removed in 3.0. Use Ref instead') // ignore: unused_element typedef AuthDevicesRef = - AutoDisposeFutureProviderRef>; + AutoDisposeFutureProviderRef>; // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/lib/widgets/sites/file_item.dart b/lib/widgets/sites/file_item.dart index 733511db..872db6b2 100644 --- a/lib/widgets/sites/file_item.dart +++ b/lib/widgets/sites/file_item.dart @@ -124,7 +124,7 @@ class FileItem extends HookConsumerWidget { if (confirmed != true) return; } - await _showEditSheet(context, ref); + if (context.mounted) await _showEditSheet(context, ref); } Future _showEditSheet(BuildContext context, WidgetRef ref) async { diff --git a/lib/widgets/sites/info_row.dart b/lib/widgets/sites/info_row.dart index d2097bdf..c216f915 100644 --- a/lib/widgets/sites/info_row.dart +++ b/lib/widgets/sites/info_row.dart @@ -4,7 +4,7 @@ import 'package:google_fonts/google_fonts.dart'; class InfoRow extends StatelessWidget { final String label; - final String value; + final String? value; final IconData icon; final bool monospace; final VoidCallback? onTap; @@ -12,7 +12,7 @@ class InfoRow extends StatelessWidget { const InfoRow({ super.key, required this.label, - required this.value, + this.value, required this.icon, this.monospace = false, this.onTap, @@ -20,14 +20,17 @@ class InfoRow extends StatelessWidget { @override Widget build(BuildContext context) { - Widget valueWidget = Text( - value, - style: - monospace - ? GoogleFonts.robotoMono(fontSize: 14) - : Theme.of(context).textTheme.bodyMedium, - textAlign: TextAlign.end, - ); + Widget? valueWidget = + value == null + ? null + : Text( + value!, + style: + monospace + ? GoogleFonts.robotoMono(fontSize: 14) + : Theme.of(context).textTheme.bodyMedium, + textAlign: TextAlign.end, + ); if (onTap != null) valueWidget = InkWell(onTap: onTap, child: valueWidget); @@ -40,13 +43,16 @@ class InfoRow extends StatelessWidget { flex: 2, child: Text( label, - style: Theme.of(context).textTheme.bodyMedium?.copyWith( - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), + style: + valueWidget == null + ? null + : Theme.of(context).textTheme.bodyMedium?.copyWith( + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), ), ), - const Gap(12), - Expanded(flex: 3, child: valueWidget), + if (valueWidget != null) const Gap(12), + if (valueWidget != null) Expanded(flex: 3, child: valueWidget), ], ); }