Flutter UI freezes on hash check - flutter

I have a program that will check a password with bcrypt library, this is quite computing intensive, so as a result the UI will be stuck for like 2 seconds. It is very annoying and I cannot figure out what to do to stop it.
I want a loader to be shown when the password is being checked.
This is my code:
class _MyWidgetState<MyWidget> extends State{
build() {
return GetPassCode(PassCodeType.ENTER,
onDone: ({context, data}) async {
unlock(state, data?['password'] ?? '', Languages.of(context));
}, goBack: () {}, data: {});
}
unlock(userState, String? password, Languages strings) async {
final user = userState.currentUser;
if (!(await user.checkPassword(password))) {
return;
}
}
context.read<LockCubit>().unlock();
}
}

you can put the caculating into a isolate.
https://api.flutter-io.cn/flutter/dart-isolate/dart-isolate-library.html
here's some example code:
class IsoMessage {
final SendPort? sendPort;
final List<String> args;
IsoMessage(this.sendPort, this.args);
}
String myCaculate(IsoMessage message) {
String result = message.args[0][0] + message.args[1][1];
message.sendPort?.send(result);
return result;
}
here's how to calling the func
var port = ReceivePort();
port.listen((message) {
print("onData: $message");
}, onDone: () {
print('iso close');
}, onError: (error) {
print('iso error: $error');
});
IsoMessage message = IsoMessage(port.sendPort,["asd", "dsa"]);
Isolate.spawn<IsoMessage>(myCaculate, message);

Related

Riverpod : future provider is stuck on loading

Describe the bug
when executing the provider with ref.read or ref.watch the result is the same , it is stuck on the loading block , while testing the api in postman works fine , the funny thing is that the api call gets executed and whenever i print something inside it it appears in the console
To Reproduce
in presentation layer
onpressed:()=>ref
.read(getPatientProvider(
r.api_token))
.when(data: (data) {
data.fold(
(l) => print(
"something wrong happened"),
(r) async {
print(r.id);
print("hello");
patient.value = patient.value
.copyWith(
name: r.name,
aliid: r.id,
appointments: r
.patient_appointments,
fcmtoken: token);
ref.read(docexist(r.id)).when(
loading: () =>
print("loading"),
error: (error, _) =>
print(error),
data: (data) async {
print("heloo");
if (data.isEmpty) {
print(
"data is not empty");
} else {
return print(
"logged in normally");
}
});
});
}, error: (error, _) {
print(error);
}, loading: () {
print("object");
})
Provider with riverpod generator
#riverpod
Future<Either<ApiFailures, dynamic>> getPatient(
GetPatientRef ref, String token) async {
final patientProvider = ref.watch(patientRepositoryProvider);
return patientProvider.getInfo(token);
}
infrastructure layer
#override
Future<Either<ApiFailures, dynamic>> getInfo(String token) {
var dio = Dio();
final result = TaskEither<ApiFailures, PatientModel>(() async {
try {
final response = await dio.get(
"https://xxxxxxxx/GetInfo?api_token=$token");
if (response.data == null) {
return const Left(ApiFailures.notfound());
} else {
PatientModel patientModel =
PatientModel.fromJson(response.data["User"]);
return Right(patientModel);
}
} catch (err, st) {
final message = 'error ${err.runtimeType}]';
if (kDebugMode) log(message, error: err, stackTrace: st);
if (err is DioError) {
return Left(ApiFailures.fromDioError(error: err));
}
return const Left(ApiFailures.internalError());
}
});
return result.map((r) => r).run();
}
Expected behavior
it should get the data as always
Calling when inside a click handler such as onPressed as you did does not make sense.
"when" does not wait for the future to complete. It executes immediately based on the current status of the future.
Considering that when you call it, you just triggered the future, then the future at that time will always be in a loading state.
What you want is something like async/await, where you can wait until the completion of your future.
You could do that with:
onPressed: () async {
final value = await ref.read(provider.future);
}

why my circularProgressIndicator having strange behavior when async function called?

Im calling a function to get data from Excel file and upload it to my Firestore as following
floatingActionButton: FloatingActionButton(onPressed: () async {
Utils.showLoading(context);
await FireStoreServices.bulkUploadFromExcelToFireStore(
collectionName: 'test',
fileName: 'test',
sheetName: 'test');
Navigator.pop(context);
}),
the problem is my Progress loading indicator not working as expected in this case (not spinning only shows and freeze until the function complete after that its popped)
i tried to replace the awaited function 'bulkUploadFromExcelToFireStore' with Future.delayed and it worked as expected
await Future.delayed(const Duration(seconds: 3), () {});
what might be the problem ?
here is the code of bulkUploadFromExcelToFireStore function
static Future bulkUploadFromExcelToFireStore(
{required String fileName,
required String sheetName,
required String collectionName}) async {
try {
final rowsData = await Utils.readExcelFileData(
excelFilePath: fileName, sheetName: sheetName);
rowsData.removeAt(0);
for (var row in rowsData) {
firebaseFirestore.collection(collectionName).doc(row[0]).set(data, SetOptions(merge: true));
}
} catch (e) {
print('Cached ERROR MESSAGE = = = = ${e.toString()}');
}
I added some validations inside your function to check for possible failures.
It would also be interesting to validate a failure warning and terminate the Progression Indication initialization.
static Future<String> bulkUploadFromExcelToFireStore({required String fileName, required String sheetName,required String collectionName}) async {
try {
final rowsData = await Utils.readExcelFileData(excelFilePath: fileName, sheetName: sheetName);
rowsData.removeAt(0);
if(rowsData.length == 0) {
return "No Items!";
} else {
for (var row in rowsData) {
firebaseFirestore?.collection(collectionName)?.doc(row[0])?.set(data, SetOptions(merge: true));
}
return "Item allocated!";
}
} catch (e) {
return e.toString();
}
}

StreamProvider and TCP Socket

I wrote an one-page desktop app to communicate with TCP Server.
In my code, I use Socket.listen() method to receive data and it is OK.
I used single subscription and it was enough for me.
I tried to convert it to StreamProvider[Riverpod] and I failed.
I used StreamController() then I get bad state.
I used StreamController.broadcast() and I couldn't get data from socket
Could you suggest me correct way?
For a side note: I'm not an experienced flutter developer, just try to learn :)
I added code blocks to below and also full code.
For the full code: https://gist.github.com/sphinxlikee/3cbfa47817a5187c7b67905028674041
UI:
Working code;
Future<void> createConnection() async {
try {
_socket = await Socket.connect(serverAddress, serverPort);
_changeConnectionState();
} catch (e) {
print('connection has an error and socket is null.');
print(e);
return;
}
listenSocket();
}
void listenSocket() {
_socket.listen(
(event) {
_getData(String.fromCharCodes(event));
print('received: $receivedData');
if (!_dataReceived) {
_changeDataReceivedState();
}
},
)
..onDone(
() {
_changeConnectionState();
_streamDone();
print('socket is closed');
},
)
..onError(
(error, stackTrace) {
print('$error');
},
);
}
Working code - UI side
class ReceivedData extends ConsumerWidget {
#override
Widget build(BuildContext context, ScopedReader watch) {
final receivedData = watch(tcpClientProvider).receivedData;
return Text('Received data: $receivedData');
}
}
For the StreamProvider I tried,
Future<void> createConnection() async {
try {
_socket = await Socket.connect(serverAddress, serverPort);
streamController.sink.add(_socket.listen((event) => String.fromCharCodes(event)));
_changeConnectionState();
} catch (e) {
print('connection has an error and socket is null.');
print(e);
return;
}
}
StreamProvider - UI side
final streamProvider = StreamProvider.autoDispose(
(ref) async* {
await for (final value in ref.watch(tcpClientProvider).streamController.stream) {
yield value;
}
},
);
class ReceivedDataWithProvider extends ConsumerWidget {
#override
Widget build(BuildContext context, ScopedReader watch) {
AsyncValue receivedData = watch(streamProvider);
return receivedData.when(
data: (data) => Text('Received data: $data'),
loading: () => const CircularProgressIndicator(),
error: (err, stack) => Text('error'),
);
}
}
Socket implements Stream, so you could just write:
final streamProvider = StreamProvider.autoDispose<Uint8List>((ref) {
return ref.watch(tcpClientProvider)._socket;
});
If you still want to add a listener, there's no harm in having one if you need:
final streamProvider = StreamProvider.autoDispose<Uint8List>((ref) {
final client = ref.watch(tcpClientProvider);
return client._socket
..listen(
(event) {},
).onDone(
() {
client
.._changeConnectionState()
.._streamDone();
print('socket is closed');
},
);
});

Race condition with stream listen

I have an async function like below. However content is being returned null well before the stream listening is done.
I started playing out with Future.delayed, but thought better of it and wanted to ask if there is a better approach to ensure this is async?
import 'package:googleapis/drive/v3.dart' as ga;
static Future<String> getContentsFromFile() async {
String content;
ga.Media mediaResponse = await drive.files.get(fileId);
mediaResponse.stream.listen((data) {
print("DataReceived: "+data);
content = data
}, onDone: () async {
print("Task Done");
}, onError: (error) {
print("Some Error");
});
return content;
}
Im calling the function like so..
String content = await getContentsFromFile();
EDIT: Made the example more complete, with handling of errors and partial content.
You can use Completer for this sort of control flow:
import 'dart:async';
import 'package:googleapis/drive/v3.dart' as ga;
static Future<String> getContentsFromFile() async {
Completer<String> completer = Completer();
String content = "";
ga.Media mediaResponse = await drive.files.get(fileId);
mediaResponse.stream.listen((data) {
print("DataReceived: "+data);
content += data;
}, onDone: () async {
print("Task Done");
completer.complete(content);
}, onError: (error) {
print("Some Error");
completer.completeError(error);
});
return completer.future;
}

How to post observer from normal class and receive listener to widget?

I'm pretty new to Flutter and experimenting with the SDK. I am working with the flutter application which works with Socket connection. I saw lots of example which communicate with widget to widget. But, I want to add listener from Socket class to widgets. The actual scenario is, I have socket listeners in my socket manager class. Here is the rough code for better idea.
class SocketManager {
static SocketIO socketIO;
static SocketIOManager manager = SocketIOManager();
//Constructor
SocketManager(){
initSocket().then((socketIO){
addListener();
});
}
void addListener(){
socketIO.onConnect((data){
print("connected...");
});
}
}
I want to notify to my widgets when socket connected.
What kind of thing am I looking for to implement this?
Thanks in advance.
here is my class, you can follow to create yours
import 'dart:convert';
import 'package:flutter_app/global.dart';
import 'package:flutter_app/strings.dart';
import 'package:rxdart/subjects.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:socket_io_client/socket_io_client.dart' as IO;
IO.Socket kSocket;
class Sockets {
static PublishSubject socket = PublishSubject(sync: true);
static PublishSubject status = PublishSubject(sync: true);
static PublishSubject notify = PublishSubject(sync: true);
static PublishSubject chatCount = PublishSubject(sync: true);
static PublishSubject typing = PublishSubject(sync: true);
static PublishSubject login = PublishSubject(sync: false);
static PublishSubject getInfo = PublishSubject(sync: true);
static PublishSubject alreadyLogin = PublishSubject(sync: false);
static void connectSocket() async {
/* kSocket = await IO.io('${Strings.socket}', <String, dynamic>{
'transports': ['websocket', 'polling'],
});*/
SharedPreferences prefs = await SharedPreferences.getInstance();
String token = prefs.getString('userToken');
if (token != null && token != '') {
Map<String, dynamic> parsedToken = Functions.parseJwt(token);
String imza = token?.split('.')[2];
kSocket = await IO.io('${Strings.socket}', <String, dynamic>{
'transports': ['websocket', 'polling'],
'query': 'token=$imza'
});
parsedToken['Tur'] = 2;
kSocket.close();
kSocket.disconnect();
kSocket.open();
try {
kSocket.on('connect', (data) {
print('SOCKET CONNECTED');
kSocket.emit('adduser', parsedToken);
kSocket.on('getmessage', (res) {
print('GETMSG: $res');
chatCount.sink.add(res);
socket.sink.add(res);
});
kSocket.on('bildirim', (res) {
print('[BILDIRIM]: $res');
notify.sink.add(res);
});
kSocket.on('durum', (res) {
status.sink.add(res);
});
kSocket.on('disconnect', (data) {
// print('DISCONNECT: $data');
});
kSocket.on('typing', (res) {
typing.sink.add(res);
});
kSocket.on('login', (res) {
//print('Multi Login');
login.sink.add(res);
});
kSocket.on('getinfo', (res) {
//print('GETINFO: $res');
getInfo.sink.add(res);
});
kSocket.on('alreadylogin', (res) {
//print('ALREADY LOGIN: $res');
alreadyLogin.sink.add(res);
});
});
} catch (e) {
print(e);
}
} else {
print('SOCKET: token yok');
}
}
static void setInfo(Map<String, dynamic> data) {
kSocket.emit('setinfo', [data]);
}
static void setRead(String userid) {
kSocket.emit('setreaded', '$userid');
}
static void isTyping(String username, int status) {
kSocket.emit('istyping', [
{"user": int.parse(username), "durum": status}
]);
}
static void isActive(String userid) {
if (kSocket != null) {
if (kSocket.connected) {
try {
//print('${kSocket.connected}');
kSocket.emit('isactive', '$userid');
} catch (e) {
print(e);
}
}
}
}
static void disconnectSocket() async {
try {
await kSocket.disconnect();
await kSocket.close();
await kSocket.destroy();
print('SOCKET DISCONNECTED');
} catch (e) {
//print(e);
}
}
static void dispose(){
socket.close();
status.close();
//notify.close();
chatCount.close();
typing.close();
login.close();
getInfo.close();
alreadyLogin.close();
}
static void unSubNotify(){
notify.close();
}
}
Answer is here !! Here what I found while surfing on the web. Flutter-NotificationCenter. An IOS type post and receive observer. It is Very helpful to other developers who want to post observer from anywhere and want to receive it to anywhere.