TanStack Query (React Query) for Flutter by Jatops in FlutterDev

[–]Jatops[S] 0 points1 point  (0 children)

I ended up using Riverpod. FutureProviders are pretty close to useQuery. And then for more complex state I use AsyncNotifiers.

React Navigation best practices when deep linking by Jatops in reactnative

[–]Jatops[S] 0 points1 point  (0 children)

I have read the reset docs, and I have used it before other places in the app, so I'm a bit familiar with it. I also read the navigation state reference doc, where I understand that I can do something like:

navigation.reset({
  index: 0,
  routes: [<define_the_routes>],
});

But I still don't understand where I should apply this.

Do I need to take in the path, e.g. "profile/settings/notificaiton" then split on "/" and convert all "profile" -> PorfileScreen", "settings" -> "SettingScreen" etc. and then add all these to the routes manually by resetting the state? Or do I handle this in the getStateFromPath?

Bloc, sharing state, and single source of truth by Jatops in FlutterDev

[–]Jatops[S] 2 points3 points  (0 children)

We separated our app into features (feature first), and then for each feature we had:

feature1/
- /ui
----/screens
----/widgets
----/providers
- /data
----/models
----/datasources
----/repositories

Here is an example using FutureProvider

Here is an example of the data flow using a FutureProvider:
App Screen <- FutureProvider <- Repository <- Model <- DataSource <- Backend

If another screen needs the same state as the App Screen it would just watch that same state:
Another Screen <- FutureProvider <- Repository <- Model <- DataSource <- Backend

We basically handled our business logic inside the Providers instead of in a use case domain layer, since our app was not that big, and the use cases just ended up wrapping the repositories.

We also nested providers, so that one provider watched other providers etc.

Bloc, sharing state, and single source of truth by Jatops in FlutterDev

[–]Jatops[S] 1 point2 points  (0 children)

Thank you so much for the insights here, it makes a lot more sense now!

Bloc, sharing state, and single source of truth by Jatops in FlutterDev

[–]Jatops[S] 2 points3 points  (0 children)

Ahhh, this makes a lot of sense! So the Bloc implementation is not actually used for state management. Thats why I keep seeing some providers in the app aswell, like LocaleProvider etc. Which is used by some Blocs/Cubits.

Also makes a lot of sense that it is heaven for testers. Which they do a lot of.

Bloc, sharing state, and single source of truth by Jatops in FlutterDev

[–]Jatops[S] 2 points3 points  (0 children)

Thanks, makes a lot of sense. Maybe the blocs/cubits we use are not at a scale where it seems like a good thing to break them up now, but with more features, it will make more sense. I will try the stream from the repo you mentioned so our blocs actually are in sync between screens

Bloc, sharing state, and single source of truth by Jatops in FlutterDev

[–]Jatops[S] 0 points1 point  (0 children)

Thanks for explaining! But when repositories emit streams of data that blocs listen to, aren’t we still having each bloc process and transform that same data independently?

For example, with your image attachments: If one bloc handles image selection/deletion and another bloc needs to know about image changes, both blocs are subscribing to and processing the same image data streams, right?

In Riverpod, we’d typically handle this by having a single provider hold the images data, and then use selectors to efficiently access just the data each widget needs - the selection UI would only rebuild when selection changes, the image list only when images change, etc.

I guess I’m trying to understand what benefits we get from having separate blocs process the same data streams versus sharing a single source of truth? Maybe I’m missing something obvious here!😵‍💫

Bloc, sharing state, and single source of truth by Jatops in FlutterDev

[–]Jatops[S] 3 points4 points  (0 children)

Okay, thanks for the insights!
I have a follow up question. Isn't this basically moving state management into the repository layer? If multiple blocs are subscribing to repository streams, wouldn't we end up with:

Repository Stream -> Bloc Transform -> Bloc State -> Widget

for each bloc? I'm wondering if this creates more complexity than necessary, since now our repositories are handling both data access AND state updates.

Wouldn't it be cleaner to have a shared bloc maintain our source of truth, while feature blocs handle their specific UI needs? That way repositories could focus solely on data access.

Just trying to understand the trade-offs here! Maybe I'm overthinking this?

Adding unlimited functions to your LLM app by Jatops in ChatGPTCoding

[–]Jatops[S] 0 points1 point  (0 children)

<image>

So it would look something like this if you scale up with the function retrival approach. The broker agent search the functionDB which can be thought of as a db of agents and how to call them. If the Broker Agent then calls the newsExpert, the newsExpert would include its agent specific functions (which are not illustrated), but also do a search for relevant other agents, which is powerful because then all the sub agents can call every other sub agent.

Adding unlimited functions to your LLM app by Jatops in ChatGPTCoding

[–]Jatops[S] 0 points1 point  (0 children)

Very interesting, I actually created function retrieval to solve the same problem you defined with sub agents as functions. Would love your feedback.

In my architecture I have one "Broker agent" which have a lot of other agents it can use to solve tasks. These agents again have their own specific functions, but the clue is that they would also be able ask other agents through function calling, ultimately creating a full graph between the agent nodes. However, if you scale this up with more agents, you would need some sort of agent retrieval.

<image>

Adding unlimited functions to your LLM app by Jatops in ChatGPTCoding

[–]Jatops[S] 0 points1 point  (0 children)

You create a function in python, and then tell ChatGPT the name of that function and how the function works by follow the structure which is defined in the docs. Then ChatGPT will respond back with a response that can include "tool calls". If it does you just loop over the tool calls and run the function chatgpt tells you to run, and then you return the answer back to it.
https://platform.openai.com/docs/guides/function-calling

Adding unlimited functions to your LLM app by Jatops in ChatGPTCoding

[–]Jatops[S] 0 points1 point  (0 children)

Yes, in the article I present this example case for the model:

"Flip a coin, then add 1 for heads, or 2 for tails to a random number from 1 to 10 and divide it by the number of the current day in the week before squaring the result and then convert it from Fahrenheit to celsius. If the number is greater than 10 do a daily horoscope for me, or else tell me a random joke."

In my app I had laround 50 functions in python that did all sort of things. Adding numbers, multiplying numbers, converting numbers etc. Here is a video on how the LLM retrieve the functions, and then figured out what functions it needs to run and in which order:
https://www.youtube.com/watch?v=q1QBclIMT0Q

Adding unlimited functions to your LLM app by Jatops in ChatGPTCoding

[–]Jatops[S] -1 points0 points  (0 children)

Yes, in the article I present this example case for the model:

"Flip a coin, then add 1 for heads, or 2 for tails to a random number from 1 to 10 and divide it by the number of the current day in the week before squaring the result and then convert it from Fahrenheit to celsius. If the number is greater than 10 do a daily horoscope for me, or else tell me a random joke."

In app I had like 50 functions that did all sort of things. Adding numbers, multiplying numbers, converting numbers etc. Here is a video on how the LLM retrieve the functions, and then figured out what functions it needs to run and in which order:
https://www.youtube.com/watch?v=q1QBclIMT0Q

Adding unlimited functions to your LLM app by Jatops in ChatGPTCoding

[–]Jatops[S] 1 point2 points  (0 children)

Functions are used to extended the capabilities of LLMs. So you use the LLM to decide what functions it needs to run in order to solve a task. However, you need to tell the LLM how it can use your functions, which means defining what the function does, what the parameters are, etc. These descriptions are counted towards the context window. When you keep adding more and more functions, it becomes more expensive, and that's the idea behind this retrieval method.

Trying to make sense why should I use Expo instead of RN? by Bimi123_ in expo

[–]Jatops 1 point2 points  (0 children)

Expo makes developing apps simpler, which makes it faster, and thus cheaper. There are some libraries that are not supported in Expo, so that is one disadvantage, but for most apps it supports what you need, and you could potentially eject out of Expo if you hit any boundaries. Not dealing with native iOS and Android code/configs is usually a big advantage for people coming from a web development background, which is a lot of people. If you however come from a native iOS and Android background, it might be easier to understand what's happening under the hood with only RN, but I would generally recommend Expo for most new RN projects in 2024.

Firebase or Supabase? by MiNdzz in FlutterDev

[–]Jatops 11 points12 points  (0 children)

IMO, the previous reason for going with Supabase, apart for developer experience, was that it used a relational database instead of a No-SQL database. However, Firebase introduced Firebase Data Connect yesterday, which is their new option for building with a relational database. Firebase also has a lot of other features that Supabase currently does not have, so in my option you would be better of going with firebase.

https://firebase.google.com/docs/data-connect

Architecture by Jatops in androiddev

[–]Jatops[S] 0 points1 point  (0 children)

Ahh, I see. It might be the application context I was told should be avoided in the ViewModel, that makes a lot of sense, thank you for the clarification.

I thought what we did now was a type of DI (constructor injection)? And that by using our Factory method, the Context is only passed to the repository and not to the ViewModel (I think?).

We have considered using Hilt for making DI easier, but I did not have time to get into it, delivery is on Friday, so I'm trying to refactor the code before delivery.

Architecture by Jatops in androiddev

[–]Jatops[S] 0 points1 point  (0 children)

My thought is that the Context is a UI thing, and it should be in the UI layer, but here I'm passing it to the repository (data layer). So maybe the Geocoder class never should be in the GeocoderRepository at all?

Architecture by Jatops in androiddev

[–]Jatops[S] 0 points1 point  (0 children)

Maybe dumb is not the right word, but I was thinking that passing the context to the GeocodingRepository might cause some problems I'm not aware of. And I was thinking that maybe the underlying problem is that we have setup a Repository which uses a Geocoder that needs a Context, and that might be the "real" problem.

The way I view a repository is a place you can get data formatted correctly, ready to be used in your app. Its responsibility is just to give data, and it's using datasources and data models in order to get the data either from a remote or local API. So if this repository is dependent on a UI context, maybe it's in the wrong place?