how to browse and upload files in Windows Phone App - c#

How to upload a file in windows phone i mean which controls are used to browse the files (phone Content) are they pre-defined for windows phone or do we need to create manually. Browsing them and uploading them .

you can try the MSDN way
Make sure that the user has consented to the required scope, and then create an upload
Handle pending uploads when the app restarts.
private async void Upload()
{
try
{
// Ensure that the user has consented to the wl.skydrive and wl.skydrive_update scopes.
var authClient = new LiveAuthClient();
var authResult = await authClient.LoginAsync(new string[] { "wl.skydrive", "wl.skydrive_update" });
if (authResult.Session != null)
{
var liveConnectClient = new LiveConnectClient(authResult.Session);
// Upload to OneDrive.
LiveUploadOperation uploadOperation = await liveConnectClient.CreateBackgroundUploadAsync(
uploadPath, fileName, uploadInputStream, OverwriteOption.Rename);
LiveOperationResult uploadResult = await uploadOperation.StartAsync();
HandleUploadResult(uploadResult);
}
}
catch (LiveAuthException ex)
{
// Handle errors.
}
catch(LiveConnectException ex)
{
// Handle errors.
}
}
var pendingOperations = await LiveConnectClient.GetCurrentBackgroundUploadsAsync();
foreach(LiveDownloadOperation pendingOperation in pendingOperations)
{
try
{
var opResult = await pendingOperation.AttachAsync();
// Handle results.
}
catch
{
// Handle errors.
}
}

Related

Image does not display in gallery after download

I am developing a Xamarin app which retrives info from DB, take/choose photo and upload them to remote server, display this images from the remote server and the user can delete them by tap on and press a button and download the images from the remote server to the local device.
Everything works without problem, but when I download the image and after I go to the gallery for check it, the image does not appear, whereas I can see it and open in the file explorer. When I reboot the phone, the image appear in the gallery.
Below my current button download method:
private void button_download_image_Clicked(object sender, EventArgs e)
{
Uri image_url_format = new Uri(image_url);
WebClient webClient = new WebClient();
try
{
byte[] bytes_image = webClient.DownloadData(image_url_format);
Stream image_stream = new MemoryStream(bytes_image);
string dest_folder = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).ToString();
string file_name = System.IO.Path.GetFileName(image_url_format.LocalPath);
string dest_path = System.IO.Path.Combine(dest_folder, file_name);
using (var fileStream = new FileStream(dest_path, FileMode.Create, FileAccess.Write))
{
image_stream.CopyTo(fileStream);
}
}
catch (Exception ex)
{
DisplayAlert("Error", ex.ToString(), "OK");
}
DisplayAlert("Alert", "Download completed!", "OK");
}
I tried in another device, but I got the same behavior.
Probably there is a sort of thing which does not refresh the gallery.
Any idea how to force the gallery to refresh or something similar?
You need to refresh your gallery after inserting or deleting any pictures in storage.
You can try this.
var mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);
mediaScanIntent.SetData(Android.Net.Uri.FromFile(new Java.IO.File(dest_path)));
Xamarin.Forms.Forms.Context.SendBroadcast(mediaScanIntent);
Add these lines below your code.
Make it like
private void button_download_image_Clicked(object sender, EventArgs e)
{
Uri image_url_format = new Uri(image_url);
WebClient webClient = new WebClient();
try
{
byte[] bytes_image = webClient.DownloadData(image_url_format);
Stream image_stream = new MemoryStream(bytes_image);
string dest_folder = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).ToString();
string file_name = System.IO.Path.GetFileName(image_url_format.LocalPath);
string dest_path = System.IO.Path.Combine(dest_folder, file_name);
using (var fileStream = new FileStream(dest_path, FileMode.Create, FileAccess.Write))
{
image_stream.CopyTo(fileStream);
}
var mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);
mediaScanIntent.SetData(Android.Net.Uri.FromFile(new Java.IO.File(dest_path)));
//for old xamarin forms version
Xamarin.Forms.Forms.Context.SendBroadcast(mediaScanIntent);
//for new xamarin forms version
//Android.App.Application.SendBroadcast(mediaScanIntent);
}
catch (Exception ex)
{
DisplayAlert("Error", ex.ToString(), "OK");
return;
}
DisplayAlert("Alert", "Download completed!", "OK");
}
You need to just refresh the file you have downloaded. It's helpful.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File("file://"+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES));
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
this.sendBroadcast(mediaScanIntent);
}else{
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory())));
}
Make sure required permission given on both platforms.
Use in your class:
bool success = await DependencyService.Get<IPhotoLibrary>().SavePhotoAsync(data, folder, filename);
Common Interface
public interface IPhotoLibrary
{
Task<bool> SavePhotoAsync(byte[] data, string folder, string filename);
}
In Android service
public async Task<bool> SavePhotoAsync(byte[] data, string folder, string filename)
{
try
{
File picturesDirectory = Environment.GetExternalStoragePublicDirectory(Environment.DirectoryPictures);
File folderDirectory = picturesDirectory;
if (!string.IsNullOrEmpty(folder))
{
folderDirectory = new File(picturesDirectory, folder);
folderDirectory.Mkdirs();
}
using (File bitmapFile = new File(folderDirectory, filename))
{
bitmapFile.CreateNewFile();
using (FileOutputStream outputStream = new FileOutputStream(bitmapFile))
{
await outputStream.WriteAsync(data);
}
// Make sure it shows up in the Photos gallery promptly.
MediaScannerConnection.ScanFile(MainActivity.Instance,
new string[] { bitmapFile.Path },
new string[] { "image/png", "image/jpeg" }, null);
}
}
catch (System.Exception ex)
{
return false;
}
return true;
}
In iOS service:
public Task<bool> SavePhotoAsync(byte[] data, string folder, string filename)
{
NSData nsData = NSData.FromArray(data);
UIImage image = new UIImage(nsData);
TaskCompletionSource<bool> taskCompletionSource = new TaskCompletionSource<bool>();
image.SaveToPhotosAlbum((UIImage img, NSError error) =>
{
taskCompletionSource.SetResult(error == null);
});
return taskCompletionSource.Task;
}
also you can refer this one just to save an image and to reflect it in media, no need to use skiasharp for that. https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/bitmaps/saving
Hope this may resolve your issue.
Refer to Blu's answer,
I changed this Xamarin.Forms.Forms.Context.SendBroadcast(mediaScanIntent); to Android.App.Application.Context.SendBroadcast(mediaScanIntent); and all works.

display multiple permission at once xamarin forms

I am creating a Xamarin Form PCL project for Android and IOS.
Is this possible to display multiple permission at once on the screen? My App is using Location, Storage and Camera permission. From my current code, this is displaying permission popup one by one on the different page like before use of camera i display camera permission popup. As I know three permission required for my App so i want to display a single popup for all three permission.
Below is my code for storage permission.
public static async Task<dynamic> CheckStoragePermission()
{
var result = "";
try
{
var Storagestatus = await CrossPermissions.Current.CheckPermissionStatusAsync(Plugin.Permissions.Abstractions.Permission.Storage);
if (Storagestatus != PermissionStatus.Granted)
{
await Utils.CheckPermissions(Plugin.Permissions.Abstractions.Permission.Storage);
}
}
catch (Exception ex)
{
error(ex.Message, Convert.ToString(ex.InnerException), ex.Source, ex.StackTrace);
}
return result;
}
Hope someone did this before in xamarin forms, I will thank for your help for this.
You could try using the following code to request multiple permissions at one time:
private async void Button_Clicked(object sender, EventArgs e)
{
await GetPermissions();
}
public static async Task<bool> GetPermissions()
{
bool permissionsGranted = true;
var permissionsStartList = new List<Permission>()
{
Permission.Location,
Permission.LocationAlways,
Permission.LocationWhenInUse,
Permission.Storage,
Permission.Camera
};
var permissionsNeededList = new List<Permission>();
try
{
foreach (var permission in permissionsStartList)
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(permission);
if (status != PermissionStatus.Granted)
{
permissionsNeededList.Add(permission);
}
}
}
catch (Exception ex)
{
}
var results = await CrossPermissions.Current.RequestPermissionsAsync(permissionsNeededList.ToArray());
try
{
foreach (var permission in permissionsNeededList)
{
var status = PermissionStatus.Unknown;
//Best practice to always check that the key exists
if (results.ContainsKey(permission))
status = results[permission];
if (status == PermissionStatus.Granted || status == PermissionStatus.Unknown)
{
permissionsGranted = true;
}
else
{
permissionsGranted = false;
break;
}
}
}
catch (Exception ex)
{
}
return permissionsGranted;
}

Download txt file from google drive in windows phone 8.1

I'm doing a windows phone project, and need to download a text file from the internet and read its content.
This is what I have tried (but it didn't work)
private async Task pobierz()
{
string source = "https://drive.google.com/file/d/0BzgKBwKyU4oORkxxSlVITGswb1E/view?usp=sharing";
string LocalName = "hej.txt";
var srce = new Uri(source, UriKind.Absolute);
// var destinationFile =await KnownFolders.PicturesLibrary.CreateFileAsync()
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(#"ms-appx:///Assets/hej.txt"));
var downloader = new BackgroundDownloader();
DownloadOperation download = downloader.CreateDownload(srce,file);
}
Please see https://msdn.microsoft.com/en-us/library/windows/apps/xaml/jj152726.aspx?f=255&MSPPError=-2147217396 for detailed description of how to use the BackgroundDownloader.
You need to implement and call the following method:
private async void HandleDownloadAsync(DownloadOperation download, bool start)
{
try
{
// Store the download so we can pause/resume.
activeDownloads.Add(download);
Progress<DownloadOperation> progressCallback = new Progress<DownloadOperation>(DownloadProgress);
if (start)
{
// Start the download and attach a progress handler.
await download.StartAsync().AsTask(cts.Token, progressCallback);
}
else
{
// The download was already running when the application started, re-attach the progress handler.
await download.AttachAsync().AsTask(cts.Token, progressCallback);
}
ResponseInformation response = download.GetResponseInformation();
Log(String.Format("Completed: {0}, Status Code: {1}", download.Guid, response.StatusCode));
}
catch (TaskCanceledException)
{
Log("Download cancelled.");
}
catch (Exception ex)
{
LogException("Error", ex);
}
finally
{
activeDownloads.Remove(download);
}
}

Making a prettier Facebook Login Screen for Parse.com Server with Xamarin.Android

Im trying to create a login system for Xamarin.Android to be used on a Parse server. I want to login the user with Facebook and save his real name and his small user photo.
My current code of displaying the login system is this:
using Xamarin.Auth;
loginFacebookButton.Click += (sender, e) =>
{
if (CrossConnectivity.Current.IsConnected)
LoginToFacebook();
else
{
DisplayNoConnectivityMessage();
}
};
loginTwitterButton.Click += (sender, e) =>
{
LoginToTwitter();
};
}
void DisplayNoConnectivityMessage()
{
AlertDialog.Builder alert2 = new AlertDialog.Builder(this);
alert2.SetTitle("Network error");
alert2.SetMessage("Connection with the Internet is required. Please check your connectivity and try again.");
alert2.Show();
}
void DisplayLoadingMessage(bool Dismiss)
{
RunOnUiThread(() =>
{
if (!Dismiss)
{
builder = new AlertDialog.Builder(this);
builder.SetTitle("Signing in");
builder.SetMessage("Please wait...");
builder.SetCancelable(false);
alert = builder.Create();
alert.Show();
} else {
if (alert != null)
if (alert.IsShowing)
{
alert.Dismiss();
alert.Dispose();
}
}
});
}
async void LoginToFacebook()
{
var auth = new OAuth2Authenticator(
clientId: "809804315805408",
scope: "user_about_me",
authorizeUrl: new Uri("https://m.facebook.com/dialog/oauth/"),
redirectUrl: new Uri("http://www.facebook.com/connect/login_success.html")
);
auth.AllowCancel = false;
// If authorization succeeds or is canceled, .Completed will be fired.
auth.Completed += LoginComplete;
var intent = auth.GetUI(this);
StartActivity(intent);
}
public async void LoginComplete(object sender, AuthenticatorCompletedEventArgs e)
{
string id = "";
string name = "";
JsonValue obj;
if (!e.IsAuthenticated)
{
var builder = new AlertDialog.Builder(this);
builder.SetMessage("Not Authenticated");
builder.SetPositiveButton("Ok", (o, c) => { });
builder.Create().Show();
return;
}
else {
DisplayLoadingMessage(false);
AccountStore.Create(this) .Save(e.Account, "Facebook");
// Now that we're logged in, make a OAuth2 request to get the user's info.
var request = new OAuth2Request("GET", new Uri("https://graph.facebook.com/me"), null, e.Account);
await request.GetResponseAsync().ContinueWith(t =>
{
var builder2 = new AlertDialog.Builder(this);
if (t.IsFaulted)
{
builder2.SetTitle("Error");
builder2.SetMessage(t.Exception.Flatten().InnerException.ToString());
builder2.Show();
}
else if (t.IsCanceled)
{
builder2.SetTitle("Task Canceled");
builder2.Show();
}
else {
obj = JsonValue.Parse(t.Result.GetResponseText());
id = obj["id"];
name = obj["name"];
}
builder.SetPositiveButton("Ok", (o, c) => { });
builder.Create();
}, UIScheduler);
var accessToken = e.Account.Properties["access_token"];
var expiresIn = Convert.ToDouble(e.Account.Properties["expires_in"]);
var expiryDate = DateTime.Now + TimeSpan.FromSeconds(expiresIn);
var user = await ParseFacebookUtils.LogInAsync(id, accessToken, expiryDate);
try
{
user.Add("Name", name);
}
catch (Exception ex)
{
Console.WriteLine("LoginFragment.cs | LoginComplete() :: user.Add (\"Name\",name); :: " + ex.Message);
}
var webClient = new WebClient();
//var httpClient = new HttpClient(new NativeMessageHandler());
var url = new Uri("http://graph.facebook.com/" + id + "/picture?type=small");
application.currentUserImageUrl = url.ToString();
application.currentUserName = name;
byte[] bytes = null;
//bytes = await httpClient.GetByteArrayAsync(url);
bytes = await webClient.DownloadDataTaskAsync(url);
ParseFile saveImageFile = new ParseFile("profileImage.jpg", bytes);
try
{
user.Add("profile_pic", saveImageFile);
}
catch (Exception ex)
{
Console.WriteLine("LoginFragment.cs | LoginComplete() :: user.Add (\"profile_pic\",saveImageFile); :: " + ex.Message);
}
application.currentUser = user;
await user.SaveAsync();
DisplayLoadingMessage(true);
ChangeScreen();
}
}
The problem with this code is this:
After the login i get a Success message displayed (a simple
success message on a white page) that must be from facebook and
obviously i dont wnat to be displayed on the user.
While the
LoginCompete code is running the app is working on background and the user doesn't see anyhting, its like the app closes and after
the login opens again. I have try to display an AlertDialog with
the function DisplayNoConnectivityMessage but it doesnt be shown
in the user anything i dont know way.
The easiest way to login with Facebook on Parse is the official Parse SDK in combination with the offical Facebook for Android SDK to handle the Single-Sign On Scenario.
With just some small steps you achieve the expected result:
Follow this small guide to setup your app for the Facebook SDK: https://components.xamarin.com/gettingstarted/facebookandroid
Setup the Parse SDK
public App()
{
// App.xaml initialization
ParseClient.Initialize("Your Application ID", "Your .NET Key");
ParseFacebookUtils.Initialize("Your Facebook App Id");
// Other initialization
}
Add a FB Login Button to your View.
<com.facebook.login.widget.LoginButton
android:id="#+id/login_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="30dp"
android:layout_marginBottom="30dp" />
Get the callback and use the token to signin the user with Parse.
public class MainActivity : Activity, IFacebookCallback
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
// SetContentView (Resource.Layout.Main);
var callbackManager = CallbackManagerFactory.Create();
var loginButton = FindViewById<LoginButton>(Resource.Id.login_button);
loginButton.RegisterCallback(callbackManager, this);
}
#region IFacebookCallback
public void OnCancel()
{
// Handle Cancel
}
public void OnError(FacebookException error)
{
// Handle Error
}
public async void OnSuccess(Object result)
{
// We know that this is a LoginResult
var loginResult = (LoginResult) result;
// Convert Java.Util.Date to DateTime
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var expireDate = epoch.AddMilliseconds(loginResult.AccessToken.Expires.Time);
// FB User AccessToken
var accessToken = loginResult.AccessToken.Token;
ParseUser user = await ParseFacebookUtils.LogInAsync("Your Facebook App Id", accessToken, expireDate);
}
#endregion
...
}
(Optional) Interact with the Facebook SDK & ParseUser
// You can simply pass the acquired AccessToken to the GraphRequest
var parameters = new Bundle();
parameters.PutString("fields", "id,email,gender,cover,picture.type(small)");
var request = new GraphRequest(loginResult.AccessToken, "me", parameters, HttpMethod.Get);
// Execute request and Handle response (See FB Android SDK Guide)
// to get image as byte[] from GraphResponse
byte[] data;
// Store the image into the ParseUser
user["image"] = new ParseFile("image.jpg", data);
Instead of using the GraphRequest you can always fallback to the HttpClient / WebClient and pass the AccessToken as URL parameter. Docs
Additional
Here a link to the official docs: http://parseplatform.github.io/docs/dotnet/guide/#facebook-users
Pick SDK from Nuget: https://www.nuget.org/packages/Xamarin.Facebook.Android/
The Xamarin Facebook Android SDK works like the Java SDK so this docs are also worth to look at: https://developers.facebook.com/docs/facebook-login/android#addbutton
My problem finally was:
By disabling secure browsing on facebook login application settings from facebook developers dashboard, i was able to get rib of the success message.
Setting the Activity to "NoHistory = true", makes social login problematic cause the responds from the social platforms to the Activity isn't tracked as it should. Also this was the problem for not showing the AlertDialog (i would never going to guess that).
But the answer of #paul-reichelt is the best approach for native facebook login.

OneDrive file only uploads when app is terminated

I'm having a problem uploading a file to OneDrive from a universal app that I can't understand or figure out how to debug. I used this guide to go through the process of getting file IDs and such and it worked great until a few hours ago.
Now I can get folder and file ids, so I assume that I am still successfully connecting to OneDrive and my internet connection is still working. But when I step into the BackgroundUploadAsync the thread or whatever that was was executing before never returns. In the code below, the message "Uploading new file to OneDrive..." never disappears.
Strangely, while it is uploading I can refresh my OneDrive folder on ie and I'll never see what I'm trying to upload. But once I stop the debugger, or terminate the app on the phone, I can instantly refresh and the file will be there.
Here is the method for uploading:
public async Task UploadToOneDrive(string folderID, string localFileName)
{
try
{
StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync(localFileName);
string fileName = "backup-" + DateTime.Now.ToString("dd-MM") + ".db";
await file.CopyAsync(ApplicationData.Current.LocalFolder, fileName, NameCollisionOption.ReplaceExisting);
file = await ApplicationData.Current.LocalFolder.GetFileAsync(fileName);
await connectClient.BackgroundUploadAsync(folderID,
fileName, file, OverwriteOption.Overwrite);
}
catch (LiveConnectException)
{
MessageDialog m = new MessageDialog("Could not connect to to OneDrive. Cloud sync will be stopped.");
m.ShowAsync();
}
catch (LiveAuthException)
{
MessageDialog m = new MessageDialog("Error authenticating OneDrive service. Please try cloud sync again later.");
m.ShowAsync();
}
catch (Exception ex)
{
MessageDialog m = new MessageDialog("Unknown exception occurred.\n\nError:{0}", ex.Message);
m.ShowAsync();
}
}
And here is the sync process
public async Task sync()
{
var sb = StatusBar.GetForCurrentView();
sb.ProgressIndicator.Text = "Syncing with OneDrive...";
await sb.ProgressIndicator.ShowAsync();
string cloudFolderID = await syncManager.CreateOrGetOneDriveFolderID("GlucoseCalculator", "Documents/");
string cloudFileID = await syncManager.GetFileID(DataManager.sqlFileName, "Documents/GlucoseCalculator/");
try
{
if (cloudFileID != null)
{
if (!(await dbManager.DoesFileExist(DataManager.sqlFileName)))
{
sb.ProgressIndicator.Text = "Downloading file from OneDrive...";
await syncManager.DownloadFromOneDrive(cloudFileID, DataManager.sqlFileName);
goto BREAK;
}
DateTime cloudLastEditDateTime = DateTime.Parse(await syncManager.GetFileProperty(cloudFileID, "updated_time"));
DateTime localLastEditDateTime = ApplicationData.Current.LocalFolder.GetFileAsync(DataManager.sqlFileName).GetResults().GetBasicPropertiesAsync().GetResults().DateModified.DateTime;
if (cloudLastEditDateTime > localLastEditDateTime)
{
sb.ProgressIndicator.Text = "Downloading file from OneDrive...";
await syncManager.DownloadFromOneDrive(cloudFileID, DataManager.sqlFileName);
}
else if (cloudLastEditDateTime < localLastEditDateTime)
{
sb.ProgressIndicator.Text = "Uploading file to OneDrive...";
await syncManager.UploadToOneDrive(cloudFolderID, DataManager.sqlFileName);
}
}
else if (cloudFileID == null)
{
sb.ProgressIndicator.Text = "Uploading new file to OneDrive...";
await syncManager.UploadToOneDrive(cloudFolderID, DataManager.sqlFileName);
}
}
catch (Exception)
{
sb.ProgressIndicator.Text = "Cloud synchronization failed.";
sb.ProgressIndicator.HideAsync();
return;
}
sb.ProgressIndicator.Text = "Synchronization complete!";
BREAK:;
await sb.ProgressIndicator.HideAsync();
}
Most likely, you are creating some object that implements IDisposible, but it is not in a using block. Maybe the StorageFile.

Categories