Skip to content

Commit

Permalink
Implement book label logic
Browse files Browse the repository at this point in the history
  • Loading branch information
lockieRichter committed Nov 6, 2023
1 parent 9e65a5c commit d77456f
Show file tree
Hide file tree
Showing 22 changed files with 496 additions and 94 deletions.
39 changes: 23 additions & 16 deletions assets/translations/de-DE.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
{
"add": "Hinzufügen",
"navigation": {
"library": "Meine Bücher",
"stats": "Statistiken",
"timeline": "Timeline",
"wishlist": "Wunschliste",
"recommendations": "Vorschläge",
"book-keeping": "Verwaltung",
"settings": "Einstellungen"
},
"anonymous-user": "Anonymer Bücherwurm",
"account_creation_failed": "Dein Konto konnte nicht angelegt werden.",
"add": "Hinzufügen",
"add_book": {
"manual": "Manuell eingeben",
"query": "Titel suche",
"scan": "Buchode scannen"
},
"add_label_bottom_sheet": {
"choose_a_color": "TODO",
"create_new_label": "TODO",
"name": "TODO",
"no_labels_available": "TODO",
"pick_a_label": "TODO"
},
"anonymous-user": "Anonymer Bücherwurm",
"anonymous_login": {
"description": "Deine Daten sind gesichert, solange du eingeloggt bist. Wenn du dich ausloggst, werden all deine Daten gelöscht.\n\nDu kannst dein Konto später noch anlegen.",
"title": "Anonymer Login"
Expand Down Expand Up @@ -51,6 +49,15 @@
"login_with_email": "Weiter mit Mail",
"login_with_google": "Weiter mit Google",
"logout": "Logout",
"navigation": {
"book-keeping": "Verwaltung",
"library": "Meine Bücher",
"recommendations": "Vorschläge",
"settings": "Einstellungen",
"stats": "Statistiken",
"timeline": "Timeline",
"wishlist": "Wunschliste"
},
"no_thanks": "TODO",
"not_my_book": "Nicht mein Buch",
"password": "Passwort",
Expand All @@ -65,13 +72,13 @@
"reset_password": "TODO",
"reset_password_text": "TODO",
"search": {
"search": "Suchen",
"empty": {
"action": "Online suchen",
"description": "Nichts gefunden. Sollen wir online suchen?"
},
"hint": "Durchsuche deine Bibliothek...",
"page-hint": "Tippe etwas um deine Bibliothek zu durchsuchen!",
"empty": {
"description": "Nichts gefunden. Sollen wir online suchen?",
"action": "Online suchen"
}
"search": "Suchen"
},
"select": "Wählen",
"settings": {
Expand Down
18 changes: 13 additions & 5 deletions assets/translations/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,19 @@
},
"anonymous-user": "Anonymous Bookworm",
"account_creation_failed": "Failed to create account",
"add": "Add",
"add_book": {
"manual": "Add manual",
"query": "Title search",
"scan": "Scan book"
},
"add_label_bottom_sheet": {
"choose_a_color": "Choose a color",
"create_new_label": "Create new label",
"name": "Name",
"no_labels_available": "No labels available.\nCreate a new label first.",
"pick_a_label": "Pick a label"
},
"anonymous_login": {
"description": "Your data will be stored as long as you stay signed in. When you sign out, your data will be erased.\n\nYou can always upgrade to a regular account later on.",
"title": "Anonymous Login"
Expand Down Expand Up @@ -65,13 +73,13 @@
"reset_password": "Reset Password",
"reset_password_text": "A link will be sent to your registered email address with instructions on how to reset your password.",
"search": {
"search": "Search",
"empty": {
"action": "Search online",
"description": "Nothing found. Should we search online?"
},
"hint": "Search your library...",
"page-hint": "Start typing to search your library!",
"empty": {
"description": "Nothing found. Should we search online?",
"action": "Search online"
}
"search": "Search"
},
"select": "Select",
"settings": {
Expand Down
7 changes: 7 additions & 0 deletions build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
targets:
$default:
builders:
json_serializable:
options:
any_map: true
explicit_to_json: true
2 changes: 1 addition & 1 deletion lib/src/data/book/book_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ abstract class BookRepository {

Stream<List<Book>> getAllBooks();

Future<Book> getBook(String id);
Stream<Book> getBook(String id);

Future<void> create(Book book);

Expand Down
12 changes: 2 additions & 10 deletions lib/src/data/book/entity/book.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part 'book.freezed.dart';
part 'book.g.dart';

@freezed
@Freezed(makeCollectionsUnmodifiable: false)
class Book with _$Book {
const Book._();

Expand All @@ -32,19 +32,11 @@ class Book with _$Book {
required int rating,
required String? notes,
required String? summary,
@Default([]) List<BookLabel> labels,
@Default(<BookLabel>[]) List<BookLabel> labels,
}) = _Book;

factory Book.fromJson(Map<String, Object?> json) => _$BookFromJson(json);

int get progressPercentage =>
pageCount != 0 ? ((currentPage / pageCount) * 100).toInt() : 0;

void addLabel(BookLabel label) {
labels.add(label);
}

void removeLabel(String labelId) {
labels.removeWhere((label) => label.id == labelId);
}
}
2 changes: 1 addition & 1 deletion lib/src/data/book/entity/book_label.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part 'book_label.freezed.dart';
part 'book_label.g.dart';

@freezed
@Freezed(makeCollectionsUnmodifiable: false)
class BookLabel with _$BookLabel {
const factory BookLabel({
required String id,
Expand Down
33 changes: 25 additions & 8 deletions lib/src/data/book/firebase_book_label_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,43 @@ class FirebaseBookLabelRepository implements BookLabelRepository {

@override
Future<void> createBookLabel(BookLabel label) {
// TODO: implement createBookLabel
throw UnimplementedError();
final newRef = _labelsRef().push();

final data = label.copyWith(id: newRef.key!).toJson();

return newRef.set(data);
}

@override
Future<void> deleteBookLabel(String id) {
// TODO: implement deleteBookLabel
throw UnimplementedError();
return _labelsRef().child(id).remove();
}

@override
Stream<List<BookLabel>> getBookLabels() {
// TODO: implement getBookLabels
throw UnimplementedError();
return _labelsRef().onValue.map(
(DatabaseEvent event) {
final Map<String, dynamic>? data = event.snapshot.toMap();

if (data == null) {
return [];
}

return data.values.map(
(value) {
final Map<String, dynamic> bookMap =
(value as Map<dynamic, dynamic>).cast();
return BookLabel.fromJson(bookMap);
},
).toList();
},
);
}

DatabaseReference _rootRef() {
DatabaseReference _labelsRef() {
// At this point we can assume that the customer is already logged in, even as anonymous user
final user = _fbAuth.currentUser!.uid;
return _fbDb.ref('users/$user/labels');
return _fbDb.ref('users/$user/labels/');
}
}

Expand Down
83 changes: 52 additions & 31 deletions lib/src/data/book/firebase_book_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class FirebaseBookRepository implements BookRepository {

@override
Future<void> create(Book book) {
final newRef = _rootRef().push();
final newRef = _booksRef().push();

final data = book.copyWith(id: newRef.key!).toJson();

Expand All @@ -23,44 +23,50 @@ class FirebaseBookRepository implements BookRepository {

@override
Future<void> delete(String id) {
return _rootRef().child(id).remove();
return _booksRef().child(id).remove();
}

@override
Stream<List<Book>> getAllBooks() {
return _rootRef().onValue.map(
return _booksRef().onValue.map(
(DatabaseEvent event) {
final Map<String, dynamic>? data = event.snapshot.toMap();

if (data == null) {
return [];
}

return data
.map(
(key, value) {
final Map<String, dynamic> bookMap =
(value as Map<dynamic, dynamic>).cast();
final Book bookValue = Book.fromJson(bookMap);
return MapEntry(key, bookValue);
},
)
.values
.toList();
return data.values.map(
(value) {
final Map<String, dynamic> bookMap =
(value as Map<dynamic, dynamic>).cast();
return Book.fromJson(bookMap);
},
).toList();
},
);
}

@override
Future<Book> getBook(String id) async {
final bookSnapshot = await _rootRef().child(id).get();
final bookMap = bookSnapshot.child(id).toMap();
Stream<Book> getBook(String id) {
// final bookSnapshot = await _booksRef().child(id).get();
// final bookMap = bookSnapshot.child(id).toMap();

if (bookMap == null) {
throw Exception('Cannot read book with id $id as it does not exist!');
}
// if (bookMap == null) {
// throw Exception('Cannot read book with id $id as it does not exist!');
// }

// return Book.fromJson(bookMap);

return _booksRef().child(id).onValue.map((DatabaseEvent event) {
final Map<String, dynamic>? data = event.snapshot.toMap();

return Book.fromJson(bookMap);
if (data == null) {
throw Exception('Cannot read book with id $id as it does not exist!');
}

return Book.fromJson(data);
});
}

@override
Expand All @@ -83,16 +89,23 @@ class FirebaseBookRepository implements BookRepository {

@override
Future<void> update(Book book) {
return _rootRef().child(book.id).set(book);
return _booksRef().child(book.id).set(book.toJson());
}

@override
Future<void> updateCurrentPage(String bookId, int currentPage) async {
final Book currentBook = await getBook(bookId);
final bookSnapshot = await _booksRef().child(bookId).get();
final bookMap = bookSnapshot.child(bookId).toMap();

if (bookMap == null) {
throw Exception('Cannot read book with id $bookId as it does not exist!');
}
final currentBook = Book.fromJson(bookMap);

return update(currentBook.copyWith(currentPage: currentPage));
}

DatabaseReference _rootRef() {
DatabaseReference _booksRef() {
// At this point we can assume that the customer is already logged in, even as anonymous user
final user = _fbAuth.currentUser!.uid;
return _fbDb.ref('users/$user/books');
Expand Down Expand Up @@ -124,17 +137,25 @@ class FirebaseBookRepository implements BookRepository {
}

@override
Future<void> addLabelToBook(String bookId, BookLabel label) async {
final book = await getBook(bookId);
book.addLabel(label);
return update(book);
Future<void> addLabelToBook(String bookId, BookLabel label) {
// TODO: implement addLabelToBook
throw UnimplementedError();
}

@override
Future<void> removeLabelFromBook(String bookId, String labelId) async {
final book = await getBook(bookId);
book.removeLabel(labelId);
return update(book);
final bookSnapshot = await _booksRef().child(bookId).get();
final bookMap = bookSnapshot.child(bookId).toMap();

if (bookMap == null) {
throw Exception('Cannot read book with id $bookId as it does not exist!');
}
final book = Book.fromJson(bookMap);
return update(
book.copyWith(
labels: book.labels..removeWhere((label) => label.id == labelId),
),
);
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/src/data/book/in_memory_book_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class InMemoryBookRepository implements BookRepository {
}

@override
Future<Book> getBook(id) {
Stream<Book> getBook(id) {
throw UnimplementedError('Not required');
}

Expand Down
2 changes: 1 addition & 1 deletion lib/src/providers/book.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'book.g.dart';

@riverpod
Future<Book> book(BookRef ref, String id) =>
Stream<Book> book(BookRef ref, String id) =>
ref.watch(bookRepositoryProvider).getBook(id);

@riverpod
Expand Down
9 changes: 9 additions & 0 deletions lib/src/providers/labels.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import 'package:dantex/src/data/book/entity/book_label.dart';
import 'package:dantex/src/providers/repository.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'labels.g.dart';

@riverpod
Stream<List<BookLabel>> getBookLabels(GetBookLabelsRef ref) =>
ref.watch(bookLabelRepositoryProvider).getBookLabels();
Loading

0 comments on commit d77456f

Please sign in to comment.