This commit is contained in:
mossimo
2021-06-22 00:39:51 +08:00
36 changed files with 756 additions and 243 deletions
@@ -1,7 +1,7 @@
using Android.Content;
using Android.Content;
using Android.Content.Res;
using Android.OS;
using AndroidApplication = Android.App.Application;
//using Android.OS;
//using AndroidApplication = Android.App.Application;
namespace System.Application
{
@@ -38,16 +38,16 @@ namespace System.Application
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
static bool IsDarkMode(Context context)
public static bool IsDarkMode(Context context)
{
var isNight = IsNight(context);
return isNight.HasValue && isNight.Value;
}
/// <summary>
/// 是否正在安卓Q中使用深色主题(Dark)
/// </summary>
public static bool IsDarkModeQ
=> Build.VERSION.SdkInt >= BuildVersionCodes.Q && IsDarkMode(AndroidApplication.Context);
///// <summary>
///// 是否正在安卓Q中使用深色主题(Dark)
///// </summary>
//public static bool IsDarkModeQ
// => Build.VERSION.SdkInt >= BuildVersionCodes.Q && IsDarkMode(AndroidApplication.Context);
}
}
@@ -1,4 +1,4 @@
using AndroidX.AppCompat.App;
using AndroidX.AppCompat.App;
using AndroidX.AppCompat.Widget;
using System.Application.UI.Internals;
using System.Common;
@@ -4,6 +4,8 @@ namespace System.Application.UI.ViewModels
{
public abstract class IdTitleIconViewModel<TId, TIcon> : ReactiveObject
{
protected virtual bool IgnoreIcon { get; }
protected TId? id;
/// <summary>
/// 唯一键
@@ -15,7 +17,7 @@ namespace System.Application.UI.ViewModels
{
if (this.RaiseAndSetIfChanged2(ref id, value)) return;
Title = GetTitleById(value);
Icon = GetIconById(value);
if (!IgnoreIcon) Icon = GetIconById(value);
OnIdChanged(value);
}
}
@@ -251,7 +251,7 @@ navigator.__proto__ = newProto;
return theme switch
{
AppTheme.FollowingSystem => GetThemeStringByFollowingSystem(),
_ => theme.ToString(),
_ => theme.ToString2(),
};
static string GetThemeStringByFollowingSystem()
{
@@ -267,8 +267,8 @@ navigator.__proto__ = newProto;
{
goto dark;
}
return "auto";
dark: return AppTheme.Dark.ToString();
return AppTheme.FollowingSystem.ToString2();
dark: return AppTheme.Dark.ToString2();
}
}
}
@@ -18,7 +18,7 @@ namespace System.Application.UI.Views.Pages
webView = this.FindControl<WebView3>(nameof(webView));
webView.Url = string.Format(
"https://steampp.net/changelogbox?theme={0}&language={1}",
UrlConstants.OfficialWebsite_Box_Changelog_,
CefNetApp.GetTheme(),
R.Language);
}
@@ -17,7 +17,7 @@ namespace System.Application.UI.Views.Pages
InitializeComponent();
webViewQA = this.FindControl<WebView3>("webViewQA");
webViewQA.Url = string.Format(
"https://steampp.net/faqbox?theme={0}&language={1}",
UrlConstants.OfficialWebsite_Box_Faq_,
CefNetApp.GetTheme(),
R.Language);
}
@@ -20,7 +20,7 @@
x:DataType="vm:ShareManageViewModel"
x:CompileBindings="True">
<Panel>
<controls:TitleBar></controls:TitleBar>
<controls:TitleBar></controls:TitleBar>
<Menu
Margin="0 0 145 0" Height="30"
HorizontalAlignment="Right"
@@ -104,16 +104,16 @@
</ia:DataTriggerBehavior>
</i:Interaction.Behaviors>
</Ellipse>
<controls:ScrollingTextBlock x:Name="nickname"
Text="{Binding SteamNickName}"
FontSize="20"
Foreground="{DynamicResource HighlightForegroundBrushKey}"
Cursor="Hand"
<controls:ScrollingTextBlock x:Name="nickname"
Text="{Binding SteamNickName}"
FontSize="20"
Foreground="{DynamicResource HighlightForegroundBrushKey}"
Cursor="Hand"
ToolTip.Tip="{ReflectionBinding Path=Res.UserChange_BtnTootlip,Mode=OneWay,Source={x:Static resx:R.Current}}">
<i:Interaction.Behaviors>
<ia:EventTriggerBehavior EventName="Tapped"
<ia:EventTriggerBehavior EventName="Tapped"
SourceObject="{ReflectionBinding #nickname}">
<ia:InvokeCommandAction Command="{ReflectionBinding #u.DataContext.SteamId_Click}"
<ia:InvokeCommandAction Command="{ReflectionBinding #u.DataContext.SteamId_Click}"
CommandParameter="{Binding}"/>
</ia:EventTriggerBehavior>
</i:Interaction.Behaviors>
@@ -226,6 +226,6 @@
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ScrollViewer>
</Panel>
</Panel>
</Window>
@@ -238,7 +238,7 @@ namespace System.Application.UI.Views.Windows
}
else if (IsHttpUrl(x))
{
if (x.StartsWith("https://steampp.net", StringComparison.OrdinalIgnoreCase))
if (x.StartsWith(UrlConstants.OfficialWebsite, StringComparison.OrdinalIgnoreCase))
x = string.Format(
x + "?theme={0}&language={1}",
CefNetApp.GetTheme(),
+20 -1
View File
@@ -1,4 +1,6 @@
namespace System.Application.Models
using System.Application.Models;
namespace System.Application.Models
{
/// <summary>
/// 应用程序主题
@@ -23,6 +25,23 @@
/// <summary>
/// 自定义主题
/// </summary>
[Obsolete]
Custom,
}
}
namespace System
{
public static partial class AppThemeEnumExtensions
{
public static string ToString2(this AppTheme value)
{
return value switch
{
AppTheme.FollowingSystem => "auto",
AppTheme.Light => "light",
_ => "dark",
};
}
}
}
@@ -73,7 +73,7 @@ namespace System.Application.Services
#endif
}
public async void DelAccount()
public async Task DelAccountAsync()
{
if (!IsAuthenticated) return;
var msg = AppResources.Success_.Format(AppResources.DelAccount);
+27
View File
@@ -440,6 +440,15 @@ namespace System.Application.UI.Resx {
}
}
/// <summary>
/// 查找类似 Bug 反馈 的本地化字符串。
/// </summary>
public static string BugFeedback {
get {
return ResourceManager.GetString("BugFeedback", resourceCulture);
}
}
/// <summary>
/// 查找类似 取消 的本地化字符串。
/// </summary>
@@ -2520,6 +2529,15 @@ namespace System.Application.UI.Resx {
}
}
/// <summary>
/// 查找类似 产品官网 的本地化字符串。
/// </summary>
public static string ProductOfficialWebsite {
get {
return ResourceManager.GetString("ProductOfficialWebsite", resourceCulture);
}
}
/// <summary>
/// 查找类似 恢复代码 的本地化字符串。
/// </summary>
@@ -2988,6 +3006,15 @@ namespace System.Application.UI.Resx {
}
}
/// <summary>
/// 查找类似 源码仓库 的本地化字符串。
/// </summary>
public static string SourceRepository {
get {
return ResourceManager.GetString("SourceRepository", resourceCulture);
}
}
/// <summary>
/// 查找类似 开始更新 的本地化字符串。
/// </summary>
@@ -245,6 +245,9 @@
<data name="Btn_Text_Continue" xml:space="preserve">
<value>继续</value>
</data>
<data name="BugFeedback" xml:space="preserve">
<value>Bug 反馈</value>
</data>
<data name="Cancel" xml:space="preserve">
<value>取消</value>
</data>
@@ -942,6 +945,9 @@
<data name="PleaseSelect" xml:space="preserve">
<value>请选择</value>
</data>
<data name="ProductOfficialWebsite" xml:space="preserve">
<value>产品官网</value>
</data>
<data name="RecoveryCode" xml:space="preserve">
<value>恢复代码</value>
</data>
@@ -1099,6 +1105,9 @@
<data name="SMSCode" xml:space="preserve">
<value>短信验证代码</value>
</data>
<data name="SourceRepository" xml:space="preserve">
<value>源码仓库</value>
</data>
<data name="StartUpdate" xml:space="preserve">
<value>开始更新</value>
</data>
@@ -1,114 +1,39 @@
using ReactiveUI;
using System.Application.Services;
using System.Application.UI.Resx;
using System.Properties;
using System.Reactive;
using System.Runtime.InteropServices;
using System.Windows;
using static System.Application.Services.CloudService.Constants;
namespace System.Application.UI.ViewModels
{
public class AboutPageViewModel : TabItemViewModel
partial class AboutPageViewModel : TabItemViewModel
{
public static AboutPageViewModel Instance { get; } = new();
public override string Name
{
get => AppResources.About;
protected set { throw new NotImplementedException(); }
}
public AboutPageViewModel()
{
IconKey = nameof(AboutPageViewModel).Replace("ViewModel", "Svg");
OpenBrowserCommand = ReactiveCommand.Create<string>(BrowserOpen);
CopyLinkCommand = ReactiveCommand.Create<string>(IDesktopAppService.Instance.SetClipboardText);
CheckUpdateCommand = ReactiveCommand.CreateFromTask(async () =>
{
await IAppUpdateService.Instance.CheckUpdateAsync(showIsExistUpdateFalse: true);
});
DelAccountCommand = ReactiveCommand.CreateFromTask(async () =>
{
if (!UserService.Current.IsAuthenticated) return;
var r = await MessageBoxCompat.ShowAsync(AppResources.DelAccountTips, ThisAssembly.AssemblyTrademark, MessageBoxButtonCompat.OKCancel);
if (r == MessageBoxResultCompat.OK)
{
UserService.Current.DelAccount();
}
});
}
public ReactiveCommand<Unit, Unit> CheckUpdateCommand { get; }
public ReactiveCommand<string, Unit> OpenBrowserCommand { get; }
public ReactiveCommand<string, Unit> CopyLinkCommand { get; }
public ReactiveCommand<Unit, Unit> DelAccountCommand { get; }
static string GetOS() => DI.Platform switch
{
Platform.Windows => "Windows",
Platform.Linux => "Linux",
Platform.Android => "Android",
Platform.Apple => DI.DeviceIdiom switch
{
DeviceIdiom.Phone => "iOS",
DeviceIdiom.Tablet => "iPadOS",
DeviceIdiom.Desktop => "macOS",
DeviceIdiom.TV => "tvOS",
DeviceIdiom.Watch => "watchOS",
_ => string.Empty,
},
Platform.UWP => "UWP",
_ => string.Empty,
};
public string VersionDisplay => $"{ThisAssembly.VersionDisplay} for {GetOS()} ({RuntimeInformation.ProcessArchitecture})";
public string LabelVersionDisplay => ThisAssembly.IsBetaRelease ? "Beta Version:" : "Current Version:";
public string Copyright
{
get
{
// https://www.w3cschool.cn/html/html-copyright.html
int startYear = 2020, thisYear = 2021;
var nowYear = DateTime.Now.Year;
if (nowYear < thisYear) nowYear = thisYear;
return $"© {startYear}{(nowYear == startYear ? startYear : "-" + nowYear)} {ThisAssembly.AssemblyCompany}. All Rights Reserved.";
}
get => TitleName;
protected set { throw new NotSupportedException(); }
}
public static string RmbadminSteamLink => SteamApiUrls.MY_PROFILE_URL;
public static string RmbadminLink => "https://github.com/rmbadmin";
public static string RmbadminLink => UrlConstants.GitHub_User_Rmbadmin;
public static string AigioLLink => "https://github.com/AigioL";
public static string AigioLLink => UrlConstants.GitHub_User_AigioL;
public static string MossimosLink => "https://github.com/Mossimos";
public static string MossimosLink => UrlConstants.GitHub_User_Mossimos;
public static string CliencerLink => "https://space.bilibili.com/30031316";
public static string CliencerLink => UrlConstants.BILI_User_Cliencer;
public static string PrivacyLink => "https://steampp.net/privacy";
public static string PrivacyLink => UrlConstants.OfficialWebsite_Privacy;
public static string AgreementLink => "https://steampp.net/agreement";
public static string AgreementLink => UrlConstants.OfficialWebsite_Agreement;
public static string OfficialLink => "https://steampp.net";
public static string OfficialLink => UrlConstants.OfficialWebsite;
public static string SourceCodeLink => "https://github.com/rmbadmin/SteamTools";
public static string SourceCodeLink => UrlConstants.GitHub_Repository;
public static string UserSupportLink => "https://steampp.net/contact";
public static string UserSupportLink => UrlConstants.OfficialWebsite_Contact;
public static string BugReportLink => "https://github.com/rmbadmin/SteamTools/issues";
public static string BugReportLink => UrlConstants.GitHub_Issues;
public static string FAQLink => "https://steampp.net/faq";
public static string FAQLink => UrlConstants.OfficialWebsite_Faq;
public static string LicenseLink => "https://github.com/rmbadmin/SteamTools/blob/develop/LICENSE";
public static string LicenseLink => UrlConstants.License_GPLv3;
}
}
@@ -0,0 +1,132 @@
using ReactiveUI;
using System.Application.Services;
using System.Application.UI.Resx;
using System.Linq;
using System.Properties;
using System.Reactive;
using System.Runtime.InteropServices;
using System.Windows;
//#if __MOBILE__
//using Xamarin.Essentials;
//#endif
using static System.Application.Services.CloudService.Constants;
namespace System.Application.UI.ViewModels
{
public partial class AboutPageViewModel
{
static string TitleName => AppResources.About;
public AboutPageViewModel()
{
#if !__MOBILE__
IconKey = nameof(AboutPageViewModel).Replace("ViewModel", "Svg");
#endif
OpenBrowserCommand = ReactiveCommand.Create<string>(BrowserOpen);
//#if !__MOBILE__
// CopyLinkCommand =
//#if __MOBILE__
// ReactiveCommand.CreateFromTask<string>(Clipboard.SetTextAsync);
//#else
// ReactiveCommand.Create<string>(IDesktopAppService.Instance.SetClipboardText);
//#endif
//#endif
CheckUpdateCommand = ReactiveCommand.CreateFromTask(async () =>
{
await IAppUpdateService.Instance.CheckUpdateAsync(showIsExistUpdateFalse: true);
});
DelAccountCommand = ReactiveCommand.CreateFromTask(async () =>
{
if (!UserService.Current.IsAuthenticated) return;
#if !__MOBILE__
var r = await MessageBoxCompat.ShowAsync(AppResources.DelAccountTips, ThisAssembly.AssemblyTrademark, MessageBoxButtonCompat.OKCancel);
if (r == MessageBoxResultCompat.OK)
{
await UserService.Current.DelAccountAsync();
}
#else
throw new NotImplementedException();
#endif
});
#if __MOBILE__
preferenceButtons = new()
{
PreferenceButtonViewModel.Create(PreferenceButton.检查更新, this),
PreferenceButtonViewModel.Create(PreferenceButton.更新日志, this),
PreferenceButtonViewModel.Create(PreferenceButton.常见问题疑难解答, this),
PreferenceButtonViewModel.Create(PreferenceButton.开放源代码许可, this),
PreferenceButtonViewModel.Create(PreferenceButton.源码仓库, this),
PreferenceButtonViewModel.Create(PreferenceButton.产品官网, this),
PreferenceButtonViewModel.Create(PreferenceButton.联系我们, this),
PreferenceButtonViewModel.Create(PreferenceButton.Bug反馈, this),
};
UserService.Current.WhenAnyValue(x => x.User).Subscribe(value =>
{
if (value == null)
{
PreferenceButtonViewModel.RemoveAuthorized(preferenceButtons, this);
}
else
{
var delAccount = preferenceButtons.FirstOrDefault(x => x.Id == PreferenceButton.账号注销);
if (delAccount == null)
{
delAccount = PreferenceButtonViewModel.Create(PreferenceButton.账号注销, this);
preferenceButtons.Add(delAccount);
}
}
}).AddTo(this);
#endif
}
public ReactiveCommand<Unit, Unit> CheckUpdateCommand { get; }
public ReactiveCommand<string, Unit> OpenBrowserCommand { get; }
//#if !__MOBILE__
// public ReactiveCommand<string, Unit> CopyLinkCommand { get; }
//#endif
public ReactiveCommand<Unit, Unit> DelAccountCommand { get; }
static string GetOS() => DI.Platform switch
{
Platform.Windows => "Windows",
Platform.Linux => "Linux",
Platform.Android => "Android",
Platform.Apple => DI.DeviceIdiom switch
{
DeviceIdiom.Phone => "iOS",
DeviceIdiom.Tablet => "iPadOS",
DeviceIdiom.Desktop => "macOS",
DeviceIdiom.TV => "tvOS",
DeviceIdiom.Watch => "watchOS",
_ => string.Empty,
},
Platform.UWP => "UWP",
_ => string.Empty,
};
public string VersionDisplay => $"{ThisAssembly.VersionDisplay} for {GetOS()} ({RuntimeInformation.ProcessArchitecture})";
public string LabelVersionDisplay => ThisAssembly.IsBetaRelease ? "Beta Version:" : "Current Version:";
public string Copyright
{
get
{
// https://www.w3cschool.cn/html/html-copyright.html
int startYear = 2020, thisYear = 2021;
var nowYear = DateTime.Now.Year;
if (nowYear < thisYear) nowYear = thisYear;
return $"© {startYear}{(nowYear == startYear ? startYear : "-" + nowYear)} {ThisAssembly.AssemblyCompany}. All Rights Reserved.";
}
}
}
}
@@ -223,10 +223,10 @@ namespace System.Application.UI.ViewModels
switch (parameter)
{
case Agreement:
parameter = "https://steampp.net/AgreementBox";
parameter = UrlConstants.OfficialWebsite_Box_Agreement;
break;
case Privacy:
parameter = "https://steampp.net/PrivacyBox";
parameter = UrlConstants.OfficialWebsite_Box_Privacy;
break;
}
#if __MOBILE__
@@ -9,11 +9,10 @@
<include layout="@layout/shared_toolbar" />
<ScrollView
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/grey_window_background"
android:fillViewport="true">
android:background="@color/grey_window_background">
<LinearLayout
android:layout_width="match_parent"
@@ -55,6 +54,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/preference_buttons_space_min"
android:textColor="@color/text_primary"
android:textColorLink="@color/text_link"
android:textSize="14sp"
tools:text="Developers: @软妹币玩家 - @AigioL - @Mossimos"
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatTextView" />
@@ -65,6 +65,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/preference_buttons_space_min"
android:textColor="@color/text_primary"
android:textColorLink="@color/text_link"
android:textSize="14sp"
tools:text="Business Cooperation Contact: @Cliencer克总"
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatTextView" />
@@ -75,6 +76,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/preference_buttons_space_min"
android:textColor="@color/text_primary"
android:textColorLink="@color/text_link"
android:textSize="14sp"
tools:text="This open source software is licensed with GPLv3 License"
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatTextView" />
@@ -87,52 +89,29 @@
android:paddingTop="@dimen/preference_buttons_space_min"
android:paddingBottom="@dimen/preference_buttons_space_min"
tools:itemCount="9"
tools:listitem="@layout/layout_preference_large_button"
tools:listitem="@layout/layout_preference_small_button"
xamarin:managedType="AndroidX.RecyclerView.Widget.RecyclerView" />
<!--检查更新-->
<!--更新日志-->
<!--常见问题疑难解答-->
<!--开放源代码许可-->
<!--源码仓库-->
<!--产品官网-->
<!--联系我们-->
<!--Bug反馈-->
<!--账号注销-->
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvAgreementAndPrivacy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/text_primary"
android:textColorLink="@color/text_link"
android:textSize="14sp"
tools:text="用户协议 | 隐私政策"
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatTextView" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center_horizontal"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvAgreementAndPrivacy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/text_primary"
android:textSize="14sp"
tools:text="用户协议 | 隐私政策"
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatTextView" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvCopyright"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/preference_buttons_space_min"
android:layout_marginBottom="@dimen/preference_buttons_space_min"
android:textColor="@color/text_primary"
android:textSize="12sp"
tools:text="© 2020-2021 长沙次元超越科技有限公司. All Rights Reserved."
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatTextView" />
</LinearLayout>
</RelativeLayout>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvCopyright"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/preference_buttons_space_min"
android:layout_marginBottom="@dimen/preference_buttons_space_min"
android:textColor="@color/text_primary"
android:textSize="12sp"
tools:text="© 2020-2021 长沙次元超越科技有限公司. All Rights Reserved."
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatTextView" />
</LinearLayout>
</ScrollView>
</androidx.core.widget.NestedScrollView>
</LinearLayout>
@@ -20,8 +20,8 @@
android:id="@+id/ivIcon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
app:tint="@color/icon_background"
tools:src="@drawable/baseline_account_box_black_24"
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatImageView" />
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:xamarin="http://schemas.xamarin.com/android/xamarin/tools"
android:layout_width="match_parent"
android:layout_height="52dp"
android:background="?android:windowBackground"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
android:paddingStart="@dimen/activity_horizontal_margin"
android:paddingEnd="@dimen/activity_horizontal_margin">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textColor="@color/text_primary"
android:textSize="17sp"
tools:text="检查更新"
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatTextView" />
</FrameLayout>
@@ -82,6 +82,7 @@
<Compile Remove="UI\Views.Controls\**" />
<EmbeddedResource Remove="UI\Views.Controls\**" />
<None Remove="UI\Views.Controls\**" />
<Compile Include="..\Common.ClientLib.Droid\Application\DarkModeUtil.cs" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)'=='Debug'">
@@ -337,6 +338,9 @@
<AndroidResource Include="..\ST.Client.Mobile.Droid.Design\ui\src\main\res\drawable-xxxhdpi\baseline_verified_user_black_24.png">
<Link>Resources\drawable-xxxhdpi\baseline_verified_user_black_24.png</Link>
</AndroidResource>
<AndroidBoundLayout Include="..\ST.Client.Mobile.Droid.Design\ui\src\main\res\layout\activity_about.xml">
<Link>Resources\layout\activity_about.xml</Link>
</AndroidBoundLayout>
<AndroidBoundLayout Include="..\ST.Client.Mobile.Droid.Design\ui\src\main\res\layout\activity_login_or_register.xml">
<Link>Resources\layout\activity_login_or_register.xml</Link>
</AndroidBoundLayout>
@@ -373,6 +377,9 @@
<AndroidBoundLayout Include="..\ST.Client.Mobile.Droid.Design\ui\src\main\res\layout\layout_preference_large_button.xml">
<Link>Resources\layout\layout_preference_large_button.xml</Link>
</AndroidBoundLayout>
<AndroidBoundLayout Include="..\ST.Client.Mobile.Droid.Design\ui\src\main\res\layout\layout_preference_small_button.xml">
<Link>Resources\layout\layout_preference_small_button.xml</Link>
</AndroidBoundLayout>
<AndroidBoundLayout Include="..\ST.Client.Mobile.Droid.Design\ui\src\main\res\layout\shared_loading.xml">
<Link>Resources\layout\shared_loading.xml</Link>
</AndroidBoundLayout>
@@ -474,3 +481,4 @@
@@ -1,15 +1,207 @@
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Graphics;
using Android.OS;
using Android.Runtime;
using Android.Text;
using Android.Text.Style;
using AndroidX.RecyclerView.Widget;
using Binding;
using Google.Android.Material.Dialog;
using ReactiveUI;
using System.Application.UI.Adapters;
using System.Application.UI.Resx;
using System.Application.UI.ViewModels;
using System.Text;
using Xamarin.Essentials;
using static System.Application.Services.CloudService.Constants;
using static System.Application.UI.ViewModels.AboutPageViewModel;
namespace System.Application.UI.Activities
{
[Register(JavaPackageConstants.Activities + nameof(AboutActivity))]
[Activity(Theme = ManifestConstants.MainTheme,
[Activity(Theme = ManifestConstants.MainTheme_NoActionBar,
LaunchMode = LaunchMode.SingleTask,
ConfigurationChanges = ManifestConstants.ConfigurationChanges)]
internal sealed class AboutActivity : BaseActivity
internal sealed class AboutActivity : BaseActivity<activity_about, AboutPageViewModel>
{
protected override int? LayoutResource => throw new NotImplementedException();
protected override int? LayoutResource => Resource.Layout.activity_about;
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
this.SetSupportActionBarWithNavigationClick(binding!.toolbar);
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
ViewModel = new();
ViewModel.AddTo(this);
binding!.tvDevelopers.SetLinkMovementMethod();
binding!.tvBusinessCooperationContact.SetLinkMovementMethod();
binding!.tvOpenSourceLicensed.SetLinkMovementMethod();
binding!.tvAgreementAndPrivacy.SetLinkMovementMethod();
binding!.tvTitle.TextFormatted = CreateTitle();
binding!.tvVersion.Text = $"{ViewModel.LabelVersionDisplay} {ViewModel.VersionDisplay}";
binding!.tvDevelopers.TextFormatted = CreateDevelopers();
binding!.tvBusinessCooperationContact.TextFormatted = CreateBusinessCooperationContact();
binding!.tvOpenSourceLicensed.TextFormatted = CreateOpenSourceLicensed();
binding!.tvCopyright.Text = ViewModel.Copyright;
R.Current.WhenAnyValue(x => x.Res).Subscribe(_ =>
{
Title = ViewModel.Title;
binding!.tvAgreementAndPrivacy.TextFormatted = CreateAgreementAndPrivacy();
}).AddTo(this);
static void BrowserOpenByDialogClick(DialogClickEventArgs e, Func<string, string?> func)
{
if (e.Which >= 0 && e.Which < SourceRepositories.Length)
{
var value = func(SourceRepositories[e.Which]);
if (value != default) BrowserOpen(value);
}
}
var adapter = new SmallPreferenceButtonAdapter<PreferenceButtonViewModel, PreferenceButton>(ViewModel!.PreferenceButtons);
adapter.ItemClick += (_, e) =>
{
switch (e.Current.Id)
{
case PreferenceButton.检查更新:
ViewModel!.CheckUpdateCommand.Invoke();
break;
case PreferenceButton.更新日志:
BrowserOpen(string.Format(
UrlConstants.OfficialWebsite_Box_Changelog_,
MainApplication.GetTheme(),
R.Language));
break;
case PreferenceButton.常见问题疑难解答:
BrowserOpen(string.Format(
UrlConstants.OfficialWebsite_Box_Faq_,
MainApplication.GetTheme(),
R.Language));
break;
case PreferenceButton.开放源代码许可:
throw new NotImplementedException();
break;
case PreferenceButton.源码仓库:
new MaterialAlertDialogBuilder(this).SetItems(SourceRepositories, (_, e) => BrowserOpenByDialogClick(e, value => value switch
{
GitHub => UrlConstants.GitHub_Repository,
Gitee => UrlConstants.Gitee_Repository,
_ => default,
})).Show();
break;
case PreferenceButton.产品官网:
BrowserOpen(UrlConstants.OfficialWebsite);
break;
case PreferenceButton.联系我们:
BrowserOpen(UrlConstants.OfficialWebsite_Contact);
break;
case PreferenceButton.Bug反馈:
new MaterialAlertDialogBuilder(this).SetItems(SourceRepositories, (_, e) => BrowserOpenByDialogClick(e, value => value switch
{
GitHub => UrlConstants.GitHub_Issues,
Gitee => UrlConstants.Gitee_Issues,
_ => default,
})).Show();
break;
case PreferenceButton.账号注销:
ViewModel!.DelAccountCommand.Invoke();
break;
}
};
var layout = new LinearLayoutManager(this, LinearLayoutManager.Vertical, false);
binding.rvPreferenceButtons.SetLayoutManager(layout);
binding.rvPreferenceButtons.SetAdapter(adapter);
}
static SpannableString CreateTitle()
{
SpannableString spannable = new(Title_0 + Title_1);
ForegroundColorSpan fcs = new(ThemeAccentBrushKey.ToPlatformColor());
int start = Title_0.Length, end = Title_0.Length + Title_1.Length;
spannable.SetSpan(fcs, start, end, SpanTypes.ExclusiveExclusive);
StyleSpan ss = new(TypefaceStyle.Bold);
spannable.SetSpan(ss, start, end, SpanTypes.ExclusiveExclusive);
return spannable;
}
static SpannableString CreateDevelopers() => MainApplication.CreateSpannableString(list =>
{
int length;
StringBuilder str = new(Developers_0);
length = str.Length;
str.Append(At_Rmbadmin);
list.Add((new HyperlinkClickableSpan(_ =>
{
BrowserOpen(UrlConstants.GitHub_User_Rmbadmin);
}), length, str.Length, SpanTypes.ExclusiveExclusive));
str.Append(Separator);
length = str.Length;
str.Append(At_AigioL);
list.Add((new HyperlinkClickableSpan(_ =>
{
BrowserOpen(UrlConstants.GitHub_User_AigioL);
}), length, str.Length, SpanTypes.ExclusiveExclusive));
str.Append(Separator);
length = str.Length;
str.Append(At_Mossimos);
list.Add((new HyperlinkClickableSpan(_ =>
{
BrowserOpen(UrlConstants.GitHub_User_Mossimos);
}), length, str.Length, SpanTypes.ExclusiveExclusive));
return str;
});
static SpannableString CreateBusinessCooperationContact() => MainApplication.CreateSpannableString(list =>
{
int length;
StringBuilder str = new(BusinessCooperationContact_0);
length = str.Length;
str.Append(At_Cliencer);
list.Add((new HyperlinkClickableSpan(_ =>
{
BrowserOpen(UrlConstants.BILI_User_Cliencer);
}), length, str.Length, SpanTypes.ExclusiveExclusive));
return str;
});
static SpannableString CreateAgreementAndPrivacy() => MainApplication.CreateSpannableString(list =>
{
int length;
StringBuilder str = new();
length = str.Length;
str.Append(AppResources.User_Agreement);
list.Add((new HyperlinkClickableSpan(_ =>
{
BrowserOpen(UrlConstants.OfficialWebsite_Box_Agreement);
}), length, str.Length, SpanTypes.ExclusiveExclusive));
str.Append(Separator2);
length = str.Length;
str.Append(AppResources.User_Privacy);
list.Add((new HyperlinkClickableSpan(_ =>
{
BrowserOpen(UrlConstants.OfficialWebsite_Box_Privacy);
}), length, str.Length, SpanTypes.ExclusiveExclusive));
return str;
});
static SpannableString CreateOpenSourceLicensed() => MainApplication.CreateSpannableString(list =>
{
int length;
StringBuilder str = new(OpenSourceLicensed_0);
length = str.Length;
str.Append(OpenSourceLicensed_1);
list.Add((new HyperlinkClickableSpan(_ =>
{
BrowserOpen(UrlConstants.License_GPLv3);
}), length, str.Length, SpanTypes.ExclusiveExclusive));
return str;
});
}
}
@@ -10,13 +10,10 @@ using AndroidX.Navigation.UI;
using Binding;
using Microsoft.Identity.Client;
using ReactiveUI;
using System.Application.Mvvm;
using System.Application.UI.Resx;
using System.Application.UI.ViewModels;
using System.Collections.Generic;
using System.Reactive.Disposables;
using System.Text;
using JObject = Java.Lang.Object;
namespace System.Application.UI.Activities
{
@@ -24,11 +21,8 @@ namespace System.Application.UI.Activities
[Activity(Theme = ManifestConstants.MainTheme_NoActionBar,
LaunchMode = LaunchMode.SingleTask,
ConfigurationChanges = ManifestConstants.ConfigurationChanges)]
internal sealed class LoginOrRegisterActivity : BaseActivity<activity_login_or_register, LoginOrRegisterPageViewModel>, IDisposableHolder
internal sealed class LoginOrRegisterActivity : BaseActivity<activity_login_or_register, LoginOrRegisterPageViewModel>
{
readonly CompositeDisposable disposables = new();
ICollection<IDisposable> IDisposableHolder.CompositeDisposable => disposables;
protected override int? LayoutResource => Resource.Layout.activity_login_or_register;
static readonly Dictionary<int, Func<string>> title_strings = new()
@@ -73,15 +67,14 @@ namespace System.Application.UI.Activities
AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(requestCode, resultCode, data);
}
public static SpannableString CreateAgreementAndPrivacy(LoginOrRegisterPageViewModel viewModel)
public static SpannableString CreateAgreementAndPrivacy(LoginOrRegisterPageViewModel viewModel) => MainApplication.CreateSpannableString(list =>
{
int length;
var linkTextIndexs = new List<(JObject what, int start, int end, SpanTypes flags)>();
StringBuilder str = new(AppResources.User_RegisterAgreed);
str.Append(" ");
length = str.Length;
str.Append(AppResources.User_Agreement);
linkTextIndexs.Add((new HyperlinkClickableSpan(_ =>
list.Add((new HyperlinkClickableSpan(_ =>
{
viewModel.OpenHyperlink.Invoke(LoginOrRegisterPageViewModel.Agreement);
}), length, str.Length, SpanTypes.ExclusiveExclusive));
@@ -90,17 +83,11 @@ namespace System.Application.UI.Activities
str.Append(" ");
length = str.Length;
str.Append(AppResources.User_Privacy);
linkTextIndexs.Add((new HyperlinkClickableSpan(_ =>
list.Add((new HyperlinkClickableSpan(_ =>
{
viewModel.OpenHyperlink.Invoke(LoginOrRegisterPageViewModel.Privacy);
}), length, str.Length, SpanTypes.ExclusiveExclusive));
SpannableString spannable = new(str.ToString());
foreach (var (what, start, end, flags) in linkTextIndexs)
{
spannable.SetSpan(what, start, end, flags);
}
return spannable;
}
return str;
});
}
}
@@ -7,10 +7,7 @@ using AndroidX.Navigation.UI;
using Binding;
using Java.Lang;
using ReactiveUI;
using System.Application.Mvvm;
using System.Application.UI.ViewModels;
using System.Collections.Generic;
using System.Reactive.Disposables;
namespace System.Application.UI.Activities
{
@@ -18,11 +15,8 @@ namespace System.Application.UI.Activities
[Activity(Theme = ManifestConstants.MainTheme_NoActionBar,
LaunchMode = LaunchMode.SingleTask,
ConfigurationChanges = ManifestConstants.ConfigurationChanges)]
internal sealed class MainActivity : BaseActivity<activity_main>, IDisposableHolder, IReadOnlyViewFor<MyPageViewModel>
internal sealed class MainActivity : BaseActivity<activity_main>, IReadOnlyViewFor<MyPageViewModel>
{
readonly CompositeDisposable disposables = new();
ICollection<IDisposable> IDisposableHolder.CompositeDisposable => disposables;
protected override int? LayoutResource => Resource.Layout.activity_main;
protected override bool BackToHome => true;
@@ -75,7 +69,6 @@ namespace System.Application.UI.Activities
{
base.OnDestroy();
navController = null;
disposables.Dispose();
}
}
}
@@ -2,14 +2,18 @@ using Android.Views;
using Binding;
using ReactiveUI;
using System.Application.UI.ViewModels;
using TViewHolder = System.Application.UI.Adapters.MyPreferenceButtonViewHolder;
using TViewModel = System.Application.UI.ViewModels.MyPageViewModel.PreferenceButtonViewModel;
using System.Collections.ObjectModel;
namespace System.Application.UI.Adapters
{
internal sealed class MyPreferenceButtonAdapter : BaseReactiveRecycleViewAdapter<TViewHolder, TViewModel>
internal sealed class LargePreferenceButtonAdapter<TViewModel, TId> : BaseReactiveRecycleViewAdapter<LargePreferenceButtonViewHolder<TViewModel, TId>, TViewModel>
where TViewModel : RIdTitleIconViewModel<TId, ResIcon>
{
public MyPreferenceButtonAdapter(MyPageViewModel viewModel) : base(viewModel.PreferenceButtons)
public LargePreferenceButtonAdapter(ObservableCollection<TViewModel> collection) : base(collection)
{
}
public LargePreferenceButtonAdapter(ReadOnlyObservableCollection<TViewModel> collection) : base(collection)
{
}
@@ -19,11 +23,12 @@ namespace System.Application.UI.Adapters
}
}
internal sealed class MyPreferenceButtonViewHolder : BaseReactiveViewHolder<TViewModel>
internal sealed class LargePreferenceButtonViewHolder<TViewModel, TId> : BaseReactiveViewHolder<TViewModel>
where TViewModel : RIdTitleIconViewModel<TId, ResIcon>
{
readonly layout_preference_large_button binding;
public MyPreferenceButtonViewHolder(View itemView) : base(itemView)
public LargePreferenceButtonViewHolder(View itemView) : base(itemView)
{
binding = new(itemView);
}
@@ -0,0 +1,46 @@
using Android.Views;
using Binding;
using ReactiveUI;
using System.Application.UI.ViewModels;
using System.Collections.ObjectModel;
namespace System.Application.UI.Adapters
{
internal sealed class SmallPreferenceButtonAdapter<TViewModel, TId> : BaseReactiveRecycleViewAdapter<SmallPreferenceButtonViewHolder<TViewModel, TId>, TViewModel>
where TViewModel : RIdTitleViewModel<TId>
{
public SmallPreferenceButtonAdapter(ObservableCollection<TViewModel> collection) : base(collection)
{
}
public SmallPreferenceButtonAdapter(ReadOnlyObservableCollection<TViewModel> collection) : base(collection)
{
}
public override int? GetLayoutResource(int viewType)
{
return Resource.Layout.layout_preference_small_button;
}
}
internal sealed class SmallPreferenceButtonViewHolder<TViewModel, TId> : BaseReactiveViewHolder<TViewModel>
where TViewModel : RIdTitleViewModel<TId>
{
readonly layout_preference_small_button binding;
public SmallPreferenceButtonViewHolder(View itemView) : base(itemView)
{
binding = new(itemView);
}
public override void OnBind()
{
base.OnBind();
ViewModel!.WhenAnyValue(x => x.Title).Subscribe(value =>
{
binding.tvTitle.Text = value;
}).AddTo(this);
}
}
}
@@ -5,7 +5,10 @@ using Android.Views;
using AndroidX.AppCompat.App;
using ReactiveUI;
using ReactiveUI.AndroidX;
using System.Application.Mvvm;
using System.Application.UI.ViewModels;
using System.Collections.Generic;
using System.Reactive.Disposables;
using XEPlatform = Xamarin.Essentials.Platform;
// ReSharper disable once CheckNamespace
@@ -54,8 +57,12 @@ namespace System.Application.UI.Activities
}
/// <inheritdoc cref="BaseActivity"/>
public abstract partial class BaseActivity<TViewBinding> : BaseActivity where TViewBinding : class
public abstract partial class BaseActivity<TViewBinding> : BaseActivity, IDisposableHolder
where TViewBinding : class
{
readonly CompositeDisposable disposables = new();
ICollection<IDisposable> IDisposableHolder.CompositeDisposable => disposables;
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
@@ -65,6 +72,7 @@ namespace System.Application.UI.Activities
protected override void OnDestroy()
{
base.OnDestroy();
disposables.Dispose();
binding = null;
}
}
@@ -81,9 +89,13 @@ namespace System.Application.UI.Activities
/// </summary>
/// <typeparam name="TViewBinding"></typeparam>
/// <typeparam name="TViewModel"></typeparam>
public abstract partial class BaseActivity<TViewBinding, TViewModel> : ReactiveAppCompatActivity<TViewModel>, IReadOnlyViewFor<TViewModel> where TViewBinding : class
public abstract partial class BaseActivity<TViewBinding, TViewModel> : ReactiveAppCompatActivity<TViewModel>, IReadOnlyViewFor<TViewModel>, IDisposableHolder
where TViewBinding : class
where TViewModel : ViewModelBase
{
readonly CompositeDisposable disposables = new();
ICollection<IDisposable> IDisposableHolder.CompositeDisposable => disposables;
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
@@ -113,6 +125,7 @@ namespace System.Application.UI.Activities
ClearOnClickListener();
if (navController != null) navController = null;
base.OnDestroy();
disposables.Dispose();
binding = null;
}
}
@@ -1,9 +1,10 @@
using Android.OS;
using Android.Views;
using ReactiveUI.AndroidX;
using System.Application;
using System.Application.Mvvm;
using System.Application.UI.ViewModels;
using System.Collections.Generic;
using System.Reactive.Disposables;
using Fragment = AndroidX.Fragment.App.Fragment;
// ReSharper disable once CheckNamespace
@@ -37,7 +38,7 @@ namespace System.Application.UI.Fragments
public override void OnDestroyView()
{
ClearOnClickListener();
base.OnDestroy();
base.OnDestroyView();
}
}
@@ -64,10 +65,13 @@ namespace System.Application.UI.Fragments
/// </summary>
/// <typeparam name="TViewBinding"></typeparam>
/// <typeparam name="TViewModel"></typeparam>
public abstract partial class BaseFragment<TViewBinding, TViewModel> : ReactiveFragment<TViewModel>, ReactiveUI.IReadOnlyViewFor<TViewModel>
public abstract partial class BaseFragment<TViewBinding, TViewModel> : ReactiveFragment<TViewModel>, ReactiveUI.IReadOnlyViewFor<TViewModel>, IDisposableHolder
where TViewBinding : class
where TViewModel : ViewModelBase
{
readonly CompositeDisposable disposables = new();
ICollection<IDisposable> IDisposableHolder.CompositeDisposable => disposables;
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var view = BaseFragment.CreateView(LayoutResource, inflater, container);
@@ -81,7 +85,8 @@ namespace System.Application.UI.Fragments
public override void OnDestroyView()
{
ClearOnClickListener();
base.OnDestroy();
base.OnDestroyView();
disposables.Dispose();
binding = null;
}
}
@@ -1,26 +1,19 @@
using Android.Runtime;
using Android.Text.Method;
using Android.Views;
using AndroidX.RecyclerView.Widget;
using Binding;
using ReactiveUI;
using System.Application.Mvvm;
using System.Application.UI.Activities;
using System.Application.UI.Adapters;
using System.Application.UI.Resx;
using System.Application.UI.ViewModels;
using System.Collections.Generic;
using System.Reactive.Disposables;
using static System.Application.UI.ViewModels.LoginOrRegisterPageViewModel;
namespace System.Application.UI.Fragments
{
[Register(JavaPackageConstants.Fragments + nameof(FastLoginOrRegisterFragment))]
internal sealed class FastLoginOrRegisterFragment : BaseFragment<fragment_login_and_register_by_fast, LoginOrRegisterPageViewModel>, IDisposableHolder
internal sealed class FastLoginOrRegisterFragment : BaseFragment<fragment_login_and_register_by_fast, LoginOrRegisterPageViewModel>
{
readonly CompositeDisposable disposables = new();
ICollection<IDisposable> IDisposableHolder.CompositeDisposable => disposables;
protected override int? LayoutResource => Resource.Layout.fragment_login_and_register_by_fast;
public override void OnCreateView(View view)
@@ -3,23 +3,17 @@ using Android.Views;
using AndroidX.RecyclerView.Widget;
using Binding;
using ReactiveUI;
using System.Application.Mvvm;
using System.Application.Services;
using System.Application.UI.Activities;
using System.Application.UI.Adapters;
using System.Application.UI.ViewModels;
using System.Collections.Generic;
using System.Reactive.Disposables;
using static System.Application.UI.ViewModels.MyPageViewModel;
namespace System.Application.UI.Fragments
{
[Register(JavaPackageConstants.Fragments + nameof(MyFragment))]
internal sealed class MyFragment : BaseFragment<fragment_my, MyPageViewModel>, IDisposableHolder
internal sealed class MyFragment : BaseFragment<fragment_my, MyPageViewModel>
{
readonly CompositeDisposable disposables = new();
ICollection<IDisposable> IDisposableHolder.CompositeDisposable => disposables;
protected override int? LayoutResource => Resource.Layout.fragment_my;
public override void OnCreateView(View view)
@@ -34,7 +28,7 @@ namespace System.Application.UI.Fragments
SetOnClickListener(binding!.layoutUser);
var adapter = new MyPreferenceButtonAdapter(ViewModel!);
var adapter = new LargePreferenceButtonAdapter<PreferenceButtonViewModel, PreferenceButton>(ViewModel!.PreferenceButtons);
adapter.ItemClick += (_, e) =>
{
if (e.Current.Authentication && !UserService.Current.IsAuthenticated)
@@ -60,12 +54,6 @@ namespace System.Application.UI.Fragments
binding.rvPreferenceButtons.SetAdapter(adapter);
}
public override void OnDestroyView()
{
base.OnDestroyView();
disposables.Dispose();
}
protected override bool OnClick(View view)
{
if (view.Id == Resource.Id.layoutUser)
@@ -5,22 +5,16 @@ using Android.Views.InputMethods;
using Android.Widget;
using Binding;
using ReactiveUI;
using System.Application.Mvvm;
using System.Application.Services;
using System.Application.UI.Activities;
using System.Application.UI.Resx;
using System.Application.UI.ViewModels;
using System.Collections.Generic;
using System.Reactive.Disposables;
namespace System.Application.UI.Fragments
{
[Register(JavaPackageConstants.Fragments + nameof(PhoneNumberLoginOrRegisterFragment))]
internal sealed class PhoneNumberLoginOrRegisterFragment : BaseFragment<fragment_login_and_register_by_phone_number, LoginOrRegisterPageViewModel>, IDisposableHolder, TextView.IOnEditorActionListener
internal sealed class PhoneNumberLoginOrRegisterFragment : BaseFragment<fragment_login_and_register_by_phone_number, LoginOrRegisterPageViewModel>, TextView.IOnEditorActionListener
{
readonly CompositeDisposable disposables = new();
ICollection<IDisposable> IDisposableHolder.CompositeDisposable => disposables;
protected override int? LayoutResource => Resource.Layout.fragment_login_and_register_by_phone_number;
public override void OnCreateView(View view)
@@ -1,10 +1,15 @@
using Android.App;
using Android.Runtime;
using Android.Text;
using System.Application.Security;
using System.Application.UI.ViewModels;
using System.Collections.Generic;
using System.Text;
using Xamarin.Essentials;
using _ThisAssembly = System.Properties.ThisAssembly;
using AndroidApplication = Android.App.Application;
using AppTheme = System.Application.Models.AppTheme;
using JObject = Java.Lang.Object;
using XEFileProvider = Xamarin.Essentials.FileProvider;
using XEPlatform = Xamarin.Essentials.Platform;
using XEVersionTracking = Xamarin.Essentials.VersionTracking;
@@ -71,5 +76,27 @@ namespace System.Application.UI
}
return true;
}
public static string GetTheme()
{
if (DarkModeUtil.IsDarkMode(Context))
{
return AppTheme.Dark.ToString2();
}
return AppTheme.Light.ToString2();
}
public static SpannableString CreateSpannableString(Func<List<(JObject what, int start, int end, SpanTypes flags)>, StringBuilder> func)
{
var linkTextIndexs = new List<(JObject what, int start, int end, SpanTypes flags)>();
var sb = func(linkTextIndexs);
var str = sb.ToString();
SpannableString spannable = new(str);
foreach (var (what, start, end, flags) in linkTextIndexs)
{
spannable.SetSpan(what, start, end, flags);
}
return spannable;
}
}
}
@@ -64,6 +64,12 @@
<LinkBase>Services\Implementation</LinkBase>
</Compile>
<Compile Include="..\ST.Client.Desktop\ServiceCollectionExtensions.TryAddFontManager.cs"/>
<Compile Include="..\ST.Client.Desktop\UI\ViewModels\Pages\About\AboutPageViewModel.shared.cs">
<Link>UI\ViewModels\AboutPageViewModel.shared.cs</Link>
</Compile>
<Compile Include="..\ST.Client.Desktop\Models\Enum\AppTheme.cs">
<LinkBase>Models\Enum</LinkBase>
</Compile>
</ItemGroup>
<ItemGroup>
@@ -0,0 +1,102 @@
using ReactiveUI;
using System.Application.Mvvm;
using System.Application.UI.Resx;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Linq;
using Xamarin.Essentials;
namespace System.Application.UI.ViewModels
{
partial class AboutPageViewModel : ViewModelBase
{
public string Title => TitleName;
ObservableCollection<PreferenceButtonViewModel> preferenceButtons;
public ObservableCollection<PreferenceButtonViewModel> PreferenceButtons
{
get => preferenceButtons;
set => this.RaiseAndSetIfChanged(ref preferenceButtons, value);
}
public enum PreferenceButton
{
检查更新 = 1,
更新日志,
常见问题疑难解答,
开放源代码许可,
源码仓库,
产品官网,
联系我们,
Bug反馈,
账号注销,
}
public sealed class PreferenceButtonViewModel : RIdTitleViewModel<PreferenceButton>
{
PreferenceButtonViewModel()
{
}
protected override string GetTitleById(PreferenceButton id)
{
var title = id switch
{
PreferenceButton.检查更新 => AppResources.CheckUpdate,
PreferenceButton.更新日志 => AppResources.About_UpdateLog,
PreferenceButton.常见问题疑难解答 => AppResources.About_FAQ,
PreferenceButton.开放源代码许可 => AppResources.About_OpenSource,
PreferenceButton.源码仓库 => AppResources.SourceRepository,
PreferenceButton.产品官网 => AppResources.ProductOfficialWebsite,
PreferenceButton.联系我们 => AppResources.About_Contactus,
PreferenceButton.Bug反馈 => AppResources.BugFeedback,
PreferenceButton.账号注销 => AppResources.DelAccount,
_ => string.Empty,
};
return title;
}
public static void RemoveAuthorized(ICollection<PreferenceButtonViewModel> collection, IDisposableHolder vm)
{
var removeArray = collection.Where(x => x.Id == PreferenceButton.账号注销).ToArray();
Array.ForEach(removeArray, x =>
{
collection.Remove(x);
x.OnUnbind(vm);
});
}
/// <summary>
/// 创建实例
/// </summary>
/// <param name="id"></param>
/// <param name="vm"></param>
/// <returns></returns>
public static PreferenceButtonViewModel Create(PreferenceButton id, IDisposableHolder vm)
{
PreferenceButtonViewModel r = new() { Id = id, };
r.OnBind(vm);
return r;
}
}
public const string GitHub = "GitHub";
public const string Gitee = "Gitee";
public static readonly string[] SourceRepositories = new[] { GitHub, Gitee };
public const string Title_0 = "Steam++ Tools ";
public const string Title_1 = "2.0";
public const string Developers_0 = "Developers: ";
public const string Separator = " - ";
public const string Separator2 = " | ";
public const string At_Rmbadmin = "@软妹币玩家";
public const string At_AigioL = "@AigioL";
public const string At_Mossimos = "@Mossimos";
public const string At_Cliencer = "@Cliencer克总";
public const string BusinessCooperationContact_0 = "Business Cooperation Contact: ";
public const string OpenSourceLicensed_0 = "This open source software is licensed with ";
public const string OpenSourceLicensed_1 = "GPLv3 License";
const string _ThemeAccentBrushKey = "#FF0078D7";
public static readonly Color ThemeAccentBrushKey = ColorConverters.FromHex(_ThemeAccentBrushKey);
}
}
@@ -61,4 +61,11 @@ namespace System.Application.UI.ViewModels
GC.SuppressFinalize(this);
}
}
public abstract class RIdTitleViewModel<TId> : RIdTitleIconViewModel<TId, byte>
{
protected sealed override bool IgnoreIcon => true;
protected sealed override byte GetIconById(TId? id) => default;
}
}
@@ -600,7 +600,7 @@ namespace System.Application.Services.Implementation
/// <summary>
/// 在应用商店中打开
/// </summary>
protected virtual void OpenInAppStore() => BrowserOpen("https://steampp.net/");
protected virtual void OpenInAppStore() => BrowserOpen(UrlConstants.OfficialWebsite);
void StartUpdate()
{
+29
View File
@@ -0,0 +1,29 @@
namespace System.Application
{
public static class UrlConstants
{
public const string GitHub_User_Rmbadmin = "https://github.com/rmbadmin";
public const string GitHub_User_AigioL = "https://github.com/AigioL";
public const string GitHub_User_Mossimos = "https://github.com/Mossimos";
public const string BILI_User_Cliencer = "https://space.bilibili.com/30031316";
public const string OfficialWebsite = "https://steampp.net";
public const string OfficialWebsite_Privacy = "https://steampp.net/privacy";
public const string OfficialWebsite_Agreement = "https://steampp.net/agreement";
public const string OfficialWebsite_Contact = "https://steampp.net/contact";
public const string OfficialWebsite_Faq = "https://steampp.net/faq";
public const string OfficialWebsite_Box_Changelog_ = "https://steampp.net/changelogbox?theme={0}&language={1}";
public const string OfficialWebsite_Box_Faq_ = "https://steampp.net/faqbox?theme={0}&language={1}";
public const string OfficialWebsite_Box_Privacy = "https://steampp.net/PrivacyBox";
public const string OfficialWebsite_Box_Agreement = "https://steampp.net/AgreementBox";
public const string GitHub_Repository = "https://github.com/SteamTools-Team/SteamTools";
public const string Gitee_Repository = "https://gitee.com/rmbgame/SteamTools";
public const string GitHub_Issues = "https://github.com/SteamTools-Team/SteamTools";
public const string Gitee_Issues = "https://gitee.com/rmbgame/SteamTools";
public const string License_GPLv3 = "https://www.gnu.org/licenses/gpl-3.0.html";
}
}