doc(arch): add fully featured example

This commit is contained in:
2022-11-08 20:09:18 -05:00
parent db67491876
commit 6602db215f
109 changed files with 4499 additions and 29 deletions
@@ -0,0 +1,52 @@
// Copyright (C) 2022 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:architecture_example/core/constants/hive_boxes.dart';
import 'package:architecture_example/domain/data_sources/local/favorite_local_data_source.dart';
import 'package:architecture_example/domain/entities/photo.dart';
import 'package:hive/hive.dart';
class FavoriteHiveDataSource extends FavoriteLocalDataSource {
@override
Future<void> addPhotoToFavorites(Photo photo) async {
final box = await Hive.openBox<bool>(HiveBoxes.favorites);
if (box.containsKey(photo.id)) {
throw Exception('Photo already in favorites');
}
await box.put(photo.id, true);
}
@override
Future<bool> checkIfPhotoIsInFavorites(int id) async {
final box = await Hive.openBox<bool>(HiveBoxes.favorites);
return box.containsKey(id);
}
@override
Future<void> deletePhotoFromFavorites(int id) async {
final box = await Hive.openBox<bool>(HiveBoxes.favorites);
if (!box.containsKey(id)) {
throw Exception('Unknown photo');
}
await box.delete(id);
}
@override
Future<List<int>> getAllPhotosFromFavorites() async {
final box = await Hive.openBox<bool>(HiveBoxes.favorites);
return box.keys.cast<int>().toList();
}
}
@@ -0,0 +1,56 @@
// Copyright (C) 2022 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:architecture_example/data/models/photo_model.dart';
import 'package:architecture_example/domain/data_sources/local/favorite_local_data_source.dart';
import 'package:architecture_example/domain/entities/photo.dart';
class FavoriteMockDataSource extends FavoriteLocalDataSource {
final Map<int, Photo> _mock = {
2: const PhotoModel(
albumId: 1,
id: 2,
title: 'Photo 2',
url: 'https://via.placeholder.com/600/771796',
thumbnailUrl: 'https://via.placeholder.com/150/771796',
),
};
@override
Future<void> addPhotoToFavorites(Photo photo) async {
if (_mock.containsKey(photo.id)) {
throw Exception('Photo already in favorites');
}
_mock.putIfAbsent(photo.id, () => photo);
}
@override
Future<bool> checkIfPhotoIsInFavorites(int id) async => _mock.containsKey(id);
@override
Future<void> deletePhotoFromFavorites(int id) async {
if (!_mock.containsKey(id)) {
throw Exception('Unknown photo');
}
_mock.remove(id);
}
@override
Future<List<int>> getAllPhotosFromFavorites() async {
final result = _mock.keys;
return result.toList();
}
}
@@ -0,0 +1,53 @@
// Copyright (C) 2022 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'dart:convert';
import 'package:architecture_example/data/models/album_model.dart';
import 'package:architecture_example/data/models/list_album_model.dart';
import 'package:architecture_example/domain/data_sources/remote/album_remote_data_source.dart';
import 'package:architecture_example/domain/entities/album.dart';
import 'package:wyatt_http_client/wyatt_http_client.dart';
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
class AlbumApiDataSourceImpl extends AlbumRemoteDataSource {
final MiddlewareClient _client;
AlbumApiDataSourceImpl(this._client);
@override
Future<Album> getAlbum(int id) async {
final response = await _client.get(Uri.parse('/albums/$id'));
final album =
AlbumModel.fromJson(jsonDecode(response.body) as Map<String, Object?>);
return album;
}
@override
Future<List<Album>> getAllAlbums({int? start, int? limit}) async {
final startQuery = start.isNotNull ? '_start=$start' : '';
final limitQuery = limit.isNotNull ? '_limit=$limit' : '';
final delimiter1 =
(startQuery.isNotEmpty || limitQuery.isNotEmpty) ? '?' : '';
final delimiter2 =
(startQuery.isNotEmpty && limitQuery.isNotEmpty) ? '&' : '';
final url = '/albums$delimiter1$startQuery$delimiter2$limitQuery';
final response = await _client.get(Uri.parse(url));
final albums =
ListAlbumModel.fromJson({'albums': jsonDecode(response.body)});
return albums.albums;
}
}
@@ -0,0 +1,46 @@
// Copyright (C) 2022 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:architecture_example/data/models/album_model.dart';
import 'package:architecture_example/domain/data_sources/remote/album_remote_data_source.dart';
import 'package:architecture_example/domain/entities/album.dart';
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
class AlbumMockDataSourceImpl extends AlbumRemoteDataSource {
final Map<int, Album> _mock = {
1: const AlbumModel(
id: 1,
userId: 1,
title: 'Album 1',
)
};
@override
Future<Album> getAlbum(int id) async {
final response = _mock[id];
if (response.isNull) {
throw Exception('Unknown album');
}
return response!;
}
@override
Future<List<Album>> getAllAlbums({int? start, int? limit}) async {
final response = _mock.values;
final nullableEnd = (limit != null) ? start ?? 0 + limit : null;
return response.toList().sublist(start ?? 0, nullableEnd);
}
}
@@ -0,0 +1,70 @@
// Copyright (C) 2022 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'dart:convert';
import 'package:architecture_example/data/models/list_photo_model.dart';
import 'package:architecture_example/data/models/photo_model.dart';
import 'package:architecture_example/domain/data_sources/remote/photo_remote_data_source.dart';
import 'package:architecture_example/domain/entities/photo.dart';
import 'package:wyatt_http_client/wyatt_http_client.dart';
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
class PhotoApiDataSourceImpl extends PhotoRemoteDataSource {
final MiddlewareClient _client;
PhotoApiDataSourceImpl(this._client);
@override
Future<Photo> getPhoto(int id) async {
final response = await _client.get(Uri.parse('/photos/$id'));
final photo =
PhotoModel.fromJson(jsonDecode(response.body) as Map<String, Object?>);
return photo;
}
@override
Future<List<Photo>> getAllPhotos({int? start, int? limit}) async {
final startQuery = start.isNotNull ? '_start=$start' : '';
final limitQuery = limit.isNotNull ? '_limit=$limit' : '';
final delimiter1 =
(startQuery.isNotEmpty || limitQuery.isNotEmpty) ? '?' : '';
final delimiter2 =
(startQuery.isNotEmpty && limitQuery.isNotEmpty) ? '&' : '';
final url = '/photos$delimiter1$startQuery$delimiter2$limitQuery';
final response = await _client.get(Uri.parse(url));
final photos =
ListPhotoModel.fromJson({'photos': jsonDecode(response.body)});
return photos.photos;
}
@override
Future<List<Photo>> getPhotosFromAlbum(
int albumId, {
int? start,
int? limit,
}) async {
final startQuery = start.isNotNull ? '_start=$start' : '';
final limitQuery = limit.isNotNull ? '_limit=$limit' : '';
final delimiter =
(startQuery.isNotEmpty && limitQuery.isNotEmpty) ? '&' : '';
final url = '/photos?albumId=$albumId&$startQuery$delimiter$limitQuery';
final response = await _client.get(Uri.parse(url));
final photos =
ListPhotoModel.fromJson({'photos': jsonDecode(response.body)});
return photos.photos;
}
}
@@ -0,0 +1,67 @@
// Copyright (C) 2022 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:architecture_example/data/models/photo_model.dart';
import 'package:architecture_example/domain/data_sources/remote/photo_remote_data_source.dart';
import 'package:architecture_example/domain/entities/photo.dart';
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
class PhotoMockDataSourceImpl extends PhotoRemoteDataSource {
final Map<int, Photo> _mock = {
1: const PhotoModel(
albumId: 1,
id: 1,
title: 'Photo 1',
url: 'https://via.placeholder.com/600/92c952',
thumbnailUrl: 'https://via.placeholder.com/150/92c952',
),
2: const PhotoModel(
albumId: 1,
id: 2,
title: 'Photo 2',
url: 'https://via.placeholder.com/600/771796',
thumbnailUrl: 'https://via.placeholder.com/150/771796',
),
};
@override
Future<Photo> getPhoto(int id) async {
final response = _mock[id];
if (response.isNull) {
throw Exception('Unknown photo');
}
return response!;
}
@override
Future<List<Photo>> getAllPhotos({int? start, int? limit}) async {
final response = _mock.values;
final nullableEnd = (limit != null) ? start ?? 0 + limit : null;
return response.toList().sublist(start ?? 0, nullableEnd);
}
@override
Future<List<Photo>> getPhotosFromAlbum(
int albumId, {
int? start,
int? limit,
}) async {
// TODO(hpcl): use start and limit
final response = _mock.values
..where((element) => element.albumId == albumId);
return response.toList();
}
}
@@ -0,0 +1,33 @@
// Copyright (C) 2022 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:architecture_example/domain/entities/album.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'album_model.freezed.dart';
part 'album_model.g.dart';
@freezed
class AlbumModel extends Album with _$AlbumModel {
const factory AlbumModel({
required int userId,
required int id,
required String title,
}) = _AlbumModel;
factory AlbumModel.fromJson(Map<String, Object?> json) =>
_$AlbumModelFromJson(json);
}
@@ -0,0 +1,173 @@
// 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
part of 'album_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#custom-getters-and-methods');
AlbumModel _$AlbumModelFromJson(Map<String, dynamic> json) {
return _AlbumModel.fromJson(json);
}
/// @nodoc
mixin _$AlbumModel {
int get userId => throw _privateConstructorUsedError;
int get id => throw _privateConstructorUsedError;
String get title => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$AlbumModelCopyWith<AlbumModel> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $AlbumModelCopyWith<$Res> {
factory $AlbumModelCopyWith(
AlbumModel value, $Res Function(AlbumModel) then) =
_$AlbumModelCopyWithImpl<$Res, AlbumModel>;
@useResult
$Res call({int userId, int id, String title});
}
/// @nodoc
class _$AlbumModelCopyWithImpl<$Res, $Val extends AlbumModel>
implements $AlbumModelCopyWith<$Res> {
_$AlbumModelCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
@pragma('vm:prefer-inline')
@override
$Res call({
Object? userId = null,
Object? id = null,
Object? title = null,
}) {
return _then(_value.copyWith(
userId: null == userId
? _value.userId
: userId // ignore: cast_nullable_to_non_nullable
as int,
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as int,
title: null == title
? _value.title
: title // ignore: cast_nullable_to_non_nullable
as String,
) as $Val);
}
}
/// @nodoc
abstract class _$$_AlbumModelCopyWith<$Res>
implements $AlbumModelCopyWith<$Res> {
factory _$$_AlbumModelCopyWith(
_$_AlbumModel value, $Res Function(_$_AlbumModel) then) =
__$$_AlbumModelCopyWithImpl<$Res>;
@override
@useResult
$Res call({int userId, int id, String title});
}
/// @nodoc
class __$$_AlbumModelCopyWithImpl<$Res>
extends _$AlbumModelCopyWithImpl<$Res, _$_AlbumModel>
implements _$$_AlbumModelCopyWith<$Res> {
__$$_AlbumModelCopyWithImpl(
_$_AlbumModel _value, $Res Function(_$_AlbumModel) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? userId = null,
Object? id = null,
Object? title = null,
}) {
return _then(_$_AlbumModel(
userId: null == userId
? _value.userId
: userId // ignore: cast_nullable_to_non_nullable
as int,
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as int,
title: null == title
? _value.title
: title // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
@JsonSerializable()
class _$_AlbumModel implements _AlbumModel {
const _$_AlbumModel(
{required this.userId, required this.id, required this.title});
factory _$_AlbumModel.fromJson(Map<String, dynamic> json) =>
_$$_AlbumModelFromJson(json);
@override
final int userId;
@override
final int id;
@override
final String title;
@override
String toString() {
return 'AlbumModel(userId: $userId, id: $id, title: $title)';
}
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$_AlbumModelCopyWith<_$_AlbumModel> get copyWith =>
__$$_AlbumModelCopyWithImpl<_$_AlbumModel>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$_AlbumModelToJson(
this,
);
}
}
abstract class _AlbumModel implements AlbumModel {
const factory _AlbumModel(
{required final int userId,
required final int id,
required final String title}) = _$_AlbumModel;
factory _AlbumModel.fromJson(Map<String, dynamic> json) =
_$_AlbumModel.fromJson;
@override
int get userId;
@override
int get id;
@override
String get title;
@override
@JsonKey(ignore: true)
_$$_AlbumModelCopyWith<_$_AlbumModel> get copyWith =>
throw _privateConstructorUsedError;
}
@@ -0,0 +1,21 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'album_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$_AlbumModel _$$_AlbumModelFromJson(Map<String, dynamic> json) =>
_$_AlbumModel(
userId: json['userId'] as int,
id: json['id'] as int,
title: json['title'] as String,
);
Map<String, dynamic> _$$_AlbumModelToJson(_$_AlbumModel instance) =>
<String, dynamic>{
'userId': instance.userId,
'id': instance.id,
'title': instance.title,
};
@@ -0,0 +1,32 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
// Copyright (C) 2022 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:architecture_example/data/models/album_model.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'list_album_model.freezed.dart';
part 'list_album_model.g.dart';
@freezed
class ListAlbumModel with _$ListAlbumModel {
const factory ListAlbumModel({
required List<AlbumModel> albums,
}) = _ListAlbumModel;
factory ListAlbumModel.fromJson(Map<String, Object?> json) =>
_$ListAlbumModelFromJson(json);
}
@@ -0,0 +1,158 @@
// 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
part of 'list_album_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#custom-getters-and-methods');
ListAlbumModel _$ListAlbumModelFromJson(Map<String, dynamic> json) {
return _ListAlbumModel.fromJson(json);
}
/// @nodoc
mixin _$ListAlbumModel {
List<AlbumModel> get albums => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$ListAlbumModelCopyWith<ListAlbumModel> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ListAlbumModelCopyWith<$Res> {
factory $ListAlbumModelCopyWith(
ListAlbumModel value, $Res Function(ListAlbumModel) then) =
_$ListAlbumModelCopyWithImpl<$Res, ListAlbumModel>;
@useResult
$Res call({List<AlbumModel> albums});
}
/// @nodoc
class _$ListAlbumModelCopyWithImpl<$Res, $Val extends ListAlbumModel>
implements $ListAlbumModelCopyWith<$Res> {
_$ListAlbumModelCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
@pragma('vm:prefer-inline')
@override
$Res call({
Object? albums = null,
}) {
return _then(_value.copyWith(
albums: null == albums
? _value.albums
: albums // ignore: cast_nullable_to_non_nullable
as List<AlbumModel>,
) as $Val);
}
}
/// @nodoc
abstract class _$$_ListAlbumModelCopyWith<$Res>
implements $ListAlbumModelCopyWith<$Res> {
factory _$$_ListAlbumModelCopyWith(
_$_ListAlbumModel value, $Res Function(_$_ListAlbumModel) then) =
__$$_ListAlbumModelCopyWithImpl<$Res>;
@override
@useResult
$Res call({List<AlbumModel> albums});
}
/// @nodoc
class __$$_ListAlbumModelCopyWithImpl<$Res>
extends _$ListAlbumModelCopyWithImpl<$Res, _$_ListAlbumModel>
implements _$$_ListAlbumModelCopyWith<$Res> {
__$$_ListAlbumModelCopyWithImpl(
_$_ListAlbumModel _value, $Res Function(_$_ListAlbumModel) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? albums = null,
}) {
return _then(_$_ListAlbumModel(
albums: null == albums
? _value._albums
: albums // ignore: cast_nullable_to_non_nullable
as List<AlbumModel>,
));
}
}
/// @nodoc
@JsonSerializable()
class _$_ListAlbumModel implements _ListAlbumModel {
const _$_ListAlbumModel({required final List<AlbumModel> albums})
: _albums = albums;
factory _$_ListAlbumModel.fromJson(Map<String, dynamic> json) =>
_$$_ListAlbumModelFromJson(json);
final List<AlbumModel> _albums;
@override
List<AlbumModel> get albums {
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_albums);
}
@override
String toString() {
return 'ListAlbumModel(albums: $albums)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$_ListAlbumModel &&
const DeepCollectionEquality().equals(other._albums, _albums));
}
@JsonKey(ignore: true)
@override
int get hashCode =>
Object.hash(runtimeType, const DeepCollectionEquality().hash(_albums));
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$_ListAlbumModelCopyWith<_$_ListAlbumModel> get copyWith =>
__$$_ListAlbumModelCopyWithImpl<_$_ListAlbumModel>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$_ListAlbumModelToJson(
this,
);
}
}
abstract class _ListAlbumModel implements ListAlbumModel {
const factory _ListAlbumModel({required final List<AlbumModel> albums}) =
_$_ListAlbumModel;
factory _ListAlbumModel.fromJson(Map<String, dynamic> json) =
_$_ListAlbumModel.fromJson;
@override
List<AlbumModel> get albums;
@override
@JsonKey(ignore: true)
_$$_ListAlbumModelCopyWith<_$_ListAlbumModel> get copyWith =>
throw _privateConstructorUsedError;
}
@@ -0,0 +1,19 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'list_album_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$_ListAlbumModel _$$_ListAlbumModelFromJson(Map<String, dynamic> json) =>
_$_ListAlbumModel(
albums: (json['albums'] as List<dynamic>)
.map((e) => AlbumModel.fromJson(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> _$$_ListAlbumModelToJson(_$_ListAlbumModel instance) =>
<String, dynamic>{
'albums': instance.albums,
};
@@ -0,0 +1,34 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
// Copyright (C) 2022 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:architecture_example/data/models/photo_model.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'list_photo_model.freezed.dart';
part 'list_photo_model.g.dart';
@freezed
class ListPhotoModel with _$ListPhotoModel {
const factory ListPhotoModel({
required List<PhotoModel> photos,
}) = _ListPhotoModel;
factory ListPhotoModel.fromJson(Map<String, Object?> json) =>
_$ListPhotoModelFromJson(json);
}
@@ -0,0 +1,158 @@
// 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
part of 'list_photo_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#custom-getters-and-methods');
ListPhotoModel _$ListPhotoModelFromJson(Map<String, dynamic> json) {
return _ListPhotoModel.fromJson(json);
}
/// @nodoc
mixin _$ListPhotoModel {
List<PhotoModel> get photos => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$ListPhotoModelCopyWith<ListPhotoModel> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ListPhotoModelCopyWith<$Res> {
factory $ListPhotoModelCopyWith(
ListPhotoModel value, $Res Function(ListPhotoModel) then) =
_$ListPhotoModelCopyWithImpl<$Res, ListPhotoModel>;
@useResult
$Res call({List<PhotoModel> photos});
}
/// @nodoc
class _$ListPhotoModelCopyWithImpl<$Res, $Val extends ListPhotoModel>
implements $ListPhotoModelCopyWith<$Res> {
_$ListPhotoModelCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
@pragma('vm:prefer-inline')
@override
$Res call({
Object? photos = null,
}) {
return _then(_value.copyWith(
photos: null == photos
? _value.photos
: photos // ignore: cast_nullable_to_non_nullable
as List<PhotoModel>,
) as $Val);
}
}
/// @nodoc
abstract class _$$_ListPhotoModelCopyWith<$Res>
implements $ListPhotoModelCopyWith<$Res> {
factory _$$_ListPhotoModelCopyWith(
_$_ListPhotoModel value, $Res Function(_$_ListPhotoModel) then) =
__$$_ListPhotoModelCopyWithImpl<$Res>;
@override
@useResult
$Res call({List<PhotoModel> photos});
}
/// @nodoc
class __$$_ListPhotoModelCopyWithImpl<$Res>
extends _$ListPhotoModelCopyWithImpl<$Res, _$_ListPhotoModel>
implements _$$_ListPhotoModelCopyWith<$Res> {
__$$_ListPhotoModelCopyWithImpl(
_$_ListPhotoModel _value, $Res Function(_$_ListPhotoModel) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? photos = null,
}) {
return _then(_$_ListPhotoModel(
photos: null == photos
? _value._photos
: photos // ignore: cast_nullable_to_non_nullable
as List<PhotoModel>,
));
}
}
/// @nodoc
@JsonSerializable()
class _$_ListPhotoModel implements _ListPhotoModel {
const _$_ListPhotoModel({required final List<PhotoModel> photos})
: _photos = photos;
factory _$_ListPhotoModel.fromJson(Map<String, dynamic> json) =>
_$$_ListPhotoModelFromJson(json);
final List<PhotoModel> _photos;
@override
List<PhotoModel> get photos {
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_photos);
}
@override
String toString() {
return 'ListPhotoModel(photos: $photos)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$_ListPhotoModel &&
const DeepCollectionEquality().equals(other._photos, _photos));
}
@JsonKey(ignore: true)
@override
int get hashCode =>
Object.hash(runtimeType, const DeepCollectionEquality().hash(_photos));
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$_ListPhotoModelCopyWith<_$_ListPhotoModel> get copyWith =>
__$$_ListPhotoModelCopyWithImpl<_$_ListPhotoModel>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$_ListPhotoModelToJson(
this,
);
}
}
abstract class _ListPhotoModel implements ListPhotoModel {
const factory _ListPhotoModel({required final List<PhotoModel> photos}) =
_$_ListPhotoModel;
factory _ListPhotoModel.fromJson(Map<String, dynamic> json) =
_$_ListPhotoModel.fromJson;
@override
List<PhotoModel> get photos;
@override
@JsonKey(ignore: true)
_$$_ListPhotoModelCopyWith<_$_ListPhotoModel> get copyWith =>
throw _privateConstructorUsedError;
}
@@ -0,0 +1,19 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'list_photo_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$_ListPhotoModel _$$_ListPhotoModelFromJson(Map<String, dynamic> json) =>
_$_ListPhotoModel(
photos: (json['photos'] as List<dynamic>)
.map((e) => PhotoModel.fromJson(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> _$$_ListPhotoModelToJson(_$_ListPhotoModel instance) =>
<String, dynamic>{
'photos': instance.photos,
};
@@ -0,0 +1,35 @@
// Copyright (C) 2022 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:architecture_example/domain/entities/photo.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'photo_model.freezed.dart';
part 'photo_model.g.dart';
@freezed
class PhotoModel extends Photo with _$PhotoModel {
const factory PhotoModel({
required int albumId,
required int id,
required String title,
required String url,
required String thumbnailUrl,
}) = _PhotoModel;
factory PhotoModel.fromJson(Map<String, Object?> json) =>
_$PhotoModelFromJson(json);
}
@@ -0,0 +1,211 @@
// 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
part of 'photo_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#custom-getters-and-methods');
PhotoModel _$PhotoModelFromJson(Map<String, dynamic> json) {
return _PhotoModel.fromJson(json);
}
/// @nodoc
mixin _$PhotoModel {
int get albumId => throw _privateConstructorUsedError;
int get id => throw _privateConstructorUsedError;
String get title => throw _privateConstructorUsedError;
String get url => throw _privateConstructorUsedError;
String get thumbnailUrl => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$PhotoModelCopyWith<PhotoModel> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $PhotoModelCopyWith<$Res> {
factory $PhotoModelCopyWith(
PhotoModel value, $Res Function(PhotoModel) then) =
_$PhotoModelCopyWithImpl<$Res, PhotoModel>;
@useResult
$Res call(
{int albumId, int id, String title, String url, String thumbnailUrl});
}
/// @nodoc
class _$PhotoModelCopyWithImpl<$Res, $Val extends PhotoModel>
implements $PhotoModelCopyWith<$Res> {
_$PhotoModelCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
@pragma('vm:prefer-inline')
@override
$Res call({
Object? albumId = null,
Object? id = null,
Object? title = null,
Object? url = null,
Object? thumbnailUrl = null,
}) {
return _then(_value.copyWith(
albumId: null == albumId
? _value.albumId
: albumId // ignore: cast_nullable_to_non_nullable
as int,
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as int,
title: null == title
? _value.title
: title // ignore: cast_nullable_to_non_nullable
as String,
url: null == url
? _value.url
: url // ignore: cast_nullable_to_non_nullable
as String,
thumbnailUrl: null == thumbnailUrl
? _value.thumbnailUrl
: thumbnailUrl // ignore: cast_nullable_to_non_nullable
as String,
) as $Val);
}
}
/// @nodoc
abstract class _$$_PhotoModelCopyWith<$Res>
implements $PhotoModelCopyWith<$Res> {
factory _$$_PhotoModelCopyWith(
_$_PhotoModel value, $Res Function(_$_PhotoModel) then) =
__$$_PhotoModelCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{int albumId, int id, String title, String url, String thumbnailUrl});
}
/// @nodoc
class __$$_PhotoModelCopyWithImpl<$Res>
extends _$PhotoModelCopyWithImpl<$Res, _$_PhotoModel>
implements _$$_PhotoModelCopyWith<$Res> {
__$$_PhotoModelCopyWithImpl(
_$_PhotoModel _value, $Res Function(_$_PhotoModel) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? albumId = null,
Object? id = null,
Object? title = null,
Object? url = null,
Object? thumbnailUrl = null,
}) {
return _then(_$_PhotoModel(
albumId: null == albumId
? _value.albumId
: albumId // ignore: cast_nullable_to_non_nullable
as int,
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as int,
title: null == title
? _value.title
: title // ignore: cast_nullable_to_non_nullable
as String,
url: null == url
? _value.url
: url // ignore: cast_nullable_to_non_nullable
as String,
thumbnailUrl: null == thumbnailUrl
? _value.thumbnailUrl
: thumbnailUrl // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
@JsonSerializable()
class _$_PhotoModel implements _PhotoModel {
const _$_PhotoModel(
{required this.albumId,
required this.id,
required this.title,
required this.url,
required this.thumbnailUrl});
factory _$_PhotoModel.fromJson(Map<String, dynamic> json) =>
_$$_PhotoModelFromJson(json);
@override
final int albumId;
@override
final int id;
@override
final String title;
@override
final String url;
@override
final String thumbnailUrl;
@override
String toString() {
return 'PhotoModel(albumId: $albumId, id: $id, title: $title, url: $url, thumbnailUrl: $thumbnailUrl)';
}
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$_PhotoModelCopyWith<_$_PhotoModel> get copyWith =>
__$$_PhotoModelCopyWithImpl<_$_PhotoModel>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$_PhotoModelToJson(
this,
);
}
}
abstract class _PhotoModel implements PhotoModel {
const factory _PhotoModel(
{required final int albumId,
required final int id,
required final String title,
required final String url,
required final String thumbnailUrl}) = _$_PhotoModel;
factory _PhotoModel.fromJson(Map<String, dynamic> json) =
_$_PhotoModel.fromJson;
@override
int get albumId;
@override
int get id;
@override
String get title;
@override
String get url;
@override
String get thumbnailUrl;
@override
@JsonKey(ignore: true)
_$$_PhotoModelCopyWith<_$_PhotoModel> get copyWith =>
throw _privateConstructorUsedError;
}
@@ -0,0 +1,25 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'photo_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$_PhotoModel _$$_PhotoModelFromJson(Map<String, dynamic> json) =>
_$_PhotoModel(
albumId: json['albumId'] as int,
id: json['id'] as int,
title: json['title'] as String,
url: json['url'] as String,
thumbnailUrl: json['thumbnailUrl'] as String,
);
Map<String, dynamic> _$$_PhotoModelToJson(_$_PhotoModel instance) =>
<String, dynamic>{
'albumId': instance.albumId,
'id': instance.id,
'title': instance.title,
'url': instance.url,
'thumbnailUrl': instance.thumbnailUrl,
};
@@ -0,0 +1,118 @@
// Copyright (C) 2022 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:architecture_example/domain/data_sources/local/favorite_local_data_source.dart';
import 'package:architecture_example/domain/data_sources/remote/album_remote_data_source.dart';
import 'package:architecture_example/domain/data_sources/remote/photo_remote_data_source.dart';
import 'package:architecture_example/domain/entities/album.dart';
import 'package:architecture_example/domain/entities/photo.dart';
import 'package:architecture_example/domain/repositories/photo_repository.dart';
import 'package:wyatt_architecture/wyatt_architecture.dart';
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
class PhotoRepositoryImpl extends PhotoRepository {
final PhotoRemoteDataSource _photoRemoteDataSource;
final AlbumRemoteDataSource _albumRemoteDataSource;
final FavoriteLocalDataSource _favoriteLocalDataSource;
PhotoRepositoryImpl(
this._photoRemoteDataSource,
this._albumRemoteDataSource,
this._favoriteLocalDataSource,
);
@override
FutureResult<void> addPhotoToFavorites(Photo photo) => Result.tryCatchAsync(
() => _favoriteLocalDataSource.addPhotoToFavorites(photo),
(error) => ClientException('Cannot add photo to favorites.'),
);
@override
FutureResult<bool> checkIfPhotoIsInFavorites(int id) => Result.tryCatchAsync(
() => _favoriteLocalDataSource.checkIfPhotoIsInFavorites(id),
(error) =>
ClientException('Cannot check if photo `$id` is in favorites.'),
);
@override
FutureResult<void> deletePhotoFromFavorites(int id) => Result.tryCatchAsync(
() => _favoriteLocalDataSource.deletePhotoFromFavorites(id),
(error) => ClientException('Cannot delete photo `$id` from favorites.'),
);
@override
FutureResult<Album> getAlbum(int id) => Result.tryCatchAsync(
() => _albumRemoteDataSource.getAlbum(id),
(error) => ServerException('Cannot retrieve album $id.'),
);
@override
FutureResult<List<Album>> getAllAlbums({int? start, int? limit}) =>
Result.tryCatchAsync(
() => _albumRemoteDataSource.getAllAlbums(start: start, limit: limit),
(error) => ServerException('Cannot retrieve all albums.'),
);
@override
FutureResult<List<Photo>> getAllPhotos({int? start, int? limit}) async =>
Result.tryCatchAsync(
() => _photoRemoteDataSource.getAllPhotos(start: start, limit: limit),
(error) => ServerException('Cannot retrieve all photos.'),
);
@override
FutureResult<List<Photo>> getAllPhotosFromFavorites() async {
try {
final response = <Photo>[];
final favorites =
await _favoriteLocalDataSource.getAllPhotosFromFavorites();
final photos = await _photoRemoteDataSource.getAllPhotos();
for (final photo in photos) {
if (favorites.any((favId) => photo.id == favId)) {
response.add(photo);
}
}
return Ok(response);
} catch (_) {
return Err(
ClientException('Cannot retrieve all photos from favorites.'),
);
}
}
@override
FutureResult<Photo> getPhoto(int id) => Result.tryCatchAsync(
() => _photoRemoteDataSource.getPhoto(id),
(error) => ServerException('Cannot retrieve photo $id.'),
);
@override
FutureResult<List<Photo>> getPhotosFromAlbum(
int albumId, {
int? start,
int? limit,
}) async =>
Result.tryCatchAsync(
() => _photoRemoteDataSource.getPhotosFromAlbum(
albumId,
start: start,
limit: limit,
),
(error) =>
ServerException('Cannot retrieve all photos from album $albumId'),
);
}