зеркало из https://github.com/microsoft/sketch360.git
305 строки
9.1 KiB
C#
305 строки
9.1 KiB
C#
|
// Copyright (c) Microsoft. All rights reserved.
|
|||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|||
|
|
|||
|
using Autofac;
|
|||
|
using Microsoft.AppCenter;
|
|||
|
using Microsoft.AppCenter.Analytics;
|
|||
|
using Microsoft.AppCenter.Crashes;
|
|||
|
//using Microsoft.AppCenter.Distribute;
|
|||
|
using Plugin.Multilingual;
|
|||
|
using Sketch360.XPlat.Data;
|
|||
|
using Sketch360.XPlat.Interfaces;
|
|||
|
using Sketch360.XPlat.Modes;
|
|||
|
using Sketch360.XPlat.Resources;
|
|||
|
using Sketch360.XPlat.Serialization;
|
|||
|
using Sketch360.XPlat.Support;
|
|||
|
using Sketch360.XPlat.ViewModels;
|
|||
|
using System;
|
|||
|
using System.IO;
|
|||
|
using System.Linq;
|
|||
|
using System.Reflection;
|
|||
|
using System.Text.Json;
|
|||
|
using System.Threading.Tasks;
|
|||
|
using Xamarin.Essentials;
|
|||
|
using Xamarin.Forms;
|
|||
|
|
|||
|
namespace Sketch360.XPlat
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// Xamarin Forms App
|
|||
|
/// </summary>
|
|||
|
public sealed partial class App : Application, IDisposable
|
|||
|
{
|
|||
|
private SketchData _sketchData;
|
|||
|
private readonly ISplitPage _splitPage;
|
|||
|
private readonly UndoManager _undoManager = new UndoManager();
|
|||
|
/// <summary>
|
|||
|
/// Initializes a new instance of the App class
|
|||
|
/// </summary>
|
|||
|
public App()
|
|||
|
{
|
|||
|
|
|||
|
VersionTracking.Track();
|
|||
|
|
|||
|
InitializeContainer();
|
|||
|
|
|||
|
InitializeComponent();
|
|||
|
|
|||
|
var culture = CrossMultilingual.Current.DeviceCultureInfo;
|
|||
|
|
|||
|
AppResources.Culture = culture;
|
|||
|
|
|||
|
_splitPage = App.Container.Resolve<ISplitPage>();
|
|||
|
|
|||
|
if (VersionTracking.IsFirstLaunchForCurrentVersion)
|
|||
|
{
|
|||
|
// Navigating to Carousel on first time load
|
|||
|
var carouselPage = App.Container.Resolve<ICarouselPage>();
|
|||
|
MainPage = new NavigationPage(carouselPage as Page);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
MainPage = new NavigationPage(_splitPage as Page);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets the sketch data
|
|||
|
/// </summary>
|
|||
|
/// <returns>the sketch data</returns>
|
|||
|
public static ISketchData GetSketchData()
|
|||
|
{
|
|||
|
if (App.Current is App app)
|
|||
|
{
|
|||
|
return app._sketchData;
|
|||
|
}
|
|||
|
|
|||
|
return null;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets or sets the AutoFAC DI Container
|
|||
|
/// </summary>
|
|||
|
public static IContainer Container { get; private set; }
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets the sketch data path
|
|||
|
/// </summary>
|
|||
|
public static string SketchDataPath
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "_sketchData.json");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private bool _isSaving;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Show the carousel pages
|
|||
|
/// </summary>
|
|||
|
public void ShowCarouselPage()
|
|||
|
{
|
|||
|
var carouselPage = App.Container.Resolve<ICarouselPage>();
|
|||
|
|
|||
|
MainPage = new NavigationPage(carouselPage as Page);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Serialize the sketch data
|
|||
|
/// </summary>
|
|||
|
/// <returns></returns>
|
|||
|
public string SerializeSketchData()
|
|||
|
{
|
|||
|
lock (_sketchData)
|
|||
|
{
|
|||
|
var sketchData = new SketchData
|
|||
|
{
|
|||
|
BackgroundColor = _sketchData.BackgroundColor,
|
|||
|
Height = _sketchData.Height,
|
|||
|
InkStrokes = _sketchData.InkStrokes.ToArray(),
|
|||
|
Width = _sketchData.Width,
|
|||
|
Name = _sketchData.Name,
|
|||
|
Start = _sketchData.Start
|
|||
|
};
|
|||
|
|
|||
|
var options = CreateSerializationOptions();
|
|||
|
|
|||
|
var json = JsonSerializer.Serialize(sketchData, options);
|
|||
|
|
|||
|
return json;
|
|||
|
}
|
|||
|
}
|
|||
|
/// <summary>
|
|||
|
/// Save the sketch data
|
|||
|
/// </summary>
|
|||
|
/// <returns>an async task</returns>
|
|||
|
public async Task SaveSketchDataAsync()
|
|||
|
{
|
|||
|
if (_isSaving) return;
|
|||
|
|
|||
|
_isSaving = true;
|
|||
|
|
|||
|
await Task.Run(delegate
|
|||
|
{
|
|||
|
_isSaving = true;
|
|||
|
|
|||
|
var json = SerializeSketchData();
|
|||
|
|
|||
|
File.WriteAllText(SketchDataPath, json);
|
|||
|
|
|||
|
_isSaving = false;
|
|||
|
}).ConfigureAwait(false);
|
|||
|
}
|
|||
|
|
|||
|
static JsonSerializerOptions CreateSerializationOptions()
|
|||
|
{
|
|||
|
var options = new JsonSerializerOptions();
|
|||
|
options.Converters.Add(new ColorConverter());
|
|||
|
options.Converters.Add(new SKRectConverter());
|
|||
|
//options.Converters.Add(new PointConverter());
|
|||
|
//options.Converters.Add(new DateTimeOffsetConverter()); // the default converter is sufficient
|
|||
|
|
|||
|
options.WriteIndented = true;
|
|||
|
|
|||
|
return options;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Load a sketch from a JSON string
|
|||
|
/// </summary>
|
|||
|
/// <param name="json">the JSON string</param>
|
|||
|
public bool LoadSketch(string json)
|
|||
|
{
|
|||
|
if (string.IsNullOrWhiteSpace(json))
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
var options = CreateSerializationOptions();
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
var sketchData = JsonSerializer.Deserialize<SketchData>(json, options);
|
|||
|
|
|||
|
foreach (var stroke in sketchData.InkStrokes)
|
|||
|
{
|
|||
|
if (stroke.DrawingAttributes.Color.A == 0)
|
|||
|
{
|
|||
|
stroke.DrawingAttributes.Color = Xamarin.Forms.Color.FromRgba(stroke.DrawingAttributes.Color.R, stroke.DrawingAttributes.Color.G, stroke.DrawingAttributes.Color.B, 255);
|
|||
|
}
|
|||
|
stroke.UpdateBounds();
|
|||
|
}
|
|||
|
|
|||
|
_sketchData = sketchData;
|
|||
|
}
|
|||
|
catch (Exception e)
|
|||
|
{
|
|||
|
System.Diagnostics.Debug.WriteLine($"Error deserializing SketchData: {e.Message}");
|
|||
|
|
|||
|
_sketchData = new SketchData();
|
|||
|
|
|||
|
Crashes.TrackError(e);
|
|||
|
}
|
|||
|
|
|||
|
_splitPage.SketchDataUpdated(_sketchData);
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
public async Task LoadInitialSketchAsync()
|
|||
|
{
|
|||
|
var assembly = GetType().GetTypeInfo().Assembly;
|
|||
|
|
|||
|
using var stream = assembly.GetManifestResourceStream("Sketch360.XPlat.Assets.sketch360.json");
|
|||
|
using var reader = new StreamReader(stream);
|
|||
|
while (!reader.EndOfStream)
|
|||
|
{
|
|||
|
var json = await reader.ReadToEndAsync().ConfigureAwait(false);
|
|||
|
|
|||
|
LoadSketch(json);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// App startup
|
|||
|
/// </summary>
|
|||
|
protected override async void OnStart()
|
|||
|
{
|
|||
|
AppCenter.Start(
|
|||
|
"android=585676e3-a68b-48f0-8090-119788c6b1e5;" +
|
|||
|
//"uwp={Your UWP App secret here};" +
|
|||
|
"ios={87bd45a1-e43a-4c0f-9401-0ac71509de57}",
|
|||
|
typeof(Analytics), typeof(Crashes));//, typeof(Distribute));
|
|||
|
|
|||
|
await Task.Run(async delegate
|
|||
|
{
|
|||
|
var path = SketchDataPath;
|
|||
|
|
|||
|
if (File.Exists(path))
|
|||
|
{
|
|||
|
var json = File.ReadAllText(path);
|
|||
|
|
|||
|
LoadSketch(json);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (VersionTracking.IsFirstLaunchEver)
|
|||
|
{
|
|||
|
await LoadInitialSketchAsync().ConfigureAwait(true);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
_sketchData = new SketchData();
|
|||
|
|
|||
|
_splitPage.SketchDataUpdated(_sketchData);
|
|||
|
}
|
|||
|
}
|
|||
|
}).ConfigureAwait(false);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// App sleep
|
|||
|
/// </summary>
|
|||
|
protected override void OnSleep()
|
|||
|
{
|
|||
|
// Handle when your app sleeps
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// App resume
|
|||
|
/// </summary>
|
|||
|
protected override void OnResume()
|
|||
|
{
|
|||
|
// Handle when your app resumes
|
|||
|
}
|
|||
|
|
|||
|
private void InitializeContainer()
|
|||
|
{
|
|||
|
var builder = new Autofac.ContainerBuilder();
|
|||
|
|
|||
|
builder.RegisterType<AddStrokesUndoItem>().As<IAddStrokesUndoItem>();
|
|||
|
builder.RegisterType<DrawingMode>().As<IDrawingMode>();
|
|||
|
builder.RegisterType<DrawingPageViewModel>().As<IDrawingPageViewModel>();
|
|||
|
builder.RegisterType<ErasingMode>().As<IErasingMode>();
|
|||
|
builder.RegisterType<EraseStrokesUndoItem>().As<IEraseStrokesUndoItem>();
|
|||
|
builder.RegisterType<PanningMode>().As<IPanningMode>();
|
|||
|
builder.RegisterType<SplitPage>().As<ISplitPage>();
|
|||
|
builder.RegisterType<CarouselPage>().As<ICarouselPage>();
|
|||
|
builder.RegisterType<SplitPageViewModel>().As<ISplitPageViewModel>();
|
|||
|
builder.RegisterInstance(_undoManager).As<IUndoManager>();
|
|||
|
|
|||
|
Container = builder.Build();
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Dispose of the resources
|
|||
|
/// </summary>
|
|||
|
public void Dispose()
|
|||
|
{
|
|||
|
_undoManager?.Dispose();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|