diff --git a/references/AvaloniaGif b/references/AvaloniaGif
index 16c810dce..0356f4bad 160000
--- a/references/AvaloniaGif
+++ b/references/AvaloniaGif
@@ -1 +1 @@
-Subproject commit 16c810dce2178ec554ccd29b57359f8ca37bbb69
+Subproject commit 0356f4bad09c6236a5ff7f7d1a03af669575f054
diff --git a/src/Common.ClientLib.Droid/Application/DarkModeUtil.cs b/src/Common.ClientLib.Droid/Application/DarkModeUtil.cs
index 8f9edf3ae..3738a8950 100644
--- a/src/Common.ClientLib.Droid/Application/DarkModeUtil.cs
+++ b/src/Common.ClientLib.Droid/Application/DarkModeUtil.cs
@@ -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
///
///
///
- static bool IsDarkMode(Context context)
+ public static bool IsDarkMode(Context context)
{
var isNight = IsNight(context);
return isNight.HasValue && isNight.Value;
}
- ///
- /// 是否正在安卓Q中使用深色主题(Dark)
- ///
- public static bool IsDarkModeQ
- => Build.VERSION.SdkInt >= BuildVersionCodes.Q && IsDarkMode(AndroidApplication.Context);
+ /////
+ ///// 是否正在安卓Q中使用深色主题(Dark)
+ /////
+ //public static bool IsDarkModeQ
+ // => Build.VERSION.SdkInt >= BuildVersionCodes.Q && IsDarkMode(AndroidApplication.Context);
}
}
\ No newline at end of file
diff --git a/src/Common.ClientLib.Droid/Application/UI/Internals/IToolbar.cs b/src/Common.ClientLib.Droid/Application/UI/Internals/IToolbar.cs
index e40773cf9..ce0baf229 100644
--- a/src/Common.ClientLib.Droid/Application/UI/Internals/IToolbar.cs
+++ b/src/Common.ClientLib.Droid/Application/UI/Internals/IToolbar.cs
@@ -1,4 +1,4 @@
-using AndroidX.AppCompat.App;
+using AndroidX.AppCompat.App;
using AndroidX.AppCompat.Widget;
using System.Application.UI.Internals;
using System.Common;
diff --git a/src/Common.ClientLib/Application/UI/ViewModels/IdTitleIconViewModel.cs b/src/Common.ClientLib/Application/UI/ViewModels/IdTitleIconViewModel.cs
index 12ab9b4b0..e261f5f35 100644
--- a/src/Common.ClientLib/Application/UI/ViewModels/IdTitleIconViewModel.cs
+++ b/src/Common.ClientLib/Application/UI/ViewModels/IdTitleIconViewModel.cs
@@ -4,6 +4,8 @@ namespace System.Application.UI.ViewModels
{
public abstract class IdTitleIconViewModel : ReactiveObject
{
+ protected virtual bool IgnoreIcon { get; }
+
protected TId? id;
///
/// 唯一键
@@ -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);
}
}
diff --git a/src/ST.Client.Desktop.Avalonia/Application/UI/CefNetApp.cs b/src/ST.Client.Desktop.Avalonia/Application/UI/CefNetApp.cs
index df7ba372a..251a9e74b 100644
--- a/src/ST.Client.Desktop.Avalonia/Application/UI/CefNetApp.cs
+++ b/src/ST.Client.Desktop.Avalonia/Application/UI/CefNetApp.cs
@@ -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();
}
}
}
diff --git a/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Pages/About/About_Changelog.axaml.cs b/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Pages/About/About_Changelog.axaml.cs
index a09778014..60c68aeeb 100644
--- a/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Pages/About/About_Changelog.axaml.cs
+++ b/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Pages/About/About_Changelog.axaml.cs
@@ -18,7 +18,7 @@ namespace System.Application.UI.Views.Pages
webView = this.FindControl(nameof(webView));
webView.Url = string.Format(
- "https://steampp.net/changelogbox?theme={0}&language={1}",
+ UrlConstants.OfficialWebsite_Box_Changelog_,
CefNetApp.GetTheme(),
R.Language);
}
diff --git a/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Pages/About/About_FAQPage.axaml.cs b/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Pages/About/About_FAQPage.axaml.cs
index 791369992..db30ea9c1 100644
--- a/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Pages/About/About_FAQPage.axaml.cs
+++ b/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Pages/About/About_FAQPage.axaml.cs
@@ -17,7 +17,7 @@ namespace System.Application.UI.Views.Pages
InitializeComponent();
webViewQA = this.FindControl("webViewQA");
webViewQA.Url = string.Format(
- "https://steampp.net/faqbox?theme={0}&language={1}",
+ UrlConstants.OfficialWebsite_Box_Faq_,
CefNetApp.GetTheme(),
R.Language);
}
diff --git a/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Windows/ShareManagePage/ShareManageWindow.axaml b/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Windows/ShareManagePage/ShareManageWindow.axaml
index 9cc2809a7..73a872c1f 100644
--- a/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Windows/ShareManagePage/ShareManageWindow.axaml
+++ b/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Windows/ShareManagePage/ShareManageWindow.axaml
@@ -20,7 +20,7 @@
x:DataType="vm:ShareManageViewModel"
x:CompileBindings="True">
-
+
+
+
diff --git a/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Windows/WebView3Window.axaml.cs b/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Windows/WebView3Window.axaml.cs
index 8b7f60fc4..f37525214 100644
--- a/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Windows/WebView3Window.axaml.cs
+++ b/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Windows/WebView3Window.axaml.cs
@@ -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(),
diff --git a/src/ST.Client.Desktop/Models/Enum/AppTheme.cs b/src/ST.Client.Desktop/Models/Enum/AppTheme.cs
index 48e795d45..ebab2cb0b 100644
--- a/src/ST.Client.Desktop/Models/Enum/AppTheme.cs
+++ b/src/ST.Client.Desktop/Models/Enum/AppTheme.cs
@@ -1,4 +1,6 @@
-namespace System.Application.Models
+using System.Application.Models;
+
+namespace System.Application.Models
{
///
/// 应用程序主题
@@ -23,6 +25,23 @@
///
/// 自定义主题
///
+ [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",
+ };
+ }
+ }
}
\ No newline at end of file
diff --git a/src/ST.Client.Desktop/Services/Mvvm/UserService.cs b/src/ST.Client.Desktop/Services/Mvvm/UserService.cs
index 7bf427f1b..10ace03f1 100644
--- a/src/ST.Client.Desktop/Services/Mvvm/UserService.cs
+++ b/src/ST.Client.Desktop/Services/Mvvm/UserService.cs
@@ -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);
diff --git a/src/ST.Client.Desktop/UI/Resx/AppResources.Designer.cs b/src/ST.Client.Desktop/UI/Resx/AppResources.Designer.cs
index 93a2ac2e2..2d70921f8 100644
--- a/src/ST.Client.Desktop/UI/Resx/AppResources.Designer.cs
+++ b/src/ST.Client.Desktop/UI/Resx/AppResources.Designer.cs
@@ -440,6 +440,15 @@ namespace System.Application.UI.Resx {
}
}
+ ///
+ /// 查找类似 Bug 反馈 的本地化字符串。
+ ///
+ public static string BugFeedback {
+ get {
+ return ResourceManager.GetString("BugFeedback", resourceCulture);
+ }
+ }
+
///
/// 查找类似 取消 的本地化字符串。
///
@@ -2520,6 +2529,15 @@ namespace System.Application.UI.Resx {
}
}
+ ///
+ /// 查找类似 产品官网 的本地化字符串。
+ ///
+ public static string ProductOfficialWebsite {
+ get {
+ return ResourceManager.GetString("ProductOfficialWebsite", resourceCulture);
+ }
+ }
+
///
/// 查找类似 恢复代码 的本地化字符串。
///
@@ -2988,6 +3006,15 @@ namespace System.Application.UI.Resx {
}
}
+ ///
+ /// 查找类似 源码仓库 的本地化字符串。
+ ///
+ public static string SourceRepository {
+ get {
+ return ResourceManager.GetString("SourceRepository", resourceCulture);
+ }
+ }
+
///
/// 查找类似 开始更新 的本地化字符串。
///
diff --git a/src/ST.Client.Desktop/UI/Resx/AppResources.resx b/src/ST.Client.Desktop/UI/Resx/AppResources.resx
index 97d1ab529..1f80100e3 100644
--- a/src/ST.Client.Desktop/UI/Resx/AppResources.resx
+++ b/src/ST.Client.Desktop/UI/Resx/AppResources.resx
@@ -245,6 +245,9 @@
继续
+
+ Bug 反馈
+
取消
@@ -942,6 +945,9 @@
请选择
+
+ 产品官网
+
恢复代码
@@ -1099,6 +1105,9 @@
短信验证代码
+
+ 源码仓库
+
开始更新
diff --git a/src/ST.Client.Desktop/UI/ViewModels/Pages/About/AboutPageViewModel.cs b/src/ST.Client.Desktop/UI/ViewModels/Pages/About/AboutPageViewModel.cs
index 70a359ada..ffeaf1297 100644
--- a/src/ST.Client.Desktop/UI/ViewModels/Pages/About/AboutPageViewModel.cs
+++ b/src/ST.Client.Desktop/UI/ViewModels/Pages/About/AboutPageViewModel.cs
@@ -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(BrowserOpen);
-
- CopyLinkCommand = ReactiveCommand.Create(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 CheckUpdateCommand { get; }
-
- public ReactiveCommand OpenBrowserCommand { get; }
-
- public ReactiveCommand CopyLinkCommand { get; }
-
- public ReactiveCommand 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;
}
}
\ No newline at end of file
diff --git a/src/ST.Client.Desktop/UI/ViewModels/Pages/About/AboutPageViewModel.shared.cs b/src/ST.Client.Desktop/UI/ViewModels/Pages/About/AboutPageViewModel.shared.cs
new file mode 100644
index 000000000..63081a4e7
--- /dev/null
+++ b/src/ST.Client.Desktop/UI/ViewModels/Pages/About/AboutPageViewModel.shared.cs
@@ -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(BrowserOpen);
+
+ //#if !__MOBILE__
+ // CopyLinkCommand =
+ //#if __MOBILE__
+ // ReactiveCommand.CreateFromTask(Clipboard.SetTextAsync);
+ //#else
+ // ReactiveCommand.Create(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 CheckUpdateCommand { get; }
+
+ public ReactiveCommand OpenBrowserCommand { get; }
+
+ //#if !__MOBILE__
+ // public ReactiveCommand CopyLinkCommand { get; }
+ //#endif
+
+ public ReactiveCommand 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.";
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ST.Client.Desktop/UI/ViewModels/Windows/LoginOrRegisterWindowViewModel.shared.cs b/src/ST.Client.Desktop/UI/ViewModels/Windows/LoginOrRegisterWindowViewModel.shared.cs
index 55452712f..0a6829928 100644
--- a/src/ST.Client.Desktop/UI/ViewModels/Windows/LoginOrRegisterWindowViewModel.shared.cs
+++ b/src/ST.Client.Desktop/UI/ViewModels/Windows/LoginOrRegisterWindowViewModel.shared.cs
@@ -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__
diff --git a/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/activity_about.xml b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/activity_about.xml
index f1defb6ad..68f7ec469 100644
--- a/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/activity_about.xml
+++ b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/activity_about.xml
@@ -9,11 +9,10 @@
-
+ android:background="@color/grey_window_background">
@@ -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" />
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
-
+
diff --git a/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/layout_preference_large_button.xml b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/layout_preference_large_button.xml
index 95e13ff88..9fcd49825 100644
--- a/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/layout_preference_large_button.xml
+++ b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/layout_preference_large_button.xml
@@ -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" />
diff --git a/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/layout_preference_small_button.xml b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/layout_preference_small_button.xml
new file mode 100644
index 000000000..85d6bcff8
--- /dev/null
+++ b/src/ST.Client.Mobile.Droid.Design/ui/src/main/res/layout/layout_preference_small_button.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
diff --git a/src/ST.Client.Mobile.Droid/ST.Client.Mobile.Droid.csproj b/src/ST.Client.Mobile.Droid/ST.Client.Mobile.Droid.csproj
index d421018bb..d65514d9f 100644
--- a/src/ST.Client.Mobile.Droid/ST.Client.Mobile.Droid.csproj
+++ b/src/ST.Client.Mobile.Droid/ST.Client.Mobile.Droid.csproj
@@ -82,6 +82,7 @@
+
@@ -337,6 +338,9 @@
Resources\drawable-xxxhdpi\baseline_verified_user_black_24.png
+
+ Resources\layout\activity_about.xml
+
Resources\layout\activity_login_or_register.xml
@@ -373,6 +377,9 @@
Resources\layout\layout_preference_large_button.xml
+
+ Resources\layout\layout_preference_small_button.xml
+
Resources\layout\shared_loading.xml
@@ -474,3 +481,4 @@
+
diff --git a/src/ST.Client.Mobile.Droid/UI/Activities/AboutActivity.cs b/src/ST.Client.Mobile.Droid/UI/Activities/AboutActivity.cs
index 78a61d770..57134495b 100644
--- a/src/ST.Client.Mobile.Droid/UI/Activities/AboutActivity.cs
+++ b/src/ST.Client.Mobile.Droid/UI/Activities/AboutActivity.cs
@@ -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
{
- 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 func)
+ {
+ if (e.Which >= 0 && e.Which < SourceRepositories.Length)
+ {
+ var value = func(SourceRepositories[e.Which]);
+ if (value != default) BrowserOpen(value);
+ }
+ }
+
+ var adapter = new SmallPreferenceButtonAdapter(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;
+ });
}
}
\ No newline at end of file
diff --git a/src/ST.Client.Mobile.Droid/UI/Activities/LoginOrRegisterActivity.cs b/src/ST.Client.Mobile.Droid/UI/Activities/LoginOrRegisterActivity.cs
index 1491e057c..fed126425 100644
--- a/src/ST.Client.Mobile.Droid/UI/Activities/LoginOrRegisterActivity.cs
+++ b/src/ST.Client.Mobile.Droid/UI/Activities/LoginOrRegisterActivity.cs
@@ -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, IDisposableHolder
+ internal sealed class LoginOrRegisterActivity : BaseActivity
{
- readonly CompositeDisposable disposables = new();
- ICollection IDisposableHolder.CompositeDisposable => disposables;
-
protected override int? LayoutResource => Resource.Layout.activity_login_or_register;
static readonly Dictionary> 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;
+ });
}
}
\ No newline at end of file
diff --git a/src/ST.Client.Mobile.Droid/UI/Activities/MainActivity.cs b/src/ST.Client.Mobile.Droid/UI/Activities/MainActivity.cs
index df843e1a0..ee999061f 100644
--- a/src/ST.Client.Mobile.Droid/UI/Activities/MainActivity.cs
+++ b/src/ST.Client.Mobile.Droid/UI/Activities/MainActivity.cs
@@ -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, IDisposableHolder, IReadOnlyViewFor
+ internal sealed class MainActivity : BaseActivity, IReadOnlyViewFor
{
- readonly CompositeDisposable disposables = new();
- ICollection 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();
}
}
}
\ No newline at end of file
diff --git a/src/ST.Client.Mobile.Droid/UI/Adapters/MyPreferenceButtonAdapter.cs b/src/ST.Client.Mobile.Droid/UI/Adapters/LargePreferenceButtonAdapter.cs
similarity index 52%
rename from src/ST.Client.Mobile.Droid/UI/Adapters/MyPreferenceButtonAdapter.cs
rename to src/ST.Client.Mobile.Droid/UI/Adapters/LargePreferenceButtonAdapter.cs
index 34e379ad4..a6b680ad1 100644
--- a/src/ST.Client.Mobile.Droid/UI/Adapters/MyPreferenceButtonAdapter.cs
+++ b/src/ST.Client.Mobile.Droid/UI/Adapters/LargePreferenceButtonAdapter.cs
@@ -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
+ internal sealed class LargePreferenceButtonAdapter : BaseReactiveRecycleViewAdapter, TViewModel>
+ where TViewModel : RIdTitleIconViewModel
{
- public MyPreferenceButtonAdapter(MyPageViewModel viewModel) : base(viewModel.PreferenceButtons)
+ public LargePreferenceButtonAdapter(ObservableCollection collection) : base(collection)
+ {
+ }
+
+ public LargePreferenceButtonAdapter(ReadOnlyObservableCollection collection) : base(collection)
{
}
@@ -19,11 +23,12 @@ namespace System.Application.UI.Adapters
}
}
- internal sealed class MyPreferenceButtonViewHolder : BaseReactiveViewHolder
+ internal sealed class LargePreferenceButtonViewHolder : BaseReactiveViewHolder
+ where TViewModel : RIdTitleIconViewModel
{
readonly layout_preference_large_button binding;
- public MyPreferenceButtonViewHolder(View itemView) : base(itemView)
+ public LargePreferenceButtonViewHolder(View itemView) : base(itemView)
{
binding = new(itemView);
}
diff --git a/src/ST.Client.Mobile.Droid/UI/Adapters/SmallPreferenceButtonAdapter.cs b/src/ST.Client.Mobile.Droid/UI/Adapters/SmallPreferenceButtonAdapter.cs
new file mode 100644
index 000000000..237004925
--- /dev/null
+++ b/src/ST.Client.Mobile.Droid/UI/Adapters/SmallPreferenceButtonAdapter.cs
@@ -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 : BaseReactiveRecycleViewAdapter, TViewModel>
+ where TViewModel : RIdTitleViewModel
+ {
+ public SmallPreferenceButtonAdapter(ObservableCollection collection) : base(collection)
+ {
+ }
+
+ public SmallPreferenceButtonAdapter(ReadOnlyObservableCollection collection) : base(collection)
+ {
+ }
+
+ public override int? GetLayoutResource(int viewType)
+ {
+ return Resource.Layout.layout_preference_small_button;
+ }
+ }
+
+ internal sealed class SmallPreferenceButtonViewHolder : BaseReactiveViewHolder
+ where TViewModel : RIdTitleViewModel
+ {
+ 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);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ST.Client.Mobile.Droid/UI/Base/BaseActivity.cs b/src/ST.Client.Mobile.Droid/UI/Base/BaseActivity.cs
index 8cca7dfc0..53cc367fe 100644
--- a/src/ST.Client.Mobile.Droid/UI/Base/BaseActivity.cs
+++ b/src/ST.Client.Mobile.Droid/UI/Base/BaseActivity.cs
@@ -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
}
///
- public abstract partial class BaseActivity : BaseActivity where TViewBinding : class
+ public abstract partial class BaseActivity : BaseActivity, IDisposableHolder
+ where TViewBinding : class
{
+ readonly CompositeDisposable disposables = new();
+ ICollection 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
///
///
///
- public abstract partial class BaseActivity : ReactiveAppCompatActivity, IReadOnlyViewFor where TViewBinding : class
+ public abstract partial class BaseActivity : ReactiveAppCompatActivity, IReadOnlyViewFor, IDisposableHolder
+ where TViewBinding : class
where TViewModel : ViewModelBase
{
+ readonly CompositeDisposable disposables = new();
+ ICollection 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;
}
}
diff --git a/src/ST.Client.Mobile.Droid/UI/Base/BaseFragment.cs b/src/ST.Client.Mobile.Droid/UI/Base/BaseFragment.cs
index f61167f47..561341b59 100644
--- a/src/ST.Client.Mobile.Droid/UI/Base/BaseFragment.cs
+++ b/src/ST.Client.Mobile.Droid/UI/Base/BaseFragment.cs
@@ -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
///
///
///
- public abstract partial class BaseFragment : ReactiveFragment, ReactiveUI.IReadOnlyViewFor
+ public abstract partial class BaseFragment : ReactiveFragment, ReactiveUI.IReadOnlyViewFor, IDisposableHolder
where TViewBinding : class
where TViewModel : ViewModelBase
{
+ readonly CompositeDisposable disposables = new();
+ ICollection 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;
}
}
diff --git a/src/ST.Client.Mobile.Droid/UI/Fragments/FastLoginOrRegisterFragment.cs b/src/ST.Client.Mobile.Droid/UI/Fragments/FastLoginOrRegisterFragment.cs
index df13480be..c8146a914 100644
--- a/src/ST.Client.Mobile.Droid/UI/Fragments/FastLoginOrRegisterFragment.cs
+++ b/src/ST.Client.Mobile.Droid/UI/Fragments/FastLoginOrRegisterFragment.cs
@@ -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, IDisposableHolder
+ internal sealed class FastLoginOrRegisterFragment : BaseFragment
{
- readonly CompositeDisposable disposables = new();
- ICollection IDisposableHolder.CompositeDisposable => disposables;
-
protected override int? LayoutResource => Resource.Layout.fragment_login_and_register_by_fast;
public override void OnCreateView(View view)
diff --git a/src/ST.Client.Mobile.Droid/UI/Fragments/MyFragment.cs b/src/ST.Client.Mobile.Droid/UI/Fragments/MyFragment.cs
index 807a343bd..cdb524423 100644
--- a/src/ST.Client.Mobile.Droid/UI/Fragments/MyFragment.cs
+++ b/src/ST.Client.Mobile.Droid/UI/Fragments/MyFragment.cs
@@ -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, IDisposableHolder
+ internal sealed class MyFragment : BaseFragment
{
- readonly CompositeDisposable disposables = new();
- ICollection 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(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)
diff --git a/src/ST.Client.Mobile.Droid/UI/Fragments/PhoneNumberLoginOrRegisterFragment.cs b/src/ST.Client.Mobile.Droid/UI/Fragments/PhoneNumberLoginOrRegisterFragment.cs
index 87d022b2f..6b236c15b 100644
--- a/src/ST.Client.Mobile.Droid/UI/Fragments/PhoneNumberLoginOrRegisterFragment.cs
+++ b/src/ST.Client.Mobile.Droid/UI/Fragments/PhoneNumberLoginOrRegisterFragment.cs
@@ -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, IDisposableHolder, TextView.IOnEditorActionListener
+ internal sealed class PhoneNumberLoginOrRegisterFragment : BaseFragment, TextView.IOnEditorActionListener
{
- readonly CompositeDisposable disposables = new();
- ICollection IDisposableHolder.CompositeDisposable => disposables;
-
protected override int? LayoutResource => Resource.Layout.fragment_login_and_register_by_phone_number;
public override void OnCreateView(View view)
diff --git a/src/ST.Client.Mobile.Droid/UI/MainApplication.cs b/src/ST.Client.Mobile.Droid/UI/MainApplication.cs
index adf66cee6..97931d904 100644
--- a/src/ST.Client.Mobile.Droid/UI/MainApplication.cs
+++ b/src/ST.Client.Mobile.Droid/UI/MainApplication.cs
@@ -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, 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;
+ }
}
}
\ No newline at end of file
diff --git a/src/ST.Client.Mobile/ST.Client.Mobile.csproj b/src/ST.Client.Mobile/ST.Client.Mobile.csproj
index 9f52d4044..74e511d9e 100644
--- a/src/ST.Client.Mobile/ST.Client.Mobile.csproj
+++ b/src/ST.Client.Mobile/ST.Client.Mobile.csproj
@@ -64,6 +64,12 @@
Services\Implementation
+
+ UI\ViewModels\AboutPageViewModel.shared.cs
+
+
+ Models\Enum
+
diff --git a/src/ST.Client.Mobile/UI/ViewModels/AboutPageViewModel.cs b/src/ST.Client.Mobile/UI/ViewModels/AboutPageViewModel.cs
new file mode 100644
index 000000000..a5d461363
--- /dev/null
+++ b/src/ST.Client.Mobile/UI/ViewModels/AboutPageViewModel.cs
@@ -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 preferenceButtons;
+ public ObservableCollection PreferenceButtons
+ {
+ get => preferenceButtons;
+ set => this.RaiseAndSetIfChanged(ref preferenceButtons, value);
+ }
+
+ public enum PreferenceButton
+ {
+ 检查更新 = 1,
+ 更新日志,
+ 常见问题疑难解答,
+ 开放源代码许可,
+ 源码仓库,
+ 产品官网,
+ 联系我们,
+ Bug反馈,
+ 账号注销,
+ }
+
+ public sealed class PreferenceButtonViewModel : RIdTitleViewModel
+ {
+ 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 collection, IDisposableHolder vm)
+ {
+ var removeArray = collection.Where(x => x.Id == PreferenceButton.账号注销).ToArray();
+ Array.ForEach(removeArray, x =>
+ {
+ collection.Remove(x);
+ x.OnUnbind(vm);
+ });
+ }
+
+ ///
+ /// 创建实例
+ ///
+ ///
+ ///
+ ///
+ 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);
+ }
+}
\ No newline at end of file
diff --git a/src/ST.Client.Mobile/UI/ViewModels/Base/RIdTitleIconViewModel.cs b/src/ST.Client.Mobile/UI/ViewModels/Base/RIdTitleIconViewModel.cs
index 593693041..e51c5c8ee 100644
--- a/src/ST.Client.Mobile/UI/ViewModels/Base/RIdTitleIconViewModel.cs
+++ b/src/ST.Client.Mobile/UI/ViewModels/Base/RIdTitleIconViewModel.cs
@@ -61,4 +61,11 @@ namespace System.Application.UI.ViewModels
GC.SuppressFinalize(this);
}
}
+
+ public abstract class RIdTitleViewModel : RIdTitleIconViewModel
+ {
+ protected sealed override bool IgnoreIcon => true;
+
+ protected sealed override byte GetIconById(TId? id) => default;
+ }
}
\ No newline at end of file
diff --git a/src/ST.Client/Services/Implementation/AppUpdateServiceImpl.cs b/src/ST.Client/Services/Implementation/AppUpdateServiceImpl.cs
index f6f0cb1a3..7b61eefed 100644
--- a/src/ST.Client/Services/Implementation/AppUpdateServiceImpl.cs
+++ b/src/ST.Client/Services/Implementation/AppUpdateServiceImpl.cs
@@ -600,7 +600,7 @@ namespace System.Application.Services.Implementation
///
/// 在应用商店中打开
///
- protected virtual void OpenInAppStore() => BrowserOpen("https://steampp.net/");
+ protected virtual void OpenInAppStore() => BrowserOpen(UrlConstants.OfficialWebsite);
void StartUpdate()
{
diff --git a/src/ST.Client/UrlConstants.cs b/src/ST.Client/UrlConstants.cs
new file mode 100644
index 000000000..8271987f9
--- /dev/null
+++ b/src/ST.Client/UrlConstants.cs
@@ -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";
+ }
+}
\ No newline at end of file