MCSI-9 About and instruction tab #27

Merged
squid merged 6 commits from MCSI-9_about_and_instruction_tab into main 2025-07-12 05:45:35 +08:00
15 changed files with 313 additions and 40 deletions

5
assets/svg/bug.svg Normal file
View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
<path
d="M256 0c53 0 96 43 96 96l0 3.6c0 15.7-12.7 28.4-28.4 28.4l-135.1 0c-15.7 0-28.4-12.7-28.4-28.4l0-3.6c0-53 43-96 96-96zM41.4 105.4c12.5-12.5 32.8-12.5 45.3 0l64 64c.7 .7 1.3 1.4 1.9 2.1c14.2-7.3 30.4-11.4 47.5-11.4l112 0c17.1 0 33.2 4.1 47.5 11.4c.6-.7 1.2-1.4 1.9-2.1l64-64c12.5-12.5 32.8-12.5 45.3 0s12.5 32.8 0 45.3l-64 64c-.7 .7-1.4 1.3-2.1 1.9c6.2 12 10.1 25.3 11.1 39.5l64.3 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-64 0c0 24.6-5.5 47.8-15.4 68.6c2.2 1.3 4.2 2.9 6 4.8l64 64c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0l-63.1-63.1c-24.5 21.8-55.8 36.2-90.3 39.6L272 240c0-8.8-7.2-16-16-16s-16 7.2-16 16l0 239.2c-34.5-3.4-65.8-17.8-90.3-39.6L86.6 502.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l64-64c1.9-1.9 3.9-3.4 6-4.8C101.5 367.8 96 344.6 96 320l-64 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l64.3 0c1.1-14.1 5-27.5 11.1-39.5c-.7-.6-1.4-1.2-2.1-1.9l-64-64c-12.5-12.5-12.5-32.8 0-45.3z" />
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

5
assets/svg/github.svg Normal file
View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 480 512">
<!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
<path
d="M186.1 328.7c0 20.9-10.9 55.1-36.7 55.1s-36.7-34.2-36.7-55.1 10.9-55.1 36.7-55.1 36.7 34.2 36.7 55.1zM480 278.2c0 31.9-3.2 65.7-17.5 95-37.9 76.6-142.1 74.8-216.7 74.8-75.8 0-186.2 2.7-225.6-74.8-14.6-29-20.2-63.1-20.2-95 0-41.9 13.9-81.5 41.5-113.6-5.2-15.8-7.7-32.4-7.7-48.8 0-21.5 4.9-32.3 14.6-51.8 45.3 0 74.3 9 108.8 36 29-6.9 58.8-10 88.7-10 27 0 54.2 2.9 80.4 9.2 34-26.7 63-35.2 107.8-35.2 9.8 19.5 14.6 30.3 14.6 51.8 0 16.4-2.6 32.7-7.7 48.2 27.5 32.4 39 72.3 39 114.2zm-64.3 50.5c0-43.9-26.7-82.6-73.5-82.6-18.9 0-37 3.4-56 6-14.9 2.3-29.8 3.2-45.1 3.2-15.2 0-30.1-.9-45.1-3.2-18.7-2.6-37-6-56-6-46.8 0-73.5 38.7-73.5 82.6 0 87.8 80.4 101.3 150.4 101.3h48.2c70.3 0 150.6-13.4 150.6-101.3zm-82.6-55.1c-25.8 0-36.7 34.2-36.7 55.1s10.9 55.1 36.7 55.1 36.7-34.2 36.7-55.1-10.9-55.1-36.7-55.1z" />
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

5
assets/svg/send.svg Normal file
View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
<path
d="M498.1 5.6c10.1 7 15.4 19.1 13.5 31.2l-64 416c-1.5 9.7-7.4 18.2-16 23s-18.9 5.4-28 1.6L284 427.7l-68.5 74.1c-8.9 9.7-22.9 12.9-35.2 8.1S160 493.2 160 480l0-83.6c0-4 1.5-7.8 4.2-10.8L331.8 202.8c5.8-6.3 5.6-16-.4-22s-15.7-6.4-22-.7L106 360.8 17.7 316.6C7.1 311.3 .3 300.7 0 288.9s5.9-22.8 16.1-28.7l448-256c10.7-6.1 23.9-5.5 34 1.4z" />
</svg>

After

Width:  |  Height:  |  Size: 582 B

5
assets/svg/youtube.svg Normal file
View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
<!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
<path
d="M549.7 124.1c-6.3-23.7-24.8-42.3-48.3-48.6C458.8 64 288 64 288 64S117.2 64 74.6 75.5c-23.5 6.3-42 24.9-48.3 48.6-11.4 42.9-11.4 132.3-11.4 132.3s0 89.4 11.4 132.3c6.3 23.7 24.8 41.5 48.3 47.8C117.2 448 288 448 288 448s170.8 0 213.4-11.5c23.5-6.3 42-24.2 48.3-47.8 11.4-42.9 11.4-132.3 11.4-132.3s0-89.4-11.4-132.3zm-317.5 213.5V175.2l142.7 81.2-142.7 81.2z" />
</svg>

After

Width:  |  Height:  |  Size: 607 B

View File

@ -8,6 +8,10 @@ abstract class Constants {
static const eulaFileContent = static const eulaFileContent =
'#By changing the setting below to TRUE you are indicating your agreement to our EULA (https://account.mojang.com/documents/minecraft_eula).\neula=true'; '#By changing the setting below to TRUE you are indicating your agreement to our EULA (https://account.mojang.com/documents/minecraft_eula).\neula=true';
static const eulaUrl = 'https://account.mojang.com/documents/minecraft_eula'; static const eulaUrl = 'https://account.mojang.com/documents/minecraft_eula';
static const tutorialVideoUrl = 'https://www.youtube.com/watch?v=yNis5vcueQY';
static const sourceCodeUrl = 'https://git.squidspirit.com/squid/minecraft-server-installer';
static const bugReportUrl = 'https://github.com/an920107/minecraft-server-installer/issues/new';
static const authorEmail = 'squid@squidspirit.com';
static final startScriptFileName = Platform.isWindows ? 'start.bat' : 'start.sh'; static final startScriptFileName = Platform.isWindows ? 'start.bat' : 'start.sh';
} }

View File

@ -0,0 +1,149 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:gap/gap.dart';
import 'package:minecraft_server_installer/main/constants.dart';
import 'package:minecraft_server_installer/main/framework/ui/strings.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:url_launcher/url_launcher.dart';
class AboutTab extends StatelessWidget {
const AboutTab({super.key});
@override
Widget build(BuildContext context) => SizedBox(
width: 460,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Image.asset('assets/img/mcsi_logo.png', width: 100, height: 100),
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
Constants.appName,
style: Theme.of(context)
.textTheme
.headlineMedium
?.copyWith(fontWeight: FontWeight.w900, color: Colors.blueGrey.shade900),
),
FutureBuilder(
future: PackageInfo.fromPlatform(),
builder: (context, snapshot) => Text(
'Version ${snapshot.data?.version ?? ''}',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: Colors.grey.shade700),
),
),
],
),
],
),
const Gap(32),
Container(
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 24),
decoration: BoxDecoration(
color: Colors.blueGrey.shade50,
borderRadius: BorderRadius.circular(8),
border: Border(left: BorderSide(color: Colors.blueGrey.shade300, width: 6)),
),
child: Row(
children: [
Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Icon(Icons.format_quote_rounded, color: Colors.grey.shade700),
),
const Gap(8),
Text(
Strings.textSlogen,
style: Theme.of(context)
.textTheme
.bodyLarge
?.copyWith(fontWeight: FontWeight.w500, color: Colors.grey.shade700),
),
],
),
),
const Gap(32),
Row(
children: [
_actionButton(
onPressed: () => launchUrl(Uri.parse(Constants.tutorialVideoUrl)),
text: Strings.buttonTutorialVideo,
svgAssetName: 'assets/svg/youtube.svg',
),
const Gap(12),
_actionButton(
onPressed: () => launchUrl(Uri.parse(Constants.bugReportUrl)),
text: Strings.buttonBugReport,
svgAssetName: 'assets/svg/bug.svg',
),
const Gap(12),
_actionButton(
onPressed: () => launchUrl(Uri.parse('mailto:${Constants.authorEmail}')),
text: Strings.buttonContactAuthor,
svgAssetName: 'assets/svg/send.svg',
),
const Gap(12),
_actionButton(
onPressed: () => launchUrl(Uri.parse(Constants.sourceCodeUrl)),
text: Strings.buttonSourceCode,
svgAssetName: 'assets/svg/github.svg',
),
],
),
const Spacer(),
Text(
Strings.textCopyright,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: Colors.grey.shade700),
),
],
),
);
Widget _actionButton({
required String text,
required String svgAssetName,
required void Function()? onPressed,
}) =>
Builder(
builder: (context) => Expanded(
child: Material(
color: Colors.transparent,
borderRadius: BorderRadius.circular(8),
child: Ink(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.blueGrey.shade50, width: 2),
),
child: InkWell(
onTap: onPressed,
borderRadius: BorderRadius.circular(8),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 32, horizontal: 16),
child: Column(
children: [
SvgPicture.asset(
svgAssetName,
width: 32,
height: 32,
colorFilter: ColorFilter.mode(Colors.grey.shade800, BlendMode.srcIn),
),
const Gap(12),
Text(
text,
style: Theme.of(context)
.textTheme
.bodyMedium
?.copyWith(fontWeight: FontWeight.w500, color: Colors.grey.shade700),
),
],
),
),
),
),
),
),
);
}

View File

@ -39,7 +39,7 @@ class BasicConfigurationTab extends StatelessWidget {
readOnly: true, readOnly: true,
canRequestFocus: false, canRequestFocus: false,
decoration: InputDecoration( decoration: InputDecoration(
border: OutlineInputBorder(borderRadius: BorderRadius.circular(4)), border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
label: const Text('${Strings.fieldPath} *'), label: const Text('${Strings.fieldPath} *'),
), ),
), ),
@ -50,9 +50,12 @@ class BasicConfigurationTab extends StatelessWidget {
child: OutlinedButton( child: OutlinedButton(
onPressed: () => _browseDirectory(context, initialPath: state.savePath), onPressed: () => _browseDirectory(context, initialPath: state.savePath),
style: OutlinedButton.styleFrom( style: OutlinedButton.styleFrom(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
child: const Padding(
padding: EdgeInsets.symmetric(horizontal: 8),
child: Text(Strings.buttonBrowse),
), ),
child: const Text(Strings.buttonBrowse),
), ),
), ),
], ],
@ -72,7 +75,7 @@ class BasicConfigurationTab extends StatelessWidget {
.add(InstallationConfigurationUpdatedEvent(isEulaAgreed: value ?? false)), .add(InstallationConfigurationUpdatedEvent(isEulaAgreed: value ?? false)),
controlAffinity: ListTileControlAffinity.leading, controlAffinity: ListTileControlAffinity.leading,
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
)), )),
), ),
IconButton( IconButton(
@ -92,7 +95,7 @@ class BasicConfigurationTab extends StatelessWidget {
context.read<InstallationBloc>().add(InstallationConfigurationUpdatedEvent(isGuiEnabled: value)), context.read<InstallationBloc>().add(InstallationConfigurationUpdatedEvent(isGuiEnabled: value)),
controlAffinity: ListTileControlAffinity.leading, controlAffinity: ListTileControlAffinity.leading,
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
), ),
); );
@ -106,7 +109,7 @@ class BasicConfigurationTab extends StatelessWidget {
.add(InstallationConfigurationUpdatedEvent(isCustomRamSizeEnabled: value ?? false)), .add(InstallationConfigurationUpdatedEvent(isCustomRamSizeEnabled: value ?? false)),
controlAffinity: ListTileControlAffinity.leading, controlAffinity: ListTileControlAffinity.leading,
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
), ),
); );
@ -134,6 +137,7 @@ class BasicConfigurationTab extends StatelessWidget {
), ),
), ),
), ),
const Gap(16),
Row( Row(
children: [ children: [
Expanded( Expanded(
@ -143,7 +147,7 @@ class BasicConfigurationTab extends StatelessWidget {
readOnly: true, readOnly: true,
decoration: InputDecoration( decoration: InputDecoration(
label: const Text('${Strings.fieldMinRamSize} (MB)'), label: const Text('${Strings.fieldMinRamSize} (MB)'),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(4)), border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
), ),
), ),
), ),
@ -155,7 +159,7 @@ class BasicConfigurationTab extends StatelessWidget {
readOnly: true, readOnly: true,
decoration: InputDecoration( decoration: InputDecoration(
label: const Text('${Strings.fieldMaxRamSize} (MB)'), label: const Text('${Strings.fieldMaxRamSize} (MB)'),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(4)), border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
), ),
), ),
), ),
@ -175,7 +179,7 @@ class BasicConfigurationTab extends StatelessWidget {
Expanded(child: LinearProgressIndicator(value: state.downloadProgress.value)), Expanded(child: LinearProgressIndicator(value: state.downloadProgress.value)),
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(8))),
onPressed: onPressed:
context.watch<InstallationBloc>().state.canStartToInstall ? () => _downloadServerFile(context) : null, context.watch<InstallationBloc>().state.canStartToInstall ? () => _downloadServerFile(context) : null,
icon: const Icon(Icons.download), icon: const Icon(Icons.download),

View File

@ -9,6 +9,7 @@ import 'package:minecraft_server_installer/main/application/use_case/write_file_
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';
import 'package:minecraft_server_installer/main/framework/storage/installation_file_storage_impl.dart'; import 'package:minecraft_server_installer/main/framework/storage/installation_file_storage_impl.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/vanilla/adapter/gateway/vanilla_repository_impl.dart'; import 'package:minecraft_server_installer/vanilla/adapter/gateway/vanilla_repository_impl.dart';
@ -82,15 +83,39 @@ class MinecraftServerInstaller extends StatelessWidget {
Widget get _body => BlocConsumer<NavigationBloc, NavigationItem>( Widget get _body => BlocConsumer<NavigationBloc, NavigationItem>(
listener: (_, __) {}, listener: (_, __) {},
builder: (_, state) => Padding( builder: (context, state) => AnimatedSwitcher(
padding: const EdgeInsets.all(32),
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),
child: SizedBox( child: Column(
key: ValueKey('tab${state.toString()}'), key: ValueKey('tab${state.toString()}'),
children: [
Container(
padding: const EdgeInsets.symmetric(vertical: 12),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Colors.grey.shade300, width: 1),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
state.title,
style: Theme.of(context)
.textTheme
.titleSmall
?.copyWith(fontWeight: FontWeight.w700, color: Colors.blueGrey.shade900),
),
],
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(32),
child: _tabContent(state), child: _tabContent(state),
), ),
), ),
],
),
), ),
); );
@ -100,8 +125,9 @@ class MinecraftServerInstaller extends StatelessWidget {
return const BasicConfigurationTab(); return const BasicConfigurationTab();
case NavigationItem.modConfiguration: case NavigationItem.modConfiguration:
case NavigationItem.serverProperties: case NavigationItem.serverProperties:
case NavigationItem.about:
return const Placeholder(); return const Placeholder();
case NavigationItem.about:
return const AboutTab();
} }
} }
} }

View File

@ -15,16 +15,8 @@ class SideNavigationBar extends StatefulWidget {
class _SideNavigationBarState extends State<SideNavigationBar> { class _SideNavigationBarState extends State<SideNavigationBar> {
bool _isExpanded = false; bool _isExpanded = false;
PackageInfo? _packageInfo;
double get width => _isExpanded ? 360 : 80; double get width => _isExpanded ? 340 : 80;
@override
void initState() {
super.initState();
PackageInfo.fromPlatform().then((packageInfo) =>
WidgetsBinding.instance.addPostFrameCallback((_) => setState(() => _packageInfo = packageInfo)));
}
@override @override
Widget build(BuildContext context) => AnimatedContainer( Widget build(BuildContext context) => AnimatedContainer(
@ -48,9 +40,9 @@ class _SideNavigationBarState extends State<SideNavigationBar> {
children: [ children: [
_animatedText( _animatedText(
text: Constants.appName, text: Constants.appName,
leading: SizedBox.square( leading: Padding(
dimension: 36, padding: const EdgeInsets.only(right: 4),
child: Image.asset('assets/img/mcsi_logo.png', width: 2048, height: 2048), child: Image.asset('assets/img/mcsi_logo.png', width: 32, height: 32),
), ),
padding: const EdgeInsets.only(left: 4), padding: const EdgeInsets.only(left: 4),
expandedKey: const ValueKey('expandedTitle'), expandedKey: const ValueKey('expandedTitle'),
@ -87,13 +79,16 @@ class _SideNavigationBarState extends State<SideNavigationBar> {
const Gap(8), const Gap(8),
_navigationButton(NavigationItem.about), _navigationButton(NavigationItem.about),
const Spacer(), const Spacer(),
_animatedText( FutureBuilder(
text: 'Version ${_packageInfo?.version ?? ''}', future: PackageInfo.fromPlatform(),
builder: (context, snapshot) => _animatedText(
text: 'Version ${snapshot.data?.version ?? ''}',
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
expandedKey: const ValueKey('expandedVersion'), expandedKey: const ValueKey('expandedVersion'),
collapsedKey: const ValueKey('collapsedVersion'), collapsedKey: const ValueKey('collapsedVersion'),
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
), ),
),
], ],
), ),
); );
@ -173,7 +168,7 @@ class _SideNavigationBarState extends State<SideNavigationBar> {
} }
} }
extension _NavigationItemContent on NavigationItem { extension NavigationItemContent on NavigationItem {
String get title { String get title {
switch (this) { switch (this) {
case NavigationItem.basicConfiguration: case NavigationItem.basicConfiguration:

View File

@ -8,6 +8,10 @@ abstract class Strings {
static const fieldMaxRamSize = '最大 RAM 大小'; static const fieldMaxRamSize = '最大 RAM 大小';
static const buttonStartToInstall = '開始安裝'; static const buttonStartToInstall = '開始安裝';
static const buttonBrowse = '瀏覽'; static const buttonBrowse = '瀏覽';
static const buttonTutorialVideo = '教學影片';
static const buttonBugReport = '問題回報';
static const buttonContactAuthor = '聯絡作者';
static const buttonSourceCode = '原始碼';
static const tabBasicConfiguration = '基本設定'; static const tabBasicConfiguration = '基本設定';
static const tabModConfiguration = '模組設定'; static const tabModConfiguration = '模組設定';
static const tabServerProperties = '伺服器選項'; static const tabServerProperties = '伺服器選項';
@ -15,4 +19,6 @@ abstract class Strings {
static const tabInstallationProgress = '安裝進度'; static const tabInstallationProgress = '安裝進度';
static const tooltipEulaInfo = '點擊查看 EULA 條款'; static const tooltipEulaInfo = '點擊查看 EULA 條款';
static const dialogTitleSelectDirectory = '選擇安裝目錄'; static const dialogTitleSelectDirectory = '選擇安裝目錄';
static const textSlogen = '讓 Minecraft 伺服器安裝變得更簡單!';
static const textCopyright = 'Copyright © 2025 SquidSpirit';
} }

View File

@ -7,8 +7,8 @@ Future<void> main() async {
await windowManager.ensureInitialized(); await windowManager.ensureInitialized();
final windowOptions = const WindowOptions( final windowOptions = const WindowOptions(
size: Size(800, 600), size: Size(900, 600),
minimumSize: Size(800, 600), minimumSize: Size(900, 600),
center: true, center: true,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
skipTaskbar: false, skipTaskbar: false,

View File

@ -17,6 +17,9 @@ class GameVersionDropdown extends StatelessWidget {
enabled: state.gameVersions.isNotEmpty, enabled: state.gameVersions.isNotEmpty,
requestFocusOnTap: false, requestFocusOnTap: false,
expandedInsets: EdgeInsets.zero, expandedInsets: EdgeInsets.zero,
inputDecorationTheme: Theme.of(context)
.inputDecorationTheme
.copyWith(border: OutlineInputBorder(borderRadius: BorderRadius.circular(8))),
label: const Text('${Strings.fieldGameVersion} *'), label: const Text('${Strings.fieldGameVersion} *'),
onSelected: (value) { onSelected: (value) {
if (value != null) { if (value != null) {

View File

@ -22,7 +22,7 @@ static void my_application_activate(GApplication* application) {
gtk_window_set_decorated(window, FALSE); gtk_window_set_decorated(window, FALSE);
gtk_window_set_default_size(window, 800, 600); gtk_window_set_default_size(window, 900, 600);
gtk_widget_show(GTK_WIDGET(window)); gtk_widget_show(GTK_WIDGET(window));
g_autoptr(FlDartProject) project = fl_dart_project_new(); g_autoptr(FlDartProject) project = fl_dart_project_new();

View File

@ -1,6 +1,14 @@
# Generated by pub # Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile # See https://dart.dev/tools/pub/glossary#lockfile
packages: packages:
args:
dependency: transitive
description:
name: args
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
url: "https://pub.dev"
source: hosted
version: "2.7.0"
async: async:
dependency: transitive dependency: transitive
description: description:
@ -126,6 +134,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.28" version: "2.0.28"
flutter_svg:
dependency: "direct main"
description:
name: flutter_svg
sha256: cd57f7969b4679317c17af6fd16ee233c1e60a82ed209d8a475c54fd6fd6f845
url: "https://pub.dev"
source: hosted
version: "2.2.0"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -256,6 +272,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.9.1" version: "1.9.1"
path_parsing:
dependency: transitive
description:
name: path_parsing
sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
petitparser:
dependency: transitive
description:
name: petitparser
sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646"
url: "https://pub.dev"
source: hosted
version: "6.1.0"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -437,6 +469,30 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.4" version: "3.1.4"
vector_graphics:
dependency: transitive
description:
name: vector_graphics
sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6
url: "https://pub.dev"
source: hosted
version: "1.1.19"
vector_graphics_codec:
dependency: transitive
description:
name: vector_graphics_codec
sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146"
url: "https://pub.dev"
source: hosted
version: "1.1.13"
vector_graphics_compiler:
dependency: transitive
description:
name: vector_graphics_compiler
sha256: "557a315b7d2a6dbb0aaaff84d857967ce6bdc96a63dc6ee2a57ce5a6ee5d3331"
url: "https://pub.dev"
source: hosted
version: "1.1.17"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
@ -477,6 +533,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.0" version: "0.5.0"
xml:
dependency: transitive
description:
name: xml
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
url: "https://pub.dev"
source: hosted
version: "6.5.0"
sdks: sdks:
dart: ">=3.7.0 <4.0.0" dart: ">=3.7.0 <4.0.0"
flutter: ">=3.27.0" flutter: ">=3.27.0"

View File

@ -37,6 +37,7 @@ dependencies:
equatable: ^2.0.7 equatable: ^2.0.7
file_picker: ^10.2.0 file_picker: ^10.2.0
flutter_bloc: ^9.1.1 flutter_bloc: ^9.1.1
flutter_svg: ^2.2.0
gap: ^3.0.1 gap: ^3.0.1
http: ^1.4.0 http: ^1.4.0
package_info_plus: ^8.3.0 package_info_plus: ^8.3.0
@ -71,6 +72,7 @@ flutter:
# - images/a_dot_ham.jpeg # - images/a_dot_ham.jpeg
assets: assets:
- assets/img/ - assets/img/
- assets/svg/
# An image asset can refer to one or more resolution-specific "variants", see # An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/to/resolution-aware-images # https://flutter.dev/to/resolution-aware-images