MCSI-1 feat: version selection
This commit is contained in:
parent
ecee7ac16f
commit
e8ad6592f5
@ -22,7 +22,8 @@ linter:
|
||||
# producing the lint.
|
||||
rules:
|
||||
# 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
|
||||
# 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:minecraft_server_installer/main/framework/ui/basic_configuration_tab.dart';
|
||||
|
||||
class MinecraftServerInstaller extends StatelessWidget {
|
||||
const MinecraftServerInstaller({super.key});
|
||||
|
||||
@override
|
||||
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: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() {
|
||||
final apiService = GameVersionApiServiceImpl();
|
||||
apiService.fetchGameVersionList();
|
||||
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"
|
||||
source: hosted
|
||||
version: "2.12.0"
|
||||
bloc:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: bloc
|
||||
sha256: "52c10575f4445c61dd9e0cafcc6356fdd827c4c64dd7945ef3c4105f6b6ac189"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.0.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -49,6 +57,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -62,6 +78,14 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
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:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@ -75,6 +99,22 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -131,6 +171,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.16.0"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: nested
|
||||
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -139,6 +187,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.1"
|
||||
provider:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: provider
|
||||
sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.5"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@ -192,6 +248,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -208,6 +272,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.3.1"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web
|
||||
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
sdks:
|
||||
dart: ">=3.7.2 <4.0.0"
|
||||
flutter: ">=3.18.0-18.0.pre.54"
|
||||
|
@ -34,6 +34,9 @@ dependencies:
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
cupertino_icons: ^1.0.8
|
||||
equatable: ^2.0.7
|
||||
flutter_bloc: ^9.1.1
|
||||
http: ^1.4.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
Loading…
x
Reference in New Issue
Block a user