Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Commit 12576ae

Browse files
committed
Merge feature/pr/views into don/stub-ui
2 parents 87b176a + c198545 commit 12576ae

File tree

71 files changed

+1684
-573
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+1684
-573
lines changed

src/DesignTimeStyleHelper/WindowController.xaml.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ public partial class WindowController : Window
1212
{
1313
IDisposable disposable;
1414

15-
public WindowController(IObservable<IView> controls)
15+
public WindowController(IObservable<LoadData> controls)
1616
{
1717
InitializeComponent();
1818

19-
disposable = controls.Subscribe(c => Load(c),
19+
disposable = controls.Subscribe(c => Load(c.View),
2020
Close
2121
);
2222
}

src/GitHub.App/Controllers/UIController.cs

Lines changed: 196 additions & 133 deletions
Large diffs are not rendered by default.

src/GitHub.App/Factories/SqlitePersistentBlobCacheFactory.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Akavache.Sqlite3;
33
using NLog;
44
using System;
5+
using System.Collections.Generic;
56
using System.ComponentModel.Composition;
67

78
namespace GitHub.Factories
@@ -11,14 +12,19 @@ namespace GitHub.Factories
1112
public class SqlitePersistentBlobCacheFactory : IBlobCacheFactory
1213
{
1314
static readonly Logger log = LogManager.GetCurrentClassLogger();
15+
Dictionary<string, IBlobCache> cache = new Dictionary<string, IBlobCache>();
1416

1517
public IBlobCache CreateBlobCache(string path)
1618
{
1719
Guard.ArgumentNotEmptyString(path, nameof(path));
20+
if (cache.ContainsKey(path))
21+
return cache[path];
1822

1923
try
2024
{
21-
return new SQLitePersistentBlobCache(path);
25+
var c = new SQLitePersistentBlobCache(path);
26+
cache.Add(path, c);
27+
return c;
2228
}
2329
catch(Exception ex)
2430
{

src/GitHub.App/Factories/UIFactory.cs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,7 @@ public UIFactory(IExportFactoryProvider factory)
3333
/// <returns>true if the View/ViewModel didn't exist and had to be created</returns>
3434
public IUIPair CreateViewAndViewModel(UIViewType viewType)
3535
{
36-
var d = new UIPair(viewType, factory.GetView(viewType), factory.GetViewModel(viewType));
37-
d.View.ViewModel = d.ViewModel;
38-
return d;
36+
return new UIPair(viewType, factory.GetView(viewType), factory.GetViewModel(viewType));
3937
}
4038
}
4139

@@ -45,10 +43,10 @@ public IUIPair CreateViewAndViewModel(UIViewType viewType)
4543
/// </summary>
4644
public class UIPair : IUIPair
4745
{
48-
ExportLifetimeContext<IView> view;
49-
ExportLifetimeContext<IViewModel> viewModel;
50-
CompositeDisposable handlers = new CompositeDisposable();
51-
UIViewType viewType;
46+
readonly ExportLifetimeContext<IView> view;
47+
readonly ExportLifetimeContext<IViewModel> viewModel;
48+
readonly CompositeDisposable handlers = new CompositeDisposable();
49+
readonly UIViewType viewType;
5250

5351
public UIViewType ViewType => viewType;
5452
public IView View => view.Value;
@@ -90,9 +88,7 @@ void Dispose(bool disposing)
9088
if (!handlers.IsDisposed)
9189
handlers.Dispose();
9290
view?.Dispose();
93-
view = null;
9491
viewModel?.Dispose();
95-
viewModel = null;
9692
disposed = true;
9793
}
9894
}

src/GitHub.App/GitHub.App.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,10 @@
128128
<DesignTime>True</DesignTime>
129129
<DependentUpon>Resources.resx</DependentUpon>
130130
</Compile>
131+
<Compile Include="SampleData\AccountDesigner.cs" />
131132
<Compile Include="SampleData\PullRequestCreationViewModelDesigner.cs" />
132133
<Compile Include="SampleData\PullRequestDetailViewModelDesigner.cs" />
134+
<Compile Include="SampleData\LoggedOutViewModelDesigner.cs" />
133135
<Compile Include="SampleData\PullRequestListViewModelDesigner.cs" />
134136
<Compile Include="Services\AvatarProvider.cs" />
135137
<Compile Include="Services\GitHubCredentialProvider.cs" />

src/GitHub.App/Models/Account.cs

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace GitHub.Models
1111
[DebuggerDisplay("{DebuggerDisplay,nq}")]
1212
public class Account : ReactiveObject, IAccount
1313
{
14-
readonly ObservableAsPropertyHelper<BitmapSource> avatar;
14+
BitmapSource avatar;
1515

1616
public Account(
1717
string login,
@@ -29,8 +29,8 @@ public Account(
2929
IsOnFreePlan = privateRepositoryInPlanCount == 0;
3030
HasMaximumPrivateRepositories = OwnedPrivateRepos >= PrivateReposInPlan;
3131

32-
avatar = bitmapSource.ObserveOn(RxApp.MainThreadScheduler)
33-
.ToProperty(this, a => a.Avatar);
32+
bitmapSource.ObserveOn(RxApp.MainThreadScheduler)
33+
.Subscribe(x => avatar = x);
3434
}
3535

3636
public bool IsOnFreePlan { get; private set; }
@@ -47,13 +47,80 @@ public Account(
4747

4848
public long PrivateReposInPlan { get; private set; }
4949

50+
[AllowNull]
5051
public BitmapSource Avatar
5152
{
5253
[return: AllowNull]
53-
get
54-
{
55-
return avatar.Value;
56-
}
54+
get { return avatar; }
55+
set { avatar = value; this.RaisePropertyChanged(); }
56+
}
57+
58+
#region Equality things
59+
public void CopyFrom(IAccount other)
60+
{
61+
if (!Equals(other))
62+
throw new ArgumentException("Instance to copy from doesn't match this instance. this:(" + this + ") other:(" + other + ")", nameof(other));
63+
OwnedPrivateRepos = other.OwnedPrivateRepos;
64+
PrivateReposInPlan = other.PrivateReposInPlan;
65+
IsOnFreePlan = other.IsOnFreePlan;
66+
HasMaximumPrivateRepositories = other.HasMaximumPrivateRepositories;
67+
Avatar = other.Avatar;
68+
}
69+
70+
public override bool Equals([AllowNull]object obj)
71+
{
72+
if (ReferenceEquals(this, obj))
73+
return true;
74+
var other = obj as Account;
75+
return other != null && Login == other.Login && IsUser == other.IsUser && IsEnterprise == other.IsEnterprise;
76+
}
77+
78+
public override int GetHashCode()
79+
{
80+
return (Login?.GetHashCode() ?? 0) ^ IsUser .GetHashCode() ^ IsEnterprise.GetHashCode();
81+
}
82+
83+
bool IEquatable<IAccount>.Equals([AllowNull]IAccount other)
84+
{
85+
if (ReferenceEquals(this, other))
86+
return true;
87+
return other != null && Login == other.Login && IsUser == other.IsUser && IsEnterprise == other.IsEnterprise;
88+
}
89+
90+
public int CompareTo([AllowNull]IAccount other)
91+
{
92+
return other != null ? String.Compare(Login, other.Login, StringComparison.CurrentCulture) : 1;
93+
}
94+
95+
public static bool operator >([AllowNull]Account lhs, [AllowNull]Account rhs)
96+
{
97+
if (ReferenceEquals(lhs, rhs))
98+
return false;
99+
return lhs?.CompareTo(rhs) > 0;
100+
}
101+
102+
public static bool operator <([AllowNull]Account lhs, [AllowNull]Account rhs)
103+
{
104+
if (ReferenceEquals(lhs, rhs))
105+
return false;
106+
return (object)lhs == null || lhs.CompareTo(rhs) < 0;
107+
}
108+
109+
public static bool operator ==([AllowNull]Account lhs, [AllowNull]Account rhs)
110+
{
111+
return Equals(lhs, rhs) && ((object)lhs == null || lhs.CompareTo(rhs) == 0);
112+
}
113+
114+
public static bool operator !=([AllowNull]Account lhs, [AllowNull]Account rhs)
115+
{
116+
return !(lhs == rhs);
117+
}
118+
#endregion
119+
120+
[return: AllowNull]
121+
public override string ToString()
122+
{
123+
return Login;
57124
}
58125

59126
internal string DebuggerDisplay

src/GitHub.App/Models/PullRequestModel.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,21 @@
33
using GitHub.Primitives;
44
using GitHub.VisualStudio.Helpers;
55
using NullGuard;
6+
using System.Diagnostics;
67

78
namespace GitHub.Models
89
{
10+
[DebuggerDisplay("{DebuggerDisplay,nq}")]
911
public sealed class PullRequestModel : NotificationAwareObject, IPullRequestModel
1012
{
11-
public PullRequestModel(int number, string title, IAccount author, DateTimeOffset createdAt, DateTimeOffset? updatedAt = null)
13+
public PullRequestModel(int number, string title,
14+
IAccount author, [AllowNull]IAccount assignee,
15+
DateTimeOffset createdAt, DateTimeOffset? updatedAt = null)
1216
{
1317
Number = number;
1418
Title = title;
1519
Author = author;
20+
Assignee = assignee;
1621
CreatedAt = createdAt;
1722
UpdatedAt = updatedAt ?? CreatedAt;
1823
}
@@ -26,6 +31,7 @@ public void CopyFrom(IPullRequestModel other)
2631
CommentCount = other.CommentCount;
2732
HasNewComments = other.HasNewComments;
2833
IsOpen = other.IsOpen;
34+
Assignee = other.Assignee;
2935
}
3036

3137
public override bool Equals([AllowNull]object obj)
@@ -111,10 +117,28 @@ public bool HasNewComments
111117
public DateTimeOffset UpdatedAt { get; set; }
112118
public IAccount Author { get; set; }
113119

120+
IAccount assignee;
121+
[AllowNull]
122+
public IAccount Assignee
123+
{
124+
[return: AllowNull]
125+
get { return assignee; }
126+
set { assignee = value; this.RaisePropertyChange(); }
127+
}
128+
129+
114130
[return: AllowNull] // nullguard thinks a string.Format can return null. sigh.
115131
public override string ToString()
116132
{
117133
return string.Format(CultureInfo.InvariantCulture, "id:{0} title:{1} created:{2:u} updated:{3:u}", Number, Title, CreatedAt, UpdatedAt);
118134
}
135+
136+
internal string DebuggerDisplay
137+
{
138+
get
139+
{
140+
return string.Format(CultureInfo.InvariantCulture, "id:{0} title:{1} created:{2:u} updated:{3:u}", Number, Title, CreatedAt, UpdatedAt);
141+
}
142+
}
119143
}
120144
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
using System;
2+
using System.Diagnostics.CodeAnalysis;
3+
using System.Windows.Media.Imaging;
4+
using GitHub.Models;
5+
using GitHub.Services;
6+
7+
namespace GitHub.SampleData
8+
{
9+
[ExcludeFromCodeCoverage]
10+
public sealed class AccountDesigner : IAccount
11+
{
12+
public AccountDesigner()
13+
{
14+
Login = "octocat";
15+
IsUser = true;
16+
}
17+
18+
public BitmapSource Avatar
19+
{
20+
get
21+
{
22+
return IsUser
23+
? AvatarProvider.CreateBitmapImage("pack://application:,,,/GitHub.App;component/Images/default_user_avatar.png")
24+
: AvatarProvider.CreateBitmapImage("pack://application:,,,/GitHub.App;component/Images/default_org_avatar.png");
25+
}
26+
}
27+
28+
public bool HasMaximumPrivateRepositories { get; set; }
29+
public bool IsEnterprise { get; set; }
30+
public bool IsOnFreePlan { get; set; }
31+
public bool IsUser { get; set; }
32+
public string Login { get; set; }
33+
public int OwnedPrivateRepos { get; set; }
34+
public long PrivateReposInPlan { get; set; }
35+
36+
public override string ToString()
37+
{
38+
return Login;
39+
}
40+
41+
#region Equality things
42+
public void CopyFrom(IAccount other)
43+
{
44+
if (!Equals(other))
45+
throw new ArgumentException("Instance to copy from doesn't match this instance. this:(" + this + ") other:(" + other + ")", nameof(other));
46+
OwnedPrivateRepos = other.OwnedPrivateRepos;
47+
PrivateReposInPlan = other.PrivateReposInPlan;
48+
IsOnFreePlan = other.IsOnFreePlan;
49+
HasMaximumPrivateRepositories = other.HasMaximumPrivateRepositories;
50+
}
51+
52+
public override bool Equals(object obj)
53+
{
54+
if (ReferenceEquals(this, obj))
55+
return true;
56+
var other = obj as Account;
57+
return other != null && Login == other.Login && IsUser == other.IsUser && IsEnterprise == other.IsEnterprise;
58+
}
59+
60+
public override int GetHashCode()
61+
{
62+
return (Login?.GetHashCode() ?? 0) ^ IsUser.GetHashCode() ^ IsEnterprise.GetHashCode();
63+
}
64+
65+
bool IEquatable<IAccount>.Equals(IAccount other)
66+
{
67+
if (ReferenceEquals(this, other))
68+
return true;
69+
return other != null && Login == other.Login && IsUser == other.IsUser && IsEnterprise == other.IsEnterprise;
70+
}
71+
72+
public int CompareTo(IAccount other)
73+
{
74+
return other != null ? String.Compare(Login, other.Login, StringComparison.CurrentCulture) : 1;
75+
}
76+
77+
public static bool operator >(AccountDesigner lhs, AccountDesigner rhs)
78+
{
79+
if (ReferenceEquals(lhs, rhs))
80+
return false;
81+
return lhs?.CompareTo(rhs) > 0;
82+
}
83+
84+
public static bool operator <(AccountDesigner lhs, AccountDesigner rhs)
85+
{
86+
if (ReferenceEquals(lhs, rhs))
87+
return false;
88+
return (object)lhs == null || lhs.CompareTo(rhs) < 0;
89+
}
90+
91+
public static bool operator ==(AccountDesigner lhs, AccountDesigner rhs)
92+
{
93+
return Equals(lhs, rhs) && ((object)lhs == null || lhs.CompareTo(rhs) == 0);
94+
}
95+
96+
public static bool operator !=(AccountDesigner lhs, AccountDesigner rhs)
97+
{
98+
return !(lhs == rhs);
99+
}
100+
#endregion
101+
102+
}
103+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System;
2+
using System.Diagnostics.CodeAnalysis;
3+
using System.Reactive.Linq;
4+
using System.Windows.Input;
5+
using GitHub.Collections;
6+
using GitHub.Models;
7+
using GitHub.ViewModels;
8+
9+
namespace GitHub.SampleData
10+
{
11+
[ExcludeFromCodeCoverage]
12+
public class LoggedOutViewModelDesigner : BaseViewModelDesigner, IViewModel
13+
{
14+
public LoggedOutViewModelDesigner()
15+
{
16+
}
17+
}
18+
}

0 commit comments

Comments
 (0)