Skip to content

Commit

Permalink
ui: Improve UX around clearing cache
Browse files Browse the repository at this point in the history
Testing
-------

PASS

Device: iPhone 14 Pro simulator
iOS: Tested on iOS 17.0 and 16.4
Steps:

1. Go to appearance settings
2. Enable animations. Shows confirmation dialog. PASS
3. Click cancel. Setting is toggled back. PASS
4. Enable animations again. This time click "OK". Setting stays at what was set, and cache is visibly cleared. PASS
5. Restart app. Changes are persistent. PASS
6. Disable animations. Dialog appears like before. PASS
7. Cancel. Toggles back as expected. PASS
8. Disable animations again. This time click "OK". Cache is cleared. PASS
7. Restart app. Changes are persistent. PASS
9. Click on "clear cache". Confirmation dialog appears. PASS
10. Cancel action. We do not see cache being cleared. PASS
11. Click on "clear cache" and click "OK" this time.
12. We can see the cache being visibly cleared. It shows a loading spinner and "clearing cache", and then we see a checkmark icon with a "cache cleared" indicator. We cannot click the button again for now. PASS
13. Go to home view, scroll through some views, then come back to the setting. Clear cache button is visible again.

Closes: #1301
Changelog-Changed: Improve UX around clearing cache
Signed-off-by: Daniel D’Aquino <[email protected]>
Signed-off-by: William Casarin <[email protected]>
  • Loading branch information
danieldaquino authored and jb55 committed Oct 4, 2023
1 parent 1150a14 commit 24c2be0
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 11 deletions.
20 changes: 17 additions & 3 deletions damus/Views/ConfigView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,22 @@ func handle_string_amount(new_value: String) -> Int? {
return amt
}

func clear_kingfisher_cache() -> Void {
func clear_kingfisher_cache(completion: (() -> Void)? = nil) {
KingfisherManager.shared.cache.clearMemoryCache()
KingfisherManager.shared.cache.clearDiskCache()
KingfisherManager.shared.cache.cleanExpiredDiskCache()

let group = DispatchGroup()

group.enter()
KingfisherManager.shared.cache.clearDiskCache {
group.leave()
}

group.enter()
KingfisherManager.shared.cache.cleanExpiredDiskCache {
group.leave()
}

group.notify(queue: .main) {
completion?()
}
}
101 changes: 93 additions & 8 deletions damus/Views/Settings/AppearanceSettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@

import SwiftUI

fileprivate let CACHE_CLEAR_BUTTON_RESET_TIME_IN_SECONDS: Double = 60
fileprivate let MINIMUM_CACHE_CLEAR_BUTTON_DELAY_IN_SECONDS: Double = 1

/// A simple type to keep track of the cache clearing state
fileprivate enum CacheClearingState {
case not_cleared
case clearing
case cleared
}

struct ResizedEventPreview: View {
let damus_state: DamusState
Expand All @@ -21,6 +30,11 @@ struct AppearanceSettingsView: View {
let damus_state: DamusState
@ObservedObject var settings: UserSettingsStore
@Environment(\.dismiss) var dismiss
@State fileprivate var cache_clearing_state: CacheClearingState = .not_cleared
@State var showing_cache_clear_alert: Bool = false

@State var showing_enable_animation_alert: Bool = false
@State var enable_animation_toggle_is_user_initiated: Bool = true

var FontSize: some View {
VStack(alignment: .leading) {
Expand Down Expand Up @@ -63,11 +77,7 @@ struct AppearanceSettingsView: View {

// MARK: - Images
Section(NSLocalizedString("Images", comment: "Section title for images configuration.")) {
Toggle(NSLocalizedString("Animations", comment: "Toggle to enable or disable image animation"), isOn: $settings.enable_animation)
.toggleStyle(.switch)
.onChange(of: settings.enable_animation) { _ in
clear_kingfisher_cache()
}
self.EnableAnimationsToggle
Toggle(NSLocalizedString("Always show images", comment: "Setting to always show and never blur images"), isOn: $settings.always_show_images)
.toggleStyle(.switch)

Expand All @@ -79,9 +89,7 @@ struct AppearanceSettingsView: View {
}
}

Button(NSLocalizedString("Clear Cache", comment: "Button to clear image cache.")) {
clear_kingfisher_cache()
}
self.ClearCacheButton
}

// MARK: - Content filters and moderation
Expand All @@ -100,6 +108,83 @@ struct AppearanceSettingsView: View {
dismiss()
}
}

func clear_cache_button_action() {
cache_clearing_state = .clearing

let group = DispatchGroup()

group.enter()
clear_kingfisher_cache(completion: {
group.leave()
})

// Make clear cache button take at least a second or so to avoid issues with labor perception bias (https://growth.design/case-studies/labor-perception-bias)
group.enter()
DispatchQueue.main.asyncAfter(deadline: .now() + MINIMUM_CACHE_CLEAR_BUTTON_DELAY_IN_SECONDS) {
group.leave()
}

group.notify(queue: .main) {
cache_clearing_state = .cleared
DispatchQueue.main.asyncAfter(deadline: .now() + CACHE_CLEAR_BUTTON_RESET_TIME_IN_SECONDS) {
cache_clearing_state = .not_cleared
}
}
}

var EnableAnimationsToggle: some View {
Toggle(NSLocalizedString("Animations", comment: "Toggle to enable or disable image animation"), isOn: $settings.enable_animation)
.toggleStyle(.switch)
.onChange(of: settings.enable_animation) { _ in
if self.enable_animation_toggle_is_user_initiated {
self.showing_enable_animation_alert = true
}
else {
self.enable_animation_toggle_is_user_initiated = true
}
}
.alert(isPresented: $showing_enable_animation_alert) {
Alert(title: Text(NSLocalizedString("Confirmation", comment: "Confirmation dialog title")),
message: Text(NSLocalizedString("Changing this setting will cause the cache to be cleared. This will free space, but images may take longer to load again. Are you sure you want to proceed?", comment: "Message explaining consequences of changing the 'enable animation' setting")),
primaryButton: .default(Text(NSLocalizedString("OK", comment: "Button label indicating user wants to proceed."))) {
self.clear_cache_button_action()
},
secondaryButton: .cancel() {
// Toggle back if user cancels action
self.enable_animation_toggle_is_user_initiated = false
settings.enable_animation.toggle()
}
)
}
}

var ClearCacheButton: some View {
Button(action: { self.showing_cache_clear_alert = true }, label: {
HStack(spacing: 6) {
switch cache_clearing_state {
case .not_cleared:
Text(NSLocalizedString("Clear Cache", comment: "Button to clear image cache."))
case .clearing:
ProgressView()
Text(NSLocalizedString("Clearing Cache", comment: "Loading message indicating that the cache is being cleared."))
case .cleared:
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.green)
Text(NSLocalizedString("Cache has been cleared", comment: "Message indicating that the cache was successfully cleared."))
}
}
})
.disabled(self.cache_clearing_state != .not_cleared)
.alert(isPresented: $showing_cache_clear_alert) {
Alert(title: Text(NSLocalizedString("Confirmation", comment: "Confirmation dialog title")),
message: Text(NSLocalizedString("Are you sure you want to clear the cache? This will free space, but images may take longer to load again.", comment: "Message explaining what it means to clear the cache, asking if user wants to proceed.")),
primaryButton: .default(Text(NSLocalizedString("OK", comment: "Button label indicating user wants to proceed."))) {
self.clear_cache_button_action()
},
secondaryButton: .cancel())
}
}
}


Expand Down

0 comments on commit 24c2be0

Please sign in to comment.