Skip to content

Add avatar CommitListItemView and other fixes #1676

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 23, 2024
Merged
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

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions CodeEdit/Features/Contributors/ContributorRowView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,12 @@ struct ContributorRowView: View {
.resizable()
.frame(width: 32, height: 32)
.clipShape(Circle())
.help(contributor.name)
} placeholder: {
Image(systemName: "person.circle.fill")
.resizable()
.frame(width: 32, height: 32)
.help(contributor.name)
}
}

Expand Down
34 changes: 25 additions & 9 deletions CodeEdit/Features/Git/Client/GitClient+CommitHistory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,34 @@ extension GitClient {
dateFormatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss Z"

let output = try await run(
"log --pretty=%h¦%H¦%s¦%aN¦%ae¦%cn¦%ce¦%aD¦ \(maxCountString) \(branchNameString) \(fileLocalPath)"
"log --pretty=%h¦%H¦%s¦%aN¦%ae¦%cn¦%ce¦%aD¦%b¦%D¦ \(maxCountString) \(branchNameString) \(fileLocalPath)"
.trimmingCharacters(in: .whitespacesAndNewlines)
)

let remote = try? await run("ls-remote --get-url")
let remoteURL: URL? = if let remote {
URL(string: remote.trimmingCharacters(in: .whitespacesAndNewlines))
} else {
nil
}
let remote = try await run("ls-remote --get-url")
let remoteURL = URL(string: remote.trimmingCharacters(in: .whitespacesAndNewlines))

return output
.split(separator: "\n")
.map { line -> GitCommit in
let parameters = line.components(separatedBy: "¦")
let parameters = String(line).components(separatedBy: "¦")
let infoRef = parameters[safe: 9]
var refs: [String] = []
var tag = ""
if let infoRef = infoRef {
if infoRef.contains("tag:") {
tag = infoRef.components(separatedBy: "tag:")[1].trimmingCharacters(in: .whitespaces)
} else {
refs = infoRef.split(separator: ",").compactMap {
var element = String($0)
if element.contains("origin/HEAD") { return nil }
if element.contains("HEAD -> ") {
element = element.replacingOccurrences(of: "HEAD -> ", with: "")
}
return element.trimmingCharacters(in: .whitespaces)
}
}
}

return GitCommit(
hash: parameters[safe: 0] ?? "",
commitHash: parameters[safe: 1] ?? "",
Expand All @@ -54,6 +67,9 @@ extension GitClient {
authorEmail: parameters[safe: 4] ?? "",
committer: parameters[safe: 5] ?? "",
committerEmail: parameters[safe: 6] ?? "",
body: parameters[safe: 8] ?? "",
refs: refs,
tag: tag,
remoteURL: remoteURL,
date: dateFormatter.date(from: parameters[safe: 7] ?? "") ?? Date()
)
Expand Down
3 changes: 3 additions & 0 deletions CodeEdit/Features/Git/Client/Models/GitCommit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ struct GitCommit: Equatable, Hashable, Identifiable {
let authorEmail: String
let committer: String
let committerEmail: String
let body: String
let refs: [String]
let tag: String
let remoteURL: URL?
let date: Date

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ struct HistoryInspectorItemView: View {
}

var body: some View {
CommitListItemView(commit: commit)
CommitListItemView(commit: commit, showRef: false)
.popover(isPresented: showPopup, arrowEdge: .leading) {
HistoryPopoverView(commit: commit)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,13 @@ struct CommitDetailsHeaderView: View {
.resizable()
.clipShape(Circle())
.frame(width: 32, height: 32)
.help(commit.author)
} else if phase.error != nil {
defaultAvatar
.help(commit.author)
} else {
defaultAvatar
.help(commit.author)
}
}

Expand All @@ -98,8 +101,20 @@ struct CommitDetailsHeaderView: View {
)
.padding(.horizontal, 2.5)
}
.padding(.horizontal, 16)

Divider()

Text(commitDetails())
.fontWeight(.bold)
.padding(.horizontal, 16)
.frame(alignment: .leading)

if !commit.body.isEmpty {
Text(commit.body)
.padding(.horizontal, 16)
.frame(alignment: .leading)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ struct CommitDetailsView: View {

if let commit = commit {
CommitDetailsHeaderView(commit: commit)
.padding(.horizontal, 16)
.padding(.vertical, 16)
Divider()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,126 @@ import SwiftUI
struct CommitListItemView: View {

var commit: GitCommit
var showRef: Bool
var width: CGFloat

private var defaultAvatar: some View {
Image(systemName: "person.crop.circle.fill")
.symbolRenderingMode(.hierarchical)
.resizable()
.foregroundColor(avatarColor)
.frame(width: 32, height: 32)
}

private func generateAvatarHash() -> String {
let hash = commit.authorEmail.md5(trim: true, caseSensitive: false)
return "\(hash)?d=404&s=64" // send 404 if no image available, image size 64x64 (32x32 @2x)
}

private var avatarColor: Color {
let hash = generateAvatarHash().hash
switch hash % 12 {
case 0: return .red
case 1: return .orange
case 2: return .yellow
case 3: return .green
case 4: return .mint
case 5: return .teal
case 6: return .cyan
case 7: return .blue
case 8: return .indigo
case 9: return .purple
case 10: return .brown
case 11: return .pink
default: return .teal
}
}

@Environment(\.openURL)
private var openCommit

init(commit: GitCommit) {
init(commit: GitCommit, showRef: Bool) {
self.commit = commit
self.showRef = showRef
self.width = 0
}

init(commit: GitCommit, showRef: Bool, width: CGFloat) {
self.commit = commit
self.showRef = showRef
self.width = width
}

var body: some View {
HStack(alignment: .top) {
if width > 360 {
AsyncImage(url: URL(string: "https://www.gravatar.com/avatar/\(generateAvatarHash())")) { phase in
if let image = phase.image {
image
.resizable()
.clipShape(Circle())
.frame(width: 32, height: 32)
.help(commit.author)
} else if phase.error != nil {
defaultAvatar
.help(commit.author)
} else {
defaultAvatar
.help(commit.author)
}
}
}
VStack(alignment: .leading, spacing: 0) {
Text(commit.author)
.fontWeight(.bold)
.font(.system(size: 11))
Text(commit.message)
HStack {
Text(commit.author)
.fontWeight(.bold)
.font(.system(size: 11))
if showRef {
if !commit.refs.isEmpty {
HStack {
ForEach(commit.refs, id: \.self) { ref in
HStack {
Image.branch
.imageScale(.small)
.foregroundColor(.primary)
.help(ref)
Text(ref)
.font(.system(size: 10, design: .monospaced))
}
.frame(height: 13)
.background(
RoundedRectangle(cornerRadius: 3)
.padding(.vertical, -1)
.padding(.horizontal, -2.5)
.foregroundColor(Color(nsColor: .quaternaryLabelColor))
)
.padding(.trailing, 2.5)
}
}
}

if !commit.tag.isEmpty {
HStack {
Image.breakpoint
.imageScale(.small)
.foregroundColor(.primary)
.help(commit.tag)
Text(commit.tag)
.font(.system(size: 10, design: .monospaced))
}
.frame(height: 13)
.background(
RoundedRectangle(cornerRadius: 3)
.padding(.vertical, -1)
.padding(.horizontal, -2.5)
.foregroundColor(Color(nsColor: .selectedContentBackgroundColor))
)
.padding(.trailing, 2.5)
}
}
}

Text("\(commit.message) \(commit.body)")
.font(.system(size: 11))
.lineLimit(2)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct SourceControlNavigatorHistoryView: View {
@State var commitHistory: [GitCommit] = []

@State var selection: GitCommit?
@State private var width: CGFloat = CGFloat.zero

func updateCommitHistory() async {
do {
Expand Down Expand Up @@ -55,17 +56,25 @@ struct SourceControlNavigatorHistoryView: View {
if commitHistory.isEmpty {
CEContentUnavailableView("No History")
} else {
ZStack {
List(selection: $selection) {
ForEach(commitHistory) { commit in
CommitListItemView(commit: commit)
.tag(commit)
.listRowSeparator(.hidden)
GeometryReader { geometry in
ZStack {
List(selection: $selection) {
ForEach(commitHistory) { commit in
CommitListItemView(commit: commit, showRef: true, width: width)
.tag(commit)
.listRowSeparator(.hidden)
}
}
.opacity(selection == nil ? 1 : 0)
if selection != nil {
CommitDetailsView(commit: $selection)
}
}
.onAppear {
self.width = geometry.size.width
}
.opacity(selection == nil ? 1 : 0)
if selection != nil {
CommitDetailsView(commit: $selection)
.onChange(of: geometry.size.width) { newWidth in
self.width = newWidth
}
}
}
Expand All @@ -89,11 +98,6 @@ struct SourceControlNavigatorHistoryView: View {
}
}
}
.onReceive(sourceControlManager.$currentBranch) { _ in
Task {
await updateCommitHistory()
}
}
.task {
await updateCommitHistory()
}
Expand Down