From 2425ddd0511df66b4c2e5442fedcb4f9886a15e2 Mon Sep 17 00:00:00 2001
From: atraczyk <andreastraczyk@gmail.com>
Date: Thu, 1 Sep 2016 13:16:22 -0400
Subject: [PATCH] profile: allow user to use an avatar when creating first
 account

- adds camera capture UI to wizard.
- stores avatar image to disk and logs a reference in the user's preferences.
- loads avatar from disk when loading preferences at application start.
- removes avatar icons from account list.
- removes camera capture UI from add accounts widget

Change-Id: Id3467a7214c2f52ec70690df360ce9e3a0cb2df2
Tuleap: #989
---
 SmartPanel.xaml     | 46 +++++++++++++++++----------------------
 SmartPanel.xaml.cpp | 44 +++++++++-----------------------------
 SmartPanel.xaml.h   |  1 -
 UserPreferences.cpp | 12 +++++++++--
 UserPreferences.h   |  6 ++++--
 Wizard.xaml         |  1 +
 Wizard.xaml.cpp     | 52 +++++++++++++++++++++++++++++++++++++++++++++
 Wizard.xaml.h       |  1 +
 8 files changed, 98 insertions(+), 65 deletions(-)

diff --git a/SmartPanel.xaml b/SmartPanel.xaml
index cef2e26..68baddf 100644
--- a/SmartPanel.xaml
+++ b/SmartPanel.xaml
@@ -110,38 +110,32 @@
                       x:DataType="local:Account">
             <Grid>
                 <Grid.ColumnDefinitions>
-                    <ColumnDefinition Width="60"/>
-                    <ColumnDefinition Width="200"/>
+                    <ColumnDefinition Width="260"/>
                     <ColumnDefinition Width="60"/>
                 </Grid.ColumnDefinitions>
                 <Grid.RowDefinitions>
                     <RowDefinition Height="30"/>
                     <RowDefinition Height="30"/>
                 </Grid.RowDefinitions>
-                <Image x:Name="_accountAvatar_"
-                       VerticalAlignment="Center"
-                       HorizontalAlignment="Center"
-                       Grid.Column="0"
-                       Grid.RowSpan="2"
-                       Width="55"
-                       Height="55"
-                       Source="Assets\TESTS\contactAvatar.png"/>
                 <TextBlock x:Name="_accountName_"
-                           Grid.Column="1"
+                           Grid.Column="0"
                            Grid.Row="0"
+                           Margin="10,5,10,0"
                            Text="{x:Bind name_}"/>
                 <TextBlock x:Name="_accountType_"
-                           Grid.Column="2"
+                           Grid.Column="1"
                            Grid.Row="0"
                            TextAlignment="Right"
-                           Margin="0,0,10,0"
+                           Margin="0,5,10,0"
                            Foreground="ForestGreen"
                            Text="{x:Bind accountType_}"/>
                 <TextBlock x:Name="_ringID_"
-                           Grid.Column="1"
+                           Grid.Column="0"
                            Grid.ColumnSpan="2"
                            Grid.Row="1"
                            Foreground="Crimson"
+                           Margin="10,5,10,0"
+                           FontSize="14"
                            TextTrimming="CharacterEllipsis"
                            Text="{x:Bind ringID_}"/>
             </Grid>
@@ -172,12 +166,18 @@
                     <ColumnDefinition Width="*"/>
                     <ColumnDefinition Width="50"/>
                 </Grid.ColumnDefinitions>
-                <Image x:Name="_selectedAccountAvatar_"
-                       Source="Assets\TESTS\contactAvatar.png"
-                       Width="80"
-                       Margin="5"
-                       Grid.Column="0"
-                       Height="80"/>
+                <Ellipse
+                    x:Name="_selectedAccountAvatarContainer_"
+                    Height="80"
+                    Width="80"
+                    Grid.Column="0"
+                    Margin="5">
+                    <Ellipse.Fill>
+                        <ImageBrush
+                            x:Name="_selectedAccountAvatar_"
+                            ImageSource="Assets\TESTS\contactAvatar.png"/>
+                    </Ellipse.Fill>
+                </Ellipse>
                 <StackPanel Grid.Column="1"
                             VerticalAlignment="Bottom">
                     <TextBlock x:Name="_selectedAccountName_"
@@ -263,12 +263,6 @@
                             <ComboBoxItem Content="Sip"/>
                         </ComboBox>
                     </StackPanel>
-                    <Button  x:Name="_avatarWebcamCaptureBtn_"
-                             VerticalAlignment="Center"
-                             Content="&#xE8B8;"
-                             Style="{StaticResource ButtonStyle3}"
-                             Click="_avatarWebcamCaptureBtn__Click"
-                             HorizontalAlignment="Center"/>
                     <!-- RING account. -->
                     <StackPanel x:Name="_ringAccountCreationStack_"
                                 Visibility="Visible">
diff --git a/SmartPanel.xaml.cpp b/SmartPanel.xaml.cpp
index d9e0dd5..85238c0 100644
--- a/SmartPanel.xaml.cpp
+++ b/SmartPanel.xaml.cpp
@@ -38,9 +38,16 @@ SmartPanel::SmartPanel()
 {
     InitializeComponent();
 
+    /* connect delegates */
     Configuration::UserPreferences::instance->selectIndex += ref new SelectIndex([this](int index) {
         _accountsList_->SelectedIndex = index;
     });
+    Configuration::UserPreferences::instance->loadProfileImage += ref new LoadProfileImage([this]() {
+        StorageFolder^ localfolder = ApplicationData::Current->LocalFolder;
+        String^ image_path = localfolder->Path + "\\.profile\\profile_image.png";
+        auto uri = ref new Windows::Foundation::Uri(image_path);
+        _selectedAccountAvatar_->ImageSource = ref new BitmapImage(uri);
+    });
 
     _accountsList_->ItemsSource = AccountsViewModel::instance->accountsList;
     _smartList_->ItemsSource = ContactsViewModel::instance->contactsList;
@@ -87,18 +94,18 @@ void RingClientUWP::Views::SmartPanel::setMode(RingClientUWP::Views::SmartPanel:
 {
     if (mode == RingClientUWP::Views::SmartPanel::Mode::Normal) {
         _rowRingTxtBx_->Height = 40;
-        _selectedAccountAvatar_->Height = 80;
+        _selectedAccountAvatarContainer_->Height = 80;
         _selectedAccountAvatarColumn_->Width = 90;
         _selectedAccountRow_->Height = 90;
     }
     else {
         _rowRingTxtBx_->Height = 0;
-        _selectedAccountAvatar_->Height = 50;
+        _selectedAccountAvatarContainer_->Height = 50;
         _selectedAccountAvatarColumn_->Width = 60;
         _selectedAccountRow_->Height = 60;
     }
 
-    _selectedAccountAvatar_->Width = _selectedAccountAvatar_->Height;
+    _selectedAccountAvatarContainer_->Width = _selectedAccountAvatarContainer_->Height;
     _settingsTBtn_->IsChecked = false;
     _accountsMenuButton_->IsChecked = false;
     _shareMenuButton_->IsChecked = false;
@@ -134,37 +141,6 @@ void RingClientUWP::Views::SmartPanel::_createAccountNo__Click(Platform::Object^
 
 }
 
-
-void RingClientUWP::Views::SmartPanel::_avatarWebcamCaptureBtn__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
-{
-    CameraCaptureUI^ cameraCaptureUI = ref new CameraCaptureUI();
-    cameraCaptureUI->PhotoSettings->Format = CameraCaptureUIPhotoFormat::Png;
-    cameraCaptureUI->PhotoSettings->CroppedSizeInPixels = Size(100, 100);
-
-
-    create_task(cameraCaptureUI->CaptureFileAsync(CameraCaptureUIMode::Photo)).then([this](StorageFile^ photo)
-    {
-        if (photo != nullptr) {
-            // maybe it would be possible to move some logics to the style sheet
-            auto brush = ref new ImageBrush();
-
-            auto circle = ref new Ellipse();
-            circle->Height = 80; // TODO : use some global constant when ready
-            circle->Width = 80;
-            auto path = photo->Path;
-            auto uri = ref new Windows::Foundation::Uri(path);
-            auto bitmapImage = ref new Windows::UI::Xaml::Media::Imaging::BitmapImage();
-            bitmapImage->UriSource = uri;
-
-            brush->ImageSource = bitmapImage;
-            circle->Fill = brush;
-            _avatarWebcamCaptureBtn_->Content = circle;
-        }
-    });
-
-}
-
-
 void
 SmartPanel::_smartList__SelectionChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e)
 {
diff --git a/SmartPanel.xaml.h b/SmartPanel.xaml.h
index f65b213..29e6a56 100644
--- a/SmartPanel.xaml.h
+++ b/SmartPanel.xaml.h
@@ -50,7 +50,6 @@ private:
     void _addAccountBtn__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
     void _createAccountYes__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
     void _createAccountNo__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
-    void _avatarWebcamCaptureBtn__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
     void _smartList__SelectionChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e);
     void _accountList__SelectionChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e);
     void _ringTxtBx__KeyDown(Platform::Object^ sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs^ e);
diff --git a/UserPreferences.cpp b/UserPreferences.cpp
index b6cd775..026f749 100644
--- a/UserPreferences.cpp
+++ b/UserPreferences.cpp
@@ -71,6 +71,8 @@ UserPreferences::load()
                             Destringify(fileContents);
                             // select account index after loading preferences
                             selectIndex(PREF_ACCOUNT_INDEX);
+                            if (PREF_PROFILE_PHOTO)
+                                loadProfileImage();
                         }
                     });
                 });
@@ -89,7 +91,10 @@ String^
 UserPreferences::Stringify()
 {
     JsonObject^ preferencesObject = ref new JsonObject();
-    preferencesObject->SetNamedValue("PREF_ACCOUNT_INDEX", JsonValue::CreateNumberValue(PREF_ACCOUNT_INDEX));
+
+    preferencesObject->SetNamedValue("PREF_ACCOUNT_INDEX", JsonValue::CreateNumberValue(    PREF_ACCOUNT_INDEX));
+    preferencesObject->SetNamedValue("PREF_PROFILE_PHOTO", JsonValue::CreateBooleanValue(   PREF_PROFILE_PHOTO));
+
     return preferencesObject->Stringify();
 }
 
@@ -97,6 +102,9 @@ void
 UserPreferences::Destringify(String^ data)
 {
     JsonObject^ jsonObject = JsonObject::Parse(data);
-    PREF_ACCOUNT_INDEX = static_cast<int>(jsonObject->GetNamedNumber("PREF_ACCOUNT_INDEX"));
+
+    PREF_ACCOUNT_INDEX = static_cast<int>(jsonObject->GetNamedNumber(   "PREF_ACCOUNT_INDEX"    ));
+    PREF_PROFILE_PHOTO = jsonObject->GetNamedBoolean(                   "PREF_PROFILE_PHOTO"    );
+
     JsonArray^ preferencesList = jsonObject->GetNamedArray("Account.index", ref new JsonArray());
 }
\ No newline at end of file
diff --git a/UserPreferences.h b/UserPreferences.h
index 5c8ee75..1b171b3 100644
--- a/UserPreferences.h
+++ b/UserPreferences.h
@@ -23,6 +23,7 @@ namespace RingClientUWP
 {
 
 delegate void SelectIndex(int index);
+delegate void LoadProfileImage();
 
 namespace Configuration
 {
@@ -44,6 +45,7 @@ public:
 
     /* properties */
     property int        PREF_ACCOUNT_INDEX;
+    property bool       PREF_PROFILE_PHOTO;
 
     /* functions */
     void                save();
@@ -55,9 +57,9 @@ internal:
 
     /* events */
     event SelectIndex^ selectIndex;
-
+    event LoadProfileImage^ loadProfileImage;
 private:
-    UserPreferences() { };
+    UserPreferences() { PREF_PROFILE_PHOTO = false; };
 
 };
 
diff --git a/Wizard.xaml b/Wizard.xaml
index 372beea..599ae1c 100644
--- a/Wizard.xaml
+++ b/Wizard.xaml
@@ -44,6 +44,7 @@
                                  Margin="0,10,0,0"
                                  VerticalAlignment="Center"
                                  Content="&#xE8B8;"
+                                 Click="_avatarWebcamCaptureBtn__Click"
                                  Style="{StaticResource ButtonStyle3}"
                                  HorizontalAlignment="Center"/>
                         <!-- RING account. -->
diff --git a/Wizard.xaml.cpp b/Wizard.xaml.cpp
index f385875..b706b59 100644
--- a/Wizard.xaml.cpp
+++ b/Wizard.xaml.cpp
@@ -19,6 +19,9 @@ using namespace Windows::UI::Xaml::Input;
 using namespace Windows::UI::Xaml::Media;
 using namespace Windows::UI::Xaml::Navigation;
 using namespace Windows::Media::Capture;
+using namespace Windows::Storage;
+using namespace Windows::UI::Xaml::Media::Imaging;
+using namespace Windows::UI::Xaml::Shapes;
 
 Wizard::Wizard()
 {
@@ -62,4 +65,53 @@ Wizard::_showAddAccountMenuBtn__Click(Object^ sender, RoutedEventArgs^ e)
     _accountAddMenuGrid_->Visibility = Windows::UI::Xaml::Visibility::Visible;
     _showAddAccountMenuTitle_->Visibility = Windows::UI::Xaml::Visibility::Visible;
     _showAddAccountMenuBtn_->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
+}
+
+void
+Wizard::_avatarWebcamCaptureBtn__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
+{
+    CameraCaptureUI^ cameraCaptureUI = ref new CameraCaptureUI();
+    cameraCaptureUI->PhotoSettings->Format = CameraCaptureUIPhotoFormat::Png;
+    cameraCaptureUI->PhotoSettings->CroppedSizeInPixels = Size(100, 100);
+
+    create_task(cameraCaptureUI->CaptureFileAsync(CameraCaptureUIMode::Photo))
+        .then([this](StorageFile^ photoFile)
+    {
+        if (photoFile != nullptr) {
+            // maybe it would be possible to move some logics to the style sheet
+            auto brush = ref new ImageBrush();
+
+            auto circle = ref new Ellipse();
+            circle->Height = 80; // TODO : use some global constant when ready
+            circle->Width = 80;
+            auto path = photoFile->Path;
+            auto uri = ref new Windows::Foundation::Uri(path);
+            auto bitmapImage = ref new Windows::UI::Xaml::Media::Imaging::BitmapImage();
+            bitmapImage->UriSource = uri;
+
+            StorageFolder^ localfolder = ApplicationData::Current->LocalFolder;
+            String^ profilefolder = ".profile";
+            create_task(localfolder->CreateFolderAsync(profilefolder,
+                Windows::Storage::CreationCollisionOption::OpenIfExists))
+                .then([=](StorageFolder^ copytofolder){
+                try {
+                    create_task(photoFile->CopyAsync(copytofolder))
+                        .then([=](StorageFile^ copiedfile){
+                        copiedfile->RenameAsync("profile_image.png",
+                            Windows::Storage::NameCollisionOption::ReplaceExisting);
+                    });
+                }
+                catch (Exception^ e) {
+                    RingDebug::instance->print("Exception while saving profile image");
+                }
+            });
+
+            Configuration::UserPreferences::instance->PREF_PROFILE_PHOTO = true;
+
+            brush->ImageSource = bitmapImage;
+            circle->Fill = brush;
+            _avatarWebcamCaptureBtn_->Content = circle;
+        }
+    });
+
 }
\ No newline at end of file
diff --git a/Wizard.xaml.h b/Wizard.xaml.h
index 70792c5..7c146a0 100644
--- a/Wizard.xaml.h
+++ b/Wizard.xaml.h
@@ -15,6 +15,7 @@ private:
     void _createAccountYes__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
     void _showCreateAccountMenuBtn__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
     void _showAddAccountMenuBtn__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
+    void _avatarWebcamCaptureBtn__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
 };
 
 }
-- 
GitLab