Getting network image with an url – flutter, firebase – error

Issue

I’m getting an error " Invalid argument(s): No host specified in URI file:///" and also "StateError (Bad state: field does not exist within the DocumentSnapshotPlatform)" while trying to receive an image from an url that user types in the app. The whole screen is provided with BlocProvider and BlocBuilder conected too the Firebase. I noticed the error might be connected to the url format from the internet. I’ll be thankfull for any help. My code for the Home Screen and Add Screen and also the cubits look like this…

This is the page view, where user can see the list of firebase documents:

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:curlzzz_new/features/add_upcoming_movies/addd_upcoming_movies.dart';
import 'package:curlzzz_new/features/upcoming/cubit/upcoming_movies_cubit.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.of(context).push(
            MaterialPageRoute(
              builder: (_) => AddUpcomingMovie(),
              fullscreenDialog: true,
            ),
          );
        },
        child: const Icon(Icons.add),
      ),
      body: BlocProvider(
        create: (context) => UpcomingMoviesCubit()..start(),
        child: BlocBuilder<UpcomingMoviesCubit, UpcomingMoviesState>(
          builder: (context, state) {
            if (state.errorMessage.isNotEmpty) {
              return Text('Something went wrog: ${state.errorMessage}');
            }
            if (state.isLoading) {
              return const Center(
                child: CircularProgressIndicator(),
              );
            }
            final documents = state.documents;
            return ListView(
              children: [
                for (final document in documents) ...[
                  UpcomingMovieWidget(
                    document: document,
                  ),
                ]
              ],
            );
          },
        ),
      ),
    );
  }
}

class UpcomingMovieWidget extends StatelessWidget {
  const UpcomingMovieWidget({
    Key? key,
    required this.document,
  }) : super(key: key);

  final QueryDocumentSnapshot<Object?> document;

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(20.0),
      margin: const EdgeInsets.all(20.0),
      color: const Color.fromARGB(255, 243, 177, 198),
      height: 200,
      child: Column(
        children: [
          Container(
            height: 80,
            decoration: BoxDecoration(
              color: Colors.black12,
              image: DecorationImage(
                image: NetworkImage(
                  document['url'],
                ),
                fit: BoxFit.cover,
              ),
            ),
          ),
          Container(
            color: Colors.white,
            height: 20,
            width: 300,
            child: Center(
              child: Text(document['title']),
            ),
          ),
          const SizedBox(
            height: 20,
          ),
          Container(
            color: Colors.white,
            child: Text(
              (document['date'] as Timestamp).toDate().toString(),
            ),
          )
        ],
      ),
    );
  }
}

this is my cubit

import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:meta/meta.dart';

part 'upcoming_movies_state.dart';

class UpcomingMoviesCubit extends Cubit<UpcomingMoviesState> {
  UpcomingMoviesCubit()
      : super(
          UpcomingMoviesState(
            documents: const [],
            errorMessage: '',
            isLoading: false,
          ),
        );
  StreamSubscription? _streamSubscription;

  Future<void> start() async {
    emit(
      UpcomingMoviesState(
        documents: const [],
        errorMessage: '',
        isLoading: true,
      ),
    );
    _streamSubscription = FirebaseFirestore.instance
        .collection('upcoming')
        .snapshots()
        .listen((data) {
      emit(
        UpcomingMoviesState(
          documents: data.docs,
          errorMessage: '',
          isLoading: false,
        ),
      );
    })
      ..onError((error) {
        emit(
          UpcomingMoviesState(
            documents: const [],
            errorMessage: error.toString(),
            isLoading: false,
          ),
        );
      });
  }

  @override
  Future<void> close() {
    _streamSubscription?.cancel();
    return super.close();
  }
}

this is an add page, where user can input the url

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:curlzzz_new/features/add_upcoming_movies/cubit/add_upcoming_movies_cubit.dart';
import 'package:curlzzz_new/features/upcoming/cubit/upcoming_movies_cubit.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class AddUpcomingMovie extends StatefulWidget {
  AddUpcomingMovie({super.key});

  @override
  State<AddUpcomingMovie> createState() => _AddUpcomingMovieState();
}

class _AddUpcomingMovieState extends State<AddUpcomingMovie> {
  String? _title;
  String? _url;
  DateTime? _date;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Add upcoming movie'),
        actions: [
          BlocProvider(
            create: (context) => AddUpcomingMoviesCubit(),
            child: BlocBuilder<AddUpcomingMoviesCubit, AddUpcomingMoviesState>(
              builder: (context, state) {
                return IconButton(
                  onPressed: _title == null || _url == null || _date == null
                      ? null
                      : () {
                          context.read<AddUpcomingMoviesCubit>().upcoming(_title!, _url!,_date!);
                         
                        },
                  icon: Icon(
                    Icons.check,
                  ),
                );
              },
            ),
          )
        ],
      ),
      body: AddBody(
        onTitleChanged: (newValue) {
          setState(
            () {
              _title = newValue;
            },
          );
        },
        onUrlChanged: (newValue) {
          setState(
            () {
              _url = newValue;
            },
          );
        },
        onDateChanged: (newValue) {
          setState(
            () {
              _date = newValue;
            },
          );
        },
        dateFormatted: _date?.toIso8601String(),
      ),
    );
  }
}

class AddBody extends StatelessWidget {
  const AddBody({
    Key? key,
    required this.onDateChanged,
    required this.onTitleChanged,
    required this.onUrlChanged,
    this.dateFormatted,
  }) : super(key: key);

  final Function(String) onTitleChanged;
  final Function(String) onUrlChanged;
  final Function(DateTime) onDateChanged;
  final String? dateFormatted;

  @override
  Widget build(BuildContext context) {
    return Center(
        child: Column(
      children: [
        TextField(
          decoration: InputDecoration(
            hintText: 'Titanic',
          ),
          onChanged: onTitleChanged,
        ),
        TextField(
          decoration: InputDecoration(
            hintText: 'data:image/basBAQA.jpeg',
          ),
          onChanged: onUrlChanged,
        ),
        ElevatedButton(
          onPressed: () async {
            final selectedDate = await showDatePicker(
              context: context,
              initialDate: DateTime.now(),
              firstDate: DateTime.now(),
              lastDate: DateTime.now().add(
                const Duration(days: 365 * 10),
              ),
            );
            onDateChanged(selectedDate!);
          },
          child: Text(dateFormatted ?? 'Choose release date'),
        ),
      ],
    ));
  }
}

this is the cubit

import 'package:bloc/bloc.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:meta/meta.dart';

part 'add_upcoming_movies_state.dart';

class AddUpcomingMoviesCubit extends Cubit<AddUpcomingMoviesState> {
  AddUpcomingMoviesCubit() : super(AddUpcomingMoviesState(errorMessage: ''));

  Future<void> upcoming(
    String title,
    String url,
    DateTime date,
  ) async {
    try {
      await FirebaseFirestore.instance.collection('upcoming').add({
        title: 'title',
        url: 'url',
        date.toString(): 'date',
      });
    } catch (error) {
      emit(AddUpcomingMoviesState(errorMessage: error.toString()));
    }
  }
}

Solution

You just need to replace the key & value of the map.
Replace

{
title: ‘title’,
url: ‘url’,
date.toString(): ‘date’,
}

With

{
‘title’: title,
‘url’: url,
‘date’: date,
}

By the way, don’t save DateTime as String. Just pass the date as it is. It saves as Timestamp object so you can do query with it. While retrieving just use map[‘date’].toDate() to convert into DateTime object.

Hope it helps!

Answered By – BHARATH T

Answer Checked By – Candace Johnson (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *