Tutorial for LinphoneSDK x UWP - C#

This commit is contained in:
Anthony Gauchy
2020-12-10 17:20:19 +01:00
parent 50483699b5
commit 29f4bbef5c
215 changed files with 13724 additions and 0 deletions

View File

@@ -0,0 +1,245 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProjectGuid>{C0C99544-E7DE-4CF5-87B9-52677828EC24}</ProjectGuid>
<OutputType>AppContainerExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>_07_AdvancedChat</RootNamespace>
<AssemblyName>07_AdvancedChat</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.19041.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WindowsXamlEnableOverview>true</WindowsXamlEnableOverview>
<AppxPackageSigningEnabled>false</AppxPackageSigningEnabled>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\ARM\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
<OutputPath>bin\ARM\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\ARM64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>ARM64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM64'">
<OutputPath>bin\ARM64\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>ARM64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<ItemGroup>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\ContentDisplay.xaml.cs">
<DependentUpon>ContentDisplay.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\GroupChatDisplay.xaml.cs">
<DependentUpon>GroupChatDisplay.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\EventDisplay.xaml.cs">
<DependentUpon>EventDisplay.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\MessageDisplay.xaml.cs">
<DependentUpon>MessageDisplay.xaml</DependentUpon>
</Compile>
<Compile Include="Service\NavigationService.cs" />
<Compile Include="Service\VideoService.cs" />
<Compile Include="Shared\ChatRoomToStringConverter.cs" />
<Compile Include="Shared\Utils.cs" />
<Compile Include="Views\CallsPage.xaml.cs">
<DependentUpon>CallsPage.xaml</DependentUpon>
</Compile>
<Compile Include="Service\CoreService.cs" />
<Compile Include="Views\ChatPage.xaml.cs">
<DependentUpon>ChatPage.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ChatsPage.xaml.cs">
<DependentUpon>ChatsPage.xaml</DependentUpon>
</Compile>
<Compile Include="Views\CreateGroupChatRoom.xaml.cs">
<DependentUpon>CreateGroupChatRoom.xaml</DependentUpon>
</Compile>
<Compile Include="Views\LoginPage.xaml.cs">
<DependentUpon>LoginPage.xaml</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Views\NavigationRoot.xaml.cs">
<DependentUpon>NavigationRoot.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
</ItemGroup>
<ItemGroup>
<Content Include="Properties\Default.rd.xml" />
<Content Include="Assets\LockScreenLogo.scale-200.png" />
<Content Include="Assets\SplashScreen.scale-200.png" />
<Content Include="Assets\Square150x150Logo.scale-200.png" />
<Content Include="Assets\Square44x44Logo.scale-200.png" />
<Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
<Content Include="Assets\StoreLogo.png" />
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Page Include="Controls\ContentDisplay.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Controls\GroupChatDisplay.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Controls\EventDisplay.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Controls\MessageDisplay.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\ChatPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\ChatsPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\CreateGroupChatRoom.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\LoginPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\CallsPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\NavigationRoot.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<PackageReference Include="ANGLE.WindowsStore">
<Version>2.1.13</Version>
</PackageReference>
<PackageReference Include="LinphoneSDK">
<Version>5.1.0-alpha.56</Version>
</PackageReference>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.2.11</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<None Include="Readme.md" />
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,4 @@
<Application
x:Class="_07_AdvancedChat.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" />

View File

@@ -0,0 +1,129 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of Linphone TutorialCS.
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using _07_AdvancedChat.Service;
using _07_AdvancedChat.Views;
using Linphone;
using System;
using System.Diagnostics;
using System.Text;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace _07_AdvancedChat
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
sealed partial class App : Application
{
private CoreService CoreService { get; } = CoreService.Instance;
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used such as when the application is launched to open a specific file.
/// </summary>
/// <param name="e">Details about the launch request and process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
// Start Linphone
LoggingService.Instance.LogLevel = LogLevel.Debug;
LoggingService.Instance.Listener.OnLogMessageWritten = OnLog;
CoreService.CoreStart(Windows.ApplicationModel.Core.CoreApplication.GetCurrentView().CoreWindow.Dispatcher);
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
if (e.PrelaunchActivated == false)
{
if (rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
rootFrame.Navigate(typeof(LoginPage), e.Arguments);
}
// Ensure the current window is active
Window.Current.Activate();
}
}
private void OnLog(LoggingService logService, string domain, LogLevel lev, string message)
{
StringBuilder builder = new StringBuilder();
_ = builder.Append("Linphone-[").Append(lev.ToString()).Append("](").Append(domain).Append(")").Append(message);
Debug.WriteLine(builder.ToString());
}
/// <summary>
/// Invoked when Navigation to a certain page fails
/// </summary>
/// <param name="sender">The Frame which failed navigation</param>
/// <param name="e">Details about the navigation failure</param>
private void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
{
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
}
/// <summary>
/// Invoked when application execution is being suspended. Application state is saved
/// without knowing whether the application will be terminated or resumed with the contents
/// of memory still intact.
/// </summary>
/// <param name="sender">The source of the suspend request.</param>
/// <param name="e">Details about the suspend request.</param>
private void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
//TODO: Save application state and stop any background activity
deferral.Complete();
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1,20 @@
<UserControl
x:Class="_07_AdvancedChat.Controls.ContentDisplay"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<StackPanel x:Name="TextStack" Orientation="Vertical" Visibility="Collapsed" Margin="0,0,0,10">
<TextBlock Text="Text :" />
<TextBlock x:Name="TextMessage" Text="" FontWeight="Bold" TextWrapping="Wrap" />
</StackPanel>
<StackPanel x:Name="FileStack" Orientation="Vertical" Visibility="Collapsed" Margin="0,0,0,10">
<TextBlock Text="File : " />
<TextBlock x:Name="FileName" Text="" FontWeight="Bold" />
<TextBlock x:Name="FileSize" Text="" />
<Button x:Name="Download" Content="Download" Click="Download_Click" Visibility="Collapsed" />
<Button x:Name="OpenFile" Content="Open file" Click="OpenFile_Click" Visibility="Collapsed" />
</StackPanel>
</Grid>
</UserControl>

View File

@@ -0,0 +1,92 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of Linphone TutorialCS.
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Linphone;
using System;
using System.IO;
using Windows.Storage;
using Windows.System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace _07_AdvancedChat.Controls
{
public sealed partial class ContentDisplay : UserControl
{
private readonly ChatMessage ChatMessage;
private readonly Content DisplayedContent;
public ContentDisplay(Content content, ChatMessage chatMessage)
{
this.InitializeComponent();
DisplayedContent = content;
ChatMessage = chatMessage;
UpdateLayoutFromContent();
}
private void UpdateLayoutFromContent()
{
if (DisplayedContent.IsFile || DisplayedContent.IsFileTransfer)
{
TextStack.Visibility = Visibility.Collapsed;
FileStack.Visibility = Visibility.Visible;
FileName.Text = DisplayedContent.Name;
FileSize.Text = DisplayedContent.FileSize + " bits";
if (DisplayedContent.IsFile || DisplayedContent.IsFileTransfer && ChatMessage.IsOutgoing)
{
OpenFile.Visibility = Visibility.Visible;
Download.Visibility = Visibility.Collapsed;
}
else
{
Download.Visibility = Visibility.Visible;
OpenFile.Visibility = Visibility.Collapsed;
}
}
else if (DisplayedContent.IsText)
{
TextStack.Visibility = Visibility.Visible;
FileStack.Visibility = Visibility.Collapsed;
TextMessage.Text = DisplayedContent.Utf8Text;
}
}
private void Download_Click(object sender, RoutedEventArgs e)
{
Download.Visibility = Visibility.Collapsed;
FileSize.Text = "Download in progress ...";
string downloadPathFolder = ApplicationData.Current.LocalFolder.Path + @"\Downloads\";
Directory.CreateDirectory(downloadPathFolder);
DisplayedContent.FilePath = downloadPathFolder + DisplayedContent.Name;
ChatMessage.DownloadContent(DisplayedContent);
}
private async void OpenFile_Click(object sender, RoutedEventArgs e)
{
string filePath = DisplayedContent.FilePath;
string folderPath = filePath.Substring(0, filePath.LastIndexOf("\\"));
await Launcher.LaunchFolderAsync(await StorageFolder.GetFolderFromPathAsync(folderPath));
}
}
}

View File

@@ -0,0 +1,11 @@
<UserControl
x:Class="_07_AdvancedChat.Controls.EventDisplay"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="10">
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE949;" />
<TextBlock x:Name="EventText" Text="" Margin="10" />
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE949;" />
</StackPanel>
</UserControl>

View File

@@ -0,0 +1,83 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of Linphone TutorialCS.
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Linphone;
using Windows.UI.Xaml.Controls;
namespace _07_AdvancedChat.Controls
{
public sealed partial class EventDisplay : UserControl
{
public EventDisplay(EventLog eventLog)
{
this.InitializeComponent();
switch (eventLog.Type)
{
case EventLogType.ConferenceCreated:
EventText.Text = $"The conference {eventLog.Subject} is created";
break;
case EventLogType.ConferenceTerminated:
EventText.Text = $"The conference {eventLog.Subject} is terminated";
break;
case EventLogType.ConferenceCallStart:
EventText.Text = "Call start";
break;
case EventLogType.ConferenceCallEnd:
EventText.Text = "Call end";
break;
case EventLogType.ConferenceParticipantAdded:
EventText.Text = $"{eventLog.ParticipantAddress.Username} is added";
break;
case EventLogType.ConferenceParticipantRemoved:
EventText.Text = $"{eventLog.ParticipantAddress.Username} is removed";
break;
case EventLogType.ConferenceParticipantSetAdmin:
EventText.Text = $"{eventLog.ParticipantAddress.Username} is now admin";
break;
case EventLogType.ConferenceParticipantUnsetAdmin:
EventText.Text = $"{eventLog.ParticipantAddress.Username} admin status removed";
break;
case EventLogType.ConferenceSubjectChanged:
EventText.Text = $"The conference subject is now {eventLog.Subject}";
break;
// With the ephemeral mode handling new event types can appear.
case EventLogType.ConferenceEphemeralMessageDisabled:
EventText.Text = "Ephemeral message mode is disabled";
break;
case EventLogType.ConferenceEphemeralMessageEnabled:
EventText.Text = "Ephemeral message mode is enabled";
break;
case EventLogType.ConferenceEphemeralMessageLifetimeChanged:
EventText.Text = $"Ephemeral message lifetime is now {eventLog.EphemeralMessageLifetime}";
break;
}
}
}
}

View File

@@ -0,0 +1,52 @@
<UserControl
x:Class="_07_AdvancedChat.Controls.GroupChatDisplay"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:linphone="using:Linphone"
Loaded="GroupChatDisplay_Loaded"
Unloaded="GroupChatDisplay_Unloaded">
<Grid x:Name="GroupChatDisplayGrid">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row="0">
<TextBlock>Participants :</TextBlock>
<Button x:Name="AddParticipant" Click="AddParticipant_Click" FontFamily="Segoe MDL2 Assets" Content="&#xE8FA;" />
</StackPanel>
<ListView x:Name="ParticipantsLV" SelectionMode="None" IsItemClickEnabled="False" Grid.Row="1">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate x:DataType="linphone:Participant">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.8*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=Address.Username}" Grid.Row="0" Grid.Column="0" />
<Button Tag="{Binding}" Click="Remove_Click" FontFamily="Segoe MDL2 Assets" Content="&#xE8F8;" Grid.Column="1" Grid.Row="0" />
<StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal">
<TextBlock Text="Is admin : " />
<TextBlock Text="{Binding Path=IsAdmin}" Margin="1,0,0,0" />
</StackPanel>
<Button Tag="{Binding}" Click="AdminSwitch_Click" FontFamily="Segoe MDL2 Assets" Content="&#xE8CB;" Grid.Column="1" Grid.Row="1" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button x:Name="RenameGroupChat" Click="RenameGroupChat_Click" Content="Rename group chat" VerticalAlignment="Bottom" Grid.Row="2" />
</Grid>
</UserControl>

View File

@@ -0,0 +1,126 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of Linphone TutorialCS.
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using _07_AdvancedChat.Service;
using _07_AdvancedChat.Shared;
using Linphone;
using System;
using System.Linq;
using Windows.UI.Xaml.Controls;
namespace _07_AdvancedChat.Controls
{
public sealed partial class GroupChatDisplay : UserControl
{
private CoreService CoreService { get; } = CoreService.Instance;
private readonly ChatRoom ChatRoom;
public GroupChatDisplay(ChatRoom chatRoom)
{
this.InitializeComponent();
ChatRoom = chatRoom;
}
private void GroupChatDisplay_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
UpdateList();
UpdateGuiFromAdminState();
ChatRoom.Listener.OnParticipantAdded += OnParticipantListUpdate;
ChatRoom.Listener.OnParticipantRemoved += OnParticipantListUpdate;
ChatRoom.Listener.OnParticipantAdminStatusChanged += OnParticipantAdminStatusChanged;
}
private void GroupChatDisplay_Unloaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
ChatRoom.Listener.OnParticipantAdded -= OnParticipantListUpdate;
ChatRoom.Listener.OnParticipantRemoved -= OnParticipantListUpdate;
ChatRoom.Listener.OnParticipantAdminStatusChanged -= OnParticipantAdminStatusChanged;
}
private void OnParticipantAdminStatusChanged(ChatRoom chatRoom, EventLog eventLog)
{
UpdateList();
UpdateGuiFromAdminState();
}
private void UpdateGuiFromAdminState()
{
AddParticipant.IsEnabled = ChatRoom.Me.IsAdmin;
foreach (var control in GroupChatDisplayGrid.Children.OfType<Control>())
{
control.IsEnabled = ChatRoom.Me.IsAdmin;
}
}
private void OnParticipantListUpdate(ChatRoom chatRoom, EventLog eventLog) => UpdateList();
private void UpdateList()
{
ParticipantsLV.Items.Clear();
foreach (Participant participant in ChatRoom.Participants)
{
if (participant.Address != null && !String.IsNullOrWhiteSpace(participant.Address.Username))
{
ParticipantsLV.Items.Add(participant);
}
}
}
private void Remove_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
Participant participantToRemove = (Participant)((Button)sender).Tag;
ChatRoom.RemoveParticipant(participantToRemove);
}
private async void AddParticipant_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
string peerSipAddress = await Utils.InputTextDialogAsync("Enter peer sip address");
Address address = CoreService.Core.InterpretUrl(peerSipAddress);
if (address != null)
{
ChatRoom.AddParticipant(address);
}
else
{
ContentDialog badAddressDialog = new ContentDialog
{
Title = "Adding participant failed",
Content = "An error occurred during address interpretation, check sip address validity and try again.",
CloseButtonText = "OK"
};
await badAddressDialog.ShowAsync();
}
}
private void AdminSwitch_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
Participant participantToUpgrade = (Participant)((Button)sender).Tag;
ChatRoom.SetParticipantAdminStatus(participantToUpgrade, !participantToUpgrade.IsAdmin);
}
private async void RenameGroupChat_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
string newName = await Utils.InputTextDialogAsync("Enter new name for group");
ChatRoom.Subject = newName;
}
}
}

View File

@@ -0,0 +1,29 @@
<UserControl
x:Class="_07_AdvancedChat.Controls.MessageDisplay"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Loaded="MessageDisplay_Loaded"
Unloaded="MessageDisplay_Unloaded">
<Border BorderBrush="{ThemeResource SystemAccentColorDark3}" BorderThickness="1" Padding="2" CornerRadius="20,20,20,20">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition MaxWidth="500" />
</Grid.ColumnDefinitions>
<TextBlock x:Name="ReceiveDate" Grid.Column="0" Text="" VerticalAlignment="Center" />
<StackPanel Orientation="Vertical" Grid.Column="1" Padding="10">
<TextBlock x:Name="SenderName" Text="Sent by : " />
<StackPanel x:Name="ContentsStack" Orientation="Vertical">
</StackPanel>
<TextBlock x:Name="MessageState" />
<TextBlock x:Name="EphemeralLifetime" />
</StackPanel>
</Grid>
</Border>
</UserControl>

View File

@@ -0,0 +1,156 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of Linphone TutorialCS.
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Linphone;
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace _07_AdvancedChat.Controls
{
public sealed partial class MessageDisplay : UserControl
{
private readonly ChatMessage ChatMessage;
private readonly DispatcherTimer Timer;
private int Basetime;
public MessageDisplay(ChatMessage message)
{
this.InitializeComponent();
ChatMessage = message;
UpdateLayoutFromMessage();
UpdateLayoutFromContents();
// Used to create a second by second count down.
Timer = new DispatcherTimer
{
Interval = new TimeSpan(0, 0, 1)
};
Timer.Tick += Timer_Tick;
}
private void MessageDisplay_Loaded(object sender, RoutedEventArgs e)
{
ChatMessage.Listener.OnMsgStateChanged += OnMessageStateChanged;
// The countdown for ephemeral lifetime start only when the message status is "Displayed".
// So we register to this callback to be notified when to start the countdown.
// See OnEphemeralMessageTimerStarted to see how we setup the countdown.
ChatMessage.Listener.OnEphemeralMessageTimerStarted += OnEphemeralMessageTimerStarted;
// Even if we setup a client side countdown we will be notified by the OnEphemeralMessageDeleted
// callback when we should destroy the message.
ChatMessage.Listener.OnEphemeralMessageDeleted += OnEphemeralMessageDeleted;
}
private void MessageDisplay_Unloaded(object sender, RoutedEventArgs e)
{
ChatMessage.Listener = null;
}
private void OnMessageStateChanged(ChatMessage message, ChatMessageState state)
{
MessageState.Text = "The message state is : " + state;
switch (state)
{
case ChatMessageState.FileTransferError:
case ChatMessageState.FileTransferDone:
UpdateLayoutFromContents();
return;
}
}
private void UpdateLayoutFromMessage()
{
MessageState.Text = "The message state is : " + ChatMessage.State;
ReceiveDate.Text = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(ChatMessage.Time).ToLocalTime().ToString("HH:mm");
SenderName.Text += ChatMessage.FromAddress.Username;
if (ChatMessage.IsOutgoing)
{
this.HorizontalAlignment = HorizontalAlignment.Right;
}
else
{
this.HorizontalAlignment = HorizontalAlignment.Left;
}
}
private void UpdateLayoutFromContents()
{
ContentsStack.Children.Clear();
foreach (Content content in ChatMessage.Contents)
{
AddContent(content);
}
}
private void AddContent(Content content)
{
if (content.IsMultipart)
{
foreach (Content innerContent in content.Parts)
{
AddContent(innerContent);
}
return;
}
ContentDisplay contentDisplay = new ContentDisplay(content, ChatMessage);
ContentsStack.Children.Add(contentDisplay);
}
private void OnEphemeralMessageTimerStarted(ChatMessage message)
{
// Here we create a basic timer with the windows UI library, you can
// just note that we can found the ephemeral lifetime of this message
// as a read only attribute (ChatMessage.EphemeralLifetime).
Basetime = ChatMessage.EphemeralLifetime;
EphemeralLifetime.Text = $"{Basetime.ToString()} remaining before deletion";
// See Timer_Tick
Timer.Start();
}
private void OnEphemeralMessageDeleted(ChatMessage message)
{
// When this callback is triggered we erase the message from the view.
// Be careful, if you communicate with different clients some can choose
// to keep the message displayed even if it was an ephemeral one !
this.Content = new TextBlock
{
Text = "deleted ephemeral message"
};
}
private void Timer_Tick(object sender, object e)
{
// Every second we update the text under the ephemeral message
Basetime -= 1;
EphemeralLifetime.Text = $"{Basetime} remaining before deletion";
if (Basetime == 0)
{
Timer.Stop();
}
}
}
}

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:uap7="http://schemas.microsoft.com/appx/manifest/uap/windows10/7"
xmlns:uap8="http://schemas.microsoft.com/appx/manifest/uap/windows10/8"
IgnorableNamespaces="uap mp uap7 uap8">
<Identity
Name="754c9d43-0820-475a-b433-8a1be86b241c"
Publisher="CN=Anthony"
Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="754c9d43-0820-475a-b433-8a1be86b241c" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Properties>
<DisplayName>07_AdvancedChat</DisplayName>
<PublisherDisplayName>Anthony</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="_07_AdvancedChat.App">
<uap:VisualElements
DisplayName="07_AdvancedChat"
Square150x150Logo="Assets\Square150x150Logo.png"
Square44x44Logo="Assets\Square44x44Logo.png"
Description="07_AdvancedChat"
BackgroundColor="transparent">
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png"/>
<uap:SplashScreen Image="Assets\SplashScreen.png" />
</uap:VisualElements>
<uap7:Properties>
<uap8:ActiveCodePage>UTF-8</uap8:ActiveCodePage>
</uap7:Properties>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient" />
<uap:Capability Name="voipCall"/>
<Capability Name="codeGeneration"/>
<uap:Capability Name="picturesLibrary"/>
<uap:Capability Name="removableStorage"/>
<DeviceCapability Name="microphone"/>
<DeviceCapability Name="webcam"/>
</Capabilities>
</Package>

View File

@@ -0,0 +1,28 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("07_AdvancedChat")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("07_AdvancedChat")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: ComVisible(false)]

View File

@@ -0,0 +1,28 @@
<!--
This file contains Runtime Directives used by .NET Native. The defaults here are suitable for most
developers. However, you can modify these parameters to modify the behavior of the .NET Native
optimizer.
Runtime Directives are documented at https://go.microsoft.com/fwlink/?LinkID=391919
To fully enable reflection for App1.MyClass and all of its public/private members
<Type Name="App1.MyClass" Dynamic="Required All" />
To enable dynamic creation of the specific instantiation of AppClass<T> over System.Int32
<TypeInstantiation Name="App1.AppClass" Arguments="System.Int32" Activate="Required Public" />
Using the Namespace directive to apply reflection policy to all the types in a particular namespace
<Namespace Name="DataClasses.ViewModels" Serialize="All" />
-->
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Application>
<!--
An Assembly element with Name="*Application*" applies to all assemblies in
the application package. The asterisks are not wildcards.
-->
<Assembly Name="*Application*" Dynamic="Required All" />
<!-- Add your application specific runtime directives here. -->
</Application>
</Directives>

View File

@@ -0,0 +1,53 @@
Linphone X UWP tutorial 07_AdvancedChat
========================================
You reached the last step of this tutorial ! Well done ! In this step we will show you
how to create group chat, enable encryption and send ephemeral messages.
Linphone provide end-to-end encryption to your Flexisip chat with LIME. We will learn
in this step how to enable and use LIME to secure our ChatRoom. If you want more
informations about LIME take a look to [this page](https://linphone.org/technical-corner/lime).
To test a secure chat room try to create a group chat room and tick the check box
"I want a secure chat room". Most of the new and documented code can be found in
CoreService.cs.
One-to-one encryption is similar to group chat encryption as it uses LIME. To learn
how to create a one-to-one encrypted chat room also see CoreService.cs. You can also try to create one
yourself using the new "Create a new secure ChatRoom" on top of the ChatsPage.
Ephemeral messages are meant to disappear after a certain amount of time. You can enable the ephemeral
mode directly on a ChatRoom object, see ChatPage.xaml.cs to learn how to enable/disable it. And finally
watch the new code in MessageDisplay.xaml(.cs) to see how to handle ephemeral messages.
Don't forget to install those NuGet packages :
- LinphoneSDK (can be found here : https://www.linphone.org/snapshots/windows/sdk/)
- Microsoft.NETCore.UniversalWindowsPlatform (version 6.2.12 recommended)
- ANGLE.WindowsStore (for video rendering, version 2.1.13 recommended)
New/updated files :
```
07_AdvancedChat
└───Controls :
│ │
│ │ MessageDisplay.xaml(.cs) : A user control to display chat bubbles from message event.
│ │ Ephemeral messages handling is added here in this step !
└───Service :
│ │ CoreService.cs : A singleton service which contains the Linphone.Core.
│ │ Updated to allow creation of encrypted group chat room.
│ │
└───Shared :
│ │ ChatRoomToStringConverter.cs : a class that implement IValueConverter to display the
│ │ the chat room name according to its type. Now we display a SECURE tag
│ │ for secure chat room
│ │
└───Views :
│ │
│ │ ChatPage.xaml(.cs) : This is the frame displayed when you select a chat room.
│ │ You can now enable/disable ephemeral mode here.
│ │
│ │ ChatsPage.xaml(.cs) : ChatRoom list with a new "Create a new secure ChatRoom" button.
│ │
```

View File

@@ -0,0 +1,339 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of Linphone TutorialCS.
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Linphone;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Windows.Media.Audio;
using Windows.Media.Capture;
using Windows.Storage;
using Windows.UI.Core;
using static Linphone.CoreListener;
namespace _07_AdvancedChat.Service
{
internal class CoreService
{
private Timer Timer;
private static readonly CoreService instance = new CoreService();
public static CoreService Instance
{
get
{
return instance;
}
}
private Core core;
public Core Core
{
get
{
if (core == null)
{
Factory factory = Factory.Instance;
string assetsPath = Path.Combine(Windows.ApplicationModel.Package.Current.InstalledLocation.Path, "share");
factory.TopResourcesDir = assetsPath;
factory.DataResourcesDir = assetsPath;
factory.SoundResourcesDir = Path.Combine(assetsPath, "sounds", "linphone");
factory.RingResourcesDir = Path.Combine(factory.SoundResourcesDir, "rings");
factory.ImageResourcesDir = Path.Combine(assetsPath, "images");
factory.MspluginsDir = ".";
core = factory.CreateCore(Path.Combine(ApplicationData.Current.LocalFolder.Path, "configuration"), "", IntPtr.Zero);
core.AudioPort = 7666;
core.VideoPort = 9666;
// You only need to give your LIME server URL
core.LimeX3DhServerUrl = "https://lime.linphone.org/lime-server/lime-server.php";
// and enable LIME on your core to use encryption.
core.LimeX3DhEnabled = true;
// Now see the CoreService.CreateGroupChatRoom to see how to create a secure chat room
core.RootCa = Path.Combine(Windows.ApplicationModel.Package.Current.InstalledLocation.Path, "share", "Linphone", "rootca.pem");
core.UserCertificatesPath = ApplicationData.Current.LocalFolder.Path;
VideoActivationPolicy videoActivationPolicy = factory.CreateVideoActivationPolicy();
videoActivationPolicy.AutomaticallyAccept = true;
videoActivationPolicy.AutomaticallyInitiate = false;
core.VideoActivationPolicy = videoActivationPolicy;
if (core.VideoSupported())
{
core.VideoCaptureEnabled = true;
}
core.UsePreviewWindow(true);
core.FileTransferServer = "https://www.linphone.org:444/lft.php";
}
return core;
}
}
public void CoreStart(CoreDispatcher dispatcher)
{
Core.Start();
Timer = new Timer(OnTimedEvent, dispatcher, 20, 20);
}
private async void OnTimedEvent(object state)
{
await ((CoreDispatcher)state).RunIdleAsync((args) =>
{
Core.Iterate();
});
}
public void AddOnAccountRegistrationStateChangedDelegate(OnAccountRegistrationStateChangedDelegate myDelegate)
{
Core.Listener.OnAccountRegistrationStateChanged += myDelegate;
}
public void RemoveOnAccountRegistrationStateChangedDelegate(OnAccountRegistrationStateChangedDelegate myDelegate)
{
Core.Listener.OnAccountRegistrationStateChanged -= myDelegate;
}
public void AddOnCallStateChangedDelegate(OnCallStateChangedDelegate myDelegate)
{
Core.Listener.OnCallStateChanged += myDelegate;
}
public void RemoveOnCallStateChangedDelegate(OnCallStateChangedDelegate myDelegate)
{
Core.Listener.OnCallStateChanged -= myDelegate;
}
public void AddOnOnMessageReceivedDelegate(OnMessageReceivedDelegate myDelegate)
{
Core.Listener.OnMessageReceived += myDelegate;
}
public void RemoveOnOnMessageReceivedDelegate(OnMessageReceivedDelegate myDelegate)
{
Core.Listener.OnMessageReceived -= myDelegate;
}
public void AddOnMessageSentDelegate(OnMessageSentDelegate myDelegate)
{
Core.Listener.OnMessageSent += myDelegate;
}
public void RemoveOnMessageSentDelegate(OnMessageSentDelegate myDelegate)
{
Core.Listener.OnMessageSent -= myDelegate;
}
public void AddOnChatRoomSubjectChangedDelegate(OnChatRoomSubjectChangedDelegate myDelegate)
{
Core.Listener.OnChatRoomSubjectChanged += myDelegate;
}
public void RemoveOnChatRoomSubjectChangedDelegate(OnChatRoomSubjectChangedDelegate myDelegate)
{
Core.Listener.OnChatRoomSubjectChanged -= myDelegate;
}
public void LogIn(string identity, string password)
{
Address address = Factory.Instance.CreateAddress(identity);
AuthInfo authInfo = Factory.Instance.CreateAuthInfo(address.Username, "", password, "", "", address.Domain);
Core.AddAuthInfo(authInfo);
AccountParams accountParams = Core.CreateAccountParams();
accountParams.IdentityAddress = address;
string serverAddr = "sip:" + address.Domain + ";transport=tls";
accountParams.ServerAddr = serverAddr;
accountParams.RegisterEnabled = true;
// If you want to create some group chats (conferences) you need to
// specify a conference factory URI. Here is the Linphone.org conference
// factory URI.
accountParams.ConferenceFactoryUri = "sip:conference-factory@sip.linphone.org";
Account account = Core.CreateAccount(accountParams);
Core.AddAccount(account);
Core.DefaultAccount = account;
}
public void LogOut()
{
Account account = Core.DefaultAccount;
if (account != null)
{
AccountParams accountParams = account.Params.Clone();
accountParams.RegisterEnabled = false;
account.Params = accountParams;
}
}
public void ClearCoreAfterLogOut()
{
Core.ClearAllAuthInfo();
Core.ClearAccounts();
}
public async void Call(string uriToCall)
{
await OpenMicrophonePopup();
Address address = Core.InterpretUrl(uriToCall);
Core.InviteAddress(address);
}
public bool MicEnabledSwitch()
{
return Core.MicEnabled = !Core.MicEnabled;
}
public bool SpeakerMutedSwitch()
{
return Core.CurrentCall.SpeakerMuted = !Core.CurrentCall.SpeakerMuted;
}
public async Task<bool> CameraEnabledSwitchAsync()
{
await OpenCameraPopup();
Call call = Core.CurrentCall;
CallParams param = core.CreateCallParams(call);
bool newValue = !param.VideoEnabled;
param.VideoEnabled = newValue;
call.Update(param);
return newValue;
}
public ChatRoom CreateOrGetChatRoom(string sipAddress, bool isSecure)
{
Address remoteAddress = Core.InterpretUrl(sipAddress);
Address localAdress = Core.DefaultProxyConfig.IdentityAddress;
ChatRoomParams chatRoomParams = Core.CreateDefaultChatRoomParams();
// To create a one-to-one encrypted chat room we still put GroupEnabled to false.
chatRoomParams.GroupEnabled = false;
chatRoomParams.RttEnabled = false;
if (isSecure)
{
// But here are the things that differ from a basic chat room.
// You must use a Flexisip backend,
chatRoomParams.Backend = ChatRoomBackend.FlexisipChat;
// enable encryption and choose your type of encryption backend,
chatRoomParams.EncryptionBackend = ChatRoomEncryptionBackend.Lime;
chatRoomParams.EncryptionEnabled = isSecure;
// and you must set a subject. But often for one-to-one chat rooms the client
// don't use or display the subject (see ChatRoomToStringConverter), so you can
// put a hard coded subject.
chatRoomParams.Subject = "Dummy Subject";
}
else
{
chatRoomParams.Backend = ChatRoomBackend.Basic;
chatRoomParams.EncryptionBackend = ChatRoomEncryptionBackend.None;
chatRoomParams.EncryptionEnabled = isSecure;
}
return Core.CreateChatRoom(chatRoomParams, localAdress, new[] { remoteAddress });
}
public ChatRoom CreateGroupChatRoom(IEnumerable<Address> participants, string subject, bool isSecure)
{
Address localAdress = Core.DefaultProxyConfig.IdentityAddress;
ChatRoomParams chatRoomParams = Core.CreateDefaultChatRoomParams();
chatRoomParams.Backend = ChatRoomBackend.FlexisipChat;
chatRoomParams.GroupEnabled = true;
chatRoomParams.RttEnabled = false;
chatRoomParams.Subject = subject;
if (isSecure)
{
// If you want to use encryption you should be in a chat room with a Flexisip
// backend, this why we offer the option only on the group chat room for now.
// Then simply choose your encryption backend (only LIME is available by default)
chatRoomParams.EncryptionBackend = ChatRoomEncryptionBackend.Lime;
// and put EncryptionEnabled to true.
chatRoomParams.EncryptionEnabled = isSecure;
// Simply doing this you have now a group chat room with end-to-end encryption.
}
else
{
chatRoomParams.EncryptionBackend = ChatRoomEncryptionBackend.None;
chatRoomParams.EncryptionEnabled = isSecure;
}
return Core.CreateChatRoom(chatRoomParams, localAdress, participants);
}
public async Task<Content> CreateContentFromFile(StorageFile file)
{
StorageFile fileCopy = await file.CopyAsync(ApplicationData.Current.LocalFolder, file.Name, NameCollisionOption.ReplaceExisting);
Content content = Core.CreateContent();
content.FilePath = fileCopy.Path;
string[] splittedMimeType = fileCopy.ContentType.Split("/");
content.Type = splittedMimeType[0];
content.Subtype = splittedMimeType[1];
// Set the file name for the receiver
content.Name = fileCopy.Name;
return content;
}
private async Task OpenMicrophonePopup()
{
AudioGraphSettings settings = new AudioGraphSettings(Windows.Media.Render.AudioRenderCategory.Media);
CreateAudioGraphResult result = await AudioGraph.CreateAsync(settings);
AudioGraph audioGraph = result.Graph;
CreateAudioDeviceInputNodeResult resultNode = await audioGraph.CreateDeviceInputNodeAsync(Windows.Media.Capture.MediaCategory.Media);
AudioDeviceInputNode deviceInputNode = resultNode.DeviceInputNode;
deviceInputNode.Dispose();
audioGraph.Dispose();
}
private async Task OpenCameraPopup()
{
MediaCapture mediaCapture = new Windows.Media.Capture.MediaCapture();
await mediaCapture.InitializeAsync(new MediaCaptureInitializationSettings
{
StreamingCaptureMode = StreamingCaptureMode.Video
});
mediaCapture.Dispose();
}
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of Linphone TutorialCS.
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using _07_AdvancedChat.Views;
namespace _07_AdvancedChat.Service
{
internal class NavigationService
{
private static readonly NavigationService instance = new NavigationService();
public static NavigationService Instance
{
get
{
return instance;
}
}
public NavigationRoot CurrentNavigationRoot { get; set; }
public ChatsPage CurrentChatspage { get; set; }
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of Linphone TutorialCS.
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Windows.UI.Xaml.Controls;
namespace _07_AdvancedChat.Service
{
internal class VideoService
{
private static readonly VideoService instance = new VideoService();
public static VideoService Instance
{
get
{
return instance;
}
}
private CoreService CoreService { get; } = CoreService.Instance;
public void StartVideoStream(SwapChainPanel main, SwapChainPanel preview)
{
CoreService.Core.NativePreviewWindowId = preview;
CoreService.Core.NativeVideoWindowId = main;
}
public void StopVideoStream()
{
CoreService.Core.NativePreviewWindowId = null;
CoreService.Core.NativeVideoWindowId = null;
}
}
}

View File

@@ -0,0 +1,47 @@
using Linphone;
using System;
using System.Linq;
using Windows.UI.Xaml.Data;
namespace _07_AdvancedChat.Shared
{
public class ChatRoomToStringConverter : IValueConverter
{
object IValueConverter.Convert(object value, Type targetType, object parameter, string language)
{
ChatRoom chatRoom = (ChatRoom)value;
string nameInList = null;
if (chatRoom.HasCapability((int)ChatRoomCapabilities.Basic))
{
nameInList = chatRoom.PeerAddress.Username;
}
else if (chatRoom.HasCapability((int)ChatRoomCapabilities.OneToOne))
{
nameInList = chatRoom.Participants.FirstOrDefault() == null ? "" : chatRoom.Participants.First().Address.Username;
}
else if (chatRoom.HasCapability((int)ChatRoomCapabilities.Conference))
{
nameInList = chatRoom.Subject;
}
// You can check the Encrypted ChatRoomCapabilities to know if a ChatRoom uses
// encryption or not.
if (chatRoom.HasCapability((int)ChatRoomCapabilities.Encrypted))
{
nameInList += " #SECURE#";
}
if (String.IsNullOrEmpty(nameInList))
{
nameInList = "Incoherent ChatRoom values";
}
return nameInList;
}
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of Linphone TutorialCS.
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Threading.Tasks;
using Windows.UI.Xaml.Controls;
namespace _07_AdvancedChat.Shared
{
public class Utils
{
public static async Task<string> InputTextDialogAsync(string title)
{
TextBox inputTextBox = new TextBox
{
AcceptsReturn = false,
Height = 32
};
ContentDialog dialog = new ContentDialog
{
Content = inputTextBox,
Title = title,
IsSecondaryButtonEnabled = true,
PrimaryButtonText = "OK",
SecondaryButtonText = "Cancel"
};
if (await dialog.ShowAsync() == ContentDialogResult.Primary)
return inputTextBox.Text;
else
return "";
}
}
}

View File

@@ -0,0 +1,72 @@
<Page
x:Class="_07_AdvancedChat.Views.CallsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Grid.Row="0" Background="{ThemeResource SystemAccentColorLight3}" Padding="10">
<TextBlock x:Name="HelloText" HorizontalAlignment="Center" VerticalAlignment="Center" Style="{ThemeResource HeaderTextBlockStyle}" Text="Hello " />
</Border>
<Grid Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" VerticalAlignment="Center" Margin="20">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="URI to call : " />
<TextBox x:Name="UriToCall" Width="350" MinWidth="350" MaxWidth="350" Text="sip:" />
</StackPanel>
<Button x:Name="CallButton" Content="Call" Click="CallClick" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5" />
<TextBlock x:Name="CallText" Text="Your call state is : Idle" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="10" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="10">
<Button x:Name="HangOut" Content="Hang out" Click="HangOutClick" IsEnabled="False" />
<Button x:Name="Sound" Content="Switch off Sound" Click="SoundClick" IsEnabled="False" />
<Button x:Name="Camera" Content="Switch on Camera" Click="CameraClick" IsEnabled="False" />
<Button x:Name="Mic" Content="Mute" Click="MicClick" IsEnabled="False" />
</StackPanel>
</StackPanel>
<Grid Grid.Row="1" x:Name="VideoGrid" Canvas.ZIndex="-1" Background="Black" Visibility="Collapsed">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<SwapChainPanel x:Name="VideoSwapChainPanel" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Grid.RowSpan="3" />
<SwapChainPanel x:Name="PreviewSwapChainPanel" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Column="2" Grid.Row="0" Grid.RowSpan="3">
</SwapChainPanel>
</Grid>
<StackPanel Grid.Row="2" x:Name="IncomingCallStackPanel" Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Collapsed" Margin="10">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="You have a call from :" />
<TextBlock x:Name="IncommingCallText" Text="" />
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button x:Name="Answer" Content="Answer" Click="AnswerClick" />
<Button x:Name="Decline" Content="Decline" Click="DeclineClick" />
</StackPanel>
</StackPanel>
</Grid>
</Grid>
</Page>

View File

@@ -0,0 +1,201 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of Linphone TutorialCS.
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using _07_AdvancedChat.Service;
using Linphone;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace _07_AdvancedChat.Views
{
public sealed partial class CallsPage : Page
{
private CoreService CoreService { get; } = CoreService.Instance;
private VideoService VideoService { get; } = VideoService.Instance;
private Call IncommingCall;
public CallsPage()
{
this.InitializeComponent();
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
VideoService.StopVideoStream();
CoreService.RemoveOnCallStateChangedDelegate(OnCallStateChanged);
base.OnNavigatedFrom(e);
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
HelloText.Text += CoreService.Core.DefaultProxyConfig.FindAuthInfo().Username;
CoreService.AddOnCallStateChangedDelegate(OnCallStateChanged);
if (CoreService.Core.CurrentCall != null)
{
OnCallStateChanged(CoreService.Core, CoreService.Core.CurrentCall, CoreService.Core.CurrentCall.State, null);
}
}
private void CallClick(object sender, RoutedEventArgs e)
{
CoreService.Call(UriToCall.Text);
}
private void HangOutClick(object sender, RoutedEventArgs e)
{
CoreService.Core.TerminateAllCalls();
}
private void SoundClick(object sender, RoutedEventArgs e)
{
if (CoreService.SpeakerMutedSwitch())
{
Sound.Content = "Switch on Sound";
}
else
{
Sound.Content = "Switch off Sound";
}
}
private async void CameraClick(object sender, RoutedEventArgs e)
{
await CoreService.CameraEnabledSwitchAsync();
Camera.Content = "Waiting for accept ...";
Camera.IsEnabled = false;
}
private void MicClick(object sender, RoutedEventArgs e)
{
if (CoreService.MicEnabledSwitch())
{
Mic.Content = "Mute";
}
else
{
Mic.Content = "Unmute";
}
}
private void AnswerClick(object sender, RoutedEventArgs e)
{
IncommingCall.Accept();
IncommingCall = null;
}
private void DeclineClick(object sender, RoutedEventArgs e)
{
if (IncommingCall != null)
{
IncommingCall.Decline(Reason.Declined);
IncommingCall = null;
}
}
private void OnCallStateChanged(Core core, Call call, CallState state, string message)
{
CallText.Text = "Your call state is : " + state.ToString();
switch (state)
{
case CallState.IncomingReceived:
IncommingCall = call;
IncomingCallStackPanel.Visibility = Visibility.Visible;
IncommingCallText.Text = " " + call.RemoteAddress.AsString();
break;
case CallState.OutgoingInit:
case CallState.OutgoingProgress:
case CallState.OutgoingRinging:
HangOut.IsEnabled = true;
break;
case CallState.StreamsRunning:
case CallState.UpdatedByRemote:
CallInProgressGuiUpdates();
if (call.CurrentParams.VideoEnabled)
{
StartVideoAndUpdateGui();
}
else
{
StopVideoAndUpdateGui();
}
break;
case CallState.Error:
case CallState.End:
case CallState.Released:
IncommingCall = null;
EndingCallGuiUpdates();
VideoService.StopVideoStream();
break;
}
}
private void StopVideoAndUpdateGui()
{
Camera.Content = "Switch on Camera";
Camera.IsEnabled = true;
VideoGrid.Visibility = Visibility.Collapsed;
VideoService.StopVideoStream();
}
private void StartVideoAndUpdateGui()
{
VideoGrid.Visibility = Visibility.Visible;
Camera.Content = "Switch off Camera";
VideoService.StartVideoStream(VideoSwapChainPanel, PreviewSwapChainPanel);
Camera.IsEnabled = true;
}
private void EndingCallGuiUpdates()
{
IncomingCallStackPanel.Visibility = Visibility.Collapsed;
CallButton.IsEnabled = true;
HangOut.IsEnabled = false;
Sound.IsEnabled = false;
Camera.IsEnabled = false;
Mic.IsEnabled = false;
VideoGrid.Visibility = Visibility.Collapsed;
Camera.Content = "Switch on Camera";
Mic.Content = "Mute";
Sound.Content = "Switch off Sound";
}
private void CallInProgressGuiUpdates()
{
IncomingCallStackPanel.Visibility = Visibility.Collapsed;
CallButton.IsEnabled = false;
HangOut.IsEnabled = true;
Sound.IsEnabled = true;
Camera.IsEnabled = true;
Mic.IsEnabled = true;
}
}
}

View File

@@ -0,0 +1,66 @@
<Page
x:Class="_07_AdvancedChat.Views.ChatPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.1*" />
<RowDefinition Height="0.9*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<TextBlock x:Name="ChatHeaderText" Text="Your conversation with : " Style="{ThemeResource HeaderTextBlockStyle}" />
</StackPanel>
<Grid Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="0.70*" />
<RowDefinition Height="0.30*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="auto" MaxWidth="350" />
</Grid.ColumnDefinitions>
<Grid Grid.Row="0" Padding="10,0,10,0">
<TextBlock x:Name="PeerUsername" Text="Peer user-name : " />
<TextBlock x:Name="YourUsername" Text="Your user-name : " HorizontalAlignment="Right" />
</Grid>
<ScrollViewer Grid.Row="1" x:Name="MessagesScroll">
<StackPanel Padding="10"
x:Name="MessagesList"
Orientation="Vertical"
VerticalAlignment="Bottom">
</StackPanel>
</ScrollViewer>
<Border x:Name="GroupChatDisplayBorder" BorderBrush="{ThemeResource SystemAccentColorLight3}"
BorderThickness="1,0,0,0" Padding="5" Grid.Column="1" Grid.RowSpan="2" Visibility="Collapsed" />
<Grid Grid.Row="2" Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.80*" />
<ColumnDefinition Width="0.20*" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" x:Name="OutgoingMessageText" Text="" AcceptsReturn="True" TextWrapping="Wrap" />
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button Grid.Row="0" x:Name="OutgoingMessageButton" Click="OutgoingMessageButton_Click" Content="Send" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1" />
<Button Grid.Row="1" x:Name="SendFileButton" Click="SendFileButton_Click" Content="Send a file" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1" />
<Button Grid.Row="2" x:Name="SendMultipartButton" Click="SendMultipartButton_Click" Content="Send multipart (text+file)" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="1" />
<CheckBox Grid.Row="3" x:Name="EphemeralCheckBox" Content="Ephemeral mode enable" Checked="EphemeralCheckBox_Checked" Unchecked="EphemeralCheckBox_Unchecked" IsChecked="True" HorizontalAlignment="Center" />
</Grid>
</Grid>
</Grid>
</Grid>
</Page>

View File

@@ -0,0 +1,261 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of Linphone TutorialCS.
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using _07_AdvancedChat.Controls;
using _07_AdvancedChat.Service;
using Linphone;
using System;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace _07_AdvancedChat.Views
{
public sealed partial class ChatPage : Page
{
private NavigationService NavigationService { get; } = NavigationService.Instance;
private CoreService CoreService { get; } = CoreService.Instance;
private ChatRoom ChatRoom;
public ChatPage()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
ChatRoom = ((ChatRoom)e.Parameter);
ChatRoom.Listener.OnMessageReceived += OnMessageReceived;
ChatRoom.Listener.OnConferenceLeft += AddEvent;
ChatRoom.Listener.OnConferenceJoined += AddEvent;
ChatRoom.Listener.OnParticipantDeviceRemoved += AddEvent;
ChatRoom.Listener.OnSubjectChanged += AddEvent;
ChatRoom.Listener.OnParticipantRemoved += AddEvent;
ChatRoom.Listener.OnParticipantAdminStatusChanged += AddEvent;
ChatRoom.Listener.OnParticipantAdded += AddEvent;
ChatRoom.Listener.OnEphemeralEvent += AddEvent;
// In this step we want to test the ephemeral messages. This feature is only
// available if you are using in a Flexisip backend.
if (ChatRoomBackend.FlexisipChat.Equals(ChatRoom.CurrentParams.Backend) && !ChatRoom.EphemeralEnabled)
{
// In this step when the ephemeral feature is available we enable it
// by default. Just set the EphemeralEnabled to true to activate the
// ephemeral mode, after this point every message send will be marked
// as ephemeral
ChatRoom.EphemeralEnabled = true;
// You can choose how many times you want the message to be displayed before
// getting destroyed with EphemeralLifetime, the value is in second.
// Here we set a low value for testing purpose.
ChatRoom.EphemeralLifetime = 15;
// At any time you can choose to disable the ephemeral mode moving EphemeralEnabled to false.
// See the EphemeralCheckBox_Unchecked method.
}
else if (!ChatRoomBackend.FlexisipChat.Equals(ChatRoom.CurrentParams.Backend))
{
// If the backend is not a Flexisip one we hide the ephemeral feature in the ChatPage
// because it doesn't support it.
EphemeralCheckBox.Visibility = Visibility.Collapsed;
}
if (ChatRoom.PeerAddress != null)
{
UpdateGUI();
}
else
{
ChatHeaderText.Text = "Creation in progress";
ChatRoom.Listener.OnConferenceJoined += OnConferenceJoin;
}
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
ChatRoom.Listener.OnMessageReceived -= OnMessageReceived;
ChatRoom.Listener.OnConferenceLeft -= AddEvent;
ChatRoom.Listener.OnConferenceJoined -= AddEvent;
ChatRoom.Listener.OnParticipantDeviceRemoved -= AddEvent;
ChatRoom.Listener.OnSubjectChanged -= AddEvent;
ChatRoom.Listener.OnParticipantRemoved -= AddEvent;
ChatRoom.Listener.OnParticipantAdminStatusChanged -= AddEvent;
ChatRoom.Listener.OnParticipantAdded -= AddEvent;
ChatRoom.Listener.OnConferenceJoined -= OnConferenceJoin;
base.OnNavigatedFrom(e);
}
private void OnConferenceJoin(ChatRoom chatRoom, EventLog eventLog)
{
UpdateGUI();
}
private void UpdateGUI()
{
ChatHeaderText.Text = "Your conversation with : " + ChatRoom.PeerAddress.Username;
foreach (EventLog eventLog in ChatRoom.GetHistoryEvents(0))
{
if (EventLogType.ConferenceChatMessage.Equals(eventLog.Type))
{
AddMessage(eventLog.ChatMessage);
}
else
{
AddEvent(null, eventLog);
}
}
ChatRoom.MarkAsRead();
NavigationService.CurrentNavigationRoot.UpdateUnreadMessageCount();
NavigationService.CurrentChatspage.UpdateChatRooms();
PeerUsername.Text += ChatRoom.PeerAddress.Username;
YourUsername.Text += ChatRoom.LocalAddress.Username;
// We only display the GroupChatDisplay if we are in real group chat,
// we don't if it's a OneToOne secure ChatRoom.
if (ChatRoom.HasCapability((int)ChatRoomCapabilities.Conference)
&& !ChatRoom.HasCapability((int)ChatRoomCapabilities.OneToOne))
{
GroupChatDisplay participantsDisplay = new GroupChatDisplay(ChatRoom);
GroupChatDisplayBorder.Child = participantsDisplay;
GroupChatDisplayBorder.Visibility = Visibility.Visible;
}
if (ChatRoom.HasCapability((int)ChatRoomCapabilities.Basic))
{
SendMultipartButton.Visibility = Visibility.Collapsed;
}
}
private void OnMessageReceived(ChatRoom chatRoom, ChatMessage message)
{
if (ChatRoom != null)
{
AddMessage(message);
chatRoom.MarkAsRead();
}
}
private void AddMessage(ChatMessage chatMessage)
{
MessageDisplay messageDisplay = new MessageDisplay(chatMessage);
MessagesList.Children.Add(messageDisplay);
ScrollToBottom();
}
private void AddEvent(ChatRoom chatRoom, EventLog eventLog)
{
EventDisplay eventDisplay = new EventDisplay(eventLog);
MessagesList.Children.Add(eventDisplay);
ScrollToBottom();
}
private void ScrollToBottom()
{
MessagesScroll.UpdateLayout();
MessagesScroll.ChangeView(1, MessagesScroll.ExtentHeight, 1);
}
private void OutgoingMessageButton_Click(object sender, RoutedEventArgs e)
{
if (ChatRoom != null && OutgoingMessageText.Text != null && OutgoingMessageText.Text.Length > 0)
{
ChatMessage chatMessage = ChatRoom.CreateMessage(OutgoingMessageText.Text);
chatMessage.Send();
AddMessage(chatMessage);
}
OutgoingMessageText.Text = "";
}
private async void SendFileButton_Click(object sender, RoutedEventArgs e)
{
FileOpenPicker picker = new FileOpenPicker
{
ViewMode = PickerViewMode.List,
SuggestedStartLocation = PickerLocationId.DocumentsLibrary
};
picker.FileTypeFilter.Add("*");
StorageFile file = await picker.PickSingleFileAsync();
if (file != null)
{
Content content = await CoreService.CreateContentFromFile(file);
ChatMessage fileMessage = ChatRoom.CreateFileTransferMessage(content);
fileMessage.Send();
AddMessage(fileMessage);
}
}
private async void SendMultipartButton_Click(object sender, RoutedEventArgs e)
{
if (ChatRoom != null && OutgoingMessageText.Text != null && OutgoingMessageText.Text.Length > 0)
{
ChatMessage multipartMessage = ChatRoom.CreateMessage(OutgoingMessageText.Text);
FileOpenPicker picker = new FileOpenPicker
{
ViewMode = PickerViewMode.List,
SuggestedStartLocation = PickerLocationId.DocumentsLibrary
};
picker.FileTypeFilter.Add("*");
StorageFile file = await picker.PickSingleFileAsync();
if (file != null)
{
Content content = await CoreService.CreateContentFromFile(file);
multipartMessage.AddFileContent(content);
multipartMessage.Send();
AddMessage(multipartMessage);
}
}
OutgoingMessageText.Text = "";
}
private void EphemeralCheckBox_Checked(object sender, RoutedEventArgs e)
{
if (ChatRoom != null)
{
ChatRoom.EphemeralEnabled = true;
}
}
private void EphemeralCheckBox_Unchecked(object sender, RoutedEventArgs e)
{
if (ChatRoom != null)
{
ChatRoom.EphemeralEnabled = false;
}
}
}
}

View File

@@ -0,0 +1,45 @@
<Page
x:Class="_07_AdvancedChat.Views.ChatsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:_07_AdvancedChat.Shared"
xmlns:linphone="using:Linphone"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.Resources>
<local:ChatRoomToStringConverter x:Key="ChatRoomToStringConverter" />
</Page.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="0.7*" />
</Grid.ColumnDefinitions>
<Border BorderBrush="{ThemeResource SystemAccentColorLight3}"
BorderThickness="2,2,1,2"
Padding="2">
<StackPanel Grid.Column="0" Orientation="Vertical">
<Button x:Name="NewChatRoom" Click="NewChatRoom_Click" Content="Create a new basic ChatRoom" Tag="false" HorizontalAlignment="Stretch" />
<Button x:Name="NewSecureChatRoom" Click="NewChatRoom_Click" Content="Create a new secure ChatRoom" Tag="true" HorizontalAlignment="Stretch" />
<Button x:Name="NewGroupChatRoom" Click="NewGroupChatRoom_Click" Content="Create a new group ChatRoom" HorizontalAlignment="Stretch" />
<ListView x:Name="ChatRoomsLV" SelectionMode="Single" IsItemClickEnabled="True" ItemClick="ChatRoomsLV_ItemClick">
<ListView.ItemTemplate>
<DataTemplate x:DataType="linphone:ChatRoom">
<StackPanel Orientation="Horizontal">
<Border BorderThickness="1" BorderBrush="{ThemeResource SystemAccentColorLight3}" CornerRadius="10" Margin="0,0,5,0" Padding="3,0,3,0">
<TextBlock Text="{x:Bind UnreadMessagesCount}" FontSize="14" />
</Border>
<TextBlock Text="{x:Bind Converter={StaticResource ChatRoomToStringConverter}}" FontSize="14" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Border>
<Border BorderBrush="{ThemeResource SystemAccentColorLight3}"
BorderThickness="1,2,2,2"
Padding="2"
Grid.Column="1">
<Frame x:Name="ChatRoomFrame" />
</Border>
</Grid>
</Page>

View File

@@ -0,0 +1,117 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of Linphone TutorialCS.
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using _07_AdvancedChat.Service;
using _07_AdvancedChat.Shared;
using Linphone;
using System;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace _07_AdvancedChat.Views
{
public sealed partial class ChatsPage : Page
{
private CoreService CoreService { get; } = CoreService.Instance;
private NavigationService NavigationService { get; } = NavigationService.Instance;
public ChatsPage()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
NavigationService.CurrentChatspage = this;
UpdateChatRooms();
CoreService.AddOnOnMessageReceivedDelegate(OnMessageReceiveOrSent);
CoreService.AddOnMessageSentDelegate(OnMessageReceiveOrSent);
CoreService.AddOnChatRoomSubjectChangedDelegate(AddOnChatRoomSubjectChanged);
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
NavigationService.CurrentChatspage = null;
CoreService.RemoveOnOnMessageReceivedDelegate(OnMessageReceiveOrSent);
CoreService.RemoveOnMessageSentDelegate(OnMessageReceiveOrSent);
CoreService.RemoveOnChatRoomSubjectChangedDelegate(AddOnChatRoomSubjectChanged);
base.OnNavigatedFrom(e);
}
private void OnMessageReceiveOrSent(Core core, ChatRoom chatRoom, ChatMessage message) => UpdateChatRooms();
private void AddOnChatRoomSubjectChanged(Core core, ChatRoom chatRoom) => UpdateChatRooms();
public void UpdateChatRooms()
{
ChatRoom selectedChatRoom = (ChatRoom)ChatRoomsLV.SelectedItem;
ChatRoomsLV.Items.Clear();
foreach (ChatRoom chatRoom in CoreService.Core.ChatRooms)
{
if (chatRoom.HistoryEventsSize > 0)
{
ChatRoomsLV.Items.Add(chatRoom);
if (selectedChatRoom == chatRoom)
{
ChatRoomsLV.SelectedItem = chatRoom;
}
}
}
}
private void ChatRoomsLV_ItemClick(object sender, ItemClickEventArgs e)
{
ChatRoomsLV.SelectedItem = e.ClickedItem;
ChatRoomFrame.Navigate(typeof(ChatPage), e.ClickedItem);
}
private async void NewChatRoom_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
string peerSipAddress = await Utils.InputTextDialogAsync("Enter peer sip address");
bool secure = Boolean.Parse((string)((Button)sender).Tag);
if (!String.IsNullOrWhiteSpace(peerSipAddress))
{
ChatRoom newChatRoom = CoreService.CreateOrGetChatRoom(peerSipAddress, secure);
if (newChatRoom != null)
{
ChatRoomFrame.Navigate(typeof(ChatPage), newChatRoom);
}
else
{
ContentDialog noSettingsDialog = new ContentDialog
{
Title = "ChatRoom creation error",
Content = "An error occurred during ChatRoom creation, check sip address validity and try again.",
CloseButtonText = "OK"
};
await noSettingsDialog.ShowAsync();
}
}
}
private void NewGroupChatRoom_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
ChatRoomFrame.Navigate(typeof(CreateGroupChatRoom));
}
}
}

View File

@@ -0,0 +1,33 @@
<Page
x:Class="_07_AdvancedChat.Views.CreateGroupChatRoom"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:linphone="using:Linphone">
<Grid>
<StackPanel VerticalAlignment="Center">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Vertical">
<TextBlock Text="Group ChatRoom subject :" />
<TextBox x:Name="Subject" PlaceholderText="A subject" />
<CheckBox x:Name="SecureCheckBox" Content="I want a secure ChatRoom" />
</StackPanel>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal" Margin="0,10,0,10">
<TextBox x:Name="Address" Width="350" MinWidth="350" MaxWidth="350" Text="sip:" />
<Button x:Name="AddAddress" Click="AddAddress_Click" Content="Add" HorizontalAlignment="Center" VerticalAlignment="Center" />
</StackPanel>
<ListView x:Name="AddressesLV" SelectionMode="None" IsItemClickEnabled="False">
<ListView.ItemTemplate>
<DataTemplate x:DataType="linphone:Address">
<TextBlock Text="{x:Bind AsString()}" FontSize="14" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button x:Name="Create" Click="Create_Click" Content="Create" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10,0,0" />
</StackPanel>
</Grid>
</Page>

View File

@@ -0,0 +1,74 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of Linphone TutorialCS.
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using _07_AdvancedChat.Service;
using Linphone;
using System;
using System.Collections.ObjectModel;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace _07_AdvancedChat.Views
{
public sealed partial class CreateGroupChatRoom : Page
{
private CoreService CoreService { get; } = CoreService.Instance;
private readonly ObservableCollection<Address> addresses = new ObservableCollection<Address>();
public ObservableCollection<Address> DisplayedAddresses
{
get { return this.addresses; }
}
public CreateGroupChatRoom()
{
this.InitializeComponent();
}
private async void Create_Click(object sender, RoutedEventArgs e)
{
ChatRoom newChatRoom = CoreService.CreateGroupChatRoom(DisplayedAddresses, Subject.Text, SecureCheckBox.IsChecked ?? false);
if (newChatRoom != null)
{
this.Frame.Navigate(typeof(ChatPage), newChatRoom);
}
else
{
ContentDialog noSettingsDialog = new ContentDialog
{
Title = "ChatRoom creation error",
Content = "An error occurred during group ChatRoom creation, check sip addresses validity and try again.",
CloseButtonText = "OK"
};
await noSettingsDialog.ShowAsync();
}
}
private void AddAddress_Click(object sender, RoutedEventArgs e)
{
if (!String.IsNullOrWhiteSpace(Address.Text))
{
DisplayedAddresses.Add(CoreService.Core.InterpretUrl(Address.Text));
AddressesLV.ItemsSource = DisplayedAddresses;
}
}
}
}

View File

@@ -0,0 +1,34 @@
<Page
x:Class="_07_AdvancedChat.Views.LoginPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid KeyUp="GridKeyUp">
<Grid.RowDefinitions>
<RowDefinition Height="0.15*" />
<RowDefinition Height="0.85*" />
</Grid.RowDefinitions>
<Border Grid.Row="0" Background="{ThemeResource SystemAccentColorLight3}">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Style="{ThemeResource HeaderTextBlockStyle}" Text="Login Form" />
</Border>
<StackPanel Grid.Row="1" VerticalAlignment="Center">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Vertical">
<TextBlock Text="Identity :" />
<TextBox x:Name="Identity" Width="350" MinWidth="350" MaxWidth="350" Text="sip:" />
</StackPanel>
<StackPanel Margin="0,10,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Vertical">
<TextBlock Text="Password :" />
<PasswordBox x:Name="Password" Width="350" MinWidth="350" MaxWidth="350" PlaceholderText="myPasswd" />
</StackPanel>
<Button x:Name="LogIn" Click="LogInClick" Content="Login" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10,0,0" />
<TextBlock x:Name="RegistrationText" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10,0,0" />
</StackPanel>
</Grid>
</Page>

View File

@@ -0,0 +1,112 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of Linphone TutorialCS.
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using _07_AdvancedChat.Service;
using Linphone;
using Windows.System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Navigation;
namespace _07_AdvancedChat.Views
{
/// <summary>
/// A really simple app for a first Login with LinphoneSDK x UWP
/// </summary>
public sealed partial class LoginPage : Page
{
private CoreService CoreService { get; } = CoreService.Instance;
public LoginPage()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
CoreService.AddOnAccountRegistrationStateChangedDelegate(OnAccountRegistrationStateChanged);
}
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
CoreService.RemoveOnAccountRegistrationStateChangedDelegate(OnAccountRegistrationStateChanged);
base.OnNavigatingFrom(e);
}
/// <summary>
/// Called when you click on the "Login" button.
/// </summary>
private void LogInClick(object sender, RoutedEventArgs e)
{
if (LogIn.IsEnabled)
{
LogIn.IsEnabled = false;
CoreService.LogIn(Identity.Text, Password.Password);
}
}
/// <summary>
/// Called when a key is pressed and released on the login page.
/// If you pressed "Enter", simulate a login click.
/// </summary>
private void GridKeyUp(object sender, KeyRoutedEventArgs e)
{
if (VirtualKey.Enter.Equals(e.Key))
{
LogInClick(null, null);
}
}
/// <summary>
/// This method is called every time the RegistrationState is updated by background core's actions.
/// In this example we use this to update the GUI.
/// </summary>
private void OnAccountRegistrationStateChanged(Core core, Account account, RegistrationState state, string message)
{
RegistrationText.Text = "Your registration state is : " + state.ToString();
switch (state)
{
case RegistrationState.Cleared:
case RegistrationState.None:
CoreService.ClearCoreAfterLogOut();
LogIn.IsEnabled = true;
break;
case RegistrationState.Ok:
LogIn.IsEnabled = false;
this.Frame.Navigate(typeof(NavigationRoot));
break;
case RegistrationState.Progress:
LogIn.IsEnabled = false;
break;
case RegistrationState.Failed:
LogIn.IsEnabled = true;
break;
default:
break;
}
}
}
}

View File

@@ -0,0 +1,43 @@
<Page
x:Class="_07_AdvancedChat.Views.NavigationRoot"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Loaded="Page_Loaded">
<Grid x:Name="NavRootGrid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<NavigationView
x:Name="navview"
AlwaysShowHeader="False"
ItemInvoked="Navview_ItemInvoked"
PaneDisplayMode="Top"
IsBackButtonVisible="Collapsed">
<NavigationView.MenuItems>
<NavigationViewItem Content="Calls" IsSelected="True">
<NavigationViewItem.Icon>
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xF715;" />
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem>
<NavigationViewItem.Icon>
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE8F2;" />
</NavigationViewItem.Icon>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Chats" />
<Border x:Name="NewMessageCountBorder" BorderThickness="1" BorderBrush="Red" CornerRadius="10" Margin="5,0,0,0" Padding="3,0,3,0">
<TextBlock x:Name="NewMessageCount" Text="0" />
</Border>
</StackPanel>
</NavigationViewItem>
</NavigationView.MenuItems>
<NavigationView.PaneFooter>
<NavigationViewItem Content="Sign out" Tapped="SignOut_Tapped">
<NavigationViewItem.Icon>
<FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xF3B1;" />
</NavigationViewItem.Icon>
</NavigationViewItem>
</NavigationView.PaneFooter>
<Frame x:Name="AppNavFrame" Navigated="AppNavFrame_Navigated" />
</NavigationView>
</Grid>
</Page>

View File

@@ -0,0 +1,154 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of Linphone TutorialCS.
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using _07_AdvancedChat.Service;
using Linphone;
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Navigation;
namespace _07_AdvancedChat.Views
{
/// <summary>
/// A really simple app for a first Login with LinphoneSDK x UWP
/// </summary>
public sealed partial class NavigationRoot : Page
{
private CoreService CoreService { get; } = CoreService.Instance;
private NavigationService NavigationService { get; } = NavigationService.Instance;
private bool hasLoadedPreviously;
public NavigationRoot()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
this.CoreService.AddOnOnMessageReceivedDelegate(OnMessageReveive);
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
this.CoreService.RemoveOnOnMessageReceivedDelegate(OnMessageReveive);
base.OnNavigatedFrom(e);
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
// Only do an inital navigate the first time the page loads
// when we switch out of compactoverloadmode this will fire but we don't want to navigate because
// there is already a page loaded
if (!hasLoadedPreviously)
{
AppNavFrame.Navigate(typeof(CallsPage));
UpdateUnreadMessageCount();
hasLoadedPreviously = true;
NavigationService.CurrentNavigationRoot = this;
}
}
private void AppNavFrame_Navigated(object sender, NavigationEventArgs e)
{
switch (e.SourcePageType)
{
case Type c when e.SourcePageType == typeof(CallsPage):
((NavigationViewItem)navview.MenuItems[0]).IsSelected = true;
break;
case Type c when e.SourcePageType == typeof(ChatsPage):
((NavigationViewItem)navview.MenuItems[1]).IsSelected = true;
break;
}
}
private async void Navview_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
{
if (args.IsSettingsInvoked)
{
ContentDialog noSettingsDialog = new ContentDialog
{
Title = "No settings",
Content = "There is no settings in this little app",
CloseButtonText = "OK"
};
ContentDialogResult result = await noSettingsDialog.ShowAsync();
return;
}
string invokedItemValue = args.InvokedItem as string;
if (invokedItemValue != null && invokedItemValue.Contains("Calls"))
{
AppNavFrame.Navigate(typeof(CallsPage));
}
else
{
AppNavFrame.Navigate(typeof(ChatsPage));
}
}
private void SignOut_Tapped(object sender, TappedRoutedEventArgs e)
{
DisplaySignOutDialog();
}
private async void DisplaySignOutDialog()
{
ContentDialog signOutDialog = new ContentDialog
{
Title = "Sign out ?",
Content = "All your current calls and actions will be canceled, are you sure to continue ?",
PrimaryButtonText = "Sign out",
CloseButtonText = "Cancel"
};
ContentDialogResult result = await signOutDialog.ShowAsync();
if (result == ContentDialogResult.Primary)
{
CoreService.Core.TerminateAllCalls();
CoreService.LogOut();
this.Frame.Navigate(typeof(LoginPage));
}
}
private void OnMessageReveive(Core core, ChatRoom chatRoom, ChatMessage message)
{
UpdateUnreadMessageCount();
}
public void UpdateUnreadMessageCount()
{
if (CoreService.Core.UnreadChatMessageCountFromActiveLocals > 0)
{
NewMessageCount.Text = "" + CoreService.Core.UnreadChatMessageCountFromActiveLocals;
NewMessageCountBorder.Visibility = Visibility.Visible;
}
else
{
NewMessageCountBorder.Visibility = Visibility.Collapsed;
}
}
}
}