Compare commits
2 Commits
24ddbf34e4
...
b5d12f31a1
| Author | SHA1 | Date | |
|---|---|---|---|
| b5d12f31a1 | |||
| 74f470219a |
@@ -230,6 +230,11 @@ void configureAppRouter() {
|
||||
name: 'videocall',
|
||||
pageBuilder: const VideocallBuilder().buildPage,
|
||||
),
|
||||
GoRoute(
|
||||
path: 'friends',
|
||||
name: 'friends',
|
||||
pageBuilder: const FriendsBuilder().buildPage,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
||||
@@ -15,3 +15,4 @@ export 'src/features/background_image/background_image_builder.dart';
|
||||
export 'src/features/installed_apps/installed_apps_builder.dart';
|
||||
export 'src/features/app_usage_schedules/app_usage_schedules_builder.dart';
|
||||
export 'src/features/videocall/videocall_builder.dart';
|
||||
export 'src/features/friends/friends_builder.dart';
|
||||
|
||||
@@ -145,6 +145,15 @@ class DeviceManagementScreen extends ConsumerWidget {
|
||||
iconSize: SizeUtils.getByScreen(small: 42, big: 40),
|
||||
text: context.translate(I18n.callHistory),
|
||||
),
|
||||
gap,
|
||||
AppMenuButton(
|
||||
color: primaryColor,
|
||||
onPressed: () =>
|
||||
navigationContract.pushTo(AppRoutes.friends),
|
||||
icon: Icons.people_outline,
|
||||
iconSize: SizeUtils.getByScreen(small: 42, big: 40),
|
||||
text: context.translate(I18n.makeFriends),
|
||||
),
|
||||
if (capabilities?.appUsageSchedules != null) ...[
|
||||
gap,
|
||||
AppMenuButton(
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'friend_entity.freezed.dart';
|
||||
|
||||
@freezed
|
||||
abstract class FriendEntity with _$FriendEntity {
|
||||
const factory FriendEntity({
|
||||
required String id,
|
||||
required String deviceId,
|
||||
required String friendId,
|
||||
String? phone,
|
||||
required String name,
|
||||
required int createdAt,
|
||||
}) = _FriendEntity;
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'friend_entity.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$FriendEntity {
|
||||
|
||||
String get id; String get deviceId; String get friendId; String? get phone; String get name; int get createdAt;
|
||||
/// Create a copy of FriendEntity
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$FriendEntityCopyWith<FriendEntity> get copyWith => _$FriendEntityCopyWithImpl<FriendEntity>(this as FriendEntity, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is FriendEntity&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.friendId, friendId) || other.friendId == friendId)&&(identical(other.phone, phone) || other.phone == phone)&&(identical(other.name, name) || other.name == name)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,deviceId,friendId,phone,name,createdAt);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'FriendEntity(id: $id, deviceId: $deviceId, friendId: $friendId, phone: $phone, name: $name, createdAt: $createdAt)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $FriendEntityCopyWith<$Res> {
|
||||
factory $FriendEntityCopyWith(FriendEntity value, $Res Function(FriendEntity) _then) = _$FriendEntityCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String id, String deviceId, String friendId, String? phone, String name, int createdAt
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$FriendEntityCopyWithImpl<$Res>
|
||||
implements $FriendEntityCopyWith<$Res> {
|
||||
_$FriendEntityCopyWithImpl(this._self, this._then);
|
||||
|
||||
final FriendEntity _self;
|
||||
final $Res Function(FriendEntity) _then;
|
||||
|
||||
/// Create a copy of FriendEntity
|
||||
/// 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? friendId = null,Object? phone = freezed,Object? name = null,Object? createdAt = 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
|
||||
as String,friendId: null == friendId ? _self.friendId : friendId // ignore: cast_nullable_to_non_nullable
|
||||
as String,phone: freezed == phone ? _self.phone : phone // ignore: cast_nullable_to_non_nullable
|
||||
as String?,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
||||
as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [FriendEntity].
|
||||
extension FriendEntityPatterns on FriendEntity {
|
||||
/// A variant of `map` that fallback to returning `orElse`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _FriendEntity value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _FriendEntity() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// Callbacks receives the raw object, upcasted.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case final Subclass2 value:
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _FriendEntity value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _FriendEntity():
|
||||
return $default(_that);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `map` that fallback to returning `null`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _FriendEntity value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _FriendEntity() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to an `orElse` callback.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String deviceId, String friendId, String? phone, String name, int createdAt)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _FriendEntity() when $default != null:
|
||||
return $default(_that.id,_that.deviceId,_that.friendId,_that.phone,_that.name,_that.createdAt);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// As opposed to `map`, this offers destructuring.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case Subclass2(:final field2):
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String deviceId, String friendId, String? phone, String name, int createdAt) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _FriendEntity():
|
||||
return $default(_that.id,_that.deviceId,_that.friendId,_that.phone,_that.name,_that.createdAt);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String deviceId, String friendId, String? phone, String name, int createdAt)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _FriendEntity() when $default != null:
|
||||
return $default(_that.id,_that.deviceId,_that.friendId,_that.phone,_that.name,_that.createdAt);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
|
||||
class _FriendEntity implements FriendEntity {
|
||||
const _FriendEntity({required this.id, required this.deviceId, required this.friendId, this.phone, required this.name, required this.createdAt});
|
||||
|
||||
|
||||
@override final String id;
|
||||
@override final String deviceId;
|
||||
@override final String friendId;
|
||||
@override final String? phone;
|
||||
@override final String name;
|
||||
@override final int createdAt;
|
||||
|
||||
/// Create a copy of FriendEntity
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$FriendEntityCopyWith<_FriendEntity> get copyWith => __$FriendEntityCopyWithImpl<_FriendEntity>(this, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _FriendEntity&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.friendId, friendId) || other.friendId == friendId)&&(identical(other.phone, phone) || other.phone == phone)&&(identical(other.name, name) || other.name == name)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,deviceId,friendId,phone,name,createdAt);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'FriendEntity(id: $id, deviceId: $deviceId, friendId: $friendId, phone: $phone, name: $name, createdAt: $createdAt)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$FriendEntityCopyWith<$Res> implements $FriendEntityCopyWith<$Res> {
|
||||
factory _$FriendEntityCopyWith(_FriendEntity value, $Res Function(_FriendEntity) _then) = __$FriendEntityCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String id, String deviceId, String friendId, String? phone, String name, int createdAt
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$FriendEntityCopyWithImpl<$Res>
|
||||
implements _$FriendEntityCopyWith<$Res> {
|
||||
__$FriendEntityCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _FriendEntity _self;
|
||||
final $Res Function(_FriendEntity) _then;
|
||||
|
||||
/// Create a copy of FriendEntity
|
||||
/// 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? friendId = null,Object? phone = freezed,Object? name = null,Object? createdAt = null,}) {
|
||||
return _then(_FriendEntity(
|
||||
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,friendId: null == friendId ? _self.friendId : friendId // ignore: cast_nullable_to_non_nullable
|
||||
as String,phone: freezed == phone ? _self.phone : phone // ignore: cast_nullable_to_non_nullable
|
||||
as String?,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
||||
as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
@@ -0,0 +1,61 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:sf_infrastructure/sf_infrastructure.dart';
|
||||
|
||||
import 'friend_entity.dart';
|
||||
import 'friends_response_dto.dart';
|
||||
|
||||
class FriendsDatasource {
|
||||
FriendsDatasource(this._repository);
|
||||
|
||||
final SaveFamilyRepository _repository;
|
||||
|
||||
Future<List<FriendEntity>> getFriends({
|
||||
required String deviceIdentificator,
|
||||
String? search,
|
||||
}) async {
|
||||
try {
|
||||
final queryParams = <String, dynamic>{'pageSize': 1000};
|
||||
if (search != null && search.isNotEmpty) {
|
||||
queryParams['search'] = search;
|
||||
}
|
||||
|
||||
final response = await _repository.get<Map<String, dynamic>>(
|
||||
'/devices/identificator/$deviceIdentificator/friends',
|
||||
queryParameters: queryParams,
|
||||
);
|
||||
|
||||
final data = response.data;
|
||||
if (data == null || data.isEmpty) return [];
|
||||
|
||||
final model = FriendsResponseDto.fromJson(data);
|
||||
return model.items
|
||||
.map(
|
||||
(item) => FriendEntity(
|
||||
id: item.id,
|
||||
deviceId: item.deviceId,
|
||||
friendId: item.friendId,
|
||||
phone: item.phone,
|
||||
name: item.name,
|
||||
createdAt: item.createdAt,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
} on DioException catch (error) {
|
||||
if (error.response?.statusCode == 404) return [];
|
||||
throw mapDioError(error, defaultMessage: 'Error getting friends');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteFriend({
|
||||
required String deviceIdentificator,
|
||||
required String friendId,
|
||||
}) async {
|
||||
try {
|
||||
await _repository.delete<dynamic>(
|
||||
'/devices/identificator/$deviceIdentificator/friends/$friendId',
|
||||
);
|
||||
} on DioException catch (error) {
|
||||
throw mapDioError(error, defaultMessage: 'Error deleting friend');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:sf_infrastructure/sf_infrastructure.dart';
|
||||
|
||||
import 'friends_datasource.dart';
|
||||
|
||||
final friendsDatasourceProvider = Provider<FriendsDatasource>((ref) {
|
||||
return FriendsDatasource(GetIt.I<SaveFamilyRepository>());
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'friends_response_dto.freezed.dart';
|
||||
part 'friends_response_dto.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class FriendsResponseDto with _$FriendsResponseDto {
|
||||
const factory FriendsResponseDto({
|
||||
required int total,
|
||||
required List<FriendItemDto> items,
|
||||
}) = _FriendsResponseDto;
|
||||
|
||||
factory FriendsResponseDto.fromJson(Map<String, dynamic> json) =>
|
||||
_$FriendsResponseDtoFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class FriendItemDto with _$FriendItemDto {
|
||||
const factory FriendItemDto({
|
||||
required String id,
|
||||
required String deviceId,
|
||||
required String friendId,
|
||||
String? phone,
|
||||
required String name,
|
||||
required int createdAt,
|
||||
}) = _FriendItemDto;
|
||||
|
||||
factory FriendItemDto.fromJson(Map<String, dynamic> json) =>
|
||||
_$FriendItemDtoFromJson(json);
|
||||
}
|
||||
@@ -0,0 +1,564 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'friends_response_dto.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
/// @nodoc
|
||||
mixin _$FriendsResponseDto {
|
||||
|
||||
int get total; List<FriendItemDto> get items;
|
||||
/// Create a copy of FriendsResponseDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$FriendsResponseDtoCopyWith<FriendsResponseDto> get copyWith => _$FriendsResponseDtoCopyWithImpl<FriendsResponseDto>(this as FriendsResponseDto, _$identity);
|
||||
|
||||
/// Serializes this FriendsResponseDto to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is FriendsResponseDto&&(identical(other.total, total) || other.total == total)&&const DeepCollectionEquality().equals(other.items, items));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,total,const DeepCollectionEquality().hash(items));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'FriendsResponseDto(total: $total, items: $items)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $FriendsResponseDtoCopyWith<$Res> {
|
||||
factory $FriendsResponseDtoCopyWith(FriendsResponseDto value, $Res Function(FriendsResponseDto) _then) = _$FriendsResponseDtoCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
int total, List<FriendItemDto> items
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$FriendsResponseDtoCopyWithImpl<$Res>
|
||||
implements $FriendsResponseDtoCopyWith<$Res> {
|
||||
_$FriendsResponseDtoCopyWithImpl(this._self, this._then);
|
||||
|
||||
final FriendsResponseDto _self;
|
||||
final $Res Function(FriendsResponseDto) _then;
|
||||
|
||||
/// Create a copy of FriendsResponseDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? total = null,Object? items = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
total: null == total ? _self.total : total // ignore: cast_nullable_to_non_nullable
|
||||
as int,items: null == items ? _self.items : items // ignore: cast_nullable_to_non_nullable
|
||||
as List<FriendItemDto>,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [FriendsResponseDto].
|
||||
extension FriendsResponseDtoPatterns on FriendsResponseDto {
|
||||
/// A variant of `map` that fallback to returning `orElse`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _FriendsResponseDto value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _FriendsResponseDto() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// Callbacks receives the raw object, upcasted.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case final Subclass2 value:
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _FriendsResponseDto value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _FriendsResponseDto():
|
||||
return $default(_that);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `map` that fallback to returning `null`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _FriendsResponseDto value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _FriendsResponseDto() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to an `orElse` callback.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( int total, List<FriendItemDto> items)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _FriendsResponseDto() when $default != null:
|
||||
return $default(_that.total,_that.items);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// As opposed to `map`, this offers destructuring.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case Subclass2(:final field2):
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( int total, List<FriendItemDto> items) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _FriendsResponseDto():
|
||||
return $default(_that.total,_that.items);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( int total, List<FriendItemDto> items)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _FriendsResponseDto() when $default != null:
|
||||
return $default(_that.total,_that.items);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
|
||||
class _FriendsResponseDto implements FriendsResponseDto {
|
||||
const _FriendsResponseDto({required this.total, required final List<FriendItemDto> items}): _items = items;
|
||||
factory _FriendsResponseDto.fromJson(Map<String, dynamic> json) => _$FriendsResponseDtoFromJson(json);
|
||||
|
||||
@override final int total;
|
||||
final List<FriendItemDto> _items;
|
||||
@override List<FriendItemDto> get items {
|
||||
if (_items is EqualUnmodifiableListView) return _items;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_items);
|
||||
}
|
||||
|
||||
|
||||
/// Create a copy of FriendsResponseDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$FriendsResponseDtoCopyWith<_FriendsResponseDto> get copyWith => __$FriendsResponseDtoCopyWithImpl<_FriendsResponseDto>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$FriendsResponseDtoToJson(this, );
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _FriendsResponseDto&&(identical(other.total, total) || other.total == total)&&const DeepCollectionEquality().equals(other._items, _items));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,total,const DeepCollectionEquality().hash(_items));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'FriendsResponseDto(total: $total, items: $items)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$FriendsResponseDtoCopyWith<$Res> implements $FriendsResponseDtoCopyWith<$Res> {
|
||||
factory _$FriendsResponseDtoCopyWith(_FriendsResponseDto value, $Res Function(_FriendsResponseDto) _then) = __$FriendsResponseDtoCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
int total, List<FriendItemDto> items
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$FriendsResponseDtoCopyWithImpl<$Res>
|
||||
implements _$FriendsResponseDtoCopyWith<$Res> {
|
||||
__$FriendsResponseDtoCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _FriendsResponseDto _self;
|
||||
final $Res Function(_FriendsResponseDto) _then;
|
||||
|
||||
/// Create a copy of FriendsResponseDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? total = null,Object? items = null,}) {
|
||||
return _then(_FriendsResponseDto(
|
||||
total: null == total ? _self.total : total // ignore: cast_nullable_to_non_nullable
|
||||
as int,items: null == items ? _self._items : items // ignore: cast_nullable_to_non_nullable
|
||||
as List<FriendItemDto>,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// @nodoc
|
||||
mixin _$FriendItemDto {
|
||||
|
||||
String get id; String get deviceId; String get friendId; String? get phone; String get name; int get createdAt;
|
||||
/// Create a copy of FriendItemDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$FriendItemDtoCopyWith<FriendItemDto> get copyWith => _$FriendItemDtoCopyWithImpl<FriendItemDto>(this as FriendItemDto, _$identity);
|
||||
|
||||
/// Serializes this FriendItemDto to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is FriendItemDto&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.friendId, friendId) || other.friendId == friendId)&&(identical(other.phone, phone) || other.phone == phone)&&(identical(other.name, name) || other.name == name)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,deviceId,friendId,phone,name,createdAt);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'FriendItemDto(id: $id, deviceId: $deviceId, friendId: $friendId, phone: $phone, name: $name, createdAt: $createdAt)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $FriendItemDtoCopyWith<$Res> {
|
||||
factory $FriendItemDtoCopyWith(FriendItemDto value, $Res Function(FriendItemDto) _then) = _$FriendItemDtoCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String id, String deviceId, String friendId, String? phone, String name, int createdAt
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$FriendItemDtoCopyWithImpl<$Res>
|
||||
implements $FriendItemDtoCopyWith<$Res> {
|
||||
_$FriendItemDtoCopyWithImpl(this._self, this._then);
|
||||
|
||||
final FriendItemDto _self;
|
||||
final $Res Function(FriendItemDto) _then;
|
||||
|
||||
/// Create a copy of FriendItemDto
|
||||
/// 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? friendId = null,Object? phone = freezed,Object? name = null,Object? createdAt = 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
|
||||
as String,friendId: null == friendId ? _self.friendId : friendId // ignore: cast_nullable_to_non_nullable
|
||||
as String,phone: freezed == phone ? _self.phone : phone // ignore: cast_nullable_to_non_nullable
|
||||
as String?,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
||||
as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [FriendItemDto].
|
||||
extension FriendItemDtoPatterns on FriendItemDto {
|
||||
/// A variant of `map` that fallback to returning `orElse`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _FriendItemDto value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _FriendItemDto() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// Callbacks receives the raw object, upcasted.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case final Subclass2 value:
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _FriendItemDto value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _FriendItemDto():
|
||||
return $default(_that);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `map` that fallback to returning `null`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _FriendItemDto value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _FriendItemDto() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to an `orElse` callback.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String deviceId, String friendId, String? phone, String name, int createdAt)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _FriendItemDto() when $default != null:
|
||||
return $default(_that.id,_that.deviceId,_that.friendId,_that.phone,_that.name,_that.createdAt);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// As opposed to `map`, this offers destructuring.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case Subclass2(:final field2):
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String deviceId, String friendId, String? phone, String name, int createdAt) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _FriendItemDto():
|
||||
return $default(_that.id,_that.deviceId,_that.friendId,_that.phone,_that.name,_that.createdAt);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String deviceId, String friendId, String? phone, String name, int createdAt)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _FriendItemDto() when $default != null:
|
||||
return $default(_that.id,_that.deviceId,_that.friendId,_that.phone,_that.name,_that.createdAt);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
|
||||
class _FriendItemDto implements FriendItemDto {
|
||||
const _FriendItemDto({required this.id, required this.deviceId, required this.friendId, this.phone, required this.name, required this.createdAt});
|
||||
factory _FriendItemDto.fromJson(Map<String, dynamic> json) => _$FriendItemDtoFromJson(json);
|
||||
|
||||
@override final String id;
|
||||
@override final String deviceId;
|
||||
@override final String friendId;
|
||||
@override final String? phone;
|
||||
@override final String name;
|
||||
@override final int createdAt;
|
||||
|
||||
/// Create a copy of FriendItemDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$FriendItemDtoCopyWith<_FriendItemDto> get copyWith => __$FriendItemDtoCopyWithImpl<_FriendItemDto>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$FriendItemDtoToJson(this, );
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _FriendItemDto&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.friendId, friendId) || other.friendId == friendId)&&(identical(other.phone, phone) || other.phone == phone)&&(identical(other.name, name) || other.name == name)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,deviceId,friendId,phone,name,createdAt);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'FriendItemDto(id: $id, deviceId: $deviceId, friendId: $friendId, phone: $phone, name: $name, createdAt: $createdAt)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$FriendItemDtoCopyWith<$Res> implements $FriendItemDtoCopyWith<$Res> {
|
||||
factory _$FriendItemDtoCopyWith(_FriendItemDto value, $Res Function(_FriendItemDto) _then) = __$FriendItemDtoCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String id, String deviceId, String friendId, String? phone, String name, int createdAt
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$FriendItemDtoCopyWithImpl<$Res>
|
||||
implements _$FriendItemDtoCopyWith<$Res> {
|
||||
__$FriendItemDtoCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _FriendItemDto _self;
|
||||
final $Res Function(_FriendItemDto) _then;
|
||||
|
||||
/// Create a copy of FriendItemDto
|
||||
/// 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? friendId = null,Object? phone = freezed,Object? name = null,Object? createdAt = null,}) {
|
||||
return _then(_FriendItemDto(
|
||||
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,friendId: null == friendId ? _self.friendId : friendId // ignore: cast_nullable_to_non_nullable
|
||||
as String,phone: freezed == phone ? _self.phone : phone // ignore: cast_nullable_to_non_nullable
|
||||
as String?,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
|
||||
as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
@@ -0,0 +1,38 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'friends_response_dto.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_FriendsResponseDto _$FriendsResponseDtoFromJson(Map<String, dynamic> json) =>
|
||||
_FriendsResponseDto(
|
||||
total: (json['total'] as num).toInt(),
|
||||
items: (json['items'] as List<dynamic>)
|
||||
.map((e) => FriendItemDto.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$FriendsResponseDtoToJson(_FriendsResponseDto instance) =>
|
||||
<String, dynamic>{'total': instance.total, 'items': instance.items};
|
||||
|
||||
_FriendItemDto _$FriendItemDtoFromJson(Map<String, dynamic> json) =>
|
||||
_FriendItemDto(
|
||||
id: json['id'] as String,
|
||||
deviceId: json['deviceId'] as String,
|
||||
friendId: json['friendId'] as String,
|
||||
phone: json['phone'] as String?,
|
||||
name: json['name'] as String,
|
||||
createdAt: (json['createdAt'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$FriendItemDtoToJson(_FriendItemDto instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'deviceId': instance.deviceId,
|
||||
'friendId': instance.friendId,
|
||||
'phone': instance.phone,
|
||||
'name': instance.name,
|
||||
'createdAt': instance.createdAt,
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import 'presentation/friends_screen.dart';
|
||||
|
||||
class FriendsBuilder {
|
||||
const FriendsBuilder();
|
||||
|
||||
Page<void> buildPage(BuildContext context, GoRouterState state) {
|
||||
return MaterialPage<void>(
|
||||
key: state.pageKey,
|
||||
child: const FriendsScreen(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:device_management/src/features/friends/data/friend_entity.dart';
|
||||
import 'package:device_management/src/features/friends/presentation/providers/friends_controller.dart';
|
||||
import 'package:device_management/src/features/friends/presentation/providers/friends_provider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:legacy_ui/legacy_ui.dart';
|
||||
import 'package:sf_localizations/sf_localizations.dart';
|
||||
import 'package:sf_shared/sf_shared.dart';
|
||||
|
||||
class FriendsScreen extends ConsumerStatefulWidget {
|
||||
const FriendsScreen({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<FriendsScreen> createState() => _FriendsScreenState();
|
||||
}
|
||||
|
||||
class _FriendsScreenState extends ConsumerState<FriendsScreen> {
|
||||
bool _editMode = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final device = ref.watch(selectedDeviceProvider).value;
|
||||
|
||||
if (device == null) {
|
||||
return LegacyPageLayout(
|
||||
title: context.translate(I18n.makeFriends),
|
||||
body: const SizedBox.shrink(),
|
||||
);
|
||||
}
|
||||
|
||||
final friendsAsync = ref.watch(friendsProvider(device.identificator));
|
||||
|
||||
ref.listen(friendsControllerProvider, (previous, next) {
|
||||
if (next.hasError) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(context.translate(I18n.friendDeleteError)),
|
||||
backgroundColor: Theme.of(context).colorScheme.error,
|
||||
),
|
||||
);
|
||||
}
|
||||
if (previous?.isLoading == true && next.hasValue && !next.hasError) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(context.translate(I18n.friendDeleted))),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return LegacyPageLayout(
|
||||
title: context.translate(I18n.makeFriends),
|
||||
showEdit: true,
|
||||
onEditChange: () => setState(() => _editMode = !_editMode),
|
||||
body: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8),
|
||||
child: Text(
|
||||
context.translate(I18n.friendsMaxInfo),
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: friendsAsync.when(
|
||||
loading: () => const LegacyLoadingIndicator(),
|
||||
error: (error, _) => Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.error_outline,
|
||||
size: 64,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
error.toString(),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
fontSize: 14,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
data: (friends) {
|
||||
if (friends.isEmpty) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.people_outline,
|
||||
size: 64,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
context.translate(I18n.friendsEmpty),
|
||||
style: TextStyle(
|
||||
color:
|
||||
Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 4,
|
||||
),
|
||||
itemCount: friends.length,
|
||||
itemBuilder: (context, index) {
|
||||
final friend = friends[index];
|
||||
return _FriendTile(
|
||||
friend: friend,
|
||||
showDelete: _editMode,
|
||||
onDelete: () => _confirmDelete(
|
||||
context,
|
||||
deviceIdentificator: device.identificator,
|
||||
friend: friend,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _confirmDelete(
|
||||
BuildContext context, {
|
||||
required String deviceIdentificator,
|
||||
required FriendEntity friend,
|
||||
}) async {
|
||||
final confirmed = await showLegacyDialog<bool>(
|
||||
context: context,
|
||||
builder: (dialogContext) => AlertDialog(
|
||||
title: Text(context.translate(I18n.friendDeleteConfirm)),
|
||||
content: Text(friend.name),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(dialogContext, false),
|
||||
child: Text(context.translate(I18n.cancel)),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () => Navigator.pop(dialogContext, true),
|
||||
style: FilledButton.styleFrom(
|
||||
backgroundColor: Theme.of(context).colorScheme.error,
|
||||
),
|
||||
child: Text(context.translate(I18n.delete)),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
if (confirmed != true) return;
|
||||
ref.read(friendsControllerProvider.notifier).deleteFriend(
|
||||
deviceIdentificator: deviceIdentificator,
|
||||
friendId: friend.friendId,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _FriendTile extends StatelessWidget {
|
||||
final FriendEntity friend;
|
||||
final bool showDelete;
|
||||
final VoidCallback onDelete;
|
||||
|
||||
const _FriendTile({
|
||||
required this.friend,
|
||||
required this.showDelete,
|
||||
required this.onDelete,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final date = DateTime.fromMillisecondsSinceEpoch(friend.createdAt);
|
||||
final dateStr =
|
||||
'${date.day.toString().padLeft(2, '0')}/${date.month.toString().padLeft(2, '0')}/${date.year}';
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 2),
|
||||
child: ListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
leading: Image.asset(
|
||||
'assets/shared/images/iso_sf.png',
|
||||
width: 44,
|
||||
height: 44,
|
||||
),
|
||||
title: Text(
|
||||
friend.name,
|
||||
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w500),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
subtitle: Text(
|
||||
friend.phone ?? dateStr,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
trailing: showDelete
|
||||
? IconButton(
|
||||
icon: Icon(
|
||||
Icons.delete_outline,
|
||||
color: Theme.of(context).colorScheme.error,
|
||||
),
|
||||
onPressed: onDelete,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import 'package:device_management/src/features/friends/data/friends_datasource_provider.dart';
|
||||
import 'package:device_management/src/features/friends/presentation/providers/friends_provider.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'friends_controller.g.dart';
|
||||
|
||||
@riverpod
|
||||
class FriendsController extends _$FriendsController {
|
||||
@override
|
||||
FutureOr<void> build() {}
|
||||
|
||||
Future<bool> deleteFriend({
|
||||
required String deviceIdentificator,
|
||||
required String friendId,
|
||||
}) async {
|
||||
state = const AsyncLoading();
|
||||
state = await AsyncValue.guard(() async {
|
||||
await ref
|
||||
.read(friendsDatasourceProvider)
|
||||
.deleteFriend(
|
||||
deviceIdentificator: deviceIdentificator,
|
||||
friendId: friendId,
|
||||
);
|
||||
});
|
||||
if (!state.hasError) {
|
||||
ref.invalidate(friendsProvider);
|
||||
}
|
||||
return !state.hasError;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'friends_controller.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(FriendsController)
|
||||
const friendsControllerProvider = FriendsControllerProvider._();
|
||||
|
||||
final class FriendsControllerProvider
|
||||
extends $AsyncNotifierProvider<FriendsController, void> {
|
||||
const FriendsControllerProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'friendsControllerProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$friendsControllerHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
FriendsController create() => FriendsController();
|
||||
}
|
||||
|
||||
String _$friendsControllerHash() => r'7b4faf55a771ebb1386cfe43c045f2dbf986be77';
|
||||
|
||||
abstract class _$FriendsController extends $AsyncNotifier<void> {
|
||||
FutureOr<void> build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
build();
|
||||
final ref = this.ref as $Ref<AsyncValue<void>, void>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<AsyncValue<void>, void>,
|
||||
AsyncValue<void>,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import 'package:device_management/src/features/friends/data/friends_datasource_provider.dart';
|
||||
import 'package:device_management/src/features/friends/data/friend_entity.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'friends_provider.g.dart';
|
||||
|
||||
@riverpod
|
||||
Future<List<FriendEntity>> friends(
|
||||
Ref ref,
|
||||
String deviceIdentificator, {
|
||||
String? search,
|
||||
}) async {
|
||||
final friends = await ref
|
||||
.read(friendsDatasourceProvider)
|
||||
.getFriends(deviceIdentificator: deviceIdentificator, search: search);
|
||||
friends.sort((a, b) => b.createdAt.compareTo(a.createdAt));
|
||||
return friends;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'friends_provider.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(friends)
|
||||
const friendsProvider = FriendsFamily._();
|
||||
|
||||
final class FriendsProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
AsyncValue<List<FriendEntity>>,
|
||||
List<FriendEntity>,
|
||||
FutureOr<List<FriendEntity>>
|
||||
>
|
||||
with
|
||||
$FutureModifier<List<FriendEntity>>,
|
||||
$FutureProvider<List<FriendEntity>> {
|
||||
const FriendsProvider._({
|
||||
required FriendsFamily super.from,
|
||||
required (String, {String? search}) super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'friendsProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$friendsHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'friendsProvider'
|
||||
''
|
||||
'$argument';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$FutureProviderElement<List<FriendEntity>> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $FutureProviderElement(pointer);
|
||||
|
||||
@override
|
||||
FutureOr<List<FriendEntity>> create(Ref ref) {
|
||||
final argument = this.argument as (String, {String? search});
|
||||
return friends(ref, argument.$1, search: argument.search);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is FriendsProvider && other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return argument.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
String _$friendsHash() => r'd02a13d813bcc31fade65a9d7a1ed9670fce1b89';
|
||||
|
||||
final class FriendsFamily extends $Family
|
||||
with
|
||||
$FunctionalFamilyOverride<
|
||||
FutureOr<List<FriendEntity>>,
|
||||
(String, {String? search})
|
||||
> {
|
||||
const FriendsFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'friendsProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: true,
|
||||
);
|
||||
|
||||
FriendsProvider call(String deviceIdentificator, {String? search}) =>
|
||||
FriendsProvider._(
|
||||
argument: (deviceIdentificator, search: search),
|
||||
from: this,
|
||||
);
|
||||
|
||||
@override
|
||||
String toString() => r'friendsProvider';
|
||||
}
|
||||
@@ -42,7 +42,7 @@ final class VideocallControllerProvider
|
||||
}
|
||||
|
||||
String _$videocallControllerHash() =>
|
||||
r'72a9b2eac6a4fedbb7b8234c10ce5084d178dee4';
|
||||
r'e94071625d05927701912826102a5b526b72140b';
|
||||
|
||||
abstract class _$VideocallController extends $Notifier<VideocallState> {
|
||||
VideocallState build();
|
||||
|
||||
BIN
packages/design_system/assets/animations/birds_loading.gif
Normal file
BIN
packages/design_system/assets/animations/birds_loading.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.9 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 516 KiB |
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:sf_localizations/sf_localizations.dart';
|
||||
|
||||
class LegacyLoadingIndicator extends StatelessWidget {
|
||||
final double size;
|
||||
@@ -8,10 +9,23 @@ class LegacyLoadingIndicator extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Image.asset(
|
||||
'packages/design_system/assets/animations/loading_legacy.gif',
|
||||
width: size,
|
||||
height: size,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Image.asset(
|
||||
'packages/design_system/assets/animations/birds_loading.gif',
|
||||
width: size,
|
||||
height: size,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
context.translate(I18n.loadingText),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ class AppRoutes {
|
||||
static const callHistory = '$deviceManagement/call_history';
|
||||
static const backgroundImage = '$deviceManagement/background_image';
|
||||
static const videocall = '$deviceManagement/videocall';
|
||||
static const friends = '$deviceManagement/friends';
|
||||
|
||||
static const legacyLogin = '$legacy/login';
|
||||
static const legacySignup = '$legacy/signup';
|
||||
|
||||
@@ -998,6 +998,13 @@
|
||||
"logOutConfirm": "Möchten Sie sich wirklich abmelden?",
|
||||
"loginEmail": "(E-Mail)",
|
||||
"makeFriends": "Freunde finden",
|
||||
"friendsEmpty": "Noch keine Freunde",
|
||||
"friendDeleted": "Freund gelöscht",
|
||||
"friendDeleteError": "Fehler beim Löschen des Freundes",
|
||||
"friendDeleteConfirm": "Diesen Freund löschen?",
|
||||
"friendSearchHint": "Nach Name suchen",
|
||||
"friendsMaxInfo": "*Das Gerät kann sich mit bis zu vier Freunden verbinden",
|
||||
"loadingText": "Laden...",
|
||||
"male": "Männlich",
|
||||
"maximum": "Maximum",
|
||||
"minimum": "Minimum",
|
||||
|
||||
@@ -642,6 +642,13 @@
|
||||
"topApps": "Top apps",
|
||||
"appsSurveillance": "Apps surveillance",
|
||||
"makeFriends": "Make friends",
|
||||
"friendsEmpty": "No friends yet",
|
||||
"friendDeleted": "Friend deleted",
|
||||
"friendDeleteError": "Error deleting friend",
|
||||
"friendDeleteConfirm": "Delete this friend?",
|
||||
"friendSearchHint": "Search by name",
|
||||
"friendsMaxInfo": "*The device can connect with up to four friends",
|
||||
"loadingText": "Loading...",
|
||||
"locateDevicePlaySoundButton": "Play sound on device",
|
||||
"locateDeviceDescription": "Locate your device with a sound.",
|
||||
"locateDeviceInstructions": "1. Press the Play Sound button to activate the sound on the device.\n2. Press OK.\n3. The device will play a sound.\n4. The device will start sounding after receiving the instructions.",
|
||||
|
||||
@@ -643,6 +643,13 @@
|
||||
"topApps": "Apps más usadas",
|
||||
"appsSurveillance": "Supervisión de las aplicaciones",
|
||||
"makeFriends": "Hacer amigos",
|
||||
"friendsEmpty": "No hay amigos todavía",
|
||||
"friendDeleted": "Amigo eliminado",
|
||||
"friendDeleteError": "Error al eliminar amigo",
|
||||
"friendDeleteConfirm": "¿Eliminar este amigo?",
|
||||
"friendSearchHint": "Buscar por nombre",
|
||||
"friendsMaxInfo": "*El dispositivo podrá conectarse hasta con cuatro amigos",
|
||||
"loadingText": "Cargando...",
|
||||
"locateDevicePlaySoundButton": "Reproducir sonido en dispositivo",
|
||||
"locateDeviceDescription": "Localiza tu dispositivo con un sonido.",
|
||||
"locateDeviceInstructions": "1. Pulsa el botón Reproducir Sonido para activar el sonido en el dispositivo.\n2. Pulsa OK\n3. El dispositivo reproducirá un sonido\n4. El dispositivo comenzará a sonar después de recibir las instrucciones",
|
||||
|
||||
@@ -998,6 +998,13 @@
|
||||
"logOutConfirm": "Êtes-vous sûr de vouloir vous déconnecter ?",
|
||||
"loginEmail": "(E-mail)",
|
||||
"makeFriends": "Se faire des amis",
|
||||
"friendsEmpty": "Pas encore d'amis",
|
||||
"friendDeleted": "Ami supprimé",
|
||||
"friendDeleteError": "Erreur lors de la suppression de l'ami",
|
||||
"friendDeleteConfirm": "Supprimer cet ami ?",
|
||||
"friendSearchHint": "Rechercher par nom",
|
||||
"friendsMaxInfo": "*L'appareil peut se connecter avec jusqu'à quatre amis",
|
||||
"loadingText": "Chargement...",
|
||||
"male": "Homme",
|
||||
"maximum": "Maximum",
|
||||
"minimum": "Minimum",
|
||||
|
||||
@@ -998,6 +998,13 @@
|
||||
"logOutConfirm": "Sei sicuro di voler disconnetterti?",
|
||||
"loginEmail": "(Email)",
|
||||
"makeFriends": "Fare amicizia",
|
||||
"friendsEmpty": "Nessun amico ancora",
|
||||
"friendDeleted": "Amico eliminato",
|
||||
"friendDeleteError": "Errore durante l'eliminazione dell'amico",
|
||||
"friendDeleteConfirm": "Eliminare questo amico?",
|
||||
"friendSearchHint": "Cerca per nome",
|
||||
"friendsMaxInfo": "*Il dispositivo può connettersi con un massimo di quattro amici",
|
||||
"loadingText": "Caricamento...",
|
||||
"male": "Uomo",
|
||||
"maximum": "Massimo",
|
||||
"minimum": "Minimo",
|
||||
|
||||
@@ -998,6 +998,13 @@
|
||||
"logOutConfirm": "Tem certeza de que deseja sair?",
|
||||
"loginEmail": "(E-mail)",
|
||||
"makeFriends": "Fazer amigos",
|
||||
"friendsEmpty": "Ainda sem amigos",
|
||||
"friendDeleted": "Amigo eliminado",
|
||||
"friendDeleteError": "Erro ao eliminar amigo",
|
||||
"friendDeleteConfirm": "Eliminar este amigo?",
|
||||
"friendSearchHint": "Pesquisar por nome",
|
||||
"friendsMaxInfo": "*O dispositivo pode conectar-se com até quatro amigos",
|
||||
"loadingText": "Carregando...",
|
||||
"male": "Homem",
|
||||
"maximum": "Máximo",
|
||||
"minimum": "Mínimo",
|
||||
|
||||
@@ -665,6 +665,13 @@ class I18n {
|
||||
static const String loginSuccess = 'loginSuccess';
|
||||
static const String mainContactPhoneNumber = 'mainContactPhoneNumber';
|
||||
static const String makeFriends = 'makeFriends';
|
||||
static const String friendsEmpty = 'friendsEmpty';
|
||||
static const String friendDeleted = 'friendDeleted';
|
||||
static const String friendDeleteError = 'friendDeleteError';
|
||||
static const String friendDeleteConfirm = 'friendDeleteConfirm';
|
||||
static const String friendSearchHint = 'friendSearchHint';
|
||||
static const String friendsMaxInfo = 'friendsMaxInfo';
|
||||
static const String loadingText = 'loadingText';
|
||||
static const String male = 'male';
|
||||
static const String mapTitle = 'mapTitle';
|
||||
static const String maximum = 'maximum';
|
||||
|
||||
Reference in New Issue
Block a user