ExampleStorage · Database

File Upload

Pick an image from the device, upload it to Cloudflare R2, and save the URL to the user's profile in the database.

Prerequisites

Add image_picker to your pubspec.yaml and create an avatars bucket in the dashboard.

pubspec.yamlYAML
dependencies:
  koolbase: ^1.4.0
  image_picker: ^1.0.0

Profile avatar upload

lib/screens/profile_screen.dartDart
class ProfileScreen extends StatefulWidget {
  const ProfileScreen({super.key});
  @override
  State<ProfileScreen> createState() => _ProfileScreenState();
}
class _ProfileScreenState extends State<ProfileScreen> {
  String? _avatarUrl;
  bool _uploading = false;
  Future<void> _pickAndUpload() async {
    final picker = ImagePicker();
    final picked = await picker.pickImage(
      source: ImageSource.gallery,
      maxWidth: 800,
      imageQuality: 85,
    );
    if (picked == null) return;
    setState(() => _uploading = true);
    try {
      final user = await Koolbase.auth.currentUser();
      final bytes = await picked.readAsBytes();
      // 1. Upload to R2
      await Koolbase.storage.uploadBytes(
        bytes,
        bucket: 'avatars',
        path: 'user_${user!.id}.jpg',
        contentType: 'image/jpeg',
        onProgress: (sent, total) {
          // Optional: show progress
        },
      );
      // 2. Get the download URL
      final url = await Koolbase.storage.getDownloadUrl(
        bucket: 'avatars',
        path: 'user_${user.id}.jpg',
      );
      // 3. Save URL to user's profile record
      await Koolbase.db
        .collection('profiles')
        .doc(user.id)
        .update({'avatar_url': url});
      setState(() => _avatarUrl = url);
    } finally {
      setState(() => _uploading = false);
    }
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            GestureDetector(
              onTap: _uploading ? null : _pickAndUpload,
              child: CircleAvatar(
                radius: 50,
                backgroundImage: _avatarUrl != null
                  ? NetworkImage(_avatarUrl!)
                  : null,
                child: _uploading
                  ? const CircularProgressIndicator()
                  : (_avatarUrl == null ? const Icon(Icons.add_a_photo) : null),
              ),
            ),
            const SizedBox(height: 16),
            const Text('Tap to change avatar'),
          ],
        ),
      ),
    );
  }
}

Load profile on startup

lib/screens/profile_screen.dartDart
@override
void initState() {
  super.initState();
  _loadProfile();
}
Future<void> _loadProfile() async {
  final user = await Koolbase.auth.currentUser();
  if (user == null) return;
  final record = await Koolbase.db
    .collection('profiles')
    .doc(user.id)
    .get();
  setState(() => _avatarUrl = record.data['avatar_url']);
}