Add fade out effect also to nav bar settings page

This commit is contained in:
Ming Ming 2024-10-27 03:29:04 +08:00
parent 78c02fd280
commit 058a8d38af
5 changed files with 171 additions and 116 deletions

View file

@ -0,0 +1,118 @@
import 'dart:async';
import 'package:flutter/material.dart';
class FadeOutListContainer extends StatefulWidget {
const FadeOutListContainer({
super.key,
required this.scrollController,
required this.child,
});
@override
State<StatefulWidget> createState() => _FadeOutListContainerState();
final ScrollController scrollController;
final Widget child;
}
class _FadeOutListContainerState extends State<FadeOutListContainer> {
@override
void initState() {
super.initState();
widget.scrollController.addListener(_onScrollEvent);
_ensureUpdateButtonScroll();
}
@override
void dispose() {
widget.scrollController.removeListener(_onScrollEvent);
super.dispose();
}
@override
Widget build(BuildContext context) {
return ShaderMask(
shaderCallback: (rect) {
final colors = <Color>[];
final stops = <double>[];
if (_hasLeftContent) {
colors.addAll([Colors.white, Colors.transparent]);
stops.addAll([0, .1]);
} else {
colors.add(Colors.transparent);
stops.add(0);
}
if (_hasRightContent) {
colors.addAll([Colors.transparent, Colors.white]);
stops.addAll([.9, 1]);
} else {
colors.add(Colors.transparent);
stops.add(1);
}
return LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: colors,
stops: stops,
).createShader(rect);
},
blendMode: BlendMode.dstOut,
child: widget.child,
);
}
void _onScrollEvent() {
_updateButtonScroll(widget.scrollController.position);
}
bool _updateButtonScroll(ScrollPosition pos) {
if (!pos.hasContentDimensions || !pos.hasPixels) {
return false;
}
if (pos.pixels <= pos.minScrollExtent) {
if (_hasLeftContent) {
setState(() {
_hasLeftContent = false;
});
}
} else {
if (!_hasLeftContent) {
setState(() {
_hasLeftContent = true;
});
}
}
if (pos.pixels >= pos.maxScrollExtent) {
if (_hasRightContent) {
setState(() {
_hasRightContent = false;
});
}
} else {
if (!_hasRightContent) {
setState(() {
_hasRightContent = true;
});
}
}
_hasFirstScrollUpdate = true;
return true;
}
void _ensureUpdateButtonScroll() {
if (_hasFirstScrollUpdate || !mounted) {
return;
}
if (widget.scrollController.hasClients) {
if (_updateButtonScroll(widget.scrollController.position)) {
return;
}
}
Timer(const Duration(milliseconds: 100), _ensureUpdateButtonScroll);
}
var _hasFirstScrollUpdate = false;
var _hasLeftContent = false;
var _hasRightContent = false;
}

View file

@ -34,6 +34,7 @@ import 'package:nc_photos/widget/archive_browser.dart';
import 'package:nc_photos/widget/collection_browser.dart';
import 'package:nc_photos/widget/collection_grid_item.dart';
import 'package:nc_photos/widget/enhanced_photo_browser.dart';
import 'package:nc_photos/widget/fade_out_list.dart';
import 'package:nc_photos/widget/handler/double_tap_exit_handler.dart';
import 'package:nc_photos/widget/home_app_bar.dart';
import 'package:nc_photos/widget/navigation_bar_blur_filter.dart';

View file

@ -20,15 +20,6 @@ class _NavigationBar extends StatefulWidget {
}
class _NavigationBarState extends State<_NavigationBar> {
@override
void initState() {
super.initState();
_scrollController = ScrollController();
_scrollController
.addListener(() => _updateButtonScroll(_scrollController.position));
_ensureUpdateButtonScroll();
}
@override
void dispose() {
_scrollController.dispose();
@ -42,32 +33,8 @@ class _NavigationBarState extends State<_NavigationBar> {
child: Row(
children: [
Expanded(
child: ShaderMask(
shaderCallback: (rect) {
final colors = <Color>[];
final stops = <double>[];
if (_hasLeftContent) {
colors.addAll([Colors.white, Colors.transparent]);
stops.addAll([0, .1]);
} else {
colors.add(Colors.transparent);
stops.add(0);
}
if (_hasRightContent) {
colors.addAll([Colors.transparent, Colors.white]);
stops.addAll([.9, 1]);
} else {
colors.add(Colors.transparent);
stops.add(1);
}
return LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: colors,
stops: stops,
).createShader(rect);
},
blendMode: BlendMode.dstOut,
child: FadeOutListContainer(
scrollController: _scrollController,
child: _BlocSelector(
selector: (state) => state.navBarButtons,
builder: (context, navBarButtons) {
@ -112,56 +79,7 @@ class _NavigationBarState extends State<_NavigationBar> {
}
}
bool _updateButtonScroll(ScrollPosition pos) {
if (!pos.hasContentDimensions || !pos.hasPixels) {
return false;
}
if (pos.pixels <= pos.minScrollExtent) {
if (_hasLeftContent) {
setState(() {
_hasLeftContent = false;
});
}
} else {
if (!_hasLeftContent) {
setState(() {
_hasLeftContent = true;
});
}
}
if (pos.pixels >= pos.maxScrollExtent) {
if (_hasRightContent) {
setState(() {
_hasRightContent = false;
});
}
} else {
if (!_hasRightContent) {
setState(() {
_hasRightContent = true;
});
}
}
_hasFirstScrollUpdate = true;
return true;
}
void _ensureUpdateButtonScroll() {
if (_hasFirstScrollUpdate || !mounted) {
return;
}
if (_scrollController.hasClients) {
if (_updateButtonScroll(_scrollController.position)) {
return;
}
}
Timer(const Duration(milliseconds: 100), _ensureUpdateButtonScroll);
}
late final ScrollController _scrollController;
var _hasFirstScrollUpdate = false;
var _hasLeftContent = false;
var _hasRightContent = false;
final _scrollController = ScrollController();
}
class _NavBarButtonIndicator extends StatelessWidget {

View file

@ -1,8 +1,19 @@
part of '../collections_nav_bar_settings.dart';
class _DemoView extends StatelessWidget {
class _DemoView extends StatefulWidget {
const _DemoView();
@override
State<StatefulWidget> createState() => _DemoViewState();
}
class _DemoViewState extends State<_DemoView> {
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return _BlocSelector(
@ -13,38 +24,42 @@ class _DemoView extends StatelessWidget {
child: Row(
children: [
Expanded(
child: ListView.builder(
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.only(left: 16 - 6),
itemCount: buttons.length,
itemBuilder: (context, i) {
final btn = buttons[i];
return my.Draggable<HomeCollectionsNavBarButtonType>(
data: btn.type,
feedback: _CandidateButtonDelegate(btn.type),
onDropBefore: (data) {
context.addEvent(_MoveButton.before(
which: data,
target: btn.type,
));
},
onDropAfter: (data) {
context.addEvent(_MoveButton.after(
which: data,
target: btn.type,
));
},
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 6),
child: _DemoButtonDelegate(
btn.type,
isMinimized: btn.isMinimized,
child: FadeOutListContainer(
scrollController: _scrollController,
child: ListView.builder(
controller: _scrollController,
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.only(left: 16 - 6),
itemCount: buttons.length,
itemBuilder: (context, i) {
final btn = buttons[i];
return my.Draggable<HomeCollectionsNavBarButtonType>(
data: btn.type,
feedback: _CandidateButtonDelegate(btn.type),
onDropBefore: (data) {
context.addEvent(_MoveButton.before(
which: data,
target: btn.type,
));
},
onDropAfter: (data) {
context.addEvent(_MoveButton.after(
which: data,
target: btn.type,
));
},
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 6),
child: _DemoButtonDelegate(
btn.type,
isMinimized: btn.isMinimized,
),
),
),
),
);
},
);
},
),
),
),
const SizedBox(width: 8),
@ -81,6 +96,8 @@ class _DemoView extends StatelessWidget {
},
);
}
final _scrollController = ScrollController();
}
class _DemoButtonDelegate extends StatelessWidget {

View file

@ -12,6 +12,7 @@ import 'package:nc_photos/exception_event.dart';
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/widget/draggable.dart' as my;
import 'package:nc_photos/widget/fade_out_list.dart';
import 'package:nc_photos/widget/home_collections.dart';
import 'package:nc_photos/widget/page_visibility_mixin.dart';
import 'package:np_codegen/np_codegen.dart';