using System; using System.Collections.ObjectModel; using System.Device.Location; using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Windows; using System.Windows.Media.Imaging; using MahTweets.Mobile.Core; using MahTweets.Mobile.Core.Extensions; using MahTweets.Mobile.Core.Interfaces; using MahTweets.Mobile.Core.Repositories; using MahTweets.Mobile.Core.Services; using MahTweets.Mobile.TwitterPlugin.Models; using Microsoft.Phone.Tasks; using Microsoft.Xna.Framework.Media; namespace MahTweets.Mobile.ViewModels { public class CompositionViewModel : MahViewModelBase { private readonly IStatusUpdatesManager _statusUpdates; private readonly INavigationService _navigationService; private readonly ILocationService _locationService; private readonly ContactRepository _contactRepository; private readonly Func _uploaderFactory; private string _id = string.Empty; private string _text = string.Empty; private readonly AccountRepository _accounts; private readonly ThreadSafeObservableCollection _selectedAccounts = new ThreadSafeObservableCollection(); private readonly ThreadSafeObservableCollection _usernameSuggestions = new ThreadSafeObservableCollection(); private readonly UrlShortenerRepository _urlShortenerRepository; private bool _geotagEnabled; private string _locationStatus; private GeoCoordinate _location; private bool _findingLocation; private bool _usernameSuggestionAvailable; private readonly IApplicationSettings _applicationSettings; private readonly ThreadSafeObservableCollection _statusManagers; public CompositionViewModel( INavigationService navigationService, ILocationService locationService, IStatusUpdatesManager statusUpdatesManager, AccountRepository accountRepository, ContactRepository contactRepository, UrlShortenerRepository urlShortenerRepository, Func uploader, ThreadSafeObservableCollection statusManagers, IApplicationSettings applicationSettings) { _statusManagers = statusManagers; _applicationSettings = applicationSettings; _urlShortenerRepository = urlShortenerRepository; _accounts = accountRepository; _navigationService = navigationService; _locationService = locationService; _statusUpdates = statusUpdatesManager; _contactRepository = contactRepository; _uploaderFactory = uploader; foreach (var account in _accounts) { _selectedAccounts.Add(account); } Drafts = new ObservableCollection(); ID = null; Text = String.Empty; var drafts = Settings.GetDrafts(); foreach (var d in drafts) Drafts.Add(d); } public void RemoveDraft(string text) { Drafts.Remove(text); Settings.GetDrafts().Remove(text); } public void SaveDraft(string text) { Drafts.Add(text); Settings.StoreDraft(text); } public void Initialise() { if (ContactReplyingTo != null) { if (Mode == "All") { var additionalContacts = ""; var words = InReplyToUpdate.Text.Split(' '); foreach (var w in words) if (w.StartsWith("@")) { additionalContacts += " "+w; } additionalContacts = InReplyToUpdate.Parents.Aggregate(additionalContacts, (current, p) => current.Replace(" @" + p.OwnerName, "")); Text = string.Format("@{0}{1}", ContactReplyingTo.Name, additionalContacts); } else Text = string.Format("@{0} ", ContactReplyingTo.Name); } } public String Mode { get; set; } public string ID { get { return _id; } set { _id = value; RaisePropertyChanged(() => ID); } } private IStatusUpdate _update = null; public IStatusUpdate InReplyToUpdate { get { if (_id == null) return null; foreach (var s in _statusManagers) { var update = s.Collection.Where(u => u.ID == ID).FirstOrDefault(); if (update == null) continue; _update = update; break; } return _update; } } public Contact ContactReplyingTo { get { return InReplyToUpdate != null ? InReplyToUpdate.Contact : null; } } public string Text { get { return _text; } set { _text = value; RaisePropertyChanged(() => Text); } } public ObservableCollection Drafts { get; set; } public ThreadSafeObservableCollection Accounts { get { return _accounts; } } public ThreadSafeObservableCollection SelectedAccounts { get { return _selectedAccounts; } } public void SendStatusUpdate(String text) { if (IsBusy) return; foreach (var c in SelectedAccounts) { c.NewStatusUpdate(text, ID, Location); } ID = string.Empty; Text = string.Empty; GeotagEnabled = false; _navigationService.GoBack(); } public string LocationStatus { get { return _locationStatus; } private set { _locationStatus = value; RaisePropertyChanged(() => LocationStatus); } } public bool GeotagEnabled { get { return _geotagEnabled; } set { _geotagEnabled = value; Location = null; LocationStatus = string.Empty; if (_geotagEnabled && !_findingLocation) { _findingLocation = true; AddWork(_locationService.BeginGetLocation, _locationService.EndGetLocation) .WhenComplete(c => { if ((c.Error != null && c.Error.GetType() == typeof(NoLocationDataException)) || c.Result == null) { LocationStatus = "Unable to find location"; GeotagEnabled = false; } else { Location = c.Result; LocationStatus = "Located"; } _findingLocation = false; }) .PerformWork(); } RaisePropertyChanged(() => GeotagEnabled); } } public GeoCoordinate Location { get { return _location; } set { _location = value; RaisePropertyChanged(() => Location); } } public void CaptureCameraImage() { var cam = new PhotoChooserTask { ShowCamera = true }; cam.Completed += OnCameraCaptureCompleted; cam.Show(); } private void OnCameraCaptureCompleted(object sender, PhotoResult e) { if (e.TaskResult != TaskResult.OK) return; var uploader = _uploaderFactory(); AddWork(uploader.BeginUpload, e.ChosenPhoto, uploader.EndUpload) .WhenComplete(c => Text += c.Result) .PerformWork(); } public void SharePhoto(string fileId) { var library = new MediaLibrary(); Picture pic = library.GetPictureFromToken(fileId); Stream shareStream; if ((pic.Width > 640 && pic.Height > 480) && MessageBox.Show(string.Format("Image is {0}x{1}. Press OK to resize to 640x480?", pic.Width, pic.Height), "Resize Image?", MessageBoxButton.OKCancel) == MessageBoxResult.OK) { var bmp = new BitmapImage(); bmp.SetSource(pic.GetImage()); var writeable = new WriteableBitmap(bmp); shareStream = new MemoryStream(); writeable.SaveJpeg(shareStream, 640, 480, 0, 100); shareStream.Seek(0, SeekOrigin.Begin); } else { shareStream = pic.GetImage(); } if (shareStream == null) return; var uploader = _uploaderFactory(); AddWork(uploader.BeginUpload, shareStream, uploader.EndUpload) .WhenComplete(c => Text += c.Result) .WhenComplete( c => { pic.Dispose(); library.Dispose(); shareStream.Close(); }) .PerformWork(); } public bool UserNameSuggestionAvailable { get { return _usernameSuggestionAvailable; } set { _usernameSuggestionAvailable = value; RaisePropertyChanged(() => UserNameSuggestionAvailable); } } public ThreadSafeObservableCollection UsernameSuggestions { get { return _usernameSuggestions; } } public void UpdateUsernameSuggestion(int selectionStart, int selectionLength, string text) { UsernameSuggestions.Clear(); UserNameSuggestionAvailable = false; string selectedText; if (selectionLength == 0) { var startIndexOfUsername = selectionStart == 0 ? -1 : text.LastIndexOf(' ', selectionStart - 1); selectedText = startIndexOfUsername == -1 ? text.Trim() : text.Substring(startIndexOfUsername, selectionStart - startIndexOfUsername).Trim(); } else return; if (string.IsNullOrEmpty(selectedText) || selectedText[0] != '@') return; var userName = selectedText.Substring(1); if (ContactReplyingTo != null && userName == ContactReplyingTo.Name) return; foreach (var contact in _contactRepository .Where(c => c.Name.IndexOf(userName, StringComparison.CurrentCultureIgnoreCase) != -1) .Select(c => c.Name) .Distinct() .OrderBy(n => n) .Take(10)) { UsernameSuggestions.Add(string.Format("@{0}", contact)); } UserNameSuggestionAvailable = UsernameSuggestions.Count > 0; } public int SelectUsername(string suggestedUsername, int selectionStart, int selectionLength) { UsernameSuggestions.Clear(); UserNameSuggestionAvailable = false; if (selectionLength == 0) { var startIndexOfUsername = selectionStart == 0 ? -1 : Text.LastIndexOf(' ', selectionStart - 1); //First word is a username if (startIndexOfUsername == -1) { Text = suggestedUsername + " "; return Text.Length; } Text = string.Format("{0}{1} {2}", Text.Substring(0, startIndexOfUsername + 1), suggestedUsername, Text.Substring(selectionStart)); return selectionStart + suggestedUsername.Length; } return selectionStart; } public void ShortenUrls() { var urlShortenerName = _applicationSettings.UrlShortener; var urlShortener = _urlShortenerRepository.Where(u => u.Name == (string) urlShortenerName).FirstOrDefault(); if (urlShortener != null) { var links = Text.GetHyperlinks(); foreach (Match l in links) { Match l1 = l; urlShortener.Shorten(l.Value, (newUrl) => { Text= Text.Replace(l1.Value, newUrl); GlobalDispatcher.Dispatcher.BeginInvoke(() => RaisePropertyChanged(() => Text)); }); } } } } }