How to transform a Future method in a Stream method to feed a list - flutter

I have this method to feed my list, but with it i'm not able to change items dynamically ( add items, drop it...) :
loadLab(String submenu, [int limit]) async {
var parts = submenu.split('/');
var pathSlashless = parts[0].trim();
var subPathSlashless = parts.sublist(1).join('/').trim();
var snapshot = await _storage.ref().child("/${submenu}");
var retorno = await snapshot.listAll();
List<ItemLab> conteudo = [];
if(subPathSlashless.isEmpty || subPathSlashless == null){
retorno.prefixes.forEach((element) {
conteudo.add(
ItemLab(
tipo: 'PASTA',
elemento: element,
),
);
});
}
if(limit != null){
if(conteudo.length > limit){
hasMore = true;
return Stream.value(conteudo);
}else{
hasMore = false;
print("menor quen ove");
}
}
}
try {
if(subPathSlashless.isNotEmpty){
print(subPathSlashless);
List items;
await databaseReference
.collection("lab_${pathSlashless}_url")
.snapshots().forEach((element) {
element.docs.forEach((f) {
if(f.data()['videos'] != null){
items == null ? items = f.data()['videos'] :
items.addAll(f.data()['videos']);
};
print("ITEMS :::: >>> ${items}");
});
});
}catch(e){
print(e);
}
pathSlashless = null;
subPathSlashless = null;
conteudo = checkDuplicateFolder(conteudo, submenu);
print(conteudo);
return Stream.value(conteudo);
}
and the list>
return StreamBuilder(
stream: ctrlLab.loadLab(submenu),
throw this error:
type 'Future' is not a subtype of type 'Stream'
What I need to do to Make the return a Stream instead of a Future

Related

Pull to refresh package in flutter for pagination purpose

Hello Readers I am new in flutter and i want to do pagination, for pagination I am using one package which name is "pull to refersh".
Problems :
I have total 6 post and per page limits are 3.
1)When I reached at the end of list then api will call and set current page variable value is 2 and it will load all data of page 2 as a new list, but i want to merge page 2 data into same list... (Pagination like facebook instagram etc).
2)My another problem is when i pull for refersh, page is refersh perfectly and it will go to the first page but problem is, when i again go at the end of list it shows me no more data(which means page 2 api is not working)
I have one condition like if else:- "hasNextPage" this variable getting from api and the response is 1 or 2, if response is 1 then there further page after current page and if is 0 then there is no page after current page.
I am posting my code and api link also can you please help me.
Method for get data from API
int currentPage = 1;
bool isRefersh = false;
final RefreshController refreshController = RefreshController();
Future<UserPost> getUserPost() async {
var url =
"LINK=$currentPage";
var response = await http.get(Uri.parse(url));
var jsondata = jsonDecode(response.body.toString());
var _apiData = UserPost.fromJson(jsondata);
if (response.statusCode == 200) {
print("******getUserPost API");
print("current page****$currentPage");
print("hasnext page ${_apiData.hasNextPage}");
print(jsondata);
if(isRefersh == true){
setState((){
//currentPage = 1;
isRefersh = false;
});
refreshController.refreshCompleted();
return UserPost.fromJson(jsondata);
}
else{
print("//////////////// has next page");
print(_apiData.hasNextPage.toString());
if(_apiData.hasNextPage == 0){
refreshController.loadNoData();
return UserPost.fromJson(jsondata);
}else{
}
return UserPost.fromJson(jsondata);
}
} else {
return UserPost.fromJson(jsondata);
}
}
Method for pull to Refersh
onRefresh: () async{
await Future.delayed(Duration(milliseconds: 1000));
setState(() {
isRefersh = true;
currentPage = 1;
});
},
Method for Pagination
onLoading: () async {
if(snapshot.data!.hasNextPage == 0){
refreshController.loadNoData();
}else{
setState(() {
currentPage++;
});
await Future.delayed(Duration(milliseconds: 1000));
refreshController.loadComplete();
}
},
I Hope it's help you
try this way :-
final RefreshController refreshController =
RefreshController(initialRefresh: true);
Future<bool> getPassengerData({bool isRefresh = false}) async {
if (isRefresh) {
currentPage = 1;
} else {
if (currentPage >= totalPages) {
refreshController.loadNoData();
return false;
}
}
final Uri uri = Uri.parse(
"api url=$currentPage&size=10");
final response = await http.get(uri);
if (response.statusCode == 200) {
final result = passengersDataFromJson(response.body);
if (isRefresh) {
passengers = result.data;
}else{
passengers.addAll(result.data);
}
currentPage++;
totalPages = result.totalPages;
print(response.body);
setState(() {});
return true;
} else {
return false;
}
}
Method for pull to Refersh
onRefresh: () async {
final result = await getPassengerData(isRefresh: true);
if (result) {
refreshController.refreshCompleted();
} else {
refreshController.refreshFailed();
}
},
Method for onLoading:
onLoading: () async {
final result = await getPassengerData();
if (result) {
refreshController.loadComplete();
} else {
refreshController.loadFailed();
}
},
Try this way.
when you get the response in second page just create new list with previous list.
i.e var newData = [...?dummyData.data, ...?_apiData.data];
than return this same list.
UserPostModel dummyData = UserPostModel();
Future<UserPostModel> getUserPost() async {
var url =
"*****?page=$currentPage";
var response = await http.get(Uri.parse(url));
var jsondata = jsonDecode(response.body.toString());
var _apiData = UserPostModel.fromJson(jsondata);
var newData = [...?dummyData.data, ...?_apiData.data];
//totalPage = _apiData.totalPages as int?;
if (response.statusCode == 200) {
if (isRefersh == true) {
setState(() {
isRefersh = false;
});
refreshController.refreshCompleted();
} else {
if (_apiData.hasNextPage == 0) {
refreshController.loadNoData();
} else {
refreshController.loadComplete();
}
}
dummyData.data = newData;
return dummyData;
} else {
return dummyData;
}
}

Flutter & Firebase - Get a specific field from document

I have been trying to get a specific field from a specific document. I need token for toWho. But I always got null. How do I fix this?
Main Code is
Future<String> getUserToken(String toWho) async {
DocumentSnapshot _doc = await FirebaseFirestore.instance.doc("tokens/" + toWho).get();
if (_doc != null) {
Map<String, dynamic> _data = _doc.data();
return _data["token"];
} else {
return null;
}
}
in Repository
Future<bool> sendMessage(
MessageModel sendingMessage, UserModel currentUser) async {
if (appMode == AppMode.DEBUG) {
return true;
} else {
var _writePrcs = await _firestoreDBService.saveMessage(sendingMessage);
if (_writePrcs) {
var _token = "";
if (_userToken.containsKey(sendingMessage.toWho)) {
_token = _userToken[sendingMessage.toWho];
print("Token lokalden geldi.");
} else {
_token = await _firestoreDBService.getUserToken(sendingMessage.toWho);
_userToken[sendingMessage.toWho] = _token;
print("Token veritabanından geldi.");
}
Thanks for your help from now on
Try ...........
Future<String> getUserToken(String toWho) async {
DocumentSnapshot _doc = await
FirebaseFirestore.instance.collection("tokens/groupChatId/message").doc(toWho).get();
if (_doc != null) {
Map<String, dynamic> _data = _doc.data();
return _data["token"];
} else {
return null;
}
}

type 'Future<dynamic>' is not a subtype of type 'Stream<dynamic>' getting data from Firebase

I'm retrieving data from Firebase Storage and Firestore, to show the items in a list with the icon (if the item is a file) or the image (if is image). The problem is, If I get all the images in one time it doesn't load all.. It loads at maximum 20 and crashes due to memory leaking. So My idea is to do a list which gets 10 elements by time, and when the user scroll down to the bottom of the results, it loads more 10 and subsequently. But, I was using Future builder and with it I cant update the list when I need and the problem continues, so now, I'm trying to get in a stream and show with a StreamBuilder to be able to update the list dynamically.
this is my controller:
loadList(String submenu, [int limit]) async {
var parts = submenu.split('/');
var pathSlashless = parts[0].trim();
var subPathSlashless = parts.sublist(1).join('/').trim();
var snapshot = await _storage.ref().child("/${submenu}");
var retorno = await snapshot.listAll();
List<ItemLab> conteudo = [];
if(subPathSlashless.isEmpty || subPathSlashless == null){
retorno.prefixes.forEach((element) {
conteudo.add(
ItemLab(
tipo: 'PASTA',
elemento: element,
),
);
});
}
for(int i = 0; i < retorno.items.length ; i++){
var url = await retorno.items[i].getDownloadURL();
conteudo.add(
ItemLab(
tipo: 'FILE',
elemento: retorno.items[i],
imageUrl: url,
),
);
if(limit != null){
if(conteudo.length > limit){
hasMore = true;
return Stream.value(conteudo);
}else{
hasMore = false;
print("less than 9");
}
}
}
try {
if(subPathSlashless.isNotEmpty){
print(subPathSlashless);
List items;
await databaseReference
.collection("lab_${pathSlashless}_url")
.snapshots().forEach((element) {
element.docs.forEach((f) {
if(f.data()['videos'] != null){
items == null ? items = f.data()['videos'] :
items.addAll(f.data()['videos']);
};
print("ITEMS :::: >>> ${items}");
});
});
for(int i = 0; i < items.length; i ++){
//print(items[i]);
conteudo.add(
ItemLab(
tipo: 'VIDEO',
elemento: null,
video: items[i],
),
);
}
}else{
await databaseReference
.collection("lab_${pathSlashless}_url")
.snapshots().forEach((element) {
element.docs.forEach((f) {
if(f.data().isNotEmpty){
print(f.data());
if(f.data().keys.contains("videos")){
conteudo.add(
ItemLab(
tipo: 'PASTA',
pastaVideo: findFolderName(f.reference.path)
),
);
}else{
conteudo.add(
ItemLab(
tipo: 'VIDEO',
elemento: null,
video: f.data(),
),
);
}
}
});
});
}
}catch(e){
print(e);
}
pathSlashless = null;
subPathSlashless = null;
conteudo = checkDuplicateFolder(conteudo, submenu);
return Stream.value(conteudo);
}
And here my list:
return StreamBuilder(
stream: ctrl.loadList(submenu),
builder: (ctx, snapshot) {
But, if I run this code it throws this error:
type 'Future' is not a subtype of type 'Stream'
How Can I handle that to be able to update the list dynamically using a stream instead of a Future
You can't await .snapshots(), as it returns stream, you can change it to get. Also learn more about flutter firebase realtime and normal use case, check the flutter fire docs
loadList(String submenu, [int limit]) async {
var parts = submenu.split('/');
var pathSlashless = parts[0].trim();
var subPathSlashless = parts.sublist(1).join('/').trim();
var snapshot = await _storage.ref().child("/${submenu}");
var retorno = await snapshot.listAll();
List<ItemLab> conteudo = [];
if(subPathSlashless.isEmpty || subPathSlashless == null){
retorno.prefixes.forEach((element) {
conteudo.add(
ItemLab(
tipo: 'PASTA',
elemento: element,
),
);
});
}
for(int i = 0; i < retorno.items.length ; i++){
var url = await retorno.items[i].getDownloadURL();
conteudo.add(
ItemLab(
tipo: 'FILE',
elemento: retorno.items[i],
imageUrl: url,
),
);
if(limit != null){
if(conteudo.length > limit){
hasMore = true;
return Stream.value(conteudo);
}else{
hasMore = false;
print("less than 9");
}
}
}
try {
if(subPathSlashless.isNotEmpty){
print(subPathSlashless);
List items;
(await databaseReference
.collection("lab_${pathSlashless}_url")
.get()).docs.forEach((f) {
if(f.data()['videos'] != null){
items == null ? items = f.data()['videos'] :
items.addAll(f.data()['videos']);
};
print("ITEMS :::: >>> ${items}");
});
for(int i = 0; i < items.length; i ++){
//print(items[i]);
conteudo.add(
ItemLab(
tipo: 'VIDEO',
elemento: null,
video: items[i],
),
);
}
}else{
(await databaseReference
.collection("lab_${pathSlashless}_url")
.get()).docs.forEach((f) {
if(f.data().isNotEmpty){
print(f.data());
if(f.data().keys.contains("videos")){
conteudo.add(
ItemLab(
tipo: 'PASTA',
pastaVideo: findFolderName(f.reference.path)
),
);
}else{
conteudo.add(
ItemLab(
tipo: 'VIDEO',
elemento: null,
video: f.data(),
),
);
}
}
});
}
}catch(e){
print(e);
}
pathSlashless = null;
subPathSlashless = null;
conteudo = checkDuplicateFolder(conteudo, submenu);
return conteudo;
}
And the list
return FutureBuilder(
future: ctrl.loadList(submenu),
builder: (ctx, snapshot) {

Send string values from one smartphone device to another smartphone device via Bluetooth in flutter

I want to send multiple string values from one smartphone device to another device via Bluetooth in flutter. I have seen flutter_blue and flutter_bluetooth_searial package examples also but i cant find anything that sends multiple strings values via Bluetooth. can anyone please suggest how i can be able to achieve this task?
I used flutter_bluetooth_searial in one of my projects, here is the the whole class including: sending data (multiple strings), receiving data, connect, disconnect, auto-pairing, ...etc
Hope you find this helpful.
import 'dart:async';
import 'dart:typed_data';
import 'dart:convert' show utf8;
import 'package:flutter/foundation.dart';
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
class BluetoothStore extends ChangeNotifier {
var _instance = FlutterBluetoothSerial.instance;
var _dataBuffer = '';
void Function(String) _onDataCallback = (String data) {};
StreamSubscription<Uint8List> _dataSubscription;
StreamSubscription<BluetoothDiscoveryResult> _scannedDevicesSubscription;
BluetoothDiscoveryResult _connectedDevice;
BluetoothConnection _connection;
var name = "...";
var address = "...";
var pinNum = "1234";
var isScanning = false;
var _isConnecting = false;
var _autoPair = false;
var scannedDevices = List<BluetoothDiscoveryResult>();
var state = BluetoothState.UNKNOWN;
BluetoothStore() {
initBluetooth();
}
bool get autoPair => _autoPair;
bool get isConnecting => _isConnecting;
bool get isConnected => _dataSubscription != null;
set autoPair(bool value) {
_autoPair = value;
if (value) {
_instance.setPairingRequestHandler((request) {
if (request.pairingVariant == PairingVariant.Pin)
return Future.value(pinNum);
return Future.value("");
});
} else {
_instance.setPairingRequestHandler(null);
}
notifyListeners();
}
void initBluetooth() async {
// Get bluetooth initial state
this.state = await _instance.state;
this.address = await _instance.address;
this.name = await _instance.name;
notifyListeners();
_instance.onStateChanged().listen((state) {
this.state = state;
_reset();
});
}
Future<bool> pairWith(BluetoothDevice device) async {
var pairedDevices = await _instance.getBondedDevices();
if (pairedDevices.length < 7) {
var result = await _instance.bondDeviceAtAddress(device.address);
if (result) {
var deviceIndex = scannedDevices.indexWhere((scannedDevice) {
return scannedDevice.device.address == device.address;
});
scannedDevices[deviceIndex] = BluetoothDiscoveryResult(
device: BluetoothDevice(
name: device.name ?? '',
address: device.address,
type: device.type,
bondState:
result ? BluetoothBondState.bonded : BluetoothBondState.none,
),
rssi: scannedDevices[deviceIndex].rssi,
);
notifyListeners();
}
return Future.value(result);
}
return Future.value(false);
}
// Notice the return value
Future<bool> unpairFrom(BluetoothDevice device) async {
var result = await _instance.removeDeviceBondWithAddress(device.address);
if (result) {
var deviceIndex = scannedDevices.indexWhere((scannedDevice) {
return scannedDevice.device.address == device.address;
});
scannedDevices[deviceIndex] = BluetoothDiscoveryResult(
device: BluetoothDevice(
name: device.name ?? '',
address: device.address,
type: device.type,
bondState:
result ? BluetoothBondState.none : BluetoothBondState.bonded,
),
rssi: scannedDevices[deviceIndex].rssi,
);
notifyListeners();
}
return Future.value(result);
}
Future<bool> enable() => _instance.requestEnable();
Future<bool> disable() => _instance.requestDisable();
Future<void> openSettings() => _instance.openSettings();
Future<bool> connectTo(BluetoothDevice device) async {
_isConnecting = true;
if (isConnected) await _connection.close();
notifyListeners();
try {
var connection = await BluetoothConnection.toAddress(device.address);
_isConnecting = false;
_connection = connection;
_dataSubscription = connection.input.listen(_onDataReceived);
_dataSubscription.onDone(_onDisconnect);
var deviceIndex = scannedDevices.indexWhere((scannedDevice) {
return scannedDevice.device.address == device.address;
});
_connectedDevice = scannedDevices[deviceIndex] = BluetoothDiscoveryResult(
device: BluetoothDevice(
name: device.name ?? '',
address: device.address,
bondState: device.bondState,
type: device.type,
isConnected: true,
),
rssi: scannedDevices[deviceIndex].rssi,
);
notifyListeners();
return Future.value(true);
} catch (_) {
_isConnecting = false;
_dataSubscription = null;
_connection = null;
notifyListeners();
return Future.value(false);
}
}
Future<List<BluetoothDevice>> pairedDevices() async {
var result = await _instance.getBondedDevices();
return Future.value(result);
}
void disConnect() async {
if (isConnected) {
this.unpairFrom(_connectedDevice.device);
_connection.dispose();
}
}
void startScanning() {
isScanning = true;
scannedDevices.clear();
notifyListeners();
if (isConnected) scannedDevices.add(_connectedDevice);
_scannedDevicesSubscription = _instance.startDiscovery().listen((device) {
scannedDevices.add(device);
});
_scannedDevicesSubscription.onDone(() async {
isScanning = false;
notifyListeners();
});
}
void _onDataReceived(Uint8List data) {
// Allocate buffer for parsed data
var backspacesCounter = 0;
data.forEach((byte) {
if (byte == 8 || byte == 127) backspacesCounter++;
});
var buffer = Uint8List(data.length - backspacesCounter);
var bufferIndex = buffer.length;
// Apply backspace control character
backspacesCounter = 0;
for (int i = data.length - 1; i >= 0; i--) {
if (data[i] == 8 || data[i] == 127) {
backspacesCounter++;
} else {
if (backspacesCounter > 0) {
backspacesCounter--;
} else {
buffer[--bufferIndex] = data[i];
}
}
}
// Create message if there is new line character
var dataString = String.fromCharCodes(buffer);
var index = buffer.indexOf(13);
if (~index != 0) {
// \r\n
var data = backspacesCounter > 0
? _dataBuffer.substring(0, _dataBuffer.length - backspacesCounter)
: _dataBuffer = _dataBuffer + dataString.substring(0, index);
_onDataCallback(data);
_dataBuffer = dataString.substring(index);
} else {
_dataBuffer = (backspacesCounter > 0
? _dataBuffer.substring(0, _dataBuffer.length - backspacesCounter)
: _dataBuffer + dataString);
}
}
void _onDisconnect() {
// reset
if (this.state == BluetoothState.STATE_ON) {
var deviceIndex = scannedDevices.indexWhere((scannedDevice) {
return scannedDevice.device.address == _connectedDevice.device.address;
});
scannedDevices[deviceIndex] = BluetoothDiscoveryResult(
device: BluetoothDevice(
name: _connectedDevice.device.name ?? '',
address: _connectedDevice.device.address,
type: _connectedDevice.device.type,
bondState: _connectedDevice.device.bondState,
),
rssi: _connectedDevice.rssi,
);
}
_reset();
}
void _reset() {
_dataBuffer = '';
_isConnecting = false;
_dataSubscription = null;
_scannedDevicesSubscription = null;
_connectedDevice = null;
_connection = null;
if (this.state != BluetoothState.STATE_ON) {
scannedDevices.clear();
}
notifyListeners();
}
void onDataReceived(void Function(String) callback) {
_onDataCallback = callback;
}
bool sendData(String data) {
try {
data = data.trim();
if (data.length > 0 && isConnected) {
_connection.output.add(utf8.encode(data + "\r\n"));
return true;
}
} catch (e) {
return false;
}
return false;
}
void dispose() {
_instance.setPairingRequestHandler(null);
if (isConnected) _dataSubscription.cancel();
_scannedDevicesSubscription?.cancel();
super.dispose();
}
}
You can consume this class using ChangeNotifierProvider
ChangeNotifierProvider<BluetoothStore>.value(value: BluetoothStore())

issue with geting all data from sqflite database

i have been trying to get all my data from a sqflite database, when i try to get a single data, this works totally fine:
Future<dynamic> getUser() async {
final db = await database;
var res = await db.query("files");
if (res.length == 0) {
return null;
} else {
var resMap = res[0];
return resMap;
}
}
but when i try to get all data using a for loop like the example below, i get an error
Future<dynamic> getUser() async {
final db = await database;
var res = await db.query("files");
var resMap;
var count = res.length;
if (count != 0) {
for (int i = 0; i < count; i++) {
resMap.add(res[i]);
}
}
return resMap;
}
the error says:
The method 'forEach' was called on null.
Receiver: null
Tried calling: forEach(Closure: (dynamic, dynamic) => Null)
i understand that it says that I've got no data,
and i also tried to remove the if statement, but still no luck!
change this method:
EDIT
Future<List<Map>> getUser() async {
final db = await database;
var res = await db.query("files");
List<Map> resMap = [];
if (res != null res.length > 0) {
for (int i = 0; i < count; i++) {
resMap.add(res[i]);
}
return resMap;
} else
{
return null;
}
}
try this in you widget
List<Map> newUser = [];
#override
void initState() {
super.initState();
getUser();
}
getUser() async {
final _userData = await DBProvider.db.getUser();
if(_userData != null ){
setState(() {
newUser = _userData;
});
} else{
setState(() {
newUser =[];
});
}
}