govardhan
govardhan

Reputation: 1

how to pass database as a constructor argument to the ......class and use that as an instance variable rather than with Provider.of<Database>

I want to write the data to the fire store database.

I wrote the code in this way in subscriptions class:

import 'package:flutter/material.dart';
import 'package:flutterapptest/services/database.dart';
import 'package:provider/provider.dart';

class Subscriptions extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Subscribed'),
        ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () => _addTrack(context),
      ),
    );
  }
  Future<void> _addTrack(BuildContext context) async {
    final database = Provider.of<Database>(context, listen: false);
    await database.addTrack({
      'name': 'Track',
      'time': 20,
    });
  }
}

in the database class ......

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

abstract class Database {
Future<void> addTrack(Map<String, dynamic> trackData);
}
class FirestoreDatabase implements Database {
  FirestoreDatabase({@required this.uid}) : assert(uid != null);
  final String uid;

  Future<void> addTrack(Map<String, dynamic> trackData) async{
    final path = '/users/$uid/track/track_abc';
    final documentReference = Firestore.instance.document(path);
    await documentReference.setData(trackData);
  }
}

for this i am getting the error:

could not find the correct Provider<Database> above the subscriptions widget

For this a friend suggested me to do:

If you push the Subscriptions widget inside a route, it won't have access to Provider.of<Database>.

The quickest solution is to pass Database as a constructor argument to the Subscriptions class, and use that as an instance variable rather than with Provider.of<Database>

Can anyone please help me what should i do now? I am new to flutter.

Upvotes: 0

Views: 364

Answers (1)

Neli
Neli

Reputation: 741

This is how I would do it. I know this includes much more then just the addTrack function but I guess you also need a global state somewhen and a changeNotifier, otherwise it makes no sense to use the provider.

First create the service:

import 'package:cloud_firestore/cloud_firestore.dart';

final CollectionReference firestoreUsers =
    Firestore.instance.collection('users');

class UserService {
  static Future<Stream<Map<String, dynamic>>> streamTrack(String userId) async {
    Stream<DocumentSnapshot> query =
        await firestoreUsers.document('pathToListen...').snapshots();
    return query.map((doc) => Map.from(doc.data));
  }

  static addTrack(String userId, Map<String, dynamic> trackData) async {
    await firestoreUsers
        .document(userId)
        .collection('track')
        .document('track_abc')
        .setData(trackData);
  }
}

Then the provider which holds the global state and uses the changeNotifier. These are just placeholders. Put there whatever you want to listen in the database.

import 'dart:async';
import 'package:flutter/material.dart';
import '../models_services/user_services.dart';

class UserProvider with ChangeNotifier {

  // your global state, if you want to listen for data from database
  StreamSubscription<Map<String, dynamic>> trackStream;
  Map<String, dynamic> _streamedTrack;
  Map<String, dynamic> get streamedTrack => _streamedTrack;

  Future streamCurrentTrack(uid) async {

    if(trackStream != null) {
      trackStream.cancel();
    }
    Stream<Map<String, dynamic>> res = await UserService.streamTrack(uid);

    trackStream = res.listen((track) {
      _streamedTrack = track;
      notifyListeners();
    });
  }

  Future<void> addTrack(Map<String, dynamic> trackData) async {
    // not sure what this is doing, i guess uid is null here...
    FirestoreDatabase({@required this.uid}) : assert(uid != null);
    final String uid;

    await UserService.addTrack(uid, trackData);
  }
}

Use the provider with changeNotifier in your code:

import 'package:flutter/material.dart';
import 'package:flutterapptest/provider/user_provider.dart';
import 'package:provider/provider.dart';

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
        providers: [
          ChangeNotifierProvider(create: (context) => UserProvider()),
          ...
        ],
        child: MaterialApp(
            home: Scaffold(body: Subscriptions()
                )));
  }
}

class Subscriptions extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Subscribed'),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () => _addTrack(context),
      ),
    );
  }

  Future<void> _addTrack(BuildContext context) async {
    final database = Provider.of<UserProvider>(context, listen: false);
    await database.addTrack({
      'name': 'Track',
      'time': 20,
    });
  }
}

Upvotes: 1

Related Questions