MCSI-2 Browse installing directory #19
7
lib/main/adapter/gateway/installation_api_service.dart
Normal file
7
lib/main/adapter/gateway/installation_api_service.dart
Normal file
@ -0,0 +1,7 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:minecraft_server_installer/main/application/repository/installation_repository.dart';
|
||||
|
||||
abstract interface class InstallationApiService {
|
||||
Future<Uint8List> fetchRemoteFile(Uri url, {DownloadProgressCallback? onProgressChanged});
|
||||
}
|
5
lib/main/adapter/gateway/installation_file_storage.dart
Normal file
5
lib/main/adapter/gateway/installation_file_storage.dart
Normal file
@ -0,0 +1,5 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
abstract interface class InstallationFileStorage {
|
||||
Future<void> saveFile(Uint8List fileBytes, String path);
|
||||
}
|
16
lib/main/adapter/gateway/installation_repository_impl.dart
Normal file
16
lib/main/adapter/gateway/installation_repository_impl.dart
Normal file
@ -0,0 +1,16 @@
|
||||
import 'package:minecraft_server_installer/main/adapter/gateway/installation_api_service.dart';
|
||||
import 'package:minecraft_server_installer/main/adapter/gateway/installation_file_storage.dart';
|
||||
import 'package:minecraft_server_installer/main/application/repository/installation_repository.dart';
|
||||
|
||||
class InstallationRepositoryImpl implements InstallationRepository {
|
||||
final InstallationApiService _apiService;
|
||||
final InstallationFileStorage _fileStorage;
|
||||
|
||||
InstallationRepositoryImpl(this._apiService, this._fileStorage);
|
||||
|
||||
@override
|
||||
Future<void> downloadServerFile(Uri url, String path, {DownloadProgressCallback? onProgressChanged}) async {
|
||||
final fileBytes = await _apiService.fetchRemoteFile(url, onProgressChanged: onProgressChanged);
|
||||
await _fileStorage.saveFile(fileBytes, path);
|
||||
}
|
||||
}
|
@ -1,9 +1,46 @@
|
||||
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/application/use_case/download_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> {
|
||||
InstallationBloc() : super(const InstallationState.empty()) {
|
||||
InstallationBloc(DownloadFileUseCase downloadFileUseCase) : super(const InstallationState.empty()) {
|
||||
on<InstallationStartedEvent>((_, emit) async {
|
||||
if (!state.canStartToInstall) {
|
||||
return;
|
||||
}
|
||||
|
||||
final gameVersion = state.gameVersion!;
|
||||
final savePath = state.savePath!;
|
||||
|
||||
emit(state.copyWith(isLocked: true, downloadProgress: const ProgressViewModel.start()));
|
||||
|
||||
await downloadFileUseCase(
|
||||
gameVersion.url,
|
||||
path.join(savePath, Constants.serverFileName),
|
||||
onProgressChanged: (progressValue) => add(_InstallationProgressValueChangedEvent(progressValue)),
|
||||
);
|
||||
|
||||
emit(state.copyWith(isLocked: false, downloadProgress: const ProgressViewModel.complete()));
|
||||
});
|
||||
|
||||
on<_InstallationProgressValueChangedEvent>((event, emit) {
|
||||
ProgressViewModel newProgress;
|
||||
|
||||
if (event.progressValue < 0) {
|
||||
newProgress = state.downloadProgress.copyWith(value: 0.0);
|
||||
} else if (event.progressValue > 1) {
|
||||
newProgress = state.downloadProgress.copyWith(value: 1.0);
|
||||
} else {
|
||||
newProgress = state.downloadProgress.copyWith(value: event.progressValue);
|
||||
}
|
||||
|
||||
emit(state.copyWith(downloadProgress: newProgress));
|
||||
});
|
||||
|
||||
on<InstallationConfigurationUpdatedEvent>((event, emit) {
|
||||
final newState = state.copyWith(
|
||||
gameVersion: event.gameVersion,
|
||||
@ -16,6 +53,14 @@ class InstallationBloc extends Bloc<InstallationEvent, InstallationState> {
|
||||
|
||||
sealed class InstallationEvent {}
|
||||
|
||||
class InstallationStartedEvent extends InstallationEvent {}
|
||||
|
||||
class _InstallationProgressValueChangedEvent extends InstallationEvent {
|
||||
final double progressValue;
|
||||
|
||||
_InstallationProgressValueChangedEvent(this.progressValue);
|
||||
}
|
||||
|
||||
class InstallationConfigurationUpdatedEvent extends InstallationEvent {
|
||||
final GameVersionViewModel? gameVersion;
|
||||
final String? savePath;
|
||||
|
@ -1,39 +1,52 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:minecraft_server_installer/main/adapter/presentation/progress_view_model.dart';
|
||||
import 'package:minecraft_server_installer/vanilla/adapter/presentation/game_version_view_model.dart';
|
||||
|
||||
class InstallationState with EquatableMixin {
|
||||
final GameVersionViewModel? gameVersion;
|
||||
final String? savePath;
|
||||
final ProgressViewModel downloadProgress;
|
||||
final bool isLocked;
|
||||
|
||||
const InstallationState({
|
||||
this.gameVersion,
|
||||
this.savePath,
|
||||
required this.gameVersion,
|
||||
required this.savePath,
|
||||
required this.downloadProgress,
|
||||
required this.isLocked,
|
||||
});
|
||||
|
||||
const InstallationState.empty()
|
||||
: this(
|
||||
gameVersion: null,
|
||||
savePath: null,
|
||||
downloadProgress: const ProgressViewModel.zero(),
|
||||
isLocked: false,
|
||||
);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
gameVersion,
|
||||
savePath,
|
||||
downloadProgress,
|
||||
isLocked,
|
||||
];
|
||||
|
||||
InstallationState copyWith({
|
||||
GameVersionViewModel? gameVersion,
|
||||
String? savePath,
|
||||
ProgressViewModel? downloadProgress,
|
||||
bool? isLocked,
|
||||
}) =>
|
||||
InstallationState(
|
||||
gameVersion: gameVersion ?? this.gameVersion,
|
||||
savePath: savePath ?? this.savePath,
|
||||
downloadProgress: downloadProgress ?? this.downloadProgress,
|
||||
isLocked: isLocked ?? this.isLocked,
|
||||
);
|
||||
|
||||
bool get isGameVersionSelected => gameVersion != null;
|
||||
|
||||
bool get isSavePathSelected => savePath != null && savePath!.isNotEmpty;
|
||||
|
||||
bool get canStartToInstall => isGameVersionSelected && isSavePathSelected;
|
||||
bool get canStartToInstall => isGameVersionSelected && isSavePathSelected && !isLocked;
|
||||
}
|
||||
|
33
lib/main/adapter/presentation/progress_view_model.dart
Normal file
33
lib/main/adapter/presentation/progress_view_model.dart
Normal file
@ -0,0 +1,33 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
class ProgressViewModel with EquatableMixin {
|
||||
/// The value should between 0.0 and 1.0.
|
||||
final double value;
|
||||
final bool isInProgress;
|
||||
|
||||
const ProgressViewModel({
|
||||
required this.value,
|
||||
required this.isInProgress,
|
||||
});
|
||||
|
||||
const ProgressViewModel.zero() : this(value: 0.0, isInProgress: false);
|
||||
|
||||
const ProgressViewModel.start() : this(value: 0.0, isInProgress: true);
|
||||
|
||||
const ProgressViewModel.complete() : this(value: 1.0, isInProgress: false);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
value,
|
||||
isInProgress,
|
||||
];
|
||||
|
||||
ProgressViewModel copyWith({
|
||||
double? value,
|
||||
bool? isInProgress,
|
||||
}) =>
|
||||
ProgressViewModel(
|
||||
value: value ?? this.value,
|
||||
isInProgress: isInProgress ?? this.isInProgress,
|
||||
);
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
typedef DownloadProgressCallback = void Function(double progress);
|
||||
|
||||
abstract interface class InstallationRepository {
|
||||
Future<void> downloadServerFile(Uri url, String path, {DownloadProgressCallback? onProgressChanged});
|
||||
}
|
10
lib/main/application/use_case/download_file_use_case.dart
Normal file
10
lib/main/application/use_case/download_file_use_case.dart
Normal file
@ -0,0 +1,10 @@
|
||||
import 'package:minecraft_server_installer/main/application/repository/installation_repository.dart';
|
||||
|
||||
class DownloadFileUseCase {
|
||||
final InstallationRepository _installationRepository;
|
||||
|
||||
DownloadFileUseCase(this._installationRepository);
|
||||
|
||||
Future<void> call(Uri url, String path, {DownloadProgressCallback? onProgressChanged}) =>
|
||||
_installationRepository.downloadServerFile(url, path, onProgressChanged: onProgressChanged);
|
||||
}
|
40
lib/main/framework/api/installation_api_service_impl.dart
Normal file
40
lib/main/framework/api/installation_api_service_impl.dart
Normal file
@ -0,0 +1,40 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:minecraft_server_installer/main/adapter/gateway/installation_api_service.dart';
|
||||
import 'package:minecraft_server_installer/main/application/repository/installation_repository.dart';
|
||||
|
||||
class InstallationApiServiceImpl implements InstallationApiService {
|
||||
@override
|
||||
Future<Uint8List> fetchRemoteFile(Uri url, {DownloadProgressCallback? onProgressChanged}) async {
|
||||
final client = http.Client();
|
||||
final request = http.Request('GET', url);
|
||||
final response = await client.send(request);
|
||||
|
||||
final contentLength = response.contentLength;
|
||||
final completer = Completer<Uint8List>();
|
||||
final bytes = <int>[];
|
||||
var receivedBytes = 0;
|
||||
|
||||
response.stream.listen(
|
||||
(chunk) {
|
||||
bytes.addAll(chunk);
|
||||
receivedBytes += chunk.length;
|
||||
if (onProgressChanged != null && contentLength != null) {
|
||||
onProgressChanged(receivedBytes / contentLength);
|
||||
}
|
||||
},
|
||||
onDone: () {
|
||||
if (onProgressChanged != null) {
|
||||
onProgressChanged(1);
|
||||
}
|
||||
completer.complete(Uint8List.fromList(bytes));
|
||||
},
|
||||
onError: completer.completeError,
|
||||
cancelOnError: true,
|
||||
);
|
||||
|
||||
return completer.future;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:minecraft_server_installer/main/adapter/gateway/installation_file_storage.dart';
|
||||
|
||||
class InstallationFileStorageImpl implements InstallationFileStorage {
|
||||
@override
|
||||
Future<void> saveFile(Uint8List fileBytes, String path) async {
|
||||
final file = File(path);
|
||||
|
||||
if (!await file.parent.exists()) {
|
||||
await file.parent.create(recursive: true);
|
||||
}
|
||||
|
||||
await file.create();
|
||||
await file.writeAsBytes(fileBytes, flush: true);
|
||||
}
|
||||
}
|
@ -2,11 +2,10 @@ import 'package:flutter/material.dart';
|
||||
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/framework/ui/path_browsing_field.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/game_version_view_model.dart';
|
||||
import 'package:minecraft_server_installer/vanilla/adapter/presentation/vanilla_state.dart';
|
||||
import 'package:minecraft_server_installer/vanilla/framework/ui/game_version_dropdown.dart';
|
||||
|
||||
class BasicConfigurationTab extends StatefulWidget {
|
||||
@ -30,16 +29,17 @@ class _BasicConfigurationTabState extends State<BasicConfigurationTab> {
|
||||
],
|
||||
);
|
||||
|
||||
Widget get _bottomControl => BlocConsumer<VanillaBloc, VanillaState>(
|
||||
Widget get _bottomControl => BlocConsumer<InstallationBloc, InstallationState>(
|
||||
listener: (_, __) {},
|
||||
builder: (_, state) => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
if (state.isDownloading) Expanded(child: LinearProgressIndicator(value: state.downloadProgress)),
|
||||
if (state.downloadProgress.isInProgress)
|
||||
Expanded(child: LinearProgressIndicator(value: state.downloadProgress.value)),
|
||||
const Gap(32),
|
||||
ElevatedButton.icon(
|
||||
style: ElevatedButton.styleFrom(shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4))),
|
||||
onPressed: context.watch<InstallationBloc>().state.isGameVersionSelected ? _downloadServerFile : null,
|
||||
onPressed: context.watch<InstallationBloc>().state.canStartToInstall ? _downloadServerFile : null,
|
||||
icon: const Icon(Icons.download),
|
||||
label: const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 12),
|
||||
@ -51,7 +51,6 @@ class _BasicConfigurationTabState extends State<BasicConfigurationTab> {
|
||||
);
|
||||
|
||||
void _downloadServerFile() {
|
||||
final savePath = context.read<InstallationBloc>().state.savePath;
|
||||
context.read<VanillaBloc>().add(VanillaServerFileDownloadedEvent(savePath!));
|
||||
context.read<InstallationBloc>().add((InstallationStartedEvent()));
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,16 @@
|
||||
import 'package:flutter/material.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/presentation/installation_bloc.dart';
|
||||
import 'package:minecraft_server_installer/main/adapter/presentation/installation_state.dart';
|
||||
import 'package:minecraft_server_installer/main/application/use_case/download_file_use_case.dart';
|
||||
import 'package:minecraft_server_installer/main/framework/api/installation_api_service_impl.dart';
|
||||
import 'package:minecraft_server_installer/main/framework/storage/installation_file_storage_impl.dart';
|
||||
import 'package:minecraft_server_installer/main/framework/ui/basic_configuration_tab.dart';
|
||||
import 'package:minecraft_server_installer/vanilla/adapter/gateway/vanilla_repository_impl.dart';
|
||||
import 'package:minecraft_server_installer/vanilla/adapter/presentation/vanilla_bloc.dart';
|
||||
import 'package:minecraft_server_installer/vanilla/adapter/presentation/vanilla_state.dart';
|
||||
import 'package:minecraft_server_installer/vanilla/application/use_case/download_server_file_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/storage/vanilla_file_storage_impl.dart';
|
||||
|
||||
class MinecraftServerInstaller extends StatelessWidget {
|
||||
const MinecraftServerInstaller({super.key});
|
||||
@ -18,27 +20,28 @@ class MinecraftServerInstaller extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final gameVersionApiService = VanillaApiServiceImpl();
|
||||
final gameVersionFileStorage = VanillaFileStorageImpl();
|
||||
final gameVersionRepository = VanillaRepositoryImpl(gameVersionApiService, gameVersionFileStorage);
|
||||
final getGameVersionListUseCase = GetGameVersionListUseCase(gameVersionRepository);
|
||||
final downloadServerFileUseCase = DownloadServerFileUseCase(gameVersionRepository);
|
||||
final installationApiService = InstallationApiServiceImpl();
|
||||
final installationFileStorage = InstallationFileStorageImpl();
|
||||
final installationRepository = InstallationRepositoryImpl(installationApiService, installationFileStorage);
|
||||
|
||||
final installationBloc = InstallationBloc();
|
||||
final gameVersionApiService = VanillaApiServiceImpl();
|
||||
final gameVersionRepository = VanillaRepositoryImpl(gameVersionApiService);
|
||||
|
||||
final downloadFileUseCase = DownloadFileUseCase(installationRepository);
|
||||
final getGameVersionListUseCase = GetGameVersionListUseCase(gameVersionRepository);
|
||||
|
||||
return MaterialApp(
|
||||
title: 'Minecraft Server Installer',
|
||||
theme: ThemeData.light().copyWith(colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue.shade900)),
|
||||
home: MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider.value(value: installationBloc),
|
||||
BlocProvider(create: (_) => InstallationBloc(downloadFileUseCase)),
|
||||
BlocProvider<VanillaBloc>(
|
||||
create: (_) => VanillaBloc(installationBloc, getGameVersionListUseCase, downloadServerFileUseCase)
|
||||
..add(VanillaGameVersionListLoadedEvent()),
|
||||
create: (_) => VanillaBloc(getGameVersionListUseCase)..add(VanillaGameVersionListLoadedEvent()),
|
||||
),
|
||||
],
|
||||
child: Scaffold(
|
||||
body: BlocConsumer<VanillaBloc, VanillaState>(
|
||||
body: BlocConsumer<InstallationBloc, InstallationState>(
|
||||
listener: (_, __) {},
|
||||
builder: (_, state) {
|
||||
if (state.isLocked) {
|
||||
|
@ -1,10 +1,5 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:minecraft_server_installer/vanilla/application/use_case/download_server_file_use_case.dart';
|
||||
import 'package:minecraft_server_installer/vanilla/domain/entity/game_version.dart';
|
||||
|
||||
abstract interface class VanillaApiService {
|
||||
Future<List<GameVersion>> fetchGameVersionList();
|
||||
|
||||
Future<Uint8List> fetchServerFile(Uri url, {DownloadProgressCallback? onProgressChanged});
|
||||
}
|
||||
|
@ -1,5 +0,0 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
abstract interface class VanillaFileStorage {
|
||||
Future<void> saveFile(Uint8List fileBytes, String savePath);
|
||||
}
|
@ -1,28 +1,12 @@
|
||||
import 'package:minecraft_server_installer/vanilla/adapter/gateway/vanilla_api_service.dart';
|
||||
import 'package:minecraft_server_installer/vanilla/adapter/gateway/vanilla_file_storage.dart';
|
||||
import 'package:minecraft_server_installer/vanilla/application/repository/vanilla_repository.dart';
|
||||
import 'package:minecraft_server_installer/vanilla/application/use_case/download_server_file_use_case.dart';
|
||||
import 'package:minecraft_server_installer/vanilla/domain/entity/game_version.dart';
|
||||
|
||||
class VanillaRepositoryImpl implements VanillaRepository {
|
||||
final VanillaApiService _gameVersionApiService;
|
||||
final VanillaFileStorage _gameVersionFileStorage;
|
||||
|
||||
VanillaRepositoryImpl(this._gameVersionApiService, this._gameVersionFileStorage);
|
||||
VanillaRepositoryImpl(this._gameVersionApiService);
|
||||
|
||||
@override
|
||||
Future<List<GameVersion>> getGameVersionList() => _gameVersionApiService.fetchGameVersionList();
|
||||
|
||||
@override
|
||||
Future<void> downloadServerFile(
|
||||
GameVersion version,
|
||||
String savePath, {
|
||||
DownloadProgressCallback? onProgressChanged,
|
||||
}) async {
|
||||
final fileBytes = await _gameVersionApiService.fetchServerFile(
|
||||
version.url,
|
||||
onProgressChanged: onProgressChanged,
|
||||
);
|
||||
await _gameVersionFileStorage.saveFile(fileBytes, savePath);
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,13 @@
|
||||
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/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/application/use_case/download_server_file_use_case.dart';
|
||||
import 'package:minecraft_server_installer/vanilla/application/use_case/get_game_version_list_use_case.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
class VanillaBloc extends Bloc<VanillaEvent, VanillaState> {
|
||||
final InstallationBloc _installationBloc;
|
||||
final GetGameVersionListUseCase _getGameVersionListUseCase;
|
||||
final DownloadServerFileUseCase _downloadServerFileUseCase;
|
||||
|
||||
VanillaBloc(
|
||||
this._installationBloc,
|
||||
this._getGameVersionListUseCase,
|
||||
this._downloadServerFileUseCase,
|
||||
) : super(const VanillaState.empty()) {
|
||||
VanillaBloc(GetGameVersionListUseCase getGameVersionListUseCase) : super(const VanillaState.empty()) {
|
||||
on<VanillaGameVersionListLoadedEvent>((_, emit) async {
|
||||
try {
|
||||
final gameVersions = await _getGameVersionListUseCase();
|
||||
final gameVersions = await getGameVersionListUseCase();
|
||||
emit(
|
||||
const VanillaState.empty().copyWith(
|
||||
gameVersions: gameVersions.map((entity) => GameVersionViewModel.fromEntity(entity)).toList(),
|
||||
@ -29,31 +17,6 @@ class VanillaBloc extends Bloc<VanillaEvent, VanillaState> {
|
||||
emit(const VanillaState.empty());
|
||||
}
|
||||
});
|
||||
|
||||
on<VanillaServerFileDownloadedEvent>((event, emit) async {
|
||||
final gameVersion = _installationBloc.state.gameVersion;
|
||||
if (gameVersion == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
emit(state.copyWith(isLocked: true));
|
||||
await _downloadServerFileUseCase(
|
||||
gameVersion.toEntity(),
|
||||
path.join(event.savePath, Constants.serverFileName),
|
||||
onProgressChanged: (progress) => add(_VanillaDownloadProgressChangedEvent(progress)),
|
||||
);
|
||||
emit(state.copyWith(isLocked: false));
|
||||
});
|
||||
|
||||
on<_VanillaDownloadProgressChangedEvent>((event, emit) {
|
||||
if (event.progress < 0) {
|
||||
emit(state.copyWith(downloadProgress: 0));
|
||||
} else if (event.progress > 1) {
|
||||
emit(state.copyWith(downloadProgress: 1));
|
||||
} else {
|
||||
emit(state.copyWith(downloadProgress: event.progress));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,15 +29,3 @@ class VanillaGameVersionSelectedEvent extends VanillaEvent {
|
||||
|
||||
VanillaGameVersionSelectedEvent(this.gameVersion);
|
||||
}
|
||||
|
||||
class VanillaServerFileDownloadedEvent extends VanillaEvent {
|
||||
final String savePath;
|
||||
|
||||
VanillaServerFileDownloadedEvent(this.savePath);
|
||||
}
|
||||
|
||||
class _VanillaDownloadProgressChangedEvent extends VanillaEvent {
|
||||
final double progress;
|
||||
|
||||
_VanillaDownloadProgressChangedEvent(this.progress);
|
||||
}
|
||||
|
@ -2,32 +2,22 @@ import 'package:equatable/equatable.dart';
|
||||
import 'package:minecraft_server_installer/vanilla/adapter/presentation/game_version_view_model.dart';
|
||||
|
||||
class VanillaState with EquatableMixin {
|
||||
final bool isLocked;
|
||||
final double downloadProgress;
|
||||
final List<GameVersionViewModel> gameVersions;
|
||||
|
||||
const VanillaState({
|
||||
required this.isLocked,
|
||||
required this.downloadProgress,
|
||||
required this.gameVersions,
|
||||
});
|
||||
|
||||
const VanillaState.empty()
|
||||
: this(
|
||||
isLocked: false,
|
||||
downloadProgress: 0,
|
||||
gameVersions: const [],
|
||||
);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
isLocked,
|
||||
downloadProgress,
|
||||
gameVersions,
|
||||
];
|
||||
|
||||
bool get isDownloading => downloadProgress > 0 && downloadProgress < 1;
|
||||
|
||||
VanillaState copyWith({
|
||||
bool? isLocked,
|
||||
double? downloadProgress,
|
||||
@ -35,8 +25,6 @@ class VanillaState with EquatableMixin {
|
||||
GameVersionViewModel? selectedGameVersion,
|
||||
}) =>
|
||||
VanillaState(
|
||||
isLocked: isLocked ?? this.isLocked,
|
||||
downloadProgress: downloadProgress ?? this.downloadProgress,
|
||||
gameVersions: gameVersions ?? this.gameVersions,
|
||||
);
|
||||
}
|
||||
|
@ -1,12 +1,5 @@
|
||||
import 'package:minecraft_server_installer/vanilla/application/use_case/download_server_file_use_case.dart';
|
||||
import 'package:minecraft_server_installer/vanilla/domain/entity/game_version.dart';
|
||||
|
||||
abstract interface class VanillaRepository {
|
||||
Future<List<GameVersion>> getGameVersionList();
|
||||
|
||||
Future<void> downloadServerFile(
|
||||
GameVersion version,
|
||||
String savePath, {
|
||||
DownloadProgressCallback? onProgressChanged,
|
||||
});
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
import 'package:minecraft_server_installer/vanilla/application/repository/vanilla_repository.dart';
|
||||
import 'package:minecraft_server_installer/vanilla/domain/entity/game_version.dart';
|
||||
|
||||
typedef DownloadProgressCallback = void Function(double progress);
|
||||
|
||||
class DownloadServerFileUseCase {
|
||||
final VanillaRepository _gameVersionRepository;
|
||||
|
||||
DownloadServerFileUseCase(this._gameVersionRepository);
|
||||
|
||||
Future<void> call(
|
||||
GameVersion version,
|
||||
String savePath, {
|
||||
DownloadProgressCallback? onProgressChanged,
|
||||
}) =>
|
||||
_gameVersionRepository.downloadServerFile(
|
||||
version,
|
||||
savePath,
|
||||
onProgressChanged: onProgressChanged,
|
||||
);
|
||||
}
|
@ -1,10 +1,8 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:minecraft_server_installer/main/constants.dart';
|
||||
import 'package:minecraft_server_installer/vanilla/adapter/gateway/vanilla_api_service.dart';
|
||||
import 'package:minecraft_server_installer/vanilla/application/use_case/download_server_file_use_case.dart';
|
||||
import 'package:minecraft_server_installer/vanilla/domain/entity/game_version.dart';
|
||||
|
||||
class VanillaApiServiceImpl implements VanillaApiService {
|
||||
@ -22,36 +20,4 @@ class VanillaApiServiceImpl implements VanillaApiService {
|
||||
|
||||
return gameVersionList;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Uint8List> fetchServerFile(Uri url, {DownloadProgressCallback? onProgressChanged}) async {
|
||||
final client = http.Client();
|
||||
final request = http.Request('GET', url);
|
||||
final response = await client.send(request);
|
||||
|
||||
final contentLength = response.contentLength;
|
||||
final completer = Completer<Uint8List>();
|
||||
final bytes = <int>[];
|
||||
var receivedBytes = 0;
|
||||
|
||||
response.stream.listen(
|
||||
(chunk) {
|
||||
bytes.addAll(chunk);
|
||||
receivedBytes += chunk.length;
|
||||
if (onProgressChanged != null && contentLength != null) {
|
||||
onProgressChanged(receivedBytes / contentLength);
|
||||
}
|
||||
},
|
||||
onDone: () {
|
||||
if (onProgressChanged != null) {
|
||||
onProgressChanged(1);
|
||||
}
|
||||
completer.complete(Uint8List.fromList(bytes));
|
||||
},
|
||||
onError: completer.completeError,
|
||||
cancelOnError: true,
|
||||
);
|
||||
|
||||
return completer.future;
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +0,0 @@
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:minecraft_server_installer/vanilla/adapter/gateway/vanilla_file_storage.dart';
|
||||
|
||||
class VanillaFileStorageImpl implements VanillaFileStorage {
|
||||
@override
|
||||
Future<void> saveFile(Uint8List fileBytes, String savePath) async {
|
||||
final file = File(savePath);
|
||||
|
||||
if (!await file.parent.exists()) {
|
||||
await file.parent.create(recursive: true);
|
||||
}
|
||||
|
||||
await file.create();
|
||||
await file.writeAsBytes(fileBytes, flush: true);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user