add openhack files

This commit is contained in:
Ryan Peters
2022-11-03 16:41:13 -04:00
commit b2c9f7e29f
920 changed files with 118861 additions and 0 deletions

View File

@ -0,0 +1,39 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
using Foundation;
using System;
using UIKit;
namespace MyDriving.iOS
{
public partial class GettingStartedContentViewController : UIViewController
{
public UIImage Image { get; set; }
public int PageIndex { get; set; }
public GettingStartedContentViewController (IntPtr handle) : base (handle)
{
}
public static GettingStartedContentViewController ControllerForPageIndex(int pageIndex)
{
var imagePath = string.Format($"screen_{pageIndex+1}.png");
var image = UIImage.FromBundle(imagePath);
var page = (GettingStartedContentViewController)UIStoryboard.FromName("Main", null).InstantiateViewController("gettingStartedContentViewController");
page.Image = image;
page.PageIndex = pageIndex;
return page;
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
View.BackgroundColor = UIColor.FromPatternImage(UIImage.FromBundle("background_started.png"));
imageView.Image = Image;
}
}
}

View File

@ -0,0 +1,29 @@
// WARNING
//
// This file has been generated automatically by Visual Studio from the outlets and
// actions declared in your storyboard file.
// Manual changes to this file will not be maintained.
//
using Foundation;
using System;
using System.CodeDom.Compiler;
using UIKit;
namespace MyDriving.iOS
{
[Register ("GettingStartedContentViewController")]
partial class GettingStartedContentViewController
{
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIImageView imageView { get; set; }
void ReleaseDesignerOutlets ()
{
if (imageView != null) {
imageView.Dispose ();
imageView = null;
}
}
}
}

View File

@ -0,0 +1,71 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
using Foundation;
using System;
using UIKit;
namespace MyDriving.iOS
{
public partial class GettingStartedViewController : UIPageViewController
{
GettingStartedContentViewController pageOne = (GettingStartedContentViewController)UIStoryboard.FromName("Main", null).InstantiateViewController("gettingStartedContentViewController");
public GettingStartedViewController (IntPtr handle) : base (handle)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
AutomaticallyAdjustsScrollViewInsets = false;
//self.automaticallyAdjustsScrollViewInsets = false;
Title = "MyDriving";
NavigationItem.SetRightBarButtonItem(new UIBarButtonItem("Dismiss", UIBarButtonItemStyle.Plain, (sender, e) =>
{
var viewController = UIStoryboard.FromName("Main", null).InstantiateViewController("loginViewController");
var appDelegate = (AppDelegate)UIApplication.SharedApplication.Delegate;
appDelegate.Window.RootViewController = viewController;
}), false);
pageOne.PageIndex = 0;
pageOne.Image = UIImage.FromBundle("screen_1.png");
SetViewControllers(new UIViewController[] { pageOne }, UIPageViewControllerNavigationDirection.Forward, true, null);
DataSource = new PageViewControllerSource();
}
public class PageViewControllerSource : UIPageViewControllerDataSource
{
public override nint GetPresentationCount(UIPageViewController pageViewController)
{
return 5;
}
public override UIViewController GetPreviousViewController(UIPageViewController pageViewController, UIViewController referenceViewController)
{
var vc = (GettingStartedContentViewController)referenceViewController;
var index = vc.PageIndex;
if (index == 0)
return null;
return GettingStartedContentViewController.ControllerForPageIndex(index-1);
}
public override UIViewController GetNextViewController(UIPageViewController pageViewController, UIViewController referenceViewController)
{
var vc = (GettingStartedContentViewController)referenceViewController;
var index = vc.PageIndex;
if (index == 4)
return null;
return GettingStartedContentViewController.ControllerForPageIndex(index+1);
}
}
}
}

View File

@ -0,0 +1,21 @@
// WARNING
//
// This file has been generated automatically by Visual Studio from the outlets and
// actions declared in your storyboard file.
// Manual changes to this file will not be maintained.
//
using Foundation;
using System;
using System.CodeDom.Compiler;
using UIKit;
namespace MyDriving.iOS
{
[Register ("GettingStartedViewController")]
partial class GettingStartedViewController
{
void ReleaseDesignerOutlets ()
{
}
}
}

View File

@ -0,0 +1,112 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
using MyDriving.Utils;
using MyDriving.ViewModel;
using System;
using System.Threading.Tasks;
using UIKit;
namespace MyDriving.iOS
{
partial class LoginViewController : UIViewController
{
bool didAnimate;
LoginViewModel viewModel;
public LoginViewController(IntPtr handle) : base(handle)
{
}
public override void ViewDidLoad()
{
viewModel = new LoginViewModel();
//Prepare buttons for fade in animation.
btnFacebook.Alpha = 0;
btnTwitter.Alpha = 0;
btnMicrosoft.Alpha = 0;
btnSkipAuth.Alpha = 0;
btnSkipAuth.Layer.CornerRadius = 4;
btnSkipAuth.Layer.MasksToBounds = true;
#if DEBUG || XTC
btnSkipAuth.Hidden = false;
#else
btnSkipAuth.Hidden = true;
#endif
}
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
if (didAnimate)
return;
didAnimate = true;
btnFacebook.FadeIn(0.3, 0.3f);
btnTwitter.FadeIn(0.3, 0.5f);
btnMicrosoft.FadeIn(0.3, 0.7f);
btnSkipAuth.FadeIn(0.3, 0.9f);
}
async partial void BtnFacebook_TouchUpInside(UIButton sender)
{
await LoginAsync(LoginAccount.Facebook);
}
async partial void BtnTwitter_TouchUpInside(UIButton sender)
{
await LoginAsync(LoginAccount.Twitter);
}
async partial void BtnMicrosoft_TouchUpInside(UIButton sender)
{
await LoginAsync(LoginAccount.Microsoft);
}
async Task LoginAsync(LoginAccount account)
{
switch (account)
{
case LoginAccount.Facebook:
await viewModel.ExecuteLoginFacebookCommandAsync();
break;
case LoginAccount.Microsoft:
await viewModel.ExecuteLoginMicrosoftCommandAsync();
break;
case LoginAccount.Twitter:
await viewModel.ExecuteLoginTwitterCommandAsync();
break;
}
if (viewModel.IsLoggedIn)
{
//When the first screen of the app is launched after user has logged in, initialize the processor that manages connection to OBD Device and to the IOT Hub
Services.OBDDataProcessor.GetProcessor().Initialize(ViewModel.ViewModelBase.StoreManager);
NavigateToTabs();
}
}
partial void BtnSkipAuth_TouchUpInside(UIButton sender)
{
viewModel.InitFakeUser();
NavigateToTabs();
}
void NavigateToTabs()
{
InvokeOnMainThread(() =>
{
var app = (AppDelegate) UIApplication.SharedApplication.Delegate;
var viewController =
UIStoryboard.FromName("Main", null).InstantiateViewController("tabBarController") as
UITabBarController;
viewController.SelectedIndex = 1;
app.Window.RootViewController = viewController;
});
}
}
}

View File

@ -0,0 +1,81 @@
// WARNING
//
// This file has been generated automatically by Visual Studio from the outlets and
// actions declared in your storyboard file.
// Manual changes to this file will not be maintained.
//
using Foundation;
using System;
using System.CodeDom.Compiler;
using UIKit;
namespace MyDriving.iOS
{
[Register ("LoginViewController")]
partial class LoginViewController
{
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIButton btnFacebook { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIButton btnMicrosoft { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIButton btnSkipAuth { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIButton btnTwitter { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIImageView imgLogo { get; set; }
[Action ("BtnFacebook_TouchUpInside:")]
[GeneratedCode ("iOS Designer", "1.0")]
partial void BtnFacebook_TouchUpInside (UIKit.UIButton sender);
[Action ("BtnMicrosoft_TouchUpInside:")]
[GeneratedCode ("iOS Designer", "1.0")]
partial void BtnMicrosoft_TouchUpInside (UIKit.UIButton sender);
[Action ("BtnSkipAuth_TouchUpInside:")]
[GeneratedCode ("iOS Designer", "1.0")]
partial void BtnSkipAuth_TouchUpInside (UIKit.UIButton sender);
[Action ("BtnTwitter_TouchUpInside:")]
[GeneratedCode ("iOS Designer", "1.0")]
partial void BtnTwitter_TouchUpInside (UIKit.UIButton sender);
void ReleaseDesignerOutlets ()
{
if (btnFacebook != null) {
btnFacebook.Dispose ();
btnFacebook = null;
}
if (btnMicrosoft != null) {
btnMicrosoft.Dispose ();
btnMicrosoft = null;
}
if (btnSkipAuth != null) {
btnSkipAuth.Dispose ();
btnSkipAuth = null;
}
if (btnTwitter != null) {
btnTwitter.Dispose ();
btnTwitter = null;
}
if (imgLogo != null) {
imgLogo.Dispose ();
imgLogo = null;
}
}
}
}

View File

@ -0,0 +1,91 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
using Foundation;
using System.Collections.Generic;
using UIKit;
using System;
using MyDriving.ViewModel;
using SDWebImage;
using System.Threading.Tasks;
namespace MyDriving.iOS
{
public partial class ProfileTableViewController : UITableViewController
{
const string StatCellIdentifier = "STAT_CELL_IDENTIFIER";
List<DrivingStatistic> data;
public ProfileTableViewController(IntPtr handle) : base(handle)
{
}
public ProfileViewModel ViewModel { get; set; }
public override void ViewDidLoad()
{
base.ViewDidLoad();
ViewModel = new ProfileViewModel();
NavigationItem.Title = $"{ViewModel.Settings.UserFirstName} {ViewModel.Settings.UserLastName}";
var url = ViewModel.Settings.UserProfileUrl;
imgAvatar.SetImage(new NSUrl(url));
imgAvatar.Layer.CornerRadius = imgAvatar.Frame.Width/2;
imgAvatar.Layer.BorderWidth = 2;
imgAvatar.Layer.BorderColor = "15A9FE".ToUIColor().CGColor;
imgAvatar.Layer.MasksToBounds = true;
UpdateUI();
}
public override async void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
await ViewModel.UpdateProfileAsync()
.ContinueWith(t => { UpdateUI(); }, scheduler: TaskScheduler.FromCurrentSynchronizationContext());
}
void UpdateUI()
{
lblDrivingSkills.Text = $"Driving Skills: {ViewModel.DrivingSkillsPlacementBucket.Description}";
lblScore.Text = $"Score: {ViewModel.DrivingSkills}%";
PercentageView.Value = (ViewModel.DrivingSkills/100f)*360f;
data = new List<DrivingStatistic>
{
new DrivingStatistic {Name = "Total Distance", Value = ViewModel.TotalDistanceDisplay},
new DrivingStatistic {Name = "Total Duration", Value = ViewModel.TotalTimeDisplay},
new DrivingStatistic {Name = "Max Speed", Value = ViewModel.MaxSpeedDisplay},
new DrivingStatistic {Name = "Fuel Consumption", Value = ViewModel.FuelDisplay},
new DrivingStatistic {Name = "Hard Stops", Value = ViewModel.HardStops.ToString()},
new DrivingStatistic {Name = "Hard Accelerations", Value = ViewModel.HardAccelerations.ToString()},
new DrivingStatistic {Name = "Total Trips", Value = ViewModel.TotalTrips.ToString()},
};
TableView.ReloadData();
}
#region UITableViewSource
public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{
return 60;
}
public override nint RowsInSection(UITableView tableView, nint section)
{
return (data?.Count).GetValueOrDefault();
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell(StatCellIdentifier) as ProfileStatCell;
cell.Name = data[indexPath.Row].Name;
cell.Value = data[indexPath.Row].Value;
return cell;
}
#endregion
}
}

View File

@ -0,0 +1,56 @@
// WARNING
//
// This file has been generated automatically by Visual Studio from the outlets and
// actions declared in your storyboard file.
// Manual changes to this file will not be maintained.
//
using Foundation;
using System;
using System.CodeDom.Compiler;
using UIKit;
namespace MyDriving.iOS
{
[Register ("ProfileTableViewController")]
partial class ProfileTableViewController
{
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIImageView imgAvatar { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UILabel lblDrivingSkills { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UILabel lblScore { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
MyDriving.iOS.CustomControls.CirclePercentage PercentageView { get; set; }
void ReleaseDesignerOutlets ()
{
if (imgAvatar != null) {
imgAvatar.Dispose ();
imgAvatar = null;
}
if (lblDrivingSkills != null) {
lblDrivingSkills.Dispose ();
lblDrivingSkills = null;
}
if (lblScore != null) {
lblScore.Dispose ();
lblScore = null;
}
if (PercentageView != null) {
PercentageView.Dispose ();
PercentageView = null;
}
}
}
}

View File

@ -0,0 +1,134 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
using System;
using Foundation;
using UIKit;
using MyDriving.Model;
using MyDriving.ViewModel;
namespace MyDriving.iOS
{
public partial class SettingsDetailViewController : UIViewController
{
public SettingsViewModel ViewModel;
public SettingsDetailViewController(IntPtr handle) : base(handle)
{
}
public string SettingKey { get; set; }
public Setting Setting { get; set; }
public override void ViewDidLoad()
{
base.ViewDidLoad();
NavigationItem.Title = Setting.Name;
settingsDetailTableView.Source = new SettingsDetailTableViewSource(SettingKey, Setting);
NSNotificationCenter.DefaultCenter.AddObserver(new NSString("SettingTextFieldChanged"),
HandleSettingChangedNotification);
}
void HandleSettingChangedNotification(NSNotification obj)
{
var dict = (NSDictionary) obj.Object;
var row = dict.ObjectForKey(new NSString("Row")) as NSString;
var section = dict.ObjectForKey(new NSString("Section")) as NSString;
var value = dict.ObjectForKey(new NSString("Value")) as NSString;
ViewModel.SettingsData[section.ToString()][Int32.Parse(row.ToString())].Value = value.ToString();
}
}
public class SettingsDetailTableViewSource : UITableViewSource
{
readonly string key;
readonly Setting setting;
public SettingsDetailTableViewSource(string key, Setting setting)
{
this.setting = setting;
this.key = key;
}
public override string TitleForHeader(UITableView tableView, nint section)
{
return setting.Name;
}
public override void WillDisplayHeaderView(UITableView tableView, UIView headerView, nint section)
{
var header = headerView as UITableViewHeaderFooterView;
header.TextLabel.TextColor = "5C5C5C".ToUIColor();
header.TextLabel.Font = UIFont.FromName("AvenirNext-Medium", 16);
header.TextLabel.Text = TitleForHeader(tableView, section);
}
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
if (!setting.IsButton)
{
setting.Value = setting.PossibleValues[indexPath.Row];
var cells = tableView.VisibleCells;
int i = 0;
foreach (var cell in cells)
{
var value = setting.PossibleValues[i];
cell.Accessory = setting.Value != value
? UITableViewCellAccessory.None
: UITableViewCellAccessory.Checkmark;
i++;
}
NSNotificationCenter.DefaultCenter.PostNotificationName("RefreshTripUnits", null);
NSNotificationCenter.DefaultCenter.PostNotificationName("RefreshSettingsTable", null);
}
}
public override nint RowsInSection(UITableView tableview, nint section)
{
if (!setting.IsTextField)
return setting.PossibleValues.Count;
else
return 1;
}
public override nint NumberOfSections(UITableView tableView)
{
return 1;
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
if (!setting.IsTextField)
{
var cell = tableView.DequeueReusableCell("SETTING__DETAIL_VALUE_CELL") as SettingDetailTableViewCell;
cell.Name = setting.PossibleValues[indexPath.Row];
cell.Accessory = UITableViewCellAccessory.None;
if (cell.Name == setting.Value)
cell.Accessory = UITableViewCellAccessory.Checkmark;
return cell;
}
else
{
var cell =
tableView.DequeueReusableCell("SETTING_DETAIL_TEXTFIELD_CELL") as
SettingDetailTextFieldTableViewCell;
cell.Row = indexPath.Row.ToString();
cell.Section = key;
cell.Value = setting.Value ?? string.Empty;
return cell;
}
}
}
}

View File

@ -0,0 +1,29 @@
// WARNING
//
// This file has been generated automatically by Visual Studio from the outlets and
// actions declared in your storyboard file.
// Manual changes to this file will not be maintained.
//
using Foundation;
using System;
using System.CodeDom.Compiler;
using UIKit;
namespace MyDriving.iOS
{
[Register ("SettingsDetailViewController")]
partial class SettingsDetailViewController
{
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UITableView settingsDetailTableView { get; set; }
void ReleaseDesignerOutlets ()
{
if (settingsDetailTableView != null) {
settingsDetailTableView.Dispose ();
settingsDetailTableView = null;
}
}
}
}

View File

@ -0,0 +1,164 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
using Foundation;
using System;
using System.Collections.Generic;
using UIKit;
using MyDriving.Model;
using MyDriving.ViewModel;
using HockeyApp;
namespace MyDriving.iOS
{
partial class SettingsViewController : UIViewController
{
string[] keys;
public SettingsViewController(IntPtr handle) : base(handle)
{
}
SettingsViewModel ViewModel { get; set; }
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Wire up view model
ViewModel = new SettingsViewModel();
keys = new string[ViewModel.SettingsData.Count];
int i = 0;
foreach (var grouping in ViewModel.SettingsData)
{
keys[i] = grouping.Key;
i++;
}
// Wire up table source
settingsTableView.Source = new SettingsDataSource(ViewModel, keys);
btnLogout.SetTitle("Leave Feedback", UIControlState.Normal);
btnLogout.TouchUpInside += LeaveFeedbackButtonClicked;
NSNotificationCenter.DefaultCenter.AddObserver(new NSString("RefreshSettingsTable"),
HandleReloadTableNotification);
}
public override bool ShouldPerformSegue(string segueIdentifier, NSObject sender)
{
var cell = (SettingTableViewCell) sender;
if (cell.Accessory == UITableViewCellAccessory.None)
return false;
else
return true;
}
public override void PrepareForSegue(UIStoryboardSegue segue, NSObject sender)
{
if (segue.Identifier == "settingsDetailSegue")
{
var controller = segue.DestinationViewController as SettingsDetailViewController;
var cell = settingsTableView.IndexPathForCell(sender as UITableViewCell);
var row = cell.Row;
var section = cell.Section;
var setting = ViewModel.SettingsData[keys[section]][row];
settingsTableView.DeselectRow(settingsTableView.IndexPathForSelectedRow, true);
controller.Setting = setting;
controller.ViewModel = ViewModel;
controller.SettingKey = keys[cell.Section];
}
}
void LeaveFeedbackButtonClicked(object sender, EventArgs e)
{
BITHockeyManager.SharedHockeyManager.FeedbackManager.ShowFeedbackComposeView();
}
void HandleReloadTableNotification(NSNotification obj)
{
InvokeOnMainThread(delegate { settingsTableView.ReloadData(); });
}
}
public class SettingsDataSource : UITableViewSource
{
readonly Dictionary<string, List<Setting>> data;
readonly string[] keys;
readonly SettingsViewModel viewModel;
public SettingsDataSource(SettingsViewModel viewModel, string[] keys)
{
this.viewModel = viewModel;
data = viewModel.SettingsData;
this.keys = keys;
}
public override void WillDisplayHeaderView(UITableView tableView, UIView headerView, nint section)
{
var header = headerView as UITableViewHeaderFooterView;
header.TextLabel.TextColor = "5C5C5C".ToUIColor();
header.TextLabel.Font = UIFont.FromName("AvenirNext-Medium", 16);
header.TextLabel.Text = TitleForHeader(tableView, section);
}
public override async void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
var setting = data[keys[indexPath.Section]][indexPath.Row];
if (setting.IsButton)
{
if (setting.ButtonUrl != "Permissions")
{
await viewModel.ExecuteOpenBrowserCommandAsync(setting.ButtonUrl);
}
else
{
var url = NSUrl.FromString(UIApplication.OpenSettingsUrlString);
UIApplication.SharedApplication.OpenUrl(url);
}
}
}
public override nint NumberOfSections(UITableView tableView)
{
return keys.Length;
}
public override string TitleForHeader(UITableView tableView, nint section)
{
return keys[section];
}
public override nint RowsInSection(UITableView tableView, nint section)
{
return data[keys[section]].Count;
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell("SETTING_VALUE_CELL") as SettingTableViewCell;
var setting = data[keys[indexPath.Section]][indexPath.Row];
if (setting.IsButton)
{
cell.Accessory = UITableViewCellAccessory.None;
cell.Value = "";
}
else
{
cell.Value = !String.IsNullOrEmpty(setting.Value) ? cell.Value = setting.Value : cell.Value = "";
}
cell.Name = setting.Name;
return cell;
}
}
}

View File

@ -0,0 +1,38 @@
// WARNING
//
// This file has been generated automatically by Visual Studio from the outlets and
// actions declared in your storyboard file.
// Manual changes to this file will not be maintained.
//
using Foundation;
using System;
using System.CodeDom.Compiler;
using UIKit;
namespace MyDriving.iOS
{
[Register ("SettingsViewController")]
partial class SettingsViewController
{
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIButton btnLogout { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UITableView settingsTableView { get; set; }
void ReleaseDesignerOutlets ()
{
if (btnLogout != null) {
btnLogout.Dispose ();
btnLogout = null;
}
if (settingsTableView != null) {
settingsTableView.Dispose ();
settingsTableView = null;
}
}
}
}

View File

@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
using System;
using UIKit;
using CoreGraphics;
namespace MyDriving.iOS
{
partial class TabBarController : UITabBarController
{
public TabBarController(IntPtr handle) : base(handle)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
SetupTabChangeAnimation();
}
void SetupTabChangeAnimation()
{
ShouldSelectViewController = (tabController, controller) =>
{
if (SelectedViewController == null || controller == SelectedViewController)
return true;
var fromView = SelectedViewController.View;
var toView = controller.View;
var destFrame = fromView.Frame;
const float offset = 25;
//Position toView off screen
fromView.Superview.AddSubview(toView);
toView.Frame = new CGRect(offset, destFrame.Y, destFrame.Width, destFrame.Height);
UIView.Animate(0.2,
() => { toView.Frame = new CGRect(0, destFrame.Y, destFrame.Width, destFrame.Height); }, () =>
{
fromView.RemoveFromSuperview();
SelectedViewController = controller;
});
return true;
};
}
}
}

View File

@ -0,0 +1,21 @@
// WARNING
//
// This file has been generated automatically by Visual Studio from the outlets and
// actions declared in your storyboard file.
// Manual changes to this file will not be maintained.
//
using Foundation;
using System;
using System.CodeDom.Compiler;
using UIKit;
namespace MyDriving.iOS
{
[Register ("TabBarController")]
partial class TabBarController
{
void ReleaseDesignerOutlets ()
{
}
}
}

View File

@ -0,0 +1,442 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
using System;
using System.Globalization;
using System.Collections.Generic;
using System.Threading.Tasks;
using CoreAnimation;
using CoreLocation;
using Foundation;
using MapKit;
using UIKit;
using MyDriving.DataObjects;
using MyDriving.ViewModel;
using Plugin.Permissions;
using Plugin.Permissions.Abstractions;
using MyDriving.Utils;
using Microsoft.WindowsAzure.MobileServices;
using MyDriving.iOS.Helpers;
using MyDriving.AzureClient;
namespace MyDriving.iOS
{
partial class CurrentTripViewController : UIViewController
{
CarAnnotation currentLocationAnnotation;
TripMapViewDelegate mapDelegate;
List<CLLocationCoordinate2D> route;
public CurrentTripViewController(IntPtr handle) : base(handle)
{
}
public CurrentTripViewModel CurrentTripViewModel { get; set; }
public PastTripsDetailViewModel PastTripsDetailViewModel { get; set; }
public override async void ViewDidLoad()
{
base.ViewDidLoad();
NavigationItem.RightBarButtonItem = null;
if (PastTripsDetailViewModel == null)
await ConfigureCurrentTripUserInterface();
else
await ConfigurePastTripUserInterface();
}
public override async void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
PopRecordButtonAnimation();
if (CurrentTripViewModel != null)
{
await CurrentTripViewModel.ExecuteStartTrackingTripCommandAsync().ContinueWith(async (task) =>
{
// If we don't have permission from the user, prompt a dialog requesting permission.
await PromptPermissionsChangeDialog();
});
if (!CurrentTripViewModel.Geolocator.IsGeolocationEnabled)
{
tripMapView.Camera.CenterCoordinate = new CLLocationCoordinate2D(47.6204, -122.3491);
tripMapView.Camera.Altitude = 5000;
}
}
}
#region Current Trip User Interface Logic
async Task ConfigureCurrentTripUserInterface()
{
// Configure map
mapDelegate = new TripMapViewDelegate(true);
tripMapView.Delegate = mapDelegate;
tripMapView.ShowsUserLocation = false;
tripMapView.Camera.Altitude = 5000;
// Setup record button
recordButton.Hidden = false;
recordButton.Layer.CornerRadius = recordButton.Frame.Width/2;
recordButton.Layer.MasksToBounds = true;
recordButton.Layer.BorderColor = UIColor.White.CGColor;
recordButton.Layer.BorderWidth = 0;
recordButton.TouchUpInside += RecordButton_TouchUpInside;
// Hide slider
tripSlider.Hidden = true;
wayPointA.Hidden = true;
wayPointB.Hidden = true;
UpdateRecordButton(false);
tripInfoView.Alpha = 0;
ResetTripInfoView();
CurrentTripViewModel = new CurrentTripViewModel();
CurrentTripViewModel.Geolocator.PositionChanged += Geolocator_PositionChanged;
}
void AnimateTripInfoView()
{
tripInfoView.FadeIn(0.3, 0);
}
void ResetMapViewState()
{
InvokeOnMainThread(() =>
{
route = null;
tripMapView.RemoveAnnotations(tripMapView.Annotations);
if (tripMapView.Overlays != null && tripMapView.Overlays.Length > 0)
{
tripMapView.RemoveOverlays(tripMapView.Overlays[0]);
}
});
}
void ResetTripInfoView()
{
labelOneValue.Text = "N/A";
labelTwoValue.Text = "0";
labelThreeValue.Text = "0:00";
labelFourValue.Text = "N/A";
}
void UpdateRecordButton(bool isRecording)
{
//Corner Radius
var radiusAnimation = CABasicAnimation.FromKeyPath("cornerRadius");
radiusAnimation.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseIn);
radiusAnimation.From = NSNumber.FromNFloat(recordButton.Layer.CornerRadius);
//Border Thickness
var borderAnimation = CABasicAnimation.FromKeyPath("borderWidth");
borderAnimation.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseIn);
radiusAnimation.From = NSNumber.FromNFloat(recordButton.Layer.BorderWidth);
//Animation Group
var animationGroup = CAAnimationGroup.CreateAnimation();
animationGroup.Animations = new CAAnimation[] {radiusAnimation, borderAnimation};
animationGroup.Duration = 0.6;
animationGroup.FillMode = CAFillMode.Forwards;
recordButton.Layer.CornerRadius = isRecording ? 4 : recordButton.Frame.Width/2;
recordButton.Layer.BorderWidth = isRecording ? 2 : 3;
recordButton.Layer.AddAnimation(animationGroup, "borderChanges");
}
async Task PromptPermissionsChangeDialog()
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Location);
if (status == PermissionStatus.Denied)
{
InvokeOnMainThread(() =>
{
var alertController = UIAlertController.Create("Location Permission Denied",
"Tracking your location is required to record trips. Visit the Settings app to change the permission status.",
UIAlertControllerStyle.Alert);
alertController.AddAction(UIAlertAction.Create("Change Permission", UIAlertActionStyle.Default,
obj =>
{
var url = NSUrl.FromString(UIApplication.OpenSettingsUrlString);
UIApplication.SharedApplication.OpenUrl(url);
}));
alertController.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Cancel, null));
PresentViewController(alertController, true, null);
tripMapView.Camera.CenterCoordinate = new CLLocationCoordinate2D(47.6204, -122.3491);
tripMapView.Camera.Altitude = 5000;
});
}
}
async void RecordButton_TouchUpInside(object sender, EventArgs e)
{
if (!CurrentTripViewModel.Geolocator.IsGeolocationEnabled)
{
Acr.UserDialogs.UserDialogs.Instance.Alert(
"Please ensure that geolocation is enabled and permissions are allowed for MyDriving to start a recording.",
"Geolocation Disabled", "OK");
return;
}
if (!CurrentTripViewModel.IsRecording)
{
if (!await CurrentTripViewModel.StartRecordingTrip())
return;
UpdateRecordButton(true);
ResetTripInfoView();
AnimateTripInfoView();
if (CurrentTripViewModel.CurrentTrip.HasSimulatedOBDData)
NavigationItem.Title = "Current Trip (Sim OBD)";
var endpoint = "A";
var annotation = new WaypointAnnotation(CurrentTripViewModel.CurrentPosition.ToCoordinate(), endpoint);
tripMapView.AddAnnotation(annotation);
}
else
{
if (await CurrentTripViewModel.StopRecordingTrip())
{
ResetMapViewState();
InvokeOnMainThread(delegate
{
mapDelegate = new TripMapViewDelegate(true);
tripMapView.Delegate = mapDelegate;
});
UpdateRecordButton(false);
tripInfoView.Alpha = 0;
NavigationItem.Title = "Current Trip";
await CurrentTripViewModel.SaveRecordingTripAsync();
var vc =
Storyboard.InstantiateViewController("tripSummaryViewController") as TripSummaryViewController;
vc.ViewModel = CurrentTripViewModel;
PresentModalViewController(vc, true);
}
}
}
void Geolocator_PositionChanged(object sender, Plugin.Geolocator.Abstractions.PositionEventArgs e)
{
var coordinate = e.Position.ToCoordinate();
UpdateCarAnnotationPosition(coordinate);
if (CurrentTripViewModel.IsRecording)
{
// Update trip information
labelOneValue.Text = CurrentTripViewModel.FuelConsumption;
labelOneTitle.Text = CurrentTripViewModel.FuelConsumptionUnits;
labelThreeValue.Text = CurrentTripViewModel.ElapsedTime;
labelTwoValue.Text = CurrentTripViewModel.CurrentTrip.Distance.ToString("F");
labelTwoTitle.Text =
CultureInfo.CurrentCulture.TextInfo.ToTitleCase(CurrentTripViewModel.CurrentTrip.Units.ToLower());
labelFourValue.Text = CurrentTripViewModel.EngineLoad;
// If we already haven't starting tracking route yet, start that.
if (route == null)
StartTrackingRoute(coordinate);
// Draw from last known coordinate to new coordinate.
else
DrawNewRouteWaypoint(coordinate);
}
}
void StartTrackingRoute(CLLocationCoordinate2D coordinate)
{
route = new List<CLLocationCoordinate2D>();
var count = CurrentTripViewModel.CurrentTrip.Points.Count;
if (count == 0)
{
route.Add(coordinate);
}
else
{
var firstPoint = CurrentTripViewModel.CurrentTrip.Points?[0];
var firstCoordinate = new CLLocationCoordinate2D(firstPoint.Latitude, firstPoint.Longitude);
route.Add(firstCoordinate);
}
}
#endregion
#region Past Trip User Interface Logic
async Task ConfigurePastTripUserInterface()
{
NavigationItem.Title = PastTripsDetailViewModel.Title;
sliderView.Hidden = false;
tripSlider.Hidden = false;
wayPointA.Layer.CornerRadius = wayPointA.Frame.Width / 2;
wayPointA.Layer.BorderWidth = 2;
wayPointA.Layer.BorderColor = UIColor.White.CGColor;
wayPointB.Layer.CornerRadius = wayPointB.Frame.Width / 2;
wayPointB.Layer.BorderWidth = 2;
wayPointB.Layer.BorderColor = UIColor.White.CGColor;
var success = await PastTripsDetailViewModel.ExecuteLoadTripCommandAsync(PastTripsDetailViewModel.Trip.Id);
if(!success)
{
NavigationController.PopViewController(true);
return;
}
// Setup map
mapDelegate = new TripMapViewDelegate(false);
tripMapView.Delegate = mapDelegate;
tripMapView.ShowsUserLocation = false;
if (PastTripsDetailViewModel.Trip == null || PastTripsDetailViewModel.Trip.Points == null || PastTripsDetailViewModel.Trip.Points.Count == 0)
return;
var coordinateCount = PastTripsDetailViewModel.Trip.Points.Count;
// Draw endpoints
var startEndpoint = new WaypointAnnotation(PastTripsDetailViewModel.Trip.Points[0].ToCoordinate(), "A");
tripMapView.AddAnnotation(startEndpoint);
var endEndpoint =
new WaypointAnnotation(PastTripsDetailViewModel.Trip.Points[coordinateCount - 1].ToCoordinate(), "B");
tripMapView.AddAnnotation(endEndpoint);
// Draw route
tripMapView.DrawRoute(PastTripsDetailViewModel.Trip.Points.ToCoordinateArray());
// Draw car
var carCoordinate = PastTripsDetailViewModel.Trip.Points[0];
currentLocationAnnotation = new CarAnnotation(carCoordinate.ToCoordinate(), UIColor.Blue);
tripMapView.AddAnnotation(currentLocationAnnotation);
// Configure slider area
ConfigureSlider();
ConfigureWayPointButtons();
ConfigurePoiAnnotations();
recordButton.Hidden = true;
tripMapView.SetVisibleMapRect(
MKPolyline.FromCoordinates(PastTripsDetailViewModel.Trip.Points.ToCoordinateArray()).BoundingMapRect,
new UIEdgeInsets(25, 25, 25, 25), false);
tripMapView.CenterCoordinate = carCoordinate.ToCoordinate();
UpdateTripStatistics(carCoordinate);
NSNotificationCenter.DefaultCenter.AddObserver(new NSString("RefreshTripUnits"), HandleTripUnitsChanged);
}
void HandleTripUnitsChanged(NSNotification obj)
{
UpdateTripStatistics(PastTripsDetailViewModel.CurrentPosition);
}
void UpdateTripStatistics(TripPoint point)
{
PastTripsDetailViewModel.CurrentPosition = point;
labelOneTitle.Text = PastTripsDetailViewModel.FuelConsumptionUnits;
labelOneValue.Text = PastTripsDetailViewModel.FuelConsumption;
labelTwoTitle.Text = PastTripsDetailViewModel.DistanceUnits;
labelTwoValue.Text = PastTripsDetailViewModel.Distance;
labelThreeTitle.Text = "Elapsed Time";
labelThreeValue.Text = PastTripsDetailViewModel.ElapsedTime;
labelFourTitle.Text = PastTripsDetailViewModel.SpeedUnits;
labelFourValue.Text = PastTripsDetailViewModel.Speed;
}
void ConfigureSlider()
{
tripSlider.MinValue = 0;
tripSlider.MaxValue = PastTripsDetailViewModel.Trip.Points.Count - 1;
tripSlider.Value = 0;
tripSlider.ValueChanged += TripSlider_ValueChanged;
}
void ConfigureWayPointButtons()
{
startTimeLabel.Hidden = false;
endTimeLabel.Hidden = false;
startTimeLabel.Text = PastTripsDetailViewModel.Trip.StartTimeDisplay;
endTimeLabel.Text = PastTripsDetailViewModel.Trip.EndTimeDisplay;
wayPointA.TouchUpInside += delegate
{
tripSlider.Value = 0;
TripSlider_ValueChanged(this, null);
};
wayPointB.TouchUpInside += delegate
{
tripSlider.Value = tripSlider.MaxValue;
TripSlider_ValueChanged(this, null);
};
}
void ConfigurePoiAnnotations()
{
foreach (var poi in PastTripsDetailViewModel.POIs)
{
var poiAnnotation = new PoiAnnotation(poi, poi.ToCoordinate());
tripMapView.AddAnnotation(poiAnnotation);
}
}
void TripSlider_ValueChanged(object sender, EventArgs e)
{
var value = (int) tripSlider.Value;
var tripPoint = PastTripsDetailViewModel.Trip.Points[value];
UpdateCarAnnotationPosition(tripPoint.ToCoordinate());
UpdateTripStatistics(tripPoint);
}
void PopRecordButtonAnimation()
{
if (recordButton.Hidden && PastTripsDetailViewModel == null)
recordButton.Pop(0.5, 0, 1);
}
#endregion
#region Shared User Interface Logic
void UpdateCarAnnotationPosition(CLLocationCoordinate2D coordinate)
{
if (currentLocationAnnotation != null)
tripMapView.RemoveAnnotation(currentLocationAnnotation);
var color = CurrentTripViewModel != null && CurrentTripViewModel.IsRecording ? UIColor.Red : UIColor.Blue;
currentLocationAnnotation = new CarAnnotation(coordinate, color);
tripMapView.AddAnnotation(currentLocationAnnotation);
tripMapView.Camera.CenterCoordinate = coordinate;
}
void DrawNewRouteWaypoint(CLLocationCoordinate2D coordinate)
{
route.Add(coordinate);
if (tripMapView.Overlays != null)
tripMapView.RemoveOverlays(tripMapView.Overlays);
tripMapView.DrawRoute(route.ToArray());
}
#endregion
}
}

View File

@ -0,0 +1,173 @@
// WARNING
//
// This file has been generated automatically by Visual Studio from the outlets and
// actions declared in your storyboard file.
// Manual changes to this file will not be maintained.
//
using Foundation;
using System;
using System.CodeDom.Compiler;
using UIKit;
namespace MyDriving.iOS
{
[Register ("CurrentTripViewController")]
partial class CurrentTripViewController
{
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UILabel endTimeLabel { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UILabel labelFourTitle { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UILabel labelFourValue { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UILabel labelOneTitle { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UILabel labelOneValue { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UILabel labelThreeTitle { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UILabel labelThreeValue { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UILabel labelTwoTitle { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UILabel labelTwoValue { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIButton recordButton { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIView sliderView { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UILabel startTimeLabel { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIView tripInfoView { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
MyDriving.iOS.TripMapView tripMapView { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UISlider tripSlider { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIButton wayPointA { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIButton wayPointB { get; set; }
void ReleaseDesignerOutlets ()
{
if (endTimeLabel != null) {
endTimeLabel.Dispose ();
endTimeLabel = null;
}
if (labelFourTitle != null) {
labelFourTitle.Dispose ();
labelFourTitle = null;
}
if (labelFourValue != null) {
labelFourValue.Dispose ();
labelFourValue = null;
}
if (labelOneTitle != null) {
labelOneTitle.Dispose ();
labelOneTitle = null;
}
if (labelOneValue != null) {
labelOneValue.Dispose ();
labelOneValue = null;
}
if (labelThreeTitle != null) {
labelThreeTitle.Dispose ();
labelThreeTitle = null;
}
if (labelThreeValue != null) {
labelThreeValue.Dispose ();
labelThreeValue = null;
}
if (labelTwoTitle != null) {
labelTwoTitle.Dispose ();
labelTwoTitle = null;
}
if (labelTwoValue != null) {
labelTwoValue.Dispose ();
labelTwoValue = null;
}
if (recordButton != null) {
recordButton.Dispose ();
recordButton = null;
}
if (sliderView != null) {
sliderView.Dispose ();
sliderView = null;
}
if (startTimeLabel != null) {
startTimeLabel.Dispose ();
startTimeLabel = null;
}
if (tripInfoView != null) {
tripInfoView.Dispose ();
tripInfoView = null;
}
if (tripMapView != null) {
tripMapView.Dispose ();
tripMapView = null;
}
if (tripSlider != null) {
tripSlider.Dispose ();
tripSlider = null;
}
if (wayPointA != null) {
wayPointA.Dispose ();
wayPointA = null;
}
if (wayPointB != null) {
wayPointB.Dispose ();
wayPointB = null;
}
}
}
}

View File

@ -0,0 +1,48 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
using System;
using UIKit;
namespace MyDriving.iOS
{
public partial class TripSummaryViewController : UIViewController
{
public TripSummaryViewController(IntPtr handle) : base(handle)
{
}
public ViewModel.CurrentTripViewModel ViewModel { get; set; }
public override void ViewDidLoad()
{
lblDateTime.Text = $"{DateTime.Now.ToString("M")} {DateTime.Now.ToString("t")}";
lblDistance.Text = ViewModel.TripSummary.TotalDistanceDisplay;
lblDuration.Text = ViewModel.TripSummary.TotalTimeDisplay;
lblFuelConsumed.Text = ViewModel.TripSummary.FuelDisplay;
lblTopSpeed.Text = ViewModel.TripSummary.MaxSpeedDisplay;
lblDistance.Alpha = 0;
lblDuration.Alpha = 0;
lblTopSpeed.Alpha = 0;
lblFuelConsumed.Alpha = 0;
lblTopSpeed.Alpha = 0;
}
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
lblDistance.FadeIn(0.4, 0.1f);
lblDuration.FadeIn(0.4, 0.2f);
lblTopSpeed.FadeIn(0.4, 0.3f);
lblFuelConsumed.FadeIn(0.4, 0.4f);
lblTopSpeed.FadeIn(0.4, 0.5f);
}
async partial void BtnClose_TouchUpInside(UIButton sender)
{
await DismissViewControllerAsync(true);
}
}
}

View File

@ -0,0 +1,78 @@
// WARNING
//
// This file has been generated automatically by Visual Studio from the outlets and
// actions declared in your storyboard file.
// Manual changes to this file will not be maintained.
//
using Foundation;
using System;
using System.CodeDom.Compiler;
using UIKit;
namespace MyDriving.iOS
{
[Register ("TripSummaryViewController")]
partial class TripSummaryViewController
{
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIButton btnClose { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UILabel lblDateTime { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UILabel lblDistance { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UILabel lblDuration { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UILabel lblFuelConsumed { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UILabel lblTopSpeed { get; set; }
[Action ("BtnClose_TouchUpInside:")]
[GeneratedCode ("iOS Designer", "1.0")]
partial void BtnClose_TouchUpInside (UIKit.UIButton sender);
void ReleaseDesignerOutlets ()
{
if (btnClose != null) {
btnClose.Dispose ();
btnClose = null;
}
if (lblDateTime != null) {
lblDateTime.Dispose ();
lblDateTime = null;
}
if (lblDistance != null) {
lblDistance.Dispose ();
lblDistance = null;
}
if (lblDuration != null) {
lblDuration.Dispose ();
lblDuration = null;
}
if (lblFuelConsumed != null) {
lblFuelConsumed.Dispose ();
lblFuelConsumed = null;
}
if (lblTopSpeed != null) {
lblTopSpeed.Dispose ();
lblTopSpeed = null;
}
}
}
}

View File

@ -0,0 +1,152 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
using System;
using CoreGraphics;
using Foundation;
using ObjCRuntime;
using UIKit;
using MyDriving.ViewModel;
using SDWebImage;
namespace MyDriving.iOS
{
public partial class TripsTableViewController : UITableViewController
{
const string TripCellWithImageIdentifier = "TRIP_CELL_WITHIMAGE_IDENTIFIER";
const string TripCellIdentifier = "TRIP_CELL_IDENTIFIER";
const string PastTripSegueIdentifier = "pastTripSegue";
public TripsTableViewController(IntPtr handle) : base(handle)
{
}
public PastTripsViewModel ViewModel { get; set; }
public override async void ViewDidLoad()
{
base.ViewDidLoad();
ViewModel = new PastTripsViewModel();
await ViewModel.ExecuteLoadPastTripsCommandAsync();
TableView.ReloadData();
TableView.TableFooterView = new UIView(new CGRect(0, 0, 0, 0));
RefreshControl.AddTarget(this, new Selector("RefreshSource"), UIControlEvent.ValueChanged);
NSNotificationCenter.DefaultCenter.AddObserver(new NSString("RefreshPastTripsTable"),
HandleReloadTableNotification);
}
public override void PrepareForSegue(UIStoryboardSegue segue, NSObject sender)
{
if (segue.Identifier == PastTripSegueIdentifier)
{
var controller = segue.DestinationViewController as CurrentTripViewController;
var indexPath = TableView.IndexPathForCell(sender as UITableViewCell);
var trip = ViewModel.Trips[indexPath.Row];
controller.PastTripsDetailViewModel = new PastTripsDetailViewModel(trip);
}
}
[Export("RefreshSource")]
async void RefreshControl_ValueChanged()
{
await ViewModel.ExecuteLoadPastTripsCommandAsync();
InvokeOnMainThread(delegate
{
TableView.ReloadData();
RefreshControl.EndRefreshing();
});
}
async void HandleReloadTableNotification(NSNotification obj)
{
await ViewModel.ExecuteLoadPastTripsCommandAsync();
InvokeOnMainThread(delegate { TableView.ReloadData(); });
}
#region UITableViewSource
public override nint RowsInSection(UITableView tableView, nint section)
{
return ViewModel.Trips.Count;
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
if (ViewModel.CanLoadMore && !ViewModel.IsBusy && ViewModel.Trips.Count > 0 && indexPath.Row == ViewModel.Trips.Count - 1)
{
ViewModel.ExecuteLoadMorePastTripsCommandAsync().ContinueWith((t) =>
{
InvokeOnMainThread(delegate { TableView.ReloadData(); });
}, scheduler: System.Threading.Tasks.TaskScheduler.Current);
}
var trip = ViewModel.Trips[indexPath.Row];
if (string.IsNullOrEmpty(trip.MainPhotoUrl))
{
var cell = tableView.DequeueReusableCell(TripCellIdentifier) as TripTableViewCell;
if (cell == null)
{
cell = new TripTableViewCell(new NSString(TripCellIdentifier));
}
cell.LocationName = trip.Name;
cell.TimeAgo = trip.TimeAgo;
cell.Distance = trip.TotalDistance;
return cell;
}
else
{
var cell = tableView.DequeueReusableCell(TripCellWithImageIdentifier) as TripTableViewCellWithImage;
if (cell == null)
{
cell = new TripTableViewCellWithImage(new NSString(TripCellWithImageIdentifier));
}
cell.DisplayImage.SetImage(new NSUrl(trip.MainPhotoUrl));
cell.LocationName = trip.Name;
cell.TimeAgo = trip.TimeAgo;
cell.Distance = trip.TotalDistance;
return cell;
}
}
public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{
var trip = ViewModel.Trips[indexPath.Row];
if (string.IsNullOrEmpty(trip.MainPhotoUrl))
return 70;
else
return 221;
}
public override bool CanEditRow(UITableView tableView, NSIndexPath indexPath)
{
return true;
}
public override async void CommitEditingStyle(UITableView tableView, UITableViewCellEditingStyle editingStyle,
NSIndexPath indexPath)
{
switch (editingStyle)
{
case UITableViewCellEditingStyle.Delete:
var trip = ViewModel.Trips[indexPath.Row];
if(await ViewModel.ExecuteDeleteTripCommand(trip))
tableView.DeleteRows(new[] {indexPath}, UITableViewRowAnimation.Automatic);
break;
}
}
#endregion
}
}

View File

@ -0,0 +1,21 @@
// WARNING
//
// This file has been generated automatically by Visual Studio from the outlets and
// actions declared in your storyboard file.
// Manual changes to this file will not be maintained.
//
using Foundation;
using System;
using System.CodeDom.Compiler;
using UIKit;
namespace MyDriving.iOS
{
[Register ("TripsTableViewController")]
partial class TripsTableViewController
{
void ReleaseDesignerOutlets ()
{
}
}
}