supabase_easy 0.0.1
supabase_easy: ^0.0.1 copied to clipboard
Easy-to-use Supabase helpers for Flutter
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:supabase_easy/supabase_easy.dart';
import 'todo_model.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await SupabaseEasy.initialize(
url: 'YOUR_SUPABASE_URL',
anonKey: 'YOUR_SUPABASE_ANON_KEY',
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Supabase Easy Demo',
theme: ThemeData(primarySwatch: Colors.blue, useMaterial3: true),
home: const TodoListScreen(),
);
}
}
class TodoListScreen extends StatefulWidget {
const TodoListScreen({super.key});
@override
State<TodoListScreen> createState() => _TodoListScreenState();
}
class _TodoListScreenState extends State<TodoListScreen> {
// Create a repository for Todos
final todoRepository = EasyRepository<Todo>(
tableName: 'todos',
fromJson: Todo.fromJson,
);
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
bool _isLoading = false;
Future<void> _signIn() async {
setState(() => _isLoading = true);
try {
await EasyAuth.signIn(
email: _emailController.text.trim(),
password: _passwordController.text.trim(),
);
} catch (e) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Login failed: $e'),
backgroundColor: Colors.red,
),
);
} finally {
if (mounted) setState(() => _isLoading = false);
}
}
Future<void> _signUp() async {
setState(() => _isLoading = true);
try {
await EasyAuth.signUp(
email: _emailController.text.trim(),
password: _passwordController.text.trim(),
);
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Check your email for confirmation!')),
);
} catch (e) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Signup failed: $e'),
backgroundColor: Colors.red,
),
);
} finally {
if (mounted) setState(() => _isLoading = false);
}
}
Future<void> _createTodo() async {
try {
await todoRepository.create(
Todo(
id: DateTime.now().millisecondsSinceEpoch.toString(),
title: 'New Todo',
),
);
} catch (e) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $e'), backgroundColor: Colors.red),
);
}
}
@override
Widget build(BuildContext context) {
return StreamBuilder<AuthState>(
stream: EasyAuth.onAuthStateChange,
builder: (context, authSnapshot) {
final session = authSnapshot.data?.session;
if (session == null && EasyAuth.currentSession == null) {
return Scaffold(
appBar: AppBar(title: const Text('Login')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: _emailController,
decoration: const InputDecoration(labelText: 'Email'),
),
TextField(
controller: _passwordController,
decoration: const InputDecoration(labelText: 'Password'),
obscureText: true,
),
const SizedBox(height: 20),
if (_isLoading)
const CircularProgressIndicator()
else ...[
ElevatedButton(
onPressed: _signIn,
child: const Text('Sign In'),
),
TextButton(
onPressed: _signUp,
child: const Text('Sign Up'),
),
],
],
),
),
);
}
return Scaffold(
appBar: AppBar(
title: const Text('Easy Todos'),
actions: [
IconButton(
icon: const Icon(Icons.logout),
onPressed: () async {
try {
await EasyAuth.signOut();
} catch (e) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Logout failed: $e')),
);
}
},
),
],
),
body: Column(
children: [
Expanded(
child: StreamBuilder<List<Todo>>(
// Simplified Real-time stream
stream: todoRepository.stream(primaryKey: ['id']),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
}
if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator());
}
final todos = snapshot.data!;
if (todos.isEmpty) {
return const Center(
child: Text('No todos yet. Add one!'),
);
}
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: ListView.builder(
padding: EdgeInsets.zero,
itemCount: todos.length,
itemBuilder: (context, index) {
final todo = todos[index];
return ListTile(
contentPadding: EdgeInsets.zero,
title: Text(todo.title),
trailing: Checkbox(
value: todo.isCompleted,
onChanged: (val) async {
try {
await todoRepository.update(
Todo(
id: todo.id,
title: todo.title,
isCompleted: val ?? false,
),
);
} catch (e) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Update failed: $e'),
backgroundColor: Colors.red,
),
);
}
},
),
onLongPress: () async {
try {
await todoRepository.delete(todo.id);
} catch (e) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Delete failed: $e'),
backgroundColor: Colors.red,
),
);
}
},
);
},
),
);
},
),
),
CircularProgressIndicator(),
],
),
floatingActionButton: FloatingActionButton(
onPressed: _createTodo,
child: const Icon(Icons.add),
),
);
},
);
}
}