Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 35 additions & 12 deletions ExtraIsland/Components/BetterCountdown/BetterCountdown.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ void OnLoad() {
SilentUpdater();
OnTimeChanged += DetectEvent;
OnTimeChanged += DetectTimeUp;
OnTimeChanged += DetectTimeNode;
Settings.OnAccuracyChanged += UpdateAccuracy;
Settings.OnNoGapDisplayChanged += UpdateGap;
LessonsService.PostMainTimerTicked += UpdateTime;
Expand Down Expand Up @@ -115,7 +116,7 @@ void DetectEvent() {
_dyAnimator.Update(_days,Settings.IsAnimationEnabled);
}
}
if ((_hours != span.Hours.ToString() | _isAccurateChanged) & (Settings.IsNotify | (int)Settings.Accuracy >= 1)) {
if ((_hours != span.Hours.ToString() | _isAccurateChanged) & (Settings.IsNotify | (int)Settings.Accuracy >= 1 | Settings.LatestNode is not null)) {
int hourI = span.Hours;
int hourCi = (int)Settings.Accuracy == 1 & Settings.IsCorrectorEnabled ? hourI + 1 : hourI;
_hours = hourCi.ToString();
Expand All @@ -132,7 +133,7 @@ void DetectEvent() {
_hrAnimator.Update(_hours,Settings.IsAnimationEnabled);
}
}
if ((_minutes != span.Minutes.ToString() | _isAccurateChanged) & (Settings.IsNotify | (int)Settings.Accuracy >= 2)) {
if ((_minutes != span.Minutes.ToString() | _isAccurateChanged) & (Settings.IsNotify | (int)Settings.Accuracy >= 2 | Settings.LatestNode is not null)) {
int minuteI = span.Minutes;
int minuteCi = (int)Settings.Accuracy == 2 & Settings.IsCorrectorEnabled ? minuteI + 1 : minuteI;
_minutes = minuteCi.ToString();
Expand All @@ -156,7 +157,7 @@ void DetectEvent() {
}
}
// ReSharper disable once InvertIf
if ((_seconds != span.Seconds.ToString() | _isAccurateChanged) & (Settings.IsNotify | (int)Settings.Accuracy >= 3)) {
if ((_seconds != span.Seconds.ToString() | _isAccurateChanged) & (Settings.IsNotify | (int)Settings.Accuracy >= 3 | Settings.LatestNode is not null)) {
_seconds = span.Seconds.ToString();
string s = _seconds;
if (s.Length == 1) {
Expand All @@ -175,12 +176,12 @@ void SilentUpdater() {
_days = (int)Settings.Accuracy == 0 ? (dayI + 1).ToString() : dayI.ToString();
_dyAnimator.SilentUpdate(_days);
}
if ((_hours != span.Hours.ToString() | _isAccurateChanged) & (Settings.IsNotify | (int)Settings.Accuracy >= 1)) {
if ((_hours != span.Hours.ToString() | _isAccurateChanged) & (Settings.IsNotify | (int)Settings.Accuracy >= 1 | Settings.LatestNode is not null)) {
int hourI = span.Hours;
_hours = (int)Settings.Accuracy == 1 ? (hourI + 1).ToString() : hourI.ToString();
_hrAnimator.SilentUpdate(_hours);
}
if ((_minutes != span.Minutes.ToString() | _isAccurateChanged) & (Settings.IsNotify | (int)Settings.Accuracy >= 2)) {
if ((_minutes != span.Minutes.ToString() | _isAccurateChanged) & (Settings.IsNotify | (int)Settings.Accuracy >= 2 | Settings.LatestNode is not null)) {
int minuteI = span.Minutes;
_minutes = (int)Settings.Accuracy == 2 ? (minuteI + 1).ToString() : minuteI.ToString();
string m = _minutes;
Expand All @@ -190,7 +191,7 @@ void SilentUpdater() {
_mnAnimator.SilentUpdate(m);
}
// ReSharper disable once InvertIf
if ((_seconds != span.Seconds.ToString() | _isAccurateChanged) & (Settings.IsNotify | (int)Settings.Accuracy >= 3)) {
if ((_seconds != span.Seconds.ToString() | _isAccurateChanged) & (Settings.IsNotify | (int)Settings.Accuracy >= 3 | Settings.LatestNode is not null)) {
_seconds = span.Seconds.ToString();
string s = _seconds;
if (s.Length == 1) {
Expand All @@ -200,36 +201,58 @@ void SilentUpdater() {
}
}

void Notify() {
TimeUpNotification.Notify(string.Format(Settings.Message, Settings.Prefix, Settings.Suffix),
void TimeUpNotify() {
BetterCountdownNotification.Notify(Settings.Name, Settings.Message, 0,
Settings.LeftIcon, Settings.RightIcon);
Settings.IsNotified = true;
}
void TimeNodeNotify(TimeNode tn) {
BetterCountdownNotification.Notify(Settings.Name, tn.NotifyText, 1,
Settings.LeftIcon, Settings.RightIcon, tn.ToString());
_isTimeNodeDetected = true;
}

void DetectTimeUp() {
if (!Settings.IsNotify || Settings.IsNotified) return;
if (Settings.IsCorrectorEnabled) {
if ((int)Settings.Accuracy == 1 & _days == "0" & _hours == "1" & _minutes == "0" & _seconds == "-1") {
Notify();
TimeUpNotify();
}
if ((int)Settings.Accuracy == 2 & _days == "0" & _hours == "0" & _minutes == "1" & _seconds == "-1") {
Notify();
TimeUpNotify();
}
if ((int)Settings.Accuracy == 3 & _days == "0" & _hours == "0" & _minutes == "0" & _seconds == "0") {
Notify();
TimeUpNotify();
}
} else {
if (_days == "0" & _hours == "0" & _minutes == "0" & _seconds == "0") {
Notify();
TimeUpNotify();
}
}
}
bool _isTimeNodeDetected = false;
void DetectTimeNode() {
if (Settings.LatestNode is null || _isTimeNodeDetected) return;
TimeSpan span = EiUtils.GetDateTimeSpan(Now,Settings.TargetDateTime);
if (span.Days==Settings.LatestNode.CountdownTime.Days
&& span.Hours==Settings.LatestNode.CountdownTime.Hours
&& span.Minutes==Settings.LatestNode.CountdownTime.Minutes
&& span.Seconds==Settings.LatestNode.CountdownTime.Seconds) {
TimeNodeNotify(Settings.LatestNode);
Settings.LatestNode = Settings.Times[Settings.Times.IndexOf(Settings.LatestNode) + 1];
Console.WriteLine(Settings.LatestNode);
}
_isTimeNodeDetected = false;
}
void OnAttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs visualTreeAttachmentEventArgs) {
Dispatcher.UIThread.InvokeAsync(OnLoad);
Settings.Times.Config = Settings;
Settings.Times.GetLatest();
}
void OnDetachedFromVisualTree(object? sender,VisualTreeAttachmentEventArgs visualTreeAttachmentEventArgs) {
OnTimeChanged -= DetectEvent;
OnTimeChanged -= DetectTimeUp;
OnTimeChanged -= DetectTimeNode;
Settings.OnAccuracyChanged -= UpdateAccuracy;
Settings.OnNoGapDisplayChanged -= UpdateGap;
LessonsService.PostMainTimerTicked -= UpdateTime;
Expand Down
30 changes: 29 additions & 1 deletion ExtraIsland/Components/BetterCountdown/BetterCountdownConfig.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
using System.ComponentModel;
using CommunityToolkit.Mvvm.ComponentModel;
using ExtraIsland.Shared;

namespace ExtraIsland.Components;

// ReSharper disable once ClassNeverInstantiated.Global
public class BetterCountdownConfig : ObservableObject {
public BetterCountdownConfig() {
Separators.PropertyChanged += (_,_) => OnPropertyChanged();
Console.WriteLine("Bcd Consturct!");
Times = [];
Times.Config = this;
TargetDateTime = DateTime.Now.AddMinutes(1);
}

Expand All @@ -17,6 +21,8 @@ public DateTime TargetDateTime {
if (_targetDateTime == value) return;
_targetDateTime = value;
IsNotified = false;

Times.GetLatest();
}
}

Expand Down Expand Up @@ -81,11 +87,22 @@ public CountdownAccuracy Accuracy {
public bool IsFocusedModeEnabled { get; set; }
public bool IsNotify {get; set;}

public string Message { get; set; } = "{0} 已结束";
public string Name {get; set;} = "倒计时名称";
public string Message { get; set; } = "";

public string LeftIcon { get; set; } = "\uE352";

public string RightIcon { get; set; } = "";

//TimeNodeObservableCollection _times;

public TimeNodeObservableCollection Times {
get;
set;
}

public TimeNode? LatestNode { get; set; }

}

public class CountdownSeparatorConfigs : ObservableObject {
Expand Down Expand Up @@ -136,4 +153,15 @@ public enum CountdownAccuracy {
Minute,
[Description("秒")]
Second
}

public partial class TimeNode: ObservableObject {

[ObservableProperty]
TimeSpan _countdownTime = new TimeSpan(1, 1 ,1 ,1 );
public bool IsNotify { get; set; }
public String NotifyText { get; set; } = "距离{n}仅剩{t}";
public override string ToString() {
return CountdownTime.Days + "天" + CountdownTime.Hours + "小时" + CountdownTime.Minutes+"分"+CountdownTime.Seconds+"秒";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@
</Grid>
</controls:SettingsExpander.Footer>
</controls:SettingsExpander>
<controls:SettingsExpander IconSource="{ci:FluentIconSource &#xE8AC;}"
Header="事件名称"
Description="事件名称,可以用于提醒中">
<controls:SettingsExpander.Footer>
<TextBox Text="{Binding Settings.Name, Mode=TwoWay}" />
</controls:SettingsExpander.Footer>
</controls:SettingsExpander>
<controls:SettingsExpander IconSource="{ci:FluentIconSource &#xE324;}"
Header="目标时间"
Description="倒计时设定的日期和时间">
Expand All @@ -100,6 +107,13 @@
</StackPanel>
</controls:SettingsExpander.Footer>
</controls:SettingsExpander>
<controls:SettingsExpander IconSource="{ci:FluentIconSource &#xE4B5;}"
Header="时间节点"
Description="某时间节点要执行的任务">
<controls:SettingsExpander.Items>
<components:TimeNodeControl Times="{Binding Settings.Times}"/>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<controls:SettingsExpander IconSource="{ci:FluentIconSource &#xE5E5;}"
Header="时间精度"
Description="倒计时显示的差值精度">
Expand Down Expand Up @@ -163,18 +177,18 @@
</controls:SettingsExpander>
<controls:SettingsExpander IconSource="{ci:FluentIconSource &#xE4D4;}"
Header="启用提醒"
Description="启用后,倒计时到后将进行提醒">
Description="启用后,倒计时到后将进行提醒">
<controls:SettingsExpander.Footer>
<ToggleSwitch IsChecked="{Binding Settings.IsNotify, Mode=TwoWay}"/>
</controls:SettingsExpander.Footer>
<controls:SettingsExpander.Items>
<controls:SettingsExpanderItem IconSource="{ci:FluentIconSource &#xE8AC;}"
Content="编辑提醒"
Description="修改提醒的文字, 可以用 {0} {1} 分别指代前缀和后缀">
<controls:SettingsExpanderItem.Footer>
<TextBox Text="{Binding Settings.Message, Mode=TwoWay}" />
</controls:SettingsExpanderItem.Footer>
</controls:SettingsExpanderItem>
<controls:SettingsExpanderItem IconSource="{ci:FluentIconSource &#xE8AC;}"
Content="提醒消息"
Description="修改提醒消息的文案, 留空以继承‘提醒渠道’中的设置,{n}表示事件名称">
<controls:SettingsExpanderItem.Footer>
<TextBox Text="{Binding Settings.Message, Mode=TwoWay}" />
</controls:SettingsExpanderItem.Footer>
</controls:SettingsExpanderItem>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<Label HorizontalAlignment="Center"
Expand Down
76 changes: 76 additions & 0 deletions ExtraIsland/Components/BetterCountdown/TimeNodeControl.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<UserControl xmlns="https://github.com/avaloniaui"
x:Class="ExtraIsland.Components.TimeNodeControl"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:components="clr-namespace:ExtraIsland.Components"
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:ci="http://classisland.tech/schemas/xaml/core"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
>
<StackPanel DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=components:TimeNodeControl}}">
<StackPanel Orientation="Horizontal">
<Button HorizontalAlignment="Left"
Click="ButtonAddTime_Click">
<ci:IconText Glyph="&#xE00C;"
Text="添加"/>
</Button>
<Button HorizontalAlignment="Left"
Click="SaveButton_OnClick">
<ci:IconText Glyph="&#xEEB4;"
Text="保存"/>
</Button>
</StackPanel>
<ItemsControl ItemsSource="{Binding Times}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<controls:SettingsExpander IconSource="{ci:FluentIconSource &#xF357;}"
Header="时间点"
Description="选择一个时间, 并选择该节点要执行的操作">
<controls:SettingsExpander.Footer>
<StackPanel Orientation="Horizontal">
<NumericUpDown
Width="150"
Minimum="0"
Maximum="114514"
FormatString="0"
Value="{Binding CountdownTime.Days, Mode=TwoWay}"
ValueChanged="NumericUpDown_OnValueChanged"
Watermark="天"/>
<TextBlock Text="天" VerticalAlignment="Center"/>
<TimePicker UseSeconds="True"
Margin="5,0,0,0"
Loaded="CountdownTimeModeTp_OnLoaded"
SelectedTimeChanged="CountdownTimeModeTp_SelectedTimeChanged"
Tag="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}}"/>
<Button Command="{Binding ButtonRemoveTimeCommand,
RelativeSource={RelativeSource AncestorType=components:TimeNodeControl}}"
CommandParameter="{Binding}">
<ci:IconText Glyph="&#xE61C;"/>
</Button>
</StackPanel>
</controls:SettingsExpander.Footer>
<controls:SettingsExpander.Items>
<controls:SettingsExpanderItem IconSource="{ci:FluentIconSource &#xE4D4;}"
Content="提醒"
Description="到达该时间点时,发送提醒">
<controls:SettingsExpanderItem.Footer>
<ToggleSwitch IsChecked="{Binding IsNotify,Mode=TwoWay}"/>
</controls:SettingsExpanderItem.Footer>
</controls:SettingsExpanderItem>
<controls:SettingsExpanderItem
IconSource="{ci:FluentIconSource &#xE4C0;}"
Content="提醒文本"
Description="提醒内容的文本,{t}表示剩余时间,{n}表示事件名称">
<controls:SettingsExpanderItem.Footer>
<TextBox Text="{Binding NotifyText, Mode=TwoWay}"/>
</controls:SettingsExpanderItem.Footer>
</controls:SettingsExpanderItem>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>

</UserControl>
73 changes: 73 additions & 0 deletions ExtraIsland/Components/BetterCountdown/TimeNodeControl.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using CommunityToolkit.Mvvm.Input;
using ExtraIsland.Shared;

namespace ExtraIsland.Components;

public partial class TimeNodeControl : UserControl {
public TimeNodeControl() {
InitializeComponent();
}

//public BetterCountdownConfig Config {get; set;}
public static readonly StyledProperty<TimeNodeObservableCollection> TimesProperty =
AvaloniaProperty.Register<TimeNodeControl, TimeNodeObservableCollection>(nameof(Times));

public TimeNodeObservableCollection Times {
get => GetValue(TimesProperty);
set {
Console.WriteLine("Times属性被设置!");
SetValue(TimesProperty,value);
}
}

public void ButtonAddTime_Click(object? sender, RoutedEventArgs e) {
Times.Add(new TimeNode());
}

[RelayCommand]
void ButtonRemoveTime(TimeNode node) {
Times.Remove(node);
}

void CountdownTimeModeTp_OnLoaded(object? sender,RoutedEventArgs e) {
if (sender is TimePicker
{
DataContext: TimeNode tn,
} tp) {
tp.SelectedTime = new TimeSpan(tn.CountdownTime.Hours,tn.CountdownTime.Minutes,tn.CountdownTime.Seconds);
}
}

void CountdownTimeModeTp_SelectedTimeChanged(object? sender,TimePickerSelectedValueChangedEventArgs e) {
if (sender is TimePicker
{
DataContext: TimeNode tn,
SelectedTime: not null
} tp) {
TimeSpan newTime = new TimeSpan(tn.CountdownTime.Days, tp.SelectedTime.Value.Hours, tp.SelectedTime.Value.Minutes, tp.SelectedTime.Value.Seconds);
if (newTime == tn.CountdownTime) return;
tn.CountdownTime = newTime;
}
}
void NumericUpDown_OnValueChanged(object? sender,NumericUpDownValueChangedEventArgs e) {
if (sender is NumericUpDown
{
DataContext: TimeNode tn,
Value: not null
} numericUpDown) {
TimeSpan newTime = new TimeSpan((int)numericUpDown.Value, tn.CountdownTime.Hours, tn.CountdownTime.Minutes, tn.CountdownTime.Seconds);
if (newTime == tn.CountdownTime) return;
tn.CountdownTime = newTime;

}
}
void SaveButton_OnClick(object? sender,RoutedEventArgs e) {
if(Times.Count == 0) return;
Console.WriteLine("SaveButton调用!");
Times.GetLatest();
}

}
Loading