Initial commit with gitignore

This commit is contained in:
2026-01-13 14:11:59 +09:00
parent d01c0b781a
commit b302e25132
143 changed files with 7030 additions and 0 deletions

View File

@@ -0,0 +1,279 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../services/formation_generator.dart';
import '../data/league_data.dart';
import '../data/cardtype_data.dart';
import 'result_screen.dart';
import '../models/player.dart';
import 'pool_screen.dart';
const allRoles = [
'GK',
'CB', 'LSB', 'RSB',
'DMF', 'CMF', 'OMF', 'LMF', 'RMF',
'CF', 'ST', 'RWG', 'LWG',
];
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
static const _poolKey = 'player_pool_v1';
ConstraintMode _mode = ConstraintMode.playstyle;
bool _rareStyleOn = false;
String? _selectedLeague;
String? _selectedCardType;
// 保存対象:選手プール
List<Map<String, dynamic>> _playerPool = [];
// ★チムスタ重み0〜100の重み。合計は気にしない
final Map<String, int> _teamStyleWeights = {
'ポゼッション': 50,
'ショートカウンター': 50,
'ロングカウンター': 50,
'サイドアタック': 50,
'ロングボール': 50,
};
@override
void initState() {
super.initState();
_loadPool();
}
Future<void> _loadPool() async {
final prefs = await SharedPreferences.getInstance();
final raw = prefs.getString(_poolKey);
if (raw == null || raw.isEmpty) return;
try {
final decoded = jsonDecode(raw) as List;
setState(() {
_playerPool = decoded
.map((e) => {
'name': (e['name'] ?? '').toString(),
'positions': List<String>.from(e['positions'] ?? const []),
})
.toList();
});
} catch (_) {
// 破損時は無視
}
}
Future<void> _savePool() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_poolKey, jsonEncode(_playerPool));
}
Future<void> _openPoolManager() async {
// Map -> Player
final currentPlayers = _playerPool.map((m) => Player.fromMap(m)).toList();
final updated = await Navigator.push<List<Player>>(
context,
MaterialPageRoute(
builder: (_) => PoolScreen(initial: currentPlayers),
),
);
if (updated != null) {
final mapped = updated.map((p) => p.toMap()).toList();
setState(() => _playerPool = mapped);
await _savePool();
}
}
// ★チムスタスライダー部品
Widget _teamStyleSlider(String label) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'$label : ${_teamStyleWeights[label]}',
style: const TextStyle(color: Colors.white),
),
Slider(
value: (_teamStyleWeights[label] ?? 0).toDouble(),
min: 0,
max: 100,
divisions: 100,
onChanged: (v) => setState(() {
_teamStyleWeights[label] = v.round();
}),
),
],
);
}
void _goResult() {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => ResultScreen(
mode: _mode,
rareStyleOn: _rareStyleOn,
selectedLeague: _selectedLeague,
selectedCardType: _selectedCardType,
playerPool: _playerPool,
teamStyleWeights: _teamStyleWeights, // ★追加Resultへ渡す
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.green[900],
appBar: AppBar(
title: const Text('efootball スカッドメーカー'),
backgroundColor: Colors.green[900],
actions: [
IconButton(
onPressed: _openPoolManager,
icon: const Icon(Icons.people_alt),
tooltip: '選手プール',
),
],
),
body: ListView(
padding: const EdgeInsets.all(12),
children: [
Row(
children: [
Expanded(
child: Text(
'登録選手: ${_playerPool.length}',
style: const TextStyle(color: Colors.white70),
),
),
TextButton(
onPressed: _openPoolManager,
child: const Text('選手プール'),
),
],
),
const SizedBox(height: 8),
DropdownButtonFormField<ConstraintMode>(
value: _mode,
decoration: const InputDecoration(
labelText: '遊び方(縛り)',
filled: true,
),
items: const [
DropdownMenuItem(
value: ConstraintMode.playstyle,
child: Text('プレースタイル縛り'),
),
DropdownMenuItem(
value: ConstraintMode.league,
child: Text('リーグ縛り'),
),
DropdownMenuItem(
value: ConstraintMode.cardType,
child: Text('カードタイプ縛り'),
),
DropdownMenuItem(
value: ConstraintMode.pool,
child: Text('選手プール抽選'),
),
],
onChanged: (v) {
if (v == null) return;
setState(() {
_mode = v;
if (_mode != ConstraintMode.league) _selectedLeague = null;
if (_mode != ConstraintMode.cardType) _selectedCardType = null;
});
},
),
const SizedBox(height: 10),
if (_mode == ConstraintMode.playstyle)
SwitchListTile(
title: const Text(
'希少なプレースタイルを出したい時にON',
style: TextStyle(color: Colors.white),
),
value: _rareStyleOn,
onChanged: (v) => setState(() => _rareStyleOn = v),
),
if (_mode == ConstraintMode.league)
DropdownButtonFormField<String?>(
value: _selectedLeague,
decoration: const InputDecoration(
labelText: 'リーグ(ランダム=ポジション別)',
filled: true,
),
items: [
const DropdownMenuItem<String?>(
value: null,
child: Text('ランダム'),
),
...leagues.map(
(l) => DropdownMenuItem<String?>(value: l, child: Text(l)),
),
],
onChanged: (v) => setState(() => _selectedLeague = v),
),
if (_mode == ConstraintMode.cardType)
DropdownButtonFormField<String?>(
value: _selectedCardType,
decoration: const InputDecoration(
labelText: 'カードタイプ(ランダム=ポジション別)',
filled: true,
),
items: [
const DropdownMenuItem<String?>(
value: null,
child: Text('ランダム'),
),
...cardTypes.map(
(c) => DropdownMenuItem<String?>(value: c, child: Text(c)),
),
],
onChanged: (v) => setState(() => _selectedCardType = v),
),
// ★チムスタ確率UI
const SizedBox(height: 12),
const Text(
'チームスタイル確率(重み)',
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
),
_teamStyleSlider('ポゼッション'),
_teamStyleSlider('ショートカウンター'),
_teamStyleSlider('ロングカウンター'),
_teamStyleSlider('サイドアタック'),
_teamStyleSlider('ロングボール'),
const SizedBox(height: 14),
ElevatedButton.icon(
onPressed: _goResult,
icon: const Icon(Icons.arrow_forward),
label: const Text('結果を見る(抽選)'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white,
foregroundColor: Colors.green[900],
padding: const EdgeInsets.symmetric(vertical: 14),
),
),
],
),
);
}
}