From 1cd18b002c383b6763da146a47c14887f3169638 Mon Sep 17 00:00:00 2001 From: aitorarana Date: Thu, 5 Feb 2026 17:51:52 +0100 Subject: [PATCH] added functions module and functions and contacts screens, state and use cases --- .idea/modules.xml | 4 +- .../mobile_app/lib/navigation/app_router.dart | 15 + apps/mobile_app/pubspec.yaml | 2 + modules/legacy/melos_legacy.iml | 5 +- .../functions_remote_datasource.dart | 5 + .../functions_remote_datasource_impl.dart | 82 +++++ .../functions_repository_impl.dart | 14 + .../repositories/functions_repository.dart | 5 + .../functions_remote_datasource_provider.dart | 9 + .../functions_repository_provider.dart | 9 + .../features/contacts/contacts_builder.dart | 18 + .../domain/entities/contact_list_entity.dart | 19 ++ .../entities/contact_list_entity.freezed.dart | 301 +++++++++++++++++ .../domain/entities/list_contact_entity.dart | 11 + .../entities/list_contact_entity.freezed.dart | 274 ++++++++++++++++ .../domain/get_contacts_use_case.dart | 5 + .../domain/get_contacts_use_case_impl.dart | 14 + .../presentation/contacts_screen.dart | 212 ++++++++++++ .../presentation/edit_contact_screen.dart | 0 .../providers/get_contacts_provider.dart | 9 + .../state/contacts_view_model.dart | 56 ++++ .../state/contacts_view_state.dart | 16 + .../state/contacts_view_state.freezed.dart | 310 ++++++++++++++++++ .../features/functions/functions_builder.dart | 18 + .../features/functions/functions_screen.dart | 179 ++++++++++ .../features/hub/presentation/hub_screen.dart | 2 +- packages/navigation/lib/app_routes.dart | 3 + .../lib/src/generated/i18n.dart | 21 ++ 28 files changed, 1615 insertions(+), 3 deletions(-) create mode 100644 modules/legacy/modules/functions/lib/src/core/data/datasources/functions_remote_datasource.dart create mode 100644 modules/legacy/modules/functions/lib/src/core/data/datasources/functions_remote_datasource_impl.dart create mode 100644 modules/legacy/modules/functions/lib/src/core/data/repositories/functions_repository_impl.dart create mode 100644 modules/legacy/modules/functions/lib/src/core/domain/repositories/functions_repository.dart create mode 100644 modules/legacy/modules/functions/lib/src/core/providers/functions_remote_datasource_provider.dart create mode 100644 modules/legacy/modules/functions/lib/src/core/providers/functions_repository_provider.dart create mode 100644 modules/legacy/modules/functions/lib/src/features/contacts/contacts_builder.dart create mode 100644 modules/legacy/modules/functions/lib/src/features/contacts/domain/entities/contact_list_entity.dart create mode 100644 modules/legacy/modules/functions/lib/src/features/contacts/domain/entities/contact_list_entity.freezed.dart create mode 100644 modules/legacy/modules/functions/lib/src/features/contacts/domain/entities/list_contact_entity.dart create mode 100644 modules/legacy/modules/functions/lib/src/features/contacts/domain/entities/list_contact_entity.freezed.dart create mode 100644 modules/legacy/modules/functions/lib/src/features/contacts/domain/get_contacts_use_case.dart create mode 100644 modules/legacy/modules/functions/lib/src/features/contacts/domain/get_contacts_use_case_impl.dart create mode 100644 modules/legacy/modules/functions/lib/src/features/contacts/presentation/contacts_screen.dart create mode 100644 modules/legacy/modules/functions/lib/src/features/contacts/presentation/edit_contact_screen.dart create mode 100644 modules/legacy/modules/functions/lib/src/features/contacts/presentation/providers/get_contacts_provider.dart create mode 100644 modules/legacy/modules/functions/lib/src/features/contacts/presentation/state/contacts_view_model.dart create mode 100644 modules/legacy/modules/functions/lib/src/features/contacts/presentation/state/contacts_view_state.dart create mode 100644 modules/legacy/modules/functions/lib/src/features/contacts/presentation/state/contacts_view_state.freezed.dart create mode 100644 modules/legacy/modules/functions/lib/src/features/functions/functions_builder.dart create mode 100644 modules/legacy/modules/functions/lib/src/features/functions/functions_screen.dart diff --git a/.idea/modules.xml b/.idea/modules.xml index cfa0d987..b7aa4bbc 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,17 +2,19 @@ + + + - diff --git a/apps/mobile_app/lib/navigation/app_router.dart b/apps/mobile_app/lib/navigation/app_router.dart index 485f4469..e28987b5 100644 --- a/apps/mobile_app/lib/navigation/app_router.dart +++ b/apps/mobile_app/lib/navigation/app_router.dart @@ -1,4 +1,5 @@ import 'package:auth/auth.dart'; +import 'package:functions/functions.dart'; import 'package:legacy_dashboard_shell/legacy_dashboard_builder.dart'; import 'package:dashboard_shell/dashboard_builder.dart'; import 'package:flutter/material.dart'; @@ -40,8 +41,22 @@ void configureAppRouter() { ), ], ), + StatefulShellBranch( + routes: [ + GoRoute( + path: AppRoutes.dashboardFunctions, + name: 'functions', + pageBuilder: FunctionsBuilder().buildPage, + ), + ], + ), ], ), + GoRoute( + path: AppRoutes.contacts, + name: 'contacts', + pageBuilder: ContactsBuilder().buildPage, + ), GoRoute( path: AppRoutes.login, diff --git a/apps/mobile_app/pubspec.yaml b/apps/mobile_app/pubspec.yaml index 9fdc39d3..4e4247a9 100644 --- a/apps/mobile_app/pubspec.yaml +++ b/apps/mobile_app/pubspec.yaml @@ -53,6 +53,8 @@ dependencies: path: ../../modules/legacy/modules/legacy_dashboard_shell splash: path: ../../modules/splash + functions: + path: ../../modules/legacy/modules/functions #packages dependencies go here navigation: path: ../../packages/navigation diff --git a/modules/legacy/melos_legacy.iml b/modules/legacy/melos_legacy.iml index 26a45e79..e8a4d511 100644 --- a/modules/legacy/melos_legacy.iml +++ b/modules/legacy/melos_legacy.iml @@ -17,10 +17,13 @@ + + + - + \ No newline at end of file diff --git a/modules/legacy/modules/functions/lib/src/core/data/datasources/functions_remote_datasource.dart b/modules/legacy/modules/functions/lib/src/core/data/datasources/functions_remote_datasource.dart new file mode 100644 index 00000000..bae23bbc --- /dev/null +++ b/modules/legacy/modules/functions/lib/src/core/data/datasources/functions_remote_datasource.dart @@ -0,0 +1,5 @@ +import 'package:functions/src/features/contacts/domain/entities/contact_list_entity.dart'; + +abstract class FunctionsRemoteDatasource { + Future getContacts({required String deviceId}); +} diff --git a/modules/legacy/modules/functions/lib/src/core/data/datasources/functions_remote_datasource_impl.dart b/modules/legacy/modules/functions/lib/src/core/data/datasources/functions_remote_datasource_impl.dart new file mode 100644 index 00000000..ffef59af --- /dev/null +++ b/modules/legacy/modules/functions/lib/src/core/data/datasources/functions_remote_datasource_impl.dart @@ -0,0 +1,82 @@ +import 'dart:convert'; + +import 'package:dio/dio.dart'; +// import 'package:flutter/material.dart'; +import 'package:functions/src/core/data/datasources/functions_remote_datasource.dart'; +import 'package:functions/src/features/contacts/domain/entities/contact_list_entity.dart'; +import 'package:functions/src/features/contacts/domain/entities/list_contact_entity.dart'; +import 'package:sf_infrastructure/sf_infrastructure.dart'; + +class FunctionsRemoteDatasourceImpl implements FunctionsRemoteDatasource { + FunctionsRemoteDatasourceImpl(this._repository); + + final QuestiaRepository _repository; + + @override + Future getContacts({required String deviceId}) async { + /*try { + final response = await _repository.post>( + '/devices/$deviceId/contact-lists', + ); + + final data = response.data; + if (data == null || data.isEmpty) { + throw Exception('Empty response from /devices/:deviceId/contact-lists'); + } + + final model = GetContactsResponseModel.fromJson(data); + return model.toEntity(); + } on DioException catch (error) { + throw _mapDioError(error, defaultMessage: 'Error to get contacts'); + }*/ + return ContactListEntity( + id: 'id', + delegationId: 'delegationId', + userId: 'userId', + groupId: 'groupId', + deviceId: 'deviceId', + type: 'type', + contacts: [ + ListContactEntity(name: 'Ana', phone: '111111111'), + ListContactEntity(name: 'Carlos', phone: '222222222'), + ], + createdAt: 'createdAt', + updatedAt: 'updatedAt' + ); + } +} + +Exception _mapDioError(DioException error, {required String defaultMessage}) { + final apiMsg = _extractApiMessage(error.response?.data); + final msg = apiMsg ?? error.message ?? defaultMessage; + return Exception(msg); +} + +String? _extractApiMessage(Object? data) { + if (data == null) return null; + + if (data is Map) { + final errorObj = data['error']; + if (errorObj is Map && errorObj['message'] is String) { + return (errorObj['message'] as String).trim(); + } + if (data['message'] is String) { + return (data['message'] as String).trim(); + } + return null; + } + + if (data is String) { + final raw = data.trim(); + if (raw.isEmpty) return null; + + try { + final decoded = jsonDecode(raw); + return _extractApiMessage(decoded); + } catch (_) { + return raw; + } + } + + return null; +} diff --git a/modules/legacy/modules/functions/lib/src/core/data/repositories/functions_repository_impl.dart b/modules/legacy/modules/functions/lib/src/core/data/repositories/functions_repository_impl.dart new file mode 100644 index 00000000..4ee55fae --- /dev/null +++ b/modules/legacy/modules/functions/lib/src/core/data/repositories/functions_repository_impl.dart @@ -0,0 +1,14 @@ +import 'package:functions/src/core/data/datasources/functions_remote_datasource.dart'; +import 'package:functions/src/core/domain/repositories/functions_repository.dart'; +import 'package:functions/src/features/contacts/domain/entities/contact_list_entity.dart'; + +class FunctionsRepositoryImpl implements FunctionsRepository { + const FunctionsRepositoryImpl(this._remote); + + final FunctionsRemoteDatasource _remote; + + @override + Future getContacts({required String deviceId}) { + return _remote.getContacts(deviceId: deviceId); + } +} diff --git a/modules/legacy/modules/functions/lib/src/core/domain/repositories/functions_repository.dart b/modules/legacy/modules/functions/lib/src/core/domain/repositories/functions_repository.dart new file mode 100644 index 00000000..3df7fc4e --- /dev/null +++ b/modules/legacy/modules/functions/lib/src/core/domain/repositories/functions_repository.dart @@ -0,0 +1,5 @@ +import 'package:functions/src/features/contacts/domain/entities/contact_list_entity.dart'; + +abstract class FunctionsRepository { + Future getContacts({required String deviceId}); +} diff --git a/modules/legacy/modules/functions/lib/src/core/providers/functions_remote_datasource_provider.dart b/modules/legacy/modules/functions/lib/src/core/providers/functions_remote_datasource_provider.dart new file mode 100644 index 00000000..062ca5d4 --- /dev/null +++ b/modules/legacy/modules/functions/lib/src/core/providers/functions_remote_datasource_provider.dart @@ -0,0 +1,9 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:functions/src/core/data/datasources/functions_remote_datasource.dart'; +import 'package:functions/src/core/data/datasources/functions_remote_datasource_impl.dart'; +import 'package:sf_infrastructure/sf_infrastructure.dart'; + +final functionsRemoteDatasourceProvider = Provider((ref) { + final questiaRepository = getIt(); + return FunctionsRemoteDatasourceImpl(questiaRepository); +}); diff --git a/modules/legacy/modules/functions/lib/src/core/providers/functions_repository_provider.dart b/modules/legacy/modules/functions/lib/src/core/providers/functions_repository_provider.dart new file mode 100644 index 00000000..325fa7f8 --- /dev/null +++ b/modules/legacy/modules/functions/lib/src/core/providers/functions_repository_provider.dart @@ -0,0 +1,9 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:functions/src/core/providers/functions_remote_datasource_provider.dart'; +import 'package:functions/src/core/data/repositories/functions_repository_impl.dart'; +import 'package:functions/src/core/domain/repositories/functions_repository.dart'; + +final functionsRepositoryProvider = Provider((ref) { + final remote = ref.read(functionsRemoteDatasourceProvider); + return FunctionsRepositoryImpl(remote); +}); diff --git a/modules/legacy/modules/functions/lib/src/features/contacts/contacts_builder.dart b/modules/legacy/modules/functions/lib/src/features/contacts/contacts_builder.dart new file mode 100644 index 00000000..df0822e7 --- /dev/null +++ b/modules/legacy/modules/functions/lib/src/features/contacts/contacts_builder.dart @@ -0,0 +1,18 @@ +import 'presentation/contacts_screen.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:get_it/get_it.dart'; +import 'package:navigation/navigation.dart'; + +class ContactsBuilder { + const ContactsBuilder(); + + Page buildPage(BuildContext context, GoRouterState state) { + final NavigationContract navigationContract = GetIt.I(); + + return MaterialPage( + key: state.pageKey, + child: ContactsScreen(navigationContract: navigationContract), + ); + } +} diff --git a/modules/legacy/modules/functions/lib/src/features/contacts/domain/entities/contact_list_entity.dart b/modules/legacy/modules/functions/lib/src/features/contacts/domain/entities/contact_list_entity.dart new file mode 100644 index 00000000..ba87d9eb --- /dev/null +++ b/modules/legacy/modules/functions/lib/src/features/contacts/domain/entities/contact_list_entity.dart @@ -0,0 +1,19 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:functions/src/features/contacts/domain/entities/list_contact_entity.dart'; + +part 'contact_list_entity.freezed.dart'; + +@freezed +abstract class ContactListEntity with _$ContactListEntity { + const factory ContactListEntity({ + required String id, + required String delegationId, + required String userId, + required String groupId, + required String deviceId, + required String type, + required List contacts, + required String createdAt, + required String updatedAt + }) = _ContactListEntity; +} diff --git a/modules/legacy/modules/functions/lib/src/features/contacts/domain/entities/contact_list_entity.freezed.dart b/modules/legacy/modules/functions/lib/src/features/contacts/domain/entities/contact_list_entity.freezed.dart new file mode 100644 index 00000000..a32a2dea --- /dev/null +++ b/modules/legacy/modules/functions/lib/src/features/contacts/domain/entities/contact_list_entity.freezed.dart @@ -0,0 +1,301 @@ +// 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 'contact_list_entity.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; +/// @nodoc +mixin _$ContactListEntity { + + String get id; String get delegationId; String get userId; String get groupId; String get deviceId; String get type; List get contacts; String get createdAt; String get updatedAt; +/// Create a copy of ContactListEntity +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$ContactListEntityCopyWith get copyWith => _$ContactListEntityCopyWithImpl(this as ContactListEntity, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is ContactListEntity&&(identical(other.id, id) || other.id == id)&&(identical(other.delegationId, delegationId) || other.delegationId == delegationId)&&(identical(other.userId, userId) || other.userId == userId)&&(identical(other.groupId, groupId) || other.groupId == groupId)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.contacts, contacts)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)); +} + + +@override +int get hashCode => Object.hash(runtimeType,id,delegationId,userId,groupId,deviceId,type,const DeepCollectionEquality().hash(contacts),createdAt,updatedAt); + +@override +String toString() { + return 'ContactListEntity(id: $id, delegationId: $delegationId, userId: $userId, groupId: $groupId, deviceId: $deviceId, type: $type, contacts: $contacts, createdAt: $createdAt, updatedAt: $updatedAt)'; +} + + +} + +/// @nodoc +abstract mixin class $ContactListEntityCopyWith<$Res> { + factory $ContactListEntityCopyWith(ContactListEntity value, $Res Function(ContactListEntity) _then) = _$ContactListEntityCopyWithImpl; +@useResult +$Res call({ + String id, String delegationId, String userId, String groupId, String deviceId, String type, List contacts, String createdAt, String updatedAt +}); + + + + +} +/// @nodoc +class _$ContactListEntityCopyWithImpl<$Res> + implements $ContactListEntityCopyWith<$Res> { + _$ContactListEntityCopyWithImpl(this._self, this._then); + + final ContactListEntity _self; + final $Res Function(ContactListEntity) _then; + +/// Create a copy of ContactListEntity +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? delegationId = null,Object? userId = null,Object? groupId = null,Object? deviceId = null,Object? type = null,Object? contacts = null,Object? createdAt = null,Object? updatedAt = null,}) { + return _then(_self.copyWith( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,delegationId: null == delegationId ? _self.delegationId : delegationId // ignore: cast_nullable_to_non_nullable +as String,userId: null == userId ? _self.userId : userId // ignore: cast_nullable_to_non_nullable +as String,groupId: null == groupId ? _self.groupId : groupId // ignore: cast_nullable_to_non_nullable +as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable +as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable +as String,contacts: null == contacts ? _self.contacts : contacts // ignore: cast_nullable_to_non_nullable +as List,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as String,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable +as String, + )); +} + +} + + +/// Adds pattern-matching-related methods to [ContactListEntity]. +extension ContactListEntityPatterns on ContactListEntity { +/// 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 Function( _ContactListEntity value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _ContactListEntity() 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 Function( _ContactListEntity value) $default,){ +final _that = this; +switch (_that) { +case _ContactListEntity(): +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? Function( _ContactListEntity value)? $default,){ +final _that = this; +switch (_that) { +case _ContactListEntity() 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 Function( String id, String delegationId, String userId, String groupId, String deviceId, String type, List contacts, String createdAt, String updatedAt)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _ContactListEntity() when $default != null: +return $default(_that.id,_that.delegationId,_that.userId,_that.groupId,_that.deviceId,_that.type,_that.contacts,_that.createdAt,_that.updatedAt);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 Function( String id, String delegationId, String userId, String groupId, String deviceId, String type, List contacts, String createdAt, String updatedAt) $default,) {final _that = this; +switch (_that) { +case _ContactListEntity(): +return $default(_that.id,_that.delegationId,_that.userId,_that.groupId,_that.deviceId,_that.type,_that.contacts,_that.createdAt,_that.updatedAt);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? Function( String id, String delegationId, String userId, String groupId, String deviceId, String type, List contacts, String createdAt, String updatedAt)? $default,) {final _that = this; +switch (_that) { +case _ContactListEntity() when $default != null: +return $default(_that.id,_that.delegationId,_that.userId,_that.groupId,_that.deviceId,_that.type,_that.contacts,_that.createdAt,_that.updatedAt);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _ContactListEntity implements ContactListEntity { + const _ContactListEntity({required this.id, required this.delegationId, required this.userId, required this.groupId, required this.deviceId, required this.type, required final List contacts, required this.createdAt, required this.updatedAt}): _contacts = contacts; + + +@override final String id; +@override final String delegationId; +@override final String userId; +@override final String groupId; +@override final String deviceId; +@override final String type; + final List _contacts; +@override List get contacts { + if (_contacts is EqualUnmodifiableListView) return _contacts; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_contacts); +} + +@override final String createdAt; +@override final String updatedAt; + +/// Create a copy of ContactListEntity +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$ContactListEntityCopyWith<_ContactListEntity> get copyWith => __$ContactListEntityCopyWithImpl<_ContactListEntity>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _ContactListEntity&&(identical(other.id, id) || other.id == id)&&(identical(other.delegationId, delegationId) || other.delegationId == delegationId)&&(identical(other.userId, userId) || other.userId == userId)&&(identical(other.groupId, groupId) || other.groupId == groupId)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._contacts, _contacts)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)); +} + + +@override +int get hashCode => Object.hash(runtimeType,id,delegationId,userId,groupId,deviceId,type,const DeepCollectionEquality().hash(_contacts),createdAt,updatedAt); + +@override +String toString() { + return 'ContactListEntity(id: $id, delegationId: $delegationId, userId: $userId, groupId: $groupId, deviceId: $deviceId, type: $type, contacts: $contacts, createdAt: $createdAt, updatedAt: $updatedAt)'; +} + + +} + +/// @nodoc +abstract mixin class _$ContactListEntityCopyWith<$Res> implements $ContactListEntityCopyWith<$Res> { + factory _$ContactListEntityCopyWith(_ContactListEntity value, $Res Function(_ContactListEntity) _then) = __$ContactListEntityCopyWithImpl; +@override @useResult +$Res call({ + String id, String delegationId, String userId, String groupId, String deviceId, String type, List contacts, String createdAt, String updatedAt +}); + + + + +} +/// @nodoc +class __$ContactListEntityCopyWithImpl<$Res> + implements _$ContactListEntityCopyWith<$Res> { + __$ContactListEntityCopyWithImpl(this._self, this._then); + + final _ContactListEntity _self; + final $Res Function(_ContactListEntity) _then; + +/// Create a copy of ContactListEntity +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? delegationId = null,Object? userId = null,Object? groupId = null,Object? deviceId = null,Object? type = null,Object? contacts = null,Object? createdAt = null,Object? updatedAt = null,}) { + return _then(_ContactListEntity( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,delegationId: null == delegationId ? _self.delegationId : delegationId // ignore: cast_nullable_to_non_nullable +as String,userId: null == userId ? _self.userId : userId // ignore: cast_nullable_to_non_nullable +as String,groupId: null == groupId ? _self.groupId : groupId // ignore: cast_nullable_to_non_nullable +as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable +as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable +as String,contacts: null == contacts ? _self._contacts : contacts // ignore: cast_nullable_to_non_nullable +as List,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as String,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable +as String, + )); +} + + +} + +// dart format on diff --git a/modules/legacy/modules/functions/lib/src/features/contacts/domain/entities/list_contact_entity.dart b/modules/legacy/modules/functions/lib/src/features/contacts/domain/entities/list_contact_entity.dart new file mode 100644 index 00000000..32bcab66 --- /dev/null +++ b/modules/legacy/modules/functions/lib/src/features/contacts/domain/entities/list_contact_entity.dart @@ -0,0 +1,11 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'list_contact_entity.freezed.dart'; + +@freezed +abstract class ListContactEntity with _$ListContactEntity { + const factory ListContactEntity({ + required String name, + required String phone, + }) = _ListContactEntity; +} diff --git a/modules/legacy/modules/functions/lib/src/features/contacts/domain/entities/list_contact_entity.freezed.dart b/modules/legacy/modules/functions/lib/src/features/contacts/domain/entities/list_contact_entity.freezed.dart new file mode 100644 index 00000000..efd95bd7 --- /dev/null +++ b/modules/legacy/modules/functions/lib/src/features/contacts/domain/entities/list_contact_entity.freezed.dart @@ -0,0 +1,274 @@ +// 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 'list_contact_entity.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; +/// @nodoc +mixin _$ListContactEntity { + + String get name; String get phone; +/// Create a copy of ListContactEntity +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$ListContactEntityCopyWith get copyWith => _$ListContactEntityCopyWithImpl(this as ListContactEntity, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is ListContactEntity&&(identical(other.name, name) || other.name == name)&&(identical(other.phone, phone) || other.phone == phone)); +} + + +@override +int get hashCode => Object.hash(runtimeType,name,phone); + +@override +String toString() { + return 'ListContactEntity(name: $name, phone: $phone)'; +} + + +} + +/// @nodoc +abstract mixin class $ListContactEntityCopyWith<$Res> { + factory $ListContactEntityCopyWith(ListContactEntity value, $Res Function(ListContactEntity) _then) = _$ListContactEntityCopyWithImpl; +@useResult +$Res call({ + String name, String phone +}); + + + + +} +/// @nodoc +class _$ListContactEntityCopyWithImpl<$Res> + implements $ListContactEntityCopyWith<$Res> { + _$ListContactEntityCopyWithImpl(this._self, this._then); + + final ListContactEntity _self; + final $Res Function(ListContactEntity) _then; + +/// Create a copy of ListContactEntity +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? name = null,Object? phone = null,}) { + return _then(_self.copyWith( +name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String,phone: null == phone ? _self.phone : phone // ignore: cast_nullable_to_non_nullable +as String, + )); +} + +} + + +/// Adds pattern-matching-related methods to [ListContactEntity]. +extension ListContactEntityPatterns on ListContactEntity { +/// 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 Function( _ListContactEntity value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _ListContactEntity() 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 Function( _ListContactEntity value) $default,){ +final _that = this; +switch (_that) { +case _ListContactEntity(): +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? Function( _ListContactEntity value)? $default,){ +final _that = this; +switch (_that) { +case _ListContactEntity() 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 Function( String name, String phone)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _ListContactEntity() when $default != null: +return $default(_that.name,_that.phone);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 Function( String name, String phone) $default,) {final _that = this; +switch (_that) { +case _ListContactEntity(): +return $default(_that.name,_that.phone);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? Function( String name, String phone)? $default,) {final _that = this; +switch (_that) { +case _ListContactEntity() when $default != null: +return $default(_that.name,_that.phone);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _ListContactEntity implements ListContactEntity { + const _ListContactEntity({required this.name, required this.phone}); + + +@override final String name; +@override final String phone; + +/// Create a copy of ListContactEntity +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$ListContactEntityCopyWith<_ListContactEntity> get copyWith => __$ListContactEntityCopyWithImpl<_ListContactEntity>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _ListContactEntity&&(identical(other.name, name) || other.name == name)&&(identical(other.phone, phone) || other.phone == phone)); +} + + +@override +int get hashCode => Object.hash(runtimeType,name,phone); + +@override +String toString() { + return 'ListContactEntity(name: $name, phone: $phone)'; +} + + +} + +/// @nodoc +abstract mixin class _$ListContactEntityCopyWith<$Res> implements $ListContactEntityCopyWith<$Res> { + factory _$ListContactEntityCopyWith(_ListContactEntity value, $Res Function(_ListContactEntity) _then) = __$ListContactEntityCopyWithImpl; +@override @useResult +$Res call({ + String name, String phone +}); + + + + +} +/// @nodoc +class __$ListContactEntityCopyWithImpl<$Res> + implements _$ListContactEntityCopyWith<$Res> { + __$ListContactEntityCopyWithImpl(this._self, this._then); + + final _ListContactEntity _self; + final $Res Function(_ListContactEntity) _then; + +/// Create a copy of ListContactEntity +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? name = null,Object? phone = null,}) { + return _then(_ListContactEntity( +name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String,phone: null == phone ? _self.phone : phone // ignore: cast_nullable_to_non_nullable +as String, + )); +} + + +} + +// dart format on diff --git a/modules/legacy/modules/functions/lib/src/features/contacts/domain/get_contacts_use_case.dart b/modules/legacy/modules/functions/lib/src/features/contacts/domain/get_contacts_use_case.dart new file mode 100644 index 00000000..bf0dde3f --- /dev/null +++ b/modules/legacy/modules/functions/lib/src/features/contacts/domain/get_contacts_use_case.dart @@ -0,0 +1,5 @@ +import 'package:functions/src/features/contacts/domain/entities/contact_list_entity.dart'; + +abstract class GetContactsUseCase { + Future getContacts({required String deviceId}); +} diff --git a/modules/legacy/modules/functions/lib/src/features/contacts/domain/get_contacts_use_case_impl.dart b/modules/legacy/modules/functions/lib/src/features/contacts/domain/get_contacts_use_case_impl.dart new file mode 100644 index 00000000..250f0cfb --- /dev/null +++ b/modules/legacy/modules/functions/lib/src/features/contacts/domain/get_contacts_use_case_impl.dart @@ -0,0 +1,14 @@ +import 'package:functions/src/core/domain/repositories/functions_repository.dart'; +import 'package:functions/src/features/contacts/domain/entities/contact_list_entity.dart'; +import 'package:functions/src/features/contacts/domain/get_contacts_use_case.dart'; + +class GetContactsUseCaseImpl implements GetContactsUseCase { + GetContactsUseCaseImpl(this._repository); + + final FunctionsRepository _repository; + + @override + Future getContacts({required String deviceId}) { + return _repository.getContacts(deviceId: deviceId); + } +} diff --git a/modules/legacy/modules/functions/lib/src/features/contacts/presentation/contacts_screen.dart b/modules/legacy/modules/functions/lib/src/features/contacts/presentation/contacts_screen.dart new file mode 100644 index 00000000..ea57f14b --- /dev/null +++ b/modules/legacy/modules/functions/lib/src/features/contacts/presentation/contacts_screen.dart @@ -0,0 +1,212 @@ +import 'package:design_system/design_system.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:functions/src/features/contacts/domain/entities/list_contact_entity.dart'; +import 'package:functions/src/features/contacts/presentation/state/contacts_view_model.dart'; +import 'package:navigation/navigation.dart'; +import 'package:sf_localizations/sf_localizations.dart'; +import 'package:utils/utils.dart'; + +class ContactsScreen extends ConsumerWidget { + final NavigationContract navigationContract; + + const ContactsScreen({super.key, required this.navigationContract}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final vm = ref.read(contactsViewModelProvider.notifier); + final state = ref.watch(contactsViewModelProvider); + + final theme = ref.watch(themePortProvider); + + return Scaffold( + backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary), + body: SafeArea( + child: Column( + children: [ + Container( + padding: SizeUtils.getByScreen( + small: EdgeInsets.symmetric(horizontal: 22, vertical: 10), + big: EdgeInsets.symmetric(horizontal: 21, vertical: 8) + ), + child: Stack( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + IconButton(onPressed: () {Navigator.pop(context);}, + icon: Icon(Icons.arrow_back)), + if (!state.isEditing) ...[ + DecoratedBox( + decoration: BoxDecoration( + color: Color(0xFF588EA5), + shape: BoxShape.circle + ), + child: IconButton(onPressed: vm.toggleIsEditing, + icon: Icon(Icons.edit_outlined, + color: Colors.white, + size: SizeUtils.getByScreen(small: 30, big: 28), + ) + ), + ) + ] + ], + ), + Center( + child: Text(context.translate('Agenda'), + style: TextStyle( + fontSize: SizeUtils.getByScreen(small: 28, big: 27) + ), + ) + ) + ], + ), + ), + SizedBox(height: SizeUtils.getByScreen(small: 20, big: 18)), + Expanded( child: Container( + padding: SizeUtils.getByScreen( + small: EdgeInsets.symmetric(horizontal: 22, vertical: 10), + big: EdgeInsets.symmetric(horizontal: 21, vertical: 8) + ), + child: ListView.separated( + itemBuilder: (BuildContext context, int index)=>ContactCard( + contact: state.contactList!.contacts[index], + isEditing: state.isEditing, + ), + separatorBuilder: (BuildContext context, int index)=>SizedBox( + height: SizeUtils.getByScreen(small: 18, big: 17) + ), + itemCount: state.contactList?.contacts.length ?? 0 + ), + )), + if (state.isEditing) ...[ + Container( + padding: SizeUtils.getByScreen( + small: EdgeInsets.symmetric(horizontal: 26, vertical: 14), + big: EdgeInsets.symmetric(horizontal: 24, vertical: 12) + ), + ), + ] + ], + ) + ), + ); + } +} + +class ContactCard extends ConsumerWidget { + + final ListContactEntity contact; + final bool isEditing; + + const ContactCard({ + required this.contact, + required this.isEditing, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final theme = ref.read(themePortProvider); + + return Container( + padding: SizeUtils.getByScreen( + small: EdgeInsets.symmetric(horizontal: 22, vertical: 10), + big: EdgeInsets.symmetric(horizontal: 21, vertical: 8) + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(SizeUtils.getByScreen(small: 12, big: 18))), + color: theme.getColorFor(ThemeCode.backgroundSecondary), + ), + child: Row( + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: theme.getColorFor(ThemeCode.backgroundPrimary), + ), + padding: EdgeInsets.all(SizeUtils.getByScreen(small: 4, big: 12)), + child: Icon(SFIcons.account, + size: SizeUtils.getByScreen(small: 40, big: 44), + color: Color(0xFF588EA5), + weight: 30, + ), + ), + SizedBox(width: SizeUtils.getByScreen(small: 16, big: 15)), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(contact.name, + style: TextStyle( + fontSize: SizeUtils.getByScreen(small: 18, big: 19), + fontWeight: FontWeight.w500 + ) + ), + Text(contact.phone, + style: TextStyle( + fontSize: SizeUtils.getByScreen(small: 14, big: 13), + ) + ) + ], + ) + ), + if (isEditing) ...[ + DecoratedBox( + decoration: BoxDecoration( + color: Color(0xFFFF5D52), + borderRadius: BorderRadius.all(Radius.circular(12)), + ), + child: IconButton( + onPressed: (){showDialog(context: context, builder: (context)=>Dialog( + child: Container( + padding: SizeUtils.getByScreen( + small: EdgeInsets.symmetric(horizontal: 32, vertical: 30), + big: EdgeInsets.symmetric(horizontal: 30, vertical: 28) + ), + width: SizeUtils.getByScreen(small: 360, big: 350), + height: SizeUtils.getByScreen(small: 195, big: 185), + child: Column( + children: [ + Text(context.translate(I18n.legacyDeleteUserDialog), + textAlign: TextAlign.center, + style: TextStyle(fontSize: SizeUtils.getByScreen(small: 19, big: 18)), + ), + SizedBox(height: SizeUtils.getByScreen(small: 28, big: 27)), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded(child: PrimaryButton( + onPressed: (){Navigator.pop(context);}, + text: context.translate(I18n.legacyCancel), + color: Color(0xFF588EA5), + height: SizeUtils.getByScreen(small: 38, big: 36), + radius: SizeUtils.getByScreen(small: 32, big: 34), + )), + SizedBox(width: SizeUtils.getByScreen(small: 4, big: 16)), + Expanded(child: PrimaryButton( + onPressed: (){ + Navigator.pop(context); + }, + text: context.translate(I18n.legacyDelete), + color: Color(0xFF588EA5), + height: SizeUtils.getByScreen(small: 38, big: 36), + radius: SizeUtils.getByScreen(small: 32, big: 34), + )) + ], + ) + ], + ), + ), + ));}, + icon: Icon( + Icons.close, + color: Colors.white, + ), + ), + ), + ] + ], + ), + ); + } +} \ No newline at end of file diff --git a/modules/legacy/modules/functions/lib/src/features/contacts/presentation/edit_contact_screen.dart b/modules/legacy/modules/functions/lib/src/features/contacts/presentation/edit_contact_screen.dart new file mode 100644 index 00000000..e69de29b diff --git a/modules/legacy/modules/functions/lib/src/features/contacts/presentation/providers/get_contacts_provider.dart b/modules/legacy/modules/functions/lib/src/features/contacts/presentation/providers/get_contacts_provider.dart new file mode 100644 index 00000000..913d152f --- /dev/null +++ b/modules/legacy/modules/functions/lib/src/features/contacts/presentation/providers/get_contacts_provider.dart @@ -0,0 +1,9 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:functions/src/core/providers/functions_repository_provider.dart'; +import 'package:functions/src/features/contacts/domain/get_contacts_use_case.dart'; +import 'package:functions/src/features/contacts/domain/get_contacts_use_case_impl.dart'; + +final getContactsUseCaseProvider = Provider.autoDispose((ref) { + final functionsRepository = ref.read(functionsRepositoryProvider); + return GetContactsUseCaseImpl(functionsRepository); +}); diff --git a/modules/legacy/modules/functions/lib/src/features/contacts/presentation/state/contacts_view_model.dart b/modules/legacy/modules/functions/lib/src/features/contacts/presentation/state/contacts_view_model.dart new file mode 100644 index 00000000..1c3d2c98 --- /dev/null +++ b/modules/legacy/modules/functions/lib/src/features/contacts/presentation/state/contacts_view_model.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:functions/src/features/contacts/domain/entities/contact_list_entity.dart'; +import 'package:functions/src/features/contacts/domain/get_contacts_use_case.dart'; +import 'package:functions/src/features/contacts/presentation/providers/get_contacts_provider.dart'; +import 'package:functions/src/features/contacts/presentation/state/contacts_view_state.dart'; +// import 'package:sf_localizations/sf_localizations.dart'; + +final contactsViewModelProvider = +NotifierProvider.autoDispose( + ContactsViewModel.new, +); + +class ContactsViewModel extends Notifier { + late final GetContactsUseCase _getContactsUseCase; + + late final TextEditingController nameController; + + @override + ContactsViewState build() { + _getContactsUseCase = ref.read(getContactsUseCaseProvider); + + nameController = TextEditingController(); + + nameController.addListener(_onNameChanged); + + _getContactsUseCase.getContacts(deviceId: '').then(setContacts); + + ref.onDispose(disposeControllers); + + return const ContactsViewState(); + } + + void setContacts(ContactListEntity contactList) { + state = state.copyWith( + contactList: contactList + ); + } + + void toggleIsEditing() { + state = state.copyWith(isEditing: !state.isEditing); + } + + void _onNameChanged() { + final text = nameController.text; + if (text == state.name) return; + + state = state.copyWith(name: text, errorMessage: ''); + } + + void disposeControllers() { + nameController.removeListener(_onNameChanged); + + nameController.dispose(); + } +} diff --git a/modules/legacy/modules/functions/lib/src/features/contacts/presentation/state/contacts_view_state.dart b/modules/legacy/modules/functions/lib/src/features/contacts/presentation/state/contacts_view_state.dart new file mode 100644 index 00000000..439ee615 --- /dev/null +++ b/modules/legacy/modules/functions/lib/src/features/contacts/presentation/state/contacts_view_state.dart @@ -0,0 +1,16 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:functions/src/features/contacts/domain/entities/contact_list_entity.dart'; + +part 'contacts_view_state.freezed.dart'; + +@freezed +abstract class ContactsViewState with _$ContactsViewState { + const factory ContactsViewState({ + @Default(null) ContactListEntity? contactList, + @Default(false) bool isLoading, + @Default(false) bool isEditing, + @Default('') String name, + @Default('') String phone, + @Default('') String errorMessage, + }) = _ContactsViewState; +} diff --git a/modules/legacy/modules/functions/lib/src/features/contacts/presentation/state/contacts_view_state.freezed.dart b/modules/legacy/modules/functions/lib/src/features/contacts/presentation/state/contacts_view_state.freezed.dart new file mode 100644 index 00000000..1d74938c --- /dev/null +++ b/modules/legacy/modules/functions/lib/src/features/contacts/presentation/state/contacts_view_state.freezed.dart @@ -0,0 +1,310 @@ +// 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 'contacts_view_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; +/// @nodoc +mixin _$ContactsViewState { + + ContactListEntity? get contactList; bool get isLoading; bool get isEditing; String get name; String get phone; String get errorMessage; +/// Create a copy of ContactsViewState +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$ContactsViewStateCopyWith get copyWith => _$ContactsViewStateCopyWithImpl(this as ContactsViewState, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is ContactsViewState&&(identical(other.contactList, contactList) || other.contactList == contactList)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isEditing, isEditing) || other.isEditing == isEditing)&&(identical(other.name, name) || other.name == name)&&(identical(other.phone, phone) || other.phone == phone)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)); +} + + +@override +int get hashCode => Object.hash(runtimeType,contactList,isLoading,isEditing,name,phone,errorMessage); + +@override +String toString() { + return 'ContactsViewState(contactList: $contactList, isLoading: $isLoading, isEditing: $isEditing, name: $name, phone: $phone, errorMessage: $errorMessage)'; +} + + +} + +/// @nodoc +abstract mixin class $ContactsViewStateCopyWith<$Res> { + factory $ContactsViewStateCopyWith(ContactsViewState value, $Res Function(ContactsViewState) _then) = _$ContactsViewStateCopyWithImpl; +@useResult +$Res call({ + ContactListEntity? contactList, bool isLoading, bool isEditing, String name, String phone, String errorMessage +}); + + +$ContactListEntityCopyWith<$Res>? get contactList; + +} +/// @nodoc +class _$ContactsViewStateCopyWithImpl<$Res> + implements $ContactsViewStateCopyWith<$Res> { + _$ContactsViewStateCopyWithImpl(this._self, this._then); + + final ContactsViewState _self; + final $Res Function(ContactsViewState) _then; + +/// Create a copy of ContactsViewState +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? contactList = freezed,Object? isLoading = null,Object? isEditing = null,Object? name = null,Object? phone = null,Object? errorMessage = null,}) { + return _then(_self.copyWith( +contactList: freezed == contactList ? _self.contactList : contactList // ignore: cast_nullable_to_non_nullable +as ContactListEntity?,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable +as bool,isEditing: null == isEditing ? _self.isEditing : isEditing // ignore: cast_nullable_to_non_nullable +as bool,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String,phone: null == phone ? _self.phone : phone // ignore: cast_nullable_to_non_nullable +as String,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable +as String, + )); +} +/// Create a copy of ContactsViewState +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$ContactListEntityCopyWith<$Res>? get contactList { + if (_self.contactList == null) { + return null; + } + + return $ContactListEntityCopyWith<$Res>(_self.contactList!, (value) { + return _then(_self.copyWith(contactList: value)); + }); +} +} + + +/// Adds pattern-matching-related methods to [ContactsViewState]. +extension ContactsViewStatePatterns on ContactsViewState { +/// 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 Function( _ContactsViewState value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _ContactsViewState() 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 Function( _ContactsViewState value) $default,){ +final _that = this; +switch (_that) { +case _ContactsViewState(): +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? Function( _ContactsViewState value)? $default,){ +final _that = this; +switch (_that) { +case _ContactsViewState() 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 Function( ContactListEntity? contactList, bool isLoading, bool isEditing, String name, String phone, String errorMessage)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _ContactsViewState() when $default != null: +return $default(_that.contactList,_that.isLoading,_that.isEditing,_that.name,_that.phone,_that.errorMessage);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 Function( ContactListEntity? contactList, bool isLoading, bool isEditing, String name, String phone, String errorMessage) $default,) {final _that = this; +switch (_that) { +case _ContactsViewState(): +return $default(_that.contactList,_that.isLoading,_that.isEditing,_that.name,_that.phone,_that.errorMessage);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? Function( ContactListEntity? contactList, bool isLoading, bool isEditing, String name, String phone, String errorMessage)? $default,) {final _that = this; +switch (_that) { +case _ContactsViewState() when $default != null: +return $default(_that.contactList,_that.isLoading,_that.isEditing,_that.name,_that.phone,_that.errorMessage);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _ContactsViewState implements ContactsViewState { + const _ContactsViewState({this.contactList = null, this.isLoading = false, this.isEditing = false, this.name = '', this.phone = '', this.errorMessage = ''}); + + +@override@JsonKey() final ContactListEntity? contactList; +@override@JsonKey() final bool isLoading; +@override@JsonKey() final bool isEditing; +@override@JsonKey() final String name; +@override@JsonKey() final String phone; +@override@JsonKey() final String errorMessage; + +/// Create a copy of ContactsViewState +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$ContactsViewStateCopyWith<_ContactsViewState> get copyWith => __$ContactsViewStateCopyWithImpl<_ContactsViewState>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _ContactsViewState&&(identical(other.contactList, contactList) || other.contactList == contactList)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isEditing, isEditing) || other.isEditing == isEditing)&&(identical(other.name, name) || other.name == name)&&(identical(other.phone, phone) || other.phone == phone)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)); +} + + +@override +int get hashCode => Object.hash(runtimeType,contactList,isLoading,isEditing,name,phone,errorMessage); + +@override +String toString() { + return 'ContactsViewState(contactList: $contactList, isLoading: $isLoading, isEditing: $isEditing, name: $name, phone: $phone, errorMessage: $errorMessage)'; +} + + +} + +/// @nodoc +abstract mixin class _$ContactsViewStateCopyWith<$Res> implements $ContactsViewStateCopyWith<$Res> { + factory _$ContactsViewStateCopyWith(_ContactsViewState value, $Res Function(_ContactsViewState) _then) = __$ContactsViewStateCopyWithImpl; +@override @useResult +$Res call({ + ContactListEntity? contactList, bool isLoading, bool isEditing, String name, String phone, String errorMessage +}); + + +@override $ContactListEntityCopyWith<$Res>? get contactList; + +} +/// @nodoc +class __$ContactsViewStateCopyWithImpl<$Res> + implements _$ContactsViewStateCopyWith<$Res> { + __$ContactsViewStateCopyWithImpl(this._self, this._then); + + final _ContactsViewState _self; + final $Res Function(_ContactsViewState) _then; + +/// Create a copy of ContactsViewState +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? contactList = freezed,Object? isLoading = null,Object? isEditing = null,Object? name = null,Object? phone = null,Object? errorMessage = null,}) { + return _then(_ContactsViewState( +contactList: freezed == contactList ? _self.contactList : contactList // ignore: cast_nullable_to_non_nullable +as ContactListEntity?,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable +as bool,isEditing: null == isEditing ? _self.isEditing : isEditing // ignore: cast_nullable_to_non_nullable +as bool,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String,phone: null == phone ? _self.phone : phone // ignore: cast_nullable_to_non_nullable +as String,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable +as String, + )); +} + +/// Create a copy of ContactsViewState +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$ContactListEntityCopyWith<$Res>? get contactList { + if (_self.contactList == null) { + return null; + } + + return $ContactListEntityCopyWith<$Res>(_self.contactList!, (value) { + return _then(_self.copyWith(contactList: value)); + }); +} +} + +// dart format on diff --git a/modules/legacy/modules/functions/lib/src/features/functions/functions_builder.dart b/modules/legacy/modules/functions/lib/src/features/functions/functions_builder.dart new file mode 100644 index 00000000..186a46cb --- /dev/null +++ b/modules/legacy/modules/functions/lib/src/features/functions/functions_builder.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:functions/src/features/functions/functions_screen.dart'; +import 'package:go_router/go_router.dart'; +import 'package:get_it/get_it.dart'; +import 'package:navigation/navigation.dart'; + +class FunctionsBuilder { + const FunctionsBuilder(); + + Page buildPage(BuildContext context, GoRouterState state) { + final NavigationContract navigationContract = GetIt.I(); + + return MaterialPage( + key: state.pageKey, + child: FunctionsScreen(navigationContract: navigationContract), + ); + } +} diff --git a/modules/legacy/modules/functions/lib/src/features/functions/functions_screen.dart b/modules/legacy/modules/functions/lib/src/features/functions/functions_screen.dart new file mode 100644 index 00000000..390cee00 --- /dev/null +++ b/modules/legacy/modules/functions/lib/src/features/functions/functions_screen.dart @@ -0,0 +1,179 @@ +import 'package:design_system/design_system.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:navigation/navigation.dart'; +import 'package:sf_localizations/sf_localizations.dart'; +import 'package:utils/utils.dart'; + +class FunctionsScreen extends ConsumerWidget { + final NavigationContract navigationContract; + + const FunctionsScreen({super.key, required this.navigationContract}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final theme = ref.watch(themePortProvider); + + return Scaffold( + backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary), + body: SafeArea( + child: Column( + children: [ + Container( + padding: SizeUtils.getByScreen( + small: EdgeInsets.symmetric(horizontal: 22, vertical: 10), + big: EdgeInsets.symmetric(horizontal: 21, vertical: 8) + ), + child: Stack( + children: [ + IconButton(onPressed: () {Navigator.pop(context);}, + icon: Icon(Icons.arrow_back)), + Center( + child: Text(context.translate('Device Features'), + style: TextStyle( + fontSize: SizeUtils.getByScreen(small: 28, big: 27) + ), + ) + ) + ], + ), + ), + SizedBox(height: SizeUtils.getByScreen(small: 30, big: 28)), + Expanded(child: SingleChildScrollView(child: Container( + padding: SizeUtils.getByScreen( + small: EdgeInsets.symmetric(horizontal: 22, vertical: 10), + big: EdgeInsets.symmetric(horizontal: 21, vertical: 8) + ), + child: Column( + children: [ + AppSectionButton( + onPressed: (){}, + icon: Icons.menu, + text: 'Remote connection' + ), + SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)), + AppSectionButton( + onPressed: (){}, + icon: Icons.menu, + text: 'Calendar' + ), + SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)), + AppSectionButton( + onPressed: (){navigationContract.pushTo(AppRoutes.contacts);}, + icon: Icons.menu, + text: 'Contacts' + ), + SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)), + AppSectionButton( + onPressed: (){}, + icon: Icons.menu, + text: 'Do not disturb' + ), + SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)), + AppSectionButton( + onPressed: (){}, + icon: Icons.menu, + text: 'Safety zone' + ), + SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)), + AppSectionButton( + onPressed: (){}, + icon: Icons.menu, + text: 'Video call' + ), + SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)), + AppSectionButton( + onPressed: (){}, + icon: Icons.menu, + text: 'Fall notice' + ), + SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)), + AppSectionButton( + onPressed: (){}, + icon: Icons.menu, + text: 'Medication reminder' + ), + SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)), + AppSectionButton( + onPressed: (){}, + icon: Icons.menu, + text: 'Activity meter' + ), + SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)), + AppSectionButton( + onPressed: (){}, + icon: Icons.menu, + text: 'Rewards' + ), + SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)), + AppSectionButton( + onPressed: (){}, + icon: Icons.menu, + text: 'Locate your SaveFamily' + ), + ], + ), + ))), + ], + ) + ), + ); + } +} + +class AppSectionButton extends ConsumerWidget { + + final GestureTapCallback onPressed; + final IconData icon; + final String text; + + const AppSectionButton({ + required this.onPressed, + required this.icon, + required this.text, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final theme = ref.read(themePortProvider); + + return GestureDetector( + onTap: onPressed, + child: Container( + padding: SizeUtils.getByScreen( + small: EdgeInsets.symmetric(horizontal: 22, vertical: 14), + big: EdgeInsets.symmetric(horizontal: 21, vertical: 12) + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(SizeUtils.getByScreen(small: 12, big: 18))), + color: theme.getColorFor(ThemeCode.backgroundSecondary), + ), + child: Row( + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Color(0xFF588EA5), + ), + padding: EdgeInsets.all(SizeUtils.getByScreen(small: 4, big: 12)), + child: Icon(icon, + size: SizeUtils.getByScreen(small: 40, big: 44), + color: theme.getColorFor(ThemeCode.backgroundPrimary), + weight: 30, + ), + ), + SizedBox(width: SizeUtils.getByScreen(small: 16, big: 15)), + Expanded( + child: Text(context.translate(text), + style: TextStyle( + fontSize: SizeUtils.getByScreen(small: 18, big: 19), + fontWeight: FontWeight.w500 + ) + ) + ) + ], + ), + ) + ); + } +} \ No newline at end of file diff --git a/modules/legacy/modules/hub/lib/src/features/hub/presentation/hub_screen.dart b/modules/legacy/modules/hub/lib/src/features/hub/presentation/hub_screen.dart index 47eb7af8..dc9898d6 100644 --- a/modules/legacy/modules/hub/lib/src/features/hub/presentation/hub_screen.dart +++ b/modules/legacy/modules/hub/lib/src/features/hub/presentation/hub_screen.dart @@ -61,7 +61,7 @@ class HubScreen extends ConsumerWidget { text: I18n.sfPay), SizedBox(height: SizeUtils.getByScreen(small: 8, big: 7)), AppSectionButton( - onPressed: (){}, + onPressed: (){navigationContract.pushTo(AppRoutes.dashboardFunctions);}, icon: SFIcons.functions, text: I18n.functions), SizedBox(height: SizeUtils.getByScreen(small: 8, big: 7)), diff --git a/packages/navigation/lib/app_routes.dart b/packages/navigation/lib/app_routes.dart index 45ba35c8..63dd0af8 100644 --- a/packages/navigation/lib/app_routes.dart +++ b/packages/navigation/lib/app_routes.dart @@ -20,4 +20,7 @@ class AppRoutes { static const legacyDashboard = '$legacy/dashboard'; static const dashboardHub = '$legacyDashboard/hub'; + static const dashboardFunctions = '$legacyDashboard/functions'; + + static const contacts = '$dashboardFunctions/contacts'; } diff --git a/packages/sf_localizations/lib/src/generated/i18n.dart b/packages/sf_localizations/lib/src/generated/i18n.dart index bd01ab75..4b254ea3 100755 --- a/packages/sf_localizations/lib/src/generated/i18n.dart +++ b/packages/sf_localizations/lib/src/generated/i18n.dart @@ -170,4 +170,25 @@ class I18n { static const String home = 'home'; static const String location = 'location'; static const String chat = 'chat'; + static const String legacyPersonalData = 'personalData'; + static const String legacyAddNewSF = 'addNewSF'; + static const String legacyLinkedDevices = 'linkedDevices'; + static const String legacyAppUsers = 'appUsers'; + static const String legacyPrivacyPolicy = 'privacyPolicy'; + static const String legacyLogOut = 'logOut'; + static const String legacyLoginEmail = 'loginEmail'; + static const String legacyUserNameLabel = 'userNameLabel'; + static const String legacyUserPhoneLabel = 'userPhoneLabel'; + static const String legacyContactEmailLabel = 'contactEmailLabel'; + static const String passwordLabel = 'passwordLabel'; + static const String legacySubmit = 'submit'; + static const String legacySave = 'save'; + static const String legacyEditDeviceTitle = 'editDeviceTitle'; + static const String legacyName = 'name'; + static const String legacyDeleteDeviceDialog = 'deleteDeviceDialog'; + static const String legacyDeleteUserDialog = 'deleteUserDialog'; + static const String legacyCancel = 'cancel'; + static const String legacyDelete = 'delete'; + static const String legacyUserAccount = 'userAccount'; + static const String legacyUserRole = 'userRole'; }