changed everything, added theme, added gameboard fixed minor bugs
parent
d7d42dd689
commit
f4939c62d7
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"java.configuration.updateBuildConfiguration": "interactive"
|
||||||
|
}
|
|
@ -26,6 +26,6 @@ subprojects {
|
||||||
project.evaluationDependsOn(':app')
|
project.evaluationDependsOn(':app')
|
||||||
}
|
}
|
||||||
|
|
||||||
task clean(type: Delete) {
|
tasks.register("clean", Delete) {
|
||||||
delete rootProject.buildDir
|
delete rootProject.buildDir
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,22 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:werwolf/screens/playerregistry.dart';
|
import 'package:werwolf/screens/playerregistry.dart';
|
||||||
|
import 'package:werwolf/theme/theme.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(MaterialApp(
|
runApp(
|
||||||
// theme: ThemeData.dark(),
|
const MyApp(),
|
||||||
theme: ThemeData(
|
);
|
||||||
colorScheme: ColorScheme.fromSwatch()
|
}
|
||||||
.copyWith(primary: const Color.fromARGB(255, 29, 29, 29)),
|
|
||||||
scaffoldBackgroundColor: Colors.grey[800],
|
class MyApp extends StatelessWidget {
|
||||||
),
|
const MyApp({super.key});
|
||||||
darkTheme: ThemeData.dark(),
|
|
||||||
home: const PlayerRegistry(),
|
@override
|
||||||
));
|
Widget build(BuildContext context) {
|
||||||
|
return MaterialApp(
|
||||||
|
theme: halloweenTheme,
|
||||||
|
home: PlayerRegistry(),
|
||||||
|
debugShowCheckedModeBanner: false,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,8 @@ class Game {
|
||||||
}
|
}
|
||||||
randomRoles.shuffle();
|
randomRoles.shuffle();
|
||||||
for (var playerName in playernames) {
|
for (var playerName in playernames) {
|
||||||
players.add(Player(name: playerName, role: randomRoles.last));
|
players
|
||||||
|
.add(Player(name: playerName, role: randomRoles.last, isDead: false));
|
||||||
randomRoles.removeLast();
|
randomRoles.removeLast();
|
||||||
}
|
}
|
||||||
return players;
|
return players;
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'package:werwolf/models/role.dart';
|
||||||
class Player {
|
class Player {
|
||||||
String name;
|
String name;
|
||||||
Role role;
|
Role role;
|
||||||
|
bool isDead;
|
||||||
|
|
||||||
Player({required this.name, required this.role});
|
Player({required this.name, required this.role, required this.isDead});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import 'package:flip_card/flip_card_controller.dart';
|
import 'package:flip_card/flip_card_controller.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flip_card/flip_card.dart';
|
import 'package:flip_card/flip_card.dart';
|
||||||
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
|
import 'package:werwolf/screens/gameboard.dart';
|
||||||
|
|
||||||
import '../models/player.dart';
|
import '../models/player.dart';
|
||||||
import '../models/role.dart';
|
import '../models/role.dart';
|
||||||
|
@ -37,29 +39,26 @@ class _FlipingCardState extends State<FlipingCard> {
|
||||||
speed: 300,
|
speed: 300,
|
||||||
onFlipDone: (status) {},
|
onFlipDone: (status) {},
|
||||||
front: Container(
|
front: Container(
|
||||||
decoration: const BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Color(0xFF006666),
|
color: Theme.of(context).colorScheme.primary,
|
||||||
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
child: Text(
|
child: Text(
|
||||||
widget.players[index].name,
|
widget.players[index].name,
|
||||||
|
style: Theme.of(context).textTheme.headlineMedium,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.displayMedium
|
|
||||||
?.copyWith(color: Colors.white),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text('Klick um deine Rolle zu sehen!',
|
Text(
|
||||||
textAlign: TextAlign.center,
|
'Klick um deine Rolle zu sehen!',
|
||||||
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
|
textAlign: TextAlign.center,
|
||||||
color: const Color.fromARGB(255, 202, 202, 202))),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -67,22 +66,19 @@ class _FlipingCardState extends State<FlipingCard> {
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: widget.players[index].role != Role.werwolf
|
color: widget.players[index].role != Role.werwolf
|
||||||
? const Color(0xFF006666)
|
? const Color(0xFF006666)
|
||||||
: Color.fromARGB(255, 100, 21, 15),
|
: const Color.fromARGB(255, 100, 21, 15),
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8.0)),
|
borderRadius: const BorderRadius.all(Radius.circular(8.0)),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
child: Text(
|
child: Text(
|
||||||
widget.players[index].role.stringValue,
|
widget.players[index].role.stringValue,
|
||||||
|
style: Theme.of(context).textTheme.headlineMedium,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.displaySmall
|
|
||||||
?.copyWith(color: Colors.white),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -98,6 +94,12 @@ class _FlipingCardState extends State<FlipingCard> {
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text("Werwolf"),
|
title: const Text("Werwolf"),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
|
leading: IconButton(
|
||||||
|
icon: const Icon(FontAwesomeIcons.xmark),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.popUntil(context, ModalRoute.withName('/'));
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
@ -105,18 +107,12 @@ class _FlipingCardState extends State<FlipingCard> {
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Expanded(child: _renderContent(context)),
|
Expanded(child: _renderContent(context)),
|
||||||
Container(
|
Container(
|
||||||
color: const Color.fromARGB(255, 29, 29, 29),
|
padding: EdgeInsets.only(bottom: 15),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
style: OutlinedButton.styleFrom(
|
|
||||||
foregroundColor: Colors.red,
|
|
||||||
side: const BorderSide(
|
|
||||||
color: Colors.red,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (index > 0 && index <= widget.players.length) {
|
if (index > 0 && index <= widget.players.length) {
|
||||||
|
@ -129,13 +125,7 @@ class _FlipingCardState extends State<FlipingCard> {
|
||||||
},
|
},
|
||||||
child: const Text("Zurück"),
|
child: const Text("Zurück"),
|
||||||
),
|
),
|
||||||
OutlinedButton(
|
ElevatedButton(
|
||||||
style: OutlinedButton.styleFrom(
|
|
||||||
foregroundColor: const Color.fromARGB(255, 40, 168, 168),
|
|
||||||
side: const BorderSide(
|
|
||||||
color: Color.fromARGB(255, 40, 168, 168),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (index >= 0 && index < widget.players.length - 1) {
|
if (index >= 0 && index < widget.players.length - 1) {
|
||||||
|
@ -143,10 +133,20 @@ class _FlipingCardState extends State<FlipingCard> {
|
||||||
if (!_controller.state!.isFront) {
|
if (!_controller.state!.isFront) {
|
||||||
_controller.toggleCardWithoutAnimation();
|
_controller.toggleCardWithoutAnimation();
|
||||||
}
|
}
|
||||||
|
} else if (index == widget.players.length - 1) {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) =>
|
||||||
|
PlayerGridView(players: widget.players),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: const Text("Nächster Spieler"),
|
child: Text(index != widget.players.length - 1
|
||||||
|
? "Nächster Spieler"
|
||||||
|
: "Spiel anfangen!"),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -0,0 +1,225 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
|
import '../models/player.dart';
|
||||||
|
import '../models/role.dart';
|
||||||
|
|
||||||
|
class PlayerGridView extends StatefulWidget {
|
||||||
|
final List<Player> players;
|
||||||
|
|
||||||
|
const PlayerGridView({required this.players, Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_PlayerGridViewState createState() => _PlayerGridViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PlayerGridViewState extends State<PlayerGridView> {
|
||||||
|
bool isNight = true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
isNight ? Icons.nights_stay : Icons.wb_sunny,
|
||||||
|
size: 24,
|
||||||
|
color: isNight ? Colors.grey[300] : Colors.yellow,
|
||||||
|
),
|
||||||
|
SizedBox(width: 10),
|
||||||
|
Text(
|
||||||
|
isNight ? 'Nacht' : 'Tag',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
centerTitle: true,
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.info),
|
||||||
|
onPressed: () {
|
||||||
|
_showRolesDialog();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
leading: IconButton(
|
||||||
|
icon: const Icon(FontAwesomeIcons.xmark),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.popUntil(context, ModalRoute.withName('/'));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: Container(
|
||||||
|
color: isNight
|
||||||
|
? const Color(0xff2d2d2d)
|
||||||
|
: const Color.fromARGB(255, 178, 203, 214),
|
||||||
|
padding: const EdgeInsets.only(left: 15, right: 15),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: GridView.builder(
|
||||||
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
crossAxisCount: 2,
|
||||||
|
mainAxisSpacing: 10,
|
||||||
|
crossAxisSpacing: 10,
|
||||||
|
),
|
||||||
|
itemCount: widget.players.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
widget.players[index];
|
||||||
|
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
if (!widget.players[index].isDead) {
|
||||||
|
_killPlayer(widget.players[index]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Card(
|
||||||
|
color: widget.players[index].isDead
|
||||||
|
? Colors.grey
|
||||||
|
: Theme.of(context).colorScheme.primary,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
widget.players[index].name,
|
||||||
|
style: TextStyle(fontSize: 24),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
maxLines: 3,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
if (widget.players[index].isDead)
|
||||||
|
Icon(Icons.close, color: Colors.red, size: 48),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Divider(
|
||||||
|
height: 1,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(bottom: 15, top: 15),
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: _changePhase,
|
||||||
|
child: Text(isNight ? 'Tag skippen' : 'Nacht skippen'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _killPlayer(Player player) {
|
||||||
|
if (isNight) {
|
||||||
|
if (player.role != Role.werwolf) {
|
||||||
|
player.isDead = true;
|
||||||
|
_checkWinCondition();
|
||||||
|
isNight = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
player.isDead = true;
|
||||||
|
_checkWinCondition();
|
||||||
|
if (player.role == Role.joker) {
|
||||||
|
_showWinDialog('Der Joker hat gewonnen!');
|
||||||
|
}
|
||||||
|
isNight = true;
|
||||||
|
}
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _changePhase() {
|
||||||
|
if (isNight) {
|
||||||
|
isNight = false;
|
||||||
|
} else {
|
||||||
|
isNight = true;
|
||||||
|
}
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _checkWinCondition() {
|
||||||
|
int countWolves = widget.players
|
||||||
|
.where((player) => !player.isDead && player.role == Role.werwolf)
|
||||||
|
.length;
|
||||||
|
int countVillagers = widget.players
|
||||||
|
.where((player) => !player.isDead && player.role != Role.werwolf)
|
||||||
|
.length;
|
||||||
|
|
||||||
|
if (countWolves == 0) {
|
||||||
|
_showWinDialog('Die Dorfbewohner haben gewonnen!');
|
||||||
|
} else if (countWolves >= countVillagers) {
|
||||||
|
_showWinDialog('Die Werwölfe haben gewonnen!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showWinDialog(String message) {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text('Spielende'),
|
||||||
|
content: Text(message),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
child: Text('Spiel beenden'),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.popUntil(context, ModalRoute.withName('/'));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showRolesDialog() {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text('Spielerrollen'),
|
||||||
|
content: Container(
|
||||||
|
width: double.maxFinite,
|
||||||
|
child: ListView.builder(
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemCount: widget.players.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final player = widget.players[index];
|
||||||
|
return ListTile(
|
||||||
|
title: Text(
|
||||||
|
player.name,
|
||||||
|
style: Theme.of(context).textTheme.labelLarge,
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
player.role.name,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
child: Text('OK'),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,74 +21,91 @@ class _PlayerRegistryState extends State<PlayerRegistry> {
|
||||||
title: const Text("Werwolf"),
|
title: const Text("Werwolf"),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Padding(
|
||||||
children: [
|
padding: const EdgeInsets.all(8.0),
|
||||||
TextField(
|
child: Column(
|
||||||
key: _formKey,
|
children: [
|
||||||
controller: _playerController,
|
Padding(
|
||||||
decoration: InputDecoration(
|
padding: const EdgeInsets.all(15),
|
||||||
errorText: _errorMessage == "" ? null : _errorMessage,
|
child: TextField(
|
||||||
labelText: 'Spielername',
|
key: _formKey,
|
||||||
labelStyle: const TextStyle(
|
controller: _playerController,
|
||||||
color: Colors.white,
|
decoration: InputDecoration(
|
||||||
|
errorText: _errorMessage == "" ? null : _errorMessage,
|
||||||
|
labelText: 'Spielername',
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Theme.of(context).colorScheme.primary),
|
||||||
|
),
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Theme.of(context).colorScheme.primary),
|
||||||
|
),
|
||||||
|
errorBorder: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Theme.of(context).colorScheme.secondary),
|
||||||
|
),
|
||||||
|
focusedErrorBorder: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Theme.of(context).colorScheme.secondary),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onSubmitted: (value) {
|
||||||
|
setState(() {
|
||||||
|
if (_playerController.text.isEmpty) {
|
||||||
|
_errorMessage = "Spielername ist leer!";
|
||||||
|
} else if (playernames.contains(value)) {
|
||||||
|
_errorMessage = "Dieser Spieler existiert bereits";
|
||||||
|
_playerController.clear();
|
||||||
|
} else {
|
||||||
|
_errorMessage = "";
|
||||||
|
_playerController.clear();
|
||||||
|
playernames.add(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
style: const TextStyle(color: Colors.white),
|
Expanded(
|
||||||
onSubmitted: (value) {
|
child: ListView.builder(
|
||||||
setState(() {
|
itemCount: playernames.length,
|
||||||
if (_playerController.text.isEmpty) {
|
itemBuilder: (context, index) {
|
||||||
_errorMessage = "Spielername ist leer!";
|
return ListTile(
|
||||||
} else if (playernames.contains(value)) {
|
title: Text(
|
||||||
_errorMessage = "Dieser Spieler existiert bereits";
|
playernames[index],
|
||||||
_playerController.clear();
|
),
|
||||||
} else {
|
trailing: IconButton(
|
||||||
_errorMessage = "";
|
onPressed: () {
|
||||||
_playerController.clear();
|
setState(() {
|
||||||
playernames.add(value);
|
playernames.remove(playernames[index]);
|
||||||
}
|
});
|
||||||
});
|
},
|
||||||
},
|
icon: const Icon(Icons.remove)),
|
||||||
),
|
);
|
||||||
Expanded(
|
},
|
||||||
child: ListView.builder(
|
),
|
||||||
itemCount: playernames.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
return ListTile(
|
|
||||||
title: Text(
|
|
||||||
playernames[index],
|
|
||||||
style: const TextStyle(color: Colors.white),
|
|
||||||
),
|
|
||||||
tileColor: Colors.grey,
|
|
||||||
trailing: IconButton(
|
|
||||||
onPressed: () {
|
|
||||||
setState(() {
|
|
||||||
playernames.remove(playernames[index]);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.remove, color: Colors.white)),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
ElevatedButton(
|
||||||
ElevatedButton(
|
onPressed: () {
|
||||||
onPressed: () {
|
if (playernames.length >= 6) {
|
||||||
if (playernames.length >= 6) {
|
Navigator.push(
|
||||||
Navigator.push(
|
context,
|
||||||
context,
|
MaterialPageRoute(
|
||||||
MaterialPageRoute(
|
builder: (context) => GameSettings(
|
||||||
builder: (context) => GameSettings(
|
playernames: playernames,
|
||||||
playernames: playernames,
|
),
|
||||||
),
|
));
|
||||||
));
|
} else {
|
||||||
} else {
|
setState(() {
|
||||||
setState(() {
|
_errorMessage = "Es müssen mindestens 6 Spieler sein!";
|
||||||
_errorMessage = "Es müssen mindestens 6 Spieler sein!";
|
});
|
||||||
});
|
}
|
||||||
}
|
},
|
||||||
},
|
child: const Text('Spiel einstellen'),
|
||||||
child: const Text('Spiel einstellen'),
|
),
|
||||||
),
|
Padding(padding: EdgeInsets.all(30))
|
||||||
],
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:werwolf/screens/flippingcards.dart';
|
import 'package:werwolf/screens/flippingcards.dart';
|
||||||
|
|
||||||
import '../models/game.dart';
|
import '../models/game.dart';
|
||||||
|
@ -14,6 +15,7 @@ class GameSettings extends StatefulWidget {
|
||||||
|
|
||||||
class _GameSettingsState extends State<GameSettings> {
|
class _GameSettingsState extends State<GameSettings> {
|
||||||
late Game game;
|
late Game game;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
game = Game(playernames: widget.playernames);
|
game = Game(playernames: widget.playernames);
|
||||||
|
@ -24,20 +26,28 @@ class _GameSettingsState extends State<GameSettings> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text("Werwolf"),
|
title: Text(
|
||||||
|
"Werwolf",
|
||||||
|
style: Theme.of(context).textTheme.titleLarge, // Apply text theme
|
||||||
|
),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
|
leading: IconButton(
|
||||||
|
icon: const Icon(FontAwesomeIcons.xmark),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.popUntil(context, ModalRoute.withName('/'));
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
body: Padding(
|
body: Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(30.0, 40.0, 30.0, 0.0),
|
padding: const EdgeInsets.fromLTRB(30.0, 40.0, 30.0, 0.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Anzahl der Spieler ${widget.playernames.length}", // hier muss noch die anzahl der spieler hin
|
"Anzahl der Spieler ${widget.playernames.length}",
|
||||||
style: const TextStyle(color: Colors.white, fontSize: 18),
|
style: Theme.of(context).textTheme.titleLarge, // Apply text theme
|
||||||
),
|
),
|
||||||
const Divider(
|
const Divider(
|
||||||
height: 60,
|
height: 60,
|
||||||
color: Colors.grey,
|
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
@ -45,31 +55,37 @@ class _GameSettingsState extends State<GameSettings> {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Anzahl der Werwölfe ${game.getWolves()}",
|
"Anzahl der Werwölfe ${game.getWolves()}",
|
||||||
style: const TextStyle(color: Colors.white, fontSize: 18),
|
style:
|
||||||
|
Theme.of(context).textTheme.bodyLarge, // Apply text theme
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
game.decrementWolves();
|
game.decrementWolves();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.remove, color: Colors.white)),
|
icon: const Icon(Icons.remove, color: Colors.white),
|
||||||
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
game.incrementWolves();
|
game.incrementWolves();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.add, color: Colors.white)),
|
icon: const Icon(Icons.add, color: Colors.white),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const Divider(
|
const Divider(
|
||||||
height: 60,
|
height: 60,
|
||||||
color: Colors.grey,
|
|
||||||
),
|
),
|
||||||
const Text(
|
Padding(
|
||||||
"Spezielle Rollen",
|
padding: const EdgeInsets.only(top: 8.0, bottom: 20),
|
||||||
style: TextStyle(color: Colors.white, fontSize: 18),
|
child: Text(
|
||||||
|
"Spezielle Rollen",
|
||||||
|
style:
|
||||||
|
Theme.of(context).textTheme.titleLarge, // Apply text theme
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
|
@ -81,20 +97,18 @@ class _GameSettingsState extends State<GameSettings> {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
role.stringValue,
|
role.stringValue,
|
||||||
style:
|
style: Theme.of(context)
|
||||||
const TextStyle(color: Colors.white, fontSize: 16),
|
.textTheme
|
||||||
|
.bodyLarge, // Apply text theme
|
||||||
),
|
),
|
||||||
trailing: Switch(
|
trailing: Switch(
|
||||||
value: game.specialRoles[role],
|
value: game.specialRoles[role],
|
||||||
trackColor: const MaterialStatePropertyAll<Color>(
|
onChanged: (bool value) {
|
||||||
Color.fromARGB(255, 189, 189, 189)),
|
setState(() {
|
||||||
thumbColor: const MaterialStatePropertyAll<Color>(
|
game.specialRoles[role] = value;
|
||||||
Colors.black),
|
});
|
||||||
onChanged: (bool value) {
|
},
|
||||||
setState(() {
|
),
|
||||||
game.specialRoles[role] = value;
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return Container();
|
return Container();
|
||||||
|
@ -104,14 +118,18 @@ class _GameSettingsState extends State<GameSettings> {
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) =>
|
builder: (context) =>
|
||||||
FlipingCard(players: game.getAllPlayers()),
|
FlipingCard(players: game.getAllPlayers()),
|
||||||
));
|
),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
child: const Text('Spiel starten!'),
|
child: Text(
|
||||||
|
'Spiel starten!',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
const Padding(padding: EdgeInsets.all(30)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
ThemeData halloweenTheme = ThemeData(
|
||||||
|
useMaterial3: true,
|
||||||
|
brightness: Brightness.dark,
|
||||||
|
colorScheme: ColorScheme.dark(
|
||||||
|
surface: const Color(0xff2d2d2d), // Dark grey for a spooky base
|
||||||
|
primary: const Color(0xffff7518), // Halloween orange
|
||||||
|
secondary: const Color(0xff8b0000), // Deep red for a sinister touch
|
||||||
|
tertiary: Colors.black, // Black for an eerie contrast
|
||||||
|
),
|
||||||
|
scaffoldBackgroundColor: const Color(0xff2d2d2d), // Match the surface color
|
||||||
|
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||||
|
style: ButtonStyle(
|
||||||
|
backgroundColor: WidgetStateProperty.all<Color>(
|
||||||
|
const Color(0xffff7518), // Halloween orange
|
||||||
|
),
|
||||||
|
foregroundColor: WidgetStateProperty.all<Color>(
|
||||||
|
Colors.black, // Text color to contrast with button background
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
iconTheme: const IconThemeData(
|
||||||
|
color: Color(0xffff7518), // Halloween orange
|
||||||
|
),
|
||||||
|
chipTheme: ChipThemeData(
|
||||||
|
backgroundColor: const Color(0xff8b0000), // Deep red
|
||||||
|
selectedColor: const Color(0xffff7518), // Halloween orange
|
||||||
|
labelStyle: TextStyle(
|
||||||
|
color: Colors.white, // Text color for better readability
|
||||||
|
),
|
||||||
|
),
|
||||||
|
sliderTheme: SliderThemeData(
|
||||||
|
activeTickMarkColor: const Color(0xffff7518), // Halloween orange
|
||||||
|
activeTrackColor: const Color(0xffff7518), // Halloween orange
|
||||||
|
thumbColor: const Color(0xffff7518), // Halloween orange
|
||||||
|
valueIndicatorTextStyle: TextStyle(
|
||||||
|
color: Colors.black, // Text color for the value indicator
|
||||||
|
),
|
||||||
|
),
|
||||||
|
dividerTheme: DividerThemeData(
|
||||||
|
color: Colors.white, // Halloween orange
|
||||||
|
thickness: 1.0, // Set the thickness of the divider
|
||||||
|
),
|
||||||
|
textTheme: TextTheme(
|
||||||
|
displayLarge: TextStyle(
|
||||||
|
color: Colors.white, // Halloween orange
|
||||||
|
fontSize: 32.0,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
displayMedium: TextStyle(
|
||||||
|
color: Colors.white, // Deep red
|
||||||
|
fontSize: 28.0,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
displaySmall: TextStyle(
|
||||||
|
color: Colors.white, // White for contrast
|
||||||
|
fontSize: 24.0,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
bodyLarge: TextStyle(
|
||||||
|
color: Colors.white, // Halloween orange
|
||||||
|
fontSize: 16.0,
|
||||||
|
),
|
||||||
|
bodyMedium: TextStyle(
|
||||||
|
color: Colors.white, // White for contrast
|
||||||
|
fontSize: 14.0,
|
||||||
|
),
|
||||||
|
bodySmall: TextStyle(
|
||||||
|
color: Colors.white, // Deep red
|
||||||
|
fontSize: 12.0,
|
||||||
|
),
|
||||||
|
labelLarge: TextStyle(
|
||||||
|
color: Colors.white, // Black for contrast
|
||||||
|
fontSize: 16.0,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
89
pubspec.lock
89
pubspec.lock
|
@ -5,10 +5,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: async
|
name: async
|
||||||
sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0
|
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.10.0"
|
version: "2.11.0"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -37,10 +37,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: collection
|
name: collection
|
||||||
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
|
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.1"
|
version: "1.18.0"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -75,54 +75,78 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
js:
|
font_awesome_flutter:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: js
|
name: font_awesome_flutter
|
||||||
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
|
sha256: "275ff26905134bcb59417cf60ad979136f1f8257f2f449914b2c3e05bbb4cd6f"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.7"
|
version: "10.7.0"
|
||||||
|
leak_tracker:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker
|
||||||
|
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.0.5"
|
||||||
|
leak_tracker_flutter_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_flutter_testing
|
||||||
|
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.5"
|
||||||
|
leak_tracker_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_testing
|
||||||
|
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.1"
|
||||||
lints:
|
lints:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: lints
|
name: lints
|
||||||
sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593"
|
sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.1.1"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: c94db23593b89766cda57aab9ac311e3616cf87c6fa4e9749df032f66f30dcb8
|
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.14"
|
version: "0.12.16+1"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
|
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0"
|
version: "0.11.1"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "12307e7f0605ce3da64cf0db90e5fcab0869f3ca03f76be6bb2991ce0a55e82b"
|
sha256: "25dfcaf170a0190f47ca6355bdd4552cb8924b430512ff0cafb8db9bd41fe33b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.0"
|
version: "1.14.0"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path
|
name: path
|
||||||
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
|
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.3"
|
version: "1.9.0"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -132,26 +156,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_span
|
name: source_span
|
||||||
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
|
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.10.0"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stack_trace
|
name: stack_trace
|
||||||
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
|
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.11.0"
|
version: "1.11.1"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stream_channel
|
name: stream_channel
|
||||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.2"
|
||||||
string_scanner:
|
string_scanner:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -172,10 +196,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "6182294da5abf431177fccc1ee02401f6df30f766bc6130a0852c6b6d7ee6b2d"
|
sha256: "2419f20b0c8677b2d67c8ac4d1ac7372d862dc6c460cdbb052b40155408cd794"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.4.18"
|
version: "0.7.1"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -184,5 +208,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.1.4"
|
||||||
|
vm_service:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vm_service
|
||||||
|
sha256: "7475cb4dd713d57b6f7464c0e13f06da0d535d8b2067e188962a59bac2cf280b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "14.2.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.0.0-313.0.dev <4.0.0"
|
dart: ">=3.3.0 <4.0.0"
|
||||||
|
flutter: ">=3.18.0-18.0.pre.54"
|
||||||
|
|
|
@ -8,6 +8,7 @@ environment:
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
flip_card: ^0.7.0
|
flip_card: ^0.7.0
|
||||||
|
font_awesome_flutter: ^10.7.0
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue