280 lines
8.3 KiB
Dart
280 lines
8.3 KiB
Dart
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),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
}
|