blog: update past Flutter blog content to use supabase_flutter v2 (#19634)

* update flutter quick start and example app to use flutter v2

* update examples and blog articles to use Flutter SDK v2

* fix versions used in examples

* update image picker to 1.0.5

* minor code refactor for sample code
This commit is contained in:
Tyler authored and GitHub committed 2023-12-19 11:34:03 +09:00
1 parent 6ac489018e
commit eae972b55a
19 files changed
+169 -344

No files matched your search

@@ -68,7 +68,7 @@ export const meta = {
<StepHikeCompact.Code>
```yaml pubspec.yaml
supabase_flutter: ^1.6.2
supabase_flutter: ^2.0.0
```
</StepHikeCompact.Code>
@@ -138,7 +138,7 @@ export const meta = {
class _HomePageState extends State<HomePage> {
final _future = Supabase.instance.client
.from('countries')
.select<List<Map<String, dynamic>>>();
.select();
@override
Widget build(BuildContext context) {
@@ -36,7 +36,7 @@ Then let's install the only additional dependency: [`supabase_flutter`](https://
Copy and paste the following line in your pubspec.yaml to install the package:
```yaml
supabase_flutter: ^1.10.3
supabase_flutter: ^2.0.0
```
Run `flutter pub get` to install the dependencies.
@@ -136,7 +136,6 @@ Future<void> main() async {
await Supabase.initialize(
url: 'YOUR_SUPABASE_URL',
anonKey: 'YOUR_SUPABASE_ANON_KEY',
authFlowType: AuthFlowType.pkce,
);
runApp(MyApp());
}
@@ -144,8 +143,6 @@ Future<void> main() async {
final supabase = Supabase.instance.client;
```
`AuthFlowType.pkce` on `authFlowType` parameter indicates that we are using a secure [PKCE flow](https://supabase.com/blog/supabase-auth-sso-pkce#introducing-pkce) to perform our magic link login.
### Set up Splash Screen
Let's create a splash screen that will be shown to users right after they open the app.
@@ -331,11 +328,8 @@ class _AccountPageState extends State<AccountPage> {
try {
final userId = supabase.auth.currentUser!.id;
final data = await supabase
.from('profiles')
.select<Map<String, dynamic>>()
.eq('id', userId)
.single();
final data =
await supabase.from('profiles').select().eq('id', userId).single();
_usernameController.text = (data['username'] ?? '') as String;
_websiteController.text = (data['website'] ?? '') as String;
} on PostgrestException catch (error) {
@@ -547,7 +541,7 @@ We will use [`image_picker`](https://pub.dev/packages/image_picker) plugin to se
Add the following line in your pubspec.yaml file to install `image_picker`:
```yaml
image_picker: ^0.8.4
image_picker: ^1.0.5
```
Using [`image_picker`](https://pub.dev/packages/image_picker) requires some additional preparation depending on the platform.
@@ -693,10 +687,10 @@ class _AccountPageState extends State<AccountPage> {
});
try {
final userId = supabase.auth.currentUser!.id;
final userId = supabase.auth.currentSession!.user.id;
final data = await supabase
.from('profiles')
.select<Map<String, dynamic>>()
.select()
.eq('id', userId)
.single();
_usernameController.text = (data['username'] ?? '') as String;
@@ -210,10 +210,10 @@ Now the fun part starts! We will start out by creating our game class. We create
![Structure of the shooting game](/images/blog/flutter-realtime-game/game-structure.png)
Let’s add flame to our app by adding the following to our `pubspec.yaml` file to install flame.
Let's add flame to our app. Run the following command:
```yaml
flame: ^1.6.0
```bash
flutter pub add flame
```
We can then create `MyGame` class. Add the following code in `lib/game.dart` file.
@@ -567,23 +567,22 @@ class Bullet extends PositionComponent with CollisionCallbacks, HasGameRef {
At this point, we have a working shooting game except the opponent does not move, because we have not added any ways to communicate between clients. We will use Supabase’s [realtime features](https://supabase.com/docs/guides/realtime) for this, because it gives us an out of the box solution to handle low-latency real-time communication between players. If you do not have a Supabase project created yet, head over to [database.new](https://database.new/) to create one.
Before we get into any coding, let’s install the Supabase SDK into our app. We will also use the [uuid package](https://pub.dev/packages/uuid) to generate random unique ids for the users. Add the following to `pubspec.yaml` file.
Before we get into any coding, let’s install the Supabase SDK into our app. We will also use the [uuid package](https://pub.dev/packages/uuid) to generate random unique ids for the users. Run the following command:
```yaml
supabase_flutter: ^1.4.0
uuid: ^3.0.7
```bash
flutter pub add supabase_flutter uuid
```
Once `pub get` is complete, let’s initialize Supabase. We will override the `main` function to initialize Supabase. You can get your Supabase URL and Anon Key at `Project Setting` > `API`. Copy and paste them into the `Supabase.initialize` call.
```dart
void main() async {
await Supabase.initialize(
url: 'YOUR_SUPABASE_URL',
anonKey: 'YOUR_ANON_KEY',
realtimeClientOptions: const RealtimeClientOptions(eventsPerSecond: 40),
);
runApp(const MyApp());
await Supabase.initialize(
url: 'YOUR_SUPABASE_URL',
anonKey: 'YOUR_ANON_KEY',
realtimeClientOptions: const RealtimeClientOptions(eventsPerSecond: 40),
);
runApp(const MyApp());
}
// Extract Supabase client for easy access to Supabase
@@ -618,33 +617,36 @@ class _LobbyDialogState extends State<_LobbyDialog> {
'lobby',
opts: const RealtimeChannelConfig(self: true),
);
_lobbyChannel.on(RealtimeListenTypes.presence, ChannelFilter(event: 'sync'),
(payload, [ref]) {
// Update the lobby count
final presenceState = _lobbyChannel.presenceState();
_lobbyChannel
.onPresenceSync((payload, [ref]) {
// Update the lobby count
final presenceStates = _lobbyChannel.presenceState();
setState(() {
_userids = presenceState.values
.map((presences) =>
(presences.first as Presence).payload['user_id'] as String)
.toList();
});
}).on(RealtimeListenTypes.broadcast, ChannelFilter(event: 'game_start'),
(payload, [_]) {
// Start the game if someone has started a game with you
final participantIds = List<String>.from(payload['participants']);
if (participantIds.contains(myUserId)) {
final gameId = payload['game_id'] as String;
widget.onGameStarted(gameId);
Navigator.of(context).pop();
}
}).subscribe(
(status, [ref]) async {
if (status == 'SUBSCRIBED') {
await _lobbyChannel.track({'user_id': myUserId});
}
},
);
setState(() {
_userids = presenceStates
.map((presenceState) => (presenceState.presences.first)
.payload['user_id'] as String)
.toList();
});
})
.onBroadcast(
event: 'game_start',
callback: (payload, [_]) {
// Start the game if someone has started a game with you
final participantIds = List<String>.from(payload['participants']);
if (participantIds.contains(myUserId)) {
final gameId = payload['game_id'] as String;
widget.onGameStarted(gameId);
Navigator.of(context).pop();
}
})
.subscribe(
(status, _) async {
if (status == RealtimeSubscribeStatus.subscribed) {
await _lobbyChannel.track({'user_id': myUserId});
}
},
);
}
@override
@@ -675,8 +677,7 @@ class _LobbyDialogState extends State<_LobbyDialog> {
final opponentId =
_userids.firstWhere((userId) => userId != myUserId);
final gameId = const Uuid().v4();
await _lobbyChannel.send(
type: RealtimeListenTypes.broadcast,
await _lobbyChannel.sendBroadcastMessage(
event: 'game_start',
payload: {
'participants': [
@@ -738,10 +739,8 @@ class _GamePageState extends State<GamePage> {
_game = MyGame(
onGameStateUpdate: (position, health) async {
ChannelResponse response;
// Loop until the send succeeds if the payload is to notify defeat.
do {
response = await _gameChannel!.send(
type: RealtimeListenTypes.broadcast,
response = await _gameChannel!.sendBroadcastMessage(
event: 'game_state',
payload: {'x': position.x, 'y': position.y, 'health': health},
);
@@ -799,23 +798,27 @@ class _GamePageState extends State<GamePage> {
_gameChannel = supabase.channel(gameId,
opts: const RealtimeChannelConfig(ack: true));
_gameChannel!.on(RealtimeListenTypes.broadcast,
ChannelFilter(event: 'game_state'), (payload, [_]) {
final position =
Vector2(payload['x'] as double, payload['y'] as double);
final opponentHealth = payload['health'] as int;
_game.updateOpponent(
position: position,
health: opponentHealth,
);
_gameChannel!
.onBroadcast(
event: 'game_state',
callback: (payload, [_]) {
final position = Vector2(
payload['x'] as double, payload['y'] as double);
final opponentHealth = payload['health'] as int;
_game.updateOpponent(
position: position,
health: opponentHealth,
);
if (opponentHealth <= 0) {
if (!_game.isGameOver) {
_game.isGameOver = true;
_game.onGameOver(true);
}
}
}).subscribe();
if (opponentHealth <= 0) {
if (!_game.isGameOver) {
_game.isGameOver = true;
_game.onGameOver(true);
}
}
},
)
.subscribe();
},
);
});
@@ -668,8 +668,7 @@ class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final privatePostsFuture =
supabase.from('private_posts').select<List<Map<String, dynamic>>>();
final privatePostsFuture = supabase.from('private_posts').select();
return Scaffold(
appBar: AppBar(
@@ -208,7 +208,7 @@ class _LoginScreenState extends State<LoginScreen> {
}
return supabase.auth.signInWithIdToken(
provider: Provider.google,
provider: OAuthProvider.google,
idToken: idToken,
accessToken: accessToken,
);
@@ -11,8 +11,7 @@ class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final privatePostsFuture =
supabase.from('private_posts').select<List<Map<String, dynamic>>>();
final privatePostsFuture = supabase.from('private_posts').select();
return Scaffold(
appBar: AppBar(
+3 -68
View File
@@ -1,40 +1,18 @@
name: mfa_app
description: A new Flutter project.
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions whie build-number is used as the build suffix.
publish_to: 'none'
version: 1.0.0+1
environment:
sdk: '>=2.19.6 <4.0.0'
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
supabase_flutter: ^1.8.1
supabase_flutter: ^2.0.0
go_router: ^7.0.0
flutter_svg: ^2.0.5
@@ -42,50 +20,7 @@ dev_dependencies:
flutter_test:
sdk: flutter
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^2.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter packages.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages
@@ -62,7 +62,7 @@ class _LoginScreenState extends State<LoginScreen> {
}
return supabase.auth.signInWithIdToken(
provider: Provider.google,
provider: OAuthProvider.google,
idToken: idToken,
accessToken: accessToken,
);
@@ -69,10 +69,10 @@ packages:
dependency: transitive
description:
name: collection
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev"
source: hosted
version: "1.17.2"
version: "1.18.0"
convert:
dependency: transitive
description:
@@ -140,10 +140,10 @@ packages:
dependency: transitive
description:
name: functions_client
sha256: "3b157b4d3ae9e38614fd80fab76d1ef1e0e39ff3412a45de2651f27cecb9d2d2"
sha256: "57c383e82d9e66c1781918117d32a3b01581478cb0be883ec0cc394402cb7449"
url: "https://pub.dev"
source: hosted
version: "1.3.2"
version: "2.0.0-dev.0"
glob:
dependency: transitive
description:
@@ -204,10 +204,10 @@ packages:
dependency: transitive
description:
name: gotrue
sha256: "3d15ee24bd05c6b4e5587f6dba727a7c031e5513424aa2ab4fb35b42f8c45ba7"
sha256: "64a20fb8897838b9bf3e265c57c9c343c21a8e73bf8877de9e2a66228594dbe5"
url: "https://pub.dev"
source: hosted
version: "1.12.2"
version: "2.0.0-dev.2"
hive:
dependency: transitive
description:
@@ -284,10 +284,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
url: "https://pub.dev"
source: hosted
version: "1.9.1"
version: "1.10.0"
mime:
dependency: transitive
description:
@@ -388,10 +388,10 @@ packages:
dependency: transitive
description:
name: postgrest
sha256: "87e35d3a59e327188321befbfbfcc5a7a2e71f0d0a13d975cbc7d169387ec712"
sha256: "38ab04fc739bc02e407c26bee05e9981122aa4a9b08e188f46dffac16dca776e"
url: "https://pub.dev"
source: hosted
version: "1.5.1"
version: "2.0.0-dev.2"
pub_semver:
dependency: transitive
description:
@@ -412,10 +412,10 @@ packages:
dependency: transitive
description:
name: realtime_client
sha256: bf25420988263ba3811f65756685bf4813a527277a784150b8b7de0a583e122f
sha256: aabb7de6051a0621c30640784fefd034676a2057ac17b5d5c84d099564363bec
url: "https://pub.dev"
source: hosted
version: "1.2.3"
version: "2.0.0-dev.3"
retry:
dependency: transitive
description:
@@ -488,30 +488,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.3.1"
sign_in_with_apple:
dependency: transitive
description:
name: sign_in_with_apple
sha256: "0975c23b9f8b30a80e27d5659a75993a093d4cb5f4eb7d23a9ccc586fea634e0"
url: "https://pub.dev"
source: hosted
version: "5.0.0"
sign_in_with_apple_platform_interface:
dependency: transitive
description:
name: sign_in_with_apple_platform_interface
sha256: a5883edee09ed6be19de19e7d9f618a617fe41a6fa03f76d082dfb787e9ea18d
url: "https://pub.dev"
source: hosted
version: "1.0.0"
sign_in_with_apple_web:
dependency: transitive
description:
name: sign_in_with_apple_web
sha256: "44b66528f576e77847c14999d5e881e17e7223b7b0625a185417829e5306f47a"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
sky_engine:
dependency: transitive
description: flutter
@@ -529,26 +505,26 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.11.1"
storage_client:
dependency: transitive
description:
name: storage_client
sha256: "4bf2fc76f09c3698f0ba3f1a44d567995796f6aef76501f194631d0c03752ab7"
sha256: "8803864e1ca8157ab88c7fd292e3182d75b19553198da5e0760f433fcd633784"
url: "https://pub.dev"
source: hosted
version: "1.5.2"
version: "2.0.0-dev.0"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev"
source: hosted
version: "2.1.1"
version: "2.1.2"
string_scanner:
dependency: transitive
description:
@@ -561,18 +537,18 @@ packages:
dependency: transitive
description:
name: supabase
sha256: ee6ab8aa31438de59027888f87e53df97e138cdd00c0125d4f6f5244c31fc21e
sha256: "627fba3c0727b4285e2bc26f36f07746021c9997ab7a273c3628e152a1243ae8"
url: "https://pub.dev"
source: hosted
version: "1.11.6"
version: "2.0.0-dev.4"
supabase_flutter:
dependency: "direct main"
description:
name: supabase_flutter
sha256: "27ae595efb3ef6612be1270bd368237916e41b2ba20ea99fedd2df220b424888"
sha256: d6b17ea4c8437e1e648039b68ee2ddf48a5ab66e66f83b90b6b5f3e44c980d1d
url: "https://pub.dev"
source: hosted
version: "1.10.19"
version: "2.0.0-dev.4"
term_glyph:
dependency: transitive
description:
@@ -585,10 +561,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
url: "https://pub.dev"
source: hosted
version: "0.6.0"
version: "0.6.1"
typed_data:
dependency: transitive
description:
@@ -597,14 +573,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.2"
universal_io:
dependency: transitive
description:
name: universal_io
sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad"
url: "https://pub.dev"
source: hosted
version: "2.2.2"
url_launcher:
dependency: transitive
description:
@@ -689,10 +657,10 @@ packages:
dependency: transitive
description:
name: web
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
url: "https://pub.dev"
source: hosted
version: "0.1.4-beta"
version: "0.3.0"
web_socket_channel:
dependency: transitive
description:
@@ -701,38 +669,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.4.0"
webview_flutter:
dependency: transitive
description:
name: webview_flutter
sha256: c1ab9b81090705c6069197d9fdc1625e587b52b8d70cdde2339d177ad0dbb98e
url: "https://pub.dev"
source: hosted
version: "4.4.1"
webview_flutter_android:
dependency: transitive
description:
name: webview_flutter_android
sha256: b0cd33dd7d3dd8e5f664e11a19e17ba12c352647269921a3b568406b001f1dff
url: "https://pub.dev"
source: hosted
version: "3.12.0"
webview_flutter_platform_interface:
dependency: transitive
description:
name: webview_flutter_platform_interface
sha256: "6d9213c65f1060116757a7c473247c60f3f7f332cac33dc417c9e362a9a13e4f"
url: "https://pub.dev"
source: hosted
version: "2.6.0"
webview_flutter_wkwebview:
dependency: transitive
description:
name: webview_flutter_wkwebview
sha256: "30b9af6bdd457b44c08748b9190d23208b5165357cc2eb57914fee1366c42974"
url: "https://pub.dev"
source: hosted
version: "3.9.1"
win32:
dependency: transitive
description:
@@ -761,10 +697,10 @@ packages:
dependency: transitive
description:
name: yet_another_json_isolate
sha256: "86fad76026c4241a32831d6c7febd8f9bded5019e2cd36c5b148499808d8307d"
sha256: b1de9d553a20c7d47077b8ba388319194365ccc4890ee6fdea9e845a6e7e4164
url: "https://pub.dev"
source: hosted
version: "1.1.1"
version: "2.0.0-dev.0"
sdks:
dart: ">=3.1.0 <4.0.0"
dart: ">=3.2.0-194.0.dev <4.0.0"
flutter: ">=3.13.0"
@@ -12,7 +12,7 @@ dependencies:
flutter:
sdk: flutter
supabase_flutter: ^1.10.19
supabase_flutter: ^2.0.0
google_sign_in: ^6.1.5
dev_dependencies:
@@ -65,8 +65,7 @@ class _GamePageState extends State<GamePage> {
onGameStateUpdate: (position, health) async {
ChannelResponse response;
do {
response = await _gameChannel!.send(
type: RealtimeListenTypes.broadcast,
response = await _gameChannel!.sendBroadcastMessage(
event: 'game_state',
payload: {'x': position.x, 'y': position.y, 'health': health},
);
@@ -124,23 +123,27 @@ class _GamePageState extends State<GamePage> {
_gameChannel = supabase.channel(gameId,
opts: const RealtimeChannelConfig(ack: true));
_gameChannel!.on(RealtimeListenTypes.broadcast,
ChannelFilter(event: 'game_state'), (payload, [_]) {
final position =
Vector2(payload['x'] as double, payload['y'] as double);
final opponentHealth = payload['health'] as int;
_game.updateOpponent(
position: position,
health: opponentHealth,
);
_gameChannel!
.onBroadcast(
event: 'game_state',
callback: (payload, [_]) {
final position = Vector2(
payload['x'] as double, payload['y'] as double);
final opponentHealth = payload['health'] as int;
_game.updateOpponent(
position: position,
health: opponentHealth,
);
if (opponentHealth <= 0) {
if (!_game.isGameOver) {
_game.isGameOver = true;
_game.onGameOver(true);
}
}
}).subscribe();
if (opponentHealth <= 0) {
if (!_game.isGameOver) {
_game.isGameOver = true;
_game.onGameOver(true);
}
}
},
)
.subscribe();
},
);
});
@@ -175,33 +178,36 @@ class _LobbyDialogState extends State<_LobbyDialog> {
'lobby',
opts: const RealtimeChannelConfig(self: true),
);
_lobbyChannel.on(RealtimeListenTypes.presence, ChannelFilter(event: 'sync'),
(payload, [ref]) {
// Update the lobby count
final presenceState = _lobbyChannel.presenceState();
_lobbyChannel
.onPresenceSync((payload, [ref]) {
// Update the lobby count
final presenceStates = _lobbyChannel.presenceState();
setState(() {
_userids = presenceState.values
.map((presences) =>
(presences.first as Presence).payload['user_id'] as String)
.toList();
});
}).on(RealtimeListenTypes.broadcast, ChannelFilter(event: 'game_start'),
(payload, [_]) {
// Start the game if someone has started a game with you
final participantIds = List<String>.from(payload['participants']);
if (participantIds.contains(myUserId)) {
final gameId = payload['game_id'] as String;
widget.onGameStarted(gameId);
Navigator.of(context).pop();
}
}).subscribe(
(status, [ref]) async {
if (status == 'SUBSCRIBED') {
await _lobbyChannel.track({'user_id': myUserId});
}
},
);
setState(() {
_userids = presenceStates
.map((presenceState) => (presenceState.presences.first)
.payload['user_id'] as String)
.toList();
});
})
.onBroadcast(
event: 'game_start',
callback: (payload, [_]) {
// Start the game if someone has started a game with you
final participantIds = List<String>.from(payload['participants']);
if (participantIds.contains(myUserId)) {
final gameId = payload['game_id'] as String;
widget.onGameStarted(gameId);
Navigator.of(context).pop();
}
})
.subscribe(
(status, _) async {
if (status == RealtimeSubscribeStatus.subscribed) {
await _lobbyChannel.track({'user_id': myUserId});
}
},
);
}
@override
@@ -232,8 +238,7 @@ class _LobbyDialogState extends State<_LobbyDialog> {
final opponentId =
_userids.firstWhere((userId) => userId != myUserId);
final gameId = const Uuid().v4();
await _lobbyChannel.send(
type: RealtimeListenTypes.broadcast,
await _lobbyChannel.sendBroadcastMessage(
event: 'game_start',
payload: {
'participants': [
@@ -12,9 +12,9 @@ dependencies:
flutter:
sdk: flutter
supabase_flutter: ^1.4.0
flame: ^1.6.0
uuid: ^3.0.7
supabase_flutter: ^2.0.0
flame: ^1.12.0
uuid: ^4.2.1
dev_dependencies:
flutter_test:
@@ -1,30 +0,0 @@
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility in the flutter_test package. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flame_realtime_shooting/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const MyApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}
@@ -10,12 +10,8 @@ PODS:
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- sign_in_with_apple (0.0.1):
- Flutter
- url_launcher_ios (0.0.1):
- Flutter
- webview_flutter_wkwebview (0.0.1):
- Flutter
DEPENDENCIES:
- app_links (from `.symlinks/plugins/app_links/ios`)
@@ -23,9 +19,7 @@ DEPENDENCIES:
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sign_in_with_apple (from `.symlinks/plugins/sign_in_with_apple/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`)
EXTERNAL SOURCES:
app_links:
@@ -38,12 +32,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
sign_in_with_apple:
:path: ".symlinks/plugins/sign_in_with_apple/ios"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
webview_flutter_wkwebview:
:path: ".symlinks/plugins/webview_flutter_wkwebview/ios"
SPEC CHECKSUMS:
app_links: 5ef33d0d295a89d9d16bb81b0e3b0d5f70d6c875
@@ -51,9 +41,7 @@ SPEC CHECKSUMS:
image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5
path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8
shared_preferences_foundation: e2dae3258e06f44cc55f49d42024fd8dd03c590c
sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
webview_flutter_wkwebview: 2e2d318f21a5e036e2c3f26171342e95908bd60a
PODFILE CHECKSUM: 7368163408c647b7eb699d0d788ba6718e18fb8d
@@ -156,7 +156,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1300;
LastUpgradeCheck = 1430;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
LastUpgradeVersion = "1430"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -9,7 +9,6 @@ Future<void> main() async {
// TODO: Replace credentials with your own
url: 'YOUR_SUPABASE_URL',
anonKey: 'YOUR_SUPABASE_ANON_KEY',
authFlowType: AuthFlowType.pkce,
);
runApp(MyApp());
}
@@ -24,12 +24,9 @@ class _AccountPageState extends State<AccountPage> {
});
try {
final userId = supabase.auth.currentUser!.id;
final data = await supabase
.from('profiles')
.select<Map<String, dynamic>>()
.eq('id', userId)
.single();
final userId = supabase.auth.currentSession!.user.id;
final data =
await supabase.from('profiles').select().eq('id', userId).single();
_usernameController.text = (data['username'] ?? '') as String;
_websiteController.text = (data['website'] ?? '') as String;
_avatarUrl = (data['avatar_url'] ?? '') as String;
@@ -12,8 +12,8 @@ dependencies:
flutter:
sdk: flutter
image_picker: ^0.8.4
supabase_flutter: ^1.10.3
image_picker: ^1.0.5
supabase_flutter: ^2.0.0
dev_dependencies:
flutter_test: