Skip to content

Commit 53bf6b3

Browse files
committed
Add day-of-week and localized-date display options
Two independent, opt-in additions to how dates are shown everywhere: - Day of week: a dropdown in Preferences > General (None / Short / Full) that prepends ddd/dddd to the active date format. Stored as DayOfWeekStyle; day names come from the active culture. - Localized dates: a toggle that ties day/month names to the application's selected language (UseLocalizedCulture) instead of the invariant/English culture. The culture is derived from the app locale key, not the operating-system culture. Both options flow through DateTimeFormat.Format and are bound into the CommitTimeTextBlock and DateTimePresenter views. New locale keys added to en_US and el_GR.
1 parent 8b1b6b2 commit 53bf6b3

9 files changed

Lines changed: 229 additions & 19 deletions

File tree

src/App.axaml.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ public override void Initialize()
239239

240240
var pref = ViewModels.Preferences.Instance;
241241
SetLocale(pref.Locale);
242+
Models.DateTimeFormat.UseCulture(pref.Locale);
242243
SetTheme(pref.Theme, pref.ThemeOverrides);
243244
SetFonts(pref.DefaultFontFamily, pref.MonospaceFontFamily);
244245
}

src/Models/DateTimeFormat.cs

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,21 +33,62 @@ public static bool Use24Hours
3333
set;
3434
} = true;
3535

36+
public static int DayOfWeekStyle
37+
{
38+
get;
39+
set;
40+
} = 0;
41+
42+
public static bool UseLocalizedCulture
43+
{
44+
get;
45+
set;
46+
} = true;
47+
3648
public string DateFormat
3749
{
3850
get;
3951
}
4052

4153
public string Example
4254
{
43-
get => DateTime.Now.ToString(DateFormat, _culture);
55+
get => DateTime.Now.ToString(DateFormat, ActiveCulture);
4456
}
4557

46-
private static readonly CultureInfo _culture = CreateCulture();
58+
// Raised when the formatting culture changes at runtime (e.g. the app language
59+
// was switched). Views that render dates in code subscribe to refresh themselves,
60+
// since such a change is invisible to their bound properties.
61+
public static event Action Changed;
62+
63+
private static CultureInfo ActiveCulture => UseLocalizedCulture ? _localizedCulture : _invariantCulture;
64+
65+
private static CultureInfo _localizedCulture = CreateCulture(CultureInfo.CurrentCulture);
66+
private static readonly CultureInfo _invariantCulture = CreateCulture(CultureInfo.InvariantCulture);
67+
68+
// Ties the localized day/month names to the application's selected language
69+
// (e.g. locale key "el_GR"), instead of the operating-system culture.
70+
public static void UseCulture(string localeKey)
71+
{
72+
var baseCulture = CultureInfo.CurrentCulture;
73+
if (!string.IsNullOrEmpty(localeKey))
74+
{
75+
try
76+
{
77+
baseCulture = CultureInfo.GetCultureInfo(localeKey.Replace('_', '-'));
78+
}
79+
catch (CultureNotFoundException)
80+
{
81+
// fall back to the operating-system culture
82+
}
83+
}
84+
85+
_localizedCulture = CreateCulture(baseCulture);
86+
Changed?.Invoke();
87+
}
4788

48-
private static CultureInfo CreateCulture()
89+
private static CultureInfo CreateCulture(CultureInfo baseCulture)
4990
{
50-
var culture = (CultureInfo)CultureInfo.CurrentCulture.Clone();
91+
var culture = (CultureInfo)baseCulture.Clone();
5192
culture.DateTimeFormat.DateSeparator = "/";
5293
culture.DateTimeFormat.TimeSeparator = ":";
5394
return culture;
@@ -67,11 +108,18 @@ public static string Format(ulong timestamp, bool dateOnly = false)
67108
public static string Format(DateTime localTime, bool dateOnly = false)
68109
{
69110
var actived = Supported[ActiveIndex];
111+
var dateFormat = DayOfWeekStyle switch
112+
{
113+
1 => $"ddd {actived.DateFormat}",
114+
2 => $"dddd {actived.DateFormat}",
115+
_ => actived.DateFormat,
116+
};
117+
70118
if (dateOnly)
71-
return localTime.ToString(actived.DateFormat, _culture);
119+
return localTime.ToString(dateFormat, ActiveCulture);
72120

73-
var format = Use24Hours ? $"{actived.DateFormat} HH:mm:ss" : $"{actived.DateFormat} hh:mm:ss tt";
74-
return localTime.ToString(format, _culture);
121+
var format = Use24Hours ? $"{dateFormat} HH:mm:ss" : $"{dateFormat} hh:mm:ss tt";
122+
return localTime.ToString(format, ActiveCulture);
75123
}
76124
}
77125
}

src/Resources/Locales/el_GR.axaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,8 +660,12 @@
660660
<x:String x:Key="Text.Preferences.General" xml:space="preserve">ΓΕΝΙΚΑ</x:String>
661661
<x:String x:Key="Text.Preferences.General.Check4UpdatesOnStartup" xml:space="preserve">Έλεγχος για ενημερώσεις κατά την εκκίνηση</x:String>
662662
<x:String x:Key="Text.Preferences.General.DateFormat" xml:space="preserve">Μορφή ημερομηνίας</x:String>
663+
<x:String x:Key="Text.Preferences.General.DayOfWeek.None" xml:space="preserve">Χωρίς ημέρα</x:String>
664+
<x:String x:Key="Text.Preferences.General.DayOfWeek.Short" xml:space="preserve">Σύντομη ημέρα</x:String>
665+
<x:String x:Key="Text.Preferences.General.DayOfWeek.Full" xml:space="preserve">Πλήρης ημέρα</x:String>
663666
<x:String x:Key="Text.Preferences.General.EnableCompactFolders" xml:space="preserve">Ενεργοποίηση συμπαγών φακέλων στο δέντρο αλλαγών</x:String>
664667
<x:String x:Key="Text.Preferences.General.Locale" xml:space="preserve">Γλώσσα</x:String>
668+
<x:String x:Key="Text.Preferences.General.LocalizedDates" xml:space="preserve">Τοπικές ημερομηνίες</x:String>
665669
<x:String x:Key="Text.Preferences.General.MaxHistoryCommits" xml:space="preserve">Commits ιστορικού</x:String>
666670
<x:String x:Key="Text.Preferences.General.ShowChangesPageByDefault" xml:space="preserve">Εμφάνιση της σελίδας `ΤΟΠΙΚΕΣ ΑΛΛΑΓΕΣ` από προεπιλογή</x:String>
667671
<x:String x:Key="Text.Preferences.General.ShowChangesTabInCommitDetailByDefault" xml:space="preserve">Εμφάνιση της καρτέλας `ΑΛΛΑΓΕΣ` στις λεπτομέρειες commit από προεπιλογή</x:String>

src/Resources/Locales/en_US.axaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,8 +682,12 @@
682682
<x:String x:Key="Text.Preferences.General" xml:space="preserve">GENERAL</x:String>
683683
<x:String x:Key="Text.Preferences.General.Check4UpdatesOnStartup" xml:space="preserve">Check for updates on startup</x:String>
684684
<x:String x:Key="Text.Preferences.General.DateFormat" xml:space="preserve">Date Format</x:String>
685+
<x:String x:Key="Text.Preferences.General.DayOfWeek.None" xml:space="preserve">No day of week</x:String>
686+
<x:String x:Key="Text.Preferences.General.DayOfWeek.Short" xml:space="preserve">Short day</x:String>
687+
<x:String x:Key="Text.Preferences.General.DayOfWeek.Full" xml:space="preserve">Full day</x:String>
685688
<x:String x:Key="Text.Preferences.General.EnableCompactFolders" xml:space="preserve">Enable compact folders in changes tree</x:String>
686689
<x:String x:Key="Text.Preferences.General.Locale" xml:space="preserve">Language</x:String>
690+
<x:String x:Key="Text.Preferences.General.LocalizedDates" xml:space="preserve">Localized dates</x:String>
687691
<x:String x:Key="Text.Preferences.General.MaxHistoryCommits" xml:space="preserve">History Commits</x:String>
688692
<x:String x:Key="Text.Preferences.General.ShowChangesPageByDefault" xml:space="preserve">Show `LOCAL CHANGES` page by default</x:String>
689693
<x:String x:Key="Text.Preferences.General.ShowChangesTabInCommitDetailByDefault" xml:space="preserve">Show `CHANGES` tab in commit detail by default</x:String>

src/ViewModels/Preferences.cs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,12 @@ public string Locale
3636
get => _locale;
3737
set
3838
{
39-
if (SetProperty(ref _locale, value) && !_isLoading)
40-
App.SetLocale(value);
39+
if (SetProperty(ref _locale, value))
40+
{
41+
Models.DateTimeFormat.UseCulture(value);
42+
if (!_isLoading)
43+
App.SetLocale(value);
44+
}
4145
}
4246
}
4347

@@ -169,6 +173,34 @@ public bool Use24Hours
169173
}
170174
}
171175

176+
public int DayOfWeekStyle
177+
{
178+
get => Models.DateTimeFormat.DayOfWeekStyle;
179+
set
180+
{
181+
if (value != Models.DateTimeFormat.DayOfWeekStyle &&
182+
value >= 0 &&
183+
value <= 2)
184+
{
185+
Models.DateTimeFormat.DayOfWeekStyle = value;
186+
OnPropertyChanged();
187+
}
188+
}
189+
}
190+
191+
public bool DateTimeUseLocalizedCulture
192+
{
193+
get => Models.DateTimeFormat.UseLocalizedCulture;
194+
set
195+
{
196+
if (value != Models.DateTimeFormat.UseLocalizedCulture)
197+
{
198+
Models.DateTimeFormat.UseLocalizedCulture = value;
199+
OnPropertyChanged();
200+
}
201+
}
202+
}
203+
172204
public bool UseFixedTabWidth
173205
{
174206
get => _useFixedTabWidth;

src/Views/CommitTimeTextBlock.cs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,30 @@ public int DateTimeFormat
4646
set => SetAndRaise(DateTimeFormatProperty, ref _dateTimeFormat, value);
4747
}
4848

49+
public static readonly DirectProperty<CommitTimeTextBlock, int> DayOfWeekStyleProperty =
50+
AvaloniaProperty.RegisterDirect<CommitTimeTextBlock, int>(
51+
nameof(DayOfWeekStyle),
52+
static o => o.DayOfWeekStyle,
53+
static (o, v) => o.DayOfWeekStyle = v);
54+
55+
public int DayOfWeekStyle
56+
{
57+
get => _dayOfWeekStyle;
58+
set => SetAndRaise(DayOfWeekStyleProperty, ref _dayOfWeekStyle, value);
59+
}
60+
61+
public static readonly DirectProperty<CommitTimeTextBlock, bool> UseLocalizedCultureProperty =
62+
AvaloniaProperty.RegisterDirect<CommitTimeTextBlock, bool>(
63+
nameof(UseLocalizedCulture),
64+
static o => o.UseLocalizedCulture,
65+
static (o, v) => o.UseLocalizedCulture = v);
66+
67+
public bool UseLocalizedCulture
68+
{
69+
get => _useLocalizedCulture;
70+
set => SetAndRaise(UseLocalizedCultureProperty, ref _useLocalizedCulture, value);
71+
}
72+
4973
public static readonly DirectProperty<CommitTimeTextBlock, ulong> TimestampProperty =
5074
AvaloniaProperty.RegisterDirect<CommitTimeTextBlock, ulong>(
5175
nameof(Timestamp),
@@ -83,7 +107,10 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
83107
HorizontalAlignment = HorizontalAlignment.Center;
84108
}
85109
}
86-
else if (change.Property == DateTimeFormatProperty || change.Property == Use24HoursProperty)
110+
else if (change.Property == DateTimeFormatProperty ||
111+
change.Property == Use24HoursProperty ||
112+
change.Property == DayOfWeekStyleProperty ||
113+
change.Property == UseLocalizedCultureProperty)
87114
{
88115
if (ShowAsDateTime)
89116
SetCurrentValue(TextProperty, GetDisplayText());
@@ -107,16 +134,26 @@ protected override void OnLoaded(RoutedEventArgs e)
107134
}
108135
};
109136
_refreshTimer.IsEnabled = !ShowAsDateTime;
137+
138+
Models.DateTimeFormat.Changed += OnDateTimeFormatChanged;
110139
}
111140

112141
protected override void OnUnloaded(RoutedEventArgs e)
113142
{
143+
Models.DateTimeFormat.Changed -= OnDateTimeFormatChanged;
144+
114145
_refreshTimer.Tag = null;
115146
_refreshTimer.IsEnabled = false;
116147

117148
base.OnUnloaded(e);
118149
}
119150

151+
private void OnDateTimeFormatChanged()
152+
{
153+
if (ShowAsDateTime)
154+
SetCurrentValue(TextProperty, GetDisplayText());
155+
}
156+
120157
protected override void OnDataContextChanged(EventArgs e)
121158
{
122159
base.OnDataContextChanged(e);
@@ -174,6 +211,8 @@ private string GetDisplayText()
174211
private bool _showAsDateTime = true;
175212
private bool _use24Hours = true;
176213
private int _dateTimeFormat = 0;
214+
private int _dayOfWeekStyle = 0;
215+
private bool _useLocalizedCulture = true;
177216
private ulong _timestamp = 0;
178217
private DispatcherTimer _refreshTimer = null;
179218
}

src/Views/DateTimePresenter.cs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Avalonia;
44
using Avalonia.Controls;
55
using Avalonia.Data;
6+
using Avalonia.Interactivity;
67

78
namespace SourceGit.Views
89
{
@@ -44,6 +45,30 @@ public int DateTimeFormat
4445
set => SetAndRaise(DateTimeFormatProperty, ref _dateTimeFormat, value);
4546
}
4647

48+
public static readonly DirectProperty<DateTimePresenter, int> DayOfWeekStyleProperty =
49+
AvaloniaProperty.RegisterDirect<DateTimePresenter, int>(
50+
nameof(DayOfWeekStyle),
51+
static o => o.DayOfWeekStyle,
52+
static (o, v) => o.DayOfWeekStyle = v);
53+
54+
public int DayOfWeekStyle
55+
{
56+
get => _dayOfWeekStyle;
57+
set => SetAndRaise(DayOfWeekStyleProperty, ref _dayOfWeekStyle, value);
58+
}
59+
60+
public static readonly DirectProperty<DateTimePresenter, bool> UseLocalizedCultureProperty =
61+
AvaloniaProperty.RegisterDirect<DateTimePresenter, bool>(
62+
nameof(UseLocalizedCulture),
63+
static o => o.UseLocalizedCulture,
64+
static (o, v) => o.UseLocalizedCulture = v);
65+
66+
public bool UseLocalizedCulture
67+
{
68+
get => _useLocalizedCulture;
69+
set => SetAndRaise(UseLocalizedCultureProperty, ref _useLocalizedCulture, value);
70+
}
71+
4772
public static readonly DirectProperty<DateTimePresenter, ulong> TimestampProperty =
4873
AvaloniaProperty.RegisterDirect<DateTimePresenter, ulong>(
4974
nameof(Timestamp),
@@ -73,6 +98,37 @@ public DateTimePresenter()
7398
Source = ViewModels.Preferences.Instance,
7499
Path = "DateTimeFormat"
75100
});
101+
102+
Bind(DayOfWeekStyleProperty, new Binding()
103+
{
104+
Mode = BindingMode.OneWay,
105+
Source = ViewModels.Preferences.Instance,
106+
Path = "DayOfWeekStyle"
107+
});
108+
109+
Bind(UseLocalizedCultureProperty, new Binding()
110+
{
111+
Mode = BindingMode.OneWay,
112+
Source = ViewModels.Preferences.Instance,
113+
Path = "DateTimeUseLocalizedCulture"
114+
});
115+
}
116+
117+
protected override void OnLoaded(RoutedEventArgs e)
118+
{
119+
base.OnLoaded(e);
120+
Models.DateTimeFormat.Changed += OnDateTimeFormatChanged;
121+
}
122+
123+
protected override void OnUnloaded(RoutedEventArgs e)
124+
{
125+
Models.DateTimeFormat.Changed -= OnDateTimeFormatChanged;
126+
base.OnUnloaded(e);
127+
}
128+
129+
private void OnDateTimeFormatChanged()
130+
{
131+
SetCurrentValue(TextProperty, Models.DateTimeFormat.Format(Timestamp, ShowDateOnly));
76132
}
77133

78134
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
@@ -82,6 +138,8 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
82138
if (change.Property == ShowDateOnlyProperty ||
83139
change.Property == Use24HoursProperty ||
84140
change.Property == DateTimeFormatProperty ||
141+
change.Property == DayOfWeekStyleProperty ||
142+
change.Property == UseLocalizedCultureProperty ||
85143
change.Property == TimestampProperty)
86144
{
87145
var text = Models.DateTimeFormat.Format(Timestamp, ShowDateOnly);
@@ -92,6 +150,8 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
92150
private bool _showDateOnly = false;
93151
private bool _use24Hours = true;
94152
private int _dateTimeFormat = 0;
153+
private int _dayOfWeekStyle = 0;
154+
private bool _useLocalizedCulture = true;
95155
private ulong _timestamp = 0;
96156
}
97157
}

src/Views/Histories.axaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@
206206
Timestamp="{Binding AuthorTime, Mode=OneWay}"
207207
ShowAsDateTime="{Binding Source={x:Static vm:Preferences.Instance}, Path=!DisplayTimeAsPeriodInHistories, Mode=OneWay}"
208208
DateTimeFormat="{Binding Source={x:Static vm:Preferences.Instance}, Path=DateTimeFormat, Mode=OneWay}"
209+
DayOfWeekStyle="{Binding Source={x:Static vm:Preferences.Instance}, Path=DayOfWeekStyle, Mode=OneWay}"
210+
UseLocalizedCulture="{Binding Source={x:Static vm:Preferences.Instance}, Path=DateTimeUseLocalizedCulture, Mode=OneWay}"
209211
Use24Hours="{Binding Source={x:Static vm:Preferences.Instance}, Path=Use24Hours, Mode=OneWay}"/>
210212
</Border>
211213
</DataTemplate>
@@ -226,6 +228,8 @@
226228
Timestamp="{Binding CommitterTime, Mode=OneWay}"
227229
ShowAsDateTime="{Binding Source={x:Static vm:Preferences.Instance}, Path=!DisplayTimeAsPeriodInHistories, Mode=OneWay}"
228230
DateTimeFormat="{Binding Source={x:Static vm:Preferences.Instance}, Path=DateTimeFormat, Mode=OneWay}"
231+
DayOfWeekStyle="{Binding Source={x:Static vm:Preferences.Instance}, Path=DayOfWeekStyle, Mode=OneWay}"
232+
UseLocalizedCulture="{Binding Source={x:Static vm:Preferences.Instance}, Path=DateTimeUseLocalizedCulture, Mode=OneWay}"
229233
Use24Hours="{Binding Source={x:Static vm:Preferences.Instance}, Path=Use24Hours, Mode=OneWay}"/>
230234
</Border>
231235
</DataTemplate>

0 commit comments

Comments
 (0)