Skip to content
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

fix: pprof list should scroll to top after importing new pprof files #16

Merged
merged 1 commit into from
Aug 15, 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
2 changes: 1 addition & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
uses: actions/checkout@v4
- name: Set up Xcode
run: |
sudo xcode-select -s "/Applications/Xcode_16_beta_4.app"
sudo xcode-select -s "/Applications/Xcode_16_beta_5.app"
xcodebuild -version
- name: Allow macro
run: |
Expand Down
24 changes: 12 additions & 12 deletions approf.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
EB85AB992C3EAA410080200A /* SuccessView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB85AB982C3EAA410080200A /* SuccessView.swift */; };
EB8624A72C47A03B0010E153 /* Texts.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB8624A62C47A03B0010E153 /* Texts.swift */; };
EB8624A92C47B19D0010E153 /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB8624A82C47B19D0010E153 /* File.swift */; };
EB8BADE32C6E8FA60036B81E /* TestAppDropFiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB8BADE22C6E8FA60036B81E /* TestAppDropFiles.swift */; };
EB9355652C47E9D10055C90D /* StatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB9355642C47E9D10055C90D /* StatusView.swift */; };
EB9355672C47F4E50055C90D /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB9355662C47F4E50055C90D /* Image.swift */; };
EB94442A2C42F6E50050F0D1 /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB9444192C42F6E50050F0D1 /* State.swift */; };
Expand All @@ -57,7 +58,6 @@
EB9444352C42F6E50050F0D1 /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB94441F2C42F6E50050F0D1 /* WelcomeView.swift */; };
EB9444362C42F6E50050F0D1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EB9444242C42F6E50050F0D1 /* Assets.xcassets */; };
EB9444372C42F6E50050F0D1 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EB9444162C42F6E50050F0D1 /* Preview Assets.xcassets */; };
EB94443B2C42F7050050F0D1 /* pprofTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB9444392C42F7050050F0D1 /* pprofTests.swift */; };
EB94443F2C42F70E0050F0D1 /* pprofUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB94443D2C42F70E0050F0D1 /* pprofUITestsLaunchTests.swift */; };
EB9444402C42F70E0050F0D1 /* pprofUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB94443C2C42F70E0050F0D1 /* pprofUITests.swift */; };
EB96D98D2C470E9C00FA6E52 /* UTH.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB96D98B2C470E9C00FA6E52 /* UTH.swift */; };
Expand All @@ -73,11 +73,11 @@
EBBB83272C60E4D6002F2892 /* NameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBBB83262C60E4D6002F2892 /* NameView.swift */; };
EBBB83292C60E673002F2892 /* NameFeature.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBBB83282C60E673002F2892 /* NameFeature.swift */; };
EBBB832B2C60EC3A002F2892 /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBBB832A2C60EC3A002F2892 /* Date.swift */; };
EBBC581A2C668A0F00A72918 /* TestDropFiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBBC58192C668A0F00A72918 /* TestDropFiles.swift */; };
EBBC581A2C668A0F00A72918 /* TestDropFilesLegacy.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBBC58192C668A0F00A72918 /* TestDropFilesLegacy.swift */; };
EBBC581B2C668A0F00A72918 /* Dummy.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBBC58172C668A0F00A72918 /* Dummy.swift */; };
EBBC581C2C668A0F00A72918 /* b.pb in Resources */ = {isa = PBXBuildFile; fileRef = EBBC58162C668A0F00A72918 /* b.pb */; };
EBBC581D2C668A0F00A72918 /* a.pb.gz in Resources */ = {isa = PBXBuildFile; fileRef = EBBC58152C668A0F00A72918 /* a.pb.gz */; };
EBBC581F2C669A8100A72918 /* TestDropFilesUsingSwiftTesting.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBBC581E2C669A8100A72918 /* TestDropFilesUsingSwiftTesting.swift */; };
EBBC581F2C669A8100A72918 /* TestDropFiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBBC581E2C669A8100A72918 /* TestDropFiles.swift */; };
EBD20FBD2C42D06300EE88D7 /* LightsOff.metal in Sources */ = {isa = PBXBuildFile; fileRef = EBD20FBC2C42D06300EE88D7 /* LightsOff.metal */; };
EBD292B42C430F8000FFB285 /* ShortcutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBD292B32C430F8000FFB285 /* ShortcutView.swift */; };
EBD292BA2C430F9700FFB285 /* KeyboardShortcuts in Frameworks */ = {isa = PBXBuildFile; productRef = EBD292B92C430F9700FFB285 /* KeyboardShortcuts */; };
Expand Down Expand Up @@ -168,6 +168,7 @@
EB85AB982C3EAA410080200A /* SuccessView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuccessView.swift; sourceTree = "<group>"; };
EB8624A62C47A03B0010E153 /* Texts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Texts.swift; sourceTree = "<group>"; };
EB8624A82C47B19D0010E153 /* File.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = File.swift; sourceTree = "<group>"; };
EB8BADE22C6E8FA60036B81E /* TestAppDropFiles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestAppDropFiles.swift; sourceTree = "<group>"; };
EB9355642C47E9D10055C90D /* StatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusView.swift; sourceTree = "<group>"; };
EB9355662C47F4E50055C90D /* Image.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Image.swift; sourceTree = "<group>"; };
EB9444162C42F6E50050F0D1 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
Expand All @@ -182,7 +183,6 @@
EB9444252C42F6E50050F0D1 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
EB9444272C42F6E50050F0D1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
EB9444282C42F6E50050F0D1 /* pprof.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = pprof.entitlements; sourceTree = "<group>"; };
EB9444392C42F7050050F0D1 /* pprofTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = pprofTests.swift; sourceTree = "<group>"; };
EB94443C2C42F70E0050F0D1 /* pprofUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = pprofUITests.swift; sourceTree = "<group>"; };
EB94443D2C42F70E0050F0D1 /* pprofUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = pprofUITestsLaunchTests.swift; sourceTree = "<group>"; };
EB96D98B2C470E9C00FA6E52 /* UTH.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UTH.swift; sourceTree = "<group>"; };
Expand All @@ -200,8 +200,8 @@
EBBC58152C668A0F00A72918 /* a.pb.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = a.pb.gz; sourceTree = "<group>"; };
EBBC58162C668A0F00A72918 /* b.pb */ = {isa = PBXFileReference; lastKnownFileType = file; path = b.pb; sourceTree = "<group>"; };
EBBC58172C668A0F00A72918 /* Dummy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dummy.swift; sourceTree = "<group>"; };
EBBC58192C668A0F00A72918 /* TestDropFiles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestDropFiles.swift; sourceTree = "<group>"; };
EBBC581E2C669A8100A72918 /* TestDropFilesUsingSwiftTesting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestDropFilesUsingSwiftTesting.swift; sourceTree = "<group>"; };
EBBC58192C668A0F00A72918 /* TestDropFilesLegacy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestDropFilesLegacy.swift; sourceTree = "<group>"; };
EBBC581E2C669A8100A72918 /* TestDropFiles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestDropFiles.swift; sourceTree = "<group>"; };
EBBC58202C669B0500A72918 /* TestPlan.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; name = TestPlan.xctestplan; path = approfTests/TestPlan.xctestplan; sourceTree = "<group>"; };
EBD20FBC2C42D06300EE88D7 /* LightsOff.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = LightsOff.metal; sourceTree = "<group>"; };
EBD292B32C430F8000FFB285 /* ShortcutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -388,9 +388,9 @@
isa = PBXGroup;
children = (
EBBC58182C668A0F00A72918 /* Files */,
EBBC58192C668A0F00A72918 /* TestDropFiles.swift */,
EBBC581E2C669A8100A72918 /* TestDropFilesUsingSwiftTesting.swift */,
EB9444392C42F7050050F0D1 /* pprofTests.swift */,
EBBC58192C668A0F00A72918 /* TestDropFilesLegacy.swift */,
EBBC581E2C669A8100A72918 /* TestDropFiles.swift */,
EB8BADE22C6E8FA60036B81E /* TestAppDropFiles.swift */,
);
path = approfTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -742,10 +742,10 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
EBBC581A2C668A0F00A72918 /* TestDropFiles.swift in Sources */,
EBBC581A2C668A0F00A72918 /* TestDropFilesLegacy.swift in Sources */,
EBBC581B2C668A0F00A72918 /* Dummy.swift in Sources */,
EBBC581F2C669A8100A72918 /* TestDropFilesUsingSwiftTesting.swift in Sources */,
EB94443B2C42F7050050F0D1 /* pprofTests.swift in Sources */,
EB8BADE32C6E8FA60036B81E /* TestAppDropFiles.swift in Sources */,
EBBC581F2C669A8100A72918 /* TestDropFiles.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
9 changes: 5 additions & 4 deletions approf.xcodeproj/xcshareddata/xcschemes/approf.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
shouldUseLaunchSchemeArgsEnv = "YES">
<TestPlans>
<TestPlanReference
reference = "container:approfTests/TestPlan.xctestplan">
reference = "container:approfTests/TestPlan.xctestplan"
default = "YES">
</TestPlanReference>
</TestPlans>
<Testables>
Expand Down Expand Up @@ -59,9 +60,9 @@
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
buildConfiguration = "Release"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
Expand Down
24 changes: 17 additions & 7 deletions approf/View/AppFeature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,14 @@ struct AppFeature {
case onMoveUpCommand
case onMoveDownCommand


case deleteNow(UUID)
case pprofs(IdentifiedActionOf<DetailFeature>)


case drop(DropFeature.Action)
}

@Dependency(\.uuid) var uuid
@Dependency(\.continuousClock) var clock

var body: some ReducerOf<Self> {
Scope(state: \.drop, action: \.drop) {
Expand Down Expand Up @@ -105,7 +104,19 @@ struct AppFeature {
case .pprofs:
return .none
case let .drop(.delegate(.addNewBasic(basic))):
self.addNewBasic(&state, basic)
self.addNewBasics(&state, [basic])
return .run { send in
try await clock.sleep(for: .seconds(0.2))
await send(.onPprofsSelectedIdChanged(basic.id))
}
case let .drop(.delegate(.addNewBasics(basics))):
self.addNewBasics(&state, basics)
if let first = basics.first {
return .run { send in
try await clock.sleep(for: .seconds(0.2))
await send(.onPprofsSelectedIdChanged(first.id))
}
}
return .none
case let .drop(.delegate(.selectPProf(uuid))):
if state.pprofs.contains(where: { $0.id == uuid }) {
Expand All @@ -121,8 +132,8 @@ struct AppFeature {
}
}

func addNewBasic(_ state: inout Self.State, _ basic: PProfBasic) {
state.basics.insert(basic, at: 0)
func addNewBasics(_ state: inout Self.State, _ basics: [PProfBasic]) {
state.basics.insert(contentsOf: basics, at: 0)
state.synced = false
sync(&state)
}
Expand Down Expand Up @@ -180,7 +191,7 @@ struct AppFeature {
}
}
}

private func move(_ state: inout Self.State, _ source: IndexSet, _ destination: Int) {
state.pprofs.move(fromOffsets: source, toOffset: destination)
}
Expand All @@ -202,7 +213,6 @@ struct AppFeature {
state.pprofs.move(fromOffsets: IndexSet([index]), toOffset: index + 2)
}
}

}

extension PersistenceReaderKey
Expand Down
36 changes: 12 additions & 24 deletions approf/View/ImportFeature/DropFeature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ struct DropFeature {
@CasePathable
enum Delegate {
case addNewBasic(PProfBasic)
case addNewBasics([PProfBasic])
case selectPProf(UUID)
}
}
Expand All @@ -49,48 +50,35 @@ struct DropFeature {
if filePaths.isEmpty {
return .none
} else if filePaths.count == 1 {
let basic = PProfBasic(uuid: uuid(), filePaths: filePaths, createdAt: date.now ,presentation: .dft)
return .run { send in
try await clock.sleep(for: .seconds(0.1))
await send(.delegate(.addNewBasic(basic)), animation: .default)
try await clock.sleep(for: .seconds(0.1))
await send(.delegate(.selectPProf(basic.id)), animation: .default)
}
let basic = PProfBasic(uuid: uuid(), filePaths: filePaths, createdAt: date.now, presentation: .dft)
return .send(.delegate(.addNewBasic(basic)))
} else if filePaths.count == 2 {
state.destination = .uth(UnderTheHood.State(basic: Shared(PProfBasic(uuid: uuid(), filePaths: filePaths, createdAt: date.now, presentation: .diff))))
return .none
} else {
state.destination = .uth(UnderTheHood.State(basic: Shared(PProfBasic(uuid: uuid(), filePaths: filePaths, createdAt: date.now, presentation: .acc))))
return .none
}
case .destination(.presented(.uth(.delegate(.onCancelImportButtonTapped)))), .destination(.presented(.uth(.delegate(.onImportViewAutoDismissed)))):
state.destination = nil
return .none
case .destination(.presented(.uth(.delegate(.onConfirmImportButtonTapped)))):
guard case let .uth(uthFeature) = state.destination else {
return .none
}
state.destination = nil
// When DropView disappears, the animation for the profs list doesn't work.
// To fix this, update the profs list after DropView has fully disappeared.
if case .dft = uthFeature.basic.presentation {
let filePaths = uthFeature.basic.filePaths
let basics = uthFeature.basic.filePaths.reversed().map {
PProfBasic(uuid: uuid(), filePaths: [$0], createdAt: date.now, presentation: .dft)
}
return .run { send in
for fp in filePaths.reversed() {
try await clock.sleep(for: .seconds(0.03))
let basic = PProfBasic(uuid: uuid(), filePaths: [fp], createdAt: date.now, presentation: .dft)
await send(.delegate(.addNewBasic(basic)), animation: .default)
if fp == filePaths.first {
try await clock.sleep(for: .seconds(0.03))
await send(.delegate(.selectPProf(basic.id)), animation: .default)
}
}
try await clock.sleep(for: .seconds(0.25))
await send(.delegate(.addNewBasics(basics)))
}
} else {
let basic = PProfBasic(uuid: uuid(), filePaths: uthFeature.basic.filePaths, createdAt: date.now, presentation: uthFeature.basic.presentation)
return .run { send in
try await clock.sleep(for: .seconds(0.03))
await send(.delegate(.addNewBasic(basic)), animation: .default)
try await clock.sleep(for: .seconds(0.03))
await send(.delegate(.selectPProf(basic.id)), animation: .default)
try await clock.sleep(for: .seconds(0.25))
await send(.delegate(.addNewBasic(basic)))
}
}
case .destination:
Expand Down
5 changes: 1 addition & 4 deletions approf/View/ImportFeature/ImportView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,13 @@ struct ImportView: View {
.toolbar {
toolbar()
}
.onDisappear {
store.send(.delegate(.onImportViewAutoDismissed))
}
}

@ToolbarContentBuilder
private func toolbar() -> some ToolbarContent {
ToolbarItem(placement: .destructiveAction) {
Button("Cancel(ESC)", role: .cancel) {
store.send(.delegate(.onCancelImportButtonTapped))
store.send(.onCancelImportButtonTapped)
}
}
ToolbarItem(placement: .confirmationAction) {
Expand Down
35 changes: 23 additions & 12 deletions approf/View/NavigaionView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,31 @@ struct NavigaionView: View {

@ViewBuilder
private func list() -> some View {
List(selection: $store.pprofsSelectedId.sending(\.onPprofsSelectedIdChanged).animation()) {
ForEach(store.scope(state: \.pprofs, action: \.pprofs), id: \.basic.id) { pprofStore in
PProfRowView(store: pprofStore)
.addHiddenView(pprofStore.id) {
if store.pprofsSelectedId == pprofStore.id {
rowContextMenu(pprofUUID: pprofStore.id)
ScrollViewReader { proxy in
List(selection: $store.pprofsSelectedId.sending(\.onPprofsSelectedIdChanged).animation()) {
ForEach(store.scope(state: \.pprofs, action: \.pprofs), id: \.basic.id) { pprofStore in
PProfRowView(store: pprofStore)
.addHiddenView(pprofStore.id) {
if store.pprofsSelectedId == pprofStore.id {
rowContextMenu(pprofUUID: pprofStore.id)
}
}
}
.contextMenu { rowContextMenu(pprofUUID: pprofStore.id) }
.listRowSeparator(.visible)
.listRowSeparatorTint(.secondary.opacity(0.5))
.contextMenu { rowContextMenu(pprofUUID: pprofStore.id) }
.listRowSeparator(.visible)
.listRowSeparatorTint(.secondary.opacity(0.5))
.id(pprofStore.id)
}
.onMove { from, to in
store.send(.onMove(from: from, to: to), animation: .default)
}
}
.onMove { from, to in
store.send(.onMove(from: from, to: to), animation: .default)
.onChange(of: store.pprofs.count) { old, neu in
// scroll to top of the list when new elements are added
if neu > old, let first = store.pprofs.first {
withAnimation {
proxy.scrollTo(first.id, anchor: .top)
}
}
}
}
}
Expand Down
8 changes: 6 additions & 2 deletions approf/View/UnderTheHood/UTH.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,19 @@ struct UnderTheHood {
case newNotification(String)
case newCountDownNotification(String, UInt)

case onCancelImportButtonTapped

case delegate(Delegate)

@CasePathable
enum Delegate {
// MARK: for import view
case onImportViewAutoDismissed
case onCancelImportButtonTapped
case onConfirmImportButtonTapped
}
}

@Dependency(\.dismiss) var dismiss

var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
Expand Down Expand Up @@ -93,6 +95,8 @@ struct UnderTheHood {
case let .newCountDownNotification(text, seconds):
state.destination = .notification(.init(text: text, seconds: seconds))
return .none
case .onCancelImportButtonTapped:
return .run { _ in await dismiss() }
}
}
.ifLet(\.$destination, action: \.destination)
Expand Down
Loading
Loading