Clarify indeterminate flag docs

This commit is contained in:
Flower Realm 2025-10-18 10:46:20 +08:00
parent d04b8fa018
commit cd3e5cf4f9
5 changed files with 76 additions and 9 deletions

View file

@ -20,20 +20,23 @@ public static class ConfigHandler
public static Config? LoadConfig() public static Config? LoadConfig()
{ {
Config? config = null; Config? config = null;
var result = EmbedUtils.LoadResource(Utils.GetConfigPath(_configRes)); var configPath = Utils.GetConfigPath(_configRes);
var configFileExists = File.Exists(configPath);
var result = EmbedUtils.LoadResource(configPath);
if (result.IsNotEmpty()) if (result.IsNotEmpty())
{ {
config = JsonUtils.Deserialize<Config>(result); config = JsonUtils.Deserialize<Config>(result);
} }
else else
{ {
if (File.Exists(Utils.GetConfigPath(_configRes))) if (configFileExists)
{ {
Logging.SaveLog("LoadConfig Exception"); Logging.SaveLog("LoadConfig Exception");
return null; return null;
} }
} }
var isNewConfig = config == null;
config ??= new Config(); config ??= new Config();
config.CoreBasicItem ??= new() config.CoreBasicItem ??= new()
@ -171,6 +174,22 @@ public static class ConfigHandler
config.SystemProxyItem.SystemProxyExceptions = Utils.IsWindows() ? Global.SystemProxyExceptionsWindows : Global.SystemProxyExceptionsLinux; config.SystemProxyItem.SystemProxyExceptions = Utils.IsWindows() ? Global.SystemProxyExceptionsWindows : Global.SystemProxyExceptionsLinux;
} }
if (isNewConfig && !configFileExists)
{
try
{
var ret = SaveConfig(config).GetAwaiter().GetResult();
if (ret != 0)
{
Logging.SaveLog($"{_tag}: Failed to create default config file.");
}
}
catch (Exception ex)
{
Logging.SaveLog($"{_tag}: Failed to create default config file", ex);
}
}
return config; return config;
} }

View file

@ -146,6 +146,10 @@ public sealed class SubscriptionInfoManager
{ {
try try
{ {
if (config == null)
{
return;
}
var subs = await AppManager.Instance.SubItems(); var subs = await AppManager.Instance.SubItems();
if (subs is not { Count: > 0 }) return; if (subs is not { Count: > 0 }) return;
foreach (var s in subs) foreach (var s in subs)
@ -160,6 +164,10 @@ public sealed class SubscriptionInfoManager
{ {
try try
{ {
if (config == null || s == null)
{
return;
}
var originalUrl = Utils.GetPunycode(s.Url.TrimEx()); var originalUrl = Utils.GetPunycode(s.Url.TrimEx());
if (originalUrl.IsNullOrEmpty()) return; if (originalUrl.IsNullOrEmpty()) return;

View file

@ -47,12 +47,26 @@ public class ProfilesViewModel : MyReactiveObject
[Reactive] [Reactive]
public string SubUsageText { get; set; } public string SubUsageText { get; set; }
/// <summary>
/// 当订阅用量仍在请求、或远端未提供总流量时保持进度条在“未知/占位”马灯状态,避免显示 0% 等误导性的数值。
/// 该值直接绑定到视图层进度条的 <c>IsIndeterminate</c> 属性。
/// </summary>
[Reactive]
public bool SubUsageIndeterminate { get; set; }
[Reactive] [Reactive]
public int SubExpirePercent { get; set; } public int SubExpirePercent { get; set; }
[Reactive] [Reactive]
public string SubExpireText { get; set; } public string SubExpireText { get; set; }
/// <summary>
/// 在未能计算到期日或仍在加载时,让到期进度条保持“不确定”马灯动画,提示用户等待最新数据。
/// 该值直接绑定到视图层进度条的 <c>IsIndeterminate</c> 属性。
/// </summary>
[Reactive]
public bool SubExpireIndeterminate { get; set; }
[Reactive] [Reactive]
public SubItem SelectedMoveToGroup { get; set; } public SubItem SelectedMoveToGroup { get; set; }
@ -306,10 +320,12 @@ public class ProfilesViewModel : MyReactiveObject
SelectedMoveToGroup = new(); SelectedMoveToGroup = new();
BlSubInfoVisible = true; BlSubInfoVisible = true;
SubUsagePercent = -1; SubUsagePercent = 0;
SubExpirePercent = -1; SubExpirePercent = 0;
SubUsageText = string.Empty; SubUsageText = string.Empty;
SubExpireText = string.Empty; SubExpireText = string.Empty;
SubUsageIndeterminate = true;
SubExpireIndeterminate = true;
await RefreshSubscriptions(); await RefreshSubscriptions();
//await RefreshServers(); //await RefreshServers();
@ -383,6 +399,13 @@ public class ProfilesViewModel : MyReactiveObject
{ {
if (!c) if (!c)
{ {
SubUsageIndeterminate = true;
SubExpireIndeterminate = true;
SubUsagePercent = 0;
SubExpirePercent = 0;
SubUsageText = "—";
SubExpireText = "—";
BlSubInfoVisible = true;
return; return;
} }
_config.SubIndexId = SelectedSub?.Id; _config.SubIndexId = SelectedSub?.Id;
@ -407,6 +430,9 @@ public class ProfilesViewModel : MyReactiveObject
SubExpirePercent = 0; SubExpirePercent = 0;
SubUsageText = "—"; SubUsageText = "—";
SubExpireText = "—"; SubExpireText = "—";
SubUsageIndeterminate = true;
SubExpireIndeterminate = true;
BlSubInfoVisible = true;
return; return;
} }
@ -421,11 +447,14 @@ public class ProfilesViewModel : MyReactiveObject
SubExpirePercent = 0; SubExpirePercent = 0;
SubUsageText = "—"; SubUsageText = "—";
SubExpireText = "—"; SubExpireText = "—";
SubUsageIndeterminate = true;
SubExpireIndeterminate = true;
// 尝试即时抓取一次响应头,避免必须“更新订阅”才显示 // 尝试即时抓取一次响应头,避免必须“更新订阅”才显示
try { await SubscriptionInfoManager.Instance.FetchHeaderForSub(_config, SelectedSub); } catch { } try { await SubscriptionInfoManager.Instance.FetchHeaderForSub(_config, SelectedSub); } catch { }
info = SubscriptionInfoManager.Instance.Get(subId); info = SubscriptionInfoManager.Instance.Get(subId);
if (info == null) if (info == null)
{ {
BlSubInfoVisible = true;
return; return;
} }
} }
@ -435,11 +464,13 @@ public class ProfilesViewModel : MyReactiveObject
{ {
SubUsagePercent = info.UsagePercent; SubUsagePercent = info.UsagePercent;
SubUsageText = string.Format("{0} / {1} ({2}%)", Utils.HumanFy(info.UsedBytes), Utils.HumanFy(info.Total), SubUsagePercent); SubUsageText = string.Format("{0} / {1} ({2}%)", Utils.HumanFy(info.UsedBytes), Utils.HumanFy(info.Total), SubUsagePercent);
SubUsageIndeterminate = false;
} }
else else
{ {
SubUsagePercent = -1; SubUsagePercent = 0;
SubUsageText = string.Format("{0}", Utils.HumanFy(info.UsedBytes)); SubUsageText = string.Format("{0}", Utils.HumanFy(info.UsedBytes));
SubUsageIndeterminate = true;
} }
// Expire // Expire
@ -456,16 +487,19 @@ public class ProfilesViewModel : MyReactiveObject
int baseDays = daysLeft <= 31 ? 31 : (daysLeft <= 92 ? 92 : 365); int baseDays = daysLeft <= 31 ? 31 : (daysLeft <= 92 ? 92 : 365);
var percentRemain = (int)Math.Round(Math.Min(daysLeft, baseDays) * 100.0 / baseDays); var percentRemain = (int)Math.Round(Math.Min(daysLeft, baseDays) * 100.0 / baseDays);
SubExpirePercent = Math.Clamp(percentRemain, 0, 100); SubExpirePercent = Math.Clamp(percentRemain, 0, 100);
SubExpireIndeterminate = false;
} }
else else
{ {
SubExpirePercent = -1; SubExpirePercent = 0;
SubExpireIndeterminate = true;
} }
} }
else else
{ {
SubExpireText = string.Empty; SubExpireText = string.Empty;
SubExpirePercent = -1; SubExpirePercent = 0;
SubExpireIndeterminate = true;
} }
BlSubInfoVisible = true; BlSubInfoVisible = true;
@ -474,6 +508,10 @@ public class ProfilesViewModel : MyReactiveObject
{ {
// 出错也别隐藏 // 出错也别隐藏
BlSubInfoVisible = true; BlSubInfoVisible = true;
SubUsageIndeterminate = true;
SubExpireIndeterminate = true;
SubUsagePercent = 0;
SubExpirePercent = 0;
} }
await Task.CompletedTask; await Task.CompletedTask;
} }

View file

@ -79,12 +79,12 @@
<StackPanel Margin="{StaticResource MarginLr8}" IsVisible="{Binding BlSubInfoVisible}"> <StackPanel Margin="{StaticResource MarginLr8}" IsVisible="{Binding BlSubInfoVisible}">
<StackPanel Orientation="Horizontal" Spacing="6" HorizontalAlignment="Left" Margin="0,0,0,2"> <StackPanel Orientation="Horizontal" Spacing="6" HorizontalAlignment="Left" Margin="0,0,0,2">
<TextBlock Width="56" VerticalAlignment="Center" Text="流量" /> <TextBlock Width="56" VerticalAlignment="Center" Text="流量" />
<ProgressBar Height="16" Minimum="0" Maximum="100" Value="{Binding SubUsagePercent}" Width="240" /> <ProgressBar Height="16" Minimum="0" Maximum="100" Value="{Binding SubUsagePercent}" Width="240" IsIndeterminate="{Binding SubUsageIndeterminate}" />
<TextBlock VerticalAlignment="Center" Text="{Binding SubUsageText}" /> <TextBlock VerticalAlignment="Center" Text="{Binding SubUsageText}" />
</StackPanel> </StackPanel>
<StackPanel Orientation="Horizontal" Spacing="6" HorizontalAlignment="Left"> <StackPanel Orientation="Horizontal" Spacing="6" HorizontalAlignment="Left">
<TextBlock Width="56" VerticalAlignment="Center" Text="到期" /> <TextBlock Width="56" VerticalAlignment="Center" Text="到期" />
<ProgressBar Height="16" Minimum="0" Maximum="100" Value="{Binding SubExpirePercent}" Width="240" /> <ProgressBar Height="16" Minimum="0" Maximum="100" Value="{Binding SubExpirePercent}" Width="240" IsIndeterminate="{Binding SubExpireIndeterminate}" />
<TextBlock VerticalAlignment="Center" Text="{Binding SubExpireText}" /> <TextBlock VerticalAlignment="Center" Text="{Binding SubExpireText}" />
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>

View file

@ -96,6 +96,7 @@
Minimum="0" Minimum="0"
Maximum="100" Maximum="100"
Value="{Binding SubUsagePercent}" Value="{Binding SubUsagePercent}"
IsIndeterminate="{Binding SubUsageIndeterminate}"
Style="{StaticResource MaterialDesignProgressBar}" Style="{StaticResource MaterialDesignProgressBar}"
Margin="4,0,4,0" Margin="4,0,4,0"
Width="240" /> Width="240" />
@ -114,6 +115,7 @@
Minimum="0" Minimum="0"
Maximum="100" Maximum="100"
Value="{Binding SubExpirePercent}" Value="{Binding SubExpirePercent}"
IsIndeterminate="{Binding SubExpireIndeterminate}"
Style="{StaticResource MaterialDesignProgressBar}" Style="{StaticResource MaterialDesignProgressBar}"
Margin="4,0,4,0" Margin="4,0,4,0"
Width="240" /> Width="240" />