From 1ddcb5a6bc8f76b4d3657ab46aeeacdac2f219e0 Mon Sep 17 00:00:00 2001
From: atraczyk <andreastraczyk@gmail.com>
Date: Wed, 7 Sep 2016 16:18:30 -0400
Subject: [PATCH] UI/accounts: adds a loading screen during account loading

- adds faded loading pages with a spinner animation
- starts and stops the load page during account creation and loading
- resizes the loading graphics when window is resized
- adds an event handler for DPI and scale factor changes
- removes stretching from welcome page image
- clears account creation alias box after account creation clicked

Change-Id: I5046e0bc820e91c8b2f91ca223534d93ddf916f1
Tuleap: #1010
---
 MainPage.xaml        | 60 +++++++++++++++++++++++-----
 MainPage.xaml.cpp    | 93 ++++++++++++++++++++++++++++++++++++++++++++
 MainPage.xaml.h      | 15 +++++++
 RingD.cpp            |  5 ++-
 SmartPanel.xaml.cpp  |  7 +++-
 UserPreferences.cpp  | 27 +++++++------
 WelcomePage.xaml     | 11 ++++--
 WelcomePage.xaml.cpp | 21 +++++++++-
 WelcomePage.xaml.h   |  3 ++
 pch.h                |  5 ++-
 10 files changed, 215 insertions(+), 32 deletions(-)

diff --git a/MainPage.xaml b/MainPage.xaml
index 31d3e27..7dc2143 100644
--- a/MainPage.xaml
+++ b/MainPage.xaml
@@ -1,6 +1,7 @@
 <!-- **********************************************************************
 * Copyright (C) 2016 by Savoir-faire Linux                                *
 * Author: Jäger Nicolas<nicolas.jager@savoirfairelinux.com>               *
+* Author: Traczyk Andreas<andreas.traczyk@savoirfairelinux.com>           *
 *                                                                         *
 * This program is free software; you can redistribute it and/or modify    *
 * it under the terms of the GNU General Public License as published by    *
@@ -23,18 +24,57 @@
       xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
       mc:Ignorable="d">
 
+    <Page.Resources>
+        <Storyboard x:Name="_fadeOutStoryboard_">
+            <DoubleAnimation
+            Storyboard.TargetName="_loadingOverlay_"
+            Storyboard.TargetProperty="Opacity"
+            From="1.0" To="0.0" Duration="0:0:1" Completed="hideLoadingOverlay"/>
+        </Storyboard>
+        <Storyboard x:Name="_fadeInModalStoryboard_">
+            <DoubleAnimation
+            Storyboard.TargetName="_loadingOverlay_"
+            Storyboard.TargetProperty="Opacity"
+            From="0.0" To="0.85" Duration="0:0:0.25"/>
+        </Storyboard>
+    </Page.Resources>
+
     <Grid>
+        <Grid   x:Name="_loadingOverlay_"
+                Canvas.ZIndex="4"
+                Visibility="Collapsed">
+            <Rectangle  x:Name="_loadingOverlayRect_"
+                        Canvas.ZIndex="5"
+                        Fill="Black"
+                        Opacity="0.85"
+                        Width="auto"
+                        Height="auto">
+            </Rectangle>
+            <Canvas  Canvas.ZIndex="6">
+                <Image  x:Name="_loadingImage_"
+                        Source="Assets/Tests/logo-ring.scale-100.png"
+                        Width="620"
+                        Height="300"/>
+                <ProgressRing   Foreground="#19a0b7"
+                                Name="_splashProgressRing_"
+                                IsActive="True"
+                                MaxWidth="200"
+                                MaxHeight="200"
+                                Width="118"
+                                Height="118"/>
+            </Canvas>
+        </Grid>
         <SplitView x:Name="_outerSplitView_"
                    IsPaneOpen="False">
-        <SplitView.Pane>
-            <Frame x:Name="_consolePanel_"/>
-        </SplitView.Pane>
-        <SplitView.Content>
-            <SplitView x:Name="_innerSplitView_"
+            <SplitView.Pane>
+                <Frame x:Name="_consolePanel_"/>
+            </SplitView.Pane>
+            <SplitView.Content>
+                <SplitView x:Name="_innerSplitView_"
                        IsPaneOpen="True"
                        CompactPaneLength="60"
                        DisplayMode="CompactInline">
-                <SplitView.Pane>
+                    <SplitView.Pane>
                         <Grid>
                             <Grid.RowDefinitions>
                                 <RowDefinition Height="32"/>
@@ -62,7 +102,7 @@
                             </Frame>
                         </Grid>
                     </SplitView.Pane>
-                <SplitView.Content>
+                    <SplitView.Content>
                         <Grid x:Name="_navGrid_">
                             <Grid.RowDefinitions>
                                 <!-- stores the hidden frames. -->
@@ -81,8 +121,8 @@
                                    Visibility="Visible"/>
                         </Grid>
                     </SplitView.Content>
-            </SplitView>
-        </SplitView.Content>
-    </SplitView>
+                </SplitView>
+            </SplitView.Content>
+        </SplitView>
     </Grid>
 </Page>
diff --git a/MainPage.xaml.cpp b/MainPage.xaml.cpp
index d6b4bb9..5e30336 100644
--- a/MainPage.xaml.cpp
+++ b/MainPage.xaml.cpp
@@ -51,6 +51,8 @@ MainPage::MainPage()
 {
     InitializeComponent();
 
+    Window::Current->SizeChanged += ref new WindowSizeChangedEventHandler(this, &MainPage::OnResize);
+
     _welcomeFrame_->Navigate(TypeName(RingClientUWP::Views::WelcomePage::typeid));
     _smartPanel_->Navigate(TypeName(RingClientUWP::Views::SmartPanel::typeid));
     _consolePanel_->Navigate(TypeName(RingClientUWP::Views::RingConsolePanel::typeid));
@@ -64,6 +66,10 @@ MainPage::MainPage()
     ContactsViewModel::instance->noContactSelected += ref new NoContactSelected([&]() {
         showFrame(_welcomeFrame_);
     });
+
+    DisplayInformation^ displayInformation = DisplayInformation::GetForCurrentView();
+    dpiChangedtoken = (displayInformation->DpiChanged += ref new TypedEventHandler<DisplayInformation^,
+        Platform::Object^>(this, &MainPage::DisplayProperties_DpiChanged));
 }
 
 void
@@ -109,4 +115,91 @@ void
 RingClientUWP::MainPage::OnNavigatedTo(NavigationEventArgs ^ e)
 {
     RingD::instance->startDaemon();
+    showLoadingOverlay(true, false);
+}
+
+void
+RingClientUWP::MainPage::showLoadingOverlay(bool load, bool modal)
+{
+    if (!isLoading && load) {
+        isLoading = true;
+        _loadingOverlay_->Visibility = Windows::UI::Xaml::Visibility::Visible;
+        if (modal) {
+            _fadeInModalStoryboard_->Begin();
+            auto blackBrush = ref new Windows::UI::Xaml::Media::SolidColorBrush(Windows::UI::Colors::Black);
+            _loadingOverlayRect_->Fill = blackBrush;
+        }
+        else {
+            auto whiteBrush = ref new Windows::UI::Xaml::Media::SolidColorBrush(Windows::UI::Colors::White);
+            _loadingOverlayRect_->Fill = whiteBrush;
+            _loadingOverlayRect_->Opacity = 1.0;
+        }
+        OnResize(nullptr, nullptr);
+    }
+    else if (!load) {
+        isLoading = false;
+        _fadeOutStoryboard_->Begin();
+    }
+}
+
+void
+RingClientUWP::MainPage::PositionImage()
+{
+    bounds = ApplicationView::GetForCurrentView()->VisibleBounds;
+
+    auto img = ref new Image();
+    auto bitmapImage = ref new Windows::UI::Xaml::Media::Imaging::BitmapImage();
+    Windows::Foundation::Uri^ uri;
+
+    if (bounds.Width < 1200)
+        uri = ref new Windows::Foundation::Uri("ms-appx:///Assets/TESTS/logo-ring.scale-200.png");
+    else
+        uri = ref new Windows::Foundation::Uri("ms-appx:///Assets/TESTS/logo-ring.scale-150.png");
+
+    bitmapImage->UriSource = uri;
+    img->Source = bitmapImage;
+    _loadingImage_->Source = img->Source;
+
+    _loadingImage_->SetValue(Canvas::LeftProperty, bounds.Width * 0.5 - _loadingImage_->Width * 0.5);
+    _loadingImage_->SetValue(Canvas::TopProperty, bounds.Height * 0.5 - _loadingImage_->Height * 0.5);
+}
+
+void
+RingClientUWP::MainPage::PositionRing()
+{
+    double left;
+    double top;
+    if (bounds.Width < 1200) {
+        _splashProgressRing_->Width = 118;
+        _splashProgressRing_->Height = 118;
+        left = bounds.Width * 0.5 - _loadingImage_->Width * 0.5 - 145;
+        top = bounds.Height * 0.5 - _loadingImage_->Height * 0.5 - 60;
+    }
+    else {
+        _splashProgressRing_->Width = 162;
+        _splashProgressRing_->Height = 162;
+        left = bounds.Width * 0.5 - _loadingImage_->Width * 0.5 - 195;
+        top = bounds.Height * 0.5 - _loadingImage_->Height * 0.5 - 84;
+    }
+    _splashProgressRing_->SetValue(Canvas::LeftProperty, left + _loadingImage_->Width * 0.5);
+    _splashProgressRing_->SetValue(Canvas::TopProperty, top + _loadingImage_->Height * 0.5);
+}
+
+void
+RingClientUWP::MainPage::OnResize(Platform::Object^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ e)
+{
+    PositionImage();
+    PositionRing();
+}
+
+void
+RingClientUWP::MainPage::DisplayProperties_DpiChanged(DisplayInformation^ sender, Platform::Object^ args)
+{
+    OnResize(nullptr, nullptr);
+}
+
+void
+RingClientUWP::MainPage::hideLoadingOverlay()
+{
+    _loadingOverlay_->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
 }
\ No newline at end of file
diff --git a/MainPage.xaml.h b/MainPage.xaml.h
index 7b9691b..aa76667 100644
--- a/MainPage.xaml.h
+++ b/MainPage.xaml.h
@@ -20,6 +20,7 @@
 
 using namespace Windows::UI::Xaml::Controls;
 using namespace Windows::UI::Xaml::Input;
+using namespace Windows::Foundation;
 
 namespace RingClientUWP
 {
@@ -29,11 +30,25 @@ public ref class MainPage sealed
 {
 public:
     MainPage();
+    void showLoadingOverlay(bool load, bool modal);
+    void hideLoadingOverlay();
+
+    property bool isLoading;
 
 protected:
     virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override;
     virtual void OnKeyDown(KeyRoutedEventArgs^ e) override;
+
+    void PositionImage();
+    void PositionRing();
+    void OnResize(Platform::Object^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ e);
+
 private:
+    // Multi-monitor, DPI, scale factor change, and window resize detection
+    void DisplayProperties_DpiChanged(Windows::Graphics::Display::DisplayInformation^ sender, Platform::Object^ args);
+    Windows::Foundation::EventRegistrationToken dpiChangedtoken;
+    Rect bounds;
+
     void _toggleSmartBoxButton__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
     void showFrame(Windows::UI::Xaml::Controls::Frame^ frame);
 };
diff --git a/RingD.cpp b/RingD.cpp
index 3abac15..b52c2e2 100644
--- a/RingD.cpp
+++ b/RingD.cpp
@@ -207,10 +207,11 @@ RingClientUWP::RingD::startDaemon()
                         int detailsCode, const std::string& detailsStr)
             {
                 MSG_("<RegistrationStateChanged>: ID = " + account_id + "state = " + state);
-                if (state == DRing::Account::States::UNREGISTERED) {
+                if (state == DRing::Account::States::REGISTERED) {
                     CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(CoreDispatcherPriority::Normal,
                     ref new DispatchedHandler([=]() {
-                        reloadAccountList();
+                        auto frame = dynamic_cast<Frame^>(Window::Current->Content);
+                        dynamic_cast<RingClientUWP::MainPage^>(frame->Content)->showLoadingOverlay(false, false);
                     }));
                 }
             }),
diff --git a/SmartPanel.xaml.cpp b/SmartPanel.xaml.cpp
index 2366bec..db4bf79 100644
--- a/SmartPanel.xaml.cpp
+++ b/SmartPanel.xaml.cpp
@@ -130,7 +130,6 @@ void RingClientUWP::Views::SmartPanel::_shareMenuButton__Unchecked(Platform::Obj
     _shareMenuGrid_->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
 }
 
-
 void RingClientUWP::Views::SmartPanel::_addAccountBtn__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
 {
     _accountsMenuGrid_->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
@@ -143,6 +142,11 @@ void RingClientUWP::Views::SmartPanel::_createAccountYes__Click(Platform::Object
     {
     case 0:
     {
+        CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(CoreDispatcherPriority::High,
+        ref new DispatchedHandler([=]() {
+            auto frame = dynamic_cast<Windows::UI::Xaml::Controls::Frame^>(Window::Current->Content);
+            dynamic_cast<RingClientUWP::MainPage^>(frame->Content)->showLoadingOverlay(true, true);
+        }));
         RingD::instance->createRINGAccount(_aliasTextBox_->Text);
         _accountCreationMenuGrid_->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
         _accountsMenuButton__Checked(nullptr, nullptr);
@@ -159,6 +163,7 @@ void RingClientUWP::Views::SmartPanel::_createAccountYes__Click(Platform::Object
     default:
         break;
     }
+    _aliasTextBox_->Text = "";
 }
 
 
diff --git a/UserPreferences.cpp b/UserPreferences.cpp
index 026f749..2307c78 100644
--- a/UserPreferences.cpp
+++ b/UserPreferences.cpp
@@ -59,22 +59,25 @@ UserPreferences::load()
         .then([this,preferencesFile](bool contacts_file_exists)
     {
         if (contacts_file_exists) {
-            RingDebug::instance->print("opened preferences file");
             try {
                 create_task(ApplicationData::Current->LocalFolder->GetFileAsync(preferencesFile))
                     .then([this](StorageFile^ file)
                 {
-                    create_task(FileIO::ReadTextAsync(file))
-                        .then([this](String^ fileContents){
-                        RingDebug::instance->print("reading preferences file");
-                        if (fileContents != nullptr) {
-                            Destringify(fileContents);
-                            // select account index after loading preferences
-                            selectIndex(PREF_ACCOUNT_INDEX);
-                            if (PREF_PROFILE_PHOTO)
-                                loadProfileImage();
-                        }
-                    });
+                    try {
+                        create_task(FileIO::ReadTextAsync(file))
+                            .then([this](String^ fileContents){
+                            if (fileContents != nullptr) {
+                                Destringify(fileContents);
+                                // select account index after loading preferences
+                                selectIndex(PREF_ACCOUNT_INDEX);
+                                if (PREF_PROFILE_PHOTO)
+                                    loadProfileImage();
+                            }
+                        });
+                    }
+                    catch (Exception^ e) {
+                        RingDebug::instance->print("Exception while reading preferences file");
+                    }
                 });
             }
             catch (Exception^ e) {
diff --git a/WelcomePage.xaml b/WelcomePage.xaml
index f9aa112..d4f01f6 100644
--- a/WelcomePage.xaml
+++ b/WelcomePage.xaml
@@ -23,15 +23,18 @@
       xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
       mc:Ignorable="d">
 
-    <StackPanel HorizontalAlignment="Center"
-                VerticalAlignment="Center">
+    <Grid x:Name="_welcomePage_"
+        >
         <!--<TextBlock x:Uid="_welcomeMsg"
                    x:Name="_welcomeMsg_"
                    Style="{StaticResource TextStyle1}"
                    HorizontalAlignment="Center"
                    VerticalAlignment="Center"
                    TextWrapping="Wrap" />-->
-        <Image Source="Assets\TESTS\logo-ring.scale-125.png"/>
-    </StackPanel>
+        <Image x:Name="_welcomeImage_"
+            Source="Assets\TESTS\logo-ring.square-100.png"
+               Width="310"
+               Height="310"/>
+    </Grid>
 
 </Page>
diff --git a/WelcomePage.xaml.cpp b/WelcomePage.xaml.cpp
index 7112811..1a22547 100644
--- a/WelcomePage.xaml.cpp
+++ b/WelcomePage.xaml.cpp
@@ -25,4 +25,23 @@ using namespace RingClientUWP::Views;
 WelcomePage::WelcomePage()
 {
     InitializeComponent();
-};
\ No newline at end of file
+    Window::Current->SizeChanged += ref new WindowSizeChangedEventHandler(this, &WelcomePage::OnResize);
+    OnResize(nullptr, nullptr);
+};
+
+void
+WelcomePage::PositionImage()
+{
+    Rect imageBounds;
+    imageBounds.Width = _welcomePage_->ActualWidth;
+    imageBounds.Height = _welcomePage_->ActualWidth;
+
+    _welcomeImage_->SetValue(Canvas::LeftProperty, imageBounds.Width * 0.5 - _welcomeImage_->Width * 0.5);
+    _welcomeImage_->SetValue(Canvas::TopProperty, imageBounds.Height * 0.5 - _welcomeImage_->Height * 0.5);
+}
+
+void
+WelcomePage::OnResize(Platform::Object^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ e)
+{
+    PositionImage();
+}
\ No newline at end of file
diff --git a/WelcomePage.xaml.h b/WelcomePage.xaml.h
index 29cb127..1f37c15 100644
--- a/WelcomePage.xaml.h
+++ b/WelcomePage.xaml.h
@@ -26,6 +26,9 @@ public ref class WelcomePage sealed
 {
 public:
     WelcomePage();
+protected:
+    void PositionImage();
+    void OnResize(Platform::Object^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ e);
 };
 }
 }
\ No newline at end of file
diff --git a/pch.h b/pch.h
index daba861..3860e31 100644
--- a/pch.h
+++ b/pch.h
@@ -18,8 +18,8 @@
 **************************************************************************/
 
 /* standard system include files. */
-#include <ppltasks.h>
 #include <iomanip>
+#include <ppltasks.h>
 #include <queue>
 
 /* required by generated headers. */
@@ -31,9 +31,10 @@
 #include "Contact.h"
 #include "ContactsViewModel.h"
 #include "Conversation.h"
+#include "MainPage.xaml.h"
 
 /* ensure to be accessed from anywhere */
 #include "RingD.h"
 #include "RingDebug.h"
 #include "Utils.h"
-#include "UserPreferences.h"
+#include "UserPreferences.h"
\ No newline at end of file
-- 
GitLab