MCSI-2 Browse installing directory #19

Merged
squid merged 5 commits from MCSI-2_browse_installing_path into main 2025-07-10 22:38:48 +08:00
7 changed files with 23 additions and 20 deletions
Showing only changes of commit b3aa8e095c - Show all commits

View File

@ -31,5 +31,9 @@ class InstallationState with EquatableMixin {
savePath: savePath ?? this.savePath, savePath: savePath ?? this.savePath,
); );
bool get canStartToInstall => gameVersion != null && savePath != null && savePath!.isNotEmpty; bool get isGameVersionSelected => gameVersion != null;
bool get isSavePathSelected => savePath != null && savePath!.isNotEmpty;
bool get canStartToInstall => isGameVersionSelected && isSavePathSelected;
} }

View File

@ -39,7 +39,7 @@ class _BasicConfigurationTabState extends State<BasicConfigurationTab> {
const Gap(32), const Gap(32),
ElevatedButton.icon( ElevatedButton.icon(
style: ElevatedButton.styleFrom(shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4))), style: ElevatedButton.styleFrom(shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4))),
onPressed: state.isGameVersionSelected ? _downloadServerFile : null, onPressed: context.watch<InstallationBloc>().state.isGameVersionSelected ? _downloadServerFile : null,
icon: const Icon(Icons.download), icon: const Icon(Icons.download),
label: const Padding( label: const Padding(
padding: EdgeInsets.symmetric(vertical: 12), padding: EdgeInsets.symmetric(vertical: 12),

View File

@ -24,16 +24,18 @@ class MinecraftServerInstaller extends StatelessWidget {
final getGameVersionListUseCase = GetGameVersionListUseCase(gameVersionRepository); final getGameVersionListUseCase = GetGameVersionListUseCase(gameVersionRepository);
final downloadServerFileUseCase = DownloadServerFileUseCase(gameVersionRepository); final downloadServerFileUseCase = DownloadServerFileUseCase(gameVersionRepository);
final installationBloc = InstallationBloc();
return MaterialApp( return MaterialApp(
title: 'Minecraft Server Installer', title: 'Minecraft Server Installer',
theme: ThemeData.light().copyWith(colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue.shade900)), theme: ThemeData.light().copyWith(colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue.shade900)),
home: MultiBlocProvider( home: MultiBlocProvider(
providers: [ providers: [
BlocProvider.value(value: installationBloc),
BlocProvider<VanillaBloc>( BlocProvider<VanillaBloc>(
create: (_) => VanillaBloc(getGameVersionListUseCase, downloadServerFileUseCase) create: (_) => VanillaBloc(installationBloc, getGameVersionListUseCase, downloadServerFileUseCase)
..add(VanillaGameVersionListLoadedEvent()), ..add(VanillaGameVersionListLoadedEvent()),
), ),
BlocProvider(create: (_) => InstallationBloc())
], ],
child: Scaffold( child: Scaffold(
body: BlocConsumer<VanillaBloc, VanillaState>( body: BlocConsumer<VanillaBloc, VanillaState>(

View File

@ -36,6 +36,7 @@ class _PathBrowsingFieldState extends State<PathBrowsingField> {
child: TextField( child: TextField(
controller: _textEditingController, controller: _textEditingController,
readOnly: true, readOnly: true,
canRequestFocus: false,
decoration: InputDecoration( decoration: InputDecoration(
border: OutlineInputBorder(borderRadius: BorderRadius.circular(4)), border: OutlineInputBorder(borderRadius: BorderRadius.circular(4)),
label: const Text('${Strings.fieldPath} *'), label: const Text('${Strings.fieldPath} *'),

View File

@ -1,4 +1,5 @@
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:minecraft_server_installer/main/adapter/presentation/installation_bloc.dart';
import 'package:minecraft_server_installer/main/constants.dart'; import 'package:minecraft_server_installer/main/constants.dart';
import 'package:minecraft_server_installer/vanilla/adapter/presentation/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/presentation/vanilla_state.dart'; import 'package:minecraft_server_installer/vanilla/adapter/presentation/vanilla_state.dart';
@ -7,10 +8,15 @@ import 'package:minecraft_server_installer/vanilla/application/use_case/get_game
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
class VanillaBloc extends Bloc<VanillaEvent, VanillaState> { class VanillaBloc extends Bloc<VanillaEvent, VanillaState> {
final InstallationBloc _installationBloc;
final GetGameVersionListUseCase _getGameVersionListUseCase; final GetGameVersionListUseCase _getGameVersionListUseCase;
final DownloadServerFileUseCase _downloadServerFileUseCase; final DownloadServerFileUseCase _downloadServerFileUseCase;
VanillaBloc(this._getGameVersionListUseCase, this._downloadServerFileUseCase) : super(const VanillaState.empty()) { VanillaBloc(
this._installationBloc,
this._getGameVersionListUseCase,
this._downloadServerFileUseCase,
) : super(const VanillaState.empty()) {
on<VanillaGameVersionListLoadedEvent>((_, emit) async { on<VanillaGameVersionListLoadedEvent>((_, emit) async {
try { try {
final gameVersions = await _getGameVersionListUseCase(); final gameVersions = await _getGameVersionListUseCase();
@ -24,12 +30,8 @@ class VanillaBloc extends Bloc<VanillaEvent, VanillaState> {
} }
}); });
on<VanillaGameVersionSelectedEvent>((event, emit) {
emit(state.copyWith(selectedGameVersion: event.gameVersion));
});
on<VanillaServerFileDownloadedEvent>((event, emit) async { on<VanillaServerFileDownloadedEvent>((event, emit) async {
final gameVersion = state.selectedGameVersion; final gameVersion = _installationBloc.state.gameVersion;
if (gameVersion == null) { if (gameVersion == null) {
return; return;
} }

View File

@ -5,13 +5,11 @@ class VanillaState with EquatableMixin {
final bool isLocked; final bool isLocked;
final double downloadProgress; final double downloadProgress;
final List<GameVersionViewModel> gameVersions; final List<GameVersionViewModel> gameVersions;
final GameVersionViewModel? selectedGameVersion;
const VanillaState({ const VanillaState({
required this.isLocked, required this.isLocked,
required this.downloadProgress, required this.downloadProgress,
required this.gameVersions, required this.gameVersions,
required this.selectedGameVersion,
}); });
const VanillaState.empty() const VanillaState.empty()
@ -19,7 +17,6 @@ class VanillaState with EquatableMixin {
isLocked: false, isLocked: false,
downloadProgress: 0, downloadProgress: 0,
gameVersions: const [], gameVersions: const [],
selectedGameVersion: null,
); );
@override @override
@ -27,11 +24,8 @@ class VanillaState with EquatableMixin {
isLocked, isLocked,
downloadProgress, downloadProgress,
gameVersions, gameVersions,
selectedGameVersion,
]; ];
bool get isGameVersionSelected => selectedGameVersion != null;
bool get isDownloading => downloadProgress > 0 && downloadProgress < 1; bool get isDownloading => downloadProgress > 0 && downloadProgress < 1;
VanillaState copyWith({ VanillaState copyWith({
@ -44,6 +38,5 @@ class VanillaState with EquatableMixin {
isLocked: isLocked ?? this.isLocked, isLocked: isLocked ?? this.isLocked,
downloadProgress: downloadProgress ?? this.downloadProgress, downloadProgress: downloadProgress ?? this.downloadProgress,
gameVersions: gameVersions ?? this.gameVersions, gameVersions: gameVersions ?? this.gameVersions,
selectedGameVersion: selectedGameVersion ?? this.selectedGameVersion,
); );
} }

View File

@ -1,5 +1,6 @@
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/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/presentation/vanilla_bloc.dart'; import 'package:minecraft_server_installer/vanilla/adapter/presentation/vanilla_bloc.dart';
import 'package:minecraft_server_installer/vanilla/adapter/presentation/game_version_view_model.dart'; import 'package:minecraft_server_installer/vanilla/adapter/presentation/game_version_view_model.dart';
@ -11,15 +12,15 @@ class GameVersionDropdown extends StatelessWidget {
@override @override
Widget build(BuildContext context) => BlocConsumer<VanillaBloc, VanillaState>( Widget build(BuildContext context) => BlocConsumer<VanillaBloc, VanillaState>(
listener: (_, __) {}, listener: (_, __) {},
builder: (_, state) => DropdownMenu( builder: (_, state) => DropdownMenu<GameVersionViewModel>(
initialSelection: state.selectedGameVersion, initialSelection: context.read<InstallationBloc>().state.gameVersion,
enabled: state.gameVersions.isNotEmpty, enabled: state.gameVersions.isNotEmpty,
requestFocusOnTap: false, requestFocusOnTap: false,
expandedInsets: EdgeInsets.zero, expandedInsets: EdgeInsets.zero,
label: const Text('${Strings.fieldGameVersion} *'), label: const Text('${Strings.fieldGameVersion} *'),
onSelected: (value) { onSelected: (value) {
if (value != null) { if (value != null) {
context.read<VanillaBloc>().add(VanillaGameVersionSelectedEvent(value)); context.read<InstallationBloc>().add(InstallationConfigurationUpdatedEvent(gameVersion: value));
} }
}, },
dropdownMenuEntries: state.gameVersions dropdownMenuEntries: state.gameVersions