-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow custom Java Executable selection!
Closes #3
- Loading branch information
1 parent
8fe6faa
commit 9a57eb0
Showing
8 changed files
with
307 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import "package:flutter/material.dart"; | ||
import "package:flutter_riverpod/flutter_riverpod.dart"; | ||
|
||
import "../prefs.dart"; | ||
import "radio_list_tile_custom_java_picker.dart"; | ||
import "radio_list_tile_system_java_picker.dart"; | ||
|
||
final javaPathProvider = Provider<String?>((ref) { | ||
return Prefs.instance.javaPath; | ||
}); | ||
|
||
enum JavaPickerMode { | ||
system, | ||
pick, | ||
} | ||
|
||
class JavaPicker extends ConsumerStatefulWidget { | ||
const JavaPicker({super.key}); | ||
|
||
@override | ||
ConsumerState<JavaPicker> createState() => _JavaPickerState(); | ||
} | ||
|
||
class _JavaPickerState extends ConsumerState<JavaPicker> { | ||
JavaPickerMode? javaPickerMode; | ||
|
||
@override | ||
void initState() { | ||
super.initState(); | ||
if (Prefs.instance.javaPath != null) { | ||
javaPickerMode = | ||
Prefs.instance.javaPath == "java" ? JavaPickerMode.system : JavaPickerMode.pick; | ||
} | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return ConstrainedBox( | ||
constraints: const BoxConstraints(maxWidth: 500), | ||
child: Column( | ||
mainAxisSize: MainAxisSize.min, | ||
mainAxisAlignment: MainAxisAlignment.start, | ||
crossAxisAlignment: CrossAxisAlignment.center, | ||
children: [ | ||
const Text("Select your Java executable:"), | ||
const SizedBox(height: 4), | ||
RadioListTileSystemJavaPicker( | ||
groupValue: javaPickerMode, | ||
onSet: () { | ||
setState(() { | ||
javaPickerMode = JavaPickerMode.system; | ||
}); | ||
Prefs.instance.javaPath = "java"; | ||
ref.invalidate(javaPathProvider); | ||
}, | ||
), | ||
RadioListTileCustomJavaPicker( | ||
groupValue: javaPickerMode, | ||
onChanged: (javaPath) { | ||
setState(() { | ||
javaPickerMode = JavaPickerMode.pick; | ||
}); | ||
Prefs.instance.javaPath = javaPath; | ||
ref.invalidate(javaPathProvider); | ||
}, | ||
) | ||
], | ||
), | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import "package:file_picker/file_picker.dart"; | ||
import "package:flutter/material.dart"; | ||
|
||
import "java_picker.dart"; | ||
import "util_for_checking_java_path_version.dart"; | ||
|
||
enum _CustomPickingState { | ||
nothing, | ||
picking, | ||
checking, | ||
failed, | ||
success, | ||
} | ||
|
||
class RadioListTileCustomJavaPicker extends StatefulWidget { | ||
final JavaPickerMode? groupValue; | ||
final Function(String javaPath) onChanged; | ||
|
||
const RadioListTileCustomJavaPicker({ | ||
super.key, | ||
required this.groupValue, | ||
required this.onChanged, | ||
}); | ||
|
||
@override | ||
State<RadioListTileCustomJavaPicker> createState() => | ||
_RadioListTileCustomJavaPickerState(); | ||
} | ||
|
||
class _RadioListTileCustomJavaPickerState extends State<RadioListTileCustomJavaPicker> { | ||
_CustomPickingState customPickingState = _CustomPickingState.nothing; | ||
String? customPickErrorText; | ||
int? customJavaVersion; | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return RadioListTile<JavaPickerMode>( | ||
title: const Text("Custom"), | ||
subtitle: switch (customPickingState) { | ||
_CustomPickingState.nothing => const Text("Select a Java executable manually"), | ||
_CustomPickingState.picking => const Text("Selecting Java executable..."), | ||
_CustomPickingState.checking => const Text("Checking Java version..."), | ||
_CustomPickingState.failed => Text( | ||
customPickErrorText ?? "Unknown error", | ||
style: const TextStyle(color: Colors.red), | ||
), | ||
_CustomPickingState.success => Text( | ||
"Detected Java version: $customJavaVersion", | ||
), | ||
}, | ||
value: JavaPickerMode.pick, | ||
groupValue: widget.groupValue, | ||
onChanged: (JavaPickerMode? value) async { | ||
if (customPickingState != _CustomPickingState.nothing && | ||
customPickingState != _CustomPickingState.failed && | ||
customPickingState != _CustomPickingState.success) return; | ||
setState(() => customPickingState = _CustomPickingState.picking); | ||
final FilePickerResult? picked = await FilePicker.platform.pickFiles( | ||
dialogTitle: "Select Java executable", | ||
//cannot use FileType.custom, because it doesn't support files with no extension, which is the case for executables on linux | ||
type: FileType.any, | ||
); | ||
if (picked == null) { | ||
setState(() => customPickingState = _CustomPickingState.nothing); | ||
return; // User canceled the picker | ||
} | ||
setState(() => customPickingState = _CustomPickingState.checking); | ||
|
||
final String? javaPath = picked.files.single.path; | ||
if (javaPath == null) { | ||
setState(() { | ||
customPickingState = _CustomPickingState.failed; | ||
customPickErrorText = "Path is null"; | ||
}); | ||
return; | ||
} | ||
|
||
int javaVersion; | ||
try { | ||
javaVersion = await checkJavaVersion(javaPath); | ||
} catch (e) { | ||
setState(() { | ||
customPickingState = _CustomPickingState.failed; | ||
customPickErrorText = e.toString().replaceAll("Exception:", "Error:"); | ||
}); | ||
return; | ||
} | ||
|
||
setState(() { | ||
customPickingState = _CustomPickingState.success; | ||
customJavaVersion = javaVersion; | ||
widget.onChanged(javaPath); | ||
}); | ||
}, | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import "package:flutter/material.dart"; | ||
import "package:flutter_riverpod/flutter_riverpod.dart"; | ||
|
||
import "../utils.dart"; | ||
import "java_picker.dart"; | ||
import "util_for_checking_java_path_version.dart"; | ||
|
||
final _systemJavaVersionProvider = FutureProvider((ref) async { | ||
return checkJavaVersion("java"); | ||
}); | ||
|
||
class RadioListTileSystemJavaPicker extends ConsumerWidget { | ||
final JavaPickerMode? groupValue; | ||
final Function() onSet; | ||
|
||
const RadioListTileSystemJavaPicker({ | ||
super.key, | ||
required this.groupValue, | ||
required this.onSet, | ||
}); | ||
|
||
@override | ||
Widget build(BuildContext context, WidgetRef ref) { | ||
final AsyncValue<int> javaVersion = ref.watch(_systemJavaVersionProvider); | ||
final bool hasSuitableJavaInstalled = javaVersion.valueOrNull != null; | ||
|
||
return RadioListTile<JavaPickerMode>( | ||
title: Text(JavaPickerMode.system.name.capitalize()), | ||
subtitle: switch (javaVersion) { | ||
AsyncData(:final value) => Text("Detected System Java version: $value"), | ||
AsyncError(:final error) => Text( | ||
error.toString(), | ||
style: const TextStyle(color: Colors.red), | ||
), | ||
_ => const Text("Checking System Java version..."), | ||
}, | ||
value: JavaPickerMode.system, | ||
groupValue: groupValue, | ||
onChanged: hasSuitableJavaInstalled ? (JavaPickerMode? value) => onSet() : null, | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import "dart:io"; | ||
|
||
const int _minJavaVersion = 16; | ||
|
||
/// Checks the Java version at the given path. | ||
/// Throw an exception if the Java version is too old, not installed, or the path is invalid. | ||
Future<int> checkJavaVersion(String javaPath) async { | ||
if (javaPath.isEmpty) { | ||
throw "Provided path is empty."; | ||
} | ||
|
||
if (!javaPath.contains("java")) { | ||
throw "Provided path is not a Java executable."; | ||
} | ||
|
||
// If the path is not the system Java path, check if the file exists | ||
if (javaPath != "java") { | ||
if (!File(javaPath).existsSync()) { | ||
throw "File at provided path does not exist."; | ||
} | ||
} | ||
|
||
try { | ||
ProcessResult jv = await Process.run(javaPath, ["--version"]); | ||
final int exitCode = jv.exitCode; | ||
final String stdout = jv.stdout; | ||
final String stderr = jv.stderr; | ||
|
||
if (exitCode != 0) { | ||
throw "Process exited with $exitCode.\n$stderr"; | ||
} | ||
|
||
RegExp r = RegExp(r"\d+"); | ||
final Match? match = r.firstMatch(stdout); | ||
if (match == null) { | ||
throw "Version message did not contain a version number."; | ||
} | ||
|
||
int? version = int.tryParse(match.group(0) ?? ""); | ||
if (version == null) { | ||
throw "Couldn't parse version message."; | ||
} | ||
|
||
if (version < _minJavaVersion) { | ||
throw "System Java version $version is too old. Please install Java $_minJavaVersion or newer."; | ||
} | ||
|
||
return version; | ||
} on ProcessException { | ||
if (javaPath == "java") { | ||
throw "Java (probably) not installed on your system. Please install Java $_minJavaVersion or newer."; | ||
} else { | ||
throw "Invalid Java executable."; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.