From c551c365e83c768ba053189063b29b6a4de1256f Mon Sep 17 00:00:00 2001 From: Nicolas Jager <nicolas.jager@savoirfairelinux.com> Date: Sat, 1 Oct 2016 19:24:50 -0400 Subject: [PATCH] smartpanel : refactoring Change-Id: Iea01dd8242270e1c080cd95030da4d211638d993 Tuleap: #1202 --- Call.cpp | 9 +- Call.h | 18 +++- CallsViewModel.cpp | 45 ++++----- CallsViewModel.h | 1 + Contact.cpp | 28 +----- Contact.h | 21 ++-- ContactsViewModel.cpp | 24 ++--- ContactsViewModel.h | 27 ----- MainPage.xaml.cpp | 96 ++++++++++++------ MainPage.xaml.h | 6 ++ MessageTextPage.xaml.cpp | 24 ++--- RingD.cpp | 29 +++++- RingD.h | 3 +- SmartPanel.xaml | 201 +++++++++++++++++++++++-------------- SmartPanel.xaml.cpp | 139 +++++++++++++++++++------ SmartPanel.xaml.h | 39 ++++++- SmartPanelItem.cpp | 5 +- SmartPanelItem.h | 49 +++------ SmartPanelItemsViewModel.h | 14 ++- Styles.xaml | 15 +++ VideoPage.xaml.cpp | 19 ++-- 21 files changed, 493 insertions(+), 319 deletions(-) diff --git a/Call.cpp b/Call.cpp index b756033..6cc2fe3 100644 --- a/Call.cpp +++ b/Call.cpp @@ -35,17 +35,10 @@ Call::Call(String^ accountIdz, String^ callIdz, String^ fromz) isOutGoing = false; // by default, we consider the call incomming, REFACTO : add this to the constructor params... - this->state = "incoming call"; + this->state = CallStatus::NONE; this->code = -1; } -void RingClientUWP::Call::stateChange(String ^ state, int code) -{ - this->state = state; - PropertyChanged(this, ref new PropertyChangedEventArgs("state")); - this->code = code; -} - void Call::NotifyPropertyChanged(String^ propertyName) { diff --git a/Call.h b/Call.h index fb5be0b..dfebe21 100644 --- a/Call.h +++ b/Call.h @@ -21,12 +21,15 @@ using namespace Windows::UI::Xaml::Data; namespace RingClientUWP { +/* enumerations. */ +public enum class CallStatus { NONE, INCOMING_RINGING, OUTGOING_RINGING, SEARCHING, IN_PROGRESS, ENDED }; + public ref class Call sealed : public INotifyPropertyChanged { public: + /* functions */ Call(String^ accountId, String^ callId, String^ from); - void stateChange(String^ state, int code); /* properties */ virtual event PropertyChangedEventHandler^ PropertyChanged; @@ -34,7 +37,15 @@ public: property String^ accountId; property String^ callId; property String^ from; - property String^ state; + property CallStatus state { + CallStatus get() { + return state_; + } + void set(CallStatus value) { + state_ = value; + PropertyChanged(this, ref new PropertyChangedEventArgs("state")); + } + } property bool isOutGoing; property int code; @@ -49,6 +60,9 @@ internal: void accept(); void cancel(); +private: + CallStatus state_; + }; } diff --git a/CallsViewModel.cpp b/CallsViewModel.cpp index b714790..07e9019 100644 --- a/CallsViewModel.cpp +++ b/CallsViewModel.cpp @@ -34,32 +34,10 @@ CallsViewModel::CallsViewModel() RingD::instance->incomingCall += ref new RingClientUWP::IncomingCall([&]( String^ accountId, String^ callId, String^ from) { auto call = addNewCall(accountId, callId, from); - // REFACTO : add if call == nullptr - callRecieved(call); - }); - - RingD::instance->stateChange += ref new RingClientUWP::StateChange([&]( - String^ callId, String^ state, int code) { - for each (auto call in CallsList_) { - if (call->callId == callId) { - if (state == "OVER") { - delete call; - call->stateChange("", code); - callEnded(); - callStatusUpdated(call); // used ? - RingD::instance->hangUpCall(call); - return; - } - else if (state == "CURRENT") { - callStarted(); - } - call->stateChange(state, code); - callStatusUpdated(call); // same... - return; - } - } - WNG_("Call not found"); + if (call) + callRecieved(call); }); + RingD::instance->stateChange += ref new RingClientUWP::StateChange(this, &RingClientUWP::ViewModel::CallsViewModel::OnstateChange); } Call^ @@ -87,3 +65,20 @@ CallsViewModel::findCall(String^ callId) return nullptr; } + + +void RingClientUWP::ViewModel::CallsViewModel::OnstateChange(Platform::String ^callId, RingClientUWP::CallStatus state, int code) +{ + auto call = findCall(callId); + + if (!call) + return; + + switch (state) + { + case CallStatus::ENDED: + RingD::instance->hangUpCall(call); + default: + break; + } +} diff --git a/CallsViewModel.h b/CallsViewModel.h index 4938249..24ddbb0 100644 --- a/CallsViewModel.h +++ b/CallsViewModel.h @@ -66,6 +66,7 @@ private: CallsViewModel(); // singleton Vector<Call^>^ CallsList_; // refacto : change C to c + void OnstateChange(Platform::String ^callId, RingClientUWP::CallStatus state, int code); }; } } diff --git a/Contact.cpp b/Contact.cpp index fd463af..155a7ff 100644 --- a/Contact.cpp +++ b/Contact.cpp @@ -65,28 +65,6 @@ Contact::Contact(String^ name, notificationNewMessage = Windows::UI::Xaml::Visibility::Visible; PropertyChanged(this, ref new PropertyChangedEventArgs("unreadMessages")); } - - /* connect to delegate */ - ContactsViewModel::instance->notifyNewConversationMessage += ref new NotifyNewConversationMessage([&] ( - bool isContactNotSelected) { - if (isContactNotSelected) - PropertyChanged(this, ref new PropertyChangedEventArgs("unreadMessages")); - }); - ContactsViewModel::instance->newContactSelected += ref new RingClientUWP::NewContactSelected([&]() { - if (ContactsViewModel::instance->selectedContact == this) { - PropertyChanged(this, ref new PropertyChangedEventArgs("unreadMessages")); - notificationNewMessage = Windows::UI::Xaml::Visibility::Collapsed; - unreadMessages_ = 0; - ContactsViewModel::instance->saveContactsToFile(); - } - }); -} - -void -Contact::addNotifyNewConversationMessage() -{ - notificationNewMessage = Windows::UI::Xaml::Visibility::Visible; - unreadMessages_++; } void @@ -169,4 +147,8 @@ Contact::saveConversationToFile() file.close(); } } -} \ No newline at end of file +} + + + + diff --git a/Contact.h b/Contact.h index a88d648..d2cdf28 100644 --- a/Contact.h +++ b/Contact.h @@ -64,23 +64,16 @@ public: PropertyChanged(this, ref new PropertyChangedEventArgs("notificationNewMessage")); } } - property String^ unreadMessages + property uint32 _unreadMessages { - String^ get() + uint32 get() { - return unreadMessages_.ToString(); + return unreadMessages_; } - } - property Call^ _call - { - Call^ get() - { - return call_; - } - void set(Call^ call) + void set(uint32 value) { - call_ = call; - PropertyChanged(this, ref new PropertyChangedEventArgs("_call")); + unreadMessages_ = value; + PropertyChanged(this, ref new PropertyChangedEventArgs("_unreadMessages")); } } property Windows::UI::Xaml::GridLength _contactBarHeight @@ -100,7 +93,6 @@ internal: void saveConversationToFile(); String^ StringifyConversation(); void DestringifyConversation(String^ data); - void addNotifyNewConversationMessage(); protected: void NotifyPropertyChanged(String^ propertyName); @@ -110,7 +102,6 @@ private: Visibility notificationNewMessage_; unsigned int unreadMessages_; Windows::UI::Xaml::GridLength contactBarHeight_ = 0; - Call^ call_; }; } diff --git a/ContactsViewModel.cpp b/ContactsViewModel.cpp index e49ea1c..cb98f58 100644 --- a/ContactsViewModel.cpp +++ b/ContactsViewModel.cpp @@ -39,13 +39,13 @@ ContactsViewModel::ContactsViewModel() /* connect delegates. */ RingD::instance->incomingAccountMessage += ref new IncomingAccountMessage([&](String^ accountId, - String^ from, String^ payload) { - auto contact = findContactByName(from); + String^ fromRingId, String^ payload) { + auto contact = findContactByName(fromRingId); if (contact == nullptr) - contact = addNewContact(from, from); // contact checked inside addNewContact. + contact = addNewContact(fromRingId, fromRingId); // contact checked inside addNewContact. - bool isNotSelected = (contact != ContactsViewModel::instance->selectedContact) ? true : false; + auto item = SmartPanelItemsViewModel::instance->_selectedItem; if (contact == nullptr) { ERR_("contact not handled!"); @@ -57,15 +57,13 @@ ContactsViewModel::ContactsViewModel() /* save contacts conversation to disk */ contact->saveConversationToFile(); - if (contact->ringID_ == from) { - // increment contact's unread message count - if (isNotSelected) { - contact->addNotifyNewConversationMessage(); - // save to disk - saveContactsToFile(); - } - // update the xaml for all contacts - notifyNewConversationMessage(isNotSelected); + + auto selectedContact = (item) ? item->_contact : nullptr; + + if (contact->ringID_ == fromRingId && contact != selectedContact) { + contact->_unreadMessages++; + /* saveContactsToFile used to save the notification */ + saveContactsToFile(); } }); } diff --git a/ContactsViewModel.h b/ContactsViewModel.h index 8350f6d..ab7e56d 100644 --- a/ContactsViewModel.h +++ b/ContactsViewModel.h @@ -26,11 +26,6 @@ namespace RingClientUWP { /* delegates */ -delegate void NewContactSelected(); -delegate void NoContactSelected(); -delegate void ScreenConversationMessage(String^ accountId, String^ from, String^ payload); -delegate void NotifyNewConversationMessage(bool isContactNotSelected); -delegate void ShowContactBar(); delegate void ContactAdded(Contact^); namespace ViewModel { @@ -56,23 +51,6 @@ internal: void Destringify(String^ data); /* properties */ - property Contact^ selectedContact - { - Contact^ get() - { - return currentItem_; - } - void set(Contact^ value) - { - oldItem_ = currentItem_; - currentItem_ = value; - if (value) - newContactSelected(); - else - noContactSelected(); - } - } - property Vector<Contact^>^ contactsList { Vector<Contact^>^ get() @@ -82,11 +60,6 @@ internal: } /* events */ - event NewContactSelected^ newContactSelected; - event NoContactSelected^ noContactSelected; - event ScreenConversationMessage^ screenConversationMessage; - event NotifyNewConversationMessage^ notifyNewConversationMessage; - event ShowContactBar^ showContactBar; event ContactAdded^ contactAdded; private: diff --git a/MainPage.xaml.cpp b/MainPage.xaml.cpp index 67ec540..191ae3b 100644 --- a/MainPage.xaml.cpp +++ b/MainPage.xaml.cpp @@ -60,36 +60,13 @@ MainPage::MainPage() _messageTextFrame_->Navigate(TypeName(RingClientUWP::Views::MessageTextPage::typeid)); /* connect to delegates */ - ContactsViewModel::instance->newContactSelected += ref new NewContactSelected([&]() { - Contact^ selectedContact = ContactsViewModel::instance->selectedContact; - auto call = selectedContact? - SmartPanelItemsViewModel::instance->findItem(selectedContact)->_call: - nullptr; - if (call != nullptr) { - if (call->state == "CURRENT") - showFrame(_videoFrame_); - else - showFrame(_messageTextFrame_); - } - else { - showFrame(_messageTextFrame_); - } - }); - ContactsViewModel::instance->noContactSelected += ref new NoContactSelected([&]() { - showFrame(_welcomeFrame_); - }); - CallsViewModel::instance->callStarted += ref new CallStarted([&]() { - showFrame(_videoFrame_); - }); - CallsViewModel::instance->callEnded += ref new CallEnded([&]() { - auto contact = ContactsViewModel::instance->selectedContact; - - if(contact) - showFrame(_messageTextFrame_); - else - showFrame(_welcomeFrame_); - - }); + RingD::instance->stateChange += ref new RingClientUWP::StateChange(this, &RingClientUWP::MainPage::OnstateChange); + auto smartPanel = dynamic_cast<SmartPanel^>(_smartPanel_->Content); + smartPanel->summonMessageTextPage += ref new RingClientUWP::SummonMessageTextPage(this, &RingClientUWP::MainPage::OnsummonMessageTextPage); + smartPanel->summonWelcomePage += ref new RingClientUWP::SummonWelcomePage(this, &RingClientUWP::MainPage::OnsummonWelcomePage); + smartPanel->summonVideoPage += ref new RingClientUWP::SummonVideoPage(this, &RingClientUWP::MainPage::OnsummonVideoPage); + auto videoPage = dynamic_cast<VideoPage^>(_videoFrame_->Content); + videoPage->pressHangUpCall += ref new RingClientUWP::PressHangUpCall(this, &RingClientUWP::MainPage::OnpressHangUpCall); DisplayInformation^ displayInformation = DisplayInformation::GetForCurrentView(); dpiChangedtoken = (displayInformation->DpiChanged += ref new TypedEventHandler<DisplayInformation^, @@ -132,7 +109,6 @@ RingClientUWP::MainPage::showFrame(Windows::UI::Xaml::Controls::Frame^ frame) dynamic_cast<VideoPage^>(_videoFrame_->Content)->updatePageContent(); } else if (frame == _messageTextFrame_) { _navGrid_->SetRow(_messageTextFrame_, 1); - dynamic_cast<MessageTextPage^>(_messageTextFrame_->Content)->updatePageContent(); } } @@ -227,4 +203,60 @@ void RingClientUWP::MainPage::hideLoadingOverlay() { _loadingOverlay_->Visibility = Windows::UI::Xaml::Visibility::Collapsed; -} \ No newline at end of file +} + +void RingClientUWP::MainPage::OnsummonMessageTextPage() +{ + auto messageTextPage = dynamic_cast<MessageTextPage^>(_messageTextFrame_->Content); + messageTextPage->updatePageContent(); + showFrame(_messageTextFrame_); + +} + + +void RingClientUWP::MainPage::OnsummonWelcomePage() +{ + showFrame(_welcomeFrame_); +} + + +void RingClientUWP::MainPage::OnsummonVideoPage() +{ + auto videoPage = dynamic_cast<VideoPage^>(_videoFrame_->Content); + videoPage->updatePageContent(); + showFrame(_videoFrame_); +} + + +void RingClientUWP::MainPage::OnpressHangUpCall() +{ + OnsummonMessageTextPage(); +} + + + +void RingClientUWP::MainPage::OnstateChange(Platform::String ^callId, RingClientUWP::CallStatus state, int code) +{ + auto item = SmartPanelItemsViewModel::instance->_selectedItem; + + switch (state) { + /* send the user to the peer's message text page */ + case CallStatus::ENDED: + { + if (item) + OnsummonMessageTextPage(); + break; + } + /* if the state changes to IN_PROGRESS for any peer, show the video page. + nb : the peer is currently selected from the SmartPannel. */ + case CallStatus::IN_PROGRESS: + { + if (item) + OnsummonVideoPage(); + break; + } + default: + break; + } + +} diff --git a/MainPage.xaml.h b/MainPage.xaml.h index aa76667..d97fd59 100644 --- a/MainPage.xaml.h +++ b/MainPage.xaml.h @@ -24,6 +24,7 @@ using namespace Windows::Foundation; namespace RingClientUWP { + namespace Views { } public ref class MainPage sealed @@ -51,5 +52,10 @@ private: void _toggleSmartBoxButton__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); void showFrame(Windows::UI::Xaml::Controls::Frame^ frame); + void OnsummonMessageTextPage(); + void OnsummonWelcomePage(); + void OnsummonVideoPage(); + void OnpressHangUpCall(); + void OnstateChange(Platform::String ^callId, RingClientUWP::CallStatus state, int code); }; } \ No newline at end of file diff --git a/MessageTextPage.xaml.cpp b/MessageTextPage.xaml.cpp index aca763d..aa539a1 100644 --- a/MessageTextPage.xaml.cpp +++ b/MessageTextPage.xaml.cpp @@ -16,8 +16,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * **************************************************************************/ #include "pch.h" - #include "ContactsViewModel.h" + #include "MainPage.xaml.h" #include "MessageTextPage.xaml.h" @@ -44,25 +44,19 @@ MessageTextPage::MessageTextPage() { InitializeComponent(); - /* connect delegates. */ - // REFACTO : useless ? + /* connect to delegates */ RingD::instance->incomingAccountMessage += ref new IncomingAccountMessage([&](String^ accountId, - String^ from, String^ payload) { - }); - ContactsViewModel::instance->notifyNewConversationMessage += ref new NotifyNewConversationMessage([&]( - bool isContactNotSelected) { - if (!isContactNotSelected) { - /* if the contact is selected that means we should scroll down */ - scrollDown(); - } - + String^ fromRingId, String^ payload) { + scrollDown(); }); } void RingClientUWP::Views::MessageTextPage::updatePageContent() { - auto contact = ContactsViewModel::instance->selectedContact; + auto item = SmartPanelItemsViewModel::instance->_selectedItem; + auto contact = item->_contact; + if (!contact) return; @@ -96,7 +90,9 @@ RingClientUWP::Views::MessageTextPage::_messageTextBox__KeyDown(Platform::Object void RingClientUWP::Views::MessageTextPage::sendMessage() { - auto contact = ContactsViewModel::instance->selectedContact; + auto item = SmartPanelItemsViewModel::instance->_selectedItem; + auto contact = item->_contact; + auto txt = _messageTextBox_->Text; /* empty the textbox */ diff --git a/RingD.cpp b/RingD.cpp index 3187639..2508fb8 100644 --- a/RingD.cpp +++ b/RingD.cpp @@ -67,7 +67,8 @@ void RingClientUWP::RingD::sendAccountTextMessage(String^ message) std::string accountId3(accountId2.begin(), accountId2.end()); /* recipient */ - auto contact = ContactsViewModel::instance->selectedContact; + auto item = SmartPanelItemsViewModel::instance->_selectedItem; + auto contact = item->_contact; auto toRingId = contact->ringID_; std::wstring toRingId2(toRingId->Begin()); std::string toRingId3(toRingId2.begin(), toRingId2.end()); @@ -197,7 +198,7 @@ RingClientUWP::RingD::startDaemon() CoreDispatcherPriority::Normal, ref new DispatchedHandler([=]() { incomingCall(accountId2, callId2, from2); - stateChange(callId2, "incoming call", 0); + stateChange(callId2, CallStatus::INCOMING_RINGING, 0); })); }), DRing::exportable_callback<DRing::CallSignal::StateChange>([this]( @@ -213,11 +214,13 @@ RingClientUWP::RingD::startDaemon() auto callId2 = toPlatformString(callId); auto state2 = toPlatformString(state); + auto state3 = getCallStatus(state2); + CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync( CoreDispatcherPriority::Low, ref new DispatchedHandler([=]() { - stateChange(callId2, state2, code); + stateChange(callId2, state3, code); })); }), DRing::exportable_callback<DRing::ConfigurationSignal::IncomingAccountMessage>([&]( @@ -414,3 +417,23 @@ RingD::dequeueTasks() tasksList_.pop(); } } + +CallStatus RingClientUWP::RingD::getCallStatus(String^ state) +{ + if (state == "INCOMING") + return CallStatus::INCOMING_RINGING; + + if (state == "CURRENT") + return CallStatus::IN_PROGRESS; + + if (state == "OVER") + return CallStatus::ENDED; + + if (state == "RINGING") + return CallStatus::OUTGOING_RINGING; + + if (state == "CONNECTING") + return CallStatus::SEARCHING; + + return CallStatus::NONE; +} diff --git a/RingD.h b/RingD.h index 0bcfbdb..06334a6 100644 --- a/RingD.h +++ b/RingD.h @@ -24,7 +24,7 @@ namespace RingClientUWP /* delegate */ delegate void IncomingCall(String^ accountId, String^ callId, String^ from); -delegate void StateChange(String^ callId, String^ state, int code); +delegate void StateChange(String^ callId, CallStatus state, int code); delegate void IncomingAccountMessage(String^ accountId, String^ from, String^ payload); delegate void Calling(Call^ call); @@ -104,6 +104,7 @@ private: /* functions */ RingD(); // singleton void dequeueTasks(); + CallStatus getCallStatus(String^ state); /* members */ std::string localFolder_; diff --git a/SmartPanel.xaml b/SmartPanel.xaml index 4431fcc..3876183 100644 --- a/SmartPanel.xaml +++ b/SmartPanel.xaml @@ -21,11 +21,18 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:RingClientUWP" xmlns:controls="using:RingClientUWP.Controls" + xmlns:views="using:RingClientUWP.Views" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Page.Resources> + <!-- converters --> + <views:NewMessageBubleNotification x:Key="_NewMessageBubleNotification_" /> + <views:IncomingVisibility x:Key="_IncomingVisibility_" /> + <views:OutGoingVisibility x:Key="_OutGoingVisibility_" /> + <views:HasAnActiveCall x:Key="_HasAnActiveCall_" /> + <Style x:Key="addContactTextBoxStyle" TargetType="TextBox"> <Setter Property="MinWidth" Value="{ThemeResource TextControlThemeMinWidth}"/> @@ -146,15 +153,6 @@ <TranslateTransform X="17" Y="-14"/> </Border.RenderTransform> </Border> - <Border x:Name="_visualNotificationNewMessage_" - Visibility="{x:Bind notificationNewMessage, Mode=OneWay}" - Style="{StaticResource BorderStyle2}"> - <TextBlock Text="{x:Bind unreadMessages, Mode=OneWay}" - Style="{StaticResource TextStyle3}"/> - <Border.RenderTransform> - <TranslateTransform X="-17" Y="-14"/> - </Border.RenderTransform> - </Border> <Grid Grid.Column="1"> <Grid.RowDefinitions> <RowDefinition Height="30"/> @@ -166,42 +164,8 @@ Text="{x:Bind name_}" TextTrimming="CharacterEllipsis"> </TextBlock> - <!-- call status. REFACTO : REMOVE CODE BELOW --> - <!--<StackPanel MaxWidth="240" - MinWidth="240" - Grid.Row="1" - HorizontalAlignment="Left"> - <TextBlock x:Name="_contactCallStatus_" - Foreground="DarkGray" - Text="{x:Bind _call.state, Mode=OneWay}" - Visibility="Visible" - HorizontalAlignment="Center"> - </TextBlock> - </StackPanel>--> </Grid> </Grid> - <!-- REFACTO : REMOVE CODE BELOW --> - <!-- button bar for accept/reject or cancel call. --> - <!-- nb : dont use Visibility with the grid, use the height of the hosting row (_contactBar_). --> - <!--<Grid Width="320" - HorizontalAlignment="Left" - Grid.Row="2" - Background="DarkGray"> - <StackPanel Orientation="Horizontal" - Grid.Row="0" - HorizontalAlignment="Center"> - <Button x:Name="_acceptIncomingCallBtn_" - Click="_acceptIncomingCallBtn__Click" - VerticalAlignment="Center" - HorizontalAlignment="Center" - Content="Accept"/> - <Button x:Name="_rejectIncomingCallBtn_" - Click="_rejectIncomingCallBtn__Click" - VerticalAlignment="Center" - HorizontalAlignment="Center" - Content="Reject"/> - </StackPanel> - </Grid>--> </Grid> </DataTemplate> <!-- template for accounts. --> @@ -303,40 +267,127 @@ x:DataType="controls:SmartPanelItem"> <Grid PointerEntered="Grid_PointerEntered" PointerExited="Grid_PointerExited"> <Grid.RowDefinitions> + <!-- row definition for the contact. --> <RowDefinition Height="auto"/> + <!-- row definition for the incoming call bar. --> + <RowDefinition Height="auto"/> + <!-- row definition for the outgoing call bar. --> <RowDefinition Height="auto"/> </Grid.RowDefinitions> - <ListBoxItem x:Name="_contactItem_" - Padding="0" - Margin="0" - Grid.Row="0" - PointerReleased="_contactItem__PointerReleased" - ContentTemplate="{StaticResource ContactTemplate}" - Content="{x:Bind _contact, Mode=OneWay}"/> - <ListBoxItem Grid.Row="1" - Visibility="{x:Bind _IncomingCallBar, Mode=OneWay}" - Padding="0" - Margin="0" - ContentTemplate="{StaticResource IncomingCallTemplate}" - Content="{x:Bind _call, Mode=OneWay}"/> - <Button Grid.Row="0" - HorizontalAlignment="Left" - Visibility="{x:Bind _callBar, Mode=OneWay}" - Content="call" - Padding="0" - Click="_callContact__Click" - VerticalAlignment="Bottom" - Margin="10"> - <Button.RenderTransform> - <TranslateTransform X="160"/> - </Button.RenderTransform> - </Button> - <ListBoxItem Grid.Row="1" - Visibility="{x:Bind _OutGoingCallBar, Mode=OneWay}" - Padding="0" - Margin="0" - ContentTemplate="{StaticResource OutGoingCallTemplate}" - Content="{x:Bind _call, Mode=OneWay}"/> + <!--helper to detect mouse overing--> + <Rectangle Fill="Transparent" Grid.Row="0"/> + <!-- contact. --> + <Grid Grid.Row="0"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="310"/> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition Height="60"/> + <!-- use the height of _contactBar_ to make it visible or collapsed. --> + <RowDefinition x:Name="_contactBar_" + Height="{x:Bind _contact._contactBarHeight, Mode=OneWay}"/> + </Grid.RowDefinitions> + <Grid Grid.Row="0"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="60"/> + <ColumnDefinition Width="*" + MinWidth="200"/> + </Grid.ColumnDefinitions> + <Image x:Name="_contactAvatar_" + VerticalAlignment="Center" + HorizontalAlignment="Center" + Grid.Column="0" + Width="55" + Height="55" + Source="Assets\TESTS\contactAvatar.png"/> + <!-- visual notifications. --> + <Border x:Name="_visualNotificationVideoChat_" + Visibility="Collapsed" + Style="{StaticResource BorderStyle1}"> + <TextBlock Text="" + Style="{StaticResource TextSegoeStyle1}"/> + <Border.RenderTransform> + <TranslateTransform X="17" Y="-14"/> + </Border.RenderTransform> + </Border> + <Border x:Name="_visualNotificationNewMessage_" + Visibility="{x:Bind _contact._unreadMessages, Converter={StaticResource _NewMessageBubleNotification_}, Mode=OneWay}" + Style="{StaticResource BorderStyle2}"> + <TextBlock Text="{x:Bind _contact._unreadMessages, Mode=OneWay}" + Style="{StaticResource TextStyle3}"/> + <Border.RenderTransform> + <TranslateTransform X="-17" Y="-14"/> + </Border.RenderTransform> + </Border> + + <Grid Grid.Column="1"> + <Grid.RowDefinitions> + <RowDefinition Height="30"/> + <RowDefinition Height="30"/> + </Grid.RowDefinitions> + <!-- name of the contact. --> + <TextBlock x:Name="_contactName_" + Grid.Row="0" + Text="{x:Bind _contact.name_}" + TextTrimming="CharacterEllipsis"> + </TextBlock> + <!-- call button. --> + <Button Grid.Row="0" + Visibility="{x:Bind _hovered, Mode=OneWay}" + Click="_callContact__Click" + VerticalAlignment="Bottom" + HorizontalAlignment="Left" + Margin="10,0" + Style="{StaticResource roundButtonTemplate}" + FontFamily="Segoe MDL2 Assets" + Content=""> + <Button.RenderTransform> + <TranslateTransform X="90" Y="25"/> + </Button.RenderTransform> + </Button> + </Grid> + </Grid> + </Grid> + <!-- incomming call bar. --> + <Grid Width="320" + Grid.Row="1" + HorizontalAlignment="Left" + Background="DarkGray"> + <Grid.RowDefinitions> + <RowDefinition Height="auto"/> + <RowDefinition Height="auto"/> + </Grid.RowDefinitions> + <TextBlock x:Name="_incommingCallStatus_" + Grid.Row="0" + Foreground="White" + Text="{x:Bind _call.state, Mode=OneWay}" + Visibility="{x:Bind _call.state, Converter={StaticResource _HasAnActiveCall_}, Mode=OneWay}" + HorizontalAlignment="Center"> + </TextBlock> + <StackPanel Orientation="Horizontal" + Visibility="Visible" + Grid.Row="1" + HorizontalAlignment="Center"> + <Button x:Name="_acceptIncomingCallBtn_" + Click="_acceptIncomingCallBtn__Click" + Visibility="{x:Bind _call.state, Converter={StaticResource _IncomingVisibility_}, Mode=OneWay}" + VerticalAlignment="Center" + HorizontalAlignment="Center" + Content="Accept"/> + <Button x:Name="_rejectIncomingCallBtn_" + Click="_rejectIncomingCallBtn__Click" + Visibility="{x:Bind _call.state, Converter={StaticResource _IncomingVisibility_}, Mode=OneWay}" + VerticalAlignment="Center" + HorizontalAlignment="Center" + Content="Reject"/> + <Button x:Name="_cancelCallBtn_" + Click="_cancelCallBtn__Click" + Visibility="{x:Bind _call.state, Converter={StaticResource _OutGoingVisibility_}, Mode=OneWay}" + VerticalAlignment="Center" + HorizontalAlignment="Center" + Content="Cancel"/> + </StackPanel> + </Grid> </Grid> </DataTemplate> </Page.Resources> @@ -409,7 +460,7 @@ </Grid> <!--sub menus like the accounts list or the share menu are just below, technicaly they are nested inside the - same row. To sumon them we use the visibility of their own grid, by linking it to a toggle button--> + same row. To summon them we use the visibility of their own grid, by linking it to a toggle button--> <!-- accounts menu. --> <Grid x:Name="_accountsMenuGrid_" diff --git a/SmartPanel.xaml.cpp b/SmartPanel.xaml.cpp index a61c161..8aec15d 100644 --- a/SmartPanel.xaml.cpp +++ b/SmartPanel.xaml.cpp @@ -77,8 +77,9 @@ SmartPanel::SmartPanel() auto item = SmartPanelItemsViewModel::instance->findItem(contact); item->_call = call; + }); - RingD::instance->stateChange += ref new StateChange([this](String^ callId, String^ state, int code) { + RingD::instance->stateChange += ref new StateChange([this](String^ callId, CallStatus state, int code) { auto call = CallsViewModel::instance->findCall(callId); if (call == nullptr) @@ -91,18 +92,11 @@ SmartPanel::SmartPanel() return; } - if (call->state == "incoming call") - item->_IncomingCallBar = Windows::UI::Xaml::Visibility::Visible; + call->state = state; - if (call->state == "CURRENT") { - item->_IncomingCallBar = Windows::UI::Xaml::Visibility::Collapsed; - item->_OutGoingCallBar = Windows::UI::Xaml::Visibility::Collapsed; - } + if (state == CallStatus::IN_PROGRESS) + _smartList_->SelectedIndex = SmartPanelItemsViewModel::instance->getIndex(call); - if (call->state == "") { - item->_IncomingCallBar = Windows::UI::Xaml::Visibility::Collapsed; - item->_OutGoingCallBar = Windows::UI::Xaml::Visibility::Collapsed; - } }); @@ -129,10 +123,8 @@ SmartPanel::SmartPanel() return; } - /* use underscore to differentiate states from UI, we need to think more about states management */ - call->state = "_calling_"; + call->state = CallStatus::SEARCHING; - item->_OutGoingCallBar = Windows::UI::Xaml::Visibility::Visible; item->_call = call; }); @@ -253,12 +245,31 @@ void RingClientUWP::Views::SmartPanel::_createAccountNo__Click(Platform::Object^ void SmartPanel::_smartList__SelectionChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e) { - auto listbox = safe_cast<ListBox^>(sender); - auto item = safe_cast<SmartPanelItem^>(listbox->SelectedItem); + auto listbox = dynamic_cast<ListBox^>(sender); + auto item = dynamic_cast<SmartPanelItem^>(listbox->SelectedItem); + SmartPanelItemsViewModel::instance->_selectedItem = item; + + if (!item) { + summonWelcomePage(); + return; + } - Contact^ contact = (item) ? safe_cast<Contact^>(item->_contact) : nullptr; + auto call = item->_call; + if (call) { + auto state = call->state; + if (state == CallStatus::IN_PROGRESS) { + summonVideoPage(); + return; + } + } - ContactsViewModel::instance->selectedContact = contact; + auto contact = item->_contact; + if (contact) { + summonMessageTextPage(); + contact->_unreadMessages = 0; + ContactsViewModel::instance->saveContactsToFile(); + return; + } } void @@ -303,7 +314,8 @@ void RingClientUWP::Views::SmartPanel::_ringTxtBx__Click(Platform::Object^ sende void RingClientUWP::Views::SmartPanel::_rejectIncomingCallBtn__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) { auto button = dynamic_cast<Button^>(e->OriginalSource); - auto call = dynamic_cast<Call^>(button->DataContext); + auto item = dynamic_cast<SmartPanelItem^>(button->DataContext); + auto call = item->_call; call->refuse(); } @@ -312,9 +324,8 @@ void RingClientUWP::Views::SmartPanel::_rejectIncomingCallBtn__Click(Platform::O void RingClientUWP::Views::SmartPanel::_acceptIncomingCallBtn__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) { auto button = dynamic_cast<Button^>(e->OriginalSource); - auto call = dynamic_cast<Call^>(button->DataContext); - - _smartList_->SelectedIndex = SmartPanelItemsViewModel::instance->getIndex(call); + auto item = dynamic_cast<SmartPanelItem^>(button->DataContext); + auto call = item->_call; call->accept(); } @@ -326,8 +337,6 @@ SmartPanel::_callContact__Click(Platform::Object^ sender, Windows::UI::Xaml::Rou auto item = dynamic_cast<SmartPanelItem^>(button->DataContext); auto contact = item->_contact; - _smartList_->SelectedIndex = SmartPanelItemsViewModel::instance->getIndex(contact); - RingD::instance->placeCall(contact); } @@ -335,7 +344,8 @@ SmartPanel::_callContact__Click(Platform::Object^ sender, Windows::UI::Xaml::Rou void RingClientUWP::Views::SmartPanel::_cancelCallBtn__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) { auto button = dynamic_cast<Button^>(e->OriginalSource); - auto call = dynamic_cast<Call^>(button->DataContext); + auto item = dynamic_cast<SmartPanelItem^>(button->DataContext); + auto call = item->_call; call->cancel(); } @@ -347,7 +357,7 @@ void RingClientUWP::Views::SmartPanel::Grid_PointerEntered(Platform::Object^ sen auto listBoxItem = dynamic_cast<ListBoxItem^>(sender); auto item = dynamic_cast<SmartPanelItem^>(grid->DataContext); - item->_callBar = Windows::UI::Xaml::Visibility::Visible; + item->_hovered = Windows::UI::Xaml::Visibility::Visible; } @@ -357,7 +367,7 @@ void RingClientUWP::Views::SmartPanel::Grid_PointerExited(Platform::Object^ send auto grid = dynamic_cast<Grid^>(sender); auto item = dynamic_cast<SmartPanelItem^>(grid->DataContext); - item->_callBar = Windows::UI::Xaml::Visibility::Collapsed; + item->_hovered = Windows::UI::Xaml::Visibility::Collapsed; } @@ -371,4 +381,77 @@ void RingClientUWP::Views::SmartPanel::_contactItem__PointerReleased(Platform::O else _smartList_->SelectedItem = nullptr; -} \ No newline at end of file +} + +Object ^ RingClientUWP::Views::IncomingVisibility::Convert(Object ^ value, Windows::UI::Xaml::Interop::TypeName targetType, Object ^ parameter, String ^ language) +{ + auto state = static_cast<CallStatus>(value); + if (state == CallStatus::INCOMING_RINGING) + return Windows::UI::Xaml::Visibility::Visible; + else + return Windows::UI::Xaml::Visibility::Collapsed; +} + +Object ^ RingClientUWP::Views::IncomingVisibility::ConvertBack(Object ^ value, Windows::UI::Xaml::Interop::TypeName targetType, Object ^ parameter, String ^ language) +{ + throw ref new Platform::NotImplementedException(); +} + +RingClientUWP::Views::IncomingVisibility::IncomingVisibility() +{} + + +Object ^ RingClientUWP::Views::OutGoingVisibility::Convert(Object ^ value, Windows::UI::Xaml::Interop::TypeName targetType, Object ^ parameter, String ^ language) +{ + auto state = static_cast<CallStatus>(value); + + if (state == CallStatus::SEARCHING || state == CallStatus::OUTGOING_RINGING) + return Windows::UI::Xaml::Visibility::Visible; + else + return Windows::UI::Xaml::Visibility::Collapsed; +} + +Object ^ RingClientUWP::Views::OutGoingVisibility::ConvertBack(Object ^ value, Windows::UI::Xaml::Interop::TypeName targetType, Object ^ parameter, String ^ language) +{ + throw ref new Platform::NotImplementedException(); +} + +RingClientUWP::Views::OutGoingVisibility::OutGoingVisibility() +{} + +Object ^ RingClientUWP::Views::HasAnActiveCall::Convert(Object ^ value, Windows::UI::Xaml::Interop::TypeName targetType, Object ^ parameter, String ^ language) +{ + auto state = static_cast<CallStatus>(value); + + if (state == CallStatus::NONE || state == CallStatus::ENDED) + return Windows::UI::Xaml::Visibility::Collapsed; + else + return Windows::UI::Xaml::Visibility::Visible; +} + +Object ^ RingClientUWP::Views::HasAnActiveCall::ConvertBack(Object ^ value, Windows::UI::Xaml::Interop::TypeName targetType, Object ^ parameter, String ^ language) +{ + throw ref new Platform::NotImplementedException(); + +} + +RingClientUWP::Views::HasAnActiveCall::HasAnActiveCall() +{} + +Object ^ RingClientUWP::Views::NewMessageBubleNotification::Convert(Object ^ value, Windows::UI::Xaml::Interop::TypeName targetType, Object ^ parameter, String ^ language) +{ + auto unreadMessages = static_cast<uint32>(value); + + if (unreadMessages > 0) + return Windows::UI::Xaml::Visibility::Visible; + + return Windows::UI::Xaml::Visibility::Collapsed; +} + +Object ^ RingClientUWP::Views::NewMessageBubleNotification::ConvertBack(Object ^ value, Windows::UI::Xaml::Interop::TypeName targetType, Object ^ parameter, String ^ language) +{ + throw ref new Platform::NotImplementedException(); +} + +RingClientUWP::Views::NewMessageBubleNotification::NewMessageBubleNotification() +{} diff --git a/SmartPanel.xaml.h b/SmartPanel.xaml.h index 58c9f05..c017617 100644 --- a/SmartPanel.xaml.h +++ b/SmartPanel.xaml.h @@ -22,11 +22,41 @@ namespace RingClientUWP { delegate void ToggleSmartPan(); -delegate void SumonMessageTextPage(); -delegate void SumonVideoPage(); +delegate void SummonMessageTextPage(); +delegate void SummonVideoPage(); +delegate void SummonWelcomePage(); namespace Views { + +public ref class IncomingVisibility sealed : IValueConverter { +public: + virtual Object^ Convert(Object^ value, Windows::UI::Xaml::Interop::TypeName targetType, Object^ parameter, String^ language); + virtual Object^ ConvertBack(Object^ value, Windows::UI::Xaml::Interop::TypeName targetType, Object^ parameter, String^ language); + IncomingVisibility(); +}; + +public ref class OutGoingVisibility sealed : IValueConverter { +public: + virtual Object^ Convert(Object^ value, Windows::UI::Xaml::Interop::TypeName targetType, Object^ parameter, String^ language); + virtual Object^ ConvertBack(Object^ value, Windows::UI::Xaml::Interop::TypeName targetType, Object^ parameter, String^ language); + OutGoingVisibility(); +}; + +public ref class HasAnActiveCall sealed : IValueConverter { +public: + virtual Object^ Convert(Object^ value, Windows::UI::Xaml::Interop::TypeName targetType, Object^ parameter, String^ language); + virtual Object^ ConvertBack(Object^ value, Windows::UI::Xaml::Interop::TypeName targetType, Object^ parameter, String^ language); + HasAnActiveCall(); +}; + +public ref class NewMessageBubleNotification sealed : IValueConverter { +public: + virtual Object^ Convert(Object^ value, Windows::UI::Xaml::Interop::TypeName targetType, Object^ parameter, String^ language); + virtual Object^ ConvertBack(Object^ value, Windows::UI::Xaml::Interop::TypeName targetType, Object^ parameter, String^ language); + NewMessageBubleNotification(); +}; + public ref class SmartPanel sealed { public: @@ -36,8 +66,9 @@ public: internal: enum class Mode { Minimized, Normal }; event ToggleSmartPan^ toggleSmartPan; - event SumonMessageTextPage^ sumonMessageTextPage; - event SumonVideoPage^ sumonVideoPage; + event SummonMessageTextPage^ summonMessageTextPage; + event SummonVideoPage^ summonVideoPage; + event SummonWelcomePage^ summonWelcomePage; void setMode(RingClientUWP::Views::SmartPanel::Mode mode); private: diff --git a/SmartPanelItem.cpp b/SmartPanelItem.cpp index ab986a6..d93b454 100644 --- a/SmartPanelItem.cpp +++ b/SmartPanelItem.cpp @@ -30,7 +30,10 @@ using namespace RingClientUWP::Controls; using namespace ViewModel; SmartPanelItem::SmartPanelItem() -{} +{ + /* create an empty call to avoid the call bar */ + _call = ref new Call("", "", ""); +} void SmartPanelItem::NotifyPropertyChanged(String^ propertyName) diff --git a/SmartPanelItem.h b/SmartPanelItem.h index aa5484b..0803fb1 100644 --- a/SmartPanelItem.h +++ b/SmartPanelItem.h @@ -32,52 +32,28 @@ public: virtual event PropertyChangedEventHandler^ PropertyChanged; property Contact^ _contact; - property Visibility _IncomingCallBar - { - Visibility get() - { - return incomingCallBar_; - } - void set(Visibility value) - { - incomingCallBar_ = value; - PropertyChanged(this, ref new PropertyChangedEventArgs("_IncomingCallBar")); - } - } - property Visibility _OutGoingCallBar + property Call^ _call { - Visibility get() + Call^ get() { - return outGoingCallBar_; + return call_; } - void set(Visibility value) + void set(Call^ value) { - outGoingCallBar_ = value; - PropertyChanged(this, ref new PropertyChangedEventArgs("_OutGoingCallBar")); + call_ = value; + PropertyChanged(this, ref new PropertyChangedEventArgs("_call")); } } - property Visibility _callBar + property Visibility _hovered { Visibility get() { - return callBar_; + return hovered_; } void set(Visibility value) { - callBar_ = value; - PropertyChanged(this, ref new PropertyChangedEventArgs("_callBar")); - } - } - property Call^ _call - { - Call^ get() - { - return call_; - } - void set(Call^ value) - { - call_ = value; - PropertyChanged(this, ref new PropertyChangedEventArgs("_call")); + hovered_ = value; + PropertyChanged(this, ref new PropertyChangedEventArgs("_hovered")); } } @@ -85,10 +61,9 @@ protected: void NotifyPropertyChanged(String^ propertyName); private: - Visibility incomingCallBar_ = Visibility::Collapsed; - Visibility outGoingCallBar_ = Visibility::Collapsed; - Visibility callBar_ = Visibility::Collapsed; Call^ call_; + Visibility hovered_ = Visibility::Collapsed; + }; } } diff --git a/SmartPanelItemsViewModel.h b/SmartPanelItemsViewModel.h index 52e1c86..7bcdfe7 100644 --- a/SmartPanelItemsViewModel.h +++ b/SmartPanelItemsViewModel.h @@ -26,7 +26,6 @@ using namespace RingClientUWP::Controls; namespace RingClientUWP { - namespace ViewModel { public ref class SmartPanelItemsViewModel sealed { @@ -55,7 +54,18 @@ internal: } } - /* events */ + property SmartPanelItem^ _selectedItem + { + SmartPanelItem^ get() + { + return currentItem_; + } + void set(SmartPanelItem^ value) + { + oldItem_ = currentItem_; + currentItem_ = value; + } + } private: SmartPanelItemsViewModel(); // singleton diff --git a/Styles.xaml b/Styles.xaml index d010259..3f5854a 100644 --- a/Styles.xaml +++ b/Styles.xaml @@ -290,5 +290,20 @@ </Setter.Value> </Setter> </Style> + <!-- rounded button for call --> + <Style x:Key ="roundButtonTemplate" TargetType ="Button"> + <Setter Property ="Foreground" Value ="Black"/> + <Setter Property ="FontWeight" Value ="Bold"/> + <Setter Property ="Template"> + <Setter.Value> + <ControlTemplate TargetType ="Button"> + <Grid> + <Ellipse Name ="OuterRing" Width ="30" Height ="30" Fill ="LightBlue"/> + <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White"/> + </Grid> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> </ResourceDictionary> diff --git a/VideoPage.xaml.cpp b/VideoPage.xaml.cpp index 70eed4a..112741c 100644 --- a/VideoPage.xaml.cpp +++ b/VideoPage.xaml.cpp @@ -21,6 +21,7 @@ #include "VideoPage.xaml.h" using namespace RingClientUWP::Views; +using namespace ViewModel; using namespace Concurrency; using namespace Platform; @@ -56,10 +57,9 @@ RingClientUWP::Views::VideoPage::OnNavigatedTo(Windows::UI::Xaml::Navigation::Na void RingClientUWP::Views::VideoPage::updatePageContent() { - auto selectedContact = ViewModel::ContactsViewModel::instance->selectedContact; - Contact^ contact = selectedContact? - ViewModel::SmartPanelItemsViewModel::instance->findItem(selectedContact)->_contact: - nullptr; + auto item = SmartPanelItemsViewModel::instance->_selectedItem; + auto contact = (item) ? item->_contact : nullptr; + if (!contact) return; @@ -93,7 +93,9 @@ RingClientUWP::Views::VideoPage::_messageTextBox__KeyDown(Platform::Object^ send void RingClientUWP::Views::VideoPage::sendMessage() { - auto contact = ViewModel::ContactsViewModel::instance->selectedContact; + auto item = SmartPanelItemsViewModel::instance->_selectedItem; + auto contact = item->_contact; + auto txt = _messageTextBox_->Text; /* empty the textbox */ @@ -118,10 +120,9 @@ void RingClientUWP::Views::VideoPage::_btnCancel__Click(Platform::Object^ sender void RingClientUWP::Views::VideoPage::_btnHangUp__Tapped(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e) { - Contact^ selectedContact = ViewModel::ContactsViewModel::instance->selectedContact; - Call^ call = selectedContact? - ViewModel::SmartPanelItemsViewModel::instance->findItem(selectedContact)->_call: - nullptr; + auto item = SmartPanelItemsViewModel::instance->_selectedItem; + auto call = item->_call; + if (call) RingD::instance->hangUpCall(call); pressHangUpCall(); -- GitLab