add openhack files
@ -0,0 +1,101 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for details.
|
||||
|
||||
using Android.OS;
|
||||
using Android.Support.V7.App;
|
||||
using Android.Support.V7.Widget;
|
||||
using MyDriving.Droid.Helpers;
|
||||
using Plugin.Permissions;
|
||||
using Android.Content.PM;
|
||||
using Android.Transitions;
|
||||
|
||||
namespace MyDriving.Droid
|
||||
{
|
||||
public abstract class BaseActivity : AppCompatActivity, IAccelerometerListener
|
||||
{
|
||||
AccelerometerManager accelerometerManager;
|
||||
bool canShowFeedback;
|
||||
public Toolbar Toolbar { get; set; }
|
||||
protected abstract int LayoutResource { get; }
|
||||
|
||||
protected int ActionBarIcon
|
||||
{
|
||||
set { Toolbar.SetNavigationIcon(value); }
|
||||
}
|
||||
|
||||
public void OnAccelerationChanged(float x, float y, float z)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnShake(float force)
|
||||
{
|
||||
if (!canShowFeedback)
|
||||
return;
|
||||
canShowFeedback = false;
|
||||
HockeyApp.FeedbackManager.ShowFeedbackActivity(this);
|
||||
}
|
||||
|
||||
protected override void OnCreate(Bundle bundle)
|
||||
{
|
||||
InitActivityTransitions();
|
||||
base.OnCreate(bundle);
|
||||
SetContentView(LayoutResource);
|
||||
Toolbar = FindViewById<Toolbar>(Resource.Id.toolbar);
|
||||
if (Toolbar != null)
|
||||
{
|
||||
SetSupportActionBar(Toolbar);
|
||||
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
|
||||
SupportActionBar.SetHomeButtonEnabled(true);
|
||||
}
|
||||
|
||||
accelerometerManager = new AccelerometerManager(this, this);
|
||||
accelerometerManager.Configure(40, 350);
|
||||
}
|
||||
|
||||
|
||||
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
|
||||
{
|
||||
PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
|
||||
protected override void OnResume()
|
||||
{
|
||||
base.OnResume();
|
||||
canShowFeedback = true;
|
||||
if (accelerometerManager.IsSupported)
|
||||
accelerometerManager.StartListening();
|
||||
}
|
||||
|
||||
void InitActivityTransitions()
|
||||
{
|
||||
if ((int) Build.VERSION.SdkInt >= 21)
|
||||
{
|
||||
var transition = new Slide();
|
||||
transition.ExcludeTarget(Android.Resource.Id.StatusBarBackground, true);
|
||||
Window.EnterTransition = transition;
|
||||
Window.ReturnTransition = transition;
|
||||
Window.RequestFeature(Android.Views.WindowFeatures.ContentTransitions);
|
||||
Window.RequestFeature(Android.Views.WindowFeatures.ActivityTransitions);
|
||||
Window.SharedElementEnterTransition = new ChangeBounds();
|
||||
Window.SharedElementReturnTransition = new ChangeBounds();
|
||||
Window.AllowEnterTransitionOverlap = true;
|
||||
Window.AllowReturnTransitionOverlap = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnStop()
|
||||
{
|
||||
base.OnStop();
|
||||
if (accelerometerManager.IsListening)
|
||||
accelerometerManager.StopListening();
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
if (accelerometerManager.IsListening)
|
||||
accelerometerManager.StopListening();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for details.
|
||||
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Content.PM;
|
||||
using Android.OS;
|
||||
using Android.Support.V4.App;
|
||||
using Android.Support.V4.View;
|
||||
using Android.Views;
|
||||
using MyDriving.Droid.Fragments;
|
||||
using Android.Graphics;
|
||||
using Android.Support.V4.Content;
|
||||
|
||||
namespace MyDriving.Droid.Activities
|
||||
{
|
||||
[Activity(Label = "Getting Started", Icon = "@drawable/ic_launcher",
|
||||
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
|
||||
ScreenOrientation = ScreenOrientation.Portrait)]
|
||||
public class GettingStartedActivity : BaseActivity
|
||||
{
|
||||
TabAdapter adapter;
|
||||
|
||||
ViewPager pager;
|
||||
protected override int LayoutResource => Resource.Layout.activity_getting_started;
|
||||
|
||||
protected override void OnCreate(Bundle savedInstanceState)
|
||||
{
|
||||
base.OnCreate(savedInstanceState);
|
||||
|
||||
if ((int) Build.VERSION.SdkInt >= 21)
|
||||
{
|
||||
Window.SetStatusBarColor(new Color(ContextCompat.GetColor(this, Resource.Color.primary_dark)));
|
||||
Window.DecorView.SystemUiVisibility = StatusBarVisibility.Visible;
|
||||
}
|
||||
|
||||
adapter = new TabAdapter(this, SupportFragmentManager);
|
||||
pager = FindViewById<ViewPager>(Resource.Id.pager);
|
||||
pager.Adapter = adapter;
|
||||
pager.OffscreenPageLimit = 3;
|
||||
|
||||
SupportActionBar.Title = "Getting Started (1/5)";
|
||||
pager.PageSelected += (sender, e) => { SupportActionBar.Title = $"Getting Started ({e.Position + 1}/5)"; };
|
||||
|
||||
SupportActionBar?.SetDisplayHomeAsUpEnabled(false);
|
||||
SupportActionBar?.SetDisplayShowHomeEnabled(false);
|
||||
// Create your application here
|
||||
}
|
||||
|
||||
public override void OnBackPressed()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class TabAdapter : FragmentStatePagerAdapter
|
||||
{
|
||||
public TabAdapter(Context context, Android.Support.V4.App.FragmentManager fm) : base(fm)
|
||||
{
|
||||
}
|
||||
|
||||
public override int Count => 5;
|
||||
|
||||
public override Java.Lang.ICharSequence GetPageTitleFormatted(int position)
|
||||
=> new Java.Lang.String(string.Empty);
|
||||
|
||||
|
||||
public override Android.Support.V4.App.Fragment GetItem(int position)
|
||||
{
|
||||
switch (position)
|
||||
{
|
||||
case 0:
|
||||
return FragmentGettingStarted1.NewInstance();
|
||||
case 1:
|
||||
return FragmentGettingStarted2.NewInstance();
|
||||
case 2:
|
||||
return FragmentGettingStarted3.NewInstance();
|
||||
case 3:
|
||||
return FragmentGettingStarted4.NewInstance();
|
||||
case 4:
|
||||
return FragmentGettingStarted5.NewInstance();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public override int GetItemPosition(Java.Lang.Object frag) => PositionNone;
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for details.
|
||||
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Android.Content.PM;
|
||||
using MyDriving.ViewModel;
|
||||
using MyDriving.Utils;
|
||||
using Android.Support.V4.Content;
|
||||
using Android.Graphics;
|
||||
|
||||
namespace MyDriving.Droid.Activities
|
||||
{
|
||||
[Activity(Label = "Login", Theme = "@style/MyThemeDark",
|
||||
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
|
||||
ScreenOrientation = ScreenOrientation.Portrait)]
|
||||
public class LoginActivity : BaseActivity
|
||||
{
|
||||
LoginViewModel viewModel;
|
||||
|
||||
protected override int LayoutResource => Resource.Layout.activity_login;
|
||||
|
||||
protected override void OnCreate(Bundle savedInstanceState)
|
||||
{
|
||||
base.OnCreate(savedInstanceState);
|
||||
|
||||
if ((int) Build.VERSION.SdkInt >= 21)
|
||||
{
|
||||
Window.SetStatusBarColor(new Color(ContextCompat.GetColor(this, Resource.Color.primary_dark)));
|
||||
Window.DecorView.SystemUiVisibility = StatusBarVisibility.Visible;
|
||||
}
|
||||
|
||||
viewModel = new LoginViewModel();
|
||||
viewModel.PropertyChanged += ViewModel_PropertyChanged;
|
||||
var twitter = FindViewById<Button>(Resource.Id.button_twitter);
|
||||
var microsoft = FindViewById<Button>(Resource.Id.button_microsoft);
|
||||
var facebook = FindViewById<Button>(Resource.Id.button_facebook);
|
||||
|
||||
twitter.Click += (sender, e) => Login(LoginAccount.Twitter);
|
||||
microsoft.Click += (sender, e) => Login(LoginAccount.Microsoft);
|
||||
facebook.Click += (sender, e) => Login(LoginAccount.Facebook);
|
||||
|
||||
FindViewById<Button>(Resource.Id.button_skip).Click += (sender, e) =>
|
||||
{
|
||||
viewModel.InitFakeUser();
|
||||
var intent = new Intent(this, typeof(MainActivity));
|
||||
intent.AddFlags(ActivityFlags.ClearTop);
|
||||
StartActivity(intent);
|
||||
Finish();
|
||||
};
|
||||
|
||||
#if XTC || DEBUG
|
||||
#else
|
||||
FindViewById<Button>(Resource.Id.button_skip).Visibility = ViewStates.Gone;
|
||||
#endif
|
||||
var typeface = Typeface.CreateFromAsset(Assets, "fonts/Corbert-Regular.otf");
|
||||
FindViewById<TextView>(Resource.Id.text_app_name).Typeface = typeface;
|
||||
}
|
||||
|
||||
void ViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
if (!viewModel.IsLoggedIn)
|
||||
return;
|
||||
|
||||
//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
|
||||
MyDriving.Services.OBDDataProcessor.GetProcessor().Initialize(ViewModel.ViewModelBase.StoreManager);
|
||||
|
||||
var intent = new Intent(this, typeof (MainActivity));
|
||||
intent.AddFlags(ActivityFlags.ClearTop);
|
||||
StartActivity(intent);
|
||||
Finish();
|
||||
}
|
||||
|
||||
|
||||
void Login(LoginAccount account)
|
||||
{
|
||||
switch (account)
|
||||
{
|
||||
case LoginAccount.Facebook:
|
||||
viewModel.LoginFacebookCommand.Execute(null);
|
||||
break;
|
||||
case LoginAccount.Microsoft:
|
||||
viewModel.LoginMicrosoftCommand.Execute(null);
|
||||
break;
|
||||
case LoginAccount.Twitter:
|
||||
viewModel.LoginTwitterCommand.Execute(null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,188 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for details.
|
||||
|
||||
using Android.App;
|
||||
using Android.Content.PM;
|
||||
using Android.OS;
|
||||
using Android.Support.V4.Widget;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using MyDriving.Droid.Fragments;
|
||||
using Android.Support.V4.View;
|
||||
using Android.Support.Design.Widget;
|
||||
using MyDriving.Utils;
|
||||
using Android.Runtime;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using HockeyApp;
|
||||
|
||||
|
||||
namespace MyDriving.Droid
|
||||
{
|
||||
[Activity(Label = "MyDriving", Icon = "@drawable/ic_launcher",
|
||||
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
|
||||
ScreenOrientation = ScreenOrientation.Portrait)]
|
||||
public class MainActivity : BaseActivity
|
||||
{
|
||||
DrawerLayout drawerLayout;
|
||||
NavigationView navigationView;
|
||||
|
||||
int oldPosition = -1;
|
||||
|
||||
bool shouldClose;
|
||||
|
||||
protected override int LayoutResource => Resource.Layout.activity_main;
|
||||
|
||||
protected override void OnCreate(Bundle bundle)
|
||||
{
|
||||
base.OnCreate(bundle);
|
||||
|
||||
#if !XTC
|
||||
InitializeHockeyApp();
|
||||
#endif
|
||||
drawerLayout = FindViewById<DrawerLayout>(Resource.Id.drawer_layout);
|
||||
|
||||
//Set hamburger items menu
|
||||
SupportActionBar.SetHomeAsUpIndicator(Resource.Drawable.ic_menu);
|
||||
|
||||
//setup navigation view
|
||||
navigationView = FindViewById<NavigationView>(Resource.Id.nav_view);
|
||||
|
||||
//handle navigation
|
||||
navigationView.NavigationItemSelected += (sender, e) =>
|
||||
{
|
||||
e.MenuItem.SetChecked(true);
|
||||
|
||||
ListItemClicked(e.MenuItem.ItemId);
|
||||
|
||||
|
||||
SupportActionBar.Title = e.MenuItem.ItemId == Resource.Id.menu_profile
|
||||
? Settings.Current.UserFirstName
|
||||
: e.MenuItem.TitleFormatted.ToString();
|
||||
|
||||
drawerLayout.CloseDrawers();
|
||||
};
|
||||
|
||||
if (Intent.GetBooleanExtra("tracking", false))
|
||||
{
|
||||
ListItemClicked(Resource.Id.menu_current_trip);
|
||||
SupportActionBar.Title = "Current Trip";
|
||||
return;
|
||||
}
|
||||
|
||||
//if first time you will want to go ahead and click first item.
|
||||
if (bundle == null)
|
||||
{
|
||||
ListItemClicked(Resource.Id.menu_current_trip);
|
||||
SupportActionBar.Title = "Current Trip";
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeHockeyApp()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Logger.HockeyAppAndroid))
|
||||
return;
|
||||
|
||||
HockeyApp.CrashManager.Register(this, Logger.HockeyAppAndroid);
|
||||
HockeyApp.Metrics.MetricsManager.Register(this, Application, Logger.HockeyAppAndroid);
|
||||
HockeyApp.Metrics.MetricsManager.EnableUserMetrics();
|
||||
|
||||
CheckForUpdates();
|
||||
|
||||
}
|
||||
|
||||
void CheckForUpdates()
|
||||
{
|
||||
// Remove this for store builds!
|
||||
UpdateManager.Register(this, Logger.HockeyAppAndroid);
|
||||
}
|
||||
|
||||
void UnregisterManagers()
|
||||
{
|
||||
UpdateManager.Unregister();
|
||||
}
|
||||
|
||||
protected override void OnPause()
|
||||
{
|
||||
base.OnPause();
|
||||
|
||||
UnregisterManagers();
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
|
||||
UnregisterManagers();
|
||||
}
|
||||
|
||||
|
||||
void ListItemClicked(int itemId)
|
||||
{
|
||||
//this way we don't load twice, but you might want to modify this a bit.
|
||||
if (itemId == oldPosition)
|
||||
return;
|
||||
shouldClose = false;
|
||||
oldPosition = itemId;
|
||||
|
||||
Android.Support.V4.App.Fragment fragment = null;
|
||||
switch (itemId)
|
||||
{
|
||||
case Resource.Id.menu_past_trips:
|
||||
fragment = FragmentPastTrips.NewInstance();
|
||||
break;
|
||||
case Resource.Id.menu_current_trip:
|
||||
fragment = FragmentCurrentTrip.NewInstance();
|
||||
break;
|
||||
case Resource.Id.menu_profile:
|
||||
fragment = FragmentProfile.NewInstance();
|
||||
break;
|
||||
case Resource.Id.menu_settings:
|
||||
fragment = FragmentSettings.NewInstance();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
SupportFragmentManager.BeginTransaction()
|
||||
.Replace(Resource.Id.content_frame, fragment)
|
||||
.Commit();
|
||||
|
||||
navigationView.SetCheckedItem(itemId);
|
||||
}
|
||||
|
||||
public override bool OnOptionsItemSelected(IMenuItem item)
|
||||
{
|
||||
switch (item.ItemId)
|
||||
{
|
||||
case Android.Resource.Id.Home:
|
||||
drawerLayout.OpenDrawer(GravityCompat.Start);
|
||||
return true;
|
||||
}
|
||||
return base.OnOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
protected override void OnStart()
|
||||
{
|
||||
base.OnStart();
|
||||
shouldClose = false;
|
||||
}
|
||||
|
||||
public override void OnBackPressed()
|
||||
{
|
||||
if (drawerLayout.IsDrawerOpen((int) GravityFlags.Start))
|
||||
{
|
||||
drawerLayout.CloseDrawer(GravityCompat.Start);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!shouldClose)
|
||||
{
|
||||
Toast.MakeText(this, "Press back again to exit.", ToastLength.Short).Show();
|
||||
shouldClose = true;
|
||||
return;
|
||||
}
|
||||
base.OnBackPressed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,204 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for details.
|
||||
|
||||
using System.Linq;
|
||||
using Android.App;
|
||||
using Android.OS;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Android.Content.PM;
|
||||
using Android.Graphics;
|
||||
using Android.Support.V4.Content;
|
||||
using Android.Gms.Maps;
|
||||
using MyDriving.ViewModel;
|
||||
using Android.Gms.Maps.Model;
|
||||
using Android.Graphics.Drawables;
|
||||
using System;
|
||||
using MyDriving.DataObjects;
|
||||
|
||||
namespace MyDriving.Droid.Activities
|
||||
{
|
||||
[Activity(Label = "Details", ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
|
||||
ScreenOrientation = ScreenOrientation.Portrait)]
|
||||
public class PastTripDetailsActivity : BaseActivity, IOnMapReadyCallback
|
||||
{
|
||||
Marker carMarker;
|
||||
TextView distance, distanceUnits, time, speed, speedUnits, consumption, consumptionUnits;
|
||||
string id;
|
||||
|
||||
GoogleMap map;
|
||||
SupportMapFragment mapFrag;
|
||||
SeekBar seekBar;
|
||||
TextView startTime, endTime;
|
||||
PastTripsDetailViewModel viewModel;
|
||||
|
||||
protected override int LayoutResource => Resource.Layout.activity_past_trip_details;
|
||||
|
||||
|
||||
public async void OnMapReady(GoogleMap googleMap)
|
||||
{
|
||||
map = googleMap;
|
||||
|
||||
var success = await viewModel.ExecuteLoadTripCommandAsync(id);
|
||||
if (!success)
|
||||
{
|
||||
Finish();
|
||||
return;
|
||||
}
|
||||
|
||||
startTime.Text = viewModel.Trip.StartTimeDisplay;
|
||||
endTime.Text = viewModel.Trip.EndTimeDisplay;
|
||||
SupportActionBar.Title = viewModel.Title;
|
||||
SetupMap();
|
||||
UpdateStats();
|
||||
}
|
||||
public static Trip Trip { get; set; }
|
||||
protected override void OnCreate(Bundle bundle)
|
||||
{
|
||||
base.OnCreate(bundle);
|
||||
if ((int) Build.VERSION.SdkInt >= 21)
|
||||
{
|
||||
Window.SetStatusBarColor(new Color(ContextCompat.GetColor(this, Resource.Color.primary_dark)));
|
||||
Window.DecorView.SystemUiVisibility = StatusBarVisibility.Visible;
|
||||
}
|
||||
|
||||
|
||||
viewModel = new PastTripsDetailViewModel {Title = id = Intent.GetStringExtra("Id")};
|
||||
|
||||
viewModel.Trip = Trip;
|
||||
seekBar = FindViewById<SeekBar>(Resource.Id.trip_progress);
|
||||
seekBar.Enabled = false;
|
||||
|
||||
startTime = FindViewById<TextView>(Resource.Id.text_start_time);
|
||||
endTime = FindViewById<TextView>(Resource.Id.text_end_time);
|
||||
startTime.Text = endTime.Text = string.Empty;
|
||||
|
||||
time = FindViewById<TextView>(Resource.Id.text_time);
|
||||
distance = FindViewById<TextView>(Resource.Id.text_distance);
|
||||
distanceUnits = FindViewById<TextView>(Resource.Id.text_distance_units);
|
||||
consumption = FindViewById<TextView>(Resource.Id.text_consumption);
|
||||
consumptionUnits = FindViewById<TextView>(Resource.Id.text_consumption_units);
|
||||
speed = FindViewById<TextView>(Resource.Id.text_speed);
|
||||
speedUnits = FindViewById<TextView>(Resource.Id.text_speed_units);
|
||||
|
||||
mapFrag = (SupportMapFragment) SupportFragmentManager.FindFragmentById(Resource.Id.map);
|
||||
mapFrag.GetMapAsync(this);
|
||||
}
|
||||
|
||||
void UpdateStats()
|
||||
{
|
||||
time.Text = viewModel.ElapsedTime;
|
||||
consumption.Text = viewModel.FuelConsumption;
|
||||
consumptionUnits.Text = viewModel.FuelConsumptionUnits;
|
||||
speed.Text = viewModel.Speed;
|
||||
speedUnits.Text = viewModel.SpeedUnits;
|
||||
distanceUnits.Text = viewModel.DistanceUnits;
|
||||
distance.Text = viewModel.Distance;
|
||||
}
|
||||
|
||||
void SetupMap()
|
||||
{
|
||||
if (mapFrag.View.Width == 0)
|
||||
{
|
||||
mapFrag.View.PostDelayed(SetupMap, 500);
|
||||
return;
|
||||
}
|
||||
if (viewModel.Trip == null || viewModel.Trip.Points == null || viewModel.Trip.Points.Count == 0)
|
||||
return;
|
||||
|
||||
var start = viewModel.Trip.Points[0];
|
||||
var end = viewModel.Trip.Points[viewModel.Trip.Points.Count - 1];
|
||||
seekBar.Max = viewModel.Trip.Points.Count - 1;
|
||||
seekBar.ProgressChanged += SeekBar_ProgressChanged;
|
||||
|
||||
var logicalDensity = Resources.DisplayMetrics.Density;
|
||||
var thicknessCar = (int) Math.Ceiling(26*logicalDensity + .5f);
|
||||
var thicknessPoints = (int) Math.Ceiling(20*logicalDensity + .5f);
|
||||
|
||||
var b = ContextCompat.GetDrawable(this, Resource.Drawable.ic_car_blue) as BitmapDrawable;
|
||||
var finalIcon = Bitmap.CreateScaledBitmap(b.Bitmap, thicknessCar, thicknessCar, false);
|
||||
|
||||
var car = new MarkerOptions();
|
||||
car.SetPosition(new LatLng(start.Latitude, start.Longitude));
|
||||
car.SetIcon(BitmapDescriptorFactory.FromBitmap(finalIcon));
|
||||
car.Anchor(.5f, .5f);
|
||||
|
||||
b = ContextCompat.GetDrawable(this, Resource.Drawable.ic_start_point) as BitmapDrawable;
|
||||
finalIcon = Bitmap.CreateScaledBitmap(b.Bitmap, thicknessPoints, thicknessPoints, false);
|
||||
|
||||
var startMarker = new MarkerOptions();
|
||||
startMarker.SetPosition(new LatLng(start.Latitude, start.Longitude));
|
||||
startMarker.SetIcon(BitmapDescriptorFactory.FromBitmap(finalIcon));
|
||||
startMarker.Anchor(.5f, .5f);
|
||||
|
||||
b = ContextCompat.GetDrawable(this, Resource.Drawable.ic_end_point) as BitmapDrawable;
|
||||
finalIcon = Bitmap.CreateScaledBitmap(b.Bitmap, thicknessPoints, thicknessPoints, false);
|
||||
|
||||
var endMarker = new MarkerOptions();
|
||||
endMarker.SetPosition(new LatLng(end.Latitude, end.Longitude));
|
||||
endMarker.SetIcon(BitmapDescriptorFactory.FromBitmap(finalIcon));
|
||||
endMarker.Anchor(.5f, .5f);
|
||||
|
||||
b = ContextCompat.GetDrawable(this, Resource.Drawable.ic_tip) as BitmapDrawable;
|
||||
finalIcon = Bitmap.CreateScaledBitmap(b.Bitmap, thicknessPoints, thicknessPoints, false);
|
||||
var poiIcon = BitmapDescriptorFactory.FromBitmap(finalIcon);
|
||||
foreach (var poi in viewModel.POIs)
|
||||
{
|
||||
var poiMarker = new MarkerOptions();
|
||||
poiMarker.SetPosition(new LatLng(poi.Latitude, poi.Longitude));
|
||||
poiMarker.SetIcon(poiIcon);
|
||||
poiMarker.Anchor(.5f, .5f);
|
||||
map.AddMarker(poiMarker);
|
||||
}
|
||||
|
||||
|
||||
var points = viewModel.Trip.Points.Select(s => new LatLng(s.Latitude, s.Longitude)).ToArray();
|
||||
var rectOptions = new PolylineOptions();
|
||||
rectOptions.Add(points);
|
||||
rectOptions.InvokeColor(ContextCompat.GetColor(this, Resource.Color.primary_dark));
|
||||
map.AddPolyline(rectOptions);
|
||||
|
||||
|
||||
map.AddMarker(startMarker);
|
||||
map.AddMarker(endMarker);
|
||||
|
||||
carMarker = map.AddMarker(car);
|
||||
|
||||
var boundsPoints = new LatLngBounds.Builder();
|
||||
foreach (var point in points)
|
||||
boundsPoints.Include(point);
|
||||
|
||||
var bounds = boundsPoints.Build();
|
||||
map.MoveCamera(CameraUpdateFactory.NewLatLngBounds(bounds, 64));
|
||||
|
||||
map.MoveCamera(CameraUpdateFactory.NewLatLng(carMarker.Position));
|
||||
|
||||
|
||||
seekBar.Enabled = true;
|
||||
}
|
||||
|
||||
void SeekBar_ProgressChanged(object sender, SeekBar.ProgressChangedEventArgs e)
|
||||
{
|
||||
if (carMarker == null)
|
||||
return;
|
||||
|
||||
viewModel.CurrentPosition = viewModel.Trip.Points[e.Progress];
|
||||
|
||||
RunOnUiThread(() =>
|
||||
{
|
||||
UpdateStats();
|
||||
carMarker.Position = new LatLng(viewModel.CurrentPosition.Latitude,
|
||||
viewModel.CurrentPosition.Longitude);
|
||||
map.MoveCamera(CameraUpdateFactory.NewLatLng(carMarker.Position));
|
||||
});
|
||||
}
|
||||
|
||||
public override bool OnOptionsItemSelected(IMenuItem item)
|
||||
{
|
||||
if (item.ItemId == Android.Resource.Id.Home)
|
||||
Finish();
|
||||
|
||||
return base.OnOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for details.
|
||||
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Support.V7.App;
|
||||
using MyDriving.Utils;
|
||||
|
||||
namespace MyDriving.Droid.Activities
|
||||
{
|
||||
[Activity(Label = "MyDriving", Theme = "@style/SplashTheme", MainLauncher = true)]
|
||||
public class SplashActivity : AppCompatActivity
|
||||
{
|
||||
protected override void OnCreate(Bundle savedInstanceState)
|
||||
{
|
||||
base.OnCreate(savedInstanceState);
|
||||
|
||||
Intent newIntent;
|
||||
if (Settings.Current.IsLoggedIn)
|
||||
{
|
||||
newIntent = new Intent(this, typeof(MainActivity));
|
||||
|
||||
//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
|
||||
MyDriving.Services.OBDDataProcessor.GetProcessor().Initialize(ViewModel.ViewModelBase.StoreManager);
|
||||
}
|
||||
|
||||
else if (Settings.Current.FirstRun)
|
||||
{
|
||||
#if XTC
|
||||
newIntent = new Intent(this, typeof(LoginActivity));
|
||||
|
||||
#else
|
||||
newIntent = new Intent(this, typeof(GettingStartedActivity));
|
||||
|
||||
#endif
|
||||
|
||||
#if !DEBUG
|
||||
Settings.Current.FirstRun = false;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
newIntent = new Intent(this, typeof(LoginActivity));
|
||||
|
||||
|
||||
newIntent.AddFlags(ActivityFlags.ClearTop);
|
||||
newIntent.AddFlags(ActivityFlags.SingleTop);
|
||||
StartActivity(newIntent);
|
||||
Finish();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for details.
|
||||
|
||||
using Android.App;
|
||||
using Android.OS;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Android.Content.PM;
|
||||
using MyDriving.ViewModel;
|
||||
using Android.Graphics;
|
||||
using Android.Support.V4.Content;
|
||||
|
||||
namespace MyDriving.Droid.Activities
|
||||
{
|
||||
[Activity(Label = "Trip Summary", Theme = "@style/MyTheme",
|
||||
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
|
||||
ScreenOrientation = ScreenOrientation.Portrait)]
|
||||
public class TripSummaryActivity : BaseActivity
|
||||
{
|
||||
public static TripSummaryViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
protected override int LayoutResource => Resource.Layout.activity_trip_summary;
|
||||
|
||||
protected override void OnCreate(Bundle savedInstanceState)
|
||||
{
|
||||
base.OnCreate(savedInstanceState);
|
||||
|
||||
if ((int) Build.VERSION.SdkInt >= 21)
|
||||
{
|
||||
Window.SetStatusBarColor(new Color(ContextCompat.GetColor(this, Resource.Color.primary_dark)));
|
||||
Window.DecorView.SystemUiVisibility = StatusBarVisibility.Visible;
|
||||
}
|
||||
|
||||
|
||||
if (ViewModel == null)
|
||||
{
|
||||
Finish();
|
||||
return;
|
||||
}
|
||||
|
||||
SupportActionBar.SetDisplayShowHomeEnabled(false);
|
||||
SupportActionBar.SetDisplayHomeAsUpEnabled(false);
|
||||
|
||||
|
||||
var date = ViewModel.Date.ToLocalTime();
|
||||
FindViewById<TextView>(Resource.Id.text_time).Text = ViewModel.TotalTimeDisplay;
|
||||
FindViewById<TextView>(Resource.Id.text_date).Text = date.ToString("M") + " " + date.ToString("t");
|
||||
FindViewById<TextView>(Resource.Id.text_distance).Text = ViewModel.TotalDistanceDisplay;
|
||||
FindViewById<TextView>(Resource.Id.text_max_speed).Text = ViewModel.MaxSpeedDisplay;
|
||||
FindViewById<TextView>(Resource.Id.text_fuel_consumption).Text = ViewModel.FuelDisplay;
|
||||
FindViewById<TextView>(Resource.Id.text_hard_accelerations).Text = ViewModel.HardAccelerations.ToString();
|
||||
FindViewById<TextView>(Resource.Id.text_hard_breaks).Text = ViewModel.HardStops.ToString();
|
||||
|
||||
ViewModel = null;
|
||||
}
|
||||
|
||||
public override bool OnCreateOptionsMenu(IMenu menu)
|
||||
{
|
||||
MenuInflater.Inflate(Resource.Menu.menu_summary, menu);
|
||||
return base.OnCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
public override bool OnOptionsItemSelected(IMenuItem item)
|
||||
{
|
||||
switch (item.ItemId)
|
||||
{
|
||||
case Resource.Id.menu_close:
|
||||
Finish();
|
||||
break;
|
||||
}
|
||||
return base.OnOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
Any raw assets you want to be deployed with your application can be placed in
|
||||
this directory (and child directories) and given a Build Action of "AndroidAsset".
|
||||
|
||||
These files will be deployed with your package and will be accessible using Android's
|
||||
AssetManager, like this:
|
||||
|
||||
public class ReadAsset : Activity
|
||||
{
|
||||
protected override void OnCreate (Bundle bundle)
|
||||
{
|
||||
base.OnCreate (bundle);
|
||||
|
||||
InputStream input = Assets.Open ("my_asset.txt");
|
||||
}
|
||||
}
|
||||
|
||||
Additionally, some Android functions will automatically load asset files:
|
||||
|
||||
Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
|
@ -0,0 +1,80 @@
|
||||
The Fontspring Desktop Font End User License Agreement
|
||||
Version 1.6.0 - March 13, 2014
|
||||
|
||||
By downloading and/or installing font software (“Font”) offered by Fontspring or its distributors, you (“Licensee”) agree to be bound by the following terms and conditions of this End User Licensing Agreement (“EULA”):
|
||||
|
||||
1. Right Granted
|
||||
Fontspring grants Licensee a perpetual, worldwide, non-exclusive and non-transferrable license to:
|
||||
a. Use the Font to create graphics for display on any surface including computer screens, television screens, paper, t-shirts or any other surface where the image will be a fixed size.
|
||||
|
||||
b. Licensee may embed or link the Font in accordance with the rules described in Section 4 “Embedding and Linking” of this EULA.
|
||||
|
||||
2. Requirements and Restrictions
|
||||
a. Products
|
||||
Licensee may not use the Font to create alphabet or letterform products for resale where the product consists of individual letterforms, including rubber stamps, die-cut products, stencil products, or adhesive sticker alphabet products where the likeness of the Font can be reproduced and the end-user of said products can create their own typesetting. An extended license may be available for an additional fee.
|
||||
|
||||
Licensee may create typographic products using the Font if the product consists of commonly recognized words or phrases. For example: a rubber stamp that has the words "Thank You" or a sticker that says "Great!"
|
||||
|
||||
b. Dingbats and Illustrations
|
||||
Licensee may NOT use illustrations or images in the Font OTHER THAN letterforms, numbers, punctuation marks, diacritics, etc., in a manner where the illustration or image becomes the primary aspect of a product for resale. For example, a dingbat image in the font can not be the sole design element on a coffee cup, t-shirt, greeting card, etc., intended for resale. An extended license may be available for an additional fee.
|
||||
|
||||
c. Users
|
||||
The Font may be simultaneously used by no more than the number of users specified in the Receipt. A "user" is a single person or single machine, at the discretion of the Licensee. All users must belong to the same company or household purchasing the font except for temporary use by third parties as described in Section 3 “Provision to Third Parties” of this EULA.
|
||||
|
||||
3. Provision to Third Parties
|
||||
Licensee may temporarily provide the Font to a graphic designer, printer, agent or independent contractor who is working on behalf of the Licensee, ONLY IF the developer, agent or independent contractor (1) agrees in writing to use the Font exclusively for Licensee’s work, according to the terms of this EULA, and (2) retains no copies of the Font upon completion of the work.
|
||||
|
||||
Licensee may not otherwise distribute the Font to third parties or make the Font publicly accessible except by embedding or linking in accordance with this EULA.
|
||||
|
||||
4. Embedding and Linking
|
||||
a. Document Embedding (including PDF, Microsoft Word® & Microsoft Powerpoint®)
|
||||
1. Documents embedding the Font and sent to third parties, must be read-only by those recipients.
|
||||
2. Documents embedding the Font and created for in-house use or sent to third parties working on behalf of the Licensee as described in Section 3 “Provision to Third Parties” may be editable.
|
||||
|
||||
b. Flash and Silverlight Embedding
|
||||
Licensee may embed the Font into Flash or Silverlight with the following restrictions:
|
||||
1. The Font must be subset to include only the glyphs necessary for displaying the work.
|
||||
2. The text rendered in the Font must not be manipulatable by an end user.
|
||||
3. All care must be taken to prevent unauthorized users from accessing the Font.
|
||||
|
||||
c. @font-face Cascading Style Sheet ("CSS") Linking
|
||||
Licensee may not link the Font to web sites using the @font-face selector in CSS. An extended license may be available for an additional fee.
|
||||
|
||||
5. Term
|
||||
This EULA grants a perpetual license for the rights set forth in Paragraph 1 unless and until the EULA terminates under Paragraph 8. Fontspring will not charge additional fees post purchase, annually or otherwise.
|
||||
|
||||
6. Other Usage
|
||||
Licenses for @font-face embedding, computer applications and games, installable interactive books, software, mobile applications and games, Ebooks and Epubs, product creation websites, website template distribution, website templates, and other uses not allowed by this EULA may be available for an additional fee. Contact Fontspring at support@fontspring.com for more information.
|
||||
|
||||
7. Modifications
|
||||
Licensee may import and alter the bezier outlines of the Font in a drawing program.
|
||||
|
||||
Licensee may not modify the Font or create derivative works based on the Font without prior written consent from Fontspring or the owning foundry EXCEPT THAT Licensee may generate files necessary for embedding or linking in accordance with this EULA.
|
||||
|
||||
8. Copyright
|
||||
The Font is protected by copyright law. The Foundry is the sole, exclusive owner of all intellectual property rights, including rights under copyright and trademark law. Licensee agrees not to use the Font in any manner that infringes the intellectual property rights of the Foundry or violates the terms of this EULA. Licensee will be held legally responsible, and indemnifies Fontspring, for any infringements on the foundry's rights caused by failure to abide by the terms of this EULA.
|
||||
|
||||
9. Termination
|
||||
This EULA is effective until terminated. If Licensee fails to comply with any term of this EULA, Fontspring may terminate the EULA with 30 days notice. This EULA will terminate automatically 30 days after the issuance of such notice.
|
||||
|
||||
10. Disclaimer and Limited Warranty
|
||||
Fontspring warrants the Product to be free from defects in materials and workmanship under normal use for a period of twenty one (21) days from the date of delivery as shown on Receipt. Fontspring's entire liability, and Licensee’s exclusive remedy, for a defective product shall be, at Fontspring's election, either (1) return of purchase price or (2) replacement of any such product that is returned to Fontspring with a copy of the Receipt. Fontspring shall have no responsibility to replace the product or refund the purchase price if failure results from accident, abuse or misapplication, or if any product is lost or damaged due to theft, fire, or negligence. Any replacement product will be warranted for twenty one (21) days. This warranty gives Licensee specific legal rights. Licensee may have other rights, which vary from state to state.
|
||||
|
||||
EXCEPT AS EXPRESSLY PROVIDED ABOVE, THE PRODUCT, IS PROVIDED “AS IS”. FONTSPRING MAKES NO WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
The entire risk as to the quality and performance of the Product rests upon Licensee. Neither Fontspring nor the Foundry warrants that the functions contained in the Product will meet Licensee’s requirements or that the operation of the software will be uninterrupted or error free.
|
||||
|
||||
FONTSPRING SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, CONSEQUENTIAL, OR INCIDENTAL DAMAGES (INCLUDING DAMAGES FROM LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, AND THE LIKE) ARISING OUT OF THE USE OF OR INABILITY TO USE THE PRODUCT EVEN IF Fontspring OR THE FOUNDRY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
Because some states do not allow the exclusion or limitation of liability for consequential or incidental damages, the above limitation may not apply to Licensee.
|
||||
|
||||
11. Governing Law
|
||||
This EULA is governed by the laws of the United States of America and the State of Delaware.
|
||||
|
||||
12. Entire Agreement
|
||||
This EULA, in conjunction with the receipt (“Receipt”) that accompanies each Font licensed from Fontspring or its distributors, constitutes the entire agreement between Fontspring and Licensee.
|
||||
|
||||
13. Modification
|
||||
The Parties may modify or amend this EULA in writing.
|
||||
|
||||
14. Waiver. The waiver of one breach or default hereunder shall not constitute the waiver of any subsequent breach or default.
|
BIN
MobileApps/MyDriving/MyDriving.Android/Build2016.keystore
Normal file
BIN
MobileApps/MyDriving/MyDriving.Android/ClientDeviceAndroid.dll
Normal file
149
MobileApps/MyDriving/MyDriving.Android/Controls/RatingCircle.cs
Normal file
@ -0,0 +1,149 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for details.
|
||||
|
||||
using Android.Content;
|
||||
using Android.Graphics;
|
||||
using Android.Runtime;
|
||||
using Android.Util;
|
||||
using Android.Views;
|
||||
using Android.Views.Animations;
|
||||
using Android.Animation;
|
||||
using System;
|
||||
using Android.Support.V4.Content;
|
||||
|
||||
namespace MyDriving.Droid.Controls
|
||||
{
|
||||
public class RatingCircle : View
|
||||
{
|
||||
Bitmap bitmap;
|
||||
Canvas canvas;
|
||||
|
||||
RectF circleOuterBounds, circleInnerBounds;
|
||||
|
||||
Paint circlePaint, eraserPaint;
|
||||
Context context;
|
||||
float currentRating;
|
||||
float rating;
|
||||
|
||||
ValueAnimator timerAnimator;
|
||||
|
||||
public RatingCircle(IntPtr handle, JniHandleOwnership transfer)
|
||||
: base(handle, transfer)
|
||||
{
|
||||
}
|
||||
|
||||
public RatingCircle(Context context)
|
||||
: this(context, null)
|
||||
{
|
||||
}
|
||||
|
||||
public RatingCircle(Context context, IAttributeSet attrs)
|
||||
: base(context, attrs)
|
||||
{
|
||||
Init(context, attrs);
|
||||
}
|
||||
|
||||
public RatingCircle(Context context, IAttributeSet attrs, int defStyle)
|
||||
: base(context, attrs, defStyle)
|
||||
{
|
||||
Init(context, attrs);
|
||||
}
|
||||
|
||||
public float Rating
|
||||
{
|
||||
get { return rating; }
|
||||
set
|
||||
{
|
||||
rating = value;
|
||||
currentRating = 0;
|
||||
if (PlayAnimation)
|
||||
Start(1);
|
||||
else
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public bool PlayAnimation { get; set; } = true;
|
||||
|
||||
void Init(Context context, IAttributeSet attributeSet)
|
||||
{
|
||||
SetBackgroundColor(Color.Transparent);
|
||||
this.context = context;
|
||||
circlePaint = new Paint
|
||||
{
|
||||
Color = new Color(ContextCompat.GetColor(context, Resource.Color.accent)),
|
||||
AntiAlias = true
|
||||
};
|
||||
|
||||
eraserPaint = new Paint
|
||||
{
|
||||
AntiAlias = true,
|
||||
Color = Color.Transparent,
|
||||
};
|
||||
eraserPaint.SetXfermode(new PorterDuffXfermode(PorterDuff.Mode.Clear));
|
||||
}
|
||||
|
||||
protected override void OnSizeChanged(int w, int h, int oldw, int oldh)
|
||||
{
|
||||
if (w != oldw || h != oldh)
|
||||
{
|
||||
bitmap = Bitmap.CreateBitmap(w, h, Bitmap.Config.Argb8888);
|
||||
bitmap.EraseColor(Color.Transparent);
|
||||
canvas = new Canvas(bitmap);
|
||||
}
|
||||
base.OnSizeChanged(w, h, oldw, oldh);
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
void UpdateBounds()
|
||||
{
|
||||
var logicalDensity = context.Resources.DisplayMetrics.Density;
|
||||
var thickness = (int) Math.Ceiling(4*logicalDensity + .5f);
|
||||
|
||||
circleOuterBounds = new RectF(0, 0, Width, Height);
|
||||
circleInnerBounds = new RectF(
|
||||
circleOuterBounds.Left + thickness,
|
||||
circleOuterBounds.Top + thickness,
|
||||
circleOuterBounds.Right - thickness,
|
||||
circleOuterBounds.Bottom - thickness);
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
//make a perfect square
|
||||
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
|
||||
{
|
||||
var spec = widthMeasureSpec;
|
||||
base.OnMeasure(spec, spec);
|
||||
}
|
||||
|
||||
protected override void OnDraw(Canvas canvas)
|
||||
{
|
||||
this.canvas.DrawColor(Color.Transparent, PorterDuff.Mode.Clear);
|
||||
|
||||
|
||||
var sweepAngle = PlayAnimation ? (currentRating/100f)*360 : (Rating/100f)*360;
|
||||
if (sweepAngle > 0f)
|
||||
{
|
||||
this.canvas.DrawArc(circleOuterBounds, 270, sweepAngle, true, circlePaint);
|
||||
this.canvas.DrawOval(circleInnerBounds, eraserPaint);
|
||||
}
|
||||
|
||||
|
||||
canvas.DrawBitmap(bitmap, 0, 0, null);
|
||||
}
|
||||
|
||||
void Start(long secs)
|
||||
{
|
||||
timerAnimator = ValueAnimator.OfFloat(0f, Rating);
|
||||
timerAnimator.SetDuration(Java.Util.Concurrent.TimeUnit.Seconds.ToMillis(secs));
|
||||
timerAnimator.SetInterpolator(new AccelerateInterpolator());
|
||||
timerAnimator.Update += (sender, e) =>
|
||||
{
|
||||
currentRating = (float) e.Animation.AnimatedValue;
|
||||
Invalidate();
|
||||
};
|
||||
timerAnimator.Start();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,489 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for details.
|
||||
|
||||
using Android.OS;
|
||||
using Android.Support.V4.Content;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using MyDriving.Droid.Services;
|
||||
using MyDriving.ViewModel;
|
||||
using MvvmHelpers;
|
||||
using MyDriving.DataObjects;
|
||||
using Android.Gms.Maps;
|
||||
using Android.Gms.Maps.Model;
|
||||
using System;
|
||||
using Android.Graphics;
|
||||
using Android.Graphics.Drawables;
|
||||
using Plugin.Permissions;
|
||||
using Plugin.Permissions.Abstractions;
|
||||
using System.Threading.Tasks;
|
||||
using MyDriving.Droid.Activities;
|
||||
using MyDriving.Utils;
|
||||
using MyDriving.Droid.Helpers;
|
||||
using Android.Support.Design.Widget;
|
||||
using System.Collections.Specialized;
|
||||
using System.Collections.Generic;
|
||||
using Android.Views.Animations;
|
||||
using Android.Animation;
|
||||
|
||||
|
||||
namespace MyDriving.Droid.Fragments
|
||||
{
|
||||
public class FragmentCurrentTrip : Android.Support.V4.App.Fragment, IOnMapReadyCallback
|
||||
{
|
||||
List<LatLng> allPoints;
|
||||
Marker carMarker;
|
||||
TextView distance, distanceUnits, time, load, consumption, consumptionUnits;
|
||||
Polyline driveLine;
|
||||
Color? driveLineColor;
|
||||
FloatingActionButton fab;
|
||||
GoogleMap map;
|
||||
MapView mapView;
|
||||
bool setZoom = true;
|
||||
LinearLayout stats;
|
||||
|
||||
ObservableRangeCollection<TripPoint> trailPointList;
|
||||
CurrentTripViewModel viewModel;
|
||||
|
||||
public void OnMapReady(GoogleMap googleMap)
|
||||
{
|
||||
map = googleMap;
|
||||
if (viewModel != null)
|
||||
SetupMap();
|
||||
}
|
||||
|
||||
public static FragmentCurrentTrip NewInstance() => new FragmentCurrentTrip {Arguments = new Bundle()};
|
||||
|
||||
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
base.OnCreateView(inflater, container, savedInstanceState);
|
||||
HasOptionsMenu = true;
|
||||
var view = inflater.Inflate(Resource.Layout.fragment_current_trip, null);
|
||||
|
||||
mapView = view.FindViewById<MapView>(Resource.Id.map);
|
||||
mapView.OnCreate(savedInstanceState);
|
||||
|
||||
fab = view.FindViewById<FloatingActionButton>(Resource.Id.fab);
|
||||
time = view.FindViewById<TextView>(Resource.Id.text_time);
|
||||
distance = view.FindViewById<TextView>(Resource.Id.text_distance);
|
||||
distanceUnits = view.FindViewById<TextView>(Resource.Id.text_distance_units);
|
||||
consumption = view.FindViewById<TextView>(Resource.Id.text_consumption);
|
||||
consumptionUnits = view.FindViewById<TextView>(Resource.Id.text_consumption_units);
|
||||
load = view.FindViewById<TextView>(Resource.Id.text_load);
|
||||
stats = view.FindViewById<LinearLayout>(Resource.Id.stats);
|
||||
stats.Visibility = ViewStates.Invisible;
|
||||
return view;
|
||||
}
|
||||
|
||||
public override void OnActivityCreated(Bundle savedInstanceState)
|
||||
{
|
||||
mapView.GetMapAsync(this);
|
||||
base.OnActivityCreated(savedInstanceState);
|
||||
}
|
||||
|
||||
|
||||
void StartFadeAnimation(bool fadeIn)
|
||||
{
|
||||
//handle first run
|
||||
if (!viewModel.IsRecording && stats.Visibility == ViewStates.Invisible)
|
||||
return;
|
||||
|
||||
var start = fadeIn ? 0f : 1f;
|
||||
var end = fadeIn ? 1f : 0f;
|
||||
stats.Alpha = fadeIn ? 0f : 1f;
|
||||
stats.Visibility = ViewStates.Visible;
|
||||
|
||||
|
||||
var timerAnimator = ValueAnimator.OfFloat(start, end);
|
||||
timerAnimator.SetDuration(Java.Util.Concurrent.TimeUnit.Seconds.ToMillis(1));
|
||||
timerAnimator.SetInterpolator(new AccelerateInterpolator());
|
||||
timerAnimator.Update +=
|
||||
(sender, e) => { Activity.RunOnUiThread(() => stats.Alpha = (float) e.Animation.AnimatedValue); };
|
||||
timerAnimator.Start();
|
||||
}
|
||||
|
||||
void OnLocationServiceConnected(object sender, ServiceConnectedEventArgs e)
|
||||
{
|
||||
viewModel = GeolocationHelper.Current.LocationService.ViewModel;
|
||||
viewModel.PropertyChanged += OnPropertyChanged;
|
||||
ResetTrip();
|
||||
}
|
||||
|
||||
void OnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
case nameof(viewModel.CurrentPosition):
|
||||
var latlng = viewModel.CurrentPosition.ToLatLng();
|
||||
UpdateCar(latlng);
|
||||
UpdateCamera(latlng);
|
||||
break;
|
||||
case nameof(viewModel.CurrentTrip):
|
||||
TripSummaryActivity.ViewModel = viewModel.TripSummary;
|
||||
ResetTrip();
|
||||
StartActivity(new Android.Content.Intent(Activity, typeof (TripSummaryActivity)));
|
||||
break;
|
||||
case "Stats":
|
||||
UpdateStats();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateStats()
|
||||
{
|
||||
Activity?.RunOnUiThread(() =>
|
||||
{
|
||||
time.Text = viewModel.ElapsedTime;
|
||||
consumption.Text = viewModel.FuelConsumption;
|
||||
consumptionUnits.Text = viewModel.FuelConsumptionUnits;
|
||||
load.Text = viewModel.EngineLoad;
|
||||
distanceUnits.Text = viewModel.DistanceUnits;
|
||||
distance.Text = viewModel.CurrentTrip.TotalDistanceNoUnits;
|
||||
});
|
||||
}
|
||||
|
||||
void ResetTrip()
|
||||
{
|
||||
trailPointList = viewModel.CurrentTrip.Points as ObservableRangeCollection<TripPoint>;
|
||||
trailPointList.CollectionChanged += OnTrailUpdated;
|
||||
carMarker = null;
|
||||
map?.Clear();
|
||||
allPoints?.Clear();
|
||||
allPoints = null;
|
||||
SetupMap();
|
||||
UpdateStats();
|
||||
StartFadeAnimation(viewModel.IsRecording);
|
||||
Activity.SupportInvalidateOptionsMenu();
|
||||
}
|
||||
|
||||
|
||||
void AddStartMarker(LatLng start)
|
||||
{
|
||||
Activity?.RunOnUiThread(() =>
|
||||
{
|
||||
var logicalDensity = Resources.DisplayMetrics.Density;
|
||||
var thicknessPoints = (int) Math.Ceiling(20*logicalDensity + .5f);
|
||||
|
||||
var b = ContextCompat.GetDrawable(Activity, Resource.Drawable.ic_start_point) as BitmapDrawable;
|
||||
var finalIcon = Bitmap.CreateScaledBitmap(b.Bitmap, thicknessPoints, thicknessPoints, false);
|
||||
|
||||
var startMarker = new MarkerOptions();
|
||||
startMarker.SetPosition(start);
|
||||
startMarker.SetIcon(BitmapDescriptorFactory.FromBitmap(finalIcon));
|
||||
startMarker.Anchor(.5f, .5f);
|
||||
map.AddMarker(startMarker);
|
||||
});
|
||||
}
|
||||
|
||||
void AddEndMarker(LatLng end)
|
||||
{
|
||||
Activity?.RunOnUiThread(() =>
|
||||
{
|
||||
var logicalDensity = Resources.DisplayMetrics.Density;
|
||||
var thicknessPoints = (int) Math.Ceiling(20*logicalDensity + .5f);
|
||||
var b = ContextCompat.GetDrawable(Activity, Resource.Drawable.ic_end_point) as BitmapDrawable;
|
||||
var finalIcon = Bitmap.CreateScaledBitmap(b.Bitmap, thicknessPoints, thicknessPoints, false);
|
||||
|
||||
var endMarker = new MarkerOptions();
|
||||
endMarker.SetPosition(end);
|
||||
endMarker.SetIcon(BitmapDescriptorFactory.FromBitmap(finalIcon));
|
||||
endMarker.Anchor(.5f, .5f);
|
||||
|
||||
map.AddMarker(endMarker);
|
||||
});
|
||||
}
|
||||
|
||||
void OnTrailUpdated(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
Activity?.RunOnUiThread(() =>
|
||||
{
|
||||
var item = viewModel.CurrentTrip.Points[viewModel.CurrentTrip.Points.Count - 1];
|
||||
if (carMarker != null)
|
||||
UpdateMap(item);
|
||||
else
|
||||
SetupMap();
|
||||
});
|
||||
}
|
||||
|
||||
void UpdateCarIcon(bool recording)
|
||||
{
|
||||
Activity?.RunOnUiThread(() =>
|
||||
{
|
||||
var logicalDensity = Resources.DisplayMetrics.Density;
|
||||
var thicknessCar = (int) Math.Ceiling(26*logicalDensity + .5f);
|
||||
var b =
|
||||
ContextCompat.GetDrawable(Activity,
|
||||
recording ? Resource.Drawable.ic_car_red : Resource.Drawable.ic_car_blue) as BitmapDrawable;
|
||||
//var b = ContextCompat.GetDrawable(Activity, Resource.Drawable.ic_car) as BitmapDrawable;
|
||||
|
||||
var finalIcon = Bitmap.CreateScaledBitmap(b.Bitmap, thicknessCar, thicknessCar, false);
|
||||
|
||||
carMarker?.SetIcon(BitmapDescriptorFactory.FromBitmap(finalIcon));
|
||||
|
||||
fab.SetImageResource(recording ? Resource.Drawable.ic_stop : Resource.Drawable.ic_start);
|
||||
});
|
||||
}
|
||||
|
||||
void SetupMap()
|
||||
{
|
||||
if (map == null)
|
||||
return;
|
||||
|
||||
if (mapView.Width == 0)
|
||||
{
|
||||
mapView.PostDelayed(SetupMap, 500);
|
||||
return;
|
||||
}
|
||||
|
||||
if (viewModel.CurrentTrip.HasSimulatedOBDData)
|
||||
{
|
||||
var activity = (BaseActivity) Activity;
|
||||
activity.SupportActionBar.Title = "Current Trip (Sim OBD)";
|
||||
}
|
||||
|
||||
|
||||
TripPoint start = null;
|
||||
if (viewModel.CurrentTrip.Points.Count != 0)
|
||||
start = viewModel.CurrentTrip.Points[0];
|
||||
|
||||
UpdateMap(start, false);
|
||||
|
||||
if (start != null)
|
||||
{
|
||||
UpdateCamera(carMarker.Position);
|
||||
AddStartMarker(start.ToLatLng());
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateMap(TripPoint point, bool updateCamera = true)
|
||||
{
|
||||
if (map == null)
|
||||
return;
|
||||
//Get trail position or current potion to move car
|
||||
var latlng = point == null
|
||||
? viewModel?.CurrentPosition?.ToLatLng()
|
||||
: point.ToLatLng();
|
||||
Activity?.RunOnUiThread(() =>
|
||||
{
|
||||
UpdateCar(latlng);
|
||||
driveLine?.Remove();
|
||||
var polyOptions = new PolylineOptions();
|
||||
|
||||
if (allPoints == null)
|
||||
{
|
||||
allPoints = viewModel.CurrentTrip.Points.ToLatLngs();
|
||||
}
|
||||
else if (point != null)
|
||||
{
|
||||
allPoints.Add(point.ToLatLng());
|
||||
}
|
||||
|
||||
polyOptions.Add(allPoints.ToArray());
|
||||
|
||||
if (!driveLineColor.HasValue)
|
||||
driveLineColor = new Color(ContextCompat.GetColor(Activity, Resource.Color.recording_accent));
|
||||
|
||||
polyOptions.InvokeColor(driveLineColor.Value);
|
||||
driveLine = map.AddPolyline(polyOptions);
|
||||
if (updateCamera)
|
||||
UpdateCamera(latlng);
|
||||
});
|
||||
}
|
||||
|
||||
void UpdateCar(LatLng latlng)
|
||||
{
|
||||
if (latlng == null || map == null)
|
||||
return;
|
||||
Activity?.RunOnUiThread(() =>
|
||||
{
|
||||
if (carMarker == null)
|
||||
{
|
||||
var car = new MarkerOptions();
|
||||
car.SetPosition(latlng);
|
||||
car.Anchor(.5f, .5f);
|
||||
carMarker = map.AddMarker(car);
|
||||
UpdateCarIcon(viewModel.IsRecording);
|
||||
return;
|
||||
}
|
||||
carMarker.Position = latlng;
|
||||
});
|
||||
}
|
||||
|
||||
void UpdateCamera(LatLng latlng)
|
||||
{
|
||||
if (map == null)
|
||||
return;
|
||||
Activity?.RunOnUiThread(() =>
|
||||
{
|
||||
if (setZoom)
|
||||
{
|
||||
map.MoveCamera(CameraUpdateFactory.NewLatLngZoom(latlng, 14));
|
||||
setZoom = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
map.MoveCamera(CameraUpdateFactory.NewLatLng(latlng));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public override void OnStop()
|
||||
{
|
||||
base.OnStop();
|
||||
|
||||
GeolocationHelper.Current.LocationServiceConnected -= OnLocationServiceConnected;
|
||||
if (viewModel != null)
|
||||
viewModel.PropertyChanged -= OnPropertyChanged;
|
||||
if (trailPointList != null)
|
||||
trailPointList.CollectionChanged -= OnTrailUpdated;
|
||||
if (fab != null)
|
||||
fab.Click -= OnRecordButtonClick;
|
||||
//If we are recording then don't stop the background service
|
||||
if ((viewModel?.IsRecording).GetValueOrDefault())
|
||||
return;
|
||||
|
||||
GeolocationHelper.Current.LocationService.StopLocationUpdates();
|
||||
GeolocationHelper.StopLocationService();
|
||||
}
|
||||
|
||||
public override async void OnStart()
|
||||
{
|
||||
base.OnStart();
|
||||
|
||||
GeolocationHelper.Current.LocationServiceConnected += OnLocationServiceConnected;
|
||||
|
||||
if (fab != null)
|
||||
fab.Click += OnRecordButtonClick;
|
||||
await StartLocationService();
|
||||
}
|
||||
|
||||
async Task StartLocationService()
|
||||
{
|
||||
try
|
||||
{
|
||||
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Location);
|
||||
if (status != PermissionStatus.Granted)
|
||||
{
|
||||
var results = await CrossPermissions.Current.RequestPermissionsAsync(Permission.Location);
|
||||
status = results[Permission.Location];
|
||||
}
|
||||
|
||||
if (status == PermissionStatus.Granted)
|
||||
{
|
||||
if ((viewModel == null || !viewModel.IsRecording) && !GeolocationHelper.Current.IsRunning)
|
||||
await GeolocationHelper.StartLocationService();
|
||||
else
|
||||
OnLocationServiceConnected(null, null);
|
||||
}
|
||||
else if (status != PermissionStatus.Unknown)
|
||||
{
|
||||
Toast.MakeText(Activity, "Location permission is not granted, can't track location",
|
||||
ToastLength.Long);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Instance.Report(ex);
|
||||
}
|
||||
}
|
||||
|
||||
#region Options Menu & User Actions
|
||||
|
||||
public override void OnCreateOptionsMenu(IMenu menu, MenuInflater inflater)
|
||||
{
|
||||
//if((viewModel?.IsRecording).GetValueOrDefault())
|
||||
// inflater.Inflate(Resource.Menu.menu_current_trip, menu);
|
||||
base.OnCreateOptionsMenu(menu, inflater);
|
||||
}
|
||||
|
||||
public override bool OnOptionsItemSelected(IMenuItem item)
|
||||
{
|
||||
switch (item.ItemId)
|
||||
{
|
||||
case Resource.Id.menu_take_photo:
|
||||
if (!(viewModel?.IsBusy).GetValueOrDefault())
|
||||
viewModel?.TakePhotoCommand.Execute(null);
|
||||
break;
|
||||
}
|
||||
return base.OnOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
async void OnRecordButtonClick(object sender, EventArgs e)
|
||||
{
|
||||
if (viewModel?.CurrentPosition == null || viewModel.IsBusy)
|
||||
return;
|
||||
|
||||
if (viewModel.NeedSave)
|
||||
{
|
||||
await viewModel.SaveRecordingTripAsync();
|
||||
}
|
||||
|
||||
if (viewModel.IsRecording)
|
||||
{
|
||||
if (!await viewModel.StopRecordingTrip())
|
||||
return;
|
||||
|
||||
AddEndMarker(viewModel.CurrentPosition.ToLatLng());
|
||||
UpdateCarIcon(false);
|
||||
|
||||
var activity = (BaseActivity) Activity;
|
||||
activity.SupportActionBar.Title = "Current Trip";
|
||||
|
||||
await viewModel.SaveRecordingTripAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!await viewModel.StartRecordingTrip())
|
||||
return;
|
||||
AddStartMarker(viewModel.CurrentPosition.ToLatLng());
|
||||
|
||||
Activity.SupportInvalidateOptionsMenu();
|
||||
UpdateCarIcon(true);
|
||||
UpdateStats();
|
||||
StartFadeAnimation(true);
|
||||
|
||||
if (viewModel.CurrentTrip.HasSimulatedOBDData)
|
||||
{
|
||||
var activity = (BaseActivity) Activity;
|
||||
activity.SupportActionBar.Title = "Current Trip (Sim OBD)";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MapView Lifecycle Events
|
||||
|
||||
public override void OnResume()
|
||||
{
|
||||
base.OnResume();
|
||||
mapView?.OnResume();
|
||||
}
|
||||
|
||||
public override void OnPause()
|
||||
{
|
||||
base.OnPause();
|
||||
mapView?.OnPause();
|
||||
}
|
||||
|
||||
public override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
mapView?.OnDestroy();
|
||||
}
|
||||
|
||||
public override void OnSaveInstanceState(Bundle outState)
|
||||
{
|
||||
base.OnSaveInstanceState(outState);
|
||||
mapView?.OnSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
public override void OnLowMemory()
|
||||
{
|
||||
base.OnLowMemory();
|
||||
mapView?.OnLowMemory();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for details.
|
||||
|
||||
using Android.OS;
|
||||
using Fragment = Android.Support.V4.App.Fragment;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Android.Content;
|
||||
using MyDriving.Droid.Activities;
|
||||
|
||||
namespace MyDriving.Droid.Fragments
|
||||
{
|
||||
public class FragmentGettingStarted1 : Fragment
|
||||
{
|
||||
public static FragmentGettingStarted1 NewInstance() => new FragmentGettingStarted1 {Arguments = new Bundle()};
|
||||
|
||||
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
base.OnCreateView(inflater, container, savedInstanceState);
|
||||
return inflater.Inflate(Resource.Layout.fragment_started_1, null);
|
||||
}
|
||||
}
|
||||
|
||||
public class FragmentGettingStarted2 : Fragment
|
||||
{
|
||||
public static FragmentGettingStarted2 NewInstance() => new FragmentGettingStarted2 {Arguments = new Bundle()};
|
||||
|
||||
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
base.OnCreateView(inflater, container, savedInstanceState);
|
||||
return inflater.Inflate(Resource.Layout.fragment_started_2, null);
|
||||
}
|
||||
}
|
||||
|
||||
public class FragmentGettingStarted3 : Fragment
|
||||
{
|
||||
public static FragmentGettingStarted3 NewInstance() => new FragmentGettingStarted3 {Arguments = new Bundle()};
|
||||
|
||||
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
base.OnCreateView(inflater, container, savedInstanceState);
|
||||
return inflater.Inflate(Resource.Layout.fragment_started_3, null);
|
||||
}
|
||||
}
|
||||
|
||||
public class FragmentGettingStarted4 : Fragment
|
||||
{
|
||||
public static FragmentGettingStarted4 NewInstance() => new FragmentGettingStarted4 {Arguments = new Bundle()};
|
||||
|
||||
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
base.OnCreateView(inflater, container, savedInstanceState);
|
||||
return inflater.Inflate(Resource.Layout.fragment_started_4, null);
|
||||
}
|
||||
}
|
||||
|
||||
public class FragmentGettingStarted5 : Fragment
|
||||
{
|
||||
public static FragmentGettingStarted5 NewInstance() => new FragmentGettingStarted5 {Arguments = new Bundle()};
|
||||
|
||||
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
base.OnCreateView(inflater, container, savedInstanceState);
|
||||
var view = inflater.Inflate(Resource.Layout.fragment_started_5, null);
|
||||
|
||||
|
||||
view.FindViewById<Button>(Resource.Id.button_close).Click += (sender, args) =>
|
||||
{
|
||||
var intent = new Intent(Activity, typeof (LoginActivity));
|
||||
intent.AddFlags(ActivityFlags.ClearTop);
|
||||
Activity.StartActivity(intent);
|
||||
Activity.Finish();
|
||||
};
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,209 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for details.
|
||||
|
||||
using Android.OS;
|
||||
using Android.Support.V4.App;
|
||||
using Android.Views;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Support.V4.Widget;
|
||||
using Android.Widget;
|
||||
using MyDriving.ViewModel;
|
||||
using System;
|
||||
using MyDriving.Droid.Activities;
|
||||
using Android.Content;
|
||||
|
||||
|
||||
namespace MyDriving.Droid.Fragments
|
||||
{
|
||||
public class FragmentPastTrips : Fragment
|
||||
{
|
||||
TripAdapter adapter;
|
||||
LinearLayoutManager layoutManager;
|
||||
|
||||
RecyclerView recyclerView;
|
||||
SwipeRefreshLayout refresher;
|
||||
PastTripsViewModel viewModel;
|
||||
|
||||
public static FragmentPastTrips NewInstance() => new FragmentPastTrips {Arguments = new Bundle()};
|
||||
|
||||
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
base.OnCreateView(inflater, container, savedInstanceState);
|
||||
var view = inflater.Inflate(Resource.Layout.fragment_past_trips, null);
|
||||
|
||||
viewModel = new PastTripsViewModel();
|
||||
|
||||
recyclerView = view.FindViewById<RecyclerView>(Resource.Id.recyclerView);
|
||||
refresher = view.FindViewById<SwipeRefreshLayout>(Resource.Id.refresher);
|
||||
|
||||
refresher.Refresh += (sender, e) => viewModel.LoadPastTripsCommand.Execute(null);
|
||||
|
||||
|
||||
adapter = new TripAdapter(Activity, viewModel);
|
||||
adapter.ItemClick += OnItemClick;
|
||||
adapter.ItemLongClick += OnItemLongClick;
|
||||
layoutManager = new LinearLayoutManager(Activity) {Orientation = LinearLayoutManager.Vertical};
|
||||
recyclerView.SetLayoutManager(layoutManager);
|
||||
recyclerView.SetAdapter(adapter);
|
||||
recyclerView.ClearOnScrollListeners();
|
||||
recyclerView.AddOnScrollListener(new TripsOnScrollListenerListener(viewModel, layoutManager));
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
public override async void OnStart()
|
||||
{
|
||||
base.OnStart();
|
||||
viewModel.PropertyChanged += ViewModel_PropertyChanged;
|
||||
if (viewModel.Trips.Count == 0)
|
||||
await viewModel.ExecuteLoadPastTripsCommandAsync();
|
||||
}
|
||||
|
||||
void ViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
case nameof(viewModel.IsBusy):
|
||||
refresher.Refreshing = viewModel.IsBusy;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnStop()
|
||||
{
|
||||
base.OnStop();
|
||||
viewModel.PropertyChanged -= ViewModel_PropertyChanged;
|
||||
}
|
||||
|
||||
void OnItemClick(object sender, TripClickEventArgs args)
|
||||
{
|
||||
var trip = viewModel.Trips[args.Position];
|
||||
var intent = new Intent(Activity, typeof (PastTripDetailsActivity));
|
||||
intent.PutExtra("Id", trip.Id);
|
||||
intent.PutExtra("Rating", trip.Rating);
|
||||
|
||||
PastTripDetailsActivity.Trip = trip;
|
||||
Activity.StartActivity(intent);
|
||||
}
|
||||
|
||||
async void OnItemLongClick(object sender, TripClickEventArgs args)
|
||||
{
|
||||
var trip = viewModel.Trips[args.Position];
|
||||
await viewModel.ExecuteDeleteTripCommand(trip);
|
||||
}
|
||||
|
||||
class TripsOnScrollListenerListener : RecyclerView.OnScrollListener
|
||||
{
|
||||
readonly LinearLayoutManager layoutManager;
|
||||
readonly PastTripsViewModel viewModel;
|
||||
|
||||
public TripsOnScrollListenerListener(PastTripsViewModel viewModel, LinearLayoutManager layoutManager)
|
||||
{
|
||||
this.layoutManager = layoutManager;
|
||||
this.viewModel = viewModel;
|
||||
}
|
||||
|
||||
public override void OnScrolled(RecyclerView recyclerView, int dx, int dy)
|
||||
{
|
||||
base.OnScrolled(recyclerView, dx, dy);
|
||||
if (viewModel.IsBusy || viewModel.Trips.Count == 0 || !viewModel.CanLoadMore)
|
||||
return;
|
||||
|
||||
var lastVisiblePosition = layoutManager.FindLastCompletelyVisibleItemPosition();
|
||||
if (lastVisiblePosition == RecyclerView.NoPosition)
|
||||
return;
|
||||
|
||||
//if we are at the bottom and can load more.
|
||||
if (lastVisiblePosition == viewModel.Trips.Count - 1)
|
||||
viewModel.LoadMorePastTripCommand.Execute(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class TripViewHolder : RecyclerView.ViewHolder
|
||||
{
|
||||
public TripViewHolder(View itemView, Action<TripClickEventArgs> listener,
|
||||
Action<TripClickEventArgs> listenerLong) : base(itemView)
|
||||
{
|
||||
itemView.LongClickable = true;
|
||||
Title = itemView.FindViewById<TextView>(Resource.Id.text_title);
|
||||
Distance = itemView.FindViewById<TextView>(Resource.Id.text_distance);
|
||||
Date = itemView.FindViewById<TextView>(Resource.Id.text_date);
|
||||
Photo = itemView.FindViewById<ImageView>(Resource.Id.photo);
|
||||
itemView.Click +=
|
||||
(sender, e) => listener(new TripClickEventArgs {View = sender as View, Position = AdapterPosition});
|
||||
itemView.LongClick +=
|
||||
(sender, e) => listenerLong(new TripClickEventArgs {View = sender as View, Position = AdapterPosition});
|
||||
}
|
||||
|
||||
public TextView Title { get; set; }
|
||||
public TextView Date { get; set; }
|
||||
public TextView Distance { get; set; }
|
||||
public ImageView Photo { get; set; }
|
||||
}
|
||||
|
||||
public class TripClickEventArgs : EventArgs
|
||||
{
|
||||
public View View { get; set; }
|
||||
public int Position { get; set; }
|
||||
}
|
||||
|
||||
public class TripAdapter : RecyclerView.Adapter
|
||||
{
|
||||
readonly Android.App.Activity activity;
|
||||
readonly PastTripsViewModel viewModel;
|
||||
|
||||
public TripAdapter(Android.App.Activity activity, PastTripsViewModel viewModel)
|
||||
{
|
||||
this.activity = activity;
|
||||
this.viewModel = viewModel;
|
||||
|
||||
this.viewModel.Trips.CollectionChanged +=
|
||||
(sender, e) => { this.activity.RunOnUiThread(NotifyDataSetChanged); };
|
||||
}
|
||||
|
||||
public override int ItemCount => viewModel.Trips.Count;
|
||||
|
||||
public event EventHandler<TripClickEventArgs> ItemClick;
|
||||
public event EventHandler<TripClickEventArgs> ItemLongClick;
|
||||
|
||||
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType) =>
|
||||
new TripViewHolder(LayoutInflater.From(parent.Context).Inflate(Resource.Layout.item_trip, parent, false),
|
||||
OnClick, OnClickLong);
|
||||
|
||||
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
|
||||
{
|
||||
var vh = holder as TripViewHolder;
|
||||
if (vh == null)
|
||||
return;
|
||||
|
||||
var trip = viewModel.Trips[position];
|
||||
vh.Title.Text = trip.Name;
|
||||
vh.Distance.Text = trip.TotalDistance;
|
||||
vh.Date.Text = trip.TimeAgo;
|
||||
vh.Photo.Visibility = (trip?.Photos?.Count).GetValueOrDefault() > 0 ||
|
||||
!string.IsNullOrWhiteSpace(trip.MainPhotoUrl)
|
||||
? ViewStates.Visible
|
||||
: ViewStates.Gone;
|
||||
|
||||
if (vh.Photo.Visibility == ViewStates.Visible)
|
||||
{
|
||||
if ((trip?.Photos?.Count).GetValueOrDefault() > 0)
|
||||
Square.Picasso.Picasso.With(activity).Load($"file://{trip.Photos[0].PhotoUrl}").Into(vh.Photo);
|
||||
else
|
||||
Square.Picasso.Picasso.With(activity).Load(trip.MainPhotoUrl).Into(vh.Photo);
|
||||
}
|
||||
}
|
||||
|
||||
void OnClick(TripClickEventArgs args)
|
||||
{
|
||||
ItemClick?.Invoke(this, args);
|
||||
}
|
||||
|
||||
void OnClickLong(TripClickEventArgs args)
|
||||
{
|
||||
ItemLongClick?.Invoke(this, args);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for details.
|
||||
|
||||
using Android.OS;
|
||||
using Android.Support.V4.App;
|
||||
using Android.Views;
|
||||
using MyDriving.Droid.Controls;
|
||||
using Refractored.Controls;
|
||||
using MyDriving.Utils;
|
||||
using MyDriving.ViewModel;
|
||||
using Android.Widget;
|
||||
|
||||
namespace MyDriving.Droid.Fragments
|
||||
{
|
||||
public class FragmentProfile : Fragment
|
||||
{
|
||||
CircleImageView circleImage;
|
||||
|
||||
TextView distance,
|
||||
maxSpeed,
|
||||
time,
|
||||
stops,
|
||||
accelerations,
|
||||
trips,
|
||||
fuelUsed,
|
||||
distanceUnits,
|
||||
profileRating,
|
||||
profileGreat;
|
||||
|
||||
LinearLayout profileAll;
|
||||
|
||||
RatingCircle ratingCircle;
|
||||
bool refresh = true;
|
||||
ProfileViewModel viewModel;
|
||||
public static FragmentProfile NewInstance() => new FragmentProfile {Arguments = new Bundle()};
|
||||
|
||||
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
base.OnCreateView(inflater, container, savedInstanceState);
|
||||
var view = inflater.Inflate(Resource.Layout.fragment_profile, null);
|
||||
|
||||
ratingCircle = view.FindViewById<RatingCircle>(Resource.Id.rating_circle);
|
||||
circleImage = view.FindViewById<CircleImageView>(Resource.Id.profile_image);
|
||||
|
||||
|
||||
viewModel = new ProfileViewModel();
|
||||
Square.Picasso.Picasso.With(Activity).Load(Settings.Current.UserProfileUrl).Into(circleImage);
|
||||
|
||||
trips = view.FindViewById<TextView>(Resource.Id.text_trips);
|
||||
time = view.FindViewById<TextView>(Resource.Id.text_time);
|
||||
distance = view.FindViewById<TextView>(Resource.Id.text_distance);
|
||||
maxSpeed = view.FindViewById<TextView>(Resource.Id.text_max_speed);
|
||||
fuelUsed = view.FindViewById<TextView>(Resource.Id.text_fuel_consumption);
|
||||
accelerations = view.FindViewById<TextView>(Resource.Id.text_hard_accelerations);
|
||||
stops = view.FindViewById<TextView>(Resource.Id.text_hard_breaks);
|
||||
profileAll = view.FindViewById<LinearLayout>(Resource.Id.text_profile_all);
|
||||
|
||||
profileGreat = view.FindViewById<TextView>(Resource.Id.text_profile_great);
|
||||
profileRating = view.FindViewById<TextView>(Resource.Id.text_profile_rating);
|
||||
profileAll.Visibility = ViewStates.Invisible;
|
||||
UpdateUI();
|
||||
return view;
|
||||
}
|
||||
|
||||
public override void OnStart()
|
||||
{
|
||||
base.OnStart();
|
||||
|
||||
if (refresh)
|
||||
{
|
||||
refresh = false;
|
||||
viewModel.UpdateProfileAsync().ContinueWith(t => UpdateUI());
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateUI()
|
||||
{
|
||||
Activity.RunOnUiThread(() =>
|
||||
{
|
||||
trips.Text = viewModel.TotalTrips.ToString();
|
||||
time.Text = viewModel.TotalTimeDisplay;
|
||||
distance.Text = viewModel.TotalDistanceDisplay;
|
||||
maxSpeed.Text = viewModel.MaxSpeedDisplay;
|
||||
fuelUsed.Text = viewModel.FuelDisplay;
|
||||
accelerations.Text = viewModel.HardAccelerations.ToString();
|
||||
stops.Text = viewModel.HardStops.ToString();
|
||||
ratingCircle.Rating = viewModel.DrivingSkills;
|
||||
|
||||
profileGreat.Text = $"Driving Skills: {viewModel.DrivingSkillsPlacementBucket.Description}";
|
||||
profileRating.Text = $"{viewModel.DrivingSkills.ToString()}%";
|
||||
|
||||
|
||||
profileAll.Visibility = ViewStates.Visible;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for details.
|
||||
|
||||
using Android.OS;
|
||||
using Android.Support.V7.Preferences;
|
||||
using MyDriving.ViewModel;
|
||||
|
||||
namespace MyDriving.Droid.Fragments
|
||||
{
|
||||
public class FragmentSettings : PreferenceFragmentCompat
|
||||
{
|
||||
SettingsViewModel viewModel;
|
||||
public static FragmentSettings NewInstance() => new FragmentSettings {Arguments = new Bundle()};
|
||||
|
||||
public override void OnCreatePreferences(Bundle p0, string p1)
|
||||
{
|
||||
AddPreferencesFromResource(Resource.Xml.preferences);
|
||||
viewModel = new SettingsViewModel();
|
||||
}
|
||||
|
||||
public override void OnCreate(Bundle savedInstanceState)
|
||||
{
|
||||
base.OnCreate(savedInstanceState);
|
||||
|
||||
FindPreference("url_privacy").PreferenceClick +=
|
||||
(sender, args) => viewModel.OpenBrowserCommand.Execute(viewModel.PrivacyPolicyUrl);
|
||||
FindPreference("url_copyright").PreferenceClick +=
|
||||
(sender, args) => viewModel.OpenBrowserCommand.Execute(viewModel.PrivacyPolicyUrl);
|
||||
FindPreference("url_xamarin").PreferenceClick +=
|
||||
(sender, args) => viewModel.OpenBrowserCommand.Execute(viewModel.XamarinUrl);
|
||||
FindPreference("url_terms").PreferenceClick +=
|
||||
(sender, args) => viewModel.OpenBrowserCommand.Execute(viewModel.TermsOfUseUrl);
|
||||
FindPreference("url_open_notice").PreferenceClick +=
|
||||
(sender, args) => viewModel.OpenBrowserCommand.Execute(viewModel.OpenSourceNoticeUrl);
|
||||
FindPreference("url_github").PreferenceClick +=
|
||||
(sender, args) => viewModel.OpenBrowserCommand.Execute(viewModel.SourceOnGitHubUrl);
|
||||
FindPreference("leave_feedback").PreferenceClick +=
|
||||
(sender, args) => HockeyApp.FeedbackManager.ShowFeedbackActivity(Activity);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for details.
|
||||
|
||||
using Android.Content;
|
||||
using Android.Hardware;
|
||||
using Java.Lang;
|
||||
using Exception = System.Exception;
|
||||
using Math = System.Math;
|
||||
|
||||
namespace MyDriving.Droid.Helpers
|
||||
{
|
||||
public interface IAccelerometerListener
|
||||
{
|
||||
void OnAccelerationChanged(float x, float y, float z);
|
||||
void OnShake(float force);
|
||||
}
|
||||
|
||||
public class AccelerometerManager
|
||||
{
|
||||
readonly ShakeSensorEventListener eventListener;
|
||||
readonly SensorManager sensorManager;
|
||||
Sensor sensor;
|
||||
|
||||
public AccelerometerManager(Context context, IAccelerometerListener listener)
|
||||
{
|
||||
eventListener = new ShakeSensorEventListener(listener);
|
||||
sensorManager = (SensorManager) context.GetSystemService(Context.SensorService);
|
||||
IsSupported = sensorManager.GetSensorList(SensorType.Accelerometer).Count > 0;
|
||||
}
|
||||
|
||||
public bool IsSupported { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets if the manager is listening to orientation changes
|
||||
/// </summary>
|
||||
public bool IsListening { get; private set; }
|
||||
|
||||
public void Configure(int threshold, int interval)
|
||||
{
|
||||
eventListener.Threshold = threshold;
|
||||
eventListener.Interval = interval;
|
||||
}
|
||||
|
||||
public void StopListening()
|
||||
{
|
||||
IsListening = false;
|
||||
try
|
||||
{
|
||||
if (sensorManager != null && eventListener != null)
|
||||
{
|
||||
sensorManager.UnregisterListener(eventListener);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void StartListening()
|
||||
{
|
||||
var sensors = sensorManager.GetSensorList(SensorType.Accelerometer);
|
||||
if (sensors.Count > 0)
|
||||
{
|
||||
sensor = sensors[0];
|
||||
IsListening = sensorManager.RegisterListener(eventListener, sensor, SensorDelay.Game);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ShakeSensorEventListener : Object, ISensorEventListener
|
||||
{
|
||||
readonly IAccelerometerListener listener;
|
||||
long now, timeDiff, lastUpdate, lastShake;
|
||||
float x, y, z, lastX, lastY, lastZ, force;
|
||||
|
||||
|
||||
public ShakeSensorEventListener(IAccelerometerListener listener)
|
||||
{
|
||||
this.listener = listener;
|
||||
Threshold = 25.0f;
|
||||
Interval = 200;
|
||||
}
|
||||
|
||||
//Accuracy Configuration
|
||||
public float Threshold { get; set; }
|
||||
public int Interval { get; set; }
|
||||
|
||||
public void OnAccuracyChanged(Sensor sensor, SensorStatus accuracy)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnSensorChanged(SensorEvent e)
|
||||
{
|
||||
try
|
||||
{
|
||||
now = e.Timestamp;
|
||||
x = e.Values[0];
|
||||
y = e.Values[1];
|
||||
z = e.Values[2];
|
||||
|
||||
if (lastUpdate == 0)
|
||||
{
|
||||
lastUpdate = now;
|
||||
lastShake = now;
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
lastZ = z;
|
||||
}
|
||||
else
|
||||
{
|
||||
timeDiff = now - lastUpdate;
|
||||
if (timeDiff <= 0)
|
||||
return;
|
||||
|
||||
force = Math.Abs(x + y + z - lastX - lastY - lastZ);
|
||||
if (Float.Compare(force, Threshold) > 0)
|
||||
{
|
||||
if (now - lastShake >= Interval)
|
||||
listener.OnShake(force);
|
||||
|
||||
lastShake = now;
|
||||
}
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
lastZ = z;
|
||||
lastUpdate = now;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
listener.OnAccelerationChanged(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for details.
|
||||
|
||||
using Android.Gms.Maps.Model;
|
||||
using MyDriving.DataObjects;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MyDriving.Droid.Helpers
|
||||
{
|
||||
public static class LocationExtensions
|
||||
{
|
||||
public static LatLng ToLatLng(this TripPoint point) => new LatLng(point.Latitude, point.Longitude);
|
||||
|
||||
public static LatLng ToLatLng(this Plugin.Geolocator.Abstractions.Position point)
|
||||
=> new LatLng(point.Latitude, point.Longitude);
|
||||
|
||||
public static List<LatLng> ToLatLngs(this IEnumerable<TripPoint> points)
|
||||
=> new List<LatLng>(points.Select(s => s.ToLatLng()));
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for details.
|
||||
|
||||
using System;
|
||||
using MyDriving.Utils;
|
||||
using MyDriving.Utils.Interfaces;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.WindowsAzure.MobileServices;
|
||||
using Plugin.CurrentActivity;
|
||||
|
||||
namespace MyDriving.Droid.Helpers
|
||||
{
|
||||
public class Authentication : IAuthentication
|
||||
{
|
||||
public async Task<MobileServiceUser> LoginAsync(IMobileServiceClient client, MobileServiceAuthenticationProvider provider)
|
||||
{
|
||||
MobileServiceUser user = null;
|
||||
|
||||
try
|
||||
{
|
||||
Settings.Current.LoginAttempts++;
|
||||
|
||||
user = await client.LoginAsync(CrossCurrentActivity.Current.Activity, provider);
|
||||
Settings.Current.AuthToken = user?.MobileServiceAuthenticationToken ?? string.Empty;
|
||||
Settings.Current.AzureMobileUserId = user?.UserId ?? string.Empty;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//Don't log if the user cancelled out of the login screen
|
||||
if (!e.Message.Contains("cancelled"))
|
||||
{
|
||||
e.Data["method"] = "LoginAsync";
|
||||
Logger.Instance.Report(e);
|
||||
}
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
public void ClearCookies()
|
||||
{
|
||||
try
|
||||
{
|
||||
if ((int) Android.OS.Build.VERSION.SdkInt >= 21)
|
||||
Android.Webkit.CookieManager.Instance.RemoveAllCookies(null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Instance.Report(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for details.
|
||||
|
BIN
MobileApps/MyDriving/MyDriving.Android/Icon.png
Normal file
After Width: | Height: | Size: 60 KiB |
77
MobileApps/MyDriving/MyDriving.Android/MainApplication.cs
Normal file
@ -0,0 +1,77 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for details.
|
||||
|
||||
using System;
|
||||
using Android.App;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Plugin.CurrentActivity;
|
||||
using MyDriving.Utils;
|
||||
using MyDriving.Utils.Interfaces;
|
||||
using MyDriving.Interfaces;
|
||||
using MyDriving.Droid.Helpers;
|
||||
using Acr.UserDialogs;
|
||||
using MyDriving.Shared;
|
||||
|
||||
namespace MyDriving.Droid
|
||||
{
|
||||
[Application]
|
||||
public class MainApplication : Application, Application.IActivityLifecycleCallbacks
|
||||
{
|
||||
public MainApplication(IntPtr handle, JniHandleOwnership transer)
|
||||
: base(handle, transer)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnActivityCreated(Activity activity, Bundle savedInstanceState)
|
||||
=> CrossCurrentActivity.Current.Activity = activity;
|
||||
|
||||
public void OnActivityDestroyed(Activity activity)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnActivityPaused(Activity activity)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnActivityResumed(Activity activity) => CrossCurrentActivity.Current.Activity = activity;
|
||||
|
||||
public void OnActivitySaveInstanceState(Activity activity, Bundle outState)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnActivityStarted(Activity activity)
|
||||
{
|
||||
CrossCurrentActivity.Current.Activity = activity;
|
||||
#if !XTC
|
||||
HockeyApp.Tracking.StartUsage(activity);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void OnActivityStopped(Activity activity)
|
||||
{
|
||||
#if !XTC
|
||||
HockeyApp.Tracking.StopUsage(activity);
|
||||
#endif
|
||||
}
|
||||
|
||||
public override void OnCreate()
|
||||
{
|
||||
base.OnCreate();
|
||||
RegisterActivityLifecycleCallbacks(this);
|
||||
ViewModel.ViewModelBase.Init();
|
||||
ServiceLocator.Instance.Add<IAuthentication, Authentication>();
|
||||
ServiceLocator.Instance.Add<Utils.Interfaces.ILogger, PlatformLogger>();
|
||||
ServiceLocator.Instance.Add<IOBDDevice, OBDDevice>();
|
||||
|
||||
Microsoft.WindowsAzure.MobileServices.CurrentPlatform.Init();
|
||||
UserDialogs.Init(() => CrossCurrentActivity.Current.Activity);
|
||||
}
|
||||
|
||||
public override void OnTerminate()
|
||||
{
|
||||
base.OnTerminate();
|
||||
UnregisterActivityLifecycleCallbacks(this);
|
||||
}
|
||||
}
|
||||
}
|
481
MobileApps/MyDriving/MyDriving.Android/MyDriving.Android.csproj
Normal file
@ -0,0 +1,481 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<ProjectGuid>{B09661C2-82A6-4D16-B4FD-7B23D0FFE1FE}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>MyDriving.Droid</RootNamespace>
|
||||
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
|
||||
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
|
||||
<AndroidResgenClass>Resource</AndroidResgenClass>
|
||||
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
|
||||
<AndroidApplication>True</AndroidApplication>
|
||||
<AndroidUseLatestPlatformSdk>False</AndroidUseLatestPlatformSdk>
|
||||
<TargetFrameworkVersion>v6.0</TargetFrameworkVersion>
|
||||
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;__ANDROID__</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
|
||||
<AndroidKeyStore>True</AndroidKeyStore>
|
||||
<AndroidSigningKeyStore>Build2016.keystore</AndroidSigningKeyStore>
|
||||
<AndroidSigningStorePass>Build*1234</AndroidSigningStorePass>
|
||||
<AndroidSigningKeyAlias>Build2016</AndroidSigningKeyAlias>
|
||||
<AndroidSigningKeyPass>Build*1234</AndroidSigningKeyPass>
|
||||
<AssemblyName>MyDriving.Droid</AssemblyName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
<AndroidSupportedAbis>armeabi-v7a;x86</AndroidSupportedAbis>
|
||||
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
|
||||
<AssemblyName>MyDriving.Droid</AssemblyName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'XTC|AnyCPU' ">
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\XTC</OutputPath>
|
||||
<DefineConstants>XTC</DefineConstants>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AndroidSupportedAbis>armeabi-v7a;x86;armeabi;arm64-v8a;x86_64</AndroidSupportedAbis>
|
||||
<AndroidFastDeploymentType>
|
||||
</AndroidFastDeploymentType>
|
||||
<AssemblyName>MyDriving.Android</AssemblyName>
|
||||
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
|
||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="HockeySDK, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\HockeySDK.Xamarin.4.1.0-beta1\lib\MonoAndroid403\HockeySDK.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Azure.Devices.Client.PCL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Microsoft.Azure.Devices.Client.PCL.1.0.3\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10+UAP10\Microsoft.Azure.Devices.Client.PCL.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Newtonsoft.Json.8.0.3\lib\portable-net40+sl5+wp80+win8+wpa81\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="PCLCrypto, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d4421c8a4786956c, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\PCLCrypto.1.0.86\lib\monoandroid\PCLCrypto.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.DeviceInfo, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xam.Plugin.DeviceInfo.2.0.2\lib\MonoAndroid10\Plugin.DeviceInfo.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.DeviceInfo.Abstractions, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xam.Plugin.DeviceInfo.2.0.2\lib\MonoAndroid10\Plugin.DeviceInfo.Abstractions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.Media, Version=2.2.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xam.Plugin.Media.2.4.0-beta3\lib\MonoAndroid10\Plugin.Media.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.Media.Abstractions, Version=2.2.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xam.Plugin.Media.2.4.0-beta3\lib\MonoAndroid10\Plugin.Media.Abstractions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.Share, Version=4.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Plugin.Share.4.0.0\lib\MonoAndroid10\Plugin.Share.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.Share.Abstractions, Version=4.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Plugin.Share.4.0.0\lib\MonoAndroid10\Plugin.Share.Abstractions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Square.OkHttp, Version=2.7.5.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Square.OkHttp.2.7.5.0\lib\MonoAndroid\Square.OkHttp.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="Mono.Android" />
|
||||
<Reference Include="Microsoft.WindowsAzure.Mobile, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
|
||||
<HintPath>..\..\packages\Microsoft.Azure.Mobile.Client.2.0.1\lib\monoandroid\Microsoft.WindowsAzure.Mobile.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.WindowsAzure.Mobile.Ext, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
|
||||
<HintPath>..\..\packages\Microsoft.Azure.Mobile.Client.2.0.1\lib\monoandroid\Microsoft.WindowsAzure.Mobile.Ext.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.WindowsAzure.Mobile.SQLiteStore, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
|
||||
<HintPath>..\..\packages\Microsoft.Azure.Mobile.Client.SQLiteStore.2.0.1\lib\portable-win+net45+wp8+wpa81+monotouch+monoandroid\Microsoft.WindowsAzure.Mobile.SQLiteStore.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.CurrentActivity, Version=1.0.1.0, Culture=neutral, PublicKeyToken=null">
|
||||
<HintPath>..\..\packages\Plugin.CurrentActivity.1.0.1\lib\MonoAndroid10\Plugin.CurrentActivity.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.Geolocator, Version=3.0.4.0, Culture=neutral, PublicKeyToken=null">
|
||||
<HintPath>..\..\packages\Xam.Plugin.Geolocator.3.0.4\lib\MonoAndroid10\Plugin.Geolocator.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.Geolocator.Abstractions, Version=3.0.4.0, Culture=neutral, PublicKeyToken=null">
|
||||
<HintPath>..\..\packages\Xam.Plugin.Geolocator.3.0.4\lib\MonoAndroid10\Plugin.Geolocator.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.Permissions, Version=1.1.6.0, Culture=neutral, PublicKeyToken=null">
|
||||
<HintPath>..\..\packages\Plugin.Permissions.1.1.7\lib\MonoAndroid10\Plugin.Permissions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.Permissions.Abstractions, Version=1.1.6.0, Culture=neutral, PublicKeyToken=null">
|
||||
<HintPath>..\..\packages\Plugin.Permissions.1.1.7\lib\MonoAndroid10\Plugin.Permissions.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.Settings, Version=2.1.0.0, Culture=neutral, PublicKeyToken=null">
|
||||
<HintPath>..\..\packages\Xam.Plugins.Settings.2.1.0\lib\MonoAndroid10\Plugin.Settings.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.Settings.Abstractions, Version=2.1.0.0, Culture=neutral, PublicKeyToken=null">
|
||||
<HintPath>..\..\packages\Xam.Plugins.Settings.2.1.0\lib\MonoAndroid10\Plugin.Settings.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCL, Version=3.8.7.2, Culture=neutral, PublicKeyToken=bddade01e9c850c5">
|
||||
<HintPath>..\..\packages\SQLitePCL.3.8.7.2\lib\MonoAndroid\SQLitePCL.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCL.Ext, Version=3.8.7.2, Culture=neutral, PublicKeyToken=bddade01e9c850c5">
|
||||
<HintPath>..\..\packages\SQLitePCL.3.8.7.2\lib\MonoAndroid\SQLitePCL.Ext.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http.Extensions, Version=2.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<HintPath>..\..\packages\Microsoft.Net.Http.2.2.29\lib\monoandroid\System.Net.Http.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http.Primitives, Version=4.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<HintPath>..\..\packages\Microsoft.Net.Http.2.2.29\lib\monoandroid\System.Net.Http.Primitives.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.EmbeddedResource">
|
||||
<HintPath>..\..\packages\Xam.Plugin.EmbeddedResource.1.0.1.0\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Plugin.EmbeddedResource.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PCLStorage">
|
||||
<HintPath>..\..\packages\PCLStorage.1.0.2\lib\monoandroid\PCLStorage.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PCLStorage.Abstractions">
|
||||
<HintPath>..\..\packages\PCLStorage.1.0.2\lib\monoandroid\PCLStorage.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Humanizer, Version=2.0.1.0, Culture=neutral, PublicKeyToken=979442b78dfc278e">
|
||||
<HintPath>..\..\packages\Humanizer.Core.2.0.1\lib\dotnet\Humanizer.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Refractored.Controls.CircleImageView">
|
||||
<HintPath>..\..\packages\Refractored.Controls.CircleImageView.1.0.1\lib\MonoAndroid10\Refractored.Controls.CircleImageView.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Validation, Version=2.0.0.0, Culture=neutral, PublicKeyToken=2fc06f0d701809a7, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Validation.2.0.6.15003\lib\portable-net40+sl50+win+wpa81+wp80+Xamarin.iOS10+MonoAndroid10+MonoTouch10\Validation.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Android.Support.CustomTabs, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Android.Support.CustomTabs.23.1.1.1\lib\MonoAndroid403\Xamarin.Android.Support.CustomTabs.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Android.Support.Design, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Android.Support.Design.23.1.1.1\lib\MonoAndroid403\Xamarin.Android.Support.Design.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Android.Support.v14.Preference, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Android.Support.v14.Preference.23.1.1.1\lib\MonoAndroid41\Xamarin.Android.Support.v14.Preference.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Android.Support.v4, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Android.Support.v4.23.1.1.1\lib\MonoAndroid403\Xamarin.Android.Support.v4.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Android.Support.v7.AppCompat, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Android.Support.v7.AppCompat.23.1.1.1\lib\MonoAndroid403\Xamarin.Android.Support.v7.AppCompat.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Android.Support.v7.CardView, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Android.Support.v7.CardView.23.1.1.1\lib\MonoAndroid403\Xamarin.Android.Support.v7.CardView.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Android.Support.v7.Palette, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Android.Support.v7.Palette.23.1.1.1\lib\MonoAndroid403\Xamarin.Android.Support.v7.Palette.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Android.Support.v7.Preference, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Android.Support.v7.Preference.23.1.1.1\lib\MonoAndroid41\Xamarin.Android.Support.v7.Preference.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Android.Support.v7.RecyclerView, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Android.Support.v7.RecyclerView.23.1.1.1\lib\MonoAndroid403\Xamarin.Android.Support.v7.RecyclerView.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Android.Support.v8.RenderScript, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.Android.Support.v8.RenderScript.23.1.1.1\lib\MonoAndroid403\Xamarin.Android.Support.v8.RenderScript.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.GooglePlayServices.Base, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.GooglePlayServices.Base.29.0.0.1\lib\MonoAndroid41\Xamarin.GooglePlayServices.Base.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.GooglePlayServices.Basement, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.GooglePlayServices.Basement.29.0.0.1\lib\MonoAndroid41\Xamarin.GooglePlayServices.Basement.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.GooglePlayServices.Maps, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Xamarin.GooglePlayServices.Maps.29.0.0.1\lib\MonoAndroid41\Xamarin.GooglePlayServices.Maps.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Square.Picasso">
|
||||
<HintPath>..\..\packages\Square.Picasso.2.5.2.1\lib\MonoAndroid\Square.Picasso.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Square.OkIO">
|
||||
<HintPath>..\..\packages\Square.OkIO.1.6.0.0\lib\MonoAndroid\Square.OkIO.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Splat">
|
||||
<HintPath>..\..\packages\Splat.1.6.2\lib\monoandroid\Splat.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Acr.Support.Android">
|
||||
<HintPath>..\..\packages\Acr.Support.1.1.1\lib\MonoAndroid10\Acr.Support.Android.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.Connectivity">
|
||||
<HintPath>..\..\packages\Xam.Plugin.Connectivity.2.1.2\lib\MonoAndroid10\Plugin.Connectivity.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Plugin.Connectivity.Abstractions">
|
||||
<HintPath>..\..\packages\Xam.Plugin.Connectivity.2.1.2\lib\MonoAndroid10\Plugin.Connectivity.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Acr.UserDialogs">
|
||||
<HintPath>..\..\packages\Acr.UserDialogs.Android.AppCompat.4.3.2\lib\MonoAndroid10\Acr.UserDialogs.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Acr.UserDialogs.Interface">
|
||||
<HintPath>..\..\packages\Acr.UserDialogs.Android.AppCompat.4.3.2\lib\MonoAndroid10\Acr.UserDialogs.Interface.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="AndHUD">
|
||||
<HintPath>..\..\packages\Acr.UserDialogs.Android.AppCompat.4.3.2\lib\MonoAndroid10\AndHUD.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MvvmHelpers">
|
||||
<HintPath>..\..\packages\Refractored.MvvmHelpers.1.0.1\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10+UAP10\MvvmHelpers.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MyDriving.DataStore.Abstractions\MyDriving.DataStore.Abstractions.csproj">
|
||||
<Project>{649300CE-70EA-4606-983F-F4476FDD6C7E}</Project>
|
||||
<Name>MyDriving.DataStore.Abstractions</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MyDriving.DataStore.Azure\MyDriving.DataStore.Azure.csproj">
|
||||
<Project>{E05FB3D8-372D-4FD3-84F3-1E908E3861B6}</Project>
|
||||
<Name>MyDriving.DataStore.Azure</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MyDriving.DataStore.Mock\MyDriving.DataStore.Mock.csproj">
|
||||
<Project>{42F3D3DF-B854-4A5B-9C94-F3D823116AD5}</Project>
|
||||
<Name>MyDriving.DataStore.Mock</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MyDriving\MyDriving.csproj">
|
||||
<Name>MyDriving</Name>
|
||||
<Project>{A68CCCDA-E4A5-4128-920F-AC00ECB9E3E6}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MyDriving.Utils\MyDriving.Utils.csproj">
|
||||
<Project>{CEF8CB82-B2BF-42D0-998C-8C50A4CA7AE6}</Project>
|
||||
<Name>MyDriving.Utils</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MyDriving.AzureClient\MyDriving.AzureClient.csproj">
|
||||
<Project>{29B6B823-6639-4942-9723-0075BBEF7C69}</Project>
|
||||
<Name>MyDriving.AzureClient</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\OBDLibrary\ObdLibAndroid\ObdLibAndroid.csproj">
|
||||
<Project>{9A377DF7-3E28-4B4B-8BD2-61416F7AEA1F}</Project>
|
||||
<Name>ObdLibAndroid</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Helpers\Settings.cs" />
|
||||
<Compile Include="MainApplication.cs" />
|
||||
<Compile Include="Resources\Resource.designer.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Fragments\FragmentPastTrips.cs" />
|
||||
<Compile Include="Fragments\FragmentCurrentTrip.cs" />
|
||||
<Compile Include="Fragments\FragmentSettings.cs" />
|
||||
<Compile Include="Helpers\Authentication.cs" />
|
||||
<Compile Include="Services\GeolocationService.cs" />
|
||||
<Compile Include="Services\GeolocationHelper.cs" />
|
||||
<Compile Include="Activities\BaseActivity.cs" />
|
||||
<Compile Include="Activities\LoginActivity.cs" />
|
||||
<Compile Include="Activities\MainActivity.cs" />
|
||||
<Compile Include="Activities\SplashActivity.cs" />
|
||||
<Compile Include="Activities\PastTripDetailsActivity.cs" />
|
||||
<Compile Include="Helpers\AccelerometerManager.cs" />
|
||||
<Compile Include="Controls\RatingCircle.cs" />
|
||||
<Compile Include="Fragments\FragmentProfile.cs" />
|
||||
<Compile Include="Activities\TripSummaryActivity.cs" />
|
||||
<Compile Include="Helpers\AndroidExtensions.cs" />
|
||||
<Compile Include="Fragments\FragmentGettingStarted.cs" />
|
||||
<Compile Include="Activities\GettingStartedActivity.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
<None Include="Resources\AboutResources.txt" />
|
||||
<None Include="Properties\AndroidManifest.xml" />
|
||||
<None Include="Assets\AboutAssets.txt" />
|
||||
<AndroidResource Include="Resources\layout\toolbar.axml">
|
||||
<SubType>AndroidResource</SubType>
|
||||
</AndroidResource>
|
||||
<AndroidResource Include="Resources\layout\nav_header.axml">
|
||||
<SubType>AndroidResource</SubType>
|
||||
</AndroidResource>
|
||||
<AndroidResource Include="Resources\layout\fragment_past_trips.axml" />
|
||||
<AndroidResource Include="Resources\layout\item_trip.axml" />
|
||||
<AndroidResource Include="Resources\layout\fragment_profile.axml" />
|
||||
<AndroidResource Include="Resources\layout\activity_login.axml" />
|
||||
<AndroidResource Include="Resources\layout\activity_main.axml" />
|
||||
<AndroidResource Include="Resources\values\dimen.xml" />
|
||||
<AndroidResource Include="Resources\layout\activity_past_trip_details.axml" />
|
||||
<AndroidResource Include="Resources\xml\preferences.xml" />
|
||||
<AndroidResource Include="Resources\drawable-hdpi\menu_past_trips.png" />
|
||||
<AndroidResource Include="Resources\drawable-mdpi\menu_past_trips.png" />
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\menu_past_trips.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\menu_past_trips.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\menu_past_trips.png" />
|
||||
<AndroidResource Include="Resources\drawable-hdpi\menu_settings.png" />
|
||||
<AndroidResource Include="Resources\drawable-mdpi\menu_settings.png" />
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\menu_settings.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\menu_settings.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\menu_settings.png" />
|
||||
<AndroidResource Include="Resources\drawable-hdpi\menu_profile.png" />
|
||||
<AndroidResource Include="Resources\drawable-mdpi\menu_profile.png" />
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\menu_profile.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\menu_profile.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\menu_profile.png" />
|
||||
<AndroidResource Include="Resources\drawable-hdpi\menu_current_trip.png" />
|
||||
<AndroidResource Include="Resources\drawable-mdpi\menu_current_trip.png" />
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\menu_current_trip.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\menu_current_trip.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\menu_current_trip.png" />
|
||||
<AndroidResource Include="Resources\drawable-hdpi\ic_camera.png" />
|
||||
<AndroidResource Include="Resources\drawable-mdpi\ic_camera.png" />
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\ic_camera.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\ic_camera.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\ic_camera.png" />
|
||||
<AndroidResource Include="Resources\menu\menu_current_trip.xml" />
|
||||
<AndroidResource Include="Resources\drawable-hdpi\ic_stop.png" />
|
||||
<AndroidResource Include="Resources\drawable-hdpi\ic_start.png" />
|
||||
<AndroidResource Include="Resources\drawable-mdpi\ic_start.png" />
|
||||
<AndroidResource Include="Resources\drawable-mdpi\ic_stop.png" />
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\ic_start.png" />
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\ic_stop.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\ic_start.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\ic_stop.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\ic_start.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\ic_stop.png" />
|
||||
<AndroidResource Include="Resources\drawable-hdpi\ic_twitter.png" />
|
||||
<AndroidResource Include="Resources\drawable-hdpi\ic_windows.png" />
|
||||
<AndroidResource Include="Resources\drawable-hdpi\ic_facebook.png" />
|
||||
<AndroidResource Include="Resources\drawable-mdpi\ic_facebook.png" />
|
||||
<AndroidResource Include="Resources\drawable-mdpi\ic_windows.png" />
|
||||
<AndroidResource Include="Resources\drawable-mdpi\ic_twitter.png" />
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\ic_facebook.png" />
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\ic_windows.png" />
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\ic_twitter.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\ic_facebook.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\ic_windows.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\ic_twitter.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\ic_facebook.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\ic_windows.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\ic_twitter.png" />
|
||||
<AndroidResource Include="Resources\drawable-hdpi\ic_notification.png" />
|
||||
<AndroidResource Include="Resources\drawable-mdpi\ic_notification.png" />
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\ic_notification.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\ic_notification.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\ic_notification.png" />
|
||||
<AndroidResource Include="Resources\layout\activity_trip_summary.axml" />
|
||||
<AndroidResource Include="Resources\layout\fragment_current_trip.axml">
|
||||
<SubType>AndroidResource</SubType>
|
||||
</AndroidResource>
|
||||
<AndroidResource Include="Resources\layout\fragment_started_1.axml" />
|
||||
<AndroidResource Include="Resources\layout\fragment_started_3.axml" />
|
||||
<AndroidResource Include="Resources\layout\fragment_started_2.axml" />
|
||||
<AndroidResource Include="Resources\layout\fragment_started_4.axml" />
|
||||
<AndroidResource Include="Resources\layout\fragment_started_5.axml" />
|
||||
<AndroidResource Include="Resources\layout\activity_getting_started.axml" />
|
||||
<AndroidResource Include="Resources\drawable-nodpi\screen_1.png" />
|
||||
<AndroidResource Include="Resources\drawable-nodpi\screen_2.png" />
|
||||
<AndroidResource Include="Resources\drawable-nodpi\screen_3.png" />
|
||||
<AndroidResource Include="Resources\drawable-nodpi\screen_4.png" />
|
||||
<AndroidResource Include="Resources\drawable-nodpi\screen_5.png" />
|
||||
<AndroidResource Include="Resources\drawable-hdpi\ic_close.png" />
|
||||
<AndroidResource Include="Resources\drawable-mdpi\ic_close.png" />
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\ic_close.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\ic_close.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\ic_close.png" />
|
||||
<AndroidResource Include="Resources\menu\menu_summary.xml" />
|
||||
<AndroidResource Include="Resources\drawable-nodpi\ic_end_point.png" />
|
||||
<AndroidResource Include="Resources\drawable-nodpi\ic_car_blue.png" />
|
||||
<AndroidResource Include="Resources\drawable-nodpi\ic_car_red.png" />
|
||||
<AndroidResource Include="Resources\drawable-nodpi\ic_start_point.png" />
|
||||
<AndroidResource Include="Resources\drawable\navigation_logo.png" />
|
||||
<AndroidResource Include="Resources\drawable\logo.png" />
|
||||
<AndroidResource Include="Resources\drawable-nodpi\background_started.png" />
|
||||
<AndroidResource Include="Resources\drawable\navigation_header.png" />
|
||||
<None Include="Assets\Desktop EULA 1.6.txt" />
|
||||
<AndroidResource Include="Resources\drawable-hdpi\ic_launcher.png" />
|
||||
<AndroidResource Include="Resources\drawable-mdpi\ic_launcher.png" />
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\ic_launcher.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\ic_launcher.png" />
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\ic_launcher.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\values\Strings.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\ic_menu.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\values\colors.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\values\styles.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\values-v19\styles.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\values-v21\styles.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\background_splash.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\menu\nav_menu.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-mdpi\ic_menu.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\ic_menu.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\ic_menu.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\ic_menu.png" />
|
||||
</ItemGroup>
|
||||
<Import Project="..\..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<AndroidEnvironment Include="environment.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<AndroidAsset Include="Assets\fonts\Corbert-Regular.otf" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-nodpi\ic_tip.png" />
|
||||
</ItemGroup>
|
||||
<Import Project="..\MyDriving.Shared\MyDriving.Shared.projitems" Label="Shared" />
|
||||
</Project>
|
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.microsoft.mydriving" android:versionCode="1" android:versionName="1.0.0" android:installLocation="auto">
|
||||
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" />
|
||||
<application android:theme="@style/MyTheme" android:label="MyDriving" android:icon="@drawable/ic_launcher">
|
||||
<activity android:name="net.hockeyapp.android.UpdateActivity" />
|
||||
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AIzaSyBV35qO2UwecYbthByA87H4Fbkqa5Fpbrk" />
|
||||
</application>
|
||||
</manifest>
|
@ -0,0 +1,32 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for details.
|
||||
|
||||
using System.Reflection;
|
||||
using Android.App;
|
||||
|
||||
// Information about this assembly is defined by the following attributes.
|
||||
// Change them to the values specific to your project.
|
||||
|
||||
[assembly: AssemblyTitle("MyDriving.Droid")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("")]
|
||||
[assembly: AssemblyCopyright("joe")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
|
||||
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
|
||||
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
|
||||
|
||||
[assembly: AssemblyVersion("1.0.0")]
|
||||
|
||||
// The following attributes are used to specify the signing key for the assembly,
|
||||
// if desired. See the Mono documentation for more information about signing.
|
||||
|
||||
//[assembly: AssemblyDelaySign(false)]
|
||||
//[assembly: AssemblyKeyFile("")]
|
||||
|
||||
[assembly: UsesPermission(Android.Manifest.Permission.Internet)]
|
||||
[assembly: UsesPermission(Android.Manifest.Permission.WriteExternalStorage)]
|
@ -0,0 +1,44 @@
|
||||
Images, layout descriptions, binary blobs and string dictionaries can be included
|
||||
in your application as resource files. Various Android APIs are designed to
|
||||
operate on the resource IDs instead of dealing with images, strings or binary blobs
|
||||
directly.
|
||||
|
||||
For example, a sample Android app that contains a user interface layout (main.axml),
|
||||
an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
|
||||
would keep its resources in the "Resources" directory of the application:
|
||||
|
||||
Resources/
|
||||
drawable/
|
||||
icon.png
|
||||
|
||||
layout/
|
||||
main.axml
|
||||
|
||||
values/
|
||||
strings.xml
|
||||
|
||||
In order to get the build system to recognize Android resources, set the build action to
|
||||
"AndroidResource". The native Android APIs do not operate directly with filenames, but
|
||||
instead operate on resource IDs. When you compile an Android application that uses resources,
|
||||
the build system will package the resources for distribution and generate a class called "R"
|
||||
(this is an Android convention) that contains the tokens for each one of the resources
|
||||
included. For example, for the above Resources layout, this is what the R class would expose:
|
||||
|
||||
public class R {
|
||||
public class drawable {
|
||||
public const int icon = 0x123;
|
||||
}
|
||||
|
||||
public class layout {
|
||||
public const int main = 0x456;
|
||||
}
|
||||
|
||||
public class strings {
|
||||
public const int first_string = 0xabc;
|
||||
public const int second_string = 0xbcd;
|
||||
}
|
||||
}
|
||||
|
||||
You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main
|
||||
to reference the layout/main.axml file, or R.strings.first_string to reference the first
|
||||
string in the dictionary file values/strings.xml.
|
8835
MobileApps/MyDriving/MyDriving.Android/Resources/Resource.designer.cs
generated
Normal file
After Width: | Height: | Size: 716 B |
After Width: | Height: | Size: 568 B |
After Width: | Height: | Size: 552 B |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 297 B |
After Width: | Height: | Size: 800 B |
After Width: | Height: | Size: 640 B |
After Width: | Height: | Size: 137 B |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 586 B |
After Width: | Height: | Size: 603 B |
After Width: | Height: | Size: 507 B |
After Width: | Height: | Size: 510 B |
After Width: | Height: | Size: 700 B |
After Width: | Height: | Size: 456 B |
After Width: | Height: | Size: 308 B |
After Width: | Height: | Size: 403 B |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 190 B |
After Width: | Height: | Size: 505 B |
After Width: | Height: | Size: 396 B |
After Width: | Height: | Size: 110 B |
After Width: | Height: | Size: 533 B |
After Width: | Height: | Size: 397 B |
After Width: | Height: | Size: 365 B |
After Width: | Height: | Size: 365 B |
After Width: | Height: | Size: 328 B |
After Width: | Height: | Size: 462 B |
After Width: | Height: | Size: 908 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 650 KiB |
After Width: | Height: | Size: 649 KiB |
After Width: | Height: | Size: 664 KiB |
After Width: | Height: | Size: 625 KiB |
After Width: | Height: | Size: 257 KiB |
After Width: | Height: | Size: 975 B |
After Width: | Height: | Size: 618 B |
After Width: | Height: | Size: 695 B |
After Width: | Height: | Size: 7.4 KiB |
After Width: | Height: | Size: 341 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 943 B |
After Width: | Height: | Size: 192 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 754 B |
After Width: | Height: | Size: 778 B |
After Width: | Height: | Size: 700 B |
After Width: | Height: | Size: 609 B |
After Width: | Height: | Size: 871 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 577 B |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 253 B |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 876 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 17 KiB |