I have an odd issue I can't explain the reason for it - maybe someone here can shed some light on it
I have a ticket scanning app in Xamarin Forms currently testing it on android
the interface allows you to:
type an order number and click the check order Button
use the camera scanner to scan which automatically triggers check order
use the barcode scanner to scan which automatically triggers check order
after the check order validation, user has to select the number of tickets from a drop down list and press confrim entry button
what I'm trying to do, is if the seats available on that ticket is just 1 - then automatically trigger confirm entry button functionality
problem that I have is that - some of my logic depends on setting the drop down index in code - for some reason it doesn't update - as seen in the debugger shot here
and this is the second tme I've noticed this today, earlier it was a var I was trying to assign a string and it kept coming up as null - eventually I replaced that code
is this a bug in xamarin ?
code has been simplified:
async void OnCheckOrderButtonClicked(object sender, EventArgs e)
{
await ValidateOrderEntry();
}
private async void scanCameraButton_Clicked(object sender, EventArgs e)
{
messageLabel.Text = string.Empty;
var options = new ZXing.Mobile.MobileBarcodeScanningOptions();
options.PossibleFormats = new List<ZXing.BarcodeFormat>() {
ZXing.BarcodeFormat.QR_CODE,ZXing.BarcodeFormat.EAN_8, ZXing.BarcodeFormat.EAN_13
};
var scanPage = new ZXingScannerPage(options);
scanPage.OnScanResult += (result) =>
{
//stop scan
scanPage.IsScanning = false;
Device.BeginInvokeOnMainThread(async () =>
{
//pop the page and get the result
await Navigation.PopAsync();
orderNoEntry.Text = result.Text;
//automatically trigger update
await ValidateOrderEntry();
});
};
await Navigation.PushAsync(scanPage);
}
private async Task ValidateOrderEntry()
{
//...other code....
checkInPicker.Items.Clear();
if (availablTickets == 1)
{
checkInPickerStack.IsVisible = true;
checkInPicker.SelectedIndex = 0;
messageLabel.Text = "Ticket OK! - " + orderNoEntry.Text;
messageLabel.TextColor = Color.Green;
//select the only element
checkInPicker.SelectedIndex = 0;
await PostDoorEntry();
}
//...other code....
}
private async Task PostDoorEntry()
{
int entryCount = checkInPicker.SelectedIndex + 1;
//... more code...
//...post api code..
}
Maybe I'm overlooking something, but you clear all the items a few lines above the one you are pointing out. That means there are no items in your Picker and thus you can't set the SelectedIndex to anything other than -1, simply because there are no items.
Related
I am developing an application in Flutter where I need to implement an image selection function like in instagram.
But there is an issue, my app UI is freezing when trying to get and compress files from user phone gallery.
This is my first experience with flutter isolates, but as far as i know it should work without freezes.
Here is an image for a better understanding of what i want to do.
This is a function that calls getFiles function in isolation.
Here i get paths of user phone gallery files and pass them to another function in order to compress and get files for rendering.
Future fetchImages({ bool fetchMore = false, bool force = false }) async {
if (!fetchMore) {
setState(() => fetched = false);
}
if (force) {
assetsCount = await assetPathEntity!.assetCountAsync;
page = 0;
files.clear();
}
if (assetsCount == 0 || page >= (assetsCount / pageSize)) {
return setState(() => fetched = true);
}
final assetEntities = await assetPathEntity!.getAssetListPaged(page: page++, size: pageSize);
lastCompletedIndex = files.length;
final receivePort = ReceivePort();
final completer = Completer();
getFiles(receivePort.sendPort, assetEntities);
try {
receivePort.listen((filesPaths) {
for (final filePath in filesPaths) {
files.add({
"path": filePath,
"compressedFile": null,
});
}
if (scaledFile == null && files.isNotEmpty) {
scaledFile = File(files.first["path"]);
}
compressAlbumImages();
completer.complete();
setState(() => fetched = true);
}).onError((_) {
compressAlbumImages();
completer.complete();
setState(() => fetched = true);
});
await Future.wait([completer.future]);
} catch (_) { }
finally {
receivePort.close();
}
}
This is getFiles function that runs in isolation
void getFiles(SendPort sendPort, List<AssetEntity> assetEntities) async {
final List<String> filesPaths = [];
for (final assetEntity in assetEntities) {
try {
final file = await assetEntity.file;
if (file != null) {
filesPaths.add(file.path);
}
} catch (_) { }
}
sendPort.send(filesPaths);
}
This is a function that calls compressImages function and adds any value to refresh the list of images
Here i pass the paths and get compressed files for rendering.
void compressAlbumImages() async {
final receivePort = ReceivePort();
final completer = Completer();
compressImages(receivePort.sendPort, files, lastCompletedIndex);
try {
receivePort.listen((compressedFilesWithPath) {
files = compressedFilesWithPath;
fileStreamCt.sink.add(1);
completer.complete();
}).onError((_) {
completer.complete();
});
await Future.wait([completer.future]);
} catch (_) {}
finally {
receivePort.close();
}
return;
}
This is an image compression function that runs in isolation
void compressImages(SendPort sendPort, List<Map<String, dynamic>> files, int startFromIndex) async {
final List<String> filesToBeRemoved = [];
for (int idx = startFromIndex; idx < files.length; idx++) {
final file = files[idx];
try {
final compressedFile = await FlutterNativeImage.compressImage(
file["path"],
quality: 20,
percentage: 20,
targetHeight: 300,
targetWidth: 300,
);
file["compressedFile"] = compressedFile;
} catch (_) {
filesToBeRemoved.add(file["path"]);
}
}
if (filesToBeRemoved.isEmpty) {
return sendPort.send(files);
}
final compressedFilesWithPaths = files
.whereNot((element) => filesToBeRemoved.contains(element["path"]))
.toList();
sendPort.send(compressedFilesWithPaths);
}
And finally i render compressed images
return StreamBuilder(
stream: fileStreamCt.stream,
builder: (ctx, AsyncSnapshot<int> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("LOADING...");
}
if (snapshot.hasError) {
return Text("AN ERROR OCCURRED");
}
return buildAlbumImages();
}
);
Render like this
Image.file(compressedImage);
If in short - When i'm getting user phone gallery files && compress them, my app UI starts freezing.
I don't know why it's freezing.
I tried the same process but with file.readAsBytes() and to render like Image.memory(compressedFileBytes), but it was useless.
I would be very grateful for any help.
Thanks in advance.
In your code you never actually create an isolate. The 'isolate code' in getFile, compressImages etc simply runs on the main isolate and indeed will block the UI.
Per documentation, you create an isolate with Isolate.spawn and pass only the sendPort. The isolate then must send back a receivePort, and the main thread uses that port to send the data you want to isolate to process (like assetEntities), processes it and sends the results back to the main thread. It's a bit complicated, and requires different function signatures than you have here.
Fortunately, a much easier way to accomplish what you want (still using Isolates that won't block the UI) is to use the compute function from the dart:async package:
Change the signature of your getFiles function to Future<List<String>> getFiles(List<AssetEntity> assetEntities) async and do in it what you need to do, returning the list of filesPaths as you do now. Importantly, getFiles must be a top level or a static function, it cannot be a regular class method. Then, where you need the calculation done you use something like var filesPaths = await compute(getFiles, assetEntities). Now, the getFiles function is called in an isolate, and the return value is given back to you on the main isolate. The nice thing is that now this looks a lot like regular await call, no need for sendPorts etc. You can do the same thing for your other heavy calculation methods.
One (big) constraint with isolates is the type of argument you can pass to and from an isolate, see here. Those same constraints apply here, because under the hood the compute function also uses sendPorts etc.
I have displayed a Line chart using fl_chart ^0.10.1 (Tested on Flutter ver 52.2.1 & 53.0.1).
I am updating the FlSpots from a csv file.
I am trying to get the index or Spot object if I touch somewhere in the plot.
But I am getting an empty list from the touchResponse if I touch (both tap or long-press) somewhere.
But I am getting the value in the plot itself. I am assuming it's there because of the built-in touch handler.
The code I am trying it:
lineTouchData: LineTouchData(
touchCallback: (LineTouchResponse touchResponse) {
if (touchResponse.touchInput is FlPanEnd ||
touchResponse.touchInput is FlLongPressEnd) {
var spots = touchResponse.lineBarSpots;
setState(() {
var lengthList = spots.length;
print(
'touched spot---> ${spots.toString()},,,len--->$lengthList');
});
} else {
print('wait');
}
}),
My end goal is to use and pass the touched index to open a new screen/widget.
touchCallback: (LineTouchResponse? lineTouch) {
final value = lineTouch.lineBarSpots![0].x;
// set state...
});
It's in the demo by fl_chart in github.
https://github.com/imaNNeoFighT/fl_chart/blob/master/example/lib/line_chart/samples/line_chart_sample3.dart
How to get the following list from the Instagram account using the access token
I tried everything but not work.
here some API link which I tried before but none of them work.
I tried this one https://www.instagram.com/urvish_._/?__a=1
also this one
I tried but nothing can help me.
You can get the following (or also follower) list using the code below. Steps:
Make sure you're logged in on instagram.com
Open the API link: https://www.instagram.com/urvish_._/?__a=1 (your target username here is urvish_._)
Open the browser console: normally Ctrl+Shift+J on Windows/Linux or ⌘+Option+J on Mac
Paste this code and press Enter:
const GRAPHQL_MAX_PER_PAGE = 50;
async function getList() {
let pageLimit = 200; // from my testing
let baseInfo = JSON.parse(document.getElementsByTagName('body')[0].innerText);
let userId = baseInfo.graphql.user.id;
let config = { user_edge: 'edge_follow', query_hash: 'd04b0a864b4b54837c0d870b0e77e076', total_count: baseInfo.graphql.user.edge_follow.count };
// for followers instead of followings:
// { user_edge: 'edge_followed_by', query_hash: 'c76146de99bb02f6415203be841dd25a', total_count: baseInfo.graphql.user.edge_followed_by.count }
let after = null, hasNext = true, thisList = [];
for (pageCount = 1; hasNext && (pageCount <= pageLimit); ++pageCount) {
try {
let response = await fetch(`https://www.instagram.com/graphql/query/?query_hash=${config.query_hash}&variables=` + encodeURIComponent(JSON.stringify({
id: userId, include_reel: true, fetch_mutual: true, first: GRAPHQL_MAX_PER_PAGE, after: after
})));
if (!response.ok) {
console.warn(`Failed at page number ${pageCount.toLocaleString()}. HTTP status ${response.status}: ${response.statusText}.`);
break;
}
try {
response = await response.json();
} catch (error) {
console.error(`You may need to verify your account. Stopping. Failed at page number ${pageCount.toLocaleString()}.`, error);
break;
}
hasNext = response.data.user[config.user_edge].page_info.has_next_page
after = response.data.user[config.user_edge].page_info.end_cursor
thisList = thisList.concat(response.data.user[config.user_edge].edges.map(({ node }) => {
return {
id: node.id,
username: node.username,
full_name: node.full_name,
profile_pic_url: node.profile_pic_url,
};
}));
} catch (error) {
console.warn(`Error at page number ${pageCount.toLocaleString()}:`, error);
}
console.log(`${thisList.length.toLocaleString()} of ${config.total_count.toLocaleString()} fetched so far`);
}
console.info(`${thisList.length.toLocaleString()} fetched.`);
console.log(thisList);
}
getList()
Browser console showing a fetched list after code execution
In the code I've set the page limit to 200 so you can get up to 10,000 of your followings.
PS: For a way to visualise your lists and get more details, you can try Instagram Lists, a tool I made.
my development team and I have run into an issue on our Android distribution of our Xamarin project. The issue is as such: The application uses an observable collection of objects and represents these objects in the form of a list view and a map view with pins representing the objects. In the map view, our code is designed to subscribe to a messaging center call that periodically updates the observable collection of objects from our API (other part of project). The issue we are having is that when we call PlotPins method in the messaging center code block, the application should first retrieve the updated list and then access that list to plot pins on the map. Every time an update is received, the application will clear all pins from the map and then replot the pins based on the updated list (inefficient we know, but this is a temporary solution). However, the pins are never updated. Through the use of the debugger we have discovered that once map.Pins.Clear() within PlotPins() is called, the application jumps to the end of the RequestUpdatedListAsync method (which occurs periodically to retrieve the updated list and which triggers the Messaging Center) and then halts.
Our solution works for our GTK build, with the pins being cleared and redrawn on the map as intended, so this seems to be an Android specific issue.
Any help would be appreciated, thank you.
Relevant code located below:
MESSAGING CENTER:
MessagingCenter.Subscribe<object, ObservableCollection<MyObject>>(Application.Current, Constants.ListUpdateContract, (sender, newList) =>
{
//update list
listUpdater.UpdateList(newList);
//call method to plot pins again
PlotPins(map);
});
PLOTPINS:
private void PlotPins(Map map)
{
map.Pins.Clear();
foreach (MyObject in MyObjects)
{
var pin = new Pin
{
Label = MyObject.ID,
Address = "Latitude: " + MyObject.Latitude + " " + "Longitude: " + MyObject.Longitude,
Type = PinType.Place,
Position = new Position(Convert.ToDouble(MyObject.Latitude), Convert.ToDouble(MyObject.Longitude))
};
//event handler for when user clicks on pin's info window
pin.InfoWindowClicked += async (s, args) =>
{
//opens up detail page for pin associated with myObject
await Navigation.PushAsync(new DetailPage(MyObject));
};
map.Pins.Add(pin);
}
}
REQUEST UPDATED LIST ASYNC:
public static async System.Threading.Tasks.Task<bool> RequestUpdatedListAsync()
{
if (!_tokenIsGood)
return false;
var success = false;
var response = new HttpResponseMessage();
try
{
response = await _client.GetAsync(Constants. MyObjectDisplayUrl);
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("Error requesting updated list.");
System.Diagnostics.Debug.WriteLine(e.Message);
System.Diagnostics.Debug.WriteLine(e.StackTrace);
return success;
}
response.EnsureSuccessStatusCode();
success = true;
var responseBody = await response.Content.ReadAsStringAsync();
// Update list
MyObjects.Clear();
MyObjects = JsonConvert.DeserializeObject<ObservableCollection< MyObject >>(responseBody);
//Alert subscribed ViewModels to update list
MessagingCenter.Send<object, ObservableCollection< MyObject >>(Application.Current, Constants.ListUpdateContract, units);
return success;
}
Since maps.Pins is UI related it has to be run in main UI thread.
MessagingCenter doesnt always publish/subscribe in main threads .
So to fix this issue call the maps.Pins.Clear() in main thread.
Device.BeginInvokeOnMainThread(()=> maps.Pins.Clear());
Credits: #shanranm for mentioning limitation of MessagingCenter for using main threads.
I'm developing an Android App (Android 6.0 and above) and I have performance issues with large XML-Files. (about 17 mB)
When the app is started the required XML-document is loaded from the private storage and a List is returned (takes about 2-3 sek.) and filled in an custom adapter -> this works perfectly fine.
But the user can start a synchronization manually inside the app (e.g.: data
was updated on server)
Therefor I've implemented a background download-service so that the UI stays responsive during the download.
The downloaded data is stored inside the private folder again.
problem:
The background download works perfectly and my UI stays responive until I start reading the information from the new XML-File.
I don't get any result back -> even after 3 min there is no return value from the function although I use the same function for reading the XML like I do at the beginning -> GetKontaktliste()
public class MainActivity : AppCompatActivity
{
alert.SetPositiveButton("Synchronisieren", async (senderAlert, args) =>
{ new DownloadTask(this).Execute("");});
}
public class DownloadTask : AsyncTask
{
protected override Java.Lang.Object DoInBackground(params Java.Lang.Object[] #params)
{
App_Tools lAppTools = new App_Tools();
ThreadPool.QueueUserWorkItem(async state =>
{
//Download Function -> received XML-Data is saved in local storage
bool lKontakte = await lAppTools.DownloadKontakte(_context);
bool lVorgaenge = await lAppTools.DownloadVorgaenge(_context);
bool lVorgaengeImport = await lAppTools.ImportVorgaenge(_context);
if (lKontakte == true)
{
//Problem is that i dont get any results back here
List<KontaktItem> lResult = new List<KontaktItem>();
LinqAbfragen lLinq = new LinqAbfragen();
lLinq.GetKontaktliste();
}
});
return true;
}
}
public class LinqAbfragen
{
//Read Contacts
public List<KontaktItem> GetKontaktliste()
{
List<KontaktItem> lResult = new List<KontaktItem>();
//Read from IEnumerable<XElement>
var KontakteAsXElement = ReadXmlAsXElement("Kontakte.xml", "Kontakt");
lResult = (from kontakt in KontakteAsXElement
select new KontaktItem
{
AdressNr = kontakt.Element("AdressNr").Value,
Vorname = kontakt.Element("Vorname1").Value,
Nachname = kontakt.Element("Name1").Value,
xmlData = (string)kontakt.ToString()
}
).ToList();
return lResult;
}
}