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,14 +75,20 @@ class InstallerView extends StatelessWidget {
), ),
), ),
), ),
body: CustomScrollView( body: NotificationListener<ScrollNotification>(
onNotification: model.handleAutoScrollNotification,
child: Stack(
children: [
CustomScrollView(
key: model.logCustomScrollKey,
controller: model.scrollController, controller: model.scrollController,
slivers: <Widget>[ slivers: <Widget>[
CustomSliverAppBar( CustomSliverAppBar(
title: Text( title: Text(
model.headerLogs, model.headerLogs,
style: GoogleFonts.inter( style: GoogleFonts.inter(
color: Theme.of(context).textTheme.titleLarge!.color, color:
Theme.of(context).textTheme.titleLarge!.color,
), ),
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
@ -90,7 +96,9 @@ class InstallerView extends StatelessWidget {
onBackButtonPressed: () => Navigator.maybePop(context), onBackButtonPressed: () => Navigator.maybePop(context),
bottom: PreferredSize( bottom: PreferredSize(
preferredSize: const Size(double.infinity, 1.0), preferredSize: const Size(double.infinity, 1.0),
child: GradientProgressIndicator(progress: model.progress), child: GradientProgressIndicator(
progress: model.progress,
),
), ),
), ),
SliverPadding( SliverPadding(
@ -113,6 +121,19 @@ class InstallerView extends StatelessWidget {
), ),
], ],
), ),
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();
} }