Showing posts with label MonoTouch. Show all posts
Showing posts with label MonoTouch. Show all posts

Wednesday, March 13, 2013

UIDocumentInteractionController Delegate MonoTouch

Sometimes you need to be able to show Documents within your application.  This is the code in Monotouch to Provide a native "Document Preview" via QuickLook referenced here:

Opening and Previewing Files


This is the code you can place in your ViewController.

                    UIDocumentInteractionController docpreview = UIDocumentInteractionController.FromUrl (NSUrl.FromFilename(path));

                    InvokeOnMainThread (delegate {
                        this.DismissViewController(true,delegate {
                        docpreview.Delegate = new Test(this);

                        docpreview.PresentPreview (true);
                    });
                    });


The Delegate made for your specific UIViewController to control behavior after the Preview Ends :

In this particular instance my ViewController I was calling the DocumentPreview from was called "FirstViewController".

public class Test : UIDocumentInteractionControllerDelegate
    {

            UIViewController viewC;
            
            public Test(UIViewController controller)
            {
                viewC = controller;
            }
            
            public override UIViewController ViewControllerForPreview (UIDocumentInteractionController controller)
            {
                return viewC;
            }
            
            public override UIView ViewForPreview (UIDocumentInteractionController controller)
            {
                return viewC.View;
            }
            
            public override RectangleF RectangleForPreview (UIDocumentInteractionController controller)
            {
                return viewC.View.Frame;
            }
            public override void DidEndPreview (UIDocumentInteractionController controller)
            {
                ((FirstViewController)viewC).PresentPrintDialog (controller.Url.Path);
            }
    }

Below is the screenshot of opening the file in the QuickLook Document Preview :





Saturday, March 2, 2013

ViewWillDisappear ViewWillAppear Monotouch.

When you deal in buttons, you need to make sure in your ViewWillDisappear, and your ViewWillAppear, that you subscribe to events for your buttons and unsubscribe.   Just so that while the new view is being presented, you don't get hit with an error.











        EventHandler StatusClick;
        EventHandler ConditionClick;
        EventHandler PhotoClick;

public override void ViewWillAppear (bool animated)
        {
            base.ViewWillAppear (animated);
            StatusClick = delegate {
                DisplayStatus ();
            };
            ConditionClick = delegate {
                DisplayConditions();
            };
            PhotoClick = delegate {
                PickPhoto();
            };
            this.Condition.TouchUpInside += ConditionClick;
            this.Status.TouchUpInside += StatusClick;
            this.Photo.TouchUpInside += PhotoClick;
        }
        public override void ViewWillDisappear (bool animated)
        {
            base.ViewWillDisappear (animated);
            this.Status.TouchUpInside -= StatusClick;
            this.Condition.TouchUpInside -= ConditionClick;
            this.Photo.TouchUpInside -= PhotoClick;
        }

Monday, February 18, 2013

Monotouch NSDefaults and useful Keychain code.


Just some useful code.

public static class KeychainHandler
    {
        public static SecStatusCode HasCredentials(string generic)
        {
            var record = new SecRecord (SecKind.GenericPassword)
            {
                Generic = NSData.FromString(generic)
            };
            SecStatusCode result;
            var match = SecKeyChain.QueryAsRecord (record, out result);
            return result;
        }
        public static SecRecord Credentials(string generic)
        {
            var record = new SecRecord (SecKind.GenericPassword)
            {
                Generic = NSData.FromString(generic)
            };
            SecStatusCode result;
            var match = SecKeyChain.QueryAsRecord (record, out result);
            return match;
        }
        public static void DeleteKeychain(string generic)
        {
            SecKeyChain.Remove(KeychainHandler.Credentials(generic));
        }
}

To save NSDefaults for a User :

NSUserDefaults.StandardUserDefaults.SetString(yourstringvalue,yourstringkey);
NSUserDefaults.StandardUserDefaults.Init();

To Retrieve :

if(NSUserDefaults.StandardUserDefaults["whatever"] != null)
{
string value = NSUserDefaults.StandardUserDefaults.StringForKey("whatever");
}

Saturday, February 16, 2013

Monotouch and UTI handling.


Just making a demo app of Google Cloud Printing in Monotouch, and I wanted to be able to pass specific mime types to my app via Monotouch.  There isn't a recipe on the site for it, so I went about figuring out how to do it myself.

As you can see in your Monotouch Project Options, you need to navigate to "IPhone Applications", then go to the Advanced tab.  

Go to the "Document Types" list, and add on a Name.. then put in your type, which should resolve a text string listed by type here:  Apple UTI References

For PDF, you obviously put 'com.adobe.pdf'.



After entering that value, if you build your application, when you open a PDF in a documentview you should be able to see your application listed in the "Open In" action.


You still have some code to drop though, you need to be able to pass that file into your view controller. 
So, below is what you put in your appdelegate.cs to get access to the stream for the file that was passed in to your application.

public override bool HandleOpenURL (UIApplication application, NSUrl url)
{
    NSInputStream stream = NSInputStream.FromFile(url.Path);
    viewController.stream = stream;
    return true;
}

Tuesday, January 29, 2013

Cloud Print in MonoDroid or MonoTouch.

Printed from Google Cloud Print via Mono Droid.
I spent quite a bit of time.. trying to print in Mono for Android via Google Cloud Print, I needed it for a piece or three I've been working on.

Stack Overflow Google Cloud Print

This link, basically got me through everything, and here is the code, tweaked a bit to remove the Proxy issue.  If you need the Proxy code, you can go pull from the original post.

Update :

Git Hub Repo with Google Cloud Print for Monodroid.

[You should easily be able to modify this to work for MonoTouch also.  I submitted the project to Xamarin, and they said they would have the Documentation team add an example]

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using System.Web;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.IO;
using System.ServiceModel.Web;

namespace GoogleCloudPrint
{
    public class GoogleCloudPrint
    {
        public string UserName { get; set; }
        public string Password { get; set; }
        public string Source { get; set; }
        
        private const int ServiceTimeout = 10000;
        

        
        public CloudPrintJob PrintDocument (string printerId, string title, byte[] document, String mimeType)
        {
            try
            {
                string authCode;
                if (!Authorize (out authCode))
                return new CloudPrintJob { success = false };
                
                var b64 = Convert.ToBase64String (document);
                
                var request = (HttpWebRequest)WebRequest.Create ("http://www.google.com/cloudprint/submit?output=json&printerid=" + printerId);
                request.Method = "POST";
                
                // Setup the web request
                request.ServicePoint.Expect100Continue = false;
                
                // Add the headers
                request.Headers.Add ("X-CloudPrint-Proxy", Source);
                request.Headers.Add ("Authorization", "GoogleLogin auth=" + authCode);
                
                var p = new PostData ();
                
                p.Params.Add (new PostDataParam { Name = "printerid", Value = printerId, Type = PostDataParamType.Field });
                p.Params.Add (new PostDataParam { Name = "capabilities", Value = "{\"capabilities\":[{}]}", Type = PostDataParamType.Field });
                p.Params.Add (new PostDataParam { Name = "contentType", Value = "dataUrl", Type = PostDataParamType.Field });
                p.Params.Add (new PostDataParam { Name = "title", Value = title, Type = PostDataParamType.Field });
                
                p.Params.Add (new PostDataParam
                              {
                    Name = "content",
                    Type = PostDataParamType.Field,
                    Value = "data:" + mimeType + ";base64," + b64
                });
                
                var postData = p.GetPostData ();

                
                byte[] data = Encoding.UTF8.GetBytes (postData);
                
                request.ContentType = "multipart/form-data; boundary=" + p.Boundary;
                
                Stream stream = request.GetRequestStream ();
                stream.Write (data, 0, data.Length);
                stream.Close ();
                
                // Get response
                var response = (HttpWebResponse)request.GetResponse ();
                var responseContent = new StreamReader (response.GetResponseStream ()).ReadToEnd ();
                
                var serializer = new DataContractJsonSerializer (typeof (CloudPrintJob));
                var ms = new MemoryStream (Encoding.Unicode.GetBytes (responseContent));
                var printJob = serializer.ReadObject (ms) as CloudPrintJob;
                
                return printJob;
            }
            catch (Exception ex)
            {
                return new CloudPrintJob { success = false, message = ex.Message };
            }
        }
        
        public CloudPrinters Printers
        {
            get
            {
                var printers = new CloudPrinters ();
                
                string authCode;
                if (!Authorize (out authCode))
                return new CloudPrinters { success = false };
                
                try
                {
                    var request = (HttpWebRequest)WebRequest.Create ("http://www.google.com/cloudprint/search?output=json");
                    request.Method = "POST";
                    
                    // Setup the web request
                    request.ServicePoint.Expect100Continue = false;
                    
                    // Add the headers
                    request.Headers.Add ("X-CloudPrint-Proxy", Source);
                    request.Headers.Add ("Authorization", "GoogleLogin auth=" + authCode);
                    
                    request.ContentType = "application/x-www-form-urlencoded";
                    request.ContentLength = 0;
                    
                    var response = (HttpWebResponse)request.GetResponse ();
                    var responseContent = new StreamReader (response.GetResponseStream ()).ReadToEnd ();
                    
                    var serializer = new DataContractJsonSerializer (typeof (CloudPrinters));
                    var ms = new MemoryStream (Encoding.Unicode.GetBytes (responseContent));
                    printers = serializer.ReadObject (ms) as CloudPrinters;
                    
                    return printers;
                }
                catch (Exception)
                {
                    return printers;
                }
            }
        }
        
        private bool Authorize (out string authCode)
        {
            var result = false;
            authCode = "";
            
            var queryString = String.Format ("https://www.google.com/accounts/ClientLogin?accountType=HOSTED_OR_GOOGLE&Email={0}&Passwd={1}&service=cloudprint&source={2}",
                                             UserName, Password, Source);
            var request = (HttpWebRequest)WebRequest.Create (queryString);
            
            request.ServicePoint.Expect100Continue = false;
            
            var response = (HttpWebResponse)request.GetResponse ();
            var responseContent = new StreamReader (response.GetResponseStream ()).ReadToEnd ();
            
            var split = responseContent.Split ('\n');
            foreach (var s in split)
            {
                var nvsplit = s.Split ('=');
                if (nvsplit.Length == 2)
                {
                    if (nvsplit[0] == "Auth")
                    {
                        authCode = nvsplit[1];
                        result = true;
                    }
                }
            }
            
            return result;
        }

    }

    [DataContract]
    public class CloudPrinter
    {
        [DataMember (Order = 0)]
        public string id { get; set; }
        
        [DataMember (Order = 1)]
        public string name { get; set; }
        
        [DataMember (Order = 2)]
        public string description { get; set; }
        
        [DataMember (Order = 3)]
        public string proxy { get; set; }
        
        [DataMember (Order = 4)]
        public string status { get; set; }
        
        [DataMember (Order = 5)]
        public string capsHash { get; set; }
        
        [DataMember (Order = 6)]
        public string createTime { get; set; }
        
        [DataMember (Order = 7)]
        public string updateTime { get; set; }
        
        [DataMember (Order = 8)]
        public string accessTime { get; set; }
        
        [DataMember (Order = 9)]
        public bool confirmed { get; set; }
        
        [DataMember (Order = 10)]
        public int numberOfDocuments { get; set; }
        
        [DataMember (Order = 11)]
        public int numberOfPages { get; set; }
    }

    [DataContract]
    public class CloudPrinters
    {
        [DataMember (Order = 0)]
        public bool success { get; set; }
        
        [DataMember (Order = 1)]
        public List<CloudPrinter> printers { get; set; }
    }



    [DataContract]
    public class CloudPrintJob
    {
        [DataMember (Order = 0)]
        public bool success { get; set; }
        
        [DataMember (Order = 1)]
        public string message { get; set; }
    }



    internal class PostData
    {
        private const String CRLF = "\r\n";
        
        public string Boundary { get; set; }
        private List<PostDataParam> _mParams;
        
        public List<PostDataParam> Params
        {
            get { return _mParams; }
            set { _mParams = value; }
        }
        
        public PostData ()
        {
            // Get boundary, default is --AaB03x
            Boundary = "----CloudPrintFormBoundary" + DateTime.UtcNow;
            
            // The set of parameters
            _mParams = new List<PostDataParam> ();
        }
        
        public string GetPostData ()
        {
            var sb = new StringBuilder ();
            foreach (var p in _mParams)
            {
                sb.Append ("--" + Boundary).Append (CRLF);
                
                if (p.Type == PostDataParamType.File)
                {
                    sb.Append (string.Format ("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"", p.Name, p.FileName)).Append (CRLF);
                    sb.Append ("Content-Type: ").Append (p.FileMimeType).Append (CRLF);
                    sb.Append ("Content-Transfer-Encoding: base64").Append (CRLF);
                    sb.Append ("").Append (CRLF);
                    sb.Append (p.Value).Append (CRLF);
                }
                else
                {
                    sb.Append (string.Format ("Content-Disposition: form-data; name=\"{0}\"", p.Name)).Append (CRLF);
                    sb.Append ("").Append (CRLF);
                    sb.Append (p.Value).Append (CRLF);
                }
            }
            
            sb.Append ("--" + Boundary + "--").Append (CRLF);
            
            return sb.ToString ();
        }
    }
    
    public enum PostDataParamType
    {
        Field,
        File
    }
    
    public class PostDataParam
    {
        public string Name { get; set; }
        public string FileName { get; set; }
        public string FileMimeType { get; set; }
        public string Value { get; set; }
        public PostDataParamType Type { get; set; }
        
        public PostDataParam ()
        {
            FileMimeType = "text/plain";
        }
    }
}

Saturday, January 19, 2013

Login for Mono Touch.


So folks.  Looks like making good code still has some worth.  Ipad / Iphone app, with Login functionality now.  This code is placed in the AppDelegate.cs in Mono Touch for the interface on app start.


            RootElement re = new RootElement("Login");
            Section creds = new Section("Credentials");
            Section welcome = new Section("Welcome to Youth Impact!");
            UIImageView ie;
            if(UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone) ie = new UIImageView(UIImage.FromBundle("resized.png"));
            else ie = new UIImageView(UIImage.FromBundle("small2.png"));
            welcome.Add(ie);
            login = new EntryElement("Login","Enter your Email", "");
            password = new EntryElement("Password","","",true);

            creds.Add(login);
            creds.Add(password);
            Section button = new Section();
            button.Add(new StringElement("Sign In",delegate { Validate();}));

            re.Add(welcome);
            re.Add(creds);
            re.Add(button);

            window = new UIWindow (UIScreen.MainScreen.Bounds);
            DialogViewController dialog = new DialogViewController(re);


            window.RootViewController = new DialogViewController(re);

I only put in a bit of logic for swapping the image out for IPhone / Ipad.  There is some code to do for when the app shifts Orientation.  As your properly sized image needs to be replaced with an image with the proper width / height due to the orientation change.

Using that if(UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone), should provide you the ability to handle that.. and maybe I'll just update this post later.

In the Validate method, I check the two Entries, one for password, and one for Login.. and use my web service call to validate the user.. if the response comes back as valid credentials, then I load the default ViewController that was generated when you create a "Universal" iphone / ipad app in Mono Touch.

Most of this code was taken as ill-gotten gains from this great recipe on Xamarin:

Xamarin Login Window Recipe.


Friday, January 18, 2013

Monotouch Development.


Yeah, if you've been here because of my links, you'll notice that the title of the blog changed.

Mobile Development.  Started working a bit in Mono Touch.

The great thing about working in Xamarin, is that you can re-use almost all your data access, if you started in Android.

I imported my model classes.  I imported my service call methods.



Made a nice little MasterViewController, and a DetailView where I could render custom data from the data made in my calls. Sorry, I had to blur the names.. because those kids don't deserve to have some stupid developer expose the fact that they are in a program at an address that can be found pretty easily.

Creating this app, took about 30 minutes.   (I had to read a little).  I can actually say nowadays, that my new personality is stronger / faster / happier, than I can easily explain and I'm going to take advantage of that.