added animation for bottomNavBar and overlayWidget

This commit is contained in:
ashilkn 2022-05-07 19:02:55 +05:30
parent 01dff4be2a
commit 3d3f9ce4fc
3 changed files with 259 additions and 159 deletions

View file

@ -37,11 +37,13 @@ extension CustomColorScheme on ColorScheme {
: Color(0xFF1DB954); : Color(0xFF1DB954);
Color get frostyBlurBackdropFilterColor => Color get frostyBlurBackdropFilterColor =>
brightness == Brightness.light ? Colors.black : Colors.white; Colors.white; //same for both themes
// brightness == Brightness.light ? Colors.black : Colors.white;
Color get cancelSelectedButtonColor => brightness == Brightness.light Color get cancelSelectedButtonColor => Colors.black; //same for both themes
? Color.fromARGB(255, 225, 225, 225) // brightness == Brightness.light
: Color.fromARGB(255, 30, 30, 30); // ? Color.fromARGB(255, 225, 225, 225)
// : Color.fromARGB(255, 30, 30, 30);
} }
OutlinedButtonThemeData buildOutlinedButtonThemeData( OutlinedButtonThemeData buildOutlinedButtonThemeData(

View file

@ -4,7 +4,6 @@ import 'dart:ui';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:page_transition/page_transition.dart'; import 'package:page_transition/page_transition.dart';
import 'package:photos/core/configuration.dart'; import 'package:photos/core/configuration.dart';
@ -38,8 +37,72 @@ class GalleryOverlayWidget extends StatefulWidget {
final SelectedFiles selectedFiles; final SelectedFiles selectedFiles;
final String path; final String path;
final Collection collection; final Collection collection;
const GalleryOverlayWidget(this.type, this.selectedFiles,
{this.path, this.collection, Key key})
: super(key: key);
GalleryOverlayWidget( @override
State<GalleryOverlayWidget> createState() => _GalleryOverlayWidgetState();
}
class _GalleryOverlayWidgetState extends State<GalleryOverlayWidget>
with SingleTickerProviderStateMixin {
StreamSubscription _userAuthEventSubscription;
Function() _selectedFilesListener;
final GlobalKey shareButtonKey = GlobalKey();
@override
void initState() {
_selectedFilesListener = () {
setState(() {});
};
widget.selectedFiles.addListener(_selectedFilesListener);
_userAuthEventSubscription =
Bus.instance.on<SubscriptionPurchasedEvent>().listen((event) {
setState(() {});
});
super.initState();
}
@override
void dispose() {
_userAuthEventSubscription.cancel();
widget.selectedFiles.removeListener(_selectedFilesListener);
super.dispose();
}
@override
Widget build(BuildContext context) {
bool filesAreSelected = widget.selectedFiles.files.isNotEmpty;
return AnimatedContainer(
duration: Duration(milliseconds: 200),
curve: Curves.easeInOut,
height: filesAreSelected ? 108 : 0,
child: AnimatedOpacity(
duration: Duration(milliseconds: 75),
opacity: filesAreSelected ? 1.0 : 0.0,
curve: Curves.easeIn,
child: IgnorePointer(
ignoring: !filesAreSelected,
child: OverlayWidget(
widget.type,
widget.selectedFiles,
path: widget.path,
collection: widget.collection,
),
),
),
);
}
}
class OverlayWidget extends StatefulWidget {
final GalleryOverlayType type;
final SelectedFiles selectedFiles;
final String path;
final Collection collection;
const OverlayWidget(
this.type, this.type,
this.selectedFiles, { this.selectedFiles, {
this.path, this.path,
@ -47,10 +110,10 @@ class GalleryOverlayWidget extends StatefulWidget {
}); });
@override @override
_GalleryOverlayWidgetState createState() => _GalleryOverlayWidgetState(); _OverlayWidgetState createState() => _OverlayWidgetState();
} }
class _GalleryOverlayWidgetState extends State<GalleryOverlayWidget> { class _OverlayWidgetState extends State<OverlayWidget> {
final _logger = Logger("GalleryOverlay"); final _logger = Logger("GalleryOverlay");
StreamSubscription _userAuthEventSubscription; StreamSubscription _userAuthEventSubscription;
Function() _selectedFilesListener; Function() _selectedFilesListener;
@ -77,11 +140,11 @@ class _GalleryOverlayWidgetState extends State<GalleryOverlayWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (widget.selectedFiles.files.isNotEmpty) {
return Container( return Container(
height: 108,
color: Colors.transparent, color: Colors.transparent,
child: Column( child: ListView(
//ListView for animation to work without render overflow
physics: const NeverScrollableScrollPhysics(),
children: [ children: [
Padding( Padding(
padding: EdgeInsets.symmetric(horizontal: 12), padding: EdgeInsets.symmetric(horizontal: 12),
@ -93,8 +156,7 @@ class _GalleryOverlayWidgetState extends State<GalleryOverlayWidget> {
color: Theme.of(context) color: Theme.of(context)
.colorScheme .colorScheme
.frostyBlurBackdropFilterColor .frostyBlurBackdropFilterColor
.withOpacity(0.6), .withOpacity(0.5),
height: 46,
width: double.infinity, width: double.infinity,
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -104,12 +166,9 @@ class _GalleryOverlayWidgetState extends State<GalleryOverlayWidget> {
child: Text( child: Text(
widget.selectedFiles.files.length.toString() + widget.selectedFiles.files.length.toString() +
' selected', ' selected',
style: style: Theme.of(context).textTheme.subtitle2.copyWith(
Theme.of(context).textTheme.subtitle2.copyWith(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Theme.of(context) color: Colors.black //same for both themes
.colorScheme
.inverseTextColor,
), ),
), ),
), ),
@ -122,29 +181,42 @@ class _GalleryOverlayWidgetState extends State<GalleryOverlayWidget> {
), ),
), ),
), ),
const SizedBox(height: 16), const Padding(padding: EdgeInsets.symmetric(vertical: 8)),
InkWell( Row(
child: Container( mainAxisAlignment: MainAxisAlignment.center,
height: 32, children: [
width: 86, ClipRRect(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24), borderRadius: BorderRadius.circular(24),
color: child: InkWell(
Theme.of(context).colorScheme.cancelSelectedButtonColor, child: BackdropFilter(
), filter: ImageFilter.blur(sigmaX: 50, sigmaY: 50),
child: Container(
padding: EdgeInsets.symmetric(vertical: 8),
//height: 32,
width: 86,
color: Theme.of(context)
.colorScheme
.cancelSelectedButtonColor
.withOpacity(0.5),
child: Center( child: Center(
child: Text('Cancel', child: Text('Cancel',
style: Theme.of(context).textTheme.subtitle2), style: Theme.of(context)
.textTheme
.subtitle2
.copyWith(
color: Colors.white, //same for both themes
)),
),
), ),
), ),
onTap: _clearSelectedFiles, onTap: _clearSelectedFiles,
), ),
),
],
),
], ],
), ),
); );
} else {
return const SizedBox.shrink();
}
} }
void _clearSelectedFiles() { void _clearSelectedFiles() {
@ -196,7 +268,7 @@ class _GalleryOverlayWidgetState extends State<GalleryOverlayWidget> {
Tooltip( Tooltip(
message: msg, message: msg,
child: IconButton( child: IconButton(
color: Theme.of(context).colorScheme.inverseIconColor, color: Colors.black, //same for both themes
icon: Icon(iconData), icon: Icon(iconData),
onPressed: () { onPressed: () {
_createAlbum(); _createAlbum();
@ -212,7 +284,7 @@ class _GalleryOverlayWidgetState extends State<GalleryOverlayWidget> {
Tooltip( Tooltip(
message: "move", message: "move",
child: IconButton( child: IconButton(
color: Theme.of(context).colorScheme.inverseIconColor, color: Colors.black, //same for both themes
icon: Icon(Platform.isAndroid icon: Icon(Platform.isAndroid
? Icons.arrow_forward ? Icons.arrow_forward
: CupertinoIcons.arrow_right), : CupertinoIcons.arrow_right),
@ -227,7 +299,7 @@ class _GalleryOverlayWidgetState extends State<GalleryOverlayWidget> {
Tooltip( Tooltip(
message: "share", message: "share",
child: IconButton( child: IconButton(
color: Theme.of(context).colorScheme.inverseIconColor, color: Colors.black, //same for both themes
key: shareButtonKey, key: shareButtonKey,
icon: Icon(Platform.isAndroid ? Icons.share : CupertinoIcons.share), icon: Icon(Platform.isAndroid ? Icons.share : CupertinoIcons.share),
onPressed: () { onPressed: () {
@ -243,7 +315,7 @@ class _GalleryOverlayWidgetState extends State<GalleryOverlayWidget> {
Tooltip( Tooltip(
message: "delete", message: "delete",
child: IconButton( child: IconButton(
color: Theme.of(context).colorScheme.inverseIconColor, color: Colors.black, //same for both themes
icon: icon:
Icon(Platform.isAndroid ? Icons.delete : CupertinoIcons.delete), Icon(Platform.isAndroid ? Icons.delete : CupertinoIcons.delete),
onPressed: () { onPressed: () {
@ -258,7 +330,7 @@ class _GalleryOverlayWidgetState extends State<GalleryOverlayWidget> {
Tooltip( Tooltip(
message: "delete", message: "delete",
child: IconButton( child: IconButton(
color: Theme.of(context).colorScheme.inverseIconColor, color: Colors.black, //same for both themes
icon: Icon( icon: Icon(
Platform.isAndroid ? Icons.delete : CupertinoIcons.delete, Platform.isAndroid ? Icons.delete : CupertinoIcons.delete,
), ),
@ -273,7 +345,7 @@ class _GalleryOverlayWidgetState extends State<GalleryOverlayWidget> {
Tooltip( Tooltip(
message: "remove", message: "remove",
child: IconButton( child: IconButton(
color: Theme.of(context).colorScheme.inverseIconColor, color: Colors.black, //same for both themes
icon: Icon( icon: Icon(
Icons.remove_circle_rounded, Icons.remove_circle_rounded,
), ),
@ -292,9 +364,9 @@ class _GalleryOverlayWidgetState extends State<GalleryOverlayWidget> {
actions.add(Tooltip( actions.add(Tooltip(
message: showArchive ? "archive" : "unarchive", message: showArchive ? "archive" : "unarchive",
child: IconButton( child: IconButton(
color: Colors.black, //same for both themes
icon: Icon( icon: Icon(
showArchive ? Icons.visibility_off : Icons.visibility, showArchive ? Icons.visibility_off : Icons.visibility,
color: Theme.of(context).colorScheme.inverseIconColor,
), ),
onPressed: () { onPressed: () {
_handleVisibilityChangeRequest( _handleVisibilityChangeRequest(
@ -310,6 +382,7 @@ class _GalleryOverlayWidgetState extends State<GalleryOverlayWidget> {
actions.add(Tooltip( actions.add(Tooltip(
message: "restore", message: "restore",
child: IconButton( child: IconButton(
color: Colors.black, //same for both themes
icon: Icon( icon: Icon(
Icons.restore, Icons.restore,
color: Theme.of(context).colorScheme.inverseIconColor, color: Theme.of(context).colorScheme.inverseIconColor,
@ -331,7 +404,7 @@ class _GalleryOverlayWidgetState extends State<GalleryOverlayWidget> {
Tooltip( Tooltip(
message: "delete permanently", message: "delete permanently",
child: IconButton( child: IconButton(
color: Theme.of(context).colorScheme.inverseIconColor, color: Colors.black, //same for both themes
icon: Icon( icon: Icon(
Icons.delete_forever, Icons.delete_forever,
), ),

View file

@ -2,10 +2,8 @@ import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:move_to_background/move_to_background.dart'; import 'package:move_to_background/move_to_background.dart';
import 'package:photo_manager/photo_manager.dart'; import 'package:photo_manager/photo_manager.dart';
@ -294,12 +292,21 @@ class _HomeWidgetState extends State<HomeWidget> {
Align(alignment: Alignment.bottomCenter, child: BottomShadowWidget()), Align(alignment: Alignment.bottomCenter, child: BottomShadowWidget()),
Align( Align(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
child: Stack(children: [ child: Stack(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
HomeBottomNavigationBar( HomeBottomNavigationBar(
_selectedFiles, _selectedFiles,
selectedTabIndex: _selectedTabIndex, selectedTabIndex: _selectedTabIndex,
), ),
])), const SizedBox(height: 8),
],
),
],
),
),
Align( Align(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
child: child:
@ -545,12 +552,24 @@ class _HomeBottomNavigationBarState extends State<HomeBottomNavigationBar> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (widget.selectedFiles.files.isNotEmpty) { bool filesAreSelected = widget.selectedFiles.files.isNotEmpty;
return const SizedBox.shrink(); return AnimatedContainer(
} else { duration: Duration(milliseconds: 200),
return Padding( curve: Curves.easeInOut,
padding: const EdgeInsets.only(bottom: 8.0), height: filesAreSelected ? 0 : 52,
child: ClipRRect( child: AnimatedOpacity(
duration: Duration(milliseconds: 75),
opacity: filesAreSelected ? 0.0 : 1.0,
curve: Curves.easeIn,
child: IgnorePointer(
ignoring: filesAreSelected,
child: ListView(
physics: const NeverScrollableScrollPhysics(),
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(36), borderRadius: BorderRadius.circular(36),
child: Container( child: Container(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
@ -558,10 +577,12 @@ class _HomeBottomNavigationBarState extends State<HomeBottomNavigationBar> {
width: 240, width: 240,
child: ClipRect( child: ClipRect(
child: BackdropFilter( child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 4, sigmaY: 4), filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20),
child: GNav( child: GNav(
curve: Curves.easeOutExpo, curve: Curves.easeOutExpo,
backgroundColor: Theme.of(context).bottomAppBarColor, // backgroundColor: Colors.white.withOpacity(0.6),
backgroundColor:
Theme.of(context).bottomAppBarColor,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
rippleColor: Colors.white.withOpacity(0.2), rippleColor: Colors.white.withOpacity(0.2),
hoverColor: Colors.white.withOpacity(0.2), hoverColor: Colors.white.withOpacity(0.2),
@ -622,10 +643,14 @@ class _HomeBottomNavigationBarState extends State<HomeBottomNavigationBar> {
), ),
), ),
), ),
],
),
]),
),
),
); );
} }
} }
}
class HeaderWidget extends StatelessWidget { class HeaderWidget extends StatelessWidget {
static const _memoriesWidget = MemoriesWidget(); static const _memoriesWidget = MemoriesWidget();