From 2b0dfdac731a1ba839c3aff71f886ee8f4d4680c Mon Sep 17 00:00:00 2001 From: Przemyslaw Raciborski Date: Sun, 1 May 2016 23:06:35 +0200 Subject: [PATCH] Fixed Droid Forms Presenter. Navigation from Mvx-Non Forms Activity to Forms Activity is available by ShowViewModel<..> now. Issue #49 --- .../MvxFormsPagePresenter.cs | 24 ++++-- .../MvxFormsPresenterProxy.cs | 1 - .../MvvmCross.Forms.Presenter.Droid.csproj | 5 ++ .../MvxDroidFormsPagePresenter.cs | 54 ++++++++++++++ .../MvxFormsAppCompatActivity.cs | 73 ++++++++++++++++++- .../packages.config | 1 + .../FeedbackActivity.cs | 24 ++++-- .../IntegrationSample.Droid.csproj | 15 +++- .../IntegrationSample.Droid/MainActivity.cs | 10 +-- .../IntegrationSample.Droid/Setup.cs | 33 ++++++--- .../SplashScreenActivity.cs | 23 +++--- .../Forms/Pages/AboutPage.xaml | 2 +- .../Forms/Pages/MainPage.xaml | 2 +- .../IntegrationSample.csproj | 24 ++++++ .../IntegrationSampleMvxApp.cs | 15 ++-- 15 files changed, 250 insertions(+), 56 deletions(-) create mode 100644 MvvmCross.Forms.Presenter.Droid/MvxDroidFormsPagePresenter.cs diff --git a/MvvmCross.Forms.Presenter.Core/MvxFormsPagePresenter.cs b/MvvmCross.Forms.Presenter.Core/MvxFormsPagePresenter.cs index 9c0725402..82b73c44b 100644 --- a/MvvmCross.Forms.Presenter.Core/MvxFormsPagePresenter.cs +++ b/MvvmCross.Forms.Presenter.Core/MvxFormsPagePresenter.cs @@ -15,8 +15,7 @@ namespace MvvmCross.Forms.Presenter.Core { - public class MvxFormsPagePresenter - : MvxViewPresenter + public abstract class MvxFormsPagePresenter : MvxViewPresenter { private Application _mvxFormsApp; @@ -26,18 +25,18 @@ public Application MvxFormsApp set { if (value == null) - { throw new ArgumentException("MvxFormsApp cannot be null"); - } _mvxFormsApp = value; } } - public MvxFormsPagePresenter() - { } + protected MvxFormsPagePresenter() + { + + } - public MvxFormsPagePresenter(Application mvxFormsApp) + protected MvxFormsPagePresenter(Application mvxFormsApp) { MvxFormsApp = mvxFormsApp; } @@ -63,12 +62,23 @@ public override async void ChangePresentation(MvxPresentationHint hint) public override void Show(MvxViewModelRequest request) { + if (!IsNativeFormPageActive()) + { + NavigateToNativeFormPage(request); + return; + } + if (TryShowPage(request)) return; Mvx.Error("Skipping request for {0}", request.ViewModelType.Name); } + protected abstract bool IsNativeFormPageActive(); + + protected abstract void NavigateToNativeFormPage(MvxViewModelRequest withViewModelRequest); + + protected virtual void CustomPlatformInitialization(NavigationPage mainPage) { } diff --git a/MvvmCross.Forms.Presenter.Core/MvxFormsPresenterProxy.cs b/MvvmCross.Forms.Presenter.Core/MvxFormsPresenterProxy.cs index 35f0bc23a..8377cbebc 100644 --- a/MvvmCross.Forms.Presenter.Core/MvxFormsPresenterProxy.cs +++ b/MvvmCross.Forms.Presenter.Core/MvxFormsPresenterProxy.cs @@ -31,7 +31,6 @@ public override void Show(MvxViewModelRequest request) } } - public override void ChangePresentation(MvxPresentationHint hint) { // TODO: At this moment only Classic ViewModels support change presentation diff --git a/MvvmCross.Forms.Presenter.Droid/MvvmCross.Forms.Presenter.Droid.csproj b/MvvmCross.Forms.Presenter.Droid/MvvmCross.Forms.Presenter.Droid.csproj index 22552024c..e6042528c 100644 --- a/MvvmCross.Forms.Presenter.Droid/MvvmCross.Forms.Presenter.Droid.csproj +++ b/MvvmCross.Forms.Presenter.Droid/MvvmCross.Forms.Presenter.Droid.csproj @@ -75,6 +75,10 @@ ..\packages\MvvmCross.Platform.4.1.4\lib\MonoAndroid\MvvmCross.Platform.Droid.dll True + + ..\packages\Newtonsoft.Json.8.0.3\lib\portable-net40+sl5+wp80+win8+wpa81\Newtonsoft.Json.dll + True + @@ -134,6 +138,7 @@ + diff --git a/MvvmCross.Forms.Presenter.Droid/MvxDroidFormsPagePresenter.cs b/MvvmCross.Forms.Presenter.Droid/MvxDroidFormsPagePresenter.cs new file mode 100644 index 000000000..d7207ecfd --- /dev/null +++ b/MvvmCross.Forms.Presenter.Droid/MvxDroidFormsPagePresenter.cs @@ -0,0 +1,54 @@ +using System; +using Android.Content; +using MvvmCross.Core.ViewModels; +using MvvmCross.Forms.Presenter.Core; +using MvvmCross.Platform; +using MvvmCross.Platform.Droid.Platform; +using Newtonsoft.Json; + +namespace MvvmCross.Forms.Presenter.Droid +{ + public class MvxDroidFormsPagePresenter : MvxFormsPagePresenter + { + private readonly Type _formsAppCompatActivityType; + public static readonly string FirstNavigationRequestPackageExtraKey = "FirstNavigationRequestPackageKey"; + + + public MvxDroidFormsPagePresenter(Type formsAppCompatActivityType) : base() + { + _formsAppCompatActivityType = formsAppCompatActivityType; + + if (!typeof(MvxFormsAppCompatActivity).IsAssignableFrom(_formsAppCompatActivityType)) + throw new InvalidOperationException($"Passed type should inherit from {nameof(MvxFormsAppCompatActivity)}"); + } + + public MvxDroidFormsPagePresenter(Type formsAppCompatActivityType, Xamarin.Forms.Application mvxFormsApp) : base(mvxFormsApp) + { + _formsAppCompatActivityType = formsAppCompatActivityType; + + if (!typeof(MvxFormsAppCompatActivity).IsAssignableFrom(_formsAppCompatActivityType)) + throw new InvalidOperationException($"Passed type should inherit from {nameof(MvxFormsAppCompatActivity)}"); + } + + protected override bool IsNativeFormPageActive() + { + Type baseDroidFormPage = typeof(MvxFormsAppCompatActivity); + Type currentActivityType = Mvx.Resolve().Activity.GetType(); + + return baseDroidFormPage.IsAssignableFrom(currentActivityType); + } + + protected override void NavigateToNativeFormPage(MvxViewModelRequest withViewModelRequest) + { + var currentActivity = Mvx.Resolve().Activity; + var requestText = JsonConvert.SerializeObject(withViewModelRequest); + var intent = new Intent(currentActivity, _formsAppCompatActivityType); + intent.PutExtra(FirstNavigationRequestPackageExtraKey, requestText); + + currentActivity.StartActivity(intent); + } + + + + } +} \ No newline at end of file diff --git a/MvvmCross.Forms.Presenter.Droid/MvxFormsAppCompatActivity.cs b/MvvmCross.Forms.Presenter.Droid/MvxFormsAppCompatActivity.cs index 8bbd76c71..e1982333d 100644 --- a/MvvmCross.Forms.Presenter.Droid/MvxFormsAppCompatActivity.cs +++ b/MvvmCross.Forms.Presenter.Droid/MvxFormsAppCompatActivity.cs @@ -1,17 +1,33 @@ using System; +using Android.App; +using Android.Content; using Android.OS; using MvvmCross.Core.ViewModels; using MvvmCross.Core.Views; +using MvvmCross.Droid.Platform; using MvvmCross.Forms.Presenter.Core; using MvvmCross.Platform; +using MvvmCross.Platform.Droid.Views; +using Newtonsoft.Json; using Xamarin.Forms.Platform.Android; namespace MvvmCross.Forms.Presenter.Droid { public abstract class MvxFormsAppCompatActivity : FormsAppCompatActivity { + // thefex notes in comments + + // TODO: LOGIC EXCEPT OnCreate should be refactored into something like Native MvxEventSource..Activity + // MvxForms..Activity should be a bridge between Forms and Classic Xamarin world + protected MvxFormsAppCompatActivity() + { + } + protected override void OnCreate(Bundle bundle) { + // TODO ENSURE SETUP OF MVVMCROSS DONE + OnLifeTimeEvent((listener, activity) => listener.OnCreate(activity)); + base.OnCreate(bundle); Xamarin.Forms.Forms.Init(this, bundle); @@ -38,8 +54,61 @@ protected override void OnCreate(Bundle bundle) formsPresenter.MvxFormsApp = mvxFormsApp; - // TODO: Forms specific MvxAppStart - Mvx.Resolve().Start(); + + if (Intent?.Extras != null && Intent.Extras.ContainsKey(MvxDroidFormsPagePresenter.FirstNavigationRequestPackageExtraKey)) + { + var jsonViewModelRequest = Intent.Extras.GetString(MvxDroidFormsPagePresenter.FirstNavigationRequestPackageExtraKey) as string; + var viewModelRequest = JsonConvert.DeserializeObject(jsonViewModelRequest); + formsPresenter.Show(viewModelRequest); + } + } + + + // TODO: REFACTOR IMVXANDROIDVIEW INTO FEW INTERFACES + // TODO: SO LIFE TIME EVENTS CAN BE USED Like in EventSource activities + + protected override void OnDestroy() + { + OnLifeTimeEvent((listener, activity) => listener.OnDestroy(activity)); + base.OnDestroy(); + } + + + + protected override void OnResume() + { + base.OnResume(); + OnLifeTimeEvent((listener, activity) => listener.OnResume(activity)); + } + + protected override void OnPause() + { + OnLifeTimeEvent((listener, activity) => listener.OnPause(activity)); + base.OnPause(); + } + + protected override void OnStart() + { + base.OnStart(); + OnLifeTimeEvent((listener, activity) => listener.OnStart(activity)); + } + + protected override void OnRestart() + { + base.OnRestart(); + OnLifeTimeEvent((listener, activity) => listener.OnRestart(activity)); + } + + protected override void OnStop() + { + OnLifeTimeEvent((listener, activity) => listener.OnStop(activity)); + base.OnStop(); + } + + private void OnLifeTimeEvent(Action report) + { + var activityTracker = Mvx.Resolve(); + report(activityTracker, this); } } } \ No newline at end of file diff --git a/MvvmCross.Forms.Presenter.Droid/packages.config b/MvvmCross.Forms.Presenter.Droid/packages.config index 26a817943..808b06925 100644 --- a/MvvmCross.Forms.Presenter.Droid/packages.config +++ b/MvvmCross.Forms.Presenter.Droid/packages.config @@ -3,6 +3,7 @@ + diff --git a/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample.Droid/FeedbackActivity.cs b/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample.Droid/FeedbackActivity.cs index 248ff1584..df0d814a7 100644 --- a/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample.Droid/FeedbackActivity.cs +++ b/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample.Droid/FeedbackActivity.cs @@ -1,18 +1,26 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - using Android.App; -using Android.Content; +using Android.Content.PM; using Android.OS; using Android.Runtime; -using Android.Views; -using Android.Widget; +using IntegrationSample.ViewModels; +using MvvmCross.Droid.Views; namespace IntegrationSample.Droid { - class FeedbackActivity + [Activity(Label = "Feedback", Theme = "@style/MainTheme", MainLauncher = false, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)] + public class FeedbackActivity : MvxActivity { + public FeedbackActivity() + { + + } + + protected override void OnCreate(Bundle bundle) + { + base.OnCreate(bundle); + + SetContentView(Resource.Layout.FeedbackLayout); + } } } \ No newline at end of file diff --git a/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample.Droid/IntegrationSample.Droid.csproj b/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample.Droid/IntegrationSample.Droid.csproj index 8f5dc6ec8..334fecfd1 100644 --- a/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample.Droid/IntegrationSample.Droid.csproj +++ b/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample.Droid/IntegrationSample.Droid.csproj @@ -75,6 +75,9 @@ ..\..\packages\MvvmCross.Core.4.1.4\lib\MonoAndroid\MvvmCross.Droid.Shared.dll True + + ..\..\..\bin\Debug\Droid\MvvmCross.Forms.Presenter.Core.dll + ..\..\..\bin\Debug\Droid\MvvmCross.Forms.Presenter.Droid.dll @@ -145,10 +148,12 @@ + + @@ -165,8 +170,8 @@ - - + + @@ -175,6 +180,12 @@ IntegrationSample + + + + + + diff --git a/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample.Droid/MainActivity.cs b/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample.Droid/MainActivity.cs index ec1b4e310..ef1a41030 100644 --- a/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample.Droid/MainActivity.cs +++ b/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample.Droid/MainActivity.cs @@ -6,21 +6,19 @@ using Android.Views; using Android.Widget; using Android.OS; +using MvvmCross.Forms.Presenter.Droid; namespace IntegrationSample.Droid { - [Activity(Label = "IntegrationSample", Icon = "@drawable/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)] - public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity + [Activity(Label = "IntegrationSample", Icon = "@drawable/icon", Theme = "@style/MainTheme", MainLauncher = false, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)] + public class MainActivity : MvxFormsAppCompatActivity { protected override void OnCreate(Bundle bundle) { TabLayoutResource = Resource.Layout.Tabbar; ToolbarResource = Resource.Layout.Toolbar; - base.OnCreate(bundle); - - global::Xamarin.Forms.Forms.Init(this, bundle); - LoadApplication(new App()); + base.OnCreate(bundle); } } } diff --git a/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample.Droid/Setup.cs b/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample.Droid/Setup.cs index c5140389b..c58103322 100644 --- a/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample.Droid/Setup.cs +++ b/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample.Droid/Setup.cs @@ -1,19 +1,30 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -using Android.App; using Android.Content; -using Android.OS; -using Android.Runtime; -using Android.Views; -using Android.Widget; +using MvvmCross.Core.ViewModels; +using MvvmCross.Core.Views; using MvvmCross.Droid.Platform; +using MvvmCross.Droid.Views; +using MvvmCross.Forms.Presenter.Core; +using MvvmCross.Forms.Presenter.Droid; +using MvvmCross.Platform; namespace IntegrationSample.Droid { - class Setup : MvxAndroidSetup + public class Setup : MvxAndroidSetup { + public Setup(Context applicationContext) : base(applicationContext) + { + } + + protected override IMvxApplication CreateApp() + => new IntegrationSampleMvxApp(); + protected override IMvxAndroidViewPresenter CreateViewPresenter() + { + var baseAndroidPresenter = base.CreateViewPresenter(); + + var presenter = new MvxDroidFormsPresenterProxy(baseAndroidPresenter, new MvxDroidFormsPagePresenter(typeof(MainActivity))); + Mvx.RegisterSingleton(presenter); + + return presenter; + } } } \ No newline at end of file diff --git a/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample.Droid/SplashScreenActivity.cs b/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample.Droid/SplashScreenActivity.cs index 47c5bcfd0..f769806f5 100644 --- a/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample.Droid/SplashScreenActivity.cs +++ b/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample.Droid/SplashScreenActivity.cs @@ -1,18 +1,19 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - using Android.App; -using Android.Content; -using Android.OS; -using Android.Runtime; -using Android.Views; -using Android.Widget; +using Android.Content.PM; +using MvvmCross.Forms.Presenter.Droid; namespace IntegrationSample.Droid { - class SplashScreenActivity + [Activity( + Label = "Example.Droid" + , MainLauncher = true + , Icon = "@drawable/icon" + , NoHistory = true + , ScreenOrientation = ScreenOrientation.Portrait)] + public class SplashScreenActivity : MvxFormsSplashScreenActivity { + public SplashScreenActivity() : base(Resource.Layout.SplashScreen) + { + } } } \ No newline at end of file diff --git a/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample/Forms/Pages/AboutPage.xaml b/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample/Forms/Pages/AboutPage.xaml index 9a58478b6..d8539f81c 100644 --- a/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample/Forms/Pages/AboutPage.xaml +++ b/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample/Forms/Pages/AboutPage.xaml @@ -2,7 +2,7 @@ diff --git a/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample/Forms/Pages/MainPage.xaml b/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample/Forms/Pages/MainPage.xaml index 3bab38931..2fb73265d 100644 --- a/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample/Forms/Pages/MainPage.xaml +++ b/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample/Forms/Pages/MainPage.xaml @@ -2,7 +2,7 @@ diff --git a/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample/IntegrationSample.csproj b/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample/IntegrationSample.csproj index 338a7382f..87f9d7d99 100644 --- a/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample/IntegrationSample.csproj +++ b/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample/IntegrationSample.csproj @@ -38,6 +38,14 @@ App.xaml + + AboutPage.xaml + PreserveNewest + + + MainPage.xaml + + MainPage.xaml @@ -88,11 +96,27 @@ ..\..\packages\Xamarin.Forms.2.3.0.38-pre2\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.Xaml.dll True + + ..\..\..\bin\Debug\Droid\Xamarin.Forms.Xaml.Design.dll + + + + MSBuild:UpdateDesignTimeXaml + Designer + PreserveNewest + + + + + MSBuild:UpdateDesignTimeXaml + Designer + + diff --git a/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample/IntegrationSampleMvxApp.cs b/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample/IntegrationSampleMvxApp.cs index 5da500a03..12cd0836f 100644 --- a/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample/IntegrationSampleMvxApp.cs +++ b/MvvmCross.Forms.Sample.Integration/IntegrationSample/IntegrationSample/IntegrationSampleMvxApp.cs @@ -1,12 +1,15 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using IntegrationSample.ViewModels; +using MvvmCross.Core.ViewModels; namespace IntegrationSample { - class IntegrationSampleMvxApp + public class IntegrationSampleMvxApp : MvxApplication { + public override void Initialize() + { + base.Initialize(); + + RegisterAppStart(); + } } }