Files
myfriendsaround/main/MyFriendsAround.WP7/ViewModel/MainViewModel.cs
T
2011-04-04 09:47:17 +03:00

957 lines
28 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Device.Location;
using System.IO;
using System.Net;
using System.Security;
using System.ServiceModel.Channels;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Coding4Fun.Phone.Controls;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using GalaSoft.MvvmLight.Threading;
using Hammock;
using Hammock.Serialization;
using Microsoft.Phone;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Controls.Maps;
using Microsoft.Silverlight.Testing;
using MyFriendsAround.Common.Entities;
using MyFriendsAround.WP7.Service;
using MyFriendsAround.WP7.Utils;
using MyFriendsAround.WP7.ViewModel;
using MyFriendsAround.WP7.Views;
using NetworkDetection;
using Newtonsoft.Json;
using Microsoft.Phone.Tasks;
namespace MyFriendsAround.WP7.ViewModel
{
/// <summary>
/// This class contains properties that the main View can data bind to.
/// <para>
/// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
/// </para>
/// <para>
/// You can also use Blend to data bind with the tool's support.
/// </para>
/// <para>
/// See http://www.galasoft.ch/mvvm/getstarted
/// </para>
/// </summary>
public class MainViewModel : ViewModelBase
{
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel()
{
//
MainLoadCommand = new RelayCommand(() => MainLoad());
PublishLocationCommand = new RelayCommand(() => PublishLocationAction());
DisplayAboutCommand = new RelayCommand(() => DisplayAbout());
NavigateToSettingsCommand = new RelayCommand(() => NavigateToSettings());
RefreshFriendsCommand = new RelayCommand(() => RefreshFriends());
ShowAboutCommand = new RelayCommand(() => ShowAbout());
SaveMySettingsCommand = new RelayCommand(() => SaveMySettings());
CancelMySettingsCommand = new RelayCommand(() => CancelMySettings());
ChoosePhotoCommand = new RelayCommand(() => ChoosePhoto());
CropSaveCommand = new RelayCommand(() => CropSave());
CropCancelCommand = new RelayCommand(() => CropCancel());
MapViewChangedCommand = new RelayCommand<LocationRect>(boundRectangle => MapViewChanged(boundRectangle));
ShowMyLocationCommand = new RelayCommand(() => ShowMyLocation());
MapZoomInCommand = new RelayCommand(() => MapZoomIn());
MapZoomOutCommand = new RelayCommand(() => MapZoomOut());
if (IsInDesignMode)
{
// Code runs in Blend --> create design time data.
}
else
{
// Code runs "for real"
}
photoChooserTask = new PhotoChooserTask();
photoChooserTask.Completed += cameraTask_Completed;
//photoChooserTask.PixelHeight = 100;
//photoChooserTask.PixelWidth = 100;
photoChooserTask.ShowCamera = true;
//init GPS
InitGps();
}
private void MapZoomOut()
{
//
if(MapZoom<22)
{
MapZoom++;
}
}
private void MapZoomIn()
{
//
if (MapZoom >2 )
{
MapZoom--;
}
}
private void InitGps()
{
#if GPS_EMULATOR
_gpsWatcher = new GpsEmulatorClient.GeoCoordinateWatcher();
#else
_gpsWatcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High)
{
MovementThreshold = 10
};
#endif
_gpsWatcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged);
_gpsWatcher.StatusChanged += new EventHandler<GeoPositionStatusChangedEventArgs>(watcher_StatusChanged);
//
_gpsWatcher.Start();
}
void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
{
GpsStatus = e.Status;
}
void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
{
if (e.Position.Location != GeoCoordinate.Unknown)
{
GpsTimestamp = e.Position.Timestamp;
GpsLocation = e.Position.Location;
if (LastBoundRect.Intersects(new LocationRect(GpsLocation, .5, .5)))
{
ObservableCollection<PushPinModel> _mynewlocation = new ObservableCollection<PushPinModel>();
_mynewlocation.Add(new PushPinModel()
{
Location = GpsLocation,
PinUserName = "Me"
});
MyLocationPushPins = _mynewlocation;
}
else
{
MyLocationPushPins = new ObservableCollection<PushPinModel>();
}
}
System.Diagnostics.Debug.WriteLine("watcher_PositionChanged + " + DateTime.Now.Second);
}
#region Properties & Fields
private PhotoChooserTask photoChooserTask;
private IGeoPositionWatcher<GeoCoordinate> _gpsWatcher;
public string ApplicationTitle
{
get
{
return "MyFriendsAround";
}
}
#region PageTitles
public string PageName
{
get
{
return "Friends Map";
}
}
public string PageNameSettings
{
get
{
return "Settings";
}
}
public string PageNameCropping
{
get
{
return "Crop";
}
}
#endregion
/// <summary>
/// The <see cref="GpsLocation" /> property's name.
/// </summary>
public const string GpsLocationPropertyName = "GpsLocation";
private GeoCoordinate _gpsLocation = GeoCoordinate.Unknown;
/// <summary>
/// Gets the GpsLocation property.
/// </summary>
public GeoCoordinate GpsLocation
{
get
{
return _gpsLocation;
}
set
{
if (_gpsLocation == value)
{
return;
}
_gpsLocation = value;
// Update bindings, no broadcast
RaisePropertyChanged(GpsLocationPropertyName);
}
}
/// <summary>
/// The <see cref="GpsTimestamp" /> property's name.
/// </summary>
public const string GpsTimestampPropertyName = "GpsTimestamp";
private DateTimeOffset _gpsTimestamp = DateTimeOffset.MinValue;
/// <summary>
/// Gets the GpsTimestamp property.
/// </summary>
public DateTimeOffset GpsTimestamp
{
get
{
return _gpsTimestamp;
}
set
{
if (_gpsTimestamp == value)
{
return;
}
_gpsTimestamp = value;
// Update bindings, no broadcast
RaisePropertyChanged(GpsTimestampPropertyName);
}
}
/// <summary>
/// The <see cref="GpsStatus" /> property's name.
/// </summary>
public const string GpsStatusPropertyName = "GpsStatus";
private GeoPositionStatus _gpsStatus = GeoPositionStatus.Disabled;
/// <summary>
/// Gets the GpsStatus property.
/// </summary>
public GeoPositionStatus GpsStatus
{
get
{
return _gpsStatus;
}
set
{
if (_gpsStatus == value)
{
return;
}
_gpsStatus = value;
// Update bindings, no broadcast
RaisePropertyChanged(GpsStatusPropertyName);
}
}
/// <summary>
/// The <see cref="MyPicture" /> property's name.
/// </summary>
public const string MyPicturePropertyName = "MyPicture";
private ImageSource _myPicture = new BitmapImage(new Uri("/icons/anonymousIcon.png", UriKind.RelativeOrAbsolute));
/// <summary>
/// Gets the MyPicture property.
/// </summary>
public ImageSource MyPicture
{
get
{
return _myPicture;
}
set
{
if (_myPicture == value)
{
return;
}
_myPicture = value;
// Update bindings, no broadcast
RaisePropertyChanged(MyPicturePropertyName);
}
}
/// <summary>
/// The <see cref="MyName" /> property's name.
/// </summary>
public const string MyNamePropertyName = "MyName";
private string _myName = "Guest";
/// <summary>
/// Gets the MyName property.
/// </summary>
public string MyName
{
get { return _myName; }
set
{
if (_myName == value)
{
return;
}
var oldValue = _myName;
_myName = value;
// Update bindings, no broadcast
RaisePropertyChanged(MyNamePropertyName);
}
}
public string AppBarTextAbout
{
get { return "About"; }
}
public string AppBarTextSettings
{
get { return "Settings"; }
}
public string AppBarTextPublish
{
get { return "Publish"; }
}
public string AppBarTextRefresh
{
get { return "Refresh"; }
}
public string AppBarTextMyLocation
{
get { return "My Location"; }
}
public string AppBarTextSaveSettings
{
get { return "Save"; }
}
public string AppBarTextCancelSettings
{
get { return "Cancel"; }
}
/// <summary>
/// The <see cref="PushPins" /> property's name.
/// </summary>
public const string PushPinsPropertyName = "PushPins";
private ObservableCollection<PushPinModel> _PushPins = new ObservableCollection<PushPinModel>();
/// <summary>
/// Gets the PushPins property.
/// </summary>
public ObservableCollection<PushPinModel> PushPins
{
get
{
return _PushPins;
}
set
{
if (_PushPins == value)
{
return;
}
_PushPins = value;
// Update bindings, no broadcast
RaisePropertyChanged(PushPinsPropertyName);
}
}
/// <summary>
/// The <see cref="VisiblePushPins" /> property's name.
/// </summary>
public const string VisiblePushPinsPropertyName = "VisiblePushPins";
private ObservableCollection<PushPinModel> _VisiblePushPins = new ObservableCollection<PushPinModel>();
/// <summary>
/// Gets the VisiblePushPins property.
/// </summary>
public ObservableCollection<PushPinModel> VisiblePushPins
{
get
{
return _VisiblePushPins;
}
set
{
if (_VisiblePushPins == value)
{
return;
}
_VisiblePushPins = value;
// Update bindings, no broadcast
RaisePropertyChanged(VisiblePushPinsPropertyName);
}
}
/// <summary>
/// The <see cref="MyLocationPushPins" /> property's name.
/// </summary>
public const string MyLocationPushPinsPropertyName = "MyLocationPushPins";
private ObservableCollection<PushPinModel> _MyLocationPushPins = new ObservableCollection<PushPinModel>();
/// <summary>
/// Gets the MyLocationPushPins property.
/// </summary>
public ObservableCollection<PushPinModel> MyLocationPushPins
{
get
{
return _MyLocationPushPins;
}
set
{
if (_MyLocationPushPins == value)
{
return;
}
_MyLocationPushPins = value;
// Update bindings, no broadcast
RaisePropertyChanged(MyLocationPushPinsPropertyName);
}
}
/// <summary>
/// The <see cref="MapZoom" /> property's name.
/// </summary>
public const string MapZoomPropertyName = "MapZoom";
private int _mapZoom = 1;
/// <summary>
/// Gets the MapZoom property.
/// </summary>
public int MapZoom
{
get
{
return _mapZoom;
}
set
{
if (_mapZoom == value)
{
return;
}
_mapZoom = value;
// Update bindings, no broadcast
RaisePropertyChanged(MapZoomPropertyName);
}
}
/// <summary>
/// The <see cref="IsBusy" /> property's name.
/// </summary>
public const string IsBusyPropertyName = "IsBusy";
private bool _isBusy = false;
/// <summary>
/// Gets the IsBusy property.
/// </summary>
public bool IsBusy
{
get
{
return _isBusy;
}
set
{
if (_isBusy == value)
{
return;
}
var oldValue = _isBusy;
_isBusy = value;
// Update bindings, no broadcast
RaisePropertyChanged(IsBusyPropertyName);
}
}
/// <summary>
/// The <see cref="MapCenter" /> property's name.
/// </summary>
public const string MapCenterPropertyName = "MapCenter";
private GeoCoordinate _mapCenter = null;
/// <summary>
/// Gets the MapCenter property.
/// </summary>
public GeoCoordinate MapCenter
{
get
{
return _mapCenter;
}
set
{
if (_mapCenter == value)
{
return;
}
var oldValue = _mapCenter;
_mapCenter = value;
// Update bindings, no broadcast
RaisePropertyChanged(MapCenterPropertyName);
}
}
#endregion
#region Commands
public ICommand MainLoadCommand { get; set; }
public ICommand PublishLocationCommand { get; set; }
public ICommand DisplayAboutCommand { get; set; }
public ICommand NavigateToSettingsCommand { get; set; }
public ICommand ShowMyLocationCommand { get; set; }
public ICommand RefreshFriendsCommand { get; set; }
public ICommand ShowAboutCommand { get; set; }
public ICommand SaveMySettingsCommand { get; set; }
public ICommand CancelMySettingsCommand { get; set; }
public ICommand ChoosePhotoCommand { get; set; }
public ICommand CropSaveCommand { get; set; }
public ICommand CropCancelCommand { get; set; }
public ICommand MapViewChangedCommand { get; set; }
public ICommand MapZoomInCommand { get; set; }
public ICommand MapZoomOutCommand { get; set; }
#endregion
#region Implemented Commands & Methods
private void ShowMyLocation()
{
//
if (GpsLocation != GeoCoordinate.Unknown &&
GpsStatus == GeoPositionStatus.Ready
)
{
MapCenter = GpsLocation;
}
}
private LocationRect LastBoundRect = null;
private void MapViewChanged(LocationRect boundRectangle)
{
LastBoundRect = boundRectangle;
//
ObservableCollection<PushPinModel> _newVisiblePushPins = new ObservableCollection<PushPinModel>();
//filter visible pushpins
foreach (PushPinModel pushPin in PushPins)
{
if (LastBoundRect.Intersects(new LocationRect(pushPin.Location, .5, .5)))
{
_newVisiblePushPins.Add(pushPin);
}
}
VisiblePushPins = _newVisiblePushPins;
//
if (!LastBoundRect.Intersects(new LocationRect(GpsLocation, .5, .5)))
{
MyLocationPushPins = new ObservableCollection<PushPinModel>();
}
}
public void CropCancel()
{
//
this.PageNav.GoBack();
}
public void CropSave()
{
//
}
private void MainLoad()
{
if (IsLoaded)
{
//
ThreadPool.QueueUserWorkItem(LoadMyPicture);
//
IsLoaded = false;
}
}
private void LoadMyPicture(object param) //Background thread
{
Thread.Sleep(500);
byte[] img = IsolatedStorageHelper.LoadFromLocalStorageArray("myphoto.jpg", "profiles");
if (img != null)
{
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
using (MemoryStream ms = new MemoryStream(img))
{
BitmapImage bi = new BitmapImage();
bi.SetSource(ms);
Container.Instance.Resolve<MainViewModel>("MainViewModel").MyPicture = bi;// PictureDecoder.DecodeJpeg(ms);
}
});
}
else
{
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
Container.Instance.Resolve<MainViewModel>("MainViewModel").MyPicture = new BitmapImage(new Uri("/icons/anonymousIcon.png", UriKind.RelativeOrAbsolute));
});
}
}
private void ChoosePhoto()
{
//choose photo
//ShowCameraCaptureTask();
//ShowPhotoChooserTask();
if (!NetworkDetector.Instance.GetZuneStatus())
{
this.PageNav.NavigateTo(new Uri("/Views/CropPage.xaml", UriKind.RelativeOrAbsolute));
}
else
{
MessageBox.Show("Please disconnect from Zune!");
}
}
private void ShowPhotoChooserTask()
{
photoChooserTask.Show();
}
private void ShowCameraCaptureTask()
{
var cameraTask = new CameraCaptureTask();
cameraTask.Completed += cameraTask_Completed;
cameraTask.Show();
}
private void cameraTask_Completed(object sender, PhotoResult e)
{
if (e.ChosenPhoto != null && e.ChosenPhoto.Length > 0) // e.TaskResult == TaskResult.OK)
{
// Get the image temp file from e.OriginalFileName.
// Get the image temp stream from e.ChosenPhoto.
// Don't keep either the stream or rely on the temp
// file name as they may be vanished!
// Store the image bytes.
byte[] _imageBytes = new byte[e.ChosenPhoto.Length];
e.ChosenPhoto.Read(_imageBytes, 0, _imageBytes.Length);
//save
IsolatedStorageHelper.SaveToLocalStorage("myphoto.jpg", "profiles", _imageBytes);
// Seek back so we can create an image.
e.ChosenPhoto.Seek(0, SeekOrigin.Begin);
// Create an image from the stream.
//var imageSource = PictureDecoder.DecodeJpeg(e.ChosenPhoto);
BitmapImage bi = new BitmapImage();
bi.SetSource(e.ChosenPhoto);
MyPicture = bi;// imageSource;
}
}
private void CancelMySettings()
{
//navigate back
this.PageNav.GoBack();
}
private void SaveMySettings()
{
//save settings locally and on the server
}
private void ShowAbout()
{
//
var aboutPrompt = new AboutPrompt();
aboutPrompt.Title = "About";
aboutPrompt.Body = Environment.NewLine + "Created by Claudiu Farcas" + Environment.NewLine + Environment.NewLine + "@claudiufarcas" + Environment.NewLine + Environment.NewLine + "Please visit" + Environment.NewLine + Environment.NewLine + "http://www.vorienteering.com";
aboutPrompt.VersionNumber = "1.0";
aboutPrompt.Show();
}
private void RefreshFriends()
{
IsBusy = true;
ServiceAgent.GetFriends(this.GetFriendsResult);
}
private void NavigateToSettings()
{
//
this.PageNav.NavigateTo(new Uri("/Views/SettingsPage.xaml", UriKind.Relative));
}
private void DisplayAbout()
{
MessageBox.Show("About");
}
private void PopulatePushPins(List<Friend> list)
{
ObservableCollection<PushPinModel> result = new ObservableCollection<PushPinModel>();
list.ForEach((f) =>
{
//f.LocationStr
result.Add(new PushPinModel()
{
PinSource = "/ApplicationIcon.png",
Location = new GeoCoordinate(f.Latitude, f.Longitude),
PinUserName = f.FriendName,
PinImageUrl = string.Format("https://myfriendsaround.blob.core.windows.net/profiles/profile_{0}.jpg", f.Id)
});
});
PushPins = result;
}
private void PublishLocationAction()
{
if (GpsLocation != GeoCoordinate.Unknown)
{
Friend myInfo = new Friend();
myInfo.Id = Identification.GetDeviceId();
myInfo.FriendName = MyName;
myInfo.LastUpdated = DateTime.UtcNow;
myInfo.LocationStr = string.Format("POINT({0} {1})", GpsLocation.Latitude, GpsLocation.Longitude);
IsBusy = true;
ServiceAgent.PublishLocation(myInfo, new EventHandler<PublishLocationEventArgs>(PublishLocationResult));
}
else
{
MessageBox.Show("GPS position not aquired yet!");
}
}
public void GetFriendsResult(object sender, FriendsListEventArgs args)
{
if (args.Error == null)
{
List<Friend> list = args.Friends;
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
PopulatePushPins(list);
IsBusy = false;
}
);
}
else
{
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
IsBusy = false;
var exception = new ExceptionPrompt();
exception.Show(args.Error);
}
);
}
}
public void PublishLocationResult(object sender, PublishLocationEventArgs args)
{
if (args.Error != null)
{
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
IsBusy = false;
var exception = new ExceptionPrompt();
exception.Show(args.Error);
});
}
else
{
if (!args.IsSuccess)
{
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
var message = new DialogMessage(
"Communication error!", DialogMessageCallback)
{
Button = MessageBoxButton.OK,
Caption = "Error!"
};
Messenger.Default.Send(message);
});
}
else
{
//update also the picture
byte[] img = IsolatedStorageHelper.LoadFromLocalStorageArray("myphoto.jpg", "profiles");
if (img != null)
{
ServiceAgent.PublishMyPicture(Identification.GetDeviceId(), img, new EventHandler<PublishLocationEventArgs>(PublishMyPictureResult));
}
else
{
//update friends list
ServiceAgent.GetFriends(this.GetFriendsResult);
}
}
}
}
public void PublishMyPictureResult(object sender, PublishLocationEventArgs args)
{
//
if (args.Error != null)
{
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
IsBusy = false;
var exception = new ExceptionPrompt();
exception.Show(args.Error);
});
}
else
{
if (!args.IsSuccess)
{
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
var message = new DialogMessage(
"Communication error!", DialogMessageCallback)
{
Button = MessageBoxButton.OK,
Caption = "Error!"
};
Messenger.Default.Send(message);
});
}
else
{
//update friends list
ServiceAgent.GetFriends(this.GetFriendsResult);
}
}
}
private void DialogMessageCallback(MessageBoxResult result)
{
if (result == MessageBoxResult.OK)
{
//Message = "Continue";
}
else
{
//Message = "Stop";
}
}
public override void Cleanup()
{
// Clean up if needed
base.Cleanup();
_gpsWatcher.Stop();
}
#endregion
}
}