Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Expanded cover background behind AppBar #332

Merged
merged 1 commit into from
Sep 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 84 additions & 51 deletions lib/ui/book_screen/book_screen.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:openreads/core/themes/app_theme.dart';
import 'package:openreads/generated/locale_keys.g.dart';
import 'package:openreads/logic/bloc/theme_bloc/theme_bloc.dart';
import 'package:openreads/logic/cubit/current_book_cubit.dart';
import 'package:openreads/logic/cubit/edit_book_cubit.dart';
import 'package:openreads/main.dart';
Expand Down Expand Up @@ -235,61 +237,93 @@ class BookScreen extends StatelessWidget {
];

return Scaffold(
appBar: AppBar(
actions: [
BlocBuilder<CurrentBookCubit, Book>(
builder: (context, state) {
if (moreButtonOptions.length == 1) {
if (state.deleted == true) {
moreButtonOptions.add(LocaleKeys.restore_book.tr());
moreButtonOptions.add(LocaleKeys.delete_permanently.tr());
} else {
moreButtonOptions.add(LocaleKeys.delete_book.tr());
}
}
extendBodyBehindAppBar: true,
appBar: PreferredSize(
preferredSize: AppBar().preferredSize,
// Needed to add BlocBuilder because the status bar was changing
// to different color then in BooksScreen
child: BlocBuilder<ThemeBloc, ThemeState>(
builder: (context, state) {
final themeMode = (state as SetThemeState).themeMode;

return PopupMenuButton<String>(
onSelected: (_) {},
itemBuilder: (_) {
return moreButtonOptions.map((String choice) {
return PopupMenuItem<String>(
value: choice,
child: Text(choice),
onTap: () async {
context.read<EditBookCubit>().setBook(state);
return AppBar(
backgroundColor: Colors.transparent,
scrolledUnderElevation: 0,
systemOverlayStyle: SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: themeMode == ThemeMode.system
? MediaQuery.platformBrightnessOf(context) ==
Brightness.dark
? Brightness.light
: Brightness.dark
: themeMode == ThemeMode.dark
? Brightness.light
: Brightness.dark,
),
actions: [
BlocBuilder<CurrentBookCubit, Book>(
builder: (context, state) {
if (moreButtonOptions.length == 1) {
if (state.deleted == true) {
moreButtonOptions.add(LocaleKeys.restore_book.tr());
moreButtonOptions.add(
LocaleKeys.delete_permanently.tr(),
);
} else {
moreButtonOptions.add(LocaleKeys.delete_book.tr());
}
}

await Future.delayed(const Duration(
milliseconds: 0,
));
if (!context.mounted) return;
return PopupMenuButton<String>(
onSelected: (_) {},
itemBuilder: (_) {
return moreButtonOptions.map((String choice) {
return PopupMenuItem<String>(
value: choice,
child: Text(choice),
onTap: () async {
context.read<EditBookCubit>().setBook(state);

if (choice == moreButtonOptions[0]) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => const AddBookScreen(
editingExistingBook: true,
),
),
await Future.delayed(const Duration(
milliseconds: 0,
));
if (!context.mounted) return;

if (choice == moreButtonOptions[0]) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => const AddBookScreen(
editingExistingBook: true,
),
),
);
} else if (choice == moreButtonOptions[1]) {
if (state.deleted == false) {
_showDeleteRestoreDialog(
context, true, null, state);
} else {
_showDeleteRestoreDialog(
context, false, null, state);
}
} else if (choice == moreButtonOptions[2]) {
_showDeleteRestoreDialog(
context,
true,
true,
state,
);
}
},
);
} else if (choice == moreButtonOptions[1]) {
if (state.deleted == false) {
_showDeleteRestoreDialog(
context, true, null, state);
} else {
_showDeleteRestoreDialog(
context, false, null, state);
}
} else if (choice == moreButtonOptions[2]) {
_showDeleteRestoreDialog(context, true, true, state);
}
}).toList();
},
);
}).toList();
},
);
},
),
],
},
),
],
);
},
),
),
body: BlocBuilder<CurrentBookCubit, Book>(
builder: (context, state) {
Expand All @@ -299,14 +333,13 @@ class BookScreen extends StatelessWidget {
(state.hasCover == true)
? Center(
child: CoverView(
onPressed: null,
heroTag: heroTag,
book: state,
),
)
: const SizedBox(),
Padding(
padding: const EdgeInsets.all(5),
padding: const EdgeInsets.fromLTRB(5, 0, 5, 5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expand Down
52 changes: 30 additions & 22 deletions lib/ui/book_screen/widgets/cover_background.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:blurhash_dart/blurhash_dart.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:openreads/core/themes/app_theme.dart';
import 'package:openreads/logic/cubit/current_book_cubit.dart';
import 'package:openreads/model/book.dart';
import 'package:image/image.dart' as img;
Expand All @@ -18,29 +19,36 @@ class CoverBackground extends StatelessWidget {
builder: (context, state) {
final image = BlurHash.decode(state.blurHash!).toImage(35, 20);

return Image.memory(
Uint8List.fromList(
img.encodeJpg(image),
return ClipRRect(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(cornerRadius),
bottomRight: Radius.circular(cornerRadius),
),
child: Image.memory(
Uint8List.fromList(
img.encodeJpg(image),
),
fit: BoxFit.cover,
width: MediaQuery.of(context).size.width,
height: (MediaQuery.of(context).size.height / 2.5) +
MediaQuery.of(context).padding.top,
frameBuilder: (
BuildContext context,
Widget child,
int? frame,
bool wasSynchronouslyLoaded,
) {
if (wasSynchronouslyLoaded) {
return child;
}
return AnimatedOpacity(
opacity: frame == null ? 0 : 0.8,
duration: const Duration(milliseconds: 400),
curve: Curves.easeIn,
child: child,
);
},
),
fit: BoxFit.cover,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height / 2.5,
frameBuilder: (
BuildContext context,
Widget child,
int? frame,
bool wasSynchronouslyLoaded,
) {
if (wasSynchronouslyLoaded) {
return child;
}
return AnimatedOpacity(
opacity: frame == null ? 0 : 0.8,
duration: const Duration(milliseconds: 300),
curve: Curves.easeIn,
child: child,
);
},
);
},
);
Expand Down
72 changes: 38 additions & 34 deletions lib/ui/book_screen/widgets/cover_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@ class CoverView extends StatefulWidget {
const CoverView({
Key? key,
this.heroTag,
this.onPressed,
this.book,
this.coverFile,
this.blurHashString,
}) : super(key: key);

final Function()? onPressed;
final String? heroTag;
final String? blurHashString;
final Book? book;
Expand All @@ -39,43 +37,49 @@ class _CoverViewState extends State<CoverView> {
@override
Widget build(BuildContext context) {
_loadCoverFile();
final mediaQuery = MediaQuery.of(context);

return InkWell(
onTap: widget.onPressed,
child: Stack(
children: [
SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height / 2.5,
child: const Stack(
children: [
CoverBackground(),
],
),
return Stack(
children: [
SizedBox(
width: mediaQuery.size.width,
height: (mediaQuery.size.height / 2.5) + mediaQuery.padding.top,
child: const Stack(
children: [
CoverBackground(),
],
),
Center(
child: SizedBox(
height: ((MediaQuery.of(context).size.height / 2.5) - 0),
child: Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(cornerRadius),
child: coverFile != null
? Hero(
tag: widget.heroTag ?? "",
child: Image.file(
coverFile!,
fit: BoxFit.cover,
height:
(MediaQuery.of(context).size.height / 2.5) - 40,
),
)
: const SizedBox(),
),
Column(
children: [
SizedBox(height: mediaQuery.padding.top),
Center(
child: SizedBox(
height: mediaQuery.size.height / 2.5,
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 20),
child: Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(cornerRadius),
child: coverFile != null
? Hero(
tag: widget.heroTag ?? "",
child: Image.file(
coverFile!,
fit: BoxFit.cover,
height: mediaQuery.size.height / 2.5,
),
)
: const SizedBox(),
),
),
),
),
),
),
],
),
const SizedBox(height: 10),
],
),
],
);
}
}
Loading