Cache in GrapghQl Flutter package settings and how to check it works - flutter

I'm trying to implement graphQl Flutter package in my app.
https://github.com/zino-app/graphql-flutter
Everything works well, but I have some issues with cache.
If we ran example from this package https://github.com/zino-app/graphql-flutter/tree/master/packages/graphql_flutter/example we can see that cache doesn't work.
In my app I also can't increase speed, it always get data online.
The code from this example
class GraphQLWidgetScreen extends StatelessWidget {
const GraphQLWidgetScreen() : super();
#override
Widget build(BuildContext context) {
final HttpLink httpLink = HttpLink(
uri: 'https://api.github.com/graphql',
);
final AuthLink authLink = AuthLink(
// ignore: undefined_identifier
getToken: () async => 'Bearer $YOUR_TOKEN',
);
Link link = authLink.concat(httpLink);
if (ENABLE_WEBSOCKETS) {
final WebSocketLink websocketLink = WebSocketLink(
url: 'ws://localhost:8080/ws/graphql',
config: SocketClientConfig(
autoReconnect: true, inactivityTimeout: Duration(seconds: 15)),
);
link = link.concat(websocketLink);
}
final ValueNotifier<GraphQLClient> client = ValueNotifier<GraphQLClient>(
GraphQLClient(
cache: OptimisticCache(
dataIdFromObject: typenameDataIdFromObject,
),
link: link,
),
);
return GraphQLProvider(
client: client,
child: const CacheProvider(
child: MyHomePage(title: 'GraphQL Widget'),
),
);
}
}
Animation that shows that cache doesn't work
So, the question is - what is the right way to implement cache and how check it works.
Thank you!

The examples are meant to be standalone - as such they use separate clients and caches. The consequence of this is that it is re-instantiated every mount. In other words, every time you navigates to the example's route, you get a new cache, so you can't see the caching effects. For a more substantial example where you can see if the cache is working, see the starwars example (related github discussion)

Related

Flutter image assets not loading after redirect with go_router & login

I have a small Flutter app with 2 screens (/login & /home) and I use go_router to navigate and animated_login. The assets are placed on the home screen and they load fine if I directly access the screen, so pubspec.yaml is correctly defined.
The images fail to load only when I redirect to /home after /login. One interesting observation is that when this happens, the Flutter dev server seems to be hanging (stops responding, but doesn't crash, can't restart it with R, the browser tab complains that it lost connection to the server etc.). This problem occurs also with a combination of auto_route and flutter_login.
Thanks for any hints.
Router setup (tried also w/ the redirect parameter at router level rather than individual routes):
GoRouter routerGenerator(UserData userData) {
return GoRouter(
initialLocation: Routes.home,
refreshListenable: userData,
debugLogDiagnostics: true,
routes: [
GoRoute(
path: Routes.home,
builder: (_, __) => BasicScreen(),
redirect: (state) => userData.loggedIn ? null : Routes.login
),
GoRoute(
path: Routes.login,
builder: (_, __) => AnimLoginScreen(),
redirect: (state) => !userData.loggedIn ? null : Routes.home
),
GoRoute(path: '/', builder: (_, __) => BasicScreen())
]);
}
abstract class Routes {
static const home = '/home';
static const login = '/login';
}
Main app:
void main() {
runApp(
MultiProvider(providers: [
//other providers here
ChangeNotifierProvider(create: (_) => UserData()),
], child: MyApp()),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
final router =
routerGenerator(Provider.of<UserData>(context, listen: false));
return MaterialApp.router(
title: 'Playground',
routeInformationParser: router.routeInformationParser,
routeInformationProvider: router.routeInformationProvider,
routerDelegate: router.routerDelegate,
);
}
}
Basic screen:
class BasicScreen extends StatelessWidget {
BasicScreen({super.key});
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
Image(image: AssetImage("assets/images/image1.png")),
Image(image: AssetImage("assets/images/image2.png")),
Image(image: AssetImage("assets/images/image3.png")),
],
),
);
}
}
Solution
Provide a simple proxy over both Flutter DevTool & backend services with SSL capabilities.
Explanation
The issue has nothing to do with routing, but rather the dev setup. Our backend services require SSL connections, but Flutter dev tool doesn't support that. Flow:
Flutter DevTool starts the project (plain HTTP) and opens Chrome window.
Assets load ok.
User logs in, backend service requires HTTPS for secure cookies.
Browser upgrades all localhost connections to HTTPS.
Flutter DevTools fails to provide SSL connection.
Assets fail to load.
The hanging DevTool is caused by the same issue: seems to me that the DevTool is pending the WebSocket connection to be opened by the JS code running in the browser, but as the browser initiates an HTTPS connection to the DevTool, it even fails to load the JS code. Therefore, the DevTool never completes the init process (as it has no incoming connection).

Open Facebook app with url_launcher package in Flutter

I am trying to open the Facebook app on a company page in Flutter but it keeps opening it in the web browser instead.
It's just a simple widget that outputs a row of social media icons from a list:
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
class SocialMediaLinks extends StatelessWidget {
SocialMediaLinks({Key? key}) : super(key: key);
final List<Map<dynamic, dynamic>> icons = [
{
'name': 'twitter',
'launchUrl': 'twitter://PAGENAME',
'backupUrl': 'https://twitter.com/PAGENAME',
},
{
'name': 'facebook',
'launchUrl': 'fb://page/PAGEID',
'backupUrl': 'https://www.facebook.com/PAGENAME',
},
{
'name': 'instagram',
'launchUrl': 'instagram://PAGENAME',
'backupUrl': 'https://www.instagram.com/PAGENAME',
}
];
#override
Widget build(BuildContext context) {
return Row(
children: [
for (Map i in icons)
IconButton(
onPressed: () async {
await canLaunch(i['launchUrl'])
? launch(
i['launchUrl'],
forceSafariVC: false,
forceWebView: false,
)
: launch(
i['backupUrl'],
forceSafariVC: false,
forceWebView: false,
);
},
splashRadius: 30.0,
iconSize: 38.0,
icon: Image.asset(
"assets/images/icons/${i['name']}.png",
color: Colors.white,
),
),
],
);
}
}
Twitter and Instagram work and open in their apps but Facebook still only opens in the web browser. I've tried tonnes of solutions on stackoverflow but to no avail. Am I missing something?
Thanks.
I've observed a limitation with the supported URLs configured in the Facebook app. In Android at least, while the Facebook app has support for facebook.com, I noticed that the Facebook app opens when it's a link to a specific post i.e. https://www.facebook.com/$profileId/posts/$postId
However, the Facebook app seems to be unable to handle direct links to the profile or page i.e. https://www.facebook.com/$profileId
If you're linking to a profile/page in Facebook, you can pin a post in the profile/page and share the link of the Facebook post as a workaround. This should successfully open the Facebook app installed on the device.

graphql-flutter subscriptions in flutter connectivity issue

I am new to flutter development but I have good experience in nodejs and graphql. I am trying to consume the subscription widget of graphql-flutter and update the changes. but the connection is not being established. But I could use the query and Mutation widget and get the results. The examples provided by the graphql-flutter team is 2 years old and same with https://hasura.io/ documents. Can someone help me providing the latest examples or samples.
graphql-flutter:^5.0.0
If additional infos needed please comment below.
Thanks in advance
I made a class that I use with graphql but it'll be able to work with graphql-flutter but passing the client to
return GraphQLProvider(
client: Services().graphQL.client, // just how I have my services set up
child: MaterialApp(
title: 'Flutter Demo',
...
),
);
class:
class GraphQL {
static final HttpLink _httpLink = HttpLink(environment[envMode]!['server']);
static WebSocketLink _wsLink(String token) => WebSocketLink(
environment[envMode]!['webSocket'],
config: SocketClientConfig(
inactivityTimeout: const Duration(hours: 1),
initialPayload: {
'Authorization': 'Bearer $token',
},
),
);
Link _splitLink(String token) => Link.split(
(request) => request.isSubscription,
_wsLink(token),
_httpLink,
);
GraphQLClient client(String token) {
return GraphQLClient(
link: AuthLink(getToken: () async => 'Bearer $token')
.concat(_splitLink(token)),
cache: GraphQLCache(
store: HiveStore(),
),
);
}
Future<void> initHive() async {
return await initHiveForFlutter();
}
}
The environment and envMode come from a config file that has gets its data from an env file to keep manage env and secrets.

How to send cookie in flutter graphql calls

I am working on an Graphql QUERY API which reads domain cookies and based on that return data but when working on flutter app I am not able to send cookies(Which is default in browser). Is there an easier way to send cookies.
Below is my code snippet for Reading cookies from domain. I think there should be some way to set cookies/options in httpLink somehow.
final cookieManager = WebviewCookieManager();
final gotCookies = await cookieManager.getCookies('https://someApp.com');
final HttpLink httpLink = HttpLink(
uri: 'https://someApp.com/graphql',
includeExtensions: true
);
ValueNotifier<GraphQLClient> client = ValueNotifier(
GraphQLClient(
cache: InMemoryCache(),
link: httpLink,
),
);
Found solution for this. We can set cookie in headers just like below and it works.
HttpLink httpLink = HttpLink(
uri: 'https://apps.cloudhealthtech.com/ui-session',
headers: {'Cookie': 'session_id=ctHB0ZewfasKWBWIUu;'});
Found a solution to pass Browser cookies along GraphQL requests without retrieving them first. It uses the Browser client
import 'package:http/browser_client.dart';
Insert a prepared Http client into the httpLink
var myClient = BrowserClient();
myClient.withCredentials =true;
final httpLink = HttpLink(endpoint +"/graphql",
httpClient: myClient,
// ...
);

Websocket reconnection loop, graphql_flutter

I am using graphql_flutter package in my app. This is the code for my client:
HttpLink httpLink = HttpLink(
uri: 'https://*******/graphql',
);
WebSocketLink webSocketLink = WebSocketLink(
url: "wss://*******/graphql/websocket/",
config: SocketClientConfig(
autoReconnect: true,
inactivityTimeout: Duration(seconds: 30),
),
);
AuthLink authLink = AuthLink(
getToken: ()async{
print(await SharedPreferencesHelper.getAuthenticationToken());
return "Bearer ${await SharedPreferencesHelper.getAuthenticationToken()}";
}
);
Link link = authLink.concat(httpLink);
link = link.concat(webSocketLink);
client = ValueNotifier(
GraphQLClient(
cache: InMemoryCache(),
link: link,
),
);
However whenever I create a subscription like this:
client.value.subscribe(Operation(
document: Subscriptions.chatMessageReceived,
variables: {
"receiverId": *******
}
)).listen((fetchResult){
print(fetchResult.data);
});
I get this log in repetition:
Connecting to websocket: wss://******/graphql/websocket/... flutter:
Connected to websocket. flutter: Disconnected from websocket. flutter:
Scheduling to connect in 5 seconds... flutter: Connecting to
websocket: wss://******/graphql/websocket/...
Even though everything works fine in graphql playground. What can it be?
this is because of inactivityTimeout: Duration(seconds: 30), in WebSocketLink config
you can increase the Duration to prevent it from auto disconnecting.