Sigurd Snørteland


tweet search – one code, three mobile platforms (wp7, monodroid, monotouch)

Here is the presentation and the source code from the speech I held at the Norwegian .Net User Group last wednesday.

tweet search
‘tweet search’ is a mobile twitter search app written in c# for Windows Phone 7, iPhone and Android. All three apps share the same twitter search code, but they have custom gui code (WP7=Silverlight, iPhone=MonoTouch, Android=MonoDroid).

Go to the bottom of this article to find links to the source code & presentation.

Shared twitter-code:

public class Twitter
    {
        public event EventHandler twitteSearchCompleted;

        public Twitter()
        {
        }

        public void search(string searchText)
        {
            if (searchText != "")
            {
                WebClient client = new WebClient();
                client.DownloadStringAsync(new Uri("http://search.twitter.com/search.atom?q=" + searchText));
                client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
            }
        }

        private void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                List twitteList = new List();

                XDocument xml = XDocument.Parse(e.Result);
                XNamespace atomNS = "http://www.w3.org/2005/Atom";

                var tempList = (from entry in xml.Descendants(atomNS + "entry")
                                select new TwitterObject()
                                {
                                    ID = entry.Element(atomNS + "id").Value,
                                    Title = entry.Element(atomNS + "title").Value,
                                    Date = DateTime.Parse(entry.Element(atomNS + "published").Value),
                                    AuthorName = entry.Descendants(atomNS + "author").Elements(atomNS + "name").FirstOrDefault().Value,
                                    AuthorUri = entry.Descendants(atomNS + "author").Elements(atomNS + "uri").FirstOrDefault().Value,
                                    AuthorImage = (from imgElement in entry.Elements(atomNS + "link")
                                                   where imgElement.Attribute("rel") != null
                                                   && imgElement.Attribute("rel").Value.Contains("image")
                                                   && imgElement.Attribute("href") != null
                                                   select imgElement.Attribute("href").Value).FirstOrDefault()
                                }).ToList();

                twitteList = tempList.ToList();
                twitteSearchCompleted(twitteList, null);
            }
        }
    }

    public class TwitterObject
    {
        public string ID { get; set; }
        public string Title { get; set; }
        public DateTime Date { get; set; }
        public string AuthorName { get; set; }
        public string AuthorUri { get; set; }
        public string AuthorImage { get; set; }
    }

WP7 code:

namespace tweet_search_wp7
{
    public partial class MainPage : PhoneApplicationPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        #region UI

        private void txtSearch_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                this.Focus();
            }
        }

        private void txtSearch_LostFocus(object sender, RoutedEventArgs e)
        {
            search();
        }

        private void lboTwitte_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            lboTwitte.SelectedIndex = -1;
        }

        private void imgSearch_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            search();
        }

        #endregion

        #region Twitter

        private void search()
        {
            lblLoading.Visibility = Visibility.Visible;
            lboTwitte.Opacity = 0.3;

            Twitter twitter = new Twitter();
            twitter.twitteSearchCompleted += new EventHandler(twitter_downloadCompleted);
            twitter.search(txtSearch.Text);
        }

        private void twitter_downloadCompleted(object sender, EventArgs e)
        {
            List list = (List)sender;
            lboTwitte.ItemsSource = list;

            lblLoading.Visibility = Visibility.Collapsed;
            lboTwitte.Opacity = 1;
        }

        #endregion
    }
}

MonoTouch code:

namespace tweetsearchiphone
{
	public partial class MainPage : UIViewController
	{
		#region Constructors

		// The IntPtr and initWithCoder constructors are required for items that need
		// to be able to be created from a xib rather than from managed code

		public MainPage (IntPtr handle) : base(handle)
		{
			Initialize ();
		}

		[Export("initWithCoder:")]
		public MainPage (NSCoder coder) : base(coder)
		{
			Initialize ();
		}

		public MainPage () : base("MainPage", null)
		{
			Initialize ();
		}

		void Initialize ()
		{
		}

		#endregion

		#region UI

		public override void ViewDidLoad()
		{
			base.ViewDidLoad();

			lblTwitter.Text = "";
			txtSearch.ShouldReturn = delegate
			{
				txtSearch.ResignFirstResponder();
				search();

				return true;
			};

			imgSearch.TouchUpInside += HandleImgSearchTouchUpInside;
		}

		void HandleImgSearchTouchUpInside (object sender, EventArgs e)
		{
			search();
		}

		#endregion

		#region Twitter

		private void search()
		{
			Twitter twitter = new Twitter();
			twitter.twitteSearchCompleted += twitter_downloadCompleted;
			twitter.search(txtSearch.Text);
		}

		void twitter_downloadCompleted (object sender, EventArgs e)
		{
			List list = (List) sender;
			BeginInvokeOnMainThread (delegate {

				foreach(TwitterObject tweet in list)
				{
		        	lblTwitter.Text += tweet.Date.ToString() + Environment.NewLine + tweet.Title + Environment.NewLine + Environment.NewLine;
				}

		    });
		}

		#endregion
	}
}

MonoDroid code:

namespace tweet_search_android
{
	[Activity (Label = "tweet search", MainLauncher = true)]
	public class ButtonActivity : Activity
	{
        List list = new List();
        Android.Widget.Button btnSearch;
        TextView lblTwitter;
        EditText txtSearch;

        private List photo_ids = new List() { Resource.drawable.bird };

		protected override void OnCreate (Bundle bundle)
		{
			base.OnCreate (bundle);
            SetContentView(Resource.layout.main);

            ImageView btnSearch = FindViewById(Resource.id.btnSearch);
            btnSearch.SetImageResource(photo_ids[0]);
            btnSearch.Click += new EventHandler(btnSearch_Click);

            txtSearch = FindViewById(Resource.id.txtSearch);
            lblTwitter = FindViewById(Resource.id.lblTwitter);
		}

        void btnSearch_Click(object sender, EventArgs e)
        {
            if (list.Count == 0)
            {
                Twitter twitter = new Twitter();
                twitter.twitteSearchCompleted += new EventHandler(twitter_twitteSearchCompleted);
                twitter.search("nnug");
            }
            else
            {
                foreach (TwitterObject twitter in list)
                {
                    lblTwitter.Text += twitter.Date.ToString() + System.Environment.NewLine + twitter.Title + System.Environment.NewLine + System.Environment.NewLine;
                }

                list = new List();
            }
        }

        void twitter_twitteSearchCompleted(object sender, EventArgs e)
        {
            list = (List)sender;
        }
	}
}


WP7 – Silverlight på mobilen

Click here to find RTM-version of the source code.

Mix10 konferansen som Microsoft arrangerte i midten av mars var i år spekket med mange spennende  nyheter, deriblant RC versjon av Silverlight 4. Det som likevel fikk mest oppmerksomhet var Microsoft’s neste mobile os ‘Windows Phone 7 (WP7)’ hvor man utvikler applikasjoner i XNA og Silverlight. Helt siden versjon 2 av silverlight har utviklere etterlyst muligheten for å kjøre silverlight på bærbare enheter og med WP7 blir dette mulig. Nedenfor ser du et skjermbildet av hovedmenyen i WP7. Det nye os’et har fått masse kule effekter i brukergrensesnittet og Microsoft har utviklet ett eget gui-konsept, Metro, som det anbefales å følge når man utvikler applikasjoner for WP7.

For å gjøre det klart med en gang: silverlight-utvikling på WP7 er utrolig enkelt og morsomt. Dersom du har kodet litt silverlight fra før så er du produktiv fra starten av. Stort sett eneste forskjell fra vanlig silverlight-utvikling er at man benytter noen andre visual studio templates, samt at man får tilgang til noen nye api’er som f.eks. gps, accelerometer, kamera, osv. Når du utvikler har du tilgang til en wp7-emulator i visual studio som applikasjonene kjører i.

WP7 er forventet å bli lansert i 4 kvartal 2010 og kommer da med en applikasjons-butikk tilsvarende iPhone’s AppStore, så det blir muligheter for å tjene penger på WP7-applikasjonen. Jeg anbefaler derfor alle til å gå til http://developer.windowsphone.com og laste ned software og test ut silverlight mobilutvikling slik at vi alle er forberedt på WP7!

Jeg holdt et foredrag om mobil Silverlight-utvikling på NNUG Stavanger i april og anbefaler derfor de som er interessert i mer info om dette temaet til å lese powerpoint’en nedenfor.

.

myWeather
Nedenfor ser du en WP7 silverlight applikasjon for å displaye værvarsel på mobilen. Link til kildekoden finner du rett under bilden.

I forbindelse med foredraget hos NNUG Stavanger konverterte jeg en del kjente “gamle/vanlige” silverlight-applikasjoner, som jeg fant på ‘silverlight.net’, over til å kjøre på WP7. Konverteringsprosessen er utrolig enkelt og i hovedsak innebærer det å kopiere over koden i en nyopprettet WP7-solution i visual studio.

.

wp7clock

Nedenfor vises den opprinnelige applikasjonen i vanlig webbrowser-mode:

Her er en linken til den opprinnelige kildekoden:
http://www.silverlight.net/community/samples/silverlight-samples/silverlight-analogclock–enhancing-the-view

Her er en link til det nye WP7-prosjektet:

.

wp7coverflow

Nedenfor vises den opprinnelige applikasjonen i vanlig webbrowser-mode:

Her er en linken til den opprinnelige kildekoden:
http://www.silverlight.net/community/samples/silverlight-samples/collectionflow

Her er en link til det nye WP7-prosjektet:

.

wp7solitarie

Nedenfor vises den opprinnelige applikasjonen i vanlig webbrowser-mode:

Her er en linken til den opprinnelige kildekoden:
http://www.silverlight.net/community/samples/silverlight-samples/klondike-solitaire

Her er en link til det nye WP7-prosjektet:

.

PS: Til informasjon så er det nå også mulig å teste ut silverlight-utvikling på Nokia’s Symbian-plattform. Sjekk ut denne linken: http://www.silverlight.net/getstarted/devices/symbian.


Live Mesh/Live Framework

Live Framework er et rammeverk for å kommunisere med Microsoft’s Live tjenester, med hovedvekt på Live Services, som er en del av Windows Azure. Live Framework gjør det mulig å utvikle Silverlight applikasjoner som kan bli hosted på Desktop-webgrensesnittet inne i Live Mesh, samt offline på din lokale windows eller mac maskin. I powerpointen nedenfor kan du lese mer om Live Framework.

download_LiveFramework

Mesh Buddy er en veldig enkel Live Mesh applikasjon for å lage lister over personer med navn og epost og  lagrer denne informasjonen i Live Mesh.

LiveMaps - 3

Nedenfor finnes et kodeeksempel på hvordan man kan lagre informasjon som objekter til Live Mesh og hvordan disse data kan hentes tilbake igjen.
Live Mesh Buddy - kode1

download_MeshBuddy

Mesh Contacts er en enkel Live Mesh applikasjon som leser ut informasjon om dine Microsoft Messanger kontakter fra Live Mesh og presenterer dem i en liste . Løsningen henter også ut MSN-statusmelding til kontaktene dine og presenterer den sammen med annen kontaktinformasjon.

LiveMaps - 4

Nedenfor vises et kodeeksempel på hvordan kontaktinformasjonen kan hentes ut fra Live Mesh:
Live Mesh Contacts2 - kode1

download_MeshContacts