+using Clock;
+using Clock.Mvvm;
+using Clock.ViewModel;
using System;
namespace Clock.TizenMobile
<ItemGroup>
<Compile Include="Clock.cs" />
<Compile Include="Clock.TizenMobile.cs" />
+ <Compile Include="Clock.Dependency.cs" />
<Compile Include="Controls\FloatingButtonRenderer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Controls\TimePickerRenderer.cs" />
using Xamarin.Forms;
using Clock.TizenMobile.Views;
+using Clock.Mvvm;
+using Clock.ViewModel;
+using Clock.Abstractions;
+using Clock.TizenMobile;
-namespace Clock.TizenMobile
+namespace Clock
{
public class App : Application
{
public App()
{
+
MainPage = new NavigationPage(new MainView());
}
+ static App()
+ {
+ ViewModelsModule.RegisterViewModels();
+ }
+
protected override void OnStart()
{
// Handle when your app starts
+++ /dev/null
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Clock.ViewModel
-{
- public class AlarmViewModel
- {
- }
-}
<?xml version="1.0" encoding="utf-8" ?>
-<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
+<ContentPage x:Class="Clock.TizenMobile.Views.WorldClockView"
+ xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:Clock.TizenMobile.Controls;assembly=Clock.TizenMobile"
- x:Class="Clock.TizenMobile.Views.WorldClockView">
-
- <AbsoluteLayout>
+ xmlns:converters="clr-namespace:Clock.Tools.Converters;assembly=Clock"
+ xmlns:mvvm="clr-namespace:Clock.Mvvm;assembly=Clock"
+ mvvm:ViewModelLocator.AutoWireViewModel="True">
+ <ContentPage.Resources>
+ <ResourceDictionary>
+ <converters:ClockLocationToTimeConverter x:Key="LocationToTimeConverter"/>
+ <converters:ClockLocationToPMDesignationConverter x:Key="LocationToPmDesignationConverter"/>
+ <converters:ClockLocationToOffsetConverter x:Key="ClockLocationToOffsetConverter"/>
+ </ResourceDictionary>
+ </ContentPage.Resources>
+
+ <AbsoluteLayout>
<Image Source="images/clock_world_map_01.png" AbsoluteLayout.LayoutBounds="0, 0.025, 1, 0.37" AbsoluteLayout.LayoutFlags="All"/>
<Button BackgroundColor="Transparent" Image="images/clock_icon_world_clock_arrow_left.png" AbsoluteLayout.LayoutBounds="0.015, 0.205, 0.08, 0.073" AbsoluteLayout.LayoutFlags="All"/>
<Button BackgroundColor="Transparent" Image="images/clock_icon_world_clock_arrow_right.png" AbsoluteLayout.LayoutBounds="0.99, 0.205, 0.08, 0.073" AbsoluteLayout.LayoutFlags="All"/>
<StackLayout Orientation="Horizontal" HorizontalOptions="Center" AbsoluteLayout.LayoutBounds="0.5, 0.47, 1, 0.086" AbsoluteLayout.LayoutFlags="All">
- <Label Text="7:50" FontSize="36" TextColor="White"
+ <Label Text="{Binding Location, Converter={StaticResource LocationToTimeConverter}}" FontSize="36" TextColor="White"
VerticalTextAlignment="Center" HorizontalTextAlignment="Center" VerticalOptions="EndAndExpand"/>
- <Label Text="a.m." FontSize="24" TextColor="White" Margin="10,0,0,4"
+ <Label Text="{Binding Location, Converter={StaticResource LocationToPmDesignationConverter}}" FontSize="24" TextColor="White" Margin="10,0,0,4"
VerticalTextAlignment="Center" HorizontalTextAlignment="Center" VerticalOptions="EndAndExpand"/>
- <Label Text="1h behind" FontSize="24" TextColor="White" Margin="10,0,0,4"
+ <Label Text="{Binding Location, Converter={StaticResource ClockLocationToOffsetConverter}}" FontSize="24" TextColor="White" Margin="10,0,0,4"
VerticalTextAlignment="Center" HorizontalTextAlignment="Center" VerticalOptions="EndAndExpand"/>
</StackLayout>
- <Label Text="Belijning, Denpasar, Guangssho" FontSize="24" TextColor="White" AbsoluteLayout.LayoutBounds="0.5, 0.55, 1, 0.047" AbsoluteLayout.LayoutFlags="All"
+ <Label Text="{Binding Location.Place}" FontSize="24" TextColor="White" AbsoluteLayout.LayoutBounds="0.5, 0.55, 1, 0.047" AbsoluteLayout.LayoutFlags="All"
VerticalTextAlignment="Center" HorizontalTextAlignment="Center"/>
<BoxView BackgroundColor="White" AbsoluteLayout.LayoutBounds="0, 1, 1, 0.38" AbsoluteLayout.LayoutFlags="All"/>
AbsoluteLayout.LayoutBounds="0, 1, 1, 0.38" AbsoluteLayout.LayoutFlags="All"
VerticalTextAlignment="Center" HorizontalTextAlignment="Center" VerticalOptions="Center" HorizontalOptions="Center"/>
<AbsoluteLayout x:Name="FloatingButtonSpacer" AbsoluteLayout.LayoutBounds=".5, 1, 1, .17" AbsoluteLayout.LayoutFlags="All">
- <controls:FloatingButton AbsoluteLayout.LayoutBounds=".5, .5, 1, 1" AbsoluteLayout.LayoutFlags="All"/>
+ <controls:FloatingButton AbsoluteLayout.LayoutBounds=".5, .5, 1, 1" AbsoluteLayout.LayoutFlags="All" Command="{Binding AddCommand}"/>
</AbsoluteLayout>
</AbsoluteLayout>
</ContentPage>
\ No newline at end of file
<label>Clock</label>
</ui-application>
<shortcut-list />
+ <privileges>
+ <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
+ </privileges>
</manifest>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<ItemGroup>
+ <Compile Include="Abstractions\IAppControl.cs" />
+ <Compile Include="Model\ClockLocation.cs" />
<Compile Include="Model\Counter.cs" />
<Compile Include="Model\StopWatch.cs" />
+ <Compile Include="Mvvm\INavigationAware.cs" />
+ <Compile Include="Mvvm\ViewModelLocationProvider.cs" />
+ <Compile Include="Mvvm\ViewModelLocator.cs" />
+ <Compile Include="Tools\Converters\ClockLocationToOffsetConverter.cs" />
+ <Compile Include="Tools\Converters\ClockLocationToPMDesignationConverter.cs" />
+ <Compile Include="Tools\Converters\ClockLocationToTimeConverter.cs" />
<Compile Include="ViewModel\AlarmViewModel.cs" />
<Compile Include="ViewModel\StopWatchViewModel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="ViewModel\WorldClockViewModel.cs" />
</ItemGroup>
<ItemGroup>
<!-- <None Include="GettingStarted.Xamarin" /> -->
<Private>True</Private>
</Reference>
</ItemGroup>
+ <ItemGroup />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<Import Project="..\..\packages\Xamarin.Forms.2.3.3.175\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets" Condition="Exists('..\..\packages\Xamarin.Forms.2.3.3.175\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
--- /dev/null
+using Clock.Abstractions;
+using Clock.TizenMobile.Views;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xamarin.Forms;
+using Clock.TizenMobile;
+using Clock.Mvvm;
+using Clock.ViewModel;
+using Clock.Model;
+using static Tizen.Applications.AppControl;
+
+[assembly: Dependency(typeof(TizenAppControl))]
+namespace Clock.TizenMobile
+{
+ public class ViewModelsModule
+ {
+ public static void RegisterViewModels()
+ {
+ ViewModelLocationProvider.Register<WorldClockView>(() => new WorldClockViewModel(DependencyService.Get<IAppControl>()));
+ }
+ }
+
+ class TizenAppControl : IAppControl
+ {
+ public const string AppControlOperationPick = "http://tizen.org/appcontrol/operation/pick";
+ public const string WorldclockId = "org.tizen.worldclock-efl";
+
+ public void RequestLocationsModule(Action<ClockLocation> action)
+ {
+ Tizen.Applications.AppControl appControl = new Tizen.Applications.AppControl();
+ appControl.Operation = AppControlOperationPick;
+ appControl.ApplicationId = WorldclockId;
+ appControl.LaunchMode = Tizen.Applications.AppControlLaunchMode.Group;
+ Tizen.Applications.AppControl.SendLaunchRequest(appControl, (launchRequest, replyRequest, result) =>
+ {
+ if (result == Tizen.Applications.AppControlReplyResult.Succeeded && replyRequest != null)
+ {
+ try
+ {
+ action(CreateLocation(replyRequest.ExtraData));
+ }
+ catch (FormatException ex)
+ {
+ Tizen.Log.Error(nameof(IAppControl), "FormatException while creating location: " + ex.Message);
+ }
+ catch (Exception ex)
+ {
+ Tizen.Log.Error(nameof(IAppControl), "Exception while creating location: " + ex.Message);
+ }
+ }
+ });
+ }
+
+ private ClockLocation CreateLocation(ExtraDataCollection collection)
+ {
+ ClockLocation result = new ClockLocation(collection.Get("city_name") as string
+ , collection.Get("country_name") as string
+ , GetOffsetMinutes(collection.Get("timezone") as string)
+ , 0
+ , 0);
+ result.TimeZonePath = collection.Get("tzpath") as string;
+ return result;
+ }
+
+ private int GetOffsetMinutes(string timeZone)
+ {
+ IEnumerable<string> timeNumbers = timeZone.Substring(1)?.Split(':');
+ int hours = Convert.ToInt32(timeNumbers.FirstOrDefault());
+ int minutes = Convert.ToInt32(timeNumbers.Skip(1)?.FirstOrDefault());
+ return (60 * hours + minutes) * ((timeZone[0] == '-') ? (-1) : (1));
+ }
+ }
+}
--- /dev/null
+using Clock.Model;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Clock.Abstractions
+{
+ public interface IAppControl
+ {
+ void RequestLocationsModule(Action<ClockLocation> action);
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Clock.Model
+{
+ public class ClockLocation
+ {
+ #region Location Collection
+ public static List<ClockLocation> Locations = new List<ClockLocation>
+ {
+ new ClockLocation( "Midway Atoll", "USA", -11 * 60, 43, 218 ),
+ new ClockLocation( "Pago Pago", "American Samoa", -11 * 60, 54, 230 ),
+ new ClockLocation( "Honolulu", "USA", -10 * 60, 57, 223 ),
+ new ClockLocation( "Anchorage", "USA", -9 * 60, 74, 144 ),
+ new ClockLocation( "Los Angeles", "USA", -8 * 60, 131, 196 ),
+ new ClockLocation( "San Francisco", "USA", -8 * 60, 126, 191 ),
+ new ClockLocation( "Vancouver", "Canada", -8 * 60, 122, 166 ),
+ new ClockLocation( "Denver", "USA", -7 * 60, 156, 185 ),
+ new ClockLocation( "Austin", "USA", -6 * 60, 168, 199 ),
+ new ClockLocation( "Chicago", "USA", -6 * 60, 187, 181 ),
+ new ClockLocation( "Guatemala City", "Guatemala", -6 * 60, 181, 233 ),
+ new ClockLocation( "Mexico City", "Mexico", -6 * 60, 167, 244 ),
+ new ClockLocation( "Bogota", "Colombia", -5 * 60, 212, 253 ),
+ new ClockLocation( "Lima", "Peru", -5 * 60, 206, 286 ),
+ new ClockLocation( "Miami", "USA", -5 * 60, 200, 211 ),
+ new ClockLocation( "New York", "USA", -5 * 60, 211, 184 ),
+ new ClockLocation( "Ottawa", "Canada", -5 * 60, 208, 173 ),
+ new ClockLocation( "Washington DC", "USA", -5 * 60, 205, 189 ),
+ new ClockLocation( "Santiago", "Chile", -4 * 60, 217, 327 ),
+ new ClockLocation( "Santo Domingo", "Dominican Republic", -4 * 60, 218, 226 ),
+ new ClockLocation( "Brasilia", "Brazil", -3 * 60, 257, 290 ),
+ new ClockLocation( "Buenos Aires", "Argentina", -3 * 60, 239, 329 ),
+ new ClockLocation( "Nuuk", "Greenland", -3 * 60, 256, 143 ),
+ new ClockLocation( "Sao Paulo", "Brazil", -3 * 60, 260, 308 ),
+ new ClockLocation( "Mid-Atlantic", "", -2 * 60, 296, 266 ),
+ new ClockLocation( "Grytvieken", "South Georgia", -2 * 60, 276, 364 ),
+ new ClockLocation( "Azores", "Portugal", -1 * 60, 308, 188 ),
+ new ClockLocation( "Ponta Delaga", "Portugal", -1 * 60, 300, 190 ),
+ new ClockLocation( "Accra", "Ghana", 0, 343, 250 ),
+ new ClockLocation( "Dakar", "Senegal", 0, 314, 234 ),
+ new ClockLocation( "Lisbon", "Portugal", 0, 327, 187 ),
+ new ClockLocation( "London", "United Kingdom", 0, 343, 162 ),
+ new ClockLocation( "Reykjavik", "Iceland", 0, 306, 138 ),
+ new ClockLocation( "Algiers", "Algeria", 1 * 60, 349, 190 ),
+ new ClockLocation( "Bracelona", "Spain", 1 * 60, 346, 181 ),
+ new ClockLocation( "Berlin", "Germany", 1 * 60, 367, 162 ),
+ new ClockLocation( "Luanda", "Angola", 1 * 60, 367, 278 ),
+ new ClockLocation( "Madrid", "Spain", 1 * 60, 337, 185 ),
+ new ClockLocation( "Paris", "France", 1 * 60, 349, 168 ),
+ new ClockLocation( "Rome", "Italy", 1 * 60, 365, 180 ),
+ new ClockLocation( "Stockholm", "Sweden", 1 * 60, 375, 147 ),
+ new ClockLocation( "Athens", "Greece", 2 * 60, 385, 188 ),
+ new ClockLocation( "Cairo", "Egypt", 2 * 60, 400, 205 ),
+ new ClockLocation( "Cape Town", "South Africa", 2 * 60, 376, 326 ),
+ new ClockLocation( "Harare", "Zimbabwe", 2 * 60, 403, 293 ),
+ new ClockLocation( "Istanbul", "Turkey", 2 * 60, 395, 183 ),
+ new ClockLocation( "Doha", "Qatar", 3 * 60, 437, 213 ),
+ new ClockLocation( "Nairobi", "Kenia", 3 * 60, 409, 263 ),
+ new ClockLocation( "Moscow", "Russia", 3 * 60, 410, 155 ),
+ new ClockLocation( "Tehran", "Iran", 3 * 60 + 30, 435, 192 ),
+ new ClockLocation( "Izhevsk", "Russia", 4 * 60, 437, 152 ),
+ new ClockLocation( "Dubai", "United Arab Emirates", 4 * 60, 441, 213 ),
+ new ClockLocation( "Kabul", "Afghanistan", 4 * 60 + 30, 464, 194 ),
+ new ClockLocation( "Islamabad", "Pakistan", 5 * 60, 467, 196 ),
+ new ClockLocation( "Tashkent", "Uzbekistan", 5 * 60, 467, 182 ),
+ new ClockLocation( "Delhi", "India", 5 * 60 + 30, 481, 203 ),
+ new ClockLocation( "Kathmandu", "Nepal", 5 * 60 + 45, 494, 204 ),
+ new ClockLocation( "Almaty", "Kazakhstan", 6 * 60, 481, 177 ),
+ new ClockLocation( "Bishkek", "Kyrgyzstan", 6 * 60, 477, 179 ),
+ new ClockLocation( "Dhaka", "Bangladesh", 6 * 60, 504, 213 ),
+ new ClockLocation( "Omsk", "Russia", 6 * 60, 474, 156 ),
+ new ClockLocation( "Bangkok", "Thailand", 7 * 60, 522, 235 ),
+ new ClockLocation( "Hanoi", "Vietnam", 7 * 60, 532, 220 ),
+ new ClockLocation( "Jakarta", "Indonesia", 7 * 60, 532, 274 ),
+ new ClockLocation( "Beijing", "China", 8 * 60, 550, 185 ),
+ new ClockLocation( "Kuala Lumpur", "Malaysia", 8 * 60, 523, 255 ),
+ new ClockLocation( "Manila", "Philipines", 8 * 60, 559, 234 ),
+ new ClockLocation( "Perth", "Australia", 8 * 60, 550, 322 ),
+ new ClockLocation( "Singapore", "Republic of Singapore", 8 * 60, 528, 258 ),
+ new ClockLocation( "Ulan Bator", "Mongolia", 8 * 60, 535, 168 ),
+ new ClockLocation( "Seoul", "South Korea", 9 * 60, 570, 190 ),
+ new ClockLocation( "Tokyo", "Japan", 9 * 60, 592, 193 ),
+ new ClockLocation( "Sydney", "Australia", 10 * 60, 613, 326 ),
+ new ClockLocation( "Noumea", "New Caledonia", 11 * 60, 639, 304 ),
+ new ClockLocation( "Khabarowsk", "Russia", 11 * 60, 584, 169 ),
+ new ClockLocation( "Auckland", "New Zealand", 12 * 60, 654, 328 ),
+ new ClockLocation( "Nuku'alofa", "Tonga", 13 * 60, 668, 304 ),
+ new ClockLocation( "Caracas", "Venezuela", -4 * 60 - 30, 219, 247 ),
+ new ClockLocation( "St John's", "Newfoundland", -3 * 60 - 30, 249, 166 ),
+ new ClockLocation( "Yangon", "Myanmar", 6 * 60 + 30, 516, 232 ),
+ new ClockLocation( "Adelaide", "Australia", 9 * 60 + 30, 603, 332 )
+ };
+ #endregion
+
+ public ClockLocation(string place, string country, int gmtMinutesOffset, int x, int y)
+ {
+ Place = place;
+ Country = country;
+ GmtMinutesOffset = gmtMinutesOffset;
+ X = x;
+ Y = y;
+ }
+
+ public string Place
+ {
+ get;
+ set;
+ }
+
+ public string Country
+ {
+ get;
+ set;
+ }
+
+ public int GmtMinutesOffset
+ {
+ get;
+ set;
+ }
+
+ public int X
+ {
+ get;
+ set;
+ }
+
+ public int Y
+ {
+ get;
+ set;
+ }
+
+ public bool IsSummertime
+ {
+ get;
+ set;
+ }
+
+ public string TimeZonePath
+ {
+ get;
+ set;
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xamarin.Forms;
+
+namespace Clock.Mvvm
+{
+ public interface INavigationAware
+ {
+ INavigation Navigation
+ {
+ get;
+ set;
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Reflection;
+
+namespace Clock.Mvvm
+{
+ /// <summary>
+ /// The ViewModelLocationProvider class locates the view model for the view that has the AutoWireViewModelChanged attached property set to true.
+ /// The view model will be located and injected into the view's DataContext. To locate the view, two strategies are used: First the ViewModelLocationProvider
+ /// will look to see if there is a view model factory registered for that view, if not it will try to infer the view model using a convention based approach.
+ /// This class also provide methods for registering the view model factories,
+ /// and also to override the default view model factory and the default view type to view model type resolver.
+ /// </summary>
+ // Documentation on using the MVVM pattern is at http://go.microsoft.com/fwlink/?LinkID=288814&clcid=0x409
+
+ public static class ViewModelLocationProvider
+ {
+ /// <summary>
+ /// A dictionary that contains all the registered factories for the views.
+ /// </summary>
+ static Dictionary<string, Func<object>> _factories = new Dictionary<string, Func<object>>();
+
+ /// <summary>
+ /// A dictionary that contains all the registered ViewModel types for the views.
+ /// </summary>
+ static Dictionary<string, Type> _typeFactories = new Dictionary<string, Type>();
+
+ /// <summary>
+ /// The default view model factory which provides the ViewModel type as a parameter.
+ /// </summary>
+ static Func<Type, object> _defaultViewModelFactory = type => Activator.CreateInstance(type);
+
+ /// <summary>
+ /// ViewModelfactory that provides the View instance and ViewModel type as parameters.
+ /// </summary>
+ static Func<object, Type, object> _defaultViewModelFactoryWithViewParameter;
+
+ /// <summary>
+ /// Default view type to view model type resolver, assumes the view model is in same assembly as the view type, but in the "ViewModels" namespace.
+ /// </summary>
+ static Func<Type, Type> _defaultViewTypeToViewModelTypeResolver =
+ viewType =>
+ {
+ var viewName = viewType.FullName;
+ viewName = viewName.Replace(".Views.", ".ViewModels.");
+ var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
+ var suffix = viewName.EndsWith("View") ? "Model" : "ViewModel";
+ var viewModelName = String.Format(CultureInfo.InvariantCulture, "{0}{1}, {2}", viewName, suffix, viewAssemblyName);
+ return Type.GetType(viewModelName);
+ };
+
+ /// <summary>
+ /// Sets the default view model factory.
+ /// </summary>
+ /// <param name="viewModelFactory">The view model factory which provides the ViewModel type as a parameter.</param>
+ public static void SetDefaultViewModelFactory(Func<Type, object> viewModelFactory)
+ {
+ _defaultViewModelFactory = viewModelFactory;
+ }
+
+ /// <summary>
+ /// Sets the default view model factory.
+ /// </summary>
+ /// <param name="viewModelFactory">The view model factory that provides the View instance and ViewModel type as parameters.</param>
+ public static void SetDefaultViewModelFactory(Func<object, Type, object> viewModelFactory)
+ {
+ _defaultViewModelFactoryWithViewParameter = viewModelFactory;
+ }
+
+ /// <summary>
+ /// Sets the default view type to view model type resolver.
+ /// </summary>
+ /// <param name="viewTypeToViewModelTypeResolver">The view type to view model type resolver.</param>
+ public static void SetDefaultViewTypeToViewModelTypeResolver(Func<Type, Type> viewTypeToViewModelTypeResolver)
+ {
+ _defaultViewTypeToViewModelTypeResolver = viewTypeToViewModelTypeResolver;
+ }
+
+ /// <summary>
+ /// Automatically looks up the viewmodel that corresponds to the current view, using two strategies:
+ /// It first looks to see if there is a mapping registered for that view, if not it will fallback to the convention based approach.
+ /// </summary>
+ /// <param name="view">The dependency object, typically a view.</param>
+ /// <param name="setDataContextCallback">The call back to use to create the binding between the View and ViewModel</param>
+ public static void AutoWireViewModelChanged(object view, Action<object, object> setDataContextCallback)
+ {
+ // Try mappings first
+ object viewModel = GetViewModelForView(view);
+
+ // try to use ViewModel type
+ if (viewModel == null)
+ {
+ //check type mappings
+ var viewModelType = GetViewModelTypeForView(view.GetType());
+
+ // fallback to convention based
+ if (viewModelType == null)
+ {
+ viewModelType = _defaultViewTypeToViewModelTypeResolver(view.GetType());
+ }
+
+ if (viewModelType == null)
+ {
+ return;
+ }
+
+ viewModel = _defaultViewModelFactoryWithViewParameter != null ? _defaultViewModelFactoryWithViewParameter(view, viewModelType) : _defaultViewModelFactory(viewModelType);
+ }
+
+
+ setDataContextCallback(view, viewModel);
+ }
+
+ /// <summary>
+ /// Gets the view model for the specified view.
+ /// </summary>
+ /// <param name="view">The view that the view model wants.</param>
+ /// <returns>The ViewModel that corresponds to the view passed as a parameter.</returns>
+ private static object GetViewModelForView(object view)
+ {
+ var viewKey = view.GetType().ToString();
+
+ // Mapping of view models base on view type (or instance) goes here
+ if (_factories.ContainsKey(viewKey))
+ {
+ return _factories[viewKey]();
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Gets the ViewModel type for the specified view.
+ /// </summary>
+ /// <param name="view">The View that the ViewModel wants.</param>
+ /// <returns>The ViewModel type that corresponds to the View.</returns>
+ private static Type GetViewModelTypeForView(Type view)
+ {
+ var viewKey = view.ToString();
+
+ if (_typeFactories.ContainsKey(viewKey))
+ {
+ return _typeFactories[viewKey];
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Registers the ViewModel factory for the specified view type.
+ /// </summary>
+ /// <typeparam name="T">The View</typeparam>
+ /// <param name="factory">The ViewModel factory.</param>
+ public static void Register<T>(Func<object> factory)
+ {
+ Register(typeof(T).ToString(), factory);
+ }
+
+ /// <summary>
+ /// Registers the ViewModel factory for the specified view type name.
+ /// </summary>
+ /// <param name="viewTypeName">The name of the view type.</param>
+ /// <param name="factory">The ViewModel factory.</param>
+ public static void Register(string viewTypeName, Func<object> factory)
+ {
+ _factories[viewTypeName] = factory;
+ }
+
+ /// <summary>
+ /// Registers a ViewModel type for the specified view type.
+ /// </summary>
+ /// <typeparam name="T">The View</typeparam>
+ /// <typeparam name="VM">The ViewModel</typeparam>
+ public static void Register<T, VM>()
+ {
+ var viewType = typeof(T);
+ var viewModelType = typeof(VM);
+
+ Register(viewType.ToString(), viewModelType);
+ }
+
+ /// <summary>
+ /// Registers a ViewModel type for the specified view.
+ /// </summary>
+ /// <param name="viewTypeName">The View type name</param>
+ /// <param name="viewModelType">The ViewModel type</param>
+ public static void Register(string viewTypeName, Type viewModelType)
+ {
+ _typeFactories[viewTypeName] = viewModelType;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using Xamarin.Forms;
+
+namespace Clock.Mvvm
+{
+ /// <summary>
+ /// This class defines the attached property and related change handler that calls the <see cref="Prism.Mvvm.ViewModelLocationProvider"/>.
+ /// </summary>
+ public static class ViewModelLocator
+ {
+ /// <summary>
+ /// Instructs Prism whether or not to automatically create an instance of a ViewModel using a convention, and assign the associated View's <see cref="Xamarin.Forms.BindableObject.BindingContext"/> to that instance.
+ /// </summary>
+ public static readonly BindableProperty AutoWireViewModelProperty =
+ BindableProperty.CreateAttached("AutoWireViewModel", typeof(bool?), typeof(ViewModelLocator), null, propertyChanged: OnAutoWireViewModelChanged);
+
+ /// <summary>
+ /// Gets the AutowireViewModel property value.
+ /// </summary>
+ /// <param name="bindable"></param>
+ /// <returns></returns>
+ public static bool? GetAutoWireViewModel(BindableObject bindable)
+ {
+ return (bool?)bindable.GetValue(ViewModelLocator.AutoWireViewModelProperty);
+ }
+
+ /// <summary>
+ /// Sets the AutowireViewModel property value. If <c>true</c>, creates an instance of a ViewModel using a convention, and sets the associated View's <see cref="Xamarin.Forms.BindableObject.BindingContext"/> to that instance.
+ /// </summary>
+ /// <param name="bindable"></param>
+ /// <param name="value"></param>
+ public static void SetAutowireViewModel(BindableObject bindable, bool? value)
+ {
+ bindable.SetValue(ViewModelLocator.AutoWireViewModelProperty, value);
+ }
+
+ private static void OnAutoWireViewModelChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ bool? bNewValue = (bool?)newValue;
+ if (bNewValue.HasValue && bNewValue.Value)
+ {
+ ViewModelLocationProvider.AutoWireViewModelChanged(bindable, Bind);
+ }
+ }
+
+ /// <summary>
+ /// Sets the <see cref="Xamarin.Forms.BindableObject.BindingContext"/> of a View
+ /// </summary>
+ /// <param name="view">The View to set the <see cref="Xamarin.Forms.BindableObject.BindingContext"/> on</param>
+ /// <param name="viewModel">The object to use as the <see cref="Xamarin.Forms.BindableObject.BindingContext"/> for the View</param>
+ static void Bind(object view, object viewModel)
+ {
+ BindableObject element = view as BindableObject;
+ if (element != null)
+ {
+ element.BindingContext = viewModel;
+ }
+ if (viewModel is INavigationAware && view is VisualElement)
+ {
+ (viewModel as INavigationAware).Navigation = (view as VisualElement).Navigation;
+ }
+ }
+ }
+}
--- /dev/null
+using Clock.Model;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xamarin.Forms;
+
+namespace Clock.Tools.Converters
+{
+ public class ClockLocationToOffsetConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ StringBuilder builder = new StringBuilder();
+ var location = value as ClockLocation;
+ if (location == null || location.GmtMinutesOffset == 0)
+ {
+ builder.Append("same as local");
+ }
+ else
+ {
+ var hours = Math.Abs(location.GmtMinutesOffset) / 60;
+ builder.Append(hours);
+ builder.Append("h");
+ if (location.GmtMinutesOffset - hours * 60 >= 30)
+ {
+ builder.Append(" 30m");
+ }
+ builder.Append(location.GmtMinutesOffset > 0 ? " ahead" : " behind");
+ }
+ return builder.ToString();
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
--- /dev/null
+using Clock.Model;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xamarin.Forms;
+
+namespace Clock.Tools.Converters
+{
+ public class ClockLocationToPMDesignationConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ var location = value as ClockLocation;
+ var time = DateTime.Now.AddMinutes(location?.GmtMinutesOffset ?? 0);
+ return time.Hour < 12 ? "a.m." : "p.m.";
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
--- /dev/null
+using Clock.Model;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xamarin.Forms;
+
+namespace Clock.Tools.Converters
+{
+ public class ClockLocationToTimeConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ var location = value as ClockLocation;
+ var time = DateTime.Now.AddMinutes(location?.GmtMinutesOffset ?? 0);
+ return string.Format("{0:hh:mm}", time);
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
--- /dev/null
+using Clock.Abstractions;
+using Clock.Model;
+using Clock.Mvvm;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Input;
+using Xamarin.Forms;
+
+namespace Clock.ViewModel
+{
+ public class WorldClockViewModel : INotifyPropertyChanged, INavigationAware
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+ private IAppControl _appControl = null;
+
+ public WorldClockViewModel( IAppControl appControl )
+ {
+ AddCommand = new Command(Add);
+ _appControl = appControl;
+ }
+
+ public ICommand AddCommand
+ {
+ get;
+ set;
+ }
+
+ public INavigation Navigation
+ {
+ get;
+ set;
+ }
+
+ public ClockLocation Location
+ {
+ get;
+ private set;
+ }
+
+ private void Add()
+ {
+ _appControl?.RequestLocationsModule(OnLocationsResult);
+ }
+
+ private void OnLocationsResult( ClockLocation location )
+ {
+ Location = location;
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Location)));
+ }
+ }
+}