✨ Account settings auth devices
This commit is contained in:
parent
d832729278
commit
3dd7c8a5b2
@ -338,5 +338,20 @@
|
|||||||
"confirm": "Confirm",
|
"confirm": "Confirm",
|
||||||
"authFactorAdditional": "One more step",
|
"authFactorAdditional": "One more step",
|
||||||
"authFactorHint": "Contact method hint",
|
"authFactorHint": "Contact method hint",
|
||||||
"authFactorHintHelper": "You need provide a part of your contact method and we will send the verification code to that contact method if it matched our records"
|
"authFactorHintHelper": "You need provide a part of your contact method and we will send the verification code to that contact method if it matched our records",
|
||||||
|
"authSessions": "Active Sessions",
|
||||||
|
"authSessionsDescription": "See devices you currently logged in.",
|
||||||
|
"authSessionsCount": {
|
||||||
|
"one": "{} session",
|
||||||
|
"other": "{} sessions"
|
||||||
|
},
|
||||||
|
"authDeviceCurrent": "Current device",
|
||||||
|
"lastActiveAt": "Last active at {}",
|
||||||
|
"authDeviceLogout": "Logout",
|
||||||
|
"authDeviceLogoutHint": "Are you sure you want to logout this device? This will also disable the push notification to this device.",
|
||||||
|
"authDeviceEditLabel": "Edit Label",
|
||||||
|
"authDeviceLabelTitle": "Edit Device Label",
|
||||||
|
"authDeviceLabelHint": "Enter a name for this device",
|
||||||
|
"authDeviceSwipeEditHint": "Swipe left to edit label",
|
||||||
|
"authDeviceSwipeLogoutHint": "Swipe right to logout device"
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 54;
|
objectVersion = 77;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
@ -448,10 +448,14 @@
|
|||||||
inputFileListPaths = (
|
inputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
);
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
name = "[CP] Copy Pods Resources";
|
name = "[CP] Copy Pods Resources";
|
||||||
outputFileListPaths = (
|
outputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
);
|
);
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||||
@ -487,10 +491,14 @@
|
|||||||
inputFileListPaths = (
|
inputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
);
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
name = "[CP] Embed Pods Frameworks";
|
name = "[CP] Embed Pods Frameworks";
|
||||||
outputFileListPaths = (
|
outputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
);
|
);
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||||
|
@ -18,13 +18,18 @@ sealed class SnAuthChallenge with _$SnAuthChallenge {
|
|||||||
required DateTime expiredAt,
|
required DateTime expiredAt,
|
||||||
required int stepRemain,
|
required int stepRemain,
|
||||||
required int stepTotal,
|
required int stepTotal,
|
||||||
|
required int failedAttempts,
|
||||||
|
required int platform,
|
||||||
|
required int type,
|
||||||
required List<String> blacklistFactors,
|
required List<String> blacklistFactors,
|
||||||
required List<String> audiences,
|
required List<dynamic> audiences,
|
||||||
required List<String> scopes,
|
required List<dynamic> scopes,
|
||||||
required String ipAddress,
|
required String ipAddress,
|
||||||
required String userAgent,
|
required String userAgent,
|
||||||
required String? deviceId,
|
required String deviceId,
|
||||||
required String? nonce,
|
required String? nonce,
|
||||||
|
required String? location,
|
||||||
|
required String accountId,
|
||||||
required DateTime createdAt,
|
required DateTime createdAt,
|
||||||
required DateTime updatedAt,
|
required DateTime updatedAt,
|
||||||
required DateTime? deletedAt,
|
required DateTime? deletedAt,
|
||||||
@ -34,6 +39,25 @@ sealed class SnAuthChallenge with _$SnAuthChallenge {
|
|||||||
_$SnAuthChallengeFromJson(json);
|
_$SnAuthChallengeFromJson(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
sealed class SnAuthSession with _$SnAuthSession {
|
||||||
|
const factory SnAuthSession({
|
||||||
|
required String id,
|
||||||
|
required String? label,
|
||||||
|
required DateTime lastGrantedAt,
|
||||||
|
required DateTime expiredAt,
|
||||||
|
required String accountId,
|
||||||
|
required String challengeId,
|
||||||
|
required SnAuthChallenge challenge,
|
||||||
|
required DateTime createdAt,
|
||||||
|
required DateTime updatedAt,
|
||||||
|
required DateTime? deletedAt,
|
||||||
|
}) = _SnAuthSession;
|
||||||
|
|
||||||
|
factory SnAuthSession.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$SnAuthSessionFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
sealed class SnAuthFactor with _$SnAuthFactor {
|
sealed class SnAuthFactor with _$SnAuthFactor {
|
||||||
const factory SnAuthFactor({
|
const factory SnAuthFactor({
|
||||||
@ -51,3 +75,19 @@ sealed class SnAuthFactor with _$SnAuthFactor {
|
|||||||
factory SnAuthFactor.fromJson(Map<String, dynamic> json) =>
|
factory SnAuthFactor.fromJson(Map<String, dynamic> json) =>
|
||||||
_$SnAuthFactorFromJson(json);
|
_$SnAuthFactorFromJson(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
sealed class SnAuthDevice with _$SnAuthDevice {
|
||||||
|
const factory SnAuthDevice({
|
||||||
|
required dynamic label,
|
||||||
|
required String userAgent,
|
||||||
|
required String deviceId,
|
||||||
|
required int platform,
|
||||||
|
required List<SnAuthSession> sessions,
|
||||||
|
// Not from backend, used for UI
|
||||||
|
@Default(false) bool isCurrent,
|
||||||
|
}) = _SnAuthDevice;
|
||||||
|
|
||||||
|
factory SnAuthDevice.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$SnAuthDeviceFromJson(json);
|
||||||
|
}
|
||||||
|
@ -149,7 +149,7 @@ as String,
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$SnAuthChallenge {
|
mixin _$SnAuthChallenge {
|
||||||
|
|
||||||
String get id; DateTime get expiredAt; int get stepRemain; int get stepTotal; List<String> get blacklistFactors; List<String> get audiences; List<String> get scopes; String get ipAddress; String get userAgent; String? get deviceId; String? get nonce; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt;
|
String get id; DateTime get expiredAt; int get stepRemain; int get stepTotal; int get failedAttempts; int get platform; int get type; List<String> get blacklistFactors; List<dynamic> get audiences; List<dynamic> get scopes; String get ipAddress; String get userAgent; String get deviceId; String? get nonce; String? get location; String get accountId; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt;
|
||||||
/// Create a copy of SnAuthChallenge
|
/// Create a copy of SnAuthChallenge
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@ -162,16 +162,16 @@ $SnAuthChallengeCopyWith<SnAuthChallenge> get copyWith => _$SnAuthChallengeCopyW
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAuthChallenge&&(identical(other.id, id) || other.id == id)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(identical(other.stepRemain, stepRemain) || other.stepRemain == stepRemain)&&(identical(other.stepTotal, stepTotal) || other.stepTotal == stepTotal)&&const DeepCollectionEquality().equals(other.blacklistFactors, blacklistFactors)&&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.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.nonce, nonce) || other.nonce == nonce)&&(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 SnAuthChallenge&&(identical(other.id, id) || other.id == id)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(identical(other.stepRemain, stepRemain) || other.stepRemain == stepRemain)&&(identical(other.stepTotal, stepTotal) || other.stepTotal == stepTotal)&&(identical(other.failedAttempts, failedAttempts) || other.failedAttempts == failedAttempts)&&(identical(other.platform, platform) || other.platform == platform)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.blacklistFactors, blacklistFactors)&&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.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.nonce, nonce) || other.nonce == nonce)&&(identical(other.location, location) || other.location == location)&&(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)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,id,expiredAt,stepRemain,stepTotal,const DeepCollectionEquality().hash(blacklistFactors),const DeepCollectionEquality().hash(audiences),const DeepCollectionEquality().hash(scopes),ipAddress,userAgent,deviceId,nonce,createdAt,updatedAt,deletedAt);
|
int get hashCode => Object.hashAll([runtimeType,id,expiredAt,stepRemain,stepTotal,failedAttempts,platform,type,const DeepCollectionEquality().hash(blacklistFactors),const DeepCollectionEquality().hash(audiences),const DeepCollectionEquality().hash(scopes),ipAddress,userAgent,deviceId,nonce,location,accountId,createdAt,updatedAt,deletedAt]);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnAuthChallenge(id: $id, expiredAt: $expiredAt, stepRemain: $stepRemain, stepTotal: $stepTotal, blacklistFactors: $blacklistFactors, audiences: $audiences, scopes: $scopes, ipAddress: $ipAddress, userAgent: $userAgent, deviceId: $deviceId, nonce: $nonce, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
return 'SnAuthChallenge(id: $id, expiredAt: $expiredAt, stepRemain: $stepRemain, stepTotal: $stepTotal, failedAttempts: $failedAttempts, platform: $platform, type: $type, blacklistFactors: $blacklistFactors, audiences: $audiences, scopes: $scopes, ipAddress: $ipAddress, userAgent: $userAgent, deviceId: $deviceId, nonce: $nonce, location: $location, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -182,7 +182,7 @@ abstract mixin class $SnAuthChallengeCopyWith<$Res> {
|
|||||||
factory $SnAuthChallengeCopyWith(SnAuthChallenge value, $Res Function(SnAuthChallenge) _then) = _$SnAuthChallengeCopyWithImpl;
|
factory $SnAuthChallengeCopyWith(SnAuthChallenge value, $Res Function(SnAuthChallenge) _then) = _$SnAuthChallengeCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String id, DateTime expiredAt, int stepRemain, int stepTotal, List<String> blacklistFactors, List<String> audiences, List<String> scopes, String ipAddress, String userAgent, String? deviceId, String? nonce, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
String id, DateTime expiredAt, int stepRemain, int stepTotal, int failedAttempts, int platform, int type, List<String> blacklistFactors, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, String deviceId, String? nonce, String? location, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -199,20 +199,25 @@ class _$SnAuthChallengeCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnAuthChallenge
|
/// Create a copy of SnAuthChallenge
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? expiredAt = null,Object? stepRemain = null,Object? stepTotal = null,Object? blacklistFactors = null,Object? audiences = null,Object? scopes = null,Object? ipAddress = null,Object? userAgent = null,Object? deviceId = freezed,Object? nonce = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? expiredAt = null,Object? stepRemain = null,Object? stepTotal = null,Object? failedAttempts = null,Object? platform = null,Object? type = null,Object? blacklistFactors = null,Object? audiences = null,Object? scopes = null,Object? ipAddress = null,Object? userAgent = null,Object? deviceId = null,Object? nonce = freezed,Object? location = freezed,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
||||||
return _then(_self.copyWith(
|
return _then(_self.copyWith(
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,expiredAt: null == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable
|
as String,expiredAt: null == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime,stepRemain: null == stepRemain ? _self.stepRemain : stepRemain // ignore: cast_nullable_to_non_nullable
|
as DateTime,stepRemain: null == stepRemain ? _self.stepRemain : stepRemain // ignore: cast_nullable_to_non_nullable
|
||||||
as int,stepTotal: null == stepTotal ? _self.stepTotal : stepTotal // ignore: cast_nullable_to_non_nullable
|
as int,stepTotal: null == stepTotal ? _self.stepTotal : stepTotal // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,failedAttempts: null == failedAttempts ? _self.failedAttempts : failedAttempts // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
|
||||||
as int,blacklistFactors: null == blacklistFactors ? _self.blacklistFactors : blacklistFactors // ignore: cast_nullable_to_non_nullable
|
as int,blacklistFactors: null == blacklistFactors ? _self.blacklistFactors : blacklistFactors // ignore: cast_nullable_to_non_nullable
|
||||||
as List<String>,audiences: null == audiences ? _self.audiences : audiences // ignore: cast_nullable_to_non_nullable
|
as List<String>,audiences: null == audiences ? _self.audiences : audiences // ignore: cast_nullable_to_non_nullable
|
||||||
as List<String>,scopes: null == scopes ? _self.scopes : scopes // ignore: cast_nullable_to_non_nullable
|
as List<dynamic>,scopes: null == scopes ? _self.scopes : scopes // ignore: cast_nullable_to_non_nullable
|
||||||
as List<String>,ipAddress: null == ipAddress ? _self.ipAddress : ipAddress // ignore: cast_nullable_to_non_nullable
|
as List<dynamic>,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,userAgent: null == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable
|
||||||
as String,deviceId: freezed == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
|
as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,nonce: freezed == nonce ? _self.nonce : nonce // ignore: cast_nullable_to_non_nullable
|
as String,nonce: freezed == nonce ? _self.nonce : nonce // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
as String?,location: freezed == location ? _self.location : location // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,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
|
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,
|
as DateTime?,
|
||||||
@ -226,13 +231,16 @@ as DateTime?,
|
|||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
|
|
||||||
class _SnAuthChallenge implements SnAuthChallenge {
|
class _SnAuthChallenge implements SnAuthChallenge {
|
||||||
const _SnAuthChallenge({required this.id, required this.expiredAt, required this.stepRemain, required this.stepTotal, required final List<String> blacklistFactors, required final List<String> audiences, required final List<String> scopes, required this.ipAddress, required this.userAgent, required this.deviceId, required this.nonce, required this.createdAt, required this.updatedAt, required this.deletedAt}): _blacklistFactors = blacklistFactors,_audiences = audiences,_scopes = scopes;
|
const _SnAuthChallenge({required this.id, required this.expiredAt, required this.stepRemain, required this.stepTotal, required this.failedAttempts, required this.platform, required this.type, required final List<String> blacklistFactors, required final List<dynamic> audiences, required final List<dynamic> scopes, required this.ipAddress, required this.userAgent, required this.deviceId, required this.nonce, required this.location, required this.accountId, required this.createdAt, required this.updatedAt, required this.deletedAt}): _blacklistFactors = blacklistFactors,_audiences = audiences,_scopes = scopes;
|
||||||
factory _SnAuthChallenge.fromJson(Map<String, dynamic> json) => _$SnAuthChallengeFromJson(json);
|
factory _SnAuthChallenge.fromJson(Map<String, dynamic> json) => _$SnAuthChallengeFromJson(json);
|
||||||
|
|
||||||
@override final String id;
|
@override final String id;
|
||||||
@override final DateTime expiredAt;
|
@override final DateTime expiredAt;
|
||||||
@override final int stepRemain;
|
@override final int stepRemain;
|
||||||
@override final int stepTotal;
|
@override final int stepTotal;
|
||||||
|
@override final int failedAttempts;
|
||||||
|
@override final int platform;
|
||||||
|
@override final int type;
|
||||||
final List<String> _blacklistFactors;
|
final List<String> _blacklistFactors;
|
||||||
@override List<String> get blacklistFactors {
|
@override List<String> get blacklistFactors {
|
||||||
if (_blacklistFactors is EqualUnmodifiableListView) return _blacklistFactors;
|
if (_blacklistFactors is EqualUnmodifiableListView) return _blacklistFactors;
|
||||||
@ -240,15 +248,15 @@ class _SnAuthChallenge implements SnAuthChallenge {
|
|||||||
return EqualUnmodifiableListView(_blacklistFactors);
|
return EqualUnmodifiableListView(_blacklistFactors);
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<String> _audiences;
|
final List<dynamic> _audiences;
|
||||||
@override List<String> get audiences {
|
@override List<dynamic> get audiences {
|
||||||
if (_audiences is EqualUnmodifiableListView) return _audiences;
|
if (_audiences is EqualUnmodifiableListView) return _audiences;
|
||||||
// ignore: implicit_dynamic_type
|
// ignore: implicit_dynamic_type
|
||||||
return EqualUnmodifiableListView(_audiences);
|
return EqualUnmodifiableListView(_audiences);
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<String> _scopes;
|
final List<dynamic> _scopes;
|
||||||
@override List<String> get scopes {
|
@override List<dynamic> get scopes {
|
||||||
if (_scopes is EqualUnmodifiableListView) return _scopes;
|
if (_scopes is EqualUnmodifiableListView) return _scopes;
|
||||||
// ignore: implicit_dynamic_type
|
// ignore: implicit_dynamic_type
|
||||||
return EqualUnmodifiableListView(_scopes);
|
return EqualUnmodifiableListView(_scopes);
|
||||||
@ -256,8 +264,10 @@ class _SnAuthChallenge implements SnAuthChallenge {
|
|||||||
|
|
||||||
@override final String ipAddress;
|
@override final String ipAddress;
|
||||||
@override final String userAgent;
|
@override final String userAgent;
|
||||||
@override final String? deviceId;
|
@override final String deviceId;
|
||||||
@override final String? nonce;
|
@override final String? nonce;
|
||||||
|
@override final String? location;
|
||||||
|
@override final String accountId;
|
||||||
@override final DateTime createdAt;
|
@override final DateTime createdAt;
|
||||||
@override final DateTime updatedAt;
|
@override final DateTime updatedAt;
|
||||||
@override final DateTime? deletedAt;
|
@override final DateTime? deletedAt;
|
||||||
@ -275,16 +285,16 @@ Map<String, dynamic> toJson() {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAuthChallenge&&(identical(other.id, id) || other.id == id)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(identical(other.stepRemain, stepRemain) || other.stepRemain == stepRemain)&&(identical(other.stepTotal, stepTotal) || other.stepTotal == stepTotal)&&const DeepCollectionEquality().equals(other._blacklistFactors, _blacklistFactors)&&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.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.nonce, nonce) || other.nonce == nonce)&&(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 _SnAuthChallenge&&(identical(other.id, id) || other.id == id)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(identical(other.stepRemain, stepRemain) || other.stepRemain == stepRemain)&&(identical(other.stepTotal, stepTotal) || other.stepTotal == stepTotal)&&(identical(other.failedAttempts, failedAttempts) || other.failedAttempts == failedAttempts)&&(identical(other.platform, platform) || other.platform == platform)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._blacklistFactors, _blacklistFactors)&&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.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.nonce, nonce) || other.nonce == nonce)&&(identical(other.location, location) || other.location == location)&&(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)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,id,expiredAt,stepRemain,stepTotal,const DeepCollectionEquality().hash(_blacklistFactors),const DeepCollectionEquality().hash(_audiences),const DeepCollectionEquality().hash(_scopes),ipAddress,userAgent,deviceId,nonce,createdAt,updatedAt,deletedAt);
|
int get hashCode => Object.hashAll([runtimeType,id,expiredAt,stepRemain,stepTotal,failedAttempts,platform,type,const DeepCollectionEquality().hash(_blacklistFactors),const DeepCollectionEquality().hash(_audiences),const DeepCollectionEquality().hash(_scopes),ipAddress,userAgent,deviceId,nonce,location,accountId,createdAt,updatedAt,deletedAt]);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnAuthChallenge(id: $id, expiredAt: $expiredAt, stepRemain: $stepRemain, stepTotal: $stepTotal, blacklistFactors: $blacklistFactors, audiences: $audiences, scopes: $scopes, ipAddress: $ipAddress, userAgent: $userAgent, deviceId: $deviceId, nonce: $nonce, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
return 'SnAuthChallenge(id: $id, expiredAt: $expiredAt, stepRemain: $stepRemain, stepTotal: $stepTotal, failedAttempts: $failedAttempts, platform: $platform, type: $type, blacklistFactors: $blacklistFactors, audiences: $audiences, scopes: $scopes, ipAddress: $ipAddress, userAgent: $userAgent, deviceId: $deviceId, nonce: $nonce, location: $location, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -295,7 +305,7 @@ abstract mixin class _$SnAuthChallengeCopyWith<$Res> implements $SnAuthChallenge
|
|||||||
factory _$SnAuthChallengeCopyWith(_SnAuthChallenge value, $Res Function(_SnAuthChallenge) _then) = __$SnAuthChallengeCopyWithImpl;
|
factory _$SnAuthChallengeCopyWith(_SnAuthChallenge value, $Res Function(_SnAuthChallenge) _then) = __$SnAuthChallengeCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String id, DateTime expiredAt, int stepRemain, int stepTotal, List<String> blacklistFactors, List<String> audiences, List<String> scopes, String ipAddress, String userAgent, String? deviceId, String? nonce, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
String id, DateTime expiredAt, int stepRemain, int stepTotal, int failedAttempts, int platform, int type, List<String> blacklistFactors, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, String deviceId, String? nonce, String? location, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -312,20 +322,25 @@ class __$SnAuthChallengeCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnAuthChallenge
|
/// Create a copy of SnAuthChallenge
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? expiredAt = null,Object? stepRemain = null,Object? stepTotal = null,Object? blacklistFactors = null,Object? audiences = null,Object? scopes = null,Object? ipAddress = null,Object? userAgent = null,Object? deviceId = freezed,Object? nonce = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? expiredAt = null,Object? stepRemain = null,Object? stepTotal = null,Object? failedAttempts = null,Object? platform = null,Object? type = null,Object? blacklistFactors = null,Object? audiences = null,Object? scopes = null,Object? ipAddress = null,Object? userAgent = null,Object? deviceId = null,Object? nonce = freezed,Object? location = freezed,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
||||||
return _then(_SnAuthChallenge(
|
return _then(_SnAuthChallenge(
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,expiredAt: null == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable
|
as String,expiredAt: null == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime,stepRemain: null == stepRemain ? _self.stepRemain : stepRemain // ignore: cast_nullable_to_non_nullable
|
as DateTime,stepRemain: null == stepRemain ? _self.stepRemain : stepRemain // ignore: cast_nullable_to_non_nullable
|
||||||
as int,stepTotal: null == stepTotal ? _self.stepTotal : stepTotal // ignore: cast_nullable_to_non_nullable
|
as int,stepTotal: null == stepTotal ? _self.stepTotal : stepTotal // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,failedAttempts: null == failedAttempts ? _self.failedAttempts : failedAttempts // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
|
||||||
as int,blacklistFactors: null == blacklistFactors ? _self._blacklistFactors : blacklistFactors // ignore: cast_nullable_to_non_nullable
|
as int,blacklistFactors: null == blacklistFactors ? _self._blacklistFactors : blacklistFactors // ignore: cast_nullable_to_non_nullable
|
||||||
as List<String>,audiences: null == audiences ? _self._audiences : audiences // ignore: cast_nullable_to_non_nullable
|
as List<String>,audiences: null == audiences ? _self._audiences : audiences // ignore: cast_nullable_to_non_nullable
|
||||||
as List<String>,scopes: null == scopes ? _self._scopes : scopes // ignore: cast_nullable_to_non_nullable
|
as List<dynamic>,scopes: null == scopes ? _self._scopes : scopes // ignore: cast_nullable_to_non_nullable
|
||||||
as List<String>,ipAddress: null == ipAddress ? _self.ipAddress : ipAddress // ignore: cast_nullable_to_non_nullable
|
as List<dynamic>,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,userAgent: null == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable
|
||||||
as String,deviceId: freezed == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
|
as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,nonce: freezed == nonce ? _self.nonce : nonce // ignore: cast_nullable_to_non_nullable
|
as String,nonce: freezed == nonce ? _self.nonce : nonce // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
as String?,location: freezed == location ? _self.location : location // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,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
|
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime?,
|
as DateTime?,
|
||||||
@ -336,6 +351,184 @@ as DateTime?,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$SnAuthSession {
|
||||||
|
|
||||||
|
String get id; String? get label; DateTime get lastGrantedAt; DateTime get expiredAt; String get accountId; String get challengeId; SnAuthChallenge get challenge; 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)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnAuthSessionCopyWith<SnAuthSession> get copyWith => _$SnAuthSessionCopyWithImpl<SnAuthSession>(this as SnAuthSession, _$identity);
|
||||||
|
|
||||||
|
/// Serializes this SnAuthSession to a JSON map.
|
||||||
|
Map<String, dynamic> 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)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.challengeId, challengeId) || other.challengeId == challengeId)&&(identical(other.challenge, challenge) || other.challenge == challenge)&&(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,accountId,challengeId,challenge,createdAt,updatedAt,deletedAt);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'SnAuthSession(id: $id, label: $label, lastGrantedAt: $lastGrantedAt, expiredAt: $expiredAt, accountId: $accountId, challengeId: $challengeId, challenge: $challenge, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
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, String accountId, String challengeId, SnAuthChallenge challenge, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$SnAuthChallengeCopyWith<$Res> get challenge;
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class _$SnAuthSessionCopyWithImpl<$Res>
|
||||||
|
implements $SnAuthSessionCopyWith<$Res> {
|
||||||
|
_$SnAuthSessionCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final SnAuthSession _self;
|
||||||
|
final $Res Function(SnAuthSession) _then;
|
||||||
|
|
||||||
|
/// 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 = null,Object? accountId = null,Object? challengeId = null,Object? challenge = 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
|
||||||
|
as String?,lastGrantedAt: null == lastGrantedAt ? _self.lastGrantedAt : lastGrantedAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime,expiredAt: null == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,challengeId: null == challengeId ? _self.challengeId : challengeId // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,challenge: null == challenge ? _self.challenge : challenge // ignore: cast_nullable_to_non_nullable
|
||||||
|
as SnAuthChallenge,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
|
||||||
|
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
/// Create a copy of SnAuthSession
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnAuthChallengeCopyWith<$Res> get challenge {
|
||||||
|
|
||||||
|
return $SnAuthChallengeCopyWith<$Res>(_self.challenge, (value) {
|
||||||
|
return _then(_self.copyWith(challenge: value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
|
||||||
|
class _SnAuthSession implements SnAuthSession {
|
||||||
|
const _SnAuthSession({required this.id, required this.label, required this.lastGrantedAt, required this.expiredAt, required this.accountId, required this.challengeId, required this.challenge, required this.createdAt, required this.updatedAt, required this.deletedAt});
|
||||||
|
factory _SnAuthSession.fromJson(Map<String, dynamic> json) => _$SnAuthSessionFromJson(json);
|
||||||
|
|
||||||
|
@override final String id;
|
||||||
|
@override final String? label;
|
||||||
|
@override final DateTime lastGrantedAt;
|
||||||
|
@override final DateTime expiredAt;
|
||||||
|
@override final String accountId;
|
||||||
|
@override final String challengeId;
|
||||||
|
@override final SnAuthChallenge challenge;
|
||||||
|
@override final DateTime createdAt;
|
||||||
|
@override final DateTime updatedAt;
|
||||||
|
@override final DateTime? deletedAt;
|
||||||
|
|
||||||
|
/// Create a copy of SnAuthSession
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$SnAuthSessionCopyWith<_SnAuthSession> get copyWith => __$SnAuthSessionCopyWithImpl<_SnAuthSession>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$SnAuthSessionToJson(this, );
|
||||||
|
}
|
||||||
|
|
||||||
|
@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)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.challengeId, challengeId) || other.challengeId == challengeId)&&(identical(other.challenge, challenge) || other.challenge == challenge)&&(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,accountId,challengeId,challenge,createdAt,updatedAt,deletedAt);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'SnAuthSession(id: $id, label: $label, lastGrantedAt: $lastGrantedAt, expiredAt: $expiredAt, accountId: $accountId, challengeId: $challengeId, challenge: $challenge, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class _$SnAuthSessionCopyWith<$Res> implements $SnAuthSessionCopyWith<$Res> {
|
||||||
|
factory _$SnAuthSessionCopyWith(_SnAuthSession value, $Res Function(_SnAuthSession) _then) = __$SnAuthSessionCopyWithImpl;
|
||||||
|
@override @useResult
|
||||||
|
$Res call({
|
||||||
|
String id, String? label, DateTime lastGrantedAt, DateTime expiredAt, String accountId, String challengeId, SnAuthChallenge challenge, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@override $SnAuthChallengeCopyWith<$Res> get challenge;
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class __$SnAuthSessionCopyWithImpl<$Res>
|
||||||
|
implements _$SnAuthSessionCopyWith<$Res> {
|
||||||
|
__$SnAuthSessionCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final _SnAuthSession _self;
|
||||||
|
final $Res Function(_SnAuthSession) _then;
|
||||||
|
|
||||||
|
/// 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 = null,Object? accountId = null,Object? challengeId = null,Object? challenge = 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
|
||||||
|
as String?,lastGrantedAt: null == lastGrantedAt ? _self.lastGrantedAt : lastGrantedAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime,expiredAt: null == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,challengeId: null == challengeId ? _self.challengeId : challengeId // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,challenge: null == challenge ? _self.challenge : challenge // ignore: cast_nullable_to_non_nullable
|
||||||
|
as SnAuthChallenge,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
|
||||||
|
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a copy of SnAuthSession
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnAuthChallengeCopyWith<$Res> get challenge {
|
||||||
|
|
||||||
|
return $SnAuthChallengeCopyWith<$Res>(_self.challenge, (value) {
|
||||||
|
return _then(_self.copyWith(challenge: value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$SnAuthFactor {
|
mixin _$SnAuthFactor {
|
||||||
|
|
||||||
@ -498,6 +691,162 @@ as Map<String, dynamic>?,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$SnAuthDevice {
|
||||||
|
|
||||||
|
dynamic get label; String get userAgent; String get deviceId; int get platform; List<SnAuthSession> get sessions;// Not from backend, used for UI
|
||||||
|
bool get isCurrent;
|
||||||
|
/// Create a copy of SnAuthDevice
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnAuthDeviceCopyWith<SnAuthDevice> get copyWith => _$SnAuthDeviceCopyWithImpl<SnAuthDevice>(this as SnAuthDevice, _$identity);
|
||||||
|
|
||||||
|
/// Serializes this SnAuthDevice to a JSON map.
|
||||||
|
Map<String, dynamic> toJson();
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAuthDevice&&const DeepCollectionEquality().equals(other.label, label)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(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,const DeepCollectionEquality().hash(label),userAgent,deviceId,platform,const DeepCollectionEquality().hash(sessions),isCurrent);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'SnAuthDevice(label: $label, userAgent: $userAgent, deviceId: $deviceId, platform: $platform, sessions: $sessions, isCurrent: $isCurrent)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class $SnAuthDeviceCopyWith<$Res> {
|
||||||
|
factory $SnAuthDeviceCopyWith(SnAuthDevice value, $Res Function(SnAuthDevice) _then) = _$SnAuthDeviceCopyWithImpl;
|
||||||
|
@useResult
|
||||||
|
$Res call({
|
||||||
|
dynamic label, String userAgent, String deviceId, int platform, List<SnAuthSession> sessions, bool isCurrent
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class _$SnAuthDeviceCopyWithImpl<$Res>
|
||||||
|
implements $SnAuthDeviceCopyWith<$Res> {
|
||||||
|
_$SnAuthDeviceCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final SnAuthDevice _self;
|
||||||
|
final $Res Function(SnAuthDevice) _then;
|
||||||
|
|
||||||
|
/// Create a copy of SnAuthDevice
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline') @override $Res call({Object? label = freezed,Object? userAgent = null,Object? deviceId = null,Object? platform = null,Object? sessions = null,Object? isCurrent = null,}) {
|
||||||
|
return _then(_self.copyWith(
|
||||||
|
label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
|
||||||
|
as dynamic,userAgent: null == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,sessions: null == sessions ? _self.sessions : sessions // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<SnAuthSession>,isCurrent: null == isCurrent ? _self.isCurrent : isCurrent // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
|
||||||
|
class _SnAuthDevice implements SnAuthDevice {
|
||||||
|
const _SnAuthDevice({required this.label, required this.userAgent, required this.deviceId, required this.platform, required final List<SnAuthSession> sessions, this.isCurrent = false}): _sessions = sessions;
|
||||||
|
factory _SnAuthDevice.fromJson(Map<String, dynamic> json) => _$SnAuthDeviceFromJson(json);
|
||||||
|
|
||||||
|
@override final dynamic label;
|
||||||
|
@override final String userAgent;
|
||||||
|
@override final String deviceId;
|
||||||
|
@override final int platform;
|
||||||
|
final List<SnAuthSession> _sessions;
|
||||||
|
@override List<SnAuthSession> get sessions {
|
||||||
|
if (_sessions is EqualUnmodifiableListView) return _sessions;
|
||||||
|
// ignore: implicit_dynamic_type
|
||||||
|
return EqualUnmodifiableListView(_sessions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not from backend, used for UI
|
||||||
|
@override@JsonKey() final bool isCurrent;
|
||||||
|
|
||||||
|
/// Create a copy of SnAuthDevice
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$SnAuthDeviceCopyWith<_SnAuthDevice> get copyWith => __$SnAuthDeviceCopyWithImpl<_SnAuthDevice>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$SnAuthDeviceToJson(this, );
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAuthDevice&&const DeepCollectionEquality().equals(other.label, label)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(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,const DeepCollectionEquality().hash(label),userAgent,deviceId,platform,const DeepCollectionEquality().hash(_sessions),isCurrent);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'SnAuthDevice(label: $label, userAgent: $userAgent, deviceId: $deviceId, platform: $platform, sessions: $sessions, isCurrent: $isCurrent)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class _$SnAuthDeviceCopyWith<$Res> implements $SnAuthDeviceCopyWith<$Res> {
|
||||||
|
factory _$SnAuthDeviceCopyWith(_SnAuthDevice value, $Res Function(_SnAuthDevice) _then) = __$SnAuthDeviceCopyWithImpl;
|
||||||
|
@override @useResult
|
||||||
|
$Res call({
|
||||||
|
dynamic label, String userAgent, String deviceId, int platform, List<SnAuthSession> sessions, bool isCurrent
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class __$SnAuthDeviceCopyWithImpl<$Res>
|
||||||
|
implements _$SnAuthDeviceCopyWith<$Res> {
|
||||||
|
__$SnAuthDeviceCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final _SnAuthDevice _self;
|
||||||
|
final $Res Function(_SnAuthDevice) _then;
|
||||||
|
|
||||||
|
/// Create a copy of SnAuthDevice
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @pragma('vm:prefer-inline') $Res call({Object? label = freezed,Object? userAgent = null,Object? deviceId = null,Object? platform = null,Object? sessions = null,Object? isCurrent = null,}) {
|
||||||
|
return _then(_SnAuthDevice(
|
||||||
|
label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
|
||||||
|
as dynamic,userAgent: null == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,sessions: null == sessions ? _self._sessions : sessions // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<SnAuthSession>,isCurrent: null == isCurrent ? _self.isCurrent : isCurrent // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// dart format on
|
// dart format on
|
||||||
|
@ -19,18 +19,21 @@ _SnAuthChallenge _$SnAuthChallengeFromJson(Map<String, dynamic> json) =>
|
|||||||
expiredAt: DateTime.parse(json['expired_at'] as String),
|
expiredAt: DateTime.parse(json['expired_at'] as String),
|
||||||
stepRemain: (json['step_remain'] as num).toInt(),
|
stepRemain: (json['step_remain'] as num).toInt(),
|
||||||
stepTotal: (json['step_total'] as num).toInt(),
|
stepTotal: (json['step_total'] as num).toInt(),
|
||||||
|
failedAttempts: (json['failed_attempts'] as num).toInt(),
|
||||||
|
platform: (json['platform'] as num).toInt(),
|
||||||
|
type: (json['type'] as num).toInt(),
|
||||||
blacklistFactors:
|
blacklistFactors:
|
||||||
(json['blacklist_factors'] as List<dynamic>)
|
(json['blacklist_factors'] as List<dynamic>)
|
||||||
.map((e) => e as String)
|
.map((e) => e as String)
|
||||||
.toList(),
|
.toList(),
|
||||||
audiences:
|
audiences: json['audiences'] as List<dynamic>,
|
||||||
(json['audiences'] as List<dynamic>).map((e) => e as String).toList(),
|
scopes: json['scopes'] as List<dynamic>,
|
||||||
scopes:
|
|
||||||
(json['scopes'] as List<dynamic>).map((e) => e as String).toList(),
|
|
||||||
ipAddress: json['ip_address'] as String,
|
ipAddress: json['ip_address'] as String,
|
||||||
userAgent: json['user_agent'] as String,
|
userAgent: json['user_agent'] as String,
|
||||||
deviceId: json['device_id'] as String?,
|
deviceId: json['device_id'] as String,
|
||||||
nonce: json['nonce'] as String?,
|
nonce: json['nonce'] as String?,
|
||||||
|
location: json['location'] as String?,
|
||||||
|
accountId: json['account_id'] as String,
|
||||||
createdAt: DateTime.parse(json['created_at'] as String),
|
createdAt: DateTime.parse(json['created_at'] as String),
|
||||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||||
deletedAt:
|
deletedAt:
|
||||||
@ -45,6 +48,9 @@ Map<String, dynamic> _$SnAuthChallengeToJson(_SnAuthChallenge instance) =>
|
|||||||
'expired_at': instance.expiredAt.toIso8601String(),
|
'expired_at': instance.expiredAt.toIso8601String(),
|
||||||
'step_remain': instance.stepRemain,
|
'step_remain': instance.stepRemain,
|
||||||
'step_total': instance.stepTotal,
|
'step_total': instance.stepTotal,
|
||||||
|
'failed_attempts': instance.failedAttempts,
|
||||||
|
'platform': instance.platform,
|
||||||
|
'type': instance.type,
|
||||||
'blacklist_factors': instance.blacklistFactors,
|
'blacklist_factors': instance.blacklistFactors,
|
||||||
'audiences': instance.audiences,
|
'audiences': instance.audiences,
|
||||||
'scopes': instance.scopes,
|
'scopes': instance.scopes,
|
||||||
@ -52,6 +58,41 @@ Map<String, dynamic> _$SnAuthChallengeToJson(_SnAuthChallenge instance) =>
|
|||||||
'user_agent': instance.userAgent,
|
'user_agent': instance.userAgent,
|
||||||
'device_id': instance.deviceId,
|
'device_id': instance.deviceId,
|
||||||
'nonce': instance.nonce,
|
'nonce': instance.nonce,
|
||||||
|
'location': instance.location,
|
||||||
|
'account_id': instance.accountId,
|
||||||
|
'created_at': instance.createdAt.toIso8601String(),
|
||||||
|
'updated_at': instance.updatedAt.toIso8601String(),
|
||||||
|
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||||
|
};
|
||||||
|
|
||||||
|
_SnAuthSession _$SnAuthSessionFromJson(Map<String, dynamic> json) =>
|
||||||
|
_SnAuthSession(
|
||||||
|
id: json['id'] as String,
|
||||||
|
label: json['label'] as String?,
|
||||||
|
lastGrantedAt: DateTime.parse(json['last_granted_at'] as String),
|
||||||
|
expiredAt: DateTime.parse(json['expired_at'] as String),
|
||||||
|
accountId: json['account_id'] as String,
|
||||||
|
challengeId: json['challenge_id'] as String,
|
||||||
|
challenge: SnAuthChallenge.fromJson(
|
||||||
|
json['challenge'] as Map<String, dynamic>,
|
||||||
|
),
|
||||||
|
createdAt: DateTime.parse(json['created_at'] as String),
|
||||||
|
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||||
|
deletedAt:
|
||||||
|
json['deleted_at'] == null
|
||||||
|
? null
|
||||||
|
: DateTime.parse(json['deleted_at'] as String),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$SnAuthSessionToJson(_SnAuthSession instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'id': instance.id,
|
||||||
|
'label': instance.label,
|
||||||
|
'last_granted_at': instance.lastGrantedAt.toIso8601String(),
|
||||||
|
'expired_at': instance.expiredAt.toIso8601String(),
|
||||||
|
'account_id': instance.accountId,
|
||||||
|
'challenge_id': instance.challengeId,
|
||||||
|
'challenge': instance.challenge.toJson(),
|
||||||
'created_at': instance.createdAt.toIso8601String(),
|
'created_at': instance.createdAt.toIso8601String(),
|
||||||
'updated_at': instance.updatedAt.toIso8601String(),
|
'updated_at': instance.updatedAt.toIso8601String(),
|
||||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||||
@ -91,3 +132,26 @@ Map<String, dynamic> _$SnAuthFactorToJson(_SnAuthFactor instance) =>
|
|||||||
'trustworthy': instance.trustworthy,
|
'trustworthy': instance.trustworthy,
|
||||||
'created_response': instance.createdResponse,
|
'created_response': instance.createdResponse,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_SnAuthDevice _$SnAuthDeviceFromJson(Map<String, dynamic> json) =>
|
||||||
|
_SnAuthDevice(
|
||||||
|
label: json['label'],
|
||||||
|
userAgent: json['user_agent'] as String,
|
||||||
|
deviceId: json['device_id'] as String,
|
||||||
|
platform: (json['platform'] as num).toInt(),
|
||||||
|
sessions:
|
||||||
|
(json['sessions'] as List<dynamic>)
|
||||||
|
.map((e) => SnAuthSession.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
isCurrent: json['is_current'] as bool? ?? false,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$SnAuthDeviceToJson(_SnAuthDevice instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'label': instance.label,
|
||||||
|
'user_agent': instance.userAgent,
|
||||||
|
'device_id': instance.deviceId,
|
||||||
|
'platform': instance.platform,
|
||||||
|
'sessions': instance.sessions.map((e) => e.toJson()).toList(),
|
||||||
|
'is_current': instance.isCurrent,
|
||||||
|
};
|
||||||
|
@ -16,6 +16,7 @@ import 'package:island/pods/userinfo.dart';
|
|||||||
import 'package:island/screens/auth/captcha.dart';
|
import 'package:island/screens/auth/captcha.dart';
|
||||||
import 'package:island/screens/auth/login.dart';
|
import 'package:island/screens/auth/login.dart';
|
||||||
import 'package:island/services/responsive.dart';
|
import 'package:island/services/responsive.dart';
|
||||||
|
import 'package:island/widgets/account/account_session_sheet.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/widgets/alert.dart';
|
||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/widgets/app_scaffold.dart';
|
||||||
import 'package:island/widgets/content/sheet.dart';
|
import 'package:island/widgets/content/sheet.dart';
|
||||||
@ -90,6 +91,21 @@ class AccountSettingsScreen extends HookConsumerWidget {
|
|||||||
|
|
||||||
// Group settings into categories for better organization
|
// Group settings into categories for better organization
|
||||||
final securitySettings = [
|
final securitySettings = [
|
||||||
|
ListTile(
|
||||||
|
minLeadingWidth: 48,
|
||||||
|
leading: const Icon(Symbols.devices),
|
||||||
|
title: Text('authSessions').tr(),
|
||||||
|
subtitle: Text('authSessionsDescription').tr().fontSize(12),
|
||||||
|
contentPadding: const EdgeInsets.only(left: 24, right: 17),
|
||||||
|
trailing: const Icon(Symbols.chevron_right),
|
||||||
|
onTap: () {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
isScrollControlled: true,
|
||||||
|
builder: (context) => const AccountSessionSheet(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
ExpansionTile(
|
ExpansionTile(
|
||||||
leading: const Icon(
|
leading: const Icon(
|
||||||
Symbols.security,
|
Symbols.security,
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:animations/animations.dart';
|
import 'package:animations/animations.dart';
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -63,6 +66,19 @@ class LoginScreen extends HookConsumerWidget {
|
|||||||
LinearProgressIndicator(
|
LinearProgressIndicator(
|
||||||
minHeight: 4,
|
minHeight: 4,
|
||||||
borderRadius: BorderRadius.zero,
|
borderRadius: BorderRadius.zero,
|
||||||
|
trackGap: 0,
|
||||||
|
stopIndicatorRadius: 0,
|
||||||
|
)
|
||||||
|
else if (currentTicket.value != null)
|
||||||
|
LinearProgressIndicator(
|
||||||
|
minHeight: 4,
|
||||||
|
borderRadius: BorderRadius.zero,
|
||||||
|
trackGap: 0,
|
||||||
|
stopIndicatorRadius: 0,
|
||||||
|
value:
|
||||||
|
1 -
|
||||||
|
(currentTicket.value!.stepRemain /
|
||||||
|
currentTicket.value!.stepTotal),
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
const Gap(4),
|
const Gap(4),
|
||||||
@ -121,16 +137,7 @@ class LoginScreen extends HookConsumerWidget {
|
|||||||
).padding(all: 24),
|
).padding(all: 24),
|
||||||
).center(),
|
).center(),
|
||||||
),
|
),
|
||||||
if (currentTicket.value != null)
|
|
||||||
LinearProgressIndicator(
|
|
||||||
minHeight: 4,
|
|
||||||
borderRadius: BorderRadius.zero,
|
|
||||||
value:
|
|
||||||
1 -
|
|
||||||
(currentTicket.value!.stepRemain /
|
|
||||||
currentTicket.value!.stepTotal),
|
|
||||||
)
|
|
||||||
else
|
|
||||||
const Gap(4),
|
const Gap(4),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -170,6 +177,7 @@ class _LoginCheckScreen extends HookConsumerWidget {
|
|||||||
if (pwd.isEmpty) return;
|
if (pwd.isEmpty) return;
|
||||||
isBusy.value = true;
|
isBusy.value = true;
|
||||||
try {
|
try {
|
||||||
|
// Pass challenge
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
final resp = await client.patch(
|
final resp = await client.patch(
|
||||||
'/auth/challenge/${challenge!.id}',
|
'/auth/challenge/${challenge!.id}',
|
||||||
@ -181,6 +189,8 @@ class _LoginCheckScreen extends HookConsumerWidget {
|
|||||||
onNext();
|
onNext();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get token if challenge is completed
|
||||||
final tokenResp = await client.post(
|
final tokenResp = await client.post(
|
||||||
'/auth/token',
|
'/auth/token',
|
||||||
data: {'grant_type': 'authorization_code', 'code': result.id},
|
data: {'grant_type': 'authorization_code', 'code': result.id},
|
||||||
@ -189,6 +199,8 @@ class _LoginCheckScreen extends HookConsumerWidget {
|
|||||||
setToken(ref.watch(sharedPreferencesProvider), token);
|
setToken(ref.watch(sharedPreferencesProvider), token);
|
||||||
ref.invalidate(tokenProvider);
|
ref.invalidate(tokenProvider);
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
|
|
||||||
|
// Do post login tasks
|
||||||
final userNotifier = ref.read(userInfoProvider.notifier);
|
final userNotifier = ref.read(userInfoProvider.notifier);
|
||||||
userNotifier.fetchUser().then((_) {
|
userNotifier.fetchUser().then((_) {
|
||||||
final apiClient = ref.read(apiClientProvider);
|
final apiClient = ref.read(apiClientProvider);
|
||||||
@ -197,6 +209,31 @@ class _LoginCheckScreen extends HookConsumerWidget {
|
|||||||
wsNotifier.connect();
|
wsNotifier.connect();
|
||||||
if (context.mounted) Navigator.pop(context, true);
|
if (context.mounted) Navigator.pop(context, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Update the sessions' device name is available
|
||||||
|
if (!kIsWeb) {
|
||||||
|
String? name;
|
||||||
|
if (Platform.isIOS) {
|
||||||
|
return;
|
||||||
|
// TODO waiting for apple to respond to grant my access to com.apple.developer.device-information.user-assigned-device-name
|
||||||
|
// ignore: dead_code
|
||||||
|
final deviceInfo = await DeviceInfoPlugin().iosInfo;
|
||||||
|
name = deviceInfo.name;
|
||||||
|
} else if (Platform.isAndroid) {
|
||||||
|
final deviceInfo = await DeviceInfoPlugin().androidInfo;
|
||||||
|
name = deviceInfo.name;
|
||||||
|
} else if (Platform.isWindows) {
|
||||||
|
final deviceInfo = await DeviceInfoPlugin().windowsInfo;
|
||||||
|
name = deviceInfo.computerName;
|
||||||
|
}
|
||||||
|
if (name != null) {
|
||||||
|
final client = ref.watch(apiClientProvider);
|
||||||
|
await client.patch(
|
||||||
|
'/accounts/me/sessions/current/label',
|
||||||
|
data: jsonEncode(name),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showErrorAlert(err);
|
showErrorAlert(err);
|
||||||
return;
|
return;
|
||||||
@ -336,6 +373,14 @@ class _LoginPickerScreen extends HookConsumerWidget {
|
|||||||
onPickFactor(factors!.where((x) => x == factorPicked.value).first);
|
onPickFactor(factors!.where((x) => x == factorPicked.value).first);
|
||||||
onNext();
|
onNext();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
if (err is DioException && err.response?.statusCode == 400) {
|
||||||
|
onPickFactor(factors!.where((x) => x == factorPicked.value).first);
|
||||||
|
onNext();
|
||||||
|
if (context.mounted) {
|
||||||
|
showSnackBar(context, err.response!.data.toString());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
showErrorAlert(err);
|
showErrorAlert(err);
|
||||||
return;
|
return;
|
||||||
} finally {
|
} finally {
|
||||||
@ -404,6 +449,7 @@ class _LoginPickerScreen extends HookConsumerWidget {
|
|||||||
TextField(
|
TextField(
|
||||||
controller: hintController,
|
controller: hintController,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
|
isDense: true,
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
labelText: 'authFactorHint'.tr(),
|
labelText: 'authFactorHint'.tr(),
|
||||||
helperText: 'authFactorHintHelper'.tr(),
|
helperText: 'authFactorHintHelper'.tr(),
|
||||||
|
246
lib/widgets/account/account_session_sheet.dart
Normal file
246
lib/widgets/account/account_session_sheet.dart
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:island/models/auth.dart';
|
||||||
|
import 'package:island/pods/network.dart';
|
||||||
|
import 'package:island/services/responsive.dart';
|
||||||
|
import 'package:island/widgets/alert.dart';
|
||||||
|
import 'package:island/widgets/content/sheet.dart';
|
||||||
|
import 'package:island/widgets/response.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
|
part 'account_session_sheet.g.dart';
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
Future<List<SnAuthDevice>> authDevices(Ref ref) async {
|
||||||
|
final resp = await ref.watch(apiClientProvider).get('/accounts/me/devices');
|
||||||
|
final sessionId = resp.headers.value('x-auth-session');
|
||||||
|
final data =
|
||||||
|
resp.data.map<SnAuthDevice>((e) {
|
||||||
|
final ele = SnAuthDevice.fromJson(e);
|
||||||
|
return ele.copyWith(isCurrent: ele.sessions.first.id == sessionId);
|
||||||
|
}).toList();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DeviceListTile extends StatelessWidget {
|
||||||
|
final SnAuthDevice device;
|
||||||
|
final Function(String) updateDeviceLabel;
|
||||||
|
final Function(String) logoutDevice;
|
||||||
|
|
||||||
|
const _DeviceListTile({
|
||||||
|
required this.device,
|
||||||
|
required this.updateDeviceLabel,
|
||||||
|
required this.logoutDevice,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListTile(
|
||||||
|
isThreeLine: true,
|
||||||
|
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||||
|
leading: Icon(switch (device.platform) {
|
||||||
|
0 => Icons.device_unknown, // Unidentified
|
||||||
|
1 => Icons.web, // Web
|
||||||
|
2 => Icons.phone_iphone, // iOS
|
||||||
|
3 => Icons.phone_android, // Android
|
||||||
|
4 => Icons.laptop_mac, // macOS
|
||||||
|
5 => Icons.window, // Windows
|
||||||
|
6 => Icons.computer, // Linux
|
||||||
|
_ => Icons.device_unknown, // fallback
|
||||||
|
}).padding(top: 4),
|
||||||
|
subtitle: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
Text('authSessionsCount'.plural(device.sessions.length)),
|
||||||
|
Text(
|
||||||
|
'lastActiveAt'.tr(
|
||||||
|
args: [
|
||||||
|
DateFormat().format(
|
||||||
|
device.sessions.first.lastGrantedAt.toLocal(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(device.sessions.first.challenge.ipAddress),
|
||||||
|
if (device.isCurrent)
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Badge(
|
||||||
|
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||||
|
label: Text(
|
||||||
|
'authDeviceCurrent'.tr(),
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onPrimary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).padding(top: 4),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
title: Text(device.label ?? device.sessions.first.challenge.userAgent),
|
||||||
|
trailing:
|
||||||
|
isWideScreen(context)
|
||||||
|
? Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.edit),
|
||||||
|
tooltip: 'authDeviceEditLabel'.tr(),
|
||||||
|
onPressed:
|
||||||
|
() => updateDeviceLabel(device.sessions.first.id),
|
||||||
|
),
|
||||||
|
if (!device.isCurrent)
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.logout),
|
||||||
|
tooltip: 'authDeviceLogout'.tr(),
|
||||||
|
onPressed: () => logoutDevice(device.sessions.first.id),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AccountSessionSheet extends HookConsumerWidget {
|
||||||
|
const AccountSessionSheet({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final authDevices = ref.watch(authDevicesProvider);
|
||||||
|
|
||||||
|
void logoutDevice(String sessionId) async {
|
||||||
|
final confirm = await showConfirmAlert(
|
||||||
|
'authDeviceLogoutHint'.tr(),
|
||||||
|
'authDeviceLogout'.tr(),
|
||||||
|
);
|
||||||
|
if (!confirm || !context.mounted) return;
|
||||||
|
try {
|
||||||
|
final apiClient = ref.watch(apiClientProvider);
|
||||||
|
await apiClient.delete('/accounts/me/sessions/$sessionId');
|
||||||
|
ref.invalidate(authDevicesProvider);
|
||||||
|
} catch (err) {
|
||||||
|
showErrorAlert(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateDeviceLabel(String sessionId) async {
|
||||||
|
final controller = TextEditingController();
|
||||||
|
final label = await showDialog<String>(
|
||||||
|
context: context,
|
||||||
|
builder:
|
||||||
|
(context) => AlertDialog(
|
||||||
|
title: Text('authDeviceLabelTitle'.tr()),
|
||||||
|
content: TextField(
|
||||||
|
controller: controller,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
isDense: true,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
hintText: 'authDeviceLabelHint'.tr(),
|
||||||
|
),
|
||||||
|
autofocus: true,
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
child: Text('cancel'.tr()),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(context, controller.text),
|
||||||
|
child: Text('confirm'.tr()),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (label == null || label.isEmpty || !context.mounted) return;
|
||||||
|
try {
|
||||||
|
final apiClient = ref.watch(apiClientProvider);
|
||||||
|
await apiClient.patch(
|
||||||
|
'/accounts/me/sessions/$sessionId/label',
|
||||||
|
data: jsonEncode(label),
|
||||||
|
);
|
||||||
|
ref.invalidate(authDevicesProvider);
|
||||||
|
} catch (err) {
|
||||||
|
showErrorAlert(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final wideScreen = isWideScreen(context);
|
||||||
|
|
||||||
|
return SheetScaffold(
|
||||||
|
titleText: 'authSessions'.tr(),
|
||||||
|
child: authDevices.when(
|
||||||
|
data:
|
||||||
|
(data) => RefreshIndicator(
|
||||||
|
onRefresh:
|
||||||
|
() => Future.sync(() => ref.invalidate(authDevicesProvider)),
|
||||||
|
child: ListView.builder(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
itemCount: data.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final device = data[index];
|
||||||
|
if (wideScreen) {
|
||||||
|
return _DeviceListTile(
|
||||||
|
device: device,
|
||||||
|
updateDeviceLabel: updateDeviceLabel,
|
||||||
|
logoutDevice: logoutDevice,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Dismissible(
|
||||||
|
key: Key('device-${device.sessions.first.id}'),
|
||||||
|
direction:
|
||||||
|
device.isCurrent
|
||||||
|
? DismissDirection.startToEnd
|
||||||
|
: DismissDirection.horizontal,
|
||||||
|
background: Container(
|
||||||
|
color: Colors.blue,
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 20),
|
||||||
|
child: Icon(Icons.edit, color: Colors.white),
|
||||||
|
),
|
||||||
|
secondaryBackground: Container(
|
||||||
|
color: Colors.red,
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 20),
|
||||||
|
child: Icon(Icons.logout, color: Colors.white),
|
||||||
|
),
|
||||||
|
confirmDismiss: (direction) async {
|
||||||
|
if (direction == DismissDirection.startToEnd) {
|
||||||
|
updateDeviceLabel(device.sessions.first.id);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
final confirm = await showConfirmAlert(
|
||||||
|
'authDeviceLogoutHint'.tr(),
|
||||||
|
'authDeviceLogout'.tr(),
|
||||||
|
);
|
||||||
|
if (confirm && context.mounted) {
|
||||||
|
logoutDevice(device.sessions.first.id);
|
||||||
|
}
|
||||||
|
return false; // Don't dismiss
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: _DeviceListTile(
|
||||||
|
device: device,
|
||||||
|
updateDeviceLabel: updateDeviceLabel,
|
||||||
|
logoutDevice: logoutDevice,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
error:
|
||||||
|
(err, _) => ResponseErrorWidget(
|
||||||
|
error: err,
|
||||||
|
onRetry: () => ref.invalidate(authDevicesProvider),
|
||||||
|
),
|
||||||
|
loading: () => ResponseLoadingWidget(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
29
lib/widgets/account/account_session_sheet.g.dart
Normal file
29
lib/widgets/account/account_session_sheet.g.dart
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'account_session_sheet.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$authDevicesHash() => r'9b8101167653991314efd37788d8416f414cb9e8';
|
||||||
|
|
||||||
|
/// See also [authDevices].
|
||||||
|
@ProviderFor(authDevices)
|
||||||
|
final authDevicesProvider =
|
||||||
|
AutoDisposeFutureProvider<List<SnAuthDevice>>.internal(
|
||||||
|
authDevices,
|
||||||
|
name: r'authDevicesProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$authDevicesHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
|
typedef AuthDevicesRef = AutoDisposeFutureProviderRef<List<SnAuthDevice>>;
|
||||||
|
// 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
|
Loading…
x
Reference in New Issue
Block a user