How to Ref listen to AsyncNotifier in flutter riverpod - riverpod

So I am using the latest provider of riverpod and I want to listen on it, and these are my codes to listen
ref.listen<AccountManagementController>(
accountManagementControllerProvider, (prev, next) {
// if(next.hasError){
// }
});
however, I got some error or problem there it said
The argument type 'AsyncNotifierProviderImpl<AccountManagementController, void>' can't be assigned to the parameter type 'ProviderListenable'

I fix it , btw.
ref.listen<AsyncValue<void>>(accountManagementControllerProvider,
(prev, next) {
if (!next.isLoading && next.hasError) {
_showErrorMessage(
context,
next.error.toString(),
() {
Navigator.pop(context);
},
);
}
});

Related

Riverpod with hooks beaks when widget is disposedI

I have Flutter mobile app that is using Riverpod with hooks.
I have the following function that I would like to be called when the widget is disposed:
useEffect(
() {
final firestoreRepo =
ref.read(firebaseFirestoreRepositoryProvider);
return () async {
try {
// I get exception at this line.
// I need this future to be called when the
// widget is disposed.
// Calling this future earlier is not userful
// for my business logic.
final relationship =
await ref.read(relationshipWithProvider(pid).future);
if (relationship?.unseen ?? false) {
await firestoreRepo?.updateRelatinoship(pid: pid);
}
} catch (e, st) {
// print error
}
};
},
[],
);
I keep getting this error at the line shown in the comment above.
I/flutter ( 5967): Looking up a deactivated widget's ancestor is unsafe.
I/flutter ( 5967): At this point the state of the widget's element tree is no longer stable.
How can I sold this problem
We can initially get our relationship and then await and use it:
useEffect(
() {
final firestoreRepo = ref.read(firebaseFirestoreRepositoryProvider);
final relationship = ref.read(relationshipWithProvider(pid).future);
return () async {
try {
if (await relationship?.unseen ?? false) {
await firestoreRepo?.updateRelatinoship(pid: pid);
}
} catch (e, st) {
// print error
}
};
},
[],
);
As far as I can tell, this won't contradict the logic of the business process, because one way or another, we'll have to make the relationshipWithProvider(pid) request early (when we initialize the widget) or late (when we delete the widget).

Flutter web: Values retrieved from Firestore map are truncated when added to List

In my Flutter Web application I am retrieving values from the map timeslots in Firestore.
This is what the data looks like:
But, instead of retrieving the whole list of values, I get a truncated list like this:
[Mo-Washing-(09:00-10:00, 10:00-11:00, 11:00-12:00, ..., 20:00-21:00, 21:00-22:00)]
Below I have included the 2 functions responsible for retrieving the data and adding it to the list object
static List object = [];
static Map<String, dynamic> timeDetails = {};
static Map<String, dynamic> userDetails = {};
checkExists(docuID) async {
return await firestore()
.collection('environments')
.doc(docuID)
.get()
.then((val) {
userDetails.addAll(val.data());
}).whenComplete(() async {
fs.DocumentSnapshot snapShot = await firestore()
.collection('environments')
.doc(docuID)
.collection('Washing')
.doc('monday')
.get();
if (snapShot == null || !snapShot.exists) {
print('does not exist');
} else {
await getData(docuID, 'Washing');
}
setState(() {});
});
}
getData(docuID, machineName) async {
return await firestore()
.collection('environments')
.doc(docuID)
.collection(machineName)
.doc('monday')
.get()
.then((val) {
timeDetails.addAll(val.data());
}).whenComplete(() {
object.add('Mo-$machineName-${timeDetails['timeslots'].values}');
print(object);
setState(() {});
});
}
This also happens in debugPrint. Would anyone know why this is happening and how I could solve it? Any help on this would be appreciated!
Neither the workaround as mentioned on Github nor debugPrint worked for me, but I managed to solve this by adding .toList() to my getData function:
getData(docuID, machineName) async {
return await firestore()
.collection('environments')
.doc(docuID)
.collection(machineName)
.doc('monday')
.get()
.then((val) {
timeDetails.addAll(val.data());
}).whenComplete(() {
//toList() is added here to .add
object.add('Mo-$machineName-${timeDetails['timeslots'].values.toList()}');
print(object);
setState(() {});
});
}
Output:
[Mo-Washing-[09:00-10:00, 10:00-11:00, 11:00-12:00, 12:00-13:00, 13:00-14:00, 14:00-15:00, 15:00-16:00, 16:00-17:00, 17:00-18:00, 18:00-19:00, 19:00-20:00, 20:00-21:00, 21:00-22:00]

How to prevent multiple instances in Electron

I do not know if this is possible but I might as well give it a chance and ask.
I'm doing an Electron app and I'd like to know if it is possible to have no more than a single instance at a time.
I have found this gist but I'm not sure hot to use it. Can someone shed some light of share a better idea ?
var preventMultipleInstances = function(window) {
var socket = (process.platform === 'win32') ? '\\\\.\\pipe\\myapp-sock' : path.join(os.tmpdir(), 'myapp.sock');
net.connect({path: socket}, function () {
var errorMessage = 'Another instance of ' + pjson.productName + ' is already running. Only one instance of the app can be open at a time.'
dialog.showMessageBox(window, {'type': 'error', message: errorMessage, buttons: ['OK']}, function() {
window.destroy()
})
}).on('error', function (err) {
if (process.platform !== 'win32') {
// try to unlink older socket if it exists, if it doesn't,
// ignore ENOENT errors
try {
fs.unlinkSync(socket);
} catch (e) {
if (e.code !== 'ENOENT') {
throw e;
}
}
}
net.createServer(function (connection) {}).listen(socket);;
});
}
There is a new API now: requestSingleInstanceLock
const { app } = require('electron')
let myWindow = null
const gotTheLock = app.requestSingleInstanceLock()
if (!gotTheLock) {
app.quit()
} else {
app.on('second-instance', (event, commandLine, workingDirectory) => {
// Someone tried to run a second instance, we should focus our window.
if (myWindow) {
if (myWindow.isMinimized()) myWindow.restore()
myWindow.focus()
}
})
// Create myWindow, load the rest of the app, etc...
app.on('ready', () => {
})
}
Use the makeSingleInstance function in the app module, there's even an example in the docs.
In Case you need the code.
let mainWindow = null;
//to make singleton instance
const isSecondInstance = app.makeSingleInstance((commandLine, workingDirectory) => {
// Someone tried to run a second instance, we should focus our window.
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore()
mainWindow.focus()
}
})
if (isSecondInstance) {
app.quit()
}

How to pass message to isolate and handle error

I am trying to use dart isolate library to improve my application performance.
Look at following code:
import 'dart:isolate';
import 'package:dbcrypt/dbcrypt.dart';
main() {
var pwConPort = new ReceivePort();
pwConPort.listen((data) {
print(data);
pwConPort.close();
}, onError: (err) {
print(err);
});
Isolate.spawn(generatePasswordConcurrency, pwConPort.sendPort);
}
void generatePasswordConcurrency(SendPort sendPort) {
sendPort.send(_generateHashPassword('Passsowr1222!'));
}
String _generateHashPassword(String password) {
var regex = new RegExp(r'^.*(?=.{7,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).*$');
if (!regex.hasMatch(password)) {
throw new StateError('Errors');
}
return new DBCrypt().hashpw(password, new DBCrypt().gensalt());
}
Everything works fine but i can only pass a static password, or better to say, i don't know, how to pass something dynamically. Here you can see, password is hardcoded, but i want to pass a variable for example.
void generatePasswordConcurrency(SendPort sendPort) {
sendPort.send(_generateHashPassword('Passsowr1222!'));
}
If the method _generateHashPassword will throw an error, how can I handling this error? I try to catch the error on listen method from ReceivePort
pwConPort.listen((data) {
print(data);
pwConPort.close();
}, onError: (err) {
print(err);
});
but still got unhandling exceptions message.
Observatory listening on http://127.0.0.1:51433
in ShutdownIsolate: Unhandled exception:
Bad state: Errors
#0 _generateHashPassword (file:///D:/Dart/samples/bin/isolate_error.dart:26:9)
#1 generatePasswordConcurrency (file:///D:/Dart/samples/bin/isolate_error.dart:19:40)
#2 _startIsolate.isolateStartHandler (dart:isolate-patch/isolate_patch.dart:221)
#3 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:124)
Conclusion my question:
How can I pass a variable to called method on isolate?
How can I handling error on isolate?
First of all,
Isolate are not thread, they are independant process more like a fork() than a thread
dartApi: Isolate
Concurrent programming using isolates:
independent workers that are similar to threads but don't share memory, communicating only via
messages.
So, you can't access to the same variable than your parent process. It's a choice made by the dart team, because it's a mechanism usable when you compile your dart code in js. So it need to be possible in JS
How can I pass a variable to called method on isolate?
To do this, you need to see ReceivePort() like a unidirectionnal way of communication, so to pass variable in two way, you need two.
So on you main process:
pwConPort.listen((data) {
if (isolateSendPort == null && data is SendPort) {
isolateSendPort = data; // Receive the communication object of the isolate
isolateSendPort.send("Passsowr1222!");
} else {
print("Generated password: ${data}");
pwConPort.close();
}
}, onError: (err) {
print("SendPortError: ${err}");
});
});
In you isolate entry point :
sendPort.send(isolateConPort.sendPort);
isolateConPort.listen((data) {
// code ....
});
Note: be careful of what message you send. message send between one process and another need to respect some rules
DartApi: SendPort
The content of message can be: primitive values (null, num, bool,
double, String), instances of SendPort, and lists and maps whose
elements are any of these. List and maps are also allowed to be
cyclic.
How can I handling error on isolate?
Isolate get one method to listen throw error send by the isolate : addErrorListner
That is a useful function.
BUT ! this method is not implement in every plate-forme, so you need to do this in a others.
The way i chose is to send 2 SendPort in the entry point function :
One for the communication
One for the error.
So the spawn function looks like :
Isolate.spawn(generatePasswordConcurrency, [pwConPort.sendPort, errorPort.sendPort])
and the generatePasswordConcurrency :
void generatePasswordConcurrency(List<SendPort> commList) {
var sendPort = commList[0];
var errorPort = commList[1];
var isolateConPort = new ReceivePort();
sendPort.send(isolateConPort.sendPort);
isolateConPort.listen((data) {
try {
sendPort.send(_generateHashPassword(data));
} catch (e) {
errorPort.send("error: ${e.toString()}");
}
});
}
Here the full code :
import 'dart:isolate';
import 'package:dbcrypt/dbcrypt.dart';
main() {
var pwConPort = new ReceivePort();
var errorPort = new ReceivePort();
SendPort isolateSendPort = null;
Isolate.spawn(generatePasswordConcurrency, [pwConPort.sendPort, errorPort.sendPort])
.then((Isolate pcs) {
errorPort.listen((err) {
print("Error: ${err}");
pwConPort.close();
errorPort.close();
});
print(pcs);
pwConPort.listen((data) {
if (isolateSendPort == null && data is SendPort) {
isolateSendPort = data;
isolateSendPort.send("Passsowr1222!");
} else {
print("Generated password: ${data}");
pwConPort.close();
errorPort.close();
//pcs.kill();
}
}, onError: (err) {
print("SendPortError: ${err}");
});
});
}
void generatePasswordConcurrency(List<SendPort> commList) {
var sendPort = commList[0];
var errorPort = commList[1];
var isolateConPort = new ReceivePort();
sendPort.send(isolateConPort.sendPort);
isolateConPort.listen((data) {
try {
sendPort.send(_generateHashPassword(data));
} catch (e) {
errorPort.send("error: ${e.toString()}");
}
});
}
String _generateHashPassword(String password) {
var regex = new RegExp(r'^.*(?=.{7,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).*$');
if (!regex.hasMatch(password)) {
throw new StateError('Errors');
}
return new DBCrypt().hashpw(password, new DBCrypt().gensalt());
}

How do I register multiple handlers for a HttpServer, in Dart?

(I'm using the new lib v2 version of dart:io.)
I'd like to register multiple handlers for an HttpServer, specifically a WebSocketTransformer and other arbitrary handlers. Something like this:
// pseudo-code
var server = HttpServer;
server.register('/foo', someHandlerFunction); // 1
server.register('/bar', someOtherHandlerFunction); // 2
server.register('/ws', webSocketHandler); // 3
If #1 matches, then #2 isn't tested, and so on. So, it's greedy.
I've seen samples with just one handler. How do I register many handlers? Thanks in advance!
New answer: Use the route package: http://pub.dartlang.org/packages/route
Here's your example using route's serve() method:
HttpServer.bind('127.0.0.1', 8889).then((server) {
var router = new Router(server)
..serve('/ws').transform(new WebSocketTransformer()).listen(handleWebSocket)
..serve('/foo').listen((req) {
req.response..addString('foo')..close();
});
});
Router automatically catches unhandled requests and sends a 404, though soon you'll be able to override that with a defaultStream you can listen to.
Router also supports filters, useful for logging, auth, compression, etc.:
HttpServer.bind('127.0.0.1', 8889).then((server) {
var router = new Router(server)
..filter(new RegExp(r'/.*'), (req) {
//log all requests
_logger.info("request: $req");
return new Future.immediate(true); // keep processing request
})
..filter(new Regexp(r'/secure/.*'), (req) {
// check authentication asynchronously
return getUserFromRequest(req).then((user) {
if (user == null) {
sendRedirect('/login'); // sendRedirect coming soon
return false; // stop processing request
} else {
return true; // keep processing
}
});
})
..serve(/* ... */ );
});
Here's how the API docs recommend to register a WebSocket handler:
server
.where((request) => request.uri.path == "/ws")
.transform(new WebSocketTransformer()).listen((webSocket) => ...);
However, the server is a single-subscription stream. Once a listen is attached, you can't attach other listeners.
What I really want is for something to look at an event, decide if it can handle it, and if so then route it to another stream. Otherwise, pass it along. This way, the event (in this case an HttpRequest object) is passed along a chain until it's handled.
I built a TakeAndRoute class that extends StreamEventTransformer. The TakeAndRoute uses a function to determine if it should grab the event and route it to another stream, or simply forward it along.
Here's what I came up with:
import 'dart:io';
import 'dart:async';
handleWebSocket(WebSocket webSocket) {
webSocket.listen((event) {
if (event is MessageEvent) {
/* Handle message. */
} else if (event is CloseEvent) {
/* Handle closed. */
}
});
}
typedef bool ShouldTake(e);
typedef void RouteTo(Stream stream);
typedef void HandleEvent(e);
class TakeAndRoute<S, T> extends StreamEventTransformer<S, T> {
ShouldTake shouldTake;
RouteTo routeTo;
StreamController controller = new StreamController();
HandleEvent handler;
TakeAndRoute(this.shouldTake, {this.routeTo, this.handler}) {
if (routeTo != null) routeTo(controller.stream);
}
handleData(event, StreamSink sink) {
print("handling");
if (shouldTake(event)) {
if (routeTo != null) {
controller.add(event);
}
if (handler != null) {
handler(event);
}
} else {
sink.add(event);
}
}
}
main() {
HttpServer.bind('127.0.0.1', 8888)
.then((HttpServer server) {
server
.transform(new TakeAndRoute<HttpRequest, HttpRequest>(
(req) => req.uri.path == '/ws',
routeTo: (stream) => stream.transform(new WebSocketTransformer()).listen(handleWebSocket)))
.transform(new TakeAndRoute<HttpRequest, HttpRequest>(
(req) => req.uri.path == '/foo',
handler: (req) {
print('got foo');
req.response.addString("foo");
req.response.close();
}))
.listen((req) {
print("got 404 for ${req.uri}");
req.response.statusCode = 404;
req.response.close();
});
});
}
Admittedly, this might be overkill.
Here is a more manual, but shorter way to do it:
HttpServer.bind('127.0.0.1', 8889)
.then((HttpServer server) {
var sc = new StreamController();
sc.stream.transform(new WebSocketTransformer()).listen(handleWebSocket);
server.listen((HttpRequest request) {
print("new connection from ${request.uri.scheme} ${request.uri}");
// See https://code.google.com/p/dart/issues/detail?id=8825
//if (request.uri.scheme == 'ws') {
if (request.uri.path == '/ws') {
sc.add(request);
} else if (request.uri.path == '/foo') {
request.response.addString('foo');
request.response.close();
} else {
print("got 404 for ${request.uri}");
request.response.statusCode = 404;
request.response.close();
}
});
});
Notice how I had to create a StreamController so I could pump events to WebSocketTransformer

Resources