diff --git a/Directory.Packages.props b/Directory.Packages.props
index f1d9b205d..6bddd34fa 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -257,6 +257,7 @@
+
diff --git a/references/ArchiSteamFarm b/references/ArchiSteamFarm
index 461ed4096..fc238ca10 160000
--- a/references/ArchiSteamFarm
+++ b/references/ArchiSteamFarm
@@ -1 +1 @@
-Subproject commit 461ed409644a7cec567fc64e2a8552cdc79945db
+Subproject commit fc238ca1065aa264d92e51b9d1bf65755e0b28e5
diff --git a/src/Common.CoreLib/DateTimeFormat.cs b/src/Common.CoreLib/DateTimeFormat.cs
index add69fdd0..94120b980 100644
--- a/src/Common.CoreLib/DateTimeFormat.cs
+++ b/src/Common.CoreLib/DateTimeFormat.cs
@@ -31,5 +31,7 @@ namespace System
public const string RFC1123 = "r";
public const string File = "yyyy-MM-dd HHmmssfffffff";
+
+ public const string YearMonth = "yyyy/MM";
}
}
\ No newline at end of file
diff --git a/src/Common.CoreLib/Extensions/DateTimeExtensions.cs b/src/Common.CoreLib/Extensions/DateTimeExtensions.cs
index 57823015b..a405efb45 100644
--- a/src/Common.CoreLib/Extensions/DateTimeExtensions.cs
+++ b/src/Common.CoreLib/Extensions/DateTimeExtensions.cs
@@ -25,7 +25,7 @@ namespace System
///
///
public static DateTimeOffset GetCurrentMonth(this DateTimeOffset dt)
- => new(dt.Year, dt.Month, 1, 0, 0, 0, TimeSpan.Zero);
+ => new(dt.Year, dt.Month, 1, 0, 0, 0, dt.Offset);
///
/// 根据时间日期获取当前月(最后一天)
@@ -33,6 +33,6 @@ namespace System
///
///
public static DateTimeOffset GetCurrentMonthLastDay(this DateTimeOffset dt)
- => new DateTimeOffset(dt.Year, dt.Month, 1, 0, 0, 0, TimeSpan.Zero).AddMonths(1).AddDays(-1);
+ => new DateTimeOffset(dt.Year, dt.Month, 1, 0, 0, 0, dt.Offset).AddMonths(1).AddDays(-1);
}
}
diff --git a/src/ST.Client.Android/ST.Client.Android.csproj b/src/ST.Client.Android/ST.Client.Android.csproj
index 1c8b06add..640d220d5 100644
--- a/src/ST.Client.Android/ST.Client.Android.csproj
+++ b/src/ST.Client.Android/ST.Client.Android.csproj
@@ -119,6 +119,7 @@
+
@@ -456,6 +457,9 @@
Resources\layout\activity_detail_auth.xml
+
+ Resources\layout\activity_donate.xml
+
Resources\layout\activity_encryption_auth.xml
@@ -582,6 +586,9 @@
Resources\layout\layout_card_steam_auth_trade_confirmation_content.xml
+
+ Resources\layout\layout_donate_user.xml
+
Resources\layout\layout_file_or_dir.xml
@@ -730,27 +737,4 @@
Resources\xml\local_auth_appwidget_info.xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/src/ST.Client.Android/UI/Activities/DonateActivity.cs b/src/ST.Client.Android/UI/Activities/DonateActivity.cs
new file mode 100644
index 000000000..fec23a279
--- /dev/null
+++ b/src/ST.Client.Android/UI/Activities/DonateActivity.cs
@@ -0,0 +1,86 @@
+using Android.App;
+using Android.Content.PM;
+using Android.OS;
+using Android.Runtime;
+using Android.Views;
+using AndroidX.RecyclerView.Widget;
+using Binding;
+using ReactiveUI;
+using System.Application.UI.Adapters;
+using System.Application.UI.ViewModels;
+using System.Application.UI.Resx;
+using Google.Android.Material.DatePicker;
+
+namespace System.Application.UI.Activities
+{
+ [Register(JavaPackageConstants.Activities + nameof(ExplorerActivity))]
+ [Activity(Theme = ManifestConstants.MainTheme2_NoActionBar,
+ LaunchMode = LaunchMode.SingleTask,
+ ConfigurationChanges = ManifestConstants.ConfigurationChanges)]
+ internal sealed class DonateActivity : BaseActivity, DatePickerHelper.IOnPositiveButtonClickListener
+ {
+ protected override int? LayoutResource => Resource.Layout.activity_donate;
+
+ protected override AboutPageViewModel? OnCreateViewModel() => AboutPageViewModel.Instance;
+
+ protected override void OnCreate2(Bundle? savedInstanceState)
+ {
+ base.OnCreate2(savedInstanceState);
+
+ this.SetSupportActionBarWithNavigationClick(binding!.toolbar, true);
+
+ R.Subscribe(() =>
+ {
+ Title = AppResources.About_Donate;
+ if (binding == null) return;
+ binding.tvTitle.Text = AppResources.About_Donate_Title;
+ binding.btnUID.Text = AppResources.ClickHereCopyUIDToClipboard;
+ binding.tvDesc.Text = AppResources.About_Donate_Desc;
+ binding.tvDonateType.Text = AppResources.About_DonateType;
+ binding.tvDonateRecord.Text = AppResources.About_DonateRecord;
+ binding.tvDonateRecordPrompt.Text = AppResources.About_DonateRecord_Prompt;
+ }).AddTo(this);
+
+ binding.btn_afdian.Text = "爱发电";
+ binding.btn_ko_fi.Text = "Ko-fi";
+ binding.btn_patreon.Text = "Patreon";
+
+ if (!ViewModel!.DonateList.Any_Nullable())
+ {
+ ViewModel.LoadDonateRankListData();
+ }
+
+ binding.tbDate.Text = ViewModel!.DonateFliterDate.ToString(DateTimeFormat.YearMonth);
+
+ var adapter = new DonateUserAdapter(ViewModel);
+ binding.rvDonateList.SetAdapter(adapter);
+
+ SetOnClickListener(
+ binding.btnUID,
+ binding.layoutDate);
+ }
+
+ protected override void OnClick(View view)
+ {
+ base.OnClick(view);
+
+ if (view.Id == Resource.Id.btnUID)
+ {
+ ViewModel!.UIDCommand.Invoke();
+ return;
+ }
+ else if (view.Id == Resource.Id.layoutDate)
+ {
+ this.ShowBirthDatePicker();
+ return;
+ }
+ }
+
+ void DatePickerHelper.IOnPositiveButtonClickListener.OnPositiveButtonClick(DateTimeOffset selection)
+ {
+ ViewModel!.DonateFliterDate = selection.GetCurrentMonth();
+ }
+
+ void IMaterialPickerOnPositiveButtonClickListener.OnPositiveButtonClick(Java.Lang.Object p0) => this.OnPositiveButtonClick(p0);
+ }
+}
diff --git a/src/ST.Client.Android/UI/Adapters/DonateUserAdapter.cs b/src/ST.Client.Android/UI/Adapters/DonateUserAdapter.cs
new file mode 100644
index 000000000..59ab1d3b0
--- /dev/null
+++ b/src/ST.Client.Android/UI/Adapters/DonateUserAdapter.cs
@@ -0,0 +1,54 @@
+using Android.Views;
+using Binding;
+using ReactiveUI;
+using System.Application.UI.Resx;
+using System.Application.UI.ViewModels;
+using TViewHolder = System.Application.UI.Adapters.DonateUserViewHolder;
+using TViewModel = System.Application.Models.RankingResponse;
+using static System.Application.UI.Resx.AppResources;
+using System.Application.Services;
+using System.Collections.Generic;
+using DynamicData;
+using System.Linq;
+using System.Collections.ObjectModel;
+using System.Application.Models;
+
+namespace System.Application.UI.Adapters
+{
+ sealed class DonateUserAdapter : BaseReactiveRecycleViewAdapter
+ {
+ public DonateUserAdapter(ObservableCollection collection) : base(collection)
+ {
+
+ }
+
+ public DonateUserAdapter(AboutPageViewModel viewModel) : base(viewModel.DonateList!)
+ {
+
+ }
+
+ public override int? GetLayoutResource(int viewType)
+ {
+ return Resource.Layout.layout_donate_user;
+ }
+ }
+
+ sealed class DonateUserViewHolder : BaseReactiveViewHolder
+ {
+ readonly layout_donate_user binding;
+
+ public DonateUserViewHolder(View itemView) : base(itemView)
+ {
+ binding = new(itemView);
+ }
+
+ public override void OnBind()
+ {
+ base.OnBind();
+
+ binding.ivAvatar.SetImageSource(ViewModel!.Avatar);
+ binding.tvNickName.Text = ViewModel.Name;
+ binding.tvValue.Text = ViewModel.Amount.ToString("C", ViewModel.CurrencyCode.GetCultureInfo());
+ }
+ }
+}
diff --git a/src/ST.Client.Android/UI/Controllers/AboutController.cs b/src/ST.Client.Android/UI/Controllers/AboutController.cs
index b47ceb156..31dd5c584 100644
--- a/src/ST.Client.Android/UI/Controllers/AboutController.cs
+++ b/src/ST.Client.Android/UI/Controllers/AboutController.cs
@@ -66,6 +66,9 @@ namespace System.Application.UI.Controllers
{
switch (e.Current.Id)
{
+ case PreferenceButton.捐助:
+ Activity.StartActivity();
+ break;
case PreferenceButton.检查更新:
ViewModel!.CheckUpdateCommand.Invoke();
break;
diff --git a/src/ST.Client/UI/ViewModels/Pages/About/AboutPageViewModel.Mobile.cs b/src/ST.Client/UI/ViewModels/Pages/About/AboutPageViewModel.Mobile.cs
index 968e8f67e..851774f3c 100644
--- a/src/ST.Client/UI/ViewModels/Pages/About/AboutPageViewModel.Mobile.cs
+++ b/src/ST.Client/UI/ViewModels/Pages/About/AboutPageViewModel.Mobile.cs
@@ -23,6 +23,7 @@ namespace System.Application.UI.ViewModels
public enum PreferenceButton
{
+ 捐助,
检查更新 = 1,
更新日志,
常见问题疑难解答,
@@ -57,6 +58,7 @@ namespace System.Application.UI.ViewModels
{
var title = id switch
{
+ PreferenceButton.捐助 => AppResources.About_Donate,
PreferenceButton.检查更新 => AppResources.CheckUpdate,
PreferenceButton.更新日志 => AppResources.About_UpdateLog,
PreferenceButton.常见问题疑难解答 => AppResources.About_FAQ,
diff --git a/src/ST.Client/UI/ViewModels/Pages/About/AboutPageViewModel.cs b/src/ST.Client/UI/ViewModels/Pages/About/AboutPageViewModel.cs
index 50538d8bc..f76252403 100644
--- a/src/ST.Client/UI/ViewModels/Pages/About/AboutPageViewModel.cs
+++ b/src/ST.Client/UI/ViewModels/Pages/About/AboutPageViewModel.cs
@@ -131,18 +131,16 @@ namespace System.Application.UI.ViewModels
}
}).AddTo(this);
}
- else
- {
- DonateFliterDate = DateTimeOffset.Now.GetCurrentMonth();
- this.WhenValueChanged(x => x.DonateFliterDate, false)
- .Subscribe(x => LoadDonateRankListData(true));
- }
+ DonateFliterDate = DateTimeOffset.Now.GetCurrentMonth();
+
+ this.WhenValueChanged(x => x.DonateFliterDate, false)
+ .Subscribe(x => LoadDonateRankListData(true));
}
public override void Activation()
{
- if (IApplication.IsDesktopPlatform)
+ if (IApplication.IsDesktopPlatform) // Android 上手动调用加载
{
LoadDonateRankListData(true);
}
@@ -158,7 +156,17 @@ namespace System.Application.UI.ViewModels
public async void LoadDonateRankListData(bool refresh = false, bool nextPage = false)
{
if (refresh)
- DonateList = null;
+ {
+ if (IApplication.IsDesktopPlatform)
+ {
+ DonateList = null;
+ }
+ else
+ {
+ // Android 上 List 关联 Adapter 在初始化时,这里不能执行 null 赋值
+ DonateList?.Clear();
+ }
+ }
DonateList ??= new();
diff --git a/src/ST.Services.CloudService.Models/Models/ExternalTransaction/RankingResponse.cs b/src/ST.Services.CloudService.Models/Models/ExternalTransaction/RankingResponse.cs
index 514172cfb..daeb3a201 100644
--- a/src/ST.Services.CloudService.Models/Models/ExternalTransaction/RankingResponse.cs
+++ b/src/ST.Services.CloudService.Models/Models/ExternalTransaction/RankingResponse.cs
@@ -1,4 +1,3 @@
-using System;
using System.Collections.Generic;
using System.Text;
using MPIgnore = MessagePack.IgnoreMemberAttribute;
@@ -12,7 +11,7 @@ using S_JsonProperty = System.Text.Json.Serialization.JsonPropertyNameAttribute;
namespace System.Application.Models
{
[MPObj]
- public class RankingResponse
+ public partial class RankingResponse
{
///
/// 用户昵称
@@ -62,4 +61,11 @@ namespace System.Application.Models
[S_JsonProperty("5")]
public CurrencyCode CurrencyCode { get; set; }
}
+
+#if MVVM_VM
+ partial class RankingResponse : ReactiveUI.ReactiveObject
+ {
+
+ }
+#endif
}
diff --git a/src/ST.Tools.AndroidResourceLink/Program.cs b/src/ST.Tools.AndroidResourceLink/Program.cs
index 1b9900318..c723a8625 100644
--- a/src/ST.Tools.AndroidResourceLink/Program.cs
+++ b/src/ST.Tools.AndroidResourceLink/Program.cs
@@ -38,7 +38,7 @@ foreach (var file in files)
}
sb.AppendLine(" ");
Array.ForEach(bottom, x => sb.AppendLine(x));
-csprojContent = sb.ToString();
+csprojContent = sb.ToString().Trim();
File.WriteAllText(androidProjFilePath, csprojContent);
Console.WriteLine("OK");
\ No newline at end of file
diff --git a/src/ST/CurrencyCode.cs b/src/ST/CurrencyCode.cs
index 9a5da4e12..e0d574f45 100644
--- a/src/ST/CurrencyCode.cs
+++ b/src/ST/CurrencyCode.cs
@@ -36,10 +36,8 @@ namespace System
public static partial class CurrencyCodeEnumExtensions
{
public static CultureInfo? GetCultureInfo(this CurrencyCode eCurrencyCode)
- {
- return CultureInfo.GetCultures(CultureTypes.SpecificCultures)
- .FirstOrDefault(culture => new RegionInfo(culture.LCID).ISOCurrencySymbol == eCurrencyCode.ToString());
- }
+ => CultureInfo.GetCultures(CultureTypes.SpecificCultures)
+ .FirstOrDefault(culture => new RegionInfo(culture.LCID).ISOCurrencySymbol == eCurrencyCode.ToString());
public static CurrencyCode GetCurrencyCode(this ICurrencyCodeString @interface, CurrencyCode @default = CurrencyCode.CNY)
=> Enum.TryParse(@interface.CurrencyCode, true, out CurrencyCode currencyCode) ? currencyCode : @default;