Dart Inherit class and Use it in functions of the parent class - flutter

I want to make a parent class which use ChangeNotifier. And from this class, I want to create two separate inherited classes that will provide list data to some parts of the app, and each will have its own separate list. But I could not figure out how each class could create its own list and only make operations on that list via using superclass. Can someone explain to me how can I manage this?
import 'package:flutter/material.dart';
class ObjectListProvider<T extends num, K extends Object> with ChangeNotifier {
final Map<T, K> _map = {};
Map<T, K> get map {
return {..._map};
}
K? getSingleObjectWithId(id) {
return _map[id];
}
void add(T id, K obj) {
_map[id] = obj;
notifyListeners();
}
void remove(T id) {
_map.remove(id);
notifyListeners();
}
}
import 'object_list_provider.dart';
import '../person.dart';
class PersonList extends ObjectListProvider {
final Map<dynamic, Person> _people = {};
}
import './object_list_provider.dart';
import '../group.dart';
import '../person.dart';
class GroupList extends ObjectListProvider {
final Map<dynamic, Group> _groups = {};
void addPersonToGroup<T extends num>(Person person, T id) {
super.add(id, person);
notifyListeners();
}
void removePersonFromGroup<T extends num>(Person person, T id) {
_groups[id]?.removePerson(id);
notifyListeners();
}
}
import './person.dart';
import './transaction.dart';
class Group {
final int _id;
String _name;
List<Person> _people = [];
List<Transaction> _transactions = [];
int _totalSpending;
Group({required int id, required String name, int totalSpending = 0})
: _id = id,
_name = name,
_totalSpending = totalSpending;
int get id {
return _id;
}
String get name {
return _name;
}
int get totalSpending {
return _totalSpending;
}
set name(String newName) {
_name = newName;
}
void addPerson(Person person) {
_people.add(person);
}
void removePerson<T extends num>(T id) {
_people = _people.where((Person person) => person.id != id).toList();
}
void addTransaction(Transaction transaction) {
_transactions.add(transaction);
}
}
class Person {
final int _id;
final String _name;
int _balance;
List<int> involvedGroups = [];
Person({required int id, required String name, int balance = 0})
: _id = id,
_name = name,
_balance = balance;
int get id {
return _id;
}
}
For example, I will use this provider in some other dart file as
final groupList = Provider.of<GroupList>(context);
groupList.add(....)

I refactored my code and came up with a solution that worked for me. Let me try to explain future reads as much as I can.
changed map from private to public. I am not sure it is the best way but it worked for this case. I was also able to work it with getter and setters but by doing that provider object did end up having two variables as _map and map.
import 'package:flutter/material.dart';
class ObjectListProvider<T extends num, K extends Object> with ChangeNotifier {
Map<T, K> map = {};
K? getSingleObjectWithId(id) {
return map[id];
}
void add(T id, K obj) {
map[id] = obj;
notifyListeners();
}
void remove(T id) {
map.remove(id);
notifyListeners();
}
}
Add generics after extending. This way I was able to access the map variable which previously I made publicly accessible. did the same thing for the PersonList as well.
import './object_list_provider.dart';
import '../group.dart';
import '../person.dart';
class GroupList extends ObjectListProvider<num, Group> {
void addPersonToGroup<T extends num>(Person person, T id) {
super.map[id]?.addPerson(person);
notifyListeners();
}
void removePersonFromGroup<T extends num>(Person person, T id) {
super.map[id]?.addPerson(person);
notifyListeners();
}
}
Other than these I did not changed anything related. Now I can call and use provider in some other file as
...
#override
Widget build(BuildContext context) {
final groupList = Provider.of<GroupList>(context);
final groups = groupList.map;
return ListView.builder(
itemCount: groups.length,
itemBuilder: (context, int index) {
return ListTile(
onTap: () => index,
title: Text(groups[groups.keys.elementAt(index)]!.name),
trailing: Text(
groups[groups.keys.elementAt(index)]!.totalSpending.toString(),
),
);
},
);
}
...

I'm working on something simmilar(not current version) at the moment. I would like to try and help if and where I can - though with the caveat that I'm still figuring out a lot of the basics myself.
Could you narrow-down or re-phrase the problem?
What I've done in the app I linked to above, as far as I think it might be relevant to you after a quick skim through your code, what I've done is:
To 'hold' the list and as much as possible of the functionality in the parent class.
In my case, each child class extends that parent - I'm calling it a 'listicle', and the type of object is specific to that childTypeListicle (for now).
The child classes hold specification of the types they list - in my case each it type shares an abstract parent Item class - as well as some config details for e.g. remote access and factory constructors. These' fields communicate up to the parent interfacing and its generic-ized functionality around the list through abstract method declarations enforced by the shared parent class. So that crteates a kind of the list as axel while it its reasonably item-type agnostic. Make sense?
Seems to work well so far, basically holds the logic this side of the plane-of-presentation implementation.
I also have tertiary connected interface elements like bottom-alert-bar connecting into fields of the parent 'listicle', and creating a kind of navigation ui that manipulates the list out onto the listview builder. Would like to also build in some partial local repository-ing but that doesn't seem a priority at the moment for this project.
I hope some of that helps somehow.

Related

Error on generated file for AsyncNotifierProvider `.family` Riverpod providers

I wonder if I am overlooking something. When ever I try to generate the following via riverpod_annotation I'm getting the error below where it cannot find Family class. I'm pretty sure I'm doing something wrong, but I'm not sure what.
I've deleted and rebuilt the file multiple times and I'm not sure what I can change to make it work.
Here's the gist with both the controller and the generated controller logic
https://gist.github.com/Morzaram/7d75bcfed06ea7cce88a8b11c4fad223
import 'package:front_end/utils/pocketbase_provider.dart';
import 'package:pocketbase/pocketbase.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'mangage_topic_voices_controller.g.dart';
#riverpod
class ManageTopicVoicesController extends _$ManageTopicVoicesController {
List<String> _selectedVoices = [];
bool mounted = true;
get selectedVoices => _selectedVoices;
#override
FutureOr<void> build({required List<String> ids}) {
ref.onDispose(() {
mounted = false;
});
if (mounted) {
_selectedVoices = ids;
}
}
void addVoice(String id) {
_selectedVoices = [..._selectedVoices, id];
}
void removeVoice(String id) {
_selectedVoices = _selectedVoices.where((e) => e != id).toList();
}
Future<RecordModel> updateTopic({topicId, selectedVoices}) async {
final res = await pb
.collection('topics')
.update(topicId, body: {"voices": selectedVoices});
return res;
}
}
The error I'm getting is Classes can only extend other classes. Try specifying a different superclass, or removing the extends clause. and it's occuring on the first line of Family<AsyncValue<void>>
class ManageTopicVoicesControllerFamily extends Family<AsyncValue<void>> {
ManageTopicVoicesControllerFamily();
ManageTopicVoicesControllerProvider call({
required List<String> ids,
}) {
return ManageTopicVoicesControllerProvider(
ids: ids,
);
}
#override
AutoDisposeAsyncNotifierProviderImpl<ManageTopicVoicesController, void>
getProviderOverride(
covariant ManageTopicVoicesControllerProvider provider,
) {
return call(
ids: provider.ids,
);
}
#override
List<ProviderOrFamily>? get allTransitiveDependencies => null;
#override
List<ProviderOrFamily>? get dependencies => null;
#override
String? get name => r'manageTopicVoicesControllerProvider';
}
I know that the error is saying that the Family class doesn't exist, but I'm not sure if the error is due to me or not.
Can I not use family with this currently? I would love any help that I can get.
I'm new to dart, so apologies, and thank you in advance!
Here's the gist with both files

What does " int? get priority => 1;" do?

I was reading a flutter code as below:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:test_get_app/user_controller.dart';
class AuthMiddleware extends GetMiddleware {
final authService = UserController.findOrInitialize; // Here is error, this line can't find UserController
#override
int? get priority => 1;
bool isAuthenticated = false;
#override
RouteSettings? redirect(String? route) {
isAuthenticated = true;
if (isAuthenticated == false) {
return const RouteSettings(name: '/login');
}
return null;
}
}
When I reached to the following line, I couldn't understand it's syntax and how does it work?
int? get priority => 1;
int? Means it is an int but the int can be null
=> 1 Means () {return 1;}
This is a so-called getter. Getters can be used to provide read access to class properties.
They can also return values directly, like in your case.
They are accessed like properties of the class they are declared in:
final middleWare = AuthMiddleware();
final priority = middleWare.priority;
In your case the getter probably must or can be implemented (see the #override annotation), since all implementations of a middleware must declare their priority, I guess. Since the declared type is int? it may also return null instead of an integer.
Getters can be declared using an expression. Like in your case. Using a block body does also work:
int? get priority {
return 1;
}

Unable to access property values of a class from another class in Dart

I'm trying to access property values of a class from another class but unable to do so. I may be doing it wrong and hence I'm here looking for answers.
In my app there is a class called CartRepository which holds cart items.
class CartRepository {
List<Product> cartItems = [];
List<Product> get getCartItems => cartItems;
void addItem(Product product) {
cartItems.add(product);
}
}
Through bloc I'm updating the values of cartItems by creating an object for CartRepository.
There is another class called OrderRepository where I need to bring in the cartItems from CartRepository along with other information from UI and update it in a db.
But when I create another object for CartRepository inside OrderBloc and access the cartItems, the value it returns is an empty List. How can I access the cartItems that has the data in another place?
OrderBloc
class OrderProviderBloc extends Bloc<OrderProviderEvent, OrderProviderState> {
OrderProviderBloc() : super(OrderProviderInitial());
CartRepository cartRepository = CartRepository();
OrderRepository orderRepository = OrderRepository();
#override
Stream<OrderProviderState> mapEventToState(
OrderProviderEvent event,
) async* {
if (event is PlaceOrderEvent) {
try {
orderRepository.placeOrder(cartRepository.cartItems,event.userMobileNumber);
} on Exception {}
}
}
}
OrderRepository
class OrderRepository extends Equatable {
final List<Order> orders = [];
void placeOrder(
List<Product> cartItems, String userMobileNumber) {
orders.add(Order(
userMobileNumber: userMobileNumber,
productsFromCart: cartItems));
addOrderToFirebase(cartItems, userMobileNumber);
}
DO NOT set variables using getters!
DO NOT set value to final variables after declaring them
In these lines
List<Product> cartItems = CartRepository().cartItems;
print("Total from cart repository -------- ${cartRepository.totalCValue}");
orderRepository.placeOrder(cartRepository.cartItems,
cartRepository.totalCValue, event.userMobileNumber);
You are using getters to set values,
to fix this, add a setter along with the existing getter in CartRepository
Also since it's a final variable you need to call clear and then calladdAll to add new items to it.
class CartRepository extends Equatable {
final List<Product> _cartItems = [];
List<Product> get cartItems => _cartItems;
set cartItems(List<Product> newCardItems){
_cartItems.clear();
_cartItems.addAll(newCardItems);
}
}
What this line will do? you are not using this variable.
List<Product> cartItems = CartRepository().cartItems;

flutter : how to groupBy two or more fields?

how can I use groupBy function which is in collection.dart to group items by two fields and return a model class with them not one field like int?
If I group by one field, It works fine and there is no problem:
Map<int, List<FooterItem>> _getGroups(List<FooterItem> items) {
return groupBy(items, (FooterItem i) {
return i.groupId;
});
}
But when I wan to return a model class from result ,groupBy is not grouping values .
here I have a list of FooterItem which has It's group data and how can I use groupBy to group a List<FooterItem> by groupId and titleGroup and return FooterGroup not int :
class FooterItem {
final int id;//item id
final int groupId;
final String title;//item title
final String titleGroup;
...
}
Map<FooterGroup, List<FooterItem>> _getGroups(List<FooterItem> items) {
return groupBy(items, (FooterItem i) {
return FooterGroup(id: i.groupId, title: i.titleGroup);
});
}
I could solve problem by extending Equatable in the model class which I wanted to use as grouped values and overriding props :
import 'package:equatable/equatable.dart';
class FooterGroup extends Equatable{
final int id;
final String title;
FooterGroup({
#required this.id,
#required this.title,
});
#override
List<Object> get props => [id,title];
}
so duplicate values of Groups where not seen any more. so
Map<FooterGroup, List<FooterItem>> _getGroups(List<FooterItem> items) {
return groupBy(items, (FooterItem i) {
return FooterGroup(id: i.groupId, title: i.titleGroup);
});
}
works fine now.
A quick way to achieve this:
groupBy(footers, (FooterItem f) {
return '${f.groupId}+${f.titleGroup}';
});
Source: https://coflutter.com/dart-how-to-group-items-in-a-list/

How can I use variable of CubitState inside Cubit? Flutter/Bloc

so I don't have any idea how to take argument from mine Cubit state which is AnswerPicked in this case, there is a code from states file.
part of 'answer_cubit.dart';
abstract class AnswerState extends Equatable {
const AnswerState();
#override
List<Object> get props => [];
}
class AnswerInitial extends AnswerState {}
class AnswerPicked extends AnswerState {
final String answer;
AnswerPicked({
this.answer,
});
String toString() => '{AnswerPicked: $answer}';
}
I want to use it in Cubit function right there:
part 'answer_state.dart';
class AnswerCubit extends Cubit<AnswerState> {
final ExamScoreCubit scoreCubit;
AnswerCubit({
#required this.scoreCubit,
}) : super(AnswerInitial());
List<String> userAnswersList = [];
void pickAnswer(String answer) {
emit(AnswerInitial());
emit(AnswerPicked(answer: answer));
}
void takeAnswer(String questionAnswer, int type) {
if(state is AnswerPicked){
userAnswersList.add(state.answer); // state.answer don't work
scoreCubit.checkAnswer(AnswerPicked().answer, questionAnswer, type); // AnswerPicked().answer don't work
}
emit(AnswerInitial());
}
}
In void takeAnswer() I don't want to pass it throw argument inside the widget tree using context. Any ideas how to do it?
userAnswersList.add((state as AnswerPicked) .answer);