WP8.1

How to use WordPress to display remote notifications in your Windows Phone app

Sometimes, we need to display information to our users on demand. The easiest way is to do this in our app via a remote notification service.

If you have a WordPress blog, my solution may also be helpful for you.

I am using a page that is not linked anywhere in my blog to display the message. To add a new page, go to your WordPress Dashboard and hover over “Pages” and click on “Add New”.

image

Fill in the title and your notification and publish the page. Before closing your browser, save/remember the id of the page, we will need it later.

image

The next step is to download my WordPress Universal library, which can be downloaded right here from my Github. You can add the project directly to your solution or build it and then reference the library you will find in the bin folder of the WordPress Universal project folder. If you want to learn more about the library, visit http://bit.ly/WordPressUniversal.

Now that we have everything in place, let’s add the code that does the magic for us:

        public async void ShowNotification()
        {
            //initialize the client and load the list of pages from your blog
            wpClient = new WordPressClient();
            var pages = await wpClient.GetPostList("msicc.net", WordPressUniversal.Models.PostType.page, WordPressUniversal.Models.PostStatus.publish, 20, 0);

            //select the notification page
            var notificationContentPage = from p in pages.posts_list where p.id == 4248 select p;

            //check if has content
            if (!String.IsNullOrEmpty(notificationContentPage.FirstOrDefault().content))
            {
                //convert parapgraphs into NewLines
                //you might have more HTML content in there which needs to be converted
                string content = notificationContentPage.FirstOrDefault().content.Replace("

", string.Empty).Replace("

", "\n\n"); //App.SettingsStore = ApplicationData.Current.LocalSettings //change this to your appropriate storage like IsolatedStorage etc. //this displays the message only once to our users, but keeps the door open for an easy update mechanism if (App.SettingsStore.LastNotificationContent != content) { MessageBoxResult result = MessageBox.Show(content, notificationContentPage.FirstOrDefault().title, MessageBoxButton.OK); switch (result) { //the button click saves the actual message case MessageBoxResult.OK: App.SettingsStore.LastNotificationContent = content; break; //BackButtonPress does this as well case MessageBoxResult.None: App.SettingsStore.LastNotificationContent = content; break; } } } }

What does this code do? First, it fetches all pages from our WordPress blog. Then, we are selecting the page we created via its id. If your WordPress blog does not show you the id in the url of the page, set a BreakPoint at the “var notificationContentPage = …” line. you will then easily be able to get the id:

image

Naturally, the returned content is HTML formatted. To remove the paragraph tags and but respect their function, we are using a simple String.Replace pattern. You may have more HTML tags in your message that needs to be removed or converted.

To generate an easy way to display the message only once but keep it open for updates, we are saving the converted message locally. In this case, I used the LocalSettings of my Windows Phone 8.1 app. I am using the MessageBoxResult to make the method saving the message either at the point of the OK click as well as on BackButtonPress.

This is how the above generated WordPress Page looks as a Notification:

wp_ss_20141127_0001

As my WordPress Universal library works cross platform for C# apps, you should be able to adapt this for your Windows 8.1 or  Xamarin apps as well.

As always, I hope this is helpful for some of you.

Happy coding!

Posted by msicc in Archive, 1 comment

How to capture a photo in your Windows Phone 8.1 Runtime app – Part III: capturing and saving the photo

This is the third and last post of this series. In the first two posts I showed you how to start the preview of MediaCapture and some modifications we can apply to it. In this post, we are finally capturing and saving the photo – including the modifications we made before.

The easiest way – capture as is:

The easiest way to capture the photo is to use MediaCapture’s CapturePhotoToStorageFileAsync() method. This method shows you how to do it:

            //declare image format
            ImageEncodingProperties format = ImageEncodingProperties.CreateJpeg();

            //generate file in local folder:
            StorageFile capturefile = await ApplicationData.Current.LocalFolder.CreateFileAsync("photo_" + DateTime.Now.Ticks.ToString(), CreationCollisionOption.ReplaceExisting);

            ////take & save photo
            await captureManager.CapturePhotoToStorageFileAsync(format, capturefile);

            //show captured photo
            BitmapImage img = new BitmapImage(new Uri(capturefile.Path));
            takenImage.Source = img;
            takenImage.Visibility = Visibility.Visible;

This way however does not respect any modifications we made to the preview. The only thing that gets respected is the camera device we are using.

Respecting rotation in the captured photo:

In our ongoing sample, we are using a 90 degree rotation to display the preview element in portrait mode. Naturally, we want to port over this orientation in our captured image.

There are two ways to achieve this. We could capture the photo to a WriteableBitmap and manipulate it, or we could manipulate the image stream directly with the BitmapDecoder and  BitmapEncoder classes. We will do the latter one.

First, we need to open an InMemoryRandomAccessStream for our the captured photo. We are capturing the photo to the stream with MediaCapture’s CapturePhotoToStreamAsync() method, specifing the stream name and the image format.

The next step is to decode the stream with our BitmapDecoder. If we are performing only rotation, we can directly re-encode the InMemoryRandomAccessStream we are using. Rotating the captured photo is very simple with just setting the BitmapTransform.Rotation property to be rotated by 90 degrees, pretty much as easy as rotating the preview.

The last steps are generating a file in the storage, followed by copying the transcoded image stream into the file stream. Here is the complete code that does all this:

            //declare string for filename
            string captureFileName = string.Empty;
            //declare image format
            ImageEncodingProperties format = ImageEncodingProperties.CreateJpeg();

            //rotate and save the image
            using (var imageStream = new InMemoryRandomAccessStream())
            {
                //generate stream from MediaCapture
                await captureManager.CapturePhotoToStreamAsync(format, imageStream);

                //create decoder and encoder
                BitmapDecoder dec = await BitmapDecoder.CreateAsync(imageStream);
                BitmapEncoder enc = await BitmapEncoder.CreateForTranscodingAsync(imageStream, dec);

                //roate the image
                enc.BitmapTransform.Rotation = BitmapRotation.Clockwise90Degrees;

                //write changes to the image stream
                await enc.FlushAsync();

                //save the image
                StorageFolder folder = KnownFolders.SavedPictures;
                StorageFile capturefile = await folder.CreateFileAsync("photo_" + DateTime.Now.Ticks.ToString() + ".jpg", CreationCollisionOption.ReplaceExisting);
                captureFileName = capturefile.Name;

                //store stream in file
                using (var fileStream = await capturefile.OpenStreamForWriteAsync())
                {
                    try
                    {
                        //because of using statement stream will be closed automatically after copying finished
                        await RandomAccessStream.CopyAsync(imageStream, fileStream.AsOutputStream());
                    }
                    catch 
                    {

                    }
                }
            }

Of course, we need to stop the preview after we captured the photo. It also makes all sense to load the saved image and display it to the user. This is the code to stop the preview:

        private async void CleanCapture()
        {

            if (captureManager != null)
            {
                if (isPreviewing == true)
                {
                    await captureManager.StopPreviewAsync();
                    isPreviewing = false;
                }
                captureManager.Dispose();

                previewElement.Source = null;
                previewElement.Visibility = Visibility.Collapsed;
                takenImage.Source = null;
                takenImage.Visibility = Visibility.Collapsed;
                captureButton.Content = "capture";
            }

        }

The result of above mentioned code (screenshot of preview left, captured photo right):

16by9Photo

Cropping the captured photo

Not all Windows Phone devices have an aspect ratio of 16:9. In fact, most devices in the market have an aspect ratio of 15:9, due to the fact that they are WVGA or WXGA devices (I talked a bit about this already in my second post). If we are just capturing the photo with the method above, we will have the same black bands in our image as we have in our preview. To get around this and capture a photo that has a true 15:9 resolution (makes sense for photos that get reused in apps, but less for real life photos), additional code is needed.

As with getting the right camera solution, I generated an Enumeration that holds all possible values as well as a helper method to detect which aspect ratio the currently used device has:

        public enum DisplayAspectRatio
        {
            Unknown = -1,

            FifteenByNine = 0,

            SixteenByNine = 1
        }

        private DisplayAspectRatio GetDisplayAspectRatio()
        {
            DisplayAspectRatio result = DisplayAspectRatio.Unknown;

            //WP8.1 uses logical pixel dimensions, we need to convert this to raw pixel dimensions
            double logicalPixelWidth = Windows.UI.Xaml.Window.Current.Bounds.Width;
            double logicalPixelHeight = Windows.UI.Xaml.Window.Current.Bounds.Height;

            double rawPerViewPixels = DisplayInformation.GetForCurrentView().RawPixelsPerViewPixel;
            double rawPixelHeight = logicalPixelHeight * rawPerViewPixels;
            double rawPixelWidth = logicalPixelWidth * rawPerViewPixels;

            //calculate and return screen format
            double relation = Math.Max(rawPixelWidth, rawPixelHeight) / Math.Min(rawPixelWidth, rawPixelHeight);
            if (Math.Abs(relation - (15.0 / 9.0)) < 0.01)
            {
                result = DisplayAspectRatio.FifteenByNine;
            }
            else if (Math.Abs(relation - (16.0 / 9.0)) < 0.01)
            {
                result = DisplayAspectRatio.SixteenByNine;
            }

            return result;
        }

In Windows Phone 8.1, all Elements use logical pixel size. To get the values that most of us are used to, we need to calculate the raw pixels from the logical pixels. After that, we use the same math operations I used already for detecting the ratio of the camera resolution (see post 2). I tried to calculate the values with the logical pixels as well, but this ended up in some strange rounding behavior and not the results I wanted. That’s why I use the raw pixel sizes.

Before we continue with capturing the photo, we are going to add a border that is displayed and shows the area which is captured to the user in XAML:

            

When we are cropping our photo, we need to treaten the BitmapEncoder and the BitmapDecoder separately. To crop an image, we  need to set the Bounds and the new Width and Height of the photo via the BitmapTransform.Bounds property. We also need to read the PixelData via the GetPixelDataAsync() method, apply the changed Bounds to it and pass them to BitmapEncoder via the SetPixelData() method.

At the end, we are flushing the changed stream data directly into the file stream of our StorageFile. Here is how:

            //declare string for filename
            string captureFileName = string.Empty;
            //declare image format
            ImageEncodingProperties format = ImageEncodingProperties.CreateJpeg();

            using (var imageStream = new InMemoryRandomAccessStream())
            {
                //generate stream from MediaCapture
                await captureManager.CapturePhotoToStreamAsync(format, imageStream);

                //create decoder and transform
                BitmapDecoder dec = await BitmapDecoder.CreateAsync(imageStream);
                BitmapTransform transform = new BitmapTransform();

                //roate the image
                transform.Rotation = BitmapRotation.Clockwise90Degrees;
                transform.Bounds = GetFifteenByNineBounds();

                //get the conversion data that we need to save the cropped and rotated image
                BitmapPixelFormat pixelFormat = dec.BitmapPixelFormat;
                BitmapAlphaMode alpha = dec.BitmapAlphaMode;

                //read the PixelData
                PixelDataProvider pixelProvider = await dec.GetPixelDataAsync(
                    pixelFormat,
                    alpha,
                    transform,
                    ExifOrientationMode.RespectExifOrientation,
                    ColorManagementMode.ColorManageToSRgb
                    );
                byte[] pixels = pixelProvider.DetachPixelData();

                //generate the file
                StorageFolder folder = KnownFolders.SavedPictures;
                StorageFile capturefile = await folder.CreateFileAsync("photo_" + DateTime.Now.Ticks.ToString() + ".jpg", CreationCollisionOption.ReplaceExisting);
                captureFileName = capturefile.Name;

                //writing directly into the file stream
                using (IRandomAccessStream convertedImageStream = await capturefile.OpenAsync(FileAccessMode.ReadWrite))
                {
                    //write changes to the BitmapEncoder
                    BitmapEncoder enc = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, convertedImageStream);
                    enc.SetPixelData(
                        pixelFormat,
                        alpha,
                        transform.Bounds.Width,
                        transform.Bounds.Height,
                        dec.DpiX,
                        dec.DpiY,
                        pixels
                        );

                    await enc.FlushAsync();
                }
            }

You may have notice the GetFifteenByNineBounds() method in the above code. As we need to calculate some values for cropping the image, I decided to separate them. They are not only providing values for the image to be cropped, but also size values for our earlier added Border that is used in my sample (download link at the end of the project) to show the size that the photo will have after our cropping (which is an automatic process in our case,). Here is the code:

        private BitmapBounds GetFifteenByNineBounds()
        {
            BitmapBounds bounds = new BitmapBounds();

            //image size is raw pixels, so we need also here raw pixels
            double logicalPixelWidth = Windows.UI.Xaml.Window.Current.Bounds.Width;
            double logicalPixelHeight = Windows.UI.Xaml.Window.Current.Bounds.Height;

            double rawPerViewPixels = DisplayInformation.GetForCurrentView().RawPixelsPerViewPixel;
            double rawPixelHeight = logicalPixelHeight * rawPerViewPixels;
            double rawPixelWidth = logicalPixelWidth * rawPerViewPixels;

            //calculate scale factor of UniformToFill Height (remember, we rotated the preview)
            double scaleFactorVisualHeight = maxResolution().Width / rawPixelHeight;

            //calculate the visual Width
            //(because UniFormToFill scaled the previewElement Width down to match the previewElement Height)
            double visualWidth = maxResolution().Height / scaleFactorVisualHeight;
            
            //calculate cropping area for 15:9
            uint scaledBoundsWidth = maxResolution().Height;
            uint scaledBoundsHeight = (scaledBoundsWidth / 9) * 15;

            //we are starting at the top of the image
            bounds.Y = 0;
            //cropping the image width
            bounds.X = 0;
            bounds.Height = scaledBoundsHeight;
            bounds.Width = scaledBoundsWidth;

            //set finalPhotoAreaBorder values that shows the user the area that is captured
            finalPhotoAreaBorder.Width = (scaledBoundsWidth / scaleFactorVisualHeight) / rawPerViewPixels;
            finalPhotoAreaBorder.Height = (scaledBoundsHeight / scaleFactorVisualHeight) / rawPerViewPixels;
            finalPhotoAreaBorder.Margin = new Thickness(
                                            Math.Floor(((rawPixelWidth - visualWidth) / 2) / rawPerViewPixels), 
                                            0,
                                            Math.Floor(((rawPixelWidth - visualWidth) / 2) / rawPerViewPixels), 
                                            0);
            finalPhotoAreaBorder.Visibility = Visibility.Visible;

            return bounds;
        }

Again, we need to apply raw pixels to achieve the best results here (I just pasted those lines in for this sample). To calculate the correct values for our Border, we need the scale factor between the screen and the preview resolution we used (which is the scaleFactorVisualHeight double).  Before we’re calculating the border values, we are setting the Width to resolution’s Height (we rotated, remember?) and calculate the matching 15:9 Height.

The Border values are based on the Width and Height of the cropped image, but scaled down by scaleFactorVisualHeight’s value and converted in raw pixel. The Margin positions the border accordingly on top of the preview element.

This is the result of above mentioned code (screenshot of preview left, captured photo right):

15by9Photo

That’s all you need to know to get started with basic photo capturing from within your Windows Phone 8.1 Runtime app. Of course, there are also other modifications that you can apply, and I mentioned already most of the classes that lead you to the matching methods and properties (click on the links to get to the documentation)

By the way, most of the code can be adapted in a Windows 8.1 app as well (with some differences, of course).

Sample project

As promised, you can download the sample here. It contains all code snippets I showed you and is able to run as you build and deploy it.

As always, feedback is welcome and I hope this post is helpful for some of  you.

Until the next time, happy coding!

Posted by msicc in Archive, 21 comments

How to capture a photo in your Windows Phone 8.1 Runtime app-Part II: some common modifications

Like promised in my first post about photo capturing, I will provide some common modification scenarios when using the MediaCapture API. This is what this post is about.

Choosing a camera

If you read my first post, you probably remember that the MediaCapture API automatically selected the front camera of my Lumia 1020. Like often, we have to write some additional code to switch between the cameras.

The cameras are listed in the Panels in the Windows.Devices.Enumeration Namespace. This namespace contains all “devices” that are connected to the phone and has different properties to detect the correct panel. We are going to use the DeviceClass to detect all video capture devices (which are normally also the photo capture devices on Windows Phone, but can be different on a PC/Tablet). As we want to switch between Front and Back, we are also detecting the EnclosureLocation. Here is how I implemented it:

        private static async Task<DeviceInformation> GetCameraID(Windows.Devices.Enumeration.Panel camera)
        {
            DeviceInformation deviceID = (await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture))
                .FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == camera);

            return deviceID;
        }

To make this Task actually useful, we are also updating the InitializePreview() method from the first part:

        private async void InitializePreview()
        {
            captureManager = new MediaCapture();

            var cameraID = await GetCameraID(Windows.Devices.Enumeration.Panel.Back);

            await captureManager.InitializeAsync(new MediaCaptureInitializationSettings
            {
                StreamingCaptureMode = StreamingCaptureMode.Video,
                PhotoCaptureSource = PhotoCaptureSource.Photo,
                AudioDeviceId = string.Empty,
                VideoDeviceId = cameraID.Id,
            });

            StartPreview();
        }

In this case, we  selected the back camera. To make the MediaCapture API actually use this device, we need to generate a new instance of MediaCaptureInitializationSettings, where we select the cameras Id as VideDeviceId. If you now start capturing, this is an exemplary result:

wp_ss_20141115_0001

Rotating the preview

However, this not quite satisfying, because the preview automatically uses the landscape orientation. Luckily, this can be changed with just one single line of code (that needs to be added before actually starting the preview):

captureManager.SetPreviewRotation(VideoRotation.Clockwise90Degrees);

Now the result looks like this:

wp_ss_20141115_0002

Note: the black bands on both sides may happen due to the fact that most devices have a 15:9 ratio (WXGA, WVGA). On Devices like the Lumia 830 or 930, which have a 16:9 ratio, the preview will use the full screen in portrait mode. I tried a lot of things to get rid of those bands already, sadly without success. Once I found a proper solution, I will write another blog post and link it here on how to do it (any tips are welcome).

Limiting resolution

Sometimes, we need to limit resolutions (for example resolution limits on other parts in our app). This is possible by detecting the supported solutions and matching them to the screen ratio. As we are using the whole screen for previewing, of course we want to get our captured photo to use the same space, too.

My way to do this is to calculate the screen ratio, and return an enumeration value. This is the easiest way, and can be easily used in the further code to limit the resolution. The enumeration looks like this:

public enum CameraResolutionFormat
{
    Unknown = -1,

    FourByThree = 0,

    SixteenByNine = 1
}

And this is my helper to match the screen format (which is always wide screen on Windows Phone):

        private CameraResolutionFormat MatchScreenFormat(Size resolution)
        {
            CameraResolutionFormat result = CameraResolutionFormat.Unknown;

            double relation = Math.Max(resolution.Width, resolution.Height) / Math.Min(resolution.Width, resolution.Height);
            if (Math.Abs(relation - (4.0 / 3.0)) < 0.01)
            {
                result = CameraResolutionFormat.FourByThree;
            }
            else if (Math.Abs(relation - (16.0 / 9.0)) < 0.01)
            {
                result = CameraResolutionFormat.SixteenByNine;
            }

            return result;
        }

We could easily extend the calculation to 15:9, too. However, as the most camera resolutions are 4:3 or 16:9, this makes no sense in our use case (as 15:9 is still a widescreen format). The next thing we need to add is another helper to get the highest possible resolution for our photo and the preview. We are achieving this by generating a new object of type VideoEncodingProperties:

        private VideoEncodingProperties maxResolution()
        {
            VideoEncodingProperties resolutionMax = null;

            //get all photo properties
            var resolutions = captureManager.VideoDeviceController.GetAvailableMediaStreamProperties(MediaStreamType.Photo);

            //generate new list to work with
            List<VideoEncodingProperties> vidProps = new List<VideoEncodingProperties>();

            //add only those properties that are 16:9 to our own list
            for (var i = 0; i < resolutions.Count; i++)
            {
                VideoEncodingProperties res = (VideoEncodingProperties)resolutions[i];

                if (MatchScreenFormat(new Size(res.Width, res.Height)) != CameraResolutionFormat.FourByThree)
                {
                    vidProps.Add(res);
                }
            }

            //order the list, and select the highest resolution that fits our limit
            if (vidProps.Count != 0)
            {
                vidProps = vidProps.OrderByDescending(r => r.Width).ToList();

                resolutionMax = vidProps.Where(r => r.Width < 2600).First();                
            }

            return resolutionMax;
        }

What I am doing here: I read all available VideoEncodingProperties for the MediaStreamType Photo. As I mentioned before, we need only wide screen resolution for Windows Phone, that’s why I add only those that have not a 4:3 ratio to my list. Then I am using LINQ to order the list and select the highest resolution from that list.

Using this helper is also very easy, done with one line of code before starting the preview and best also before rotating the preview:

await captureManager.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.Photo, maxResolution());

This way, we are able to respect any resolution limits that we might face while developing our app, while keeping the photo quality as high as possible.

        private CameraResolutionFormat MatchScreenFormat(Size resolution)
        {
            CameraResolutionFormat result = CameraResolutionFormat.Unknown;

            double relation = Math.Max(resolution.Width, resolution.Height) / Math.Min(resolution.Width, resolution.Height);
            if (Math.Abs(relation - (4.0 / 3.0)) < 0.01)
            {
                result = CameraResolutionFormat.FourByThree;
            }
            else if (Math.Abs(relation - (16.0 / 9.0)) < 0.01)
            {
                result = CameraResolutionFormat.SixteenByNine;
            }

            return result;
        }

Focus

Focusing on objects in your photo is quite important. Sadly, it seems that currently we are not able to have a one solution fits all devices solution for using AutoFocus. I experimented a lot with it, and finally I got aware of known issues with Nokia drivers and the new MediaCapture API’s, as described here. Microsoft is working with Nokia (or their devices department) to fix this problem.

The only solution I got working for an Runtime app is to use manual focus. All other attempts gave me one Exception after the other, be it on cancelling the preview or be it on while previewing itself.  I’ll write another post on how to use the AutoFocus as soon as it is working like it should. In the meantime, here is my solution for manual focusing.

First, add a Slider control in your XAML page:

<Slider x:Name="FocusValueSlider" Maximum="1000" Minimum="0" Grid.Row="0" Margin="12,0,15,0" Header="adjust focus:" ValueChanged="FocusValueSlider_ValueChanged" Value="500" SmallChange="25" LargeChange="100" ></Slider>

Notice that as with any slider, you need to follow the order: Set Maximum first, then Minimum. If you do not, you will likely get an unusable Slider in return. If the VideoDeviceController.Focus property would work (seems like it is also affected by the above mentioned driver problems), we could read and set the Slider values from its MediaDeviceControl.Capabilities property. I tried to read them at any stage of previewing, but their values are always 0.0, null and false. The range up to 1000 fits in very well on all devices I tested (Lumia 920, 930 and 1020).

Ok, enough of whining. Let’s have a look at my solution. First, we need to generate a small helper that allows us to adjust the focus based on the slider values:

        private async void SetFocus(uint? focusValue = null)
        {
            //try catch used to avoid app crash at startup when no CaptureElement is active
            try
            {
                //setting default value
                if (!focusValue.HasValue)
                {
                    focusValue = 500;
                }

                //check if the devices camera supports focus control
                if (captureManager.VideoDeviceController.FocusControl.Supported)
                {
                    //disable flash assist for focus control
                    captureManager.VideoDeviceController.FlashControl.AssistantLightEnabled = false;

                    //configure the FocusControl to manual mode
                    captureManager.VideoDeviceController.FocusControl.Configure(new FocusSettings() { Mode = FocusMode.Manual, Value = focusValue, DisableDriverFallback = true });
                    //update the focus on our MediaCapture
                    await captureManager.VideoDeviceController.FocusControl.FocusAsync();
                }
            }
            catch { }
        }

This methods checks if the current camera supports Focus, and sets its value according to the slider. The AssistantLight is disabled in this case. Its default is enabled (true).

To add the possibility to adjust the focus, we need to configure our own FocusSettings that tell the camera that we are focusing manually based on the slider’s value. Finally, we need to perform the focusing action by calling the FocusControl’s FocusAsync method.

The next step is to hook up to changes in the slider values within the FocusValueSlider_ValueChanged event:

        private void FocusValueSlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
        {
            try
            {
                //convert double e.NewValue to uint and call SetFocus()
                uint focus = Convert.ToUInt32(e.NewValue);
                SetFocus(focus);
            }
            catch 
            {
                
            }
        }

Now every move of the slider will change the focus of the preview and of course also of the captured photo (which we will learn more about in the third post of this series).  To initialize our Focus correctly with the value of 500 we set in XAML, just call SetFocus(); before you start the preview. Here is the result:

focus screenshot

 

Disclaimer: I do not know if this follows best practices, but it works. If you have feedback for the above mentioned code snippets, feel free to leave a comment below.

In the third and last post I’ll show you how to save the images (also in different folders or only within the app).

Until then, happy coding!

Posted by msicc in Archive, 9 comments

How to capture a photo in your Windows Phone 8.1 Runtime app–Part I: the preview of the photo to capture

With the recent release of the public beta of RandR, I also learned a lot about taking photos from within an Windows Phone 8.1 app. There are several differences to Windows Phone 8, so I decided to start this three part series on how to capture a photo in your app (it would be too much for one single post).

The series will contain following topics:

The series concentrates on basic features to enable you to get started. I am adding relevant links to those posts, and at the end of the series, I will also attach a sample project.

Let’s start

Before we can use MediaCapture, please make sure that you enable Webcam and Microphone in your app’s Package.appxmanifest file. Then, we need is an Element that shows us the preview of the content we want to capture. In a Runtime app, we are using a CaptureElement for this. We also need to buttons, one to start/cancel the preview operation, and one to save the photo. Of course we want to show the photo we have taken, so we need also an image element.

Add this code to your XAML page:

<Grid>
    <CaptureElement x:Name="previewElement" Stretch="UniformToFill" />
    <Image x:Name="takenImage" Stretch="UniformToFill" Visibility="Collapsed"></Image>
</Grid>
<Grid VerticalAlignment="Bottom">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
<Button Grid.Row="0" x:Name="captureButton" Content="capture" Click="captureButton_Click" HorizontalAlignment="Stretch" Margin="12,0"/>
<Button Grid.Row="1" x:Name="saveButton" Content="save" Click="saveButton_Click" HorizontalAlignment="Stretch" Margin="12,0"/>
</Grid>

Asign the click handlers to the code behind file, where we will also continue to work now.

Before we’ll have a look at the preview code, we need to enable our app to obtain the whole screen. This makes all sense, as we want to capture a photo, and of course we want to see as much as possible in the preview. Add these two lines to the constructor of the page:

var appView = Windows.UI.ViewManagement.ApplicationView.GetForCurrentView();
appView.SetDesiredBoundsMode(ApplicationViewBoundsMode.UseCoreWindow);

The ApplicationViewBoundsMode enumeration has two values (UseVisible and UseCoreWindow). The later one uses the whole screen (even behind the SystemTray and also behind the BottomAppBar) and suits our needs. Only one thing to remember for your app: You need to set the Margins in this case to get your UI  right.

The preview code

Windows Runtime apps use the MediaCapture class for all photo and video capturing.

To enable your app to preview the things you want to capture, we first need to initialize the MediaCapture. We are doing this by a helper method, as we will need it in the next post to create some options for our MediaCapture. After declaring a page wide variable for the MediaCapture, add the following code to your code behind file:

       private async void InitializePreview()
       {
           captureManager = new MediaCapture();

           await captureManager.InitializeAsync();
           StartPreview();
       }

To make the initialized MediaCapture actually doing something, we also need to start the preview:

private async void StartPreview()
{

    previewElement.Source = captureManager;
    await captureManager.StartPreviewAsync();
              
    isPreviewing = true;
}

What we are doing is to set the Source of our previewElement that we declared in XAML to our captureManager and asynchronously start the preview. The isPreviewing Boolean is used to detect if we are actually previewing. We’ll need it in our method to stop the preview. This is very important. If you do not stop the preview, chances are high that you will freeze your phone or make the camera unusable for other apps, too!

To stop the preview, add this code:

private async void CleanCapture()
{
    if (captureManager != null)
    {
        if (isPreviewing == true)
        {
            await captureManager.StopPreviewAsync();
            isPreviewing = false;
        }
        previewElement.Source = null;
        captureButton.Content = "capture";
        captureManager.Dispose();
    }
}

 

We need to do a double check here: First, we need to see if we have a captureManager instance. Then, if we are previewing, we are going to stop it. If we are no longer previewing, we are setting the CaptureElement Source to null, rename our button and free all resources our captureManager used with the Dispose() method.

Now that we have everything for the preview in place, we are able to connect it to our captureButton:

private void captureButton_Click(object sender, RoutedEventArgs e)
{
    if (isPreviewing == false)
    {
        InitializePreview();
        captureButton.Content = "cancel";
    }
    else if (isPreviewing == true)
    {
        CleanCapture();
    }
}

Now we are already able to start previewing (without any options) on our phone:

wp_ss_20141114_0002

You might get similar  strange results if you start capturing. For example, the preview on my Lumia 1020 is flipped upside down and the front camera is used.

How we are going to change this, is topic of the second part.

Until then, happy coding!

Posted by msicc in Archive, 1 comment

How to load a list of a user’s twitter friends/followers in your Windows Phone app

TwitterFriendsList_WP_Blog During the last days, I was adding a new function to UniShare that suggests users the Twitter handles while typing in some text. The base of this new function is a list of the user’s twitter friends. In this post, I am going to show you how to generate this list and save it for further use. First thing I need to talk about: you can only load a maximum of 3000 friends at once due to the rate limit on Twitter’s part. At the end of the post, I’ll give you also an idea how to continue this after the first 3000 users were loaded. For the most scenarios, 3000 should be enough to cover the major part of your users. To be able to load all friends we first create a Task that fetches 200 entries of our user’s friends list. To be able to perform paging through all entries, Twitter uses so called cursors, which are 64-bit signed integers (long). You can read more about that here on Twitter’s API documentation. Let’s have a look on this Task:

        private async Task<string> TwitterFriendsListString(long twitterCursor)
        {
            ShowProgressIndicator("generating mention suggestion base...");

            //needed for generating the Signature
            string twitterRequestUrl = "https://api.twitter.com/1.1/friends/list.json";

            //used for sending the request to the API
            //for usage of the url parameters, go to https://dev.twitter.com/docs/api/1.1/get/friends/list
            string twitterUrl = string.Format("https://api.twitter.com/1.1/friends/list.json?cursor={0}&screen_name={1}&count=200&skip_status=true&include_user_entities=false", twitterCursor, App.SettingsStore.twitterName);

            string timeStamp = GetTimeStamp();
            string nonce = GetNonce();

            string response = string.Empty;

            //we need to include all url parameters in the signature
            //IMPORTANT: Twitter's API demands them to be sorted alphabetically, otherwise the Signature will not be accepted
            string sigBaseStringParams = "count=200";
            sigBaseStringParams += "&" + "cursor=" + twitterCursor;
            sigBaseStringParams += "&" + "include_user_entities=false";
            igBaseStringParams += "&" + "oauth_consumer_key=" + twitterConsumerKey;
            sigBaseStringParams += "&" + "oauth_nonce=" + nonce;
            sigBaseStringParams += "&" + "oauth_signature_method=HMAC-SHA1";
            sigBaseStringParams += "&" + "oauth_timestamp=" + timeStamp;
            sigBaseStringParams += "&" + "oauth_token=" + App.SettingsStore.twitteroAuthToken;
            sigBaseStringParams += "&" + "oauth_version=1.0";
            sigBaseStringParams += "&" + "screen_name=" + App.SettingsStore.twitterName;
            sigBaseStringParams += "&" + "skip_status=true";
            string sigBaseString = "GET&";
            sigBaseString += Uri.EscapeDataString(twitterRequestUrl) + "&" + Uri.EscapeDataString(sigBaseStringParams);

            string signature = GetSignature(sigBaseString, twitterConsumerSecret, App.SettingsStore.twitteroAuthTokenSecret);

            string authorizationHeaderParams =
                "oauth_consumer_key=\"" + twitterConsumerKey +
                "\", oauth_nonce=\"" + nonce +
                "\", oauth_signature=\"" + Uri.EscapeDataString(signature) +
                "\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"" + timeStamp +
                "\", oauth_token=\"" + Uri.EscapeDataString(App.SettingsStore.twitteroAuthToken) +
                "\", oauth_version=\"1.0\"";

            HttpClient httpClient = new HttpClient();

            httpClient.DefaultRequestHeaders.Authorization = new HttpCredentialsHeaderValue("OAuth", authorizationHeaderParams);
            var httpResponseMessage = await httpClient.GetAsync(new Uri(twitterUrl));

            response = await httpResponseMessage.Content.ReadAsStringAsync();

            return response;
        }

As you can see, we need to create our signature based on the url parameters we are requesting. Twitter demands them to be sorted alphabetically. If you would not sort them this way, the Signature is wrong and your request gets denied by Twitter. We are overloading this Task with the above mentioned cursor to get the next page of our user’s friends list. If you need the GetNonce() and GetSignature() methods, take a look at this post, I am using them for all requests to Twitter. Now that we have this Task ready to make our requests, lets load the complete list. First, declare these objects in your page/model:

        public List<TwitterMentionSuggestionBase> twitterMentionSuggestionsList;
        public long nextfriendlistCursor = -1;
        public string friendsResponseString = string.Empty;
        public string friendsJsonFileName = "twitterFriends.json";

Then we need to create a loop to go through all pages Twitter allows us until we are reaching the rate limit of 15 requests per 15 minutes. I using a do while loop, as this is the most convenient way for this request:

            //to avoid double entries, make sure the list is we are using is empty
            if (twitterMentionSuggestionsList.Count != 0)
            {
                twitterMentionSuggestionsList.Clear();
            }
            //starting the do while loop
            do
            {
                //fetching the Json response
                //to get the first page of the list from Twitter, the cursor needs to be -1
                friendsResponseString = await TwitterFriendsListString(nextfriendlistCursor);

                //using Json.net to deserialize the string
                var friendslist = JsonConvert.DeserializeObject<TwitterFriendsClass.TwitterFriends>(friendsResponseString);
                //setting the cursor for the next request
                nextfriendlistCursor = friendslist.next_cursor;

                //adding 200 users to our list
                foreach (var user in friendslist.users)
                {
                    //using the screen name ToLower() to make the further usage easier
                    TwitterMentionSuggestionsList.Add(new TwitterMentionSuggestionBase() { name = "@" + user.screen_name.ToLower() });
                }

                //once the last page is reached, the cursor will be 0
                if (nextfriendlistCursor == 0)
                {
                    //break will continue the code after the do while loop
                    break;
                }
            }
            //the while condition needs to return true if you would set up a Boolean for it!
            while (nextfriendlistCursor != 0);

As long as the cursor is not 0, the loop will load the json string with 200 entries. The class you’ll need for deserializing can be easily generated. Just set a breakpoint after the call of our Task, copy the whole response string and go to http://json2csharp.com to get your class. The TwitterMentionSuggestionBase class only contains a string property for the name and can be extended for you needs:

    public class TwitterMentionSuggestionBase
    {
        public string name { get; set; }
    }

Of course we need to save the list for further use. The code I use is pretty much the same you’ll find when you search for “saving json string to file” with your favorite search engine and works with Windows Phone 8 and 8.1:

            //saving the file to Isolated Storage
            var JsonListOfFriends = JsonConvert.SerializeObject(twitterMentionSuggestionsList);
            try
            {
                //getting the localFolder our app has access to
                StorageFolder localFolder = ApplicationData.Current.LocalFolder;
                //create/overwrite a file
                StorageFile friendsJsonFile = await localFolder.CreateFileAsync(friendsJsonFileName, CreationCollisionOption.ReplaceExisting);
                //write the json string to the file
                using (IRandomAccessStream writeFileStream = await FriendsJsonFile.OpenAsync(FileAccessMode.ReadWrite))
                {
                    using (DataWriter streamWriter = new DataWriter(writeFileStream))
                    {
                        streamWriter.WriteString(JsonListOfFriends);
                        await streamWriter.StoreAsync();
                    }
                }
            }
            catch
            {

            }

This way, we can easily generate a friends list for our users, based on their Twitter friends. Some points that might be helpful:

  • users with more than 3000 friends will receive an error after reaching this point on our task. Catch this error, but continue to save the already loaded list. Save the latest cursor for the next page and prompt the user to continue loading after 15 minutes to continue loading.
  • if you want to have a list with more details about a user’s friends, extend the TwitterMentionSuggestionBase class with the matching properties.
  • this code can also be used to determine the followers of a user, you just need to change the url parameters as well as the signature parameters according to the matching Twitter endpoint

As always, I hope this is helpful for some of you. Until the next post, happy coding!

Posted by msicc in Archive, 3 comments

How to connect your Windows Phone 8 & 8.1 app to Yammer

In my recent project UniShare I also added Yammer, because some of users asked for it and we use it also at Telefónica.

This post is all about how to connect you Yammer. First, we need to prepare our app. Five steps are needed for preparation.

First, we need an uri scheme to launch our app. To add an uri scheme, right click on the WMAppManifest.xml and click on ‘Open With…’ and select ‘XML (Text) Editor with Encoding’. After the ‘Tokens’ section, add your custom uri scheme within the ‘Extensions’ tag, for example:

      <Protocol Name="yourapp-yammercallback" NavUriFragment="encodedLaunchUri=%s" TaskID="_default" />

Next step is to add a proper UriMapper:

public class UriMapper : UriMapperBase
{
    public override Uri MapUri(Uri uri)
    {
        if (uri.ToString().Contains("yourapp-yammercallback"))
        {
            string decodedUri = HttpUtility.UrlDecode(uri.ToString());

            int redirectUriIndex = decodedUri.IndexOf("yourapp-yammercallback");
            string redirectParams = new Uri(decodedUri.Substring(redirectUriIndex)).Query;
            // Map the OAuth response to the app page
            return new Uri("/MainPage.xaml" + redirectParams, UriKind.Relative);
        }

        else return uri;
    }
}

If you want to learn more about uri schemes, you can read my blog post here.

The third step is to generate your app on Yammer to get your Tokens. Open https://www.yammer.com/client_applications, click on ‘Register New App’ and fill in the form:

Screenshot (354)

After clicking on continue, click on ‘Basic Info’ and add your uri scheme in the field ‘Redirect Uri’ and click on ‘Save’.

Screenshot (356)

The fourth step starts with downloading the Yammer oAuth SDK for Windows Phone from Github. Open the solution and built all projects. After that, you can close the solution. Go back into your project, and right click on ‘References’, followed by ‘Add Reference’. Browse to the folder ‘\WPYammer-oauth-sdk-demo-master\windows-phone-oauth-sdk-demo-master\Yammer.OAuthSDK\Bin\Release’ and add the file with the name ‘Yammer.OAuthSDK.dll’.

The last step is to add your keys and the redirect uri in your app’s resource dictionary:

<model:OAuthClientInfo xmlns:model="clr-namespace:Yammer.OAuthSDK.Model;assembly=Yammer.OAuthSDK" x:Key="MyOAuthClientInfo"
    ClientId="your client id" 
    ClientSecret="your client secret" 
    RedirectUri="yourapp-yammercallback" />

Now that our app is prepared, we can finally launch the oAuth process. First, we need to read our values from our app’s resource dictionary. Add this to the constructor to do so:

YammerClientId = App.MyOAuthClientInfo.ClientId;
YammerClientSecret = App.MyOAuthClientInfo.ClientSecret;
YammerCallbackUri = App.MyOAuthClientInfo.RedirectUri;

To kick the user out to the oAuth process, which happens in the phone’s browser, just add these two lines to your starting event (for example a button click event).

OAuthUtils.LaunchSignIn(YammerClientId, YammerCallbackUri);
App.Current.Terminate();

You might notice the app gets terminated. We have to do this because only this way, the uri scheme we added earlier can do its work. If the app is not terminated, the values cannot be passed into our app. Technically, it would also be possible to use the WebAuthenticationBroker on 8.1 for this. Sadly, the Yammer authorization pages do not work well with the WAB. The best way to use it with this library, is to kick the user to the browser.

Once we are receiving the values of the authentication, we can continue the authentication process to get the final access token. Add this code to your OnNavigatedTo event:

ShowProgressIndicator("connecting to Yammer...");

if (NavigationContext.QueryString.ContainsKey(Constants.OAuthParameters.Code) && NavigationContext.QueryString.ContainsKey(Constants.OAuthParameters.State) && e.NavigationMode != NavigationMode.Back)
{
    OAuthUtils.HandleApprove(
        YammerClientId,
        YammerClientSecret,
        NavigationContext.QueryString[Constants.OAuthParameters.Code],
        NavigationContext.QueryString[Constants.OAuthParameters.State],
        onSuccess: () =>
        {
            GetYammerCurrentUserData();
        }, onCSRF: () =>
        {
            MessageBox.Show("Please contact us via the 'help & support' page.", "Invalid redirect", MessageBoxButton.OK);
        }, onErrorResponse: errorResponse =>
        {
            Dispatcher.BeginInvoke(() => MessageBox.Show(errorResponse.OAuthError.ToString(), "Invalid operation", MessageBoxButton.OK));
            HideProgressIndicator();
        }, onException: ex =>
        {
            Dispatcher.BeginInvoke(() => MessageBox.Show(ex.ToString(), "Unexpected error", MessageBoxButton.OK));
            HideProgressIndicator();
        }
    );
}
// "Deny"
else if (NavigationContext.QueryString.ContainsKey(Constants.OAuthParameters.Error) && e.NavigationMode != NavigationMode.Back)
{
    string error, errorDescription;
    error = NavigationContext.QueryString[Constants.OAuthParameters.Error];
    NavigationContext.QueryString.TryGetValue(Constants.OAuthParameters.ErrorDescription, out errorDescription);

    string msg = string.Format("error: {0}\nerror_description:{1}", error, errorDescription);
    MessageBox.Show(msg, "Error", MessageBoxButton.OK);

    if (NavigationContext.QueryString != null)
    {
        string[] NavigationKeys = NavigationContext.QueryString.Keys.ToArray();
        ClearNavigationContext(NavigationKeys);
    }

    OAuthUtils.DeleteStoredToken();

}

With this, you are handling all errors and events properly. If the call ends successfully, we are finally able to get our user’s data:

public void GetYammerCurrentUserData()
{
    ShowProgressIndicator("connecting to Yammer...");

    var baseUrl = new Uri("https://www.yammer.com/api/v1/users/current.json", UriKind.Absolute);

    OAuthUtils.GetJsonFromApi(baseUrl,
        onSuccess: response =>
        {
            //do something with the result (json string)

            HideProgressIndicator();

        }, onErrorResponse: errorResponse =>
        {
            Dispatcher.BeginInvoke(() =>
            {
                MessageBox.Show(errorResponse.OAuthError.ToString(), "Invalid operation", MessageBoxButton.OK);
                HideProgressIndicator();

            });
        }, onException: ex =>
        {
            Dispatcher.BeginInvoke(() =>
            {
                MessageBox.Show(ex.ToString(), "Unexpected error", MessageBoxButton.OK);
                HideProgressIndicator();

            });
        }
    );
}

As you can see above, the result is a json string that contains the current user’s data. You can either create a class/model to deserialize the values or use anonymous deserialization methods.

One important point: you cannot publish your app outside your home network until it got approved as a global app by Yammer. I am waiting for nearly two weeks now for UniShare to get approved and hope it will become available for all soon.

As always, I hope this post is helpful for some of you.

Happy coding!

Posted by msicc in Archive, 1 comment

How to use the WebAuthenticationBroker in a Windows Phone 8.1 Silverlight app

oAuthDance

I already wrote how to use the WebAuthenticationBroker (WAB) in a Windows Phone Runtime app. With the need for me to switch back to Silverlight for UniShare, I needed to perform some rewriting of the WAB code.

The WAB needs some other code to work properly in a Silverlight project, and this post will got through all steps that are needed for this. I will reference to the above blog post where the methods itself are the same. I am just highlighting the changes that are needed in an 8.1 Silverlight project.

Preparing our App

First, we need to set up the proper continuation event in App.xaml.cs. We are doing this by adding this line of code in the App class:

public WebAuthenticationBrokerContinuationEventArgs WABContinuationArgs { get; set; }

This event is used when we are coming back to our app after the WAB logged the user in. The next step we need to do, is to tell our app that we have performed an authentication, and pass the values back to our main code. Unlike in the Runtime project, we are using the Application_ContractActivated event for this:

        private void Application_ContractActivated(object sender, Windows.ApplicationModel.Activation.IActivatedEventArgs e)
        {
            var _WABContinuationArgs = e as WebAuthenticationBrokerContinuationEventArgs;
            if (_WABContinuationArgs != null)
            {
                this.WABContinuationArgs = _WABContinuationArgs;
            }
        }

If you are upgrading from a WP8 project, you might have to add this event manually. Our app is now prepared to get results from the WAB.

Preparing oAuth

I am going to show you the oAuth process of Twitter to demonstrate the usage of the WAB. First, we need again the GetNonce(), GetTimeStamp () and GetSignature(string sigBaseString, string consumerSecretKey, stringoAuthTokenSecret=null) methods from my former blog post.

Performing the oAuth process

In the oAuth authentication flow, we need to obtain a so called Request Token, which allows our app to communicate with the API (in this case Twitter’s API).

Add the following code to your “connect to Twitter”- Button event:

                        string oAuth_Token = await GetTwitterRequestTokenAsync(TwitterCallBackUri, TwitterConsumerKey);
                        string TwitterUrl = "https://api.twitter.com/oauth/authorize?oauth_token=" + oAuth_Token;

                        WebAuthenticationBroker.AuthenticateAndContinue(new Uri(TwitterUrl), new Uri(TwitterCallBackUri));

Like in a Runtime app, we are getting the request token first (code is also in my former blog post), once we obtained the request token, we are able to get the oAuth token that enables us to get the final user access tokens.

Once the user has authenticated our app, we’ll receive the above mentioned oAuth tokens. To use them, add the following code to your OnNavigatedTo event:

                var appObject = Application.Current as App;

                if (appObject.WABContinuationArgs != null)
                {
                    WebAuthenticationResult result = appObject.WABContinuationArgs.WebAuthenticationResult;

                    if (result.ResponseStatus == WebAuthenticationStatus.Success)
                    {
                        await GetTwitterUserNameAsync(result.ResponseData.ToString());
                    }
                    else if (result.ResponseStatus == WebAuthenticationStatus.ErrorHttp)
                    {
                        MessageBox.Show(string.Format("There was an error connecting to Twitter: \n {0}", result.ResponseErrorDetail.ToString()), "Sorry", MessageBoxButton.OK);

                    }
                    else
                    {
                        MessageBox.Show(string.Format("Error returned: \n{0}", result.ResponseStatus.ToString()), "Sorry", MessageBoxButton.OK);
                        HideProgressIndicator();
                    }
                }

The WebAuthenticationResult now holds all values that we need to perform the final actions. To complete the oAuth process on Twitter, you can use the GetTwitterUserNameAsync(string webAuthResultResponseData) method from my former blog post. If you are not using other methods to control the result of the WAB, don’t forget to set appObject.WABContinuationArgs to null after you finished obtaining all tokens and data from Twitter (or other services).

As you can see, there are some structural differences in using the WAB when creating a Silverlight app, but we are also able to use a lot of code from my Runtime project. I hope this post is helpful for some of you to get the oAuth dance going.

In my next post, I will show you how to authenticate your app with Yammer (Microsoft’s enterprise social network).

Until then, happy coding!

Posted by msicc in Archive, 3 comments

How to send a mail from your Windows Phone 8.1 app

The old way

Sometimes, we need to pass some values to a newly generated E-Mail. In Windows Phone, we always had the EmailComposeTask for that:

EmailComposeTask mailTask = new EmailComposeTask();
mailTask .To = "mail@domain.com";
mailTask .Subject = "this is the Subject";
mailTask.Body = "this is the Body";

mailTask.Show();

This way was pretty straight forward. It will work in a Windows Phone 8.1 Silverlight app, but not in a WINPRT app.

The new way

I looked around and found the EmailManager class, which is also pretty easy to use. Let’s go through the code. First, we need to declare the EmailRecipient(s):

EmailRecipient sendTo = new EmailRecipient()
{
    Address = "mail@domain.com"
};

After that, we are now able to set up our EmailMessage, which works in a similar way like the old EmailComposeTask:

EmailMessage mail = new EmailMessage();
mail.Subject = "this is the Subject";
mail.Body = "this is the Body";

After setting up the Subject and the Body, we need to add our recipients to the EMailMessage. This is the only way to add “To”, “Bcc” and “CC” objects to our EMailMessage:

mail.To.Add(sendTo);
//mail.Bcc.Add(sendTo);
//mail.CC.Add(sendTo);

Last but not least, we are calling the  ShowComposeNewEmailAsync() method of the EmailManager class, which will open the Share contract with mail only:

await EmailManager.ShowComposeNewEmailAsync(mail);

 

wp_ss_20140424_0002

Here is once again the complete code for you to copy:

//predefine Recipient
EmailRecipient sendTo = new EmailRecipient()
{
    Address = "mail@domain.com"
};

//generate mail object
EmailMessage mail = new EmailMessage();
mail.Subject = "this is the Subject";
mail.Body = "this is the Body";

//add recipients to the mail object
mail.To.Add(sendTo);
//mail.Bcc.Add(sendTo);
//mail.CC.Add(sendTo);

//open the share contract with Mail only:
await EmailManager.ShowComposeNewEmailAsync(mail);

The new way works for both Windows Phone 8.1 Runtime and Silverlight apps.

The dirty way:

I found also another way that works with an Uri including the values as parameters launched by LaunchUriAsync() that gets recognized by the OS:

var mail = new Uri("mailto:?to=tickets@msiccdev.uservoice.com&subject=this is the Subject&body=this is the Body");
await Launcher.LaunchUriAsync(mail);

The parameters get automatically parsed by the Mail app.

I’ll leave it up to you which way you are using.

As always, I hope this is helpful for some of you.

Happy coding!

Posted by msicc in Archive, 2 comments

How to detect all urls in a string to match Twitter’s requirements (Windows 8(.1) and Windows Phone 8(.1))

url

As you might guess, I am still working on that app I mentioned in my last blog post. As I was diving deeper into the functions I want, I recognized that Twitter does a very well url handling server side.

Like the official documentation says, every url will be shortened with a link that has 22 characters (23 for https urls).

I was trying to write a RegEx expression to detect all the links that can be:

  • http
  • https
  • just plain domain names like “msicc.net”

This is not as easy as it sounds, and so I was a bit struggling. I then talked with @_MadMatt (follow him!) who has a lot of experience with twitter. My first attempt was a bit confusing as I did first only select http and https, then the plain domain names.

I found the names by their domain ending, but had some problems to get their length (which is essential). After the very helpful talk with Matthieu, I finally found a very good working RegEx expression here on GitHub.

I tested it with tons of links, and I got the desired results and it is now also very easy for me to get their length.

Recovering the amount of time I needed for this, I decided to share my solution with you. Here is the method I wrote:

        public int CalculateTweetCountWithLinks(int currentCount, string text)
        {
            int resultCount = 0;

            if (text != string.Empty)
            {
                //detailed explanation: https://gist.github.com/gruber/8891611
                string pattern = @"(?i)\b((?:https?:(?:/{1,3}|[a-z0-9%])|[a-z0-9.\-]+[.](?:com|net|org|edu|gov|mil|aero|asia|biz|cat|coop|info|int|jobs|mobi|museum|name|post|pro|tel|travel|xxx|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|dd|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|Ja|sk|sl|sm|sn|so|sr|ss|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)/)(?:[^\s()<>{}\[\]]+|\([^\s()]*?\([^\s()]+\)[^\s()]*?\)|\([^\s]+?\))+(?:\([^\s()]*?\([^\s()]+\)[^\s()]*?\)|\([^\s]+?\)|[^\s`!()\[\]{};:'.,<>?«»“”‘’])|(?:(?<!@)[a-z0-9]+(?:[.\-][a-z0-9]+)*[.](?:com|net|org|edu|gov|mil|aero|asia|biz|cat|coop|info|int|jobs|mobi|museum|name|post|pro|tel|travel|xxx|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|dd|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|Ja|sk|sl|sm|sn|so|sr|ss|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)\b/?(?!@)))";

                //generating a MatchCollection
                MatchCollection linksInText = Regex.Matches(text, pattern, RegexOptions.Multiline);

                //going forward only when links where found
                if (linksInText.Count != 0)
                {
                    //important to set them to 0 to get the correct count
                    int linkValueLength = 0;
                    int httpOrNoneCount = 0;
                    int httpsCount = 0;

                    foreach (Match m in linksInText)
                    {
                        //https urls need 23 characters, http and others 22
                        if (m.Value.Contains("https://"))
                        {
                            httpsCount = httpsCount + 1;
                        }
                        else
                        {
                            httpOrNoneCount = httpOrNoneCount + 1;
                        }

                        linkValueLength = linkValueLength + m.Value.Length;
                    }

                    //generating summaries of character counts
                    int httpOrNoneReplacedValueLength = httpOrNoneCount * 22;
                    int httpsReplacedValueLength = httpsCount * 23;

                    //calculating final count
                    resultCount = (currentCount - linkValueLength) + (httpOrNoneReplacedValueLength + httpsReplacedValueLength);                    
                }
                else
                {
                    resultCount = currentCount;
                }
            }
            return resultCount;
        }

First, we are detecting links in the string using the above mentioned RegEx expression and collect them in a MatchCollection.

As https urls have a 23 character length on t.co (Twitter’s url shortener), I am generating two new counts – one for https, one for all other urls.

The last step is to substract the the length of all Match values and add the newly calculated replaced link values lengths.

Add this little method to your TextChanged event, and you will be able to detect the character count on the fly.

As always, I hope this is helpful for some of you.

Happy coding, everyone!

 

Posted by msicc in Archive, 0 comments