0

I'd like to add more info the following UserModel and make it available throughout all screens of the app. I've been struggling with the basics of Provider. Should I use a separate class extending the ChangeNotifier and store those additional properties there? The example below is trying to add idVendor (id_vendor). I could use ProviderOf on every place where I need that information but it would be a new request every time I do it. Any help would be really appreciated:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:firebase_core/firebase_core.dart';
import 'dart:convert';
import 'package:firebase_auth/firebase_auth.dart';
import 'dart:async';
import 'package:http/http.dart' as http;

void main() async {
    WidgetsFlutterBinding.ensureInitialized();
    await Firebase.initializeApp();
    runApp(const App());
}

class App extends StatelessWidget {
    const App({Key? key}) : super(key: key);
    @override
    Widget build(BuildContext context) {
        return MultiProvider(
            providers: [
                Provider<AuthRepository>(create: (_) => AuthRepository()),
                StreamProvider<UserModel?>(create: (context) =>
                    context.read<AuthRepository>().monitorAuthStateChanges,
                    initialData: null,
                ),
            ],
            child: const MaterialApp(home: AuthCheck()),
        );
    }
}

class AuthCheck extends StatelessWidget {
    const AuthCheck({Key? key}) : super(key: key);
    @override
    Widget build(BuildContext context) {
        final userModel = Provider.of<UserModel?>(context);
        if (userModel != null) {
            return const MainPage();
        } else {
            return const LoginScreen();
        }
    }
}

class UserModel {
    final String uid;
    late final int? idVendor;
    UserModel({required this.uid, this.idVendor});
}

class AuthRepository {
    final FirebaseAuth _fireAuth = FirebaseAuth.instance;

    Stream<UserModel?> get monitorAuthStateChanges {
        return _fireAuth.authStateChanges().map(_userModel);
    }

    UserModel? _userModel(User? user) {
        if (user != null) {
            return UserModel(uid: user.uid);
        } else {
            return null;
        }
    }

    Future<void> addInfoToUser() async {
        final userModel = _userModel(_fireAuth.currentUser);
        if (userModel != null) {
            String endPoint = '${ApiEndPoints.userIdVendor}';
            String url = endPoint.replaceAll('id', userModel.uid);
        try {
            final response = await http.get(Uri.parse(url), headers: {
                'Content-Type': 'application/json; charset=utf-8',
            }).timeout(const Duration(seconds: 60));
            if (response.statusCode == 200) {
                final Map<String, dynamic> jsonResponseBody =
                    jsonDecode(response.body);
                final List<dynamic> data = jsonResponseBody['data'];
                userModel.idVendor = data[0]['id_vendor'];
            }
        } on Exception catch (e) {
            return Future.error('Exception\n($e)\n(${e.toString()})');
        }
    }
}
}
Rod Rodrigues
  • 53
  • 1
  • 9

2 Answers2

1

You can have copyWith method inside UserModel to assign or change idVendor parameter.

class UserModel {
  UserModel({required this.uid, this.idVendor});

  final String uid;
  final int? idVendor;

  UserModel copyWith({String? uid, int? idVendor}) => UserModel(
        uid: uid ?? this.uid,
        idVendor: idVendor ?? this.idVendor,
      );
}

Then inside addInfo use _userModel.copywith(idVendor: newId);

Soliev
  • 1,180
  • 1
  • 1
  • 12
  • Hi Soliev, actually I want to retrieve the id_vendor from the API and store it inside the UserModel. Then be able to use it on all screens across the app. Have you dealt with that kind of functionality in your apps? Thanks for the time answering the question though. – Rod Rodrigues Jul 12 '23 at 02:08
0

I've just found the answer. Hence the data my changenotifierprovider is using comes from an API http request I had to use a Future, then I had to "await" for it asynchronously. Finally, after reading the package documentation on pub.dev, and since the obtained values are used just as static parameters, I was able to use them with an oneliner in the initState.

https://pub.dev/packages/provider

Rod Rodrigues
  • 53
  • 1
  • 9