MCSI-3 Custom RAM size option #24
@ -3,6 +3,7 @@ import 'dart:io';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:minecraft_server_installer/main/adapter/presentation/installation_state.dart';
|
||||
import 'package:minecraft_server_installer/main/adapter/presentation/progress_view_model.dart';
|
||||
import 'package:minecraft_server_installer/main/adapter/presentation/range_view_model.dart';
|
||||
import 'package:minecraft_server_installer/main/application/use_case/download_file_use_case.dart';
|
||||
import 'package:minecraft_server_installer/main/application/use_case/grant_file_permission_use_case.dart';
|
||||
import 'package:minecraft_server_installer/main/application/use_case/write_file_use_case.dart';
|
||||
@ -59,10 +60,16 @@ class InstallationBloc extends Bloc<InstallationEvent, InstallationState> {
|
||||
});
|
||||
|
||||
on<InstallationConfigurationUpdatedEvent>((event, emit) {
|
||||
if (event.customRamSize != null && !event.customRamSize!.isValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
final newState = state.copyWith(
|
||||
gameVersion: event.gameVersion,
|
||||
savePath: event.savePath,
|
||||
isEulaAgreed: event.isEulaAgreed,
|
||||
isCustomRamSizeEnabled: event.isCustomRamSizeEnabled,
|
||||
customRamSize: event.customRamSize,
|
||||
);
|
||||
emit(newState);
|
||||
});
|
||||
@ -83,10 +90,14 @@ class InstallationConfigurationUpdatedEvent extends InstallationEvent {
|
||||
final GameVersionViewModel? gameVersion;
|
||||
final String? savePath;
|
||||
final bool? isEulaAgreed;
|
||||
final bool? isCustomRamSizeEnabled;
|
||||
final RangeViewModel? customRamSize;
|
||||
|
||||
InstallationConfigurationUpdatedEvent({
|
||||
this.gameVersion,
|
||||
this.savePath,
|
||||
this.isEulaAgreed,
|
||||
this.isCustomRamSizeEnabled,
|
||||
this.customRamSize,
|
||||
});
|
||||
}
|
||||
|
@ -1,11 +1,16 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:minecraft_server_installer/main/adapter/presentation/progress_view_model.dart';
|
||||
import 'package:minecraft_server_installer/main/adapter/presentation/range_view_model.dart';
|
||||
import 'package:minecraft_server_installer/vanilla/adapter/presentation/game_version_view_model.dart';
|
||||
|
||||
class InstallationState with EquatableMixin {
|
||||
static const _defaultRamSize = RangeViewModel(min: 2048, max: 2048);
|
||||
|
||||
final GameVersionViewModel? gameVersion;
|
||||
final String? savePath;
|
||||
final bool isEulaAgreed;
|
||||
final bool isCustomRamSizeEnabled;
|
||||
final RangeViewModel? _customRamSize;
|
||||
final ProgressViewModel downloadProgress;
|
||||
final bool isLocked;
|
||||
|
||||
@ -13,15 +18,19 @@ class InstallationState with EquatableMixin {
|
||||
required this.gameVersion,
|
||||
required this.savePath,
|
||||
required this.isEulaAgreed,
|
||||
required this.isCustomRamSizeEnabled,
|
||||
required RangeViewModel? customRamSize,
|
||||
required this.downloadProgress,
|
||||
required this.isLocked,
|
||||
});
|
||||
}) : _customRamSize = customRamSize;
|
||||
|
||||
const InstallationState.empty()
|
||||
: this(
|
||||
gameVersion: null,
|
||||
savePath: null,
|
||||
isEulaAgreed: false,
|
||||
isCustomRamSizeEnabled: false,
|
||||
customRamSize: _defaultRamSize,
|
||||
downloadProgress: const ProgressViewModel.zero(),
|
||||
isLocked: false,
|
||||
);
|
||||
@ -31,6 +40,8 @@ class InstallationState with EquatableMixin {
|
||||
gameVersion,
|
||||
savePath,
|
||||
isEulaAgreed,
|
||||
isCustomRamSizeEnabled,
|
||||
_customRamSize,
|
||||
downloadProgress,
|
||||
isLocked,
|
||||
];
|
||||
@ -39,6 +50,8 @@ class InstallationState with EquatableMixin {
|
||||
GameVersionViewModel? gameVersion,
|
||||
String? savePath,
|
||||
bool? isEulaAgreed,
|
||||
bool? isCustomRamSizeEnabled,
|
||||
RangeViewModel? customRamSize,
|
||||
ProgressViewModel? downloadProgress,
|
||||
bool? isLocked,
|
||||
}) =>
|
||||
@ -46,10 +59,14 @@ class InstallationState with EquatableMixin {
|
||||
gameVersion: gameVersion ?? this.gameVersion,
|
||||
savePath: savePath ?? this.savePath,
|
||||
isEulaAgreed: isEulaAgreed ?? this.isEulaAgreed,
|
||||
isCustomRamSizeEnabled: isCustomRamSizeEnabled ?? this.isCustomRamSizeEnabled,
|
||||
customRamSize: customRamSize ?? _customRamSize,
|
||||
downloadProgress: downloadProgress ?? this.downloadProgress,
|
||||
isLocked: isLocked ?? this.isLocked,
|
||||
);
|
||||
|
||||
RangeViewModel get ramSize => isCustomRamSizeEnabled ? _customRamSize ?? _defaultRamSize : _defaultRamSize;
|
||||
|
||||
bool get isGameVersionSelected => gameVersion != null;
|
||||
|
||||
bool get isSavePathSelected => savePath != null && savePath!.isNotEmpty;
|
||||
|
19
lib/main/adapter/presentation/range_view_model.dart
Normal file
19
lib/main/adapter/presentation/range_view_model.dart
Normal file
@ -0,0 +1,19 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
class RangeViewModel with EquatableMixin {
|
||||
final int min;
|
||||
final int max;
|
||||
|
||||
const RangeViewModel({
|
||||
required this.min,
|
||||
required this.max,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
min,
|
||||
max,
|
||||
];
|
||||
|
||||
bool get isValid => min <= max;
|
||||
}
|
@ -4,6 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:minecraft_server_installer/main/adapter/presentation/installation_bloc.dart';
|
||||
import 'package:minecraft_server_installer/main/adapter/presentation/installation_state.dart';
|
||||
import 'package:minecraft_server_installer/main/adapter/presentation/range_view_model.dart';
|
||||
import 'package:minecraft_server_installer/main/constants.dart';
|
||||
import 'package:minecraft_server_installer/main/framework/ui/strings.dart';
|
||||
import 'package:minecraft_server_installer/vanilla/framework/ui/game_version_dropdown.dart';
|
||||
@ -20,6 +21,8 @@ class BasicConfigurationTab extends StatelessWidget {
|
||||
_pathBrowsingField,
|
||||
const Gap(16),
|
||||
_eulaCheckbox,
|
||||
_enableCustomRamSizeCheckbox,
|
||||
_customRamSizeControl,
|
||||
const Spacer(),
|
||||
_bottomControl,
|
||||
],
|
||||
@ -79,6 +82,76 @@ class BasicConfigurationTab extends StatelessWidget {
|
||||
],
|
||||
);
|
||||
|
||||
Widget get _enableCustomRamSizeCheckbox => BlocConsumer<InstallationBloc, InstallationState>(
|
||||
listener: (_, __) {},
|
||||
builder: (context, state) => CheckboxListTile(
|
||||
title: const Text(Strings.fieldCustomRamSize),
|
||||
value: state.isCustomRamSizeEnabled,
|
||||
onChanged: (value) => context
|
||||
.read<InstallationBloc>()
|
||||
.add(InstallationConfigurationUpdatedEvent(isCustomRamSizeEnabled: value ?? false)),
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)),
|
||||
),
|
||||
);
|
||||
|
||||
Widget get _customRamSizeControl => BlocConsumer<InstallationBloc, InstallationState>(
|
||||
listener: (_, __) {},
|
||||
builder: (context, state) {
|
||||
if (!state.isCustomRamSizeEnabled) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
RangeSlider(
|
||||
values: RangeValues(state.ramSize.min.toDouble(), state.ramSize.max.toDouble()),
|
||||
min: 512,
|
||||
max: 16384,
|
||||
divisions: (16384 - 512) ~/ 128,
|
||||
labels: RangeLabels(
|
||||
'${state.ramSize.min} MB',
|
||||
'${state.ramSize.max} MB',
|
||||
),
|
||||
onChanged: (values) => context.read<InstallationBloc>().add(
|
||||
InstallationConfigurationUpdatedEvent(
|
||||
customRamSize: RangeViewModel(min: values.start.toInt(), max: values.end.toInt()),
|
||||
),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: TextEditingController(text: state.ramSize.min.toString()),
|
||||
canRequestFocus: false,
|
||||
readOnly: true,
|
||||
decoration: InputDecoration(
|
||||
label: const Text('${Strings.labelMinRamSize} (MB)'),
|
||||
border: OutlineInputBorder(borderRadius: BorderRadius.circular(4)),
|
||||
),
|
||||
),
|
||||
),
|
||||
const Gap(16),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: TextEditingController(text: state.ramSize.max.toString()),
|
||||
canRequestFocus: false,
|
||||
readOnly: true,
|
||||
decoration: InputDecoration(
|
||||
label: const Text('${Strings.labelMaxRamSize} (MB)'),
|
||||
border: OutlineInputBorder(borderRadius: BorderRadius.circular(4)),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
Widget get _bottomControl => BlocConsumer<InstallationBloc, InstallationState>(
|
||||
listener: (_, __) {},
|
||||
builder: (context, state) => Row(
|
||||
|
@ -2,8 +2,11 @@ abstract class Strings {
|
||||
static const fieldGameVersion = '遊戲版本';
|
||||
static const fieldPath = '安裝路徑';
|
||||
static const fieldEula = '我同意 EULA 條款';
|
||||
static const fieldCustomRamSize = '啟用自定義 RAM 大小';
|
||||
static const buttonStartToInstall = '開始安裝';
|
||||
static const buttonBrowse = '瀏覽';
|
||||
static const labelMinRamSize = '最小 RAM 大小';
|
||||
static const labelMaxRamSize = '最大 RAM 大小';
|
||||
static const tooltipEulaInfo = '點擊查看 EULA 條款';
|
||||
static const dialogTitleSelectDirectory = '選擇安裝目錄';
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user