parent
589f2f62e0
commit
afa22719bf
|
@ -47,9 +47,35 @@ extension MigrateContentView {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
List {
|
List {
|
||||||
Section {
|
profilesSection
|
||||||
Text(Strings.Views.Migrate.Sections.Main.header)
|
|
||||||
}
|
}
|
||||||
|
.themeNavigationDetail()
|
||||||
|
.toolbar {
|
||||||
|
ToolbarItem(placement: .confirmationAction) {
|
||||||
|
performButton()
|
||||||
|
.disabled(isEditing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension MigrateContentView.ListView {
|
||||||
|
var actionsHeader: some View {
|
||||||
|
VStack(alignment: .leading, spacing: 16) {
|
||||||
|
Text(Strings.Views.Migrate.Sections.Main.header)
|
||||||
|
EditProfilesButton(isEditing: $isEditing, selection: $selection) {
|
||||||
|
onDelete(profiles.filter {
|
||||||
|
selection.contains($0.id)
|
||||||
|
})
|
||||||
|
// disable isEditing after confirmation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.textCase(.none)
|
||||||
|
.listRowInsets(.init(top: 8, leading: 0, bottom: 8, trailing: 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
var profilesSection: some View {
|
||||||
Section {
|
Section {
|
||||||
ForEach(profiles, id: \.id) {
|
ForEach(profiles, id: \.id) {
|
||||||
if isEditing {
|
if isEditing {
|
||||||
|
@ -64,51 +90,11 @@ extension MigrateContentView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} header: {
|
} header: {
|
||||||
editButton
|
actionsHeader
|
||||||
}
|
}
|
||||||
.disabled(!step.canSelect)
|
.disabled(!step.canSelect)
|
||||||
}
|
}
|
||||||
.toolbar {
|
|
||||||
ToolbarItem(placement: .confirmationAction) {
|
|
||||||
performButton()
|
|
||||||
.disabled(isEditing)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private extension MigrateContentView.ListView {
|
|
||||||
var editButton: some View {
|
|
||||||
HStack {
|
|
||||||
if isEditing {
|
|
||||||
Button(Strings.Global.cancel) {
|
|
||||||
isEditing = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Spacer()
|
|
||||||
Button(isEditing ? Strings.Global.delete : Strings.Global.edit, role: isEditing ? .destructive : nil) {
|
|
||||||
if isEditing {
|
|
||||||
if !selection.isEmpty {
|
|
||||||
onDelete(profiles.filter {
|
|
||||||
selection.contains($0.id)
|
|
||||||
})
|
|
||||||
// disable isEditing after confirmation
|
|
||||||
} else {
|
|
||||||
isEditing = false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
selection = []
|
|
||||||
isEditing = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.disabled(isEditing && selection.isEmpty)
|
|
||||||
}
|
|
||||||
.frame(height: 30)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private extension MigrateContentView.ListView {
|
|
||||||
func isIncludedBinding(for profileId: UUID) -> Binding<Bool> {
|
func isIncludedBinding(for profileId: UUID) -> Binding<Bool> {
|
||||||
Binding {
|
Binding {
|
||||||
statuses[profileId] != .excluded
|
statuses[profileId] != .excluded
|
||||||
|
@ -134,6 +120,46 @@ private extension MigrateContentView.ListView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Subviews
|
||||||
|
|
||||||
|
private extension MigrateContentView.ListView {
|
||||||
|
struct EditProfilesButton: View {
|
||||||
|
|
||||||
|
@Binding
|
||||||
|
var isEditing: Bool
|
||||||
|
|
||||||
|
@Binding
|
||||||
|
var selection: Set<UUID>
|
||||||
|
|
||||||
|
let onDelete: () -> Void
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
HStack {
|
||||||
|
if isEditing {
|
||||||
|
Button(Strings.Global.cancel) {
|
||||||
|
isEditing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
Button(isEditing ? Strings.Global.delete : Strings.Global.edit, role: isEditing ? .destructive : nil) {
|
||||||
|
if isEditing {
|
||||||
|
if !selection.isEmpty {
|
||||||
|
onDelete()
|
||||||
|
} else {
|
||||||
|
isEditing = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
selection = []
|
||||||
|
isEditing = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.disabled(isEditing && selection.isEmpty)
|
||||||
|
}
|
||||||
|
.frame(height: 30)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private extension MigrateContentView.ListView {
|
private extension MigrateContentView.ListView {
|
||||||
struct EditableRowView: View {
|
struct EditableRowView: View {
|
||||||
let profile: MigratableProfile
|
let profile: MigratableProfile
|
||||||
|
|
|
@ -45,9 +45,25 @@ extension MigrateContentView {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Form {
|
Form {
|
||||||
|
messageSection
|
||||||
|
profilesSection
|
||||||
|
}
|
||||||
|
.themeForm()
|
||||||
|
.toolbar {
|
||||||
|
ToolbarItem(placement: .confirmationAction, content: performButton)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension MigrateContentView.TableView {
|
||||||
|
var messageSection: some View {
|
||||||
Section {
|
Section {
|
||||||
Text(Strings.Views.Migrate.Sections.Main.header)
|
Text(Strings.Views.Migrate.Sections.Main.header)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var profilesSection: some View {
|
||||||
Section {
|
Section {
|
||||||
Table(profiles) {
|
Table(profiles) {
|
||||||
TableColumn(Strings.Global.name) {
|
TableColumn(Strings.Global.name) {
|
||||||
|
@ -80,15 +96,7 @@ extension MigrateContentView {
|
||||||
}
|
}
|
||||||
.disabled(!step.canSelect)
|
.disabled(!step.canSelect)
|
||||||
}
|
}
|
||||||
.themeForm()
|
|
||||||
.toolbar {
|
|
||||||
ToolbarItem(placement: .confirmationAction, content: performButton)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private extension MigrateContentView.TableView {
|
|
||||||
func isIncludedBinding(for profileId: UUID) -> Binding<Bool> {
|
func isIncludedBinding(for profileId: UUID) -> Binding<Bool> {
|
||||||
Binding {
|
Binding {
|
||||||
statuses[profileId] != .excluded
|
statuses[profileId] != .excluded
|
||||||
|
@ -102,6 +110,14 @@ private extension MigrateContentView.TableView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private extension MigratableProfile {
|
||||||
|
var timestamp: String {
|
||||||
|
lastUpdate?.localizedDescription(style: .timestamp) ?? ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Subviews
|
||||||
|
|
||||||
private extension MigrateContentView.TableView {
|
private extension MigrateContentView.TableView {
|
||||||
struct ControlView: View {
|
struct ControlView: View {
|
||||||
let step: MigrateViewStep
|
let step: MigrateViewStep
|
||||||
|
@ -143,9 +159,3 @@ private extension MigrateContentView.TableView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension MigratableProfile {
|
|
||||||
var timestamp: String {
|
|
||||||
lastUpdate?.localizedDescription(style: .timestamp) ?? ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -101,15 +101,7 @@ extension AppContext {
|
||||||
profilesContainerName: Constants.shared.containers.legacyV2,
|
profilesContainerName: Constants.shared.containers.legacyV2,
|
||||||
cloudKitIdentifier: BundleConfiguration.mainString(for: .legacyV2CloudKitId)
|
cloudKitIdentifier: BundleConfiguration.mainString(for: .legacyV2CloudKitId)
|
||||||
)
|
)
|
||||||
#if DEBUG
|
|
||||||
let migrationManager = MigrationManager(profileStrategy: profileStrategy, simulation: .init(
|
|
||||||
fakeProfiles: true,
|
|
||||||
maxMigrationTime: 3.0,
|
|
||||||
randomFailures: true
|
|
||||||
))
|
|
||||||
#else
|
|
||||||
let migrationManager = MigrationManager(profileStrategy: profileStrategy)
|
let migrationManager = MigrationManager(profileStrategy: profileStrategy)
|
||||||
#endif
|
|
||||||
|
|
||||||
return AppContext(
|
return AppContext(
|
||||||
iapManager: .sharedForApp,
|
iapManager: .sharedForApp,
|
||||||
|
|
Loading…
Reference in New Issue