Make passphrase entry a dialog instead of a page.
Additionally, we set some groundwork for storing the game data (lobby id, player id, passphrase) in permanent storage in order to reconnect with it later.
This commit is contained in:
parent
4a9047fd67
commit
7a51e71767
3
.gitignore
vendored
3
.gitignore
vendored
@ -42,3 +42,6 @@ app.*.map.json
|
|||||||
/android/app/debug
|
/android/app/debug
|
||||||
/android/app/profile
|
/android/app/profile
|
||||||
/android/app/release
|
/android/app/release
|
||||||
|
|
||||||
|
# Custom ignores
|
||||||
|
deploy-web.sh
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class PlayerInfo {
|
class PlayerInfo {
|
||||||
@ -25,6 +26,42 @@ class PlayerInfo {
|
|||||||
'lobbyID': lobbyID,
|
'lobbyID': lobbyID,
|
||||||
'passphrase': passphrase,
|
'passphrase': passphrase,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void store() async {
|
||||||
|
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
|
await prefs.setBool("contains", true);
|
||||||
|
await prefs.setString("playerID", playerID.toString());
|
||||||
|
await prefs.setString("lobbyID", lobbyID.toString());
|
||||||
|
await prefs.setString("passphrase", passphrase.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete() async {
|
||||||
|
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
|
await prefs.setBool("contains", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<PlayerInfo?> get() async {
|
||||||
|
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
var contains = prefs.getBool("contains");
|
||||||
|
var playerID = prefs.getString("playerID");
|
||||||
|
var lobbyID = prefs.getString("lobbyID");
|
||||||
|
var passphrase = prefs.getString("passphrase");
|
||||||
|
|
||||||
|
if (contains == null ||
|
||||||
|
!contains ||
|
||||||
|
playerID == null ||
|
||||||
|
lobbyID == null ||
|
||||||
|
passphrase == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PlayerInfo(
|
||||||
|
playerID: UuidValue.fromString(playerID),
|
||||||
|
lobbyID: UuidValue.fromString(lobbyID),
|
||||||
|
passphrase: passphrase);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class WebsocketMessageIdentifyPlayer {
|
class WebsocketMessageIdentifyPlayer {
|
||||||
|
@ -85,4 +85,18 @@ class ChessGameArguments {
|
|||||||
required this.playerID,
|
required this.playerID,
|
||||||
required this.passphrase,
|
required this.passphrase,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
bool isValid() {
|
||||||
|
try {
|
||||||
|
lobbyID.validate();
|
||||||
|
playerID.validate();
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (passphrase == null) return false;
|
||||||
|
if (passphrase!.isEmpty) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,9 @@ class _HostGameWidgetState extends State<HostGameWidget> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
registerResponse = hostPrivateGame();
|
registerResponse = hostPrivateGame();
|
||||||
|
registerResponse.then((value) {
|
||||||
|
value?.store();
|
||||||
|
});
|
||||||
connectToWebsocket(registerResponse);
|
connectToWebsocket(registerResponse);
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
|
@ -1,118 +0,0 @@
|
|||||||
import 'dart:convert';
|
|
||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:go_router/go_router.dart';
|
|
||||||
import 'package:http/http.dart' as http;
|
|
||||||
import 'package:http/http.dart';
|
|
||||||
import 'package:mchess/api/register.dart';
|
|
||||||
import 'package:mchess/connection_cubit/connection_cubit.dart';
|
|
||||||
import 'package:mchess/pages/chess_game.dart';
|
|
||||||
|
|
||||||
class JoinGameWidget extends StatefulWidget {
|
|
||||||
const JoinGameWidget({
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<JoinGameWidget> createState() => _JoinGameWidgetState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _JoinGameWidgetState extends State<JoinGameWidget> {
|
|
||||||
final myController = TextEditingController();
|
|
||||||
late Future<PlayerInfo?> joinGameFuture;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
body: TextField(
|
|
||||||
controller: myController,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: 'Enter passphrase here',
|
|
||||||
suffixIcon: IconButton(
|
|
||||||
onPressed: () {
|
|
||||||
joinGameFuture = joinPrivateGame();
|
|
||||||
switchToGame(joinGameFuture);
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.check),
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
floatingActionButton: FloatingActionButton(
|
|
||||||
onPressed: () {
|
|
||||||
context.push('/');
|
|
||||||
},
|
|
||||||
child: const Icon(Icons.cancel),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void switchToGame(Future<PlayerInfo?> resp) {
|
|
||||||
resp.then((value) {
|
|
||||||
if (value == null) return;
|
|
||||||
|
|
||||||
var chessGameArgs = ChessGameArguments(
|
|
||||||
lobbyID: value.lobbyID!,
|
|
||||||
playerID: value.playerID!,
|
|
||||||
passphrase: value.passphrase);
|
|
||||||
|
|
||||||
ConnectionCubit.getInstance().connect(
|
|
||||||
value.playerID!.uuid,
|
|
||||||
value.lobbyID!.uuid,
|
|
||||||
value.passphrase,
|
|
||||||
);
|
|
||||||
|
|
||||||
context.push('/game', extra: chessGameArgs);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<PlayerInfo?> joinPrivateGame() async {
|
|
||||||
String addr;
|
|
||||||
Response response;
|
|
||||||
|
|
||||||
// server expects us to send the passphrase
|
|
||||||
var info = PlayerInfo(
|
|
||||||
playerID: null, lobbyID: null, passphrase: myController.text);
|
|
||||||
|
|
||||||
if (kDebugMode) {
|
|
||||||
addr = 'http://localhost:8080/api/joinPrivate';
|
|
||||||
} else {
|
|
||||||
addr = 'https://chess.sw-gross.de:9999/api/joinPrivate';
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
response = await http.post(Uri.parse(addr),
|
|
||||||
body: jsonEncode(info), headers: {"Accept": "application/json"});
|
|
||||||
} catch (e) {
|
|
||||||
log(e.toString());
|
|
||||||
|
|
||||||
if (!context.mounted) return null;
|
|
||||||
|
|
||||||
const snackBar = SnackBar(
|
|
||||||
backgroundColor: Colors.amberAccent,
|
|
||||||
content: Text("mChess server is not responding. Try again or give up"),
|
|
||||||
);
|
|
||||||
Future.delayed(const Duration(seconds: 2), () {
|
|
||||||
ScaffoldMessenger.of(context).clearSnackBars();
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
|
||||||
context.push('/'); // We go back to lobby selector
|
|
||||||
});
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
|
||||||
var info = PlayerInfo.fromJson(jsonDecode(response.body));
|
|
||||||
log('Player info received from server: ');
|
|
||||||
log('lobbyID: ${info.lobbyID}');
|
|
||||||
log('playerID: ${info.playerID}');
|
|
||||||
log('passphrase: ${info.passphrase}');
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +1,36 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:mchess/api/register.dart';
|
||||||
|
import 'package:mchess/connection_cubit/connection_cubit.dart';
|
||||||
|
import 'package:mchess/pages/chess_game.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
class LobbySelector extends StatelessWidget {
|
class LobbySelector extends StatefulWidget {
|
||||||
const LobbySelector({super.key});
|
const LobbySelector({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<LobbySelector> createState() => _LobbySelectorState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LobbySelectorState extends State<LobbySelector> {
|
||||||
final buttonStyle = const ButtonStyle();
|
final buttonStyle = const ButtonStyle();
|
||||||
|
final myController = TextEditingController();
|
||||||
|
late Future<PlayerInfo?> joinGameFuture;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
SharedPreferences.getInstance().then((prefs) {
|
||||||
|
final playerID = prefs.getString("playerID");
|
||||||
|
final lobbyID = prefs.getString("lobbyID");
|
||||||
|
final passphrase = prefs.getString("passphrase");
|
||||||
|
log("lobbyID: $lobbyID and playerID: $playerID and passphrase: $passphrase");
|
||||||
|
});
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Center(
|
body: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -15,7 +38,7 @@ class LobbySelector extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_dialogBuilder(context);
|
buildJoinOrHostDialog(context);
|
||||||
},
|
},
|
||||||
child: const Row(
|
child: const Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
@ -34,23 +57,65 @@ class LobbySelector extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _dialogBuilder(BuildContext context) {
|
Future<void> buildJoinOrHostDialog(BuildContext context) {
|
||||||
|
return showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: AlertDialog(
|
||||||
|
title: const Text('Host or join?'),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
child: const Text('Cancel'),
|
||||||
|
onPressed: () {
|
||||||
|
context.pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
child: const Text('Host'),
|
||||||
|
onPressed: () {
|
||||||
|
context.push('/host');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
child: const Text('Join'),
|
||||||
|
onPressed: () {
|
||||||
|
buildEnterPassphraseDialog(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> buildEnterPassphraseDialog(BuildContext context) {
|
||||||
return showDialog<void>(
|
return showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: const Text('Host or join?'),
|
title: const Text('Enter the passphrase here:'),
|
||||||
|
content: TextField(
|
||||||
|
controller: myController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: 'Enter passphrase here',
|
||||||
|
suffixIcon: IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
joinGameFuture = joinPrivateGame();
|
||||||
|
joinGameFuture.then((value) {
|
||||||
|
if (value == null) return;
|
||||||
|
switchToGame(value);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.check),
|
||||||
|
)),
|
||||||
|
),
|
||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
TextButton(
|
TextButton(
|
||||||
child: const Text('Host'),
|
child: const Text('Cancel'),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.push('/host');
|
context.pop();
|
||||||
},
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
child: const Text('Join'),
|
|
||||||
onPressed: () {
|
|
||||||
context.push('/join');
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -58,4 +123,73 @@ class LobbySelector extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void switchToGame(PlayerInfo info) {
|
||||||
|
var chessGameArgs = ChessGameArguments(
|
||||||
|
lobbyID: info.lobbyID!,
|
||||||
|
playerID: info.playerID!,
|
||||||
|
passphrase: info.passphrase);
|
||||||
|
|
||||||
|
ConnectionCubit.getInstance().connect(
|
||||||
|
info.playerID!.uuid,
|
||||||
|
info.lobbyID!.uuid,
|
||||||
|
info.passphrase,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!chessGameArgs.isValid()) {
|
||||||
|
context.push('/');
|
||||||
|
const snackBar = SnackBar(
|
||||||
|
backgroundColor: Colors.amberAccent,
|
||||||
|
content: Text("Game information is corrupted"),
|
||||||
|
);
|
||||||
|
ScaffoldMessenger.of(context).clearSnackBars();
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.push('/game', extra: chessGameArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<PlayerInfo?> joinPrivateGame() async {
|
||||||
|
String addr;
|
||||||
|
http.Response response;
|
||||||
|
|
||||||
|
// server expects us to send the passphrase
|
||||||
|
var info = PlayerInfo(
|
||||||
|
playerID: null, lobbyID: null, passphrase: myController.text);
|
||||||
|
|
||||||
|
if (kDebugMode) {
|
||||||
|
addr = 'http://localhost:8080/api/joinPrivate';
|
||||||
|
} else {
|
||||||
|
addr = 'https://chess.sw-gross.de:9999/api/joinPrivate';
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
response = await http.post(Uri.parse(addr),
|
||||||
|
body: jsonEncode(info), headers: {"Accept": "application/json"});
|
||||||
|
} catch (e) {
|
||||||
|
log(e.toString());
|
||||||
|
|
||||||
|
if (!context.mounted) return null;
|
||||||
|
|
||||||
|
const snackBar = SnackBar(
|
||||||
|
backgroundColor: Colors.amberAccent,
|
||||||
|
content: Text("mChess server is not responding. Try again or give up"),
|
||||||
|
);
|
||||||
|
ScaffoldMessenger.of(context).clearSnackBars();
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
var info = PlayerInfo.fromJson(jsonDecode(response.body));
|
||||||
|
log('Player info received from server: ');
|
||||||
|
log('lobbyID: ${info.lobbyID}');
|
||||||
|
log('playerID: ${info.playerID}');
|
||||||
|
log('passphrase: ${info.passphrase}');
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:mchess/pages/chess_game.dart';
|
import 'package:mchess/pages/chess_game.dart';
|
||||||
import 'package:mchess/pages/join_game.dart';
|
|
||||||
import 'package:mchess/pages/lobby_selector.dart';
|
import 'package:mchess/pages/lobby_selector.dart';
|
||||||
import 'package:mchess/pages/host_game.dart';
|
import 'package:mchess/pages/host_game.dart';
|
||||||
import 'package:mchess/pages/prepare_random_game.dart';
|
import 'package:mchess/pages/prepare_random_game.dart';
|
||||||
@ -35,12 +34,6 @@ class ChessAppRouter {
|
|||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return const HostGameWidget();
|
return const HostGameWidget();
|
||||||
}),
|
}),
|
||||||
GoRoute(
|
|
||||||
path: '/join',
|
|
||||||
name: 'join',
|
|
||||||
builder: (context, state) {
|
|
||||||
return const JoinGameWidget();
|
|
||||||
}),
|
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/game',
|
path: '/game',
|
||||||
name: 'game',
|
name: 'game',
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
import FlutterMacOS
|
import FlutterMacOS
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
import shared_preferences_foundation
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
}
|
}
|
||||||
|
134
pubspec.lock
134
pubspec.lock
@ -81,6 +81,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.1"
|
version: "1.3.1"
|
||||||
|
ffi:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: ffi
|
||||||
|
sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
|
file:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file
|
||||||
|
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.0"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -208,6 +224,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.1"
|
||||||
|
path_provider_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_linux
|
||||||
|
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.1"
|
||||||
|
path_provider_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_platform_interface
|
||||||
|
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
|
path_provider_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_windows
|
||||||
|
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.1"
|
||||||
petitparser:
|
petitparser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -216,6 +256,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.2"
|
version: "6.0.2"
|
||||||
|
platform:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: platform
|
||||||
|
sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.3"
|
||||||
|
plugin_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: plugin_platform_interface
|
||||||
|
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.7"
|
||||||
provider:
|
provider:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -232,6 +288,62 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.2.1"
|
version: "3.2.1"
|
||||||
|
shared_preferences:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: shared_preferences
|
||||||
|
sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.2"
|
||||||
|
shared_preferences_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_android
|
||||||
|
sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.1"
|
||||||
|
shared_preferences_foundation:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_foundation
|
||||||
|
sha256: "7bf53a9f2d007329ee6f3df7268fd498f8373602f943c975598bbb34649b62a7"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.4"
|
||||||
|
shared_preferences_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_linux
|
||||||
|
sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.2"
|
||||||
|
shared_preferences_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_platform_interface
|
||||||
|
sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.1"
|
||||||
|
shared_preferences_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_web
|
||||||
|
sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.2"
|
||||||
|
shared_preferences_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_windows
|
||||||
|
sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.2"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -305,10 +417,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: uuid
|
name: uuid
|
||||||
sha256: df5a4d8f22ee4ccd77f8839ac7cb274ebc11ef9adcce8b92be14b797fe889921
|
sha256: "22c94e5ad1e75f9934b766b53c742572ee2677c56bc871d850a57dad0f82127f"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2.1"
|
version: "4.2.2"
|
||||||
vector_graphics:
|
vector_graphics:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -357,6 +469,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.0"
|
version: "2.4.0"
|
||||||
|
win32:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: win32
|
||||||
|
sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.1.1"
|
||||||
|
xdg_directories:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: xdg_directories
|
||||||
|
sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.3"
|
||||||
xml:
|
xml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -367,4 +495,4 @@ packages:
|
|||||||
version: "6.5.0"
|
version: "6.5.0"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.2.0 <4.0.0"
|
dart: ">=3.2.0 <4.0.0"
|
||||||
flutter: ">=3.10.0"
|
flutter: ">=3.16.0"
|
||||||
|
@ -44,6 +44,7 @@ dependencies:
|
|||||||
go_router: ^12.0.0
|
go_router: ^12.0.0
|
||||||
http: ^1.0.0
|
http: ^1.0.0
|
||||||
uuid: ^4.0.0
|
uuid: ^4.0.0
|
||||||
|
shared_preferences: ^2.2.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
Reference in New Issue
Block a user