A Twitter-like Like Button in FlutterFlow with Supabase

Best Practices

Step 1: Set Up Supabase

  1. Create a Supabase project and set up your database.

  2. Create a 'posts' table with columns:

    • id (bigint generated by default as identity not null)

    • post_name (text)

    • profile_id (uuid, foreign key to users table)

    • created_at (timestamp with time zone)

    • post_like_counter (int4, default: 0)

  3. Create a 'likes' table with columns:

    • id (bigint generated by default as identity not null)

    • post_id (bigint not null)

    • profile_id (uuid, foreign key to users table)

    • created_at (timestamp with time zone)

Step 2: Add the Like Button Package

  1. In your FlutterFlow project, go to "Project Settings" > "Pub Dependencies".

  2. Add like_button: ^2.0.5 to the list of dependencies.

Step 3: Create a Custom Widget

  1. In FlutterFlow, create a new Custom Widget named "LikeButtonPost".

// Automatic FlutterFlow imports
import '/backend/backend.dart';
import '/backend/schema/structs/index.dart';
import '/backend/supabase/supabase.dart';
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/custom_code/widgets/index.dart'; // Imports other custom widgets
import '/custom_code/actions/index.dart'; // Imports custom actions
import '/flutter_flow/custom_functions.dart'; // Imports custom functions
import 'package:flutter/material.dart';
// Begin custom widget code
// DO NOT REMOVE OR MODIFY THE CODE ABOVE!

import 'package:like_button/like_button.dart';

class LikeButtonPost extends StatefulWidget {
  const LikeButtonPost({
    Key? key,
    this.width,
    this.height,
    required this.postId,
    required this.initialCount,
  }) : super(key: key);

  final double? width;
  final double? height;
  final int postId;
  final int initialCount;

  @override
  _LikeButtonPostState createState() => _LikeButtonPostState();
}

class _LikeButtonPostState extends State<LikeButtonPost> {
  late int _likeCount;
  bool _isLiked = false;
  String? _currentUserId;

  @override
  void initState() {
    super.initState();
    _likeCount = widget.initialCount;
    _getCurrentUserAndCheckLikeStatus();
  }

  Future<void> _getCurrentUserAndCheckLikeStatus() async {
    final client = SupaFlow.client;
    _currentUserId = client.auth.currentUser?.id;
    if (_currentUserId != null) {
      await _checkLikeStatus();
    }
  }

  Future<void> _checkLikeStatus() async {
    try {
      final client = SupaFlow.client;
      final response = await client
          .from('likes')
          .select()
          .eq('post_id', widget.postId)
          .eq('profile_id', _currentUserId)
          .execute();

      setState(() {
        _isLiked = response.data != null && response.data.isNotEmpty;
      });
    } catch (e) {
      print('Error checking like status: $e');
    }
  }

  Future<bool> _onLikeButtonTapped(bool isLiked) async {
    if (_currentUserId == null) return false;

    try {
      final client = SupaFlow.client;
      if (isLiked) {
        await client.from('likes').delete().match({
          'post_id': widget.postId,
          'profile_id': _currentUserId,
        }).execute();
        _likeCount--;
      } else {
        await client.from('likes').insert({
          'post_id': widget.postId,
          'profile_id': _currentUserId,
          'challenge_id': 0,
          'forum_id': 0,
        }).execute();
        _likeCount++;
      }

      await client
          .from('posts')
          .update({
            'post_like_counter': _likeCount,
          })
          .eq('id', widget.postId)
          .execute();

      return !isLiked;
    } catch (e) {
      print('Error toggling like: $e');
      return isLiked;
    }
  }

  @override
  Widget build(BuildContext context) {
    return LikeButton(
      size: 30,
      isLiked: _isLiked,
      likeCount: _likeCount,
      likeBuilder: (bool isLiked) {
        return Icon(
          isLiked ? Icons.favorite : Icons.favorite_border,
          color: isLiked ? Colors.red : Colors.white,
          size: 30,
        );
      },
      likeCountPadding: const EdgeInsets.only(left: 12.0),
      countBuilder: (int? count, bool isLiked, String text) {
        return Text(
          text,
          style: TextStyle(
            color: Colors.white,
            fontSize: 16,
            fontWeight: FontWeight.bold,
          ),
        );
      },
      onTap: _currentUserId != null ? _onLikeButtonTapped : null,
    );
  }
}

Step 4: Use the Custom Widget

  1. In your FlutterFlow page, drag and drop the custom widget where you want the like button to appear.

  2. Set the required parameters:

    • postId: The ID of the post you want to like

    • initialCount: The initial number of likes for the post

Step 5: Update Post Like Count (Optional)

To keep the post's like count updated, you may want to add a trigger in Supabase or create a separate function to update the post's like count whenever a like is added or removed. This tutorial provides a basic implementation of a Twitter-like toggle button in FlutterFlow with Supabase integration. The button animates when clicked, updates the like status in real-time, and stores the like information in your Supabase database. Remember to handle authentication in your FlutterFlow app to ensure that_currentUserIdis properly set when a user is logged in.

Screen Recording 2024-10-01 at 20.35.16-00.00.00.000-00.00.08.972.mp4
2.43MB

2
2 replies