Merged PR 30: [1.2] Submission #11
- 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 - Updated version number - 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 - Added ability to report videos and comments - Added video categories link to video page and improved search to display video categories - Improved background process - Updated changelog - Updated locales - Patchnotes corrected and updated - Cleanup - Fixed history page refresh button - Fixed video playback problems
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
using Google.Apis.Services;
|
||||
using Google.Apis.Auth.OAuth2;
|
||||
using Google.Apis.Oauth2.v2;
|
||||
using Google.Apis.Services;
|
||||
using Google.Apis.YouTube.v3;
|
||||
using Google.Apis.YouTube.v3.Data;
|
||||
using Newtonsoft.Json;
|
||||
@@ -6,6 +8,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Windows.ApplicationModel.Background;
|
||||
@@ -19,11 +22,6 @@ namespace FoxTube.Background
|
||||
private DateTime lastCheck;
|
||||
private readonly ApplicationDataContainer settings = ApplicationData.Current.RoamingSettings;
|
||||
dynamic prefs;
|
||||
private readonly YouTubeService Service = new YouTubeService(new BaseClientService.Initializer()
|
||||
{
|
||||
ApiKey = "AIzaSyBgHrCnrlzlVmk0cJKL8RqP9Y8x6XSuk_0",
|
||||
ApplicationName = "FoxTube"
|
||||
});
|
||||
BackgroundTaskDeferral def;
|
||||
|
||||
public async void Run(IBackgroundTaskInstance taskInstance)
|
||||
@@ -44,7 +42,7 @@ namespace FoxTube.Background
|
||||
prefs = JsonConvert.DeserializeObject<dynamic>(settings.Values["settings"] as string);
|
||||
if ((bool)prefs.devNotifications)
|
||||
CheckAnnouncements();
|
||||
if ((bool)prefs.videoNotifications)
|
||||
if ((bool)prefs.videoNotifications && (bool)prefs.hasAccount)
|
||||
await CheckAccount();
|
||||
}
|
||||
finally
|
||||
@@ -58,15 +56,59 @@ namespace FoxTube.Background
|
||||
{
|
||||
try
|
||||
{
|
||||
Dictionary<string, string> subscriptions = JsonConvert.DeserializeObject<Dictionary<string, string>>(settings.Values["subscriptions"] as string);
|
||||
UserCredential Credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
|
||||
new ClientSecrets
|
||||
{
|
||||
ClientId = "349735264870-2ekqlm0a4mkg3mmrfcv90s3qp3o15dq0.apps.googleusercontent.com",
|
||||
ClientSecret = "BkVZOAaCU2Zclf0Zlicg6y2_"
|
||||
},
|
||||
new[]
|
||||
{
|
||||
Oauth2Service.Scope.UserinfoProfile,
|
||||
Oauth2Service.Scope.UserinfoEmail,
|
||||
YouTubeService.Scope.YoutubeForceSsl,
|
||||
YouTubeService.Scope.Youtube,
|
||||
YouTubeService.Scope.YoutubeUpload,
|
||||
YouTubeService.Scope.YoutubeReadonly,
|
||||
YouTubeService.Scope.Youtubepartner
|
||||
},
|
||||
"user",
|
||||
CancellationToken.None);
|
||||
|
||||
if (Credential == null)
|
||||
return;
|
||||
|
||||
YouTubeService service = new YouTubeService(new BaseClientService.Initializer
|
||||
{
|
||||
HttpClientInitializer = Credential,
|
||||
ApplicationName = "FoxTube"
|
||||
});
|
||||
|
||||
List<Subscription> subscriptions = new List<Subscription>();
|
||||
List<SearchResult> results = new List<SearchResult>();
|
||||
|
||||
foreach (var s in subscriptions)
|
||||
SubscriptionsResource.ListRequest subRequest = service.Subscriptions.List("snippet");
|
||||
subRequest.Mine = true;
|
||||
subRequest.MaxResults = 50;
|
||||
subRequest.Order = SubscriptionsResource.ListRequest.OrderEnum.Relevance;
|
||||
SubscriptionListResponse subResponse;
|
||||
string nextToken = null;
|
||||
|
||||
do
|
||||
{
|
||||
SearchResource.ListRequest request = Service.Search.List("snippet");
|
||||
subRequest.PageToken = nextToken;
|
||||
subResponse = await subRequest.ExecuteAsync();
|
||||
foreach (Subscription s in subResponse.Items)
|
||||
subscriptions.Add(s);
|
||||
nextToken = subResponse.NextPageToken;
|
||||
|
||||
} while (!string.IsNullOrWhiteSpace(nextToken));
|
||||
|
||||
foreach (Subscription item in subscriptions)
|
||||
{
|
||||
SearchResource.ListRequest request = service.Search.List("snippet");
|
||||
request.PublishedAfter = lastCheck;
|
||||
request.ChannelId = s.Key;
|
||||
request.ChannelId = item.Snippet.ResourceId.ChannelId;
|
||||
request.Type = "video";
|
||||
request.MaxResults = 5;
|
||||
SearchListResponse response = await request.ExecuteAsync();
|
||||
@@ -75,15 +117,15 @@ namespace FoxTube.Background
|
||||
{
|
||||
results.Add(i);
|
||||
|
||||
if(i.Snippet.LiveBroadcastContent == "live")
|
||||
if (i.Snippet.LiveBroadcastContent == "live")
|
||||
ToastNotificationManager.CreateToastNotifier().Show(
|
||||
Notification.GetStreamToast(i.Id.VideoId, i.Snippet.ChannelId, i.Snippet.Title.ConvertEscapeSymbols(), i.Snippet.ChannelTitle, i.Snippet.Thumbnails.Medium.Url, i.Snippet.PublishedAt.Value, s.Value));
|
||||
else if(i.Snippet.LiveBroadcastContent == "upcoming")
|
||||
Notification.GetStreamToast(i.Id.VideoId, i.Snippet.ChannelId, i.Snippet.Title.ConvertEscapeSymbols(), i.Snippet.ChannelTitle, i.Snippet.Thumbnails.Medium.Url, i.Snippet.PublishedAt.Value, item.Snippet.Thumbnails.Default__.Url));
|
||||
else if (i.Snippet.LiveBroadcastContent == "upcoming")
|
||||
ToastNotificationManager.CreateToastNotifier().Show(
|
||||
Notification.GetUpcomingToast(i.Id.VideoId, i.Snippet.ChannelId, i.Snippet.Title.ConvertEscapeSymbols(), i.Snippet.ChannelTitle, i.Snippet.Thumbnails.Medium.Url, i.Snippet.PublishedAt.Value, s.Value));
|
||||
Notification.GetUpcomingToast(i.Id.VideoId, i.Snippet.ChannelId, i.Snippet.Title.ConvertEscapeSymbols(), i.Snippet.ChannelTitle, i.Snippet.Thumbnails.Medium.Url, i.Snippet.PublishedAt.Value, item.Snippet.Thumbnails.Default__.Url));
|
||||
else
|
||||
ToastNotificationManager.CreateToastNotifier().Show(
|
||||
Notification.GetVideoToast(i.Id.VideoId, i.Snippet.ChannelId, i.Snippet.Title.ConvertEscapeSymbols(), i.Snippet.ChannelTitle, i.Snippet.Thumbnails.Medium.Url, i.Snippet.PublishedAt.Value, s.Value));
|
||||
Notification.GetVideoToast(i.Id.VideoId, i.Snippet.ChannelId, i.Snippet.Title.ConvertEscapeSymbols(), i.Snippet.ChannelTitle, i.Snippet.Thumbnails.Medium.Url, i.Snippet.PublishedAt.Value, item.Snippet.Thumbnails.Default__.Url));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +135,7 @@ namespace FoxTube.Background
|
||||
updater.EnableNotificationQueue(true);
|
||||
updater.Clear();
|
||||
for (int i = 0; i < 5 && i < results.Count; i++)
|
||||
updater.Update(Tiles.GetTileLayout(System.Security.SecurityElement.Escape(results[i].Snippet.Title.ConvertEscapeSymbols()), System.Security.SecurityElement.Escape(results[i].Snippet.ChannelTitle), results[i].Snippet.Thumbnails.Medium.Url.Replace("&", "%26"), subscriptions[results[i].Snippet.ChannelId]));
|
||||
updater.Update(Tiles.GetTileLayout(System.Security.SecurityElement.Escape(results[i].Snippet.Title.ConvertEscapeSymbols()), System.Security.SecurityElement.Escape(results[i].Snippet.ChannelTitle), results[i].Snippet.Thumbnails.Medium.Url.Replace("&", "%26"), subscriptions.Find(x => x.Snippet.ResourceId.ChannelId == results[i].Snippet.ChannelId).Snippet.Thumbnails.Medium.Url));
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
<Version>1.29.2.1006</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.AppCenter.Analytics">
|
||||
<Version>1.13.2</Version>
|
||||
<Version>2.1.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
|
||||
<Version>6.2.8</Version>
|
||||
@@ -137,7 +137,7 @@
|
||||
<Version>5.1.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="YoutubeExplode">
|
||||
<Version>4.6.7</Version>
|
||||
<Version>4.7.6</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
|
||||
@@ -16,7 +16,8 @@ namespace FoxTube.Background
|
||||
private static Dictionary<string, string> LoadPack()
|
||||
{
|
||||
dynamic saved = JsonConvert.DeserializeObject<dynamic>(ApplicationData.Current.RoamingSettings.Values["settings"] as string);
|
||||
if (saved.language as string == "ru-RU")
|
||||
string hl = saved.language;
|
||||
if (hl == "ru-RU")
|
||||
return new Dictionary<string, string>()
|
||||
{
|
||||
{ "addLater", "Посмотреть позже" },
|
||||
|
||||
@@ -22,6 +22,8 @@ namespace FoxTube
|
||||
{
|
||||
sealed partial class App : Application
|
||||
{
|
||||
public static string[] AvailableLanguages => new[] { "en-US", "ru-RU" };
|
||||
|
||||
Stopwatch sw = new Stopwatch();
|
||||
public App()
|
||||
{
|
||||
@@ -252,6 +254,20 @@ namespace FoxTube
|
||||
case "dcancel":
|
||||
DownloadAgent.Cancel(args[1]);
|
||||
break;
|
||||
case "clipboard":
|
||||
switch (args[1])
|
||||
{
|
||||
case "video":
|
||||
Methods.MainPage.GoToVideo(args[2]);
|
||||
break;
|
||||
case "channel":
|
||||
Methods.MainPage.GoToChannel(args[2]);
|
||||
break;
|
||||
case "playlist":
|
||||
Methods.MainPage.GoToPlaylist(args[2]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@@ -1,5 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<items>
|
||||
<item time="2019-06-23" version="1.2">
|
||||
<content>
|
||||
<en-US>### 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
|
||||
</en-US>
|
||||
<ru-RU>### Что нового:
|
||||
- Исправлены проблемы с воспроизведением видео
|
||||
- Исправлены некоторые случаи при которых карточки плейлистов не отображались
|
||||
- Исправлены некоторые случай при которых приложение вылетало
|
||||
- Исправлены вылеты приложения при попытке перейти на несуществующий канал/плейлист/видео
|
||||
- Исправлена кнопка обновления на странице истории просмотров
|
||||
- Теперь вы можете помечать комментарии как спам
|
||||
- Теперь вы можете отправлять жалобы на видео
|
||||
- Улучшена проверка новых видео подписок в фоне
|
||||
- Исправлены ошибки в английской локализации
|
||||
</ru-RU>
|
||||
</content>
|
||||
</item>
|
||||
<item time="2019-06-20" version="1.1">
|
||||
<content>
|
||||
<en-US>### 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.
|
||||
</en-US>
|
||||
<ru-RU>### Что нового:
|
||||
- Теперь вы можете помочь нам переводить приложение на новые языки!
|
||||
- Добавлена возможность полностью скрывать панель команд (см. Настройки)
|
||||
- Добавлена функция которая сканирует ваш буфер обмена и, если там есть YouTube-ссылка, предлагает открыть соответствующую страницу в приложении (см. Настройки)
|
||||
- Добавлены дополнительные инструменты аналитики для обнаружения ошибок авторизации
|
||||
- Добавлен ползунок управления скоростью воспроизведения видео (см. Настройки видео)
|
||||
- Теперь показываются тестовая реклама
|
||||
- Исправлены пропуски в сетках
|
||||
- Исправлены некоторые случаи при которых разворачивание видео останавливало/воспроизодило видео
|
||||
- Исправлены пропущенные сообщения из-за несовместимых форматов дат системы
|
||||
- Исправлена невозможность отписаться от канала
|
||||
- Исправлено сворачивание видео с необычными соотношениями сторон
|
||||
- Исправлены некоторые случаи при которых видео продолжало воспроизводиться в фоне после закрытия/обновления страницы видео
|
||||
|
||||
### NB:
|
||||
Поскольку Майкрософт все еще не исправили реальные рекламные баннеры, мне необходимо выпустить тестовые. Это поможет мне оптимизировать процесс доставки рекламы и позволит вам чувствовать себя более комфортно когда будут запущены настоящие. Отзывы приветствуются.
|
||||
</ru-RU>
|
||||
</content>
|
||||
</item>
|
||||
<item time="2019-06-19" version="1.0.1">
|
||||
<content>
|
||||
<en-US>### What's new:
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<items>
|
||||
<item time="2019-02-02" version="0.3">
|
||||
<content>
|
||||
<en-US>### What's new:
|
||||
|
||||
- Small fixes
|
||||
- First public pre-release version
|
||||
- Some content was cut out due to its incompleteness
|
||||
</en-US>
|
||||
<ru-RU>### Что нового:
|
||||
|
||||
- Мелкие исправления багов
|
||||
- Эта версия является первой пред-релизной публичной версией
|
||||
- Некотроые функции были вырезаны из-за их незавершенности
|
||||
</ru-RU>
|
||||
</content>
|
||||
</item>
|
||||
<item time="2019-01-05" version="0.2.19012">
|
||||
<content>
|
||||
<en-US>### 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
|
||||
</en-US>
|
||||
<ru-RU>### Что нового:
|
||||
|
||||
- Кнопка перехода к прямому эфиру на стримах теперь работает
|
||||
- Исправлен баг с длинными именами каналов на карточках
|
||||
- Исправлено исчезание описания видео при изменении размеров окна
|
||||
- Исправлен ползунок перемотки видео
|
||||
- Добавлен индикатор буферизации видео
|
||||
- Мелкие исправления
|
||||
|
||||
### Что по-прежнему не работает:
|
||||
|
||||
- Страница рекомендованных видео и страница видео с подписок
|
||||
- История
|
||||
- Работа с плейлистами
|
||||
- Нет карточек рекламы
|
||||
</ru-RU>
|
||||
</content>
|
||||
</item>
|
||||
</items>
|
||||
@@ -0,0 +1,12 @@
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace FoxTube.Classes
|
||||
{
|
||||
class AdaptiveCommandBar : CommandBar
|
||||
{
|
||||
public AdaptiveCommandBar()
|
||||
{
|
||||
ClosedDisplayMode = SettingsStorage.AppBarClosedMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ namespace FoxTube
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
settings.Values["downloads"] = JsonConvert.SerializeObject(new List<DownloadItemContainer>());
|
||||
Analytics.TrackEvent("Failed to load downloads history", new Dictionary<string, string>
|
||||
{
|
||||
{ "Exception", e.GetType().ToString() },
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using AngleSharp.Dom.Html;
|
||||
using AngleSharp.Parser.Html;
|
||||
using AngleSharp.Html.Dom;
|
||||
using AngleSharp.Html.Parser;
|
||||
using Google.Apis.YouTube.v3.Data;
|
||||
using Microsoft.AppCenter.Analytics;
|
||||
using Newtonsoft.Json.Linq;
|
||||
@@ -141,7 +141,7 @@ namespace FoxTube.Controls.Player
|
||||
HttpClient http = new HttpClient();
|
||||
|
||||
string response = await http.GetStringAsync($"https://youtube.com/watch?v={info.Id}&disable_polymer=true&bpctr=9999999999&hl=en");
|
||||
IHtmlDocument videoEmbedPageHtml = new HtmlParser().Parse(response);
|
||||
IHtmlDocument videoEmbedPageHtml = new HtmlParser().ParseDocument(response);
|
||||
|
||||
string playerConfigRaw = Regex.Match(videoEmbedPageHtml.Source.Text,
|
||||
@"ytplayer\.config = (?<Json>\{[^\{\}]*(((?<Open>\{)[^\{\}]*)+((?<Close-Open>\})[^\{\}]*)+)*(?(Open)(?!))\})")
|
||||
|
||||
@@ -5,6 +5,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Mail;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
@@ -44,7 +45,8 @@ namespace FoxTube
|
||||
|
||||
public static Uri ToUri(this string url)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(url) ? null : new Uri(url);
|
||||
try { return string.IsNullOrWhiteSpace(url) ? null : new Uri(url); }
|
||||
catch { return null; }
|
||||
}
|
||||
|
||||
public static string GuardFromNull(string str)
|
||||
@@ -52,6 +54,20 @@ namespace FoxTube
|
||||
return str ?? string.Empty;
|
||||
}
|
||||
|
||||
public static void SendMail(string content)
|
||||
{
|
||||
MailMessage msg = new MailMessage();
|
||||
msg.To.Add("michael.xfox@outlook.com");
|
||||
msg.From = new MailAddress(SecretsVault.EmailCredential.UserName);
|
||||
msg.Subject = "[Automatic message] FoxTube service message";
|
||||
msg.Body = content;
|
||||
|
||||
SmtpClient client = new SmtpClient("smtp.gmail.com", 587);
|
||||
client.EnableSsl = true;
|
||||
client.Credentials = SecretsVault.EmailCredential;
|
||||
client.Send(msg);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public static string GetChars(this string str, int count)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Google.Apis.YouTube.v3.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static Google.Apis.YouTube.v3.SearchResource.ListRequest;
|
||||
|
||||
@@ -34,11 +35,11 @@ namespace FoxTube
|
||||
case Enumerations.ConversionType.Captions:
|
||||
if (Captions)
|
||||
return VideoCaptionEnum.ClosedCaption;
|
||||
else return null;
|
||||
else return VideoCaptionEnum.Any;
|
||||
case Enumerations.ConversionType.CreativeCommons:
|
||||
if (CreativeCommons)
|
||||
return VideoLicenseEnum.CreativeCommon;
|
||||
else return null;
|
||||
else return VideoLicenseEnum.Any;
|
||||
case Enumerations.ConversionType.Date:
|
||||
switch(Date)
|
||||
{
|
||||
@@ -61,7 +62,7 @@ namespace FoxTube
|
||||
case Enumerations.ConversionType.HD:
|
||||
if (HD)
|
||||
return VideoDefinitionEnum.High;
|
||||
else return null;
|
||||
else return VideoDefinitionEnum.Any;
|
||||
case Enumerations.ConversionType.LiveEvent:
|
||||
if (LiveEvent)
|
||||
return EventTypeEnum.Live;
|
||||
@@ -79,7 +80,7 @@ namespace FoxTube
|
||||
case Enumerations.ConversionType.ThreeD:
|
||||
if (Is3D)
|
||||
return VideoDimensionEnum.Value3d;
|
||||
else return null;
|
||||
else return VideoDimensionEnum.Any;
|
||||
case Enumerations.ConversionType.Type:
|
||||
switch(Type)
|
||||
{
|
||||
@@ -100,6 +101,7 @@ namespace FoxTube
|
||||
|
||||
public string Term { get; private set; }
|
||||
public string Channel { get; private set; }
|
||||
public VideoCategory Category { get; set; }
|
||||
public Filters Filter { get; private set; } = new Filters();
|
||||
|
||||
public SearchParameters(string term)
|
||||
@@ -107,6 +109,13 @@ namespace FoxTube
|
||||
Term = term;
|
||||
}
|
||||
|
||||
public SearchParameters(VideoCategory category)
|
||||
{
|
||||
Category = category;
|
||||
Filter = new Filters();
|
||||
Filter.Type = Filters.Enumerations.Type.Video;
|
||||
}
|
||||
|
||||
public SearchParameters(string term, Filters filters)
|
||||
{
|
||||
Term = term;
|
||||
@@ -119,6 +128,7 @@ namespace FoxTube
|
||||
Channel = channelId;
|
||||
}
|
||||
|
||||
|
||||
public SearchParameters(string term, string channelId, Filters filters)
|
||||
{
|
||||
Term = term;
|
||||
@@ -130,6 +140,7 @@ namespace FoxTube
|
||||
{
|
||||
return $@"Term: {Term}
|
||||
Channel id: {Channel}
|
||||
Category id: {Category}
|
||||
Filters:
|
||||
Order: {Filter.Order}
|
||||
Type: {Filter.Type}
|
||||
@@ -14,6 +14,7 @@ using Google.Apis.Oauth2.v2.Data;
|
||||
using Google.Apis.Oauth2.v2;
|
||||
using static Google.Apis.Auth.OAuth2.UwpCodeReceiver;
|
||||
using Microsoft.AppCenter.Analytics;
|
||||
using System.Net;
|
||||
|
||||
namespace FoxTube
|
||||
{
|
||||
@@ -26,17 +27,18 @@ namespace FoxTube
|
||||
public static event ObjectEventHandler Purchased; //Rising when app finds out that it's not a PRO version
|
||||
|
||||
//Properties
|
||||
private static ClientSecrets Secrets => new ClientSecrets()
|
||||
public static NetworkCredential EmailCredential => new NetworkCredential("mikhailagord@gmail.com", "JkY39w$.7?bT57O,8k3a");
|
||||
private static ClientSecrets Secrets => new ClientSecrets
|
||||
{
|
||||
ClientId = "349735264870-2ekqlm0a4mkg3mmrfcv90s3qp3o15dq0.apps.googleusercontent.com",
|
||||
ClientSecret = "BkVZOAaCU2Zclf0Zlicg6y2_"
|
||||
};
|
||||
private static YouTubeService NoAuthService => new YouTubeService(new BaseClientService.Initializer()
|
||||
private static YouTubeService NoAuthService => new YouTubeService(new BaseClientService.Initializer
|
||||
{
|
||||
ApiKey = "AIzaSyBgHrCnrlzlVmk0cJKL8RqP9Y8x6XSuk_0",
|
||||
ApplicationName = "FoxTube"
|
||||
});
|
||||
public static BaseClientService.Initializer Initializer => new BaseClientService.Initializer()
|
||||
public static BaseClientService.Initializer Initializer => new BaseClientService.Initializer
|
||||
{
|
||||
HttpClientInitializer = Credential,
|
||||
ApplicationName = "FoxTube"
|
||||
@@ -46,7 +48,7 @@ namespace FoxTube
|
||||
public static HttpClient HttpClient { get; } = new HttpClient();
|
||||
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" : "1100044398";
|
||||
public static string AdUnitId => TestAds ? "test" : "1100037769";
|
||||
public static bool AdsDisabled { get; private set; } = true;
|
||||
|
||||
//User info
|
||||
@@ -82,8 +84,10 @@ namespace FoxTube
|
||||
try { await Service.Subscriptions.Delete(s.Id).ExecuteAsync(); }
|
||||
catch { return true; }
|
||||
|
||||
SubscriptionsChanged?.Invoke(null, "remove", s.Snippet.ResourceId.ChannelId);
|
||||
SubscriptionsChanged?.Invoke(null, "remove", s);
|
||||
Subscriptions.Remove(s);
|
||||
|
||||
SaveSubscriptions();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@@ -105,6 +109,8 @@ namespace FoxTube
|
||||
return false;
|
||||
Subscriptions.Add(s);
|
||||
SubscriptionsChanged?.Invoke(null, "add", s);
|
||||
|
||||
SaveSubscriptions();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -207,6 +213,9 @@ namespace FoxTube
|
||||
catch (Exception e)
|
||||
{
|
||||
AuthorizationStateChanged?.Invoke(args: new bool?[] { null });
|
||||
Methods.SendMail($@"Exception: {e.GetType()}
|
||||
Message: {e.Message}
|
||||
Stack trace: {e.StackTrace}");
|
||||
Analytics.TrackEvent("Failed to retrieve user's info", new Dictionary<string, string>
|
||||
{
|
||||
{ "Exception", e.GetType().ToString() },
|
||||
@@ -220,9 +229,11 @@ namespace FoxTube
|
||||
/// Saves user's subscriptions keypairs (channel ID: avatar URL) into "background.json" file for concurrent background processing
|
||||
/// </summary>
|
||||
public static void SaveSubscriptions()
|
||||
{
|
||||
try
|
||||
{
|
||||
Dictionary<string, string> subs = new Dictionary<string, string>();
|
||||
foreach(Subscription i in Subscriptions)
|
||||
foreach (Subscription i in Subscriptions)
|
||||
try
|
||||
{
|
||||
subs.Add(i.Snippet.ResourceId.ChannelId, i.Snippet.Thumbnails.Default__.Url);
|
||||
@@ -240,6 +251,16 @@ namespace FoxTube
|
||||
}
|
||||
ApplicationData.Current.RoamingSettings.Values["subscriptions"] = JsonConvert.SerializeObject(subs);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Analytics.TrackEvent("Failed to write user's subscriptions", new Dictionary<string, string>
|
||||
{
|
||||
{ "Exception", e.GetType().ToString() },
|
||||
{ "Message", e.Message },
|
||||
{ "StackTrace", e.StackTrace }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deauthenticates current user
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Globalization;
|
||||
using System.Linq;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.Storage;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace FoxTube
|
||||
{
|
||||
@@ -23,9 +24,9 @@ namespace FoxTube
|
||||
public bool autoplay = true;
|
||||
public double volume = 100;
|
||||
|
||||
public string language = (new[] { "ua", "ru", "by", "kz", "kg", "md", "lv", "ee" }).Contains(CultureInfo.InstalledUICulture.TwoLetterISOLanguageName) ? "ru-RU" : "en-US";
|
||||
public string relevanceLanguage = (new[] { "ua", "ru", "by", "kz", "kg", "md", "lv", "ee" }).Contains(CultureInfo.InstalledUICulture.TwoLetterISOLanguageName) ? "ru" : "en";
|
||||
public string region = (new[] { "ua", "ru", "by", "kz", "kg", "md", "lv", "ee" }).Contains(CultureInfo.InstalledUICulture.TwoLetterISOLanguageName) ? "ru" : "us";
|
||||
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 = false;
|
||||
@@ -34,6 +35,19 @@ namespace FoxTube
|
||||
public TimeSpan uptime = TimeSpan.FromSeconds(0);
|
||||
public bool promptReview = true;
|
||||
public bool promptFeedback = true;
|
||||
|
||||
public bool processClipboard = true;
|
||||
public bool minimizeCommandbar = false;
|
||||
|
||||
private static string GetLanguage()
|
||||
{
|
||||
if (App.AvailableLanguages.Contains(CultureInfo.InstalledUICulture.Name))
|
||||
return CultureInfo.InstalledUICulture.Name;
|
||||
else if ((new[] { "ua", "ru", "by", "kz", "kg", "md", "lv", "ee" }).Contains(CultureInfo.InstalledUICulture.TwoLetterISOLanguageName))
|
||||
return "ru-RU";
|
||||
else
|
||||
return "en-US";
|
||||
}
|
||||
}
|
||||
|
||||
public static class SettingsStorage
|
||||
@@ -221,6 +235,26 @@ namespace FoxTube
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
private static readonly ApplicationDataContainer storage = ApplicationData.Current.RoamingSettings;
|
||||
private static SettingsContainer Container = new SettingsContainer();
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<UserControl
|
||||
x:Class="FoxTube.Controls.Advert"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ad="using:Microsoft.Advertising.WinRT.UI"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Name="grid" SizeChanged="Grid_SizeChanged">
|
||||
<ad:AdControl VerticalAlignment="Top"
|
||||
Name="ad" ApplicationId="{x:Bind AppId}"
|
||||
AdUnitId="{x:Bind AdUnitId}"
|
||||
Height="50"
|
||||
Width="300"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -1,69 +0,0 @@
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace FoxTube.Controls
|
||||
{
|
||||
public sealed partial class Advert : UserControl
|
||||
{
|
||||
public string AdUnitId { get; set; } = "test";
|
||||
public string AppId => "3f83fe91-d6be-434d-a0ae-7351c5a997f1";
|
||||
public bool OverrideSize { get; set; } = false;
|
||||
|
||||
public new double Height
|
||||
{
|
||||
get { return ad.Height; }
|
||||
set
|
||||
{
|
||||
ad.Height = value;
|
||||
OverrideSize = true;
|
||||
}
|
||||
}
|
||||
|
||||
public new double Width
|
||||
{
|
||||
get { return ad.Width; }
|
||||
set
|
||||
{
|
||||
ad.Width = value;
|
||||
OverrideSize = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Advert()
|
||||
{
|
||||
InitializeComponent();
|
||||
if (!SecretsVault.AdsDisabled)
|
||||
Visibility = Visibility.Visible;
|
||||
else
|
||||
Visibility = Visibility.Collapsed;
|
||||
SecretsVault.Purchased += (s, e) => Visibility = (bool)e[0] ? Visibility.Collapsed : Visibility.Visible;
|
||||
}
|
||||
|
||||
private void Grid_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
if (OverrideSize)
|
||||
return;
|
||||
|
||||
if(grid.ActualWidth >= 728)
|
||||
{
|
||||
ad.Width = 728;
|
||||
ad.Height = 90;
|
||||
}
|
||||
else if (grid.ActualWidth >= 640)
|
||||
{
|
||||
ad.Width = 640;
|
||||
ad.Height = 100;
|
||||
}
|
||||
else if (grid.ActualWidth >= 320)
|
||||
{
|
||||
ad.Width = 320;
|
||||
ad.Height = 50;
|
||||
}
|
||||
else
|
||||
{
|
||||
ad.Width = 300;
|
||||
ad.Height = 50;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Microsoft.Advertising.WinRT.UI;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
using Microsoft.Toolkit.Uwp.UI.Controls;
|
||||
|
||||
namespace FoxTube.Controls.Adverts
|
||||
{
|
||||
@@ -23,6 +24,7 @@ namespace FoxTube.Controls.Adverts
|
||||
|
||||
private void ErrorOccurred(object sender, NativeAdErrorEventArgs e)
|
||||
{
|
||||
(Parent as AdaptiveGridView)?.Items.Remove(this);
|
||||
System.Diagnostics.Debug.WriteLine("Error has occured while loading ad");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Google.Apis.YouTube.v3;
|
||||
using Google.Apis.YouTube.v3.Data;
|
||||
using Microsoft.Toolkit.Uwp.UI.Controls;
|
||||
using System;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
@@ -73,6 +74,7 @@ namespace FoxTube.Controls
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
(Parent as AdaptiveGridView)?.Items.Remove(this);
|
||||
Visibility = Visibility.Collapsed;
|
||||
Microsoft.AppCenter.Analytics.Analytics.TrackEvent("VideoCard loading failed", new System.Collections.Generic.Dictionary<string, string>()
|
||||
{
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
FontFamily="Segoe MDL2 Assets" Text="" FontSize="20"/>
|
||||
<TextBlock Name="rating" Foreground="Gray" VerticalAlignment="Center" Text="123"/>
|
||||
|
||||
<Button Click="showReplies_Click" Name="showReplies" Background="Transparent" Foreground="Gray" Padding="0" Margin="10,0,0,0"
|
||||
<Button Click="showReplies_Click" Name="showReplies" Background="Transparent" Foreground="Gray" Padding="5,0" Margin="5,0"
|
||||
VerticalContentAlignment="Center" HorizontalContentAlignment="Center"
|
||||
Height="35">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
@@ -45,7 +45,7 @@
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<Button Click="replyBtn_Click" Name="replyBtn" Background="Transparent" Foreground="Gray" Padding="0" Margin="10,0,0,0"
|
||||
<Button Click="replyBtn_Click" Name="replyBtn" Background="Transparent" Foreground="Gray" Padding="5,0" Margin="5,0"
|
||||
VerticalContentAlignment="Center" HorizontalContentAlignment="Center"
|
||||
Height="35">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
@@ -54,7 +54,7 @@
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<Button Click="editBtn_Click" Visibility="Collapsed" Name="editBtn" Background="Transparent" Foreground="Gray" Padding="0" Margin="10,0,0,0"
|
||||
<Button Click="editBtn_Click" Visibility="Collapsed" Name="editBtn" Background="Transparent" Foreground="Gray" Padding="5,0" Margin="5,0"
|
||||
VerticalContentAlignment="Center" HorizontalContentAlignment="Center"
|
||||
Height="35">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
@@ -62,6 +62,14 @@
|
||||
<TextBlock x:Uid="/CommentsPage/edit" Text="Edit"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<Button x:Name="spam" Background="Transparent" Foreground="Gray" Padding="5,0" Margin="5,0" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Height="35" Content="⁝">
|
||||
<Button.Flyout>
|
||||
<MenuFlyout>
|
||||
<MenuFlyoutItem x:Uid="/CommentsPage/spam" Icon="Flag" Text="Report as spam" Click="MarkAsSpam_Click"/>
|
||||
</MenuFlyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
|
||||
<Grid Name="replyEditor" Visibility="Collapsed">
|
||||
|
||||
@@ -39,6 +39,7 @@ namespace FoxTube.Controls
|
||||
thread = comment;
|
||||
|
||||
replyBtn.Visibility = comment.Snippet.CanReply.Value && SecretsVault.IsAuthorized ? Visibility.Visible : Visibility.Collapsed;
|
||||
spam.Visibility = SecretsVault.IsAuthorized ? Visibility.Visible : Visibility.Collapsed;
|
||||
if (!comment.Snippet.TotalReplyCount.HasValue || comment.Snippet.TotalReplyCount.Value == 0)
|
||||
showReplies.Visibility = Visibility.Collapsed;
|
||||
else
|
||||
@@ -101,6 +102,7 @@ namespace FoxTube.Controls
|
||||
|
||||
replyBtn.Visibility = Visibility.Collapsed;
|
||||
showReplies.Visibility = Visibility.Collapsed;
|
||||
spam.Visibility = SecretsVault.IsAuthorized ? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
if (comment.Snippet.CanRate == false)
|
||||
{
|
||||
@@ -327,5 +329,17 @@ namespace FoxTube.Controls
|
||||
|
||||
await dialog.ShowAsync();
|
||||
}
|
||||
|
||||
private async void MarkAsSpam_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ResourceLoader resources = ResourceLoader.GetForCurrentView("Report");
|
||||
try { await SecretsVault.Service.Comments.MarkAsSpam(item.Id).ExecuteAsync(); }
|
||||
catch
|
||||
{
|
||||
await new MessageDialog(resources.GetString("/Report/err")).ShowAsync();
|
||||
return;
|
||||
}
|
||||
await new MessageDialog(resources.GetString("/Report/submittedHeader"), resources.GetString("/Report/submittedBody")).ShowAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@ namespace FoxTube
|
||||
|
||||
Slider volume;
|
||||
Slider seek;
|
||||
Slider playbackSpeed;
|
||||
ProgressBar seekIndicator;
|
||||
|
||||
ComboBox captions;
|
||||
@@ -130,6 +131,7 @@ namespace FoxTube
|
||||
|
||||
next.Click += Next_Click;
|
||||
volume.ValueChanged += Volume_ValueChanged;
|
||||
playbackSpeed.ValueChanged += PlaybackSpeed_ValueChanged;
|
||||
live.Click += Live_Click;
|
||||
|
||||
captionsSwitch.Toggled += CaptionsSwitch_Toggled;
|
||||
@@ -142,7 +144,7 @@ namespace FoxTube
|
||||
Rect view = new Rect(0, 0, centerTrigger.ActualWidth, centerTrigger.ActualHeight);
|
||||
Point p = e.GetPosition(centerTrigger);
|
||||
|
||||
if (!view.Contains(p) || e.PointerDeviceType != Windows.Devices.Input.PointerDeviceType.Mouse)
|
||||
if (!view.Contains(p) || e.PointerDeviceType != Windows.Devices.Input.PointerDeviceType.Mouse || State != PlayerDisplayState.Normal)
|
||||
return;
|
||||
|
||||
if (Player.CurrentState == Windows.UI.Xaml.Media.MediaElementState.Playing)
|
||||
@@ -158,6 +160,11 @@ namespace FoxTube
|
||||
base.OnApplyTemplate();
|
||||
}
|
||||
|
||||
private void PlaybackSpeed_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
|
||||
{
|
||||
Player.PlaybackRate = playbackSpeed.Value;
|
||||
}
|
||||
|
||||
void AssignControls()
|
||||
{
|
||||
minimize = GetTemplateChild("MinimizeButton") as Button;
|
||||
@@ -183,6 +190,7 @@ namespace FoxTube
|
||||
|
||||
volume = GetTemplateChild("VolumeSlider") as Slider;
|
||||
seek = GetTemplateChild("ProgressSlider") as Slider;
|
||||
playbackSpeed = GetTemplateChild("PlaybackSpeedSlider") as Slider;
|
||||
seekIndicator = GetTemplateChild("SeekIndicator") as ProgressBar;
|
||||
|
||||
captions = GetTemplateChild("CaptionsSelector") as ComboBox;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Page
|
||||
<UserControl
|
||||
x:Class="FoxTube.Controls.PlaylistCard"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -69,4 +69,4 @@
|
||||
<MenuFlyoutItem x:Uid="/Cards/share" Icon="Share" Text="Share" Name="share" Visibility="Collapsed"/>
|
||||
</MenuFlyout>
|
||||
</UserControl.ContextFlyout>
|
||||
</Page>
|
||||
</UserControl>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Google.Apis.YouTube.v3;
|
||||
using Google.Apis.YouTube.v3.Data;
|
||||
using Microsoft.AppCenter.Analytics;
|
||||
using Microsoft.Toolkit.Uwp.UI.Controls;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
@@ -8,13 +9,14 @@ using Windows.System;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
using YoutubeExplode;
|
||||
|
||||
namespace FoxTube.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Playlist card control
|
||||
/// </summary>
|
||||
public sealed partial class PlaylistCard : Page
|
||||
public sealed partial class PlaylistCard : UserControl
|
||||
{
|
||||
Playlist item;
|
||||
public string playlistId;
|
||||
@@ -45,13 +47,18 @@ namespace FoxTube.Controls
|
||||
ChannelsResource.ListRequest r = SecretsVault.Service.Channels.List("snippet");
|
||||
r.Id = item.Snippet.ChannelId;
|
||||
|
||||
try
|
||||
{
|
||||
thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri());
|
||||
avatar.ProfilePicture = new BitmapImage(new Uri((await r.ExecuteAsync()).Items[0].Snippet.Thumbnails.Medium.Url)) { DecodePixelWidth = 46, DecodePixelHeight = 46 };
|
||||
avatar.ProfilePicture = new BitmapImage((await new YoutubeClient().GetChannelAsync(item.Snippet.ChannelId)).LogoUrl.ToUri()) { DecodePixelWidth = 46, DecodePixelHeight = 46 };
|
||||
}
|
||||
catch { }
|
||||
|
||||
show.Begin();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
(Parent as AdaptiveGridView)?.Items.Remove(this);
|
||||
Visibility = Visibility.Collapsed;
|
||||
Analytics.TrackEvent("PlaylistCard loading failed", new Dictionary<string, string>()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<ContentDialog
|
||||
x:Class="FoxTube.Controls.ReportVideo"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:FoxTube.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
Title="Report a video"
|
||||
PrimaryButtonText="Report"
|
||||
PrimaryButtonClick="ContentDialog_PrimaryButtonClick"
|
||||
IsPrimaryButtonEnabled="False"
|
||||
CloseButtonText="Cancel"
|
||||
DefaultButton="Primary"
|
||||
x:Uid="/Report/report">
|
||||
|
||||
<StackPanel>
|
||||
<ComboBox x:Uid="/Report/reason" x:Name="primaryReason" Header="Reason" PlaceholderText="Select a reason..." SelectionChanged="PrimaryReason_SelectionChanged" Width="300"/>
|
||||
<ComboBox x:Uid="/Report/secondaryReason" x:Name="secondaryReason" PlaceholderText="Select a category..." Visibility="Collapsed" Width="300"/>
|
||||
<TextBox x:Uid="/Report/comment" x:Name="comment" Header="Additional information (optional)" MinHeight="200" AcceptsReturn="True" Margin="0,10"/>
|
||||
</StackPanel>
|
||||
</ContentDialog>
|
||||
@@ -0,0 +1,69 @@
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Google.Apis.YouTube.v3.Data;
|
||||
using Google.Apis.YouTube.v3;
|
||||
using Windows.UI.Xaml;
|
||||
using System;
|
||||
using Windows.UI.Popups;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
|
||||
namespace FoxTube.Controls
|
||||
{
|
||||
public sealed partial class ReportVideo : ContentDialog
|
||||
{
|
||||
string videoId;
|
||||
public ReportVideo(string id)
|
||||
{
|
||||
InitializeComponent();
|
||||
Initialize();
|
||||
videoId = id;
|
||||
}
|
||||
|
||||
async void Initialize()
|
||||
{
|
||||
VideoAbuseReportReasonsResource.ListRequest req = SecretsVault.Service.VideoAbuseReportReasons.List("id,snippet");
|
||||
req.Hl = SettingsStorage.RelevanceLanguage;
|
||||
VideoAbuseReportReasonListResponse reasons = await req.ExecuteAsync();
|
||||
|
||||
foreach (VideoAbuseReportReason i in reasons.Items)
|
||||
primaryReason.Items.Add(new ComboBoxItem
|
||||
{
|
||||
Tag = i,
|
||||
Content = i.Snippet.Label
|
||||
});
|
||||
}
|
||||
|
||||
private async void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
|
||||
{
|
||||
VideoAbuseReport report = new VideoAbuseReport
|
||||
{
|
||||
Comments = Methods.GuardFromNull(comment.Text),
|
||||
VideoId = videoId,
|
||||
ReasonId = ((primaryReason.SelectedItem as ComboBoxItem).Tag as VideoAbuseReportReason).Id,
|
||||
SecondaryReasonId = secondaryReason.SelectedItem == null ? null : (secondaryReason.SelectedItem as ComboBoxItem).Tag as string
|
||||
};
|
||||
|
||||
ResourceLoader resources = ResourceLoader.GetForCurrentView("Report");
|
||||
try { await SecretsVault.Service.Videos.ReportAbuse(report).ExecuteAsync(); }
|
||||
catch
|
||||
{
|
||||
await new MessageDialog(resources.GetString("/Report/err")).ShowAsync();
|
||||
return;
|
||||
}
|
||||
await new MessageDialog(resources.GetString("/Report/submittedHeader"), resources.GetString("/Report/submittedBody")).ShowAsync();
|
||||
}
|
||||
|
||||
private void PrimaryReason_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
IsPrimaryButtonEnabled = true;
|
||||
secondaryReason.Items.Clear();
|
||||
foreach (VideoAbuseReportSecondaryReason i in ((primaryReason.SelectedItem as ComboBoxItem).Tag as VideoAbuseReportReason).Snippet.SecondaryReasons)
|
||||
secondaryReason.Items.Add(new ComboBoxItem
|
||||
{
|
||||
Tag = i.Id,
|
||||
Content = i.Label
|
||||
});
|
||||
|
||||
secondaryReason.Visibility = secondaryReason.Items.Count == 0 ? Visibility.Collapsed : Visibility.Visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ using YoutubeExplode.Models.MediaStreams;
|
||||
using Windows.Foundation;
|
||||
using FoxTube.Pages;
|
||||
using Windows.Networking.Connectivity;
|
||||
using Microsoft.Toolkit.Uwp.UI.Controls;
|
||||
|
||||
namespace FoxTube.Controls
|
||||
{
|
||||
@@ -98,8 +99,12 @@ namespace FoxTube.Controls
|
||||
}
|
||||
LoadAddTo();
|
||||
|
||||
try
|
||||
{
|
||||
thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri());
|
||||
avatar.ProfilePicture = new BitmapImage((await new YoutubeClient().GetChannelAsync(item.Snippet.ChannelId)).LogoUrl.ToUri()) { DecodePixelWidth = 46, DecodePixelHeight = 46 };
|
||||
}
|
||||
catch { }
|
||||
|
||||
if (SecretsVault.History.Contains(item.Id))
|
||||
watched.Visibility = Visibility.Visible;
|
||||
@@ -114,7 +119,10 @@ namespace FoxTube.Controls
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
(Parent as AdaptiveGridView)?.Items.Remove(this);
|
||||
Visibility = Visibility.Collapsed;
|
||||
if (item == null)
|
||||
return;
|
||||
Analytics.TrackEvent("VideoCard loading failed", new Dictionary<string, string>()
|
||||
{
|
||||
{ "Exception", e.GetType().ToString() },
|
||||
|
||||
+31
-13
@@ -20,8 +20,8 @@
|
||||
<PackageCertificateKeyFile>FoxTube_StoreKey.pfx</PackageCertificateKeyFile>
|
||||
<PackageCertificateThumbprint>50B93E6A246058D555BA65CD203D7A02064A7409</PackageCertificateThumbprint>
|
||||
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
|
||||
<AppxAutoIncrementPackageRevision>False</AppxAutoIncrementPackageRevision>
|
||||
<AppxPackageDir>E:\XFox\Documents\FoxTube builds\1.0\</AppxPackageDir>
|
||||
<AppxAutoIncrementPackageRevision>True</AppxAutoIncrementPackageRevision>
|
||||
<AppxPackageDir>E:\XFox\Documents\FoxTube builds\1.1\</AppxPackageDir>
|
||||
<AppxBundle>Always</AppxBundle>
|
||||
<AppxBundlePlatforms>x86|x64|arm</AppxBundlePlatforms>
|
||||
<AppInstallerUpdateFrequency>1</AppInstallerUpdateFrequency>
|
||||
@@ -103,15 +103,13 @@
|
||||
<Compile Include="App.xaml.cs">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Classes\AdaptiveCommandBar.cs" />
|
||||
<Compile Include="Classes\HistorySet.cs" />
|
||||
<Compile Include="Classes\InboxItem.cs" />
|
||||
<Compile Include="Classes\Methods.cs" />
|
||||
<Compile Include="Classes\SearchPaameters.cs" />
|
||||
<Compile Include="Classes\SearchParameters.cs" />
|
||||
<Compile Include="Classes\SettingsStorage.cs" />
|
||||
<Compile Include="Classes\ManifestGenerator.cs" />
|
||||
<Compile Include="Controls\Advert.xaml.cs">
|
||||
<DependentUpon>Advert.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\Adverts\CardAdvert.xaml.cs">
|
||||
<DependentUpon>CardAdvert.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@@ -144,6 +142,9 @@
|
||||
<Compile Include="Controls\PlaylistCard.xaml.cs">
|
||||
<DependentUpon>PlaylistCard.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ReportVideo.xaml.cs">
|
||||
<DependentUpon>ReportVideo.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ShowMore.xaml.cs">
|
||||
<DependentUpon>ShowMore.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@@ -183,6 +184,9 @@
|
||||
<Compile Include="Pages\PlaylistPage.xaml.cs">
|
||||
<DependentUpon>PlaylistPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\SettingsPages\Translate.xaml.cs">
|
||||
<DependentUpon>Translate.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\Subscriptions.xaml.cs">
|
||||
<DependentUpon>Subscriptions.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@@ -220,7 +224,6 @@
|
||||
<Content Include="Assets\BadgeLogo.scale-200.png" />
|
||||
<Content Include="Assets\BadgeLogo.scale-400.png" />
|
||||
<Content Include="Assets\ChannelCoverTemplate.png" />
|
||||
<Content Include="Assets\Data\RevEn.xml" />
|
||||
<Content Include="Assets\Data\Patchnotes.xml" />
|
||||
<Content Include="Assets\FoxGame.png" />
|
||||
<Content Include="Assets\Icons\Profile.png" />
|
||||
@@ -270,6 +273,7 @@
|
||||
<Content Include="Assets\Wide310x150Logo.scale-125.png" />
|
||||
<Content Include="Assets\Wide310x150Logo.scale-150.png" />
|
||||
<Content Include="Assets\Wide310x150Logo.scale-400.png" />
|
||||
<None Include="Assets\Data\Package.zip" />
|
||||
<None Include="FoxTube_StoreKey.pfx" />
|
||||
<None Include="Package.StoreAssociation.xml" />
|
||||
<Content Include="Properties\Default.rd.xml" />
|
||||
@@ -279,16 +283,16 @@
|
||||
<Content Include="Assets\Square44x44Logo.scale-200.png" />
|
||||
<Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
|
||||
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
|
||||
<PRIResource Include="Strings\ru-RU\Report.resw" />
|
||||
<PRIResource Include="Strings\en-US\Report.resw" />
|
||||
<PRIResource Include="Strings\ru-RU\Translate.resw" />
|
||||
<PRIResource Include="Strings\en-US\Translate.resw" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="App.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Page Include="Controls\Advert.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\Adverts\CardAdvert.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
@@ -329,6 +333,10 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\ReportVideo.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\ShowMore.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
@@ -389,6 +397,10 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Pages\SettingsPages\Translate.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Pages\Subscriptions.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
@@ -419,6 +431,9 @@
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AngleSharp">
|
||||
<Version>0.12.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Google.Apis">
|
||||
<Version>1.30.0-beta02</Version>
|
||||
</PackageReference>
|
||||
@@ -438,7 +453,7 @@
|
||||
<Version>10.1811.22001</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.AppCenter.Analytics">
|
||||
<Version>2.0.0</Version>
|
||||
<Version>2.1.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
|
||||
<Version>6.2.8</Version>
|
||||
@@ -458,8 +473,11 @@
|
||||
<PackageReference Include="runtime.win10-arm64.runtime.native.System.IO.Compression">
|
||||
<Version>4.3.2</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.IO.Compression.ZipFile">
|
||||
<Version>4.3.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="YoutubeExplode">
|
||||
<Version>4.7.0</Version>
|
||||
<Version>4.7.6</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" IgnorableNamespaces="uap mp uap3">
|
||||
<Identity Name="53949MichaelXFoxGordeev.FoxTube" Publisher="CN=FD7A34DD-FE4D-4D7D-9D33-2DA9EBBE7725" Version="1.0.1.0" />
|
||||
<Identity Name="53949MichaelXFoxGordeev.FoxTube" Publisher="CN=FD7A34DD-FE4D-4D7D-9D33-2DA9EBBE7725" Version="1.1.0.0" />
|
||||
<mp:PhoneIdentity PhoneProductId="04fd81c1-6473-4174-afd7-4ac71dd85721" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
|
||||
<Properties>
|
||||
<DisplayName>FoxTube</DisplayName>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:pages="using:FoxTube.Pages"
|
||||
xmlns:controls="using:FoxTube.Controls"
|
||||
xmlns:classes="using:FoxTube.Classes"
|
||||
mc:Ignorable="d"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
@@ -95,10 +96,10 @@
|
||||
</Pivot.RightHeader>
|
||||
</Pivot>
|
||||
|
||||
<CommandBar Grid.Row="1" VerticalAlignment="Bottom" Name="commandBar">
|
||||
<classes:AdaptiveCommandBar Grid.Row="1" VerticalAlignment="Bottom" Name="commandBar">
|
||||
<AppBarButton x:Uid="/Channel/openWeb" Icon="Globe" Label="Open in browser" Name="inBrowser" Click="InBrowser_Click"/>
|
||||
<AppBarButton x:Uid="/Channel/refresh" Icon="Refresh" Label="Refresh" Name="refresh" Click="Refresh_Click"/>
|
||||
<AppBarButton x:Uid="/Channel/share" Icon="Share" Label="Share" Name="share" Click="Share_Click"/>
|
||||
</CommandBar>
|
||||
</classes:AdaptiveCommandBar>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
||||
@@ -113,6 +113,12 @@ namespace FoxTube.Pages
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if(item == null)
|
||||
{
|
||||
Methods.MainPage.PageContent.LoadingPage.Error("ChannelNotFound", "Such channel doesn't exist");
|
||||
return;
|
||||
}
|
||||
|
||||
Methods.MainPage.PageContent.LoadingPage.Error(e.GetType().ToString(), e.Message);
|
||||
Analytics.TrackEvent("Channel loading error", new Dictionary<string, string>()
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:foxtube="using:FoxTube"
|
||||
xmlns:controls="using:FoxTube.Controls"
|
||||
xmlns:classes="using:FoxTube.Classes"
|
||||
mc:Ignorable="d"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
@@ -56,9 +57,9 @@
|
||||
</PivotItem>
|
||||
</Pivot>
|
||||
|
||||
<CommandBar Grid.Row="1" DefaultLabelPosition="Right">
|
||||
<classes:AdaptiveCommandBar Grid.Row="1" DefaultLabelPosition="Right">
|
||||
<AppBarButton x:Uid="/Playlist/refresh" Icon="Refresh" Label="Refresh" Name="refresh" Click="Refresh_Click"/>
|
||||
<AppBarButton x:Uid="/Playlist/openWeb" Label="Open in browser" Icon="Globe" Name="toBrowser" Click="toBrowser_Click"/>
|
||||
</CommandBar>
|
||||
</classes:AdaptiveCommandBar>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace FoxTube.Pages
|
||||
|
||||
private void Refresh_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Methods.MainPage.VideoContent.Refresh();
|
||||
Methods.MainPage.PageContent.Refresh();
|
||||
}
|
||||
|
||||
private async void ShowMore_Clicked()
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:pages="using:FoxTube.Pages"
|
||||
xmlns:controls="using:FoxTube.Controls"
|
||||
xmlns:classes="using:FoxTube.Classes"
|
||||
mc:Ignorable="d"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
@@ -54,8 +55,8 @@
|
||||
</PivotItem>
|
||||
</Pivot>
|
||||
|
||||
<CommandBar Grid.Row="1" Name="commandbar">
|
||||
<classes:AdaptiveCommandBar Grid.Row="1" Name="commandbar">
|
||||
<AppBarButton Icon="Refresh" Label="Refresh" x:Uid="/Home/refresh" Click="Refresh_Click"/>
|
||||
</CommandBar>
|
||||
</classes:AdaptiveCommandBar>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
xmlns:ui="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:controls="using:FoxTube.Controls">
|
||||
|
||||
<Grid Name="grid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
<Grid Name="grid">
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup>
|
||||
<VisualState>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Windows.UI;
|
||||
using Windows.UI.ViewManagement;
|
||||
@@ -7,7 +8,6 @@ using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
using System.Xml;
|
||||
using Google.Apis.YouTube.v3.Data;
|
||||
using Windows.ApplicationModel.Core;
|
||||
using Windows.System;
|
||||
@@ -18,6 +18,10 @@ using Microsoft.Services.Store.Engagement;
|
||||
using Windows.UI.Xaml.Shapes;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using FoxTube.Controls;
|
||||
using Microsoft.AppCenter.Analytics;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
using Windows.UI.Notifications;
|
||||
using System.Xml;
|
||||
|
||||
namespace FoxTube
|
||||
{
|
||||
@@ -77,9 +81,77 @@ namespace FoxTube
|
||||
if(StoreServicesFeedbackLauncher.IsSupported())
|
||||
feedback.Visibility = Visibility.Visible;
|
||||
|
||||
if(SettingsStorage.ProcessClipboard)
|
||||
{
|
||||
Clipboard.ContentChanged += ParseClipboard;
|
||||
ParseClipboard(this);
|
||||
}
|
||||
|
||||
PromptFeedback();
|
||||
}
|
||||
|
||||
async void ParseClipboard(object sender = null, object e = null)
|
||||
{
|
||||
if (sender == null && Window.Current.CoreWindow.ActivationMode != Windows.UI.Core.CoreWindowActivationMode.Deactivated)
|
||||
return;
|
||||
try
|
||||
{
|
||||
string link = await Clipboard.GetContent().GetTextAsync();
|
||||
|
||||
if (!link.Contains("youtube") && !link.Contains("youtu.be"))
|
||||
return;
|
||||
|
||||
string id;
|
||||
string type;
|
||||
string name;
|
||||
|
||||
if (YoutubeExplode.YoutubeClient.TryParseChannelId(link, out id))
|
||||
{
|
||||
type = "channel";
|
||||
name = (await new YoutubeExplode.YoutubeClient().GetChannelAsync(id)).Title;
|
||||
goto Complete;
|
||||
}
|
||||
else if (YoutubeExplode.YoutubeClient.TryParsePlaylistId(link, out id))
|
||||
{
|
||||
type = "playlist";
|
||||
name = (await new YoutubeExplode.YoutubeClient().GetPlaylistAsync(id)).Title;
|
||||
goto Complete;
|
||||
}
|
||||
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;
|
||||
goto Complete;
|
||||
}
|
||||
else if (YoutubeExplode.YoutubeClient.TryParseVideoId(link, out id))
|
||||
{
|
||||
type = "video";
|
||||
name = (await new YoutubeExplode.YoutubeClient().GetVideoAsync(id)).Title;
|
||||
goto Complete;
|
||||
}
|
||||
return;
|
||||
|
||||
Complete:
|
||||
Windows.Data.Xml.Dom.XmlDocument toastXml = new Windows.Data.Xml.Dom.XmlDocument();
|
||||
toastXml.LoadXml($@"<toast launch='clipboard|{type}|{id}'>
|
||||
<visual>
|
||||
<binding template='ToastGeneric'>
|
||||
<text>{resources.GetString("/Main/clipboardHead")}</text>
|
||||
<text>{name}</text>
|
||||
<text>{resources.GetString($"/Main/{type}")}</text>
|
||||
</binding>
|
||||
</visual>
|
||||
<actions>
|
||||
<action content='{resources.GetString("/Main/clipboardOpen")}' arguments='clipboard|{type}|{id}'/>
|
||||
</actions>
|
||||
</toast>");
|
||||
ToastNotificationManager.CreateToastNotifier().Show(new ToastNotification(toastXml));
|
||||
return;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
async void PromptFeedback()
|
||||
{
|
||||
if (SettingsStorage.Uptime.TotalHours >= 12 && SettingsStorage.PromptFeedback)
|
||||
@@ -157,9 +229,9 @@ namespace FoxTube
|
||||
break;
|
||||
|
||||
case "remove":
|
||||
if (nav.MenuItems.Find(i => ((i as Microsoft.UI.Xaml.Controls.NavigationViewItem).Content as StackPanel).Tag.ToString() == (string)args[1]) is Microsoft.UI.Xaml.Controls.NavigationViewItem item)
|
||||
if(nav.MenuItems.Contains((Subscription)args[1]))
|
||||
{
|
||||
nav.MenuItems.Remove(item);
|
||||
nav.MenuItems.Remove(args[1]);
|
||||
if (SecretsVault.Subscriptions.Count >= 10)
|
||||
nav.MenuItems.Add(SecretsVault.Subscriptions[9]);
|
||||
}
|
||||
@@ -266,6 +338,7 @@ namespace FoxTube
|
||||
private void SignIn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SecretsVault.Authorize();
|
||||
Analytics.TrackEvent("Initialized authorization sequence");
|
||||
}
|
||||
|
||||
private void Logout_Click(object sender, RoutedEventArgs e)
|
||||
@@ -338,7 +411,7 @@ namespace FoxTube
|
||||
public void MinimizeVideo()
|
||||
{
|
||||
videoPlaceholder.Width = 432;
|
||||
videoPlaceholder.Height = 243;
|
||||
videoPlaceholder.Height = 432 * (videoPlaceholder.Frame.Content as VideoPage).Player.ActualHeight / (videoPlaceholder.Frame.Content as VideoPage).Player.ActualWidth;
|
||||
videoPlaceholder.VerticalAlignment = VerticalAlignment.Bottom;
|
||||
videoPlaceholder.HorizontalAlignment = HorizontalAlignment.Right;
|
||||
videoPlaceholder.Margin = new Thickness(0, 0, 25, 50);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:controls="using:FoxTube.Controls"
|
||||
xmlns:classes="using:FoxTube.Classes"
|
||||
mc:Ignorable="d"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
@@ -76,7 +77,7 @@
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
|
||||
<CommandBar Grid.Row="2">
|
||||
<classes:AdaptiveCommandBar Grid.Row="2">
|
||||
<AppBarButton x:Uid="/Playlist/openWeb" Icon="Globe" Label="Open in browser" Name="inBrowser" Click="inBrowser_Click"/>
|
||||
<AppBarButton x:Uid="/Playlist/addTo" Icon="Add" Label="Add to" IsEnabled="False" Visibility="Collapsed">
|
||||
<AppBarButton.Flyout>
|
||||
@@ -87,6 +88,6 @@
|
||||
</AppBarButton>
|
||||
<AppBarButton x:Uid="/Playlist/refresh" Icon="Refresh" Label="Refresh" Name="refresh" Click="refresh_Click"/>
|
||||
<AppBarButton x:Uid="/Playlist/share" Icon="Share" Label="Share" Name="share" Click="share_Click"/>
|
||||
</CommandBar>
|
||||
</classes:AdaptiveCommandBar>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
||||
@@ -63,8 +63,12 @@ namespace FoxTube.Pages
|
||||
|
||||
channelName.Text = Methods.GuardFromNull(item.Snippet.ChannelTitle);
|
||||
|
||||
avatar.ProfilePicture = new BitmapImage((await new YoutubeExplode.YoutubeClient().GetChannelAsync(item.Snippet.ChannelId)).LogoUrl.ToUri()) { DecodePixelWidth = 50, DecodePixelHeight = 50 };
|
||||
try
|
||||
{
|
||||
thumbnail.Source = new BitmapImage(item.Snippet.Thumbnails.Medium.Url.ToUri());
|
||||
avatar.ProfilePicture = new BitmapImage((await new YoutubeExplode.YoutubeClient().GetChannelAsync(item.Snippet.ChannelId)).LogoUrl.ToUri()) { DecodePixelWidth = 50, DecodePixelHeight = 50 };
|
||||
}
|
||||
catch { }
|
||||
|
||||
request = SecretsVault.Service.PlaylistItems.List("contentDetails");
|
||||
request.PlaylistId = id;
|
||||
@@ -126,6 +130,11 @@ namespace FoxTube.Pages
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
Methods.MainPage.PageContent.LoadingPage.Error("PlaylistNotFound", "Such playlist doesn't exist");
|
||||
return;
|
||||
}
|
||||
Methods.MainPage.PageContent.LoadingPage.Error(e.GetType().ToString(), e.Message);
|
||||
Analytics.TrackEvent("WL playlist loading error", new Dictionary<string, string>()
|
||||
{
|
||||
@@ -148,7 +157,7 @@ namespace FoxTube.Pages
|
||||
|
||||
private void refresh_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Methods.MainPage.VideoContent.Refresh();
|
||||
Methods.MainPage.PageContent.Refresh();
|
||||
}
|
||||
|
||||
private void share_Click(object sender, RoutedEventArgs e)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:controls="using:FoxTube.Controls"
|
||||
xmlns:classes="using:FoxTube.Classes"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Name="grid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
@@ -72,9 +73,9 @@
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<CommandBar Grid.Row="1">
|
||||
<classes:AdaptiveCommandBar Grid.Row="1">
|
||||
<AppBarButton Label="Open in browser" Icon="Globe" Name="inBrowser" Click="InBrowser_Click"/>
|
||||
<AppBarButton Label="Refresh" Icon="Refresh" Click="AppBarButton_Click"/>
|
||||
</CommandBar>
|
||||
</classes:AdaptiveCommandBar>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
||||
@@ -77,12 +77,20 @@ namespace FoxTube
|
||||
{
|
||||
Parameters = arg;
|
||||
request = SecretsVault.Service.Search.List("id,snippet");
|
||||
|
||||
searchTerm.Text = $"{resources.GetString("/Search/header")} '{Parameters.Term}'";
|
||||
if (!string.IsNullOrWhiteSpace(arg.Channel))
|
||||
{
|
||||
request.ChannelId = arg.Channel;
|
||||
(type.Items[2] as ComboBoxItem).Visibility = Visibility.Collapsed;
|
||||
(grid.Children[1] as CommandBar).Visibility = Visibility.Collapsed;
|
||||
}
|
||||
else if (arg.Category != null)
|
||||
{
|
||||
(filters.Children[0] as GridView).Items.Remove(type);
|
||||
searchTerm.Text = $"{resources.GetString("/Search/category")} '{arg.Category.Snippet.Title}'";
|
||||
request.VideoCategoryId = arg.Category.Id;
|
||||
}
|
||||
request.Q = arg.Term;
|
||||
request.SafeSearch = (SearchResource.ListRequest.SafeSearchEnum)SettingsStorage.SafeSearch;
|
||||
|
||||
@@ -101,7 +109,7 @@ namespace FoxTube
|
||||
request.VideoDefinition = (SearchResource.ListRequest.VideoDefinitionEnum)arg.Filter.GetParameter(SearchParameters.Filters.Enumerations.ConversionType.HD);
|
||||
request.VideoDimension = (SearchResource.ListRequest.VideoDimensionEnum)arg.Filter.GetParameter(SearchParameters.Filters.Enumerations.ConversionType.ThreeD);
|
||||
request.VideoCaption = (SearchResource.ListRequest.VideoCaptionEnum)arg.Filter.GetParameter(SearchParameters.Filters.Enumerations.ConversionType.Captions);
|
||||
request.EventType = (SearchResource.ListRequest.EventTypeEnum)arg.Filter.GetParameter(SearchParameters.Filters.Enumerations.ConversionType.LiveEvent);
|
||||
request.EventType = (SearchResource.ListRequest.EventTypeEnum?)arg.Filter.GetParameter(SearchParameters.Filters.Enumerations.ConversionType.LiveEvent);
|
||||
request.VideoLicense = (SearchResource.ListRequest.VideoLicenseEnum)arg.Filter.GetParameter(SearchParameters.Filters.Enumerations.ConversionType.CreativeCommons);
|
||||
}
|
||||
|
||||
@@ -120,7 +128,6 @@ namespace FoxTube
|
||||
features.SelectedItems.Add(features.Items[4]);
|
||||
|
||||
SearchListResponse response = await request.ExecuteAsync();
|
||||
searchTerm.Text = $"{resources.GetString("/Search/header")} '{Parameters.Term}'";
|
||||
resultsCount.Text = $"{resources.GetString("/Search/found")}: {SetResults(response.PageInfo.TotalResults)} {resources.GetString("/Search/items")}";
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(response.NextPageToken))
|
||||
|
||||
@@ -19,6 +19,11 @@
|
||||
<settingspages:About/>
|
||||
</ScrollViewer>
|
||||
</PivotItem>
|
||||
<PivotItem Name="translateTab" Header="Help us translate this app" x:Uid="/Settings/helpTranslate">
|
||||
<ScrollViewer>
|
||||
<settingspages:Translate/>
|
||||
</ScrollViewer>
|
||||
</PivotItem>
|
||||
<PivotItem Name="inboxTab" Header="Inbox" x:Uid="/Settings/inbox">
|
||||
<ScrollViewer>
|
||||
<settingspages:Inbox x:Name="inbox"/>
|
||||
|
||||
@@ -29,6 +29,9 @@ namespace FoxTube
|
||||
case "about":
|
||||
pivot.SelectedItem = aboutTab;
|
||||
break;
|
||||
case "translate":
|
||||
pivot.SelectedItem = translateTab;
|
||||
break;
|
||||
default:
|
||||
inboxId = (string)e.Parameter;
|
||||
pivot.SelectedItem = inboxTab;
|
||||
|
||||
@@ -26,6 +26,10 @@
|
||||
<ComboBoxItem x:Uid="/General/strict" Content="Strict"/>
|
||||
</ComboBox>
|
||||
|
||||
<TextBlock x:Uid="/General/interface" Text="Interface" FontSize="22" Margin="0,10,0,0"/>
|
||||
<ToggleSwitch x:Uid="/General/minimizedCommandBar" Name="minimizedCB" OnContent="Use compact command bar" OffContent="Use minimized command bar" Toggled="MinimizedCB_Toggled"/>
|
||||
<ToggleSwitch x:Uid="/General/clipboardProcessing" x:Name="clipboardProcessing" OnContent="Process youtube links from your clipboard" OffContent="Process youtube links from your clipboard" Toggled="ClipboardProcessing_Toggled"/>
|
||||
|
||||
<TextBlock x:Uid="/General/playback" Text="Playback" FontSize="22" Margin="0,10,0,0"/>
|
||||
<ComboBox x:Uid="/General/quality" Width="250" Header="Default video playback quality" Name="quality" SelectionChanged="quality_SelectionChanged">
|
||||
<ComboBoxItem Tag="remember" x:Uid="/General/remember" Content="Remember my choice"/>
|
||||
|
||||
@@ -27,6 +27,9 @@ namespace FoxTube.Pages.SettingsPages
|
||||
quality.Items.Add(new ComboBoxItem() { Tag = i.GetVideoQualityLabel(), Content = i.GetVideoQualityLabel() });
|
||||
quality.SelectedItem = quality.Items.ToList().Find(i => ((ComboBoxItem)i).Tag.ToString() == SettingsStorage.VideoQuality);
|
||||
|
||||
clipboardProcessing.IsOn = SettingsStorage.ProcessClipboard;
|
||||
minimizedCB.IsOn = SettingsStorage.AppBarClosedMode == AppBarClosedDisplayMode.Minimal;
|
||||
|
||||
mobileWarning.IsOn = SettingsStorage.CheckConnection;
|
||||
autoplay.IsOn = SettingsStorage.Autoplay;
|
||||
|
||||
@@ -152,5 +155,15 @@ namespace FoxTube.Pages.SettingsPages
|
||||
{
|
||||
CoreApplication.Exit();
|
||||
}
|
||||
|
||||
private void MinimizedCB_Toggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SettingsStorage.AppBarClosedMode = minimizedCB.IsOn ? AppBarClosedDisplayMode.Minimal : AppBarClosedDisplayMode.Compact;
|
||||
}
|
||||
|
||||
private void ClipboardProcessing_Toggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SettingsStorage.ProcessClipboard = clipboardProcessing.IsOn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using FoxTube.Classes;
|
||||
using Windows.Storage;
|
||||
using System.Xml;
|
||||
using Microsoft.AppCenter.Analytics;
|
||||
using System.Globalization;
|
||||
|
||||
namespace FoxTube.Pages.SettingsPages
|
||||
{
|
||||
@@ -23,6 +24,14 @@ namespace FoxTube.Pages.SettingsPages
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
string GetLanguage()
|
||||
{
|
||||
if ((new[] { "ua", "ru", "by", "kz", "kg", "md", "lv", "ee" }).Contains(CultureInfo.InstalledUICulture.TwoLetterISOLanguageName))
|
||||
return "ru-RU";
|
||||
else
|
||||
return "en-US";
|
||||
}
|
||||
|
||||
public async void LoadItems(string id = null)
|
||||
{
|
||||
try
|
||||
@@ -34,15 +43,15 @@ namespace FoxTube.Pages.SettingsPages
|
||||
foreach (XmlElement e in doc["items"].ChildNodes)
|
||||
items.Add(new InboxItem(
|
||||
e.GetAttribute("version"),
|
||||
e["content"][SettingsStorage.Language].InnerText,
|
||||
DateTime.Parse(e.GetAttribute("time"))));
|
||||
e["content"][GetLanguage()].InnerText,
|
||||
DateTime.Parse(e.GetAttribute("time"), CultureInfo.GetCultureInfo("en-US").DateTimeFormat)));
|
||||
|
||||
doc.Load("http://foxgame-studio.000webhostapp.com/foxtube-messages.xml");
|
||||
foreach (XmlElement e in doc["posts"].ChildNodes)
|
||||
items.Add(new InboxItem(
|
||||
e["header"][SettingsStorage.Language].InnerText,
|
||||
e["content"][SettingsStorage.Language].InnerText,
|
||||
DateTime.Parse(e.GetAttribute("time")),
|
||||
e["header"][GetLanguage()].InnerText,
|
||||
e["content"][GetLanguage()].InnerText,
|
||||
DateTime.Parse(e.GetAttribute("time"), CultureInfo.GetCultureInfo("en-US").DateTimeFormat),
|
||||
e["id"].InnerText,
|
||||
e["contentHeader"].InnerText));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
<Page
|
||||
x:Class="FoxTube.Pages.SettingsPages.Translate"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:globalization="using:System.Globalization"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
<StackPanel Orientation="Vertical" Margin="10">
|
||||
<TextBlock x:Uid="/Translate/header" Text="Help us translate this app" FontSize="28"/>
|
||||
<TextBlock x:Uid="/Translate/description" TextWrapping="WrapWholeWords" Text="You can help us make this app even better by contributing to its development by translating this app" Margin="0,0,0,10"/>
|
||||
<TextBlock x:Uid="/Translate/guide0" Text="It's quite simple:" Margin="0,0,0,10"/>
|
||||
|
||||
<ComboBox x:Uid="/Translate/guide1" Header="1. Choose language you want to translate" PlaceholderText="Choose language..." Name="LangList" Margin="0,0,0,10" MinWidth="350" SelectionChanged="LangList_SelectionChanged">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="globalization:CultureInfo">
|
||||
<TextBlock Text="{Binding DisplayName}" Tag="{Binding ThreeLetterISOLanguageName}"/>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<TextBlock x:Uid="/Translate/guide2" Text="2. Save language pack file to your PC" Margin="0,0,0,10"/>
|
||||
|
||||
<Button x:Uid="/Translate/export" Content="Export to PC (.zip)" Margin="0,0,0,10" Name="export" Click="export_Click" IsEnabled="False"/>
|
||||
|
||||
<TextBlock x:Uid="/Translate/guide3" TextWrapping="WrapWholeWords" Text="3. Open archive's files with any text editor you want (Notepad, Wordpad, Notepad++, VS Code, etc.)" Margin="0,0,0,10"/>
|
||||
<TextBlock x:Uid="/Translate/guide4" TextWrapping="WrapWholeWords" Text="4. Edit file by translating nececcary words and sentences" Margin="0,0,0,10"/>
|
||||
<TextBlock x:Uid="/Translate/guide5" TextWrapping="WrapWholeWords" Text="5. Upload final package to our servers" Margin="0,0,0,10"/>
|
||||
|
||||
<StackPanel Name="submitNotification" Visibility="Collapsed" BorderThickness="2" BorderBrush="OrangeRed" Width="350" HorizontalAlignment="Left" Margin="0,0,0,10" Padding="0,0,0,3">
|
||||
<TextBlock Foreground="OrangeRed" FontWeight="SemiBold" Text="Attention! Once you submitted this language pack you won't be able to contribute to the language anymore. Think twice before continuing" TextWrapping="WrapWholeWords" Margin="5"/>
|
||||
</StackPanel>
|
||||
|
||||
<Button x:Uid="/Translate/upload" Content="Choose file to upload" Margin="-1,0,0,10" HorizontalAlignment="Left" VerticalAlignment="Top" Name="upload" IsEnabled="False" Click="upload_Click"/>
|
||||
|
||||
<Border Background="{ThemeResource SystemChromeMediumLowColor}" CornerRadius="10" Padding="10" HorizontalAlignment="Left" Name="certification" Visibility="Collapsed">
|
||||
<StackPanel>
|
||||
<TextBlock x:Uid="/Translate/certHeader" FontWeight="Bold" Text="Package certification result"/>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="0,5" Name="certificationStatus">
|
||||
<FontIcon Glyph="" Foreground="Green"/>
|
||||
<TextBlock Text="Passed" Margin="5,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Visibility="Visible">
|
||||
<Button x:Uid="/Translate/submit" Content="Upload" Name="submit" Click="Submit_Click"/>
|
||||
<Button x:Uid="/Translate/log" Content="View log" Name="log" Click="Log_Click"/>
|
||||
<Button x:Uid="/Translate/choose" Content="Choose another file" Margin="10,0,0,0" Name="chooseFile" Click="upload_Click"/>
|
||||
</StackPanel>
|
||||
<ProgressBar HorizontalAlignment="Stretch" IsIndeterminate="True" Name="uploadingProgress" Visibility="Visible"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<TextBlock x:Uid="/Translate/info" TextWrapping="WrapWholeWords">
|
||||
It takes about 2-3 weeks to process new language pack and include it to the next updateThank you for your help 😚<LineBreak/>
|
||||
Best wishes,</TextBlock>
|
||||
<TextBlock Text=" XFox"/>
|
||||
<StackPanel Orientation="Horizontal" BorderBrush="Green" BorderThickness="5" Margin="0,10,30,0" Visibility="Collapsed" Name="greenResult">
|
||||
<TextBlock FontFamily="Segoe MDL2 Assets" Text="" FontSize="40" Foreground="Green" Margin="5"/>
|
||||
<StackPanel>
|
||||
<TextBlock x:Uid="/Translate/success" Text="Your language pack has been sent!" Foreground="Green" FontWeight="Bold" FontSize="20"/>
|
||||
<TextBlock x:Uid="/Translate/successSub" Text="Thank you! It's very imortant for us. You help us making the app better" Foreground="Green"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Page>
|
||||
@@ -0,0 +1,224 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.Storage.Pickers;
|
||||
using Windows.Storage;
|
||||
using System.Net.Mail;
|
||||
using Windows.UI.Popups;
|
||||
using Windows.System;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI;
|
||||
using System.IO.Compression;
|
||||
using System.Xml;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
|
||||
namespace FoxTube.Pages.SettingsPages
|
||||
{
|
||||
public sealed partial class Translate : Page
|
||||
{
|
||||
//TODO: Localize page
|
||||
ResourceLoader resources = ResourceLoader.GetForCurrentView("Translate");
|
||||
StorageFile submission;
|
||||
public Translate()
|
||||
{
|
||||
InitializeComponent();
|
||||
foreach (CultureInfo culture in CultureInfo.GetCultures(CultureTypes.AllCultures))
|
||||
if (culture.ThreeLetterISOLanguageName != "rus" && culture.ThreeLetterISOLanguageName != "eng" && culture.IsNeutralCulture)
|
||||
LangList.Items.Add(culture);
|
||||
}
|
||||
|
||||
private async void export_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
FileSavePicker picker = new FileSavePicker();
|
||||
picker.CommitButtonText = resources.GetString("/Translate/exportPicker");
|
||||
picker.DefaultFileExtension = ".zip";
|
||||
picker.SuggestedFileName = "foxtube_langpack_" + ((CultureInfo)LangList.SelectedItem).ThreeLetterISOLanguageName;
|
||||
picker.SuggestedStartLocation = PickerLocationId.Desktop;
|
||||
picker.FileTypeChoices.Add(resources.GetString("/Translate/langpackScheme"), new List<string>() { ".zip" });
|
||||
|
||||
StorageFile file = await picker.PickSaveFileAsync();
|
||||
if (file == null)
|
||||
return;
|
||||
|
||||
await (await StorageFile.GetFileFromApplicationUriAsync("ms-appx:///Assets/Data/Package.zip".ToUri())).CopyAndReplaceAsync(file);
|
||||
|
||||
await Launcher.LaunchFileAsync(file);
|
||||
}
|
||||
|
||||
private void LangList_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
greenResult.Visibility = Visibility.Collapsed;
|
||||
certification.Visibility = Visibility.Collapsed;
|
||||
upload.Visibility = Visibility.Visible;
|
||||
|
||||
upload.IsEnabled = true;
|
||||
export.IsEnabled = true;
|
||||
}
|
||||
|
||||
private async void upload_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
FileOpenPicker picker = new FileOpenPicker()
|
||||
{
|
||||
CommitButtonText = resources.GetString("/Translate/submit/Content"),
|
||||
SuggestedStartLocation = PickerLocationId.Desktop
|
||||
};
|
||||
picker.FileTypeFilter.Clear();
|
||||
picker.FileTypeFilter.Add(".zip");
|
||||
|
||||
StorageFile file = await picker.PickSingleFileAsync();
|
||||
if (file == null)
|
||||
return;
|
||||
|
||||
export.IsEnabled = false;
|
||||
upload.Visibility = Visibility.Collapsed;
|
||||
certification.Visibility = Visibility.Visible;
|
||||
|
||||
(certificationStatus.Children[0] as FontIcon).Glyph = "\xECC5";
|
||||
(certificationStatus.Children[0] as FontIcon).Foreground = new SolidColorBrush(Colors.Orange);
|
||||
(certificationStatus.Children[1] as TextBlock).Text = resources.GetString("/Translate/inprogress");
|
||||
|
||||
submit.IsEnabled = log.IsEnabled = chooseFile.IsEnabled = true;
|
||||
submit.Visibility = Visibility.Collapsed;
|
||||
log.Visibility = Visibility.Collapsed;
|
||||
chooseFile.Visibility = Visibility.Collapsed;
|
||||
uploadingProgress.Visibility = Visibility.Visible;
|
||||
|
||||
CertificationReport report = await PerformCetification(file);
|
||||
if (report.Status == CertificationReport.CertificationStatus.Failed)
|
||||
{
|
||||
(certificationStatus.Children[0] as FontIcon).Glyph = "\xEB90";
|
||||
(certificationStatus.Children[0] as FontIcon).Foreground = new SolidColorBrush(Colors.Red);
|
||||
(certificationStatus.Children[1] as TextBlock).Text = resources.GetString("/Translate/failed");
|
||||
chooseFile.Visibility = Visibility.Visible;
|
||||
log.Visibility = Visibility.Visible;
|
||||
log.Tag = report.Report;
|
||||
export.IsEnabled = true;
|
||||
uploadingProgress.Visibility = Visibility.Collapsed;
|
||||
return;
|
||||
}
|
||||
|
||||
submission = file;
|
||||
|
||||
(certificationStatus.Children[0] as FontIcon).Glyph = "\xEC61";
|
||||
(certificationStatus.Children[0] as FontIcon).Foreground = new SolidColorBrush(Colors.Green);
|
||||
(certificationStatus.Children[1] as TextBlock).Text = resources.GetString("/Translate/passed");
|
||||
|
||||
export.IsEnabled = true;
|
||||
submit.Visibility = Visibility.Visible;
|
||||
chooseFile.Visibility = Visibility.Visible;
|
||||
uploadingProgress.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
async Task<CertificationReport> PerformCetification(StorageFile file)
|
||||
{
|
||||
CertificationReport report = new CertificationReport { Status = CertificationReport.CertificationStatus.Passed };
|
||||
|
||||
string log = string.Empty;
|
||||
StorageFolder folder = await ApplicationData.Current.RoamingFolder.CreateFolderAsync("Package certification");
|
||||
StorageFile submissionSample = await folder.CreateFileAsync("sample.zip");
|
||||
await file.CopyAndReplaceAsync(submissionSample);
|
||||
ZipFile.ExtractToDirectory(submissionSample.Path, folder.Path);
|
||||
|
||||
List<string> filesDescriptions = new List<string>
|
||||
{
|
||||
"About", "Cards", "Channel", "Chat", "CommentsPage", "Downloads", "General", "Home", "Inbox",
|
||||
"LoadingPage", "Main", "Methods", "Playlist", "Search", "Settings", "Translate", "VideoPage"
|
||||
};
|
||||
|
||||
foreach(string i in filesDescriptions)
|
||||
if (await folder.TryGetItemAsync($"{i}.resw") == null)
|
||||
{
|
||||
log += $"- {resources.GetString("/Translate/file")} '{i}.resw' {resources.GetString("/Translate/notfound")}\n";
|
||||
report.Status = CertificationReport.CertificationStatus.Failed;
|
||||
}
|
||||
else
|
||||
{
|
||||
try { new XmlDocument().Load(await (await folder.GetFileAsync(i + ".resw")).OpenStreamForReadAsync()); }
|
||||
catch
|
||||
{
|
||||
log += $"- {resources.GetString("/Translate/file")} '{i}.resw': {resources.GetString("/Translate/failedRead")}";
|
||||
report.Status = CertificationReport.CertificationStatus.Failed;
|
||||
}
|
||||
}
|
||||
|
||||
if(report.Status == CertificationReport.CertificationStatus.Failed)
|
||||
{
|
||||
report.Report = await ApplicationData.Current.RoamingFolder.CreateFileAsync("certReport.txt", CreationCollisionOption.ReplaceExisting);
|
||||
await FileIO.WriteTextAsync(report.Report, log);
|
||||
}
|
||||
|
||||
await folder.DeleteAsync(StorageDeleteOption.PermanentDelete);
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
private async void Log_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await Launcher.LaunchFileAsync(((Button)sender).Tag as StorageFile);
|
||||
}
|
||||
|
||||
private async void Submit_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
uploadingProgress.Visibility = Visibility.Visible;
|
||||
submit.IsEnabled = false;
|
||||
chooseFile.IsEnabled = false;
|
||||
|
||||
MailMessage msg = new MailMessage();
|
||||
msg.To.Add("michael.xfox@outlook.com");
|
||||
msg.From = new MailAddress(SecretsVault.EmailCredential.UserName, "FoxTube Automatic response system");
|
||||
msg.Subject = "[Automatic message] FoxTube language pack contribution";
|
||||
msg.Body = $@"Language: {((CultureInfo)LangList.SelectedItem).EnglishName}
|
||||
Language code: {((CultureInfo)LangList.SelectedItem).ThreeLetterISOLanguageName}
|
||||
-----------------
|
||||
Contributor info:
|
||||
Username: {(SecretsVault.UserInfo == null ? "/UNAUTHORIZED_USER/" : SecretsVault.UserInfo.Name)}
|
||||
E-mail: {(SecretsVault.UserInfo == null ? "/UNAUTHORIZED_USER/" : SecretsVault.UserInfo.Email)}";
|
||||
msg.Attachments.Add(new Attachment(await submission.OpenStreamForReadAsync(), "submission.zip"));
|
||||
|
||||
SmtpClient client = new SmtpClient("smtp.gmail.com", 587);
|
||||
client.EnableSsl = true;
|
||||
client.Credentials = SecretsVault.EmailCredential;
|
||||
|
||||
upload.IsEnabled = false;
|
||||
export.IsEnabled = false;
|
||||
uploadingProgress.Visibility = Visibility.Visible;
|
||||
try
|
||||
{
|
||||
client.Send(msg);
|
||||
if(!string.IsNullOrWhiteSpace(SecretsVault.UserInfo.Email))
|
||||
{
|
||||
msg = new MailMessage();
|
||||
msg.To.Add(SecretsVault.UserInfo.Email);
|
||||
msg.From = new MailAddress(SecretsVault.EmailCredential.UserName, resources.GetString("/Translate/username"));
|
||||
msg.Subject = resources.GetString("/Translate/subject");
|
||||
msg.Body = $@"{SecretsVault.UserInfo.Name},
|
||||
{resources.GetString("/Translate/body")}";
|
||||
client.Send(msg);
|
||||
}
|
||||
greenResult.Visibility = Visibility.Visible;
|
||||
submitNotification.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
catch
|
||||
{
|
||||
MessageDialog message = new MessageDialog(resources.GetString("/Translate/failedSend/Body"), resources.GetString("/Translate/failedSend/Header"));
|
||||
await message.ShowAsync();
|
||||
export.IsEnabled = true;
|
||||
upload.IsEnabled = true;
|
||||
submit.IsEnabled = true;
|
||||
chooseFile.IsEnabled = true;
|
||||
}
|
||||
uploadingProgress.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
public class CertificationReport
|
||||
{
|
||||
public enum CertificationStatus { Passed, Failed, Processing }
|
||||
public CertificationStatus Status { get; set; }
|
||||
public StorageFile Report { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:pages="using:FoxTube.Pages"
|
||||
xmlns:classes="using:FoxTube.Classes"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Name="grid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" SizeChanged="grid_SizeChanged">
|
||||
@@ -28,7 +29,12 @@
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="400"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ScrollViewer Margin="0,0,0,50" Name="mainScroll" VerticalScrollBarVisibility="Hidden">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<ScrollViewer Name="mainScroll" VerticalScrollBarVisibility="Hidden">
|
||||
<StackPanel Name="mainContent">
|
||||
<Border BorderBrush="Red" BorderThickness="5" CornerRadius="10" Margin="10" Name="upcoming" Visibility="Collapsed">
|
||||
<Grid Margin="10">
|
||||
@@ -60,7 +66,7 @@
|
||||
<StackPanel Margin="0,10">
|
||||
<Button FontFamily="Segoe UI, Segoe MDL2 Assets" Content=" Continue from: 00:10:37" Name="left" Click="Left_Click" Visibility="Collapsed"/>
|
||||
<TextBlock IsTextSelectionEnabled="True" Name="title" Text="[Video title]" FontSize="25" TextWrapping="WrapWholeWords" HorizontalTextAlignment="Start"/>
|
||||
<TextBlock Text="Published at: " Name="date"/>
|
||||
<TextBlock Text="Published at: " Name="meta"/>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
@@ -104,7 +110,7 @@
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<CommandBar VerticalAlignment="Bottom" Name="commandbar">
|
||||
<classes:AdaptiveCommandBar Grid.Row="1" VerticalAlignment="Bottom" x:Name="commandbar">
|
||||
<AppBarButton x:Uid="/VideoPage/download" Icon="Download" Label="Download video" Name="download">
|
||||
<AppBarButton.Flyout>
|
||||
<MenuFlyout x:Name="downloadSelector"/>
|
||||
@@ -122,7 +128,12 @@
|
||||
<AppBarButton x:Uid="/VideoPage/refresh" Name="refresh" Click="refresh_Click" Icon="Refresh" Label="Refresh page"/>
|
||||
<AppBarButton x:Uid="/VideoPage/share" Name="share" Click="share_Click" Icon="Share" Label="Share"/>
|
||||
<AppBarButton x:Uid="/VideoPage/openWeb" Name="openBrowser" Click="openBrowser_Click" Icon="Globe" Label="Open in browser"/>
|
||||
</CommandBar>
|
||||
|
||||
<classes:AdaptiveCommandBar.SecondaryCommands>
|
||||
<AppBarButton x:Uid="/VideoPage/report" Icon="Flag" x:Name="report" Label="Report this video" Click="Report_Click"/>
|
||||
</classes:AdaptiveCommandBar.SecondaryCommands>
|
||||
</classes:AdaptiveCommandBar>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Column="1" Name="tabsPlaceholder">
|
||||
<Pivot Name="pivot" SelectedIndex="0" IsHeaderItemsCarouselEnabled="False">
|
||||
|
||||
@@ -14,6 +14,7 @@ using Windows.System;
|
||||
using Windows.UI;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Documents;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
@@ -95,6 +96,12 @@ namespace FoxTube.Pages
|
||||
Initialize(e.Parameter as object[]);
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedFrom(e);
|
||||
Player.Player.Stop();
|
||||
}
|
||||
|
||||
public async void Initialize(object[] ids)
|
||||
{
|
||||
try
|
||||
@@ -130,6 +137,12 @@ namespace FoxTube.Pages
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
Methods.MainPage.PageContent.LoadingPage.Error("VideoNotFound", "Such video doesn't exist");
|
||||
return;
|
||||
}
|
||||
|
||||
Methods.MainPage.VideoContent.LoadingPage.Error(e.GetType().ToString(), e.Message);
|
||||
Analytics.TrackEvent("Video loading error", new Dictionary<string, string>()
|
||||
{
|
||||
@@ -246,7 +259,32 @@ namespace FoxTube.Pages
|
||||
{
|
||||
//Setting meta
|
||||
title.Text = item.Snippet.Localized.Title;
|
||||
date.Text = $"{resources.GetString("/VideoPage/publishedAt")}: {item.Snippet.PublishedAt} ({Methods.GetAgo(item.Snippet.PublishedAt.Value)})";
|
||||
meta.Text = "";
|
||||
meta.Inlines.Add(new Run
|
||||
{
|
||||
Text = $"{resources.GetString("/VideoPage/publishedAt")}: {item.Snippet.PublishedAt} ({Methods.GetAgo(item.Snippet.PublishedAt.Value)})"
|
||||
});
|
||||
if(!string.IsNullOrWhiteSpace(item.Snippet.CategoryId))
|
||||
{
|
||||
VideoCategoriesResource.ListRequest request = SecretsVault.Service.VideoCategories.List("snippet,id");
|
||||
request.Id = item.Snippet.CategoryId;
|
||||
request.Hl = SettingsStorage.RelevanceLanguage;
|
||||
VideoCategoryListResponse response = await request.ExecuteAsync();
|
||||
if(response.Items.Count != 0)
|
||||
{
|
||||
meta.Inlines.Add(new Run
|
||||
{
|
||||
Text = $" {resources.GetString("/VideoPage/inCat")} "
|
||||
});
|
||||
Hyperlink hl = new Hyperlink();
|
||||
hl.Inlines.Add(new Run
|
||||
{
|
||||
Text = response.Items[0].Snippet.Title
|
||||
});
|
||||
hl.Click += (s, e) => Methods.MainPage.GoToSearch(new SearchParameters(response.Items[0]));
|
||||
meta.Inlines.Add(hl);
|
||||
}
|
||||
}
|
||||
description.FormatText(item.Snippet.Localized.Description);
|
||||
|
||||
//Setting channel button
|
||||
@@ -391,6 +429,8 @@ namespace FoxTube.Pages
|
||||
|
||||
foreach (SearchResult video in response.Items)
|
||||
relatedVideos.Add(new VideoCard(video.Id.VideoId));
|
||||
|
||||
relatedVideos.Children.Insert(1, new Controls.Adverts.CardAdvert());
|
||||
}
|
||||
|
||||
private void Player_Minimize(object sender, params object[] e)
|
||||
@@ -772,5 +812,11 @@ namespace FoxTube.Pages
|
||||
{
|
||||
Player.Player.Position = history.LeftOn;
|
||||
}
|
||||
|
||||
private async void Report_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await new ReportVideo(item.Id).ShowAsync();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,10 +145,10 @@
|
||||
<value>Submit</value>
|
||||
</data>
|
||||
<data name="failedDelete" xml:space="preserve">
|
||||
<value>Failed to delete your commentary. Please, try again later.</value>
|
||||
<value>Failed to delete your comment. Please, try again later.</value>
|
||||
</data>
|
||||
<data name="failedEdit" xml:space="preserve">
|
||||
<value>Failed to edit your commentary. Please, try again later.</value>
|
||||
<value>Failed to edit your comment. Please, try again later.</value>
|
||||
</data>
|
||||
<data name="failedReply" xml:space="preserve">
|
||||
<value>Failed to send your reply. Please, try again later.</value>
|
||||
@@ -174,6 +174,9 @@
|
||||
<data name="sortBy.Text" xml:space="preserve">
|
||||
<value>Sort by: </value>
|
||||
</data>
|
||||
<data name="spam.Text" xml:space="preserve">
|
||||
<value>Report as spam</value>
|
||||
</data>
|
||||
<data name="textbox.PlaceholderText" xml:space="preserve">
|
||||
<value>Add a public comment</value>
|
||||
</data>
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
<value>Bug report has been sent</value>
|
||||
</data>
|
||||
<data name="failedHead" xml:space="preserve">
|
||||
<value>Error occured while dowloading a video</value>
|
||||
<value>Error occurred while downloading a video</value>
|
||||
</data>
|
||||
<data name="gotoOrign.Text" xml:space="preserve">
|
||||
<value>Go to original</value>
|
||||
|
||||
@@ -210,4 +210,19 @@
|
||||
<data name="auto.Content" xml:space="preserve">
|
||||
<value>Auto</value>
|
||||
</data>
|
||||
<data name="interface.Text" xml:space="preserve">
|
||||
<value>Interface</value>
|
||||
</data>
|
||||
<data name="minimizedCommandBar.OffContent" xml:space="preserve">
|
||||
<value>Use compact command bar</value>
|
||||
</data>
|
||||
<data name="minimizedCommandBar.OnContent" xml:space="preserve">
|
||||
<value>Use compact command bar</value>
|
||||
</data>
|
||||
<data name="clipboardProcessing.OffContent" xml:space="preserve">
|
||||
<value>Process YouTube links from your clipboard</value>
|
||||
</data>
|
||||
<data name="clipboardProcessing.OnContent" xml:space="preserve">
|
||||
<value>Process YouTube links from your clipboard</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -126,6 +126,12 @@
|
||||
<data name="channel" xml:space="preserve">
|
||||
<value>Channel</value>
|
||||
</data>
|
||||
<data name="clipboardHead" xml:space="preserve">
|
||||
<value>We've found this on your clipboard</value>
|
||||
</data>
|
||||
<data name="clipboardOpen" xml:space="preserve">
|
||||
<value>Open in FoxTube</value>
|
||||
</data>
|
||||
<data name="close" xml:space="preserve">
|
||||
<value>Close the app</value>
|
||||
</data>
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="comment.Header" xml:space="preserve">
|
||||
<value>Additional information (optional)</value>
|
||||
</data>
|
||||
<data name="err" xml:space="preserve">
|
||||
<value>We are unable to send your report right now. Please, try again later</value>
|
||||
</data>
|
||||
<data name="reason.Header" xml:space="preserve">
|
||||
<value>Reason</value>
|
||||
</data>
|
||||
<data name="reason.PlaceholderText" xml:space="preserve">
|
||||
<value>Select a reason...</value>
|
||||
</data>
|
||||
<data name="report.CloseButtonText" xml:space="preserve">
|
||||
<value>Cancel</value>
|
||||
</data>
|
||||
<data name="report.PrimaryButtonText" xml:space="preserve">
|
||||
<value>Report</value>
|
||||
</data>
|
||||
<data name="report.Title" xml:space="preserve">
|
||||
<value>Report a video</value>
|
||||
</data>
|
||||
<data name="secondaryReason.PlaceholderText" xml:space="preserve">
|
||||
<value>Select a category...</value>
|
||||
</data>
|
||||
<data name="submittedBody" xml:space="preserve">
|
||||
<value>Thanks for making YouTube community better</value>
|
||||
</data>
|
||||
<data name="submittedHeader" xml:space="preserve">
|
||||
<value>Your report has been sent</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -129,6 +129,9 @@
|
||||
<data name="apply.Content" xml:space="preserve">
|
||||
<value>Apply</value>
|
||||
</data>
|
||||
<data name="category" xml:space="preserve">
|
||||
<value>Collection from</value>
|
||||
</data>
|
||||
<data name="cc.Text" xml:space="preserve">
|
||||
<value>Creative Commons</value>
|
||||
</data>
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="body" xml:space="preserve">
|
||||
<value>Thanks for your contribution into my application. It's very important to me. It will take some time to process your package, correct mistakes and prepare it for integration. I will send you an e-mail when it's done.
|
||||
Cheers,
|
||||
XFox
|
||||
|
||||
This is an automatic message. Please, don't respond it. Nah, ok, only if you want to :)</value>
|
||||
</data>
|
||||
<data name="certHeader.Text" xml:space="preserve">
|
||||
<value>Package certification result</value>
|
||||
</data>
|
||||
<data name="choose.Content" xml:space="preserve">
|
||||
<value>Choose another file</value>
|
||||
</data>
|
||||
<data name="description.Text" xml:space="preserve">
|
||||
<value>You can help us make this app even better by contributing to its development by translating this app</value>
|
||||
</data>
|
||||
<data name="export.Content" xml:space="preserve">
|
||||
<value>Export to PC (.zip)</value>
|
||||
</data>
|
||||
<data name="exportPicker" xml:space="preserve">
|
||||
<value>Export</value>
|
||||
</data>
|
||||
<data name="failed" xml:space="preserve">
|
||||
<value>Failed</value>
|
||||
</data>
|
||||
<data name="failedRead" xml:space="preserve">
|
||||
<value>Failed to read file. File's structure is corrupted</value>
|
||||
</data>
|
||||
<data name="failedSend.Body" xml:space="preserve">
|
||||
<value>We were unable to send your submission due to connection problems or internal server error. Please, try again later.</value>
|
||||
</data>
|
||||
<data name="failedSend.Header" xml:space="preserve">
|
||||
<value>Failed to send your package</value>
|
||||
</data>
|
||||
<data name="file" xml:space="preserve">
|
||||
<value>File</value>
|
||||
</data>
|
||||
<data name="guide0.Text" xml:space="preserve">
|
||||
<value>It's quite simple:</value>
|
||||
</data>
|
||||
<data name="guide1.Header" xml:space="preserve">
|
||||
<value>1. Choose language you you want to translate on</value>
|
||||
</data>
|
||||
<data name="guide1.PlaceholderText" xml:space="preserve">
|
||||
<value>Choose language...</value>
|
||||
</data>
|
||||
<data name="guide2.Text" xml:space="preserve">
|
||||
<value>2. Save language pack file to your PC</value>
|
||||
</data>
|
||||
<data name="guide3.Text" xml:space="preserve">
|
||||
<value>3. Open archive's files with any text editor you want (Notepad, Wordpad, Notepad++, VS Code, etc.)</value>
|
||||
</data>
|
||||
<data name="guide4.Text" xml:space="preserve">
|
||||
<value>4. Edit file by translating nececcary words and sentences</value>
|
||||
</data>
|
||||
<data name="guide5.Text" xml:space="preserve">
|
||||
<value>5. Upload final package to our servers</value>
|
||||
</data>
|
||||
<data name="header.Text" xml:space="preserve">
|
||||
<value>Help us translate this app</value>
|
||||
</data>
|
||||
<data name="info.Text" xml:space="preserve">
|
||||
<value>It takes about 2-3 weeks to process new language pack and include it to the next update
|
||||
Thank you for your help 😉
|
||||
|
||||
Cheers,</value>
|
||||
</data>
|
||||
<data name="inprogress" xml:space="preserve">
|
||||
<value>In progress...</value>
|
||||
</data>
|
||||
<data name="langpackScheme" xml:space="preserve">
|
||||
<value>Language pack scheme</value>
|
||||
</data>
|
||||
<data name="log.Content" xml:space="preserve">
|
||||
<value>View log</value>
|
||||
</data>
|
||||
<data name="notfound" xml:space="preserve">
|
||||
<value>not found</value>
|
||||
</data>
|
||||
<data name="passed" xml:space="preserve">
|
||||
<value>Passed</value>
|
||||
</data>
|
||||
<data name="subject" xml:space="preserve">
|
||||
<value>FoxTube language pack contribution</value>
|
||||
</data>
|
||||
<data name="submit.Content" xml:space="preserve">
|
||||
<value>Upload</value>
|
||||
</data>
|
||||
<data name="success.Text" xml:space="preserve">
|
||||
<value>Your language pack has been sent!</value>
|
||||
</data>
|
||||
<data name="successSub.Text" xml:space="preserve">
|
||||
<value>Thank you! It's very imortant for us. You help us making the app better</value>
|
||||
</data>
|
||||
<data name="upload.Content" xml:space="preserve">
|
||||
<value>Choose file to upload</value>
|
||||
</data>
|
||||
<data name="username" xml:space="preserve">
|
||||
<value>FoxTube auto reply</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -175,7 +175,7 @@
|
||||
<value>Go to live broadcast</value>
|
||||
</data>
|
||||
<data name="matureText" xml:space="preserve">
|
||||
<value>This content may be not apropriate for children under 18</value>
|
||||
<value>This content may be not appropriate for children under 18</value>
|
||||
</data>
|
||||
<data name="maximize.Text" xml:space="preserve">
|
||||
<value>Maximize</value>
|
||||
@@ -303,4 +303,13 @@
|
||||
<data name="auto" xml:space="preserve">
|
||||
<value>Auto</value>
|
||||
</data>
|
||||
<data name="playbackSpeed.Header" xml:space="preserve">
|
||||
<value>Playback speed</value>
|
||||
</data>
|
||||
<data name="report.Label" xml:space="preserve">
|
||||
<value>Report this video</value>
|
||||
</data>
|
||||
<data name="inCat" xml:space="preserve">
|
||||
<value>in</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -174,6 +174,9 @@
|
||||
<data name="sortBy.Text" xml:space="preserve">
|
||||
<value>Сортировать по:</value>
|
||||
</data>
|
||||
<data name="spam.Text" xml:space="preserve">
|
||||
<value>Отметить как спам</value>
|
||||
</data>
|
||||
<data name="textbox.PlaceholderText" xml:space="preserve">
|
||||
<value>Оставить комментарий</value>
|
||||
</data>
|
||||
|
||||
@@ -210,4 +210,19 @@
|
||||
<data name="auto.Content" xml:space="preserve">
|
||||
<value>Авто</value>
|
||||
</data>
|
||||
<data name="interface.Text" xml:space="preserve">
|
||||
<value>Интерфейс</value>
|
||||
</data>
|
||||
<data name="minimizedCommandBar.OffContent" xml:space="preserve">
|
||||
<value>Использовать компактную панель команд</value>
|
||||
</data>
|
||||
<data name="minimizedCommandBar.OnContent" xml:space="preserve">
|
||||
<value>Использовать компактную панель команд</value>
|
||||
</data>
|
||||
<data name="clipboardProcessing.OffContent" xml:space="preserve">
|
||||
<value>Обрабатывать ссылки YouTube из буфера обмена</value>
|
||||
</data>
|
||||
<data name="clipboardProcessing.OnContent" xml:space="preserve">
|
||||
<value>Обрабатывать ссылки YouTube из буфера обмена</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -126,6 +126,9 @@
|
||||
<data name="channel" xml:space="preserve">
|
||||
<value>Канал</value>
|
||||
</data>
|
||||
<data name="clipboardOpen" xml:space="preserve">
|
||||
<value>Открыть в FoxTube</value>
|
||||
</data>
|
||||
<data name="close" xml:space="preserve">
|
||||
<value>Закрыть приложение</value>
|
||||
</data>
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="comment.Header" xml:space="preserve">
|
||||
<value>Дополнительная информация (необязательно)</value>
|
||||
</data>
|
||||
<data name="err" xml:space="preserve">
|
||||
<value>Нам не удалось отправить жалобу прямо сейчас. Пожалуйста, попробуйте позже</value>
|
||||
</data>
|
||||
<data name="reason.Header" xml:space="preserve">
|
||||
<value>Причина</value>
|
||||
</data>
|
||||
<data name="reason.PlaceholderText" xml:space="preserve">
|
||||
<value>Выберите причину...</value>
|
||||
</data>
|
||||
<data name="report.CloseButtonText" xml:space="preserve">
|
||||
<value>Отмена</value>
|
||||
</data>
|
||||
<data name="report.PrimaryButtonText" xml:space="preserve">
|
||||
<value>Пожаловаться</value>
|
||||
</data>
|
||||
<data name="report.Title" xml:space="preserve">
|
||||
<value>Пожаловаться на видео</value>
|
||||
</data>
|
||||
<data name="secondaryReason.PlaceholderText" xml:space="preserve">
|
||||
<value>Выберите категорию...</value>
|
||||
</data>
|
||||
<data name="submittedBody" xml:space="preserve">
|
||||
<value>Спасибо что помогаете делать сообщество YouTube лучше</value>
|
||||
</data>
|
||||
<data name="submittedHeader" xml:space="preserve">
|
||||
<value>Ваша жалоба отправлена</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -129,6 +129,9 @@
|
||||
<data name="apply.Content" xml:space="preserve">
|
||||
<value>Применить</value>
|
||||
</data>
|
||||
<data name="category" xml:space="preserve">
|
||||
<value>Коллекция категории</value>
|
||||
</data>
|
||||
<data name="cc.Text" xml:space="preserve">
|
||||
<value>Лицензия Creative Commons</value>
|
||||
</data>
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="body" xml:space="preserve">
|
||||
<value>Спасибо за ваш вклад в развитие моего приложения. Это очень важно для меня. Обработка пакета, исправление технических ошибок и подготовка пакета к интеграции займет некоторое время. Я пришлю вам письмо, когда локализация будет готова.
|
||||
Всего лучшего,
|
||||
XFox
|
||||
|
||||
Это автоматический ответ. Пожалуйста, не отвечайте на это письмо. Ладно, только если очень хочется)</value>
|
||||
</data>
|
||||
<data name="certHeader.Text" xml:space="preserve">
|
||||
<value>Результат сертификации пакета</value>
|
||||
</data>
|
||||
<data name="choose.Content" xml:space="preserve">
|
||||
<value>Выбрать другой файл</value>
|
||||
</data>
|
||||
<data name="description.Text" xml:space="preserve">
|
||||
<value>Вы можете помочь нам сделать приложение еще лучше, помогая перевести его на новые языки</value>
|
||||
</data>
|
||||
<data name="export.Content" xml:space="preserve">
|
||||
<value>Экспортировать на ПК (.zip)</value>
|
||||
</data>
|
||||
<data name="exportPicker" xml:space="preserve">
|
||||
<value>Сохранить</value>
|
||||
</data>
|
||||
<data name="failed" xml:space="preserve">
|
||||
<value>Провал</value>
|
||||
</data>
|
||||
<data name="failedRead" xml:space="preserve">
|
||||
<value>Ошибка чтения файла. Структура данных повреждена</value>
|
||||
</data>
|
||||
<data name="failedSend.Body" xml:space="preserve">
|
||||
<value>Не удалось отправить ваш пакет из-за проблем с соединением или внутренней ошибкой сервера. Пожалуйста, попробуйте позже</value>
|
||||
</data>
|
||||
<data name="failedSend.Header" xml:space="preserve">
|
||||
<value>Ошибка при отправке пакета</value>
|
||||
</data>
|
||||
<data name="file" xml:space="preserve">
|
||||
<value>Файл</value>
|
||||
</data>
|
||||
<data name="guide0.Text" xml:space="preserve">
|
||||
<value>Это достаточно просто:</value>
|
||||
</data>
|
||||
<data name="guide1.Header" xml:space="preserve">
|
||||
<value>1. Выберите язык на который вы хотите перевести</value>
|
||||
</data>
|
||||
<data name="guide1.PlaceholderText" xml:space="preserve">
|
||||
<value>Выберите язык...</value>
|
||||
</data>
|
||||
<data name="guide2.Text" xml:space="preserve">
|
||||
<value>2. Сохраните языковой пакет на свой ПК</value>
|
||||
</data>
|
||||
<data name="guide3.Text" xml:space="preserve">
|
||||
<value>3. Откройте файлы в архиве любым текстовым редактором на ваш выбор (Блокнот, Wordpad, Notepad++, VS Code, и т.д.)</value>
|
||||
</data>
|
||||
<data name="guide4.Text" xml:space="preserve">
|
||||
<value>4. Переведите необходимые слова и предложения</value>
|
||||
</data>
|
||||
<data name="guide5.Text" xml:space="preserve">
|
||||
<value>5. Загрузите финальный пакет на наши сервера</value>
|
||||
</data>
|
||||
<data name="header.Text" xml:space="preserve">
|
||||
<value>Помогите нам перевести это приложение</value>
|
||||
</data>
|
||||
<data name="info.Text" xml:space="preserve">
|
||||
<value>Обработка пакета займет 2-3 недели. Новая локализация будет доступна в ближайших обновлениях
|
||||
Спасибо за вашу помощь 😉
|
||||
|
||||
С наилучшими пожеланиями,</value>
|
||||
</data>
|
||||
<data name="inprogress" xml:space="preserve">
|
||||
<value>В процессе...</value>
|
||||
</data>
|
||||
<data name="langpackScheme" xml:space="preserve">
|
||||
<value>Схема языкового пакета</value>
|
||||
</data>
|
||||
<data name="log.Content" xml:space="preserve">
|
||||
<value>Посмотреть лог</value>
|
||||
</data>
|
||||
<data name="notfound" xml:space="preserve">
|
||||
<value>не найден</value>
|
||||
</data>
|
||||
<data name="passed" xml:space="preserve">
|
||||
<value>Пройдена</value>
|
||||
</data>
|
||||
<data name="subject" xml:space="preserve">
|
||||
<value>Помощь в локализации приложения FoxTube</value>
|
||||
</data>
|
||||
<data name="submit.Content" xml:space="preserve">
|
||||
<value>Загрузить</value>
|
||||
</data>
|
||||
<data name="success.Text" xml:space="preserve">
|
||||
<value>Ваш языковой пакт отправлен!</value>
|
||||
</data>
|
||||
<data name="successSub.Text" xml:space="preserve">
|
||||
<value>Спасибо! Это очень важно для нас. Вы помогаете сделать приложение лучше!</value>
|
||||
</data>
|
||||
<data name="upload.Content" xml:space="preserve">
|
||||
<value>Выберите файл для отправки</value>
|
||||
</data>
|
||||
<data name="username" xml:space="preserve">
|
||||
<value>Автоответчик FoxTube</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -303,4 +303,13 @@
|
||||
<data name="auto" xml:space="preserve">
|
||||
<value>Авто</value>
|
||||
</data>
|
||||
<data name="playbackSpeed.Header" xml:space="preserve">
|
||||
<value>Скорость видео</value>
|
||||
</data>
|
||||
<data name="report.Label" xml:space="preserve">
|
||||
<value>Пожаловаться на видео</value>
|
||||
</data>
|
||||
<data name="inCat" xml:space="preserve">
|
||||
<value>в категории</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -342,10 +342,13 @@
|
||||
</Flyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
<Button x:Name="QualityMenuButton" Content="">
|
||||
<Button x:Name="SettingsMenuButton" Content="">
|
||||
<Button.Flyout>
|
||||
<Flyout>
|
||||
<StackPanel>
|
||||
<Slider x:Name="PlaybackSpeedSlider" x:Uid="/VideoPage/playbackSpeed" Orientation="Horizontal" TickPlacement="Outside" StepFrequency=".1" Value="1" Maximum="3" Header="Playback speed"/>
|
||||
<ComboBox Width="225" x:Name="QualitySelector" Header="Language" x:Uid="/VideoPage/qualitySelector"/>
|
||||
</StackPanel>
|
||||
</Flyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user