UserAccountBindFragment

This commit is contained in:
Aigio Liu
2021-11-10 14:54:11 +08:00
parent 5ac414d590
commit 3142e55471
15 changed files with 513 additions and 345 deletions
+5
View File
@@ -17,6 +17,7 @@ using System.Application.Services;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic;
using System.Application.Services.Implementation;
// ReSharper disable once CheckNamespace
namespace System.Application.UI
@@ -136,6 +137,10 @@ namespace System.Application.UI
b.AppendLine();
#endif
b.Append("[app.updcha] ");
b.Append(ApplicationUpdateServiceBaseImpl.UpdateChannelType);
b.AppendLine();
b.Append("[clr.ver] ");
string? clrVersion;
try
@@ -1,4 +1,5 @@
using Android.Views;
using Android.Widget;
using Binding;
using ReactiveUI;
using System.Application.Services;
@@ -13,43 +14,76 @@ namespace System.Application.UI.Fragments
{
protected override int? LayoutResource => Resource.Layout.fragment_account_binding;
static readonly Dictionary<int, FastLoginChannel> btnAccountBindDict = new()
{
{ Resource.Id.btnAccountBindSteam, FastLoginChannel.Steam },
{ Resource.Id.btnAccountBindMicrosoft, FastLoginChannel.Microsoft },
{ Resource.Id.btnAccountBindApple, FastLoginChannel.Apple },
{ Resource.Id.btnAccountBindQQ, FastLoginChannel.QQ },
};
static readonly Dictionary<int, FastLoginChannel> tbAccountBindDict = new()
{
{ Resource.Id.tbAccountBindSteam, FastLoginChannel.Steam },
{ Resource.Id.tbAccountBindMicrosoft, FastLoginChannel.Microsoft },
{ Resource.Id.tbAccountBindApple, FastLoginChannel.Apple },
{ Resource.Id.tbAccountBindQQ, FastLoginChannel.QQ },
};
Button[]? btnAccountBinds;
EditText[]? tbAccountBinds;
ImageView[]? ivIconAccountBinds;
public override void OnCreateView(View view)
{
base.OnCreateView(view);
var btnAccountBinds = new[] { binding!.btnAccountBindSteam, binding.btnAccountBindMicrosoft, binding.btnAccountBindApple, binding.btnAccountBindQQ, };
var tbAccountBinds = new[] { binding.tbAccountBindSteam, binding.tbAccountBindMicrosoft, binding.tbAccountBindApple, binding.tbAccountBindQQ, };
btnAccountBinds = new[] {
binding!.btnAccountBind0,
binding.btnAccountBind1,
binding.btnAccountBind2,
binding.btnAccountBind3,
};
tbAccountBinds = new[] {
binding.tbAccountBind0,
binding.tbAccountBind1,
binding.tbAccountBind2,
binding.tbAccountBind3,
};
ivIconAccountBinds = new[]
{
binding.ivIconAccountBind0,
binding.ivIconAccountBind1,
binding.ivIconAccountBind2,
binding.ivIconAccountBind3,
};
for (int i = 0; i < ivIconAccountBinds.Length; i++)
{
var iconResId = ThirdPartyLoginHelper.FastLoginChannels[i]
.ToIcon().ToImageResource();
if (iconResId.HasValue)
{
ivIconAccountBinds[i].SetImageResource(iconResId.Value);
}
}
UserService.Current.WhenAnyValue(x => x.HasPhoneNumber).SubscribeInMainThread(value =>
{
if (binding == null) return;
foreach (var item in btnAccountBinds)
for (int i = 0; i < btnAccountBinds.Length; i++)
{
item.Enabled = value;
var item = btnAccountBinds[i];
var cha = ThirdPartyLoginHelper.FastLoginChannels[i];
if (cha.IsSupported())
{
if (item.Enabled != value)
{
item.Enabled = value;
}
}
else if (item.Enabled)
{
item.Enabled = false;
}
}
}).AddTo(this);
UserService.Current.WhenAnyValue(x => x.User).SubscribeInMainThread(value =>
{
if (binding == null) return;
foreach (var item in tbAccountBinds)
for (int i = 0; i < tbAccountBinds.Length; i++)
{
item.Text = GetIsBindOrUnbundleTbText(tbAccountBindDict[item.Id]) ?? string.Empty;
var item = tbAccountBinds[i];
var cha = ThirdPartyLoginHelper.FastLoginChannels[i];
if (cha.IsSupported())
{
item.Text = GetIsBindOrUnbundleTbText(cha) ?? string.Empty;
}
}
}).AddTo(this);
@@ -63,9 +97,18 @@ namespace System.Application.UI.Fragments
binding.tvAccountBindTip.Text = AppResources.User_AccountBindTip;
foreach (var item in btnAccountBinds)
for (int i = 0; i < btnAccountBinds.Length; i++)
{
item.Text = GetIsBindOrUnbundleBtnText(btnAccountBindDict[item.Id]);
var item = btnAccountBinds[i];
var cha = ThirdPartyLoginHelper.FastLoginChannels[i];
if (cha.IsSupported())
{
item.Text = GetIsBindOrUnbundleBtnText(cha);
}
else
{
item.Text = AppResources.UnderConstruction;
}
}
}).AddTo(this);
@@ -74,10 +117,18 @@ namespace System.Application.UI.Fragments
protected override bool OnClick(View view)
{
if (btnAccountBindDict.ContainsKey(view.Id))
for (int i = 0; i < btnAccountBinds!.Length; i++)
{
ViewModel!.OnBindOrUnbundleFastLoginClick(btnAccountBindDict[view.Id]);
return true;
var item = btnAccountBinds[i];
if (item.Id == view.Id)
{
var cha = ThirdPartyLoginHelper.FastLoginChannels[i];
if (cha.IsSupported())
{
ViewModel!.OnBindOrUnbundleFastLoginClick(cha);
return true;
}
}
}
return base.OnClick(view);
}
@@ -41,6 +41,7 @@
<PackageReference Include="System.Security.Cryptography.ProtectedData" />
<!--<PackageReference Include="Avalonia.Direct2D1" />
<PackageReference Include="System.Diagnostics.Tracing" />-->
<PackageReference Include="Squid-Box.SevenZipSharp.Lite" />
</ItemGroup>
<ItemGroup>
@@ -36,8 +36,12 @@ namespace Microsoft.Extensions.DependencyInjection
}
services.AddSingleton<INativeWindowApiService, NativeWindowApiServiceImpl>();
services.AddSingleton<IJumpListService, JumpListServiceImpl>();
if (options.HasMainProcessRequired) services.AddNotifyIcon();
if (options.HasMainProcessRequired)
{
services.AddNotifyIcon();
}
//services.AddSingleton<AvaloniaFontManagerImpl, WindowsAvaloniaFontManagerImpl>();
services.AddSingleton<ISevenZipHelper, SevenZipHelper>();
}
else
{
@@ -0,0 +1,49 @@
using SevenZip;
using System.IO;
using CC = System.Common.Constants;
namespace System.Application.Services.Implementation
{
internal sealed class SevenZipHelper : ISevenZipHelper
{
public static bool IsInitialized { get; private set; }
static void Initialize()
{
if (IsInitialized) return;
// ✅ AppContext.BaseDirectory
var sevenZipLibraryPath = Path.Combine(AppContext.BaseDirectory, "7z.dll");
SevenZipBase.SetLibraryPath(sevenZipLibraryPath);
IsInitialized = true;
}
public bool Unpack(string filePath, string dirPath,
IProgress<float>? progress = null,
float maxProgress = CC.MaxProgress)
{
Initialize();
if (!File.Exists(filePath)) return false;
if (Directory.Exists(dirPath)) return false;
using var fs = File.OpenRead(filePath);
float length = fs.Length;
Directory.CreateDirectory(dirPath);
using var archive = new SevenZipExtractor(fs);
var hasProgress = progress != null;
if (hasProgress)
{
archive.Extracting += (_, e) =>
{
progress!.Report(e.PercentDone);
};
}
archive.ExtractArchive(dirPath);
if (hasProgress)
{
progress!.Report(maxProgress);
}
return true;
}
}
}
@@ -1,264 +1,264 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
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="wrap_content"
xamarin:managedType="AndroidX.ConstraintLayout.Widget.ConstraintLayout">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline_vertical_begin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xamarin:managedType="AndroidX.ConstraintLayout.Widget.ConstraintLayout">
android:orientation="vertical"
app:layout_constraintGuide_begin="@dimen/activity_horizontal_margin"
xamarin:managedType="AndroidX.ConstraintLayout.Widget.Guideline" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline_vertical_begin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="@dimen/activity_horizontal_margin"
xamarin:managedType="AndroidX.ConstraintLayout.Widget.Guideline" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline_vertical_end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_end="@dimen/activity_horizontal_margin"
xamarin:managedType="AndroidX.ConstraintLayout.Widget.Guideline" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline_vertical_end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_end="@dimen/activity_horizontal_margin"
xamarin:managedType="AndroidX.ConstraintLayout.Widget.Guideline" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnAccountBind0"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:insetBottom="0dp"
android:textAllCaps="false"
android:textSize="@dimen/input_font_size_min"
app:layout_constraintBottom_toBottomOf="@+id/layoutAccountBind0"
app:layout_constraintEnd_toStartOf="@+id/guideline_vertical_end"
app:layout_constraintTop_toTopOf="@+id/layoutAccountBind0"
tools:text="绑定"
xamarin:managedType="Google.Android.Material.Button.MaterialButton" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnAccountBindSteam"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:insetBottom="0dp"
android:textAllCaps="false"
android:textSize="@dimen/input_font_size_min"
app:layout_constraintBottom_toBottomOf="@+id/layoutAccountBindSteam"
app:layout_constraintEnd_toStartOf="@+id/guideline_vertical_end"
app:layout_constraintTop_toTopOf="@+id/layoutAccountBindSteam"
tools:text="绑定"
xamarin:managedType="Google.Android.Material.Button.MaterialButton" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layoutAccountBind0"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
android:clickable="false"
android:enabled="false"
android:focusable="false"
android:focusableInTouchMode="false"
app:layout_constraintEnd_toStartOf="@+id/btnAccountBind0"
app:layout_constraintStart_toEndOf="@+id/ivIconAccountBind0"
app:layout_constraintTop_toTopOf="parent"
xamarin:managedType="Google.Android.Material.TextField.TextInputLayout">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layoutAccountBindSteam"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
android:clickable="false"
android:enabled="false"
android:focusable="false"
android:focusableInTouchMode="false"
app:layout_constraintEnd_toStartOf="@+id/btnAccountBindSteam"
app:layout_constraintStart_toEndOf="@+id/ivIconAccountBindSteam"
app:layout_constraintTop_toTopOf="parent"
xamarin:managedType="Google.Android.Material.TextField.TextInputLayout">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/tbAccountBind0"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:enabled="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:inputType="text"
tools:hint="未绑定"
xamarin:managedType="Google.Android.Material.TextField.TextInputEditText" />
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/tbAccountBindSteam"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:enabled="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:inputType="text"
tools:hint="未绑定"
xamarin:managedType="Google.Android.Material.TextField.TextInputEditText" />
</com.google.android.material.textfield.TextInputLayout>
</com.google.android.material.textfield.TextInputLayout>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/ivIconAccountBind0"
android:layout_width="24dp"
android:layout_height="24dp"
app:layout_constraintBottom_toBottomOf="@+id/layoutAccountBind0"
app:layout_constraintStart_toStartOf="@+id/guideline_vertical_begin"
app:layout_constraintTop_toTopOf="@+id/layoutAccountBind0"
app:tint="@color/icon_background"
tools:src="@drawable/icon_steam_24"
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatImageView" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/ivIconAccountBindSteam"
android:layout_width="24dp"
android:layout_height="24dp"
app:layout_constraintBottom_toBottomOf="@+id/layoutAccountBindSteam"
app:layout_constraintStart_toStartOf="@+id/guideline_vertical_begin"
app:layout_constraintTop_toTopOf="@+id/layoutAccountBindSteam"
app:srcCompat="@drawable/icon_steam_24"
app:tint="@color/icon_background"
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatImageView" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnAccountBind1"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:insetBottom="0dp"
android:textAllCaps="false"
android:textSize="@dimen/input_font_size_min"
app:layout_constraintBottom_toBottomOf="@+id/layoutAccountBind1"
app:layout_constraintEnd_toStartOf="@+id/guideline_vertical_end"
app:layout_constraintTop_toTopOf="@+id/layoutAccountBind1"
tools:text="绑定"
xamarin:managedType="Google.Android.Material.Button.MaterialButton" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnAccountBindMicrosoft"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:insetBottom="0dp"
android:textAllCaps="false"
android:textSize="@dimen/input_font_size_min"
app:layout_constraintBottom_toBottomOf="@+id/layoutAccountBindMicrosoft"
app:layout_constraintEnd_toStartOf="@+id/guideline_vertical_end"
app:layout_constraintTop_toTopOf="@+id/layoutAccountBindMicrosoft"
tools:text="绑定"
xamarin:managedType="Google.Android.Material.Button.MaterialButton" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layoutAccountBind1"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
android:clickable="false"
android:enabled="false"
android:focusable="false"
android:focusableInTouchMode="false"
app:layout_constraintEnd_toStartOf="@+id/btnAccountBind1"
app:layout_constraintStart_toEndOf="@+id/ivIconAccountBind1"
app:layout_constraintTop_toBottomOf="@+id/layoutAccountBind0"
xamarin:managedType="Google.Android.Material.TextField.TextInputLayout">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layoutAccountBindMicrosoft"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
android:clickable="false"
android:enabled="false"
android:focusable="false"
android:focusableInTouchMode="false"
app:layout_constraintEnd_toStartOf="@+id/btnAccountBindMicrosoft"
app:layout_constraintStart_toEndOf="@+id/ivIconAccountBindMicrosoft"
app:layout_constraintTop_toBottomOf="@+id/layoutAccountBindSteam"
xamarin:managedType="Google.Android.Material.TextField.TextInputLayout">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/tbAccountBind1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:enabled="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:inputType="text"
tools:hint="未绑定"
xamarin:managedType="Google.Android.Material.TextField.TextInputEditText" />
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/tbAccountBindMicrosoft"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:enabled="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:inputType="text"
tools:hint="未绑定"
xamarin:managedType="Google.Android.Material.TextField.TextInputEditText" />
</com.google.android.material.textfield.TextInputLayout>
</com.google.android.material.textfield.TextInputLayout>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/ivIconAccountBind1"
android:layout_width="24dp"
android:layout_height="24dp"
app:layout_constraintBottom_toBottomOf="@+id/layoutAccountBind1"
app:layout_constraintStart_toStartOf="@+id/guideline_vertical_begin"
app:layout_constraintTop_toTopOf="@+id/layoutAccountBind1"
app:tint="@color/icon_background"
tools:src="@drawable/icon_xbox_24"
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatImageView" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/ivIconAccountBindMicrosoft"
android:layout_width="24dp"
android:layout_height="24dp"
app:layout_constraintBottom_toBottomOf="@+id/layoutAccountBindMicrosoft"
app:layout_constraintStart_toStartOf="@+id/guideline_vertical_begin"
app:layout_constraintTop_toTopOf="@+id/layoutAccountBindMicrosoft"
app:srcCompat="@drawable/icon_xbox_24"
app:tint="@color/icon_background"
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatImageView" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnAccountBind2"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:insetBottom="0dp"
android:textAllCaps="false"
android:textSize="@dimen/input_font_size_min"
app:layout_constraintBottom_toBottomOf="@+id/layoutAccountBind2"
app:layout_constraintEnd_toStartOf="@+id/guideline_vertical_end"
app:layout_constraintTop_toTopOf="@+id/layoutAccountBind2"
tools:text="绑定"
xamarin:managedType="Google.Android.Material.Button.MaterialButton" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnAccountBindApple"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:insetBottom="0dp"
android:textAllCaps="false"
android:textSize="@dimen/input_font_size_min"
app:layout_constraintBottom_toBottomOf="@+id/layoutAccountBindApple"
app:layout_constraintEnd_toStartOf="@+id/guideline_vertical_end"
app:layout_constraintTop_toTopOf="@+id/layoutAccountBindApple"
tools:text="绑定"
xamarin:managedType="Google.Android.Material.Button.MaterialButton" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layoutAccountBind2"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
android:clickable="false"
android:enabled="false"
android:focusable="false"
android:focusableInTouchMode="false"
app:layout_constraintEnd_toStartOf="@+id/btnAccountBind2"
app:layout_constraintStart_toEndOf="@+id/ivIconAccountBind2"
app:layout_constraintTop_toBottomOf="@+id/layoutAccountBind1"
xamarin:managedType="Google.Android.Material.TextField.TextInputLayout">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layoutAccountBindApple"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
android:clickable="false"
android:enabled="false"
android:focusable="false"
android:focusableInTouchMode="false"
app:layout_constraintEnd_toStartOf="@+id/btnAccountBindApple"
app:layout_constraintStart_toEndOf="@+id/ivIconAccountBindApple"
app:layout_constraintTop_toBottomOf="@+id/layoutAccountBindMicrosoft"
xamarin:managedType="Google.Android.Material.TextField.TextInputLayout">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/tbAccountBind2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:enabled="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:inputType="text"
tools:hint="该功能正在开发中,敬请期待"
xamarin:managedType="Google.Android.Material.TextField.TextInputEditText" />
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/tbAccountBindApple"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:enabled="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:inputType="text"
tools:hint="未绑定"
xamarin:managedType="Google.Android.Material.TextField.TextInputEditText" />
</com.google.android.material.textfield.TextInputLayout>
</com.google.android.material.textfield.TextInputLayout>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/ivIconAccountBind2"
android:layout_width="24dp"
android:layout_height="24dp"
app:layout_constraintBottom_toBottomOf="@+id/layoutAccountBind2"
app:layout_constraintStart_toStartOf="@+id/guideline_vertical_begin"
app:layout_constraintTop_toTopOf="@+id/layoutAccountBind2"
app:tint="@color/icon_background"
tools:src="@drawable/icon_apple_24"
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatImageView" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/ivIconAccountBindApple"
android:layout_width="24dp"
android:layout_height="24dp"
app:layout_constraintBottom_toBottomOf="@+id/layoutAccountBindApple"
app:layout_constraintStart_toStartOf="@+id/guideline_vertical_begin"
app:layout_constraintTop_toTopOf="@+id/layoutAccountBindApple"
app:srcCompat="@drawable/icon_apple_24"
app:tint="@color/icon_background"
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatImageView" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnAccountBind3"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:insetBottom="0dp"
android:textAllCaps="false"
android:textSize="@dimen/input_font_size_min"
app:layout_constraintBottom_toBottomOf="@+id/layoutAccountBind3"
app:layout_constraintEnd_toStartOf="@+id/guideline_vertical_end"
app:layout_constraintTop_toTopOf="@+id/layoutAccountBind3"
tools:text="绑定"
xamarin:managedType="Google.Android.Material.Button.MaterialButton" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnAccountBindQQ"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:insetBottom="0dp"
android:textAllCaps="false"
android:textSize="@dimen/input_font_size_min"
app:layout_constraintBottom_toBottomOf="@+id/layoutAccountBindQQ"
app:layout_constraintEnd_toStartOf="@+id/guideline_vertical_end"
app:layout_constraintTop_toTopOf="@+id/layoutAccountBindQQ"
tools:text="绑定"
xamarin:managedType="Google.Android.Material.Button.MaterialButton" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layoutAccountBind3"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
android:clickable="false"
android:enabled="false"
android:focusable="false"
android:focusableInTouchMode="false"
app:layout_constraintEnd_toStartOf="@+id/btnAccountBind3"
app:layout_constraintStart_toEndOf="@+id/ivIconAccountBind3"
app:layout_constraintTop_toBottomOf="@+id/layoutAccountBind2"
xamarin:managedType="Google.Android.Material.TextField.TextInputLayout">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layoutAccountBindQQ"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
android:clickable="false"
android:enabled="false"
android:focusable="false"
android:focusableInTouchMode="false"
app:layout_constraintEnd_toStartOf="@+id/btnAccountBindQQ"
app:layout_constraintStart_toEndOf="@+id/ivIconAccountBindQQ"
app:layout_constraintTop_toBottomOf="@+id/layoutAccountBindApple"
xamarin:managedType="Google.Android.Material.TextField.TextInputLayout">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/tbAccountBind3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:enabled="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:inputType="text"
tools:hint="未绑定"
xamarin:managedType="Google.Android.Material.TextField.TextInputEditText" />
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/tbAccountBindQQ"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:enabled="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:inputType="text"
tools:hint="未绑定"
xamarin:managedType="Google.Android.Material.TextField.TextInputEditText" />
</com.google.android.material.textfield.TextInputLayout>
</com.google.android.material.textfield.TextInputLayout>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/ivIconAccountBind3"
android:layout_width="24dp"
android:layout_height="24dp"
app:layout_constraintBottom_toBottomOf="@+id/layoutAccountBind3"
app:layout_constraintStart_toStartOf="@+id/guideline_vertical_begin"
app:layout_constraintTop_toTopOf="@+id/layoutAccountBind3"
app:tint="@color/icon_background"
tools:src="@drawable/icon_qq_24"
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatImageView" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/ivIconAccountBindQQ"
android:layout_width="24dp"
android:layout_height="24dp"
app:layout_constraintBottom_toBottomOf="@+id/layoutAccountBindQQ"
app:layout_constraintStart_toStartOf="@+id/guideline_vertical_begin"
app:layout_constraintTop_toTopOf="@+id/layoutAccountBindQQ"
app:srcCompat="@drawable/icon_qq_24"
app:tint="@color/icon_background"
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatImageView" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvAccountBindTip"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:textColor="@color/text_primary"
app:layout_constraintEnd_toStartOf="@+id/guideline_vertical_end"
app:layout_constraintStart_toStartOf="@+id/guideline_vertical_begin"
app:layout_constraintTop_toBottomOf="@+id/layoutAccountBind3"
tools:text="解绑第三方账号需要已绑定手机号才能解绑,如果要将已绑定第三方账号换绑至另一个账号,可以使用 [关于-此软件-账号注销] 注销已绑定的账号。"
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatTextView" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvAccountBindTip"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:textColor="@color/text_primary"
app:layout_constraintEnd_toStartOf="@+id/guideline_vertical_end"
app:layout_constraintStart_toStartOf="@+id/guideline_vertical_begin"
app:layout_constraintTop_toBottomOf="@+id/layoutAccountBindQQ"
tools:text="解绑第三方账号需要已绑定手机号才能解绑,如果要将已绑定第三方账号换绑至另一个账号,可以使用 [关于-此软件-账号注销] 注销已绑定的账号。"
xamarin:managedType="AndroidX.AppCompat.Widget.AppCompatTextView" />
<Space
android:layout_width="wrap_content"
android:layout_height="@dimen/activity_vertical_margin"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tvAccountBindTip" />
<Space
android:layout_width="wrap_content"
android:layout_height="@dimen/activity_vertical_margin"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tvAccountBindTip" />
</androidx.constraintlayout.widget.ConstraintLayout>
-1
View File
@@ -29,7 +29,6 @@
<PackageReference Include="NLog.Extensions.Logging" />
<PackageReference Include="NotifyIcon.Base" />
<PackageReference Include="SharpZipLib" />
<PackageReference Include="Squid-Box.SevenZipSharp.Lite" />
<!--<PackageReference Include="Titanium.Web.Proxy" />-->
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" />
<!--<PackageReference Include="Nito.Disposables" />-->
+24
View File
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Text;
using CC = System.Common.Constants;
namespace System.Application.Services
{
public interface ISevenZipHelper
{
static ISevenZipHelper Instance => DI.Get_Nullable<ISevenZipHelper>() ?? throw new PlatformNotSupportedException();
/// <summary>
/// 解压压缩包文件
/// </summary>
/// <param name="filePath">要解压的压缩包文件路径</param>
/// <param name="dirPath">要解压的文件夹路径,文件夹必须不存在</param>
/// <param name="progress">进度值监听</param>
/// <param name="maxProgress"></param>
/// <returns></returns>
bool Unpack(string filePath, string dirPath,
IProgress<float>? progress = null,
float maxProgress = CC.MaxProgress);
}
}
@@ -24,6 +24,7 @@ namespace System.Application.Services.Implementation
/// <inheritdoc cref="IApplicationUpdateService"/>
public abstract class ApplicationUpdateServiceBaseImpl : ReactiveObject, IApplicationUpdateService
{
protected const string TAG = "AppUpdateS";
protected readonly ICloudServiceClient client;
protected readonly AppSettings settings;
protected readonly IToast toast;
@@ -572,17 +573,28 @@ namespace System.Application.Services.Implementation
Directory.Delete(dirPath, true);
}
var isOK = await Task.Run(() => downloadType switch
var isOK = await Task.Run(() =>
{
AppDownloadType.Compressed_GZip
=> TarGZipHelper.Unpack(value, dirPath,
progress: new Progress<float>(OnReportDecompressing),
maxProgress: CC.MaxProgress),
AppDownloadType.Compressed_7z
=> SevenZipHelper.Unpack(value, dirPath,
progress: new Progress<float>(OnReportDecompressing),
maxProgress: CC.MaxProgress),
_ => false,
try
{
return downloadType switch
{
AppDownloadType.Compressed_GZip
=> TarGZipHelper.Unpack(value, dirPath,
progress: new Progress<float>(OnReportDecompressing),
maxProgress: CC.MaxProgress),
AppDownloadType.Compressed_7z
=> ISevenZipHelper.Instance.Unpack(value, dirPath,
progress: new Progress<float>(OnReportDecompressing),
maxProgress: CC.MaxProgress),
_ => false,
};
}
catch (Exception ex)
{
Log.Error(TAG, ex, "Compressed unpack catch.");
return false;
}
});
if (isOK)
{
@@ -655,18 +667,30 @@ namespace System.Application.Services.Implementation
}
}
/// <summary>
/// 当前应用设置的更新渠道
/// </summary>
public static UpdateChannelType UpdateChannelType
{
get
{
var channel = GeneralSettings.UpdateChannel.Value;
switch (channel)
{
case UpdateChannelType.GitHub:
case UpdateChannelType.Gitee:
break;
default:
channel = R.IsChineseSimplified ? UpdateChannelType.Gitee : UpdateChannelType.GitHub;
break;
}
return channel;
}
}
protected virtual AppVersionDTO.Download? GetByDownloadChannelSettings(IEnumerable<AppVersionDTO.Download> downloads)
{
var channel = GeneralSettings.UpdateChannel.Value;
switch (channel)
{
case UpdateChannelType.GitHub:
case UpdateChannelType.Gitee:
break;
default:
channel = R.Language.StartsWith("zh") ? UpdateChannelType.Gitee : UpdateChannelType.GitHub;
break;
}
var channel = UpdateChannelType;
return downloads.FirstOrDefault(x => x.DownloadChannelType == channel)
?? downloads.FirstOrDefault();
}
-54
View File
@@ -1,54 +0,0 @@
using SevenZip;
using System.IO;
using CC = System.Common.Constants;
namespace System.Application
{
public static class SevenZipHelper
{
static SevenZipHelper()
{
if (OperatingSystem2.IsWindows)
{
// ✅ AppContext.BaseDirectory
var sevenZipLibraryPath = Path.Combine(AppContext.BaseDirectory, "7z.dll");
SevenZipBase.SetLibraryPath(sevenZipLibraryPath);
}
}
/// <summary>
/// 解压压缩包文件
/// </summary>
/// <param name="filePath">要解压的压缩包文件路径</param>
/// <param name="dirPath">要解压的文件夹路径,文件夹必须不存在</param>
/// <param name="progress">进度值监听</param>
/// <param name="maxProgress"></param>
/// <returns></returns>
public static bool Unpack(string filePath, string dirPath,
IProgress<float>? progress = null,
float maxProgress = CC.MaxProgress)
{
if (!File.Exists(filePath)) return false;
if (Directory.Exists(dirPath)) return false;
using var fs = File.OpenRead(filePath);
float length = fs.Length;
Directory.CreateDirectory(dirPath);
using var archive = new SevenZipExtractor(fs);
var hasProgress = progress != null;
if (hasProgress)
{
archive.Extracting += (_, e) =>
{
progress!.Report(e.PercentDone);
};
}
archive.ExtractArchive(dirPath);
if (hasProgress)
{
progress!.Report(maxProgress);
}
return true;
}
}
}
+20
View File
@@ -1,3 +1,6 @@
using System.Application;
using System.Application.UI;
namespace System.Application.UI
{
/// <summary>
@@ -23,4 +26,21 @@ namespace System.Application.UI
/// </summary>
PlatformPhone,
}
}
// ReSharper disable once CheckNamespace
namespace System
{
public static class ResIconEnumExtensions
{
public static ResIcon ToIcon(this FastLoginChannel fastLoginChannel)
=> fastLoginChannel switch
{
FastLoginChannel.Steam => ResIcon.Steam,
FastLoginChannel.Microsoft => ResIcon.Xbox,
FastLoginChannel.QQ => ResIcon.QQ,
FastLoginChannel.Apple => ResIcon.Apple,
_ => throw new ArgumentOutOfRangeException(nameof(fastLoginChannel), fastLoginChannel, null),
};
}
}
+6 -2
View File
@@ -28,13 +28,17 @@ namespace System.Application.UI.Resx
public static CultureInfo DefaultCurrentUICulture { get; private set; }
public static bool IsChineseSimplified => IsMatch(Culture, zh_Hans);
const string zh_Hans = "zh-Hans";
static R()
{
DefaultCurrentUICulture = CultureInfo.CurrentUICulture;
var languagesDict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "", "Auto" },
{ "zh-Hans", "Chinese (Simplified)" },
{ zh_Hans, "Chinese (Simplified)" },
{ "zh-Hant", "Chinese (Traditional)" },
{ "en", "English" },
{ "ko", "Korean" },
@@ -47,7 +51,7 @@ namespace System.Application.UI.Resx
SteamLanguages = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "zh-CN", "schinese" },
{ "zh-Hans", "schinese" },
{ zh_Hans, "schinese" },
{ "zh-Hant", "tchinese" },
{ "en","english"},
{ "ko", "koreana" },
@@ -239,6 +239,14 @@ namespace System.Application.UI.ViewModels
public string Msg { get; set; } = string.Empty;
}
public static FastLoginChannel[] FastLoginChannels = new[] // 更改此数组可控制UI列表的顺序
{
FastLoginChannel.QQ,
FastLoginChannel.Steam,
FastLoginChannel.Microsoft,
FastLoginChannel.Apple,
};
}
partial class UserProfileWindowViewModel : IBindWindowViewModel
@@ -55,12 +55,18 @@ namespace System.Application.UI.ViewModels
IEnumerable<FastLoginChannelViewModel> GetFastLoginChannels()
{
yield return FastLoginChannelViewModel.Create(nameof(FastLoginChannel.QQ), this);
yield return FastLoginChannelViewModel.Create(nameof(FastLoginChannel.Steam), this);
yield return FastLoginChannelViewModel.Create(nameof(FastLoginChannel.Xbox), this);
#if DEBUG
yield return FastLoginChannelViewModel.Create(nameof(FastLoginChannel.Apple), this);
#endif
foreach (var item in ThirdPartyLoginHelper.FastLoginChannels)
{
if (item.IsSupported())
{
yield return FastLoginChannelViewModel.Create(item switch
{
FastLoginChannel.Microsoft => nameof(FastLoginChannel.Xbox),
_ => item.ToString(),
}, this);
}
}
if (IsMobileLayout)
{
yield return FastLoginChannelViewModel.Create(FastLoginChannelViewModel.PhoneNumber, this);
+27
View File
@@ -1,3 +1,5 @@
using System.Application;
namespace System.Application
{
/// <summary>
@@ -52,4 +54,29 @@ namespace System.Application
Xbox = Microsoft,
}
}
// ReSharper disable once CheckNamespace
namespace System
{
public static class FastLoginChannelEnumExtensions
{
/// <summary>
/// 当前快速登录渠道是否已支持
/// </summary>
/// <param name="fastLoginChannel"></param>
/// <returns></returns>
public static bool IsSupported(this FastLoginChannel fastLoginChannel)
#if DEBUG
=> true;
#else
=> fastLoginChannel switch
{
FastLoginChannel.Steam or
FastLoginChannel.Microsoft or
FastLoginChannel.QQ => true,
_ => false,
};
#endif
}
}