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

Offline: Remove downloaded area and view details #843

Merged
merged 62 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
d72c3ee
Add logics related to mmpk removal.
yo1995 Aug 21, 2024
6c8afda
Add metadata view.
yo1995 Aug 26, 2024
a6f8dac
Changes to the list view to present metadata view.
yo1995 Aug 26, 2024
1a5c007
Move constant strings to an enum.
yo1995 Aug 26, 2024
49b1db3
Fix loadable image view to fit aspect ratio.
yo1995 Aug 26, 2024
463d335
File size related changes.
yo1995 Aug 27, 2024
0aae655
Metadata related changes.
yo1995 Aug 27, 2024
d00b8e0
Merge branch 'OfflineMapAreasView' into Ting/RemovalAndDetails
yo1995 Aug 27, 2024
a1105c5
Dismiss full swipe to avoid accidental deletion.
yo1995 Aug 27, 2024
954a5bd
Limit the display scale of thumbnail to not exceed resolution.
yo1995 Aug 27, 2024
0c29ae8
Add onTap list item to show the metadata and remove swipe action.
yo1995 Aug 27, 2024
6ac2ff1
Set selectedMap to nil when a map area is removed from local disk.
yo1995 Aug 27, 2024
d4dc292
Set selectedMap to nil when a map area is removed from local disk.
yo1995 Aug 28, 2024
29db2c9
Renamve boolean.
yo1995 Aug 28, 2024
fbdce12
Rename metadata view.
yo1995 Aug 28, 2024
c99254b
Refactor downloaded status check.
yo1995 Aug 28, 2024
95e1aa5
No need to write metadata for preplanned.
yo1995 Aug 28, 2024
0afbcc4
Remove unneeded strings.
yo1995 Aug 28, 2024
48edbd1
MetadataView -> PreplannedMetadataView.
yo1995 Aug 28, 2024
21d7d88
Handle empty description.
yo1995 Aug 28, 2024
70b58f3
Don't use image for delete button.
yo1995 Aug 28, 2024
7170162
Remove unused string literal.
yo1995 Aug 29, 2024
bf05aa8
Add unit test for remove method.
yo1995 Aug 29, 2024
c637a95
Refactor removal method.
yo1995 Aug 29, 2024
a2a95c4
Use destructive delete button.
yo1995 Aug 29, 2024
e438a21
Change thumbnail style.
yo1995 Aug 29, 2024
5822c36
Adjust appearance.
yo1995 Aug 29, 2024
c111220
Rename onDelete closure.
yo1995 Aug 29, 2024
e4ffa56
Fix comment.
yo1995 Aug 29, 2024
e6abe37
Rename onDelete.
yo1995 Aug 29, 2024
53c0723
Add failure handling.
yo1995 Aug 29, 2024
eac92f6
Add content shape to make HStack tappable.
yo1995 Aug 29, 2024
ae3464c
Address suggestions from code review.
yo1995 Aug 30, 2024
c226361
Make size not optional.
yo1995 Aug 30, 2024
ef8859f
Rename deletion closure.
yo1995 Aug 30, 2024
e5d4657
Add URL suffix.
yo1995 Aug 30, 2024
414ac80
File size naming.
yo1995 Aug 30, 2024
b64ccad
File size formatting.
yo1995 Aug 31, 2024
c2fe659
Remove unneeded nav modifier.
yo1995 Aug 31, 2024
8fd4f76
Swap call order.
yo1995 Sep 3, 2024
cc77628
Move the convenience Booleans to the model.
yo1995 Sep 3, 2024
48521dc
Remove string constant type.
yo1995 Sep 3, 2024
72678b1
Use convenience appending method.
yo1995 Sep 4, 2024
cf9b325
Make constants computed.
yo1995 Sep 4, 2024
464a66a
Refactor done button.
yo1995 Sep 4, 2024
e4b5214
Move size calculation.
yo1995 Sep 4, 2024
282ed0f
More changes for mmpk size.
yo1995 Sep 4, 2024
d9ce613
Add tests for convenience booleans.
yo1995 Sep 4, 2024
6af6676
Apply suggestions from code review.
yo1995 Sep 5, 2024
7a67a85
Fix optionality.
yo1995 Sep 5, 2024
4a9c8ad
URL related suggestion.
yo1995 Sep 6, 2024
94ffbbe
Add button to go back online.
yo1995 Sep 11, 2024
a1e6680
Revamp selection logic.
yo1995 Sep 11, 2024
15e2a7b
Move reload back into the remove method.
yo1995 Sep 11, 2024
72b96de
Fix test.
yo1995 Sep 11, 2024
7f1e9a6
Remove onDeletion closure as it is not used.
yo1995 Sep 11, 2024
b9749e3
Resolve merge conflict.
yo1995 Sep 11, 2024
fe527f7
Remove `onMapSelectionChanged` closure.
yo1995 Sep 12, 2024
8a61fd5
Update selection condition and mmpk loading.
yo1995 Sep 13, 2024
626590e
Add missing comment.
yo1995 Sep 13, 2024
ba9c4b5
Rename Boolean to read like assertion.
yo1995 Sep 13, 2024
8d1bd04
Merge pull request #867 from Esri/Ting/RevampSelection
yo1995 Sep 13, 2024
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
128 changes: 128 additions & 0 deletions Sources/ArcGISToolkit/Components/Offline/MetadataDetailView.swift
yo1995 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// Copyright 2024 Esri
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import ArcGIS
import SwiftUI

struct MetadataDetailView: View {
/// The view model for the preplanned map.
@ObservedObject var model: PreplannedMapModel

/// The action to dismiss the view.
@Environment(\.dismiss) private var dismiss: DismissAction

public var body: some View {
Form {
Section {
VStack(alignment: .leading) {
if let image = model.preplannedMapArea.thumbnail {
VStack(alignment: .leading, spacing: 0) {
Text("Thumbnail")
.font(.caption)
.foregroundStyle(.secondary)
LoadableImageView(loadableImage: image)
.clipShape(.rect(cornerRadius: 10))
.padding(.vertical, 10)
}
Divider()
}
VStack(alignment: .leading, spacing: 0) {
Text("Name")
.font(.caption)
.foregroundStyle(.secondary)
Text(model.preplannedMapArea.title)
.font(.subheadline)
}
Divider()
VStack(alignment: .leading, spacing: 0) {
Text("Description")
.font(.caption)
.foregroundStyle(.secondary)
Text(model.preplannedMapArea.description)
.font(.subheadline)
}
Divider()
if let size = model.directorySize {
yo1995 marked this conversation as resolved.
Show resolved Hide resolved
VStack(alignment: .leading, spacing: 0) {
Text("Size")
.font(.caption)
.foregroundStyle(.secondary)
Text(size.formatted(.byteCount(style: .file, allowedUnits: [.kb, .mb])))
.font(.subheadline)
}
}
}
}
Section {
HStack {
ZStack {
Image(systemName: "circle.fill")
.foregroundStyle(.secondary)
.opacity(0.1)
.font(.title)
yo1995 marked this conversation as resolved.
Show resolved Hide resolved
Image(systemName: "trash.fill")
.foregroundStyle(.red)
.imageScale(.medium)
}
Button {
dismiss()
Task {
await model.removeDownloadedPreplannedMapArea()
}
} label: {
Text("Delete Map Area")
.font(.subheadline)
.foregroundColor(.red)
yo1995 marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}
.navigationTitle(model.preplannedMapArea.title)
.navigationBarTitleDisplayMode(.inline)
.navigationBarBackButtonHidden()
.toolbar {
ToolbarItem(placement: .confirmationAction) {
Button {
dismiss()
} label: {
Text("Done")
.bold()
}
}
}
}
}

#Preview {
struct MockPreplannedMapArea: PreplannedMapAreaProtocol {
var packagingStatus: PreplannedMapArea.PackagingStatus? = .complete
var title: String = "Mock Preplanned Map Area"
var description: String = "This is the description text"
var thumbnail: LoadableImage? = nil

func retryLoad() async throws { }
func makeParameters(using offlineMapTask: OfflineMapTask) async throws -> DownloadPreplannedOfflineMapParameters {
DownloadPreplannedOfflineMapParameters()
}
}

return MetadataDetailView(
model: PreplannedMapModel(
offlineMapTask: OfflineMapTask(onlineMap: Map()),
mapArea: MockPreplannedMapArea(),
portalItemID: .init("preview")!,
preplannedMapAreaID: .init("preview")!
)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ public struct OfflineMapAreasView: View {
PreplannedListItemView(model: preplannedMapModel) { newMap in
selectedMap = newMap
dismiss()
} onMapDeletion: {
yo1995 marked this conversation as resolved.
Show resolved Hide resolved
selectedMap = nil
}
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,15 @@ struct PreplannedListItemView: View {
/// The view model for the preplanned map.
@ObservedObject var model: PreplannedMapModel

/// A Boolean value indicating whether the metadata view is presented.
@State private var detailsViewIsPresented = false

/// The closure to perform when the map selection changes.
let onMapSelectionChanged: (Map) -> Void

yo1995 marked this conversation as resolved.
Show resolved Hide resolved
/// The closure to perform when the map is removed from local disk.
let onMapDeletion: () -> Void

var body: some View {
HStack(alignment: .center, spacing: 10) {
thumbnailView
Expand All @@ -37,6 +43,19 @@ struct PreplannedListItemView: View {
statusView
}
}
.swipeActions {
deleteButton
}
yo1995 marked this conversation as resolved.
Show resolved Hide resolved
.onTapGesture {
if case .downloaded = model.status {
detailsViewIsPresented = true
}
}
.sheet(isPresented: $detailsViewIsPresented) {
NavigationStack {
MetadataDetailView(model: model)
}
}
.task {
await model.load()
}
Expand All @@ -55,6 +74,20 @@ struct PreplannedListItemView: View {
.font(.body)
}

@ViewBuilder private var deleteButton: some View {
if model.status.allowsRemoval {
Button {
Task {
await model.removeDownloadedPreplannedMapArea()
onMapDeletion()
}
} label: {
Label("Remove Area", systemImage: "trash")
yo1995 marked this conversation as resolved.
Show resolved Hide resolved
}
.tint(.red)
}
}

@ViewBuilder private var downloadButton: some View {
switch model.status {
case .downloaded:
Expand Down Expand Up @@ -154,6 +187,6 @@ struct PreplannedListItemView: View {
portalItemID: .init("preview")!,
preplannedMapAreaID: .init("preview")!
)
) { _ in }
) { _ in } onMapDeletion: { }
.padding()
}
Loading