Compare commits
No commits in common. "MCSI-8_server_properties_tab" and "main" have entirely different histories.
MCSI-8_ser
...
main
@ -3,22 +3,22 @@ import 'package:minecraft_server_installer/main/adapter/gateway/installation_fil
|
|||||||
import 'package:minecraft_server_installer/main/application/repository/installation_repository.dart';
|
import 'package:minecraft_server_installer/main/application/repository/installation_repository.dart';
|
||||||
|
|
||||||
class InstallationRepositoryImpl implements InstallationRepository {
|
class InstallationRepositoryImpl implements InstallationRepository {
|
||||||
final InstallationApiService _installationApiService;
|
final InstallationApiService _apiService;
|
||||||
final InstallationFileStorage _installationFileStorage;
|
final InstallationFileStorage _fileStorage;
|
||||||
|
|
||||||
InstallationRepositoryImpl(this._installationApiService, this._installationFileStorage);
|
InstallationRepositoryImpl(this._apiService, this._fileStorage);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> downloadFile(Uri url, String path, {DownloadProgressCallback? onProgressChanged}) async {
|
Future<void> downloadFile(Uri url, String path, {DownloadProgressCallback? onProgressChanged}) async {
|
||||||
final fileBytes = await _installationApiService.fetchRemoteFile(url, onProgressChanged: onProgressChanged);
|
final fileBytes = await _apiService.fetchRemoteFile(url, onProgressChanged: onProgressChanged);
|
||||||
await _installationFileStorage.saveFile(fileBytes, path);
|
await _fileStorage.saveFile(fileBytes, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> writeFile(String path, String content) => _installationFileStorage.writeFile(path, content);
|
Future<void> writeFile(String path, String content) => _fileStorage.writeFile(path, content);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> grantFileExecutePermission(String path) {
|
Future<void> grantFileExecutePermission(String path) {
|
||||||
return _installationFileStorage.grantFileExecutePermission(path);
|
return _fileStorage.grantFileExecutePermission(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,32 +1,45 @@
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:minecraft_server_installer/main/adapter/presenter/installation_state.dart';
|
import 'package:minecraft_server_installer/main/adapter/presentation/installation_state.dart';
|
||||||
import 'package:minecraft_server_installer/main/adapter/presenter/progress_view_model.dart';
|
import 'package:minecraft_server_installer/main/adapter/presentation/progress_view_model.dart';
|
||||||
import 'package:minecraft_server_installer/main/adapter/presenter/range_view_model.dart';
|
import 'package:minecraft_server_installer/main/adapter/presentation/range_view_model.dart';
|
||||||
import 'package:minecraft_server_installer/main/application/use_case/install_server_use_case.dart';
|
import 'package:minecraft_server_installer/main/application/use_case/download_file_use_case.dart';
|
||||||
import 'package:minecraft_server_installer/properties/adapter/presenter/server_properties_view_model.dart';
|
import 'package:minecraft_server_installer/main/application/use_case/grant_file_permission_use_case.dart';
|
||||||
import 'package:minecraft_server_installer/vanilla/adapter/presenter/game_version_view_model.dart';
|
import 'package:minecraft_server_installer/main/application/use_case/write_file_use_case.dart';
|
||||||
|
import 'package:minecraft_server_installer/main/constants.dart';
|
||||||
|
import 'package:minecraft_server_installer/vanilla/adapter/presentation/game_version_view_model.dart';
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
class InstallationBloc extends Bloc<InstallationEvent, InstallationState> {
|
class InstallationBloc extends Bloc<InstallationEvent, InstallationState> {
|
||||||
InstallationBloc(
|
InstallationBloc(
|
||||||
InstallServerUseCase installServerUseCase,
|
DownloadFileUseCase downloadFileUseCase,
|
||||||
|
WriteFileUseCase writeFileUseCase,
|
||||||
|
GrantFilePermissionUseCase grantFilePermissionUseCase,
|
||||||
) : super(const InstallationState.empty()) {
|
) : super(const InstallationState.empty()) {
|
||||||
on<InstallationStartedEvent>((event, emit) async {
|
on<InstallationStartedEvent>((_, emit) async {
|
||||||
if (!state.canStartToInstall) {
|
if (!state.canStartToInstall) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final gameVersion = state.gameVersion!;
|
||||||
|
final savePath = state.savePath!;
|
||||||
|
|
||||||
emit(state.copyWith(isLocked: true, downloadProgress: const ProgressViewModel.start()));
|
emit(state.copyWith(isLocked: true, downloadProgress: const ProgressViewModel.start()));
|
||||||
|
|
||||||
await installServerUseCase(
|
await downloadFileUseCase(
|
||||||
gameVersion: state.gameVersion!.toEntity(),
|
gameVersion.url,
|
||||||
savePath: state.savePath!,
|
path.join(savePath, Constants.serverFileName),
|
||||||
maxRam: state.ramSize.max,
|
|
||||||
minRam: state.ramSize.min,
|
|
||||||
isGuiEnabled: state.isGuiEnabled,
|
|
||||||
serverProperties: event.serverProperties.toEntity(),
|
|
||||||
onProgressChanged: (progressValue) => add(_InstallationProgressValueChangedEvent(progressValue)),
|
onProgressChanged: (progressValue) => add(_InstallationProgressValueChangedEvent(progressValue)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final startScriptFilePath = path.join(savePath, Constants.startScriptFileName);
|
||||||
|
final serverFilePath = path.join('.', Constants.serverFileName);
|
||||||
|
final startScriptContent =
|
||||||
|
'java -Xmx${state.ramSize.max}M -Xms${state.ramSize.min}M -jar $serverFilePath ${state.isGuiEnabled ? '' : 'nogui'}';
|
||||||
|
await writeFileUseCase(startScriptFilePath, startScriptContent);
|
||||||
|
await grantFilePermissionUseCase(startScriptFilePath);
|
||||||
|
|
||||||
|
await writeFileUseCase(path.join(savePath, Constants.eulaFileName), Constants.eulaFileContent);
|
||||||
|
|
||||||
emit(state.copyWith(isLocked: false, downloadProgress: const ProgressViewModel.complete()));
|
emit(state.copyWith(isLocked: false, downloadProgress: const ProgressViewModel.complete()));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -64,11 +77,7 @@ class InstallationBloc extends Bloc<InstallationEvent, InstallationState> {
|
|||||||
|
|
||||||
sealed class InstallationEvent {}
|
sealed class InstallationEvent {}
|
||||||
|
|
||||||
class InstallationStartedEvent extends InstallationEvent {
|
class InstallationStartedEvent extends InstallationEvent {}
|
||||||
final ServerPropertiesViewModel serverProperties;
|
|
||||||
|
|
||||||
InstallationStartedEvent(this.serverProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
class _InstallationProgressValueChangedEvent extends InstallationEvent {
|
class _InstallationProgressValueChangedEvent extends InstallationEvent {
|
||||||
final double progressValue;
|
final double progressValue;
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:minecraft_server_installer/main/adapter/presenter/progress_view_model.dart';
|
import 'package:minecraft_server_installer/main/adapter/presentation/progress_view_model.dart';
|
||||||
import 'package:minecraft_server_installer/main/adapter/presenter/range_view_model.dart';
|
import 'package:minecraft_server_installer/main/adapter/presentation/range_view_model.dart';
|
||||||
import 'package:minecraft_server_installer/vanilla/adapter/presenter/game_version_view_model.dart';
|
import 'package:minecraft_server_installer/vanilla/adapter/presentation/game_version_view_model.dart';
|
||||||
|
|
||||||
class InstallationState with EquatableMixin {
|
class InstallationState with EquatableMixin {
|
||||||
static const _defaultRamSize = RangeViewModel(min: 2048, max: 2048);
|
static const _defaultRamSize = RangeViewModel(min: 2048, max: 2048);
|
@ -1,53 +0,0 @@
|
|||||||
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';
|
|
||||||
import 'package:minecraft_server_installer/main/constants.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/application/use_case/write_server_properties_use_case.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/domain/entity/server_properties.dart';
|
|
||||||
import 'package:minecraft_server_installer/vanilla/domain/entity/game_version.dart';
|
|
||||||
import 'package:path/path.dart' as path;
|
|
||||||
|
|
||||||
class InstallServerUseCase {
|
|
||||||
final DownloadFileUseCase _downloadFileUseCase;
|
|
||||||
final WriteFileUseCase _writeFileUseCase;
|
|
||||||
final GrantFilePermissionUseCase _grantFilePermissionUseCase;
|
|
||||||
final WriteServerPropertiesUseCase _writeServerPropertiesUseCase;
|
|
||||||
|
|
||||||
InstallServerUseCase(
|
|
||||||
this._downloadFileUseCase,
|
|
||||||
this._writeFileUseCase,
|
|
||||||
this._grantFilePermissionUseCase,
|
|
||||||
this._writeServerPropertiesUseCase,
|
|
||||||
);
|
|
||||||
|
|
||||||
Future<void> call({
|
|
||||||
required GameVersion gameVersion,
|
|
||||||
required String savePath,
|
|
||||||
required int maxRam,
|
|
||||||
required int minRam,
|
|
||||||
required bool isGuiEnabled,
|
|
||||||
required ServerProperties serverProperties,
|
|
||||||
required void Function(double) onProgressChanged,
|
|
||||||
}) async {
|
|
||||||
// 1. Download server file
|
|
||||||
await _downloadFileUseCase(
|
|
||||||
gameVersion.url,
|
|
||||||
path.join(savePath, Constants.serverFileName),
|
|
||||||
onProgressChanged: onProgressChanged,
|
|
||||||
);
|
|
||||||
|
|
||||||
// 2. Write start script
|
|
||||||
final startScriptFilePath = path.join(savePath, Constants.startScriptFileName);
|
|
||||||
final serverFilePath = path.join('.', Constants.serverFileName);
|
|
||||||
final startScriptContent = 'java -Xmx${maxRam}M -Xms${minRam}M -jar $serverFilePath ${isGuiEnabled ? '' : 'nogui'}';
|
|
||||||
await _writeFileUseCase(startScriptFilePath, startScriptContent);
|
|
||||||
await _grantFilePermissionUseCase(startScriptFilePath);
|
|
||||||
|
|
||||||
// 3. Write EULA file
|
|
||||||
final eulaFilePath = path.join(savePath, Constants.eulaFileName);
|
|
||||||
await _writeFileUseCase(eulaFilePath, Constants.eulaFileContent);
|
|
||||||
|
|
||||||
// 4. Write server.properties file
|
|
||||||
await _writeServerPropertiesUseCase(serverProperties, savePath);
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,12 +2,11 @@ import 'package:file_picker/file_picker.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:minecraft_server_installer/main/adapter/presenter/installation_bloc.dart';
|
import 'package:minecraft_server_installer/main/adapter/presentation/installation_bloc.dart';
|
||||||
import 'package:minecraft_server_installer/main/adapter/presenter/installation_state.dart';
|
import 'package:minecraft_server_installer/main/adapter/presentation/installation_state.dart';
|
||||||
import 'package:minecraft_server_installer/main/adapter/presenter/range_view_model.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/constants.dart';
|
||||||
import 'package:minecraft_server_installer/main/framework/ui/strings.dart';
|
import 'package:minecraft_server_installer/main/framework/ui/strings.dart';
|
||||||
import 'package:minecraft_server_installer/properties/adapter/presenter/server_properties_bloc.dart';
|
|
||||||
import 'package:minecraft_server_installer/vanilla/framework/ui/game_version_dropdown.dart';
|
import 'package:minecraft_server_installer/vanilla/framework/ui/game_version_dropdown.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
@ -210,6 +209,6 @@ class BasicConfigurationTab extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _downloadServerFile(BuildContext context) {
|
void _downloadServerFile(BuildContext context) {
|
||||||
context.read<InstallationBloc>().add((InstallationStartedEvent(context.read<ServerPropertiesBloc>().state)));
|
context.read<InstallationBloc>().add((InstallationStartedEvent()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:minecraft_server_installer/main/adapter/gateway/installation_repository_impl.dart';
|
import 'package:minecraft_server_installer/main/adapter/gateway/installation_repository_impl.dart';
|
||||||
import 'package:minecraft_server_installer/main/adapter/presenter/installation_bloc.dart';
|
import 'package:minecraft_server_installer/main/adapter/presentation/installation_bloc.dart';
|
||||||
import 'package:minecraft_server_installer/main/adapter/presenter/navigation_bloc.dart';
|
import 'package:minecraft_server_installer/main/adapter/presentation/navigation_bloc.dart';
|
||||||
import 'package:minecraft_server_installer/main/application/use_case/download_file_use_case.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/grant_file_permission_use_case.dart';
|
||||||
import 'package:minecraft_server_installer/main/application/use_case/install_server_use_case.dart';
|
|
||||||
import 'package:minecraft_server_installer/main/application/use_case/write_file_use_case.dart';
|
import 'package:minecraft_server_installer/main/application/use_case/write_file_use_case.dart';
|
||||||
import 'package:minecraft_server_installer/main/constants.dart';
|
import 'package:minecraft_server_installer/main/constants.dart';
|
||||||
import 'package:minecraft_server_installer/main/framework/api/installation_api_service_impl.dart';
|
import 'package:minecraft_server_installer/main/framework/api/installation_api_service_impl.dart';
|
||||||
@ -13,13 +12,8 @@ import 'package:minecraft_server_installer/main/framework/storage/installation_f
|
|||||||
import 'package:minecraft_server_installer/main/framework/ui/about_tab.dart';
|
import 'package:minecraft_server_installer/main/framework/ui/about_tab.dart';
|
||||||
import 'package:minecraft_server_installer/main/framework/ui/basic_configuration_tab.dart';
|
import 'package:minecraft_server_installer/main/framework/ui/basic_configuration_tab.dart';
|
||||||
import 'package:minecraft_server_installer/main/framework/ui/side_navigation_bar.dart';
|
import 'package:minecraft_server_installer/main/framework/ui/side_navigation_bar.dart';
|
||||||
import 'package:minecraft_server_installer/properties/adapter/gateway/server_properties_repository_impl.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/adapter/presenter/server_properties_bloc.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/application/use_case/write_server_properties_use_case.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/framework/storage/server_properties_file_storage_impl.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/framework/ui/server_properties_tab.dart';
|
|
||||||
import 'package:minecraft_server_installer/vanilla/adapter/gateway/vanilla_repository_impl.dart';
|
import 'package:minecraft_server_installer/vanilla/adapter/gateway/vanilla_repository_impl.dart';
|
||||||
import 'package:minecraft_server_installer/vanilla/adapter/presenter/vanilla_bloc.dart';
|
import 'package:minecraft_server_installer/vanilla/adapter/presentation/vanilla_bloc.dart';
|
||||||
import 'package:minecraft_server_installer/vanilla/application/use_case/get_game_version_list_use_case.dart';
|
import 'package:minecraft_server_installer/vanilla/application/use_case/get_game_version_list_use_case.dart';
|
||||||
import 'package:minecraft_server_installer/vanilla/framework/api/vanilla_api_service_impl.dart';
|
import 'package:minecraft_server_installer/vanilla/framework/api/vanilla_api_service_impl.dart';
|
||||||
|
|
||||||
@ -28,27 +22,17 @@ class MinecraftServerInstaller extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final gameVersionApiService = VanillaApiServiceImpl();
|
|
||||||
final gameVersionRepository = VanillaRepositoryImpl(gameVersionApiService);
|
|
||||||
final getGameVersionListUseCase = GetGameVersionListUseCase(gameVersionRepository);
|
|
||||||
|
|
||||||
final serverPropertiesFileStorage = ServerPropertiesFileStorageImpl();
|
|
||||||
final serverPropertiesRepository = ServerPropertiesRepositoryImpl(serverPropertiesFileStorage);
|
|
||||||
final writeServerPropertiesUseCase = WriteServerPropertiesUseCase(serverPropertiesRepository);
|
|
||||||
|
|
||||||
final installationApiService = InstallationApiServiceImpl();
|
final installationApiService = InstallationApiServiceImpl();
|
||||||
final installationFileStorage = InstallationFileStorageImpl();
|
final installationFileStorage = InstallationFileStorageImpl();
|
||||||
final installationRepository = InstallationRepositoryImpl(installationApiService, installationFileStorage);
|
final installationRepository = InstallationRepositoryImpl(installationApiService, installationFileStorage);
|
||||||
|
|
||||||
|
final gameVersionApiService = VanillaApiServiceImpl();
|
||||||
|
final gameVersionRepository = VanillaRepositoryImpl(gameVersionApiService);
|
||||||
|
|
||||||
final downloadFileUseCase = DownloadFileUseCase(installationRepository);
|
final downloadFileUseCase = DownloadFileUseCase(installationRepository);
|
||||||
final writeFileUseCase = WriteFileUseCase(installationRepository);
|
final writeFileUseCase = WriteFileUseCase(installationRepository);
|
||||||
final grantFilePermissionUseCase = GrantFilePermissionUseCase(installationRepository);
|
final grantFilePermissionUseCase = GrantFilePermissionUseCase(installationRepository);
|
||||||
|
final getGameVersionListUseCase = GetGameVersionListUseCase(gameVersionRepository);
|
||||||
final installServerUseCase = InstallServerUseCase(
|
|
||||||
downloadFileUseCase,
|
|
||||||
writeFileUseCase,
|
|
||||||
grantFilePermissionUseCase,
|
|
||||||
writeServerPropertiesUseCase,
|
|
||||||
);
|
|
||||||
|
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
title: Constants.appName,
|
title: Constants.appName,
|
||||||
@ -61,13 +45,16 @@ class MinecraftServerInstaller extends StatelessWidget {
|
|||||||
home: MultiBlocProvider(
|
home: MultiBlocProvider(
|
||||||
providers: [
|
providers: [
|
||||||
BlocProvider(create: (_) => NavigationBloc()),
|
BlocProvider(create: (_) => NavigationBloc()),
|
||||||
BlocProvider(create: (_) => ServerPropertiesBloc()),
|
BlocProvider(
|
||||||
|
create: (_) => InstallationBloc(
|
||||||
|
downloadFileUseCase,
|
||||||
|
writeFileUseCase,
|
||||||
|
grantFilePermissionUseCase,
|
||||||
|
),
|
||||||
|
),
|
||||||
BlocProvider<VanillaBloc>(
|
BlocProvider<VanillaBloc>(
|
||||||
create: (_) => VanillaBloc(getGameVersionListUseCase)..add(VanillaGameVersionListLoadedEvent()),
|
create: (_) => VanillaBloc(getGameVersionListUseCase)..add(VanillaGameVersionListLoadedEvent()),
|
||||||
),
|
),
|
||||||
BlocProvider(
|
|
||||||
create: (_) => InstallationBloc(installServerUseCase),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
body: Row(
|
body: Row(
|
||||||
@ -124,24 +111,21 @@ class MinecraftServerInstaller extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(32),
|
padding: const EdgeInsets.all(32),
|
||||||
child: state.tabContent,
|
child: _tabContent(state),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
extension _NavigationItemExtension on NavigationItem {
|
Widget _tabContent(NavigationItem navigationItem) {
|
||||||
Widget get tabContent {
|
switch (navigationItem) {
|
||||||
switch (this) {
|
|
||||||
case NavigationItem.basicConfiguration:
|
case NavigationItem.basicConfiguration:
|
||||||
return const BasicConfigurationTab();
|
return const BasicConfigurationTab();
|
||||||
case NavigationItem.modConfiguration:
|
case NavigationItem.modConfiguration:
|
||||||
return const Placeholder();
|
|
||||||
case NavigationItem.serverProperties:
|
case NavigationItem.serverProperties:
|
||||||
return const ServerPropertiesTab();
|
return const Placeholder();
|
||||||
case NavigationItem.about:
|
case NavigationItem.about:
|
||||||
return const AboutTab();
|
return const AboutTab();
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:minecraft_server_installer/main/adapter/presenter/navigation_bloc.dart';
|
import 'package:minecraft_server_installer/main/adapter/presentation/navigation_bloc.dart';
|
||||||
import 'package:minecraft_server_installer/main/constants.dart';
|
import 'package:minecraft_server_installer/main/constants.dart';
|
||||||
import 'package:minecraft_server_installer/main/framework/ui/strings.dart';
|
import 'package:minecraft_server_installer/main/framework/ui/strings.dart';
|
||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
@ -49,7 +49,7 @@ class _SideNavigationBarState extends State<SideNavigationBar> {
|
|||||||
collapsedKey: const ValueKey('collapsedTitle'),
|
collapsedKey: const ValueKey('collapsedTitle'),
|
||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.titleSmall
|
.titleMedium
|
||||||
?.copyWith(fontWeight: FontWeight.w900, color: Colors.blueGrey.shade900),
|
?.copyWith(fontWeight: FontWeight.w900, color: Colors.blueGrey.shade900),
|
||||||
),
|
),
|
||||||
Material(
|
Material(
|
||||||
@ -83,7 +83,6 @@ class _SideNavigationBarState extends State<SideNavigationBar> {
|
|||||||
future: PackageInfo.fromPlatform(),
|
future: PackageInfo.fromPlatform(),
|
||||||
builder: (context, snapshot) => _animatedText(
|
builder: (context, snapshot) => _animatedText(
|
||||||
text: 'Version ${snapshot.data?.version ?? ''}',
|
text: 'Version ${snapshot.data?.version ?? ''}',
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: Colors.grey.shade700),
|
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
expandedKey: const ValueKey('expandedVersion'),
|
expandedKey: const ValueKey('expandedVersion'),
|
||||||
collapsedKey: const ValueKey('collapsedVersion'),
|
collapsedKey: const ValueKey('collapsedVersion'),
|
||||||
|
@ -6,15 +6,6 @@ abstract class Strings {
|
|||||||
static const fieldCustomRamSize = '啟用自定義 RAM 大小';
|
static const fieldCustomRamSize = '啟用自定義 RAM 大小';
|
||||||
static const fieldMinRamSize = '最小 RAM 大小';
|
static const fieldMinRamSize = '最小 RAM 大小';
|
||||||
static const fieldMaxRamSize = '最大 RAM 大小';
|
static const fieldMaxRamSize = '最大 RAM 大小';
|
||||||
static const fieldServerPort = '伺服器連接埠';
|
|
||||||
static const fieldMaxPlayers = '玩家人數上限';
|
|
||||||
static const fieldSpawnProtection = '重生點保護';
|
|
||||||
static const fieldViewDistance = '最大視野距離';
|
|
||||||
static const fieldPvp = '玩家間傷害';
|
|
||||||
static const fieldGameMode = '預設遊戲模式';
|
|
||||||
static const fieldDifficulty = '遊戲難度';
|
|
||||||
static const fieldEnableCommandBlock = '啟用指令方塊';
|
|
||||||
static const fieldMotd = '伺服器描述';
|
|
||||||
static const buttonStartToInstall = '開始安裝';
|
static const buttonStartToInstall = '開始安裝';
|
||||||
static const buttonBrowse = '瀏覽';
|
static const buttonBrowse = '瀏覽';
|
||||||
static const buttonTutorialVideo = '教學影片';
|
static const buttonTutorialVideo = '教學影片';
|
||||||
@ -27,20 +18,7 @@ abstract class Strings {
|
|||||||
static const tabAbout = '關於與說明';
|
static const tabAbout = '關於與說明';
|
||||||
static const tabInstallationProgress = '安裝進度';
|
static const tabInstallationProgress = '安裝進度';
|
||||||
static const tooltipEulaInfo = '點擊查看 EULA 條款';
|
static const tooltipEulaInfo = '點擊查看 EULA 條款';
|
||||||
static const tooltipResetToDefault = '重置為預設值';
|
|
||||||
static const tooltipRestoreChanges = '取消變更';
|
|
||||||
static const tooltipApplyChanges = '套用變更';
|
|
||||||
static const dialogTitleSelectDirectory = '選擇安裝目錄';
|
static const dialogTitleSelectDirectory = '選擇安裝目錄';
|
||||||
static const gamemodeSurvival = '生存';
|
|
||||||
static const gamemodeCreative = '創造';
|
|
||||||
static const gamemodeAdventure = '冒險';
|
|
||||||
static const gamemodeSpectator = '觀察者';
|
|
||||||
static const difficultyPeaceful = '和平';
|
|
||||||
static const difficultyEasy = '簡單';
|
|
||||||
static const difficultyNormal = '普通';
|
|
||||||
static const difficultyHard = '困難';
|
|
||||||
static const textEnable = '啟用';
|
|
||||||
static const textDisable = '禁用';
|
|
||||||
static const textSlogen = '讓 Minecraft 伺服器安裝變得更簡單!';
|
static const textSlogen = '讓 Minecraft 伺服器安裝變得更簡單!';
|
||||||
static const textCopyright = 'Copyright © 2025 SquidSpirit';
|
static const textCopyright = 'Copyright © 2025 SquidSpirit';
|
||||||
}
|
}
|
||||||
|
@ -1,86 +0,0 @@
|
|||||||
import 'package:minecraft_server_installer/properties/domain/entity/server_properties.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/domain/enum/difficulty.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/domain/enum/game_mode.dart';
|
|
||||||
|
|
||||||
class ServerPropertiesDto {
|
|
||||||
final int serverPort;
|
|
||||||
final int maxPlayers;
|
|
||||||
final int spawnProtection;
|
|
||||||
final int viewDistance;
|
|
||||||
final bool pvp;
|
|
||||||
final String gameMode;
|
|
||||||
final String difficulty;
|
|
||||||
final bool enableCommandBlock;
|
|
||||||
final bool onlineMode;
|
|
||||||
final String motd;
|
|
||||||
|
|
||||||
const ServerPropertiesDto({
|
|
||||||
required this.serverPort,
|
|
||||||
required this.maxPlayers,
|
|
||||||
required this.spawnProtection,
|
|
||||||
required this.viewDistance,
|
|
||||||
required this.pvp,
|
|
||||||
required this.gameMode,
|
|
||||||
required this.difficulty,
|
|
||||||
required this.enableCommandBlock,
|
|
||||||
required this.onlineMode,
|
|
||||||
required this.motd,
|
|
||||||
});
|
|
||||||
|
|
||||||
ServerPropertiesDto.fromEntity(ServerProperties serverProperties)
|
|
||||||
: this(
|
|
||||||
serverPort: serverProperties.serverPort,
|
|
||||||
maxPlayers: serverProperties.maxPlayers,
|
|
||||||
spawnProtection: serverProperties.spawnProtection,
|
|
||||||
viewDistance: serverProperties.viewDistance,
|
|
||||||
pvp: serverProperties.pvp,
|
|
||||||
gameMode: serverProperties.gameMode.value,
|
|
||||||
difficulty: serverProperties.difficulty.value,
|
|
||||||
enableCommandBlock: serverProperties.enableCommandBlock,
|
|
||||||
onlineMode: serverProperties.onlineMode,
|
|
||||||
motd: serverProperties.motd,
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, String> toStringMap() => {
|
|
||||||
'server-port': serverPort.toString(),
|
|
||||||
'max-players': maxPlayers.toString(),
|
|
||||||
'spawn-protection': spawnProtection.toString(),
|
|
||||||
'view-distance': viewDistance.toString(),
|
|
||||||
'pvp': pvp.toString(),
|
|
||||||
'gamemode': gameMode,
|
|
||||||
'difficulty': difficulty,
|
|
||||||
'enable-command-block': enableCommandBlock.toString(),
|
|
||||||
'online-mode': onlineMode.toString(),
|
|
||||||
'motd': motd,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
extension _GameModeExtension on GameMode {
|
|
||||||
String get value {
|
|
||||||
switch (this) {
|
|
||||||
case GameMode.survival:
|
|
||||||
return 'survival';
|
|
||||||
case GameMode.creative:
|
|
||||||
return 'creative';
|
|
||||||
case GameMode.adventure:
|
|
||||||
return 'adventure';
|
|
||||||
case GameMode.spectator:
|
|
||||||
return 'spectator';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension _DifficultyExtension on Difficulty {
|
|
||||||
String get value {
|
|
||||||
switch (this) {
|
|
||||||
case Difficulty.peaceful:
|
|
||||||
return 'peaceful';
|
|
||||||
case Difficulty.easy:
|
|
||||||
return 'easy';
|
|
||||||
case Difficulty.normal:
|
|
||||||
return 'normal';
|
|
||||||
case Difficulty.hard:
|
|
||||||
return 'hard';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
import 'package:minecraft_server_installer/properties/adapter/gateway/server_properties_dto.dart';
|
|
||||||
|
|
||||||
abstract interface class ServerPropertiesFileStorage {
|
|
||||||
Future<void> writeServerProperties(ServerPropertiesDto serverPropertiesDto, String savePath);
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
import 'package:minecraft_server_installer/properties/adapter/gateway/server_properties_dto.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/adapter/gateway/server_properties_file_storage.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/application/repository/server_properties_repository.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/domain/entity/server_properties.dart';
|
|
||||||
|
|
||||||
class ServerPropertiesRepositoryImpl implements ServerPropertiesRepository {
|
|
||||||
final ServerPropertiesFileStorage _serverPropertiesFileStorage;
|
|
||||||
|
|
||||||
ServerPropertiesRepositoryImpl(this._serverPropertiesFileStorage);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> writeServerProperties(ServerProperties serverProperties, String savePath) =>
|
|
||||||
_serverPropertiesFileStorage.writeServerProperties(
|
|
||||||
ServerPropertiesDto.fromEntity(serverProperties),
|
|
||||||
savePath,
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/adapter/presenter/server_properties_view_model.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/domain/enum/difficulty.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/domain/enum/game_mode.dart';
|
|
||||||
|
|
||||||
class ServerPropertiesBloc extends Bloc<ServerPropertiesEvent, ServerPropertiesViewModel> {
|
|
||||||
ServerPropertiesBloc() : super(ServerPropertiesViewModel.defaultValue) {
|
|
||||||
on<ServerPropertiesUpdatedEvent>((event, emit) => emit(
|
|
||||||
state.copyWith(
|
|
||||||
serverPort: event.serverPort ?? state.serverPort,
|
|
||||||
maxPlayers: event.maxPlayers ?? state.maxPlayers,
|
|
||||||
spawnProtection: event.spawnProtection ?? state.spawnProtection,
|
|
||||||
viewDistance: event.viewDistance ?? state.viewDistance,
|
|
||||||
pvp: event.pvp ?? state.pvp,
|
|
||||||
gameMode: event.gameMode ?? state.gameMode,
|
|
||||||
difficulty: event.difficulty ?? state.difficulty,
|
|
||||||
enableCommandBlock: event.enableCommandBlock ?? state.enableCommandBlock,
|
|
||||||
onlineMode: event.onlineMode ?? state.onlineMode,
|
|
||||||
motd: event.motd ?? state.motd,
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class ServerPropertiesEvent {}
|
|
||||||
|
|
||||||
class ServerPropertiesUpdatedEvent extends ServerPropertiesEvent {
|
|
||||||
final int? serverPort;
|
|
||||||
final int? maxPlayers;
|
|
||||||
final int? spawnProtection;
|
|
||||||
final int? viewDistance;
|
|
||||||
final bool? pvp;
|
|
||||||
final GameMode? gameMode;
|
|
||||||
final Difficulty? difficulty;
|
|
||||||
final bool? enableCommandBlock;
|
|
||||||
final bool? onlineMode;
|
|
||||||
final String? motd;
|
|
||||||
|
|
||||||
ServerPropertiesUpdatedEvent({
|
|
||||||
this.serverPort,
|
|
||||||
this.maxPlayers,
|
|
||||||
this.spawnProtection,
|
|
||||||
this.viewDistance,
|
|
||||||
this.pvp,
|
|
||||||
this.gameMode,
|
|
||||||
this.difficulty,
|
|
||||||
this.enableCommandBlock,
|
|
||||||
this.onlineMode,
|
|
||||||
this.motd,
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,100 +0,0 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/domain/entity/server_properties.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/domain/enum/difficulty.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/domain/enum/game_mode.dart';
|
|
||||||
|
|
||||||
class ServerPropertiesViewModel with EquatableMixin {
|
|
||||||
final int serverPort;
|
|
||||||
final int maxPlayers;
|
|
||||||
final int spawnProtection;
|
|
||||||
final int viewDistance;
|
|
||||||
final bool pvp;
|
|
||||||
final GameMode gameMode;
|
|
||||||
final Difficulty difficulty;
|
|
||||||
final bool enableCommandBlock;
|
|
||||||
final bool onlineMode;
|
|
||||||
final String motd;
|
|
||||||
|
|
||||||
const ServerPropertiesViewModel({
|
|
||||||
required this.serverPort,
|
|
||||||
required this.maxPlayers,
|
|
||||||
required this.spawnProtection,
|
|
||||||
required this.viewDistance,
|
|
||||||
required this.pvp,
|
|
||||||
required this.gameMode,
|
|
||||||
required this.difficulty,
|
|
||||||
required this.enableCommandBlock,
|
|
||||||
required this.onlineMode,
|
|
||||||
required this.motd,
|
|
||||||
});
|
|
||||||
|
|
||||||
static const defaultValue = ServerPropertiesViewModel(
|
|
||||||
serverPort: 25565,
|
|
||||||
maxPlayers: 20,
|
|
||||||
spawnProtection: 16,
|
|
||||||
viewDistance: 10,
|
|
||||||
pvp: true,
|
|
||||||
gameMode: GameMode.survival,
|
|
||||||
difficulty: Difficulty.normal,
|
|
||||||
enableCommandBlock: false,
|
|
||||||
onlineMode: true,
|
|
||||||
motd: 'A Minecraft Server',
|
|
||||||
);
|
|
||||||
|
|
||||||
ServerProperties toEntity() => ServerProperties(
|
|
||||||
serverPort: serverPort,
|
|
||||||
maxPlayers: maxPlayers,
|
|
||||||
spawnProtection: spawnProtection,
|
|
||||||
viewDistance: viewDistance,
|
|
||||||
pvp: pvp,
|
|
||||||
gameMode: gameMode,
|
|
||||||
difficulty: difficulty,
|
|
||||||
enableCommandBlock: enableCommandBlock,
|
|
||||||
onlineMode: onlineMode,
|
|
||||||
motd: motd,
|
|
||||||
);
|
|
||||||
|
|
||||||
ServerPropertiesViewModel copyWith({
|
|
||||||
int? serverPort,
|
|
||||||
int? maxPlayers,
|
|
||||||
int? spawnProtection,
|
|
||||||
int? viewDistance,
|
|
||||||
bool? pvp,
|
|
||||||
GameMode? gameMode,
|
|
||||||
Difficulty? difficulty,
|
|
||||||
bool? enableCommandBlock,
|
|
||||||
bool? onlineMode,
|
|
||||||
String? motd,
|
|
||||||
}) =>
|
|
||||||
ServerPropertiesViewModel(
|
|
||||||
serverPort: serverPort ?? this.serverPort,
|
|
||||||
maxPlayers: maxPlayers ?? this.maxPlayers,
|
|
||||||
spawnProtection: spawnProtection ?? this.spawnProtection,
|
|
||||||
viewDistance: viewDistance ?? this.viewDistance,
|
|
||||||
pvp: pvp ?? this.pvp,
|
|
||||||
gameMode: gameMode ?? this.gameMode,
|
|
||||||
difficulty: difficulty ?? this.difficulty,
|
|
||||||
enableCommandBlock: enableCommandBlock ?? this.enableCommandBlock,
|
|
||||||
onlineMode: onlineMode ?? this.onlineMode,
|
|
||||||
motd: motd ?? this.motd,
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [
|
|
||||||
serverPort,
|
|
||||||
maxPlayers,
|
|
||||||
spawnProtection,
|
|
||||||
viewDistance,
|
|
||||||
pvp,
|
|
||||||
gameMode,
|
|
||||||
difficulty,
|
|
||||||
enableCommandBlock,
|
|
||||||
onlineMode,
|
|
||||||
motd,
|
|
||||||
];
|
|
||||||
|
|
||||||
bool get isServerPortValid => serverPort > 0 && serverPort <= 65535;
|
|
||||||
bool get isMaxPlayersValid => maxPlayers > 0;
|
|
||||||
bool get isSpawnProtectionValid => spawnProtection >= 0;
|
|
||||||
bool get isViewDistanceValid => viewDistance > 0;
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
import 'package:minecraft_server_installer/properties/domain/entity/server_properties.dart';
|
|
||||||
|
|
||||||
abstract interface class ServerPropertiesRepository {
|
|
||||||
Future<void> writeServerProperties(ServerProperties serverProperties, String savePath);
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
import 'package:minecraft_server_installer/properties/application/repository/server_properties_repository.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/domain/entity/server_properties.dart';
|
|
||||||
|
|
||||||
class WriteServerPropertiesUseCase {
|
|
||||||
final ServerPropertiesRepository _serverPropertiesRepository;
|
|
||||||
|
|
||||||
WriteServerPropertiesUseCase(this._serverPropertiesRepository);
|
|
||||||
|
|
||||||
Future<void> call(ServerProperties serverProperties, String savePath) =>
|
|
||||||
_serverPropertiesRepository.writeServerProperties(serverProperties, savePath);
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/domain/enum/difficulty.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/domain/enum/game_mode.dart';
|
|
||||||
|
|
||||||
class ServerProperties with EquatableMixin {
|
|
||||||
final int serverPort;
|
|
||||||
final int maxPlayers;
|
|
||||||
final int spawnProtection;
|
|
||||||
final int viewDistance;
|
|
||||||
final bool pvp;
|
|
||||||
final GameMode gameMode;
|
|
||||||
final Difficulty difficulty;
|
|
||||||
final bool enableCommandBlock;
|
|
||||||
final bool onlineMode;
|
|
||||||
final String motd;
|
|
||||||
|
|
||||||
const ServerProperties({
|
|
||||||
required this.serverPort,
|
|
||||||
required this.maxPlayers,
|
|
||||||
required this.spawnProtection,
|
|
||||||
required this.viewDistance,
|
|
||||||
required this.pvp,
|
|
||||||
required this.gameMode,
|
|
||||||
required this.difficulty,
|
|
||||||
required this.enableCommandBlock,
|
|
||||||
required this.onlineMode,
|
|
||||||
required this.motd,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [
|
|
||||||
serverPort,
|
|
||||||
maxPlayers,
|
|
||||||
spawnProtection,
|
|
||||||
viewDistance,
|
|
||||||
pvp,
|
|
||||||
gameMode,
|
|
||||||
difficulty,
|
|
||||||
enableCommandBlock,
|
|
||||||
onlineMode,
|
|
||||||
motd,
|
|
||||||
];
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
enum Difficulty {
|
|
||||||
peaceful,
|
|
||||||
easy,
|
|
||||||
normal,
|
|
||||||
hard,
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
enum GameMode {
|
|
||||||
survival,
|
|
||||||
creative,
|
|
||||||
adventure,
|
|
||||||
spectator,
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:minecraft_server_installer/properties/adapter/gateway/server_properties_dto.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/adapter/gateway/server_properties_file_storage.dart';
|
|
||||||
|
|
||||||
class ServerPropertiesFileStorageImpl implements ServerPropertiesFileStorage {
|
|
||||||
@override
|
|
||||||
Future<void> writeServerProperties(ServerPropertiesDto serverPropertiesDto, String savePath) async {
|
|
||||||
File file = File('$savePath/server.properties');
|
|
||||||
await file.create(recursive: true);
|
|
||||||
|
|
||||||
final propertiesMap = serverPropertiesDto.toStringMap();
|
|
||||||
await file.writeAsString(propertiesMap.entries.map((e) => '${e.key}=${e.value}').join('\n'));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:gap/gap.dart';
|
|
||||||
import 'package:minecraft_server_installer/main/framework/ui/strings.dart';
|
|
||||||
|
|
||||||
class InlineTextField extends StatefulWidget {
|
|
||||||
const InlineTextField({
|
|
||||||
super.key,
|
|
||||||
required this.labelText,
|
|
||||||
required this.defaultValue,
|
|
||||||
required this.value,
|
|
||||||
required this.onChanged,
|
|
||||||
});
|
|
||||||
|
|
||||||
final String labelText;
|
|
||||||
final String defaultValue;
|
|
||||||
final String value;
|
|
||||||
final void Function(String) onChanged;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<InlineTextField> createState() => _InlineTextFieldState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _InlineTextFieldState extends State<InlineTextField> {
|
|
||||||
final _textEditingController = TextEditingController();
|
|
||||||
final _focusNode = FocusNode();
|
|
||||||
|
|
||||||
bool _isEditing = false;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
|
|
||||||
_textEditingController.text = widget.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) => Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: TextField(
|
|
||||||
controller: _textEditingController,
|
|
||||||
focusNode: _focusNode,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: widget.labelText,
|
|
||||||
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
|
|
||||||
),
|
|
||||||
onChanged: (newValue) {
|
|
||||||
if (newValue != widget.value) {
|
|
||||||
setState(() => _isEditing = true);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (_isEditing) ...[
|
|
||||||
const Gap(8),
|
|
||||||
IconButton.filledTonal(
|
|
||||||
tooltip: Strings.tooltipRestoreChanges,
|
|
||||||
onPressed: () {
|
|
||||||
_focusNode.unfocus();
|
|
||||||
_textEditingController.text = widget.value;
|
|
||||||
setState(() => _isEditing = false);
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.cancel_outlined)),
|
|
||||||
const Gap(8),
|
|
||||||
IconButton.filled(
|
|
||||||
tooltip: Strings.tooltipApplyChanges,
|
|
||||||
onPressed: () {
|
|
||||||
_focusNode.unfocus();
|
|
||||||
widget.onChanged(_textEditingController.text);
|
|
||||||
setState(() => _isEditing = false);
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.check_circle_outline),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
if (!_isEditing && widget.value != widget.defaultValue) ...[
|
|
||||||
const Gap(8),
|
|
||||||
IconButton.filledTonal(
|
|
||||||
tooltip: Strings.tooltipResetToDefault,
|
|
||||||
onPressed: () {
|
|
||||||
_focusNode.unfocus();
|
|
||||||
_textEditingController.text = widget.defaultValue;
|
|
||||||
widget.onChanged(widget.defaultValue);
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.refresh),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,152 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:gap/gap.dart';
|
|
||||||
import 'package:minecraft_server_installer/main/framework/ui/strings.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/adapter/presenter/server_properties_bloc.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/adapter/presenter/server_properties_view_model.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/domain/enum/difficulty.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/domain/enum/game_mode.dart';
|
|
||||||
import 'package:minecraft_server_installer/properties/framework/ui/inline_text_field.dart';
|
|
||||||
|
|
||||||
class ServerPropertiesTab extends StatelessWidget {
|
|
||||||
const ServerPropertiesTab({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) => SingleChildScrollView(
|
|
||||||
child: BlocConsumer<ServerPropertiesBloc, ServerPropertiesViewModel>(
|
|
||||||
listener: (_, __) {},
|
|
||||||
builder: (context, state) {
|
|
||||||
final serverPropertiesBloc = context.read<ServerPropertiesBloc>();
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
InlineTextField(
|
|
||||||
labelText: 'server-port | ${Strings.fieldServerPort}',
|
|
||||||
defaultValue: ServerPropertiesViewModel.defaultValue.serverPort.toString(),
|
|
||||||
value: state.serverPort.toString(),
|
|
||||||
onChanged: (value) =>
|
|
||||||
serverPropertiesBloc.add(ServerPropertiesUpdatedEvent(serverPort: int.tryParse(value))),
|
|
||||||
),
|
|
||||||
const Gap(16),
|
|
||||||
InlineTextField(
|
|
||||||
labelText: 'max-player | ${Strings.fieldMaxPlayers}',
|
|
||||||
defaultValue: ServerPropertiesViewModel.defaultValue.maxPlayers.toString(),
|
|
||||||
value: state.maxPlayers.toString(),
|
|
||||||
onChanged: (value) =>
|
|
||||||
serverPropertiesBloc.add(ServerPropertiesUpdatedEvent(maxPlayers: int.tryParse(value))),
|
|
||||||
),
|
|
||||||
const Gap(16),
|
|
||||||
InlineTextField(
|
|
||||||
labelText: 'spawn-protection | ${Strings.fieldSpawnProtection}',
|
|
||||||
defaultValue: ServerPropertiesViewModel.defaultValue.spawnProtection.toString(),
|
|
||||||
value: state.spawnProtection.toString(),
|
|
||||||
onChanged: (value) =>
|
|
||||||
serverPropertiesBloc.add(ServerPropertiesUpdatedEvent(spawnProtection: int.tryParse(value))),
|
|
||||||
),
|
|
||||||
const Gap(16),
|
|
||||||
InlineTextField(
|
|
||||||
labelText: 'view-distance | ${Strings.fieldViewDistance}',
|
|
||||||
defaultValue: ServerPropertiesViewModel.defaultValue.viewDistance.toString(),
|
|
||||||
value: state.viewDistance.toString(),
|
|
||||||
onChanged: (value) =>
|
|
||||||
serverPropertiesBloc.add(ServerPropertiesUpdatedEvent(viewDistance: int.tryParse(value))),
|
|
||||||
),
|
|
||||||
const Gap(16),
|
|
||||||
_dropdown<bool>(
|
|
||||||
labelText: 'pvp | ${Strings.fieldPvp}',
|
|
||||||
defaultValue: ServerPropertiesViewModel.defaultValue.pvp,
|
|
||||||
value: state.pvp,
|
|
||||||
onChanged: (value) => serverPropertiesBloc.add(ServerPropertiesUpdatedEvent(pvp: value)),
|
|
||||||
items: {true: Strings.textEnable, false: Strings.textDisable},
|
|
||||||
),
|
|
||||||
const Gap(16),
|
|
||||||
_dropdown<GameMode>(
|
|
||||||
labelText: 'gamemode | ${Strings.fieldGameMode}',
|
|
||||||
defaultValue: ServerPropertiesViewModel.defaultValue.gameMode,
|
|
||||||
value: state.gameMode,
|
|
||||||
onChanged: (value) => serverPropertiesBloc.add(ServerPropertiesUpdatedEvent(gameMode: value)),
|
|
||||||
items: {
|
|
||||||
GameMode.survival: Strings.gamemodeSurvival,
|
|
||||||
GameMode.creative: Strings.gamemodeCreative,
|
|
||||||
GameMode.adventure: Strings.gamemodeAdventure,
|
|
||||||
GameMode.spectator: Strings.gamemodeSpectator,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const Gap(16),
|
|
||||||
_dropdown<Difficulty>(
|
|
||||||
labelText: 'difficulty | ${Strings.fieldDifficulty}',
|
|
||||||
defaultValue: ServerPropertiesViewModel.defaultValue.difficulty,
|
|
||||||
value: state.difficulty,
|
|
||||||
onChanged: (value) => serverPropertiesBloc.add(ServerPropertiesUpdatedEvent(difficulty: value)),
|
|
||||||
items: {
|
|
||||||
Difficulty.peaceful: Strings.difficultyPeaceful,
|
|
||||||
Difficulty.easy: Strings.difficultyEasy,
|
|
||||||
Difficulty.normal: Strings.difficultyNormal,
|
|
||||||
Difficulty.hard: Strings.difficultyHard,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const Gap(16),
|
|
||||||
_dropdown<bool>(
|
|
||||||
labelText: 'enable-command-block | ${Strings.fieldEnableCommandBlock}',
|
|
||||||
defaultValue: ServerPropertiesViewModel.defaultValue.enableCommandBlock,
|
|
||||||
value: state.enableCommandBlock,
|
|
||||||
onChanged: (value) =>
|
|
||||||
serverPropertiesBloc.add(ServerPropertiesUpdatedEvent(enableCommandBlock: value)),
|
|
||||||
items: {true: Strings.textEnable, false: Strings.textDisable},
|
|
||||||
),
|
|
||||||
const Gap(16),
|
|
||||||
InlineTextField(
|
|
||||||
labelText: 'motd | ${Strings.fieldMotd}',
|
|
||||||
defaultValue: ServerPropertiesViewModel.defaultValue.motd,
|
|
||||||
value: state.motd,
|
|
||||||
onChanged: (value) => serverPropertiesBloc.add(ServerPropertiesUpdatedEvent(motd: value)),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _dropdown<T>({
|
|
||||||
required String labelText,
|
|
||||||
required Map<T, String> items,
|
|
||||||
required T defaultValue,
|
|
||||||
required T value,
|
|
||||||
required void Function(T) onChanged,
|
|
||||||
}) =>
|
|
||||||
Builder(
|
|
||||||
builder: (context) => Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: DropdownMenu<T>(
|
|
||||||
requestFocusOnTap: false,
|
|
||||||
expandedInsets: EdgeInsets.zero,
|
|
||||||
inputDecorationTheme: Theme.of(context)
|
|
||||||
.inputDecorationTheme
|
|
||||||
.copyWith(border: OutlineInputBorder(borderRadius: BorderRadius.circular(8))),
|
|
||||||
label: Text(labelText),
|
|
||||||
initialSelection: value,
|
|
||||||
onSelected: (value) {
|
|
||||||
if (value != null) {
|
|
||||||
onChanged(value);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dropdownMenuEntries: items.entries
|
|
||||||
.map((item) => DropdownMenuEntry<T>(
|
|
||||||
value: item.key,
|
|
||||||
label: item.value,
|
|
||||||
))
|
|
||||||
.toList(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (value != defaultValue) ...[
|
|
||||||
const Gap(8),
|
|
||||||
IconButton.filledTonal(
|
|
||||||
tooltip: Strings.tooltipResetToDefault,
|
|
||||||
onPressed: () => onChanged(defaultValue),
|
|
||||||
icon: const Icon(Icons.refresh),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:minecraft_server_installer/vanilla/adapter/presenter/game_version_view_model.dart';
|
import 'package:minecraft_server_installer/vanilla/adapter/presentation/game_version_view_model.dart';
|
||||||
import 'package:minecraft_server_installer/vanilla/adapter/presenter/vanilla_state.dart';
|
import 'package:minecraft_server_installer/vanilla/adapter/presentation/vanilla_state.dart';
|
||||||
import 'package:minecraft_server_installer/vanilla/application/use_case/get_game_version_list_use_case.dart';
|
import 'package:minecraft_server_installer/vanilla/application/use_case/get_game_version_list_use_case.dart';
|
||||||
|
|
||||||
class VanillaBloc extends Bloc<VanillaEvent, VanillaState> {
|
class VanillaBloc extends Bloc<VanillaEvent, VanillaState> {
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:minecraft_server_installer/vanilla/adapter/presenter/game_version_view_model.dart';
|
import 'package:minecraft_server_installer/vanilla/adapter/presentation/game_version_view_model.dart';
|
||||||
|
|
||||||
class VanillaState with EquatableMixin {
|
class VanillaState with EquatableMixin {
|
||||||
final List<GameVersionViewModel> gameVersions;
|
final List<GameVersionViewModel> gameVersions;
|
@ -1,10 +1,10 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:minecraft_server_installer/main/adapter/presenter/installation_bloc.dart';
|
import 'package:minecraft_server_installer/main/adapter/presentation/installation_bloc.dart';
|
||||||
import 'package:minecraft_server_installer/main/framework/ui/strings.dart';
|
import 'package:minecraft_server_installer/main/framework/ui/strings.dart';
|
||||||
import 'package:minecraft_server_installer/vanilla/adapter/presenter/vanilla_bloc.dart';
|
import 'package:minecraft_server_installer/vanilla/adapter/presentation/vanilla_bloc.dart';
|
||||||
import 'package:minecraft_server_installer/vanilla/adapter/presenter/game_version_view_model.dart';
|
import 'package:minecraft_server_installer/vanilla/adapter/presentation/game_version_view_model.dart';
|
||||||
import 'package:minecraft_server_installer/vanilla/adapter/presenter/vanilla_state.dart';
|
import 'package:minecraft_server_installer/vanilla/adapter/presentation/vanilla_state.dart';
|
||||||
|
|
||||||
class GameVersionDropdown extends StatelessWidget {
|
class GameVersionDropdown extends StatelessWidget {
|
||||||
const GameVersionDropdown({super.key});
|
const GameVersionDropdown({super.key});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user