fix : progress bar for macrecovery and wget, graceful fallback for zsync
This commit is contained in:
parent
661880bdbf
commit
51b6d576a0
|
@ -2,13 +2,16 @@ import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:quickgui/src/app.dart';
|
import 'package:quickgui/src/app.dart';
|
||||||
|
import 'package:quickgui/src/globals.dart';
|
||||||
import 'package:quickgui/src/model/operating_system.dart';
|
import 'package:quickgui/src/model/operating_system.dart';
|
||||||
|
import 'package:quickgui/src/model/option.dart';
|
||||||
import 'package:quickgui/src/model/version.dart';
|
import 'package:quickgui/src/model/version.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
import 'package:window_size/window_size.dart';
|
import 'package:window_size/window_size.dart';
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
Directory.current = gCurrentDirectoy;
|
||||||
setWindowTitle('Quickgui : a flutter frontend for Quickget and Quickemu');
|
setWindowTitle('Quickgui : a flutter frontend for Quickget and Quickemu');
|
||||||
setWindowMinSize(const Size(692, 580));
|
setWindowMinSize(const Size(692, 580));
|
||||||
setWindowMaxSize(const Size(692, 580));
|
setWindowMaxSize(const Size(692, 580));
|
||||||
|
@ -44,7 +47,7 @@ Future<List<OperatingSystem>> loadOperatingSystems(bool showUbuntus) async {
|
||||||
currentVersion = Version(supportedVersion.item3);
|
currentVersion = Version(supportedVersion.item3);
|
||||||
currentOperatingSystem!.versions.add(currentVersion!);
|
currentOperatingSystem!.versions.add(currentVersion!);
|
||||||
}
|
}
|
||||||
currentVersion!.options.add(supportedVersion.item4);
|
currentVersion!.options.add(Option(supportedVersion.item4, supportedVersion.item5));
|
||||||
});
|
});
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
var gIsSnap = Platform.environment['SNAP']?.isNotEmpty ?? false;
|
||||||
|
var gCurrentDirectoy = Directory(Platform.environment['HOME'] ?? Directory.current.absolute.path);
|
|
@ -0,0 +1,6 @@
|
||||||
|
class Option {
|
||||||
|
Option(this.option, this.downloader);
|
||||||
|
|
||||||
|
final String option;
|
||||||
|
final String downloader;
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
|
import 'package:quickgui/src/model/option.dart';
|
||||||
|
|
||||||
class Version {
|
class Version {
|
||||||
Version(this.version) : options = [];
|
Version(this.version) : options = [];
|
||||||
|
|
||||||
final String version;
|
final String version;
|
||||||
final List<String> options;
|
final List<Option> options;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:quickgui/src/model/operating_system.dart';
|
import 'package:quickgui/src/model/operating_system.dart';
|
||||||
|
import 'package:quickgui/src/model/option.dart';
|
||||||
import 'package:quickgui/src/model/version.dart';
|
import 'package:quickgui/src/model/version.dart';
|
||||||
|
|
||||||
class Downloader extends StatefulWidget {
|
class Downloader extends StatefulWidget {
|
||||||
|
@ -16,14 +17,15 @@ class Downloader extends StatefulWidget {
|
||||||
|
|
||||||
final OperatingSystem operatingSystem;
|
final OperatingSystem operatingSystem;
|
||||||
final Version version;
|
final Version version;
|
||||||
final String? option;
|
final Option? option;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_DownloaderState createState() => _DownloaderState();
|
_DownloaderState createState() => _DownloaderState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DownloaderState extends State<Downloader> {
|
class _DownloaderState extends State<Downloader> {
|
||||||
final pattern = RegExp("( [0-9.]+%)");
|
final wgetPattern = RegExp("( [0-9.]+%)");
|
||||||
|
final macRecoveryPattern = RegExp("([0-9]+\\.[0-9])");
|
||||||
late final Stream<double> _progressStream;
|
late final Stream<double> _progressStream;
|
||||||
bool _downloadFinished = false;
|
bool _downloadFinished = false;
|
||||||
var controller = StreamController<double>();
|
var controller = StreamController<double>();
|
||||||
|
@ -34,9 +36,8 @@ class _DownloaderState extends State<Downloader> {
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void parseProgress(String line) {
|
void parseWgetProgress(String line) {
|
||||||
print(line);
|
var matches = wgetPattern.allMatches(line).toList();
|
||||||
var matches = pattern.allMatches(line).toList();
|
|
||||||
if (matches.isNotEmpty) {
|
if (matches.isNotEmpty) {
|
||||||
var percent = matches[0].group(1);
|
var percent = matches[0].group(1);
|
||||||
if (percent != null) {
|
if (percent != null) {
|
||||||
|
@ -46,14 +47,33 @@ class _DownloaderState extends State<Downloader> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void parseMacRecoveryProgress(String line) {
|
||||||
|
var matches = macRecoveryPattern.allMatches(line).toList();
|
||||||
|
if (matches.isNotEmpty) {
|
||||||
|
var size = matches[0].group(1);
|
||||||
|
print(size);
|
||||||
|
if (size != null) {
|
||||||
|
var value = double.parse(size);
|
||||||
|
print(value);
|
||||||
|
controller.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Stream<double> progressStream() {
|
Stream<double> progressStream() {
|
||||||
var options = [widget.operatingSystem.code, widget.version.version];
|
var options = [widget.operatingSystem.code, widget.version.version];
|
||||||
if (widget.option != null) {
|
if (widget.option != null) {
|
||||||
options.add(widget.option!);
|
options.add(widget.option!.option);
|
||||||
}
|
}
|
||||||
Process.start('quickget', options).then((process) {
|
Process.start('quickget', options).then((process) {
|
||||||
process.stdout.transform(utf8.decoder).forEach(parseProgress);
|
if (widget.option!.downloader == 'wget') {
|
||||||
process.stderr.transform(utf8.decoder).forEach(parseProgress);
|
process.stderr.transform(utf8.decoder).forEach(parseWgetProgress);
|
||||||
|
} else if (widget.option!.downloader == 'zsync') {
|
||||||
|
controller.add(-1);
|
||||||
|
} else if (widget.option!.downloader == 'macrecovery') {
|
||||||
|
process.stdout.transform(utf8.decoder).forEach(parseMacRecoveryProgress);
|
||||||
|
}
|
||||||
|
|
||||||
process.exitCode.then((value) {
|
process.exitCode.then((value) {
|
||||||
print("Process exited with exit code $value");
|
print("Process exited with exit code $value");
|
||||||
controller.close();
|
controller.close();
|
||||||
|
@ -69,7 +89,8 @@ class _DownloaderState extends State<Downloader> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('Downloading ${widget.operatingSystem.name} ${widget.version.version}' + (widget.option != null ? ' (${widget.option})' : '')),
|
title: Text(
|
||||||
|
'Downloading ${widget.operatingSystem.name} ${widget.version.version}' + (widget.option!.option.isNotEmpty ? ' (${widget.option!.option})' : '')),
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Column(
|
||||||
|
@ -78,6 +99,7 @@ class _DownloaderState extends State<Downloader> {
|
||||||
child: StreamBuilder(
|
child: StreamBuilder(
|
||||||
stream: _progressStream,
|
stream: _progressStream,
|
||||||
builder: (context, AsyncSnapshot<double> snapshot) {
|
builder: (context, AsyncSnapshot<double> snapshot) {
|
||||||
|
var data = !snapshot.hasData || widget.option!.downloader != 'wget' ? null : snapshot.data;
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
|
@ -86,7 +108,11 @@ class _DownloaderState extends State<Downloader> {
|
||||||
child: _downloadFinished
|
child: _downloadFinished
|
||||||
? const Text('Download finished.')
|
? const Text('Download finished.')
|
||||||
: snapshot.hasData
|
: snapshot.hasData
|
||||||
? Text('Downloading...${(snapshot.data! * 100).toInt()}%')
|
? widget.option!.downloader != 'zsync'
|
||||||
|
? widget.option!.downloader == 'wget'
|
||||||
|
? Text('Downloading...${(snapshot.data! * 100).toInt()}%')
|
||||||
|
: Text('${snapshot.data} Mbs downloaded')
|
||||||
|
: const Text("Downloading (no progress available)...")
|
||||||
: const Text('Waiting for download to start'),
|
: const Text('Waiting for download to start'),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
|
@ -97,11 +123,15 @@ class _DownloaderState extends State<Downloader> {
|
||||||
value: _downloadFinished
|
value: _downloadFinished
|
||||||
? 1
|
? 1
|
||||||
: snapshot.hasData
|
: snapshot.hasData
|
||||||
? snapshot.data!
|
? data
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 32),
|
||||||
|
child: Text("Target folder : ${Directory.current}"),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -22,7 +22,7 @@ class _OptionSelectionState extends State<OptionSelection> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var list = widget.version.options.where((e) => e.toLowerCase().contains(term.toLowerCase())).toList();
|
var list = widget.version.options.where((e) => e.option.toLowerCase().contains(term.toLowerCase())).toList();
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
|
@ -73,7 +73,7 @@ class _OptionSelectionState extends State<OptionSelection> {
|
||||||
var item = list[index];
|
var item = list[index];
|
||||||
return Card(
|
return Card(
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
title: Text(item),
|
title: Text(item.option),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.of(context).pop(item);
|
Navigator.of(context).pop(item);
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:quickgui/src/model/operating_system.dart';
|
import 'package:quickgui/src/model/operating_system.dart';
|
||||||
|
import 'package:quickgui/src/model/option.dart';
|
||||||
import 'package:quickgui/src/model/version.dart';
|
import 'package:quickgui/src/model/version.dart';
|
||||||
import 'package:quickgui/src/pages/option_selection.dart';
|
import 'package:quickgui/src/pages/option_selection.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
|
@ -34,15 +35,15 @@ class _VersionSelectionState extends State<VersionSelection> {
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (widget.operatingSystem.versions[index].options.length > 1) {
|
if (widget.operatingSystem.versions[index].options.length > 1) {
|
||||||
Navigator.of(context)
|
Navigator.of(context)
|
||||||
.push<String>(
|
.push<Option>(
|
||||||
MaterialPageRoute(fullscreenDialog: true, builder: (context) => OptionSelection(widget.operatingSystem.versions[index])))
|
MaterialPageRoute(fullscreenDialog: true, builder: (context) => OptionSelection(widget.operatingSystem.versions[index])))
|
||||||
.then((selection) {
|
.then((selection) {
|
||||||
if (selection != null) {
|
if (selection != null) {
|
||||||
Navigator.of(context).pop(Tuple2<Version, String?>(item, selection));
|
Navigator.of(context).pop(Tuple2<Version, Option?>(item, selection));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Navigator.of(context).pop(Tuple2<Version, String?>(item, null));
|
Navigator.of(context).pop(Tuple2<Version, Option?>(item, widget.operatingSystem.versions[index].options[0]));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'dart:io';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:quickgui/src/model/operating_system.dart';
|
import 'package:quickgui/src/model/operating_system.dart';
|
||||||
|
import 'package:quickgui/src/model/option.dart';
|
||||||
import 'package:quickgui/src/model/version.dart';
|
import 'package:quickgui/src/model/version.dart';
|
||||||
import 'package:quickgui/src/pages/downloader.dart';
|
import 'package:quickgui/src/pages/downloader.dart';
|
||||||
import 'package:quickgui/src/pages/operating_system_selection.dart';
|
import 'package:quickgui/src/pages/operating_system_selection.dart';
|
||||||
|
@ -20,13 +21,13 @@ class HomePageButtons extends StatefulWidget {
|
||||||
class _HomePageButtonsState extends State<HomePageButtons> {
|
class _HomePageButtonsState extends State<HomePageButtons> {
|
||||||
OperatingSystem? _selectedOperatingSystem;
|
OperatingSystem? _selectedOperatingSystem;
|
||||||
Version? _selectedVersion;
|
Version? _selectedVersion;
|
||||||
String? _selectedOption;
|
Option? _selectedOption;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var _versionButtonLabel = _selectedVersion?.version ?? 'Select...';
|
var _versionButtonLabel = _selectedVersion?.version ?? 'Select...';
|
||||||
if (_selectedOption != null) {
|
if (_selectedOption?.option.isNotEmpty ?? false) {
|
||||||
_versionButtonLabel = "$_versionButtonLabel ($_selectedOption)";
|
_versionButtonLabel = "$_versionButtonLabel (${_selectedOption!.option})";
|
||||||
}
|
}
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
|
@ -53,7 +54,7 @@ class _HomePageButtonsState extends State<HomePageButtons> {
|
||||||
onPressed: (_selectedOperatingSystem != null)
|
onPressed: (_selectedOperatingSystem != null)
|
||||||
? () {
|
? () {
|
||||||
Navigator.of(context)
|
Navigator.of(context)
|
||||||
.push<Tuple2<Version, String?>>(MaterialPageRoute(
|
.push<Tuple2<Version, Option?>>(MaterialPageRoute(
|
||||||
fullscreenDialog: true,
|
fullscreenDialog: true,
|
||||||
builder: (context) => VersionSelection(operatingSystem: _selectedOperatingSystem!),
|
builder: (context) => VersionSelection(operatingSystem: _selectedOperatingSystem!),
|
||||||
))
|
))
|
||||||
|
|
Loading…
Reference in New Issue