fix(ui): Support free-scroll and auto-scroll for the installer logs (#1736) (#1836)

This commit is contained in:
DMzS 2024-04-03 22:27:47 -04:00 committed by GitHub
parent 35fdbb5988
commit 025ff527ee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 109 additions and 40 deletions

View File

@ -75,43 +75,64 @@ class InstallerView extends StatelessWidget {
), ),
), ),
), ),
body: CustomScrollView( body: NotificationListener<ScrollNotification>(
controller: model.scrollController, onNotification: model.handleAutoScrollNotification,
slivers: <Widget>[ child: Stack(
CustomSliverAppBar( children: [
title: Text( CustomScrollView(
model.headerLogs, key: model.logCustomScrollKey,
style: GoogleFonts.inter( controller: model.scrollController,
color: Theme.of(context).textTheme.titleLarge!.color, slivers: <Widget>[
), CustomSliverAppBar(
maxLines: 1, title: Text(
overflow: TextOverflow.ellipsis, model.headerLogs,
), style: GoogleFonts.inter(
onBackButtonPressed: () => Navigator.maybePop(context), color:
bottom: PreferredSize( Theme.of(context).textTheme.titleLarge!.color,
preferredSize: const Size(double.infinity, 1.0), ),
child: GradientProgressIndicator(progress: model.progress), maxLines: 1,
), overflow: TextOverflow.ellipsis,
), ),
SliverPadding( onBackButtonPressed: () => Navigator.maybePop(context),
padding: const EdgeInsets.all(20.0), bottom: PreferredSize(
sliver: SliverList( preferredSize: const Size(double.infinity, 1.0),
delegate: SliverChildListDelegate.fixed( child: GradientProgressIndicator(
<Widget>[ progress: model.progress,
CustomCard(
child: Text(
model.logs,
style: GoogleFonts.jetBrainsMono(
fontSize: 13,
height: 1.5,
),
), ),
), ),
], ),
SliverPadding(
padding: const EdgeInsets.all(20.0),
sliver: SliverList(
delegate: SliverChildListDelegate.fixed(
<Widget>[
CustomCard(
child: Text(
model.logs,
style: GoogleFonts.jetBrainsMono(
fontSize: 13,
height: 1.5,
),
),
),
],
),
),
),
],
),
Visibility(
visible: model.showAutoScrollButton,
child: Align(
alignment: const Alignment(0.9, 0.97),
child: FloatingActionButton(
onPressed: model.scrollToBottom,
child: const Icon(Icons.arrow_downward_rounded),
),
), ),
), ),
), ],
], ),
), ),
), ),
), ),

View File

@ -30,6 +30,7 @@ class InstallerViewModel extends BaseViewModel {
static const _installerChannel = MethodChannel( static const _installerChannel = MethodChannel(
'app.revanced.manager.flutter/installer', 'app.revanced.manager.flutter/installer',
); );
final Key logCustomScrollKey = UniqueKey();
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
final ScreenshotCallback screenshotCallback = ScreenshotCallback(); final ScreenshotCallback screenshotCallback = ScreenshotCallback();
double? progress = 0.0; double? progress = 0.0;
@ -44,6 +45,57 @@ class InstallerViewModel extends BaseViewModel {
bool cancel = false; bool cancel = false;
bool showPopupScreenshotWarning = true; bool showPopupScreenshotWarning = true;
bool showAutoScrollButton = false;
bool _isAutoScrollEnabled = true;
bool _isAutoScrolling = false;
double get getCurrentScrollPercentage {
final maxScrollExtent = scrollController.position.maxScrollExtent;
final currentPosition = scrollController.position.pixels;
return currentPosition / maxScrollExtent;
}
bool handleAutoScrollNotification(ScrollNotification event) {
if (_isAutoScrollEnabled && event is ScrollStartNotification) {
_isAutoScrollEnabled = _isAutoScrolling;
showAutoScrollButton = false;
notifyListeners();
return true;
}
if (event is ScrollEndNotification) {
const anchorThreshold = 0.987;
_isAutoScrollEnabled =
_isAutoScrolling || getCurrentScrollPercentage >= anchorThreshold;
showAutoScrollButton = !_isAutoScrollEnabled && !_isAutoScrolling;
notifyListeners();
return true;
}
return false;
}
void scrollToBottom() {
_isAutoScrolling = true;
WidgetsBinding.instance.addPostFrameCallback((_) async {
final maxScrollExtent = scrollController.position.maxScrollExtent;
await scrollController.animateTo(
maxScrollExtent,
duration: const Duration(milliseconds: 100),
curve: Curves.fastOutSlowIn,
);
_isAutoScrolling = false;
});
}
Future<void> initialize(BuildContext context) async { Future<void> initialize(BuildContext context) async {
isRooted = await _rootAPI.isRooted(); isRooted = await _rootAPI.isRooted();
if (await Permission.ignoreBatteryOptimizations.isGranted) { if (await Permission.ignoreBatteryOptimizations.isGranted) {
@ -123,13 +175,9 @@ class InstallerViewModel extends BaseViewModel {
if (logs[logs.length - 1] == '\n') { if (logs[logs.length - 1] == '\n') {
logs = logs.substring(0, logs.length - 1); logs = logs.substring(0, logs.length - 1);
} }
Future.delayed(const Duration(milliseconds: 100)).then((value) { if (_isAutoScrollEnabled) {
scrollController.animateTo( scrollToBottom();
scrollController.position.maxScrollExtent, }
duration: const Duration(milliseconds: 100),
curve: Curves.fastOutSlowIn,
);
});
} }
notifyListeners(); notifyListeners();
} }