Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions OneGateApp/Data/DApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public class DApp : IComparable<DApp>, IShareable, IVersioned

public bool IsGamingApp => !string.IsNullOrWhiteSpace(GameType);
public bool IsRegularApp => !IsGamingApp;
public string? PreviewUrl => Previews?.FirstOrDefault(p => !string.IsNullOrWhiteSpace(p));
public string? GameTypeDisplayName => LocalizeGameType(GameType);
public Dictionary<string, string> NameLocalizer => field ??= JsonSerializer.Deserialize<Dictionary<string, string>>(Name)!;
public Dictionary<string, string>? DescriptionLocalizer => Description is null ? null : field ??= JsonSerializer.Deserialize<Dictionary<string, string>>(Description);
Expand Down
359 changes: 291 additions & 68 deletions OneGateApp/Pages/GamingPage.xaml

Large diffs are not rendered by default.

90 changes: 89 additions & 1 deletion OneGateApp/Pages/GamingPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using CommunityToolkit.Maui.Alerts;
using NeoOrder.OneGate.Controls;
using NeoOrder.OneGate.Data;
using NeoOrder.OneGate.Models;
using NeoOrder.OneGate.Properties;
Expand All @@ -9,9 +11,14 @@ namespace NeoOrder.OneGate.Pages;

public partial class GamingPage : ContentPage
{
const string LayoutPreferenceKey = "gaming/layout";
const string GalleryLayout = "gallery";
const string ListLayout = "list";
const double GameItemMinWidth = 520;
const double GalleryItemMinWidth = 112;
const double HorizontalPageMargin = 40;
const int MaxGameColumns = 3;
const int MaxGalleryColumns = 4;

readonly ApplicationDbContext dbContext;
bool allowRestrictedContent;
Expand All @@ -23,9 +30,46 @@ public partial class GamingPage : ContentPage
public ObservableCollection<DApp> GamesRecent { get; private set { field = value; OnPropertyChanged(); } } = [];
public bool HasRecentGames { get; private set { field = value; OnPropertyChanged(); } }
public DApp[] Games { get; private set { field = value; OnPropertyChanged(); } } = [];
public DApp[] GamesFiltered { get; private set { field = value; OnPropertyChanged(); } } = [];
public DApp[] GamesFiltered
{
get;
private set
{
field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ShowGalleryLayout));
OnPropertyChanged(nameof(ShowListLayout));
OnPropertyChanged(nameof(ShowEmptyState));
}
} = [];
public DApp[] GamesQuickPicks { get; private set { field = value; OnPropertyChanged(); OnPropertyChanged(nameof(HasQuickPicks)); } } = [];
public bool HasQuickPicks => GamesQuickPicks.Length > 0;
public DApp? SpotlightGame { get; private set { field = value; OnPropertyChanged(); OnPropertyChanged(nameof(HasSpotlightGame)); } }
public bool HasSpotlightGame => SpotlightGame is not null;
public string[] GameTypes { get; private set { field = value; OnPropertyChanged(); } } = [Strings.All];
public bool HasGameTypeFilters { get; private set { field = value; OnPropertyChanged(); } }
public bool IsGalleryLayout
{
get;
private set
{
field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(IsListLayout));
OnPropertyChanged(nameof(LayoutToggleDescription));
OnPropertyChanged(nameof(ShowGalleryLayout));
OnPropertyChanged(nameof(ShowListLayout));
}
} = true;
public bool IsListLayout => !IsGalleryLayout;
public string LayoutToggleDescription => IsGalleryLayout
? Strings.GamingSwitchToListLayout
: Strings.GamingSwitchToGalleryLayout;
public bool ShowGalleryLayout => IsGalleryLayout && GamesFiltered.Length > 0;
public bool ShowListLayout => IsListLayout && GamesFiltered.Length > 0;
public bool ShowEmptyState => GamesFiltered.Length == 0;

bool layoutPreferenceLoaded;

public GamingPage(IServiceProvider serviceProvider, ApplicationDbContext dbContext)
{
Expand Down Expand Up @@ -54,13 +98,16 @@ protected override void OnSizeAllocated(double width, double height)
{
base.OnSizeAllocated(width, height);
UpdateGamesItemsLayout(width);
UpdateGalleryItemsLayout(width);
}

async Task LoadSettingsAsync()
{
allowRestrictedContent = await DAppCatalogPolicy.GetAllowRestrictedContentAsync(dbContext);
developerModeEnabled = await DAppCatalogPolicy.GetDeveloperModeEnabledAsync(dbContext);
GamesIdRecent = await dbContext.Settings.GetAsync<List<int>>("dapps/recent") ?? [];
IsGalleryLayout = !string.Equals(await dbContext.Settings.GetAsync(LayoutPreferenceKey), ListLayout, StringComparison.OrdinalIgnoreCase);
layoutPreferenceLoaded = true;
}

async Task LoadDAppsAsync()
Expand All @@ -82,6 +129,15 @@ void UpdateGamesItemsLayout(double pageWidth)
GamesItemsLayout.Span = span;
}

void UpdateGalleryItemsLayout(double pageWidth)
{
if (pageWidth <= 0) return;
var contentWidth = Math.Max(0, pageWidth - HorizontalPageMargin);
var span = Math.Clamp((int)(contentWidth / GalleryItemMinWidth), 2, MaxGalleryColumns);
if (GalleryItemsLayout.Span != span)
GalleryItemsLayout.Span = span;
}

void OnDataLoaded(object? sender, EventArgs e)
{
Games = DApps
Expand Down Expand Up @@ -110,11 +166,23 @@ void LoadRecentGames()
HasRecentGames = GamesRecent.Count > 0;
}

void UpdateGallerySections()
{
SpotlightGame = GamesFiltered
.FirstOrDefault(p => p.Previews?.Any(url => !string.IsNullOrWhiteSpace(url)) == true)
?? GamesFiltered.FirstOrDefault();
GamesQuickPicks = GamesFiltered
.Where(p => !ReferenceEquals(p, SpotlightGame))
.Take(6)
.ToArray();
}

void ApplyGameTypeFilter(TabBar tabBar)
{
if (tabBar.Tabs is not { Count: > 0 } tabs)
{
GamesFiltered = Games;
UpdateGallerySections();
return;
}

Expand All @@ -127,12 +195,32 @@ void ApplyGameTypeFilter(TabBar tabBar)
if (tabBar.SelectedTab == tabs[0])
{
GamesFiltered = Games;
UpdateGallerySections();
return;
}

GamesFiltered = Games
.Where(p => string.Equals(p.GameTypeDisplayName, tabBar.SelectedTab, StringComparison.CurrentCulture))
.ToArray();
UpdateGallerySections();
}

async void OnLayoutToggleClicked(object sender, EventArgs e)
{
if (!layoutPreferenceLoaded)
return;

bool previousLayout = IsGalleryLayout;
IsGalleryLayout = !previousLayout;
try
{
await dbContext.Settings.PutAsync(LayoutPreferenceKey, IsGalleryLayout ? GalleryLayout : ListLayout);
}
catch (Exception ex)
{
IsGalleryLayout = previousLayout;
await Toast.Show(ex.Message);
}
}

async void OnDetailsClicked(object sender, EventArgs e)
Expand Down
63 changes: 63 additions & 0 deletions OneGateApp/Properties/Strings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions OneGateApp/Properties/Strings.de.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1255,4 +1255,6 @@ Es wird empfohlen, den NEP-2-Schlüssel und das Passwort getrennt aufzubewahren
<data name="RemoteDebugWaiting" xml:space="preserve"><value>Warten auf einen vertrauenswürdigen Remote-Debugger</value></data>
<data name="RemoteDebugPairingTitle" xml:space="preserve"><value>Remote-Debugger koppeln</value></data>
<data name="RemoteDebugPairingPrompt" xml:space="preserve"><value>Remote-Debugger „{0}“ fordert Zugriff an. Fingerabdruck: {1}. Nur autorisieren, wenn du diesem Remote-Debugger vertraust.</value></data>
<data name="GamingSwitchToGalleryLayout" xml:space="preserve"><value>Zum Galerie-Layout wechseln</value></data>
<data name="GamingSwitchToListLayout" xml:space="preserve"><value>Zum Listen-Layout wechseln</value></data>
</root>
2 changes: 2 additions & 0 deletions OneGateApp/Properties/Strings.es.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1255,4 +1255,6 @@ Se recomienda almacenar la clave NEP-2 y la contraseña por separado y realizar
<data name="RemoteDebugWaiting" xml:space="preserve"><value>Esperando un depurador remoto de confianza</value></data>
<data name="RemoteDebugPairingTitle" xml:space="preserve"><value>Emparejar depurador remoto</value></data>
<data name="RemoteDebugPairingPrompt" xml:space="preserve"><value>El depurador remoto «{0}» solicita acceso. Huella: {1}. Autoriza solo si confías en este depurador remoto.</value></data>
<data name="GamingSwitchToGalleryLayout" xml:space="preserve"><value>Cambiar al diseño de galería</value></data>
<data name="GamingSwitchToListLayout" xml:space="preserve"><value>Cambiar al diseño de lista</value></data>
</root>
2 changes: 2 additions & 0 deletions OneGateApp/Properties/Strings.fr.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1255,4 +1255,6 @@ Il est recommandé de conserver séparément la clé NEP-2 et le mot de passe, e
<data name="RemoteDebugWaiting" xml:space="preserve"><value>En attente d’un débogueur distant approuvé</value></data>
<data name="RemoteDebugPairingTitle" xml:space="preserve"><value>Associer le débogueur distant</value></data>
<data name="RemoteDebugPairingPrompt" xml:space="preserve"><value>Le débogueur distant « {0} » demande l’accès. Empreinte : {1}. Autorisez uniquement si vous faites confiance à ce débogueur distant.</value></data>
<data name="GamingSwitchToGalleryLayout" xml:space="preserve"><value>Passer à l’affichage en galerie</value></data>
<data name="GamingSwitchToListLayout" xml:space="preserve"><value>Passer à l’affichage en liste</value></data>
</root>
2 changes: 2 additions & 0 deletions OneGateApp/Properties/Strings.id.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1255,4 +1255,6 @@ Disarankan untuk menyimpan kunci NEP-2 dan kata sandinya secara terpisah serta m
<data name="RemoteDebugWaiting" xml:space="preserve"><value>Menunggu debugger jarak jauh tepercaya</value></data>
<data name="RemoteDebugPairingTitle" xml:space="preserve"><value>Pasangkan debugger jarak jauh</value></data>
<data name="RemoteDebugPairingPrompt" xml:space="preserve"><value>Debugger jarak jauh “{0}” meminta akses. Sidik jari: {1}. Izinkan hanya jika Anda memercayai debugger jarak jauh ini.</value></data>
<data name="GamingSwitchToGalleryLayout" xml:space="preserve"><value>Beralih ke tata letak galeri</value></data>
<data name="GamingSwitchToListLayout" xml:space="preserve"><value>Beralih ke tata letak daftar</value></data>
</root>
2 changes: 2 additions & 0 deletions OneGateApp/Properties/Strings.it.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1255,4 +1255,6 @@ Si consiglia di conservare separatamente la chiave NEP-2 e la password e di eseg
<data name="RemoteDebugWaiting" xml:space="preserve"><value>In attesa di un debugger remoto attendibile</value></data>
<data name="RemoteDebugPairingTitle" xml:space="preserve"><value>Associa debugger remoto</value></data>
<data name="RemoteDebugPairingPrompt" xml:space="preserve"><value>Il debugger remoto “{0}” richiede l’accesso. Impronta: {1}. Autorizza solo se ritieni attendibile questo debugger remoto.</value></data>
<data name="GamingSwitchToGalleryLayout" xml:space="preserve"><value>Passa al layout galleria</value></data>
<data name="GamingSwitchToListLayout" xml:space="preserve"><value>Passa al layout elenco</value></data>
</root>
2 changes: 2 additions & 0 deletions OneGateApp/Properties/Strings.ja.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1255,4 +1255,6 @@ NEP-2 とパスワードは別々に保管し、それぞれを安全にバッ
<data name="RemoteDebugWaiting" xml:space="preserve"><value>信頼済みリモートデバッガーを待機中</value></data>
<data name="RemoteDebugPairingTitle" xml:space="preserve"><value>リモートデバッガーをペアリング</value></data>
<data name="RemoteDebugPairingPrompt" xml:space="preserve"><value>リモートデバッガー「{0}」がアクセスを要求しています。フィンガープリント: {1}。このリモートデバッガーを信頼する場合のみ許可してください。</value></data>
<data name="GamingSwitchToGalleryLayout" xml:space="preserve"><value>ギャラリーレイアウトに切り替え</value></data>
<data name="GamingSwitchToListLayout" xml:space="preserve"><value>リストレイアウトに切り替え</value></data>
</root>
2 changes: 2 additions & 0 deletions OneGateApp/Properties/Strings.ko.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1255,4 +1255,6 @@ NEP-2와 비밀번호는 별도로 보관하고 각각 안전하게 백업하는
<data name="RemoteDebugWaiting" xml:space="preserve"><value>신뢰할 수 있는 원격 디버거 대기 중</value></data>
<data name="RemoteDebugPairingTitle" xml:space="preserve"><value>원격 디버거 페어링</value></data>
<data name="RemoteDebugPairingPrompt" xml:space="preserve"><value>원격 디버거 “{0}”이(가) 액세스를 요청합니다. 지문: {1}. 이 원격 디버거를 신뢰하는 경우에만 허용하세요.</value></data>
<data name="GamingSwitchToGalleryLayout" xml:space="preserve"><value>갤러리 레이아웃으로 전환</value></data>
<data name="GamingSwitchToListLayout" xml:space="preserve"><value>목록 레이아웃으로 전환</value></data>
</root>
2 changes: 2 additions & 0 deletions OneGateApp/Properties/Strings.nl.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1255,4 +1255,6 @@ Het wordt aanbevolen om de NEP-2-sleutel en het wachtwoord apart op te slaan en
<data name="RemoteDebugWaiting" xml:space="preserve"><value>Wachten op een vertrouwde externe debugger</value></data>
<data name="RemoteDebugPairingTitle" xml:space="preserve"><value>Externe debugger koppelen</value></data>
<data name="RemoteDebugPairingPrompt" xml:space="preserve"><value>Externe debugger ‘{0}’ vraagt toegang. Vingerafdruk: {1}. Autoriseer alleen als je deze externe debugger vertrouwt.</value></data>
<data name="GamingSwitchToGalleryLayout" xml:space="preserve"><value>Overschakelen naar galerijweergave</value></data>
<data name="GamingSwitchToListLayout" xml:space="preserve"><value>Overschakelen naar lijstweergave</value></data>
</root>
2 changes: 2 additions & 0 deletions OneGateApp/Properties/Strings.pt-BR.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1255,4 +1255,6 @@ Recomenda-se armazenar a chave NEP-2 e a senha separadamente e fazer backups seg
<data name="RemoteDebugWaiting" xml:space="preserve"><value>Aguardando um depurador remoto confiável</value></data>
<data name="RemoteDebugPairingTitle" xml:space="preserve"><value>Parear depurador remoto</value></data>
<data name="RemoteDebugPairingPrompt" xml:space="preserve"><value>O depurador remoto “{0}” está solicitando acesso. Impressão digital: {1}. Autorize apenas se confiar neste depurador remoto.</value></data>
<data name="GamingSwitchToGalleryLayout" xml:space="preserve"><value>Mudar para o layout de galeria</value></data>
<data name="GamingSwitchToListLayout" xml:space="preserve"><value>Mudar para o layout de lista</value></data>
</root>
17 changes: 17 additions & 0 deletions OneGateApp/Properties/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,21 @@ By continuing, you acknowledge that you fully understand and accept all associat
<data name="GamingRecentPlayed" xml:space="preserve">
<value>Recently played</value>
</data>
<data name="GamingGallery" xml:space="preserve">
<value>Gallery</value>
</data>
<data name="GamingList" xml:space="preserve">
<value>List</value>
</data>
<data name="GamingQuickPicks" xml:space="preserve">
<value>Quick picks</value>
</data>
<data name="GamingAllGames" xml:space="preserve">
<value>All games</value>
</data>
<data name="GamingSpotlight" xml:space="preserve">
<value>Game spotlight</value>
</data>
<data name="GameType" xml:space="preserve">
<value>Game type</value>
</data>
Expand Down Expand Up @@ -1255,4 +1270,6 @@ It is recommended to store the NEP-2 key and password separately and back them u
<data name="RemoteDebugWaiting" xml:space="preserve"><value>Waiting for a trusted remote debugger</value></data>
<data name="RemoteDebugPairingTitle" xml:space="preserve"><value>Pair remote debugger</value></data>
<data name="RemoteDebugPairingPrompt" xml:space="preserve"><value>Remote debugger “{0}” is requesting access. Fingerprint: {1}. Authorize only if you trust this remote debugger.</value></data>
<data name="GamingSwitchToGalleryLayout" xml:space="preserve"><value>Switch to gallery layout</value></data>
<data name="GamingSwitchToListLayout" xml:space="preserve"><value>Switch to list layout</value></data>
</root>
2 changes: 2 additions & 0 deletions OneGateApp/Properties/Strings.ru.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1255,4 +1255,6 @@
<data name="RemoteDebugWaiting" xml:space="preserve"><value>Ожидание доверенного удалённого отладчика</value></data>
<data name="RemoteDebugPairingTitle" xml:space="preserve"><value>Сопряжение удалённого отладчика</value></data>
<data name="RemoteDebugPairingPrompt" xml:space="preserve"><value>Удалённый отладчик «{0}» запрашивает доступ. Отпечаток: {1}. Разрешайте только если доверяете этому удалённому отладчику.</value></data>
<data name="GamingSwitchToGalleryLayout" xml:space="preserve"><value>Переключиться на вид галереи</value></data>
<data name="GamingSwitchToListLayout" xml:space="preserve"><value>Переключиться на вид списка</value></data>
</root>
2 changes: 2 additions & 0 deletions OneGateApp/Properties/Strings.tr.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1255,4 +1255,6 @@ NEP-2 anahtarı ile şifreyi ayrı ayrı saklamanız ve güvenli şekilde yedekl
<data name="RemoteDebugWaiting" xml:space="preserve"><value>Güvenilir bir uzaktan hata ayıklayıcı bekleniyor</value></data>
<data name="RemoteDebugPairingTitle" xml:space="preserve"><value>Uzaktan hata ayıklayıcıyı eşleştir</value></data>
<data name="RemoteDebugPairingPrompt" xml:space="preserve"><value>“{0}” uzaktan hata ayıklayıcısı erişim istiyor. Parmak izi: {1}. Yalnızca bu uzaktan hata ayıklayıcıya güveniyorsanız izin verin.</value></data>
<data name="GamingSwitchToGalleryLayout" xml:space="preserve"><value>Galeri düzenine geç</value></data>
<data name="GamingSwitchToListLayout" xml:space="preserve"><value>Liste düzenine geç</value></data>
</root>
Loading