Flutter null or emptylist - flutter

it's just a small question about dart/flutter code.
I saw this code today :
Future<List<String>?> getAtSignListFromKeychain() async {
var atsignMap = await _getAtSignMap();
if (atsignMap.isEmpty) {
// no atsigns found in biometric storage
// read entries from flutter keychain
// for mobile platforms only
if (Platform.isAndroid || Platform.isIOS) {
atsignMap = await checkForValuesInFlutterKeychain();
if (atsignMap.isEmpty) {
return null;
}
} else {
return null;
}
}
var atsigns = atsignMap.keys.toList();
_logger.info('Retrieved atsigns $atsigns from Keychain');
return atsigns;
}
I don't understand interest of returning null with List? . Isn't better to write this code ?:
Future<List<String>> getAtSignListFromKeychain() async {
var atsignMap = await _getAtSignMap();
if (atsignMap.isEmpty) {
// no atsigns found in biometric storage
// read entries from flutter keychain
// for mobile platforms only
if (Platform.isAndroid || Platform.isIOS) {
atsignMap = await checkForValuesInFlutterKeychain();
if (atsignMap.isEmpty) {
return atsignMap;
}
} else {
return List.empty();
}
}
var atsigns = atsignMap.keys.toList();
_logger.info('Retrieved atsigns $atsigns from Keychain');
return atsigns;
}
Or I'm missing something ? Thank you !

First of all, there are always different solutions for different problems. I believe it is better to return a null value for some cases instead of creating an empty list in the memory and returning that. Either way, you have to check the returning value, handle errors, etc. So instead of checking if the list is empty or not, you can use just the ?? operator.
And in some cases, the list you expect with the items in it may be empty. If you return an empty list by default in such cases, you would not know if the list that you expected is really empty or is there a problem.

Related

Is this approach is an Anti-Pattern? - Flutter

strong textI'm implementing a contacts list search bar, where the user can search & select some contacts, but I need the selected contacts to be shown as selected while the user is still searching.
I achieved this by modifying the original list and the duplicate list which used in the searching process at the same time.
is this an Anti-Pattern and is there a better way to do it?
Here's what I'm doing with the search query:
void searchContacts([String? name]) {
if (name == null || name.isEmpty) {
searchedList.clear();
addAllContactsToSearchList();
return;
} else {
searchedList.clear();
originalContactsList!.forEach((contact) {
if (contact.name.toLowerCase().contains(name.toLowerCase())) {
searchedList.clear();
searchedList.add(contact);
return;
} else {
return;
}
});
return;
}
}
and here's the code for selecting a contact:
void _onChange(bool value, int index) {
final selectedContact = searchedList[index].copyWith(isSelected: value);
searchedList.removeAt(index);
setState(() {
searchedList.insert(index, selectedContact);
notifier.originalContactsList = notifier.originalContactsList!.map((e) {
if (e.number == selectedContact.number) {
return selectedContact;
} else {
return e;
}
}).toList();
});}
This is expected behavior: gif
Some assumptions I'm making is that (1) each contact has a unique identifier that isn't just a name, and (2) you don't need the selected contacts to be shown in the same list as a search with a different query (if you search H, select Hasan, then search Ha, you expect it to still show up as selected on the next page, but if you search He, Hasan shouldn't shouldn't be on that next list.
The best way to do this is to have one constant list, and one list with results:
Set<String> selectedContactIds = {};
List<Contact> searchedList = [];
void _onChange(bool value, int index) {
final clickedContact = searchedList[index];
bool itemAlreadySelected = selectedContactIds.contains(clickedContact.userID);
setState({
if(itemAlreadySelected) {
selectedContactIds.remove(clickedContact.userID);
} else {
selectedContactIds.add(clickedContact.userID);
}
});
}
Now once you set state, your ListView should be updating the appearance of selected objects by checking if it's selected the same way that the _onChange function is checking if the item was already selected, which was:
bool itemAlreadySelected = selectedContactIds.contains(clickedContact.userID);
And this way, you don't have a whole class for contacts with a dedicated isSelected member. You wouldn't want that anyways because you're only selecting contacts for very specific case by case uses. Hopefully this helps!

Future is stuck on return statement and never completes the function future called from

getInitialTripData calls getCurrentLocationData with await but it never prints "coming here 1" and on getCurrentLocationData the function goes on till printing the data and then stuck on return statement i dont know what the issue is
setInitialTripData() async {
print("coming here");
MapLocation startingPoint=await Get.find<LocationService>().getCurrentLocationData();
print("coming here 1");
if (startingPoint != null) {
tripData.startingPoint = startingPoint;
startingPointTextController.text = startingPoint.name;
update();
}
}
Future<MapLocation> getCurrentLocationData()async{
try{
if(!locationAllowed.value){
return null;
}
LocationData position=await _location.getLocation();
List<geo.Placemark> placemark =
await geo.placemarkFromCoordinates(position.latitude, position.longitude);
if(placemark.length==0 || placemark==null){
return null;
}
MapLocation mapLocation=MapLocation(name: "${placemark[0].name.isNotEmpty? placemark[0].name+", ":""}${placemark[0].subAdministrativeArea.isNotEmpty? placemark[0].subAdministrativeArea+", ":""}${placemark[0].isoCountryCode.isNotEmpty? placemark[0].isoCountryCode:""}",latitude: position.latitude,longitude: position.longitude);
print(mapLocation.getDataMap());
return mapLocation;
}
catch(e){
return null;
}
}
getCurrentLocation has a bunch of chances to return null, and you're not handling a potential null return value in setInitialTripData
your code only continues executing if startingPoint != null it seems.
Well Problem is in your getCurrentLocationData function because your function is expecting a return value of type MapLocation because you have declared in your function it's return type here
Future<MapLocation> getCurrentLocationData(){}
That's why when you return null from this function this throws an error and break your functions.
What you need to do is either remove return type or make it nullable whichever works fine like :
Future<MapLocation?> getCurrentLocationData(){}
Or
Future getCurrentLocationData(){}
Apart from that you need to make the receiving variable nullable so that it can handle null data
MapLocation? startingPoint=await Get.find<LocationService>().getCurrentLocationData();

Flutter flutter_blue label printer issue

I am new in flutter.
I am building an app to print on the ble label printer via Bluetooth.
I use flutter_blue library. I had successfully connected to the device and found the target characteristic. My problem is that when I call write() function of the characteristic printer show on display “waiting for data” and nothing is printed.
Could you please help me with the data format I need to put into the method?
I use utf8 encoded string as data.
Future<void> _print() async {
var serviceUuid = '0000ff00-0000-1000-8000-00805f9b34fb';
var characteristicsUuid = '0000ff02-0000-1000-8000-00805f9b34fb';
_services.forEach((service) {
if(service.uuid.toString().toLowerCase() == serviceUuid) {
printService = service;
for (var c in printService!.characteristics) {
if(c.uuid.toString().toLowerCase() == characteristicsUuid) {
var ZPL_TEST_LABEL = 'Hello WeChat!\r\n';
printCharacteristic = c;
writeData(printCharacteristic, ZPL_TEST_LABEL);
}
}
}});
}
Future<void> writeData(characteristic, data) async{
if (characteristic == null) return;
try {
var utf8Encoded = utf8.encode(data);
debugPrint(data.toString());
var result = await characteristic.write(utf8Encoded);
debugPrint(result.toString());
} catch (e) {
debugPrint(e.toString());
}
}
My first step is to print at least a string, could you pls help me?

How to use a variable for method name

I want to use a variable to access a certain value in my hive database:
In the code below if I use myBox.getAt(i).attributeSelect I get an error because attributeSelect is not defined for the box.
If I use myBox.getAt(i).test it works. How can I make flutter recognise that attributeSelect is a variable and put the value there? I have a total of 181 different variables the user can choose from. Do I really need that many if clauses? The variables are booleans. So I want to check if that attribute is true for the document at index i.
Error: NoSuchMethodError: 'attributeSelect'
method not found
Receiver: Instance of 'HiveDocMod'
attributeSelect = 'test'; //value depends on user choice
Future<void> queryHiveDocs() async {
final myBox = await Hive.openBox('my');
for (var i = 0; i < myBox.length; i++) {
if (attributeSelect == 'All Documents') {
_hiveDocs.add(myBox.getAt(i)); // get all documents
//print(myBox.getAt(24).vesselId);
} else {
// Query for attribute
if (myBox.getAt(i).attributeSelect) {
_hiveDocs.add(myBox.getAt(i)); // get only docs where the attributeSelect is true
}
}
}
setState(() {
_hiveDocs = _hiveDocs;
_isLoading = false;
});
}
I solved it the annoyingly hard way:
if (attributeSelect == 'crsAirCompressor') {
if (myBox.getAt(i).crsAirCompressor) {
_hiveDocs.add(myBox.getAt(i));
}
} else if (attributeSelect == 'crsBatteries') {
if (myBox.getAt(i).crsBatteries) {
_hiveDocs.add(myBox.getAt(i));
}...

Flutter : Conditions must have a static type of 'bool'

I'm trying to learn firebase with flutter and i ran into this problem
here is my code :
FirebaseFirestore.instance
.collection('attendees')
.doc(user.uid)
.snapshots()
.listen((snapshot) {
if (snapshot.data() != null) {
if (snapshot.data()!['attending']) {
_attending = Attending.yes;
} else {
_attending = Attending.no;
}
} else {
_attending = Attending.unknown;
}
notifyListeners();
});
what is the solution ?
the exact problem is within this line :
if (snapshot.data()!['attending']) {
how can I rewrite this so i wont ruin the current functionality ?
I appreciate your help inadvance
The reason you are getting error -
Conditions must have a static type of 'bool'
because on line snapshot.data()!['attending'] an = sign is missing.
To make your code work just do
if (snapshot.data() != snapshot.data()!['attending']) {
_attending = Attending.yes;
} else {
_attending = Attending.no;
}
Understanding The Error
I would also like to point out that Dart a stricter language (more like Java in terms of 'truthy' values).
In JavaScript you can use any ‘truthy’ value in a conditional statement. In Dart you cannot use ‘truthy’ values. For example:
var name = 'Joe';
if (name) {
// do something...
OR
var a = 1
if(a){
//this would work in JavaScript
}
You cannot do such things in Java or Dart. The reason is that Dart requires that a condition is a bool true not just a 'truthy' value. You could correct the code by changing it to:
if (name.isNotEmpty)
OR
if(a==1)
{
//these == signs are really important
}
Just store the snapshot.data() to the local map variable and do the operations by that.
_attendingSubscription = FirebaseFirestore.instance
.collection('attendees')
.doc(user.uid)
.snapshots()
.listen((snapshot) {
final Map<String, dynamic>? data = snapshot.data();
if (data != null) {
_attending = data['attending'] ? Attending.yes : Attending.no;
} else {
_attending = Attending.unknown;
}
notifyListeners();
});