Open9

【Flutter x Supabase】Supabaseを使用して実践的な開発をする

ピン留めされたアイテム
いせりゅーいせりゅー

また、こちらの投稿はSupabase Advent Calendar 2023のアドベントカレンダーにも掲載されています!!

他にもたくさんの記事があると思うので気になったかたは読んでいただけると幸いです😚

https://adventar.org/calendars/9077

いせりゅーいせりゅー

【Flutter x Supabase】 データの削除するやり方+おまけつき

データの削除の実装の流れをSupabase以外に必要そうな記載をしてみました。

1、削除してもいいかを確認する
2、データを削除する
3、適切な画面に移動する。

  void openDeleteDialog(String id) {
    showDialog(
      context: context,
      builder: (context) {
        return CupertinoAlertDialog(
          title: Text('投稿の削除'),
          content: Text('この投稿を削除しますか?\n一度削除してしまうと復元できません'),
          actions: <Widget>[
            CupertinoDialogAction(
              child: Text(
                'キャンセル',
                style: TextStyle(color: Colors.blueAccent),
              ),
              isDestructiveAction: true,
              onPressed: () => Navigator.pop(context),
            ),
            CupertinoDialogAction(
              child: Text(
                '削除する',
                style: TextStyle(color: Colors.red),
              ),
              onPressed: () {
                delete(id);
                Navigator.pop(context);
              },
            ),
          ],
        );
      },
    );
  }

  Future<void> delete(String id) async {
    final supabase = Supabase.instance.client;
    await supabase.from('posts').delete().eq('id', id);
  }



詳しい解説やコードなどはこちらから↓

https://qiita.com/isekiryu/private/7648b83927c4e3898f7c

いせりゅーいせりゅー

【Flutter x Supabase】 データの更新する方法+おまけつき

データの更新する実装の流れをSupabase以外に必要そうな記載をしてみました。

1、更新するデータが記入されていないかを確認する
2、データの更新をする
3、SnackBarを出して、その後に画面を戻る


final nameTextController = TextEditingController();
final useNameTextController = TextEditingController();
final selfIntroduceTextController = TextEditingController();
final supabase = Supabase.instance.client;

Future<void> getProfile() async {
    final userId = supabase.auth.currentUser!.id;
    final data = await supabase
        .from('users')
        .select<Map<String, dynamic>>()
        .eq('user_id', userId)
        .single();
    nameTextController.text = data['name'];
    useNameTextController.text = data['user_name'];
    selfIntroduceTextController.text = data['self_introduce'];
  }

Future<void> update() async {
  final user = supabase.auth.currentUser;
  final updates = {
    'name': nameTextController.text,
    'user_name': useNameTextController.text,
    'self_introduce': selfIntroduceTextController.text,
    'updated_at': DateTime.now().toIso8601String(),
  };

  try {
      await supabase.from('users').update(updates).match({'user_id': user!.id});
      final snackBar = SnackBar(content: Text('データの更新が完了しました'));
      ScaffoldMessenger.of(context).showSnackBar(snackBar);
      await Future.delayed(Duration(seconds: 2));
      Navigator.pop(context);
    } on PostgrestException catch (error) {
      print(error);
    }
  }
}

詳しい解説やコードなどはこちらから↓

https://qiita.com/isekiryu/private/fb4aceb0cd00e0141690

いせりゅーいせりゅー

【Flutter x Supabase】 画像のアップロードのやり方+おまけつき

画像のアップロードの流れをSupabase以外に必要そうな記載をしてみました。

1、カメラかカメラロールか選択するSheetを出す。
2、ImagePickerで写真を取得する
3、画像をアップロードする。


  final picker = ImagePicker();
  String uploadImage = '';
  final supabase = Supabase.instance.client;

  void onTapImage() {
    showCupertinoModalPopup(
      context: context,
      builder: (context) => CupertinoActionSheet(
        actions: [
          CupertinoActionSheetAction(
            isDefaultAction: true,
            onPressed: () {
              Navigator.pop(context);
              camera();
            },
            child: const Text(
              'カメラ',
              style: TextStyle(
                fontWeight: FontWeight.bold,
                color: Colors.black,
              ),
            ),
          ),
          CupertinoActionSheetAction(
            onPressed: () {
              Navigator.pop(context);
              album();
            },
            child: const Text(
              'アルバム',
              style: TextStyle(
                fontWeight: FontWeight.bold,
                color: Colors.black,
              ),
            ),
          ),
          CupertinoActionSheetAction(
            isDestructiveAction: true,
            onPressed: () =>  Navigator.pop(context),
            child: const Text('閉じる'),
          ),
        ],
      ),
    );
  }

 Future<void> camera() async {
    try {
      final image = await ImagePicker().pickImage(source: ImageSource.camera);
      if (image == null) {
        return;
      }
      imageBytes = await image.readAsBytes();
      uploadImage = image.name;
      print('画像の添付が成功しました');
    } on PlatformException catch (error) {
      print(error);
    }
  }

  Future<void> album() async {
    try {
      final image = await ImagePicker().pickImage(source: ImageSource.gallery);
      if (image == null) {
        return;
      }
      imageBytes = await image.readAsBytes();
      uploadImage = image.name;
      print('画像の添付が成功しました');
    } on PlatformException catch (e) {
      state = state.copyWith(status: e.message!);
    }
  }

  Future<void> upload() async {
    loading.state = true;
    final user = supabase.auth.currentUser?.id;
    try {
      await supabase.storage.from('food').uploadBinary('/$user/$uploadImage', imageBytes);
    } on PostgrestException catch (error) {
      print(error);
    }
  }

詳しい解説やコードなどはこちらから↓

https://qiita.com/isekiryu/private/4c32153368b0b69bd5ff

いせりゅーいせりゅー

【Flutter x Supabase】 ログアウトやり方+おまけつき

ログアウトの流れをSupabase以外に必要そうな記載をしてみました。

1、ログアウトしてもいいか確認する
2、ログアウトする
3、ログイン画面に遷移をする



final supabase = Supabase.instance.client;

  void openLogOutDialog() {
    showDialog(
      context: context,
      builder: (context) {
        return CupertinoAlertDialog(
          title: Text('ログアウト'),
          content: Text('ログアウトしますか?'),
          actions: <Widget>[
            CupertinoDialogAction(
              child: Text(
                'キャンセル',
                style: TextStyle(color: Colors.blueAccent),
              ),
              isDestructiveAction: true,
              onPressed: () => Navigator.pop(context),
            ),
            CupertinoDialogAction(
              child: Text(
                'ログアウト',
                style: TextStyle(color: Colors.red),
              ),
              onPressed: () {
                logout();
                Navigator.pop(context);
              },
            ),
          ],
        );
      },
    );
  }

  Future<void> logout() async {
    await supabase.auth.signOut();
    await Navigator.pushReplacement(
      context,
      MaterialPageRoute( 
        builder: (context) => LoginPage(),
      ),
    );
  }



詳しい解説やコードなどはこちらから↓

https://qiita.com/isekiryu/private/dc5bf6a85c03b994f622

いせりゅーいせりゅー

【Flutter x Supabase】データを追加するやり方+おまけつき

データを追加する流れをSupabase以外に必要そうな記載をしてみました。

1、記載の漏れがないかを確認する
2、データを追加する
3、投稿画面を閉じる

final supabase = Supabase.instance.client;
final foodTextController = TextEditingController();
final commentTextController = TextEditingController();

Future<void> post() async {
  if (foodTextController.text.isNotEmpty && commentTextController.text.isNotEmpty) {
  final user = supabase.auth.currentUser?.id;
  final updates = {
    'user_id': user,
    'food_name': foodTextController.text,
    'comment': commentTextController.text,
    'created_at': DateTime.now().toIso8601String(),
    'heart': 0,
  };
  try {
    await supabase.from('posts').insert(updates);
    Navigator.pop(context);
  } on PostgrestException catch (error) {
    print('error');
  } else {
  print('食べ物の名前or感想が入力されていません!');
}

詳しい解説やコードなどはこちらから↓

https://qiita.com/isekiryu/items/e37993d0df034e108cc1

いせりゅーいせりゅー

【Flutter x Supabase】ログイン(magic link)+おまけつき

ログイン(magic link)する流れをSupabase以外に必要そうな記載もしてみました。

1、記載の漏れがないかを確認する
2、magic linkでログインを試みる

Future<void> login() async {
  if (emailTextController.text.isNotEmpty) {
    try {
      // キーボードを閉じる
      primaryFocus?.unfocus();
      await supabase.auth.signInWithOtp(
        email: emailTextField.text.trim(),
        shouldCreateUser: _shouldCreateUser,
        emailRedirectTo: 'io.supabase.flutterquickstart://login-callback/',
      );
      print('メールを確認してみてください');
    } on AuthException catch (error) {
      print(error.message);
    }
  } else {
    print('メールアドレスが入力されていません!');
  }
}

詳しい解説やコードなどはこちらから↓

https://qiita.com/isekiryu/private/665b61e534f83a2cb498

いせりゅーいせりゅー

次回予告(書けそうだったら書きます)
・アカウント削除
・ソーシャルログイン
・email+passwordログイン
・ストレージの削除