1
0
mirror of git://jb55.com/damus synced 2024-09-16 02:03:45 +00:00

ui: Improve UX around clearing cache

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: https://github.com/damus-io/damus/issues/1301
Changelog-Changed: Improve UX around clearing cache
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
Daniel D’Aquino 2023-10-03 00:39:16 +00:00 committed by William Casarin
parent 1150a144bc
commit 24c2be02bb
2 changed files with 110 additions and 11 deletions

View File

@ -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?()
}
}

View File

@ -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
@ -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) {
@ -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)
@ -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
@ -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())
}
}
}