supabase_realtime_widgets 0.1.0 copy "supabase_realtime_widgets: ^0.1.0" to clipboard
supabase_realtime_widgets: ^0.1.0 copied to clipboard

A small set of Flutter widgets that bind directly to Supabase Realtime channels — list, value, and presence builders with automatic subscription lifecycle.

example/lib/main.dart

// A minimal example app for supabase_realtime_widgets.
//
// Before running:
//   1. Create a Supabase project and a `todos` table:
//        id          bigint primary key generated always as identity
//        title       text not null
//        is_done     boolean not null default false
//        created_at  timestamptz not null default now()
//   2. Enable Realtime on the `todos` table.
//   3. Drop your project URL + anon key into the constants below.
//   4. `flutter run` from this example/ directory.

import 'package:flutter/material.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:supabase_realtime_widgets/supabase_realtime_widgets.dart';

const String supabaseUrl = 'https://YOUR_PROJECT.supabase.co';
const String supabaseAnonKey = 'YOUR_ANON_KEY';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Supabase.initialize(url: supabaseUrl, anonKey: supabaseAnonKey);
  runApp(const TodoApp());
}

class Todo {
  const Todo({required this.id, required this.title, required this.isDone});

  factory Todo.fromJson(Map<String, dynamic> json) => Todo(
        id: json['id'] as int,
        title: json['title'] as String,
        isDone: (json['is_done'] as bool?) ?? false,
      );

  final int id;
  final String title;
  final bool isDone;
}

class TodoApp extends StatelessWidget {
  const TodoApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Realtime Todos',
      theme: ThemeData(useMaterial3: true, colorSchemeSeed: Colors.teal),
      home: const TodoListScreen(),
    );
  }
}

class TodoListScreen extends StatefulWidget {
  const TodoListScreen({super.key});

  @override
  State<TodoListScreen> createState() => _TodoListScreenState();
}

class _TodoListScreenState extends State<TodoListScreen> {
  final TextEditingController _controller = TextEditingController();

  Future<void> _addTodo() async {
    final text = _controller.text.trim();
    if (text.isEmpty) return;
    await Supabase.instance.client.from('todos').insert({'title': text});
    _controller.clear();
  }

  Future<void> _toggle(Todo todo) async {
    await Supabase.instance.client
        .from('todos')
        .update({'is_done': !todo.isDone}).eq('id', todo.id);
  }

  Future<void> _delete(Todo todo) async {
    await Supabase.instance.client.from('todos').delete().eq('id', todo.id);
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Realtime Todos')),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(12),
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: _controller,
                    decoration: const InputDecoration(
                      hintText: 'What needs doing?',
                      border: OutlineInputBorder(),
                    ),
                    onSubmitted: (_) => _addTodo(),
                  ),
                ),
                const SizedBox(width: 8),
                FilledButton(onPressed: _addTodo, child: const Text('Add')),
              ],
            ),
          ),
          Expanded(
            child: RealtimeListBuilder<Todo>(
              client: Supabase.instance.client,
              table: 'todos',
              fromJson: Todo.fromJson,
              getId: (t) => t.id,
              orderBy: 'created_at',
              ascending: false,
              loadingBuilder: (_) =>
                  const Center(child: CircularProgressIndicator()),
              errorBuilder: (_, error) =>
                  Center(child: Text('Error: $error')),
              builder: (context, todos) {
                if (todos.isEmpty) {
                  return const Center(child: Text('No todos yet.'));
                }
                return ListView.separated(
                  itemCount: todos.length,
                  separatorBuilder: (_, __) => const Divider(height: 1),
                  itemBuilder: (context, i) {
                    final todo = todos[i];
                    return ListTile(
                      leading: Checkbox(
                        value: todo.isDone,
                        onChanged: (_) => _toggle(todo),
                      ),
                      title: Text(
                        todo.title,
                        style: TextStyle(
                          decoration: todo.isDone
                              ? TextDecoration.lineThrough
                              : null,
                        ),
                      ),
                      trailing: IconButton(
                        icon: const Icon(Icons.delete_outline),
                        onPressed: () => _delete(todo),
                      ),
                    );
                  },
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}
0
likes
160
points
8
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A small set of Flutter widgets that bind directly to Supabase Realtime channels — list, value, and presence builders with automatic subscription lifecycle.

Repository (GitHub)
View/report issues

Topics

#supabase #realtime #widget #postgres #presence

License

MIT (license)

Dependencies

flutter, supabase_flutter

More

Packages that depend on supabase_realtime_widgets