refactor: code cleanup

This commit is contained in:
leo 2024-05-30 15:13:59 +08:00
parent 04f4293421
commit fa3a3b2dad
25 changed files with 174 additions and 233 deletions

View file

@ -1,18 +1,17 @@
using Avalonia.Controls; using Avalonia.Data.Converters;
using Avalonia.Data.Converters;
using Avalonia.Media; using Avalonia.Media;
namespace SourceGit.Converters namespace SourceGit.Converters
{ {
public static class BoolConverters public static class BoolConverters
{ {
public static readonly FuncValueConverter<bool, double> ToPageTabWidth =
new FuncValueConverter<bool, double>(x => x ? 200 : double.NaN);
public static readonly FuncValueConverter<bool, double> HalfIfFalse = public static readonly FuncValueConverter<bool, double> HalfIfFalse =
new FuncValueConverter<bool, double>(x => x ? 1 : 0.5); new FuncValueConverter<bool, double>(x => x ? 1 : 0.5);
public static readonly FuncValueConverter<bool, FontWeight> BoldIfTrue = public static readonly FuncValueConverter<bool, FontWeight> BoldIfTrue =
new FuncValueConverter<bool, FontWeight>(x => x ? FontWeight.Bold : FontWeight.Regular); new FuncValueConverter<bool, FontWeight>(x => x ? FontWeight.Bold : FontWeight.Regular);
public static readonly FuncValueConverter<bool, GridLength> ToStarOrAutoGridLength =
new(value => value ? new GridLength(1, GridUnitType.Star) : new GridLength(1, GridUnitType.Auto));
} }
} }

View file

@ -69,7 +69,7 @@ namespace SourceGit.Converters
public static readonly FormatByResourceKeyConverter FormatByResourceKey = new FormatByResourceKeyConverter(); public static readonly FormatByResourceKeyConverter FormatByResourceKey = new FormatByResourceKeyConverter();
public static readonly FuncValueConverter<string, string> ToShortSHA = public static readonly FuncValueConverter<string, string> ToShortSHA =
new FuncValueConverter<string, string>(v => v.Length > 10 ? v.Substring(0, 10) : v); new FuncValueConverter<string, string>(v => v == null ? string.Empty : (v.Length > 10 ? v.Substring(0, 10) : v));
public static readonly FuncValueConverter<string, bool> UnderRecommendGitVersion = public static readonly FuncValueConverter<string, bool> UnderRecommendGitVersion =
new(v => new(v =>

View file

@ -3,7 +3,6 @@
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Data.Converters; using Avalonia.Data.Converters;
using Avalonia.Media;
namespace SourceGit.Converters namespace SourceGit.Converters
{ {
@ -39,19 +38,6 @@ namespace SourceGit.Converters
} }
}); });
public static readonly FuncValueConverter<WindowState, StreamGeometry> ToMaxOrRestoreIcon =
new FuncValueConverter<WindowState, StreamGeometry>(state =>
{
if (state == WindowState.Maximized)
{
return Application.Current?.FindResource("Icons.Window.Restore") as StreamGeometry;
}
else
{
return Application.Current?.FindResource("Icons.Window.Maximize") as StreamGeometry;
}
});
public static readonly FuncValueConverter<WindowState, bool> IsNormal = public static readonly FuncValueConverter<WindowState, bool> IsNormal =
new FuncValueConverter<WindowState, bool>(state => state == WindowState.Normal); new FuncValueConverter<WindowState, bool>(state => state == WindowState.Normal);
} }

View file

@ -66,6 +66,12 @@
<Style Selector="Button:pointerover Path.change_mode_switcher_icon"> <Style Selector="Button:pointerover Path.change_mode_switcher_icon">
<Setter Property="Fill" Value="{DynamicResource Brush.Accent}"/> <Setter Property="Fill" Value="{DynamicResource Brush.Accent}"/>
</Style> </Style>
<Style Selector="Button.max_or_restore_btn Path">
<Setter Property="Data" Value="{StaticResource Icons.Window.Maximize}"/>
</Style>
<Style Selector="Window[WindowState=Maximized] Button.max_or_restore_btn Path">
<Setter Property="Data" Value="{StaticResource Icons.Window.Restore}"/>
</Style>
<Style Selector="TextBlock"> <Style Selector="TextBlock">
<Setter Property="HorizontalAlignment" Value="Left"/> <Setter Property="HorizontalAlignment" Value="Left"/>

View file

@ -24,9 +24,9 @@ namespace SourceGit.ViewModels
}); });
} }
public void Remove(object param) public void Remove(string file)
{ {
if (param is string file) if (!string.IsNullOrEmpty(file))
{ {
new Commands.AssumeUnchanged(_repo).Remove(file); new Commands.AssumeUnchanged(_repo).Remove(file);
Files.Remove(file); Files.Remove(file);

View file

@ -50,10 +50,10 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _extraArgs, value); set => SetProperty(ref _extraArgs, value);
} }
public Clone(Launcher launcher, LauncherPage page) public Clone(Launcher launcher)
{ {
_launcher = launcher; _launcher = launcher;
_page = page; _page = launcher.ActivePage;
View = new Views.Clone() { DataContext = this }; View = new Views.Clone() { DataContext = this };
} }

View file

@ -158,13 +158,6 @@ namespace SourceGit.ViewModels
get => _stashesPage == null ? 0 : _stashesPage.Count; get => _stashesPage == null ? 0 : _stashesPage.Count;
} }
[JsonIgnore]
public bool CanCommitWithPush
{
get => _canCommitWithPush;
private set => SetProperty(ref _canCommitWithPush, value);
}
[JsonIgnore] [JsonIgnore]
public bool IncludeUntracked public bool IncludeUntracked
{ {
@ -172,9 +165,7 @@ namespace SourceGit.ViewModels
set set
{ {
if (SetProperty(ref _includeUntracked, value)) if (SetProperty(ref _includeUntracked, value))
{
Task.Run(RefreshWorkingCopyChanges); Task.Run(RefreshWorkingCopyChanges);
}
} }
} }
@ -567,8 +558,11 @@ namespace SourceGit.ViewModels
LocalBranchTrees = builder.Locals; LocalBranchTrees = builder.Locals;
RemoteBranchTrees = builder.Remotes; RemoteBranchTrees = builder.Remotes;
var cur = Branches.Find(x => x.IsCurrent); if (_workingCopy != null)
CanCommitWithPush = cur != null && !string.IsNullOrEmpty(cur.Upstream); {
var cur = Branches.Find(x => x.IsCurrent);
_workingCopy.CanCommitWithPush = cur != null && !string.IsNullOrEmpty(cur.Upstream);
}
}); });
} }
@ -1520,7 +1514,6 @@ namespace SourceGit.ViewModels
private List<BranchTreeNode> _remoteBranchTrees = new List<BranchTreeNode>(); private List<BranchTreeNode> _remoteBranchTrees = new List<BranchTreeNode>();
private List<Models.Tag> _tags = new List<Models.Tag>(); private List<Models.Tag> _tags = new List<Models.Tag>();
private List<string> _submodules = new List<string>(); private List<string> _submodules = new List<string>();
private bool _canCommitWithPush = false;
private bool _includeUntracked = true; private bool _includeUntracked = true;
private InProgressContext _inProgressContext = null; private InProgressContext _inProgressContext = null;

View file

@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Threading; using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
@ -106,34 +106,42 @@ namespace SourceGit.ViewModels
_diffContext = null; _diffContext = null;
} }
public void Apply(object param) public ContextMenu MakeContextMenu(Models.Stash stash)
{ {
if (param is Models.Stash stash) if (stash == null)
{ return null;
Task.Run(() =>
{
new Commands.Stash(_repo.FullPath).Apply(stash.Name);
});
}
}
public void Pop(object param) var apply = new MenuItem();
{ apply.Header = App.Text("StashCM.Apply");
if (param is Models.Stash stash) apply.Click += (o, ev) =>
{ {
Task.Run(() => Task.Run(() => new Commands.Stash(_repo.FullPath).Apply(stash.Name));
{ ev.Handled = true;
new Commands.Stash(_repo.FullPath).Pop(stash.Name); };
});
}
}
public void Drop(object param) var pop = new MenuItem();
{ pop.Header = App.Text("StashCM.Pop");
if (param is Models.Stash stash && PopupHost.CanCreatePopup()) pop.Click += (o, ev) =>
{ {
PopupHost.ShowPopup(new DropStash(_repo.FullPath, stash)); Task.Run(() => new Commands.Stash(_repo.FullPath).Pop(stash.Name));
} ev.Handled = true;
};
var drop = new MenuItem();
drop.Header = App.Text("StashCM.Drop");
drop.Click += (o, ev) =>
{
if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new DropStash(_repo.FullPath, stash));
ev.Handled = true;
};
var menu = new ContextMenu();
menu.Items.Add(apply);
menu.Items.Add(pop);
menu.Items.Add(drop);
return menu;
} }
public void Clear() public void Clear()

View file

@ -2,6 +2,7 @@
using Avalonia.Collections; using Avalonia.Collections;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
@ -40,20 +41,21 @@ namespace SourceGit.ViewModels
} }
} }
public void Clone(object param) public void Clone()
{ {
var launcher = param as Launcher;
var page = launcher.ActivePage;
if (!Preference.Instance.IsGitConfigured) if (!Preference.Instance.IsGitConfigured)
{ {
App.RaiseException(page.GetId(), App.Text("NotConfigured")); App.RaiseException(string.Empty, App.Text("NotConfigured"));
return; return;
} }
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
{ {
PopupHost.ShowPopup(new Clone(launcher, page)); if (App.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
var launcher = desktop.MainWindow.DataContext as Launcher;
PopupHost.ShowPopup(new Clone(launcher));
}
} }
} }

View file

@ -37,6 +37,29 @@ namespace SourceGit.ViewModels
public class WorkingCopy : ObservableObject public class WorkingCopy : ObservableObject
{ {
public bool IncludeUntracked
{
get => _repo.IncludeUntracked;
set
{
if (_repo.IncludeUntracked != value)
{
_repo.IncludeUntracked = value;
OnPropertyChanged(nameof(IncludeUntracked));
}
}
}
public bool CanCommitWithPush
{
get => _canCommitWithPush;
set
{
if (SetProperty(ref _canCommitWithPush, value))
OnPropertyChanged(nameof(IsCommitWithPushVisible));
}
}
public bool IsStaging public bool IsStaging
{ {
get => _isStaging; get => _isStaging;
@ -74,9 +97,16 @@ namespace SourceGit.ViewModels
CommitMessage = commits[0].FullMessage; CommitMessage = commits[0].FullMessage;
} }
} }
OnPropertyChanged(nameof(IsCommitWithPushVisible));
} }
} }
public bool IsCommitWithPushVisible
{
get => !UseAmend && CanCommitWithPush;
}
public List<Models.Change> Unstaged public List<Models.Change> Unstaged
{ {
get => _unstaged; get => _unstaged;
@ -161,14 +191,31 @@ namespace SourceGit.ViewModels
public void Cleanup() public void Cleanup()
{ {
_repo = null; _repo = null;
if (_unstaged != null)
_unstaged.Clear();
if (_staged != null)
_staged.Clear();
if (_selectedUnstaged != null) if (_selectedUnstaged != null)
{
_selectedUnstaged.Clear(); _selectedUnstaged.Clear();
OnPropertyChanged(nameof(SelectedUnstaged));
}
if (_selectedStaged != null) if (_selectedStaged != null)
{
_selectedStaged.Clear(); _selectedStaged.Clear();
OnPropertyChanged(nameof(SelectedStaged));
}
if (_unstaged != null)
{
_unstaged.Clear();
OnPropertyChanged(nameof(Unstaged));
}
if (_staged != null)
{
_staged.Clear();
OnPropertyChanged(nameof(Staged));
}
_detailContext = null; _detailContext = null;
_commitMessage = string.Empty; _commitMessage = string.Empty;
} }
@ -1016,6 +1063,7 @@ namespace SourceGit.ViewModels
private bool _isUnstaging = false; private bool _isUnstaging = false;
private bool _isCommitting = false; private bool _isCommitting = false;
private bool _useAmend = false; private bool _useAmend = false;
private bool _canCommitWithPush = false;
private List<Models.Change> _unstaged = null; private List<Models.Change> _unstaged = null;
private List<Models.Change> _staged = null; private List<Models.Change> _staged = null;
private List<Models.Change> _selectedUnstaged = null; private List<Models.Change> _selectedUnstaged = null;

View file

@ -92,9 +92,7 @@
<DataGridTemplateColumn> <DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellTemplate>
<DataTemplate> <DataTemplate>
<Button Classes="icon_button" <Button Classes="icon_button" Click="OnRemoveButtonClicked">
Command="{Binding $parent[v:AssumeUnchangedManager].DataContext.(vm:AssumeUnchangedManager).Remove}"
CommandParameter="{Binding}">
<Path Width="14" Height="14" Data="{StaticResource Icons.Clear}"/> <Path Width="14" Height="14" Data="{StaticResource Icons.Clear}"/>
</Button> </Button>
</DataTemplate> </DataTemplate>

View file

@ -20,5 +20,12 @@ namespace SourceGit.Views
{ {
Close(); Close();
} }
private void OnRemoveButtonClicked(object sender, RoutedEventArgs e) {
if (DataContext is ViewModels.AssumeUnchangedManager vm && sender is Button button)
vm.Remove(button.DataContext as string);
e.Handled = true;
}
} }
} }

View file

@ -11,8 +11,8 @@
<Button Classes="caption_button" Click="MinimizeWindow"> <Button Classes="caption_button" Click="MinimizeWindow">
<Path Data="{StaticResource Icons.Window.Minimize}"/> <Path Data="{StaticResource Icons.Window.Minimize}"/>
</Button> </Button>
<Button Classes="caption_button" Click="MaximizeOrRestoreWindow"> <Button Classes="caption_button max_or_restore_btn" Click="MaximizeOrRestoreWindow">
<Path Data="{Binding $parent[Window].WindowState, Converter={x:Static c:WindowStateConverters.ToMaxOrRestoreIcon}}"/> <Path/>
</Button> </Button>
<Button Classes="caption_button" Click="CloseWindow"> <Button Classes="caption_button" Click="CloseWindow">
<Path Data="{StaticResource Icons.Window.Close}" Width="9" Height="9"/> <Path Data="{StaticResource Icons.Window.Close}" Width="9" Height="9"/>

View file

@ -12,11 +12,7 @@
<DataTemplate DataType="m:Commit"> <DataTemplate DataType="m:Commit">
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">
<!-- Author & Committer --> <!-- Author & Committer -->
<Grid Margin="0,8"> <UniformGrid Rows="1" Margin="0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding IsCommitterVisible, Converter={x:Static c:BoolConverters.ToStarOrAutoGridLength}}"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- Author --> <!-- Author -->
<Grid Grid.Column="0" ColumnDefinitions="96,*"> <Grid Grid.Column="0" ColumnDefinitions="96,*">
<v:Avatar Grid.Column="0" Width="64" Height="64" HorizontalAlignment="Right" User="{Binding Author}"/> <v:Avatar Grid.Column="0" Width="64" Height="64" HorizontalAlignment="Right" User="{Binding Author}"/>
@ -48,7 +44,7 @@
Foreground="{DynamicResource Brush.FG2}"/> Foreground="{DynamicResource Brush.FG2}"/>
</StackPanel> </StackPanel>
</Grid> </Grid>
</Grid> </UniformGrid>
<!-- Line --> <!-- Line -->
<Rectangle Height=".65" Margin="8" Fill="{DynamicResource Brush.Border2}" VerticalAlignment="Center"/> <Rectangle Height=".65" Margin="8" Fill="{DynamicResource Brush.Border2}" VerticalAlignment="Center"/>

View file

@ -213,7 +213,8 @@
<!-- Text Diff --> <!-- Text Diff -->
<DataTemplate DataType="m:TextDiff"> <DataTemplate DataType="m:TextDiff">
<v:TextDiffView TextDiff="{Binding}" UseSideBySideDiff="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSideBySideDiff, Mode=OneWay}"/> <v:TextDiffView TextDiff="{Binding}"
UseSideBySideDiff="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSideBySideDiff, Mode=OneWay}"/>
</DataTemplate> </DataTemplate>
<!-- No or only EOL changes --> <!-- No or only EOL changes -->

View file

@ -129,7 +129,6 @@
</DataGrid> </DataGrid>
<v:CommitGraph x:Name="commitGraph" <v:CommitGraph x:Name="commitGraph"
BindingDataGrid="{Binding #commitDataGrid}"
Graph="{Binding Graph}" Graph="{Binding Graph}"
DotBrush="{DynamicResource Brush.Contents}" DotBrush="{DynamicResource Brush.Contents}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"

View file

@ -3,7 +3,6 @@ using System;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.VisualTree; using Avalonia.VisualTree;
@ -90,15 +89,6 @@ namespace SourceGit.Views
set => SetValue(GraphProperty, value); set => SetValue(GraphProperty, value);
} }
public static readonly StyledProperty<DataGrid> BindingDataGridProperty =
AvaloniaProperty.Register<CommitGraph, DataGrid>(nameof(BindingDataGrid));
public DataGrid BindingDataGrid
{
get => GetValue(BindingDataGridProperty);
set => SetValue(BindingDataGridProperty, value);
}
public static readonly StyledProperty<IBrush> DotBrushProperty = public static readonly StyledProperty<IBrush> DotBrushProperty =
AvaloniaProperty.Register<CommitGraph, IBrush>(nameof(DotBrush), Brushes.Transparent); AvaloniaProperty.Register<CommitGraph, IBrush>(nameof(DotBrush), Brushes.Transparent);
@ -108,17 +98,13 @@ namespace SourceGit.Views
set => SetValue(DotBrushProperty, value); set => SetValue(DotBrushProperty, value);
} }
static CommitGraph()
{
AffectsRender<CommitGraph>(BindingDataGridProperty, GraphProperty, DotBrushProperty);
}
public override void Render(DrawingContext context) public override void Render(DrawingContext context)
{ {
base.Render(context); base.Render(context);
var parent = this.FindAncestorOfType<Histories>();
var graph = Graph; var graph = Graph;
var grid = BindingDataGrid; var grid = parent.commitDataGrid;
if (graph == null || grid == null) if (graph == null || grid == null)
return; return;
@ -277,8 +263,6 @@ namespace SourceGit.Views
public Histories() public Histories()
{ {
InitializeComponent(); InitializeComponent();
this.Bind(NavigationIdProperty, new Binding("NavigationId", BindingMode.OneWay));
} }
private void OnCommitDataGridLayoutUpdated(object sender, EventArgs e) private void OnCommitDataGridLayoutUpdated(object sender, EventArgs e)

View file

@ -166,7 +166,7 @@
</ContextMenu> </ContextMenu>
</Border.ContextMenu> </Border.ContextMenu>
<v:LauncherTab UseFixedTabWidth="{Binding Source={x:Static vm:Preference.Instance}, Path=UseFixedTabWidth}" Height="30" ColumnDefinitions="Auto,*,Auto" VerticalAlignment="Center"> <Grid Width="{Binding Source={x:Static vm:Preference.Instance}, Path=UseFixedTabWidth, Converter={x:Static c:BoolConverters.ToPageTabWidth}}" Height="30" ColumnDefinitions="Auto,*,Auto" VerticalAlignment="Center">
<Path Grid.Column="0" <Path Grid.Column="0"
Width="12" Height="12" Margin="12,0" Width="12" Height="12" Margin="12,0"
Fill="{Binding Node.Bookmark, Converter={x:Static c:BookmarkConverters.ToBrush}}" Fill="{Binding Node.Bookmark, Converter={x:Static c:BookmarkConverters.ToBrush}}"
@ -219,7 +219,7 @@
</MultiBinding> </MultiBinding>
</Rectangle.IsVisible> </Rectangle.IsVisible>
</Rectangle> </Rectangle>
</v:LauncherTab> </Grid>
</Border> </Border>
</DataTemplate> </DataTemplate>
</ListBox.ItemTemplate> </ListBox.ItemTemplate>
@ -253,7 +253,17 @@
</Grid> </Grid>
<!-- Page body --> <!-- Page body -->
<v:LauncherBody Grid.Row="1" Background="{DynamicResource Brush.ToolBar}" Data="{Binding ActivePage.Data}"/> <ContentControl Grid.Row="1" Background="{DynamicResource Brush.ToolBar}" Content="{Binding ActivePage.Data}">
<ContentControl.DataTemplates>
<DataTemplate DataType="vm:Welcome">
<v:Welcome/>
</DataTemplate>
<DataTemplate DataType="vm:Repository">
<v:Repository/>
</DataTemplate>
</ContentControl.DataTemplates>
</ContentControl>
<!-- Popup container --> <!-- Popup container -->
<Grid Grid.Row="1" Margin="0,36,0,0" IsVisible="{Binding ActivePage.Popup, Converter={x:Static ObjectConverters.IsNotNull}}"> <Grid Grid.Row="1" Margin="0,36,0,0" IsVisible="{Binding ActivePage.Popup, Converter={x:Static ObjectConverters.IsNotNull}}">

View file

@ -7,67 +7,6 @@ using Avalonia.Interactivity;
namespace SourceGit.Views namespace SourceGit.Views
{ {
public class LauncherTab : Grid
{
public static readonly StyledProperty<bool> UseFixedTabWidthProperty =
AvaloniaProperty.Register<LauncherTab, bool>(nameof(UseFixedTabWidth), false);
public bool UseFixedTabWidth
{
get => GetValue(UseFixedTabWidthProperty);
set => SetValue(UseFixedTabWidthProperty, value);
}
protected override Type StyleKeyOverride => typeof(Grid);
static LauncherTab()
{
UseFixedTabWidthProperty.Changed.AddClassHandler<LauncherTab>((tab, ev) =>
{
tab.Width = tab.UseFixedTabWidth ? 200.0 : double.NaN;
});
}
}
public class LauncherBody : Border
{
public static readonly StyledProperty<object> DataProperty =
AvaloniaProperty.Register<LauncherBody, object>(nameof(Data), false);
public object Data
{
get => GetValue(DataProperty);
set => SetValue(DataProperty, value);
}
protected override Type StyleKeyOverride => typeof(Border);
static LauncherBody()
{
DataProperty.Changed.AddClassHandler<LauncherBody>((body, ev) =>
{
var data = body.Data;
if (data == null)
{
body.Child = null;
}
else if (data is ViewModels.Welcome)
{
body.Child = new Welcome { DataContext = data };
}
else if (data is ViewModels.Repository)
{
body.Child = new Repository { DataContext = data };
}
else
{
body.Child = null;
}
});
}
}
public partial class Launcher : Window, Models.INotificationReceiver public partial class Launcher : Window, Models.INotificationReceiver
{ {
public Launcher() public Launcher()

View file

@ -589,7 +589,21 @@
<Button Grid.Column="3" Classes="flat" FontWeight="Regular" Content="{DynamicResource Text.Repository.Abort}" Height="20" Padding="8,0" Margin="4,0" Command="{Binding AbortMerge}"/> <Button Grid.Column="3" Classes="flat" FontWeight="Regular" Content="{DynamicResource Text.Repository.Abort}" Height="20" Padding="8,0" Margin="4,0" Command="{Binding AbortMerge}"/>
</Grid> </Grid>
<v:RepositorySubView Grid.Row="1" Data="{Binding SelectedView}"/> <ContentControl Grid.Row="1" Content="{Binding SelectedView}">
<ContentControl.DataTemplates>
<DataTemplate DataType="vm:Histories">
<v:Histories NavigationId="{Binding NavigationId}"/>
</DataTemplate>
<DataTemplate DataType="vm:WorkingCopy">
<v:WorkingCopy/>
</DataTemplate>
<DataTemplate DataType="vm:StashesPage">
<v:StashesPage/>
</DataTemplate>
</ContentControl.DataTemplates>
</ContentControl>
</Grid> </Grid>
</Grid> </Grid>
</Grid> </Grid>

View file

@ -11,51 +11,6 @@ using Avalonia.VisualTree;
namespace SourceGit.Views namespace SourceGit.Views
{ {
public class RepositorySubView : Border
{
public static readonly StyledProperty<object> DataProperty =
AvaloniaProperty.Register<RepositorySubView, object>(nameof(Data), false);
public object Data
{
get => GetValue(DataProperty);
set => SetValue(DataProperty, value);
}
protected override Type StyleKeyOverride => typeof(Border);
static RepositorySubView()
{
DataProperty.Changed.AddClassHandler<RepositorySubView>((view, ev) =>
{
var data = view.Data;
if (data == null)
{
view.Child = null;
}
else if (data is ViewModels.Histories)
{
view.Child = new Histories { DataContext = data };
}
else if (data is ViewModels.WorkingCopy)
{
view.Child = new WorkingCopy { DataContext = data };
}
else if (data is ViewModels.StashesPage)
{
view.Child = new StashesPage { DataContext = data };
}
else
{
view.Child = null;
}
GC.Collect();
});
}
}
public partial class Repository : UserControl public partial class Repository : UserControl
{ {
public Repository() public Repository()

View file

@ -54,15 +54,7 @@
<DataGridTemplateColumn Width="*"> <DataGridTemplateColumn Width="*">
<DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="m:Stash"> <DataTemplate DataType="m:Stash">
<Border BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="0,0,0,1" Padding="4" Background="Transparent"> <Border BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="0,0,0,1" Padding="4" Background="Transparent" ContextRequested="OnStashContextRequested">
<Border.ContextMenu>
<ContextMenu>
<MenuItem Header="{DynamicResource Text.StashCM.Apply}" Command="{Binding $parent[v:StashesPage].DataContext.(vm:StashesPage).Apply}" CommandParameter="{Binding}"/>
<MenuItem Header="{DynamicResource Text.StashCM.Pop}" Command="{Binding $parent[v:StashesPage].DataContext.(vm:StashesPage).Pop}" CommandParameter="{Binding}"/>
<MenuItem Header="{DynamicResource Text.StashCM.Drop}" Command="{Binding $parent[v:StashesPage].DataContext.(vm:StashesPage).Drop}" CommandParameter="{Binding}"/>
</ContextMenu>
</Border.ContextMenu>
<Grid RowDefinitions="Auto,*" > <Grid RowDefinitions="Auto,*" >
<Grid Grid.Row="0" ColumnDefinitions="*,Auto"> <Grid Grid.Row="0" ColumnDefinitions="*,Auto">
<TextBlock Grid.Column="0" Classes="monospace" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" TextDecorations="Underline" Cursor="Hand"/> <TextBlock Grid.Column="0" Classes="monospace" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" TextDecorations="Underline" Cursor="Hand"/>

View file

@ -8,5 +8,15 @@ namespace SourceGit.Views
{ {
InitializeComponent(); InitializeComponent();
} }
private void OnStashContextRequested(object sender, ContextRequestedEventArgs e)
{
if (DataContext is ViewModels.StashesPage vm && sender is Border border)
{
var menu = vm.MakeContextMenu(border.DataContext as Models.Stash);
border.OpenContextMenu(menu);
}
e.Handled = true;
}
} }
} }

View file

@ -11,7 +11,7 @@
<Grid RowDefinitions="36,*,36" Background="{DynamicResource Brush.Window}"> <Grid RowDefinitions="36,*,36" Background="{DynamicResource Brush.Window}">
<Border Grid.Row="0" BorderBrush="{DynamicResource Brush.Border0}" BorderThickness="0,0,0,1" Background="{DynamicResource Brush.ToolBar}"> <Border Grid.Row="0" BorderBrush="{DynamicResource Brush.Border0}" BorderThickness="0,0,0,1" Background="{DynamicResource Brush.ToolBar}">
<StackPanel Orientation="Horizontal" Margin="4,0,0,0"> <StackPanel Orientation="Horizontal" Margin="4,0,0,0">
<Button Classes="icon_button" Width="32" Command="{Binding Clone}" CommandParameter="{Binding $parent[v:Launcher].DataContext}" ToolTip.Tip="{DynamicResource Text.Welcome.Clone}"> <Button Classes="icon_button" Width="32" Command="{Binding Clone}" ToolTip.Tip="{DynamicResource Text.Welcome.Clone}">
<Path Width="13" Height="13" Data="{StaticResource Icons.Pull}"/> <Path Width="13" Height="13" Data="{StaticResource Icons.Pull}"/>
</Button> </Button>

View file

@ -211,14 +211,8 @@
Height="28" Height="28"
Margin="8,0,0,0" Margin="8,0,0,0"
Padding="8,0" Padding="8,0"
Command="{Binding CommitWithPush}"> Command="{Binding CommitWithPush}"
<Button.IsVisible> IsVisible="{Binding IsCommitWithPushVisible}"/>
<MultiBinding Converter="{x:Static BoolConverters.And}">
<Binding Path="$parent[v:Repository].DataContext.(vm:Repository).CanCommitWithPush"/>
<Binding Path="!UseAmend"/>
</MultiBinding>
</Button.IsVisible>
</Button>
</Grid> </Grid>
</Grid> </Grid>
</Grid> </Grid>