blob: 5862dad4f6bfd85921a0e7b25f78ca1f0302472f [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/system/progress_indicator/progress_indicator_animation_registry.h"
#include <set>
namespace ash {
namespace {
// Type aliases ----------------------------------------------------------------
template <typename AnimationType>
using KeyedAnimationMap = std::map<const void*, std::unique_ptr<AnimationType>>;
template <typename CallbackListType>
using KeyedAnimationChangedCallbackListMap =
std::map<const void*, CallbackListType>;
// Helpers ---------------------------------------------------------------------
// Notifies any animation changed callbacks registered for the specified `key`
// that the associated animation has changed.
template <typename AnimationType, typename CallbackListType>
void NotifyAnimationChangedForKey(
KeyedAnimationMap<AnimationType>* animations_by_key,
KeyedAnimationChangedCallbackListMap<CallbackListType>*
animation_changed_callback_lists_by_key,
const void* key) {
auto callback_lists_it = animation_changed_callback_lists_by_key->find(key);
if (callback_lists_it == animation_changed_callback_lists_by_key->end())
return;
auto animations_it = animations_by_key->find(key);
callback_lists_it->second.Notify(animations_it != animations_by_key->end()
? animations_it->second.get()
: nullptr);
}
// Implements:
// * `AddProgressIconAnimationChangedCallbackForKey()`
// * `AddProgressRingAnimationChangedCallbackForKey()`
template <typename CallbackListType>
base::CallbackListSubscription AddAnimationChangedCallbackForKey(
KeyedAnimationChangedCallbackListMap<CallbackListType>*
animation_changed_callback_lists_by_key,
const void* key,
typename CallbackListType::CallbackType callback) {
auto it = animation_changed_callback_lists_by_key->find(key);
// If this is the first time that an animation changed callback is being
// registered for the specified `key`, set a callback to destroy the created
// callback list when it becomes empty.
if (it == animation_changed_callback_lists_by_key->end()) {
it = animation_changed_callback_lists_by_key
->emplace(std::piecewise_construct, std::forward_as_tuple(key),
std::forward_as_tuple())
.first;
it->second.set_removal_callback(base::BindRepeating(
[](KeyedAnimationChangedCallbackListMap<CallbackListType>*
animation_changed_callback_lists_by_key,
const void* key) {
auto it = animation_changed_callback_lists_by_key->find(key);
if (it != animation_changed_callback_lists_by_key->end() &&
it->second.empty()) {
animation_changed_callback_lists_by_key->erase(it);
}
},
base::Unretained(animation_changed_callback_lists_by_key),
base::Unretained(key)));
}
return it->second.Add(std::move(callback));
}
// Implements:
// * `GetProgressIconAnimationForKey()`
// * `GetProgressRingAnimationForKey()`
template <typename AnimationType>
AnimationType* GetAnimationForKey(
KeyedAnimationMap<AnimationType>* animations_by_key,
const void* key) {
auto it = animations_by_key->find(key);
return it != animations_by_key->end() ? it->second.get() : nullptr;
}
// Implements:
// * `SetProgressIconAnimationForKey()`
// * `SetProgressRingAnimationForKey()`
template <typename AnimationType, typename CallbackListType>
AnimationType* SetAnimationForKey(
KeyedAnimationMap<AnimationType>* animations_by_key,
KeyedAnimationChangedCallbackListMap<CallbackListType>*
animation_changed_callback_lists_by_key,
const void* key,
std::unique_ptr<AnimationType> animation) {
AnimationType* animation_ptr = animation.get();
if (animation) {
(*animations_by_key)[key] = std::move(animation);
NotifyAnimationChangedForKey(animations_by_key,
animation_changed_callback_lists_by_key, key);
} else {
auto it = animations_by_key->find(key);
if (it != animations_by_key->end()) {
animations_by_key->erase(it);
NotifyAnimationChangedForKey(
animations_by_key, animation_changed_callback_lists_by_key, key);
}
}
return animation_ptr;
}
} // namespace
// ProgressIndicatorAnimationRegistry ------------------------------------------
ProgressIndicatorAnimationRegistry::ProgressIndicatorAnimationRegistry() =
default;
ProgressIndicatorAnimationRegistry::~ProgressIndicatorAnimationRegistry() =
default;
base::CallbackListSubscription ProgressIndicatorAnimationRegistry::
AddProgressIconAnimationChangedCallbackForKey(
const void* key,
ProgressIconAnimationChangedCallbackList::CallbackType callback) {
return AddAnimationChangedCallbackForKey(
&icon_animation_changed_callback_lists_by_key_, key, std::move(callback));
}
base::CallbackListSubscription ProgressIndicatorAnimationRegistry::
AddProgressRingAnimationChangedCallbackForKey(
const void* key,
ProgressRingAnimationChangedCallbackList::CallbackType callback) {
return AddAnimationChangedCallbackForKey(
&ring_animation_changed_callback_lists_by_key_, key, std::move(callback));
}
ProgressIconAnimation*
ProgressIndicatorAnimationRegistry::GetProgressIconAnimationForKey(
const void* key) {
return GetAnimationForKey(&icon_animations_by_key_, key);
}
ProgressRingAnimation*
ProgressIndicatorAnimationRegistry::GetProgressRingAnimationForKey(
const void* key) {
return GetAnimationForKey(&ring_animations_by_key_, key);
}
ProgressIconAnimation*
ProgressIndicatorAnimationRegistry::SetProgressIconAnimationForKey(
const void* key,
std::unique_ptr<ProgressIconAnimation> animation) {
return SetAnimationForKey(&icon_animations_by_key_,
&icon_animation_changed_callback_lists_by_key_, key,
std::move(animation));
}
ProgressRingAnimation*
ProgressIndicatorAnimationRegistry::SetProgressRingAnimationForKey(
const void* key,
std::unique_ptr<ProgressRingAnimation> animation) {
return SetAnimationForKey(&ring_animations_by_key_,
&ring_animation_changed_callback_lists_by_key_, key,
std::move(animation));
}
void ProgressIndicatorAnimationRegistry::EraseAllAnimations() {
EraseAllAnimationsForKeyIf(
base::BindRepeating([](const void* key) { return true; }));
}
void ProgressIndicatorAnimationRegistry::EraseAllAnimationsForKey(
const void* key) {
SetProgressIconAnimationForKey(key, nullptr);
SetProgressRingAnimationForKey(key, nullptr);
}
void ProgressIndicatorAnimationRegistry::EraseAllAnimationsForKeyIf(
base::RepeatingCallback<bool(const void* key)> predicate) {
std::set<const void*> keys_to_erase;
for (const auto& icon_animation_by_key : icon_animations_by_key_) {
const void* key = icon_animation_by_key.first;
if (predicate.Run(key))
keys_to_erase.insert(key);
}
for (const auto& ring_animation_by_key : ring_animations_by_key_) {
const void* key = ring_animation_by_key.first;
if (predicate.Run(key))
keys_to_erase.insert(key);
}
for (const void* key : keys_to_erase)
EraseAllAnimationsForKey(key);
}
} // namespace ash