diff --git a/FoxTube.Background/BackgroundProcessor.cs b/FoxTube.Background/BackgroundProcessor.cs index 7bfe196..089b44d 100644 --- a/FoxTube.Background/BackgroundProcessor.cs +++ b/FoxTube.Background/BackgroundProcessor.cs @@ -4,7 +4,7 @@ namespace FoxTube.Background { public sealed class BackgroundProcessor : IBackgroundTask { - public async void Run(IBackgroundTaskInstance taskInstance) + public void Run(IBackgroundTaskInstance taskInstance) { } diff --git a/FoxTube/Classes/Downloads.cs b/FoxTube.Core/Class1.cs similarity index 51% rename from FoxTube/Classes/Downloads.cs rename to FoxTube.Core/Class1.cs index 8b64ae2..ada58be 100644 --- a/FoxTube/Classes/Downloads.cs +++ b/FoxTube.Core/Class1.cs @@ -4,13 +4,9 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace FoxTube.Classes +namespace FoxTube.Core { - public static class Downloads + public sealed class Class1 { - public static void Cancel(string id) - { - - } } } diff --git a/FoxTube.Core/Controllers/StoreInterop.cs b/FoxTube.Core/Controllers/StoreInterop.cs new file mode 100644 index 0000000..5997617 --- /dev/null +++ b/FoxTube.Core/Controllers/StoreInterop.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FoxTube.Core.Controllers +{ + public static class StoreInterop + { + public static bool AdsDisabled => false; + public static string GetProPrice() + { + return "$4.99"; + } + + public static void PurchaseApp() + { + if (!AdsDisabled) + // TODO: Add purchase validation + return; + } + } +} diff --git a/FoxTube.Core/FoxTube.Core.csproj b/FoxTube.Core/FoxTube.Core.csproj new file mode 100644 index 0000000..0a7fd8e --- /dev/null +++ b/FoxTube.Core/FoxTube.Core.csproj @@ -0,0 +1,144 @@ + + + + + Debug + AnyCPU + {797951D8-BF28-4659-BDF4-C17A583E64CD} + winmdobj + Properties + FoxTube.Core + FoxTube.Core + en-US + UAP + 10.0.18362.0 + 10.0.17134.0 + 14 + 512 + {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + false + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + prompt + 4 + + + x86 + true + bin\x86\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + false + prompt + + + x86 + bin\x86\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + false + prompt + + + ARM + true + bin\ARM\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + false + prompt + + + ARM + bin\ARM\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + false + prompt + + + ARM64 + true + bin\ARM64\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + false + prompt + + + ARM64 + bin\ARM64\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + false + prompt + + + x64 + true + bin\x64\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + false + prompt + + + x64 + bin\x64\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + false + prompt + + + PackageReference + + + + + + + + + 6.2.9 + + + + 14.0 + + + + \ No newline at end of file diff --git a/FoxTube.Core/Properties/AssemblyInfo.cs b/FoxTube.Core/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..3a284da --- /dev/null +++ b/FoxTube.Core/Properties/AssemblyInfo.cs @@ -0,0 +1,29 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("FoxTube.Core")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("FoxTube.Core")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/FoxTube.sln b/FoxTube.sln index e8ba8c1..46772a3 100644 --- a/FoxTube.sln +++ b/FoxTube.sln @@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FoxTube.Background", "FoxTu EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FoxTube.Tests", "FoxTube.Tests\FoxTube.Tests.csproj", "{3D864717-2D87-4E54-BFC0-755FC2FCA2A7}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FoxTube.Core", "FoxTube.Core\FoxTube.Core.csproj", "{797951D8-BF28-4659-BDF4-C17A583E64CD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -91,6 +93,26 @@ Global {3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Release|x86.ActiveCfg = Release|x86 {3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Release|x86.Build.0 = Release|x86 {3D864717-2D87-4E54-BFC0-755FC2FCA2A7}.Release|x86.Deploy.0 = Release|x86 + {797951D8-BF28-4659-BDF4-C17A583E64CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {797951D8-BF28-4659-BDF4-C17A583E64CD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {797951D8-BF28-4659-BDF4-C17A583E64CD}.Debug|ARM.ActiveCfg = Debug|ARM + {797951D8-BF28-4659-BDF4-C17A583E64CD}.Debug|ARM.Build.0 = Debug|ARM + {797951D8-BF28-4659-BDF4-C17A583E64CD}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {797951D8-BF28-4659-BDF4-C17A583E64CD}.Debug|ARM64.Build.0 = Debug|ARM64 + {797951D8-BF28-4659-BDF4-C17A583E64CD}.Debug|x64.ActiveCfg = Debug|x64 + {797951D8-BF28-4659-BDF4-C17A583E64CD}.Debug|x64.Build.0 = Debug|x64 + {797951D8-BF28-4659-BDF4-C17A583E64CD}.Debug|x86.ActiveCfg = Debug|x86 + {797951D8-BF28-4659-BDF4-C17A583E64CD}.Debug|x86.Build.0 = Debug|x86 + {797951D8-BF28-4659-BDF4-C17A583E64CD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {797951D8-BF28-4659-BDF4-C17A583E64CD}.Release|Any CPU.Build.0 = Release|Any CPU + {797951D8-BF28-4659-BDF4-C17A583E64CD}.Release|ARM.ActiveCfg = Release|ARM + {797951D8-BF28-4659-BDF4-C17A583E64CD}.Release|ARM.Build.0 = Release|ARM + {797951D8-BF28-4659-BDF4-C17A583E64CD}.Release|ARM64.ActiveCfg = Release|ARM64 + {797951D8-BF28-4659-BDF4-C17A583E64CD}.Release|ARM64.Build.0 = Release|ARM64 + {797951D8-BF28-4659-BDF4-C17A583E64CD}.Release|x64.ActiveCfg = Release|x64 + {797951D8-BF28-4659-BDF4-C17A583E64CD}.Release|x64.Build.0 = Release|x64 + {797951D8-BF28-4659-BDF4-C17A583E64CD}.Release|x86.ActiveCfg = Release|x86 + {797951D8-BF28-4659-BDF4-C17A583E64CD}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/FoxTube/App.xaml.cs b/FoxTube/App.xaml.cs index ab6a176..34722f4 100644 --- a/FoxTube/App.xaml.cs +++ b/FoxTube/App.xaml.cs @@ -1,12 +1,5 @@ -using FoxTube.Classes; -using FoxTube.Controls; -using FoxTube.Pages; -using Microsoft.AppCenter.Analytics; -using System.Collections.Generic; -using Windows.ApplicationModel.Activation; -using Windows.Globalization; +using Windows.ApplicationModel.Activation; using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; namespace FoxTube { @@ -15,46 +8,18 @@ namespace FoxTube public App() => InitializeComponent(); - /*void Initialize() - { - Settings.LoadData(); - - switch (Settings.Theme) - { - case 0: - RequestedTheme = ApplicationTheme.Light; - break; - case 1: - RequestedTheme = ApplicationTheme.Dark; - break; - } - ApplicationLanguages.PrimaryLanguageOverride = Settings.Language; - - Processes.InitializeApp(); - - Suspending += (s, e) => Processes.SuspendApp(); - UnhandledException += (s, e) => Analytics.TrackEvent("The app crashed", new Dictionary() - { - { "Exception", e.Exception.GetType().ToString() }, - { "Details", e.Message }, - { "StackTrace", e.Exception.StackTrace } - }); - }*/ - protected override void OnLaunched(LaunchActivatedEventArgs e) { if (!e.PrelaunchActivated && Window.Current.Content == null) - Window.Current.Content = new MainPage(e.SplashScreen, e.Arguments); + Window.Current.Content = new MainPage(); Window.Current.Activate(); } - protected override async void OnBackgroundActivated(BackgroundActivatedEventArgs args) + protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args) { var deferral = args.TaskInstance.GetDeferral(); base.OnBackgroundActivated(args); - await Methods.ProcessBackgroundToast((args.TaskInstance.TriggerDetails as ToastNotificationActivatedEventArgs).Argument); - deferral.Complete(); } @@ -63,19 +28,8 @@ namespace FoxTube base.OnActivated(e); if (Window.Current.Content == null) - Window.Current.Content = new MainPage(e.SplashScreen, e); + Window.Current.Content = new MainPage(); Window.Current.Activate(); - - if (e.Kind == ActivationKind.Protocol) - Authenticator.SetResponse((e as ProtocolActivatedEventArgs).Uri); - - /*if(e.Kind == ActivationKind.ToastNotification) - { - if (UserManagement.IsAuthorized) - Methods.ProcessToast((e as ToastNotificationActivatedEventArgs).Argument); - else - UserManagement.AuthorizationStateChanged += (arg) => Methods.ProcessToast((e as ToastNotificationActivatedEventArgs).Argument); - }*/ } } } diff --git a/FoxTube/Assets/AnnouncementThumb.png b/FoxTube/Assets/AnnouncementThumb.png deleted file mode 100644 index cb1434a..0000000 Binary files a/FoxTube/Assets/AnnouncementThumb.png and /dev/null differ diff --git a/FoxTube/Assets/ChannelCoverTemplate.png b/FoxTube/Assets/ChannelCoverTemplate.png deleted file mode 100644 index 61d877a..0000000 Binary files a/FoxTube/Assets/ChannelCoverTemplate.png and /dev/null differ diff --git a/FoxTube/Assets/Data/Package.zip b/FoxTube/Assets/Data/Package.zip deleted file mode 100644 index 862d989..0000000 Binary files a/FoxTube/Assets/Data/Package.zip and /dev/null differ diff --git a/FoxTube/Assets/Data/Patchnotes.xml b/FoxTube/Assets/Data/Patchnotes.xml deleted file mode 100644 index 09510f7..0000000 --- a/FoxTube/Assets/Data/Patchnotes.xml +++ /dev/null @@ -1,331 +0,0 @@ - - - - - ### What's new: -- Fixed video playback problems -- Fixed some cases when playlist cards aren't displayed -- Fixed some cases when the app crashes -- Fixed app crashes on trying to navigate to not existing channel/playlist/video -- Fixed history page refresh button -- You can now report comments as spam -- You can now report videos -- Enchanced background subscriptions check sequence -- Corrected misspells in English localization - - ### Что нового: -- Исправлены проблемы с воспроизведением видео -- Исправлены некоторые случаи при которых карточки плейлистов не отображались -- Исправлены некоторые случай при которых приложение вылетало -- Исправлены вылеты приложения при попытке перейти на несуществующий канал/плейлист/видео -- Исправлена кнопка обновления на странице истории просмотров -- Теперь вы можете помечать комментарии как спам -- Теперь вы можете отправлять жалобы на видео -- Улучшена проверка новых видео подписок в фоне -- Исправлены ошибки в английской локализации - - - - - - ### What's new: -- Added localization contribution system -- Added ability to completely collapse command bars (check settings) -- Added feature that checks your clipboard and suggests you to open YouTube page in the app if there is any (check settings) -- Added additional analytics tools to detect authorization fails -- Added video speed controller (check video settings) -- Test ads are now shown -- Fixed gaps in grids -- Fixed some cases when on maximizing video it pauses/continues -- Fixed missing inbox items due to incompatible date formats -- Fixed inability to unsubscribe from channel -- Fixed minimization of videos with unusual aspect ratios -- Fixed some cases when video continues to play in the background after closing/reloading video page - -### NB: -Since Microsoft hasn't fixed ad banners I'm forced to release the test ones. It will help me to optimize mechanics of ads delivery and make you fill more comfortable when the real ones will appear. Feedback is welcomed. - - ### Что нового: -- Теперь вы можете помочь нам переводить приложение на новые языки! -- Добавлена возможность полностью скрывать панель команд (см. Настройки) -- Добавлена функция которая сканирует ваш буфер обмена и, если там есть YouTube-ссылка, предлагает открыть соответствующую страницу в приложении (см. Настройки) -- Добавлены дополнительные инструменты аналитики для обнаружения ошибок авторизации -- Добавлен ползунок управления скоростью воспроизведения видео (см. Настройки видео) -- Теперь показываются тестовая реклама -- Исправлены пропуски в сетках -- Исправлены некоторые случаи при которых разворачивание видео останавливало/воспроизодило видео -- Исправлены пропущенные сообщения из-за несовместимых форматов дат системы -- Исправлена невозможность отписаться от канала -- Исправлено сворачивание видео с необычными соотношениями сторон -- Исправлены некоторые случаи при которых видео продолжало воспроизводиться в фоне после закрытия/обновления страницы видео - -### NB: -Поскольку Майкрософт все еще не исправили реальные рекламные баннеры, мне необходимо выпустить тестовые. Это поможет мне оптимизировать процесс доставки рекламы и позволит вам чувствовать себя более комфортно когда будут запущены настоящие. Отзывы приветствуются. - - - - - - ### What's new: -- Improved analytics tools for more precise bugs tracking -- Fixed multipying downloads history entries on login/logout -- Added feedback button failed authentication popup -- Duplicated subscriptions are now ignored on login - - ### Что нового: -- Улучшены инструменты аналитики для более быстрого поиска багов -- Исправлено дублирование записей истории загрузок при входе/выходе из аккаунта -- Добавлена кнопка отзыва в сообщении об ошибке при входе в аккаунт -- Повторяющиеся подписки теперь игнорируются при входе - - - - - - ##[Final release] -### What's new: -- In-video advert now doesn't appear on minimized playback -- Fixed small header appearing on channel page -- Fixed home page loading in long active sessions -- Optimization and bugfixes -- Fixed crash when local watch history reaches 87 entries (now its capacity is 200) -- Added backward navigation to video page -- Improved authentication process -- Removed outdated logo from 'About' page and updated Twitter link -- Play/pause toggle on video player mouse click -- Added player hotkeys: - Space - Play/Pause - Arrow right/left - Skip forward/backward - F11 - Toggle full screen -- Activated real ads -- Fixed app crash on video's zero rating -- "Subscribe" button now is hidden on your videos - - ##[Релизная версия] -### Что нового: -- Теперь реклама в видео не появляется в компактном режиме -- Исправлено появление меленького заголовка на странице канала -- Исправлено отображение видео на домашней странице при долгой активной сессии -- Оптимизация и исправление ошибок -- Исправлен сбой приложения при достижении локальной историей 87 записей (текущая емкость журнала - 200 записей) -- Добавлена обратная навигация для страниц просмотра -- Улучшен процесс аутентификации -- Удален старый логотип с страницы 'О приложении' и обновлена ссылка на Твиттер -- Пауза/воспроизведение при клике мышью по окну плеера -- Добавлены горячие клавиши: - Пробел - Пауза/Воспроизведение - Стрелка вправо/влево - Перейти вперед на 30 секунд/назад на 10 секунд - F11 - Переключить полноэкранный режим -- Запущена реальная реклама -- Исправлен вылет приложения при нулевом рейтинге видео -- Кнопка "Подписаться" теперь скрыта на странице вашего видео - - - - - - ##[Final pre-release version] -### What's new: -- Fixed fails when trying to retrieve history, WL or recommended -- Fixed ads appearance -- Fixed ads watermarks on video when it was opened through notification -- Optimized and enchanced video playback -- Fixed special characters appearing in toast notifications -- History page re-design -- Added app history management (doesn't affect web site's history) -- Extended history information for videos (watching progress) -- Continue where you left off feature -- Watch later playlist now acts like regular playlist -- If video is longer than 1 hour ads will be shown every 30 minutes -- Added incognito mode (available in video card context menu) -- Search suggestions now run smoother -- FoxTube pro price is now displayed in menu -- Fixed crashes on opening links which don't contain http(s) prefix -- Fixed backward navigation with minimized video -- Player re-design -- Added quality selector to live streams playback -- Added "Auto" quality option for videos -- Updated design of user's avatar in the top-right corner - -####[NB] -This is the final pre-release minor version. That means that until 1.0 release there will be no new features implemented. All subsequent updates will contain only bugfixes - - ##[Последняя предварительная версия] -### Что нового: -- Исправлена проблема получения истории, "Посмотреть позже" и рекомендаций -- Исправлен внешний вид рекламы -- Исправлено появление водяных занков рекламы на видео при открытии через уведомления -- Оптимизирован и улучшен просмотр видео -- Исправлено появление особых символов в уведомлениях -- Редизайн страницы истории -- Добавлено управление историей просмотра приложения (не влияет на историю просмотров на сайте) -- Расширенная информация о просмотренном видео (прогресс просмотра) -- Функция продолжения просмотра -- Плейлист "Посмотреть позже" теперь ведет себя как обычный плейлист -- Если видео длится более 1 часа, рекламный баннер будет появляться каждые 30 минут -- Добавлен режим инкогнито (доступен в контекстном меню видео карточки) -- Подсказки при поиске работают плавнее -- Теперь на кнопке отключения рекламы отображается текущая цена -- Исправлены вылеты при попытке открыть ссылку не содержащую http(s) префикс -- Исправлена обратная навигация при уменьшенном видео -- Редизайн плеера -- Добавлено меню выбора качества для прямых эфиров -- Добавлено опция "Авто" в меню выбора качеста видео -- Обновлен дизайн аватара пользователя в верхнем правом углу - -####[NB] -Версия 0.6 станет последней пред релизной версией. Это значит, что новые функции не будут добовляться до полного релиза приложения. Все последующие обновления будут содержать лишь исправления - - - - - - ### What's new: -- App optimization -- Changelog notification now pops up after update at first launch -- Added ability to add videos to playlists on video page -- Added ability to add videos to playlists through card's context menu -- Added ability to download video through card's context menu -- Deleted videos are now also displayed -- Added support of April 2018 Update (Windows 10 build 17134) -- Added adverts (not real. Just for debugging) -- Fixed header titles -- Some items were moved from menu to header -- Added "Share" button to video cards -- Added "Delete video from playlist" button to video cards on playlist page -- Improved channel cover quality -- If available, shows localized titles and descriptions (based on "Search relevance language" parameter set in settings) -- Updated russian localization - - ### Что нового: -- Оптимизация приложения -- Добавлено уведомление со списком изменений при первом запуске после обновления -- Добавлена возможность добавлять видео в плейлисты на странице просмотра -- Добавлена возможность добавлять видео в плейлисты через контекстное меню карточки -- Добавлена возможность скачивать видео через контекстное меню карточки -- Удаленные видео теперь также отображаются -- Добавлена поддержка Апрельского Обновления 2018 (Windows 10 сборка 17134) -- Добавлена реклама (не настоящие. Только для отладки) -- Исправлено изменение заголовков -- Некоторые пункты меню перемещены в заголовок -- Добавлена кнопка "Поделиться" к видео карточкам -- Добавлена кнопка "Удалить видео из плейлиста" к видео карточкам на страницах плейлистов -- Улучшено качество обложки канала -- Показывает локализированные заголовки и описания если доступны (основан на параметре "Предпочитаемый язык поиска" установленного в настройках) -- Обновлена русская локализация - - - - - - ### What's new: -- Improved stability and speed of the app -- Fixed a lot of bugs -- Rebuilt player -- Added animations and acrylic -- Added accout information -- Added history -- Added "Watch later" playlist -- Added "Recommended" and "Subscriptions" tabs on home page -- Added tiny icon near the channel search -- Added ability to delete comments -- Rebuilt videos downloading -- Added transparent title bar -- Added prompts to rate the app and leave feedback (dialogs shows up after 12 and 24 hours of active using) -- Rebuilt cards grid -- Added publish date on the video page -- Stream countdown was rebuilt and moved to the top of video page -- Current playlist focuses on current video -- Text selection color is now red instead of system accent color -- Added toast notifications for livestreams - -### Known issues: -- 'History' and 'Watch later' playlists sometimes are missing. Solution: restart the app -- The same problem with 'Recommended' and 'Subscriptions' tabs on home page -- Somewhere there is no russian locale. Will be finished in 1.0 version -- Playlists management will be introduced in the next version but it may miss some playlists -- Even though I've done ads delivering system it's not introduced because of some problems with ads' lookup. I just want to make your ads experience to be the best one. So it won't be implemented until I make sure that they are ready - - ### Что нового: -- Улучшена стабильность и скорость приложения -- Исправлена куча багов -- Переработан плеер -- Добавлены анимации и акрил -- Добавлена информация об аккаунте -- Добавлена история -- Добавлен плейлист "Посмотреть позже" -- Добавлены вкладки "Рекоммендованные" и "Подписки" на домашней странице -- Добавлена маленькая иконка канала при прокрутке вниз на странице канала -- Добавлена возможность удалять комментарии -- Переработано скачивание видео -- Добавлен прозрачный заголовок окна -- Добавлены всплывающие уведомления с просьбой оценить приложение и оставить отзыв (появляются после 12 и 24 часов активного использования) -- Переработана сетка карточек -- Добавлена информация о дате публикации видео на странице просмотра -- Обратный отсчет для стримов переработан и перенесен вверх страницы -- Список видео текущего плейлиста сразу перематывается на текущее -- Текст выделяется красным, а не текущим цветом системы -- Добавлены уведомления для прямых эфиров - -### Известные проблемы: -- История и плейлист 'Посмотреть позже' иногда могут не отображаться. Решение: перезапустить приложение -- Аналогично и со вкладками 'Рекомендованные' и 'Подписки' на домашней странице -- В некоторых местах отсутствует русская локализация. Будет дополнена в версии 1.0 -- Управление плейлистами будет добавлено в следующей версии, но некоторые плейлисты могут отсутствовать -- Хотя я сделал систему доставки рекламы, она не введена из-за некоторых проблем с видом банеров. Я хочу сделать ваш опыт взаимодействия с рекламой в приложении лучше, так что она не будет введена до тех пор, пока я не буду в этом уверен - - - - - - ### What's new: - -- Small fixes -- First public pre-release version -- Some content was cut out due to its incompleteness - - ### Что нового: - -- Мелкие исправления багов -- Эта версия является первой пред-релизной публичной версией -- Некотроые функции были вырезаны из-за их незавершенности - - - - - - ### What's new: - -- 'Live' button fixed in the player -- Long channel names on crads fixed -- Fixed video description disappearing on window resizing -- Player seek is fixed -- Added video buffering progress indicatior -- Small fixes - -### Known issues: - -- Recommended and subscriptions pages aren't implemented -- History isn't implemented -- Playlists management isn't implemented -- Ads aren't implemented - - ### Что нового: - -- Кнопка перехода к прямому эфиру на стримах теперь работает -- Исправлен баг с длинными именами каналов на карточках -- Исправлено исчезание описания видео при изменении размеров окна -- Исправлен ползунок перемотки видео -- Добавлен индикатор буферизации видео -- Мелкие исправления - -### Что по-прежнему не работает: - -- Страница рекомендованных видео и страница видео с подписок -- История -- Работа с плейлистами -- Нет карточек рекламы - - - - diff --git a/FoxTube/Assets/DefaultChannelBanner.png b/FoxTube/Assets/DefaultChannelBanner.png new file mode 100644 index 0000000..6e129c1 Binary files /dev/null and b/FoxTube/Assets/DefaultChannelBanner.png differ diff --git a/FoxTube/Assets/DefaultVideoThumbnail.png b/FoxTube/Assets/DefaultVideoThumbnail.png new file mode 100644 index 0000000..ea1cb01 Binary files /dev/null and b/FoxTube/Assets/DefaultVideoThumbnail.png differ diff --git a/FoxTube/Assets/Icons/Contact.png b/FoxTube/Assets/Icons/Contact.png new file mode 100644 index 0000000..9815067 Binary files /dev/null and b/FoxTube/Assets/Icons/Contact.png differ diff --git a/FoxTube/Assets/Icons/Profile.png b/FoxTube/Assets/Icons/Profile.png deleted file mode 100644 index 71ac04e..0000000 Binary files a/FoxTube/Assets/Icons/Profile.png and /dev/null differ diff --git a/FoxTube/Assets/Icons/Send.png b/FoxTube/Assets/Icons/Send.png deleted file mode 100644 index 2c73623..0000000 Binary files a/FoxTube/Assets/Icons/Send.png and /dev/null differ diff --git a/FoxTube/Assets/LogoAvatar.png b/FoxTube/Assets/LogoAvatar.png deleted file mode 100644 index c2550eb..0000000 Binary files a/FoxTube/Assets/LogoAvatar.png and /dev/null differ diff --git a/FoxTube/Assets/NewsAvatar.png b/FoxTube/Assets/NewsAvatar.png deleted file mode 100644 index e614623..0000000 Binary files a/FoxTube/Assets/NewsAvatar.png and /dev/null differ diff --git a/FoxTube/Assets/WhatsNewThumb.png b/FoxTube/Assets/WhatsNewThumb.png deleted file mode 100644 index 93ab8b6..0000000 Binary files a/FoxTube/Assets/WhatsNewThumb.png and /dev/null differ diff --git a/FoxTube/Assets/videoPlaceholder.png b/FoxTube/Assets/videoPlaceholder.png deleted file mode 100644 index 54f5e6a..0000000 Binary files a/FoxTube/Assets/videoPlaceholder.png and /dev/null differ diff --git a/FoxTube/Assets/videoThumbSample.png b/FoxTube/Assets/videoThumbSample.png deleted file mode 100644 index 28c0f63..0000000 Binary files a/FoxTube/Assets/videoThumbSample.png and /dev/null differ diff --git a/FoxTube/Classes/Authenticator.cs b/FoxTube/Classes/Authenticator.cs deleted file mode 100644 index c103947..0000000 --- a/FoxTube/Classes/Authenticator.cs +++ /dev/null @@ -1,226 +0,0 @@ -using Google.Apis.Oauth2.v2; -using Google.Apis.YouTube.v3; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using Windows.Data.Json; -using Windows.Security.Cryptography; -using Windows.Security.Cryptography.Core; -using Windows.Storage.Streams; -using Google.Apis.Auth.OAuth2.Responses; -using Google.Apis.Auth.OAuth2; - -namespace FoxTube.Classes -{ - public static class Authenticator - { - const string redirectURI = "xfox111.foxtube:/oauth2redirect"; - const string authorizationEndpoint = "https://accounts.google.com/o/oauth2/v2/auth"; - const string tokenEndpoint = "https://www.googleapis.com/oauth2/v4/token"; - - readonly static string scopes = Oauth2Service.Scope.UserinfoProfile + " " + - Oauth2Service.Scope.UserinfoEmail + " " + - YouTubeService.Scope.YoutubeForceSsl; - - - static Uri responseUri = null; - static string state = null; - static string codeVerifier = null; - - - public static async Task Authorize(string clientId) - { - await SendRequest(clientId); - await WaitForResponse(); - string code = ProcessResponse(responseUri); - JsonObject response = await ExchangeForTokens(clientId, code); - - ClearFields(); - - return new TokenResponse - { - AccessToken = response.GetNamedString("access_token"), - ExpiresInSeconds = 3600, - IssuedUtc = DateTime.UtcNow, - TokenType = response.GetNamedString("token_type"), - IdToken = response.GetNamedString("id_token"), - RefreshToken = response.GetNamedString("refresh_token"), - Scope = response.GetNamedString("scope") - }; - } - - public static async Task RefreshToken(string clientId, string refreshToken) => - await RefreshToken(clientId, refreshToken, null); - - public static async Task RefreshToken(string clientId, string refreshToken, string idToken) - { - HttpClient client = new HttpClient(); - client.DefaultRequestHeaders.Host = "www.googleapis.com"; - client.DefaultRequestHeaders.Add("Content-Type", "application/x-www-form-urlencoded"); - - Dictionary body = new Dictionary - { - { "client_id", clientId }, - { "refresh_token", refreshToken }, - { "grant_type", "refresh_token" } - }; - - using(HttpResponseMessage raw = await client.PostAsync("https://www.googleapis.com/oauth2/v4/token", new FormUrlEncodedContent(body))) - { - if (!raw.IsSuccessStatusCode) - return null; - - JsonObject response = JsonObject.Parse(await raw.Content.ReadAsStringAsync()); - - return new TokenResponse - { - AccessToken = response.GetNamedString("access_token"), - IssuedUtc = DateTime.UtcNow, - RefreshToken = refreshToken, - Scope = scopes, - TokenType = "Bearer", - ExpiresInSeconds = int.Parse(response.GetNamedString("expires_in")), - IdToken = idToken - }; - } - } - - static async Task WaitForResponse() - { - while (responseUri == null) - await Task.Delay(1000); - } - - public static void SetResponse(Uri response) => - responseUri = response; - - static async Task SendRequest(string clientId) - { - // Generates state and PKCE values. - state = randomDataBase64url(32); - codeVerifier = randomDataBase64url(32); - string code_challenge = base64urlencodeNoPadding(sha256(codeVerifier)); - - // Creates the OAuth 2.0 authorization request. - string authorizationRequest = string.Format("{0}?response_type=code&redirect_uri={1}&client_id={2}&state={3}&code_challenge={4}&code_challenge_method={5}&scope={6}", - authorizationEndpoint, - Uri.EscapeDataString(redirectURI), - clientId, - state, - code_challenge, - "S256", - scopes); - - // Opens the Authorization URI in the browser. - await Windows.System.Launcher.LaunchUriAsync(new Uri(authorizationRequest)); - } - - public static string ProcessResponse(Uri response) - { - // Gets URI from navigation parameters. - string queryString = response.Query; - - // Parses URI params into a dictionary - // ref: http://stackoverflow.com/a/11957114/72176 - Dictionary queryStringParams = - queryString.Substring(1).Split('&') - .ToDictionary(c => c.Split('=')[0], - c => Uri.UnescapeDataString(c.Split('=')[1])); - - if (!queryStringParams.ContainsKey("code") - || !queryStringParams.ContainsKey("state") - || queryStringParams.ContainsKey("error")) - return null; - - // Gets the Authorization state - string incoming_state = queryStringParams["state"]; - - // Compares the receieved state to the expected value, to ensure that - // this app made the request which resulted in authorization - if (incoming_state != state) - return null; - - // Returns the Authorization code - return queryStringParams["code"]; - } - - - static async Task ExchangeForTokens(string clientId, string code) - { - // Builds the Token request - string tokenRequestBody = string.Format("code={0}&redirect_uri={1}&client_id={2}&code_verifier={3}&scope=&grant_type=authorization_code", - code, - Uri.EscapeDataString(redirectURI), - clientId, - codeVerifier - ); - StringContent content = new StringContent(tokenRequestBody, Encoding.UTF8, "application/x-www-form-urlencoded"); - - // Performs the authorization code exchange. - HttpClientHandler handler = new HttpClientHandler(); - handler.AllowAutoRedirect = true; - HttpClient client = new HttpClient(handler); - - HttpResponseMessage response = await client.PostAsync(tokenEndpoint, content); - string responseString = await response.Content.ReadAsStringAsync(); - - if (!response.IsSuccessStatusCode) - return null; - - // Retrieves access token - return JsonObject.Parse(responseString); - } - - static void ClearFields() - { - codeVerifier = null; - state = null; - responseUri = null; - } - - - /// - /// Returns URI-safe data with a given input length. - /// - /// Input length (nb. output will be longer) - /// - static string randomDataBase64url(uint length) - { - IBuffer buffer = CryptographicBuffer.GenerateRandom(length); - return base64urlencodeNoPadding(buffer); - } - - /// - /// Returns the SHA256 hash of the input string. - /// - /// - /// - static IBuffer sha256(string inputStirng) - { - HashAlgorithmProvider sha = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Sha256); - IBuffer buff = CryptographicBuffer.ConvertStringToBinary(inputStirng, BinaryStringEncoding.Utf8); - return sha.HashData(buff); - } - - /// - /// Base64url no-padding encodes the given input buffer. - /// - /// - /// - static string base64urlencodeNoPadding(IBuffer buffer) - { - string base64 = CryptographicBuffer.EncodeToBase64String(buffer); - - // Converts base64 to base64url. - base64 = base64.Replace("+", "-"); - base64 = base64.Replace("/", "_"); - // Strips padding. - base64 = base64.Replace("=", ""); - - return base64; - } - } -} diff --git a/FoxTube/Classes/Extensions.cs b/FoxTube/Classes/Extensions.cs deleted file mode 100644 index 969207a..0000000 --- a/FoxTube/Classes/Extensions.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Google.Apis.YouTube.v3.Data; -using System; -using System.Collections; -using System.Linq; - -namespace FoxTube -{ - public delegate void AuthorizationChangedEventHandler(bool isAuthorized); - public delegate void SubscriptionChangedEventHandler(string action, Subscription subscription); - public delegate void ProVersionStateChangedEventHandler(bool purchased, string price); - public delegate void NavigatingOccured(Type sourcePageType, object parameter); - public delegate void NavigationOccured(IList pivotCollection, int? selectedPivot); - public delegate void SimpleEventHandler(); - - public enum LoadingScreenState - { - Loading = 0, - Loaded = 1, - Error = 2, - Blocked = 3 - } - - public interface INavigationPage - { - object Parameter { get; set; } - } - - public static class Extensions - { - public static Uri ToUri(this string str) => - string.IsNullOrWhiteSpace(str) ? null : new Uri(str); - - public static bool Belongs(this T obj, params T[] values) => - values.Contains(obj); - - public static string GuardFromNull(this object obj, string str) => - string.IsNullOrWhiteSpace(str) ? string.Empty : str; - } -} diff --git a/FoxTube/Classes/Methods.cs b/FoxTube/Classes/Methods.cs deleted file mode 100644 index 263ff33..0000000 --- a/FoxTube/Classes/Methods.cs +++ /dev/null @@ -1,89 +0,0 @@ -using FoxTube.Classes; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Windows.ApplicationModel.Core; -using Windows.UI; -using Windows.UI.Core; -using Windows.UI.ViewManagement; -using Windows.UI.Xaml; - -namespace FoxTube -{ - public static class Methods - { - public static void ProcessToast(string argument) - { - string[] args = argument.Split('|'); - - switch (args[0]) - { - case "changelog": - case "inbox": - Navigation.GoToDeveloper(args[1]); - break; - - case "video": - Navigation.GoToVideo(args[1]); - break; - - case "channel": - Navigation.GoToChannel(args[1]); - break; - - case "download": - Navigation.GoToDownloads(); - break; - case "clipboard": - switch (args[1]) - { - case "video": - Navigation.GoToVideo(args[2]); - break; - case "channel": - Navigation.GoToChannel(args[2]); - break; - case "playlist": - Navigation.GoToPlaylist(args[2]); - break; - } - break; - } - } - - public static async Task ProcessBackgroundToast(string argument) - { - try - { - string[] args = argument.Split('|'); - - switch (args[0]) - { - case "dcancel": - Downloads.Cancel(args[1]); - break; - case "later": - await UserManagement.AddItemToWL(args[1]); - break; - } - } - catch { } - } - - public static void SetTitleBar() - { - var titleBar = ApplicationView.GetForCurrentView().TitleBar; - - titleBar.ButtonBackgroundColor = Colors.Transparent; - titleBar.ButtonHoverBackgroundColor = Colors.IndianRed; - titleBar.ButtonPressedBackgroundColor = Colors.DarkRed; - titleBar.ButtonInactiveBackgroundColor = Colors.Transparent; - titleBar.ButtonInactiveForegroundColor = Colors.Gray; - titleBar.ButtonForegroundColor = Colors.White; - - CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true; - } - } -} diff --git a/FoxTube/Classes/Navigation.cs b/FoxTube/Classes/Navigation.cs deleted file mode 100644 index 3e356a5..0000000 --- a/FoxTube/Classes/Navigation.cs +++ /dev/null @@ -1,64 +0,0 @@ -using FoxTube.Classes; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace FoxTube -{ - public static class Navigation - { - public static void GoToSubscriptions() - { - - } - public static void GoToSettings() - { - - } - public static void GoToUploadPage() - { - - } - public static void GoToSearch(SearchParameters args) - { - - } - - public static void GoToChannel(string id) - { - - } - - public static void GoToHome() - { - - } - - public static void GoToVideo(string id, string playlistId = null, bool incognito = false) - { - - } - - public static void GoToDeveloper(string id) - { - - } - - public static void GoToPlaylist(string id) - { - - } - - public static void GoToHistory() - { - - } - - public static void GoToDownloads() - { - - } - } -} diff --git a/FoxTube/Classes/Processes.cs b/FoxTube/Classes/Processes.cs deleted file mode 100644 index 347a201..0000000 --- a/FoxTube/Classes/Processes.cs +++ /dev/null @@ -1,248 +0,0 @@ -using Microsoft.AppCenter; -using Microsoft.AppCenter.Analytics; -using Microsoft.Services.Store.Engagement; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using Windows.ApplicationModel.Background; -using Windows.ApplicationModel.DataTransfer; -using Windows.ApplicationModel.Resources; -using Windows.Data.Xml.Dom; -using Windows.System; -using Windows.System.Power; -using Windows.UI.Core; -using Windows.UI.Notifications; -using Windows.UI.Popups; -using Windows.UI.Xaml; - -namespace FoxTube.Classes -{ - public static class Processes - { - static CoreWindowActivationState windowState = CoreWindowActivationState.CodeActivated; - static ResourceLoader resources = ResourceLoader.GetForViewIndependentUse("Inbox"); - - static Stopwatch sw = new Stopwatch(); - public static async void InitializeApp() => await CoreWindow.GetForCurrentThread().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => - { - CheckVersion(); - - RegisterToastTask(); - if (Settings.DevNotifications || Settings.VideoNotifications) - RegisterTask(); - else - UnregisterTask(); - - AppCenter.Start("45774462-9ea7-438a-96fc-03982666f39e", typeof(Analytics)); - AppCenter.SetCountryCode(Settings.Region); - - sw.Start(); - - Window.Current.Activated += (s, e) => windowState = e.WindowActivationState; - - // TODO: Initialize other stuff - - if (Settings.ProcessClipboard) - { - Clipboard.ContentChanged += ParseClipboard; - ParseClipboard(); - } - - PromptFeedback(); - }); - - public static void SuspendApp() - { - sw.Stop(); - - Settings.Uptime += sw.Elapsed; - - // TODO: Save other stuff - - Analytics.TrackEvent("Session terminated", new Dictionary - { - { "Uptime", sw.Elapsed.ToString() }, - { "Total time", Settings.Uptime.ToString() } - }); - } - - static async void ParseClipboard(object sender = null, object e = null) - { - if (windowState != CoreWindowActivationState.Deactivated || !Settings.ProcessClipboard) - return; - - try - { - string link = await Clipboard.GetContent().GetTextAsync(); - - if (!link.Contains("youtube") && !link.Contains("youtu.be")) - return; - - string type = string.Empty; - string name = string.Empty; - - if (YoutubeExplode.YoutubeClient.TryParseChannelId(link, out string id)) - { - type = "channel"; - name = (await new YoutubeExplode.YoutubeClient().GetChannelAsync(id)).Title; - } - else if (YoutubeExplode.YoutubeClient.TryParsePlaylistId(link, out id)) - { - type = "playlist"; - name = (await new YoutubeExplode.YoutubeClient().GetPlaylistAsync(id)).Title; - } - else if (YoutubeExplode.YoutubeClient.TryParseUsername(link, out id)) - { - id = await new YoutubeExplode.YoutubeClient().GetChannelIdAsync(id); - type = "channel"; - name = (await new YoutubeExplode.YoutubeClient().GetChannelAsync(id)).Title; - } - else if (YoutubeExplode.YoutubeClient.TryParseVideoId(link, out id)) - { - type = "video"; - name = (await new YoutubeExplode.YoutubeClient().GetVideoAsync(id)).Title; - } - - if (string.IsNullOrWhiteSpace(id)) - return; - - XmlDocument toastXml = new XmlDocument(); - toastXml.LoadXml($@" - - - {resources.GetString("/Toasts/clipboardHead")} - {name} - {resources.GetString($"/Generic/{type}")} - - - - - - "); - ToastNotificationManager.CreateToastNotifier().Show(new ToastNotification(toastXml)); - } - catch { } - } - - static void CheckVersion() - { - if (Settings.GetCurrentVersion() == Settings.Version) - return; - - try - { - XmlDocument toast = new XmlDocument(); - toast.LoadXml($@" - - - - - {resources.GetString("/Inbox/changelog")} - {resources.GetString("/Inbox/whatsNew")} {Settings.GetCurrentVersion()} - - - "); - - ToastNotificationManager.CreateToastNotifier().Show(new ToastNotification(toast)); - - Settings.Version = Settings.GetCurrentVersion(); - } - catch { } - } - - static async void RegisterToastTask() - { - if (BackgroundTaskRegistration.AllTasks.Any(i => i.Value.Name.Equals("foxtubeToast"))) - return; - - var backgroundRequest = await BackgroundExecutionManager.RequestAccessAsync(); - if (backgroundRequest == BackgroundAccessStatus.DeniedBySystemPolicy || - backgroundRequest == BackgroundAccessStatus.DeniedByUser || - backgroundRequest == BackgroundAccessStatus.Unspecified) - return; - - BackgroundTaskBuilder builder = new BackgroundTaskBuilder() { Name = "foxtubeToast" }; - builder.SetTrigger(new ToastNotificationActionTrigger()); - - BackgroundTaskRegistration registration = builder.Register(); - } - - static async void RegisterTask() - { - if (BackgroundTaskRegistration.AllTasks.Any(i => i.Value.Name.Equals("foxtubeBackground"))) - return; - - var backgroundRequest = await BackgroundExecutionManager.RequestAccessAsync(); - if (backgroundRequest == BackgroundAccessStatus.DeniedBySystemPolicy || - backgroundRequest == BackgroundAccessStatus.DeniedByUser || - backgroundRequest == BackgroundAccessStatus.Unspecified || - PowerManager.EnergySaverStatus == EnergySaverStatus.On) - return; - - BackgroundTaskBuilder builder = new BackgroundTaskBuilder() - { - Name = "foxtubeBackgound", - IsNetworkRequested = true, - TaskEntryPoint = "FoxTube.Background.BackgroundProcessor" - }; - builder.SetTrigger(new TimeTrigger(15, false)); - - BackgroundTaskRegistration registration = builder.Register(); - } - - static void UnregisterTask() - { - if (!(BackgroundTaskRegistration.AllTasks.Values.ToList().Find(i => i.Name == "foxtubeBackground") is IBackgroundTaskRegistration task)) - return; - - task.Unregister(true); - } - - static async void PromptFeedback() - { - if (Settings.Uptime.TotalHours >= 12 && Settings.PromptFeedback) - { - Analytics.TrackEvent("Prompting feedback", new Dictionary - { - { "Total uptime", Settings.Uptime.ToString() } - }); - - MessageDialog dialog = new MessageDialog(resources.GetString("/Dialogs/feedbackMessage")); - dialog.Commands.Add(new UICommand(resources.GetString("/Dialogs/dontAsk"), (command) => Settings.PromptFeedback = false)); - dialog.Commands.Add(new UICommand(resources.GetString("/Dialogs/promptLater"))); - dialog.Commands.Add(new UICommand(resources.GetString("/Dialogs/sure"), async (command) => - { - Settings.PromptFeedback = false; - if (StoreServicesFeedbackLauncher.IsSupported()) - await StoreServicesFeedbackLauncher.GetDefault().LaunchAsync(); - else - await Launcher.LaunchUriAsync("mailto:feedback@xfox111.net".ToUri()); - })); - dialog.DefaultCommandIndex = 2; - dialog.CancelCommandIndex = 1; - await dialog.ShowAsync(); - } - - if (Settings.Uptime.TotalHours >= 24 && Settings.PromptReview) - { - Analytics.TrackEvent("Prompting review", new Dictionary - { - { "Total uptime", Settings.Uptime.ToString() } - }); - - MessageDialog dialog = new MessageDialog(resources.GetString("/Dialogs/rate")); - dialog.Commands.Add(new UICommand(resources.GetString("/Dialogs/dontAsk"), (command) => Settings.PromptReview = false)); - dialog.Commands.Add(new UICommand(resources.GetString("/Dialogs/promptLater"))); - dialog.Commands.Add(new UICommand(resources.GetString("/Dialogs/sure"), async (command) => - { - Settings.PromptReview = false; - await Launcher.LaunchUriAsync("ms-windows-store://review/?ProductId=9NCQQXJTDLFH".ToUri()); - })); - dialog.DefaultCommandIndex = 2; - dialog.CancelCommandIndex = 1; - await dialog.ShowAsync(); - } - } - } -} diff --git a/FoxTube/Classes/SearchParameters.cs b/FoxTube/Classes/SearchParameters.cs deleted file mode 100644 index f9c8967..0000000 --- a/FoxTube/Classes/SearchParameters.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace FoxTube.Classes -{ - public class SearchParameters - { - public SearchParameters(string query) - { - - } - } -} diff --git a/FoxTube/Classes/Service.cs b/FoxTube/Classes/Service.cs deleted file mode 100644 index b9178ba..0000000 --- a/FoxTube/Classes/Service.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Net; -using Windows.Services.Store; - -namespace FoxTube -{ - public static class Service - { - public static bool AdsDisabled { get; private set; } = true; - public static event ProVersionStateChangedEventHandler Purchased; - - public static NetworkCredential EmailCredential => new NetworkCredential("foxtube.bot@xfox111.net", "JkY39w$.7?bT57O,8k3a"); - - private static bool TestAds => false; //TODO: Change this bool - public static string AppId => TestAds ? "d25517cb-12d4-4699-8bdc-52040c712cab" : "9ncqqxjtdlfh"; - public static string AdUnitId => TestAds ? "test" : "1100037769"; - - public static async void CheckAddons() - { - try - { - StoreProductQueryResult requset = await StoreContext.GetDefault().GetAssociatedStoreProductsAsync(new[] { "Durable" }); - - if (requset.Products["9NP1QK556625"].IsInUserCollection) - return; - - AdsDisabled = false; - Purchased?.Invoke(false, requset.Products["9NP1QK556625"].Price.FormattedPrice); - } - catch { } - } - - public static async void GetPro() - { - try - { - StorePurchaseResult request = await StoreContext.GetDefault().RequestPurchaseAsync("9NP1QK556625"); - - if (!request.Status.Belongs(StorePurchaseStatus.AlreadyPurchased, StorePurchaseStatus.Succeeded)) - return; - - Purchased?.Invoke(true, ""); - AdsDisabled = true; - } - catch { } - } - } -} diff --git a/FoxTube/Classes/Settings.cs b/FoxTube/Classes/Settings.cs deleted file mode 100644 index f817af8..0000000 --- a/FoxTube/Classes/Settings.cs +++ /dev/null @@ -1,277 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Globalization; -using System.Linq; -using Windows.ApplicationModel; -using Windows.Storage; -using Windows.UI.Xaml.Controls; - -namespace FoxTube.Classes -{ - public static class Settings - { - public class SettingsContainer - { - public string videoQuality = "remember"; - public string rememberedQuality = "1080p"; - - public bool videoNotifications = true; - public bool devNotifications = true; - - public bool checkConnection = true; - public bool autoplay = true; - public double volume = 100; - - public string language = GetLanguage(); - public string relevanceLanguage = CultureInfo.InstalledUICulture.TwoLetterISOLanguageName; - public string region = CultureInfo.InstalledUICulture.Name.Split('-')[1]; - public int safeSearch = 0; - - public bool[] hasAccount = new bool[5] { false, false, false, false, false }; - public int theme = 2; - - public string version = GetCurrentVersion(); - public bool mature = false; - - public TimeSpan uptime = TimeSpan.FromSeconds(0); - public bool promptReview = true; - public bool promptFeedback = true; - - public bool processClipboard = true; - public bool minimizeCommandbar = false; - - public int selectedUser = -1; - - static string GetLanguage() - { - if ((new[] { "ua", "ru", "by", "kz", "kg", "md", "lv", "ee" }).Contains(CultureInfo.InstalledUICulture.TwoLetterISOLanguageName)) - return "ru-RU"; - else - return "en-US"; - } - } - - public static string GetCurrentVersion() - { - PackageVersion ver = Package.Current.Id.Version; - return $"{ver.Major}.{ver.Minor}"; - } - - public static string VideoQuality - { - get => Container.videoQuality; - set - { - Container.videoQuality = value; - SaveData(); - } - } - public static string RememberedQuality - { - get => Container.rememberedQuality; - set - { - Container.rememberedQuality = value; - SaveData(); - } - } - - public static bool VideoNotifications - { - get => Container.videoNotifications; - set - { - Container.videoNotifications = value; - SaveData(); - } - } - public static bool DevNotifications - { - get => Container.devNotifications; - set - { - Container.devNotifications = value; - SaveData(); - } - } - - public static bool CheckConnection - { - get => Container.checkConnection; - set - { - Container.checkConnection = value; - SaveData(); - } - } - public static bool Autoplay - { - get => Container.autoplay; - set - { - Container.autoplay = value; - SaveData(); - } - } - public static double Volume - { - get => Container.volume; - set - { - Container.volume = value; - SaveData(); - } - } - - public static string Language - { - get => Container.language; - set - { - Container.language = value; - SaveData(); - } - } - public static string RelevanceLanguage - { - get => Container.relevanceLanguage; - set - { - Container.relevanceLanguage = value; - SaveData(); - } - } - public static string Region - { - get => Container.region; - set - { - Container.region = value; - SaveData(); - } - } - public static int SafeSearch - { - get => Container.safeSearch; - set - { - Container.safeSearch = value; - SaveData(); - } - } - public static int SelectedUser - { - get => Container.selectedUser; - set - { - Container.selectedUser = value; - SaveData(); - } - } - public static bool[] HasAccount => Container.hasAccount; - public static void SetAccount(int index, bool isAuthorized) - { - HasAccount[index] = isAuthorized; - SaveData(); - } - public static int Theme - { - get => Container.theme; - set - { - Container.theme = value; - SaveData(); - } - } - - public static string Version - { - get => Container.version; - set - { - Container.version = value; - SaveData(); - } - } - public static bool Mature - { - get => Container.mature; - set - { - Container.mature = value; - SaveData(); - } - } - - public static TimeSpan Uptime - { - get => Container.uptime; - set - { - Container.uptime = value; - SaveData(); - } - } - public static bool PromptReview - { - get => Container.promptReview; - set - { - Container.promptReview = value; - SaveData(); - } - } - public static bool PromptFeedback - { - get => Container.promptFeedback; - set - { - Container.promptFeedback = value; - SaveData(); - } - } - - public static bool ProcessClipboard - { - get => Container.processClipboard; - set - { - Container.processClipboard = value; - SaveData(); - } - } - - public static AppBarClosedDisplayMode AppBarClosedMode - { - get => Container.minimizeCommandbar ? AppBarClosedDisplayMode.Minimal : AppBarClosedDisplayMode.Compact; - set - { - Container.minimizeCommandbar = value == AppBarClosedDisplayMode.Minimal; - SaveData(); - } - } - - //Settings storage - static readonly ApplicationDataContainer storage = ApplicationData.Current.RoamingSettings; - static SettingsContainer Container = new SettingsContainer(); - - /// - /// Loads saved settings from storage - /// - public static void LoadData() - { - try - { - Container = JsonConvert.DeserializeObject(storage.Values["settings"] as string); - } - catch - { - Container = new SettingsContainer(); - SaveData(); - } - } - - static void SaveData() => - storage.Values["settings"] = JsonConvert.SerializeObject(Container); - } -} diff --git a/FoxTube/Classes/User.cs b/FoxTube/Classes/User.cs deleted file mode 100644 index 883ef43..0000000 --- a/FoxTube/Classes/User.cs +++ /dev/null @@ -1,328 +0,0 @@ -using Google.Apis.YouTube.v3.Data; -using YoutubeExplode.Models; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Google.Apis.Oauth2.v2.Data; -using YoutubeExplode; -using System.Net.Http; -using Google.Apis.Auth.OAuth2.Responses; -using Newtonsoft.Json; -using Windows.UI.Xaml; -using Windows.UI.Popups; - -namespace FoxTube.Classes -{ - public class User - { - public event SubscriptionChangedEventHandler SubscriptionsChanged; - - public List Subscriptions { get; } = new List(); - - public List WatchLater { get; private set; } - public List WebHistory { get; private set; } - public List AppHistory { get; } - - public Userinfoplus UserInfo { get; private set; } - public TokenResponse Tokens { get; private set; } - - public YoutubeClient YoutubeClient { get; } - - public string AccountId => Channel.Id; - public Google.Apis.YouTube.v3.Data.Channel Channel { get; private set; } - - HttpClient HttpClient { get; } - - DispatcherTimer timer = new DispatcherTimer(); - - public async Task Deauthenticate() => - await HttpClient.GetAsync($"https://accounts.google.com/o/oauth2/revoke?token={Tokens.AccessToken}"); - - public User(TokenResponse tokens) - { - Tokens = tokens; - - HttpClient = new HttpClient(); - HttpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", Tokens.AccessToken); - YoutubeClient = new YoutubeClient(HttpClient); - - timer.Interval = TimeSpan.FromSeconds((int)tokens.ExpiresInSeconds); - timer.Tick += Timer_Tick; - timer.Start(); - } - - async void Timer_Tick(object sender, object e) - { - Tokens = await UserManagement.RefreshToken(); - timer.Interval = TimeSpan.FromSeconds((int)Tokens.ExpiresInSeconds); - timer.Start(); - } - - public async Task Initialize() - { - string responseRaw = await HttpClient.GetStringAsync("https://www.googleapis.com/oauth2/v2/userinfo"); - dynamic response = JsonConvert.DeserializeObject(responseRaw); - - UserInfo = new Userinfoplus - { - Email = this.GuardFromNull((string)response.email), - FamilyName = this.GuardFromNull((string)response.family_name), - Gender = this.GuardFromNull((string)response.gender), - GivenName = this.GuardFromNull((string)response.given_name), - Hd = this.GuardFromNull((string)response.hd), - Id = this.GuardFromNull((string)response.id), - Link = this.GuardFromNull((string)response.link), - Locale = this.GuardFromNull((string)response.locale), - Name = this.GuardFromNull((string)response.name), - Picture = this.GuardFromNull((string)response.picture), - VerifiedEmail = true //As it said in documentation it's always true because it applies to primary e-mail - }; - - string nextToken = null; - do - { - string query = $"https://www.googleapis.com/youtube/v3/subscriptions?part=snippet&maxResults=50&mine=true&order=relevance&access_token={Tokens.AccessToken}{(string.IsNullOrWhiteSpace(nextToken) ? "" : "&pageToken=" + nextToken)}"; - HttpResponseMessage r = await HttpClient.GetAsync(query); - MessageDialog dialog = new MessageDialog(await r.Content.ReadAsStringAsync(), r.StatusCode.ToString()); - await dialog.ShowAsync(); - - responseRaw = await HttpClient.GetStringAsync(query); - response = JsonConvert.DeserializeObject(responseRaw); - nextToken = response.nextPageToken; - foreach (dynamic item in response.items) - Subscriptions.Add(new Subscription - { - Snippet = new SubscriptionSnippet - { - ChannelId = item.channelId, - ChannelTitle = item.channelTitle, - Description = item.description, - PublishedAt = item.publishedAt, - Title = item.title, - Thumbnails = new ThumbnailDetails - { - Default__ = new Thumbnail - { - Height = item.thumbnails["default"].height, - Width = item.thumbnails["default"].width, - Url = item.thumbnails["default"].url, - }, - Medium = new Thumbnail - { - Height = item.thumbnails.medium.height, - Width = item.thumbnails.medium.width, - Url = item.thumbnails.medium.url, - }, - High = new Thumbnail - { - Height = item.thumbnails.high.height, - Width = item.thumbnails.high.width, - Url = item.thumbnails.high.url, - } - }, - ResourceId = new ResourceId - { - ChannelId = item.resourceId.channelId, - Kind = item.resourceId.kind - } - }, - ETag = item.etag, - Id = item.id, - Kind = "youtube#subscription" - }); - } - while (!string.IsNullOrWhiteSpace(nextToken)); - - responseRaw = await HttpClient.GetStringAsync("https://www.googleapis.com/youtube/v3/channels?mine=true&part=contentDetails,snippet,image"); - response = JsonConvert.DeserializeObject(responseRaw); - - Channel = new Google.Apis.YouTube.v3.Data.Channel - { - Kind = "youtube#channel", - ETag = response.items[0].etag, - Id = response.items[0].id, - ContentDetails = new ChannelContentDetails - { - RelatedPlaylists = new ChannelContentDetails.RelatedPlaylistsData - { - Likes = response.items[0].contentDetails.relatedPlaylists.likes, - Favorites = response.items[0].contentDetails.relatedPlaylists.favorites, - Uploads = response.items[0].contentDetails.relatedPlaylists.uploads, - WatchHistory = "HL", - WatchLater = "WL" - } - }, - Snippet = new ChannelSnippet - { - Title = response.items[0].snippet.title, - Description = response.items[0].snippet.description, - CustomUrl = response.items[0].snippet.customUrl, - PublishedAt = response.items[0].snippet.publishedAt, - DefaultLanguage = response.items[0].snippet.defaultLanguage, - Country = response.items[0].snippet.country, - Localized = new ChannelLocalization - { - Description = response.items[0].snippet.localized.description, - Title = response.items[0].snippet.localized.title, - }, - Thumbnails = new ThumbnailDetails - { - Default__ = new Thumbnail - { - Height = response.items[0].snippet.thumbnails["default"].height, - Width = response.items[0].snippet.thumbnails["default"].width, - Url = response.items[0].snippet.thumbnails["default"].url, - }, - Medium = new Thumbnail - { - Height = response.items[0].snippet.thumbnails.medium.height, - Width = response.items[0].snippet.thumbnails.medium.width, - Url = response.items[0].snippet.thumbnails.medium.url, - }, - High = new Thumbnail - { - Height = response.items[0].snippet.thumbnails.high.height, - Width = response.items[0].snippet.thumbnails.high.width, - Url = response.items[0].snippet.thumbnails.high.url, - } - } - }, - BrandingSettings = new ChannelBrandingSettings - { - Channel = new ChannelSettings - { - Country = response.items[0].brandingSettings.channel.country, - DefaultLanguage = response.items[0].brandingSettings.channel.defaultLanguage, - DefaultTab = response.items[0].brandingSettings.channel.defaultTab, - Description = response.items[0].brandingSettings.channel.description, - FeaturedChannelsTitle = response.items[0].brandingSettings.channel.featuredChannelsTitle, - FeaturedChannelsUrls = response.items[0].brandingSettings.channel.featuredChannelsUrls, - Keywords = response.items[0].brandingSettings.channel.keywords, - ModerateComments = response.items[0].brandingSettings.channel.moderateComments, - ProfileColor = response.items[0].brandingSettings.channel.profileColor, - ShowBrowseView = response.items[0].brandingSettings.channel.showBrowseView, - ShowRelatedChannels = response.items[0].brandingSettings.channel.showRelatedChannels, - Title = response.items[0].brandingSettings.channel.title, - TrackingAnalyticsAccountId = response.items[0].brandingSettings.channel.trackingAnalyticsAccountId, - UnsubscribedTrailer = response.items[0].brandingSettings.channel.unsubscribedTrailer - }, - Image = new ImageSettings - { - BannerImageUrl = response.items[0].brandingSettings.image.bannerImageUrl, - BannerMobileImageUrl = response.items[0].brandingSettings.image.bannerMobileImage.Url, - WatchIconImageUrl = response.items[0].brandingSettings.image.watchIconImageUrl, - TrackingImageUrl = response.items[0].brandingSettings.image.trackingImageUrl, - BannerTabletLowImageUrl = response.items[0].brandingSettings.image.bannerTabletLowImageUrl, - BannerTabletImageUrl = response.items[0].brandingSettings.image.bannerTabletImageUrl, - BannerTabletHdImageUrl = response.items[0].brandingSettings.image.bannerTabletHdImageUrl, - BannerTabletExtraHdImageUrl = response.items[0].brandingSettings.image.bannerTabletExtraHdImageUrl, - BannerMobileLowImageUrl = response.items[0].brandingSettings.image.bannerMobileLowImageUrl, - BannerMobileMediumHdImageUrl = response.items[0].brandingSettings.image.bannerMobileMediumHdImageUrl, - BannerMobileHdImageUrl = response.items[0].brandingSettings.image.bannerMobileHdImageUrl, - BannerMobileExtraHdImageUrl = response.items[0].brandingSettings.image.bannerMobileExtraHdImageUrl, - BannerTvLowImageUrl = response.items[0].brandingSettings.image.bannerTvLowImageUrl, - BannerTvImageUrl = response.items[0].brandingSettings.image.bannerTvImageUrl, - BannerTvMediumImageUrl = response.items[0].brandingSettings.image.bannerTvMediumImageUrl, - BannerTvHighImageUrl = response.items[0].brandingSettings.image.bannerTvHighImageUrl, - BannerExternalUrl = response.items[0].brandingSettings.image.bannerExternalUrl - }, - Hints = response.items[0].brandingSettings.hints - } - }; - - - WatchLater = (await YoutubeClient.GetPlaylistAsync("WL")).Videos.ToList(); - WebHistory = (await YoutubeClient.GetPlaylistAsync("HL")).Videos.ToList(); - } - - /// - /// Subscribes or unsibscribes authorized user from the channel - /// - /// The ID of channel which has to be added/removed - /// Returns 'true' if channel is in subscriptions now; 'false' if it's not - public async Task ChangeSubscriptionState(string id) - { - if (Subscriptions.Find(i => i.Snippet.ResourceId.ChannelId == id) is Subscription subscription) - { - try - { - HttpResponseMessage response = await HttpClient.DeleteAsync("https://www.googleapis.com/youtube/v3/subscriptions?id=" + subscription.Id); - if (response.StatusCode != System.Net.HttpStatusCode.NoContent) - return true; - } - catch { return true; } - - SubscriptionsChanged?.Invoke("remove", subscription); - Subscriptions.Remove(subscription); - - return false; - } - else - { - Dictionary body = new Dictionary - { - { "snippet", " { \"resourceId\" : { \"channelId\" : " + id + " } }" } - }; - HttpResponseMessage response = await HttpClient.PostAsync("https://www.googleapis.com/youtube/v3/subscriptions?part=snippet", new FormUrlEncodedContent(body)); - - if (!response.IsSuccessStatusCode) - return false; - - dynamic raw = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - - Subscription sub = new Subscription - { - Snippet = new SubscriptionSnippet - { - ChannelId = raw.channelId, - ChannelTitle = raw.channelTitle, - Description = raw.description, - PublishedAt = raw.publishedAt, - Title = raw.title, - Thumbnails = new ThumbnailDetails - { - Default__ = new Thumbnail - { - Height = raw.thumbnails["default"].height, - Width = raw.thumbnails["default"].width, - Url = raw.thumbnails["default"].url, - }, - Medium = new Thumbnail - { - Height = raw.thumbnails.medium.height, - Width = raw.thumbnails.medium.width, - Url = raw.thumbnails.medium.url, - }, - High = new Thumbnail - { - Height = raw.thumbnails.high.height, - Width = raw.thumbnails.high.width, - Url = raw.thumbnails.high.url, - } - }, - ResourceId = new ResourceId - { - ChannelId = raw.resourceId.channelId, - Kind = raw.resourceId.channelId - } - }, - ETag = raw.etag, - Id = raw.id, - Kind = "youtube#subscription" - }; - - Subscriptions.Add(sub); - SubscriptionsChanged?.Invoke("add", sub); - - return true; - } - } - - public void Dispose() - { - timer.Stop(); - timer.Tick -= Timer_Tick; - } - } -} diff --git a/FoxTube/Classes/UserManagement.cs b/FoxTube/Classes/UserManagement.cs deleted file mode 100644 index 58fd2f7..0000000 --- a/FoxTube/Classes/UserManagement.cs +++ /dev/null @@ -1,173 +0,0 @@ -using FoxTube.Classes; -using Google.Apis.Auth.OAuth2; -using Google.Apis.Auth.OAuth2.Flows; -using Google.Apis.Auth.OAuth2.Responses; -using Google.Apis.Oauth2.v2.Data; -using Google.Apis.Services; -using Google.Apis.YouTube.v3; -using Microsoft.AppCenter.Analytics; -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Windows.Security.Credentials; -using Windows.Storage; -using YoutubeExplode; - -namespace FoxTube -{ - public static class UserManagement - { - static ApplicationDataContainer storage = ApplicationData.Current.LocalSettings; - - public static event AuthorizationChangedEventHandler AuthorizationStateChanged; - public static event SubscriptionChangedEventHandler SubscriptionsChanged; - - static string[] Secrets => new string[5] - { - "1096685398208-bktbnoe59bt69nhnrrb5j0tpld58orsv.apps.googleusercontent.com", - "1096685398208-u4a2pgpcn27c2kb3ud2eck1oh2ot68vs.apps.googleusercontent.com", - "1096685398208-a65ebfpqnhl7u3iipfmfe5cif6j07db3.apps.googleusercontent.com", - "1096685398208-in0gco58ckrumgjuo68st55fvb0ntllj.apps.googleusercontent.com", - "1096685398208-7gd029f6tku4sc756v2338g1f0fu4k2k.apps.googleusercontent.com" - }; - - static YouTubeService NoAuthService { get; } = new YouTubeService(new BaseClientService.Initializer - { - ApiKey = "AIzaSyBgHrCnrlzlVmk0cJKL8RqP9Y8x6XSuk_0", - ApplicationName = "FoxTube" - }); - static YoutubeClient NoAuthClient { get; } = new YoutubeClient(); - - public static YoutubeClient YoutubeClient => Current?.YoutubeClient ?? NoAuthClient; - - public static bool IsAuthorized => Current != null; - - public static User Current { get; set; } - - public static Userinfoplus[] UserInfos { get; private set; } = new Userinfoplus[5]; - static string[] tokens = new string[5]; - - public static async void Initialize() - { - if(storage.Values["users"] != null) - UserInfos = JsonConvert.DeserializeObject(storage.Values["users"] as string); - PasswordVault vault = new PasswordVault(); - foreach (Userinfoplus info in UserInfos) - { - if (info == null) - continue; - PasswordCredential credential = vault.Retrieve("FoxTube", info.Id); - credential.RetrievePassword(); - tokens[UserInfos.ToList().IndexOf(info)] = credential.Password; - } - - if(Settings.SelectedUser >= 0) - { - try { Current = new User(await Authenticator.RefreshToken(Secrets[Settings.SelectedUser], tokens[Settings.SelectedUser])); } - catch { Current = new User(await Authenticator.Authorize(Secrets[Settings.SelectedUser])); } - - await Current.Initialize(); - Current.SubscriptionsChanged += SubscriptionsChanged; - UserInfos[Settings.SelectedUser] = Current.UserInfo; - } - - AuthorizationStateChanged?.Invoke(Settings.SelectedUser > -1); - } - - public static async Task AddItemToWL(string id) - { - - } - - public static async void ChangeAccount(Userinfoplus newUser) - { - Current.Dispose(); - Current.SubscriptionsChanged -= SubscriptionsChanged; - - Current = null; - - Settings.SelectedUser = UserInfos.ToList().IndexOf(newUser); - - try { Current = new User(await Authenticator.RefreshToken(Secrets[Settings.SelectedUser], tokens[Settings.SelectedUser])); } - catch { Current = new User(await Authenticator.Authorize(Secrets[Settings.SelectedUser])); } - - await Current.Initialize(); - Current.SubscriptionsChanged += SubscriptionsChanged; - UserInfos[Settings.SelectedUser] = Current.UserInfo; - - AuthorizationStateChanged?.Invoke(true); - } - - public static async void CreateNew() - { - Analytics.TrackEvent("Initialized authorization sequence"); - try - { - for (int k = 0; k < 5; k++) - if (tokens[k] == null) - { - TokenResponse response = await Authenticator.Authorize(Secrets[k]); - tokens[k] = response.RefreshToken; - Current?.Dispose(); - if (Current != null) - Current.SubscriptionsChanged -= SubscriptionsChanged; - Current = new User(response); - await Current.Initialize(); - Current.SubscriptionsChanged += SubscriptionsChanged; - UserInfos[k] = Current.UserInfo; - - storage.Values["users"] = JsonConvert.SerializeObject(UserInfos); - PasswordVault vault = new PasswordVault(); - vault.Add(new PasswordCredential("FoxTube", Current.UserInfo.Id, response.RefreshToken)); - - Settings.SelectedUser = k; - AuthorizationStateChanged?.Invoke(true); - break; - } - } - catch { } - } - - public static async void Logout() - { - Current.Dispose(); - Current.SubscriptionsChanged -= SubscriptionsChanged; - await Current.Deauthenticate(); - - PasswordVault vault = new PasswordVault(); - vault.Remove(vault.Retrieve("FoxTube", Current.UserInfo.Id)); - UserInfos[Settings.SelectedUser] = null; - tokens[Settings.SelectedUser] = null; - storage.Values["users"] = JsonConvert.SerializeObject(UserInfos); - - Current = null; - - Settings.SelectedUser = -1; - for (int i = 0; i < 5; i++) - if (UserInfos[i] != null) - { - Settings.SelectedUser = i; - break; - } - - if (Settings.SelectedUser >= 0) - { - try { Current = new User(await Authenticator.RefreshToken(Secrets[Settings.SelectedUser], tokens[Settings.SelectedUser])); } - catch { Current = new User(await Authenticator.Authorize(Secrets[Settings.SelectedUser])); } - - await Current.Initialize(); - Current.SubscriptionsChanged += SubscriptionsChanged; - UserInfos[Settings.SelectedUser] = Current.UserInfo; - } - - AuthorizationStateChanged?.Invoke(Settings.SelectedUser > -1); - } - - public static async Task RefreshToken() => - await Authenticator.RefreshToken(Secrets[Settings.SelectedUser], tokens[Settings.SelectedUser]); - } -} diff --git a/FoxTube/Classes/ViewModel.cs b/FoxTube/Classes/ViewModel.cs deleted file mode 100644 index c6aecb1..0000000 --- a/FoxTube/Classes/ViewModel.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Windows.UI.Xaml.Controls; -using Microsoft.UI.Xaml.Controls; - -namespace FoxTube -{ - public class ViewModel : Page - { - public List PivotItems { get; } = new List(); - - public object Parameter { get; private set; } - - public void PivotChanged(int index) { } - } -} diff --git a/FoxTube/Controls/AccountManager.xaml b/FoxTube/Controls/AccountManager.xaml index d5b6908..8e7dcbf 100644 --- a/FoxTube/Controls/AccountManager.xaml +++ b/FoxTube/Controls/AccountManager.xaml @@ -1,83 +1,63 @@ - + xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls" + Style="{StaticResource AppBarButtonRevealStyle}"> - - - - - - - - + + + - - - - - - - - + + + + + + + - + - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FoxTube/Controls/AccountManager.xaml.cs b/FoxTube/Controls/AccountManager.xaml.cs index 2c0081f..d6a9c1e 100644 --- a/FoxTube/Controls/AccountManager.xaml.cs +++ b/FoxTube/Controls/AccountManager.xaml.cs @@ -1,11 +1,8 @@ -using Google.Apis.Oauth2.v2.Data; -using Microsoft.AppCenter.Analytics; -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; -using Windows.ApplicationModel.Resources; using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,86 +11,17 @@ using Windows.UI.Xaml.Controls.Primitives; using Windows.UI.Xaml.Data; using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; -using Windows.UI.Xaml.Media.Imaging; using Windows.UI.Xaml.Navigation; // The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 namespace FoxTube.Controls { - public sealed partial class AccountManager : StackPanel + public sealed partial class AccountManager : AppBarButton { - readonly ResourceLoader resources = ResourceLoader.GetForCurrentView("Main"); - public AccountManager() { InitializeComponent(); - - Service.Purchased += (purchased, price) => - { - removeAds.Visibility = purchased ? Visibility.Collapsed : Visibility.Visible; - removeAds.Content = $"{resources.GetString("/Main/adsFree/Content")} ({price})"; - }; } - - void SignIn_Click(object sender, RoutedEventArgs e) => - UserManagement.CreateNew(); - - void Logout_Click(object sender, RoutedEventArgs e) - { - manager.ContextFlyout.Hide(); - UserManagement.Logout(); - } - - public async void Logged() => await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => - { - account.Visibility = Visibility.Collapsed; - - ToolTipService.SetToolTip(manager, $"{UserManagement.Current.UserInfo.Name} ({UserManagement.Current.UserInfo.Email})"); - name.Text = UserManagement.Current.UserInfo.Name; - email.Text = UserManagement.Current.UserInfo.Email; - banner.Source = new BitmapImage(UserManagement.Current.Channel.BrandingSettings.Image.BannerMobileLowImageUrl.ToUri()); - avatar.ProfilePicture = new BitmapImage(UserManagement.Current.UserInfo.Picture.ToUri()) { DecodePixelHeight = 65, DecodePixelWidth = 65 }; - icon.ProfilePicture = new BitmapImage(UserManagement.Current.UserInfo.Picture.ToUri()) { DecodePixelHeight = 25, DecodePixelWidth = 25 }; - - foreach (Userinfoplus user in UserManagement.UserInfos) - if (user != UserManagement.Current.UserInfo) - accountsList.Items.Add(user); - - manager.Visibility = Visibility.Visible; - }); - - public void Quit() - { - manager.Visibility = Visibility.Collapsed; - account.Visibility = Visibility.Visible; - } - - void Manager_Tapped(object sender, TappedRoutedEventArgs e) => - (sender as Microsoft.UI.Xaml.Controls.NavigationViewItem).ContextFlyout.ShowAt(sender as FrameworkElement); - - void Settings_Click(object sender, RoutedEventArgs e) => - Navigation.GoToSettings(); - - void Settings_Click(object sender, TappedRoutedEventArgs e) => - Navigation.GoToSettings(); - - void RemoveAds_Tapped(object sender, TappedRoutedEventArgs e) => - Service.GetPro(); - - void Upload_Tapped(object sender, TappedRoutedEventArgs e) => - Navigation.GoToUploadPage(); - - void MyChannel_Tapped(object sender, TappedRoutedEventArgs e) => - Navigation.GoToChannel(UserManagement.Current.AccountId); - - void AccountsList_ItemClick(object sender, ItemClickEventArgs e) => - UserManagement.ChangeAccount(e.ClickedItem as Userinfoplus); - - void AddAccount_Tapped(object sender, TappedRoutedEventArgs e) => - UserManagement.CreateNew(); - - void Logout_Tapped(object sender, TappedRoutedEventArgs e) => - UserManagement.Logout(); } } diff --git a/FoxTube/Controls/Cards/AdvertCard.xaml b/FoxTube/Controls/Cards/AdvertCard.xaml new file mode 100644 index 0000000..9567cf9 --- /dev/null +++ b/FoxTube/Controls/Cards/AdvertCard.xaml @@ -0,0 +1,59 @@ + + + + + + diff --git a/FoxTube/Controls/Cards/AdvertCard.xaml.cs b/FoxTube/Controls/Cards/AdvertCard.xaml.cs new file mode 100644 index 0000000..c861c4d --- /dev/null +++ b/FoxTube/Controls/Cards/AdvertCard.xaml.cs @@ -0,0 +1,14 @@ +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; + +namespace FoxTube.Controls.Cards +{ + public sealed partial class AdvertCard : UserControl + { + public AdvertCard() => + InitializeComponent(); + + void UserControl_SizeChanged(object sender, SizeChangedEventArgs e) => + Height = .75 * ActualWidth; + } +} diff --git a/FoxTube/Controls/Cards/ChannelCard.xaml b/FoxTube/Controls/Cards/ChannelCard.xaml new file mode 100644 index 0000000..a7dbe48 --- /dev/null +++ b/FoxTube/Controls/Cards/ChannelCard.xaml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FoxTube/Controls/Cards/ChannelCard.xaml.cs b/FoxTube/Controls/Cards/ChannelCard.xaml.cs new file mode 100644 index 0000000..877930b --- /dev/null +++ b/FoxTube/Controls/Cards/ChannelCard.xaml.cs @@ -0,0 +1,14 @@ +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; + +namespace FoxTube.Controls.Cards +{ + public sealed partial class ChannelCard : UserControl + { + public ChannelCard() => + InitializeComponent(); + + void UserControl_SizeChanged(object sender, SizeChangedEventArgs e) => + Height = .75 * ActualWidth; + } +} diff --git a/FoxTube/Controls/Cards/PlaylistCard.xaml b/FoxTube/Controls/Cards/PlaylistCard.xaml new file mode 100644 index 0000000..07aff01 --- /dev/null +++ b/FoxTube/Controls/Cards/PlaylistCard.xaml @@ -0,0 +1,69 @@ + + + + + + diff --git a/FoxTube/Controls/Cards/PlaylistCard.xaml.cs b/FoxTube/Controls/Cards/PlaylistCard.xaml.cs new file mode 100644 index 0000000..aff5e38 --- /dev/null +++ b/FoxTube/Controls/Cards/PlaylistCard.xaml.cs @@ -0,0 +1,14 @@ +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; + +namespace FoxTube.Controls.Cards +{ + public sealed partial class PlaylistCard : UserControl + { + public PlaylistCard() => + InitializeComponent(); + + void UserControl_SizeChanged(object sender, SizeChangedEventArgs e) => + Height = .75 * ActualWidth; + } +} diff --git a/FoxTube/Controls/Cards/VideoCard.xaml b/FoxTube/Controls/Cards/VideoCard.xaml new file mode 100644 index 0000000..1c71fd6 --- /dev/null +++ b/FoxTube/Controls/Cards/VideoCard.xaml @@ -0,0 +1,96 @@ + + + + + + diff --git a/FoxTube/Controls/Cards/VideoCard.xaml.cs b/FoxTube/Controls/Cards/VideoCard.xaml.cs new file mode 100644 index 0000000..abc82d0 --- /dev/null +++ b/FoxTube/Controls/Cards/VideoCard.xaml.cs @@ -0,0 +1,14 @@ +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; + +namespace FoxTube.Controls.Cards +{ + public sealed partial class VideoCard : UserControl + { + public VideoCard() => + InitializeComponent(); + + void UserControl_SizeChanged(object sender, SizeChangedEventArgs e) => + Height = .75 * ActualWidth; + } +} diff --git a/FoxTube/Controls/ContentFrame.xaml b/FoxTube/Controls/ContentFrame.xaml deleted file mode 100644 index 6b1eb67..0000000 --- a/FoxTube/Controls/ContentFrame.xaml +++ /dev/null @@ -1,220 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -