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 @@ - + - -(u)); -} - -struct narrowing_error : public std::exception -{ -}; - -namespace details -{ - template - struct is_same_signedness - : public std::integral_constant::value == std::is_signed::value> - { - }; -} // namespace details - -// narrow() : a checked version of narrow_cast() that throws if the cast changed the value -template -GSL_SUPPRESS(type.1) // NO-FORMAT: attribute -GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false) -#if GSL_CONSTEXPR_NARROW -constexpr -#endif -T narrow(U u) noexcept(false) -{ - T t = narrow_cast(u); - if (static_cast(t) != u) gsl::details::throw_exception(narrowing_error()); - if (!details::is_same_signedness::value && ((t < T{}) != (u < U{}))) - gsl::details::throw_exception(narrowing_error()); - return t; -} - -// -// at() - Bounds-checked way of accessing builtin arrays, std::array, std::vector -// -template -GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute -GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute -constexpr T& at(T (&arr)[N], const index i) -{ - Expects(i >= 0 && i < narrow_cast(N)); - return arr[narrow_cast(i)]; -} - -template -GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute -GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute -constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()]) -{ - Expects(i >= 0 && i < narrow_cast(cont.size())); - using size_type = decltype(cont.size()); - return cont[narrow_cast(i)]; -} - -template -GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute -constexpr T at(const std::initializer_list cont, const index i) -{ - Expects(i >= 0 && i < narrow_cast(cont.size())); - return *(cont.begin() + i); -} - -} // namespace gsl - -#if defined(_MSC_VER) && !defined(__clang__) -#if _MSC_VER < 1910 -#undef constexpr -#pragma pop_macro("constexpr") - -#endif // _MSC_VER < 1910 - -#pragma warning(pop) - -#endif // _MSC_VER - -#endif // GSL_UTIL_H diff --git a/Unicord.Universal.Voice/gsl/multi_span b/Unicord.Universal.Voice/gsl/multi_span deleted file mode 100644 index 0c1506ed..00000000 --- a/Unicord.Universal.Voice/gsl/multi_span +++ /dev/null @@ -1,2293 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2015 Microsoft Corporation. All rights reserved. -// -// This code is licensed under the MIT License (MIT). -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef GSL_MULTI_SPAN_H -#define GSL_MULTI_SPAN_H - -#include // for Expects -#include // for byte -#include // for narrow_cast - -#include // for transform, lexicographical_compare -#include // for array -#include -#include // for ptrdiff_t, size_t, nullptr_t -#include // for PTRDIFF_MAX -#include // for divides, multiplies, minus, negate, plus -#include // for initializer_list -#include // for iterator, random_access_iterator_tag -#include // for numeric_limits -#include -#include -#include -#include // for basic_string -#include // for enable_if_t, remove_cv_t, is_same, is_co... -#include - -#if defined(_MSC_VER) && !defined(__clang__) - -// turn off some warnings that are noisy about our Expects statements -#pragma warning(push) -#pragma warning(disable : 4127) // conditional expression is constant -#pragma warning(disable : 4702) // unreachable code - -// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool. -#pragma warning(disable : 26495) // uninitalized member when constructor calls constructor -#pragma warning(disable : 26473) // in some instantiations we cast to the same type -#pragma warning(disable : 26490) // TODO: bug in parser - attributes and templates -#pragma warning(disable : 26465) // TODO: bug - suppression does not work on template functions - -#if _MSC_VER < 1910 -#pragma push_macro("constexpr") -#define constexpr /*constexpr*/ - -#endif // _MSC_VER < 1910 -#endif // _MSC_VER - -// GCC 7 does not like the signed unsigned missmatch (size_t ptrdiff_t) -// While there is a conversion from signed to unsigned, it happens at -// compiletime, so the compiler wouldn't have to warn indiscriminently, but -// could check if the source value actually doesn't fit into the target type -// and only warn in those cases. -#if defined(__GNUC__) && __GNUC__ > 6 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wsign-conversion" -#endif - -namespace gsl -{ - -/* -** begin definitions of index and bounds -*/ -namespace details -{ - template - struct SizeTypeTraits - { - static const SizeType max_value = std::numeric_limits::max(); - }; - - template - class are_integral : public std::integral_constant - { - }; - - template - class are_integral - : public std::integral_constant::value && are_integral::value> - { - }; -} // namespace details - -template -class multi_span_index final -{ - static_assert(Rank > 0, "Rank must be greater than 0!"); - - template - friend class multi_span_index; - -public: - static const std::size_t rank = Rank; - using value_type = std::ptrdiff_t; - using size_type = value_type; - using reference = std::add_lvalue_reference_t; - using const_reference = std::add_lvalue_reference_t>; - - constexpr multi_span_index() noexcept {} - - constexpr multi_span_index(const value_type (&values)[Rank]) noexcept - { - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute - std::copy(values, values + Rank, elems); - } - - template ::value>> - constexpr multi_span_index(Ts... ds) noexcept : elems{narrow_cast(ds)...} - {} - - constexpr multi_span_index(const multi_span_index& other) noexcept = default; - - constexpr multi_span_index& operator=(const multi_span_index& rhs) noexcept = default; - - // Preconditions: component_idx < rank - GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - constexpr reference operator[](std::size_t component_idx) - { - Expects(component_idx < Rank); // Component index must be less than rank - return elems[component_idx]; - } - - // Preconditions: component_idx < rank - GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - constexpr const_reference operator[](std::size_t component_idx) const - { - Expects(component_idx < Rank); // Component index must be less than rank - return elems[component_idx]; - } - - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute - constexpr bool operator==(const multi_span_index& rhs) const - { - return std::equal(elems, elems + rank, rhs.elems); - } - - constexpr bool operator!=(const multi_span_index& rhs) const - { - return !(*this == rhs); - } - - constexpr multi_span_index operator+() const noexcept { return *this; } - - constexpr multi_span_index operator-() const - { - multi_span_index ret = *this; - std::transform(ret, ret + rank, ret, std::negate{}); - return ret; - } - - constexpr multi_span_index operator+(const multi_span_index& rhs) const - { - multi_span_index ret = *this; - ret += rhs; - return ret; - } - - constexpr multi_span_index operator-(const multi_span_index& rhs) const - { - multi_span_index ret = *this; - ret -= rhs; - return ret; - } - - constexpr multi_span_index& operator+=(const multi_span_index& rhs) - { - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute - std::transform(elems, elems + rank, rhs.elems, elems, - std::plus{}); - return *this; - } - - constexpr multi_span_index& operator-=(const multi_span_index& rhs) - { - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute - std::transform(elems, elems + rank, rhs.elems, elems, std::minus{}); - return *this; - } - - constexpr multi_span_index operator*(value_type v) const - { - multi_span_index ret = *this; - ret *= v; - return ret; - } - - constexpr multi_span_index operator/(value_type v) const - { - multi_span_index ret = *this; - ret /= v; - return ret; - } - - friend constexpr multi_span_index operator*(value_type v, const multi_span_index& rhs) - { - return rhs * v; - } - - constexpr multi_span_index& operator*=(value_type v) - { - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute - std::transform(elems, elems + rank, elems, - [v](value_type x) { return std::multiplies{}(x, v); }); - return *this; - } - - constexpr multi_span_index& operator/=(value_type v) - { - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute - std::transform(elems, elems + rank, elems, - [v](value_type x) { return std::divides{}(x, v); }); - return *this; - } - -private: - value_type elems[Rank] = {}; -}; - -#if !defined(_MSC_VER) || _MSC_VER >= 1910 - -struct static_bounds_dynamic_range_t -{ - template ::value>> - constexpr operator T() const noexcept - { - return narrow_cast(-1); - } -}; - -constexpr bool operator==(static_bounds_dynamic_range_t, static_bounds_dynamic_range_t) noexcept -{ - return true; -} - -constexpr bool operator!=(static_bounds_dynamic_range_t, static_bounds_dynamic_range_t) noexcept -{ - return false; -} - -template ::value>> -constexpr bool operator==(static_bounds_dynamic_range_t, T other) noexcept -{ - return narrow_cast(-1) == other; -} - -template ::value>> -constexpr bool operator==(T left, static_bounds_dynamic_range_t right) noexcept -{ - return right == left; -} - -template ::value>> -constexpr bool operator!=(static_bounds_dynamic_range_t, T other) noexcept -{ - return narrow_cast(-1) != other; -} - -template ::value>> -constexpr bool operator!=(T left, static_bounds_dynamic_range_t right) noexcept -{ - return right != left; -} - -constexpr static_bounds_dynamic_range_t dynamic_range{}; -#else -const std::ptrdiff_t dynamic_range = -1; -#endif - -struct generalized_mapping_tag -{ -}; -struct contiguous_mapping_tag : generalized_mapping_tag -{ -}; - -namespace details -{ - - template - struct LessThan - { - static const bool value = Left < Right; - }; - - template - struct BoundsRanges - { - using size_type = std::ptrdiff_t; - static const size_type Depth = 0; - static const size_type DynamicNum = 0; - static const size_type CurrentRange = 1; - static const size_type TotalSize = 1; - - // TODO : following signature is for work around VS bug - template - constexpr BoundsRanges(const OtherRange&, bool /* firstLevel */) - {} - - constexpr BoundsRanges(const std::ptrdiff_t* const) {} - constexpr BoundsRanges() noexcept = default; - - template - constexpr void serialize(T&) const - {} - - template - constexpr size_type linearize(const T&) const - { - return 0; - } - - template - constexpr size_type contains(const T&) const - { - return -1; - } - - constexpr size_type elementNum(std::size_t) const noexcept { return 0; } - - constexpr size_type totalSize() const noexcept { return TotalSize; } - - constexpr bool operator==(const BoundsRanges&) const noexcept { return true; } - }; - - template - struct BoundsRanges : BoundsRanges - { - using Base = BoundsRanges; - using size_type = std::ptrdiff_t; - static const std::size_t Depth = Base::Depth + 1; - static const std::size_t DynamicNum = Base::DynamicNum + 1; - static const size_type CurrentRange = dynamic_range; - static const size_type TotalSize = dynamic_range; - - private: - size_type m_bound; - - public: - GSL_SUPPRESS(f.23) // NO-FORMAT: attribute // this pointer type is cannot be assigned nullptr - issue in not_null - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - constexpr BoundsRanges(const std::ptrdiff_t* const arr) - : Base(arr + 1), m_bound(*arr * this->Base::totalSize()) - { - Expects(0 <= *arr); - } - - constexpr BoundsRanges() noexcept : m_bound(0) {} - - template - constexpr BoundsRanges(const BoundsRanges& other, - bool /* firstLevel */ = true) - : Base(static_cast&>(other), false) - , m_bound(other.totalSize()) - {} - - template - constexpr void serialize(T& arr) const - { - arr[Dim] = elementNum(); - this->Base::template serialize(arr); - } - - template - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - constexpr size_type linearize(const T& arr) const - { - const size_type index = this->Base::totalSize() * arr[Dim]; - Expects(index < m_bound); - return index + this->Base::template linearize(arr); - } - - template - constexpr size_type contains(const T& arr) const - { - const ptrdiff_t last = this->Base::template contains(arr); - if (last == -1) return -1; - const ptrdiff_t cur = this->Base::totalSize() * arr[Dim]; - return cur < m_bound ? cur + last : -1; - } - - GSL_SUPPRESS(c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used - constexpr size_type totalSize() const noexcept - { - return m_bound; - } - - GSL_SUPPRESS(c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used - constexpr size_type elementNum() const noexcept - { - return totalSize() / this->Base::totalSize(); - } - - GSL_SUPPRESS(c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used - constexpr size_type elementNum(std::size_t dim) const noexcept - { - if (dim > 0) - return this->Base::elementNum(dim - 1); - else - return elementNum(); - } - - constexpr bool operator==(const BoundsRanges& rhs) const noexcept - { - return m_bound == rhs.m_bound && - static_cast(*this) == static_cast(rhs); - } - }; - - template - struct BoundsRanges : BoundsRanges - { - using Base = BoundsRanges; - using size_type = std::ptrdiff_t; - static const std::size_t Depth = Base::Depth + 1; - static const std::size_t DynamicNum = Base::DynamicNum; - static const size_type CurrentRange = CurRange; - static const size_type TotalSize = - Base::TotalSize == dynamic_range ? dynamic_range : CurrentRange * Base::TotalSize; - - constexpr BoundsRanges(const std::ptrdiff_t* const arr) : Base(arr) {} - constexpr BoundsRanges() = default; - - template - constexpr BoundsRanges(const BoundsRanges& other, - bool firstLevel = true) - : Base(static_cast&>(other), false) - { - GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: false positive - (void) firstLevel; - } - - template - constexpr void serialize(T& arr) const - { - arr[Dim] = elementNum(); - this->Base::template serialize(arr); - } - - template - constexpr size_type linearize(const T& arr) const - { - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - Expects(arr[Dim] >= 0 && arr[Dim] < CurrentRange); // Index is out of range - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - const ptrdiff_t d = arr[Dim]; - return this->Base::totalSize() * d + - this->Base::template linearize(arr); - } - - template - constexpr size_type contains(const T& arr) const - { - if (arr[Dim] >= CurrentRange) return -1; - const size_type last = this->Base::template contains(arr); - if (last == -1) return -1; - return this->Base::totalSize() * arr[Dim] + last; - } - - GSL_SUPPRESS(c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used - constexpr size_type totalSize() const noexcept - { - return CurrentRange * this->Base::totalSize(); - } - - GSL_SUPPRESS(c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used - constexpr size_type elementNum() const noexcept - { - return CurrentRange; - } - - GSL_SUPPRESS(c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used - constexpr size_type elementNum(std::size_t dim) const noexcept - { - if (dim > 0) - return this->Base::elementNum(dim - 1); - else - return elementNum(); - } - - constexpr bool operator==(const BoundsRanges& rhs) const noexcept - { - return static_cast(*this) == static_cast(rhs); - } - }; - - template - struct BoundsRangeConvertible - : public std::integral_constant= TargetType::TotalSize || - TargetType::TotalSize == dynamic_range || - SourceType::TotalSize == dynamic_range || - TargetType::TotalSize == 0)> - { - }; - - template - struct TypeListIndexer - { - const TypeChain& obj_; - constexpr TypeListIndexer(const TypeChain& obj) : obj_(obj) {} - - template - constexpr const TypeChain& getObj(std::true_type) - { - return obj_; - } - - template - constexpr auto getObj(std::false_type) - -> decltype(TypeListIndexer(static_cast(obj_)).template get()) - { - return TypeListIndexer(static_cast(obj_)).template get(); - } - - template - constexpr auto get() -> decltype(getObj(std::integral_constant())) - { - return getObj(std::integral_constant()); - } - }; - - template - constexpr TypeListIndexer createTypeListIndexer(const TypeChain& obj) - { - return TypeListIndexer(obj); - } - - template 1), - typename Ret = std::enable_if_t>> - constexpr Ret shift_left(const multi_span_index& other) noexcept - { - Ret ret{}; - for (std::size_t i = 0; i < Rank - 1; ++i) - { - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - ret[i] = other[i + 1]; - } - return ret; - } -} // namespace details - -template -class bounds_iterator; - -template -class static_bounds -{ -public: - static_bounds(const details::BoundsRanges&) {} -}; - -template -class static_bounds -{ - using MyRanges = details::BoundsRanges; - - MyRanges m_ranges; - constexpr static_bounds(const MyRanges& range) noexcept : m_ranges(range) {} - - template - friend class static_bounds; - -public: - static const std::size_t rank = MyRanges::Depth; - static const std::size_t dynamic_rank = MyRanges::DynamicNum; - static const std::ptrdiff_t static_size = MyRanges::TotalSize; - - using size_type = std::ptrdiff_t; - using index_type = multi_span_index; - using const_index_type = std::add_const_t; - using iterator = bounds_iterator; - using const_iterator = bounds_iterator; - using difference_type = std::ptrdiff_t; - using sliced_type = static_bounds; - using mapping_type = contiguous_mapping_tag; - - constexpr static_bounds() /*noexcept*/ = default; - - template - struct BoundsRangeConvertible2; - - template > - static auto helpBoundsRangeConvertible(SourceType, TargetType, std::true_type) -> Ret; - - template - static auto helpBoundsRangeConvertible(SourceType, TargetType, ...) -> std::false_type; - - template - struct BoundsRangeConvertible2 - : decltype(helpBoundsRangeConvertible( - SourceType(), TargetType(), - std::integral_constant())) - { - }; - - template - struct BoundsRangeConvertible2 : std::true_type - { - }; - - template - struct BoundsRangeConvertible - : decltype(helpBoundsRangeConvertible( - SourceType(), TargetType(), - std::integral_constant::value || - TargetType::CurrentRange == dynamic_range || - SourceType::CurrentRange == dynamic_range)>())) - { - }; - - template - struct BoundsRangeConvertible : std::true_type - { - }; - - template , - details::BoundsRanges>::value>> - constexpr static_bounds(const static_bounds& other) : m_ranges(other.m_ranges) - { - Expects((MyRanges::DynamicNum == 0 && details::BoundsRanges::DynamicNum == 0) || - MyRanges::DynamicNum > 0 || other.m_ranges.totalSize() >= m_ranges.totalSize()); - } - - constexpr static_bounds(std::initializer_list il) : m_ranges(il.begin()) - { - // Size of the initializer list must match the rank of the array - Expects((MyRanges::DynamicNum == 0 && il.size() == 1 && *il.begin() == static_size) || - MyRanges::DynamicNum == il.size()); - // Size of the range must be less than the max element of the size type - Expects(m_ranges.totalSize() <= PTRDIFF_MAX); - } - - constexpr sliced_type slice() const noexcept - { - return sliced_type{static_cast&>(m_ranges)}; - } - - constexpr size_type stride() const noexcept { return rank > 1 ? slice().size() : 1; } - - constexpr size_type size() const noexcept { return m_ranges.totalSize(); } - - constexpr size_type total_size() const noexcept { return m_ranges.totalSize(); } - - constexpr size_type linearize(const index_type& idx) const { return m_ranges.linearize(idx); } - - constexpr bool contains(const index_type& idx) const noexcept - { - return m_ranges.contains(idx) != -1; - } - - constexpr size_type operator[](std::size_t idx) const noexcept - { - return m_ranges.elementNum(idx); - } - - template - constexpr size_type extent() const noexcept - { - static_assert(Dim < rank, - "dimension should be less than rank (dimension count starts from 0)"); - return details::createTypeListIndexer(m_ranges).template get().elementNum(); - } - - template - constexpr size_type extent(IntType dim) const - { - static_assert(std::is_integral::value, - "Dimension parameter must be supplied as an integral type."); - auto real_dim = narrow_cast(dim); - Expects(real_dim < rank); - - return m_ranges.elementNum(real_dim); - } - - constexpr index_type index_bounds() const noexcept - { - size_type extents[rank] = {}; - m_ranges.serialize(extents); - return {extents}; - } - - template - constexpr bool operator==(const static_bounds& rhs) const noexcept - { - return this->size() == rhs.size(); - } - - template - constexpr bool operator!=(const static_bounds& rhs) const noexcept - { - return !(*this == rhs); - } - - constexpr const_iterator begin() const noexcept - { - return const_iterator(*this, index_type{}); - } - - constexpr const_iterator end() const noexcept - { - return const_iterator(*this, this->index_bounds()); - } -}; - -template -class strided_bounds { - template - friend class strided_bounds; - -public: - static const std::size_t rank = Rank; - using value_type = std::ptrdiff_t; - using reference = std::add_lvalue_reference_t; - using const_reference = std::add_const_t; - using size_type = value_type; - using difference_type = value_type; - using index_type = multi_span_index; - using const_index_type = std::add_const_t; - using iterator = bounds_iterator; - using const_iterator = bounds_iterator; - static const value_type dynamic_rank = rank; - static const value_type static_size = dynamic_range; - using sliced_type = std::conditional_t, void>; - using mapping_type = generalized_mapping_tag; - - constexpr strided_bounds(const strided_bounds&) noexcept = default; - - constexpr strided_bounds& operator=(const strided_bounds&) noexcept = default; - - constexpr strided_bounds(const value_type (&values)[rank], index_type strides) - : m_extents(values), m_strides(std::move(strides)) - {} - - constexpr strided_bounds(const index_type& extents, const index_type& strides) noexcept - : m_extents(extents), m_strides(strides) - { - } - - constexpr index_type strides() const noexcept { return m_strides; } - - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - constexpr size_type total_size() const noexcept - { - size_type ret = 0; - for (std::size_t i = 0; i < rank; ++i) { ret += (m_extents[i] - 1) * m_strides[i]; } - return ret + 1; - } - - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - constexpr size_type size() const noexcept - { - size_type ret = 1; - for (std::size_t i = 0; i < rank; ++i) { ret *= m_extents[i]; } - return ret; - } - - constexpr bool contains(const index_type& idx) const noexcept - { - for (std::size_t i = 0; i < rank; ++i) - { - if (idx[i] < 0 || idx[i] >= m_extents[i]) return false; - } - return true; - } - - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - constexpr size_type linearize(const index_type& idx) const - { - size_type ret = 0; - for (std::size_t i = 0; i < rank; i++) - { - Expects(idx[i] < m_extents[i]); // index is out of bounds of the array - ret += idx[i] * m_strides[i]; - } - return ret; - } - - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - constexpr size_type stride() const noexcept { return m_strides[0]; } - - template 1), typename Ret = std::enable_if_t> - constexpr sliced_type slice() const - { - return {details::shift_left(m_extents), details::shift_left(m_strides)}; - } - - template - - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - constexpr size_type extent() const noexcept - { - static_assert(Dim < Rank, - "dimension should be less than rank (dimension count starts from 0)"); - return m_extents[Dim]; - } - - constexpr index_type index_bounds() const noexcept { return m_extents; } - - constexpr const_iterator begin() const noexcept { return const_iterator{*this, index_type{}}; } - - constexpr const_iterator end() const noexcept { return const_iterator{*this, index_bounds()}; } - -private: - index_type m_extents; - index_type m_strides; -}; - -template -struct is_bounds : std::integral_constant -{ -}; -template -struct is_bounds> : std::integral_constant -{ -}; -template -struct is_bounds> : std::integral_constant -{ -}; - -template -class bounds_iterator -{ -public: - static const std::size_t rank = IndexType::rank; - using iterator_category = std::random_access_iterator_tag; - using value_type = IndexType; - using difference_type = std::ptrdiff_t; - using pointer = value_type*; - using reference = value_type&; - using index_type = value_type; - using index_size_type = typename IndexType::value_type; - template - explicit bounds_iterator(const Bounds& bnd, value_type curr) noexcept - : boundary_(bnd.index_bounds()), curr_(std::move(curr)) - { - static_assert(is_bounds::value, "Bounds type must be provided"); - } - - constexpr reference operator*() const noexcept { return curr_; } - - constexpr pointer operator->() const noexcept { return &curr_; } - - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute - constexpr bounds_iterator& operator++() noexcept - - { - for (std::size_t i = rank; i-- > 0;) - { - if (curr_[i] < boundary_[i] - 1) - { - curr_[i]++; - return *this; - } - curr_[i] = 0; - } - // If we're here we've wrapped over - set to past-the-end. - curr_ = boundary_; - return *this; - } - - constexpr bounds_iterator operator++(int) noexcept - { - auto ret = *this; - ++(*this); - return ret; - } - - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - constexpr bounds_iterator& operator--() - { - if (!less(curr_, boundary_)) - { - // if at the past-the-end, set to last element - for (std::size_t i = 0; i < rank; ++i) { curr_[i] = boundary_[i] - 1; } - return *this; - } - for (std::size_t i = rank; i-- > 0;) - { - if (curr_[i] >= 1) - { - curr_[i]--; - return *this; - } - curr_[i] = boundary_[i] - 1; - } - // If we're here the preconditions were violated - // "pre: there exists s such that r == ++s" - Expects(false); - return *this; - } - - constexpr bounds_iterator operator--(int) noexcept - { - auto ret = *this; - --(*this); - return ret; - } - - constexpr bounds_iterator operator+(difference_type n) const noexcept - { - bounds_iterator ret{*this}; - return ret += n; - } - - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - constexpr bounds_iterator& operator+=(difference_type n) - { - auto linear_idx = linearize(curr_) + n; - std::remove_const_t stride = 0; - stride[rank - 1] = 1; - for (std::size_t i = rank - 1; i-- > 0;) { stride[i] = stride[i + 1] * boundary_[i + 1]; } - for (std::size_t i = 0; i < rank; ++i) - { - curr_[i] = linear_idx / stride[i]; - linear_idx = linear_idx % stride[i]; - } - // index is out of bounds of the array - Expects(!less(curr_, index_type{}) && !less(boundary_, curr_)); - return *this; - } - - constexpr bounds_iterator operator-(difference_type n) const noexcept - { - bounds_iterator ret{*this}; - return ret -= n; - } - - constexpr bounds_iterator& operator-=(difference_type n) noexcept { return *this += -n; } - - constexpr difference_type operator-(const bounds_iterator& rhs) const noexcept - { - return linearize(curr_) - linearize(rhs.curr_); - } - - constexpr value_type operator[](difference_type n) const noexcept { return *(*this + n); } - - constexpr bool operator==(const bounds_iterator& rhs) const noexcept - { - return curr_ == rhs.curr_; - } - - - constexpr bool operator!=(const bounds_iterator& rhs) const noexcept { return !(*this == rhs); } - - constexpr bool operator<(const bounds_iterator& rhs) const noexcept - { - return less(curr_, rhs.curr_); - } - - constexpr bool operator<=(const bounds_iterator& rhs) const noexcept { return !(rhs < *this); } - - constexpr bool operator>(const bounds_iterator& rhs) const noexcept { return rhs < *this; } - - constexpr bool operator>=(const bounds_iterator& rhs) const noexcept { return !(rhs > *this); } - - void swap(bounds_iterator& rhs) noexcept - { - std::swap(boundary_, rhs.boundary_); - std::swap(curr_, rhs.curr_); - } - -private: - - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - constexpr bool less(index_type& one, index_type& other) const noexcept - { - for (std::size_t i = 0; i < rank; ++i) - { - if (one[i] < other[i]) return true; - } - return false; - } - - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - constexpr index_size_type linearize(const value_type& idx) const noexcept - { - // TODO: Smarter impl. - // Check if past-the-end - index_size_type multiplier = 1; - index_size_type res = 0; - if (!less(idx, boundary_)) - { - res = 1; - for (std::size_t i = rank; i-- > 0;) - { - res += (idx[i] - 1) * multiplier; - multiplier *= boundary_[i]; - } - } - else - { - for (std::size_t i = rank; i-- > 0;) - { - res += idx[i] * multiplier; - multiplier *= boundary_[i]; - } - } - return res; - } - - value_type boundary_; - std::remove_const_t curr_; -}; - -template -bounds_iterator operator+(typename bounds_iterator::difference_type n, - const bounds_iterator& rhs) noexcept -{ - return rhs + n; -} - -namespace details -{ - template - constexpr std::enable_if_t< - std::is_same::value, - typename Bounds::index_type> - make_stride(const Bounds& bnd) noexcept - { - return bnd.strides(); - } - - // Make a stride vector from bounds, assuming contiguous memory. - template - constexpr std::enable_if_t< - std::is_same::value, - typename Bounds::index_type> - make_stride(const Bounds& bnd) noexcept - { - auto extents = bnd.index_bounds(); - typename Bounds::size_type stride[Bounds::rank] = {}; - - stride[Bounds::rank - 1] = 1; - for (std::size_t i = 1; i < Bounds::rank; ++i) - { - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute - stride[Bounds::rank - i - 1] = stride[Bounds::rank - i] * extents[Bounds::rank - i]; - } - return {stride}; - } - - template - void verifyBoundsReshape(const BoundsSrc& src, const BoundsDest& dest) - { - static_assert(is_bounds::value && is_bounds::value, - "The src type and dest type must be bounds"); - static_assert(std::is_same::value, - "The source type must be a contiguous bounds"); - static_assert(BoundsDest::static_size == dynamic_range || - BoundsSrc::static_size == dynamic_range || - BoundsDest::static_size == BoundsSrc::static_size, - "The source bounds must have same size as dest bounds"); - Expects(src.size() == dest.size()); - } - -} // namespace details - -template -class contiguous_span_iterator; -template -class general_span_iterator; - -template -struct dim_t -{ - static const std::ptrdiff_t value = DimSize; -}; -template <> -struct dim_t -{ - static const std::ptrdiff_t value = dynamic_range; - const std::ptrdiff_t dvalue; - constexpr dim_t(std::ptrdiff_t size) noexcept : dvalue(size) {} -}; - -template = 0)>> -constexpr dim_t dim() noexcept -{ - return dim_t(); -} - -template > -constexpr dim_t dim(std::ptrdiff_t n) noexcept -{ - return dim_t<>(n); -} - -template -class multi_span; -template -class strided_span; - -namespace details -{ - template - struct SpanTypeTraits - { - using value_type = T; - using size_type = std::size_t; - }; - - template - struct SpanTypeTraits::type> - { - using value_type = typename Traits::span_traits::value_type; - using size_type = typename Traits::span_traits::size_type; - }; - - template - struct SpanArrayTraits - { - using type = multi_span; - using value_type = T; - using bounds_type = static_bounds; - using pointer = T*; - using reference = T&; - }; - template - struct SpanArrayTraits : SpanArrayTraits - { - }; - - template - BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::true_type) // dynamic size - { - Expects(totalSize >= 0 && totalSize <= PTRDIFF_MAX); - return BoundsType{totalSize}; - } - template - BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::false_type) // static size - { - Expects(BoundsType::static_size <= totalSize); - return {}; - } - template - BoundsType newBoundsHelper(std::ptrdiff_t totalSize) - { - static_assert(BoundsType::dynamic_rank <= 1, "dynamic rank must less or equal to 1"); - return newBoundsHelperImpl( - totalSize, std::integral_constant()); - } - - struct Sep - { - }; - - template - T static_as_multi_span_helper(Sep, Args... args) - { - return T{narrow_cast(args)...}; - } - template - std::enable_if_t< - !std::is_same>::value && !std::is_same::value, T> - static_as_multi_span_helper(Arg, Args... args) - { - return static_as_multi_span_helper(args...); - } - template - T static_as_multi_span_helper(dim_t val, Args... args) - { - return static_as_multi_span_helper(args..., val.dvalue); - } - - template - struct static_as_multi_span_static_bounds_helper - { - using type = static_bounds<(Dimensions::value)...>; - }; - - template - struct is_multi_span_oracle : std::false_type - { - }; - - template - struct is_multi_span_oracle> - : std::true_type - { - }; - - template - struct is_multi_span_oracle> : std::true_type - { - }; - - template - struct is_multi_span : is_multi_span_oracle> - { - }; -} // namespace details - -template -class multi_span -{ - // TODO do we still need this? - template - friend class multi_span; - -public: - using bounds_type = static_bounds; - static const std::size_t Rank = bounds_type::rank; - using size_type = typename bounds_type::size_type; - using index_type = typename bounds_type::index_type; - using value_type = ValueType; - using const_value_type = std::add_const_t; - using pointer = std::add_pointer_t; - using reference = std::add_lvalue_reference_t; - using iterator = contiguous_span_iterator; - using const_span = multi_span; - using const_iterator = contiguous_span_iterator; - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - using sliced_type = - std::conditional_t>; - -private: - pointer data_; - bounds_type bounds_; - - friend iterator; - friend const_iterator; - -public: - // default constructor - same as constructing from nullptr_t - GSL_SUPPRESS(type.6) // NO-FORMAT: attribute // TODO: false positive - constexpr multi_span() noexcept - : multi_span(nullptr, bounds_type{}) - { - static_assert(bounds_type::dynamic_rank != 0 || - (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0), - "Default construction of multi_span only possible " - "for dynamic or fixed, zero-length spans."); - } - - // construct from nullptr - get an empty multi_span - GSL_SUPPRESS(type.6) // NO-FORMAT: attribute // TODO: false positive - constexpr multi_span(std::nullptr_t) noexcept - : multi_span(nullptr, bounds_type{}) - { - static_assert(bounds_type::dynamic_rank != 0 || - (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0), - "nullptr_t construction of multi_span only possible " - "for dynamic or fixed, zero-length spans."); - } - - // construct from nullptr with size of 0 (helps with template function calls) - template ::value>> - - // GSL_SUPPRESS(type.6) // NO-FORMAT: attribute // TODO: false positive // TODO: parser bug - constexpr multi_span(std::nullptr_t, IntType size) : multi_span(nullptr, bounds_type{}) - { - static_assert(bounds_type::dynamic_rank != 0 || - (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0), - "nullptr_t construction of multi_span only possible " - "for dynamic or fixed, zero-length spans."); - Expects(size == 0); - } - - // construct from a single element - - GSL_SUPPRESS(type.6) // NO-FORMAT: attribute // TODO: false positive - constexpr multi_span(reference data) noexcept - : multi_span(&data, bounds_type{1}) - { - static_assert(bounds_type::dynamic_rank > 0 || bounds_type::static_size == 0 || - bounds_type::static_size == 1, - "Construction from a single element only possible " - "for dynamic or fixed spans of length 0 or 1."); - } - - // prevent constructing from temporaries for single-elements - constexpr multi_span(value_type&&) = delete; - - // construct from pointer + length - GSL_SUPPRESS(type.6) // NO-FORMAT: attribute // TODO: false positive - constexpr multi_span(pointer ptr, size_type size) - : multi_span(ptr, bounds_type{size}) - {} - - // construct from pointer + length - multidimensional - constexpr multi_span(pointer data, bounds_type bounds) - : data_(data), bounds_(std::move(bounds)) - { - Expects((bounds_.size() > 0 && data != nullptr) || bounds_.size() == 0); - } - - // construct from begin,end pointer pair - template ::value && - details::LessThan::value>> - constexpr multi_span(pointer begin, Ptr end) - : multi_span(begin, - details::newBoundsHelper(static_cast(end) - begin)) - { - Expects(begin != nullptr && end != nullptr && begin <= static_cast(end)); - } - - // construct from n-dimensions static array - template > - constexpr multi_span(T (&arr)[N]) - : multi_span(reinterpret_cast(arr), bounds_type{typename Helper::bounds_type{}}) - { - static_assert(std::is_convertible::value, - "Cannot convert from source type to target multi_span type."); - static_assert(std::is_convertible::value, - "Cannot construct a multi_span from an array with fewer elements."); - } - - // construct from n-dimensions dynamic array (e.g. new int[m][4]) - // (precedence will be lower than the 1-dimension pointer) - template > - constexpr multi_span(T* const& data, size_type size) - : multi_span(reinterpret_cast(data), typename Helper::bounds_type{size}) - { - static_assert(std::is_convertible::value, - "Cannot convert from source type to target multi_span type."); - } - - // construct from std::array - template - constexpr multi_span(std::array& arr) - : multi_span(arr.data(), bounds_type{static_bounds{}}) - { - static_assert( - std::is_convertible(*)[]>::value, - "Cannot convert from source type to target multi_span type."); - static_assert(std::is_convertible, bounds_type>::value, - "You cannot construct a multi_span from a std::array of smaller size."); - } - - // construct from const std::array - template - constexpr multi_span(const std::array& arr) - : multi_span(arr.data(), bounds_type{static_bounds{}}) - { - static_assert( - std::is_convertible(*)[]>::value, - "Cannot convert from source type to target multi_span type."); - static_assert(std::is_convertible, bounds_type>::value, - "You cannot construct a multi_span from a std::array of smaller size."); - } - - // prevent constructing from temporary std::array - template - constexpr multi_span(std::array&& arr) = delete; - - // construct from containers - // future: could use contiguous_iterator_traits to identify only contiguous containers - // type-requirements: container must have .size(), operator[] which are value_type compatible - template ::value && - std::is_convertible::value && - std::is_same().size(), - *std::declval().data())>, - DataType>::value>> - constexpr multi_span(Cont& cont) - : multi_span(static_cast(cont.data()), - details::newBoundsHelper(narrow_cast(cont.size()))) - {} - - // prevent constructing from temporary containers - template ::value && - std::is_convertible::value && - std::is_same().size(), - *std::declval().data())>, - DataType>::value>> - explicit constexpr multi_span(Cont&& cont) = delete; - - // construct from a convertible multi_span - template , - typename = std::enable_if_t::value && - std::is_convertible::value>> - constexpr multi_span(multi_span other) - : data_(other.data_), bounds_(other.bounds_) - {} - - // trivial copy and move - constexpr multi_span(const multi_span&) = default; - constexpr multi_span(multi_span&&) = default; - - // trivial assignment - constexpr multi_span& operator=(const multi_span&) = default; - constexpr multi_span& operator=(multi_span&&) = default; - - // first() - extract the first Count elements into a new multi_span - template - - constexpr multi_span first() const - { - static_assert(Count >= 0, "Count must be >= 0."); - static_assert(bounds_type::static_size == dynamic_range || - Count <= bounds_type::static_size, - "Count is out of bounds."); - - Expects(bounds_type::static_size != dynamic_range || Count <= this->size()); - return {this->data(), Count}; - } - - // first() - extract the first count elements into a new multi_span - constexpr multi_span first(size_type count) const - { - Expects(count >= 0 && count <= this->size()); - return {this->data(), count}; - } - - // last() - extract the last Count elements into a new multi_span - template - constexpr multi_span last() const - { - static_assert(Count >= 0, "Count must be >= 0."); - static_assert(bounds_type::static_size == dynamic_range || - Count <= bounds_type::static_size, - "Count is out of bounds."); - - Expects(bounds_type::static_size != dynamic_range || Count <= this->size()); - return {this->data() + this->size() - Count, Count}; - } - - // last() - extract the last count elements into a new multi_span - constexpr multi_span last(size_type count) const - { - Expects(count >= 0 && count <= this->size()); - return {this->data() + this->size() - count, count}; - } - - // subspan() - create a subview of Count elements starting at Offset - template - constexpr multi_span subspan() const - { - static_assert(Count >= 0, "Count must be >= 0."); - static_assert(Offset >= 0, "Offset must be >= 0."); - static_assert(bounds_type::static_size == dynamic_range || - ((Offset <= bounds_type::static_size) && - Count <= bounds_type::static_size - Offset), - "You must describe a sub-range within bounds of the multi_span."); - - Expects(bounds_type::static_size != dynamic_range || - (Offset <= this->size() && Count <= this->size() - Offset)); - return {this->data() + Offset, Count}; - } - - // subspan() - create a subview of count elements starting at offset - // supplying dynamic_range for count will consume all available elements from offset - constexpr multi_span subspan(size_type offset, - size_type count = dynamic_range) const - { - Expects((offset >= 0 && offset <= this->size()) && - (count == dynamic_range || (count <= this->size() - offset))); - return {this->data() + offset, count == dynamic_range ? this->length() - offset : count}; - } - - // section - creates a non-contiguous, strided multi_span from a contiguous one - constexpr strided_span section(index_type origin, - index_type extents) const - { - const size_type size = this->bounds().total_size() - this->bounds().linearize(origin); - return {&this->operator[](origin), size, - strided_bounds{extents, details::make_stride(bounds())}}; - } - - // length of the multi_span in elements - constexpr size_type size() const noexcept { return bounds_.size(); } - - // length of the multi_span in elements - constexpr size_type length() const noexcept { return this->size(); } - - // length of the multi_span in bytes - constexpr size_type size_bytes() const noexcept - { - return narrow_cast(sizeof(value_type)) * this->size(); - } - - // length of the multi_span in bytes - constexpr size_type length_bytes() const noexcept { return this->size_bytes(); } - - constexpr bool empty() const noexcept { return this->size() == 0; } - - static constexpr std::size_t rank() { return Rank; } - - template - constexpr size_type extent() const noexcept - { - static_assert(Dim < Rank, - "Dimension should be less than rank (dimension count starts from 0)."); - return bounds_.template extent(); - } - - template - constexpr size_type extent(IntType dim) const - { - return bounds_.extent(dim); - } - - constexpr bounds_type bounds() const noexcept { return bounds_; } - - constexpr pointer data() const noexcept { return data_; } - - template - constexpr reference operator()(FirstIndex idx) - { - return this->operator[](narrow_cast(idx)); - } - - template - constexpr reference operator()(FirstIndex firstIndex, OtherIndices... indices) - { - const index_type idx = {narrow_cast(firstIndex), - narrow_cast(indices)...}; - return this->operator[](idx); - } - - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - constexpr reference operator[](const index_type& idx) const - { - return data_[bounds_.linearize(idx)]; - } - - template 1), typename Ret = std::enable_if_t> - - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - constexpr Ret operator[](size_type idx) const - { - Expects(idx >= 0 && idx < bounds_.size()); // index is out of bounds of the array - const size_type ridx = idx * bounds_.stride(); - - // index is out of bounds of the underlying data - Expects(ridx < bounds_.total_size()); - return Ret{data_ + ridx, bounds_.slice()}; - } - - constexpr iterator begin() const noexcept { return iterator{this, true}; } - - constexpr iterator end() const noexcept { return iterator{this, false}; } - - GSL_SUPPRESS(type.1) // NO-FORMAT: attribute - constexpr const_iterator cbegin() const noexcept - { - return const_iterator{reinterpret_cast(this), true}; - } - - constexpr const_iterator cend() const noexcept - { - return const_iterator{reinterpret_cast(this), false}; - } - - constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } - - constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; } - - constexpr const_reverse_iterator crbegin() const noexcept - { - return const_reverse_iterator{cend()}; - } - - constexpr const_reverse_iterator crend() const noexcept - { - return const_reverse_iterator{cbegin()}; - } - - template , - std::remove_cv_t>::value>> - constexpr bool operator==(const multi_span& other) const - { - return bounds_.size() == other.bounds_.size() && - (data_ == other.data_ || std::equal(this->begin(), this->end(), other.begin())); - } - - template , - std::remove_cv_t>::value>> - constexpr bool operator!=(const multi_span& other) const - { - return !(*this == other); - } - - template , - std::remove_cv_t>::value>> - constexpr bool operator<(const multi_span& other) const - { - return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end()); - } - - template , - std::remove_cv_t>::value>> - constexpr bool operator<=(const multi_span& other) const - { - return !(other < *this); - } - - template , - std::remove_cv_t>::value>> - constexpr bool operator>(const multi_span& other) const - noexcept - { - return (other < *this); - } - - template , - std::remove_cv_t>::value>> - constexpr bool operator>=(const multi_span& other) const - { - return !(*this < other); - } -}; - -// -// Free functions for manipulating spans -// - -// reshape a multi_span into a different dimensionality -// DimCount and Enabled here are workarounds for a bug in MSVC 2015 -template 0), typename = std::enable_if_t> -constexpr auto as_multi_span(SpanType s, Dimensions2... dims) - -> multi_span -{ - static_assert(details::is_multi_span::value, - "Variadic as_multi_span() is for reshaping existing spans."); - using BoundsType = - typename multi_span::bounds_type; - const auto tobounds = details::static_as_multi_span_helper(dims..., details::Sep{}); - details::verifyBoundsReshape(s.bounds(), tobounds); - return {s.data(), tobounds}; -} - -// convert a multi_span to a multi_span -template -multi_span as_bytes(multi_span s) noexcept -{ - static_assert(std::is_trivial>::value, - "The value_type of multi_span must be a trivial type."); - return {reinterpret_cast(s.data()), s.size_bytes()}; -} - -// convert a multi_span to a multi_span (a writeable byte multi_span) -// this is not currently a portable function that can be relied upon to work -// on all implementations. It should be considered an experimental extension -// to the standard GSL interface. -template -multi_span as_writeable_bytes(multi_span s) noexcept -{ - static_assert(std::is_trivial>::value, - "The value_type of multi_span must be a trivial type."); - return {reinterpret_cast(s.data()), s.size_bytes()}; -} - -// convert a multi_span to a multi_span -// this is not currently a portable function that can be relied upon to work -// on all implementations. It should be considered an experimental extension -// to the standard GSL interface. -template -constexpr auto as_multi_span(multi_span s) -> multi_span< - const U, static_cast( - multi_span::bounds_type::static_size != dynamic_range - ? (static_cast( - multi_span::bounds_type::static_size) / - sizeof(U)) - : dynamic_range)> -{ - using ConstByteSpan = multi_span; - static_assert( - std::is_trivial>::value && - (ConstByteSpan::bounds_type::static_size == dynamic_range || - ConstByteSpan::bounds_type::static_size % narrow_cast(sizeof(U)) == 0), - "Target type must be a trivial type and its size must match the byte array size"); - - Expects((s.size_bytes() % narrow_cast(sizeof(U))) == 0 && - (s.size_bytes() / narrow_cast(sizeof(U))) < PTRDIFF_MAX); - return {reinterpret_cast(s.data()), - s.size_bytes() / narrow_cast(sizeof(U))}; -} - -// convert a multi_span to a multi_span -// this is not currently a portable function that can be relied upon to work -// on all implementations. It should be considered an experimental extension -// to the standard GSL interface. -template -constexpr auto as_multi_span(multi_span s) - -> multi_span( - multi_span::bounds_type::static_size != dynamic_range - ? static_cast( - multi_span::bounds_type::static_size) / - sizeof(U) - : dynamic_range)> -{ - using ByteSpan = multi_span; - static_assert(std::is_trivial>::value && - (ByteSpan::bounds_type::static_size == dynamic_range || - ByteSpan::bounds_type::static_size % sizeof(U) == 0), - "Target type must be a trivial type and its size must match the byte array size"); - - Expects((s.size_bytes() % sizeof(U)) == 0); - return {reinterpret_cast(s.data()), - s.size_bytes() / narrow_cast(sizeof(U))}; -} - -template -constexpr auto as_multi_span(T* const& ptr, dim_t... args) - -> multi_span, Dimensions...> -{ - return {reinterpret_cast*>(ptr), - details::static_as_multi_span_helper>(args..., - details::Sep{})}; -} - -template -constexpr auto as_multi_span(T* arr, std::ptrdiff_t len) -> - typename details::SpanArrayTraits::type -{ - return {reinterpret_cast*>(arr), len}; -} - -template -constexpr auto as_multi_span(T (&arr)[N]) -> typename details::SpanArrayTraits::type -{ - return {arr}; -} - -template -constexpr multi_span as_multi_span(const std::array& arr) -{ - return {arr}; -} - -template -constexpr multi_span as_multi_span(const std::array&&) = delete; - -template -constexpr multi_span as_multi_span(std::array& arr) -{ - return {arr}; -} - -template -constexpr multi_span as_multi_span(T* begin, T* end) -{ - return {begin, end}; -} - -template -constexpr auto as_multi_span(Cont& arr) -> std::enable_if_t< - !details::is_multi_span>::value, - multi_span, dynamic_range>> -{ - Expects(arr.size() < PTRDIFF_MAX); - return {arr.data(), narrow_cast(arr.size())}; -} - -template -constexpr auto as_multi_span(Cont&& arr) -> std::enable_if_t< - !details::is_multi_span>::value, - multi_span, dynamic_range>> = delete; - -// from basic_string which doesn't have nonconst .data() member like other contiguous containers -template -GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute -constexpr auto as_multi_span(std::basic_string& str) - -> multi_span -{ - Expects(str.size() < PTRDIFF_MAX); - return {&str[0], narrow_cast(str.size())}; -} - -// strided_span is an extension that is not strictly part of the GSL at this time. -// It is kept here while the multidimensional interface is still being defined. -template -class strided_span -{ -public: - using bounds_type = strided_bounds; - using size_type = typename bounds_type::size_type; - using index_type = typename bounds_type::index_type; - using value_type = ValueType; - using const_value_type = std::add_const_t; - using pointer = std::add_pointer_t; - using reference = std::add_lvalue_reference_t; - using iterator = general_span_iterator; - using const_strided_span = strided_span; - using const_iterator = general_span_iterator; - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - using sliced_type = - std::conditional_t>; - -private: - pointer data_; - bounds_type bounds_; - - friend iterator; - friend const_iterator; - template - friend class strided_span; - -public: - // from raw data - constexpr strided_span(pointer ptr, size_type size, bounds_type bounds) - : data_(ptr), bounds_(std::move(bounds)) - { - Expects((bounds_.size() > 0 && ptr != nullptr) || bounds_.size() == 0); - // Bounds cross data boundaries - Expects(this->bounds().total_size() <= size); - GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: false positive - (void) size; - } - - // from static array of size N - template - constexpr strided_span(value_type (&values)[N], bounds_type bounds) - : strided_span(values, N, std::move(bounds)) - {} - - // from array view - template ::value, - typename = std::enable_if_t> - constexpr strided_span(multi_span av, bounds_type bounds) - : strided_span(av.data(), av.bounds().total_size(), std::move(bounds)) - {} - - // convertible - template ::value>> - constexpr strided_span(const strided_span& other) - : data_(other.data_), bounds_(other.bounds_) - {} - - // convert from bytes - template - constexpr strided_span< - typename std::enable_if::value, OtherValueType>::type, - Rank> - as_strided_span() const - { - static_assert((sizeof(OtherValueType) >= sizeof(value_type)) && - (sizeof(OtherValueType) % sizeof(value_type) == 0), - "OtherValueType should have a size to contain a multiple of ValueTypes"); - auto d = narrow_cast(sizeof(OtherValueType) / sizeof(value_type)); - - const size_type size = this->bounds().total_size() / d; - - GSL_SUPPRESS(type.3) // NO-FORMAT: attribute - return {const_cast(reinterpret_cast(this->data())), - size, - bounds_type{resize_extent(this->bounds().index_bounds(), d), - resize_stride(this->bounds().strides(), d)}}; - } - - constexpr strided_span section(index_type origin, index_type extents) const - { - const size_type size = this->bounds().total_size() - this->bounds().linearize(origin); - return {&this->operator[](origin), size, - bounds_type{extents, details::make_stride(bounds())}}; - } - - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - constexpr reference operator[](const index_type& idx) const - { - return data_[bounds_.linearize(idx)]; - } - - template 1), typename Ret = std::enable_if_t> - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - constexpr Ret operator[](size_type idx) const - { - Expects(idx < bounds_.size()); // index is out of bounds of the array - const size_type ridx = idx * bounds_.stride(); - - // index is out of bounds of the underlying data - Expects(ridx < bounds_.total_size()); - return {data_ + ridx, bounds_.slice().total_size(), bounds_.slice()}; - } - - constexpr bounds_type bounds() const noexcept { return bounds_; } - - template - constexpr size_type extent() const noexcept - { - static_assert(Dim < Rank, - "dimension should be less than Rank (dimension count starts from 0)"); - return bounds_.template extent(); - } - - constexpr size_type size() const noexcept { return bounds_.size(); } - - constexpr pointer data() const noexcept { return data_; } - - constexpr bool empty() const noexcept { return this->size() == 0; } - - constexpr explicit operator bool() const noexcept { return data_ != nullptr; } - - constexpr iterator begin() const { return iterator{this, true}; } - - constexpr iterator end() const { return iterator{this, false}; } - - constexpr const_iterator cbegin() const - { - return const_iterator{reinterpret_cast(this), true}; - } - - constexpr const_iterator cend() const - { - return const_iterator{reinterpret_cast(this), false}; - } - - constexpr reverse_iterator rbegin() const { return reverse_iterator{end()}; } - - constexpr reverse_iterator rend() const { return reverse_iterator{begin()}; } - - constexpr const_reverse_iterator crbegin() const { return const_reverse_iterator{cend()}; } - - constexpr const_reverse_iterator crend() const { return const_reverse_iterator{cbegin()}; } - - template , - std::remove_cv_t>::value>> - constexpr bool operator==(const strided_span& other) const - { - return bounds_.size() == other.bounds_.size() && - (data_ == other.data_ || std::equal(this->begin(), this->end(), other.begin())); - } - - template , - std::remove_cv_t>::value>> - constexpr bool operator!=(const strided_span& other) const - { - return !(*this == other); - } - - template , - std::remove_cv_t>::value>> - constexpr bool operator<(const strided_span& other) const - { - return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end()); - } - - template , - std::remove_cv_t>::value>> - constexpr bool operator<=(const strided_span& other) const - { - return !(other < *this); - } - - template , - std::remove_cv_t>::value>> - constexpr bool operator>(const strided_span& other) const - { - return (other < *this); - } - - template , - std::remove_cv_t>::value>> - constexpr bool operator>=(const strided_span& other) const - { - return !(*this < other); - } - -private: - static index_type resize_extent(const index_type& extent, std::ptrdiff_t d) - { - // The last dimension of the array needs to contain a multiple of new type elements - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - Expects(extent[Rank - 1] >= d && (extent[Rank - 1] % d == 0)); - - index_type ret = extent; - ret[Rank - 1] /= d; - - return ret; - } - - template > - static index_type resize_stride(const index_type& strides, std::ptrdiff_t, void* = nullptr) - { - // Only strided arrays with regular strides can be resized - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - Expects(strides[Rank - 1] == 1); - - return strides; - } - - template 1), typename = std::enable_if_t> - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - static index_type resize_stride(const index_type& strides, std::ptrdiff_t d) - { - // Only strided arrays with regular strides can be resized - Expects(strides[Rank - 1] == 1); - // The strides must have contiguous chunks of - // memory that can contain a multiple of new type elements - Expects(strides[Rank - 2] >= d && (strides[Rank - 2] % d == 0)); - - for (std::size_t i = Rank - 1; i > 0; --i) - { - // Only strided arrays with regular strides can be resized - Expects((strides[i - 1] >= strides[i]) && (strides[i - 1] % strides[i] == 0)); - } - - index_type ret = strides / d; - ret[Rank - 1] = 1; - - return ret; - } -}; - -template -class contiguous_span_iterator -{ -public: - using iterator_category = std::random_access_iterator_tag; - using value_type = typename Span::value_type; - using difference_type = std::ptrdiff_t; - using pointer = value_type*; - using reference = value_type&; - -private: - template - friend class multi_span; - - pointer data_; - const Span* m_validator; - - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - void validateThis() const { - // iterator is out of range of the array - Expects(data_ >= m_validator->data_ && data_ < m_validator->data_ + m_validator->size()); - } - - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - contiguous_span_iterator(const Span* container, bool isbegin) - : data_(isbegin ? container->data_ : container->data_ + container->size()) - , m_validator(container) - {} - -public: - reference operator*() const - { - validateThis(); - return *data_; - } - pointer operator->() const - { - validateThis(); - return data_; - } - - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - contiguous_span_iterator& operator++() noexcept - { - ++data_; - return *this; - } - contiguous_span_iterator operator++(int) noexcept - { - auto ret = *this; - ++(*this); - return ret; - } - - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - contiguous_span_iterator& operator--() noexcept - { - --data_; - return *this; - } - contiguous_span_iterator operator--(int) noexcept - { - auto ret = *this; - --(*this); - return ret; - } - contiguous_span_iterator operator+(difference_type n) const noexcept - { - contiguous_span_iterator ret{*this}; - return ret += n; - } - contiguous_span_iterator& operator+=(difference_type n) noexcept - { - data_ += n; - return *this; - } - contiguous_span_iterator operator-(difference_type n) const noexcept - { - contiguous_span_iterator ret{*this}; - return ret -= n; - } - - contiguous_span_iterator& operator-=(difference_type n) { return *this += -n; } - difference_type operator-(const contiguous_span_iterator& rhs) const - { - Expects(m_validator == rhs.m_validator); - return data_ - rhs.data_; - } - reference operator[](difference_type n) const { return *(*this + n); } - bool operator==(const contiguous_span_iterator& rhs) const - { - Expects(m_validator == rhs.m_validator); - return data_ == rhs.data_; - } - - bool operator!=(const contiguous_span_iterator& rhs) const { return !(*this == rhs); } - - bool operator<(const contiguous_span_iterator& rhs) const - { - Expects(m_validator == rhs.m_validator); - return data_ < rhs.data_; - } - - bool operator<=(const contiguous_span_iterator& rhs) const { return !(rhs < *this); } - bool operator>(const contiguous_span_iterator& rhs) const { return rhs < *this; } - bool operator>=(const contiguous_span_iterator& rhs) const { return !(rhs > *this); } - - void swap(contiguous_span_iterator& rhs) noexcept - { - std::swap(data_, rhs.data_); - std::swap(m_validator, rhs.m_validator); - } -}; - -template -contiguous_span_iterator operator+(typename contiguous_span_iterator::difference_type n, - const contiguous_span_iterator& rhs) noexcept -{ - return rhs + n; -} - -template -class general_span_iterator { -public: - using iterator_category = std::random_access_iterator_tag; - using value_type = typename Span::value_type; - using difference_type = std::ptrdiff_t; - using pointer = value_type*; - using reference = value_type&; - -private: - template - friend class strided_span; - - const Span* m_container; - typename Span::bounds_type::iterator m_itr; - general_span_iterator(const Span* container, bool isbegin) - : m_container(container) - , m_itr(isbegin ? m_container->bounds().begin() : m_container->bounds().end()) - {} - -public: - reference operator*() noexcept { return (*m_container)[*m_itr]; } - pointer operator->() noexcept { return &(*m_container)[*m_itr]; } - general_span_iterator& operator++() noexcept - { - ++m_itr; - return *this; - } - general_span_iterator operator++(int) noexcept - { - auto ret = *this; - ++(*this); - return ret; - } - general_span_iterator& operator--() noexcept - { - --m_itr; - return *this; - } - general_span_iterator operator--(int) noexcept - { - auto ret = *this; - --(*this); - return ret; - } - general_span_iterator operator+(difference_type n) const noexcept - { - general_span_iterator ret{*this}; - return ret += n; - } - general_span_iterator& operator+=(difference_type n) noexcept - { - m_itr += n; - return *this; - } - general_span_iterator operator-(difference_type n) const noexcept - { - general_span_iterator ret{*this}; - return ret -= n; - } - general_span_iterator& operator-=(difference_type n) noexcept { return *this += -n; } - difference_type operator-(const general_span_iterator& rhs) const - { - Expects(m_container == rhs.m_container); - return m_itr - rhs.m_itr; - } - - GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute - value_type operator[](difference_type n) const { return (*m_container)[m_itr[n]]; } - - bool operator==(const general_span_iterator& rhs) const - { - Expects(m_container == rhs.m_container); - return m_itr == rhs.m_itr; - } - bool operator!=(const general_span_iterator& rhs) const { return !(*this == rhs); } - bool operator<(const general_span_iterator& rhs) const - { - Expects(m_container == rhs.m_container); - return m_itr < rhs.m_itr; - } - bool operator<=(const general_span_iterator& rhs) const { return !(rhs < *this); } - bool operator>(const general_span_iterator& rhs) const { return rhs < *this; } - bool operator>=(const general_span_iterator& rhs) const { return !(rhs > *this); } - void swap(general_span_iterator& rhs) noexcept - { - std::swap(m_itr, rhs.m_itr); - std::swap(m_container, rhs.m_container); - } -}; - -template -general_span_iterator operator+(typename general_span_iterator::difference_type n, - const general_span_iterator& rhs) noexcept -{ - return rhs + n; -} - -} // namespace gsl - -#if defined(_MSC_VER) && !defined(__clang__) -#if _MSC_VER < 1910 - -#undef constexpr -#pragma pop_macro("constexpr") -#endif // _MSC_VER < 1910 - -#pragma warning(pop) - -#endif // _MSC_VER - -#if defined(__GNUC__) && __GNUC__ > 6 -#pragma GCC diagnostic pop -#endif // __GNUC__ > 6 - -#endif // GSL_MULTI_SPAN_H diff --git a/Unicord.Universal.Voice/gsl/pointers b/Unicord.Universal.Voice/gsl/pointers deleted file mode 100644 index 0f2987a0..00000000 --- a/Unicord.Universal.Voice/gsl/pointers +++ /dev/null @@ -1,294 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2015 Microsoft Corporation. All rights reserved. -// -// This code is licensed under the MIT License (MIT). -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef GSL_POINTERS_H -#define GSL_POINTERS_H - -#include // for Ensures, Expects - -#include // for forward -#include // for ptrdiff_t, nullptr_t, ostream, size_t -#include // for shared_ptr, unique_ptr -#include // for hash -#include // for enable_if_t, is_convertible, is_assignable - -#if defined(_MSC_VER) && _MSC_VER < 1910 && !defined(__clang__) -#pragma push_macro("constexpr") -#define constexpr /*constexpr*/ - -#endif // defined(_MSC_VER) && _MSC_VER < 1910 - -namespace gsl -{ - -// -// GSL.owner: ownership pointers -// -using std::unique_ptr; -using std::shared_ptr; - -// -// owner -// -// owner is designed as a bridge for code that must deal directly with owning pointers for some reason -// -// T must be a pointer type -// - disallow construction from any type other than pointer type -// -template ::value>> -using owner = T; - -// -// not_null -// -// Restricts a pointer or smart pointer to only hold non-null values. -// -// Has zero size overhead over T. -// -// If T is a pointer (i.e. T == U*) then -// - allow construction from U* -// - disallow construction from nullptr_t -// - disallow default construction -// - ensure construction from null U* fails -// - allow implicit conversion to U* -// -template -class not_null -{ -public: - static_assert(std::is_assignable::value, "T cannot be assigned nullptr."); - - template ::value>> - constexpr not_null(U&& u) : ptr_(std::forward(u)) - { - Expects(ptr_ != nullptr); - } - - template ::value>> - constexpr not_null(T u) : ptr_(u) - { - Expects(ptr_ != nullptr); - } - - template ::value>> - constexpr not_null(const not_null& other) : not_null(other.get()) - { - } - - not_null(not_null&& other) = default; - not_null(const not_null& other) = default; - not_null& operator=(const not_null& other) = default; - - constexpr T get() const - { - Ensures(ptr_ != nullptr); - return ptr_; - } - - constexpr operator T() const { return get(); } - constexpr T operator->() const { return get(); } - constexpr decltype(auto) operator*() const { return *get(); } - - // prevents compilation when someone attempts to assign a null pointer constant - not_null(std::nullptr_t) = delete; - not_null& operator=(std::nullptr_t) = delete; - - // unwanted operators...pointers only point to single objects! - not_null& operator++() = delete; - not_null& operator--() = delete; - not_null operator++(int) = delete; - not_null operator--(int) = delete; - not_null& operator+=(std::ptrdiff_t) = delete; - not_null& operator-=(std::ptrdiff_t) = delete; - void operator[](std::ptrdiff_t) const = delete; - -private: - T ptr_; -}; - -template -auto make_not_null(T&& t) { - return not_null>>{std::forward(t)}; -} - -template -std::ostream& operator<<(std::ostream& os, const not_null& val) -{ - os << val.get(); - return os; -} - -template -auto operator==(const not_null& lhs, const not_null& rhs) -> decltype(lhs.get() == rhs.get()) -{ - return lhs.get() == rhs.get(); -} - -template -auto operator!=(const not_null& lhs, const not_null& rhs) -> decltype(lhs.get() != rhs.get()) -{ - return lhs.get() != rhs.get(); -} - -template -auto operator<(const not_null& lhs, const not_null& rhs) -> decltype(lhs.get() < rhs.get()) -{ - return lhs.get() < rhs.get(); -} - -template -auto operator<=(const not_null& lhs, const not_null& rhs) -> decltype(lhs.get() <= rhs.get()) -{ - return lhs.get() <= rhs.get(); -} - -template -auto operator>(const not_null& lhs, const not_null& rhs) -> decltype(lhs.get() > rhs.get()) -{ - return lhs.get() > rhs.get(); -} - -template -auto operator>=(const not_null& lhs, const not_null& rhs) -> decltype(lhs.get() >= rhs.get()) -{ - return lhs.get() >= rhs.get(); -} - -// more unwanted operators -template -std::ptrdiff_t operator-(const not_null&, const not_null&) = delete; -template -not_null operator-(const not_null&, std::ptrdiff_t) = delete; -template -not_null operator+(const not_null&, std::ptrdiff_t) = delete; -template -not_null operator+(std::ptrdiff_t, const not_null&) = delete; - -} // namespace gsl - -namespace std -{ -template -struct hash> -{ - std::size_t operator()(const gsl::not_null& value) const { return hash{}(value); } -}; - -} // namespace std - -namespace gsl -{ - -// -// strict_not_null -// -// Restricts a pointer or smart pointer to only hold non-null values, -// -// - provides a strict (i.e. explicit contructor from T) wrapper of not_null -// - to be used for new code that wishes the design to be cleaner and make not_null -// checks intentional, or in old code that would like to make the transition. -// -// To make the transition from not_null, incrementally replace not_null -// by strict_not_null and fix compilation errors -// -// Expect to -// - remove all unneded conversions from raw pointer to not_null and back -// - make API clear by specifyning not_null in parameters where needed -// - remove unnesessary asserts -// -template -class strict_not_null: public not_null -{ -public: - - template ::value>> - constexpr explicit strict_not_null(U&& u) : - not_null(std::forward(u)) - {} - - template ::value>> - constexpr explicit strict_not_null(T u) : - not_null(u) - {} - - template ::value>> - constexpr strict_not_null(const not_null& other) : - not_null(other) - {} - - template ::value>> - constexpr strict_not_null(const strict_not_null& other) : - not_null(other) - {} - - strict_not_null(strict_not_null&& other) = default; - strict_not_null(const strict_not_null& other) = default; - strict_not_null& operator=(const strict_not_null& other) = default; - strict_not_null& operator=(const not_null& other) - { - not_null::operator=(other); - return *this; - } - - // prevents compilation when someone attempts to assign a null pointer constant - strict_not_null(std::nullptr_t) = delete; - strict_not_null& operator=(std::nullptr_t) = delete; - - // unwanted operators...pointers only point to single objects! - strict_not_null& operator++() = delete; - strict_not_null& operator--() = delete; - strict_not_null operator++(int) = delete; - strict_not_null operator--(int) = delete; - strict_not_null& operator+=(std::ptrdiff_t) = delete; - strict_not_null& operator-=(std::ptrdiff_t) = delete; - void operator[](std::ptrdiff_t) const = delete; -}; - -// more unwanted operators -template -std::ptrdiff_t operator-(const strict_not_null&, const strict_not_null&) = delete; -template -strict_not_null operator-(const strict_not_null&, std::ptrdiff_t) = delete; -template -strict_not_null operator+(const strict_not_null&, std::ptrdiff_t) = delete; -template -strict_not_null operator+(std::ptrdiff_t, const strict_not_null&) = delete; - -template -auto make_strict_not_null(T&& t) { - return strict_not_null>>{std::forward(t)}; -} - -} // namespace gsl - -namespace std -{ -template -struct hash> -{ - std::size_t operator()(const gsl::strict_not_null& value) const { return hash{}(value); } -}; - -} // namespace std - -#if defined(_MSC_VER) && _MSC_VER < 1910 && !defined(__clang__) - -#undef constexpr -#pragma pop_macro("constexpr") - -#endif // defined(_MSC_VER) && _MSC_VER < 1910 && !defined(__clang__) - -#endif // GSL_POINTERS_H diff --git a/Unicord.Universal.Voice/gsl/span b/Unicord.Universal.Voice/gsl/span deleted file mode 100644 index b4da5321..00000000 --- a/Unicord.Universal.Voice/gsl/span +++ /dev/null @@ -1,793 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2015 Microsoft Corporation. All rights reserved. -// -// This code is licensed under the MIT License (MIT). -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef GSL_SPAN_H -#define GSL_SPAN_H - -#include // for Expects -#include // for byte -#include // for narrow_cast, narrow - -#include // for lexicographical_compare -#include // for array -#include // for ptrdiff_t, size_t, nullptr_t -#include // for reverse_iterator, distance, random_access_... -#include -#include -#include // for enable_if_t, declval, is_convertible, inte... -#include -#include // for std::addressof - -#if defined(_MSC_VER) && !defined(__clang__) -#pragma warning(push) - -// turn off some warnings that are noisy about our Expects statements -#pragma warning(disable : 4127) // conditional expression is constant -#pragma warning(disable : 4702) // unreachable code - -// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool. -#pragma warning(disable : 26495) // uninitalized member when constructor calls constructor -#pragma warning(disable : 26446) // parser bug does not allow attributes on some templates - -#if _MSC_VER < 1910 -#pragma push_macro("constexpr") -#define constexpr /*constexpr*/ -#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND - -#endif // _MSC_VER < 1910 -#endif // _MSC_VER - -// See if we have enough C++17 power to use a static constexpr data member -// without needing an out-of-line definition -#if !(defined(__cplusplus) && (__cplusplus >= 201703L)) -#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND -#endif // !(defined(__cplusplus) && (__cplusplus >= 201703L)) - -// GCC 7 does not like the signed unsigned missmatch (size_t ptrdiff_t) -// While there is a conversion from signed to unsigned, it happens at -// compiletime, so the compiler wouldn't have to warn indiscriminently, but -// could check if the source value actually doesn't fit into the target type -// and only warn in those cases. -#if defined(__GNUC__) && __GNUC__ > 6 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wsign-conversion" -#endif - -namespace gsl -{ - -// [views.constants], constants -constexpr const std::ptrdiff_t dynamic_extent = -1; - -template -class span; - -// implementation details -namespace details -{ - template - struct is_span_oracle : std::false_type - { - }; - - template - struct is_span_oracle> : std::true_type - { - }; - - template - struct is_span : public is_span_oracle> - { - }; - - template - struct is_std_array_oracle : std::false_type - { - }; - - template - struct is_std_array_oracle> : std::true_type - { - }; - - template - struct is_std_array : public is_std_array_oracle> - { - }; - - template - struct is_allowed_extent_conversion - : public std::integral_constant - { - }; - - template - struct is_allowed_element_type_conversion - : public std::integral_constant::value> - { - }; - - template - class span_iterator - { - using element_type_ = typename Span::element_type; - - public: -#ifdef _MSC_VER - // Tell Microsoft standard library that span_iterators are checked. - using _Unchecked_type = typename Span::pointer; -#endif - - using iterator_category = std::random_access_iterator_tag; - using value_type = std::remove_cv_t; - using difference_type = typename Span::index_type; - - using reference = std::conditional_t&; - using pointer = std::add_pointer_t; - - span_iterator() = default; - - constexpr span_iterator(const Span* span, typename Span::index_type idx) noexcept - : span_(span), index_(idx) - {} - - friend span_iterator; - template * = nullptr> - constexpr span_iterator(const span_iterator& other) noexcept - : span_iterator(other.span_, other.index_) - {} - - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - constexpr reference operator*() const - { - Expects(index_ != span_->size()); - return *(span_->data() + index_); - } - - constexpr pointer operator->() const - { - Expects(index_ != span_->size()); - return span_->data() + index_; - } - - constexpr span_iterator& operator++() - { - Expects(0 <= index_ && index_ != span_->size()); - ++index_; - return *this; - } - - constexpr span_iterator operator++(int) - { - auto ret = *this; - ++(*this); - return ret; - } - - constexpr span_iterator& operator--() - { - Expects(index_ != 0 && index_ <= span_->size()); - --index_; - return *this; - } - - constexpr span_iterator operator--(int) - { - auto ret = *this; - --(*this); - return ret; - } - - constexpr span_iterator operator+(difference_type n) const - { - auto ret = *this; - return ret += n; - } - - friend constexpr span_iterator operator+(difference_type n, span_iterator const& rhs) - { - return rhs + n; - } - - constexpr span_iterator& operator+=(difference_type n) - { - Expects((index_ + n) >= 0 && (index_ + n) <= span_->size()); - index_ += n; - return *this; - } - - constexpr span_iterator operator-(difference_type n) const - { - auto ret = *this; - return ret -= n; - } - - constexpr span_iterator& operator-=(difference_type n) { return *this += -n; } - - constexpr difference_type operator-(span_iterator rhs) const - { - Expects(span_ == rhs.span_); - return index_ - rhs.index_; - } - - constexpr reference operator[](difference_type n) const { return *(*this + n); } - - constexpr friend bool operator==(span_iterator lhs, span_iterator rhs) noexcept - { - return lhs.span_ == rhs.span_ && lhs.index_ == rhs.index_; - } - - constexpr friend bool operator!=(span_iterator lhs, span_iterator rhs) noexcept - { - return !(lhs == rhs); - } - - constexpr friend bool operator<(span_iterator lhs, span_iterator rhs) noexcept - { - return lhs.index_ < rhs.index_; - } - - constexpr friend bool operator<=(span_iterator lhs, span_iterator rhs) noexcept - { - return !(rhs < lhs); - } - - constexpr friend bool operator>(span_iterator lhs, span_iterator rhs) noexcept - { - return rhs < lhs; - } - - constexpr friend bool operator>=(span_iterator lhs, span_iterator rhs) noexcept - { - return !(rhs > lhs); - } - -#ifdef _MSC_VER - // MSVC++ iterator debugging support; allows STL algorithms in 15.8+ - // to unwrap span_iterator to a pointer type after a range check in STL - // algorithm calls - friend constexpr void _Verify_range(span_iterator lhs, span_iterator rhs) noexcept - { // test that [lhs, rhs) forms a valid range inside an STL algorithm - Expects(lhs.span_ == rhs.span_ // range spans have to match - && lhs.index_ <= rhs.index_); // range must not be transposed - } - - constexpr void _Verify_offset(const difference_type n) const noexcept - { // test that the iterator *this + n is a valid range in an STL - // algorithm call - Expects((index_ + n) >= 0 && (index_ + n) <= span_->size()); - } - - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - constexpr pointer _Unwrapped() const noexcept - { // after seeking *this to a high water mark, or using one of the - // _Verify_xxx functions above, unwrap this span_iterator to a raw - // pointer - return span_->data() + index_; - } - - // Tell the STL that span_iterator should not be unwrapped if it can't - // validate in advance, even in release / optimized builds: -#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) - static constexpr const bool _Unwrap_when_unverified = false; -#else - static constexpr bool _Unwrap_when_unverified = false; -#endif - GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive - constexpr void _Seek_to(const pointer p) noexcept - { // adjust the position of *this to previously verified location p - // after _Unwrapped - index_ = p - span_->data(); - } -#endif - - protected: - const Span* span_ = nullptr; - std::ptrdiff_t index_ = 0; - }; - - template - class extent_type - { - public: - using index_type = std::ptrdiff_t; - - static_assert(Ext >= 0, "A fixed-size span must be >= 0 in size."); - - constexpr extent_type() noexcept {} - - template - constexpr extent_type(extent_type ext) - { - static_assert(Other == Ext || Other == dynamic_extent, - "Mismatch between fixed-size extent and size of initializing data."); - Expects(ext.size() == Ext); - } - - constexpr extent_type(index_type size) { Expects(size == Ext); } - - constexpr index_type size() const noexcept { return Ext; } - }; - - template <> - class extent_type - { - public: - using index_type = std::ptrdiff_t; - - template - explicit constexpr extent_type(extent_type ext) : size_(ext.size()) - {} - - explicit constexpr extent_type(index_type size) : size_(size) { Expects(size >= 0); } - - constexpr index_type size() const noexcept { return size_; } - - private: - index_type size_; - }; - - template - struct calculate_subspan_type - { - using type = span; - }; -} // namespace details - -// [span], class template span -template -class span -{ -public: - // constants and types - using element_type = ElementType; - using value_type = std::remove_cv_t; - using index_type = std::ptrdiff_t; - using pointer = element_type*; - using reference = element_type&; - - using iterator = details::span_iterator, false>; - using const_iterator = details::span_iterator, true>; - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - - using size_type = index_type; - -#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) - static constexpr const index_type extent{Extent}; -#else - static constexpr index_type extent{Extent}; -#endif - - // [span.cons], span constructors, copy, assignment, and destructor - template " SFINAE, - // since "std::enable_if_t" is ill-formed when Extent is greater than 0. - class = std::enable_if_t<(Dependent || Extent <= 0)>> - constexpr span() noexcept : storage_(nullptr, details::extent_type<0>()) - {} - - constexpr span(pointer ptr, index_type count) : storage_(ptr, count) {} - - constexpr span(pointer firstElem, pointer lastElem) - : storage_(firstElem, std::distance(firstElem, lastElem)) - {} - - template - constexpr span(element_type (&arr)[N]) noexcept - : storage_(KnownNotNull{std::addressof(arr[0])}, details::extent_type()) - {} - - template 0)>> - constexpr span(std::array, N>& arr) noexcept - : storage_(KnownNotNull{arr.data()}, details::extent_type()) - { - } - - constexpr span(std::array, 0>&) noexcept - : storage_(static_cast(nullptr), details::extent_type<0>()) - { - } - - template 0)>> - constexpr span(const std::array, N>& arr) noexcept - : storage_(KnownNotNull{arr.data()}, details::extent_type()) - { - } - - constexpr span(const std::array, 0>&) noexcept - : storage_(static_cast(nullptr), details::extent_type<0>()) - { - } - - // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement - // on Container to be a contiguous sequence container. - template ::value && !details::is_std_array::value && - std::is_convertible::value && - std::is_convertible().data())>::value>> - constexpr span(Container& cont) : span(cont.data(), narrow(cont.size())) - {} - - template ::value && !details::is_span::value && - std::is_convertible::value && - std::is_convertible().data())>::value>> - constexpr span(const Container& cont) : span(cont.data(), narrow(cont.size())) - {} - - constexpr span(const span& other) noexcept = default; - - template < - class OtherElementType, std::ptrdiff_t OtherExtent, - class = std::enable_if_t< - details::is_allowed_extent_conversion::value && - details::is_allowed_element_type_conversion::value>> - constexpr span(const span& other) - : storage_(other.data(), details::extent_type(other.size())) - {} - - ~span() noexcept = default; - constexpr span& operator=(const span& other) noexcept = default; - - // [span.sub], span subviews - template - constexpr span first() const - { - Expects(Count >= 0 && Count <= size()); - return {data(), Count}; - } - - template - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - constexpr span last() const - { - Expects(Count >= 0 && size() - Count >= 0); - return {data() + (size() - Count), Count}; - } - - template - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - constexpr auto subspan() const -> - typename details::calculate_subspan_type::type - { - Expects((Offset >= 0 && size() - Offset >= 0) && - (Count == dynamic_extent || (Count >= 0 && Offset + Count <= size()))); - - return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count}; - } - - constexpr span first(index_type count) const - { - Expects(count >= 0 && count <= size()); - return {data(), count}; - } - - constexpr span last(index_type count) const - { - return make_subspan(size() - count, dynamic_extent, subspan_selector{}); - } - - constexpr span subspan(index_type offset, - index_type count = dynamic_extent) const - { - return make_subspan(offset, count, subspan_selector{}); - } - - // [span.obs], span observers - constexpr index_type size() const noexcept { return storage_.size(); } - constexpr index_type size_bytes() const noexcept - { - return size() * narrow_cast(sizeof(element_type)); - } - constexpr bool empty() const noexcept { return size() == 0; } - - // [span.elem], span element access - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - constexpr reference operator[](index_type idx) const - { - Expects(CheckRange(idx, storage_.size())); - return data()[idx]; - } - - constexpr reference at(index_type idx) const { return this->operator[](idx); } - constexpr reference operator()(index_type idx) const { return this->operator[](idx); } - constexpr pointer data() const noexcept { return storage_.data(); } - - // [span.iter], span iterator support - constexpr iterator begin() const noexcept { return {this, 0}; } - constexpr iterator end() const noexcept { return {this, size()}; } - - constexpr const_iterator cbegin() const noexcept { return {this, 0}; } - constexpr const_iterator cend() const noexcept { return {this, size()}; } - - constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } - constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; } - - constexpr const_reverse_iterator crbegin() const noexcept - { - return const_reverse_iterator{cend()}; - } - constexpr const_reverse_iterator crend() const noexcept - { - return const_reverse_iterator{cbegin()}; - } - -#ifdef _MSC_VER - // Tell MSVC how to unwrap spans in range-based-for - constexpr pointer _Unchecked_begin() const noexcept { return data(); } - constexpr pointer _Unchecked_end() const noexcept - { - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - return data() + size(); - } -#endif // _MSC_VER - -private: - static constexpr bool CheckRange(index_type idx, index_type size) noexcept - { - // Optimization: - // - // idx >= 0 && idx < size - // => - // static_cast(idx) < static_cast(size) - // - // because size >=0 by span construction, and negative idx will - // wrap around to a value always greater than size when casted. - - // check if we have enough space to wrap around -#if defined(__cpp_if_constexpr) - if constexpr (sizeof(index_type) <= sizeof(size_t)) -#else - if (sizeof(index_type) <= sizeof(size_t)) -#endif - { - return narrow_cast(idx) < narrow_cast(size); - } - else - { - return idx >= 0 && idx < size; - } - } - - // Needed to remove unnecessary null check in subspans - struct KnownNotNull - { - pointer p; - }; - - // this implementation detail class lets us take advantage of the - // empty base class optimization to pay for only storage of a single - // pointer in the case of fixed-size spans - template - class storage_type : public ExtentType - { - public: - // KnownNotNull parameter is needed to remove unnecessary null check - // in subspans and constructors from arrays - template - constexpr storage_type(KnownNotNull data, OtherExtentType ext) - : ExtentType(ext), data_(data.p) - { - Expects(ExtentType::size() >= 0); - } - - template - constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data) - { - Expects(ExtentType::size() >= 0); - Expects(data || ExtentType::size() == 0); - } - - constexpr pointer data() const noexcept { return data_; } - - private: - pointer data_; - }; - - storage_type> storage_; - - // The rest is needed to remove unnecessary null check - // in subspans and constructors from arrays - constexpr span(KnownNotNull ptr, index_type count) : storage_(ptr, count) {} - - template - class subspan_selector - { - }; - - template - span make_subspan(index_type offset, index_type count, - subspan_selector) const - { - const span tmp(*this); - return tmp.subspan(offset, count); - } - - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute - span make_subspan(index_type offset, index_type count, - subspan_selector) const - { - Expects(offset >= 0 && size() - offset >= 0); - - if (count == dynamic_extent) { return {KnownNotNull{data() + offset}, size() - offset}; } - - Expects(count >= 0 && size() - offset >= count); - return {KnownNotNull{data() + offset}, count}; - } -}; - -#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) -template -constexpr const typename span::index_type span::extent; -#endif - -// [span.comparison], span comparison operators -template -constexpr bool operator==(span l, span r) -{ - return std::equal(l.begin(), l.end(), r.begin(), r.end()); -} - -template -constexpr bool operator!=(span l, span r) -{ - return !(l == r); -} - -template -constexpr bool operator<(span l, span r) -{ - return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); -} - -template -constexpr bool operator<=(span l, span r) -{ - return !(l > r); -} - -template -constexpr bool operator>(span l, span r) -{ - return r < l; -} - -template -constexpr bool operator>=(span l, span r) -{ - return !(l < r); -} - -namespace details -{ - // if we only supported compilers with good constexpr support then - // this pair of classes could collapse down to a constexpr function - - // we should use a narrow_cast<> to go to std::size_t, but older compilers may not see it as - // constexpr - // and so will fail compilation of the template - template - struct calculate_byte_size - : std::integral_constant(sizeof(ElementType) * - static_cast(Extent))> - { - }; - - template - struct calculate_byte_size - : std::integral_constant - { - }; -} // namespace details - -// [span.objectrep], views of object representation -template -span::value> -as_bytes(span s) noexcept -{ - GSL_SUPPRESS(type.1) // NO-FORMAT: attribute - return {reinterpret_cast(s.data()), s.size_bytes()}; -} - -template ::value>> -span::value> -as_writeable_bytes(span s) noexcept -{ - GSL_SUPPRESS(type.1) // NO-FORMAT: attribute - return {reinterpret_cast(s.data()), s.size_bytes()}; -} - -// -// make_span() - Utility functions for creating spans -// -template -constexpr span make_span(ElementType* ptr, - typename span::index_type count) -{ - return span(ptr, count); -} - -template -constexpr span make_span(ElementType* firstElem, ElementType* lastElem) -{ - return span(firstElem, lastElem); -} - -template -constexpr span make_span(ElementType (&arr)[N]) noexcept -{ - return span(arr); -} - -template -constexpr span make_span(Container& cont) -{ - return span(cont); -} - -template -constexpr span make_span(const Container& cont) -{ - return span(cont); -} - -template -constexpr span make_span(Ptr& cont, std::ptrdiff_t count) -{ - return span(cont, count); -} - -template -constexpr span make_span(Ptr& cont) -{ - return span(cont); -} - -// Specialization of gsl::at for span -template -constexpr ElementType& at(span s, index i) -{ - // No bounds checking here because it is done in span::operator[] called below - return s[i]; -} - -} // namespace gsl - -#if defined(_MSC_VER) && !defined(__clang__) -#if _MSC_VER < 1910 -#undef constexpr -#pragma pop_macro("constexpr") - -#endif // _MSC_VER < 1910 - -#pragma warning(pop) -#endif // _MSC_VER - -#if defined(__GNUC__) && __GNUC__ > 6 -#pragma GCC diagnostic pop -#endif // __GNUC__ > 6 - -#endif // GSL_SPAN_H diff --git a/Unicord.Universal.Voice/gsl/string_span b/Unicord.Universal.Voice/gsl/string_span deleted file mode 100644 index 85112e5d..00000000 --- a/Unicord.Universal.Voice/gsl/string_span +++ /dev/null @@ -1,722 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2015 Microsoft Corporation. All rights reserved. -// -// This code is licensed under the MIT License (MIT). -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef GSL_STRING_SPAN_H -#define GSL_STRING_SPAN_H - -#include // for Ensures, Expects -#include // for narrow_cast -#include // for operator!=, operator==, dynamic_extent -#include // for not_null - -#include // for equal, lexicographical_compare -#include // for array -#include // for ptrdiff_t, size_t, nullptr_t -#include // for PTRDIFF_MAX -#include -#include // for basic_string, allocator, char_traits -#include // for declval, is_convertible, enable_if_t, add_... - -#if defined(_MSC_VER) && !defined(__clang__) -#pragma warning(push) - -// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool. -#pragma warning(disable : 26446) // TODO: bug in parser - attributes and templates -#pragma warning(disable : 26481) // TODO: suppress does not work inside templates sometimes - -#if _MSC_VER < 1910 -#pragma push_macro("constexpr") -#define constexpr /*constexpr*/ - -#endif // _MSC_VER < 1910 -#endif // _MSC_VER - -namespace gsl -{ -// -// czstring and wzstring -// -// These are "tag" typedefs for C-style strings (i.e. null-terminated character arrays) -// that allow static analysis to help find bugs. -// -// There are no additional features/semantics that we can find a way to add inside the -// type system for these types that will not either incur significant runtime costs or -// (sometimes needlessly) break existing programs when introduced. -// - -template -using basic_zstring = CharT*; - -template -using czstring = basic_zstring; - -template -using cwzstring = basic_zstring; - -template -using cu16zstring = basic_zstring; - -template -using cu32zstring = basic_zstring; - -template -using zstring = basic_zstring; - -template -using wzstring = basic_zstring; - -template -using u16zstring = basic_zstring; - -template -using u32zstring = basic_zstring; - -namespace details -{ - template - std::ptrdiff_t string_length(const CharT* str, std::ptrdiff_t n) - { - if (str == nullptr || n <= 0) return 0; - - const span str_span{str, n}; - - std::ptrdiff_t len = 0; - while (len < n && str_span[len]) len++; - - return len; - } -} // namespace details - -// -// ensure_sentinel() -// -// Provides a way to obtain an span from a contiguous sequence -// that ends with a (non-inclusive) sentinel value. -// -// Will fail-fast if sentinel cannot be found before max elements are examined. -// -template -span ensure_sentinel(T* seq, std::ptrdiff_t max = PTRDIFF_MAX) -{ - Ensures(seq != nullptr); - - GSL_SUPPRESS(f.23) // NO-FORMAT: attribute // TODO: false positive // TODO: suppress does not work - auto cur = seq; - Ensures(cur != nullptr); // workaround for removing the warning - - GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute // TODO: suppress does not work - while ((cur - seq) < max && *cur != Sentinel) ++cur; - Ensures(*cur == Sentinel); - return {seq, cur - seq}; -} - -// -// ensure_z - creates a span for a zero terminated strings. -// Will fail fast if a null-terminator cannot be found before -// the limit of size_type. -// -template -span ensure_z(CharT* const& sz, std::ptrdiff_t max = PTRDIFF_MAX) -{ - return ensure_sentinel(sz, max); -} - -template -span ensure_z(CharT (&sz)[N]) -{ - return ensure_z(&sz[0], narrow_cast(N)); -} - -template -span::type, dynamic_extent> -ensure_z(Cont& cont) -{ - return ensure_z(cont.data(), narrow_cast(cont.size())); -} - -template -class basic_string_span; - -namespace details { - template - struct is_basic_string_span_oracle : std::false_type - { - }; - - template - struct is_basic_string_span_oracle> : std::true_type - { - }; - - template - struct is_basic_string_span : is_basic_string_span_oracle> - { - }; -} // namespace details - -// -// string_span and relatives -// -template -class basic_string_span -{ -public: - using element_type = CharT; - using value_type = std::remove_cv_t; - using pointer = std::add_pointer_t; - using reference = std::add_lvalue_reference_t; - using const_reference = std::add_lvalue_reference_t>; - using impl_type = span; - - using index_type = typename impl_type::index_type; - using iterator = typename impl_type::iterator; - using const_iterator = typename impl_type::const_iterator; - using reverse_iterator = typename impl_type::reverse_iterator; - using const_reverse_iterator = typename impl_type::const_reverse_iterator; - - using size_type = index_type; - - // default (empty) - constexpr basic_string_span() noexcept = default; - - // copy - constexpr basic_string_span(const basic_string_span& other) noexcept = default; - - // assign - constexpr basic_string_span& operator=(const basic_string_span& other) noexcept = default; - - constexpr basic_string_span(pointer ptr, index_type length) : span_(ptr, length) {} - constexpr basic_string_span(pointer firstElem, pointer lastElem) : span_(firstElem, lastElem) {} - - // From static arrays - if 0-terminated, remove 0 from the view - // All other containers allow 0s within the length, so we do not remove them - template - constexpr basic_string_span(element_type (&arr)[N]) : span_(remove_z(arr)) - {} - - template > - constexpr basic_string_span(std::array& arr) noexcept : span_(arr) - {} - - template > - constexpr basic_string_span(const std::array& arr) noexcept : span_(arr) - {} - - // Container signature should work for basic_string after C++17 version exists - template - // GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug - constexpr basic_string_span(std::basic_string& str) - : span_(&str[0], narrow_cast(str.length())) - {} - - template - constexpr basic_string_span(const std::basic_string& str) - : span_(&str[0], str.length()) - {} - - // from containers. Containers must have a pointer type and data() function signatures - template ::value && - std::is_convertible::value && - std::is_convertible().data())>::value>> - constexpr basic_string_span(Container& cont) : span_(cont) - {} - - template ::value && - std::is_convertible::value && - std::is_convertible().data())>::value>> - constexpr basic_string_span(const Container& cont) : span_(cont) - {} - - // from string_span - template < - class OtherValueType, std::ptrdiff_t OtherExtent, - class = std::enable_if_t::impl_type, impl_type>::value>> - constexpr basic_string_span(basic_string_span other) - : span_(other.data(), other.length()) - {} - - template - constexpr basic_string_span first() const - { - return {span_.template first()}; - } - - constexpr basic_string_span first(index_type count) const - { - return {span_.first(count)}; - } - - template - constexpr basic_string_span last() const - { - return {span_.template last()}; - } - - constexpr basic_string_span last(index_type count) const - { - return {span_.last(count)}; - } - - template - constexpr basic_string_span subspan() const - { - return {span_.template subspan()}; - } - - constexpr basic_string_span - subspan(index_type offset, index_type count = dynamic_extent) const - { - return {span_.subspan(offset, count)}; - } - - constexpr reference operator[](index_type idx) const { return span_[idx]; } - constexpr reference operator()(index_type idx) const { return span_[idx]; } - - constexpr pointer data() const { return span_.data(); } - - constexpr index_type length() const noexcept { return span_.size(); } - constexpr index_type size() const noexcept { return span_.size(); } - constexpr index_type size_bytes() const noexcept { return span_.size_bytes(); } - constexpr index_type length_bytes() const noexcept { return span_.length_bytes(); } - constexpr bool empty() const noexcept { return size() == 0; } - - constexpr iterator begin() const noexcept { return span_.begin(); } - constexpr iterator end() const noexcept { return span_.end(); } - - constexpr const_iterator cbegin() const noexcept { return span_.cbegin(); } - constexpr const_iterator cend() const noexcept { return span_.cend(); } - - constexpr reverse_iterator rbegin() const noexcept { return span_.rbegin(); } - constexpr reverse_iterator rend() const noexcept { return span_.rend(); } - - constexpr const_reverse_iterator crbegin() const noexcept { return span_.crbegin(); } - constexpr const_reverse_iterator crend() const noexcept { return span_.crend(); } - -private: - static impl_type remove_z(pointer const& sz, std::ptrdiff_t max) - { - return {sz, details::string_length(sz, max)}; - } - - template - static impl_type remove_z(element_type (&sz)[N]) - { - return remove_z(&sz[0], narrow_cast(N)); - } - - impl_type span_; -}; - -template -using string_span = basic_string_span; - -template -using cstring_span = basic_string_span; - -template -using wstring_span = basic_string_span; - -template -using cwstring_span = basic_string_span; - -template -using u16string_span = basic_string_span; - -template -using cu16string_span = basic_string_span; - -template -using u32string_span = basic_string_span; - -template -using cu32string_span = basic_string_span; - -// -// to_string() allow (explicit) conversions from string_span to string -// - -template -std::basic_string::type> -to_string(basic_string_span view) -{ - return {view.data(), narrow_cast(view.length())}; -} - -template , - typename Allocator = std::allocator, typename gCharT, std::ptrdiff_t Extent> -std::basic_string to_basic_string(basic_string_span view) -{ - return {view.data(), narrow_cast(view.length())}; -} - -template -basic_string_span::value> -as_bytes(basic_string_span s) noexcept -{ - GSL_SUPPRESS(type.1) // NO-FORMAT: attribute - return {reinterpret_cast(s.data()), s.size_bytes()}; -} - -template ::value>> -basic_string_span::value> -as_writeable_bytes(basic_string_span s) noexcept -{ - GSL_SUPPRESS(type.1) // NO-FORMAT: attribute - return {reinterpret_cast(s.data()), s.size_bytes()}; -} - -// zero-terminated string span, used to convert -// zero-terminated spans to legacy strings -template -class basic_zstring_span { -public: - using value_type = CharT; - using const_value_type = std::add_const_t; - - using pointer = std::add_pointer_t; - using const_pointer = std::add_pointer_t; - - using zstring_type = basic_zstring; - using const_zstring_type = basic_zstring; - - using impl_type = span; - using string_span_type = basic_string_span; - - constexpr basic_zstring_span(impl_type s) : span_(s) - { - // expects a zero-terminated span - Expects(s[s.size() - 1] == '\0'); - } - - // copy - constexpr basic_zstring_span(const basic_zstring_span& other) = default; - - // move - constexpr basic_zstring_span(basic_zstring_span&& other) = default; - - // assign - constexpr basic_zstring_span& operator=(const basic_zstring_span& other) = default; - - // move assign - constexpr basic_zstring_span& operator=(basic_zstring_span&& other) = default; - - constexpr bool empty() const noexcept { return span_.size() == 0; } - - constexpr string_span_type as_string_span() const noexcept - { - const auto sz = span_.size(); - return {span_.data(), sz > 1 ? sz - 1 : 0}; - } - constexpr string_span_type ensure_z() const { return gsl::ensure_z(span_); } - - constexpr const_zstring_type assume_z() const noexcept { return span_.data(); } - -private: - impl_type span_; -}; - -template -using zstring_span = basic_zstring_span; - -template -using wzstring_span = basic_zstring_span; - -template -using u16zstring_span = basic_zstring_span; - -template -using u32zstring_span = basic_zstring_span; - -template -using czstring_span = basic_zstring_span; - -template -using cwzstring_span = basic_zstring_span; - -template -using cu16zstring_span = basic_zstring_span; - -template -using cu32zstring_span = basic_zstring_span; - -// operator == -template ::value || - std::is_convertible>>::value>> -bool operator==(const gsl::basic_string_span& one, const T& other) -{ - const gsl::basic_string_span> tmp(other); - return std::equal(one.begin(), one.end(), tmp.begin(), tmp.end()); -} - -template ::value && - std::is_convertible>>::value>> -bool operator==(const T& one, const gsl::basic_string_span& other) -{ - const gsl::basic_string_span> tmp(one); - return std::equal(tmp.begin(), tmp.end(), other.begin(), other.end()); -} - -// operator != -template , Extent>>::value>> -bool operator!=(gsl::basic_string_span one, const T& other) -{ - return !(one == other); -} - -template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, - typename = std::enable_if_t< - std::is_convertible, Extent>>::value && - !gsl::details::is_basic_string_span::value>> -bool operator!=(const T& one, gsl::basic_string_span other) -{ - return !(one == other); -} - -// operator< -template , Extent>>::value>> -bool operator<(gsl::basic_string_span one, const T& other) -{ - const gsl::basic_string_span, Extent> tmp(other); - return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end()); -} - -template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, - typename = std::enable_if_t< - std::is_convertible, Extent>>::value && - !gsl::details::is_basic_string_span::value>> -bool operator<(const T& one, gsl::basic_string_span other) -{ - gsl::basic_string_span, Extent> tmp(one); - return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end()); -} - -#ifndef _MSC_VER - -// VS treats temp and const containers as convertible to basic_string_span, -// so the cases below are already covered by the previous operators - -template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, - typename DataType = typename T::value_type, - typename = std::enable_if_t< - !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && - std::is_convertible::value && - std::is_same().size(), *std::declval().data())>, - DataType>::value>> -bool operator<(gsl::basic_string_span one, const T& other) -{ - gsl::basic_string_span, Extent> tmp(other); - return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end()); -} - -template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, - typename DataType = typename T::value_type, - typename = std::enable_if_t< - !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && - std::is_convertible::value && - std::is_same().size(), *std::declval().data())>, - DataType>::value>> -bool operator<(const T& one, gsl::basic_string_span other) -{ - gsl::basic_string_span, Extent> tmp(one); - return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end()); -} -#endif - -// operator <= -template , Extent>>::value>> -bool operator<=(gsl::basic_string_span one, const T& other) -{ - return !(other < one); -} - -template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, - typename = std::enable_if_t< - std::is_convertible, Extent>>::value && - !gsl::details::is_basic_string_span::value>> -bool operator<=(const T& one, gsl::basic_string_span other) -{ - return !(other < one); -} - -#ifndef _MSC_VER - -// VS treats temp and const containers as convertible to basic_string_span, -// so the cases below are already covered by the previous operators - -template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, - typename DataType = typename T::value_type, - typename = std::enable_if_t< - !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && - std::is_convertible::value && - std::is_same().size(), *std::declval().data())>, - DataType>::value>> -bool operator<=(gsl::basic_string_span one, const T& other) -{ - return !(other < one); -} - -template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, - typename DataType = typename T::value_type, - typename = std::enable_if_t< - !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && - std::is_convertible::value && - std::is_same().size(), *std::declval().data())>, - DataType>::value>> -bool operator<=(const T& one, gsl::basic_string_span other) -{ - return !(other < one); -} -#endif - -// operator> -template , Extent>>::value>> -bool operator>(gsl::basic_string_span one, const T& other) -{ - return other < one; -} - -template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, - typename = std::enable_if_t< - std::is_convertible, Extent>>::value && - !gsl::details::is_basic_string_span::value>> -bool operator>(const T& one, gsl::basic_string_span other) -{ - return other < one; -} - -#ifndef _MSC_VER - -// VS treats temp and const containers as convertible to basic_string_span, -// so the cases below are already covered by the previous operators - -template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, - typename DataType = typename T::value_type, - typename = std::enable_if_t< - !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && - std::is_convertible::value && - std::is_same().size(), *std::declval().data())>, - DataType>::value>> -bool operator>(gsl::basic_string_span one, const T& other) -{ - return other < one; -} - -template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, - typename DataType = typename T::value_type, - typename = std::enable_if_t< - !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && - std::is_convertible::value && - std::is_same().size(), *std::declval().data())>, - DataType>::value>> -bool operator>(const T& one, gsl::basic_string_span other) -{ - return other < one; -} -#endif - -// operator >= -template , Extent>>::value>> -bool operator>=(gsl::basic_string_span one, const T& other) -{ - return !(one < other); -} - -template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, - typename = std::enable_if_t< - std::is_convertible, Extent>>::value && - !gsl::details::is_basic_string_span::value>> -bool operator>=(const T& one, gsl::basic_string_span other) -{ - return !(one < other); -} - -#ifndef _MSC_VER - -// VS treats temp and const containers as convertible to basic_string_span, -// so the cases below are already covered by the previous operators - -template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, - typename DataType = typename T::value_type, - typename = std::enable_if_t< - !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && - std::is_convertible::value && - std::is_same().size(), *std::declval().data())>, - DataType>::value>> -bool operator>=(gsl::basic_string_span one, const T& other) -{ - return !(one < other); -} - -template < - typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T, - typename DataType = typename T::value_type, - typename = std::enable_if_t< - !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && - std::is_convertible::value && - std::is_same().size(), *std::declval().data())>, - DataType>::value>> -bool operator>=(const T& one, gsl::basic_string_span other) -{ - return !(one < other); -} -#endif -} // namespace gsl - -#if defined(_MSC_VER) && !defined(__clang__) -#pragma warning(pop) - -#if _MSC_VER < 1910 -#undef constexpr -#pragma pop_macro("constexpr") - -#endif // _MSC_VER < 1910 -#endif // _MSC_VER - -#endif // GSL_STRING_SPAN_H diff --git a/Unicord.Universal.Voice/module.g.cpp b/Unicord.Universal.Voice/module.g.cpp deleted file mode 100644 index 94d4b802..00000000 --- a/Unicord.Universal.Voice/module.g.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// WARNING: Please don't edit this file. It was generated by C++/WinRT v2.0.190620.2 - -#include "pch.h" -#include "winrt/base.h" -void* winrt_make_Unicord_Universal_Voice_VoiceClient(); -void* winrt_make_Unicord_Universal_Voice_VoiceClientOptions(); -void* winrt_make_Unicord_Universal_Voice_VoiceOutputStream(); -void* winrt_make_Unicord_Universal_Voice_Background_VoiceBackgroundTask(); - -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(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.Voice.VoiceClient")) - { - return winrt_make_Unicord_Universal_Voice_VoiceClient(); - } - - if (requal(name, L"Unicord.Universal.Voice.VoiceClientOptions")) - { - return winrt_make_Unicord_Universal_Voice_VoiceClientOptions(); - } - - if (requal(name, L"Unicord.Universal.Voice.VoiceOutputStream")) - { - return winrt_make_Unicord_Universal_Voice_VoiceOutputStream(); - } - - if (requal(name, L"Unicord.Universal.Voice.Background.VoiceBackgroundTask")) - { - return winrt_make_Unicord_Universal_Voice_Background_VoiceBackgroundTask(); - } - - 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 -{ - uint32_t length{}; - wchar_t const* const buffer = WINRT_WindowsGetStringRawBuffer(classId, &length); - std::wstring_view const name{ buffer, length }; - *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.Voice/packages.config b/Unicord.Universal.Voice/packages.config deleted file mode 100644 index 1c90c5ba..00000000 --- a/Unicord.Universal.Voice/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Unicord.Universal.Voice/pch.cpp b/Unicord.Universal.Voice/pch.cpp deleted file mode 100644 index 331e647d..00000000 --- a/Unicord.Universal.Voice/pch.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "pch.h" \ No newline at end of file diff --git a/Unicord.Universal.Voice/pch.h b/Unicord.Universal.Voice/pch.h deleted file mode 100644 index 4706f5bd..00000000 --- a/Unicord.Universal.Voice/pch.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#define NOMINMAX -#define WEBRTC_WIN -#define ABSL_USES_STD_STRING_VIEW - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include diff --git a/Unicord.Universal/App.xaml b/Unicord.Universal/App.xaml index b0f4c0a1..7e309cf7 100644 --- a/Unicord.Universal/App.xaml +++ b/Unicord.Universal/App.xaml @@ -4,179 +4,87 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:media="using:Microsoft.UI.Xaml.Media" xmlns:converters="using:Unicord.Universal.Converters" - xmlns:commands="using:Unicord.Universal.Commands" xmlns:flyouts="using:Unicord.Universal.Controls.Flyouts" RequiresPointerMode="WhenRequested"> + xmlns:commands="using:Unicord.Universal.Commands" + xmlns:flyouts="using:Unicord.Universal.Controls.Flyouts" + xmlns:themes="using:Unicord.Universal.Themes" + RequiresPointerMode="WhenRequested"> - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 14 + 14 + + /Assets/FluentSystemIcons-Regular.ttf#FluentSystemIcons-Regular + /Assets/SegoeIcons.ttf#Segoe Fluent Icons + /Assets/FiraCode-Regular.ttf#Fira Code + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 14 - 14 - - /Assets/SegoeIcons.ttf#Segoe Fluent Icons - /Assets/FluentSystemIcons-Regular.ttf#FluentSystemIcons-Regular - /Assets/SegoeIcons.ttf#Segoe Fluent Icons - Segoe UI - Segoe UI - - - - - - - - - - - - - - - - - - - - - - - - - + + \ No newline at end of file diff --git a/Unicord.Universal/App.xaml.cs b/Unicord.Universal/App.xaml.cs index 2c0e7328..1e88068f 100644 --- a/Unicord.Universal/App.xaml.cs +++ b/Unicord.Universal/App.xaml.cs @@ -1,611 +1,445 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using DSharpPlus; -using DSharpPlus.Entities; -using DSharpPlus.EventArgs; -using Microsoft.AppCenter; -using Microsoft.AppCenter.Analytics; -using Microsoft.AppCenter.Crashes; -using Microsoft.AppCenter.Push; -#if XBOX_GAME_BAR -using Microsoft.Gaming.XboxGameBar; -using Unicord.Universal.Pages.GameBar; -#endif -using Microsoft.Toolkit.Uwp.Helpers; -using Microsoft.Toolkit.Uwp.UI; -using Unicord.Universal.Integration; -using Unicord.Universal.Misc; -using Unicord.Universal.Models; -using Unicord.Universal.Pages; -using Unicord.Universal.Services; -using Unicord.Universal.Utilities; -using WamWooWam.Core; -using Windows.ApplicationModel; -using Windows.ApplicationModel.Activation; -using Windows.ApplicationModel.Core; -using Windows.ApplicationModel.Resources; -using Windows.Foundation; -using Windows.Security.Credentials; -using Windows.Storage; -using Windows.System; -using Windows.System.Profile; -using Windows.UI.Core; -using Windows.UI.Notifications; -using Windows.UI.Popups; -using Windows.UI.ViewManagement; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Navigation; -using static Unicord.Constants; -using UnhandledExceptionEventArgs = Windows.UI.Xaml.UnhandledExceptionEventArgs; - -namespace Unicord.Universal -{ - sealed partial class App : Application - { -#if XBOX_GAME_BAR - private static XboxGameBarWidget _chatListWidget; - private static XboxGameBarWidget _friendsListWidget; -#endif - - private static SemaphoreSlim _connectSemaphore = new SemaphoreSlim(1); - private static TaskCompletionSource _readySource = new TaskCompletionSource(); - - internal static DiscordClient Discord { get; set; } - internal static LocalObjectStorageHelper LocalSettings { get; } = new LocalObjectStorageHelper(); - internal static RoamingObjectStorageHelper RoamingSettings { get; } = new RoamingObjectStorageHelper(); - - public App() - { - InitializeComponent(); - - var provider = VersionHelper.RegisterVersionProvider(); - var theme = LocalSettings.Read(REQUESTED_COLOUR_SCHEME, ElementTheme.Default); - switch (theme) - { - case ElementTheme.Light: - RequestedTheme = ApplicationTheme.Light; - break; - case ElementTheme.Dark: - RequestedTheme = ApplicationTheme.Dark; - break; - } - - Suspending += OnSuspending; - UnhandledException += OnUnhandledException; - - Debug.WriteLine("Welcome to Unicord!"); - Debug.WriteLine(provider.GetVersionString()); - - if (RoamingSettings.Read(ENABLE_ANALYTICS, true) && APPCENTER_IDENTIFIER != null) - { - AppCenter.Start(APPCENTER_IDENTIFIER, typeof(Push), typeof(Analytics), typeof(Crashes)); - } - } - - private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e) - { - Logger.LogError(e.Exception); - Logger.Log(e.Message); - e.Handled = true; - } - - protected override async void OnActivated(IActivatedEventArgs e) - { - try - { - ThemeManager.LoadCurrentTheme(Resources); - } - catch (Exception ex) - { - Logger.LogError(ex); - } - - switch (e) - { - case ContactPanelActivatedEventArgs cont: - await OnContactPanelActivated(cont); - return; - case ToastNotificationActivatedEventArgs toast: - OnLaunched(false, toast.Argument); - return; - case ProtocolActivatedEventArgs protocol: - await OnProtocolActivatedAsync(protocol); - return; -#if XBOX_GAME_BAR - case XboxGameBarWidgetActivatedEventArgs xbox: - OnXboxGameBarActivated(xbox); - return; -#endif - default: - Debug.WriteLine(e.Kind); - break; - } - } - - protected override async void OnBackgroundActivated(BackgroundActivatedEventArgs args) - { - var deferral = args.TaskInstance.GetDeferral(); - - switch (args.TaskInstance.Task.Name) - { - case TOAST_BACKGROUND_TASK_NAME: - if (args.TaskInstance.TriggerDetails is ToastNotificationActionTriggerDetail details && TryGetToken(out var token)) - { - var arguments = ParseArgs(details.Argument); - var userInput = details.UserInput; - - if (arguments.TryGetValue("channelId", out var cId) && ulong.TryParse(cId, out var channelId)) - { - if (userInput.TryGetValue("tbReply", out var t) && t is string text) - { - var client = new DiscordRestClient(new DiscordConfiguration() { Token = token, TokenType = TokenType.User }); - await client.CreateMessageAsync(channelId, text, false, null, Enumerable.Empty(), null); - } - } - } - break; - } - - deferral.Complete(); - } - -#if XBOX_GAME_BAR - private void OnXboxGameBarActivated(XboxGameBarWidgetActivatedEventArgs xbox) - { - Analytics.TrackEvent("Unicord_LaunchForGameBar"); - - if (xbox.IsLaunchActivation) - { - var name = xbox.Uri.LocalPath; - var frame = new Frame(); - frame.NavigationFailed += OnNavigationFailed; - Window.Current.Content = frame; - - Logger.Log(xbox.Uri.LocalPath); - - if (name == "unicord-friendslist") - { - _friendsListWidget = new XboxGameBarWidget(xbox, Window.Current.CoreWindow, frame); - Window.Current.Closed += OnFrendsListWidgetClosed; - - frame.Navigate(typeof(GameBarMainPage), new GameBarPageParameters(_friendsListWidget, typeof(GameBarFriendsPage), xbox.Uri)); - } - - if (name == "unicord-channel") - { - _chatListWidget = new XboxGameBarWidget(xbox, Window.Current.CoreWindow, frame); - Window.Current.Closed += OnChatListWidgetClosed; - - frame.Navigate(typeof(GameBarMainPage), new GameBarPageParameters(_chatListWidget, typeof(GameBarChannelListPage), xbox.Uri)); - } - } - } - - private void OnChatListWidgetClosed(object sender, CoreWindowEventArgs e) - { - Window.Current.Closed -= OnChatListWidgetClosed; - _chatListWidget = null; - } - - private void OnFrendsListWidgetClosed(object sender, CoreWindowEventArgs e) - { - Window.Current.Closed -= OnFrendsListWidgetClosed; - _friendsListWidget = null; - } -#endif - - private static async Task OnProtocolActivatedAsync(ProtocolActivatedEventArgs protocol) - { - if (protocol.Uri.IsAbsoluteUri) - Analytics.TrackEvent("Unicord_LaunchForProtocol", new Dictionary() { ["protocol"] = protocol.Uri.GetLeftPart(UriPartial.Authority) }); - - if (protocol.Uri.AbsolutePath.Trim('/').StartsWith("channels")) - { - var path = protocol.Uri.AbsolutePath.Split('/').Skip(1).ToArray(); - if (path.Length > 1 && ulong.TryParse(path[2], out var channel)) - { - if (!(Window.Current.Content is Frame rootFrame)) - { - rootFrame = new Frame(); - Window.Current.Content = rootFrame; - } - - rootFrame.Navigate(typeof(MainPage), new MainPageArgs() { ChannelId = channel, FullFrame = false, IsUriActivation = true }); - Window.Current.Activate(); - return; - } - } - - await Launcher.LaunchUriAsync(protocol.Uri, new LauncherOptions() { IgnoreAppUriHandlers = true }); - } - - private static async Task OnContactPanelActivated(ContactPanelActivatedEventArgs task) - { - Analytics.TrackEvent("Unicord_LaunchForMyPeople"); - - if (!(Window.Current.Content is Frame rootFrame)) - { - // Create a Frame to act as the navigation context and navigate to the first page - rootFrame = new Frame(); - - try - { - var id = await ContactListManager.TryGetChannelIdAsync(task.Contact); - if (id != 0) - { - rootFrame.Navigate(typeof(MainPage), new MainPageArgs() { UserId = id, FullFrame = true, IsUriActivation = false }); - } - } - catch - { - Analytics.TrackEvent("Unicord_MyPeopleFailedToFindPerson"); - var dialog = new MessageDialog("Something went wrong trying to find this person, sorry!", "Whoops!"); - await dialog.ShowAsync(); - } - - // Place the frame in the current Window - Window.Current.Content = rootFrame; - } - - Window.Current.Activate(); - } - - /// - /// Invoked when the application is launched normally by the end user. Other entry points - /// will be used such as when the application is launched to open a specific file. - /// - /// Details about the launch request and process. - protected override void OnLaunched(LaunchActivatedEventArgs e) - { - OnLaunched(e.PrelaunchActivated, e.Arguments, e.PreviousExecutionState); - } - - private void OnLaunched(bool preLaunch, string arguments, ApplicationExecutionState previousState = ApplicationExecutionState.NotRunning) - { - var channelId = 0ul; - Exception themeLoadException = null; - var args = ParseArgs(arguments); - - // Do not repeat app initialization when the Window already has content, - // just ensure that the window is active - if (!(Window.Current.Content is Frame rootFrame)) - { - UpgradeSettings(); - - Analytics.TrackEvent("Unicord_Launch"); - - try - { - ThemeManager.LoadCurrentTheme(Resources); - } - catch (Exception ex) - { - Logger.LogError(ex); - themeLoadException = ex; - } - - // Create a Frame to act as the navigation context and navigate to the first page - rootFrame = new Frame(); - rootFrame.NavigationFailed += OnNavigationFailed; - - if (previousState == ApplicationExecutionState.Terminated) - { - channelId = LocalSettings.Read("LastViewedChannel", 0ul); - } - - WindowingService.Current.SetMainWindow(rootFrame); - // Place the frame in the current Window - Window.Current.Content = rootFrame; - } - - if (args.TryGetValue("channelId", out var id) && ulong.TryParse(id, out var pId)) - { - channelId = pId; - } - - if (rootFrame.Content == null || channelId != 0) - rootFrame.Navigate(typeof(MainPage), new MainPageArgs() { ChannelId = channelId, ThemeLoadException = themeLoadException }); - - // Ensure the current window is active - Window.Current.Activate(); - } - - private static Dictionary ParseArgs(string arguments) - { - var rawArgs = Strings.SplitCommandLine(arguments); - var args = new Dictionary(); - foreach (var str in rawArgs) - { - if (!string.IsNullOrWhiteSpace(str) && str.Contains('-', '=')) - { - var arg = str.TrimStart('-'); - args.Add(arg.Substring(0, arg.IndexOf('=')), arg.Substring(arg.IndexOf('=') + 1)); - } - } - - return args; - } - - private bool TryGetToken(out string token) - { - if (ApplicationData.Current.LocalSettings.Values.TryGetValue("Token", out var s)) - { - token = (string)s; - return true; - } - - token = null; - return false; - } - - /// - /// This method migrates settings from previous versions of Unicord. - /// - private void UpgradeSettings() - { - // migrates the old theme store -#pragma warning disable CS0618 // Type or member is obsolete - var theme = LocalSettings.Read(SELECTED_THEME_NAME, null); - if (!string.IsNullOrWhiteSpace(theme)) - { - LocalSettings.Save(SELECTED_THEME_NAME, (string)null); - LocalSettings.Save(SELECTED_THEME_NAMES, new List() { theme }); - } - - var themes = LocalSettings.Read>(SELECTED_THEME_NAMES); - if (themes != null) - { - themes.RemoveAll(t => string.IsNullOrWhiteSpace(t)); - LocalSettings.Save(SELECTED_THEME_NAMES, themes); - } -#pragma warning restore CS0618 // Type or member is obsolete - } - - protected override async void OnFileActivated(FileActivatedEventArgs args) - { - if (Window.Current.Content != null) - { - ApplicationView view = null; - var coreView = CoreApplication.CreateNewView(); - await coreView.Dispatcher.AwaitableRunAsync(() => view = SetupCurrentView()); - await ApplicationViewSwitcher.TryShowAsStandaloneAsync(view.Id, ViewSizePreference.UseMinimum); - await coreView.Dispatcher.AwaitableRunAsync(() => OnFileActivatedForWindow(args)); - } - else - { - SetupCurrentView(); - OnFileActivatedForWindow(args); - } - } - - private static ApplicationView SetupCurrentView() - { - var view = ApplicationView.GetForCurrentView(); - view.SetPreferredMinSize(new Size(480, 480)); - - var frame = new Frame(); - Window.Current.Content = frame; - Window.Current.Activate(); - return view; - } - - private void OnFileActivatedForWindow(FileActivatedEventArgs args) - { - if (Window.Current.Content is Frame f) - { - f.Navigate(typeof(InstallThemePage), args); - } - } - - protected override void OnShareTargetActivated(ShareTargetActivatedEventArgs args) - { - if (!(Window.Current.Content is Frame rootFrame)) - { - UpgradeSettings(); - Analytics.TrackEvent("Unicord_LaunchForShare"); - - try - { - ThemeManager.LoadCurrentTheme(Resources); - } - catch (Exception ex) - { - Logger.LogError(ex); - } - - // Create a Frame to act as the navigation context and navigate to the first page - rootFrame = new Frame(); - - rootFrame.Navigate(typeof(MainPage), args.ShareOperation); - - // Place the frame in the current Window - Window.Current.Content = rootFrame; - } - - Window.Current.Activate(); - } - - /// - /// Invoked when Navigation to a certain page fails - /// - /// The Frame which failed navigation - /// Details about the navigation failure - void OnNavigationFailed(object sender, NavigationFailedEventArgs e) - { - throw new Exception("Failed to load Page " + e.SourcePageType.FullName); - } - - /// - /// Invoked when application execution is being suspended. Application state is saved - /// without knowing whether the application will be terminated or resumed with the contents - /// of memory still intact. - /// - /// The source of the suspend request. - /// Details about the suspend request. - private void OnSuspending(object sender, SuspendingEventArgs e) - { - var deferral = e.SuspendingOperation.GetDeferral(); - deferral.Complete(); - } - - internal static async Task LoginAsync(string token, AsyncEventHandler onReady, Func onError, bool background, UserStatus status = UserStatus.Online) - { - Exception taskEx = null; - - await _connectSemaphore.WaitAsync(); - try - { - var loader = ResourceLoader.GetForViewIndependentUse(); - - if (Discord == null) - { - if (background || await WindowsHelloManager.VerifyAsync(VERIFY_LOGIN, loader.GetString("VerifyLoginDisplayReason"))) - { - try - { - async Task ReadyHandler(ReadyEventArgs e) - { - LocalSettings.Save("Token", token); - - e.Client.Ready -= ReadyHandler; - e.Client.SocketErrored -= SocketErrored; - e.Client.ClientErrored -= ClientErrored; - _readySource.TrySetResult(e); - if (onReady != null) - { - await onReady(e); - } - } - - Task SocketErrored(SocketErrorEventArgs e) - { - e.Client.Ready -= ReadyHandler; - e.Client.SocketErrored -= SocketErrored; - e.Client.ClientErrored -= ClientErrored; - - Logger.LogError(e.Exception); - - _readySource.SetException(e.Exception); - return Task.CompletedTask; - } - - Task ClientErrored(ClientErrorEventArgs e) - { - e.Client.Ready -= ReadyHandler; - e.Client.SocketErrored -= SocketErrored; - e.Client.ClientErrored -= ClientErrored; - - Logger.LogError(e.Exception); - - _readySource.SetException(e.Exception); - return Task.CompletedTask; - } - - Discord = new DiscordClient(new DiscordConfiguration() - { - Token = token, - TokenType = TokenType.User, - LogLevel = DSharpPlus.LogLevel.Debug, - }); - - Discord.DebugLogger.LogMessageReceived += (o, ee) => Logger.Log(ee.Message, ee.Application); - Discord.Ready += ReadyHandler; - Discord.SocketErrored += SocketErrored; - Discord.ClientErrored += ClientErrored; - - await Discord.ConnectAsync(status: status, idlesince: AnalyticsInfo.VersionInfo.DeviceFamily == "Windows.Desktop" ? (DateTimeOffset?)null : DateTimeOffset.Now); - } - catch (Exception ex) - { - Logger.LogError(ex); - Tools.ResetPasswordVault(); - _readySource.TrySetException(ex); - await onError(ex); - } - } - else - { - await onError(null); - } - } - else - { - try - { - var res = await _readySource.Task; - await onReady(res); - } - catch - { - await onError(taskEx); - } - } - } - finally - { - _connectSemaphore.Release(); - } - } - - internal static async Task LogoutAsync() - { - await WebView.ClearTemporaryWebDataAsync(); - await WindowingService.Current.CloseAllWindowsAsync(); - await ImageCache.Instance.ClearAsync(); - await Discord.DisconnectAsync(); - Discord.Dispose(); - Discord = null; - - try - { - var passwordVault = new PasswordVault(); - foreach (var c in passwordVault.FindAllByResource(TOKEN_IDENTIFIER)) - { - passwordVault.Remove(c); - } - } - catch { } - - DiscordNavigationService.Reset(); - FullscreenService.Reset(); - OverlayService.Reset(); - SettingsService.Reset(); - SwipeOpenService.Reset(); - - var frame = (Window.Current.Content as Frame); - frame.Navigate(typeof(Page)); - frame.BackStack.Clear(); - frame.ForwardStack.Clear(); - - frame = new Frame(); - frame.Navigate(typeof(MainPage)); - Window.Current.Content = frame; - } - - internal static async Task LoginError(Exception ex) - { - if (ex != null) - { - var loader = ResourceLoader.GetForViewIndependentUse(); - await UIUtilities.ShowErrorDialogAsync(loader.GetString("LoginFailedDialogTitle"), loader.GetString("LoginFailedDialogMessage")); - RoamingSettings.Save(VERIFY_LOGIN, false); - } - - Discord = null; - - var mainPage = Window.Current.Content.FindChild(); - - if (mainPage.FindChild() == null) - { - mainPage.Nagivate(typeof(LoginPage)); - } - - mainPage.HideConnectingOverlay(); - } - } -} +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using System.Threading.Tasks; +using System.Web; +using DSharpPlus; +using DSharpPlus.Entities; +using Microsoft.AppCenter; +using Microsoft.AppCenter.Analytics; +#if XBOX_GAME_BAR +using Microsoft.Gaming.XboxGameBar; +using Unicord.Universal.Pages.GameBar; +#endif +using Microsoft.Toolkit.Uwp.Helpers; +using Microsoft.Toolkit.Uwp.UI; +using Unicord.Universal.Extensions; +using Unicord.Universal.Integration; +using Unicord.Universal.Models; +using Unicord.Universal.Pages; +using Unicord.Universal.Services; +using Unicord.Universal.Utilities; +using WamWooWam.Core; +using Windows.ApplicationModel; +using Windows.ApplicationModel.Activation; +using Windows.ApplicationModel.Resources; +using Windows.Media.Transcoding; +using Windows.Security.Credentials; +using Windows.Storage; +using Windows.UI.Notifications; +using Windows.UI.Popups; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; +using static Unicord.Constants; +using UnhandledExceptionEventArgs = Windows.UI.Xaml.UnhandledExceptionEventArgs; + +namespace Unicord.Universal +{ + sealed partial class App : Application + { +#if XBOX_GAME_BAR + private static XboxGameBarWidget _chatListWidget; + private static XboxGameBarWidget _friendsListWidget; +#endif + internal static ApplicationDataStorageHelper LocalSettings { get; } + = ApplicationDataStorageHelper.GetCurrent(); + internal static ApplicationDataStorageHelper RoamingSettings { get; } + = ApplicationDataStorageHelper.GetCurrent(); + + public App() + { + InitializeComponent(); + MigratePreV2Settings(); + + var theme = (ElementTheme)LocalSettings.Read(REQUESTED_COLOUR_SCHEME, (int)ElementTheme.Default); + switch (theme) + { + case ElementTheme.Light: + RequestedTheme = ApplicationTheme.Light; + break; + case ElementTheme.Dark: + RequestedTheme = ApplicationTheme.Dark; + break; + } + + Suspending += OnSuspending; + Resuming += OnResuming; + UnhandledException += OnUnhandledException; + + Debug.WriteLine("Welcome to Unicord!"); + } + + private static void MigratePreV2Settings() + { + foreach (var item in ApplicationData.Current.RoamingSettings.Values) + ApplicationData.Current.LocalSettings.Values[item.Key] = item.Value; + + if (LocalSettings.TryRead(AUTO_TRANSCODE_MEDIA_OLD, out var autoTranscodeMedia)) + { + if (Enum.TryParse(autoTranscodeMedia, out var result)) + LocalSettings.Save(AUTO_TRANSCODE_MEDIA, (int)result); + + LocalSettings.TryDelete(AUTO_TRANSCODE_MEDIA_OLD); + } + + if (LocalSettings.TryRead(VIDEO_PROCESSING_OLD, out var videoProcessingOptions)) + { + if (Enum.TryParse(videoProcessingOptions, out var result)) + LocalSettings.Save(VIDEO_PROCESSING, (int)result); + + LocalSettings.TryDelete(VIDEO_PROCESSING_OLD); + } + + if (LocalSettings.TryRead(TIMESTAMP_STYLE_OLD, out var timestampStyle)) + { + if (Enum.TryParse(timestampStyle, out var result)) + LocalSettings.Save(TIMESTAMP_STYLE, (int)result); + + LocalSettings.TryDelete(TIMESTAMP_STYLE_OLD); + } + + if (LocalSettings.TryRead(REQUESTED_COLOUR_SCHEME_OLD, out var requestedScheme)) + { + if (Enum.TryParse(requestedScheme, out var result)) + LocalSettings.Save(REQUESTED_COLOUR_SCHEME, (int)result); + + LocalSettings.TryDelete(REQUESTED_COLOUR_SCHEME_OLD); + } + + try + { + var passwordVault = new PasswordVault(); + foreach (var c in passwordVault.FindAllByResource(TOKEN_IDENTIFIER_OLD)) + { + c.RetrievePassword(); + passwordVault.Add(new PasswordCredential(TOKEN_IDENTIFIER, c.UserName, c.Password)); + + passwordVault.Remove(c); + } + } + catch { } + } + + private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e) + { + Logger.LogError(e.Exception); + Logger.Log(e.Message); + e.Handled = true; + } + + protected override async void OnActivated(IActivatedEventArgs e) + { + switch (e) + { + case ContactPanelActivatedEventArgs cont: + await OnContactPanelActivated(cont); + return; + case ToastNotificationActivatedEventArgs toast: + OnLaunched(false, toast.Argument); + return; + case ProtocolActivatedEventArgs protocol: + OnProtocolActivatedAsync(protocol); + return; +#if XBOX_GAME_BAR + case XboxGameBarWidgetActivatedEventArgs xbox: + OnXboxGameBarActivated(xbox); + return; +#endif + default: + Debug.WriteLine(e.Kind); + break; + } + } + + protected override async void OnBackgroundActivated(BackgroundActivatedEventArgs args) + { + var deferral = args.TaskInstance.GetDeferral(); + + switch (args.TaskInstance.Task.Name) + { + case TOAST_BACKGROUND_TASK_NAME: + if (args.TaskInstance.TriggerDetails is not ToastNotificationActionTriggerDetail details || !DiscordManager.TryGetToken(out var token)) + break; + + var arguments = ParseArgs(details.Argument); + var userInput = details.UserInput; + + if (!arguments.TryGetValue("channelId", out var cId) || !ulong.TryParse(cId, out var channelId)) + break; + + if (!userInput.TryGetValue("tbReply", out var t) || t is not string text) + break; + + var client = new DiscordRestClient(new DiscordConfiguration() { Token = token, TokenType = TokenType.User }); + await client.CreateMessageAsync(channelId, new DiscordMessageBuilder().WithContent(text)); + break; + } + + deferral.Complete(); + } + private void OnProtocolActivatedAsync(ProtocolActivatedEventArgs protocol) + { + if (protocol.Uri.IsAbsoluteUri) + Analytics.TrackEvent("Unicord_LaunchForProtocol", new Dictionary() { ["protocol"] = protocol.Uri.GetLeftPart(UriPartial.Authority) }); + + if (protocol.Uri.Scheme == "ms-ipmessaging") + { + var queryString = HttpUtility.ParseQueryString(protocol.Uri.Query); + var ids = queryString.GetValues("ContactRemoteIds").FirstOrDefault(); + if (ids != null) + { + var id = ulong.Parse(ids.Split(',')[0].Split('_')[1]); + if (!(Window.Current.Content is Frame rootFrame)) + { + rootFrame = new Frame(); + Window.Current.Content = rootFrame; + } + + rootFrame.Navigate(typeof(MainPage), new MainPageArgs() { UserId = id, IsUriActivation = true }); + Window.Current.Activate(); + return; + } + } + + if (protocol.Uri.AbsolutePath.Trim('/').StartsWith("channels")) + { + var path = protocol.Uri.AbsolutePath.Split('/').Skip(1).ToArray(); + if (path.Length > 1 && ulong.TryParse(path[2], out var channel)) + { + if (!(Window.Current.Content is Frame rootFrame)) + { + rootFrame = new Frame(); + Window.Current.Content = rootFrame; + } + + rootFrame.Navigate(typeof(MainPage), new MainPageArgs() { ChannelId = channel, IsUriActivation = true }); + Window.Current.Activate(); + return; + } + } + + OnLaunched(false, ""); + } + + private static async Task OnContactPanelActivated(ContactPanelActivatedEventArgs task) + { + Analytics.TrackEvent("Unicord_LaunchForMyPeople"); + + if (!(Window.Current.Content is Frame rootFrame)) + { + // Create a Frame to act as the navigation context and navigate to the first page + rootFrame = new Frame(); + + try + { + var id = await ContactListManager.TryGetChannelIdAsync(task.Contact); + if (id != 0) + { + rootFrame.Navigate(typeof(MainPage), new MainPageArgs() { UserId = id, FullFrame = true, IsUriActivation = false }); + } + } + catch + { + Analytics.TrackEvent("Unicord_MyPeopleFailedToFindPerson"); + var dialog = new MessageDialog("Something went wrong trying to find this person, sorry!", "Whoops!"); + await dialog.ShowAsync(); + } + + // Place the frame in the current Window + Window.Current.Content = rootFrame; + } + + Window.Current.Activate(); + } + + /// + /// Invoked when the application is launched normally by the end user. Other entry points + /// will be used such as when the application is launched to open a specific file. + /// + /// Details about the launch request and process. + protected override void OnLaunched(LaunchActivatedEventArgs e) + { + OnLaunched(e.PrelaunchActivated, e.Arguments, e.PreviousExecutionState); + } + + private void OnLaunched(bool preLaunch, string arguments, ApplicationExecutionState previousState = ApplicationExecutionState.NotRunning) + { + var channelId = 0ul; + Exception themeLoadException = null; + var args = ParseArgs(arguments); + + // Do not repeat app initialization when the Window already has content, + // just ensure that the window is active + if (!(Window.Current.Content is Frame rootFrame)) + { + Analytics.TrackEvent("Unicord_Launch"); + + // Create a Frame to act as the navigation context and navigate to the first page + rootFrame = new Frame(); + rootFrame.NavigationFailed += OnNavigationFailed; + + if (previousState == ApplicationExecutionState.Terminated) + channelId = LocalSettings.Read("LastViewedChannel", 0ul); + + WindowingService.Current.SetMainWindow(rootFrame); + Window.Current.Content = rootFrame; + } + + if (args.TryGetValue("channelId", out var id) && ulong.TryParse(id, out var pId)) + { + channelId = pId; + } + + if (rootFrame.Content == null || channelId != 0) + rootFrame.Navigate(typeof(MainPage), new MainPageArgs() { ChannelId = channelId, ThemeLoadException = themeLoadException }); + + // Ensure the current window is active + Window.Current.Activate(); + } + + private static Dictionary ParseArgs(string arguments) + { + var rawArgs = Strings.SplitCommandLine(arguments); + var args = new Dictionary(); + foreach (var str in rawArgs) + { + if (!string.IsNullOrWhiteSpace(str) && str.Contains('-', '=')) + { + var arg = str.TrimStart('-'); + args.Add(arg.Substring(0, arg.IndexOf('=')), arg.Substring(arg.IndexOf('=') + 1)); + } + } + + return args; + } + + protected override void OnShareTargetActivated(ShareTargetActivatedEventArgs args) + { + if (Window.Current.Content is not Frame rootFrame) + { + Analytics.TrackEvent("Unicord_LaunchForShare"); + + // Create a Frame to act as the navigation context and navigate to the first page + rootFrame = new Frame(); + + rootFrame.Navigate(typeof(MainPage), args.ShareOperation); + + // Place the frame in the current Window + Window.Current.Content = rootFrame; + } + + Window.Current.Activate(); + } + + /// + /// Invoked when Navigation to a certain page fails + /// + /// The Frame which failed navigation + /// Details about the navigation failure + void OnNavigationFailed(object sender, NavigationFailedEventArgs e) + { + throw new Exception("Failed to load Page " + e.SourcePageType.FullName); + } + + private DiscordClient temporaryCache; + + /// + /// Invoked when application execution is being suspended. Application state is saved + /// without knowing whether the application will be terminated or resumed with the contents + /// of memory still intact. + /// + /// The source of the suspend request. + /// Details about the suspend request. + private async void OnSuspending(object sender, SuspendingEventArgs e) + { + var deferral = e.SuspendingOperation.GetDeferral(); + + if (DiscordManager.Discord != null) + { + temporaryCache = DiscordManager.Discord; + await DiscordManager.Discord.DisconnectAsync(4002); + } + + await Logger.OnSuspendingAsync(); + deferral.Complete(); + } + + private async void OnResuming(object sender, object e) + { + if (temporaryCache != null) + { + await temporaryCache.ConnectAsync(); + } + } + + internal static async Task LogoutAsync() + { + await WebView.ClearTemporaryWebDataAsync(); + await WindowingService.Current.CloseAllWindowsAsync(); + await ImageCache.Instance.ClearAsync(); + await DiscordManager.LogoutAsync(); + + try + { + var passwordVault = new PasswordVault(); + foreach (var c in passwordVault.FindAllByResource(TOKEN_IDENTIFIER)) + { + passwordVault.Remove(c); + } + } + catch { } + + // ditto above about the background process + LocalSettings.TryDelete("Token"); + + DiscordNavigationService.Reset(); + FullscreenService.Reset(); + OverlayService.Reset(); + SettingsService.Reset(); + SwipeOpenService.Reset(); + + var frame = (Window.Current.Content as Frame); + frame.Navigate(typeof(Page)); + frame.BackStack.Clear(); + frame.ForwardStack.Clear(); + + frame = new Frame(); + frame.Navigate(typeof(MainPage)); + Window.Current.Content = frame; + } + + internal static async Task LoginError(Exception ex) + { + if (ex != null) + { + var loader = ResourceLoader.GetForViewIndependentUse(); + await UIUtilities.ShowErrorDialogAsync(loader.GetString("LoginFailedDialogTitle"), loader.GetString("LoginFailedDialogMessage")); + RoamingSettings.Save(VERIFY_LOGIN, false); + } + + await DiscordManager.LogoutAsync(); + + var mainPage = Window.Current.Content.FindChild(); + + if (mainPage.FindChild() == null) + { + mainPage.Nagivate(typeof(LoginPage)); + } + + mainPage.HideConnectingOverlay(); + } + + protected override void OnWindowCreated(WindowCreatedEventArgs args) + { + base.OnWindowCreated(args); + + if (RoamingSettings.Read(ENABLE_ANALYTICS, true) && APPCENTER_IDENTIFIER != null) + { + AppCenter.Start(APPCENTER_IDENTIFIER, typeof(Analytics)); + } + } + } +} diff --git a/Unicord.Universal/Assets/Captcha/hCaptcha.html b/Unicord.Universal/Assets/Captcha/hCaptcha.html new file mode 100644 index 00000000..d5813361 --- /dev/null +++ b/Unicord.Universal/Assets/Captcha/hCaptcha.html @@ -0,0 +1,65 @@ + + + + Beep Boop! Boop Beep? + + + + + + +
+ + diff --git a/Unicord.Universal/Assets/DiscordSplashScreen.Dark.svg b/Unicord.Universal/Assets/DiscordSplashScreen.Dark.svg new file mode 100644 index 00000000..c8e9389f --- /dev/null +++ b/Unicord.Universal/Assets/DiscordSplashScreen.Dark.svg @@ -0,0 +1,61 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/Unicord.Universal/Assets/DiscordSplashScreen.Light.svg b/Unicord.Universal/Assets/DiscordSplashScreen.Light.svg new file mode 100644 index 00000000..b88b19e7 --- /dev/null +++ b/Unicord.Universal/Assets/DiscordSplashScreen.Light.svg @@ -0,0 +1,61 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/Unicord.Universal/Assets/DiscordWordMark.Dark.pdf b/Unicord.Universal/Assets/DiscordWordMark.Dark.pdf new file mode 100644 index 00000000..a2d54c11 Binary files /dev/null and b/Unicord.Universal/Assets/DiscordWordMark.Dark.pdf differ diff --git a/Unicord.Universal/Assets/DiscordWordMark.Light.pdf b/Unicord.Universal/Assets/DiscordWordMark.Light.pdf new file mode 100644 index 00000000..137d90ec Binary files /dev/null and b/Unicord.Universal/Assets/DiscordWordMark.Light.pdf differ diff --git a/Unicord.Universal/Assets/Store/BadgeLogo.scale-100.png b/Unicord.Universal/Assets/Store/BadgeLogo.scale-100.png index 5fbab9b3..cb3921d7 100644 Binary files a/Unicord.Universal/Assets/Store/BadgeLogo.scale-100.png and b/Unicord.Universal/Assets/Store/BadgeLogo.scale-100.png differ diff --git a/Unicord.Universal/Assets/Store/BadgeLogo.scale-125.png b/Unicord.Universal/Assets/Store/BadgeLogo.scale-125.png index 4ae0a849..f1324ebc 100644 Binary files a/Unicord.Universal/Assets/Store/BadgeLogo.scale-125.png and b/Unicord.Universal/Assets/Store/BadgeLogo.scale-125.png differ diff --git a/Unicord.Universal/Assets/Store/BadgeLogo.scale-150.png b/Unicord.Universal/Assets/Store/BadgeLogo.scale-150.png index dd350e29..1e4a3cf3 100644 Binary files a/Unicord.Universal/Assets/Store/BadgeLogo.scale-150.png and b/Unicord.Universal/Assets/Store/BadgeLogo.scale-150.png differ diff --git a/Unicord.Universal/Assets/Store/BadgeLogo.scale-200.png b/Unicord.Universal/Assets/Store/BadgeLogo.scale-200.png index fb6a993d..9c267541 100644 Binary files a/Unicord.Universal/Assets/Store/BadgeLogo.scale-200.png and b/Unicord.Universal/Assets/Store/BadgeLogo.scale-200.png differ diff --git a/Unicord.Universal/Assets/Store/BadgeLogo.scale-400.png b/Unicord.Universal/Assets/Store/BadgeLogo.scale-400.png index ae291dd1..018f7b80 100644 Binary files a/Unicord.Universal/Assets/Store/BadgeLogo.scale-400.png and b/Unicord.Universal/Assets/Store/BadgeLogo.scale-400.png differ diff --git a/Unicord.Universal/Assets/Store/SplashScreen.light.scale-100.png b/Unicord.Universal/Assets/Store/SplashScreen.light.scale-100.png new file mode 100644 index 00000000..676c37a3 Binary files /dev/null and b/Unicord.Universal/Assets/Store/SplashScreen.light.scale-100.png differ diff --git a/Unicord.Universal/Assets/Store/SplashScreen.light.scale-125.png b/Unicord.Universal/Assets/Store/SplashScreen.light.scale-125.png new file mode 100644 index 00000000..71624be2 Binary files /dev/null and b/Unicord.Universal/Assets/Store/SplashScreen.light.scale-125.png differ diff --git a/Unicord.Universal/Assets/Store/SplashScreen.light.scale-150.png b/Unicord.Universal/Assets/Store/SplashScreen.light.scale-150.png new file mode 100644 index 00000000..80f87b3b Binary files /dev/null and b/Unicord.Universal/Assets/Store/SplashScreen.light.scale-150.png differ diff --git a/Unicord.Universal/Assets/Store/SplashScreen.light.scale-200.png b/Unicord.Universal/Assets/Store/SplashScreen.light.scale-200.png new file mode 100644 index 00000000..d14c3ee8 Binary files /dev/null and b/Unicord.Universal/Assets/Store/SplashScreen.light.scale-200.png differ diff --git a/Unicord.Universal/Assets/Store/SplashScreen.light.scale-400.png b/Unicord.Universal/Assets/Store/SplashScreen.light.scale-400.png new file mode 100644 index 00000000..dda296e0 Binary files /dev/null and b/Unicord.Universal/Assets/Store/SplashScreen.light.scale-400.png differ diff --git a/Unicord.Universal/Assets/Store/SplashScreen.scale-100.png b/Unicord.Universal/Assets/Store/SplashScreen.scale-100.png index 1dd41b20..1ae018f4 100644 Binary files a/Unicord.Universal/Assets/Store/SplashScreen.scale-100.png and b/Unicord.Universal/Assets/Store/SplashScreen.scale-100.png differ diff --git a/Unicord.Universal/Assets/Store/SplashScreen.scale-125.png b/Unicord.Universal/Assets/Store/SplashScreen.scale-125.png index ced25c44..595c51eb 100644 Binary files a/Unicord.Universal/Assets/Store/SplashScreen.scale-125.png and b/Unicord.Universal/Assets/Store/SplashScreen.scale-125.png differ diff --git a/Unicord.Universal/Assets/Store/SplashScreen.scale-150.png b/Unicord.Universal/Assets/Store/SplashScreen.scale-150.png index 8658d77e..b31a7cab 100644 Binary files a/Unicord.Universal/Assets/Store/SplashScreen.scale-150.png and b/Unicord.Universal/Assets/Store/SplashScreen.scale-150.png differ diff --git a/Unicord.Universal/Assets/Store/SplashScreen.scale-200.png b/Unicord.Universal/Assets/Store/SplashScreen.scale-200.png index b27f907d..bc297659 100644 Binary files a/Unicord.Universal/Assets/Store/SplashScreen.scale-200.png and b/Unicord.Universal/Assets/Store/SplashScreen.scale-200.png differ diff --git a/Unicord.Universal/Assets/Store/SplashScreen.scale-400.png b/Unicord.Universal/Assets/Store/SplashScreen.scale-400.png index 86d62fa8..a0cd256a 100644 Binary files a/Unicord.Universal/Assets/Store/SplashScreen.scale-400.png and b/Unicord.Universal/Assets/Store/SplashScreen.scale-400.png differ diff --git a/Unicord.Universal/Assets/StoreLogo.backup.png b/Unicord.Universal/Assets/StoreLogo.backup.png deleted file mode 100644 index 7385b56c..00000000 Binary files a/Unicord.Universal/Assets/StoreLogo.backup.png and /dev/null differ diff --git a/Unicord.Universal/Commands/AcknowledgeCommand.cs b/Unicord.Universal/Commands/AcknowledgeCommand.cs deleted file mode 100644 index fc98a14e..00000000 --- a/Unicord.Universal/Commands/AcknowledgeCommand.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Windows.Input; -using DSharpPlus.Entities; -using Microsoft.AppCenter.Analytics; - -namespace Unicord.Universal.Commands -{ - class AcknowledgeCommand : ICommand - { -#pragma warning disable 67 // the event is never used - public event EventHandler CanExecuteChanged; -#pragma warning restore 67 - - public bool CanExecute(object parameter) - { - return parameter is DiscordChannel c && c.ReadState?.Unread == true || parameter is DiscordGuild guild && guild.Unread; - } - - public async void Execute(object parameter) - { - if (parameter is DiscordChannel channel && channel.ReadState?.Unread == true && channel.LastMessageId != 0 && channel.IsText()) - { - Analytics.TrackEvent("AcknowledgeCommand_AckChannel"); - await channel.AcknowledgeAsync(channel.LastMessageId); - } - - if (parameter is DiscordGuild guild && guild.Unread) - { - Analytics.TrackEvent("AcknowledgeCommand_AckGuild"); - await guild.AcknowledgeAsync(); - } - } - } -} diff --git a/Unicord.Universal/Commands/BanCommand.cs b/Unicord.Universal/Commands/BanCommand.cs deleted file mode 100644 index 9ed76292..00000000 --- a/Unicord.Universal/Commands/BanCommand.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Windows.Input; -using DSharpPlus; -using DSharpPlus.Entities; -using Microsoft.AppCenter.Analytics; -using Unicord.Universal.Dialogs; -using Unicord.Universal.Utilities; -using Windows.UI.Xaml.Controls; - -namespace Unicord.Universal.Commands -{ - class BanCommand : ICommand - { -#pragma warning disable 67 // the event is never used - public event EventHandler CanExecuteChanged; -#pragma warning restore 67 - - public bool CanExecute(object parameter) - { - if (parameter is DiscordMember member) - { - if (member.Id == App.Discord.CurrentUser.Id) - return false; - - if (!Tools.CheckRoleHierarchy(member.Guild.CurrentMember, member)) - return false; - - return member.Guild.CurrentMember.PermissionsIn(null).HasPermission(Permissions.BanMembers); - } - - return false; - } - - public async void Execute(object parameter) - { - if (parameter is DiscordMember member) - { - Analytics.TrackEvent("BanCommand_Invoked"); - - var banDialog = new BanDialog(member); - var result = await banDialog.ShowAsync(); - - if (result == ContentDialogResult.Primary) - { - Analytics.TrackEvent("BanCommand_BanMember"); - await member.BanAsync(banDialog.DeleteMessageDays, banDialog.BanReason); - } - } - } - } -} diff --git a/Unicord.Universal/Commands/ChangeNicknameCommand.cs b/Unicord.Universal/Commands/ChangeNicknameCommand.cs deleted file mode 100644 index 6142fd40..00000000 --- a/Unicord.Universal/Commands/ChangeNicknameCommand.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Linq; -using System.Windows.Input; -using DSharpPlus; -using DSharpPlus.Entities; -using Microsoft.AppCenter.Analytics; -using Unicord.Universal.Dialogs; -using Windows.UI.Xaml.Controls; - -namespace Unicord.Universal.Commands -{ - class ChangeNicknameCommand : ICommand - { -#pragma warning disable 67 // the event is never used - public event EventHandler CanExecuteChanged; -#pragma warning restore 67 - - public bool CanExecute(object parameter) - { - if (parameter is DiscordMember member) - { - var permissions = member.Guild.CurrentMember.PermissionsIn(null); - if (member.Id == App.Discord.CurrentUser.Id && (permissions.HasFlag(Permissions.ChangeNickname) || permissions.HasFlag(Permissions.ManageNicknames))) - { - return true; - } - - if (permissions.HasFlag(Permissions.ManageNicknames) && Tools.CheckRoleHierarchy(member.Guild.CurrentMember, member)) - { - return true; - } - } - - return false; - } - - public async void Execute(object parameter) - { - if (parameter is DiscordMember member) - { - Analytics.TrackEvent("ChangeNicknameCommand_Invoked"); - - var dialog = new ChangeNicknameDialog(member); - if (await dialog.ShowAsync() == ContentDialogResult.Primary) - { - Analytics.TrackEvent("ChangeNicknameCommand_ChangeNickname"); - await member.ModifyAsync(m => m.Nickname = dialog.Text); - } - } - } - } -} diff --git a/Unicord.Universal/Commands/Channels/AcknowledgeChannelCommand.cs b/Unicord.Universal/Commands/Channels/AcknowledgeChannelCommand.cs new file mode 100644 index 00000000..228b2446 --- /dev/null +++ b/Unicord.Universal/Commands/Channels/AcknowledgeChannelCommand.cs @@ -0,0 +1,23 @@ +using Unicord.Universal.Models.Channels; + +namespace Unicord.Universal.Commands.Channels +{ + internal class AcknowledgeChannelCommand : DiscordCommand + { + public AcknowledgeChannelCommand(ChannelViewModel viewModel) : base(viewModel) + { + } + + public override bool CanExecute(object parameter) + { + return viewModel.Unread && viewModel.Channel.LastMessageId != null; + } + + public override async void Execute(object parameter) + { + if (!viewModel.Unread || viewModel.Channel.LastMessageId == null) return; + + await viewModel.Channel.AcknowledgeAsync(viewModel.Channel.LastMessageId.Value); + } + } +} diff --git a/Unicord.Universal/Commands/Channels/MuteChannelCommand.cs b/Unicord.Universal/Commands/Channels/MuteChannelCommand.cs new file mode 100644 index 00000000..b6c2c364 --- /dev/null +++ b/Unicord.Universal/Commands/Channels/MuteChannelCommand.cs @@ -0,0 +1,21 @@ +using Unicord.Universal.Models.Channels; + +namespace Unicord.Universal.Commands.Channels +{ + internal class MuteChannelCommand : DiscordCommand + { + public MuteChannelCommand(ChannelViewModel viewModel) : base(viewModel) + { + } + + public override bool CanExecute(object parameter) + { + return false; + } + + public override void Execute(object parameter) + { + + } + } +} diff --git a/Unicord.Universal/Commands/Channels/OpenInNewWindowCommand.cs b/Unicord.Universal/Commands/Channels/OpenInNewWindowCommand.cs new file mode 100644 index 00000000..85dba658 --- /dev/null +++ b/Unicord.Universal/Commands/Channels/OpenInNewWindowCommand.cs @@ -0,0 +1,43 @@ +using System; +using System.Windows.Input; +using Unicord.Universal.Extensions; +using Unicord.Universal.Models.Channels; +using Unicord.Universal.Services; + +namespace Unicord.Universal.Commands.Channels +{ + internal class OpenInNewWindowCommand : ICommand + { + private readonly ChannelViewModel channelViewModel; + private readonly bool compactOverlay; + + public OpenInNewWindowCommand(ChannelViewModel channelViewModel, bool compactOverlay) + { + this.channelViewModel = channelViewModel; + this.compactOverlay = compactOverlay; + } + + public event EventHandler CanExecuteChanged; + + public bool CanExecute(object parameter) + { + return WindowingService.Current.IsSupported && + WindowingService.Current.IsMainWindow(WindowingService.Current.CurrentWindow) && + channelViewModel.Channel.IsText(); + } + + public async void Execute(object parameter) + { + if (!channelViewModel.Channel.IsText()) + return; + + var newHandle = await WindowingService.Current.OpenChannelWindowAsync(channelViewModel.Channel, compactOverlay, WindowingService.Current.CurrentWindow); + if (newHandle != null) + { + WindowingService.Current.SetWindowChannel(WindowingService.Current.CurrentWindow, 0); + var service = DiscordNavigationService.GetForCurrentView(); + await service.NavigateAsync(null, true); + } + } + } +} diff --git a/Unicord.Universal/Commands/Channels/PinChannelToStartCommand.cs b/Unicord.Universal/Commands/Channels/PinChannelToStartCommand.cs new file mode 100644 index 00000000..f02b4c44 --- /dev/null +++ b/Unicord.Universal/Commands/Channels/PinChannelToStartCommand.cs @@ -0,0 +1,43 @@ +using System; +using System.Globalization; +using Microsoft.AppCenter.Analytics; +using Unicord.Universal.Models.Channels; +using Unicord.Universal.Shared; +using Windows.UI.StartScreen; + +namespace Unicord.Universal.Commands +{ + public class PinChannelToStartCommand : DiscordCommand + { + public PinChannelToStartCommand(ChannelViewModel viewModel) : base(viewModel) + { + } + + public override bool CanExecute(object parameter) + { + return !SecondaryTile.Exists($"Channel_{viewModel.Id}"); + } + + public override async void Execute(object parameter) + { + Analytics.TrackEvent("PinChannelCommand_PinChannel"); + + var channel = viewModel.Channel; + var tile = new SecondaryTile( + $"Channel_{channel.Id}", + NotificationUtils.GetChannelHeaderName(channel), + $"-channelId={channel.Id.ToString(CultureInfo.InvariantCulture)}", + new Uri("ms-appx:///Assets/Store/Square150x150Logo.png"), + TileSize.Square150x150); + + tile.VisualElements.ShowNameOnSquare150x150Logo = true; + tile.VisualElements.ShowNameOnWide310x150Logo = true; + tile.VisualElements.ShowNameOnSquare310x310Logo = true; + + if (await tile.RequestCreateAsync()) + { + SecondaryTileManager.ClearTileNotifications(channel, tile); + } + } + } +} diff --git a/Unicord.Universal/Commands/CopyIdCommand.cs b/Unicord.Universal/Commands/CopyIdCommand.cs deleted file mode 100644 index 47b61c50..00000000 --- a/Unicord.Universal/Commands/CopyIdCommand.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Windows.Input; -using DSharpPlus.Entities; -using Microsoft.AppCenter.Analytics; -using Windows.ApplicationModel.DataTransfer; - -namespace Unicord.Universal.Commands -{ - class CopyIdCommand : ICommand - { -#pragma warning disable 67 // the event is never used - public event EventHandler CanExecuteChanged; -#pragma warning restore 67 - - public bool CanExecute(object parameter) - { - return parameter is SnowflakeObject; - } - - public void Execute(object parameter) - { - if (parameter is SnowflakeObject snowflake) - { - Analytics.TrackEvent("CopyIdCommand_Invoked"); - - var package = new DataPackage(); - package.SetText(snowflake.Id.ToString()); - Clipboard.SetContent(package); - } - } - } -} diff --git a/Unicord.Universal/Commands/CopyMessageCommand.cs b/Unicord.Universal/Commands/CopyMessageCommand.cs deleted file mode 100644 index b9bc81f9..00000000 --- a/Unicord.Universal/Commands/CopyMessageCommand.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Web; -using System.Windows.Input; -using DSharpPlus; -using DSharpPlus.Entities; -using Markdig; -using Microsoft.AppCenter.Analytics; -using Windows.ApplicationModel.DataTransfer; - -namespace Unicord.Universal.Commands -{ - class CopyMessageCommand : ICommand - { - private MarkdownPipeline _pipeline; - - public CopyMessageCommand() - { - _pipeline = new MarkdownPipelineBuilder() - .DisableHeadings() - .DisableHtml() - .UseAdvancedExtensions() - .UseAutoLinks() - .Build(); - } - -#pragma warning disable 67 // the event is never used - public event EventHandler CanExecuteChanged; -#pragma warning restore 67 - - public bool CanExecute(object parameter) - { - return parameter is DiscordMessage; - } - - public void Execute(object parameter) - { - if (parameter is DiscordMessage message) - { - Analytics.TrackEvent("CopyMessageCommand_Invoked"); - - var package = new DataPackage(); - package.RequestedOperation = DataPackageOperation.Copy | DataPackageOperation.Link; - - var serverText = message.Channel.Guild != null ? message.Channel.GuildId.ToString() : "@me"; - var uri = "https://" + $"discordapp.com/channels/{serverText}/{message.ChannelId}/{message.Id}/"; - var markdown = Formatter.MaskedUrl(message.Content, new Uri(uri)); - var html = Markdown.ToHtml(markdown, _pipeline); - - package.SetText(message.Content); - package.SetWebLink(new Uri(uri)); - package.SetHtmlFormat(html); - package.SetRtf($"{{\\field{{\\*\\fldinst HYPERLINK \"{uri}\"}}{{\fldrslt {message.Content}}}"); - - Clipboard.SetContent(package); - } - - } - } -} diff --git a/Unicord.Universal/Commands/CopyUrlCommand.cs b/Unicord.Universal/Commands/CopyUrlCommand.cs deleted file mode 100644 index c43bc1a2..00000000 --- a/Unicord.Universal/Commands/CopyUrlCommand.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Windows.Input; -using DSharpPlus.Entities; -using Microsoft.AppCenter.Analytics; -using Windows.ApplicationModel.DataTransfer; - -namespace Unicord.Universal.Commands -{ - class CopyUrlCommand : ICommand - { -#pragma warning disable 67 // the event is never used - public event EventHandler CanExecuteChanged; -#pragma warning restore 67 - - public bool CanExecute(object parameter) - { - return parameter is DiscordMessage || parameter is DiscordChannel || parameter is DiscordGuild; - } - - public void Execute(object parameter) - { - var package = new DataPackage(); - - if (parameter is DiscordMessage message) - { - Analytics.TrackEvent("CopyUrlCommand_CopyMessageLink"); - var serverText = message.Channel.Guild != null ? message.Channel.GuildId.ToString() : "@me"; - package.SetText("https://" + $"discordapp.com/channels/{serverText}/{message.ChannelId}/{message.Id}"); - } - - if (parameter is DiscordChannel channel) - { - Analytics.TrackEvent("CopyUrlCommand_CopyChannelLink"); - var serverText = channel.Guild != null ? channel.GuildId.ToString() : "@me"; - package.SetText("https://" + $"discordapp.com/channels/{serverText}/{channel.Id}"); - } - - if (parameter is DiscordGuild guild) - { - Analytics.TrackEvent("CopyUrlCommand_CopyGuildLink"); - package.SetText("https://" + $"discordapp.com/channels/{guild.Id}"); - } - - Clipboard.SetContent(package); - } - } -} diff --git a/Unicord.Universal/Commands/DeleteMessageCommand.cs b/Unicord.Universal/Commands/DeleteMessageCommand.cs deleted file mode 100644 index 561eb952..00000000 --- a/Unicord.Universal/Commands/DeleteMessageCommand.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Windows.Input; -using DSharpPlus; -using DSharpPlus.Entities; -using Microsoft.AppCenter.Analytics; -using Unicord.Universal.Dialogs; -using Windows.UI.Xaml.Controls; - -namespace Unicord.Universal.Commands -{ - class DeleteMessageCommand : ICommand - { - public static readonly DeleteMessageCommand Instance - = new DeleteMessageCommand(); - -#pragma warning disable 67 // the event is never used - public event EventHandler CanExecuteChanged; -#pragma warning restore 67 - - public bool CanExecute(object parameter) - { - if (parameter is DiscordMessage message) - { - if (message.Author.Id == App.Discord.CurrentUser.Id) - { - return true; - } - - if (message.Author is DiscordMember member) - { - var currentMember = member.Guild.CurrentMember; - - if (currentMember.IsOwner) - { - return true; - } - - if (currentMember.PermissionsIn(message.Channel).HasFlag(Permissions.ManageMessages)) - { - return true; - } - } - } - - return false; - } - - public async void Execute(object parameter) - { - Analytics.TrackEvent("DeleteMessageCommand_Invoked"); - - if (parameter is DiscordMessage message) - { - var dialog = new DeleteMessageDialog() { Message = message }; - if (await dialog.ShowAsync() == ContentDialogResult.Primary) - { - Analytics.TrackEvent("DeleteMessageCommand_DeleteMessage"); - await message.DeleteAsync(); - } - } - } - } -} diff --git a/Unicord.Universal/Commands/DiscordCommand.cs b/Unicord.Universal/Commands/DiscordCommand.cs new file mode 100644 index 00000000..bcb27f0c --- /dev/null +++ b/Unicord.Universal/Commands/DiscordCommand.cs @@ -0,0 +1,29 @@ +using System; +using System.Windows.Input; +using DSharpPlus; +using Unicord.Universal.Models; +using Unicord.Universal.Services; + +namespace Unicord.Universal.Commands +{ + public abstract class DiscordCommand : ICommand where T : ViewModelBase + { + protected T viewModel; + protected DiscordClient discord; + + public event EventHandler CanExecuteChanged; + + public DiscordCommand(T viewModel) + { + this.viewModel = viewModel; + this.discord = DiscordManager.Discord; + } + + public virtual bool CanExecute(object parameter) + { + return true; + } + + public abstract void Execute(object parameter); + } +} diff --git a/Unicord.Universal/Commands/EditChannelCommand.cs b/Unicord.Universal/Commands/EditChannelCommand.cs index a58f6991..575335df 100644 --- a/Unicord.Universal/Commands/EditChannelCommand.cs +++ b/Unicord.Universal/Commands/EditChannelCommand.cs @@ -1,54 +1,57 @@ -using System; -using System.Windows.Input; -using DSharpPlus; -using DSharpPlus.Entities; -using Microsoft.AppCenter.Analytics; -using Unicord.Universal.Pages; -using Unicord.Universal.Pages.Management; -using Unicord.Universal.Services; -using Windows.UI.Xaml; - -namespace Unicord.Universal.Commands -{ - class EditChannelCommand : ICommand - { -#pragma warning disable 67 // the event is never used - public event EventHandler CanExecuteChanged; -#pragma warning restore 67 - - public bool CanExecute(object parameter) - { - if (parameter is DiscordChannel channel) - { - if (channel is DiscordDmChannel) - return false; - - var currentMember = channel.Guild.CurrentMember; - if (currentMember.IsOwner) - return true; - - var permissions = currentMember.PermissionsIn(channel); - if (permissions.HasFlag(Permissions.ManageChannels)) - { - return true; - } - } - - return false; - } - - public void Execute(object parameter) - { - if (parameter is DiscordChannel channel) - { - var page = Window.Current.Content.FindChild(); - if (page != null) - { - Analytics.TrackEvent("EditChannelCommand_Invoked"); - OverlayService.GetForCurrentView() - .ShowOverlay(channel); - } - } - } - } -} +using System; +using System.Windows.Input; +using DSharpPlus; +using DSharpPlus.Entities; +using Microsoft.AppCenter.Analytics; +using Unicord.Universal.Extensions; +using Unicord.Universal.Models.Channels; +using Unicord.Universal.Pages; +using Unicord.Universal.Pages.Management; +using Unicord.Universal.Services; +using Windows.UI.Xaml; + +namespace Unicord.Universal.Commands +{ + class EditChannelCommand : ICommand + { +#pragma warning disable 67 // the event is never used + public event EventHandler CanExecuteChanged; +#pragma warning restore 67 + + public bool CanExecute(object parameter) + { + if (parameter is DiscordChannel channel || + (parameter is ChannelViewModel channelVM && (channel = channelVM.Channel) != null)) + { + if (channel is DiscordDmChannel) + return false; + + var currentMember = channel.Guild.CurrentMember; + if (currentMember.IsOwner) + return true; + + var permissions = currentMember.PermissionsIn(channel); + if (permissions.HasFlag(Permissions.ManageChannels)) + { + return true; + } + } + + return false; + } + + public void Execute(object parameter) + { + if (parameter is DiscordChannel channel) + { + var page = Window.Current.Content.FindChild(); + if (page != null) + { + Analytics.TrackEvent("EditChannelCommand_Invoked"); + OverlayService.GetForCurrentView() + .ShowOverlayAsync(channel); + } + } + } + } +} diff --git a/Unicord.Universal/Commands/EditModeCommand.cs b/Unicord.Universal/Commands/EditModeCommand.cs deleted file mode 100644 index dca61a3d..00000000 --- a/Unicord.Universal/Commands/EditModeCommand.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Windows.Input; -using DSharpPlus; -using DSharpPlus.Entities; -using Microsoft.AppCenter.Analytics; -using Unicord.Universal.Dialogs; -using Unicord.Universal.Pages; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; - -namespace Unicord.Universal.Commands -{ - class EditModeCommand : ICommand - { -#pragma warning disable 67 // the event is never used - public event EventHandler CanExecuteChanged; -#pragma warning restore 67 - - public bool CanExecute(object parameter) - { - if (parameter is DiscordMessage message) - { - if (message.Author.Id == App.Discord.CurrentUser.Id) - { - return true; - } - - if (message.Author is DiscordMember member) - { - var currentMember = member.Guild.CurrentMember; - - if (currentMember.IsOwner) - { - return true; - } - - if (currentMember.PermissionsIn(message.Channel).HasFlag(Permissions.ManageMessages)) - { - return true; - } - } - } - - return false; - } - - public void Execute(object parameter) - { - Analytics.TrackEvent("EditModeCommand_Invoked"); - - if (parameter is DiscordMessage message) - { - var channelPage = Window.Current.Content.FindChild(); - channelPage.EnterEditMode(message); - } - } - } -} diff --git a/Unicord.Universal/Commands/Generic/CopyIdCommand.cs b/Unicord.Universal/Commands/Generic/CopyIdCommand.cs new file mode 100644 index 00000000..3fa8fd68 --- /dev/null +++ b/Unicord.Universal/Commands/Generic/CopyIdCommand.cs @@ -0,0 +1,37 @@ +using System; +using System.Globalization; +using System.Windows.Input; +using Microsoft.AppCenter.Analytics; +using Unicord.Universal.Models; +using Windows.ApplicationModel.DataTransfer; + +namespace Unicord.Universal.Commands.Generic +{ + public class CopyIdCommand : ICommand + { + private readonly ISnowflake snowflake; + +#pragma warning disable 67 // the event is never used + public event EventHandler CanExecuteChanged; +#pragma warning restore 67 + + public CopyIdCommand(ISnowflake snowflake) + { + this.snowflake = snowflake; + } + + public bool CanExecute(object parameter) + { + return true; + } + + public void Execute(object parameter) + { + Analytics.TrackEvent("CopyIdCommand_Invoked"); + + var package = new DataPackage(); + package.SetText(snowflake.Id.ToString(CultureInfo.InvariantCulture)); + Clipboard.SetContent(package); + } + } +} diff --git a/Unicord.Universal/Commands/Generic/CopyUrlCommand.cs b/Unicord.Universal/Commands/Generic/CopyUrlCommand.cs new file mode 100644 index 00000000..43563f5a --- /dev/null +++ b/Unicord.Universal/Commands/Generic/CopyUrlCommand.cs @@ -0,0 +1,66 @@ +using System; +using System.Windows.Input; +using Microsoft.AppCenter.Analytics; +using Unicord.Universal.Models; +using Unicord.Universal.Models.Channels; +using Unicord.Universal.Models.Guild; +using Unicord.Universal.Models.Messages; +using Windows.ApplicationModel.DataTransfer; + +namespace Unicord.Universal.Commands.Generic +{ + public class CopyUrlCommand : ICommand + { + private readonly ViewModelBase viewModel; + public CopyUrlCommand(ViewModelBase viewModel) + { + this.viewModel = viewModel; + } + + public event EventHandler CanExecuteChanged; + + public bool CanExecute(object parameter) + { + return true; + } + + public void Execute(object parameter) + { + var package = new DataPackage(); + + if (viewModel is MessageViewModel message) + { + Analytics.TrackEvent("CopyUrlCommand_CopyMessageLink"); + var serverText = message.Channel.Guild != null ? message.Channel.Guild.Id.ToString() : "@me"; + var url = "https://" + $"discordapp.com/channels/{serverText}/{message.Channel.Id}/{message.Id}"; + package.SetText(url); + package.SetWebLink(new Uri(url)); + } + + if (viewModel is ChannelViewModel channel) + { + Analytics.TrackEvent("CopyUrlCommand_CopyChannelLink"); + var serverText = channel.Guild != null ? channel.Guild.Id.ToString() : "@me"; + var url = "https://" + $"discordapp.com/channels/{serverText}/{channel.Id}"; + package.SetText(url); + package.SetWebLink(new Uri(url)); + } + + if (viewModel is GuildViewModel guild) + { + Analytics.TrackEvent("CopyUrlCommand_CopyGuildLink"); + var url = "https://" + $"discordapp.com/channels/{guild.Id}"; + package.SetText(url); + package.SetWebLink(new Uri(url)); + } + + if (parameter is string str && Uri.TryCreate(str, UriKind.Absolute, out var uri)) + { + package.SetText(str); + package.SetWebLink(uri); + } + + Clipboard.SetContent(package); + } + } +} diff --git a/Unicord.Universal/Commands/Generic/DownloadCommand.cs b/Unicord.Universal/Commands/Generic/DownloadCommand.cs new file mode 100644 index 00000000..20f59cef --- /dev/null +++ b/Unicord.Universal/Commands/Generic/DownloadCommand.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Windows.Input; +using Unicord.Universal.Models; +using Unicord.Universal.Utilities; +using Windows.ApplicationModel.Resources; +using Windows.Storage.Pickers; +using Windows.Web.Http; + +namespace Unicord.Universal.Commands.Generic +{ + public class ProgressInfo : ViewModelBase + { + private double _progressOpacity = 0; + private double _iconOpacity = 1; + private bool _isIndeterminate = false; + private double _progress = 0; + + public double ProgressOpacity { get => _progressOpacity; set => OnPropertySet(ref _progressOpacity, value); } + public double IconOpacity { get => _iconOpacity; set => OnPropertySet(ref _iconOpacity, value); } + public bool IsIndeterminate { get => _isIndeterminate; set => OnPropertySet(ref _isIndeterminate, value); } + public double Progress { get => _progress; set => OnPropertySet(ref _progress, value); } + + public IProgress GetProgress() + { + return new Progress(p => + { + IconOpacity = 0; + ProgressOpacity = 1; + if (p.TotalBytesToReceive.HasValue) + { + IsIndeterminate = false; + Progress = p.BytesReceived / (double)p.TotalBytesToReceive.Value; + } + else + IsIndeterminate = true; + }); + } + + public void GoToProgress() + { + IconOpacity = 0; + ProgressOpacity = 1; + IsIndeterminate = true; + } + + public void Reset() + { + IconOpacity = 1; + ProgressOpacity = 0; + IsIndeterminate = false; + } + } + + public class DownloadCommand : ICommand + { + private readonly ProgressInfo _info; + private readonly string _url; + private bool _canExecute; + + public DownloadCommand(string url, ProgressInfo info) + { + _url = url; + _info = info; + _canExecute = true; + } + + public event EventHandler CanExecuteChanged; + + + public bool CanExecute(object parameter) + { + return _canExecute; + } + + public async void Execute(object parameter) + { + _canExecute = false; + _info.GoToProgress(); + + var url = new Uri(_url); + var strings = ResourceLoader.GetForCurrentView("Controls"); + + try + { + var extension = Path.GetExtension(url.AbsolutePath); + var extensionString = Tools.GetItemTypeFromExtension(extension, strings.GetString("AttachmentExtensionPlaceholder")); + var picker = new FileSavePicker() + { + SuggestedStartLocation = PickerLocationId.Downloads, + SuggestedFileName = Path.GetFileNameWithoutExtension(url.AbsolutePath), + DefaultFileExtension = extension + }; + + picker.FileTypeChoices.Add($"{extensionString} (*{extension})", new List() { extension }); + + var file = await picker.PickSaveFileAsync(); + if (file != null) + { + await Tools.DownloadToFileAsync(url, file, _info.GetProgress()); + } + } + catch (Exception ex) + { + Logger.LogError(ex); + await UIUtilities.ShowErrorDialogAsync( + strings.GetString("AttachmentDownloadFailedTitle"), + strings.GetString("AttachmentDownloadFailedText")); + } + + _info.Reset(); + _canExecute = true; + } + } +} diff --git a/Unicord.Universal/Commands/Generic/ShareCommand.cs b/Unicord.Universal/Commands/Generic/ShareCommand.cs new file mode 100644 index 00000000..b2ca81fb --- /dev/null +++ b/Unicord.Universal/Commands/Generic/ShareCommand.cs @@ -0,0 +1,68 @@ +using System; +using System.Windows.Input; +using Unicord.Universal.Utilities; +using Windows.ApplicationModel.DataTransfer; +using Windows.ApplicationModel.Resources; +using Windows.Storage; + +namespace Unicord.Universal.Commands.Generic +{ + public class ShareCommand : ICommand + { + private readonly string url; + private readonly string fileName; + private readonly ProgressInfo shareProgress; + + public ShareCommand(string url, string fileName, ProgressInfo shareProgress) + { + this.url = url; + this.fileName = fileName; + this.shareProgress = shareProgress; + } + + public event EventHandler CanExecuteChanged; + + public bool CanExecute(object parameter) + { + return true; + } + + public async void Execute(object parameter) + { + var strings = ResourceLoader.GetForCurrentView("Controls"); + shareProgress.GoToProgress(); + + try + { + var transferManager = DataTransferManager.GetForCurrentView(); + var shareFile = await ApplicationData.Current.TemporaryFolder.CreateFileAsync(fileName, CreationCollisionOption.GenerateUniqueName); + await Tools.DownloadToFileAsync(new Uri(url), shareFile, shareProgress.GetProgress()); + + void DataRequested(DataTransferManager sender, DataRequestedEventArgs args) + { + var request = args.Request; + request.Data.Properties.Title = string.Format(strings.GetString("SharingTitleFormat"), fileName); + request.Data.Properties.Description = fileName; + + request.Data.SetWebLink(new Uri(url)); + request.Data.SetStorageItems(new[] { shareFile }); + + sender.DataRequested -= DataRequested; + } + + transferManager.DataRequested += DataRequested; + DataTransferManager.ShowShareUI(); + } + catch (Exception ex) + { + Logger.LogError(ex); + await UIUtilities.ShowErrorDialogAsync( + strings.GetString("AttachmentDownloadFailedTitle"), + strings.GetString("AttachmentDownloadFailedText")); + } + + shareProgress.Reset(); + + } + } +} diff --git a/Unicord.Universal/Commands/Guild/AcknowledgeGuildCommand.cs b/Unicord.Universal/Commands/Guild/AcknowledgeGuildCommand.cs new file mode 100644 index 00000000..6e6f605d --- /dev/null +++ b/Unicord.Universal/Commands/Guild/AcknowledgeGuildCommand.cs @@ -0,0 +1,24 @@ +using Unicord.Universal.Models.Guild; + +namespace Unicord.Universal.Commands.Guild +{ + internal class AcknowledgeGuildCommand : DiscordCommand + { + public AcknowledgeGuildCommand(GuildViewModel viewModel) : base(viewModel) + { + } + + public override bool CanExecute(object parameter) + { + return viewModel.Unread; + } + + public override async void Execute(object parameter) + { + if (!viewModel.Unread) + return; + + await viewModel.Guild.AcknowledgeAsync(); + } + } +} diff --git a/Unicord.Universal/Commands/Guild/MuteGuildCommand.cs b/Unicord.Universal/Commands/Guild/MuteGuildCommand.cs new file mode 100644 index 00000000..4b9676da --- /dev/null +++ b/Unicord.Universal/Commands/Guild/MuteGuildCommand.cs @@ -0,0 +1,21 @@ +using Unicord.Universal.Models.Guild; + +namespace Unicord.Universal.Commands.Guild +{ + internal class MuteGuildCommand : DiscordCommand + { + public MuteGuildCommand(GuildViewModel viewModel) : base(viewModel) + { + } + + public override bool CanExecute(object parameter) + { + return false; + } + + public override void Execute(object parameter) + { + + } + } +} \ No newline at end of file diff --git a/Unicord.Universal/Commands/KickCommand.cs b/Unicord.Universal/Commands/KickCommand.cs deleted file mode 100644 index 02423ad4..00000000 --- a/Unicord.Universal/Commands/KickCommand.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Windows.Input; -using DSharpPlus; -using DSharpPlus.Entities; -using Microsoft.AppCenter.Analytics; -using Unicord.Universal.Dialogs; -using Unicord.Universal.Utilities; -using Windows.UI.Xaml.Controls; - -namespace Unicord.Universal.Commands -{ - public class KickCommand : ICommand - { -#pragma warning disable 67 // the event is never used - public event EventHandler CanExecuteChanged; -#pragma warning restore 67 - - public bool CanExecute(object parameter) - { - if (parameter is DiscordMember member) - { - if (member.Id == App.Discord.CurrentUser.Id) - return false; - - if (!Tools.CheckRoleHierarchy(member.Guild.CurrentMember, member)) - return false; - - return member.Guild.CurrentMember.PermissionsIn(null).HasPermission(Permissions.KickMembers); - } - - return false; - } - - public async void Execute(object parameter) - { - Analytics.TrackEvent("KickCommand_Invoked"); - - if (parameter is DiscordMember member) - { - var kickDialog = new KickDialog(member); - var result = await kickDialog.ShowAsync(); - - if (result == ContentDialogResult.Primary) - { - Analytics.TrackEvent("KickCommand_KickMember"); - await member.RemoveAsync(kickDialog.KickReason); - } - } - } - } -} diff --git a/Unicord.Universal/Commands/Member/BanCommand.cs b/Unicord.Universal/Commands/Member/BanCommand.cs new file mode 100644 index 00000000..d6b34f92 --- /dev/null +++ b/Unicord.Universal/Commands/Member/BanCommand.cs @@ -0,0 +1,47 @@ +using System; +using DSharpPlus; +using Microsoft.AppCenter.Analytics; +using Unicord.Universal.Dialogs; +using Unicord.Universal.Models.User; +using Windows.UI.Xaml.Controls; + +namespace Unicord.Universal.Commands.Members +{ + public class BanCommand : DiscordCommand + { + public BanCommand(UserViewModel viewModel) + : base(viewModel) + { + } + + public override bool CanExecute(object parameter) + { + if (viewModel.Member == null) return false; + + var member = viewModel.Member; + + if (member.Id == discord.CurrentUser.Id) + return false; + + if (!Tools.CheckRoleHierarchy(member.Guild.CurrentMember, member)) + return false; + + return member.Guild.CurrentMember.PermissionsIn(null).HasPermission(Permissions.BanMembers); + + } + + public override async void Execute(object parameter) + { + Analytics.TrackEvent("BanCommand_Invoked"); + + var banDialog = new BanDialog(viewModel.Member); + var result = await banDialog.ShowAsync(); + + if (result == ContentDialogResult.Primary) + { + Analytics.TrackEvent("BanCommand_BanMember"); + await viewModel.Member.BanAsync(banDialog.DeleteMessageDays, banDialog.BanReason); + } + } + } +} diff --git a/Unicord.Universal/Commands/Member/ChangeNicknameCommand.cs b/Unicord.Universal/Commands/Member/ChangeNicknameCommand.cs new file mode 100644 index 00000000..5ac4094d --- /dev/null +++ b/Unicord.Universal/Commands/Member/ChangeNicknameCommand.cs @@ -0,0 +1,54 @@ +using System; +using DSharpPlus; +using Microsoft.AppCenter.Analytics; +using Unicord.Universal.Dialogs; +using Unicord.Universal.Models.User; +using Unicord.Universal.Services; +using Windows.UI.Xaml.Controls; + +namespace Unicord.Universal.Commands.Members +{ + class ChangeNicknameCommand : DiscordCommand + { + public ChangeNicknameCommand(UserViewModel viewModel) : base(viewModel) + { + } + + public override bool CanExecute(object parameter) + { + if (viewModel.Member == null) return false; + + var member = viewModel.Member; + var permissions = member.Guild.CurrentMember.PermissionsIn(null); + if (member.Id == DiscordManager.Discord.CurrentUser.Id && + (permissions.HasFlag(Permissions.ChangeNickname) || permissions.HasFlag(Permissions.ManageNicknames))) + { + return true; + } + + if (permissions.HasFlag(Permissions.ManageNicknames) + && Tools.CheckRoleHierarchy(member.Guild.CurrentMember, member)) + { + return true; + } + + return false; + } + + public override async void Execute(object parameter) + { + if (viewModel.Member == null) + return; + + var member = viewModel.Member; + Analytics.TrackEvent("ChangeNicknameCommand_Invoked"); + + var dialog = new ChangeNicknameDialog(member); + if (await dialog.ShowAsync() == ContentDialogResult.Primary) + { + Analytics.TrackEvent("ChangeNicknameCommand_ChangeNickname"); + await member.ModifyAsync(m => m.Nickname = dialog.Text); + } + } + } +} diff --git a/Unicord.Universal/Commands/Member/KickCommand.cs b/Unicord.Universal/Commands/Member/KickCommand.cs new file mode 100644 index 00000000..c1571260 --- /dev/null +++ b/Unicord.Universal/Commands/Member/KickCommand.cs @@ -0,0 +1,46 @@ +using System; +using DSharpPlus; +using Microsoft.AppCenter.Analytics; +using Unicord.Universal.Dialogs; +using Unicord.Universal.Services; +using Unicord.Universal.Models.User; +using Windows.UI.Xaml.Controls; + +namespace Unicord.Universal.Commands.Members +{ + public class KickCommand : DiscordCommand + { + public KickCommand(UserViewModel viewModel) : base(viewModel) + { + } + + public override bool CanExecute(object parameter) + { + var member = viewModel.Member; + if (member == null) + return false; + + if (member.Id == DiscordManager.Discord.CurrentUser.Id) + return false; + + if (!Tools.CheckRoleHierarchy(member.Guild.CurrentMember, member)) + return false; + + return member.Guild.CurrentMember.PermissionsIn(null).HasPermission(Permissions.KickMembers); + } + + public override async void Execute(object parameter) + { + Analytics.TrackEvent("KickCommand_Invoked"); + + var kickDialog = new KickDialog(viewModel.Member); + var result = await kickDialog.ShowAsync(); + + if (result == ContentDialogResult.Primary) + { + Analytics.TrackEvent("KickCommand_KickMember"); + await viewModel.Member.RemoveAsync(kickDialog.KickReason); + } + } + } +} diff --git a/Unicord.Universal/Commands/MessageUserCommand.cs b/Unicord.Universal/Commands/MessageUserCommand.cs deleted file mode 100644 index 8e6c4fdc..00000000 --- a/Unicord.Universal/Commands/MessageUserCommand.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using System.Linq; -using System.Windows.Input; -using DSharpPlus; -using DSharpPlus.Entities; -using Microsoft.AppCenter.Analytics; -using Unicord.Universal.Pages; -using Unicord.Universal.Services; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Media.Animation; - -namespace Unicord.Universal.Commands -{ - class MessageUserCommand : ICommand - { -#pragma warning disable 67 // the event is never used - public event EventHandler CanExecuteChanged; -#pragma warning restore 67 - - public bool CanExecute(object parameter) - { - if (App.Discord?.CurrentUser == null) - return false; - - if (parameter is DiscordMember m && m.Id != App.Discord.CurrentUser.Id) - { - return true; - } - else if (parameter is DiscordUser u && u.Id != App.Discord?.CurrentUser?.Id) - { - if (App.Discord.Relationships.TryGetValue(u.Id, out var rel) && rel.RelationshipType == DiscordRelationshipType.Friend) - { - return true; - } - - if (App.Discord.Guilds.Values.Any(g => g.Members.ContainsKey(u.Id))) - { - return true; - } - } - - return false; - } - - public async void Execute(object parameter) - { - Analytics.TrackEvent("MessageUserCommand_Invoked"); - - if (parameter is DiscordUser user) - { - var channel = App.Discord.PrivateChannels.Values.FirstOrDefault(c => c.Recipients.FirstOrDefault()?.Id == user.Id); - if (channel == null) - { - if ((App.Discord.Relationships.TryGetValue(user.Id, out var rel) && rel.RelationshipType == DiscordRelationshipType.Friend) || - App.Discord.Guilds.Any(g => g.Value.Members.ContainsKey(user.Id))) - { - // apparently this is bad - // channel = await App.Discord.CreateDmChannelAsync(user.Id); - } - } - - if (channel != null) - { - var page = Window.Current.Content.FindChild(); - if (page != null) - { - page.HideOverlay(); - - var service = DiscordNavigationService.GetForCurrentView(); - await service.NavigateAsync(channel); - } - } - } - } - } -} diff --git a/Unicord.Universal/Commands/Messages/CopyMessageCommand.cs b/Unicord.Universal/Commands/Messages/CopyMessageCommand.cs new file mode 100644 index 00000000..7e2d983a --- /dev/null +++ b/Unicord.Universal/Commands/Messages/CopyMessageCommand.cs @@ -0,0 +1,32 @@ +using System; +using Microsoft.AppCenter.Analytics; +using Unicord.Universal.Models.Messages; +using Windows.ApplicationModel.DataTransfer; + +namespace Unicord.Universal.Commands.Messages +{ + public class CopyMessageCommand : DiscordCommand + { + public CopyMessageCommand(MessageViewModel viewModel) : base(viewModel) + { + } + + public override void Execute(object parameter) + { + Analytics.TrackEvent("CopyMessageCommand_Invoked"); + var message = viewModel.Message; + + var package = new DataPackage(); + package.RequestedOperation = DataPackageOperation.Copy | DataPackageOperation.Link; + + var serverText = message.Channel.Guild != null ? message.Channel.GuildId.ToString() : "@me"; + var uri = "https://" + $"discordapp.com/channels/{serverText}/{message.ChannelId}/{message.Id}/"; + + package.SetText(message.Content); + package.SetWebLink(new Uri(uri)); + package.SetRtf($"{{\\field{{\\*\\fldinst HYPERLINK \"{uri}\"}}{{\fldrslt {message.Content}}}"); + + Clipboard.SetContent(package); + } + } +} diff --git a/Unicord.Universal/Commands/Messages/DeleteMessageCommand.cs b/Unicord.Universal/Commands/Messages/DeleteMessageCommand.cs new file mode 100644 index 00000000..b6cf233f --- /dev/null +++ b/Unicord.Universal/Commands/Messages/DeleteMessageCommand.cs @@ -0,0 +1,54 @@ +using System; +using DSharpPlus; +using DSharpPlus.Entities; +using Microsoft.AppCenter.Analytics; +using Unicord.Universal.Dialogs; +using Unicord.Universal.Models.Messages; +using Windows.UI.Xaml.Controls; + +namespace Unicord.Universal.Commands.Messages +{ + public class DeleteMessageCommand : DiscordCommand + { + public DeleteMessageCommand(MessageViewModel viewModel) : base(viewModel) { } + + public override bool CanExecute(object parameter) + { + var message = viewModel.Message; + if (message.Author.IsCurrent) + { + return true; + } + + if (message.Author is DiscordMember member) + { + var currentMember = member.Guild.CurrentMember; + + if (currentMember.IsOwner) + { + return true; + } + + if (currentMember.PermissionsIn(message.Channel).HasPermission(Permissions.ManageMessages)) + { + return true; + } + } + + return false; + } + + public override async void Execute(object parameter) + { + Analytics.TrackEvent("DeleteMessageCommand_Invoked"); + var message = viewModel.Message; + + var dialog = new DeleteMessageDialog() { Message = message }; + if (await dialog.ShowAsync() == ContentDialogResult.Primary) + { + Analytics.TrackEvent("DeleteMessageCommand_DeleteMessage"); + await message.DeleteAsync(); + } + } + } +} diff --git a/Unicord.Universal/Commands/Messages/PinMessageCommand.cs b/Unicord.Universal/Commands/Messages/PinMessageCommand.cs new file mode 100644 index 00000000..cdf8f30b --- /dev/null +++ b/Unicord.Universal/Commands/Messages/PinMessageCommand.cs @@ -0,0 +1,63 @@ +using DSharpPlus; +using DSharpPlus.Entities; +using Microsoft.AppCenter.Analytics; +using System; +using Unicord.Universal.Dialogs; +using Unicord.Universal.Models.Messages; +using Windows.UI.Xaml.Controls; + +namespace Unicord.Universal.Commands +{ + public class PinMessageCommand : DiscordCommand + { + public PinMessageCommand(MessageViewModel viewModel) : base(viewModel) { } + + public override bool CanExecute(object parameter) + { + var message = viewModel.Message; + + if (message.Channel is DiscordDmChannel) + { + return true; + } + + if (message.Author is DiscordMember member) + { + var currentMember = member.Guild.CurrentMember; + + if (currentMember.IsOwner) + { + return true; + } + + if (currentMember.PermissionsIn(message.Channel).HasFlag(Permissions.ManageMessages)) + { + return true; + } + } + + return false; + } + + public override async void Execute(object parameter) + { + Analytics.TrackEvent("PinMessageCommand_Invoked"); + + var message = viewModel.Message; + var dialog = new PinMessageDialog() { Message = message }; + if (await dialog.ShowAsync() == ContentDialogResult.Primary) + { + Analytics.TrackEvent("PinMessageCommand_PinMessage"); + + if (message.Pinned) + { + await message.UnpinAsync(); + } + else + { + await message.PinAsync(); + } + } + } + } +} diff --git a/Unicord.Universal/Commands/Messages/ReactCommand.cs b/Unicord.Universal/Commands/Messages/ReactCommand.cs new file mode 100644 index 00000000..0faf6c36 --- /dev/null +++ b/Unicord.Universal/Commands/Messages/ReactCommand.cs @@ -0,0 +1,34 @@ +using System.Linq; +using Unicord.Universal.Models.Emoji; +using Unicord.Universal.Models.Messages; + +namespace Unicord.Universal.Commands.Messages +{ + internal class ReactCommand : DiscordCommand + { + public ReactCommand(MessageViewModel message) + : base(message) + { + } + + public override bool CanExecute(object parameter) + { + return parameter is EmojiViewModel; + } + + public override async void Execute(object parameter) + { + if (parameter is not EmojiViewModel emoji || emoji.DiscordEmoji == null) + return; + + if (viewModel.Reactions.Any(r => r.IsMe && r.Emoji == emoji)) + { + await viewModel.Message.DeleteOwnReactionAsync(emoji.DiscordEmoji); + } + else + { + await viewModel.Message.CreateReactionAsync(emoji.DiscordEmoji); + } + } + } +} diff --git a/Unicord.Universal/Commands/Messages/ReplyCommand.cs b/Unicord.Universal/Commands/Messages/ReplyCommand.cs new file mode 100644 index 00000000..5b5f2934 --- /dev/null +++ b/Unicord.Universal/Commands/Messages/ReplyCommand.cs @@ -0,0 +1,39 @@ +using DSharpPlus; +using Microsoft.AppCenter.Analytics; +using Unicord.Universal.Extensions; +using Unicord.Universal.Models; +using Unicord.Universal.Models.Messages; +using Unicord.Universal.Pages; +using Windows.UI.Xaml; + +namespace Unicord.Universal.Commands +{ + public class ReplyCommand : DiscordCommand + { + public ReplyCommand(MessageViewModel viewModel) : base(viewModel) + { + } + + public override bool CanExecute(object parameter) + { + return viewModel.Channel is ChannelPageViewModel && + (viewModel.Type is MessageType.Default or MessageType.Reply or MessageType.ApplicationCommand); + } + + public override void Execute(object parameter) + { + Analytics.TrackEvent("ReplyCommand_Invoked"); + + if (viewModel.Channel is not ChannelPageViewModel pageViewModel) + return; + + pageViewModel.ReplyTo = viewModel; + + // TODO: sorta messy? + var channelPage = Window.Current.Content.FindChild(); + if (channelPage == null) + return; + channelPage.FocusTextBox(); + } + } +} diff --git a/Unicord.Universal/Commands/MuteCommand.cs b/Unicord.Universal/Commands/MuteCommand.cs deleted file mode 100644 index fded08ce..00000000 --- a/Unicord.Universal/Commands/MuteCommand.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Windows.Input; -using DSharpPlus.Entities; -using Microsoft.AppCenter.Analytics; - -namespace Unicord.Universal.Commands -{ - class MuteCommand : ICommand - { -#pragma warning disable 67 // the event is never used - public event EventHandler CanExecuteChanged; -#pragma warning restore 67 - - public bool CanExecute(object parameter) - { - if (parameter is DiscordChannel || parameter is DiscordGuild) - { - return true; - } - - return true; - } - - public async void Execute(object parameter) - { - Analytics.TrackEvent("MuteCommand_Invoked"); - - try - { - if (parameter is DiscordChannel channel) - { - // if (!channel.Muted) - // await channel.MuteAsync(); - } - - if (parameter is DiscordGuild guild) - { - // guild.Muted = !guild.Muted; - } - } - catch (Exception ex) - { - Logger.LogError(ex); - } - } - } -} diff --git a/Unicord.Universal/Commands/NullCommand.cs b/Unicord.Universal/Commands/NullCommand.cs new file mode 100644 index 00000000..0be49015 --- /dev/null +++ b/Unicord.Universal/Commands/NullCommand.cs @@ -0,0 +1,23 @@ +using System; +using System.Windows.Input; + +namespace Unicord.Universal.Commands +{ + internal class NullCommand : ICommand + { + public static readonly ICommand Instance + = new NullCommand(); + + public event EventHandler CanExecuteChanged; + + public bool CanExecute(object parameter) + { + return false; + } + + public void Execute(object parameter) + { + // do nothing + } + } +} diff --git a/Unicord.Universal/Commands/OpenNewWindowCommand.cs b/Unicord.Universal/Commands/OpenNewWindowCommand.cs deleted file mode 100644 index 6504483a..00000000 --- a/Unicord.Universal/Commands/OpenNewWindowCommand.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Windows.Input; -using DSharpPlus; -using DSharpPlus.Entities; -using Microsoft.AppCenter.Analytics; -using Unicord.Universal.Services; -using Unicord.Universal.Utilities; - -namespace Unicord.Universal.Commands -{ - class OpenNewWindowCommand : ICommand - { -#pragma warning disable 67 // the event is never used - public event EventHandler CanExecuteChanged; -#pragma warning restore 67 - - public bool CanExecute(object parameter) - { - return (parameter is DiscordChannel channel) && channel.Type != ChannelType.Voice && WindowingService.Current.Supported; - } - - public async void Execute(object parameter) - { - Analytics.TrackEvent("OpenNewWindowCommand_Invoked"); - - if (parameter is DiscordChannel channel && channel.Type != ChannelType.Voice) - { - await WindowingService.Current.OpenChannelWindowAsync(channel); - } - } - } -} diff --git a/Unicord.Universal/Commands/PinChannelCommand.cs b/Unicord.Universal/Commands/PinChannelCommand.cs deleted file mode 100644 index 7068604b..00000000 --- a/Unicord.Universal/Commands/PinChannelCommand.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Input; -using DSharpPlus.Entities; -using Microsoft.AppCenter.Analytics; -using Unicord.Universal.Shared; -using Windows.UI.StartScreen; - -namespace Unicord.Universal.Commands -{ - public class PinChannelCommand : ICommand - { -#pragma warning disable 67 // the event is never used - public event EventHandler CanExecuteChanged; -#pragma warning restore 67 - - public bool CanExecute(object parameter) - { - return parameter is DiscordChannel channel && !SecondaryTile.Exists($"Channel_{channel.Id}"); - } - - public async void Execute(object parameter) - { - if (parameter is DiscordChannel channel && !SecondaryTile.Exists($"Channel_{channel.Id}")) - { - Analytics.TrackEvent("PinChannelCommand_PinChannel"); - - var tile = new SecondaryTile( - $"Channel_{channel.Id}", - NotificationUtils.GetChannelHeaderName(channel), - $"-channelId={channel.Id}", - new Uri("ms-appx:///Assets/Store/Square150x150Logo.png"), - TileSize.Square150x150); - - tile.VisualElements.ShowNameOnSquare150x150Logo = true; - tile.VisualElements.ShowNameOnWide310x150Logo = true; - tile.VisualElements.ShowNameOnSquare310x310Logo = true; - - if (await tile.RequestCreateAsync()) - { - SecondaryTileManager.ClearTileNotifications(channel, tile); - } - } - } - } -} diff --git a/Unicord.Universal/Commands/PinMessageCommand.cs b/Unicord.Universal/Commands/PinMessageCommand.cs deleted file mode 100644 index 4afc6b13..00000000 --- a/Unicord.Universal/Commands/PinMessageCommand.cs +++ /dev/null @@ -1,68 +0,0 @@ -using DSharpPlus; -using DSharpPlus.Entities; -using Microsoft.AppCenter.Analytics; -using System; -using System.Windows.Input; -using Unicord.Universal.Dialogs; -using Windows.UI.Xaml.Controls; - -namespace Unicord.Universal.Commands -{ - class PinMessageCommand : ICommand - { -#pragma warning disable 67 // the event is never used - public event EventHandler CanExecuteChanged; -#pragma warning restore 67 - - public bool CanExecute(object parameter) - { - if (parameter is DiscordMessage message) - { - if (message.Channel is DiscordDmChannel) - { - return true; - } - - if (message.Author is DiscordMember member) - { - var currentMember = member.Guild.CurrentMember; - - if (currentMember.IsOwner) - { - return true; - } - - if (currentMember.PermissionsIn(message.Channel).HasFlag(Permissions.ManageMessages)) - { - return true; - } - } - } - - return false; - } - - public async void Execute(object parameter) - { - Analytics.TrackEvent("PinMessageCommand_Invoked"); - - if (parameter is DiscordMessage message) - { - var dialog = new PinMessageDialog() { Message = message }; - if (await dialog.ShowAsync() == ContentDialogResult.Primary) - { - Analytics.TrackEvent("PinMessageCommand_PinMessage"); - - if (message.Pinned) - { - await message.UnpinAsync(); - } - else - { - await message.PinAsync(); - } - } - } - } - } -} diff --git a/Unicord.Universal/Commands/ReplyCommand.cs b/Unicord.Universal/Commands/ReplyCommand.cs deleted file mode 100644 index a43af7b7..00000000 --- a/Unicord.Universal/Commands/ReplyCommand.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Input; -using DSharpPlus; -using DSharpPlus.Entities; -using Microsoft.AppCenter.Analytics; -using Unicord.Universal.Pages; -using Windows.UI.Xaml; - -namespace Unicord.Universal.Commands -{ - class ReplyCommand : ICommand - { -#pragma warning disable 67 // the event is never used - public event EventHandler CanExecuteChanged; -#pragma warning restore 67 - - public bool CanExecute(object parameter) - { - return (parameter is DiscordMessage message && (message.MessageType == MessageType.Default || message.MessageType == MessageType.Reply)) || parameter is null; - } - - public void Execute(object parameter) - { - Analytics.TrackEvent("ReplyCommand_Invoked"); - - var channelPage = Window.Current.Content.FindChild(); - if (channelPage == null) - return; - - if (parameter is DiscordMessage message) - { - if (channelPage?.ViewModel != null) - channelPage.ViewModel.ReplyTo = message; - } - - if (parameter is null) - { - if (channelPage?.ViewModel != null) - channelPage.ViewModel.ReplyTo = null; - } - - channelPage.FocusTextBox(); - } - } -} diff --git a/Unicord.Universal/Commands/SettingsCommand.cs b/Unicord.Universal/Commands/SettingsCommand.cs index 566c85cf..b749140e 100644 --- a/Unicord.Universal/Commands/SettingsCommand.cs +++ b/Unicord.Universal/Commands/SettingsCommand.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows.Input; using Unicord.Universal.Services; @@ -22,7 +18,7 @@ public bool CanExecute(object parameter) public async void Execute(object parameter) { var settings = SettingsService.GetForCurrentView(); - await settings.OpenAsync(parameter is SettingsPageType t ? t : SettingsPageType.Acccounts); + await settings.OpenAsync(parameter is SettingsPageType t ? t : SettingsPageType.Accounts); } } } diff --git a/Unicord.Universal/Commands/ShowUserOverlayCommand.cs b/Unicord.Universal/Commands/ShowUserOverlayCommand.cs deleted file mode 100644 index 1fb8ae39..00000000 --- a/Unicord.Universal/Commands/ShowUserOverlayCommand.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Input; -using DSharpPlus.Entities; -using Microsoft.AppCenter.Analytics; -using Windows.UI.Xaml; - -namespace Unicord.Universal.Commands -{ - public class ShowUserOverlayCommand : ICommand - { -#pragma warning disable 67 // event is unused - public event EventHandler CanExecuteChanged; -#pragma warning restore 67 - - public bool CanExecute(object parameter) => parameter is DiscordUser; - - public void Execute(object parameter) - { - if (parameter is DiscordMember member) - { - var page = Window.Current.Content.FindChild(); - if (page != null) - { - Analytics.TrackEvent("ShowUserOverlayCommand_Invoked"); - page.ShowUserOverlay(member, true); - } - } - } - } -} diff --git a/Unicord.Universal/Commands/Users/SendMessageCommand.cs b/Unicord.Universal/Commands/Users/SendMessageCommand.cs new file mode 100644 index 00000000..58b56a9a --- /dev/null +++ b/Unicord.Universal/Commands/Users/SendMessageCommand.cs @@ -0,0 +1,32 @@ +using System.Linq; +using Unicord.Universal.Models.User; +using Unicord.Universal.Services; + +namespace Unicord.Universal.Commands.Users +{ + internal class SendMessageCommand : DiscordCommand + { + public SendMessageCommand(UserViewModel viewModel) : base(viewModel) + { + } + + public override bool CanExecute(object parameter) + { + var channel = discord.PrivateChannels.Values + .Where(c => c.IsPrivate && c.Recipients.Count > 0) + .FirstOrDefault(c => c.Recipients[0].Id == viewModel.Id); + + return channel != null; + } + + public override async void Execute(object parameter) + { + var channel = discord.PrivateChannels.Values + .Where(c => c.IsPrivate && c.Recipients.Count > 0) + .FirstOrDefault(c => c.Recipients[0].Id == viewModel.Id); + + var service = DiscordNavigationService.GetForCurrentView(); + await service.NavigateAsync(channel); + } + } +} diff --git a/Unicord.Universal/Commands/Users/ShowUserOverlayCommand.cs b/Unicord.Universal/Commands/Users/ShowUserOverlayCommand.cs new file mode 100644 index 00000000..5c772a2a --- /dev/null +++ b/Unicord.Universal/Commands/Users/ShowUserOverlayCommand.cs @@ -0,0 +1,20 @@ +using Unicord.Universal.Models.User; +using Unicord.Universal.Pages.Overlay; +using Unicord.Universal.Services; + +namespace Unicord.Universal.Commands.Users +{ + public class ShowUserOverlayCommand : DiscordCommand + { + public ShowUserOverlayCommand(UserViewModel viewModel) : base(viewModel) + { + } + + public override async void Execute(object parameter) + { + // TODO: will probably be reworked + await OverlayService.GetForCurrentView() + .ShowOverlayAsync(viewModel); + } + } +} diff --git a/Unicord.Universal/Controls/AspectRatioControl.cs b/Unicord.Universal/Controls/AspectRatioControl.cs deleted file mode 100644 index e12b1924..00000000 --- a/Unicord.Universal/Controls/AspectRatioControl.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using WamWooWam.Core; -using Windows.Foundation; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; - -namespace Unicord.Universal.Controls -{ - public sealed class AspectRatioControl : UserControl - { - public double TargetAspectRatio - { - get => (double)GetValue(TargetAspectRatioProperty); - set => SetValue(TargetAspectRatioProperty, value); - } - - public static readonly DependencyProperty TargetAspectRatioProperty = - DependencyProperty.Register("TargetAspectRatio", typeof(double), typeof(AspectRatioControl), new PropertyMetadata(0)); - - public AspectRatioControl() - { - DefaultStyleKey = typeof(ScaledContentControl); - } - - protected override Size MeasureOverride(Size availableSize) - { - this.Content.Measure(availableSize); - - var desiredSize = this.Content.DesiredSize; - var size = Math.Max(desiredSize.Width, desiredSize.Height) * TargetAspectRatio; - return new Size(size, size); - } - - } -} diff --git a/Unicord.Universal/Controls/AttachmentViewer.xaml b/Unicord.Universal/Controls/AttachmentViewer.xaml deleted file mode 100644 index c828aeab..00000000 --- a/Unicord.Universal/Controls/AttachmentViewer.xaml +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +