Skip to content

Commit

Permalink
Show other book suggestion, if main book suggestion is wrong (#103)
Browse files Browse the repository at this point in the history
  • Loading branch information
lockieRichter authored Mar 13, 2024
1 parent 6520b13 commit 6143de0
Show file tree
Hide file tree
Showing 9 changed files with 300 additions and 163 deletions.
4 changes: 3 additions & 1 deletion assets/translations/de-DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,9 @@
"title": "{} wurde gemeldet. Du wirst diesen Vorschlag nicht mehr sehen."
}
},
"new-banner": "Neue Vorschläge sind wieder ab dem {} verfügbar.",
"new-banner": "TODO",
"nope": "TODO",
"other_suggestions": "Maybe one of them?",
"report-dialog": {
"content": "Willst du wirklich das Buch {} melden?\n\nDu wirst dieses Buch nicht mehr als Vorschlag sehen.",
"report": "Buch melden",
Expand Down
2 changes: 2 additions & 0 deletions assets/translations/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@
}
},
"new-banner": "New recommendations will be available again at the {}.",
"nope": "Nope",
"other_suggestions": "Maybe one of them?",
"report-dialog": {
"content": "Do you really want to report the book {}?\n\nYou will no longer see this book as a recommendation.",
"report": "Report",
Expand Down
2 changes: 1 addition & 1 deletion ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ SPEC CHECKSUMS:
FirebaseSessions: 2f348975f6d1c139231c180e12194161da2e0cd6
FirebaseSharedSwift: 2fbf73618288b7a36b2014b957745dcdd781389e
FirebaseStorage: 8505bae8ac6662474b5b50e07759fb2765c15746
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_barcode_scanner: 7a1144744c28dc0c57a8de7218ffe5ec59a9e4bf
google_sign_in_ios: 1bfaf6607b44cd1b24c4d4bc39719870440f9ce1
GoogleAppMeasurement: bb3c564c3efb933136af0e94899e0a46167466a8
Expand Down
2 changes: 1 addition & 1 deletion ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1430;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1430"
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
196 changes: 165 additions & 31 deletions lib/src/ui/add/add_book_widget.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import 'package:dantex/src/data/book/entity/book.dart';
import 'package:dantex/src/data/bookdownload/entity/book_suggestion.dart';
import 'package:dantex/src/providers/repository.dart';
import 'package:dantex/src/providers/service.dart';
import 'package:dantex/src/ui/book/book_image.dart';
import 'package:dantex/src/ui/core/dante_components.dart';
import 'package:dantex/src/ui/core/dante_loading_indicator.dart';
import 'package:dantex/src/ui/core/generic_error_widget.dart';
import 'package:dantex/src/ui/core/handle.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
Expand Down Expand Up @@ -41,15 +41,13 @@ class AddBookWidget extends ConsumerWidget {
}) : _query = query,
appearance = AddBookWidgetAppearance.fullScreen;

final double _bottomSheetHeight = 440.0;

@override
Widget build(BuildContext context, WidgetRef ref) {
final book = ref.watch(downloadBookProvider(_query));
Widget child = const DanteLoadingIndicator();
book.when(
data: (data) {
child = BookWidget(
child = _BookSuggestionWidget(
bookSuggestion: data,
appearance: appearance,
);
Expand All @@ -62,18 +60,12 @@ class AddBookWidget extends ConsumerWidget {
},
);

return Column(
children: [
if (appearance == AddBookWidgetAppearance.bottomSheet) const Handle(),
switch (appearance) {
AddBookWidgetAppearance.bottomSheet => SizedBox(
height: _bottomSheetHeight,
child: child,
),
AddBookWidgetAppearance.fullScreen => Expanded(child: child),
},
],
);
switch (appearance) {
case AddBookWidgetAppearance.bottomSheet:
return child;
case AddBookWidgetAppearance.fullScreen:
return Expanded(child: child);
}
}
}

Expand All @@ -83,30 +75,113 @@ openAddBookSheet(
}) async {
await showModalBottomSheet(
context: context,
showDragHandle: true,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
barrierColor: Colors.black54,
builder: (context) => AddBookWidget(
query,
appearance: AddBookWidgetAppearance.bottomSheet,
builder: (context) => SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
AddBookWidget(
query,
appearance: AddBookWidgetAppearance.bottomSheet,
),
],
),
),
);
}

class BookWidget extends ConsumerWidget {
enum BookSuggestionView {
first,
other,
}

class _BookSuggestionWidget extends ConsumerStatefulWidget {
final BookSuggestion bookSuggestion;
final AddBookWidgetAppearance appearance;

const BookWidget({
const _BookSuggestionWidget({
required this.bookSuggestion,
required this.appearance,
super.key,
});

@override
createState() => _BookSuggestionWidgetState();
}

class _BookSuggestionWidgetState extends ConsumerState<_BookSuggestionWidget> {
BookSuggestionView currentView = BookSuggestionView.first;
late Book currentBook;
late List<Book> otherBooks;

@override
void initState() {
super.initState();
currentBook = widget.bookSuggestion.target;
otherBooks = widget.bookSuggestion.suggestions;
}

@override
Widget build(BuildContext context) {
return AnimatedSize(
duration: const Duration(milliseconds: 300),
curve: Curves.ease,
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: SingleChildScrollView(
child: switch (currentView) {
BookSuggestionView.first => _FirstBookSuggestion(
bookSuggestion: currentBook,
appearance: widget.appearance,
notMyBookCallback: () {
setState(() {
currentView = BookSuggestionView.other;
});
},
),
BookSuggestionView.other => _OtherBookSuggestions(
otherSuggestions: widget.bookSuggestion.suggestions,
selectOtherBookCallback: (book) {
setState(() {
otherBooks.insert(0, currentBook);
otherBooks.remove(book);
currentBook = book;
currentView = BookSuggestionView.first;
});
},
appearance: widget.appearance,
backButtonCallback: () {
setState(() {
currentView = BookSuggestionView.first;
});
},
),
},
),
),
);
}
}

class _FirstBookSuggestion extends ConsumerWidget {
final Book bookSuggestion;
final AddBookWidgetAppearance appearance;
final void Function() notMyBookCallback;

const _FirstBookSuggestion({
required this.bookSuggestion,
required this.appearance,
required this.notMyBookCallback,
super.key,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
return Column(
Expand All @@ -115,21 +190,21 @@ class BookWidget extends ConsumerWidget {
if (appearance == AddBookWidgetAppearance.fullScreen)
const SizedBox(height: 16),
BookImage(
bookSuggestion.target.thumbnailAddress,
bookSuggestion.thumbnailAddress,
size: appearance.imageSize,
),
Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
bookSuggestion.target.title,
bookSuggestion.title,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headlineSmall,
),
),
Text(
bookSuggestion.target.author,
bookSuggestion.author,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyLarge,
),
Expand All @@ -146,7 +221,7 @@ class BookWidget extends ConsumerWidget {
onPressed: () async {
await ref
.read(bookRepositoryProvider)
.addToForLater(bookSuggestion.target);
.addToForLater(bookSuggestion);
// Just pop the screen here, no need to handle something else
if (context.mounted) {
Navigator.of(context).pop();
Expand All @@ -161,7 +236,7 @@ class BookWidget extends ConsumerWidget {
onPressed: () async {
await ref
.read(bookRepositoryProvider)
.addToReading(bookSuggestion.target);
.addToReading(bookSuggestion);
// Just pop the screen here, no need to handle something else
if (context.mounted) {
Navigator.of(context).pop();
Expand All @@ -176,7 +251,7 @@ class BookWidget extends ConsumerWidget {
onPressed: () async {
await ref
.read(bookRepositoryProvider)
.addToRead(bookSuggestion.target);
.addToRead(bookSuggestion);
// Just pop the screen here, no need to handle something else
if (context.mounted) {
Navigator.of(context).pop();
Expand All @@ -193,7 +268,7 @@ class BookWidget extends ConsumerWidget {
onPressed: () async {
await ref
.read(bookRepositoryProvider)
.addToWishlist(bookSuggestion.target);
.addToWishlist(bookSuggestion);
// Just pop the screen here, no need to handle something else
if (context.mounted) {
Navigator.of(context).pop();
Expand All @@ -204,12 +279,71 @@ class BookWidget extends ConsumerWidget {
],
),
TextButton(
onPressed: notMyBookCallback,
child: Text('not_my_book'.tr()),
onPressed: () {
// TODO Show bookSuggestion.suggestions in another ticket
},
),
],
);
}
}

class _OtherBookSuggestions extends ConsumerWidget {
final List<Book> otherSuggestions;
final AddBookWidgetAppearance appearance;

final void Function() backButtonCallback;
final void Function(Book) selectOtherBookCallback;

const _OtherBookSuggestions({
required this.otherSuggestions,
required this.appearance,
required this.backButtonCallback,
required this.selectOtherBookCallback,
super.key,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final mq = MediaQuery.of(context);

return ConstrainedBox(
constraints: BoxConstraints(
maxHeight: mq.size.height - mq.viewInsets.bottom - 225,
),
child: Column(
children: [
Text(
'recommendations.other_suggestions'.tr(),
style: Theme.of(context).textTheme.headlineSmall,
),
const SizedBox(height: 16),
Expanded(
child: ListView.separated(
separatorBuilder: (context, index) => const SizedBox(height: 16),
itemCount: otherSuggestions.length,
itemBuilder: (context, index) {
final book = otherSuggestions[index];
return ListTile(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
title: Text(book.title),
subtitle: Text(book.author),
leading: BookImage(
book.thumbnailAddress,
size: appearance.imageSize,
),
onTap: () => selectOtherBookCallback(book),
);
},
),
),
const Divider(),
OutlinedButton(
onPressed: backButtonCallback,
child: Text('recommendations.nope'.tr()),
),
],
),
);
}
}
2 changes: 1 addition & 1 deletion lib/src/ui/book/book_image.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class BookImage extends StatelessWidget {
Widget build(BuildContext context) {
if (_imageUrl != null) {
return CachedNetworkImage(
imageUrl: _imageUrl!,
imageUrl: _imageUrl,
width: size,
);
} else {
Expand Down
Loading

0 comments on commit 6143de0

Please sign in to comment.