added animation for bottomNavBar and overlayWidget
This commit is contained in:
parent
01dff4be2a
commit
3d3f9ce4fc
|
@ -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(
|
||||||
|
|
|
@ -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,
|
||||||
),
|
),
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in a new issue