MCSI-1 feat: version selection
This commit is contained in:
parent
ecee7ac16f
commit
e8ad6592f5
@ -22,7 +22,8 @@ linter:
|
|||||||
# producing the lint.
|
# producing the lint.
|
||||||
rules:
|
rules:
|
||||||
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||||
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||||
|
prefer_const_constructors: true
|
||||||
|
|
||||||
# Additional information about this file can be found at
|
# Additional information about this file can be found at
|
||||||
# https://dart.dev/guides/language/analysis-options
|
# https://dart.dev/guides/language/analysis-options
|
||||||
|
19
lib/main/framework/ui/basic_configuration_tab.dart
Normal file
19
lib/main/framework/ui/basic_configuration_tab.dart
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:minecraft_server_installer/vanila/adapter/presentation/game_version_view_model.dart';
|
||||||
|
import 'package:minecraft_server_installer/vanila/framework/ui/game_version_dropdown.dart';
|
||||||
|
|
||||||
|
class BasicConfigurationTab extends StatefulWidget {
|
||||||
|
const BasicConfigurationTab({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<BasicConfigurationTab> createState() => _BasicConfigurationTabState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BasicConfigurationTabState extends State<BasicConfigurationTab> {
|
||||||
|
GameVersionViewModel? selectedGameVersion;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return const Column(children: [GameVersionDropdown(onChanged: print)]);
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,17 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:minecraft_server_installer/main/framework/ui/basic_configuration_tab.dart';
|
||||||
|
|
||||||
class MinecraftServerInstaller extends StatelessWidget {
|
class MinecraftServerInstaller extends StatelessWidget {
|
||||||
const MinecraftServerInstaller({super.key});
|
const MinecraftServerInstaller({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return const Placeholder();
|
return MaterialApp(
|
||||||
|
title: 'Minecraft Server Installer',
|
||||||
|
theme: ThemeData(primarySwatch: Colors.blue),
|
||||||
|
home: const Scaffold(
|
||||||
|
body: Padding(padding: EdgeInsets.symmetric(horizontal: 24, vertical: 32), child: BasicConfigurationTab()),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
3
lib/main/framework/ui/strings.dart
Normal file
3
lib/main/framework/ui/strings.dart
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
abstract class Strings {
|
||||||
|
static const fieldGameVersion = '遊戲版本';
|
||||||
|
}
|
@ -1,6 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:minecraft_server_installer/main/framework/ui/minecraft_server_installer.dart';
|
import 'package:minecraft_server_installer/main/framework/ui/minecraft_server_installer.dart';
|
||||||
|
import 'package:minecraft_server_installer/vanila/framework/api/game_version_api_service_impl.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
final apiService = GameVersionApiServiceImpl();
|
||||||
|
apiService.fetchGameVersionList();
|
||||||
runApp(const MinecraftServerInstaller());
|
runApp(const MinecraftServerInstaller());
|
||||||
}
|
}
|
||||||
|
5
lib/vanila/adapter/gateway/game_version_api_service.dart
Normal file
5
lib/vanila/adapter/gateway/game_version_api_service.dart
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import 'package:minecraft_server_installer/vanila/domain/entity/game_version.dart';
|
||||||
|
|
||||||
|
abstract interface class GameVersionApiService {
|
||||||
|
Future<List<GameVersion>> fetchGameVersionList();
|
||||||
|
}
|
12
lib/vanila/adapter/gateway/game_version_repository_impl.dart
Normal file
12
lib/vanila/adapter/gateway/game_version_repository_impl.dart
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import 'package:minecraft_server_installer/vanila/adapter/gateway/game_version_api_service.dart';
|
||||||
|
import 'package:minecraft_server_installer/vanila/application/repository/game_version_repository.dart';
|
||||||
|
import 'package:minecraft_server_installer/vanila/domain/entity/game_version.dart';
|
||||||
|
|
||||||
|
class GameVersionRepositoryImpl implements GameVersionRepository {
|
||||||
|
final GameVersionApiService _gameVersionApiService;
|
||||||
|
|
||||||
|
GameVersionRepositoryImpl(this._gameVersionApiService);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<GameVersion>> getGameVersionList() => _gameVersionApiService.fetchGameVersionList();
|
||||||
|
}
|
22
lib/vanila/adapter/presentation/game_version_bloc.dart
Normal file
22
lib/vanila/adapter/presentation/game_version_bloc.dart
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:minecraft_server_installer/vanila/adapter/presentation/game_version_view_model.dart';
|
||||||
|
import 'package:minecraft_server_installer/vanila/application/use_case/get_game_version_list_use_case.dart';
|
||||||
|
|
||||||
|
class GameVersionBloc extends Bloc<GameVersionEvent, List<GameVersionViewModel>> {
|
||||||
|
final GetGameVersionListUseCase _getGameVersionListUseCase;
|
||||||
|
|
||||||
|
GameVersionBloc(this._getGameVersionListUseCase) : super(const []) {
|
||||||
|
on<GameVersionLoadedEvent>((_, emit) async {
|
||||||
|
try {
|
||||||
|
final gameVersions = await _getGameVersionListUseCase();
|
||||||
|
emit(gameVersions.map((entity) => GameVersionViewModel.from(entity)).toList());
|
||||||
|
} on Exception {
|
||||||
|
emit(const []);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class GameVersionEvent {}
|
||||||
|
|
||||||
|
class GameVersionLoadedEvent extends GameVersionEvent {}
|
14
lib/vanila/adapter/presentation/game_version_view_model.dart
Normal file
14
lib/vanila/adapter/presentation/game_version_view_model.dart
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:minecraft_server_installer/vanila/domain/entity/game_version.dart';
|
||||||
|
|
||||||
|
class GameVersionViewModel with EquatableMixin {
|
||||||
|
final String name;
|
||||||
|
final Uri url;
|
||||||
|
|
||||||
|
const GameVersionViewModel({required this.name, required this.url});
|
||||||
|
|
||||||
|
GameVersionViewModel.from(GameVersion gameVersion) : name = gameVersion.name, url = gameVersion.url;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [name, url];
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
import 'package:minecraft_server_installer/vanila/domain/entity/game_version.dart';
|
||||||
|
|
||||||
|
abstract interface class GameVersionRepository {
|
||||||
|
Future<List<GameVersion>> getGameVersionList();
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
import 'package:minecraft_server_installer/vanila/application/repository/game_version_repository.dart';
|
||||||
|
import 'package:minecraft_server_installer/vanila/domain/entity/game_version.dart';
|
||||||
|
|
||||||
|
class GetGameVersionListUseCase {
|
||||||
|
final GameVersionRepository _gameVersionRepository;
|
||||||
|
|
||||||
|
GetGameVersionListUseCase(this._gameVersionRepository);
|
||||||
|
|
||||||
|
Future<List<GameVersion>> call() => _gameVersionRepository.getGameVersionList();
|
||||||
|
}
|
11
lib/vanila/domain/entity/game_version.dart
Normal file
11
lib/vanila/domain/entity/game_version.dart
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
|
||||||
|
class GameVersion with EquatableMixin {
|
||||||
|
final String name;
|
||||||
|
final Uri url;
|
||||||
|
|
||||||
|
const GameVersion({required this.name, required this.url});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [name, url];
|
||||||
|
}
|
20
lib/vanila/framework/api/game_version_api_service_impl.dart
Normal file
20
lib/vanila/framework/api/game_version_api_service_impl.dart
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:minecraft_server_installer/vanila/adapter/gateway/game_version_api_service.dart';
|
||||||
|
import 'package:minecraft_server_installer/vanila/domain/entity/game_version.dart';
|
||||||
|
|
||||||
|
class GameVersionApiServiceImpl implements GameVersionApiService {
|
||||||
|
@override
|
||||||
|
Future<List<GameVersion>> fetchGameVersionList() async {
|
||||||
|
final sourceUrl = Uri.parse('https://www.dropbox.com/s/mtz3moc9dpjtz7s/GameVersions.txt?dl=1');
|
||||||
|
final response = await http.get(sourceUrl);
|
||||||
|
|
||||||
|
final rawGameVersionList = response.body.split('\n');
|
||||||
|
final gameVersionList =
|
||||||
|
rawGameVersionList.map((line) => line.split(' ')).where((parts) => parts.length == 2).map((parts) {
|
||||||
|
final [name, url] = parts;
|
||||||
|
return GameVersion(name: name, url: Uri.parse(url));
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
return gameVersionList;
|
||||||
|
}
|
||||||
|
}
|
64
lib/vanila/framework/ui/game_version_dropdown.dart
Normal file
64
lib/vanila/framework/ui/game_version_dropdown.dart
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:minecraft_server_installer/main/framework/ui/strings.dart';
|
||||||
|
import 'package:minecraft_server_installer/vanila/adapter/gateway/game_version_repository_impl.dart';
|
||||||
|
import 'package:minecraft_server_installer/vanila/adapter/presentation/game_version_bloc.dart';
|
||||||
|
import 'package:minecraft_server_installer/vanila/adapter/presentation/game_version_view_model.dart';
|
||||||
|
import 'package:minecraft_server_installer/vanila/application/use_case/get_game_version_list_use_case.dart';
|
||||||
|
import 'package:minecraft_server_installer/vanila/framework/api/game_version_api_service_impl.dart';
|
||||||
|
|
||||||
|
class GameVersionDropdown extends StatelessWidget {
|
||||||
|
const GameVersionDropdown({super.key, required this.onChanged});
|
||||||
|
|
||||||
|
final void Function(GameVersionViewModel?) onChanged;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocProvider<GameVersionBloc>(
|
||||||
|
create: (_) {
|
||||||
|
final gameVersionApiService = GameVersionApiServiceImpl();
|
||||||
|
final gameVersionRepository = GameVersionRepositoryImpl(gameVersionApiService);
|
||||||
|
final getGameVersionListUseCase = GetGameVersionListUseCase(gameVersionRepository);
|
||||||
|
return GameVersionBloc(getGameVersionListUseCase);
|
||||||
|
},
|
||||||
|
child: _GameVersionDropdown(key: key, onChanged: onChanged),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _GameVersionDropdown extends StatefulWidget {
|
||||||
|
const _GameVersionDropdown({super.key, required this.onChanged});
|
||||||
|
|
||||||
|
final void Function(GameVersionViewModel?) onChanged;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_GameVersionDropdown> createState() => _GameVersionDropdownState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _GameVersionDropdownState extends State<_GameVersionDropdown> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
context.read<GameVersionBloc>().add(GameVersionLoadedEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => BlocConsumer<GameVersionBloc, List<GameVersionViewModel>>(
|
||||||
|
listener: (_, __) {},
|
||||||
|
builder:
|
||||||
|
(_, gameVersions) => DropdownMenu(
|
||||||
|
enabled: gameVersions.isNotEmpty,
|
||||||
|
requestFocusOnTap: false,
|
||||||
|
expandedInsets: EdgeInsets.zero,
|
||||||
|
label: const Text(Strings.fieldGameVersion),
|
||||||
|
onSelected: widget.onChanged,
|
||||||
|
dropdownMenuEntries:
|
||||||
|
gameVersions
|
||||||
|
.map(
|
||||||
|
(gameVersion) =>
|
||||||
|
DropdownMenuEntry<GameVersionViewModel>(value: gameVersion, label: gameVersion.name),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
72
pubspec.lock
72
pubspec.lock
@ -9,6 +9,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.12.0"
|
version: "2.12.0"
|
||||||
|
bloc:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: bloc
|
||||||
|
sha256: "52c10575f4445c61dd9e0cafcc6356fdd827c4c64dd7945ef3c4105f6b6ac189"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "9.0.0"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -49,6 +57,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.8"
|
version: "1.0.8"
|
||||||
|
equatable:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: equatable
|
||||||
|
sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.7"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -62,6 +78,14 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_bloc:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_bloc
|
||||||
|
sha256: cf51747952201a455a1c840f8171d273be009b932c75093020f9af64f2123e38
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "9.1.1"
|
||||||
flutter_lints:
|
flutter_lints:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@ -75,6 +99,22 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
http:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: http
|
||||||
|
sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.0"
|
||||||
|
http_parser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http_parser
|
||||||
|
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.1.2"
|
||||||
leak_tracker:
|
leak_tracker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -131,6 +171,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.16.0"
|
version: "1.16.0"
|
||||||
|
nested:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: nested
|
||||||
|
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -139,6 +187,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.9.1"
|
||||||
|
provider:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: provider
|
||||||
|
sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.1.5"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -192,6 +248,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.4"
|
version: "0.7.4"
|
||||||
|
typed_data:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: typed_data
|
||||||
|
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.0"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -208,6 +272,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "14.3.1"
|
version: "14.3.1"
|
||||||
|
web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web
|
||||||
|
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.7.2 <4.0.0"
|
dart: ">=3.7.2 <4.0.0"
|
||||||
flutter: ">=3.18.0-18.0.pre.54"
|
flutter: ">=3.18.0-18.0.pre.54"
|
||||||
|
@ -34,6 +34,9 @@ dependencies:
|
|||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
cupertino_icons: ^1.0.8
|
cupertino_icons: ^1.0.8
|
||||||
|
equatable: ^2.0.7
|
||||||
|
flutter_bloc: ^9.1.1
|
||||||
|
http: ^1.4.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user