Skip to content

Commit 5eba707

Browse files
Tasks and Activity Viewer UI Improvements (#1831)
### Description This PR refines the UI around Tasks and the Activity Viewer. ### Screenshots https://github.com/user-attachments/assets/2edbd761-b09b-4a06-ad74-45825d1effa3 <img width="309" alt="image" src="https://github.com/user-attachments/assets/dfa6cd2b-3191-4a6c-80a3-28e16e654283"> <br /> <img width="303" alt="image" src="https://github.com/user-attachments/assets/8d77d592-7cbf-46b5-a9c2-c155bd3d0eda"> https://github.com/user-attachments/assets/6fae003d-244c-42eb-8ec1-22c27b6b9e9c ### Commits * Made a few minor adjustments to the activity bar UI. * Cleaned up activity viewer menus * Gave spacers a minLength * Unified TaskView duplication. Refined workspace settings and add and edit task sheet design * Displaying workspace settings in a sheet instead of a window. Added minimum width to workspace settings bottons. * Improved the activity viewer notification details popover design * Conditional display and animation of stop toolbar button * Added activity viewer notification animations. * Fix Task Renew Race Condition, Stop Button Listeners * Fixed SwiftLint error and reorganized Task folder structure * Resolved PR issues. When running a task, the task output appears in the utility area and drawer opens if closed. * Fixed SwiftLint errors * PR issues * Removed statusSubject and statusPublisher * Fixed bug where you could not rerun a task that was finished --------- Co-authored-by: Khan Winter <35942988+thecoolwinter@users.noreply.github.com>
1 parent b2b4909 commit 5eba707

33 files changed

+603
-487
lines changed

CodeEdit.xcodeproj/project.pbxproj

Lines changed: 45 additions & 13 deletions
Large diffs are not rendered by default.

CodeEdit/Features/ActivityViewer/ActivityViewer.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,14 @@ struct ActivityViewer: View {
4646
.fixedSize()
4747
}
4848
.fixedSize(horizontal: false, vertical: false)
49-
.padding(.horizontal, 10)
49+
.padding(.horizontal, 5)
50+
.padding(.vertical, 1.5)
51+
.frame(height: 22)
52+
.clipped()
5053
.background {
5154
if colorScheme == .dark {
5255
RoundedRectangle(cornerRadius: 5)
53-
.opacity(0.10)
56+
.opacity(0.1)
5457
} else {
5558
RoundedRectangle(cornerRadius: 5)
5659
.opacity(0.1)

CodeEdit/Features/ActivityViewer/Notificaitons/TaskNotificationView.swift

Lines changed: 0 additions & 66 deletions
This file was deleted.

CodeEdit/Features/ActivityViewer/Notificaitons/TaskNotificationsDetailView.swift

Lines changed: 0 additions & 108 deletions
This file was deleted.

CodeEdit/Features/ActivityViewer/Notificaitons/CustomLoadingRingView.swift renamed to CodeEdit/Features/ActivityViewer/Notifications/CECircularProgressView.swift

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
//
2-
// CustomLoadingRingView.swift
2+
// CECircularProgressView.swift
33
// CodeEdit
44
//
55
// Created by Tommy Ludwig on 21.06.24.
66
//
77

88
import SwiftUI
99

10-
struct CustomLoadingRingView: View {
10+
struct CECircularProgressView: View {
1111
@State private var isAnimating = false
1212
@State private var previousValue: Bool = false
13+
1314
var progress: Double?
14-
var currentTaskCount: Int
15+
var currentTaskCount: Int = 1
1516

1617
let lineWidth: CGFloat = 2
18+
1719
var body: some View {
1820
Circle()
1921
.stroke(style: StrokeStyle(lineWidth: lineWidth))
@@ -22,12 +24,12 @@ struct CustomLoadingRingView: View {
2224
if let progress = progress {
2325
Circle()
2426
.trim(from: 0, to: progress)
25-
.stroke(Color.blue.gradient, style: StrokeStyle(lineWidth: lineWidth, lineCap: .round))
27+
.stroke(Color.accentColor, style: StrokeStyle(lineWidth: lineWidth, lineCap: .round))
2628
.animation(.easeInOut, value: progress)
2729
} else {
2830
Circle()
2931
.trim(from: 0, to: 0.5)
30-
.stroke(Color.blue.gradient, style: StrokeStyle(lineWidth: lineWidth, lineCap: .round))
32+
.stroke(Color.accentColor, style: StrokeStyle(lineWidth: lineWidth, lineCap: .round))
3133
.rotationEffect(
3234
previousValue ?
3335
.degrees(isAnimating ? 0 : -360)
@@ -41,6 +43,7 @@ struct CustomLoadingRingView: View {
4143
}
4244
}
4345
.rotationEffect(.degrees(-90))
46+
.padding(lineWidth/2)
4447
.overlay {
4548
if currentTaskCount > 1 {
4649
Text("\(currentTaskCount)")
@@ -52,10 +55,10 @@ struct CustomLoadingRingView: View {
5255

5356
#Preview {
5457
Group {
55-
CustomLoadingRingView(currentTaskCount: 1)
58+
CECircularProgressView(currentTaskCount: 1)
5659
.frame(width: 22, height: 22)
5760

58-
CustomLoadingRingView(progress: 0.65, currentTaskCount: 1)
61+
CECircularProgressView(progress: 0.65, currentTaskCount: 1)
5962
.frame(width: 22, height: 22)
6063
}
6164
.padding()
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//
2+
// TaskNotificationView.swift
3+
// CodeEdit
4+
//
5+
// Created by Tommy Ludwig on 21.06.24.
6+
//
7+
8+
import SwiftUI
9+
10+
struct TaskNotificationView: View {
11+
@ObservedObject var taskNotificationHandler: TaskNotificationHandler
12+
@State private var isPresented: Bool = false
13+
@State var notification: TaskNotificationModel?
14+
15+
var body: some View {
16+
ZStack {
17+
if let notification {
18+
HStack {
19+
Text(notification.title)
20+
.font(.subheadline)
21+
.transition(
22+
.asymmetric(insertion: .move(edge: .top), removal: .move(edge: .bottom))
23+
.combined(with: .opacity)
24+
)
25+
.id("NotificationTitle" + notification.title)
26+
27+
if notification.isLoading {
28+
CECircularProgressView(
29+
progress: notification.percentage,
30+
currentTaskCount: taskNotificationHandler.notifications.count
31+
)
32+
.padding(.horizontal, -1)
33+
.frame(height: 16)
34+
} else {
35+
if taskNotificationHandler.notifications.count > 1 {
36+
Text("\(taskNotificationHandler.notifications.count)")
37+
.font(.caption)
38+
.padding(5)
39+
.background(
40+
Circle()
41+
.foregroundStyle(.gray)
42+
.opacity(0.2)
43+
)
44+
.padding(-5)
45+
}
46+
}
47+
}
48+
.transition(.opacity.combined(with: .move(edge: .trailing)))
49+
.padding(3)
50+
.padding(-3)
51+
.padding(.trailing, 3)
52+
.popover(isPresented: $isPresented, arrowEdge: .bottom) {
53+
TaskNotificationsDetailView(taskNotificationHandler: taskNotificationHandler)
54+
}.onTapGesture {
55+
self.isPresented.toggle()
56+
}
57+
}
58+
}
59+
.animation(.easeInOut, value: notification)
60+
.onChange(of: taskNotificationHandler.notifications) { newValue in
61+
withAnimation {
62+
notification = newValue.first
63+
}
64+
}
65+
}
66+
67+
}
68+
69+
#Preview {
70+
TaskNotificationView(taskNotificationHandler: TaskNotificationHandler())
71+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//
2+
// TaskNotificationsDetailView.swift
3+
// CodeEdit
4+
//
5+
// Created by Tommy Ludwig on 21.06.24.
6+
//
7+
8+
import SwiftUI
9+
10+
struct TaskNotificationsDetailView: View {
11+
@ObservedObject var taskNotificationHandler: TaskNotificationHandler
12+
@State private var selectedTaskNotificationIndex: Int = 0
13+
var body: some View {
14+
ScrollView {
15+
VStack(alignment: .leading, spacing: 15) {
16+
ForEach(taskNotificationHandler.notifications, id: \.id) { notification in
17+
HStack(alignment: .center, spacing: 8) {
18+
CECircularProgressView(progress: notification.percentage)
19+
.frame(width: 16, height: 16)
20+
VStack(alignment: .leading) {
21+
Text(notification.title)
22+
.fixedSize(horizontal: false, vertical: true)
23+
.transition(.identity)
24+
25+
if let message = notification.message, !message.isEmpty {
26+
Text(message)
27+
.font(.subheadline)
28+
.foregroundStyle(.secondary)
29+
}
30+
}
31+
Spacer()
32+
}
33+
}
34+
}
35+
}
36+
.padding(15)
37+
.frame(minWidth: 320)
38+
.onChange(of: taskNotificationHandler.notifications) { newValue in
39+
if selectedTaskNotificationIndex >= newValue.count {
40+
selectedTaskNotificationIndex = 0
41+
}
42+
}
43+
}
44+
}
45+
46+
#Preview {
47+
TaskNotificationsDetailView(taskNotificationHandler: TaskNotificationHandler())
48+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//
2+
// ActiveTaskView.swift
3+
// CodeEdit
4+
//
5+
// Created by Austin Condiff on 8/4/24.
6+
//
7+
8+
import SwiftUI
9+
10+
// We need to observe each active task individually because:
11+
// 1. Active tasks are nested inside TaskManager.
12+
// 2. Reference types (like objects) do not notify observers when their internal state changes.
13+
/// `ActiveTaskView` represents a single active task and observes its state.
14+
/// - Parameter activeTask: The active task to be displayed and observed.
15+
struct ActiveTaskView: View {
16+
@ObservedObject var activeTask: CEActiveTask
17+
18+
var body: some View {
19+
TaskView(task: activeTask.task, status: activeTask.status)
20+
}
21+
}

0 commit comments

Comments
 (0)