mirror of https://github.com/flutter/samples.git
[Compass App] User name and profile picture (#2435)
This PR completes the home screen, adding the username and the profile picture. ![Screenshot from 2024-09-11 14-52-32](https://github.com/user-attachments/assets/197f9932-ae86-4277-92ac-8fd413b52010) ![Screenshot from 2024-09-11 14-52-23](https://github.com/user-attachments/assets/915b8c54-ac85-40d9-adb8-3bf0521b78f5) This feature follows the basic structure: - Added repository, both local and remote. - Added API call + API model. - Added Domain model (reduced version only containing name and profile picture). - Modified the ViewModel to obtain the user and expose it to the Widget. - Updated Widget to display the username and profile picture. - Added `/user` endpoint to server project. - Updated widget tests, as well as integration tests. The Compass App is basically completed with it. Maybe the next step is to merge it to the `main` branch? And then we can do a full review, remove TODOs and setup CI jobs. ## Pre-launch Checklist - [x] I read the [Flutter Style Guide] _recently_, and have followed its advice. - [x] I signed the [CLA]. - [x] I read the [Contributors Guide]. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-devrel channel on [Discord]. <!-- Links --> [Flutter Style Guide]: https://github.com/flutter/flutter/blob/master/docs/contributing/Style-guide-for-Flutter-repo.md [CLA]: https://cla.developers.google.com/ [Discord]: https://github.com/flutter/flutter/blob/master/docs/contributing/Chat.md [Contributors Guide]: https://github.com/flutter/samples/blob/main/CONTRIBUTING.mdpull/2437/head
parent
93b86b86f3
commit
b00ce6c7b3
After Width: | Height: | Size: 41 KiB |
@ -0,0 +1,8 @@
|
|||||||
|
import '../../../domain/models/user/user.dart';
|
||||||
|
import '../../../utils/result.dart';
|
||||||
|
|
||||||
|
/// Data source for user related data
|
||||||
|
abstract class UserRepository {
|
||||||
|
/// Get current user
|
||||||
|
Future<Result<User>> getUser();
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import '../../../domain/models/user/user.dart';
|
||||||
|
import '../../../utils/result.dart';
|
||||||
|
import '../../services/local/local_data_service.dart';
|
||||||
|
import 'user_repository.dart';
|
||||||
|
|
||||||
|
class UserRepositoryLocal implements UserRepository {
|
||||||
|
UserRepositoryLocal({
|
||||||
|
required LocalDataService localDataService,
|
||||||
|
}) : _localDataService = localDataService;
|
||||||
|
|
||||||
|
final LocalDataService _localDataService;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<User>> getUser() async {
|
||||||
|
return Result.ok(_localDataService.getUser());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
import '../../../domain/models/user/user.dart';
|
||||||
|
import '../../../utils/result.dart';
|
||||||
|
import '../../services/api/api_client.dart';
|
||||||
|
import '../../services/api/model/user/user_api_model.dart';
|
||||||
|
import 'user_repository.dart';
|
||||||
|
|
||||||
|
class UserRepositoryRemote implements UserRepository {
|
||||||
|
UserRepositoryRemote({
|
||||||
|
required ApiClient apiClient,
|
||||||
|
}) : _apiClient = apiClient;
|
||||||
|
|
||||||
|
final ApiClient _apiClient;
|
||||||
|
|
||||||
|
User? _cachedData;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<User>> getUser() async {
|
||||||
|
if (_cachedData != null) {
|
||||||
|
return Future.value(Result.ok(_cachedData!));
|
||||||
|
}
|
||||||
|
|
||||||
|
final result = await _apiClient.getUser();
|
||||||
|
switch (result) {
|
||||||
|
case Ok<UserApiModel>():
|
||||||
|
final user = User(
|
||||||
|
name: result.value.name,
|
||||||
|
picture: result.value.picture,
|
||||||
|
);
|
||||||
|
_cachedData = user;
|
||||||
|
return Result.ok(user);
|
||||||
|
case Error<UserApiModel>():
|
||||||
|
return Result.error(result.error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
part 'user_api_model.freezed.dart';
|
||||||
|
part 'user_api_model.g.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class UserApiModel with _$UserApiModel {
|
||||||
|
const factory UserApiModel({
|
||||||
|
/// The user's ID.
|
||||||
|
required String id,
|
||||||
|
|
||||||
|
/// The user's name.
|
||||||
|
required String name,
|
||||||
|
|
||||||
|
/// The user's email.
|
||||||
|
required String email,
|
||||||
|
|
||||||
|
/// The user's picture URL.
|
||||||
|
required String picture,
|
||||||
|
}) = _UserApiModel;
|
||||||
|
|
||||||
|
factory UserApiModel.fromJson(Map<String, Object?> json) =>
|
||||||
|
_$UserApiModelFromJson(json);
|
||||||
|
}
|
@ -0,0 +1,241 @@
|
|||||||
|
// coverage:ignore-file
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// 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 'user_api_model.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
final _privateConstructorUsedError = UnsupportedError(
|
||||||
|
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||||
|
|
||||||
|
UserApiModel _$UserApiModelFromJson(Map<String, dynamic> json) {
|
||||||
|
return _UserApiModel.fromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$UserApiModel {
|
||||||
|
/// The user's ID.
|
||||||
|
String get id => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// The user's name.
|
||||||
|
String get name => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// The user's email.
|
||||||
|
String get email => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// The user's picture URL.
|
||||||
|
String get picture => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Serializes this UserApiModel to a JSON map.
|
||||||
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Create a copy of UserApiModel
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
$UserApiModelCopyWith<UserApiModel> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class $UserApiModelCopyWith<$Res> {
|
||||||
|
factory $UserApiModelCopyWith(
|
||||||
|
UserApiModel value, $Res Function(UserApiModel) then) =
|
||||||
|
_$UserApiModelCopyWithImpl<$Res, UserApiModel>;
|
||||||
|
@useResult
|
||||||
|
$Res call({String id, String name, String email, String picture});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$UserApiModelCopyWithImpl<$Res, $Val extends UserApiModel>
|
||||||
|
implements $UserApiModelCopyWith<$Res> {
|
||||||
|
_$UserApiModelCopyWithImpl(this._value, this._then);
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Val _value;
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of UserApiModel
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? id = null,
|
||||||
|
Object? name = null,
|
||||||
|
Object? email = null,
|
||||||
|
Object? picture = null,
|
||||||
|
}) {
|
||||||
|
return _then(_value.copyWith(
|
||||||
|
id: null == id
|
||||||
|
? _value.id
|
||||||
|
: id // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
name: null == name
|
||||||
|
? _value.name
|
||||||
|
: name // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
email: null == email
|
||||||
|
? _value.email
|
||||||
|
: email // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
picture: null == picture
|
||||||
|
? _value.picture
|
||||||
|
: picture // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
) as $Val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class _$$UserApiModelImplCopyWith<$Res>
|
||||||
|
implements $UserApiModelCopyWith<$Res> {
|
||||||
|
factory _$$UserApiModelImplCopyWith(
|
||||||
|
_$UserApiModelImpl value, $Res Function(_$UserApiModelImpl) then) =
|
||||||
|
__$$UserApiModelImplCopyWithImpl<$Res>;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call({String id, String name, String email, String picture});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$UserApiModelImplCopyWithImpl<$Res>
|
||||||
|
extends _$UserApiModelCopyWithImpl<$Res, _$UserApiModelImpl>
|
||||||
|
implements _$$UserApiModelImplCopyWith<$Res> {
|
||||||
|
__$$UserApiModelImplCopyWithImpl(
|
||||||
|
_$UserApiModelImpl _value, $Res Function(_$UserApiModelImpl) _then)
|
||||||
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of UserApiModel
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? id = null,
|
||||||
|
Object? name = null,
|
||||||
|
Object? email = null,
|
||||||
|
Object? picture = null,
|
||||||
|
}) {
|
||||||
|
return _then(_$UserApiModelImpl(
|
||||||
|
id: null == id
|
||||||
|
? _value.id
|
||||||
|
: id // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
name: null == name
|
||||||
|
? _value.name
|
||||||
|
: name // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
email: null == email
|
||||||
|
? _value.email
|
||||||
|
: email // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
picture: null == picture
|
||||||
|
? _value.picture
|
||||||
|
: picture // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
class _$UserApiModelImpl implements _UserApiModel {
|
||||||
|
const _$UserApiModelImpl(
|
||||||
|
{required this.id,
|
||||||
|
required this.name,
|
||||||
|
required this.email,
|
||||||
|
required this.picture});
|
||||||
|
|
||||||
|
factory _$UserApiModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$$UserApiModelImplFromJson(json);
|
||||||
|
|
||||||
|
/// The user's ID.
|
||||||
|
@override
|
||||||
|
final String id;
|
||||||
|
|
||||||
|
/// The user's name.
|
||||||
|
@override
|
||||||
|
final String name;
|
||||||
|
|
||||||
|
/// The user's email.
|
||||||
|
@override
|
||||||
|
final String email;
|
||||||
|
|
||||||
|
/// The user's picture URL.
|
||||||
|
@override
|
||||||
|
final String picture;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'UserApiModel(id: $id, name: $name, email: $email, picture: $picture)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _$UserApiModelImpl &&
|
||||||
|
(identical(other.id, id) || other.id == id) &&
|
||||||
|
(identical(other.name, name) || other.name == name) &&
|
||||||
|
(identical(other.email, email) || other.email == email) &&
|
||||||
|
(identical(other.picture, picture) || other.picture == picture));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType, id, name, email, picture);
|
||||||
|
|
||||||
|
/// Create a copy of UserApiModel
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$$UserApiModelImplCopyWith<_$UserApiModelImpl> get copyWith =>
|
||||||
|
__$$UserApiModelImplCopyWithImpl<_$UserApiModelImpl>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$$UserApiModelImplToJson(
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _UserApiModel implements UserApiModel {
|
||||||
|
const factory _UserApiModel(
|
||||||
|
{required final String id,
|
||||||
|
required final String name,
|
||||||
|
required final String email,
|
||||||
|
required final String picture}) = _$UserApiModelImpl;
|
||||||
|
|
||||||
|
factory _UserApiModel.fromJson(Map<String, dynamic> json) =
|
||||||
|
_$UserApiModelImpl.fromJson;
|
||||||
|
|
||||||
|
/// The user's ID.
|
||||||
|
@override
|
||||||
|
String get id;
|
||||||
|
|
||||||
|
/// The user's name.
|
||||||
|
@override
|
||||||
|
String get name;
|
||||||
|
|
||||||
|
/// The user's email.
|
||||||
|
@override
|
||||||
|
String get email;
|
||||||
|
|
||||||
|
/// The user's picture URL.
|
||||||
|
@override
|
||||||
|
String get picture;
|
||||||
|
|
||||||
|
/// Create a copy of UserApiModel
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
_$$UserApiModelImplCopyWith<_$UserApiModelImpl> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'user_api_model.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_$UserApiModelImpl _$$UserApiModelImplFromJson(Map<String, dynamic> json) =>
|
||||||
|
_$UserApiModelImpl(
|
||||||
|
id: json['id'] as String,
|
||||||
|
name: json['name'] as String,
|
||||||
|
email: json['email'] as String,
|
||||||
|
picture: json['picture'] as String,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$UserApiModelImplToJson(_$UserApiModelImpl instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'id': instance.id,
|
||||||
|
'name': instance.name,
|
||||||
|
'email': instance.email,
|
||||||
|
'picture': instance.picture,
|
||||||
|
};
|
@ -0,0 +1,17 @@
|
|||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
part 'user.freezed.dart';
|
||||||
|
part 'user.g.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class User with _$User {
|
||||||
|
const factory User({
|
||||||
|
/// The user's name.
|
||||||
|
required String name,
|
||||||
|
|
||||||
|
/// The user's picture URL.
|
||||||
|
required String picture,
|
||||||
|
}) = _User;
|
||||||
|
|
||||||
|
factory User.fromJson(Map<String, Object?> json) => _$UserFromJson(json);
|
||||||
|
}
|
@ -0,0 +1,185 @@
|
|||||||
|
// coverage:ignore-file
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// 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 'user.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
final _privateConstructorUsedError = UnsupportedError(
|
||||||
|
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||||
|
|
||||||
|
User _$UserFromJson(Map<String, dynamic> json) {
|
||||||
|
return _User.fromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$User {
|
||||||
|
/// The user's name.
|
||||||
|
String get name => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// The user's picture URL.
|
||||||
|
String get picture => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Serializes this User to a JSON map.
|
||||||
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Create a copy of User
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
$UserCopyWith<User> get copyWith => throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class $UserCopyWith<$Res> {
|
||||||
|
factory $UserCopyWith(User value, $Res Function(User) then) =
|
||||||
|
_$UserCopyWithImpl<$Res, User>;
|
||||||
|
@useResult
|
||||||
|
$Res call({String name, String picture});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$UserCopyWithImpl<$Res, $Val extends User>
|
||||||
|
implements $UserCopyWith<$Res> {
|
||||||
|
_$UserCopyWithImpl(this._value, this._then);
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Val _value;
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of User
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? name = null,
|
||||||
|
Object? picture = null,
|
||||||
|
}) {
|
||||||
|
return _then(_value.copyWith(
|
||||||
|
name: null == name
|
||||||
|
? _value.name
|
||||||
|
: name // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
picture: null == picture
|
||||||
|
? _value.picture
|
||||||
|
: picture // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
) as $Val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class _$$UserImplCopyWith<$Res> implements $UserCopyWith<$Res> {
|
||||||
|
factory _$$UserImplCopyWith(
|
||||||
|
_$UserImpl value, $Res Function(_$UserImpl) then) =
|
||||||
|
__$$UserImplCopyWithImpl<$Res>;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call({String name, String picture});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$UserImplCopyWithImpl<$Res>
|
||||||
|
extends _$UserCopyWithImpl<$Res, _$UserImpl>
|
||||||
|
implements _$$UserImplCopyWith<$Res> {
|
||||||
|
__$$UserImplCopyWithImpl(_$UserImpl _value, $Res Function(_$UserImpl) _then)
|
||||||
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of User
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? name = null,
|
||||||
|
Object? picture = null,
|
||||||
|
}) {
|
||||||
|
return _then(_$UserImpl(
|
||||||
|
name: null == name
|
||||||
|
? _value.name
|
||||||
|
: name // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
picture: null == picture
|
||||||
|
? _value.picture
|
||||||
|
: picture // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
class _$UserImpl implements _User {
|
||||||
|
const _$UserImpl({required this.name, required this.picture});
|
||||||
|
|
||||||
|
factory _$UserImpl.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$$UserImplFromJson(json);
|
||||||
|
|
||||||
|
/// The user's name.
|
||||||
|
@override
|
||||||
|
final String name;
|
||||||
|
|
||||||
|
/// The user's picture URL.
|
||||||
|
@override
|
||||||
|
final String picture;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'User(name: $name, picture: $picture)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _$UserImpl &&
|
||||||
|
(identical(other.name, name) || other.name == name) &&
|
||||||
|
(identical(other.picture, picture) || other.picture == picture));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType, name, picture);
|
||||||
|
|
||||||
|
/// Create a copy of User
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$$UserImplCopyWith<_$UserImpl> get copyWith =>
|
||||||
|
__$$UserImplCopyWithImpl<_$UserImpl>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$$UserImplToJson(
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _User implements User {
|
||||||
|
const factory _User(
|
||||||
|
{required final String name, required final String picture}) = _$UserImpl;
|
||||||
|
|
||||||
|
factory _User.fromJson(Map<String, dynamic> json) = _$UserImpl.fromJson;
|
||||||
|
|
||||||
|
/// The user's name.
|
||||||
|
@override
|
||||||
|
String get name;
|
||||||
|
|
||||||
|
/// The user's picture URL.
|
||||||
|
@override
|
||||||
|
String get picture;
|
||||||
|
|
||||||
|
/// Create a copy of User
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
_$$UserImplCopyWith<_$UserImpl> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'user.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_$UserImpl _$$UserImplFromJson(Map<String, dynamic> json) => _$UserImpl(
|
||||||
|
name: json['name'] as String,
|
||||||
|
picture: json['picture'] as String,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$UserImplToJson(_$UserImpl instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'name': instance.name,
|
||||||
|
'picture': instance.picture,
|
||||||
|
};
|
@ -0,0 +1,85 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../../auth/logout/view_models/logout_viewmodel.dart';
|
||||||
|
import '../../auth/logout/widgets/logout_button.dart';
|
||||||
|
import '../../core/localization/applocalization.dart';
|
||||||
|
import '../../core/themes/dimens.dart';
|
||||||
|
import '../view_models/home_viewmodel.dart';
|
||||||
|
|
||||||
|
class HomeHeader extends StatelessWidget {
|
||||||
|
const HomeHeader({
|
||||||
|
super.key,
|
||||||
|
required this.viewModel,
|
||||||
|
});
|
||||||
|
|
||||||
|
final HomeViewModel viewModel;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final user = viewModel.user;
|
||||||
|
if (user == null) {
|
||||||
|
return const SizedBox();
|
||||||
|
}
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
ClipOval(
|
||||||
|
child: Image.asset(
|
||||||
|
user.picture,
|
||||||
|
width: Dimens.of(context).profilePictureSize,
|
||||||
|
height: Dimens.of(context).profilePictureSize,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
LogoutButton(
|
||||||
|
viewModel: LogoutViewModel(
|
||||||
|
authRepository: context.read(),
|
||||||
|
itineraryConfigRepository: context.read(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: Dimens.paddingVertical),
|
||||||
|
_Title(
|
||||||
|
text: AppLocalization.of(context).nameTrips(user.name),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _Title extends StatelessWidget {
|
||||||
|
const _Title({
|
||||||
|
required this.text,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String text;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ShaderMask(
|
||||||
|
blendMode: BlendMode.srcIn,
|
||||||
|
shaderCallback: (bounds) => RadialGradient(
|
||||||
|
center: Alignment.bottomLeft,
|
||||||
|
radius: 2,
|
||||||
|
colors: [
|
||||||
|
Colors.purple.shade700,
|
||||||
|
Colors.purple.shade400,
|
||||||
|
],
|
||||||
|
).createShader(
|
||||||
|
Rect.fromLTWH(0, 0, bounds.width, bounds.height),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
text,
|
||||||
|
style: GoogleFonts.rubik(
|
||||||
|
textStyle: Theme.of(context).textTheme.headlineLarge,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
import 'package:compass_app/data/repositories/user/user_repository.dart';
|
||||||
|
import 'package:compass_app/domain/models/user/user.dart';
|
||||||
|
import 'package:compass_app/utils/result.dart';
|
||||||
|
|
||||||
|
import '../../models/user.dart';
|
||||||
|
|
||||||
|
class FakeUserRepository implements UserRepository {
|
||||||
|
@override
|
||||||
|
Future<Result<User>> getUser() async {
|
||||||
|
return Result.ok(user);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
import 'package:compass_app/data/services/api/model/user/user_api_model.dart';
|
||||||
|
import 'package:compass_app/domain/models/user/user.dart';
|
||||||
|
|
||||||
|
const userApiModel = UserApiModel(
|
||||||
|
id: 'ID',
|
||||||
|
name: 'NAME',
|
||||||
|
email: 'EMAIL',
|
||||||
|
picture: 'assets/user.jpg',
|
||||||
|
);
|
||||||
|
|
||||||
|
const user = User(
|
||||||
|
name: 'NAME',
|
||||||
|
picture: 'assets/user.jpg',
|
||||||
|
);
|
@ -0,0 +1,23 @@
|
|||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
part 'user.freezed.dart';
|
||||||
|
part 'user.g.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class User with _$User {
|
||||||
|
const factory User({
|
||||||
|
/// The user's ID.
|
||||||
|
required String id,
|
||||||
|
|
||||||
|
/// The user's name.
|
||||||
|
required String name,
|
||||||
|
|
||||||
|
/// The user's email.
|
||||||
|
required String email,
|
||||||
|
|
||||||
|
/// The user's picture URL.
|
||||||
|
required String picture,
|
||||||
|
}) = _User;
|
||||||
|
|
||||||
|
factory User.fromJson(Map<String, Object?> json) => _$UserFromJson(json);
|
||||||
|
}
|
@ -0,0 +1,236 @@
|
|||||||
|
// coverage:ignore-file
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// 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 'user.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
final _privateConstructorUsedError = UnsupportedError(
|
||||||
|
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||||
|
|
||||||
|
User _$UserFromJson(Map<String, dynamic> json) {
|
||||||
|
return _User.fromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$User {
|
||||||
|
/// The user's ID.
|
||||||
|
String get id => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// The user's name.
|
||||||
|
String get name => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// The user's email.
|
||||||
|
String get email => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// The user's picture URL.
|
||||||
|
String get picture => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Serializes this User to a JSON map.
|
||||||
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Create a copy of User
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
$UserCopyWith<User> get copyWith => throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class $UserCopyWith<$Res> {
|
||||||
|
factory $UserCopyWith(User value, $Res Function(User) then) =
|
||||||
|
_$UserCopyWithImpl<$Res, User>;
|
||||||
|
@useResult
|
||||||
|
$Res call({String id, String name, String email, String picture});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$UserCopyWithImpl<$Res, $Val extends User>
|
||||||
|
implements $UserCopyWith<$Res> {
|
||||||
|
_$UserCopyWithImpl(this._value, this._then);
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Val _value;
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of User
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? id = null,
|
||||||
|
Object? name = null,
|
||||||
|
Object? email = null,
|
||||||
|
Object? picture = null,
|
||||||
|
}) {
|
||||||
|
return _then(_value.copyWith(
|
||||||
|
id: null == id
|
||||||
|
? _value.id
|
||||||
|
: id // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
name: null == name
|
||||||
|
? _value.name
|
||||||
|
: name // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
email: null == email
|
||||||
|
? _value.email
|
||||||
|
: email // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
picture: null == picture
|
||||||
|
? _value.picture
|
||||||
|
: picture // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
) as $Val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class _$$UserImplCopyWith<$Res> implements $UserCopyWith<$Res> {
|
||||||
|
factory _$$UserImplCopyWith(
|
||||||
|
_$UserImpl value, $Res Function(_$UserImpl) then) =
|
||||||
|
__$$UserImplCopyWithImpl<$Res>;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call({String id, String name, String email, String picture});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$UserImplCopyWithImpl<$Res>
|
||||||
|
extends _$UserCopyWithImpl<$Res, _$UserImpl>
|
||||||
|
implements _$$UserImplCopyWith<$Res> {
|
||||||
|
__$$UserImplCopyWithImpl(_$UserImpl _value, $Res Function(_$UserImpl) _then)
|
||||||
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of User
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? id = null,
|
||||||
|
Object? name = null,
|
||||||
|
Object? email = null,
|
||||||
|
Object? picture = null,
|
||||||
|
}) {
|
||||||
|
return _then(_$UserImpl(
|
||||||
|
id: null == id
|
||||||
|
? _value.id
|
||||||
|
: id // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
name: null == name
|
||||||
|
? _value.name
|
||||||
|
: name // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
email: null == email
|
||||||
|
? _value.email
|
||||||
|
: email // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
picture: null == picture
|
||||||
|
? _value.picture
|
||||||
|
: picture // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
class _$UserImpl implements _User {
|
||||||
|
const _$UserImpl(
|
||||||
|
{required this.id,
|
||||||
|
required this.name,
|
||||||
|
required this.email,
|
||||||
|
required this.picture});
|
||||||
|
|
||||||
|
factory _$UserImpl.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$$UserImplFromJson(json);
|
||||||
|
|
||||||
|
/// The user's ID.
|
||||||
|
@override
|
||||||
|
final String id;
|
||||||
|
|
||||||
|
/// The user's name.
|
||||||
|
@override
|
||||||
|
final String name;
|
||||||
|
|
||||||
|
/// The user's email.
|
||||||
|
@override
|
||||||
|
final String email;
|
||||||
|
|
||||||
|
/// The user's picture URL.
|
||||||
|
@override
|
||||||
|
final String picture;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'User(id: $id, name: $name, email: $email, picture: $picture)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _$UserImpl &&
|
||||||
|
(identical(other.id, id) || other.id == id) &&
|
||||||
|
(identical(other.name, name) || other.name == name) &&
|
||||||
|
(identical(other.email, email) || other.email == email) &&
|
||||||
|
(identical(other.picture, picture) || other.picture == picture));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType, id, name, email, picture);
|
||||||
|
|
||||||
|
/// Create a copy of User
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$$UserImplCopyWith<_$UserImpl> get copyWith =>
|
||||||
|
__$$UserImplCopyWithImpl<_$UserImpl>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$$UserImplToJson(
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _User implements User {
|
||||||
|
const factory _User(
|
||||||
|
{required final String id,
|
||||||
|
required final String name,
|
||||||
|
required final String email,
|
||||||
|
required final String picture}) = _$UserImpl;
|
||||||
|
|
||||||
|
factory _User.fromJson(Map<String, dynamic> json) = _$UserImpl.fromJson;
|
||||||
|
|
||||||
|
/// The user's ID.
|
||||||
|
@override
|
||||||
|
String get id;
|
||||||
|
|
||||||
|
/// The user's name.
|
||||||
|
@override
|
||||||
|
String get name;
|
||||||
|
|
||||||
|
/// The user's email.
|
||||||
|
@override
|
||||||
|
String get email;
|
||||||
|
|
||||||
|
/// The user's picture URL.
|
||||||
|
@override
|
||||||
|
String get picture;
|
||||||
|
|
||||||
|
/// Create a copy of User
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
_$$UserImplCopyWith<_$UserImpl> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'user.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_$UserImpl _$$UserImplFromJson(Map<String, dynamic> json) => _$UserImpl(
|
||||||
|
id: json['id'] as String,
|
||||||
|
name: json['name'] as String,
|
||||||
|
email: json['email'] as String,
|
||||||
|
picture: json['picture'] as String,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$UserImplToJson(_$UserImpl instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'id': instance.id,
|
||||||
|
'name': instance.name,
|
||||||
|
'email': instance.email,
|
||||||
|
'picture': instance.picture,
|
||||||
|
};
|
@ -0,0 +1,23 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:compass_server/config/constants.dart';
|
||||||
|
import 'package:shelf/shelf.dart';
|
||||||
|
import 'package:shelf_router/shelf_router.dart';
|
||||||
|
|
||||||
|
/// Implements a simple user API.
|
||||||
|
///
|
||||||
|
/// This API only returns a hardcoded user for demonstration purposes.
|
||||||
|
class UserApi {
|
||||||
|
Router get router {
|
||||||
|
final router = Router();
|
||||||
|
|
||||||
|
router.get('/', (Request request) async {
|
||||||
|
return Response.ok(
|
||||||
|
json.encode(Constants.user),
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return router;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue