feat(service): Add working database persistency
This commit is contained in:
		
							parent
							
								
									624c8bd78a
								
							
						
					
					
						commit
						432796d0c4
					
				| @ -4,16 +4,31 @@ import 'package:anitrack/src/ui/bloc/navigation_bloc.dart'; | ||||
| import 'package:anitrack/src/ui/constants.dart'; | ||||
| import 'package:anitrack/src/ui/pages/anime_list.dart'; | ||||
| import 'package:anitrack/src/ui/pages/anime_search.dart'; | ||||
| import 'package:anitrack/src/service/database.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | ||||
| import 'package:get_it/get_it.dart'; | ||||
| 
 | ||||
| void main() { | ||||
| void main() async { | ||||
|   final navKey = GlobalKey<NavigatorState>(); | ||||
| 
 | ||||
|   // Initialize the widgets binding for sqflite | ||||
|   WidgetsFlutterBinding.ensureInitialized(); | ||||
| 
 | ||||
|   // Initialize the database | ||||
|   final database = DatabaseService(); | ||||
|   await database.initialize(); | ||||
| 
 | ||||
|   // Register singletons | ||||
|   GetIt.I.registerSingleton<DatabaseService>(database); | ||||
|   GetIt.I.registerSingleton<AnimeListBloc>(AnimeListBloc()); | ||||
|   GetIt.I.registerSingleton<AnimeSearchBloc>(AnimeSearchBloc()); | ||||
|   GetIt.I.registerSingleton<NavigationBloc>(NavigationBloc(navKey)); | ||||
| 
 | ||||
|   // Load animes | ||||
|   GetIt.I.get<AnimeListBloc>().add( | ||||
|     AnimesLoadedEvent(), | ||||
|   ); | ||||
|    | ||||
|   runApp( | ||||
|     MultiBlocProvider( | ||||
|  | ||||
| @ -1,50 +1,64 @@ | ||||
| import 'package:freezed_annotation/freezed_annotation.dart'; | ||||
| 
 | ||||
| part 'anime.freezed.dart'; | ||||
| part 'anime.g.dart'; | ||||
| 
 | ||||
| /// The watch state of an anime | ||||
| enum AnimeTrackingState { | ||||
|   watching, | ||||
|   completed, | ||||
|   planToWatch, | ||||
|   dropped, | ||||
|   watching,    // 0 | ||||
|   completed,   // 1 | ||||
|   planToWatch, // 2 | ||||
|   dropped,     // 3 | ||||
| } | ||||
| 
 | ||||
| extension AnimeTrackStateExtension on AnimeTrackingState { | ||||
|   int toInteger() { | ||||
|     switch (this) { | ||||
|       case AnimeTrackingState.watching: return 0; | ||||
|       case AnimeTrackingState.completed: return 1; | ||||
|       case AnimeTrackingState.planToWatch: return 2; | ||||
|       case AnimeTrackingState.dropped: return 3; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class AnimeTrackingStateConverter implements JsonConverter<AnimeTrackingState, int> { | ||||
|   const AnimeTrackingStateConverter(); | ||||
| 
 | ||||
|   @override | ||||
|   AnimeTrackingState fromJson(int json) { | ||||
|     switch (json) { | ||||
|       case 0: return AnimeTrackingState.watching; | ||||
|       case 1: return AnimeTrackingState.completed; | ||||
|       case 2: return AnimeTrackingState.planToWatch; | ||||
|       case 3: return AnimeTrackingState.dropped; | ||||
|     } | ||||
| 
 | ||||
|     return AnimeTrackingState.planToWatch; | ||||
|   } | ||||
|    | ||||
|   @override | ||||
|   int toJson(AnimeTrackingState state) => state.toInteger(); | ||||
| } | ||||
| 
 | ||||
| /// Data about a tracked anime | ||||
| class AnimeTrackingData { | ||||
|   const AnimeTrackingData( | ||||
|     this.id, | ||||
|     this.state, | ||||
|     this.title, | ||||
|     this.episodesWatched, | ||||
|     this.episodesTotal, | ||||
|     this.thumbnailUrl, | ||||
|   ); | ||||
| 
 | ||||
|   /// The ID of the anime | ||||
|   final String id; | ||||
|    | ||||
|   /// The state of the anime | ||||
|   final AnimeTrackingState state; | ||||
| 
 | ||||
|   /// The title of the anime | ||||
|   final String title; | ||||
|    | ||||
|   /// Episodes in total. | ||||
|   final int? episodesTotal; | ||||
| 
 | ||||
|   /// Episodes watched. | ||||
|   final int episodesWatched; | ||||
| 
 | ||||
|   /// URL to the thumbnail/cover art for the anime. | ||||
|   final String thumbnailUrl; | ||||
| 
 | ||||
|   AnimeTrackingData copyWith( | ||||
| @freezed | ||||
| class AnimeTrackingData with _$AnimeTrackingData{ | ||||
|   factory AnimeTrackingData( | ||||
|     /// The ID of the anime | ||||
|     String id, | ||||
|     /// The state of the anime | ||||
|     @AnimeTrackingStateConverter() AnimeTrackingState state, | ||||
|     /// The title of the anime | ||||
|     String title, | ||||
|     /// Episodes in total. | ||||
|     int episodesWatched, | ||||
|   ) { | ||||
|     return AnimeTrackingData( | ||||
|       id, | ||||
|       state, | ||||
|       title, | ||||
|       episodesWatched, | ||||
|       episodesTotal, | ||||
|       thumbnailUrl, | ||||
|     ); | ||||
|   } | ||||
|     /// Episodes watched. | ||||
|     int? episodesTotal, | ||||
|     /// URL to the thumbnail/cover art for the anime. | ||||
|     String thumbnailUrl, | ||||
|   ) = _AnimeTrackingData; | ||||
| 
 | ||||
|   /// JSON | ||||
|   factory AnimeTrackingData.fromJson(Map<String, dynamic> json) => _$AnimeTrackingDataFromJson(json); | ||||
| } | ||||
|  | ||||
							
								
								
									
										295
									
								
								lib/src/data/anime.freezed.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										295
									
								
								lib/src/data/anime.freezed.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,295 @@ | ||||
| // 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 'anime.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'); | ||||
| 
 | ||||
| AnimeTrackingData _$AnimeTrackingDataFromJson(Map<String, dynamic> json) { | ||||
|   return _AnimeTrackingData.fromJson(json); | ||||
| } | ||||
| 
 | ||||
| /// @nodoc | ||||
| mixin _$AnimeTrackingData { | ||||
|   /// The ID of the anime | ||||
|   String get id => throw _privateConstructorUsedError; | ||||
| 
 | ||||
|   /// The state of the anime | ||||
|   @AnimeTrackingStateConverter() | ||||
|   AnimeTrackingState get state => throw _privateConstructorUsedError; | ||||
| 
 | ||||
|   /// The title of the anime | ||||
|   String get title => throw _privateConstructorUsedError; | ||||
| 
 | ||||
|   /// Episodes in total. | ||||
|   int get episodesWatched => throw _privateConstructorUsedError; | ||||
| 
 | ||||
|   /// Episodes watched. | ||||
|   int? get episodesTotal => throw _privateConstructorUsedError; | ||||
| 
 | ||||
|   /// URL to the thumbnail/cover art for the anime. | ||||
|   String get thumbnailUrl => throw _privateConstructorUsedError; | ||||
| 
 | ||||
|   Map<String, dynamic> toJson() => throw _privateConstructorUsedError; | ||||
|   @JsonKey(ignore: true) | ||||
|   $AnimeTrackingDataCopyWith<AnimeTrackingData> get copyWith => | ||||
|       throw _privateConstructorUsedError; | ||||
| } | ||||
| 
 | ||||
| /// @nodoc | ||||
| abstract class $AnimeTrackingDataCopyWith<$Res> { | ||||
|   factory $AnimeTrackingDataCopyWith( | ||||
|           AnimeTrackingData value, $Res Function(AnimeTrackingData) then) = | ||||
|       _$AnimeTrackingDataCopyWithImpl<$Res>; | ||||
|   $Res call( | ||||
|       {String id, | ||||
|       @AnimeTrackingStateConverter() AnimeTrackingState state, | ||||
|       String title, | ||||
|       int episodesWatched, | ||||
|       int? episodesTotal, | ||||
|       String thumbnailUrl}); | ||||
| } | ||||
| 
 | ||||
| /// @nodoc | ||||
| class _$AnimeTrackingDataCopyWithImpl<$Res> | ||||
|     implements $AnimeTrackingDataCopyWith<$Res> { | ||||
|   _$AnimeTrackingDataCopyWithImpl(this._value, this._then); | ||||
| 
 | ||||
|   final AnimeTrackingData _value; | ||||
|   // ignore: unused_field | ||||
|   final $Res Function(AnimeTrackingData) _then; | ||||
| 
 | ||||
|   @override | ||||
|   $Res call({ | ||||
|     Object? id = freezed, | ||||
|     Object? state = freezed, | ||||
|     Object? title = freezed, | ||||
|     Object? episodesWatched = freezed, | ||||
|     Object? episodesTotal = freezed, | ||||
|     Object? thumbnailUrl = freezed, | ||||
|   }) { | ||||
|     return _then(_value.copyWith( | ||||
|       id: id == freezed | ||||
|           ? _value.id | ||||
|           : id // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       state: state == freezed | ||||
|           ? _value.state | ||||
|           : state // ignore: cast_nullable_to_non_nullable | ||||
|               as AnimeTrackingState, | ||||
|       title: title == freezed | ||||
|           ? _value.title | ||||
|           : title // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       episodesWatched: episodesWatched == freezed | ||||
|           ? _value.episodesWatched | ||||
|           : episodesWatched // ignore: cast_nullable_to_non_nullable | ||||
|               as int, | ||||
|       episodesTotal: episodesTotal == freezed | ||||
|           ? _value.episodesTotal | ||||
|           : episodesTotal // ignore: cast_nullable_to_non_nullable | ||||
|               as int?, | ||||
|       thumbnailUrl: thumbnailUrl == freezed | ||||
|           ? _value.thumbnailUrl | ||||
|           : thumbnailUrl // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|     )); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /// @nodoc | ||||
| abstract class _$$_AnimeTrackingDataCopyWith<$Res> | ||||
|     implements $AnimeTrackingDataCopyWith<$Res> { | ||||
|   factory _$$_AnimeTrackingDataCopyWith(_$_AnimeTrackingData value, | ||||
|           $Res Function(_$_AnimeTrackingData) then) = | ||||
|       __$$_AnimeTrackingDataCopyWithImpl<$Res>; | ||||
|   @override | ||||
|   $Res call( | ||||
|       {String id, | ||||
|       @AnimeTrackingStateConverter() AnimeTrackingState state, | ||||
|       String title, | ||||
|       int episodesWatched, | ||||
|       int? episodesTotal, | ||||
|       String thumbnailUrl}); | ||||
| } | ||||
| 
 | ||||
| /// @nodoc | ||||
| class __$$_AnimeTrackingDataCopyWithImpl<$Res> | ||||
|     extends _$AnimeTrackingDataCopyWithImpl<$Res> | ||||
|     implements _$$_AnimeTrackingDataCopyWith<$Res> { | ||||
|   __$$_AnimeTrackingDataCopyWithImpl( | ||||
|       _$_AnimeTrackingData _value, $Res Function(_$_AnimeTrackingData) _then) | ||||
|       : super(_value, (v) => _then(v as _$_AnimeTrackingData)); | ||||
| 
 | ||||
|   @override | ||||
|   _$_AnimeTrackingData get _value => super._value as _$_AnimeTrackingData; | ||||
| 
 | ||||
|   @override | ||||
|   $Res call({ | ||||
|     Object? id = freezed, | ||||
|     Object? state = freezed, | ||||
|     Object? title = freezed, | ||||
|     Object? episodesWatched = freezed, | ||||
|     Object? episodesTotal = freezed, | ||||
|     Object? thumbnailUrl = freezed, | ||||
|   }) { | ||||
|     return _then(_$_AnimeTrackingData( | ||||
|       id == freezed | ||||
|           ? _value.id | ||||
|           : id // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       state == freezed | ||||
|           ? _value.state | ||||
|           : state // ignore: cast_nullable_to_non_nullable | ||||
|               as AnimeTrackingState, | ||||
|       title == freezed | ||||
|           ? _value.title | ||||
|           : title // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|       episodesWatched == freezed | ||||
|           ? _value.episodesWatched | ||||
|           : episodesWatched // ignore: cast_nullable_to_non_nullable | ||||
|               as int, | ||||
|       episodesTotal == freezed | ||||
|           ? _value.episodesTotal | ||||
|           : episodesTotal // ignore: cast_nullable_to_non_nullable | ||||
|               as int?, | ||||
|       thumbnailUrl == freezed | ||||
|           ? _value.thumbnailUrl | ||||
|           : thumbnailUrl // ignore: cast_nullable_to_non_nullable | ||||
|               as String, | ||||
|     )); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /// @nodoc | ||||
| @JsonSerializable() | ||||
| class _$_AnimeTrackingData implements _AnimeTrackingData { | ||||
|   _$_AnimeTrackingData(this.id, @AnimeTrackingStateConverter() this.state, | ||||
|       this.title, this.episodesWatched, this.episodesTotal, this.thumbnailUrl); | ||||
| 
 | ||||
|   factory _$_AnimeTrackingData.fromJson(Map<String, dynamic> json) => | ||||
|       _$$_AnimeTrackingDataFromJson(json); | ||||
| 
 | ||||
|   /// The ID of the anime | ||||
|   @override | ||||
|   final String id; | ||||
| 
 | ||||
|   /// The state of the anime | ||||
|   @override | ||||
|   @AnimeTrackingStateConverter() | ||||
|   final AnimeTrackingState state; | ||||
| 
 | ||||
|   /// The title of the anime | ||||
|   @override | ||||
|   final String title; | ||||
| 
 | ||||
|   /// Episodes in total. | ||||
|   @override | ||||
|   final int episodesWatched; | ||||
| 
 | ||||
|   /// Episodes watched. | ||||
|   @override | ||||
|   final int? episodesTotal; | ||||
| 
 | ||||
|   /// URL to the thumbnail/cover art for the anime. | ||||
|   @override | ||||
|   final String thumbnailUrl; | ||||
| 
 | ||||
|   @override | ||||
|   String toString() { | ||||
|     return 'AnimeTrackingData(id: $id, state: $state, title: $title, episodesWatched: $episodesWatched, episodesTotal: $episodesTotal, thumbnailUrl: $thumbnailUrl)'; | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   bool operator ==(dynamic other) { | ||||
|     return identical(this, other) || | ||||
|         (other.runtimeType == runtimeType && | ||||
|             other is _$_AnimeTrackingData && | ||||
|             const DeepCollectionEquality().equals(other.id, id) && | ||||
|             const DeepCollectionEquality().equals(other.state, state) && | ||||
|             const DeepCollectionEquality().equals(other.title, title) && | ||||
|             const DeepCollectionEquality() | ||||
|                 .equals(other.episodesWatched, episodesWatched) && | ||||
|             const DeepCollectionEquality() | ||||
|                 .equals(other.episodesTotal, episodesTotal) && | ||||
|             const DeepCollectionEquality() | ||||
|                 .equals(other.thumbnailUrl, thumbnailUrl)); | ||||
|   } | ||||
| 
 | ||||
|   @JsonKey(ignore: true) | ||||
|   @override | ||||
|   int get hashCode => Object.hash( | ||||
|       runtimeType, | ||||
|       const DeepCollectionEquality().hash(id), | ||||
|       const DeepCollectionEquality().hash(state), | ||||
|       const DeepCollectionEquality().hash(title), | ||||
|       const DeepCollectionEquality().hash(episodesWatched), | ||||
|       const DeepCollectionEquality().hash(episodesTotal), | ||||
|       const DeepCollectionEquality().hash(thumbnailUrl)); | ||||
| 
 | ||||
|   @JsonKey(ignore: true) | ||||
|   @override | ||||
|   _$$_AnimeTrackingDataCopyWith<_$_AnimeTrackingData> get copyWith => | ||||
|       __$$_AnimeTrackingDataCopyWithImpl<_$_AnimeTrackingData>( | ||||
|           this, _$identity); | ||||
| 
 | ||||
|   @override | ||||
|   Map<String, dynamic> toJson() { | ||||
|     return _$$_AnimeTrackingDataToJson( | ||||
|       this, | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| abstract class _AnimeTrackingData implements AnimeTrackingData { | ||||
|   factory _AnimeTrackingData( | ||||
|       final String id, | ||||
|       @AnimeTrackingStateConverter() final AnimeTrackingState state, | ||||
|       final String title, | ||||
|       final int episodesWatched, | ||||
|       final int? episodesTotal, | ||||
|       final String thumbnailUrl) = _$_AnimeTrackingData; | ||||
| 
 | ||||
|   factory _AnimeTrackingData.fromJson(Map<String, dynamic> json) = | ||||
|       _$_AnimeTrackingData.fromJson; | ||||
| 
 | ||||
|   @override | ||||
| 
 | ||||
|   /// The ID of the anime | ||||
|   String get id; | ||||
|   @override | ||||
| 
 | ||||
|   /// The state of the anime | ||||
|   @AnimeTrackingStateConverter() | ||||
|   AnimeTrackingState get state; | ||||
|   @override | ||||
| 
 | ||||
|   /// The title of the anime | ||||
|   String get title; | ||||
|   @override | ||||
| 
 | ||||
|   /// Episodes in total. | ||||
|   int get episodesWatched; | ||||
|   @override | ||||
| 
 | ||||
|   /// Episodes watched. | ||||
|   int? get episodesTotal; | ||||
|   @override | ||||
| 
 | ||||
|   /// URL to the thumbnail/cover art for the anime. | ||||
|   String get thumbnailUrl; | ||||
|   @override | ||||
|   @JsonKey(ignore: true) | ||||
|   _$$_AnimeTrackingDataCopyWith<_$_AnimeTrackingData> get copyWith => | ||||
|       throw _privateConstructorUsedError; | ||||
| } | ||||
							
								
								
									
										28
									
								
								lib/src/data/anime.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								lib/src/data/anime.g.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| // GENERATED CODE - DO NOT MODIFY BY HAND | ||||
| 
 | ||||
| part of 'anime.dart'; | ||||
| 
 | ||||
| // ************************************************************************** | ||||
| // JsonSerializableGenerator | ||||
| // ************************************************************************** | ||||
| 
 | ||||
| _$_AnimeTrackingData _$$_AnimeTrackingDataFromJson(Map<String, dynamic> json) => | ||||
|     _$_AnimeTrackingData( | ||||
|       json['id'] as String, | ||||
|       const AnimeTrackingStateConverter().fromJson(json['state'] as int), | ||||
|       json['title'] as String, | ||||
|       json['episodesWatched'] as int, | ||||
|       json['episodesTotal'] as int?, | ||||
|       json['thumbnailUrl'] as String, | ||||
|     ); | ||||
| 
 | ||||
| Map<String, dynamic> _$$_AnimeTrackingDataToJson( | ||||
|         _$_AnimeTrackingData instance) => | ||||
|     <String, dynamic>{ | ||||
|       'id': instance.id, | ||||
|       'state': const AnimeTrackingStateConverter().toJson(instance.state), | ||||
|       'title': instance.title, | ||||
|       'episodesWatched': instance.episodesWatched, | ||||
|       'episodesTotal': instance.episodesTotal, | ||||
|       'thumbnailUrl': instance.thumbnailUrl, | ||||
|     }; | ||||
							
								
								
									
										55
									
								
								lib/src/service/database.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								lib/src/service/database.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,55 @@ | ||||
| import 'package:anitrack/src/data/anime.dart'; | ||||
| import 'package:sqflite/sqflite.dart'; | ||||
| 
 | ||||
| const animeTable = 'Anime'; | ||||
| 
 | ||||
| Future<void> _createDatabase(Database db, int version) async { | ||||
|   await db.execute( | ||||
|     ''' | ||||
|     CREATE TABLE $animeTable( | ||||
|       id TEXT NOT NULL PRIMARY KEY, | ||||
|       state INTEGER NOT NULL, | ||||
|       episodesTotal INTEGER, | ||||
|       episodesWatched INTEGER NOT NULL, | ||||
|       thumbnailUrl TEXT NOT NULL, | ||||
|       title TEXT NOT NULL | ||||
|     )''', | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| class DatabaseService { | ||||
|   late final Database _db; | ||||
| 
 | ||||
|   Future<void> initialize() async { | ||||
|     _db = await openDatabase( | ||||
|       'anitrack.db', | ||||
|       version: 1, | ||||
|       onCreate: _createDatabase, | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   Future<List<AnimeTrackingData>> loadAnimes() async { | ||||
|     final animes = await _db.query(animeTable); | ||||
| 
 | ||||
|     return animes | ||||
|       .cast<Map<String, dynamic>>() | ||||
|       .map((Map<String, dynamic> anime) => AnimeTrackingData.fromJson(anime)) | ||||
|       .toList(); | ||||
|   } | ||||
|    | ||||
|   Future<void> addAnime(AnimeTrackingData data) async { | ||||
|     await _db.insert( | ||||
|       animeTable, | ||||
|       data.toJson(), | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   Future<void> updateAnime(AnimeTrackingData data) async { | ||||
|     await _db.update( | ||||
|       animeTable, | ||||
|       data.toJson(), | ||||
|       where: 'id = ?', | ||||
|       whereArgs: [data.id], | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @ -1,7 +1,9 @@ | ||||
| import 'dart:math'; | ||||
| import 'package:anitrack/src/data/anime.dart'; | ||||
| import 'package:anitrack/src/service/database.dart'; | ||||
| import 'package:bloc/bloc.dart'; | ||||
| import 'package:freezed_annotation/freezed_annotation.dart'; | ||||
| import 'package:get_it/get_it.dart'; | ||||
| 
 | ||||
| part 'anime_list_state.dart'; | ||||
| part 'anime_list_event.dart'; | ||||
| @ -12,10 +14,13 @@ class AnimeListBloc extends Bloc<AnimeListEvent, AnimeListState> { | ||||
|     on<AnimeAddedEvent>(_onAnimeAdded); | ||||
|     on<AnimeEpisodeIncrementedEvent>(_onIncremented); | ||||
|     on<AnimeEpisodeDecrementedEvent>(_onDecremented); | ||||
|     on<AnimesLoadedEvent>(_onAnimesLoaded); | ||||
|   } | ||||
| 
 | ||||
|   // TODO: Remove | ||||
|   Future<void> _onAnimeAdded(AnimeAddedEvent event, Emitter<AnimeListState> emit) async { | ||||
|     // Add the anime to the database | ||||
|     await GetIt.I.get<DatabaseService>().addAnime(event.data); | ||||
| 
 | ||||
|     emit( | ||||
|       state.copyWith( | ||||
|         animes: List.from([ | ||||
| @ -34,16 +39,18 @@ class AnimeListBloc extends Bloc<AnimeListEvent, AnimeListState> { | ||||
|     if (anime.episodesTotal != null && anime.episodesWatched + 1 > anime.episodesTotal!) return; | ||||
| 
 | ||||
|     final newList = List<AnimeTrackingData>.from(state.animes); | ||||
|     newList[index] = anime.copyWith( | ||||
|       anime.episodesWatched + 1, | ||||
|     final newAnime = anime.copyWith( | ||||
|       episodesWatched: anime.episodesWatched + 1, | ||||
|     ); | ||||
|     newList[index] = newAnime; | ||||
| 
 | ||||
|     emit( | ||||
|       state.copyWith( | ||||
|         animes: newList, | ||||
|       ), | ||||
|     ); | ||||
|     print('${event.id} incremented'); | ||||
| 
 | ||||
|     await GetIt.I.get<DatabaseService>().updateAnime(newAnime); | ||||
|   } | ||||
| 
 | ||||
|   Future<void> _onDecremented(AnimeEpisodeDecrementedEvent event, Emitter<AnimeListState> emit) async { | ||||
| @ -54,15 +61,25 @@ class AnimeListBloc extends Bloc<AnimeListEvent, AnimeListState> { | ||||
|     if (anime.episodesWatched - 1 < 0) return; | ||||
| 
 | ||||
|     final newList = List<AnimeTrackingData>.from(state.animes); | ||||
|     newList[index] = anime.copyWith( | ||||
|       anime.episodesWatched - 1, | ||||
|     final newAnime = anime.copyWith( | ||||
|       episodesWatched: anime.episodesWatched - 1, | ||||
|     ); | ||||
|     newList[index] = newAnime; | ||||
| 
 | ||||
|     emit( | ||||
|       state.copyWith( | ||||
|         animes: newList, | ||||
|       ), | ||||
|     ); | ||||
|     print('${event.id} decremented'); | ||||
| 
 | ||||
|     await GetIt.I.get<DatabaseService>().updateAnime(newAnime); | ||||
|   } | ||||
| 
 | ||||
|   Future<void> _onAnimesLoaded(AnimesLoadedEvent event, Emitter<AnimeListState> emit) async { | ||||
|     emit( | ||||
|       state.copyWith( | ||||
|         animes: await GetIt.I.get<DatabaseService>().loadAnimes(), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -22,3 +22,6 @@ class AnimeAddedEvent extends AnimeListEvent { | ||||
|   /// The anime to add. | ||||
|   final AnimeTrackingData data; | ||||
| } | ||||
| 
 | ||||
| /// Triggered when animes are to be loaded from the database | ||||
| class AnimesLoadedEvent extends AnimeListEvent {} | ||||
|  | ||||
| @ -79,20 +79,27 @@ class AnimeSearchPage extends StatelessWidget { | ||||
|                                   child: Column( | ||||
|                                     mainAxisSize: MainAxisSize.min, | ||||
|                                     children: [ | ||||
|                                       Text( | ||||
|                                         item.title, | ||||
|                                         style: Theme.of(context).textTheme.titleLarge, | ||||
|                                         maxLines: 2, | ||||
|                                         softWrap: true, | ||||
|                                         overflow: TextOverflow.ellipsis, | ||||
|                                       Align( | ||||
|                                         alignment: Alignment.centerLeft, | ||||
|                                         child: Text( | ||||
|                                           item.title, | ||||
|                                           style: Theme.of(context).textTheme.titleLarge, | ||||
|                                           maxLines: 2, | ||||
|                                           softWrap: true, | ||||
|                                           overflow: TextOverflow.ellipsis, | ||||
|                                         ), | ||||
|                                       ), | ||||
| 
 | ||||
|                                       Text( | ||||
|                                         item.description, | ||||
|                                         style: Theme.of(context).textTheme.bodyMedium, | ||||
|                                         maxLines: 4, | ||||
|                                         softWrap: true, | ||||
|                                         overflow: TextOverflow.ellipsis, | ||||
|                                       Align( | ||||
|                                         alignment: Alignment.centerLeft, | ||||
|                                         child: Text( | ||||
|                                           item.description, | ||||
|                                           textAlign: TextAlign.justify, | ||||
|                                           style: Theme.of(context).textTheme.bodyMedium, | ||||
|                                           maxLines: 4, | ||||
|                                           softWrap: true, | ||||
|                                           overflow: TextOverflow.ellipsis, | ||||
|                                         ), | ||||
|                                       ), | ||||
|                                     ], | ||||
|                                   ), | ||||
|  | ||||
							
								
								
									
										41
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								pubspec.lock
									
									
									
									
									
								
							| @ -292,12 +292,19 @@ packages: | ||||
|     source: hosted | ||||
|     version: "0.6.5" | ||||
|   json_annotation: | ||||
|     dependency: transitive | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: json_annotation | ||||
|       url: "https://pub.dartlang.org" | ||||
|     source: hosted | ||||
|     version: "4.8.0" | ||||
|     version: "4.6.0" | ||||
|   json_serializable: | ||||
|     dependency: "direct dev" | ||||
|     description: | ||||
|       name: json_serializable | ||||
|       url: "https://pub.dartlang.org" | ||||
|     source: hosted | ||||
|     version: "6.3.2" | ||||
|   lints: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @ -415,6 +422,13 @@ packages: | ||||
|       url: "https://pub.dartlang.org" | ||||
|     source: hosted | ||||
|     version: "1.2.7" | ||||
|   source_helper: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: source_helper | ||||
|       url: "https://pub.dartlang.org" | ||||
|     source: hosted | ||||
|     version: "1.3.3" | ||||
|   source_span: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @ -422,6 +436,20 @@ packages: | ||||
|       url: "https://pub.dartlang.org" | ||||
|     source: hosted | ||||
|     version: "1.9.0" | ||||
|   sqflite: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: sqflite | ||||
|       url: "https://pub.dartlang.org" | ||||
|     source: hosted | ||||
|     version: "2.2.4+1" | ||||
|   sqflite_common: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: sqflite_common | ||||
|       url: "https://pub.dartlang.org" | ||||
|     source: hosted | ||||
|     version: "2.4.2+2" | ||||
|   stack_trace: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @ -457,6 +485,13 @@ packages: | ||||
|       url: "https://pub.dartlang.org" | ||||
|     source: hosted | ||||
|     version: "2.0.0+3" | ||||
|   synchronized: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: synchronized | ||||
|       url: "https://pub.dartlang.org" | ||||
|     source: hosted | ||||
|     version: "3.0.1" | ||||
|   term_glyph: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @ -515,4 +550,4 @@ packages: | ||||
|     version: "3.1.1" | ||||
| sdks: | ||||
|   dart: ">=2.18.4 <3.0.0" | ||||
|   flutter: ">=1.16.0" | ||||
|   flutter: ">=3.3.0" | ||||
|  | ||||
| @ -16,7 +16,8 @@ dependencies: | ||||
|   freezed_annotation: 2.1.0 | ||||
|   get_it: ^7.2.0 | ||||
|   jikan_api: ^2.0.0 | ||||
| 
 | ||||
|   json_annotation: 4.6.0 | ||||
|   sqflite: ^2.2.4+1 | ||||
|   swipeable_tile: ^2.0.0+3 | ||||
| 
 | ||||
| dev_dependencies: | ||||
| @ -25,6 +26,7 @@ dev_dependencies: | ||||
|     sdk: flutter | ||||
|   flutter_lints: ^2.0.0 | ||||
|   freezed: ^2.1.0+1 | ||||
|   json_serializable: ^6.3.1 | ||||
| 
 | ||||
| flutter: | ||||
|   uses-material-design: true | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user