// This method fetches the whole ImageRecord that a user taps on and then passes it to the delegate public override void ItemSelected (UICollectionView collectionView, NSIndexPath indexPath) { // If the user has already tapped on a thumbnail, prevent them from tapping any others if (controller.lockSelectThumbnail) return; else controller.lockSelectThumbnail = true; // Starts animating the thumbnail to indicate it is loading controller.ImageCollection.SetLoadingFlag (indexPath, true); // Uses convenience API to fetch the whole image record associated with the thumbnail that was tapped CKRecordID userSelectedRecordID = controller.ImageCollection.GetRecordId (indexPath); controller.PublicCloudDatabase.FetchRecord (userSelectedRecordID, (record, error) => { // If we get a partial failure, we should unwrap it if(error != null && error.Code == (long)CKErrorCode.PartialFailure) { CKErrorInfo info = new CKErrorInfo(error); error = info[userSelectedRecordID]; } Error errorResponse = controller.HandleError(error); switch(errorResponse) { case Error.Success: controller.ImageCollection.SetLoadingFlag(indexPath, false); Image selectedImage = new Image(record); InvokeOnMainThread(() => { controller.MasterController.GoTo(controller, selectedImage); }); break; case Error.Retry: Utils.Retry(()=> { controller.lockSelectThumbnail = false; ItemSelected(collectionView, indexPath); }, error); break; case Error.Ignore: Console.WriteLine ("Error: {0}", error.Description); string errorTitle = "Error"; string errorMessage = "We couldn't fetch the full size thumbnail you tried to select, try again"; string dismissButton = "Okay"; UIAlertController alert = UIAlertController.Create(errorTitle, errorMessage, UIAlertControllerStyle.Alert); alert.AddAction(UIAlertAction.Create(dismissButton, UIAlertActionStyle.Cancel, null)); InvokeOnMainThread(()=> controller.PresentViewController(alert, true, null)); controller.ImageCollection.SetLoadingFlag(indexPath, false); controller.lockSelectThumbnail = false; break; default: throw new NotImplementedException(); } }); }
public void LoadImage (string[] keys, Action updateBlock = null) { // Fetches the imageRecord this post record references in its ImageRefKey. // Only fetches the values associated with the keys passed in to the NSArray var imgRecordId = ((CKReference)PostRecord[ImageRefKey]).RecordId; CKFetchRecordsOperation imageOp = new CKFetchRecordsOperation (new CKRecordID[]{ imgRecordId }); imageOp.DesiredKeys = keys; imageOp.Completed = (NSDictionary recordDict, NSError error) => { if(error != null && error.Code == (long)CKErrorCode.PartialFailure) { CKErrorInfo info = new CKErrorInfo(error); error = info[imgRecordId]; } Error errorResponse = HandleError(error); switch(errorResponse) { case Error.Success: CKRecord fetchedImageRecord = (CKRecord)recordDict[imgRecordId]; ImageRecord = new Image(fetchedImageRecord); if(updateBlock != null) updateBlock(); break; case Error.Retry: Utils.Retry(() => LoadImage(keys, updateBlock), error); ImageRecord = null; break; case Error.Ignore: Console.WriteLine ("Error: {0}", error.Description); ImageRecord = null; break; default: throw new NotImplementedException(); } }; PublicDB.AddOperation (imageOp); }
void PublishPost (NSObject sender) { // Prevents multiple posting, locks as soon as a post is made PostButton.Enabled = false; UIActivityIndicatorView indicator = new UIActivityIndicatorView (UIActivityIndicatorViewStyle.Gray); indicator.StartAnimating (); PostButton.CustomView = indicator; // Hides the keyboards and dispatches a UI update to show the upload progress HiddenText.EndEditing (true); TagField.EndEditing (true); ProgressBar.Hidden = false; // Creates post record type and initizalizes all of its values CKRecord newRecord = new CKRecord (Post.RecordType); newRecord [Post.FontKey] = (NSString)ImageLabel.Font.Name; newRecord [Post.ImageRefKey] = new CKReference (ImageRecord.Record.Id, CKReferenceAction.DeleteSelf); newRecord [Post.TextKey] = (NSString)HiddenText.Text; string[] tags = TagField.Text.ToLower ().Split (new char[]{ ' ' }, StringSplitOptions.RemoveEmptyEntries); newRecord [Post.TagsKey] = NSArray.FromObjects (tags); Post newPost = new Post (newRecord); newPost.ImageRecord = ImageRecord; // Only upload image record if it is not on server, otherwise just upload the new post record CKRecord[] recordsToSave = ImageRecord.IsOnServer ? new CKRecord[] { newRecord } : new CKRecord[] { newRecord, ImageRecord.Record }; // TODO: https://trello.com/c/A9T8Spyp second param is null CKModifyRecordsOperation saveOp = new CKModifyRecordsOperation (recordsToSave, new CKRecordID[0]); saveOp.PerRecordProgress = (CKRecord record, double progress) => { // Image record type is probably going to take the longest to upload. Reflect it's progress in the progress bar if (record.RecordType == Image.RecordType) InvokeOnMainThread (() => { var val = (float)(progress * 0.95); ProgressBar.SetProgress (val, true); }); }; // When completed it notifies the tableView to add the post we just uploaded, displays error if it didn't work saveOp.Completed = (CKRecord[] savedRecords, CKRecordID[] deletedRecordIDs, NSError operationError) => { Error errorResponse = HandleError (operationError); switch (errorResponse) { case Error.Success: // Tells delegate to update so it can display our new post InvokeOnMainThread (() => { DismissViewController (true, null); MainController.Submit (newPost); }); break; case Error.Retry: CKErrorInfo errorInfo = new CKErrorInfo (operationError.UserInfo); nint retryAfter = errorInfo.RetryAfter.HasValue ? errorInfo.RetryAfter.Value : 3; Console.WriteLine ("Error: {0}. Recoverable, retry after {1} seconds", operationError.Description, retryAfter); Task.Delay ((int)retryAfter * 1000).ContinueWith (_ => PublishPost (sender)); break; case Error.Ignore: Console.WriteLine ("Error saving record: {0}", operationError.Description); string errorTitle = "Error"; string dismissButton = "Okay"; string errorMessage = operationError.Code == (long)CKErrorCode.NotAuthenticated ? "You must be logged in to iCloud in order to post" : "Unrecoverable error with the upload, check console logs"; InvokeOnMainThread (() => { UIAlertController alert = UIAlertController.Create (errorTitle, errorMessage, UIAlertControllerStyle.Alert); alert.AddAction (UIAlertAction.Create (dismissButton, UIAlertActionStyle.Cancel, null)); PostButton.Enabled = true; PresentViewController (alert, true, null); ProgressBar.Hidden = true; PostButton.CustomView = null; }); break; default: throw new NotImplementedException (); } }; CKContainer.DefaultContainer.PublicCloudDatabase.AddOperation (saveOp); }