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(
controller: model.scrollController,
slivers: <Widget>[
CustomSliverAppBar(
title: Text(
model.headerLogs,
style: GoogleFonts.inter(
color: Theme.of(context).textTheme.titleLarge!.color,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
onBackButtonPressed: () => Navigator.maybePop(context),
bottom: PreferredSize(
preferredSize: const Size(double.infinity, 1.0),
child: GradientProgressIndicator(progress: model.progress),
),
),
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,
),
body: NotificationListener<ScrollNotification>(
onNotification: model.handleAutoScrollNotification,
child: Stack(
children: [
CustomScrollView(
key: model.logCustomScrollKey,
controller: model.scrollController,
slivers: <Widget>[
CustomSliverAppBar(
title: Text(
model.headerLogs,
style: GoogleFonts.inter(
color:
Theme.of(context).textTheme.titleLarge!.color,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
onBackButtonPressed: () => Navigator.maybePop(context),
bottom: PreferredSize(
preferredSize: const Size(double.infinity, 1.0),
child: GradientProgressIndicator(
progress: model.progress,
),
),
],
),
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(
'app.revanced.manager.flutter/installer',
);
final Key logCustomScrollKey = UniqueKey();
final ScrollController scrollController = ScrollController();
final ScreenshotCallback screenshotCallback = ScreenshotCallback();
double? progress = 0.0;
@ -44,6 +45,57 @@ class InstallerViewModel extends BaseViewModel {
bool cancel = false;
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 {
isRooted = await _rootAPI.isRooted();
if (await Permission.ignoreBatteryOptimizations.isGranted) {
@ -123,13 +175,9 @@ class InstallerViewModel extends BaseViewModel {
if (logs[logs.length - 1] == '\n') {
logs = logs.substring(0, logs.length - 1);
}
Future.delayed(const Duration(milliseconds: 100)).then((value) {
scrollController.animateTo(
scrollController.position.maxScrollExtent,
duration: const Duration(milliseconds: 100),
curve: Curves.fastOutSlowIn,
);
});
if (_isAutoScrollEnabled) {
scrollToBottom();
}
}
notifyListeners();
}