diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
new file mode 100644
index 00000000..53a90693
--- /dev/null
+++ b/.github/workflows/build.yaml
@@ -0,0 +1,125 @@
+# This workflow will build, sign, and package a WinUI 3 MSIX desktop application
+# built on .NET.
+
+name: Build
+
+on:
+ push:
+ branches: [ redesign ]
+ pull_request:
+ branches: [ redesign ]
+
+jobs:
+
+ build:
+
+ strategy:
+ matrix:
+ configuration: [Release]
+
+ runs-on: windows-latest
+
+ env:
+ Solution_Name: Unicord.sln
+ Project_Name: Unicord.Universal.Package
+ Project_Name_2: Unicord.Universal
+ ProjectFile_Name: Unicord.Universal.Package/Unicord.Universal.Package.wapproj
+ BackgroundProjectFile_Name: Unicord.Universal.Background/Unicord.Universal.Background.csproj
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+ fetch-depth: 0
+
+ # Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
+ - name: Setup MSBuild.exe
+ uses: microsoft/setup-msbuild@v2
+
+ # Restore the application to populate the obj folder with RuntimeIdentifiers
+ - name: Restore NuGet Packages
+ run: |
+ msbuild $env:Solution_Name /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=win-x86
+ msbuild $env:Solution_Name /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=win-x64
+ msbuild $env:Solution_Name /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=win-arm
+ env:
+ Configuration: ${{ matrix.configuration }}
+
+ # - name: Build Background Task
+ # run: |
+ # msbuild $env:BackgroundProjectFile_Name /p:Configuration=$env:Configuration /p:TargetFramework=net472 /p:RuntimeIdentifier=win-x86
+ # msbuild $env:BackgroundProjectFile_Name /p:Configuration=$env:Configuration /p:TargetFramework=net472 /p:RuntimeIdentifier=win-x64
+ # msbuild $env:BackgroundProjectFile_Name /p:Configuration=$env:Configuration /p:TargetFramework=net472 /p:RuntimeIdentifier=win-arm
+ # env:
+ # Configuration: ${{ matrix.configuration }}
+
+ # Decode the base 64 encoded pfx and save the Signing_Certificate
+ - name: Load Certificate
+ run: |
+ $pfx_cert_byte = [System.Convert]::FromBase64String("${{ secrets.BASE64_ENCODED_PFX }}")
+ $certificatePath = "GitHubActionsWorkflow.pfx"
+ [IO.File]::WriteAllBytes("$env:Project_Name/$certificatePath", $pfx_cert_byte)
+ [IO.File]::WriteAllBytes("$env:Project_Name_2/$certificatePath", $pfx_cert_byte)
+
+ - name: Adjust Package Version
+ run: |
+ $appx = 'http://schemas.microsoft.com/appx/manifest/foundation/windows10'
+ $file = (Resolve-Path "$env:Project_Name/Package.appxmanifest")
+ $xml = [System.Xml.XmlDocument]::new()
+ $xml.Load($file)
+
+ $nsmgr = [System.Xml.XmlNamespaceManager]::new($xml.NameTable)
+ $nsmgr.AddNamespace("appx", $appx);
+
+ # adjust package version
+ $node = $xml.GetElementsByTagName("Identity", $appx)[0]
+ $version = [System.Version]::Parse($node.GetAttribute("Version"))
+
+ if ($env:Version -ne "Store") {
+ $commitDate = Get-Date (git show -s --format=%ci)
+ $epoch = ($commitDate - (Get-Date $commitDate.Date -Day 1))
+ $version = [System.Version]::new($version.Major, $version.Minor, $version.Build, $epoch.TotalMinutes);
+ $node.SetAttribute("Version", $version.ToString())
+ }
+
+ $xml.Save($file)
+
+ echo "Appx_Bundle_Version=$($version.ToString())" >> $env:GITHUB_ENV
+ env:
+ Appx_Bundle_Version: ''
+ # Version: ${{ matrix.version }}
+ Version: ''
+
+ - name: Install legacy SDK (10.0.22621.2428)
+ run: |
+ echo Downloading...
+ curl -L https://go.microsoft.com/fwlink/?linkid=2250105 -o winsdksetup.exe
+ echo Installing...
+ ./winsdksetup.exe /features + /q
+ echo "Waiting for SDK to finish installing..."
+ Wait-Process -Name "winsdksetup"
+ echo Done!
+
+ # Create the app package by building and packaging the project
+ - name: Build App Packages
+ run: msbuild $env:Solution_Name /t:Unicord_Universal_Package /p:Configuration=$env:Configuration /p:UapAppxPackageBuildMode=$env:Appx_Package_Build_Mode /p:AppxBundle=$env:Appx_Bundle /p:AppxBundlePlatforms="x86|x64|ARM" /p:PackageCertificateKeyFile=GitHubActionsWorkflow.pfx /p:AppxPackageDir="$env:Appx_Package_Dir" /p:PackageCertificateThumbprint=$env:AppxThumbprint
+ env:
+ Appx_Bundle: Always
+ Appx_Package_Build_Mode: SideloadOnly
+ Appx_Package_Dir: Packages\
+ Configuration: ${{ matrix.configuration }}
+ AppxThumbprint: ${{ secrets.PFX_THUMBPRINT }}
+
+ # Remove the pfx
+ - name: Cleanup
+ run: Remove-Item -path Unicord.Universal.Package/GitHubActionsWorkflow.pfx
+
+ # Upload the MSIX package: https://github.com/marketplace/actions/upload-a-build-artifact
+ - name: Upload Appx Package
+ uses: actions/upload-artifact@v4
+ with:
+ # name: AppxPackage-${{ env.Appx_Bundle_Version }}-${{ matrix.configuration }}-${{ matrix.version }}
+ name: AppxPackage-${{ env.Appx_Bundle_Version }}-${{ matrix.configuration }}
+ path: |
+ ${{ env.Project_Name }}\\Packages
diff --git a/.gitignore b/.gitignore
index 0cc2ab23..e0694d5c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -184,7 +184,6 @@ publish/
PublishScripts/
# NuGet Packages
-*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
@@ -335,3 +334,5 @@ ASALocalRun/
# MFractors (Xamarin productivity tool) working folder
.mfractor/
*.zip
+
+Output-Debug.txt
\ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
index 4d2cd035..4479216f 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,21 +1,15 @@
[submodule "Libraries/WamWooWam.Core"]
path = Libraries/WamWooWam.Core
url = https://github.com/WamWooWam/WamWooWam.Core
-[submodule "Libraries/Native/libsodium"]
- path = Libraries/Native/libsodium
- url = https://github.com/WamWooWam/libsodium
-[submodule "Libraries/Native/opus"]
- path = Libraries/Native/opus
- url = https://github.com/WamWooWam/opus
[submodule "Libraries/MomentSharp"]
path = Libraries/MomentSharp
url = https://github.com/WamWooWam/MomentSharp
[submodule "Libraries/DSharpPlus"]
path = Libraries/DSharpPlus
- url = https://github.com/WamWooWam/DSharpPlus/
-[submodule "Libraries/Native/webrtc-uwp-sdk"]
- path = Libraries/Native/webrtc-uwp-sdk
- url = https://github.com/webrtc-uwp/webrtc-uwp-sdk.git
+ url = https://github.com/UnicordDev/DSharpPlus-Unicord/
[submodule "Libraries/unicode.net"]
path = Libraries/unicode.net
url = https://github.com/wamwoowam/unicode.net
+[submodule "Libraries/WindowsCommunityToolkit"]
+ path = Libraries/WindowsCommunityToolkit
+ url = https://github.com/UnicordDev/WindowsCommunityToolkit
diff --git a/Assets/ClydeLogo.svg b/Assets/ClydeLogo.svg
index d416f12c..61412072 100644
--- a/Assets/ClydeLogo.svg
+++ b/Assets/ClydeLogo.svg
@@ -1,16 +1,49 @@
-
+
-
diff --git a/Assets/batchbuildmenu.png b/Assets/batchbuildmenu.png
new file mode 100644
index 00000000..b6bd5e14
Binary files /dev/null and b/Assets/batchbuildmenu.png differ
diff --git a/Assets/canarylauncher.png b/Assets/canarylauncher.png
new file mode 100644
index 00000000..e8d0e937
Binary files /dev/null and b/Assets/canarylauncher.png differ
diff --git a/Assets/promo1.png b/Assets/promo1.png
index 5903e6a6..8eb91bf7 100644
Binary files a/Assets/promo1.png and b/Assets/promo1.png differ
diff --git a/InboxThemes/compact.uni-theme b/InboxThemes/compact.uni-theme
deleted file mode 100644
index 9b47dcd5..00000000
Binary files a/InboxThemes/compact.uni-theme and /dev/null differ
diff --git a/InboxThemes/compact/Theme.xaml b/InboxThemes/compact/Theme.xaml
deleted file mode 100644
index fddc740a..00000000
--- a/InboxThemes/compact/Theme.xaml
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/InboxThemes/compact/images/logo.png b/InboxThemes/compact/images/logo.png
deleted file mode 100644
index 1d599ff0..00000000
Binary files a/InboxThemes/compact/images/logo.png and /dev/null differ
diff --git a/InboxThemes/compact/theme.json b/InboxThemes/compact/theme.json
deleted file mode 100644
index 3abc3774..00000000
--- a/InboxThemes/compact/theme.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "name": "Compact",
- "short_description": "Shrinks controls across the board making the whole of Unicord a little more compact.",
- "author": "WamWooWam",
- "display_logo": "images/logo.png",
- "use_compact": true
-}
\ No newline at end of file
diff --git a/InboxThemes/forest.uni-theme b/InboxThemes/forest.uni-theme
deleted file mode 100644
index 52d837f3..00000000
Binary files a/InboxThemes/forest.uni-theme and /dev/null differ
diff --git a/InboxThemes/forest/Theme.xaml b/InboxThemes/forest/Theme.xaml
deleted file mode 100644
index 46a21605..00000000
--- a/InboxThemes/forest/Theme.xaml
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
-
-
-
-
- #CC353819
- #FF353819
- #FF532215
- #FF784834
- #FF353819
-
-
-
-
-
-
-
-
- #CCF7FFFF
- #FFF7FFFF
- #FFDFEEAA
- #FFC2DB65
-
- #FFF7FFFF
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/InboxThemes/forest/images/logo.png b/InboxThemes/forest/images/logo.png
deleted file mode 100644
index e63b7ede..00000000
Binary files a/InboxThemes/forest/images/logo.png and /dev/null differ
diff --git a/InboxThemes/forest/theme.json b/InboxThemes/forest/theme.json
deleted file mode 100644
index d4b45ecd..00000000
--- a/InboxThemes/forest/theme.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "name": "Forest",
- "short_description": "Green and Brown.",
- "author": "WamWooWam",
- "display_colour": "#FF34854D",
- "display_logo": "images/logo.png",
- "contract_checks": {
- "Windows.Foundation.UniversalApiContract": 7
- }
-}
\ No newline at end of file
diff --git a/InboxThemes/lavender.uni-theme b/InboxThemes/lavender.uni-theme
deleted file mode 100644
index 60276801..00000000
Binary files a/InboxThemes/lavender.uni-theme and /dev/null differ
diff --git a/InboxThemes/lavender/Theme.xaml b/InboxThemes/lavender/Theme.xaml
deleted file mode 100644
index 325baffb..00000000
--- a/InboxThemes/lavender/Theme.xaml
+++ /dev/null
@@ -1,47 +0,0 @@
-
-
-
-
-
-
-
- #CC262738
- #FF262738
- #FF3F2E4B
- #FF64576B
- #FF262738
-
-
-
-
-
-
-
-
- #CCFEF6FF
- #FFFEF6FF
- #FFFBE4FF
- #FFEECEFF
-
- #FFFEF6FF
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/InboxThemes/lavender/images/logo.png b/InboxThemes/lavender/images/logo.png
deleted file mode 100644
index e63b7ede..00000000
Binary files a/InboxThemes/lavender/images/logo.png and /dev/null differ
diff --git a/InboxThemes/lavender/theme.json b/InboxThemes/lavender/theme.json
deleted file mode 100644
index 68e4e6a2..00000000
--- a/InboxThemes/lavender/theme.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "name": "Lavender",
- "short_description": "Purple.",
- "author": "WamWooWam",
- "display_colour": "#FF8961CC",
- "display_logo": "images/logo.png",
- "contract_checks": {
- "Windows.Foundation.UniversalApiContract": 7
- }
-}
\ No newline at end of file
diff --git a/InboxThemes/luna.uni-theme b/InboxThemes/luna.uni-theme
deleted file mode 100644
index 70ae7f75..00000000
Binary files a/InboxThemes/luna.uni-theme and /dev/null differ
diff --git a/InboxThemes/luna/Theme.xaml b/InboxThemes/luna/Theme.xaml
deleted file mode 100644
index 908caceb..00000000
--- a/InboxThemes/luna/Theme.xaml
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
-
-
-
-
- #CC0D2644
- #FF0D2644
- #FF134B82
- #FF2F7BAD
- #FF0D2644
-
-
-
-
-
-
-
-
- #CCCFEAFF
- #FFCFEAFF
- #FFB3E0F8
- #FF7CBEE0
-
- #FFCFEAFF
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/InboxThemes/luna/images/logo.png b/InboxThemes/luna/images/logo.png
deleted file mode 100644
index 34431f76..00000000
Binary files a/InboxThemes/luna/images/logo.png and /dev/null differ
diff --git a/InboxThemes/luna/theme.json b/InboxThemes/luna/theme.json
deleted file mode 100644
index 3a3b14c4..00000000
--- a/InboxThemes/luna/theme.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "name": "Luna",
- "short_description": "Blue.",
- "author": "WamWooWam",
- "display_colour": "#FFCC4D11",
- "display_logo": "images/logo.png",
- "contract_checks": {
- "Windows.Foundation.UniversalApiContract": 7
- }
-}
\ No newline at end of file
diff --git a/InboxThemes/no-transparency.uni-theme b/InboxThemes/no-transparency.uni-theme
deleted file mode 100644
index 1e0a75d2..00000000
Binary files a/InboxThemes/no-transparency.uni-theme and /dev/null differ
diff --git a/InboxThemes/no-transparency/RevealBrush_rs1_themeresources.xaml b/InboxThemes/no-transparency/RevealBrush_rs1_themeresources.xaml
deleted file mode 100644
index 0b36bd81..00000000
--- a/InboxThemes/no-transparency/RevealBrush_rs1_themeresources.xaml
+++ /dev/null
@@ -1,1064 +0,0 @@
-
-
-
-
-
-
- #F2000000
- #30000000
- #91000000
- #C2000000
- #61000000
- #F2FFFFFF
- #30FFFFFF
- #91FFFFFF
- #C2FFFFFF
- #61FFFFFF
- #F2F9F9F9
- #F2000000
- #30000000
- #61000000
- #C2000000
- #F2767676
- #F21F1F1F
- #F2393939
- #F22B2B2B
- #F2FFFFFF
- #F2767676
- #18FFFFFF
- #30FFFFFF
-
- #08FFFFFF
- #5DFFFFFF
- #3FFFFFFF
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
- 1
- 1
- 0
- 0
- 0
- 0
- 0
- 0
- 11,5,11,7
- 11,11,11,13
- 11,11,11,13
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- True
-
-
-
-
- #E6FFFFFF
- #2EFFFFFF
- #8AFFFFFF
- #B8FFFFFF
- #61FFFFFF
- #E6000000
- #2E000000
- #8A000000
- #B8000000
- #61000000
- #E6171717
- #E6000000
- #2E000000
- #66000000
- #B8000000
- #E6CCCCCC
- #E6F2F2F2
- #E6E6E6E6
- #E6F2F2F2
- #E6FFFFFF
- #E6767676
- #17000000
- #2E000000
-
- #4DF9F9F9
- #5C000000
- #51000000
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
- 1
- 1
- 0
- 0
- 0
- 0
- 0
- 0
- 11,5,11,7
- 11,11,11,13
- 11,11,11,13
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- True
-
-
-
-
- #FF000000
- #33000000
- #99000000
- #CC000000
- #66000000
- #FFFFFFFF
- #33FFFFFF
- #99FFFFFF
- #CCFFFFFF
- #66FFFFFF
- #FFF9F9F9
- #FF000000
- #33000000
- #66000000
- #CC000000
- #FF767676
- #FF1F1F1F
- #FF393939
- #FF2B2B2B
- #FFFFFFFF
- #FF767676
- #19FFFFFF
- #33FFFFFF
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
- 1
- 1
- 0
- 0
- 0
- 0
- 0
- 0
- 11,5,11,7
- 11,11,11,13
- 11,11,11,13
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- True
-
-
-
-
- 14,19,14,0
- 16
- 56
- 40
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/InboxThemes/no-transparency/Theme.xaml b/InboxThemes/no-transparency/Theme.xaml
deleted file mode 100644
index 4f2cff5b..00000000
--- a/InboxThemes/no-transparency/Theme.xaml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/InboxThemes/no-transparency/images/logo.png b/InboxThemes/no-transparency/images/logo.png
deleted file mode 100644
index 34431f76..00000000
Binary files a/InboxThemes/no-transparency/images/logo.png and /dev/null differ
diff --git a/InboxThemes/no-transparency/theme.json b/InboxThemes/no-transparency/theme.json
deleted file mode 100644
index b02f6852..00000000
--- a/InboxThemes/no-transparency/theme.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "Reduce Transparency",
- "short_description": "Removes acrylic transparency and reveal from sidebars and buttons.",
- "author": "WamWooWam",
- "display_logo": "images/logo.png"
-}
\ No newline at end of file
diff --git a/InboxThemes/oled.uni-theme b/InboxThemes/oled.uni-theme
deleted file mode 100644
index 65ed1146..00000000
Binary files a/InboxThemes/oled.uni-theme and /dev/null differ
diff --git a/InboxThemes/oled/Theme.xaml b/InboxThemes/oled/Theme.xaml
deleted file mode 100644
index 55c83ef1..00000000
--- a/InboxThemes/oled/Theme.xaml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/InboxThemes/oled/images/logo.png b/InboxThemes/oled/images/logo.png
deleted file mode 100644
index 34431f76..00000000
Binary files a/InboxThemes/oled/images/logo.png and /dev/null differ
diff --git a/InboxThemes/oled/theme.json b/InboxThemes/oled/theme.json
deleted file mode 100644
index 9b47d386..00000000
--- a/InboxThemes/oled/theme.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "OLED",
- "short_description": "Black backgrounds to save you battery!",
- "author": "WamWooWam",
- "display_logo": "images/logo.png"
-}
\ No newline at end of file
diff --git a/InboxThemes/square/Theme.xaml b/InboxThemes/square/Theme.xaml
deleted file mode 100644
index 4edc7f3a..00000000
--- a/InboxThemes/square/Theme.xaml
+++ /dev/null
@@ -1,191 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/InboxThemes/square/images/logo.png b/InboxThemes/square/images/logo.png
deleted file mode 100644
index 4850366d..00000000
Binary files a/InboxThemes/square/images/logo.png and /dev/null differ
diff --git a/InboxThemes/square/theme.json b/InboxThemes/square/theme.json
deleted file mode 100644
index d3f00bb9..00000000
--- a/InboxThemes/square/theme.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "name": "Square",
- "short_description": "Compact and square.",
- "author": "WamWooWam",
- "display_logo": "images/logo.png",
- "use_compact": true
-}
\ No newline at end of file
diff --git a/InboxThemes/white.uni-theme b/InboxThemes/white.uni-theme
deleted file mode 100644
index 1c05f3ba..00000000
Binary files a/InboxThemes/white.uni-theme and /dev/null differ
diff --git a/InboxThemes/white/Theme.xaml b/InboxThemes/white/Theme.xaml
deleted file mode 100644
index 9b20f81f..00000000
--- a/InboxThemes/white/Theme.xaml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
- #FFFFFFFF
-
-
-
-
-
\ No newline at end of file
diff --git a/InboxThemes/white/images/logo.png b/InboxThemes/white/images/logo.png
deleted file mode 100644
index 34431f76..00000000
Binary files a/InboxThemes/white/images/logo.png and /dev/null differ
diff --git a/InboxThemes/white/theme.json b/InboxThemes/white/theme.json
deleted file mode 100644
index d1afc251..00000000
--- a/InboxThemes/white/theme.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "White",
- "short_description": "Inverse, Discord like white theme. Does nothing in dark mode.",
- "author": "WamWooWam",
- "display_logo": "images/logo.png"
-}
\ No newline at end of file
diff --git a/Libraries/DSharpPlus b/Libraries/DSharpPlus
index 6cc5aaba..6e42060a 160000
--- a/Libraries/DSharpPlus
+++ b/Libraries/DSharpPlus
@@ -1 +1 @@
-Subproject commit 6cc5aaba9331f5d27826077a1498c58b90514ff7
+Subproject commit 6e42060a963dc1f987d7234453bf25874b85d0ad
diff --git a/Libraries/LocalPackages/microsoft.web.webview2.undocked/1.0.2739.170/.nupkg.metadata b/Libraries/LocalPackages/microsoft.web.webview2.undocked/1.0.2739.170/.nupkg.metadata
new file mode 100644
index 00000000..6f1dcaf4
--- /dev/null
+++ b/Libraries/LocalPackages/microsoft.web.webview2.undocked/1.0.2739.170/.nupkg.metadata
@@ -0,0 +1,5 @@
+{
+ "version": 2,
+ "contentHash": "9P9b9/H315ficqW9u01EJCjKD3QYfxzGXscGHT6lndyrAzkW5iNho28ILC6bYMpgE+G/GNzTij/OVZL9Jxq5mw==",
+ "source": null
+}
\ No newline at end of file
diff --git a/Libraries/LocalPackages/microsoft.web.webview2.undocked/1.0.2739.170/microsoft.web.webview2.undocked.1.0.2739.170.nupkg b/Libraries/LocalPackages/microsoft.web.webview2.undocked/1.0.2739.170/microsoft.web.webview2.undocked.1.0.2739.170.nupkg
new file mode 100644
index 00000000..3617e96e
Binary files /dev/null and b/Libraries/LocalPackages/microsoft.web.webview2.undocked/1.0.2739.170/microsoft.web.webview2.undocked.1.0.2739.170.nupkg differ
diff --git a/Libraries/LocalPackages/microsoft.web.webview2.undocked/1.0.2739.170/microsoft.web.webview2.undocked.1.0.2739.170.nupkg.sha512 b/Libraries/LocalPackages/microsoft.web.webview2.undocked/1.0.2739.170/microsoft.web.webview2.undocked.1.0.2739.170.nupkg.sha512
new file mode 100644
index 00000000..c050b6e7
--- /dev/null
+++ b/Libraries/LocalPackages/microsoft.web.webview2.undocked/1.0.2739.170/microsoft.web.webview2.undocked.1.0.2739.170.nupkg.sha512
@@ -0,0 +1 @@
+9P9b9/H315ficqW9u01EJCjKD3QYfxzGXscGHT6lndyrAzkW5iNho28ILC6bYMpgE+G/GNzTij/OVZL9Jxq5mw==
\ No newline at end of file
diff --git a/Libraries/LocalPackages/microsoft.web.webview2.undocked/1.0.2739.170/microsoft.web.webview2.undocked.nuspec b/Libraries/LocalPackages/microsoft.web.webview2.undocked/1.0.2739.170/microsoft.web.webview2.undocked.nuspec
new file mode 100644
index 00000000..7921ab17
--- /dev/null
+++ b/Libraries/LocalPackages/microsoft.web.webview2.undocked/1.0.2739.170/microsoft.web.webview2.undocked.nuspec
@@ -0,0 +1,22 @@
+
+
+
+ Microsoft.Web.WebView2.Undocked
+ 1.0.2739.170
+ Undocked WebView2 Library
+ Microsoft, Kimbra
+ Microsoft
+ false
+ https://aka.ms/deprecateLicenseUrl
+ https://github.com/microsoft/microsoft-ui-xaml
+ https://aka.ms/winui_icon
+ This package provides the WebView2 control, undocked from WinUI 2.8.
+ © Microsoft Corporation. All rights reserved.
+ Windows WinUI UWP XAML Fluent Controls Downlevel Compatibility TreeView ColorPicker NavigationView MenuBar
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Libraries/Native/WebRTC/.gitignore b/Libraries/Native/WebRTC/.gitignore
deleted file mode 100644
index 598946fe..00000000
--- a/Libraries/Native/WebRTC/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-*
-
-!.gitignore
-!WebRTC.vcxproj
-!WebRTC.vcxproj.filters
\ No newline at end of file
diff --git a/Libraries/Native/WebRTC/WebRTC.vcxproj b/Libraries/Native/WebRTC/WebRTC.vcxproj
deleted file mode 100644
index dcca7cc1..00000000
--- a/Libraries/Native/WebRTC/WebRTC.vcxproj
+++ /dev/null
@@ -1,360 +0,0 @@
-
-
-
-
- Debug
- ARM
-
-
- Debug
- ARM64
-
-
- Debug
- Win32
-
-
- Debug
- x64
-
-
- Release
- ARM
-
-
- Release
- ARM64
-
-
- Release
- Win32
-
-
- Release
- x64
-
-
-
- {0cae67e6-bf85-4274-a665-12b44c4cd994}
- DynamicLibrary
- WebRTC
- en-US
- 14.0
- true
- Windows Store
- 10.0
- 10.0.19041.0
- 10.0
-
-
-
- StaticLibrary
- true
- v142
-
-
- StaticLibrary
- true
- v142
-
-
- StaticLibrary
- true
- v142
-
-
- StaticLibrary
- true
- v142
-
-
- StaticLibrary
- false
- true
- v142
-
-
- StaticLibrary
- false
- true
- v142
-
-
- StaticLibrary
- false
- true
- v142
-
-
- StaticLibrary
- false
- true
- v142
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- false
- false
-
-
- false
- false
-
-
- false
- false
-
-
- false
- false
-
-
- false
- false
-
-
- false
- false
-
-
- false
- false
-
-
- false
- false
-
-
-
- Use
- false
-
-
- Console
- false
- false
-
-
- set PATH=C:\Python27;%PATH%
-call C:\Python27\python.exe "$(ProjectDir)..\webrtc-uwp-sdk\scripts\run.py" -a prepare build -t webrtc -p winuwp --cpus $(PlatformTarget) -c $(Configuration) --noColor --noWrapper
-
-
- Building WebRTC Native Lib
-
-
-
-
-
-
- Building WebRTC Native Lib
-
-
-
-
- Use
- false
-
-
- Console
- false
- false
-
-
- set PATH=C:\Python27;%PATH%
-call C:\Python27\python.exe "$(ProjectDir)..\webrtc-uwp-sdk\scripts\run.py" -a prepare build -t webrtc -p winuwp --cpus $(PlatformTarget) -c $(Configuration) --noColor --noWrapper
-
-
- Building WebRTC Native Lib
-
-
-
-
-
-
- Building WebRTC Native Lib
-
-
-
-
- Use
- false
-
-
- Console
- false
- false
-
-
- set PATH=C:\Python27;%PATH%
-call C:\Python27\python.exe "$(ProjectDir)..\webrtc-uwp-sdk\scripts\run.py" -a prepare build -t webrtc -p winuwp --cpus $(PlatformTarget) -c $(Configuration) --noColor --noWrapper
-
-
- Building WebRTC Native Lib
-
-
-
-
-
-
- Building WebRTC Native Lib
-
-
-
-
- Use
- false
-
-
- Console
- false
- false
-
-
- set PATH=C:\Python27;%PATH%
-call C:\Python27\python.exe "$(ProjectDir)..\webrtc-uwp-sdk\scripts\run.py" -a prepare build -t webrtc -p winuwp --cpus $(PlatformTarget) -c $(Configuration) --noColor --noWrapper
-
-
- Building WebRTC Native Lib
-
-
-
-
-
-
- Building WebRTC Native Lib
-
-
-
-
- Use
- false
-
-
- Console
- false
- false
-
-
- set PATH=C:\Python27;%PATH%
-call C:\Python27\python.exe "$(ProjectDir)..\webrtc-uwp-sdk\scripts\run.py" -a prepare build -t webrtc -p winuwp --cpus $(PlatformTarget) -c $(Configuration) --noColor --noWrapper
-
-
- Building WebRTC Native Lib
-
-
-
-
-
-
- Building WebRTC Native Lib
-
-
-
-
- Use
- false
-
-
- Console
- false
- false
-
-
- set PATH=C:\Python27;%PATH%
-call C:\Python27\python.exe "$(ProjectDir)..\webrtc-uwp-sdk\scripts\run.py" -a prepare build -t webrtc -p winuwp --cpus $(PlatformTarget) -c $(Configuration) --noColor --noWrapper
-
-
- Building WebRTC Native Lib
-
-
-
-
-
-
- Building WebRTC Native Lib
-
-
-
-
- Use
- false
-
-
- Console
- false
- false
-
-
- set PATH=C:\Python27;%PATH%
-call C:\Python27\python.exe "$(ProjectDir)..\webrtc-uwp-sdk\scripts\run.py" -a prepare build -t webrtc -p winuwp --cpus $(PlatformTarget) -c $(Configuration) --noColor --noWrapper
-
-
- Building WebRTC Native Lib
-
-
-
-
-
-
- Building WebRTC Native Lib
-
-
-
-
- Use
- false
-
-
- Console
- false
- false
-
-
- set PATH=C:\Python27;%PATH%
-call C:\Python27\python.exe "$(ProjectDir)..\webrtc-uwp-sdk\scripts\run.py" -a prepare build -t webrtc -p winuwp --cpus $(PlatformTarget) -c $(Configuration) --noColor --noWrapper
-
-
- Building WebRTC Native Lib
-
-
-
-
-
-
- Building WebRTC Native Lib
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Libraries/Native/WebRTC/WebRTC.vcxproj.filters b/Libraries/Native/WebRTC/WebRTC.vcxproj.filters
deleted file mode 100644
index 2c12610d..00000000
--- a/Libraries/Native/WebRTC/WebRTC.vcxproj.filters
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
- {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
- rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms
-
-
-
\ No newline at end of file
diff --git a/Libraries/Native/libsodium b/Libraries/Native/libsodium
deleted file mode 160000
index 150a4fbe..00000000
--- a/Libraries/Native/libsodium
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 150a4fbe1eba277bfe52b139b999d8e6969fd37c
diff --git a/Libraries/Native/opus b/Libraries/Native/opus
deleted file mode 160000
index 91faa0a2..00000000
--- a/Libraries/Native/opus
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 91faa0a2580cf769ee139092a2181fa612b85424
diff --git a/Libraries/Native/webrtc-uwp-sdk b/Libraries/Native/webrtc-uwp-sdk
deleted file mode 160000
index 63927ce9..00000000
--- a/Libraries/Native/webrtc-uwp-sdk
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 63927ce91574280731488995101d3868c9843453
diff --git a/Libraries/WamWooWam.Core b/Libraries/WamWooWam.Core
index cf68b689..91fae8a9 160000
--- a/Libraries/WamWooWam.Core
+++ b/Libraries/WamWooWam.Core
@@ -1 +1 @@
-Subproject commit cf68b6892c083626b488389aa228360ec98d89e5
+Subproject commit 91fae8a9aca471c47f2b864ef8c68c048357b1c5
diff --git a/Libraries/WindowsCommunityToolkit b/Libraries/WindowsCommunityToolkit
new file mode 160000
index 00000000..e7117dec
--- /dev/null
+++ b/Libraries/WindowsCommunityToolkit
@@ -0,0 +1 @@
+Subproject commit e7117dec571c8b46857a152de94072e8121c51de
diff --git a/Libraries/unicode.net b/Libraries/unicode.net
index 1dcfc5c0..a588fcb5 160000
--- a/Libraries/unicode.net
+++ b/Libraries/unicode.net
@@ -1 +1 @@
-Subproject commit 1dcfc5c0851132021bd34cb0dae4a613f3a4efa0
+Subproject commit a588fcb5cb6d38ab3c17046406c5546fe8d02cd6
diff --git a/README.md b/README.md
index 4e37a6b5..7080a99c 100644
--- a/README.md
+++ b/README.md
@@ -1,36 +1,41 @@
# Unicord
-A free, open source Discord Client for Windows 10 and Windows 10 Mobile, that tries to provide a fast, efficient, native feeling Discord experience, while adding handy extras along the way. Built on [DSharpPlus](https://github.com/DSharpPlus/DSharpPlus/)!
+A free, open source Discord Client for Windows 10 and Windows 10 Mobile, providing a fast, efficient, native feeling Discord experience, while adding handy extras along the way. Built on [DSharpPlus](https://github.com/DSharpPlus/DSharpPlus/)!
[](https://dev.azure.com/WanKerrCoLtd/Unicord/_build/latest?definitionId=4&branchName=master)
-
+
+
+## Downloads
+See the [latest release](https://github.com/UnicordDev/Unicord/releases)!
## Getting Started
So you wanna build Unicord, well you're gonna need to have a few things handy.
### Prerequisites
- - Windows 10 build 1809+
- - Visual Studio 2017/2019 (with UWP tooling for both .NET and C++)
- - Windows 10 SDK build 17763+ (subject to change)
+ - Windows 11 (Build 22000+)
+ - Windows 11 SDK Build 26100
+ - Visual Studio 2022 or later
+ - Universal Windows Platform tools
+ - For Visual Studio < `17.10`, Select `Universal Windows Platform Workload`
+ - For Visual Studio >= `17.10`, Select `WinUI Application Development Workload` and `Installation details`->`WinUI application development`->`Optional`->`Universal Windows Platform tools`
### Building and Installing
-Firstly, as with all GitHub projects, you'll want to clone the repo, but you will also need to pull submodules, to do this, use:
+By default, cloning a repository through Visual Studio should handle submodules, but for the sake of completeness and as with all GitHub projects, you'll also need to pull submodules.
+To do this, use:
+```sh
+$ git submodule update --init --recursive
```
-git submodule update --recursive
-```
-Or if it doesn't work
-```
-git submodule update --init --recursive
-```
-From here, building should be as simple as double clicking `Unicord.sln`, ensuring your targets are appropriate to your testing platform (i.e. Debug x64), and hitting F5. Once built and deployed, it should show in your start menu as "Unicord Canary", data and settings are kept separate from the Store version, so they can be installed side by side.
-
+From here, building should be as simple as double clicking `Unicord.sln`, ensuring your targets are appropriate to your testing platform (i.e. Debug x64), and hitting F5.
+Once built and deployed, it should show in your start menu as "Unicord Canary", data and settings are kept separate from the Store version, so they can be installed side by side.
+
+
## Testing
Unicord currently lacks any kind of unit testing. This will likely change as I adopt a more sane workflow, but for now, I suggest going around the app and making sure everything you'd use regularly works, and ensuring all configurations build. A handy way of doing this, is Visual Studio's Batch Build feature, accessible like so:
-
+
On one specific note, while the project technically targets a minimum of Windows 10 version 1709 (Fall Creators Update), all code should compile and run on version 170**3** (Creators Update) to maintain Windows Phone support. Please pay special attention to the minimum required Windows version when consuming UWP APIs, and be careful when consuming .NET Standard 2.0 APIs, which may require a newer Windows version.
@@ -39,6 +44,7 @@ Unicord accepts contributions! Want a feature that doesn't already exist? Feel f
## Get in Touch
We have a Discord server specifically for Unicord development and testing, join here:
+
[](https://discord.gg/64g7M5Y)
## License
diff --git a/Unicord.Universal.Background.Tasks/PeriodicNotificationsTask.cs b/Unicord.Universal.Background.Tasks/PeriodicNotificationsTask.cs
new file mode 100644
index 00000000..21051923
--- /dev/null
+++ b/Unicord.Universal.Background.Tasks/PeriodicNotificationsTask.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using DSharpPlus;
+using Unicord.Universal.Shared;
+using Windows.ApplicationModel.Background;
+using Windows.Security.Credentials;
+using Windows.UI.Notifications;
+
+namespace Unicord.Universal.Background.Tasks
+{
+ public sealed class PeriodicNotificationsTask : IBackgroundTask
+ {
+ public async void Run(IBackgroundTaskInstance taskInstance)
+ {
+ var deferral = taskInstance.GetDeferral();
+ try
+ {
+ if (!TryGetToken(out string token))
+ return;
+
+ var tileUpdateManager = TileUpdateManager.CreateTileUpdaterForApplication();
+ var toastNotifier = ToastNotificationManager.CreateToastNotifier();
+
+ var restClient = new DiscordRestClient(new DiscordConfiguration() { Token = token, TokenType = TokenType.User });
+ await restClient.InitializeAsync();
+
+ var mentions = await restClient.GetUserMentionsAsync(25, true, true);
+
+ foreach (var mention in mentions)
+ {
+ if (!NotificationUtils.WillShowToast(restClient, mention))
+ continue;
+
+ var tileNotification = NotificationUtils.CreateTileNotificationForMessage(restClient, mention);
+ var toastNotification = NotificationUtils.CreateToastNotificationForMessage(restClient, mention);
+
+ tileUpdateManager.Update(tileNotification);
+ toastNotifier.Show(toastNotification);
+ }
+ }
+ finally
+ {
+ deferral.Complete();
+ }
+ }
+
+ internal static bool TryGetToken(out string token)
+ {
+ try
+ {
+ var passwordVault = new PasswordVault();
+ var credential = passwordVault.Retrieve(Constants.TOKEN_IDENTIFIER, "Default");
+ credential.RetrievePassword();
+
+ token = credential.Password;
+ return true;
+ }
+ catch { }
+
+ token = null;
+ return false;
+ }
+ }
+}
diff --git a/Unicord.Universal.Background.Tasks/Properties/AssemblyInfo.cs b/Unicord.Universal.Background.Tasks/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..e0fc5154
--- /dev/null
+++ b/Unicord.Universal.Background.Tasks/Properties/AssemblyInfo.cs
@@ -0,0 +1,26 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+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("Unicord.Universal.Background.Tasks")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Unicord.Universal.Background.Tasks")]
+[assembly: AssemblyCopyright("Copyright © 2024")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: ComVisible(false)]
diff --git a/Unicord.Universal.Background.Tasks/RealtimeNotificationsTask.cs b/Unicord.Universal.Background.Tasks/RealtimeNotificationsTask.cs
new file mode 100644
index 00000000..5e286dbe
--- /dev/null
+++ b/Unicord.Universal.Background.Tasks/RealtimeNotificationsTask.cs
@@ -0,0 +1,158 @@
+using System;
+using System.Diagnostics;
+using System.Threading.Tasks;
+using DSharpPlus;
+using DSharpPlus.Entities;
+using DSharpPlus.EventArgs;
+using Unicord.Universal.Shared;
+using Windows.ApplicationModel.Background;
+using Windows.Security.Credentials;
+
+namespace Unicord.Universal.Background.Tasks
+{
+ public sealed class RealtimeNotificationsTask : IBackgroundTask
+ {
+ private BackgroundTaskDeferral _deferral;
+ private DiscordClient _discord;
+ private BadgeManager _badgeManager;
+ private TileManager _tileManager;
+ private SecondaryTileManager _secondaryTileManager;
+ private ToastManager _toastManager;
+
+ public async void Run(IBackgroundTaskInstance taskInstance)
+ {
+ _deferral = taskInstance.GetDeferral();
+
+ try
+ {
+ if (!TryGetToken(out string token))
+ {
+ _deferral.Complete();
+ return;
+ }
+
+ _discord = new DiscordClient(new DiscordConfiguration()
+ {
+ TokenType = TokenType.User,
+ Token = token,
+ MessageCacheSize = 16,
+ ReconnectIndefinitely = true
+ });
+
+ _badgeManager = new BadgeManager(_discord);
+ _tileManager = new TileManager(_discord);
+ _secondaryTileManager = new SecondaryTileManager(_discord);
+ _toastManager = new ToastManager();
+
+ _discord.Ready += OnReady;
+ _discord.Resumed += OnResumed;
+ _discord.MessageCreated += OnDiscordMessage;
+ _discord.MessageUpdated += OnMessageUpdated;
+ _discord.MessageAcknowledged += OnMessageAcknowledged;
+
+ await _discord.ConnectAsync(status: UserStatus.Invisible, idlesince: DateTimeOffset.Now);
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine(ex);
+ _deferral.Complete();
+ }
+ }
+
+ private async Task OnReady(DiscordClient client, ReadyEventArgs e)
+ {
+ await _tileManager.InitialiseAsync();
+ _badgeManager.Update();
+
+ _ = Task.Run(GCTask);
+ }
+
+ private Task OnResumed(DiscordClient sender, ResumedEventArgs args)
+ {
+ _ = Task.Run(GCTask);
+ return Task.CompletedTask;
+ }
+
+ private async Task GCTask()
+ {
+ await Task.Delay(5000);
+ GC.Collect(2, GCCollectionMode.Forced, true, true);
+ }
+
+ private async Task OnDiscordMessage(DiscordClient client, MessageCreateEventArgs e)
+ {
+ try
+ {
+ if (NotificationUtils.WillShowToast(client, e.Message))
+ {
+ _toastManager?.HandleMessage(client, e.Message, false);
+ _badgeManager?.Update();
+
+ if (_tileManager != null)
+ await _tileManager.HandleMessageAsync(e.Message);
+ }
+
+ if (_secondaryTileManager != null)
+ await _secondaryTileManager.HandleMessageAsync(client, e.Message);
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine(ex);
+ }
+ }
+
+ private Task OnMessageUpdated(DiscordClient client, MessageUpdateEventArgs e)
+ {
+ try
+ {
+ if (NotificationUtils.WillShowToast(client, e.Message))
+ {
+ _toastManager?.HandleMessageUpdated(client, e.Message);
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine(ex);
+ }
+
+ return Task.CompletedTask;
+ }
+
+ private async Task OnMessageAcknowledged(DiscordClient client, MessageAcknowledgeEventArgs e)
+ {
+ try
+ {
+ _badgeManager?.Update();
+ _toastManager?.HandleAcknowledge(e.Channel);
+
+ if (_tileManager != null)
+ await _tileManager.HandleAcknowledgeAsync(e.Channel);
+
+ if (_secondaryTileManager != null)
+ await _secondaryTileManager.HandleAcknowledgeAsync(e.Channel);
+ }
+ catch (Exception ex)
+ {
+ // TODO: log
+ Debug.WriteLine(ex);
+ }
+ }
+
+ internal static bool TryGetToken(out string token)
+ {
+ try
+ {
+ var passwordVault = new PasswordVault();
+ var credential = passwordVault.Retrieve(Constants.TOKEN_IDENTIFIER, "Default");
+ credential.RetrievePassword();
+
+ token = credential.Password;
+ return true;
+ }
+ catch { }
+
+ token = null;
+ return false;
+ }
+ }
+}
diff --git a/Unicord.Universal.Background.Tasks/Unicord.Universal.Background.Tasks.csproj b/Unicord.Universal.Background.Tasks/Unicord.Universal.Background.Tasks.csproj
new file mode 100644
index 00000000..57aaf249
--- /dev/null
+++ b/Unicord.Universal.Background.Tasks/Unicord.Universal.Background.Tasks.csproj
@@ -0,0 +1,167 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {69F44648-37CD-4B20-8814-2BAF85B4F624}
+ winmdobj
+ Properties
+ Unicord.Universal.Background.Tasks
+ Unicord.Universal.Background.Tasks
+ en-US
+ UAP
+ 10.0.22621.0
+ 10.0.16299.0
+ 14
+ 512
+ {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ false
+ 9
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ prompt
+ 4
+
+
+ x86
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ false
+ prompt
+
+
+ x86
+ bin\x86\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ false
+ prompt
+
+
+ ARM
+ true
+ bin\ARM\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ false
+ prompt
+
+
+ ARM
+ bin\ARM\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ false
+ prompt
+
+
+ ARM64
+ true
+ bin\ARM64\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ false
+ prompt
+
+
+ ARM64
+ bin\ARM64\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ false
+ prompt
+
+
+ x64
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ false
+ prompt
+
+
+ x64
+ bin\x64\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ false
+ prompt
+
+
+ PackageReference
+
+
+
+
+
+
+
+
+ 6.2.14
+
+
+ 7.1.3
+
+
+
+
+ {c01b8589-13fe-4a6d-b159-6644977f58de}
+ DSharpPlus.Rest
+
+
+ {0f4b3af7-9320-41ae-82d0-3737949499c7}
+ DSharpPlus
+
+
+ {8a4a933c-c579-4c36-9133-7d6721f99aec}
+ MomentSharp
+
+
+ {6e8e3c2c-a7d2-4971-a97d-fa831e3ecf15}
+ WamWooWam.Core
+
+
+
+
+ 14.0
+
+
+
+
\ No newline at end of file
diff --git a/Unicord.Universal.Background/App.config b/Unicord.Universal.Background/App.config
new file mode 100644
index 00000000..105b86a6
--- /dev/null
+++ b/Unicord.Universal.Background/App.config
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Unicord.Universal.Background/NativeMethods.txt b/Unicord.Universal.Background/NativeMethods.txt
new file mode 100644
index 00000000..4b19cea6
--- /dev/null
+++ b/Unicord.Universal.Background/NativeMethods.txt
@@ -0,0 +1,14 @@
+EnumWindows
+FindWindowEx
+IsWindowVisible
+IsIconic
+GetClassName
+GetWindowThreadProcessId
+OpenProcess
+CloseHandle
+GetPackageFullName
+GetCurrentPackageFullName
+DwmGetWindowAttribute
+DwmSetWindowAttribute
+WIN32_ERROR
+MAX_PATH
diff --git a/Unicord.Universal.Background/NotificationApplicationContext.cs b/Unicord.Universal.Background/NotificationApplicationContext.cs
index 5a2b8444..2f600876 100644
--- a/Unicord.Universal.Background/NotificationApplicationContext.cs
+++ b/Unicord.Universal.Background/NotificationApplicationContext.cs
@@ -1,189 +1,258 @@
-using System;
-using System.Diagnostics;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-using DSharpPlus;
-using DSharpPlus.Entities;
-using DSharpPlus.EventArgs;
-using Unicord.Universal.Shared;
-using Windows.Storage;
-using NotificationUtils = Unicord.Universal.Shared.NotificationUtils;
-
-namespace Unicord.Universal.Background
-{
- class NotificationApplicationContext : ApplicationContext
- {
- private DiscordClient _discord = null;
- private BadgeManager _badgeManager = null;
- private TileManager _tileManager;
- private SecondaryTileManager _secondaryTileManager;
- private ToastManager _toastManager = null;
-
- private NotifyIcon _notifyIcon;
- private ContextMenuStrip _contextMenu;
- private ToolStripMenuItem _openMenuItem;
- private ToolStripMenuItem _closeMenuItem;
-
- private Task _connectTask;
- private string _token = null;
-
- public NotificationApplicationContext()
- {
- Application.ApplicationExit += OnApplicationExit;
-
- if (!TryGetToken(out _token))
- {
- ExitThread();
- }
-
- _notifyIcon = new NotifyIcon();
- _notifyIcon.Icon = Properties.Resources.TrayIcon;
- _notifyIcon.Text = "Unicord";
-
- _contextMenu = new ContextMenuStrip();
- _contextMenu.SuspendLayout();
-
- _openMenuItem = new ToolStripMenuItem("Open Unicord");
- _openMenuItem.Click += OnOpenMenuItemClicked;
- _contextMenu.Items.Add(_openMenuItem);
-
- _contextMenu.Items.Add(new ToolStripSeparator());
-
- _closeMenuItem = new ToolStripMenuItem("Close");
- _closeMenuItem.Click += OnCloseMenuItemClicked;
- _contextMenu.Items.Add(_closeMenuItem);
-
- _contextMenu.ResumeLayout(false);
- _notifyIcon.ContextMenuStrip = _contextMenu;
-
- _connectTask = Task.Run(async () => await InitialiseAsync());
- _notifyIcon.Visible = true;
- }
-
- private void OnOpenMenuItemClicked(object sender, EventArgs e)
- {
- Process.Start("unicord:");
- }
-
- private void OnCloseMenuItemClicked(object sender, EventArgs e)
- {
- this.ExitThread();
- }
-
- private async Task InitialiseAsync()
- {
- try
- {
- _discord = new DiscordClient(new DiscordConfiguration()
- {
- LogLevel = LogLevel.Debug,
- TokenType = TokenType.User,
- Token = _token,
- MessageCacheSize = 0,
- UseInternalLogHandler = true
- });
-
- _badgeManager = new BadgeManager(_discord);
- _tileManager = new TileManager(_discord);
- _secondaryTileManager = new SecondaryTileManager(_discord);
- _toastManager = new ToastManager();
-
- _discord.Ready += OnReady;
- _discord.MessageCreated += OnDiscordMessage;
- _discord.MessageAcknowledged += OnMessageAcknowledged;
-
- await _discord.ConnectAsync(status: UserStatus.Invisible, idlesince: DateTimeOffset.Now);
- }
- catch (Exception)
- {
- this.ExitThread();
- }
- }
-
- private void OnApplicationExit(object sender, EventArgs e)
- {
- if (_discord != null)
- _discord.DisconnectAsync().GetAwaiter().GetResult();
-
- if (_notifyIcon != null)
- {
- _notifyIcon.Visible = false;
- _notifyIcon.Dispose();
- }
- }
-
- private async Task OnReady(ReadyEventArgs e)
- {
- await _tileManager.InitialiseAsync();
- }
-
- private Task OnDiscordMessage(MessageCreateEventArgs e)
- {
- _ = Task.Run(async () =>
- {
- try
- {
- await Task.Delay(1000);
-
- if (NotificationUtils.WillShowToast(e.Message))
- {
- _toastManager?.HandleMessage(e.Message);
- _badgeManager?.Update();
-
- if (_tileManager != null)
- await _tileManager.HandleMessageAsync(e.Message);
- }
-
- if (_secondaryTileManager != null)
- await _secondaryTileManager.HandleMessageAsync(e.Message);
- }
- catch (Exception)
- {
- // TODO: log
- }
- });
-
- return Task.CompletedTask;
- }
-
- private async Task OnMessageAcknowledged(MessageAcknowledgeEventArgs e)
- {
- try
- {
- _badgeManager?.Update();
- _toastManager?.HandleAcknowledge(e.Channel);
-
- if (_tileManager != null)
- await _tileManager.HandleAcknowledgeAsync(e.Channel);
-
- if (_secondaryTileManager != null)
- await _secondaryTileManager.HandleAcknowledgeAsync(e.Channel);
- }
- catch (Exception)
- {
- // TODO: log
- }
- }
-
- private bool TryGetToken(out string token)
- {
-#if DEBUG // for testing
- var args = Environment.GetCommandLineArgs();
- if (args.Length == 2)
- {
- token = args[1];
- return true;
- }
-#endif
-
- if (ApplicationData.Current.LocalSettings.Values.TryGetValue("Token", out var s))
- {
- token = (string)s;
- return true;
- }
-
- token = null;
- return false;
- }
- }
-}
+using System;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using DSharpPlus;
+using DSharpPlus.Entities;
+using DSharpPlus.EventArgs;
+using Unicord.Universal.Shared;
+using Windows.ApplicationModel;
+using Windows.Storage;
+using Windows.Win32.Foundation;
+using static Windows.Win32.Graphics.Dwm.DWMWINDOWATTRIBUTE;
+using static Windows.Win32.PInvoke;
+
+namespace Unicord.Universal.Background
+{
+ class NotificationApplicationContext : ApplicationContext
+ {
+ private DiscordClient _discord = null;
+ private BadgeManager _badgeManager = null;
+ private TileManager _tileManager;
+ private SecondaryTileManager _secondaryTileManager;
+ private ToastManager _toastManager = null;
+
+ private readonly NotifyIcon _notifyIcon;
+ private readonly ContextMenu _contextMenu;
+ private readonly MenuItem _openMenuItem;
+ private readonly MenuItem _closeMenuItem;
+
+ private Task _connectTask;
+ private string _token = null;
+
+ private static readonly FieldInfo _windowField
+ = typeof(NotifyIcon).GetField("window", BindingFlags.NonPublic | BindingFlags.Instance);
+
+ public NotificationApplicationContext()
+ {
+ Application.ApplicationExit += OnApplicationExit;
+
+ if (!TryGetToken(out _token))
+ {
+ ExitThread();
+ }
+
+ _notifyIcon = new NotifyIcon();
+ _notifyIcon.Icon = Properties.Resources.TrayIcon;
+ _notifyIcon.Text = "Unicord";
+ _notifyIcon.DoubleClick += OnOpenMenuItemClicked;
+
+ _contextMenu = new ContextMenu();
+
+ _openMenuItem = new MenuItem("Open Unicord");
+ _openMenuItem.Click += OnOpenMenuItemClicked;
+ _contextMenu.MenuItems.Add(_openMenuItem);
+
+ _contextMenu.MenuItems.Add("-");
+
+ _closeMenuItem = new MenuItem("Close");
+ _closeMenuItem.Click += OnCloseMenuItemClicked;
+ _contextMenu.MenuItems.Add(_closeMenuItem);
+
+ _notifyIcon.ContextMenu = _contextMenu;
+ _notifyIcon.Visible = true;
+
+ EnableDarkMode(_notifyIcon);
+
+ _connectTask = Task.Run(async () => await InitialiseAsync());
+ }
+
+ // here be dragons and awful hacks
+ private void EnableDarkMode(NotifyIcon notifyIcon)
+ {
+ var osVersion = Environment.OSVersion.Version;
+
+ // Windows 10 1809 and later
+ if (osVersion.Major < 10 || osVersion.Build < 17763)
+ return;
+
+ try
+ {
+ var hwnd = new HWND(((NativeWindow)_windowField.GetValue(notifyIcon)).Handle);
+ if (osVersion.Build < 18362)
+ {
+ UxThemePrivate.AllowDarkModeForWindow(hwnd, true);
+ }
+ else
+ {
+ UxThemePrivate.SetPreferredAppMode(UxThemePrivate.PreferredAppMode.AllowDark);
+ }
+
+ UxThemePrivate.FlushMenuThemes();
+ }
+ catch
+ {
+ // ignore this, it doesn't matter
+ }
+ }
+
+ private async void OnOpenMenuItemClicked(object sender, EventArgs e)
+ {
+ var appListEntries = await Package.Current.GetAppListEntriesAsync();
+ var app = appListEntries.FirstOrDefault();
+ if (app != null)
+ await app.LaunchAsync();
+ }
+
+ private void OnCloseMenuItemClicked(object sender, EventArgs e)
+ {
+ this.ExitThread();
+ }
+
+ private async Task InitialiseAsync()
+ {
+ try
+ {
+ _discord = new DiscordClient(new DiscordConfiguration()
+ {
+ TokenType = TokenType.User,
+ Token = _token,
+ MessageCacheSize = 0,
+ ReconnectIndefinitely = true
+ });
+
+ _badgeManager = new BadgeManager(_discord);
+ _tileManager = new TileManager(_discord);
+ _secondaryTileManager = new SecondaryTileManager(_discord);
+ _toastManager = new ToastManager();
+
+ _discord.Ready += OnReady;
+ _discord.Resumed += OnResumed;
+ _discord.MessageCreated += OnDiscordMessage;
+ _discord.MessageUpdated += OnMessageUpdated;
+ _discord.MessageAcknowledged += OnMessageAcknowledged;
+
+ await _discord.ConnectAsync(status: UserStatus.Invisible, idlesince: DateTimeOffset.Now);
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine(ex);
+ this.ExitThread();
+ }
+ }
+
+ private void OnApplicationExit(object sender, EventArgs e)
+ {
+ if (_discord != null)
+ _discord.DisconnectAsync().GetAwaiter().GetResult();
+
+ if (_notifyIcon != null)
+ {
+ _notifyIcon.Visible = false;
+ _notifyIcon.Dispose();
+ }
+ }
+
+ private async Task OnReady(DiscordClient client, ReadyEventArgs e)
+ {
+ await _tileManager.InitialiseAsync();
+ _badgeManager.Update();
+
+ _ = Task.Run(GCTask);
+ }
+
+ private Task OnResumed(DiscordClient sender, ResumedEventArgs args)
+ {
+ _ = Task.Run(GCTask);
+ return Task.CompletedTask;
+ }
+
+ private async Task GCTask()
+ {
+ await Task.Delay(5000);
+ GC.Collect(2, GCCollectionMode.Forced, true, true);
+ }
+
+ private async Task OnDiscordMessage(DiscordClient client, MessageCreateEventArgs e)
+ {
+ try
+ {
+ if (NotificationUtils.WillShowToast(client, e.Message))
+ {
+ _toastManager?.HandleMessage(client, e.Message, UnicordFinder.IsUnicordVisible());
+ _badgeManager?.Update();
+
+ if (_tileManager != null)
+ await _tileManager.HandleMessageAsync(e.Message);
+ }
+
+ if (_secondaryTileManager != null)
+ await _secondaryTileManager.HandleMessageAsync(client, e.Message);
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine(ex);
+ }
+ }
+
+ private Task OnMessageUpdated(DiscordClient client, MessageUpdateEventArgs e)
+ {
+ try
+ {
+ if (NotificationUtils.WillShowToast(client, e.Message))
+ {
+ _toastManager?.HandleMessageUpdated(client, e.Message);
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine(ex);
+ }
+
+ return Task.CompletedTask;
+ }
+
+ private async Task OnMessageAcknowledged(DiscordClient client, MessageAcknowledgeEventArgs e)
+ {
+ try
+ {
+ _badgeManager?.Update();
+ _toastManager?.HandleAcknowledge(e.Channel);
+
+ if (_tileManager != null)
+ await _tileManager.HandleAcknowledgeAsync(e.Channel);
+
+ if (_secondaryTileManager != null)
+ await _secondaryTileManager.HandleAcknowledgeAsync(e.Channel);
+ }
+ catch (Exception ex)
+ {
+ // TODO: log
+ Debug.WriteLine(ex);
+ }
+ }
+
+ private bool TryGetToken(out string token)
+ {
+#if DEBUG // for testing
+ var args = Environment.GetCommandLineArgs();
+ if (args.Length == 2)
+ {
+ token = args[1];
+ return true;
+ }
+#endif
+
+ if (ApplicationData.Current.LocalSettings.Values.TryGetValue("Token", out var s))
+ {
+ token = (string)s;
+ return true;
+ }
+
+ token = null;
+ return false;
+ }
+ }
+}
diff --git a/Unicord.Universal.Background/Program.cs b/Unicord.Universal.Background/Program.cs
index ee1afc67..da37aca4 100644
--- a/Unicord.Universal.Background/Program.cs
+++ b/Unicord.Universal.Background/Program.cs
@@ -1,37 +1,21 @@
-using System;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-using DSharpPlus;
-using DSharpPlus.Entities;
-using DSharpPlus.EventArgs;
-using Windows.Storage;
-using Windows.UI.Notifications;
-
-namespace Unicord.Universal.Background
-{
- class Program
- {
- private static Mutex _mutex;
-
- [STAThread]
- static void Main(string[] args)
- {
- _mutex = new Mutex(true, "{88FE061B-B4D8-41F4-99FE-15870E0F535B}", out var createdNew);
- if (!createdNew) return;
-
- try
- {
- Application.EnableVisualStyles();
- Application.SetCompatibleTextRenderingDefault(false);
- // Application.SetHighDpiMode(HighDpiMode.PerMonitorV2);
- Application.Run(new NotificationApplicationContext());
- }
- finally
- {
- _mutex.Dispose();
- }
- }
- }
-}
+using System;
+using System.Threading;
+using System.Windows.Forms;
+
+namespace Unicord.Universal.Background
+{
+ class Program
+ {
+ [STAThread]
+ static void Main(string[] args)
+ {
+ using var mutex = new Mutex(true, "{88FE061B-B4D8-41F4-99FE-15870E0F535B}", out var createdNew);
+ if (!createdNew)
+ return;
+
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
+ Application.Run(new NotificationApplicationContext());
+ }
+ }
+}
diff --git a/Unicord.Universal.Background/Unicord.Universal.Background.csproj b/Unicord.Universal.Background/Unicord.Universal.Background.csproj
index 3cf83f2e..2087ea39 100644
--- a/Unicord.Universal.Background/Unicord.Universal.Background.csproj
+++ b/Unicord.Universal.Background/Unicord.Universal.Background.csproj
@@ -1,48 +1,56 @@
-
-
-
- WinExe
- net472
- true
- win7-x64;win7-x86;win7-arm
- true
- AnyCPU;x64;x86;ARM;ARM64
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Always
-
-
-
-
-
- True
- True
- Resources.resx
-
-
-
-
-
- ResXFileCodeGenerator
- Resources.Designer.cs
-
-
-
-
-
+
+
+
+ WinExe
+ net472
+ true
+ win-x64;win-x86;win-arm;win7-x64;win7-x86;win7-arm
+ true
+ 9
+ true
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+
+
+
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+
+
diff --git a/Unicord.Universal.Background/UnicordFinder.cs b/Unicord.Universal.Background/UnicordFinder.cs
new file mode 100644
index 00000000..5bcd5f9f
--- /dev/null
+++ b/Unicord.Universal.Background/UnicordFinder.cs
@@ -0,0 +1,119 @@
+using System;
+using Windows.Win32.Foundation;
+using static Windows.Win32.Foundation.WIN32_ERROR;
+using static Windows.Win32.Graphics.Dwm.DWMWINDOWATTRIBUTE;
+using static Windows.Win32.PInvoke;
+using static Windows.Win32.System.Threading.PROCESS_ACCESS_RIGHTS;
+
+namespace Unicord.Universal.Background
+{
+ internal class UnicordFinder
+ {
+ private static unsafe (HWND hWndUnicord, HWND hWndApplicationFrameHost) FindUnicordWindow()
+ {
+ uint packageNameLen;
+ if (GetCurrentPackageFullName(&packageNameLen, null) == APPMODEL_ERROR_NO_PACKAGE)
+ throw new InvalidOperationException();
+
+ string packageName;
+ char[] packageNameChars = new char[packageNameLen];
+ fixed (char* packageNameCharsPtr = packageNameChars)
+ {
+ if (GetCurrentPackageFullName(&packageNameLen, packageNameCharsPtr) != ERROR_SUCCESS)
+ throw new InvalidOperationException();
+
+ packageName = new string(packageNameCharsPtr);
+ }
+
+ HWND hWndUnicord = HWND.Null, hWndApplicationFrame = HWND.Null;
+
+ unsafe BOOL IsUnicord(HWND hWnd, LPARAM lParam)
+ {
+ string className;
+ char[] name = new char[MAX_PATH];
+ fixed (char* namePtr = name)
+ {
+ if (GetClassName(hWnd, namePtr, (int)MAX_PATH) <= 0)
+ return true;
+
+ className = new string(namePtr);
+ }
+
+ if (string.CompareOrdinal(className, "ApplicationFrameWindow") != 0)
+ return true;
+
+ HWND hWndChild = FindWindowEx(hWnd, HWND.Null, "Windows.UI.Core.CoreWindow", null);
+ if (hWndChild == null)
+ return true;
+
+ uint procId;
+ if (GetWindowThreadProcessId(hWndChild, &procId) == 0)
+ return true;
+
+ HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, procId);
+ if (hProcess == null)
+ return true;
+
+ try
+ {
+ uint fullNameLen;
+ if (GetPackageFullName(hProcess, &fullNameLen, null) != ERROR_INSUFFICIENT_BUFFER)
+ return true;
+
+ string fullName;
+ char[] fullNameChars = new char[fullNameLen];
+ fixed (char* fullNameCharsPtr = fullNameChars)
+ {
+ if (GetPackageFullName(hProcess, &fullNameLen, fullNameCharsPtr) != ERROR_SUCCESS)
+ return true;
+
+ fullName = new string(fullNameCharsPtr);
+ }
+
+ if (packageName == fullName)
+ {
+ hWndUnicord = hWndChild;
+ hWndApplicationFrame = hWnd;
+ return false;
+ }
+ }
+ finally
+ {
+ CloseHandle(hProcess);
+ }
+
+ return false;
+ }
+
+ EnumWindows(IsUnicord, IntPtr.Zero);
+
+ return (hWndUnicord, hWndApplicationFrame);
+ }
+
+ public static unsafe bool IsUnicordVisible()
+ {
+ var (hWndUnicord, hWndApplicationFrameHost) = FindUnicordWindow();
+
+ if (hWndUnicord == HWND.Null || hWndApplicationFrameHost == HWND.Null)
+ return false;
+
+ if (!IsWindowVisible(hWndApplicationFrameHost) || !IsWindowVisible(hWndApplicationFrameHost))
+ return false;
+
+ if (IsIconic(hWndApplicationFrameHost) || IsIconic(hWndUnicord))
+ return false;
+
+ uint dwIsCloaked;
+
+ if (DwmGetWindowAttribute(hWndUnicord, DWMWA_CLOAKED, &dwIsCloaked, sizeof(uint)).Succeeded
+ && dwIsCloaked != 0)
+ return false;
+
+ if (DwmGetWindowAttribute(hWndApplicationFrameHost, DWMWA_CLOAKED, &dwIsCloaked, sizeof(uint)).Succeeded
+ && dwIsCloaked != 0)
+ return false;
+
+ return true;
+ }
+ }
+}
diff --git a/Unicord.Universal.Background/UxThemePrivate.cs b/Unicord.Universal.Background/UxThemePrivate.cs
new file mode 100644
index 00000000..6cc44c2c
--- /dev/null
+++ b/Unicord.Universal.Background/UxThemePrivate.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using Windows.Win32.Foundation;
+
+namespace Unicord.Universal.Background
+{
+ internal class UxThemePrivate
+ {
+ public enum PreferredAppMode : int
+ {
+ Default,
+ AllowDark,
+ ForceDark,
+ ForceLight,
+ Max
+ };
+
+ [DllImport("uxtheme.dll", EntryPoint = "#133", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern BOOL AllowDarkModeForWindow(HWND hwnd, BOOL allow);
+
+ [DllImport("uxtheme.dll", EntryPoint = "#135", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern BOOL SetPreferredAppMode(PreferredAppMode preferredAppMode);
+
+ [DllImport("uxtheme.dll", EntryPoint = "#136", SetLastError = true, CharSet = CharSet.Unicode)]
+ public static extern void FlushMenuThemes();
+ }
+}
diff --git a/Unicord.Universal.Native/.clang-format b/Unicord.Universal.Native/.clang-format
deleted file mode 100644
index 7c14d44d..00000000
--- a/Unicord.Universal.Native/.clang-format
+++ /dev/null
@@ -1,47 +0,0 @@
-# Visual Studio generated .clang-format file
-
-# The style options in this file are a best effort attempt to replicate the
-# current IDE formatting configuration from Tools > Options. The following
-# style options, however, should be verified:
-# AfterClass, AfterControlStatement, AfterEnum, AfterFunction, AfterNamespace,
-# AfterStruct, AfterUnion
-
-BasedOnStyle: LLVM
-AccessModifierOffset: -4
-AlignAfterOpenBracket: DontAlign
-AllowShortBlocksOnASingleLine: true
-AllowShortFunctionsOnASingleLine: All
-BraceWrapping:
- AfterClass: false # TODO: verify
- AfterControlStatement: false # TODO: verify
- AfterEnum: false # TODO: verify
- AfterFunction: false # TODO: verify
- AfterNamespace: false # TODO: verify
- AfterStruct: false # TODO: verify
- AfterUnion: false # TODO: verify
- BeforeCatch: true
- BeforeElse: true
- IndentBraces: false
- SplitEmptyFunction: true
- SplitEmptyRecord: true
-BreakBeforeBraces: Custom
-ColumnLimit: 0
-Cpp11BracedListStyle: false
-DerivePointerAlignment: true
-FixNamespaceComments: false
-IndentCaseLabels: false
-IndentPPDirectives: None
-IndentWidth: 4
-MaxEmptyLinesToKeep: 10
-NamespaceIndentation: All
-SortIncludes: false
-SortUsingDeclarations: true
-SpaceAfterCStyleCast: false
-SpaceBeforeAssignmentOperators: true
-SpaceBeforeParens: ControlStatements
-SpaceInEmptyParentheses: false
-SpacesInCStyleCastParentheses: false
-SpacesInParentheses: false
-SpacesInSquareBrackets: false
-TabWidth: 4
-UseTab: false
diff --git a/Unicord.Universal.Native/NativeHelpers.cpp b/Unicord.Universal.Native/NativeHelpers.cpp
deleted file mode 100644
index 6b5f7a5a..00000000
--- a/Unicord.Universal.Native/NativeHelpers.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#pragma once
-#include "pch.h"
-#include "NativeHelpers.h"
-
-namespace winrt::Unicord::Universal::Native {
- HMODULE NativeHelpers::GetKernelModule() {
- static HMODULE __KernelModule;
-
- if (__KernelModule == nullptr) {
- MEMORY_BASIC_INFORMATION mbi;
- if (VirtualQuery(VirtualQuery, &mbi, sizeof(MEMORY_BASIC_INFORMATION))) {
- __KernelModule = reinterpret_cast(mbi.AllocationBase);
- }
- }
-
- return __KernelModule;
- }
-
- HMODULE NativeHelpers::LoadLibrary(const std::wstring& lpLibFileName) {
- static LoadLibraryProc __LoadLibrary;
- if (__LoadLibrary == nullptr) {
- __LoadLibrary = GetKernelProcAddress("LoadLibraryW");
- }
-
- return __LoadLibrary(lpLibFileName.c_str());
- }
-
- HMODULE NativeHelpers::LoadLibraryEx(const std::wstring& lpLibFileName, HANDLE hFile, DWORD flags) {
- static LoadLibraryExProc __LoadLibraryEx;
- if (__LoadLibraryEx == nullptr) {
- __LoadLibraryEx = GetKernelProcAddress("LoadLibraryExW");
- }
-
- return __LoadLibraryEx(lpLibFileName.c_str(), hFile, flags);
- }
-}
\ No newline at end of file
diff --git a/Unicord.Universal.Native/NativeHelpers.h b/Unicord.Universal.Native/NativeHelpers.h
deleted file mode 100644
index 997590d0..00000000
--- a/Unicord.Universal.Native/NativeHelpers.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#pragma once
-#include
-#include
-
-// Unfortunately, there's no good way to represent this class in IDL :/
-
-namespace winrt::Unicord::Universal::Native {
-
- typedef HMODULE(WINAPI* GetModuleHandleProc)(_In_opt_ LPCTSTR);
- typedef HMODULE(WINAPI* LoadLibraryProc)(_In_ LPCTSTR);
- typedef HMODULE(WINAPI* LoadLibraryExProc)(_In_ LPCTSTR, _Reserved_ HANDLE, _In_ DWORD);
-
- class NativeHelpers {
- public:
- static HMODULE GetKernelModule();
- static HMODULE LoadLibrary(const std::wstring&);
- static HMODULE LoadLibraryEx(const std::wstring&, HANDLE hFile, DWORD flags);
-
- template
- static const T GetKernelProcAddress(const std::string& procName) {
- return GetProcAddress(GetKernelModule(), procName);
- }
-
- template
- static const T GetProcAddress(HMODULE mod, const std::string& procName) {
- return reinterpret_cast(::GetProcAddress(mod, procName.c_str()));
- }
- };
-}
\ No newline at end of file
diff --git a/Unicord.Universal.Native/PropertySheet.props b/Unicord.Universal.Native/PropertySheet.props
deleted file mode 100644
index e34141b0..00000000
--- a/Unicord.Universal.Native/PropertySheet.props
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Unicord.Universal.Native/Shlwapi.cpp b/Unicord.Universal.Native/Shlwapi.cpp
deleted file mode 100644
index 57513cf2..00000000
--- a/Unicord.Universal.Native/Shlwapi.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-#include "pch.h"
-#include "Shlwapi.h"
-#include "Shlwapi.g.cpp"
-#include
-
-namespace winrt::Unicord::Universal::Native::implementation {
-
- bool Shlwapi::InitShlwapiModule = false;
- bool Shlwapi::InitAssocQueryStringW = false;
- bool Shlwapi::InitStrFormatByteSizeEx = false;
-
- HMODULE Shlwapi::__ShlwapiModule = nullptr;
- StrFormatByteSizeExProc Shlwapi::__StrFormatByteSizeEx = nullptr;
- AssocQueryStringWProc Shlwapi::__AssocQueryStringW = nullptr;
-
- hstring Shlwapi::AssocQueryString(ASSOCF const& flags, ASSOCSTR const& str, hstring const& pszAssoc, hstring const& pszExtra) {
- InitShlwapi();
-
- if (!InitAssocQueryStringW) {
- InitAssocQueryStringW = true;
-
- __AssocQueryStringW = NativeHelpers::GetProcAddress(__ShlwapiModule, "AssocQueryStringW");
- if (__AssocQueryStringW == nullptr) {
- winrt::check_win32(GetLastError());
- }
- }
-
- if (__AssocQueryStringW == nullptr)
- throw hresult_not_implemented();
-
- LPCTSTR raw_pszAssoc = pszAssoc.c_str();
- LPCTSTR raw_pszExtra = pszExtra.empty() ? NULL : pszExtra.c_str();
- ASSOCF raw_flags = flags | ASSOCF::NOTRUNCATE;
- DWORD size = 0;
-
- winrt::check_hresult(__AssocQueryStringW(raw_flags, str, raw_pszAssoc, raw_pszExtra, NULL, &size));
-
- std::vector buff;
- buff.resize(size);
-
- winrt::check_hresult(__AssocQueryStringW(raw_flags, str, raw_pszAssoc, raw_pszExtra, buff.data(), &size));
-
- return hstring(buff.data());
- }
-
- hstring Shlwapi::StrFormatByteSizeEx(uint64_t size, SFBSFlags const& flags) {
- InitShlwapi();
-
- if (!InitStrFormatByteSizeEx) {
- InitStrFormatByteSizeEx = true;
-
- __StrFormatByteSizeEx = NativeHelpers::GetProcAddress(__ShlwapiModule, "StrFormatByteSizeEx");
- if (__StrFormatByteSizeEx == nullptr) {
- winrt::check_win32(GetLastError());
- }
- }
-
- if (__StrFormatByteSizeEx == nullptr)
- throw hresult_not_implemented();
-
- wchar_t str[32]{ 0 };
- winrt::check_hresult(__StrFormatByteSizeEx(size, flags, str, 32));
-
- return hstring(str);
- }
-
- void Shlwapi::InitShlwapi() {
- if (!InitShlwapiModule) {
- InitShlwapiModule = true;
-
- __ShlwapiModule = NativeHelpers::LoadLibrary(L"shlwapi.dll");
- if (__ShlwapiModule == nullptr) {
- winrt::check_win32(GetLastError());
- }
- }
-
- if (__ShlwapiModule == nullptr)
- throw hresult_not_implemented();
- }
-}
diff --git a/Unicord.Universal.Native/Shlwapi.g.cpp b/Unicord.Universal.Native/Shlwapi.g.cpp
deleted file mode 100644
index b42050f1..00000000
--- a/Unicord.Universal.Native/Shlwapi.g.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-// WARNING: Please don't edit this file. It was generated by C++/WinRT v2.0.201217.4
-
-void* winrt_make_Unicord_Universal_Native_Shlwapi()
-{
- return winrt::detach_abi(winrt::make());
-}
-WINRT_EXPORT namespace winrt::Unicord::Universal::Native
-{
- hstring Shlwapi::AssocQueryString(Unicord::Universal::Native::ASSOCF const& flags, Unicord::Universal::Native::ASSOCSTR const& str, param::hstring const& pszAssoc, param::hstring const& pszExtra)
- {
- return Unicord::Universal::Native::implementation::Shlwapi::AssocQueryString(flags, str, pszAssoc, pszExtra);
- }
- hstring Shlwapi::StrFormatByteSizeEx(uint64_t size, Unicord::Universal::Native::SFBSFlags const& flags)
- {
- return Unicord::Universal::Native::implementation::Shlwapi::StrFormatByteSizeEx(size, flags);
- }
-}
diff --git a/Unicord.Universal.Native/Shlwapi.g.h b/Unicord.Universal.Native/Shlwapi.g.h
deleted file mode 100644
index 6ff6c6ba..00000000
--- a/Unicord.Universal.Native/Shlwapi.g.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// WARNING: Please don't edit this file. It was generated by C++/WinRT v2.0.201217.4
-
-#pragma once
-#include "winrt/Unicord.Universal.Native.h"
-namespace winrt::Unicord::Universal::Native::implementation
-{
- template
- struct __declspec(empty_bases) Shlwapi_base : implements
- {
- using base_type = Shlwapi_base;
- using class_type = Unicord::Universal::Native::Shlwapi;
- using implements_type = typename Shlwapi_base::implements_type;
- using implements_type::implements_type;
-
- hstring GetRuntimeClassName() const
- {
- return L"Unicord.Universal.Native.Shlwapi";
- }
- };
-}
-namespace winrt::Unicord::Universal::Native::factory_implementation
-{
- template
- struct __declspec(empty_bases) ShlwapiT : implements
- {
- using instance_type = Unicord::Universal::Native::Shlwapi;
-
- hstring GetRuntimeClassName() const
- {
- return L"Unicord.Universal.Native.Shlwapi";
- }
- auto AssocQueryString(Unicord::Universal::Native::ASSOCF const& flags, Unicord::Universal::Native::ASSOCSTR const& str, hstring const& pszAssoc, hstring const& pszExtra)
- {
- return T::AssocQueryString(flags, str, pszAssoc, pszExtra);
- }
- auto StrFormatByteSizeEx(uint64_t size, Unicord::Universal::Native::SFBSFlags const& flags)
- {
- return T::StrFormatByteSizeEx(size, flags);
- }
- [[noreturn]] Windows::Foundation::IInspectable ActivateInstance() const
- {
- throw hresult_not_implemented();
- }
- };
-}
-
-#if defined(WINRT_FORCE_INCLUDE_SHLWAPI_XAML_G_H) || __has_include("Shlwapi.xaml.g.h")
-#include "Shlwapi.xaml.g.h"
-#else
-
-namespace winrt::Unicord::Universal::Native::implementation
-{
- template
- using ShlwapiT = Shlwapi_base;
-}
-
-#endif
diff --git a/Unicord.Universal.Native/Shlwapi.h b/Unicord.Universal.Native/Shlwapi.h
deleted file mode 100644
index 67815297..00000000
--- a/Unicord.Universal.Native/Shlwapi.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#pragma once
-#include "Shlwapi.g.h"
-#include "NativeHelpers.h"
-
-namespace winrt::Unicord::Universal::Native::implementation {
-
- typedef HRESULT(WINAPI* AssocQueryStringWProc)(ASSOCF flags, ASSOCSTR str, LPCWSTR pszAssoc, LPCWSTR pszExtra, LPWSTR pszOut, DWORD* pcchOut);
- typedef HRESULT(WINAPI* StrFormatByteSizeExProc)(ULONGLONG ull, SFBSFlags flags, _Out_writes_(cchBuf) PWSTR pszBuf, _In_range_(>, 0) UINT cchBuf);
-
- struct Shlwapi : ShlwapiT {
- Shlwapi() = default;
-
- static bool InitShlwapiModule;
- static bool InitAssocQueryStringW;
- static bool InitStrFormatByteSizeEx;
-
- static HMODULE __ShlwapiModule;
- static AssocQueryStringWProc __AssocQueryStringW;
- static StrFormatByteSizeExProc __StrFormatByteSizeEx;
-
- static void InitShlwapi();
- static hstring AssocQueryString(ASSOCF const& flags, ASSOCSTR const& str, hstring const& pszAssoc, hstring const& pszExtra);
- static hstring StrFormatByteSizeEx(uint64_t size, SFBSFlags const& flags);
- };
-}
-namespace winrt::Unicord::Universal::Native::factory_implementation {
- struct Shlwapi : ShlwapiT {
- };
-}
diff --git a/Unicord.Universal.Native/Shlwapi.idl b/Unicord.Universal.Native/Shlwapi.idl
deleted file mode 100644
index 5b635658..00000000
--- a/Unicord.Universal.Native/Shlwapi.idl
+++ /dev/null
@@ -1,71 +0,0 @@
-namespace Unicord.Universal.Native {
- ///
- /// Specifies how the StrFormatByteSizeEx function should handle rounding of undisplayed digits.
- ///
- enum SFBSFlags {
- /// Round to the nearest displayed digit.
- RoundToNearestDisplayedDigit = 0x0001,
-
- /// Discard undisplayed digits.
- TruncateUndisplayedDecimalDigits = 0x0002
- };
-
- [flags] enum ASSOCF {
- NONE = 0x00000000,
- INIT_NOREMAPCLSID = 0x00000001,
- INIT_BYEXENAME = 0x00000002,
- OPEN_BYEXENAME = 0x00000002,
- INIT_DEFAULTTOSTAR = 0x00000004,
- INIT_DEFAULTTOFOLDER = 0x00000008,
- NOUSERSETTINGS = 0x00000010,
- NOTRUNCATE = 0x00000020,
- VERIFY = 0x00000040,
- REMAPRUNDLL = 0x00000080,
- NOFIXUPS = 0x00000100,
- IGNOREBASECLASS = 0x00000200,
- INIT_IGNOREUNKNOWN = 0x00000400,
- INIT_FIXED_PROGID = 0x00000800,
- IS_PROTOCOL = 0x00001000,
- INIT_FOR_FILE = 0x00002000
- };
-
- enum ASSOCSTR {
- COMMAND,
- EXECUTABLE,
- FRIENDLYDOCNAME,
- FRIENDLYAPPNAME,
- NOOPEN,
- SHELLNEWVALUE,
- DDECOMMAND,
- DDEIFEXEC,
- DDEAPPLICATION,
- DDETOPIC,
- INFOTIP,
- QUICKTIP,
- TILEINFO,
- CONTENTTYPE,
- DEFAULTICON,
- SHELLEXTENSION,
- DROPTARGET,
- DELEGATEEXECUTE,
- SUPPORTED_URI_PROTOCOLS,
- PROGID,
- APPID,
- APPPUBLISHER,
- APPICONREFERENCE,
- MAX
- };
-
-
- [default_interface] runtimeclass Shlwapi {
- ///
- /// Searches for and retrieves a file or protocol association-related string from the registry.
- ///
- static String AssocQueryString(ASSOCF flags, ASSOCSTR str, String pszAssoc, String pszExtra);
-
- ///
- /// Converts a numeric value into a string that represents the number in bytes, kilobytes, megabytes, or gigabytes, depending on the size.
- ///
- static String StrFormatByteSizeEx(UInt64 size, SFBSFlags flags);
- }
-}
diff --git a/Unicord.Universal.Native/Unicord.Universal.Native.vcxproj b/Unicord.Universal.Native/Unicord.Universal.Native.vcxproj
deleted file mode 100644
index b9b9316d..00000000
--- a/Unicord.Universal.Native/Unicord.Universal.Native.vcxproj
+++ /dev/null
@@ -1,190 +0,0 @@
-
-
-
-
- true
- true
- true
- true
- {2427b481-8e92-433f-8714-53a2cde1bf7f}
- Unicord.Universal.Native
- Unicord.Universal.Native
- en-US
- 14.0
- true
- Windows Store
- 10.0
- 10.0
- 10.0.19041.0
- true
-
-
-
-
- Debug
- ARM
-
-
- Debug
- ARM64
-
-
- Debug
- Win32
-
-
- Debug
- x64
-
-
- Release
- ARM
-
-
- Release
- ARM64
-
-
- Release
- Win32
-
-
- Release
- x64
-
-
-
- DynamicLibrary
- v142
- v141
- v142
- Unicode
- false
-
-
- true
- true
-
-
- false
- true
- false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- $(ProjectDir)bin\$(Configuration)\$(Platform)\
- $(ProjectDir)obj\$(Configuration)\$(Platform)\
-
-
- $(ProjectDir)bin\$(Configuration)\$(Platform)\
- $(ProjectDir)obj\$(Configuration)\$(Platform)\
-
-
- $(ProjectDir)bin\$(Configuration)\$(Platform)\
- $(ProjectDir)obj\$(Configuration)\$(Platform)\
-
-
- $(ProjectDir)bin\$(Configuration)\$(Platform)\
- $(ProjectDir)obj\$(Configuration)\$(Platform)\
-
-
- $(ProjectDir)bin\$(Configuration)\$(Platform)\
- $(ProjectDir)obj\$(Configuration)\$(Platform)\
-
-
- $(ProjectDir)bin\$(Configuration)\$(Platform)\
- $(ProjectDir)obj\$(Configuration)\$(Platform)\
-
-
- $(ProjectDir)bin\$(Configuration)\$(Platform)\
- $(ProjectDir)obj\$(Configuration)\$(Platform)\
-
-
- $(ProjectDir)bin\$(Configuration)\$(Platform)\
- $(ProjectDir)obj\$(Configuration)\$(Platform)\
-
-
-
- Use
- pch.h
- $(IntDir)pch.pch
- Level4
- %(AdditionalOptions) /bigobj
-
- /DWINRT_NO_MAKE_DETECTION %(AdditionalOptions)
-
-
- _WINRT_DLL;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions)
- $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)
-
-
- Console
- false
- Unicord_Universal_Native.def
-
-
-
-
- _DEBUG;%(PreprocessorDefinitions)
-
-
-
-
- NDEBUG;%(PreprocessorDefinitions)
-
-
- true
- true
-
-
-
-
-
-
- Shlwapi.idl
-
-
-
-
-
- Create
-
-
- Shlwapi.idl
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
-
-
-
-
\ No newline at end of file
diff --git a/Unicord.Universal.Native/Unicord_Universal_Native.def b/Unicord.Universal.Native/Unicord_Universal_Native.def
deleted file mode 100644
index 24e7c123..00000000
--- a/Unicord.Universal.Native/Unicord_Universal_Native.def
+++ /dev/null
@@ -1,3 +0,0 @@
-EXPORTS
-DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
-DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
diff --git a/Unicord.Universal.Native/module.g.cpp b/Unicord.Universal.Native/module.g.cpp
deleted file mode 100644
index fbb5f93f..00000000
--- a/Unicord.Universal.Native/module.g.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-// WARNING: Please don't edit this file. It was generated by C++/WinRT v2.0.201217.4
-
-#include "pch.h"
-#include "winrt/base.h"
-void* winrt_make_Unicord_Universal_Native_Shlwapi();
-
-bool __stdcall winrt_can_unload_now() noexcept
-{
- if (winrt::get_module_lock())
- {
- return false;
- }
-
- winrt::clear_factory_cache();
- return true;
-}
-
-void* __stdcall winrt_get_activation_factory([[maybe_unused]] std::wstring_view const& name)
-{
- auto requal = [](std::wstring_view const& left, std::wstring_view const& right) noexcept
- {
- return std::equal(left.rbegin(), left.rend(), right.rbegin(), right.rend());
- };
-
- if (requal(name, L"Unicord.Universal.Native.Shlwapi"))
- {
- return winrt_make_Unicord_Universal_Native_Shlwapi();
- }
-
- return nullptr;
-}
-
-int32_t __stdcall WINRT_CanUnloadNow() noexcept
-{
-#ifdef _WRL_MODULE_H_
- if (!::Microsoft::WRL::Module<::Microsoft::WRL::InProc>::GetModule().Terminate())
- {
- return 1;
- }
-#endif
-
- return winrt_can_unload_now() ? 0 : 1;
-}
-
-int32_t __stdcall WINRT_GetActivationFactory(void* classId, void** factory) noexcept try
-{
- std::wstring_view const name{ *reinterpret_cast(&classId) };
- *factory = winrt_get_activation_factory(name);
-
- if (*factory)
- {
- return 0;
- }
-
-#ifdef _WRL_MODULE_H_
- return ::Microsoft::WRL::Module<::Microsoft::WRL::InProc>::GetModule().GetActivationFactory(static_cast(classId), reinterpret_cast<::IActivationFactory**>(factory));
-#else
- return winrt::hresult_class_not_available(name).to_abi();
-#endif
-}
-catch (...) { return winrt::to_hresult(); }
diff --git a/Unicord.Universal.Native/packages.config b/Unicord.Universal.Native/packages.config
deleted file mode 100644
index 1c90c5ba..00000000
--- a/Unicord.Universal.Native/packages.config
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/Unicord.Universal.Native/pch.cpp b/Unicord.Universal.Native/pch.cpp
deleted file mode 100644
index bcb5590b..00000000
--- a/Unicord.Universal.Native/pch.cpp
+++ /dev/null
@@ -1 +0,0 @@
-#include "pch.h"
diff --git a/Unicord.Universal.Native/pch.h b/Unicord.Universal.Native/pch.h
deleted file mode 100644
index a7030a2d..00000000
--- a/Unicord.Universal.Native/pch.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#pragma once
-#include
-#include
-#include
-
diff --git a/Unicord.Universal.Native/readme.txt b/Unicord.Universal.Native/readme.txt
deleted file mode 100644
index 5edae9f5..00000000
--- a/Unicord.Universal.Native/readme.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-========================================================================
- C++/WinRT Unicord.Universal.Native Project Overview
-========================================================================
-
-This project demonstrates how to get started authoring Windows Runtime
-classes directly with standard C++, using the C++/WinRT SDK component
-to generate implementation headers from interface (IDL) files. The
-generated Windows Runtime component binary and WinMD files should then
-be bundled with the Universal Windows Platform (UWP) app consuming them.
-
-Steps:
-1. Create an interface (IDL) file to define your Windows Runtime class,
- its default interface, and any other interfaces it implements.
-2. Build the project once to generate module.g.cpp, module.h.cpp, and
- implementation templates under the "Generated Files" folder, as
- well as skeleton class definitions under "Generated Files\sources".
-3. Use the skeleton class definitions for reference to implement your
- Windows Runtime classes.
-
-========================================================================
-Learn more about C++/WinRT here:
-http://aka.ms/cppwinrt/
-========================================================================
diff --git a/Unicord.Universal.Package/Assets/Store/BadgeLogo.scale-100.png b/Unicord.Universal.Package/Assets/Store/BadgeLogo.scale-100.png
new file mode 100644
index 00000000..5fbab9b3
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/BadgeLogo.scale-100.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/BadgeLogo.scale-125.png b/Unicord.Universal.Package/Assets/Store/BadgeLogo.scale-125.png
new file mode 100644
index 00000000..4ae0a849
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/BadgeLogo.scale-125.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/BadgeLogo.scale-150.png b/Unicord.Universal.Package/Assets/Store/BadgeLogo.scale-150.png
new file mode 100644
index 00000000..dd350e29
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/BadgeLogo.scale-150.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/BadgeLogo.scale-200.png b/Unicord.Universal.Package/Assets/Store/BadgeLogo.scale-200.png
new file mode 100644
index 00000000..fb6a993d
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/BadgeLogo.scale-200.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/BadgeLogo.scale-400.png b/Unicord.Universal.Package/Assets/Store/BadgeLogo.scale-400.png
new file mode 100644
index 00000000..ae291dd1
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/BadgeLogo.scale-400.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/LargeTile.scale-100.png b/Unicord.Universal.Package/Assets/Store/LargeTile.scale-100.png
new file mode 100644
index 00000000..5712127c
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/LargeTile.scale-100.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/LargeTile.scale-125.png b/Unicord.Universal.Package/Assets/Store/LargeTile.scale-125.png
new file mode 100644
index 00000000..6c318c7d
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/LargeTile.scale-125.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/LargeTile.scale-150.png b/Unicord.Universal.Package/Assets/Store/LargeTile.scale-150.png
new file mode 100644
index 00000000..cec69348
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/LargeTile.scale-150.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/LargeTile.scale-200.png b/Unicord.Universal.Package/Assets/Store/LargeTile.scale-200.png
new file mode 100644
index 00000000..638f6e43
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/LargeTile.scale-200.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/LargeTile.scale-400.png b/Unicord.Universal.Package/Assets/Store/LargeTile.scale-400.png
new file mode 100644
index 00000000..2ed36270
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/LargeTile.scale-400.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/SmallTile.scale-100.png b/Unicord.Universal.Package/Assets/Store/SmallTile.scale-100.png
new file mode 100644
index 00000000..4626f4e5
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/SmallTile.scale-100.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/SmallTile.scale-125.png b/Unicord.Universal.Package/Assets/Store/SmallTile.scale-125.png
new file mode 100644
index 00000000..81fee51b
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/SmallTile.scale-125.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/SmallTile.scale-150.png b/Unicord.Universal.Package/Assets/Store/SmallTile.scale-150.png
new file mode 100644
index 00000000..08cf339e
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/SmallTile.scale-150.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/SmallTile.scale-200.png b/Unicord.Universal.Package/Assets/Store/SmallTile.scale-200.png
new file mode 100644
index 00000000..6d3a03f8
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/SmallTile.scale-200.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/SmallTile.scale-400.png b/Unicord.Universal.Package/Assets/Store/SmallTile.scale-400.png
new file mode 100644
index 00000000..238902ba
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/SmallTile.scale-400.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/SplashScreen.light.scale-100.png b/Unicord.Universal.Package/Assets/Store/SplashScreen.light.scale-100.png
new file mode 100644
index 00000000..676c37a3
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/SplashScreen.light.scale-100.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/SplashScreen.light.scale-125.png b/Unicord.Universal.Package/Assets/Store/SplashScreen.light.scale-125.png
new file mode 100644
index 00000000..71624be2
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/SplashScreen.light.scale-125.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/SplashScreen.light.scale-150.png b/Unicord.Universal.Package/Assets/Store/SplashScreen.light.scale-150.png
new file mode 100644
index 00000000..80f87b3b
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/SplashScreen.light.scale-150.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/SplashScreen.light.scale-200.png b/Unicord.Universal.Package/Assets/Store/SplashScreen.light.scale-200.png
new file mode 100644
index 00000000..d14c3ee8
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/SplashScreen.light.scale-200.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/SplashScreen.light.scale-400.png b/Unicord.Universal.Package/Assets/Store/SplashScreen.light.scale-400.png
new file mode 100644
index 00000000..dda296e0
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/SplashScreen.light.scale-400.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/SplashScreen.scale-100.png b/Unicord.Universal.Package/Assets/Store/SplashScreen.scale-100.png
new file mode 100644
index 00000000..1ae018f4
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/SplashScreen.scale-100.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/SplashScreen.scale-125.png b/Unicord.Universal.Package/Assets/Store/SplashScreen.scale-125.png
new file mode 100644
index 00000000..595c51eb
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/SplashScreen.scale-125.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/SplashScreen.scale-150.png b/Unicord.Universal.Package/Assets/Store/SplashScreen.scale-150.png
new file mode 100644
index 00000000..b31a7cab
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/SplashScreen.scale-150.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/SplashScreen.scale-200.png b/Unicord.Universal.Package/Assets/Store/SplashScreen.scale-200.png
new file mode 100644
index 00000000..bc297659
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/SplashScreen.scale-200.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/SplashScreen.scale-400.png b/Unicord.Universal.Package/Assets/Store/SplashScreen.scale-400.png
new file mode 100644
index 00000000..a0cd256a
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/SplashScreen.scale-400.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square150x150Logo.scale-100.png b/Unicord.Universal.Package/Assets/Store/Square150x150Logo.scale-100.png
new file mode 100644
index 00000000..97fc0b42
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square150x150Logo.scale-100.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square150x150Logo.scale-125.png b/Unicord.Universal.Package/Assets/Store/Square150x150Logo.scale-125.png
new file mode 100644
index 00000000..51974ea2
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square150x150Logo.scale-125.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square150x150Logo.scale-150.png b/Unicord.Universal.Package/Assets/Store/Square150x150Logo.scale-150.png
new file mode 100644
index 00000000..3363aa5f
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square150x150Logo.scale-150.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square150x150Logo.scale-200.png b/Unicord.Universal.Package/Assets/Store/Square150x150Logo.scale-200.png
new file mode 100644
index 00000000..0a1ffea0
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square150x150Logo.scale-200.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square150x150Logo.scale-400.png b/Unicord.Universal.Package/Assets/Store/Square150x150Logo.scale-400.png
new file mode 100644
index 00000000..afc5befd
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square150x150Logo.scale-400.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-lightunplated_targetsize-16.png b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-lightunplated_targetsize-16.png
new file mode 100644
index 00000000..04e4d805
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-lightunplated_targetsize-16.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-lightunplated_targetsize-24.png b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-lightunplated_targetsize-24.png
new file mode 100644
index 00000000..3782bb08
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-lightunplated_targetsize-24.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-lightunplated_targetsize-256.png b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-lightunplated_targetsize-256.png
new file mode 100644
index 00000000..7e18d9fc
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-lightunplated_targetsize-256.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-lightunplated_targetsize-32.png b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-lightunplated_targetsize-32.png
new file mode 100644
index 00000000..23ea29a1
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-lightunplated_targetsize-32.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-lightunplated_targetsize-48.png b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-lightunplated_targetsize-48.png
new file mode 100644
index 00000000..3600fe08
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-lightunplated_targetsize-48.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-unplated_targetsize-16.png b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-unplated_targetsize-16.png
new file mode 100644
index 00000000..a6676277
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-unplated_targetsize-16.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-unplated_targetsize-24.png b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-unplated_targetsize-24.png
new file mode 100644
index 00000000..afa6ee3d
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-unplated_targetsize-24.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-unplated_targetsize-256.png b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-unplated_targetsize-256.png
new file mode 100644
index 00000000..e69b2b74
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-unplated_targetsize-256.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-unplated_targetsize-32.png b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-unplated_targetsize-32.png
new file mode 100644
index 00000000..1aa618c0
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-unplated_targetsize-32.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-unplated_targetsize-48.png b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-unplated_targetsize-48.png
new file mode 100644
index 00000000..20f94f11
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.altform-unplated_targetsize-48.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square44x44Logo.scale-100.png b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.scale-100.png
new file mode 100644
index 00000000..e6705493
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.scale-100.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square44x44Logo.scale-125.png b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.scale-125.png
new file mode 100644
index 00000000..1bbf09e0
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.scale-125.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square44x44Logo.scale-150.png b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.scale-150.png
new file mode 100644
index 00000000..23427cf5
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.scale-150.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square44x44Logo.scale-200.png b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.scale-200.png
new file mode 100644
index 00000000..b0b03e6f
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.scale-200.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square44x44Logo.scale-400.png b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.scale-400.png
new file mode 100644
index 00000000..34eb0115
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.scale-400.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square44x44Logo.targetsize-16.png b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.targetsize-16.png
new file mode 100644
index 00000000..0c2b3065
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.targetsize-16.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square44x44Logo.targetsize-24.png b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.targetsize-24.png
new file mode 100644
index 00000000..3254fd54
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.targetsize-24.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square44x44Logo.targetsize-256.png b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.targetsize-256.png
new file mode 100644
index 00000000..35b01c80
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.targetsize-256.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square44x44Logo.targetsize-32.png b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.targetsize-32.png
new file mode 100644
index 00000000..7ae96765
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.targetsize-32.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Square44x44Logo.targetsize-48.png b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.targetsize-48.png
new file mode 100644
index 00000000..8db2f9c2
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Square44x44Logo.targetsize-48.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/StoreLogo.scale-100.png b/Unicord.Universal.Package/Assets/Store/StoreLogo.scale-100.png
new file mode 100644
index 00000000..f3a3f1c7
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/StoreLogo.scale-100.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/StoreLogo.scale-125.png b/Unicord.Universal.Package/Assets/Store/StoreLogo.scale-125.png
new file mode 100644
index 00000000..473de3dc
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/StoreLogo.scale-125.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/StoreLogo.scale-150.png b/Unicord.Universal.Package/Assets/Store/StoreLogo.scale-150.png
new file mode 100644
index 00000000..18c2e534
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/StoreLogo.scale-150.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/StoreLogo.scale-200.png b/Unicord.Universal.Package/Assets/Store/StoreLogo.scale-200.png
new file mode 100644
index 00000000..78fd6aa3
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/StoreLogo.scale-200.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/StoreLogo.scale-400.png b/Unicord.Universal.Package/Assets/Store/StoreLogo.scale-400.png
new file mode 100644
index 00000000..7a3c858d
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/StoreLogo.scale-400.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Wide310x150Logo.scale-100.png b/Unicord.Universal.Package/Assets/Store/Wide310x150Logo.scale-100.png
new file mode 100644
index 00000000..594275c4
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Wide310x150Logo.scale-100.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Wide310x150Logo.scale-125.png b/Unicord.Universal.Package/Assets/Store/Wide310x150Logo.scale-125.png
new file mode 100644
index 00000000..36eb02de
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Wide310x150Logo.scale-125.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Wide310x150Logo.scale-150.png b/Unicord.Universal.Package/Assets/Store/Wide310x150Logo.scale-150.png
new file mode 100644
index 00000000..7e4ab5a1
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Wide310x150Logo.scale-150.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Wide310x150Logo.scale-200.png b/Unicord.Universal.Package/Assets/Store/Wide310x150Logo.scale-200.png
new file mode 100644
index 00000000..c63f21e9
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Wide310x150Logo.scale-200.png differ
diff --git a/Unicord.Universal.Package/Assets/Store/Wide310x150Logo.scale-400.png b/Unicord.Universal.Package/Assets/Store/Wide310x150Logo.scale-400.png
new file mode 100644
index 00000000..a0a364eb
Binary files /dev/null and b/Unicord.Universal.Package/Assets/Store/Wide310x150Logo.scale-400.png differ
diff --git a/Unicord.Universal.Package/Package.ARM.Debug.appxmanifest b/Unicord.Universal.Package/Package.ARM.Debug.appxmanifest
index dec9a7df..27f37a38 100644
--- a/Unicord.Universal.Package/Package.ARM.Debug.appxmanifest
+++ b/Unicord.Universal.Package/Package.ARM.Debug.appxmanifest
@@ -18,7 +18,7 @@
Assets\Store\StoreLogo.png
-
+
diff --git a/Unicord.Universal.Package/Package.ARM.appxmanifest b/Unicord.Universal.Package/Package.ARM.appxmanifest
index fdd3a99b..488eae69 100644
--- a/Unicord.Universal.Package/Package.ARM.appxmanifest
+++ b/Unicord.Universal.Package/Package.ARM.appxmanifest
@@ -17,7 +17,7 @@
Assets\Store\StoreLogo.png
-
+
diff --git a/Unicord.Universal.Package/Package.Debug.appxmanifest b/Unicord.Universal.Package/Package.Debug.appxmanifest
index 3bf77341..51ccc210 100644
--- a/Unicord.Universal.Package/Package.Debug.appxmanifest
+++ b/Unicord.Universal.Package/Package.Debug.appxmanifest
@@ -18,7 +18,7 @@
Assets\Store\StoreLogo.png
-
+
diff --git a/Unicord.Universal.Package/Package.appxmanifest b/Unicord.Universal.Package/Package.appxmanifest
index 685d8a6a..5c0ee17f 100644
--- a/Unicord.Universal.Package/Package.appxmanifest
+++ b/Unicord.Universal.Package/Package.appxmanifest
@@ -1,153 +1,154 @@
-
-
-
-
-
- ms-resource:AppDisplayName
- Wan Kerr Co. Ltd.
- Assets\Store\StoreLogo.png
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- StorageItem
- Bitmap
- Text
- WebLink
-
-
-
-
- Assets\Store\Square44x44Logo.png
- Unicord
-
-
-
-
- Assets\Store\Square44x44Logo.png
- Unicord
-
-
-
-
- Assets\Store\Square44x44Logo.png
- Unicord
-
-
-
-
-
-
-
-
-
-
-
-
- Unicord Theme
-
- .uni-theme
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+ ms-resource:AppDisplayName
+ Wan Kerr Co. Ltd.
+ Assets\Store\StoreLogo.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ StorageItem
+ Bitmap
+ Text
+ WebLink
+
+
+
+
+ Assets\Store\Square44x44Logo.png
+ Unicord
+
+
+
+
+ Assets\Store\Square44x44Logo.png
+ Unicord
+
+
+
+
+ Assets\Store\Square44x44Logo.png
+ Unicord
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Unicord.Universal.Voice.dll
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Unicord.Universal.Package/Unicord.Universal.Package.wapproj b/Unicord.Universal.Package/Unicord.Universal.Package.wapproj
index 94973fc5..9ec91110 100644
--- a/Unicord.Universal.Package/Unicord.Universal.Package.wapproj
+++ b/Unicord.Universal.Package/Unicord.Universal.Package.wapproj
@@ -1,123 +1,91 @@
-
-
-
- 15.0
-
-
-
- Debug
- x86
-
-
- Release
- x86
-
-
- Debug
- x64
-
-
- Release
- x64
-
-
- Debug
- ARM
-
-
- Release
- ARM
-
-
- Debug
- ARM64
-
-
- Release
- ARM64
-
-
- Debug
- AnyCPU
-
-
- Release
- AnyCPU
-
-
- Store
- AnyCPU
-
-
- Store
- arm
-
-
- Store
- ARM64
-
-
- Store
- x64
-
-
- Store
- x86
-
-
-
- $(MSBuildExtensionsPath)\Microsoft\DesktopBridge\
-
-
-
- 8e0255b7-b38e-423e-91c7-5637a01c2e13
- 10.0.19041.0
- 10.0.16299.0
- en-US
- True
- ..\Unicord.Universal\Unicord.Universal.csproj
- false
- false
- CBB99112037FA88434855C973D1AB39B0D4B2F10
- False
- SHA256
- False
- False
- x86|x64|arm
- 0
- Always
-
-
-
- Designer
-
-
-
-
- Designer
-
-
-
-
-
- True
-
-
-
-
-
-
-
-
-
-
+
+
+
+ 15.0
+
+
+
+ Debug
+ x86
+
+
+ Release
+ x86
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM
+
+
+ Release
+ ARM
+
+
+ Debug
+ ARM64
+
+
+ Release
+ ARM64
+
+
+ Debug
+ AnyCPU
+
+
+ Release
+ AnyCPU
+
+
+
+ $(MSBuildExtensionsPath)\Microsoft\DesktopBridge\
+
+
+
+ 8e0255b7-b38e-423e-91c7-5637a01c2e13
+ 10.0.22621.0
+ 10.0.16299.0
+ en-US
+ True
+ ..\Unicord.Universal\Unicord.Universal.csproj
+ false
+ false
+ False
+ SHA256
+ False
+ True
+ x64
+ 0
+ Always
+ https://wamwoowam.co.uk/unicord/download
+ win10-x64;win10-x86;win10-arm
+
+ true
+ 3170C79384D8E3CC9B1BB941485392BC58100230
+ Unicord.Universal.Package_TemporaryKey.pfx
+
+
+
+ Designer
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Unicord.Universal.Shared/BadgeManager.cs b/Unicord.Universal.Shared/BadgeManager.cs
index 8662822b..c88c5b7e 100644
--- a/Unicord.Universal.Shared/BadgeManager.cs
+++ b/Unicord.Universal.Shared/BadgeManager.cs
@@ -1,59 +1,64 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using DSharpPlus;
-using Windows.Data.Xml.Dom;
-using Windows.UI.Notifications;
-
-namespace Unicord.Universal.Shared
-{
- public class BadgeManager
- {
- private BadgeUpdater _badgeUpdateManager;
- private DiscordClient _discord;
-
- public BadgeManager(DiscordClient client)
- {
- _discord = client;
- _badgeUpdateManager = BadgeUpdateManager.CreateBadgeUpdaterForApplication("App");
- }
-
- public void Update()
- {
- try
- {
- var unread = _discord.Guilds.Values.Any(g => g.Unread);
- if (!unread)
- return;
-
- var badgeNumber = _discord.Guilds.Values.Sum(g => g.MentionCount) + _discord.PrivateChannels.Values.Sum(g => g.ReadState?.MentionCount);
- if (badgeNumber != 0)
- {
- var badgeXml = BadgeUpdateManager.GetTemplateContent(BadgeTemplateType.BadgeNumber);
- var badgeElement = badgeXml.SelectSingleNode("/badge") as XmlElement;
-
- badgeElement.SetAttribute("value", badgeNumber.ToString());
- _badgeUpdateManager.Update(new BadgeNotification(badgeXml));
- }
- //else if (unread)
- //{
- // var badgeXml = BadgeUpdateManager.GetTemplateContent(BadgeTemplateType.BadgeGlyph);
- // var badgeElement = badgeXml.SelectSingleNode("/badge") as XmlElement;
-
- // badgeElement.SetAttribute("value", "available");
- // _badgeUpdateManager.Update(new BadgeNotification(badgeXml));
- //}
- else
- {
- _badgeUpdateManager.Clear();
- }
- }
- catch (Exception)
- {
- // TODO: log
- }
- }
- }
-}
+using System;
+using System.Globalization;
+using DSharpPlus;
+using Unicord.Universal.Extensions;
+using Windows.Data.Xml.Dom;
+using Windows.UI.Notifications;
+
+namespace Unicord.Universal.Shared
+{
+ internal class BadgeManager
+ {
+ private BadgeUpdater _badgeUpdateManager;
+ private DiscordClient _discord;
+
+ public BadgeManager(DiscordClient client)
+ {
+ _discord = client;
+ _badgeUpdateManager = BadgeUpdateManager.CreateBadgeUpdaterForApplication("App");
+ }
+
+ public void Update()
+ {
+ try
+ {
+ var mentions = 0;
+ var unread = false;
+ foreach (var (key, value) in _discord.ReadStates)
+ {
+ if (_discord.TryGetCachedChannel(key, out var channel) && !channel.IsMuted()
+ && (channel.Guild == null || !channel.Guild.IsMuted()))
+ {
+ unread |= channel.IsUnread();
+ mentions += value.MentionCount;
+ }
+ }
+
+ if (!unread)
+ {
+ _badgeUpdateManager.Clear();
+ return;
+ }
+
+ var badgeXml = BadgeUpdateManager.GetTemplateContent(
+ mentions == 0 ? BadgeTemplateType.BadgeGlyph : BadgeTemplateType.BadgeNumber);
+ var badgeElement = badgeXml.SelectSingleNode("/badge") as XmlElement;
+
+ if (mentions != 0)
+ {
+ badgeElement.SetAttribute("value", mentions.ToString(CultureInfo.InvariantCulture));
+ }
+ else
+ {
+ badgeElement.SetAttribute("value", "available");
+ }
+
+ _badgeUpdateManager.Update(new BadgeNotification(badgeXml));
+ }
+ catch (Exception)
+ {
+ // TODO: log
+ }
+ }
+ }
+}
diff --git a/Unicord.Universal.Shared/Constants.cs b/Unicord.Universal.Shared/Constants.cs
index 97ca3d9c..bdac5a81 100644
--- a/Unicord.Universal.Shared/Constants.cs
+++ b/Unicord.Universal.Shared/Constants.cs
@@ -1,77 +1,122 @@
-using System;
-
-namespace Unicord
-{
- public static partial class Constants
- {
- public const string MAIN_URL = "https://wamwoowam.co.uk/unicord/";
-
- public const string TOKEN_IDENTIFIER = "Unicord_Token";
- public const string APP_USER_MODEL_ID = "com.wankerr.Unicord";
-
- public const string ENABLE_ANALYTICS = "EnableAnalytics";
- public const string SYNC_CONTACTS = "SyncContacts";
- public const string ENABLE_SPOILERS = "EnableSpoilers";
- public const string AUTO_TRANSCODE_MEDIA = "AutoTranscodeMedia";
- public const string WARN_UNSAFE_LINKS = "WarnUnsafeLinks";
-
- public const string VIDEO_BITRATE = "VideoBitrate";
- public const string VIDEO_WIDTH = "VideoWidth";
- public const string VIDEO_HEIGHT = "VideoHeight";
-
- public const string AUDIO_BITRATE = "AudioBitrate";
- public const string AUDIO_SAMPLERATE = "AudioSampleRate";
- public const string VIDEO_PROCESSING = "VideoProcessingAlgorithm";
-
- public const string VERIFY_LOGIN = "HelloForLogin";
- public const string VERIFY_NSFW = "HelloForNSFW";
- public const string VERIFY_SETTINGS = "HelloForSettings";
- public const string AUTHENTICATION_TIME = "AuthenticationTime";
-
- public const string GIF_AUTOPLAY = "AutoPlayGifs";
- public const string SAVE_CAPTURED_PHOTOS = "SavedPhotos";
- public const string TIMESTAMP_STYLE = "TimestampStyle";
-
- public const string BACKGROUND_NOTIFICATIONS = "BackgroundNotifications";
-
- [Obsolete("Use new theme system (SELECTED_THEME_NAMES) instead.")]
- public const string SELECTED_THEME_NAME = "SelectedThemeName";
-
- public const string SELECTED_THEME_NAMES = "SelectedThemeNames";
- public const string AVAILABLE_THEME_NAMES = "AvailableThemeNames";
- public const string REQUESTED_COLOUR_SCHEME = "RequestedTheme";
- public const string THEME_FOLDER_NAME = "Themes";
- public const string THEME_METADATA_NAME = "theme.json";
-
- public const string MESSAGE_STYLE_KEY = "MessageStyleKey";
- public const string MESSAGE_STYLE_DEFAULT = "DefaultMessageControlStyle";
-
- public const string TOAST_BACKGROUND_TASK_NAME = "ToastBackgroundTask";
-
- public const string SHOW_HUGE_EMOJI = "ShowHugeEmoji";
- public const bool SHOW_HUGE_EMOJI_DEFAULT = true;
-
- public const string ADJUST_ROLE_COLOURS = "AdjustRoleColours";
- public const bool ADJUST_ROLE_COLOURS_DEFAULT = true;
-
- public const string SHOW_STATUS_GLYPHS = "ShowStatusGlyphs";
- public const bool SHOW_STATUS_GLYPHS_DEFAULT = true;
-
- public const string MINIMUM_CONTRAST = "MinimumContrast";
- public const double MINIMUM_CONTRAST_DEFAULT = 3.5;
- }
-
- public enum MediaTranscodeOptions
- {
- Always,
- WhenNeeded,
- Never
- }
-
- public enum TimestampStyle
- {
- Relative,
- Absolute,
- Both
- }
-}
+using System;
+
+namespace Unicord
+{
+ internal static partial class Constants
+ {
+ public const string MAIN_URL = "https://wamwoowam.co.uk/unicord/";
+
+ public const string TOKEN_IDENTIFIER = "Unicord_Token_New";
+ public const string APP_USER_MODEL_ID = "com.wankerr.Unicord";
+
+ public const string ENABLE_ANALYTICS = "EnableAnalytics";
+ public const string SYNC_CONTACTS = "SyncContacts";
+ public const string ENABLE_SPOILERS = "EnableSpoilers";
+ public const string AUTO_TRANSCODE_MEDIA = "AutoTranscodeMedia_1";
+ public const string WARN_UNSAFE_LINKS = "WarnUnsafeLinks";
+
+ public const string VIDEO_BITRATE = "VideoBitrate";
+ public const uint DEFAULT_VIDEO_BITRATE = 1_115_000u;
+
+ public const string VIDEO_WIDTH = "VideoWidth";
+ public const int DEFAULT_VIDEO_WIDTH = 854;
+
+ public const string VIDEO_HEIGHT = "VideoHeight";
+ public const int DEFAULT_VIDEO_HEIGHT = 480;
+
+ public const string AUDIO_BITRATE = "AudioBitrate";
+ public const uint DEFAULT_AUDIO_BITRATE = 192 * 1000;
+
+ public const string AUDIO_SAMPLERATE = "AudioSampleRate";
+ public const uint DEFAULT_AUDIO_SAMPLERATE = 48000u;
+
+ public const string VIDEO_PROCESSING = "VideoProcessingAlgorithm_1";
+
+ public const string SAVE_PHOTOS = "SavePhotos";
+ public const bool DEFAULT_SAVE_PHOTOS = true;
+
+ public const string VIDEO_PRESERVE_FRAMERATE = "PreserveFrameRate";
+ public const bool DEFAULT_VIDEO_PRESERVE_FRAMERATE = true;
+
+ public const string VERIFY_LOGIN = "HelloForLogin";
+ public const string VERIFY_NSFW = "HelloForNSFW";
+ public const string VERIFY_SETTINGS = "HelloForSettings";
+ public const string AUTHENTICATION_TIME = "AuthenticationTime";
+
+ public const string GIF_AUTOPLAY = "AutoPlayGifs";
+ public const string SAVE_CAPTURED_PHOTOS = "SavedPhotos";
+ public const string TIMESTAMP_STYLE = "TimestampStyle_1";
+
+ public const string BACKGROUND_NOTIFICATIONS_FULL_TRUST = "BackgroundNotifications";
+
+ [Obsolete("Use new theme system (SELECTED_THEME_NAMES) instead.")]
+ public const string SELECTED_THEME_NAME = "SelectedThemeName";
+
+ public const string SELECTED_THEME_NAMES = "SelectedThemeNames";
+ public const string AVAILABLE_THEME_NAMES = "AvailableThemeNames";
+ public const string REQUESTED_COLOUR_SCHEME = "RequestedTheme_1";
+ public const string THEME_FOLDER_NAME = "Themes";
+ public const string THEME_METADATA_NAME = "theme.json";
+
+ public const string MESSAGE_STYLE_KEY = "MessageStyleKey";
+ public const string MESSAGE_STYLE_DEFAULT = "DefaultMessageControlStyle";
+
+ public const string TOAST_BACKGROUND_TASK_NAME = "ToastBackgroundTask";
+ public const string PERIODIC_BACKGROUND_TASK_NAME = "PeriodicNotificationsTask";
+ public const string REALTIME_BACKGROUND_TASK_NAME = "RealtimeNotificationsTask";
+
+ public const string SHOW_HUGE_EMOJI = "ShowHugeEmoji";
+ public const bool SHOW_HUGE_EMOJI_DEFAULT = true;
+
+ public const string ADJUST_ROLE_COLOURS = "AdjustRoleColours";
+ public const bool ADJUST_ROLE_COLOURS_DEFAULT = true;
+
+ public const string SHOW_STATUS_GLYPHS = "ShowStatusGlyphs";
+ public const bool SHOW_STATUS_GLYPHS_DEFAULT = true;
+
+ public const string MINIMUM_CONTRAST = "MinimumContrast";
+ public const double MINIMUM_CONTRAST_DEFAULT = 3.5;
+
+ public const string ENABLE_WEBP = "EnableWebp";
+ public const bool ENABLE_WEBP_DEFAULT = false; // slow as balls
+
+ public const string ENABLE_NOTIFICATIONS = "EnableNotifications";
+ public const bool ENABLE_NOTIFICATIONS_DEFAULT = true;
+
+ public const string ENABLE_DESKTOP_NOTIFICAITONS = "EnableDesktopNotifications";
+ public const bool ENABLE_DESKTOP_NOTIFICAITONS_DEFAULT = true;
+
+ public const string ENABLE_BADGE_COUNT = "EnableBadgeCount";
+ public const bool ENABLE_BADGE_COUNT_DEFAULT = true;
+
+ public const string ENABLE_BADGE_UNREAD = "EnableBadgeUnread";
+ public const bool ENABLE_BADGE_UNREAD_DEFAULT = true;
+
+ public const string ENABLE_LIVE_TILES = "EnableLiveTiles";
+ public const bool ENABLE_LIVE_TILES_DEFAULT = true;
+
+ public const string ENABLE_GUILD_BROWSING = "EnableGuildBrowsing";
+ public const bool ENABLE_GUILD_BROWSING_DEFAULT = false;
+
+ // old resource keys for migration
+ public const string TOKEN_IDENTIFIER_OLD = "Unicord_Token";
+ public const string AUTO_TRANSCODE_MEDIA_OLD = "AutoTranscodeMedia";
+ public const string VIDEO_PROCESSING_OLD = "VideoProcessingAlgorithm";
+ public const string TIMESTAMP_STYLE_OLD = "TimestampStyle";
+ public const string REQUESTED_COLOUR_SCHEME_OLD = "RequestedTheme";
+ }
+
+ internal enum MediaTranscodeOptions
+ {
+ Always,
+ WhenNeeded,
+ Never
+ }
+
+ internal enum TimestampStyle
+ {
+ Relative,
+ Absolute,
+ Both
+ }
+}
diff --git a/Unicord.Universal.Shared/Constants.pub.cs b/Unicord.Universal.Shared/Constants.pub.cs
index 4ec3a9ee..7fa65aa0 100644
--- a/Unicord.Universal.Shared/Constants.pub.cs
+++ b/Unicord.Universal.Shared/Constants.pub.cs
@@ -1,6 +1,6 @@
namespace Unicord
{
- public static partial class Constants
+ internal static partial class Constants
{
#if STORE
public const string APPCENTER_IDENTIFIER = "b87a8458-e7a2-4a68-8e6c-3a2d11d08657";
diff --git a/Unicord.Universal.Shared/Extensions.cs b/Unicord.Universal.Shared/Extensions.cs
new file mode 100644
index 00000000..d63336d9
--- /dev/null
+++ b/Unicord.Universal.Shared/Extensions.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+
+namespace Unicord
+{
+ internal static class Extensions
+ {
+ public static void Deconstruct(this KeyValuePair tuple, out T1 key, out T2 value)
+ {
+ key = tuple.Key;
+ value = tuple.Value;
+ }
+ }
+}
diff --git a/Unicord.Universal.Shared/MutedExtensions.cs b/Unicord.Universal.Shared/MutedExtensions.cs
new file mode 100644
index 00000000..4c646a17
--- /dev/null
+++ b/Unicord.Universal.Shared/MutedExtensions.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Linq;
+using DSharpPlus;
+using DSharpPlus.Entities;
+
+namespace Unicord.Universal.Extensions
+{
+ internal static class MutedExtensions
+ {
+ public static bool IsMuted(this DiscordChannel channel)
+ {
+ if (!(channel.Discord is DiscordClient client))
+ return false;
+
+ if (!client.UserGuildSettings.TryGetValue(channel.GuildId ?? 0, out var settings))
+ return false;
+
+ var channelOverride = settings.ChannelOverrides?.FirstOrDefault(o => o?.ChannelId == channel.Id);
+ if (channelOverride == null)
+ return false;
+
+ if (channelOverride.MuteConfig != null)
+ {
+ var endTime = channelOverride.MuteConfig.EndTime;
+ if (endTime.HasValue && channelOverride.Muted)
+ return endTime.Value > DateTimeOffset.Now;
+ }
+
+ return channelOverride.Muted;
+ }
+
+ public static bool IsMuted(this DiscordGuild guild)
+ {
+ if (!(guild.Discord is DiscordClient client))
+ return false;
+
+ if (!client.UserGuildSettings.TryGetValue(guild.Id, out var settings) || settings == null)
+ return false;
+
+ if (settings.MuteConfig != null)
+ {
+ var endTime = settings.MuteConfig.EndTime;
+ if (endTime.HasValue && settings.Muted)
+ return endTime.Value > DateTimeOffset.Now;
+ }
+
+ return settings.Muted;
+ }
+
+ public static bool IsUnread(this DiscordChannel channel)
+ {
+ if (!(channel.Discord is DiscordClient discord))
+ return false;
+
+ var readState = channel.ReadState;
+
+ // this shit should never happen but apparently it does sometimes, don't question it
+ if (readState == null || readState.Id == 0)
+ return false;
+
+ if (discord == null)
+ return false;
+
+ if (channel.Type == ChannelType.Voice || channel.Type == ChannelType.Category)
+ return false;
+
+ if (channel.Type == ChannelType.Private || channel.Type == ChannelType.Group)
+ {
+ return readState.MentionCount > 0;
+ }
+
+ return (readState.MentionCount > 0 || (channel.LastMessageId != 0 && channel.LastMessageId > readState.LastMessageId));
+ }
+ }
+}
diff --git a/Unicord.Universal.Shared/NotificationUtils.cs b/Unicord.Universal.Shared/NotificationUtils.cs
index e7744516..153d0e37 100644
--- a/Unicord.Universal.Shared/NotificationUtils.cs
+++ b/Unicord.Universal.Shared/NotificationUtils.cs
@@ -1,250 +1,308 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using DSharpPlus;
-using DSharpPlus.Entities;
-using Microsoft.Toolkit.Uwp.Notifications;
-using MomentSharp;
-using WamWooWam.Core;
-using Windows.Data.Xml.Dom;
-using Windows.UI.Notifications;
-
-namespace Unicord.Universal.Shared
-{
- public class NotificationUtils
- {
- public static bool WillShowToast(DiscordMessage message)
- {
- bool willNotify = false;
-
- if (message.MentionedUsers.Any(m => m?.Id == message.Discord.CurrentUser.Id))
- {
- willNotify = true;
- }
-
- if (message.Channel is DiscordDmChannel)
- {
- willNotify = true;
- }
-
- if (message.Channel.Guild != null)
- {
- var usr = message.Channel.Guild.CurrentMember;
- if (message.MentionedRoleIds.Any(r => (usr.RoleIds.Contains(r))) == true)
- {
- willNotify = true;
- }
- }
-
- if (message.Author.Id == message.Discord.CurrentUser.Id)
- {
- willNotify = false;
- }
-
- if ((message.Discord as DiscordClient)?.UserSettings.Status == "dnd")
- {
- willNotify = false;
- }
-
- if (message.Channel.NotificationMuted || !message.Channel.Unread)
- willNotify = false;
-
- return willNotify;
- }
-
-
- public static string GetMessageTitle(DiscordMessage message) => message.Channel.Guild != null ?
- $"{(message.Author as DiscordMember)?.DisplayName ?? message.Author.Username} in {message.Channel.Guild.Name}" :
- $"{message.Author.Username}";
-
- public static string GetMessageContent(DiscordMessage message)
- {
- string messageText = message.Content;
-
- foreach (var user in message.MentionedUsers)
- {
- if (user != null)
- {
- messageText = messageText
- .Replace($"<@{user.Id}>", $"@{user.Username}")
- .Replace($"<@!{user.Id}>", $"@{user.Username}");
- }
- }
-
- if (message.Channel.Guild != null)
- {
- foreach (var channel in message.MentionedChannels)
- {
- messageText = messageText.Replace(channel.Mention, $"#{channel.Name}");
- }
-
- foreach (var roleId in message.MentionedRoleIds)
- {
- var role = message.Channel.Guild.GetRole(roleId);
- if (role != null)
- messageText = messageText.Replace(role.Mention, $"@{role.Name}");
- }
- }
-
- return messageText;
- }
-
- public static string GetChannelHeaderName(DiscordChannel channel)
- {
- if (channel is DiscordDmChannel dmChannel)
- {
- if (dmChannel.Type == ChannelType.Private)
- {
- return $"@{dmChannel.Recipients[0].DisplayName}";
- }
-
- if (dmChannel.Type == ChannelType.Group)
- {
- return dmChannel.Name ?? Strings.NaturalJoin(dmChannel.Recipients.Select(r => r.DisplayName));
- }
- }
-
- if (channel.Guild != null)
- return $"#{channel.Name} - {channel.Guild.Name}";
-
- return $"#{channel.Name}";
- }
-
- public static TileNotification CreateTileNotificationForMessage(DiscordMessage message)
- {
- var tileContentBuilder = new TileContentBuilder()
- .SetBranding(TileBranding.NameAndLogo)
- .AddTile(TileSize.Large)
- .AddTile(TileSize.Medium)
- .AddTile(TileSize.Wide);
-
- if (message.Channel is DiscordDmChannel dm)
- {
- if (!string.IsNullOrEmpty(dm.IconHash))
- tileContentBuilder.SetPeekImage(new Uri(dm.IconUrl));
-
- if (!string.IsNullOrEmpty(dm.Recipient?.AvatarHash))
- tileContentBuilder.SetPeekImage(new Uri(dm.Recipient.GetAvatarUrl(ImageFormat.Png)));
-
- tileContentBuilder.AddAdaptiveTileVisualChild(new AdaptiveText() { Text = GetChannelHeaderName(message.Channel), HintStyle = AdaptiveTextStyle.Base })
- .AddAdaptiveTileVisualChild(new AdaptiveText() { Text = GetMessageContent(message), HintStyle = AdaptiveTextStyle.Caption, HintWrap = true })
- .SetDisplayName(new Moment(message.Timestamp.UtcDateTime).Calendar());
- }
- else
- {
- if (!string.IsNullOrWhiteSpace(message.Channel.Guild.IconUrl))
- tileContentBuilder.SetPeekImage(new Uri(message.Channel.Guild.IconUrl + "?size=1024"));
-
- tileContentBuilder.AddAdaptiveTileVisualChild(new AdaptiveText() { Text = $"#{message.Channel.Name}", HintStyle = AdaptiveTextStyle.Base })
- .AddAdaptiveTileVisualChild(new AdaptiveText() { Text = message.Channel.Guild.Name, HintStyle = AdaptiveTextStyle.Body })
- .AddAdaptiveTileVisualChild(new AdaptiveText() { Text = GetMessageContent(message), HintStyle = AdaptiveTextStyle.Caption, HintWrap = true })
- .SetDisplayName(new Moment(message.Timestamp.UtcDateTime).Calendar());
- }
-
- var tileContent = tileContentBuilder.GetTileContent();
- var doc = new XmlDocument();
- doc.LoadXml(tileContent.GetContent());
-
- return new TileNotification(doc);
- }
-
- public static TileNotification CreateTileNotificationForChannel(DiscordChannel channel)
- {
- var tileContentBuilder = new TileContentBuilder()
- .SetBranding(TileBranding.NameAndLogo)
- .AddTile(TileSize.Large)
- .AddTile(TileSize.Medium)
- .AddTile(TileSize.Wide);
-
- if (channel is DiscordDmChannel dm)
- {
- if (!string.IsNullOrEmpty(dm.IconHash))
- tileContentBuilder.SetPeekImage(new Uri(dm.IconUrl));
-
- if (!string.IsNullOrEmpty(dm.Recipient?.AvatarHash))
- tileContentBuilder.SetPeekImage(new Uri(dm.Recipient.AvatarUrl));
-
- tileContentBuilder.AddAdaptiveTileVisualChild(new AdaptiveText() { Text = GetChannelHeaderName(channel), HintStyle = AdaptiveTextStyle.Base });
- }
- else
- {
- if (!string.IsNullOrWhiteSpace(channel.Guild.IconUrl))
- tileContentBuilder.SetPeekImage(new Uri(channel.Guild.IconUrl + "?size=1024"));
-
- tileContentBuilder.AddAdaptiveTileVisualChild(new AdaptiveText() { Text = $"#{channel.Name}", HintStyle = AdaptiveTextStyle.Base })
- .AddAdaptiveTileVisualChild(new AdaptiveText() { Text = channel.Guild.Name, HintStyle = AdaptiveTextStyle.Body });
- }
-
- var tileContent = tileContentBuilder.GetTileContent();
- var doc = new XmlDocument();
- doc.LoadXml(tileContent.GetContent());
-
- return new TileNotification(doc);
- }
-
- public static ToastNotification CreateToastNotificationForMessage(DiscordMessage message)
- {
- var title = GetMessageTitle(message);
- var text = GetMessageContent(message);
- var channelName = GetChannelHeaderName(message.Channel);
-
- var animated = message.Author.AvatarHash?.StartsWith("a_") ?? false;
- var avatarUrl = message.Author.GetAvatarUrl(animated ? ImageFormat.Gif : ImageFormat.Png, 128);
- var replyString = message.Channel is DiscordDmChannel ? $"Reply to @{message.Author.Username}..." : $"Message #{message.Channel.Name}...";
-
- var builder = new ToastContentBuilder()
- .AddHeader(message.ChannelId.ToString(), channelName, $"-channelId={message.ChannelId}")
- .AddAppLogoOverride(new Uri(avatarUrl), ToastGenericAppLogoCrop.Circle)
- .AddText(title, AdaptiveTextStyle.Title)
- .AddText(text, AdaptiveTextStyle.Caption)
- .AddInputTextBox("tbReply", replyString)
- .AddButton("tbReply", "Reply", ToastActivationType.Background, $"-channelId={message.ChannelId}")
- .AddToastActivationInfo($"-channelId={message.ChannelId} -messageId={message.Id}", ToastActivationType.Foreground)
- .AddCustomTimeStamp(message.Timestamp.DateTime);
-
- if (GetToastThumbnail(message, out var width, out var height, out var proxyUrl))
- {
- Drawing.ScaleProportions(ref width, ref height, 640, 360);
- builder.AddHeroImage(new Uri(proxyUrl + $"?format=jpeg&width={(int)width}&height={(int)height}"));
- }
-
- var toastContent = builder.GetToastContent();
- var doc = new XmlDocument();
- doc.LoadXml(toastContent.GetContent());
- return new ToastNotification(doc)
- {
- NotificationMirroring = NotificationMirroring.Allowed,
- Group = message.Channel.Id.ToString(),
- RemoteId = message.Id.ToString(),
- };
- }
-
- private static bool GetToastThumbnail(DiscordMessage message, out double width, out double height, out string proxyUrl)
- {
- width = 0;
- height = 0;
- proxyUrl = null;
-
- var attach = message.Attachments.FirstOrDefault(a => a.Height != 0);
- var embed = message.Embeds.FirstOrDefault(e => e.Thumbnail != null || e.Image != null || e.Video != null);
- if (attach != null)
- {
- width = attach.Width;
- height = attach.Height;
- proxyUrl = attach.ProxyUrl;
- return true;
- }
- else if (embed != null)
- {
- width = embed.Thumbnail?.Width ?? embed.Image?.Width ?? embed.Video.Width;
- height = embed.Thumbnail?.Height ?? embed.Image?.Height ?? embed.Video.Height;
- proxyUrl = (embed.Thumbnail?.ProxyUrl ?? embed.Image?.ProxyUrl ?? embed.Video.Url).ToString();
- return true;
- }
-
- return false;
- }
- }
-}
+using System;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Web;
+using DSharpPlus;
+using DSharpPlus.Entities;
+using Microsoft.Toolkit.Uwp.Notifications;
+using MomentSharp;
+using Unicord.Universal.Extensions;
+using WamWooWam.Core;
+using Windows.Data.Xml.Dom;
+using Windows.UI.Notifications;
+
+namespace Unicord.Universal.Shared
+{
+ internal class NotificationUtils
+ {
+ public static bool WillShowToast(BaseDiscordClient client, DiscordMessage message)
+ {
+ if (message.Author.IsCurrent)
+ return false;
+
+ if (client is DiscordClient discord && discord.UserSettings?.Status == "dnd")
+ return false;
+
+ if (message.Channel.IsMuted() || (message.Channel.Guild != null && message.Channel.Guild.IsMuted()))
+ return false;
+
+ bool willNotify = false;
+
+ if (message.MentionedUsers.Any(m => m?.Id == message.Discord.CurrentUser.Id))
+ {
+ willNotify = true;
+ }
+
+ if (message.Channel is DiscordDmChannel)
+ {
+ willNotify = true;
+ }
+
+ if (message.Channel.Guild != null)
+ {
+ var usr = message.Channel.Guild.CurrentMember;
+ if (message.MentionedRoleIds.Any(r => (usr.RoleIds.Contains(r))) == true)
+ {
+ willNotify = true;
+ }
+ }
+
+ return willNotify;
+ }
+
+ private static readonly Regex UserRegex = new Regex(@"<@!?(\d+)>", RegexOptions.ECMAScript | RegexOptions.Compiled);
+ private static readonly Regex RoleRegex = new Regex(@"<@&(\d+)>", RegexOptions.ECMAScript | RegexOptions.Compiled);
+ private static readonly Regex ChannelRegex = new Regex(@"<#(\d+)>", RegexOptions.ECMAScript | RegexOptions.Compiled);
+ private static readonly Regex EmojiRegex = new Regex(@"", RegexOptions.ECMAScript | RegexOptions.Compiled);
+ private static readonly Regex TimestampRegex = new Regex(@"", RegexOptions.ECMAScript | RegexOptions.Compiled);
+ private static readonly Regex SpoilerRegex = new Regex("\\|\\|((?:.|\\r|\\n)*?)\\|\\|", RegexOptions.ECMAScript | RegexOptions.Multiline | RegexOptions.Compiled);
+
+ public static string GetMessageTitle(DiscordMessage message) => message.Channel.Guild != null ?
+ $"{message.Author.DisplayName} in {message.Channel.Guild.Name}" :
+ $"{message.Author.DisplayName}";
+
+ public static string GetMessageContent(BaseDiscordClient client, DiscordMessage message)
+ {
+ string messageText = message.Content;
+
+ messageText = SpoilerRegex.Replace(messageText, (match) => new string('\x2B1B', match.Value.Length - 4));
+
+ messageText = UserRegex.Replace(messageText, (match) =>
+ {
+ if (ulong.TryParse(match.Groups[1].Value, out var id))
+ {
+ if (message.Channel.Guild?.Members.TryGetValue(id, out var member) == true)
+ return $"@{member.DisplayName}";
+
+ if (client is DiscordClient discord && discord.TryGetCachedUser(id, out var user))
+ return $"@{user.DisplayName}";
+
+ return "@unknown-user";
+ }
+
+ return match.Value;
+ });
+
+ messageText = ChannelRegex.Replace(messageText, (match) =>
+ {
+ if (ulong.TryParse(match.Groups[1].Value, out var id))
+ {
+ if (message.Channel.Guild?.Channels.TryGetValue(id, out var channel) == true)
+ return $"#{channel.Name}";
+
+ if (client is DiscordClient discord && discord.TryGetCachedChannel(id, out channel))
+ return $"#{channel.Name}";
+
+ return "#unknown-channel";
+ }
+
+ return match.Value;
+ });
+
+ messageText = EmojiRegex.Replace(messageText, (match) =>
+ {
+ if (!string.IsNullOrWhiteSpace(match.Groups[1].Value))
+ return $":{match.Groups[1].Value}:";
+
+ return match.Value;
+ });
+
+ if (message.Channel.Guild != null)
+ {
+ messageText = RoleRegex.Replace(messageText, (match) =>
+ {
+ if (ulong.TryParse(match.Groups[1].Value, out var id))
+ {
+ if (message.Channel.Guild.Roles.TryGetValue(id, out var role))
+ return $"@{role.Name}";
+
+ return "@unknown-role";
+ }
+
+ return match.Value;
+ });
+ }
+ if (messageText.Length > 128)
+ messageText = messageText.Substring(0, 125) + "...";
+
+ return messageText;
+ }
+
+ public static string GetChannelHeaderName(DiscordChannel channel)
+ {
+ if (channel is DiscordDmChannel dmChannel)
+ {
+ if (dmChannel.Type == ChannelType.Private)
+ {
+ if (dmChannel.Recipients == null || dmChannel.Recipients.Count == 0)
+ return "Invalid DM channel";
+
+ return $"@{dmChannel.Recipients[0].DisplayName}";
+ }
+
+ if (dmChannel.Type == ChannelType.Group)
+ {
+ return dmChannel.Name ?? Strings.NaturalJoin(dmChannel.Recipients.Select(r => r.DisplayName));
+ }
+ }
+
+ if (channel.Guild != null)
+ return $"#{channel.Name} - {channel.Guild.Name}";
+
+ return $"#{channel.Name}";
+ }
+
+ public static TileNotification CreateTileNotificationForMessage(BaseDiscordClient client, DiscordMessage message)
+ {
+ var tileContentBuilder = new TileContentBuilder()
+ .SetBranding(TileBranding.NameAndLogo)
+ .AddTile(TileSize.Large)
+ .AddTile(TileSize.Medium)
+ .AddTile(TileSize.Wide);
+
+ if (message.Channel is DiscordDmChannel dm)
+ {
+ if (!string.IsNullOrEmpty(dm.IconHash))
+ tileContentBuilder.SetPeekImage(new Uri(dm.IconUrl));
+
+ tileContentBuilder.SetPeekImage(new Uri(message.Author.GetAvatarUrl(ImageFormat.Png)));
+
+ tileContentBuilder.AddAdaptiveTileVisualChild(new AdaptiveText() { Text = GetChannelHeaderName(message.Channel), HintStyle = AdaptiveTextStyle.Base })
+ .AddAdaptiveTileVisualChild(new AdaptiveText() { Text = GetMessageContent(client, message), HintStyle = AdaptiveTextStyle.Caption, HintWrap = true })
+ .SetDisplayName(new Moment(message.Timestamp.UtcDateTime).Calendar());
+ }
+ else if (message.Channel is not null)
+ {
+ if (!string.IsNullOrWhiteSpace(message.Channel?.Guild.IconUrl))
+ tileContentBuilder.SetPeekImage(new Uri(message.Channel.Guild.IconUrl + "?size=512"));
+
+ tileContentBuilder.AddAdaptiveTileVisualChild(new AdaptiveText() { Text = $"#{message.Channel.Name}", HintStyle = AdaptiveTextStyle.Base })
+ .AddAdaptiveTileVisualChild(new AdaptiveText() { Text = message.Channel.Guild.Name, HintStyle = AdaptiveTextStyle.Body })
+ .AddAdaptiveTileVisualChild(new AdaptiveText() { Text = GetMessageContent(client, message), HintStyle = AdaptiveTextStyle.Caption, HintWrap = true })
+ .SetDisplayName(new Moment(message.Timestamp.UtcDateTime).Calendar());
+ }
+
+ var tileContent = tileContentBuilder.GetTileContent();
+ var doc = new XmlDocument();
+ doc.LoadXml(tileContent.GetContent());
+
+ return new TileNotification(doc);
+ }
+
+ public static TileNotification CreateTileNotificationForChannel(DiscordChannel channel)
+ {
+ var tileContentBuilder = new TileContentBuilder()
+ .SetBranding(TileBranding.NameAndLogo)
+ .AddTile(TileSize.Large)
+ .AddTile(TileSize.Medium)
+ .AddTile(TileSize.Wide);
+
+ if (channel is DiscordDmChannel dm)
+ {
+ if (!string.IsNullOrEmpty(dm.IconHash))
+ tileContentBuilder.SetPeekImage(new Uri(dm.IconUrl));
+
+ if (dm.Type == ChannelType.Private && dm.Recipients.Count > 0)
+ tileContentBuilder.SetPeekImage(new Uri(dm.Recipients[0].AvatarUrl));
+
+ tileContentBuilder.AddAdaptiveTileVisualChild(new AdaptiveText()
+ {
+ Text = GetChannelHeaderName(channel),
+ HintStyle = AdaptiveTextStyle.Base
+ });
+ }
+ else
+ {
+ if (!string.IsNullOrWhiteSpace(channel.Guild.IconUrl))
+ tileContentBuilder.SetPeekImage(new Uri(channel.Guild.IconUrl + "?size=512"));
+
+ tileContentBuilder.AddAdaptiveTileVisualChild(new AdaptiveText() { Text = $"#{channel.Name}", HintStyle = AdaptiveTextStyle.Base })
+ .AddAdaptiveTileVisualChild(new AdaptiveText() { Text = channel.Guild.Name, HintStyle = AdaptiveTextStyle.Body });
+ }
+
+ var tileContent = tileContentBuilder.GetTileContent();
+ var doc = new XmlDocument();
+ doc.LoadXml(tileContent.GetContent());
+
+ return new TileNotification(doc);
+ }
+
+ public static ToastNotification CreateToastNotificationForMessage(BaseDiscordClient client, DiscordMessage message, bool isSuppressed = false)
+ {
+ var title = GetMessageTitle(message);
+ var text = GetMessageContent(client, message);
+ var channelName = GetChannelHeaderName(message.Channel);
+
+ var avatarUrl = message.Author.GetAvatarUrl(ImageFormat.Png, 128);
+ var replyString = message.Channel is DiscordDmChannel ? $"Reply to @{message.Author.DisplayName}..." : $"Message #{message.Channel.Name}...";
+
+ var builder = new ToastContentBuilder()
+ .AddHeader(message.ChannelId.ToString(), channelName, $"-channelId={message.ChannelId}")
+ .AddAppLogoOverride(new Uri(avatarUrl), ToastGenericAppLogoCrop.Circle)
+ .AddText(title, AdaptiveTextStyle.Title)
+ .AddText(text, AdaptiveTextStyle.Caption)
+ .AddInputTextBox("tbReply", replyString)
+ .AddButton("tbReply", "Reply", ToastActivationType.Background, $"-channelId={message.ChannelId}")
+ .AddToastActivationInfo($"-channelId={message.ChannelId} -messageId={message.Id}", ToastActivationType.Foreground)
+ .AddAttributionText("from Discord")
+ .AddCustomTimeStamp(message.Timestamp.DateTime)
+ .AddAudio(new Uri("ms-winsoundevent:Notification.IM"));
+
+ if (GetToastThumbnail(message, out var width, out var height, out var proxyUrl) &&
+ !Path.GetFileName(proxyUrl).StartsWith("SPOILER_", StringComparison.InvariantCultureIgnoreCase))
+ {
+ Drawing.ScaleProportions(ref width, ref height, 728, 360);
+
+ var uri = new UriBuilder(proxyUrl);
+ var query = HttpUtility.ParseQueryString(uri.Query);
+ query["format"] = "jpeg";
+ query["width"] = ((int)width).ToString(CultureInfo.InvariantCulture);
+ query["height"] = ((int)height).ToString(CultureInfo.InvariantCulture);
+ uri.Query = query.ToString();
+
+ builder.AddHeroImage(uri.Uri);
+ }
+
+ var toastContent = builder.GetToastContent();
+
+ var doc = new XmlDocument();
+ doc.LoadXml(toastContent.GetContent());
+
+ return new ToastNotification(doc)
+ {
+ NotificationMirroring = NotificationMirroring.Allowed,
+ Tag = message.Id.ToString(),
+ Group = message.Channel.Id.ToString(CultureInfo.InvariantCulture),
+ SuppressPopup = isSuppressed
+ };
+ }
+
+ private static bool GetToastThumbnail(DiscordMessage message, out double width, out double height, out string proxyUrl)
+ {
+ width = 0;
+ height = 0;
+ proxyUrl = null;
+
+ var attach = message.Attachments.FirstOrDefault(a => a.Height != 0);
+ var embed = message.Embeds.FirstOrDefault(e => e.Thumbnail != null || e.Image != null || e.Video != null);
+ if (attach != null && attach.Width != null)
+ {
+ width = attach.Width.Value;
+ height = attach.Height.Value;
+ proxyUrl = attach.ProxyUrl;
+ return true;
+ }
+ else if (embed != null)
+ {
+ width = embed.Thumbnail?.Width ?? embed.Image?.Width ?? embed.Video.Width;
+ height = embed.Thumbnail?.Height ?? embed.Image?.Height ?? embed.Video.Height;
+ proxyUrl = (embed.Thumbnail?.ProxyUrl.ToUri() ?? embed.Image?.ProxyUrl.ToUri() ?? embed.Video.Url).ToString();
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/Unicord.Universal.Shared/SecondaryTileManager.cs b/Unicord.Universal.Shared/SecondaryTileManager.cs
index b29910a9..046eb60c 100644
--- a/Unicord.Universal.Shared/SecondaryTileManager.cs
+++ b/Unicord.Universal.Shared/SecondaryTileManager.cs
@@ -1,19 +1,15 @@
using System;
using System.Collections.Concurrent;
-using System.Collections.Generic;
using System.Linq;
-using System.Text;
-using System.Threading;
using System.Threading.Tasks;
using DSharpPlus;
using DSharpPlus.Entities;
-using Microsoft.Toolkit.Uwp.Notifications;
using Windows.UI.Notifications;
using Windows.UI.StartScreen;
namespace Unicord.Universal.Shared
{
- public class SecondaryTileManager
+ internal class SecondaryTileManager
{
private readonly DiscordClient _discord = null;
private readonly ConcurrentDictionary _tileStorage;
@@ -47,12 +43,12 @@ public async Task InitialiseAsync()
}
}
- public Task HandleMessageAsync(DiscordMessage message)
+ public Task HandleMessageAsync(DiscordClient client, DiscordMessage message)
{
if (_tileStorage.TryGetValue(message.Channel.Id, out var tile))
{
var updater = TileUpdateManager.CreateTileUpdaterForSecondaryTile(tile.TileId);
- var tileNotification = NotificationUtils.CreateTileNotificationForMessage(message);
+ var tileNotification = NotificationUtils.CreateTileNotificationForMessage(client, message);
updater.EnableNotificationQueue(true);
updater.Update(tileNotification);
}
diff --git a/Unicord.Universal.Shared/TileManager.cs b/Unicord.Universal.Shared/TileManager.cs
index e9063e9a..c838982c 100644
--- a/Unicord.Universal.Shared/TileManager.cs
+++ b/Unicord.Universal.Shared/TileManager.cs
@@ -1,103 +1,112 @@
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using DSharpPlus;
-using DSharpPlus.Entities;
-using Microsoft.Toolkit.Uwp.Notifications;
-using Windows.UI.Notifications;
-
-namespace Unicord.Universal.Shared
-{
- public class TileManager
- {
- private readonly DiscordClient _discord = null;
- private readonly TileUpdater _tileUpdater = null;
- private readonly List _currentUnreads = null;
- private readonly SemaphoreSlim _semaphore;
-
- public TileManager(DiscordClient client)
- {
- _discord = client;
- _tileUpdater = TileUpdateManager.CreateTileUpdaterForApplication("App");
- _currentUnreads = new List();
- _semaphore = new SemaphoreSlim(1, 1);
- }
-
- public async Task InitialiseAsync()
- {
- await _semaphore.WaitAsync();
- try
- {
- var unreads = await FetchUnreadMessagesAsync();
- _currentUnreads.AddRange(unreads);
-
- Update();
- }
- finally
- {
- _semaphore.Release();
- }
- }
-
- public async Task HandleMessageAsync(DiscordMessage message)
- {
- await _semaphore.WaitAsync();
- try
- {
- _currentUnreads.RemoveAll(m => m.Channel == message.Channel);
- _currentUnreads.Insert(0, message);
-
- Update();
- }
- finally
- {
- _semaphore.Release();
- }
- }
-
- public async Task HandleAcknowledgeAsync(DiscordChannel channel)
- {
- await _semaphore.WaitAsync();
- try
- {
- _currentUnreads.RemoveAll(m => m.Channel == channel);
-
- Update();
- }
- finally
- {
- _semaphore.Release();
- }
- }
-
- private void Update()
- {
- _tileUpdater.EnableNotificationQueue(true);
- _tileUpdater.Clear();
-
- foreach (var message in _currentUnreads.Take(5))
- {
- var tileContent = NotificationUtils.CreateTileNotificationForMessage(message);
- _tileUpdater.Update(tileContent);
- }
- }
-
- private async Task> FetchUnreadMessagesAsync()
- {
- var unreadChannelTasks = _discord.PrivateChannels.Values
- .Where(c => c.ReadState != null && c.ReadState.Unread && c.ReadState.LastMessageId != 0)
- .Take(5)
- .Select(c => c.GetMessagesAroundAsync(c.ReadState.LastMessageId, 10)
- .ContinueWith(t => (messageId: c.ReadState.LastMessageId, messages: t.Result), TaskContinuationOptions.OnlyOnRanToCompletion));
- var channelMessages = await Task.WhenAll(unreadChannelTasks);
- return channelMessages.Select(x => x.messages.FirstOrDefault(m => m.Id > x.messageId)).Where(m => m != null)
- .Concat(await _discord.GetMentionsAsync(5))
- .OrderByDescending(m => m.Id)
- .ToList();
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using DSharpPlus;
+using DSharpPlus.Entities;
+using Unicord.Universal.Extensions;
+using Windows.UI.Notifications;
+
+namespace Unicord.Universal.Shared
+{
+ internal class TileManager
+ {
+ private readonly DiscordClient _discord = null;
+ private readonly TileUpdater _tileUpdater = null;
+ private readonly List _currentUnreads = null;
+ private readonly SemaphoreSlim _semaphore;
+
+ public TileManager(DiscordClient client)
+ {
+ _discord = client;
+ _tileUpdater = TileUpdateManager.CreateTileUpdaterForApplication("App");
+ _currentUnreads = new List();
+ _semaphore = new SemaphoreSlim(1, 1);
+ }
+
+ public async Task InitialiseAsync()
+ {
+ await _semaphore.WaitAsync();
+
+ try
+ {
+ await foreach (var msg in this.FetchUnreadMessages())
+ _currentUnreads.Add(msg);
+
+ Update();
+ }
+ finally
+ {
+ _semaphore.Release();
+ }
+ }
+
+ public async Task HandleMessageAsync(DiscordMessage message)
+ {
+ await _semaphore.WaitAsync();
+
+ try
+ {
+ _currentUnreads.RemoveAll(m => m.Channel == message.Channel);
+ _currentUnreads.Insert(0, message);
+
+ Update();
+ }
+ finally
+ {
+ _semaphore.Release();
+ }
+ }
+
+ public async Task HandleAcknowledgeAsync(DiscordChannel channel)
+ {
+ await _semaphore.WaitAsync();
+
+ try
+ {
+ _currentUnreads.RemoveAll(m => m.Channel == channel);
+
+ Update();
+ }
+ finally
+ {
+ _semaphore.Release();
+ }
+ }
+
+ private void Update()
+ {
+ //_tileUpdater.EnableNotificationQueue(true);
+ _tileUpdater.Clear();
+
+ foreach (var message in _currentUnreads.OrderByDescending(d => d.CreationTimestamp).Take(5))
+ {
+ var tileContent = NotificationUtils.CreateTileNotificationForMessage(_discord, message);
+ _tileUpdater.Update(tileContent);
+ }
+ }
+
+ private async IAsyncEnumerable FetchUnreadMessages()
+ {
+ var count = 0;
+ foreach (var (_, item) in _discord.PrivateChannels)
+ {
+ if (!item.IsUnread())
+ continue;
+
+ count++;
+ if (count > 5)
+ break;
+
+ var messages = await item.GetMessagesAroundAsync(item.ReadState.LastMessageId, 5);
+ foreach (var msg in messages)
+ yield return msg;
+ }
+
+ var mentions = await _discord.GetMentionsAsync(5);
+ foreach (var mention in mentions)
+ yield return mention;
+ }
+ }
+}
diff --git a/Unicord.Universal.Shared/ToastManager.cs b/Unicord.Universal.Shared/ToastManager.cs
index bd4dbd07..e7a1474b 100644
--- a/Unicord.Universal.Shared/ToastManager.cs
+++ b/Unicord.Universal.Shared/ToastManager.cs
@@ -1,25 +1,37 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
+using System.Linq;
+using DSharpPlus;
using DSharpPlus.Entities;
using Windows.UI.Notifications;
namespace Unicord.Universal.Shared
{
- public class ToastManager
+ internal class ToastManager
{
private ToastNotifier _toastNotifier = null;
private ToastNotificationHistory _toastHistory;
public ToastManager()
{
+#if WINDOWS_UWP
+ _toastNotifier = ToastNotificationManager.CreateToastNotifier();
+#else
_toastNotifier = ToastNotificationManager.CreateToastNotifier("App");
+#endif
_toastHistory = ToastNotificationManager.History;
}
- public void HandleMessage(DiscordMessage message)
+ public void HandleMessage(DiscordClient client, DiscordMessage message, bool isSuppressed)
{
- var notification = NotificationUtils.CreateToastNotificationForMessage(message);
+ var notification = NotificationUtils.CreateToastNotificationForMessage(client, message, isSuppressed);
+ _toastNotifier.Show(notification);
+ }
+
+ public void HandleMessageUpdated(DiscordClient client, DiscordMessage message)
+ {
+ var existingToast = _toastHistory.GetHistory().FirstOrDefault(t => t.Tag == message.Id.ToString());
+ if (existingToast == null) return;
+
+ var notification = NotificationUtils.CreateToastNotificationForMessage(client, message, true);
_toastNotifier.Show(notification);
}
diff --git a/Unicord.Universal.Shared/Unicord.Universal.Shared.projitems b/Unicord.Universal.Shared/Unicord.Universal.Shared.projitems
index c5777b71..6d19ef9b 100644
--- a/Unicord.Universal.Shared/Unicord.Universal.Shared.projitems
+++ b/Unicord.Universal.Shared/Unicord.Universal.Shared.projitems
@@ -1,20 +1,22 @@
-
-
-
- $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
- true
- 118f9d67-9235-4fc6-bf23-9abe0cd693da
-
-
- Unicord.Universal.Shared
-
-
-
-
-
-
-
-
-
-
+
+
+
+ $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
+ true
+ 118f9d67-9235-4fc6-bf23-9abe0cd693da
+
+
+ Unicord.Universal.Shared
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Unicord.Universal.Voice/.clang-format b/Unicord.Universal.Voice/.clang-format
deleted file mode 100644
index 7c14d44d..00000000
--- a/Unicord.Universal.Voice/.clang-format
+++ /dev/null
@@ -1,47 +0,0 @@
-# Visual Studio generated .clang-format file
-
-# The style options in this file are a best effort attempt to replicate the
-# current IDE formatting configuration from Tools > Options. The following
-# style options, however, should be verified:
-# AfterClass, AfterControlStatement, AfterEnum, AfterFunction, AfterNamespace,
-# AfterStruct, AfterUnion
-
-BasedOnStyle: LLVM
-AccessModifierOffset: -4
-AlignAfterOpenBracket: DontAlign
-AllowShortBlocksOnASingleLine: true
-AllowShortFunctionsOnASingleLine: All
-BraceWrapping:
- AfterClass: false # TODO: verify
- AfterControlStatement: false # TODO: verify
- AfterEnum: false # TODO: verify
- AfterFunction: false # TODO: verify
- AfterNamespace: false # TODO: verify
- AfterStruct: false # TODO: verify
- AfterUnion: false # TODO: verify
- BeforeCatch: true
- BeforeElse: true
- IndentBraces: false
- SplitEmptyFunction: true
- SplitEmptyRecord: true
-BreakBeforeBraces: Custom
-ColumnLimit: 0
-Cpp11BracedListStyle: false
-DerivePointerAlignment: true
-FixNamespaceComments: false
-IndentCaseLabels: false
-IndentPPDirectives: None
-IndentWidth: 4
-MaxEmptyLinesToKeep: 10
-NamespaceIndentation: All
-SortIncludes: false
-SortUsingDeclarations: true
-SpaceAfterCStyleCast: false
-SpaceBeforeAssignmentOperators: true
-SpaceBeforeParens: ControlStatements
-SpaceInEmptyParentheses: false
-SpacesInCStyleCastParentheses: false
-SpacesInParentheses: false
-SpacesInSquareBrackets: false
-TabWidth: 4
-UseTab: false
diff --git a/Unicord.Universal.Voice/AudioFormat.h b/Unicord.Universal.Voice/AudioFormat.h
deleted file mode 100644
index 820443e2..00000000
--- a/Unicord.Universal.Voice/AudioFormat.h
+++ /dev/null
@@ -1,132 +0,0 @@
-#pragma once
-#include
-#include
-#include
-#include
-
-namespace winrt::Unicord::Universal::Voice::Interop {
- enum VoiceApplication {
- music = OPUS_APPLICATION_AUDIO,
- voip = OPUS_APPLICATION_VOIP,
- low_latency = OPUS_APPLICATION_RESTRICTED_LOWDELAY
- };
-
- struct VoicePacket {
- public:
- VoicePacket() {}
- VoicePacket(std::vector packet_bytes, uint32_t packet_duration, bool isSilence = false) {
- bytes = packet_bytes;
- duration = packet_duration;
- is_silence = isSilence;
-
- std::bitset<12> set;
- }
-
- std::vector bytes;
- uint32_t duration = 0;
- bool is_silence = false;
- };
-
- struct PCMPacket {
- PCMPacket() {}
- PCMPacket(gsl::span packet_bytes, uint32_t packet_duration, bool isSilence = false) {
- bytes = packet_bytes;
- duration = packet_duration;
- is_silence = isSilence;
- }
-
- gsl::span bytes;
- uint32_t duration = 0;
- bool is_float = false;
- bool is_silence = false;
- };
-
- struct AudioFormat {
- public:
- AudioFormat(uint32_t sampleRate = 48000, uint32_t channelCount = 2, VoiceApplication app = music) {
- sample_rate = sampleRate;
- channel_count = channelCount;
- application = app;
- }
-
- uint32_t sample_rate = 0;
- uint32_t channel_count = 0;
- VoiceApplication application = voip;
-
- inline bool operator==(AudioFormat& lhs) noexcept {
- return (lhs.sample_rate == sample_rate) && (lhs.channel_count == channel_count) && (lhs.application == application);
- }
-
- inline bool operator!=(AudioFormat& lhs) noexcept {
- return !(lhs == *this);
- }
-
- inline size_t CalculateSampleSize(uint32_t duration) noexcept {
- return duration * channel_count * (sample_rate / 1000) * 2;
- }
-
- inline size_t CalculateSampleSizeF(uint32_t duration) noexcept {
- return duration * channel_count * (sample_rate / 1000) * 4;
- }
-
- inline size_t GetMaxBufferSize() noexcept {
- return 120 * (sample_rate / 1000);
- }
-
- inline uint32_t CalculateSampleDuration(uint32_t sampleSize) noexcept {
- return sampleSize / (sample_rate / 1000) / channel_count / 2;
- }
-
- inline uint32_t CalculateSampleDurationF(uint32_t sampleSize) noexcept {
- return sampleSize / (sample_rate / 1000) / channel_count / 4;
- }
-
- inline size_t CalculateFrameSize(uint32_t sampleDuration) noexcept {
- return sampleDuration * (sample_rate / 1000);
- }
-
- inline size_t SampleCountToSampleSize(size_t count) noexcept {
- return count * channel_count * 2;
- }
-
- inline size_t SampleCountToSampleSizeF(size_t count) noexcept {
- return count * channel_count * 4;
- }
- };
-
- struct AudioSource {
- public:
- AudioSource() {}
- AudioSource(uint32_t ssrc) {
- this->ssrc = ssrc;
- }
-
- void Initialise(AudioFormat new_format) {
- int error = 0;
-
- if (decoder != nullptr) {
- opus_decoder_destroy(decoder);
- }
- this->decoder = opus_decoder_create(new_format.sample_rate, new_format.channel_count, &error);
- this->format = new_format;
- }
-
- inline bool IsInitialised() {
- return decoder != nullptr;
- }
-
- ~AudioSource() {
- std::cout << "Freeing AudioSource\n";
- opus_decoder_destroy(decoder);
- decoder = nullptr;
- }
-
- uint32_t ssrc = 0;
- uint64_t user_id = 0;
- uint16_t seq = 0;
- uint64_t packets_lost = 0;
- bool is_speaking = false;
- AudioFormat format;
- OpusDecoder* decoder = nullptr;
- };
-}
diff --git a/Unicord.Universal.Voice/AudioRenderer.cpp b/Unicord.Universal.Voice/AudioRenderer.cpp
deleted file mode 100644
index 2303897a..00000000
--- a/Unicord.Universal.Voice/AudioRenderer.cpp
+++ /dev/null
@@ -1,271 +0,0 @@
-#include "pch.h"
-#include "AudioRenderer.h"
-#include "VoiceClient.h"
-
-using namespace winrt::Windows::Foundation;
-using namespace winrt::Windows::Media;
-using namespace winrt::Windows::Media::Audio;
-using namespace winrt::Windows::Media::Capture;
-using namespace winrt::Windows::Media::Devices;
-using namespace winrt::Windows::Media::Render;
-using namespace winrt::Windows::Media::MediaProperties;
-using namespace winrt::Windows::Devices::Enumeration;
-
-namespace winrt::Unicord::Universal::Voice::Render
-{
- AudioRenderer::AudioRenderer(winrt::Unicord::Universal::Voice::implementation::VoiceClient* client)
- {
- voice_client = client;
- buffer_length = client->audio_format.CalculateSampleSize(20);
- pcm_buffer = new uint8_t[buffer_length]{ 0 };
- }
-
- void AudioRenderer::Initialise(hstring preferred_render_device_id, hstring preferred_capture_device_id)
- {
- hstring render_device_id = L"";
- hstring capture_device_id = L"";
- if (!preferred_render_device_id.empty()) {
- render_device_id = preferred_render_device_id;
- }
-
- if (!preferred_capture_device_id.empty()) {
- capture_device_id = preferred_capture_device_id;
- }
-
- std::unique_lock in_lock(input_mutex);
- std::unique_lock out_lock(output_mutex);
-
- AudioEncodingProperties audio_format = AudioEncodingProperties::CreatePcm(voice_client->audio_format.sample_rate, voice_client->audio_format.channel_count, 16);
- AudioGraphSettings settings{ AudioRenderCategory::Communications };
- settings.EncodingProperties(audio_format);
-
- // this is slightly painful ngl
- if (!render_device_id.empty()) {
- DeviceInformation render_device_info = DeviceInformation::CreateFromIdAsync(render_device_id).get();
- settings.PrimaryRenderDevice(render_device_info);
- }
-
- if (render_graph == nullptr) {
- auto result = AudioGraph::CreateAsync(settings).get();
- if (result.Status() != AudioGraphCreationStatus::Success) { // why not just throw an exception for me?
- throw hresult_error(E_FAIL, L"Failed to initialize audio output device");
- }
- render_graph = result.Graph();
- }
- else {
- render_graph.Stop();
- }
-
- if (render_submix_node == nullptr) {
- render_submix_node = render_graph.CreateSubmixNode();
- }
-
- if (render_node != nullptr) {
- render_submix_node.RemoveOutgoingConnection(render_node);
- render_node.Close();
- render_node = nullptr;
- }
-
- auto render_node_result = render_graph.CreateDeviceOutputNodeAsync().get();
- if (render_node_result.Status() != AudioDeviceNodeCreationStatus::Success) {
- throw hresult_error(E_FAIL, L"Failed to initialize audio output device " + to_hstring((int32_t)render_node_result.Status()));
- }
-
- render_node = render_node_result.DeviceOutputNode();
- render_submix_node.AddOutgoingConnection(render_node);
-
- if (capture_graph == nullptr) {
- auto result = AudioGraph::CreateAsync(settings).get();
- if (result.Status() != AudioGraphCreationStatus::Success) {
- return;
- }
-
- capture_graph = result.Graph();
- capture_graph.QuantumStarted({ this, &AudioRenderer::OnQuantumStarted });
- }
- else {
- capture_graph.Stop();
- }
-
- if (capture_frame_node == nullptr) {
- capture_frame_node = capture_graph.CreateFrameOutputNode(audio_format);
- }
-
- if (capture_node != nullptr) {
- capture_node.RemoveOutgoingConnection(capture_frame_node);
- capture_node.Close();
- capture_node = nullptr;
- }
-
- CreateAudioDeviceInputNodeResult capture_node_result{ nullptr };
-
- if (!capture_device_id.empty()) {
- DeviceInformation capture_device_info = DeviceInformation::CreateFromIdAsync(capture_device_id).get();
- capture_node_result = capture_graph.CreateDeviceInputNodeAsync(MediaCategory::Communications, audio_format, capture_device_info).get();
- }
- else {
- capture_node_result = capture_graph.CreateDeviceInputNodeAsync(MediaCategory::Communications, audio_format).get();
- }
-
- if (capture_node_result.Status() == AudioDeviceNodeCreationStatus::Success) {
- capture_node = capture_node_result.DeviceInputNode();
- capture_node.AddOutgoingConnection(capture_frame_node);
- }
- }
-
- void AudioRenderer::ProcessIncomingPacket(std::vector packet, AudioSource* sender)
- {
- std::unique_lock lock(output_mutex);
-
- AudioFrameInputNode input_node{ nullptr };
- AudioEncodingProperties properties{ nullptr };
-
- auto mode_iter = input_nodes.find(sender->ssrc);
- if (mode_iter == input_nodes.end()) {
- CreateAudioInputNode(properties, sender, input_node);
- }
- else {
- input_node = input_nodes.at(sender->ssrc);
- properties = input_node.EncodingProperties();
- if (properties.ChannelCount() != sender->format.channel_count)
- {
- input_nodes.unsafe_erase(sender->ssrc);
- input_node.RemoveOutgoingConnection(render_submix_node);
- input_node.Close();
-
- CreateAudioInputNode(properties, sender, input_node);
- }
- }
-
- try
- {
- AudioFrame frame((uint32_t)packet.size());
- AudioBuffer buff = frame.LockBuffer(AudioBufferAccessMode::Write);
- IMemoryBufferReference buffer_reference = buff.CreateReference();
- com_ptr byte_buffer_access = buffer_reference.as();
-
- uint8_t* data_byte_ptr = nullptr;
- uint32_t byte_read = 0;
-
- winrt::check_hresult(byte_buffer_access->GetBuffer(&data_byte_ptr, &byte_read));
- std::copy(packet.begin(), packet.end(), data_byte_ptr);
-
- buffer_reference.Close();
- buff.Close();
-
- input_node.AddFrame(frame);
- }
- catch (const winrt::hresult_illegal_method_call&)
- {
- input_node.DiscardQueuedFrames();
- }
- }
-
- void AudioRenderer::CreateAudioInputNode(AudioEncodingProperties &properties, AudioSource * sender, AudioFrameInputNode &input_node)
- {
- properties = AudioEncodingProperties::CreatePcm(sender->format.sample_rate, sender->format.channel_count, 16);
- input_node = render_graph.CreateFrameInputNode(properties);
- input_node.AddOutgoingConnection(render_submix_node);
- input_node.Start();
-
- input_nodes.insert(std::pair(sender->ssrc, input_node));
- }
-
- void AudioRenderer::BeginCapture()
- {
- if (capture_graph != nullptr)
- capture_graph.Start();
- }
-
- void AudioRenderer::BeginRender()
- {
- if (render_graph != nullptr)
- render_graph.Start();
- }
-
- void AudioRenderer::StopCapture()
- {
- if (capture_graph != nullptr)
- capture_graph.Stop();
- }
-
- void AudioRenderer::StopRender()
- {
- if (render_graph != nullptr)
- render_graph.Stop();
- }
-
- AudioEncodingProperties AudioRenderer::GetRenderProperties()
- {
- return render_submix_node.EncodingProperties();
- }
-
- AudioEncodingProperties AudioRenderer::GetCaptureProperties()
- {
- return capture_frame_node.EncodingProperties();
- }
-
- void AudioRenderer::OnQuantumStarted(Windows::Media::Audio::AudioGraph graph, Windows::Foundation::IInspectable const &)
- {
- try
- {
- AudioFrame frame = capture_frame_node.GetFrame();
- AudioBuffer audio_buff = frame.LockBuffer(AudioBufferAccessMode::Read);
- IMemoryBufferReference buffer_reference = audio_buff.CreateReference();
- com_ptr byte_buffer_access = buffer_reference.as();
-
- uint8_t* buff = nullptr;
- uint32_t buffer_size = 0;
- winrt::check_hresult(byte_buffer_access->GetBuffer(&buff, &buffer_size));
-
- if (buffer_size != 0) {
-
- uint8_t* new_buff = new uint8_t[buffer_size];
- std::copy(buff, buff + buffer_size, new_buff);
-
- PCMPacket packet(gsl::make_span(new_buff, buffer_size), voice_client->audio_format.CalculateSampleDurationF(buffer_size));
- packet.is_float = true;
-
- voice_client->EnqueuePacket(packet);
- }
-
- buffer_reference.Close();
- audio_buff.Close();
- }
- catch (const std::exception&)
- {
-
- }
- }
-
- AudioRenderer::~AudioRenderer()
- {
- std::unique_lock in_lock(input_mutex);
- std::unique_lock out_lock(output_mutex);
-
- std::cout << "Freeing AudioRenderer\n";
-
- for each (auto node in input_nodes) {
- node.second.Close();
- }
-
- render_submix_node.Close();
- render_submix_node = nullptr;
- render_node.Close();
- render_node = nullptr;
- render_graph.Close();
- render_graph = nullptr;
-
- input_nodes.clear();
-
- capture_frame_node.Close();
- capture_frame_node = nullptr;
- capture_node.Close();
- capture_node = nullptr;
- capture_graph.Close();
- capture_graph = nullptr;
-
- delete[] pcm_buffer;
- voice_client = nullptr;
- }
-}
\ No newline at end of file
diff --git a/Unicord.Universal.Voice/AudioRenderer.h b/Unicord.Universal.Voice/AudioRenderer.h
deleted file mode 100644
index 877ae9d3..00000000
--- a/Unicord.Universal.Voice/AudioRenderer.h
+++ /dev/null
@@ -1,71 +0,0 @@
-#pragma once
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "AudioFormat.h"
-
-#define SAFE_CLOSE(x) \
- if (x != nullptr) { \
- x.Close(); \
- x = nullptr; \
- }
-
-struct __declspec(uuid("5b0d3235-4dba-4d44-865e-8f1d0e4fd04d")) __declspec(novtable) IMemoryBufferByteAccess : ::IUnknown {
- virtual HRESULT __stdcall GetBuffer(uint8_t** value, uint32_t* capacity) = 0;
-};
-
-
-namespace winrt::Unicord::Universal::Voice::implementation {
- struct VoiceClient;
-}
-using namespace winrt::Unicord::Universal::Voice::Interop;
-using namespace winrt::Unicord::Universal::Voice::implementation;
-
-
-namespace winrt::Unicord::Universal::Voice::Render {
- class AudioRenderer {
- public:
- AudioRenderer(implementation::VoiceClient* client);
-
- void Initialise(hstring preferred_render_device_id, hstring preferred_capture_device_id);
- void ProcessIncomingPacket(std::vector packet, AudioSource* sender);
-
- void CreateAudioInputNode(winrt::Windows::Media::MediaProperties::AudioEncodingProperties& properties, winrt::Unicord::Universal::Voice::Interop::AudioSource* sender, winrt::Windows::Media::Audio::AudioFrameInputNode& input_node);
-
- void BeginCapture();
- void BeginRender();
-
- void StopCapture();
- void StopRender();
-
- Windows::Media::MediaProperties::AudioEncodingProperties GetCaptureProperties();
- Windows::Media::MediaProperties::AudioEncodingProperties GetRenderProperties();
-
- ~AudioRenderer();
-
- private:
- implementation::VoiceClient* voice_client;
- std::mutex output_mutex;
- Windows::Media::Audio::AudioGraph render_graph{ nullptr };
- Windows::Media::Audio::AudioDeviceOutputNode render_node{ nullptr };
- Windows::Media::Audio::AudioSubmixNode render_submix_node{ nullptr };
- concurrency::concurrent_unordered_map input_nodes;
-
- std::mutex input_mutex;
- Windows::Media::Audio::AudioGraph capture_graph{ nullptr };
- Windows::Media::Audio::AudioDeviceInputNode capture_node{ nullptr };
- Windows::Media::Audio::AudioFrameOutputNode capture_frame_node{ nullptr };
-
- uint8_t* pcm_buffer = nullptr;
- size_t buffer_length = 0;
- size_t consumed_buffer_length = 0;
-
- void OnQuantumStarted(Windows::Media::Audio::AudioGraph graph, Windows::Foundation::IInspectable const&);
- };
-}
\ No newline at end of file
diff --git a/Unicord.Universal.Voice/AudioRenderer.idl b/Unicord.Universal.Voice/AudioRenderer.idl
deleted file mode 100644
index e69de29b..00000000
diff --git a/Unicord.Universal.Voice/ConnectionEndpoint.h b/Unicord.Universal.Voice/ConnectionEndpoint.h
deleted file mode 100644
index 1aee1fba..00000000
--- a/Unicord.Universal.Voice/ConnectionEndpoint.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#pragma once
-
-#include "winrt/base.h"
-#include
-
-using namespace winrt;
-namespace winrt::Unicord::Universal::Voice::Interop {
- struct ConnectionEndpoint {
- hstring hostname;
- uint16_t port;
- };
-}
\ No newline at end of file
diff --git a/Unicord.Universal.Voice/NoiseSuppressionLevel.idl b/Unicord.Universal.Voice/NoiseSuppressionLevel.idl
deleted file mode 100644
index bba642db..00000000
--- a/Unicord.Universal.Voice/NoiseSuppressionLevel.idl
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace Unicord.Universal.Voice
-{
- enum NoiseSuppressionLevel
- {
- Disabled,
- Low,
- Medium,
- High
- };
-}
\ No newline at end of file
diff --git a/Unicord.Universal.Voice/OpusWrapper.cpp b/Unicord.Universal.Voice/OpusWrapper.cpp
deleted file mode 100644
index 6658a66d..00000000
--- a/Unicord.Universal.Voice/OpusWrapper.cpp
+++ /dev/null
@@ -1,158 +0,0 @@
-#include "pch.h"
-#include "OpusWrapper.h"
-#include
-
-namespace winrt::Unicord::Universal::Voice::Interop {
- OpusWrapper::OpusWrapper(AudioFormat format) {
- int error;
- this->audio_format = format;
- this->opus_encoder = opus_encoder_create(format.sample_rate, format.channel_count, (int)format.application, &error);
- check_opus_error(error, L"Failed to instantate Opus encoder");
-
- int signal = OPUS_AUTO;
- switch (format.application) {
- case VoiceApplication::voip:
- signal = OPUS_SIGNAL_VOICE;
- break;
-
- case VoiceApplication::music:
- signal = OPUS_SIGNAL_MUSIC;
- break;
- }
-
- check_opus_error(opus_encoder_ctl(this->opus_encoder, OPUS_SET_SIGNAL_REQUEST, signal), L"Failed to set signal.");
- check_opus_error(opus_encoder_ctl(this->opus_encoder, OPUS_SET_PACKET_LOSS_PERC_REQUEST, 15), L"Failed to set packet loss percent.");
- check_opus_error(opus_encoder_ctl(this->opus_encoder, OPUS_SET_INBAND_FEC_REQUEST, 1), L"Failed to set fec.");
- check_opus_error(opus_encoder_ctl(this->opus_encoder, OPUS_SET_BITRATE_REQUEST, 131072), L"Failed to set bitrate.");
- }
-
- size_t OpusWrapper::Encode(array_view pcm, gsl::span target) {
- std::unique_lock lock(encode_mutex);
-
- try {
- auto duration = audio_format.CalculateSampleDuration(pcm.size());
- auto frame_size = audio_format.CalculateFrameSize(duration);
- auto sample_size = audio_format.CalculateSampleSize(duration);
-
- if (pcm.size() != sample_size)
- throw winrt::hresult_invalid_argument(L"Invalid PCM sample size.");
-
- int length = opus_encode(opus_encoder, (int16_t*)(pcm.data()), (int32_t)frame_size, target.data(), (int32_t)target.size());
- if (length < 0) {
- check_opus_error(length, L"Could not encode PCM to opus!");
- }
-
- return (size_t)length;
- }
- catch (winrt::hresult_invalid_argument&) {
- return 0;
- }
- }
-
- size_t OpusWrapper::EncodeFloat(array_view pcm, gsl::span target) {
- std::unique_lock lock(encode_mutex);
-
- try {
- auto duration = audio_format.CalculateSampleDurationF(pcm.size());
- auto frame_size = audio_format.CalculateFrameSize(duration);
- auto sample_size = audio_format.CalculateSampleSizeF(duration);
-
- if (pcm.size() != sample_size)
- throw winrt::hresult_invalid_argument(L"Invalid PCM sample size.");
-
- int length = opus_encode_float(opus_encoder, (float*)(pcm.data()), (int32_t)frame_size, target.data(), (int32_t)target.size());
- if (length < 0) {
- check_opus_error(length, L"Could not encode PCM to opus!");
- }
-
- return (size_t)length;
- }
- catch (winrt::hresult_invalid_argument&) {
- return 0;
- }
- }
-
- void OpusWrapper::Decode(AudioSource* decoder, array_view opus, std::vector& target, bool fec) {
- auto frames = opus_packet_get_nb_frames(opus.data(), opus.size());
- auto samples_per_frame = opus_packet_get_samples_per_frame(opus.data(), decoder->format.sample_rate);
- auto channels = opus_packet_get_nb_channels(opus.data());
-
- if (decoder->format.channel_count != (uint32_t)channels || !decoder->IsInitialised()) {
- decoder->format.channel_count = channels;
- decoder->Initialise(decoder->format);
- }
-
- auto sample_count = opus_decode(decoder->decoder, opus.data(), opus.size(), (int16_t*)target.data(), frames * samples_per_frame, fec);
- if (sample_count < 0) {
- check_opus_error(sample_count, L"Could not decode opus to PCM!");
- }
-
- auto sample_size = decoder->format.SampleCountToSampleSize(sample_count);
- target.resize(sample_size);
- }
-
- void OpusWrapper::ProcessPacketLoss(AudioSource* decoder, int32_t frame_size, std::vector& target) {
- if (!decoder->IsInitialised()) {
- decoder->Initialise(decoder->format);
- }
-
- auto sample_count = opus_decode(decoder->decoder, nullptr, 0, (int16_t*)target.data(), frame_size, 1);
- if (sample_count < 0) {
- check_opus_error(sample_count, L"Could not decode opus to PCM!");
- }
-
- auto sample_size = decoder->format.SampleCountToSampleSize(sample_count);
- target.resize(sample_size);
- }
-
- AudioSource* OpusWrapper::GetOrCreateDecoder(uint32_t ssrc) {
- auto itr = opus_decoders.find(ssrc);
- if (itr == opus_decoders.end()) {
- auto source = new AudioSource(ssrc);
- opus_decoders.insert(std::pair(ssrc, source));
- return source;
- }
- else {
- return opus_decoders.at(ssrc);
- }
- }
-
- int32_t OpusWrapper::GetLastPacketSampleCount(OpusDecoder* decoder) {
- int32_t count;
- opus_decoder_ctl(decoder, OPUS_GET_LAST_PACKET_DURATION_REQUEST, &count);
-
- return count;
- }
-
- OpusWrapper::~OpusWrapper() {
- std::cout << "Freeing OpusWrapper\n";
-
- if (this->opus_encoder != nullptr) {
- opus_encoder_destroy(this->opus_encoder);
- }
-
- for (auto decoder : this->opus_decoders) {
- delete decoder.second;
- }
-
- this->opus_decoders.clear();
- }
-
- void OpusWrapper::check_opus_error(int error, winrt::hstring message) {
- switch (error) {
- case OPUS_BAD_ARG:
- case OPUS_BUFFER_TOO_SMALL:
- case OPUS_INVALID_PACKET:
- throw winrt::hresult_invalid_argument(message);
- case OPUS_INTERNAL_ERROR:
- case OPUS_INVALID_STATE:
- throw winrt::hresult_error(E_UNEXPECTED, message);
- case OPUS_UNIMPLEMENTED:
- throw winrt::hresult_not_implemented(message);
- case OPUS_ALLOC_FAIL:
- throw winrt::hresult_error(E_OUTOFMEMORY, message);
- default:
- return;
- }
- }
-}
\ No newline at end of file
diff --git a/Unicord.Universal.Voice/OpusWrapper.h b/Unicord.Universal.Voice/OpusWrapper.h
deleted file mode 100644
index 33dba11f..00000000
--- a/Unicord.Universal.Voice/OpusWrapper.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#pragma once
-#include "AudioFormat.h"
-#include
-#include
-
-namespace winrt::Unicord::Universal::Voice::Interop {
- class OpusWrapper {
- public:
- OpusWrapper() = default;
- OpusWrapper(AudioFormat format);
-
- size_t Encode(array_view pcm, gsl::span target);
- size_t EncodeFloat(array_view pcm, gsl::span target);
- void Decode(AudioSource* decoder, array_view opus, std::vector& target, bool fec);
- void ProcessPacketLoss(AudioSource* decoder, int32_t frame_size, std::vector& target);
-
- AudioSource* GetOrCreateDecoder(uint32_t ssrc);
- int32_t GetLastPacketSampleCount(OpusDecoder* decoder);
-
- ~OpusWrapper();
-
- private:
- AudioFormat audio_format;
- std::mutex encode_mutex;
- OpusEncoder* opus_encoder = nullptr;
- std::map opus_decoders;
-
- void check_opus_error(int error, winrt::hstring message);
- };
-}
diff --git a/Unicord.Universal.Voice/PropertySheet.props b/Unicord.Universal.Voice/PropertySheet.props
deleted file mode 100644
index 5942ba39..00000000
--- a/Unicord.Universal.Voice/PropertySheet.props
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Unicord.Universal.Voice/README.md b/Unicord.Universal.Voice/README.md
deleted file mode 100644
index 0e34d89a..00000000
--- a/Unicord.Universal.Voice/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# Unicord.Universal.Voice
-This is the home of Unicord's Voice implementation, in essence, it's a C++/WinRT port of D#+'s VoiceNext, as well as a UWP IBackgroundTask to handle connecting to voice in the background.
-
-It's important to note that C++ isn't a language I'm partcularly used to, so when contributing, please keep this in mind, and add comments where appropriate.
diff --git a/Unicord.Universal.Voice/Rtp.cpp b/Unicord.Universal.Voice/Rtp.cpp
deleted file mode 100644
index f70792c7..00000000
--- a/Unicord.Universal.Voice/Rtp.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-#include "pch.h"
-#include "Rtp.h"
-#include
-
-namespace winrt::Unicord::Universal::Voice::Interop
-{
- void Rtp::EncodeHeader(uint16_t sequence, uint32_t timestamp, uint32_t ssrc, gsl::span target)
- {
- if (target.size() < HEADER_SIZE) {
- throw hresult_invalid_argument();
- }
-
- target[0] = RTP_NO_EXTENSION;
- target[1] = RTP_VERSION;
-
- // reverse_copy from big endian to little endian
- std::reverse_copy((uint8_t*)&sequence, (uint8_t*)&sequence + sizeof sequence, &target[2]);
- std::reverse_copy((uint8_t*)×tamp, (uint8_t*)×tamp + sizeof timestamp, &target[4]);
- std::reverse_copy((uint8_t*)&ssrc, (uint8_t*)&ssrc + sizeof ssrc, &target[8]);
- }
-
- bool Rtp::IsRtpHeader(array_view data)
- {
- if (data.size() < HEADER_SIZE)
- return false;
-
- if ((data[0] != RTP_NO_EXTENSION && data[0] != RTP_EXTENSION) || data[1] != RTP_VERSION)
- return false;
-
- return true;
- }
-
- void Rtp::DecodeHeader(array_view source, uint16_t& sequence, uint32_t& timestamp, uint32_t& ssrc, bool& has_extension)
- {
- if (!IsRtpHeader(source))
- throw hresult_invalid_argument();
-
- has_extension = source[0] == RTP_EXTENSION;
-
- // reverse_copy from big endian to little endian
- std::reverse_copy(&source[2], &source[2 + sizeof sequence], (uint8_t*)&sequence);
- std::reverse_copy(&source[4], &source[4 + sizeof timestamp], (uint8_t*)×tamp);
- std::reverse_copy(&source[8], &source[8 + sizeof ssrc], (uint8_t*)&ssrc);
- }
-
- void Rtp::GetDataFromPacket(array_view source, array_view &destination, EncryptionMode mode)
- {
- switch (mode)
- {
- case XSalsa20_Poly1305:
- destination = array_view(source.begin() + HEADER_SIZE, source.end());
- break;
- case XSalsa20_Poly1305_Suffix:
- destination = array_view(source.begin() + HEADER_SIZE, source.end() - crypto_secretbox_xsalsa20poly1305_NONCEBYTES);
- break;
- case XSalsa20_Poly1305_Lite:
- destination = array_view(source.begin() + HEADER_SIZE, source.end() - 4);
- break;
- default:
- throw hresult_invalid_argument();
- }
- }
-
- int Rtp::CalculatePacketSize(uint32_t encrypted_length, EncryptionMode encryption_mode)
- {
- }
-}
\ No newline at end of file
diff --git a/Unicord.Universal.Voice/Rtp.h b/Unicord.Universal.Voice/Rtp.h
deleted file mode 100644
index ff2a651e..00000000
--- a/Unicord.Universal.Voice/Rtp.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-
-#include "SodiumWrapper.h"
-
-namespace winrt::Unicord::Universal::Voice::Interop {
- class Rtp {
- public:
- static const int HEADER_SIZE = 12;
- static const uint8_t RTP_TYPE_OPUS = 120;
- static const uint8_t RTP_TYPE_H264 = 101;
- static const uint8_t RTP_TYPE_H264_RTX = 102;
- };
-}
diff --git a/Unicord.Universal.Voice/ServiceBackgroundTask.cpp b/Unicord.Universal.Voice/ServiceBackgroundTask.cpp
deleted file mode 100644
index 799cc73a..00000000
--- a/Unicord.Universal.Voice/ServiceBackgroundTask.cpp
+++ /dev/null
@@ -1,228 +0,0 @@
-#include "pch.h"
-#include "ServiceBackgroundTask.h"
-#include "ServiceBackgroundTask.g.cpp"
-#include "VoiceClient.h"
-#include "VoiceClientOptions.h"
-
-using namespace winrt::Windows::Foundation::Collections;
-using namespace winrt::Windows::ApplicationModel;
-using namespace winrt::Windows::ApplicationModel::AppService;
-using namespace winrt::Windows::ApplicationModel::Background;
-using namespace winrt::Windows::ApplicationModel::Calls;
-
-namespace winrt::Unicord::Universal::Voice::Background::implementation {
- VoipCallCoordinator ServiceBackgroundTask::voipCoordinator = VoipCallCoordinator{ nullptr };
- VoipPhoneCall ServiceBackgroundTask::activeCall = VoipPhoneCall{ nullptr };
- VoiceClient ServiceBackgroundTask::voiceClient = VoiceClient{ nullptr };
- VoiceClientOptions ServiceBackgroundTask::voiceClientOptions = VoiceClientOptions{ nullptr };
-
- void ServiceBackgroundTask::Run(IBackgroundTaskInstance const& taskInstance) {
- auto stream = new dbg_stream_for_cout();
- std::cout.rdbuf(stream);
- std::cout << std::unitbuf;
-
- this->taskDeferral = taskInstance.GetDeferral();
- taskInstance.Canceled({ this, &ServiceBackgroundTask::OnCancelled });
-
- auto details = taskInstance.TriggerDetails().try_as();
- this->appServiceConnection = details.AppServiceConnection();
- this->appServiceConnected = true;
- this->appServiceConnection.ServiceClosed({ this, &ServiceBackgroundTask::OnServiceClosed });
- this->appServiceConnection.RequestReceived({ this, &ServiceBackgroundTask::OnServiceMessage });
- }
-
- void ServiceBackgroundTask::OnUdpPing(Windows::Foundation::IInspectable sender, uint32_t ping) {
- ValueSet values;
- values.Insert(L"ping", box_value(ping));
- RaiseEvent(VoiceServiceEvent::UdpPing, values);
- }
-
- void ServiceBackgroundTask::OnWsPing(Windows::Foundation::IInspectable sender, uint32_t ping) {
- ValueSet values;
- values.Insert(L"ping", box_value(ping));
- RaiseEvent(VoiceServiceEvent::WebSocketPing, values);
- }
-
- void ServiceBackgroundTask::RaiseEvent(VoiceServiceEvent ev, ValueSet data) {
- if (appServiceConnected) {
- data.Insert(L"ev", box_value((uint32_t)ev));
- this->appServiceConnection.SendMessageAsync(data);
- }
- }
-
- void ServiceBackgroundTask::OnServiceMessage(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) {
- auto def = args.GetDeferral();
- auto request = args.Request();
- auto data = request.Message();
-
- // req signifies a request
- if (data.HasKey(L"req")) {
- VoiceServiceRequest ev = VoiceServiceRequest::RequestSucceeded;
- ValueSet values;
- ValueSet event_values;
-
- try {
- auto request_op = (VoiceServiceRequest)unbox_value(data.Lookup(L"req"));
- switch (request_op) {
- case VoiceServiceRequest::GuildConnectRequest: {
- if (voiceClient == nullptr && activeCall == nullptr) {
- voipCoordinator = VoipCallCoordinator::GetDefault();
- activeCall = voipCoordinator.RequestNewOutgoingCall(
- L"", unbox_value(data.Lookup(L"contact_name")), Package::Current().DisplayName(), VoipPhoneCallMedia::Audio);
- if (activeCall != nullptr) {
- voiceClientOptions = make();
- voiceClientOptions.Token(unbox_value(data.Lookup(L"token")));
- voiceClientOptions.SessionId(unbox_value(data.Lookup(L"session_id")));
- voiceClientOptions.Endpoint(unbox_value(data.Lookup(L"endpoint")));
- voiceClientOptions.GuildId(unbox_value(data.Lookup(L"guild_id")));
- voiceClientOptions.ChannelId(unbox_value(data.Lookup(L"channel_id")));
- voiceClientOptions.CurrentUserId(unbox_value(data.Lookup(L"user_id")));
- voiceClientOptions.SuppressionLevel((NoiseSuppressionLevel)unbox_value(data.TryLookup(L"noise_suppression")));
- voiceClientOptions.EchoCancellation(unbox_value_or(data.TryLookup(L"echo_cancellation"), true));
- voiceClientOptions.VoiceActivity(unbox_value_or(data.TryLookup(L"voice_activity"), true));
- voiceClientOptions.AutomaticGainControl(unbox_value_or(data.TryLookup(L"auto_gain_control"), true));
-
- if (data.HasKey(L"input_device")) {
- voiceClientOptions.PreferredRecordingDevice(unbox_value_or(data.Lookup(L"input_device"), L""));
- }
-
- if (data.HasKey(L"output_device")) {
- voiceClientOptions.PreferredPlaybackDevice(unbox_value_or(data.Lookup(L"output_device"), L""));
- }
-
- voiceClient = make(voiceClientOptions);
- voiceClient.UdpSocketPingUpdated({ this, &ServiceBackgroundTask::OnUdpPing });
- voiceClient.WebSocketPingUpdated({ this, &ServiceBackgroundTask::OnWsPing });
-
- if (data.HasKey(L"muted")) {
- voiceClient.Muted(unbox_value(data.Lookup(L"muted")));
- }
-
- if (data.HasKey(L"deafened")) {
- voiceClient.Deafened(unbox_value(data.Lookup(L"deafened")));
- }
-
- voiceClient.ConnectAsync().get();
- activeCall.NotifyCallActive();
-
- RaiseEvent(VoiceServiceEvent::Connected, event_values);
- }
- else {
- throw std::exception("Unable to get call");
- }
- }
- else {
- // already connected, so raise the event again
- RaiseEvent(VoiceServiceEvent::Connected, event_values);
- }
- } break;
- case VoiceServiceRequest::StateRequest:
- if (voiceClient != nullptr) {
- values.Insert(L"state", box_value((uint32_t)VoiceServiceState::Connected));
- values.Insert(L"guild_id", box_value(voiceClientOptions.GuildId()));
- values.Insert(L"channel_id", box_value(voiceClientOptions.ChannelId()));
- values.Insert(L"muted", box_value(voiceClient.Muted()));
- values.Insert(L"deafened", box_value(voiceClient.Deafened()));
- }
- else {
- values.Insert(L"state", box_value((uint32_t)VoiceServiceState::ReadyToConnect));
- }
- break;
- case VoiceServiceRequest::MuteRequest:
- if (voiceClient != nullptr) {
- auto muted = unbox_value(data.Lookup(L"muted"));
- voiceClient.Muted(muted);
-
- try {
- if (muted || voiceClient.Deafened()) {
- activeCall.NotifyCallHeld();
- }
- else {
- activeCall.NotifyCallActive();
- }
- }
- catch (const winrt::hresult_error&) {
- }
-
- event_values.Insert(L"muted", box_value(muted));
- RaiseEvent(VoiceServiceEvent::Muted, event_values);
- }
- break;
- case VoiceServiceRequest::DeafenRequest:
- if (voiceClient != nullptr) {
- auto deafened = unbox_value(data.Lookup(L"deafened"));
- voiceClient.Deafened(deafened);
-
- try {
- if (deafened || voiceClient.Muted()) {
- activeCall.NotifyCallHeld();
- }
- else {
- activeCall.NotifyCallActive();
- }
- }
- catch (const winrt::hresult_error&) {
- }
-
- event_values.Insert(L"deafened", box_value(deafened));
- RaiseEvent(VoiceServiceEvent::Deafened, event_values);
- }
- break;
- case VoiceServiceRequest::DisconnectRequest:
- if (voiceClient != nullptr) {
- voiceClient.Close();
- activeCall.NotifyCallEnded();
- activeCall = nullptr;
- voiceClient = nullptr;
- RaiseEvent(VoiceServiceEvent::Disconnected, event_values);
- }
- break;
-
- case VoiceServiceRequest::SettingsUpdate:
- if (voiceClient != nullptr) {
- if (data.HasKey(L"input_device")) {
- voiceClientOptions.PreferredRecordingDevice(unbox_value_or(data.Lookup(L"input_device"), L""));
- }
-
- if (data.HasKey(L"output_device")) {
- voiceClientOptions.PreferredPlaybackDevice(unbox_value_or(data.Lookup(L"output_device"), L""));
- }
-
- voiceClient.UpdateAudioDevices();
- }
- break;
- default:
- break;
- }
- }
- catch (const std::exception& ex) {
- ev = VoiceServiceRequest::RequestFailed;
- values.Insert(L"msg", box_value(to_hstring(ex.what())));
- }
- catch (const winrt::hresult_error& ex) {
- ev = VoiceServiceRequest::RequestFailed;
- values.Insert(L"msg", box_value(to_hstring(ex.message())));
- }
-
- values.Insert(L"req", box_value((uint32_t)ev));
- request.SendResponseAsync(values).get();
- }
-
- // ev signifies an event
- if (data.HasKey(L"ev")) {
- auto event = unbox_value(data.Lookup(L"ev"));
- }
-
- def.Complete();
- }
-
- void ServiceBackgroundTask::OnServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args) {
- this->appServiceConnected = false;
- }
-
- void ServiceBackgroundTask::OnCancelled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) {
- if (this->taskDeferral != nullptr) {
- this->taskDeferral.Complete();
- }
- }
-}
diff --git a/Unicord.Universal.Voice/ServiceBackgroundTask.g.cpp b/Unicord.Universal.Voice/ServiceBackgroundTask.g.cpp
deleted file mode 100644
index a8c7b038..00000000
--- a/Unicord.Universal.Voice/ServiceBackgroundTask.g.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-// WARNING: Please don't edit this file. It was generated by C++/WinRT v2.0.190620.2
-
-void* winrt_make_Unicord_Universal_Voice_Background_ServiceBackgroundTask()
-{
- return winrt::detach_abi(winrt::make());
-}
-namespace winrt::Unicord::Universal::Voice::Background
-{
- ServiceBackgroundTask::ServiceBackgroundTask() :
- ServiceBackgroundTask(make())
- {
- }
-}
diff --git a/Unicord.Universal.Voice/ServiceBackgroundTask.g.h b/Unicord.Universal.Voice/ServiceBackgroundTask.g.h
deleted file mode 100644
index 3df9a241..00000000
--- a/Unicord.Universal.Voice/ServiceBackgroundTask.g.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// WARNING: Please don't edit this file. It was generated by C++/WinRT v2.0.190620.2
-
-#pragma once
-#include "winrt/Unicord.Universal.Voice.Background.h"
-#include "winrt/Windows.ApplicationModel.Background.h"
-namespace winrt::Unicord::Universal::Voice::Background::implementation
-{
- template
- struct __declspec(empty_bases) ServiceBackgroundTask_base : implements
- {
- using base_type = ServiceBackgroundTask_base;
- using class_type = Unicord::Universal::Voice::Background::ServiceBackgroundTask;
- using implements_type = typename ServiceBackgroundTask_base::implements_type;
- using implements_type::implements_type;
-
- hstring GetRuntimeClassName() const
- {
- return L"Unicord.Universal.Voice.Background.ServiceBackgroundTask";
- }
- };
-}
-namespace winrt::Unicord::Universal::Voice::Background::factory_implementation
-{
- template
- struct __declspec(empty_bases) ServiceBackgroundTaskT : implements
- {
- using instance_type = Unicord::Universal::Voice::Background::ServiceBackgroundTask;
-
- hstring GetRuntimeClassName() const
- {
- return L"Unicord.Universal.Voice.Background.ServiceBackgroundTask";
- }
- auto ActivateInstance() const
- {
- return make();
- }
- };
-}
-
-#if defined(WINRT_FORCE_INCLUDE_SERVICEBACKGROUNDTASK_XAML_G_H) || __has_include("Background.ServiceBackgroundTask.xaml.g.h")
-#include "Background.ServiceBackgroundTask.xaml.g.h"
-#else
-
-namespace winrt::Unicord::Universal::Voice::Background::implementation
-{
- template
- using ServiceBackgroundTaskT = ServiceBackgroundTask_base;
-}
-
-#endif
diff --git a/Unicord.Universal.Voice/ServiceBackgroundTask.h b/Unicord.Universal.Voice/ServiceBackgroundTask.h
deleted file mode 100644
index 362d9d3d..00000000
--- a/Unicord.Universal.Voice/ServiceBackgroundTask.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#pragma once
-#include "ServiceBackgroundTask.g.h"
-#include
-#include
-#include
-
-namespace winrt::Unicord::Universal::Voice::Background::implementation {
- struct ServiceBackgroundTask : ServiceBackgroundTaskT {
- private:
- Windows::ApplicationModel::Background::BackgroundTaskDeferral taskDeferral{ nullptr };
- Windows::ApplicationModel::AppService::AppServiceConnection appServiceConnection{ nullptr };
- bool appServiceConnected = false;
-
- static Windows::ApplicationModel::Calls::VoipCallCoordinator voipCoordinator;
- static Windows::ApplicationModel::Calls::VoipPhoneCall activeCall;
- static Unicord::Universal::Voice::VoiceClient voiceClient;
- static Unicord::Universal::Voice::VoiceClientOptions voiceClientOptions;
-
- void OnUdpPing(Windows::Foundation::IInspectable sender, uint32_t ping);
- void OnWsPing(Windows::Foundation::IInspectable sender, uint32_t ping);
- void RaiseEvent(Unicord::Universal::Voice::Background::VoiceServiceEvent ev, Windows::Foundation::Collections::ValueSet data);
- void OnServiceMessage(Windows::ApplicationModel::AppService::AppServiceConnection sender, Windows::ApplicationModel::AppService::AppServiceRequestReceivedEventArgs args);
- void OnServiceClosed(Windows::ApplicationModel::AppService::AppServiceConnection sender, Windows::ApplicationModel::AppService::AppServiceClosedEventArgs args);
- void OnCancelled(Windows::ApplicationModel::Background::IBackgroundTaskInstance sender, Windows::ApplicationModel::Background::BackgroundTaskCancellationReason reason);
-
- public:
- ServiceBackgroundTask() = default;
- void Run(Windows::ApplicationModel::Background::IBackgroundTaskInstance const& taskInstance);
- };
-}
-namespace winrt::Unicord::Universal::Voice::Background::factory_implementation {
- struct ServiceBackgroundTask : ServiceBackgroundTaskT {
- };
-}
diff --git a/Unicord.Universal.Voice/ServiceBackgroundTask.idl b/Unicord.Universal.Voice/ServiceBackgroundTask.idl
deleted file mode 100644
index 98afb61f..00000000
--- a/Unicord.Universal.Voice/ServiceBackgroundTask.idl
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace Unicord.Universal.Voice.Background
-{
- [default_interface]
- runtimeclass ServiceBackgroundTask : Windows.ApplicationModel.Background.IBackgroundTask
- {
- ServiceBackgroundTask();
- };
-}
\ No newline at end of file
diff --git a/Unicord.Universal.Voice/SodiumWrapper.cpp b/Unicord.Universal.Voice/SodiumWrapper.cpp
deleted file mode 100644
index d1476630..00000000
--- a/Unicord.Universal.Voice/SodiumWrapper.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-#include "pch.h"
-#include "SodiumWrapper.h"
-#include "Rtp.h"
-#include
-#include