I have a small problem. I am currently working with MAUI and the topic of downloading a file / folder from an API. The download works so far. However, I would now like to display this in a progress bar. However, this only works if the file has already been completely downloaded. However, I would like to be able to view any progress live.
Can you help me with this? Here are 3 code snippets.
One from the ViewModel:
public class DownloadQueueViewModel : INotifyPropertyChanged
{
public ICommand AddDownloadCommand => new Command(AddDownloadToQueue);
private Queue<DownloadQueueModel> _downloadQueueModels = new Queue<DownloadQueueModel>();
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private IApiClient _client;
public ObservableCollection<DownloadQueueModel> Downloads { get; set; } = new ObservableCollection<DownloadQueueModel>();
public DownloadQueueViewModel()
{
Task.Run(async () =>
{
AddDownloadToQueue();
});
}
public void AddDownloadToQueue()
{
Task.Run(async () =>
{
while (!_cancellationTokenSource.Token.IsCancellationRequested)
{
var downloadQueue = new DownloadQueueModel { FileName = "fileName" };
_downloadQueueModels.Enqueue(downloadQueue);
Downloads.Add(downloadQueue);
await ProcessQueueAsync(downloadQueue);
await Task.Delay(1000);
}
}, _cancellationTokenSource.Token);
}
private async Task ProcessQueueAsync(DownloadQueueModel downloadQueue)
{
while (_downloadQueueModels.Count > 0)
{
downloadQueue = _downloadQueueModels.Dequeue();
_client = new APIClient();
var statusAction = new Action<StatusDownload>(status =>
{
downloadQueue.StatusDownload = status;
});
var progress = new Progress<long>(totalRead =>
{
downloadQueue.TotalBytes = totalRead;
if (downloadQueue.FileSize > 0)
{
downloadQueue.Progress = (double)totalRead / downloadQueue.FileSize * 100;
}
});
string filePath = Path.Combine(Path.GetTempPath(), downloadQueue.FileName);
try
{
downloadQueue.StatusDownload = StatusDownload.Downloading;
var fileInfo = await _client.DownloadFileAsync("https://github.com/pterodactyl/panel/files/10056889/egg-file-download-error-test.zip",
statusAction,
filePath,
progress);
downloadQueue.FileName = fileInfo.FullName;
}
catch (Exception ex)
{
downloadQueue.StatusDownload = StatusDownload.Failed;
}
}
}
Then from my client :
public async Task<FileInfo> DownloadFileAsync(string url, Action<StatusDownload> statusDownload, string filePath, IProgress<long> progress)
{
using (var response = await _httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
{
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
{
statusDownload(StatusDownload.Running);
var totalBytes = response.Content.Headers.ContentLength;
using (var stream = await response.Content.ReadAsStreamAsync())
using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
{
statusDownload(StatusDownload.Downloading);
var buffer = new byte[8192];
long totalRead = 0;
int bytesRead;
while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
await fileStream.WriteAsync(buffer, 0, bytesRead);
totalRead += bytesRead;
if (totalBytes.HasValue)
{
long percentage = totalRead * 100 / totalBytes.Value;
progress?.Report(percentage);
}
}
statusDownload(StatusDownload.Ready);
}
}
return new FileInfo(filePath);
}
And finally from my UI :
<Button Text="Add Download" Command="{Binding AddDownloadCommand}" />
<ListView ItemsSource="{Binding Downloads}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical" Padding="10">
<Label Text="{Binding FileName}" />
<ProgressBar Progress="{Binding Progress, Converter={StaticResource DoubleToProgressConverter}}" />
<Label Text="{Binding TotalBytes}" />
<Label Text="{Binding StatusDownload}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Thank you very much for your help!
Attempts have already been made to work with Action. The function is actually available, but only if the download is complete as described. I have also tried in :
while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
to include the current status of the progress or action. But since this doesn’t work either, I’m at a bit of a loss
Groot is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.