Soojeong Lee

Aug 3, 2025

Soojeong Lee

Aug 3, 2025

Soojeong Lee

Aug 3, 2025

Upload a photo

Upload a photo

Upload a photo

Firebase Storage + Firestore

Now that the integration work is complete, I am gradually working on the CRUD operations.

Basically, I am using the riverpod state management library.

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

final firebaseStorageProvider = Provider((ref) => FirebaseStorage.instance);
final firebaseFirestoreProvider = Provider((ref) => FirebaseFirestore.instance);
final firebaseAuthProvider = Provider((ref) => FirebaseAuth.instance);


There are two business logic processes that run when adding a photo.

  1. Upload the photo.

  2. Add the photo object.

import 'dart:io';

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:uuid/uuid.dart';

import '../../models/media_memory.model.dart';
import 'firebase.provider.dart';

final mediaMemoryProvider =
    StateNotifierProvider<MediaMemoryController, AsyncValue<List<MediaMemory>>>(
      (ref) => MediaMemoryController(
        ref.watch(firebaseStorageProvider),
        ref.watch(firebaseFirestoreProvider),
        ref.watch(firebaseAuthProvider),
      ),
    );

class MediaMemoryController
    extends StateNotifier<AsyncValue<List<MediaMemory>>> {
  MediaMemoryController(this._storage, this._firestore, this._auth)
    : super(const AsyncValue.data([]));

  final FirebaseStorage _storage;
  final FirebaseFirestore _firestore;
  final FirebaseAuth _auth;

  Future<void> createMany({
    required String lostPersonId,
    required List<File> files,
  }) async {
    state = const AsyncValue.loading();

    final List<MediaMemory> uploadedMemories = [];
    final userId = _auth.currentUser?.uid;

    try {
      for (final file in files) {
        final fileName = const Uuid().v4();
        final ref = _storage.ref('memories/$userId/$lostPersonId/$fileName');

        final task = await ref.putFile(file);
        final url = await task.ref.getDownloadURL();
        final memory = MediaMemory(url: url, createdAt: DateTime.now());

        final docRef = _firestore.collection('lost_persons').doc(lostPersonId);
        await docRef.update({
          'photos': FieldValue.arrayUnion([memory.toJson()]),
        });

        uploadedMemories.add(memory);
      }

      state = AsyncValue.data(uploadedMemories);
    } catch (e, st) {
      state = AsyncValue.error(e, st);
    }
  }
}

As you can see from the above actions, after uploading the photo to Firebase Storage, an object is created based on the corresponding URL.

This object is then saved to Firestore to establish a relationship. You can see that the photo upload has completed successfully. The gallery-style photo preview can be seen when fetched by URL.

itemBuilder: (context, i) {
      final photo = person.photos[i];
      return ClipRRect(
        borderRadius: BorderRadius.circular(8),
        child: Image.network(
          photo.url,
          fit: BoxFit.cover,
          errorBuilder: (context, error, stackTrace) =>
              Container(
                color: colorScheme.outline,
                child: const Icon(Icons.broken_image),
              ),
          loadingBuilder: (context, child, progress) {
            if (progress == null) return child;
            return Container(
              color: colorScheme.outline,
              child: const Center(
                child: CircularProgressIndicator(
                  strokeWidth: 2,
                ),
              ),
            );
          },
        ),
      );

I haven't started the video preview yet.


Feeling a bit overwhelmed...

Because I am handling all the logic on the client-side, the various forms that were processed on the server are getting tangled in my mind, and Firestore does not have a separate ORM that is intuitively visible, so it feels a bit overwhelming.

After refactoring the object forms and table structure, I will continue with the next tasks.

Comments

Comments

Comments

Create a free website with Framer, the website builder loved by startups, designers and agencies.