Skip to content

Commit

Permalink
Rework custom resources API (#13013)
Browse files Browse the repository at this point in the history
* Rework custom resources API

* Change files

* fix
  • Loading branch information
acoates-ms authored Apr 30, 2024
1 parent 7ff35ad commit c15f1bb
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 57 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Rework custom resources API",
"packageName": "react-native-windows",
"email": "30809111+acoates-ms@users.noreply.github.com",
"dependentChangeType": "patch"
}
6 changes: 4 additions & 2 deletions vnext/Microsoft.ReactNative/CompositionRootView.idl
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,10 @@ namespace Microsoft.ReactNative

Object GetUiaProvider();

DOC_STRING("Theme used for Platform colors within this RootView")
Microsoft.ReactNative.Composition.Theme Theme;
DOC_STRING("Provides resources used for Platform colors within this RootView")
Microsoft.ReactNative.Composition.ICustomResourceLoader Resources;

Microsoft.ReactNative.Composition.Theme Theme { get; };

#ifdef USE_WINUI3
Microsoft.UI.Content.ContentIsland Island { get; };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,50 +240,55 @@ void CompositionRootView::ScaleFactor(float value) noexcept {
}
}

winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader CompositionRootView::Resources() noexcept {
return m_resources;
}

void CompositionRootView::Resources(
const winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader &resources) noexcept {
m_resources = resources;

if (m_context && m_theme) {
Theme(winrt::make<winrt::Microsoft::ReactNative::Composition::implementation::Theme>(m_context, m_resources));
}
}

winrt::Microsoft::ReactNative::Composition::Theme CompositionRootView::Theme() noexcept {
if (!m_theme) {
Theme(winrt::Microsoft::ReactNative::Composition::Theme::GetDefaultTheme(m_context.Handle()));
m_themeChangedSubscription = m_context.Notifications().Subscribe(
winrt::Microsoft::ReactNative::ReactNotificationId<void>(
winrt::Microsoft::ReactNative::Composition::Theme::ThemeChangedEventName()),
m_context.UIDispatcher(),
[wkThis = get_weak()](
IInspectable const & /*sender*/,
winrt::Microsoft::ReactNative::ReactNotificationArgs<void> const & /*args*/) {
auto pThis = wkThis.get();
pThis->Theme(winrt::Microsoft::ReactNative::Composition::Theme::GetDefaultTheme(pThis->m_context.Handle()));
});
assert(m_context);
if (m_resources) {
Theme(winrt::make<winrt::Microsoft::ReactNative::Composition::implementation::Theme>(m_context, m_resources));
} else {
Theme(winrt::Microsoft::ReactNative::Composition::Theme::GetDefaultTheme(m_context.Handle()));
}
}
return m_theme;
}

void CompositionRootView::Theme(const winrt::Microsoft::ReactNative::Composition::Theme &value) noexcept {
if (m_themeChangedSubscription) {
m_themeChangedSubscription.Unsubscribe();
m_themeChangedSubscription = nullptr;
}

if (value == m_theme)
return;

m_theme = value;

m_themeChangedRevoker = m_theme.ThemeChanged(
winrt::auto_revoke,
[this](
[wkThis = get_weak()](
const winrt::Windows::Foundation::IInspectable & /*sender*/,
const winrt::Windows::Foundation::IInspectable & /*args*/) {
if (auto rootView = GetComponentView()) {
Mso::Functor<bool(const winrt::Microsoft::ReactNative::ComponentView &)> fn =
[](const winrt::Microsoft::ReactNative::ComponentView &view) noexcept {
winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(view)->onThemeChanged();
return false;
};

winrt::Microsoft::ReactNative::ComponentView view{nullptr};
winrt::check_hresult(rootView->QueryInterface(
winrt::guid_of<winrt::Microsoft::ReactNative::ComponentView>(), winrt::put_abi(view)));
walkTree(view, true, fn);
if (auto strongThis = wkThis.get()) {
if (auto rootView = strongThis->GetComponentView()) {
Mso::Functor<bool(const winrt::Microsoft::ReactNative::ComponentView &)> fn =
[](const winrt::Microsoft::ReactNative::ComponentView &view) noexcept {
winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(view)->onThemeChanged();
return false;
};

winrt::Microsoft::ReactNative::ComponentView view{nullptr};
winrt::check_hresult(rootView->QueryInterface(
winrt::guid_of<winrt::Microsoft::ReactNative::ComponentView>(), winrt::put_abi(view)));
walkTree(view, true, fn);
}
}
});

Expand Down Expand Up @@ -382,10 +387,8 @@ void CompositionRootView::InitRootView(
}

m_context = winrt::Microsoft::ReactNative::ReactContext(std::move(context));

m_reactViewOptions = std::move(viewOptions);
m_CompositionEventHandler =
std::make_shared<::Microsoft::ReactNative::CompositionEventHandler>(m_context, *this);
m_CompositionEventHandler = std::make_shared<::Microsoft::ReactNative::CompositionEventHandler>(m_context, *this);

UpdateRootViewInternal();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ struct CompositionRootView
void RemoveRenderedVisual(const winrt::Microsoft::ReactNative::Composition::Experimental::IVisual &visual) noexcept;
bool TrySetFocus() noexcept;

winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader Resources() noexcept;
void Resources(const winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader &resources) noexcept;

winrt::Microsoft::ReactNative::Composition::Theme Theme() noexcept;
void Theme(const winrt::Microsoft::ReactNative::Composition::Theme &value) noexcept;

Expand Down Expand Up @@ -134,8 +137,8 @@ struct CompositionRootView
winrt::Microsoft::ReactNative::Composition::Experimental::IVisual m_rootVisual{nullptr};
winrt::Microsoft::ReactNative::Composition::Experimental::ISpriteVisual m_loadingVisual{nullptr};
winrt::Microsoft::ReactNative::Composition::Experimental::IActivityVisual m_loadingActivityVisual{nullptr};
winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader m_resources{nullptr};
winrt::Microsoft::ReactNative::Composition::Theme m_theme{nullptr};
winrt::Microsoft::ReactNative::ReactNotificationSubscription m_themeChangedSubscription{nullptr};
winrt::Microsoft::ReactNative::Composition::Theme::ThemeChanged_revoker m_themeChangedRevoker;

void UpdateRootViewInternal() noexcept;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ void CompositionRootView::Theme(const winrt::Microsoft::ReactNative::Composition
winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader CompositionRootView::Resources() noexcept {
return nullptr;
}
void CompositionRootView::Resources(const winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader &) noexcept {}

void CompositionRootView::Resources(
const winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader &) noexcept {}

winrt::IInspectable CompositionRootView::GetUiaProvider() noexcept {
return nullptr;
Expand Down
38 changes: 28 additions & 10 deletions vnext/Microsoft.ReactNative/Fabric/Composition/Theme.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,15 @@ static const winrt::Microsoft::ReactNative::ReactPropertyId<winrt::Microsoft::Re
return prop;
}

static const winrt::Microsoft::ReactNative::ReactPropertyId<
winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader>
&ThemeResourcesPropertyId() noexcept {
static const winrt::Microsoft::ReactNative::ReactPropertyId<
winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader>
prop{L"ReactNative.Composition", L"ThemeResources"};
return prop;
}

winrt::Microsoft::ReactNative::Composition::Theme Theme::EmptyTheme() noexcept {
static winrt::Microsoft::ReactNative::Composition::Theme s_emptyTheme{nullptr};
if (!s_emptyTheme) {
Expand All @@ -537,24 +546,33 @@ winrt::Microsoft::ReactNative::Composition::Theme Theme::EmptyTheme() noexcept {
/*static*/ winrt::Microsoft::ReactNative::Composition::Theme Theme::GetDefaultTheme(
const winrt::Microsoft::ReactNative::IReactContext &context) noexcept {
return winrt::Microsoft::ReactNative::ReactPropertyBag(context.Properties())
.GetOrCreate(ThemePropertyId(), [context]() { return winrt::make<Theme>(context, nullptr); });
.GetOrCreate(ThemePropertyId(), [context]() {
return winrt::make<Theme>(
context,
winrt::Microsoft::ReactNative::ReactPropertyBag(context.Properties()).Get(ThemeResourcesPropertyId()));
});
}

/*static*/ void Theme::SetDefaultTheme(
/*static*/ void Theme::SetDefaultResources(
const winrt::Microsoft::ReactNative::ReactInstanceSettings &settings,
const winrt::Microsoft::ReactNative::Composition::Theme &theme) noexcept {
winrt::Microsoft::ReactNative::ReactPropertyBag(settings.Properties()).Set(ThemePropertyId(), theme);
settings.Notifications().SendNotification(ThemeChangedEventName(), nullptr, nullptr);
const winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader &resources) noexcept {
winrt::Microsoft::ReactNative::ReactPropertyBag properties(settings.Properties());
properties.Set(ThemeResourcesPropertyId(), resources);
// If a default theme has already been created - we need to update it with the new resources
if (auto theme = properties.Get(ThemePropertyId())) {
winrt::get_self<Theme>(theme)->UpdateCustomResources(resources);
}
}

void Theme::UpdateCustomResources(
const winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader &resources) noexcept {
m_customResourceLoader = resources;
ClearCacheAndRaiseChangedEvent();
}

IReactPropertyNamespace ThemeNamespace() noexcept {
static IReactPropertyNamespace value = ReactPropertyBagHelper::GetNamespace(L"ReactNative.Theme");
return value;
}

/*static*/ IReactPropertyName Theme::ThemeChangedEventName() noexcept {
static IReactPropertyName propName = ReactPropertyBagHelper::GetName(ThemeNamespace(), L"Changed");
return propName;
}

} // namespace winrt::Microsoft::ReactNative::Composition::implementation
7 changes: 4 additions & 3 deletions vnext/Microsoft.ReactNative/Fabric/Composition/Theme.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,13 @@ struct Theme : ThemeT<Theme, Experimental::IInternalTheme> {

static winrt::Microsoft::ReactNative::Composition::Theme GetDefaultTheme(
const winrt::Microsoft::ReactNative::IReactContext &context) noexcept;
static void SetDefaultTheme(
static void SetDefaultResources(
const winrt::Microsoft::ReactNative::ReactInstanceSettings &settings,
const winrt::Microsoft::ReactNative::Composition::Theme &theme) noexcept;
static winrt::Microsoft::ReactNative::IReactPropertyName ThemeChangedEventName() noexcept;
const winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader &resources) noexcept;

private:
void UpdateCustomResources(
const winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader &resources) noexcept;
bool TryGetPlatformColor(const std::string &platformColor, winrt::Windows::UI::Color &color) noexcept;
void ClearCacheAndRaiseChangedEvent() noexcept;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,8 @@ winrt::Microsoft::ReactNative::Composition::Theme Theme::EmptyTheme() noexcept {
return nullptr;
}

/*static*/ void Theme::SetDefaultTheme(
/*static*/ void Theme::SetDefaultResources(
const winrt::Microsoft::ReactNative::ReactInstanceSettings &,
const winrt::Microsoft::ReactNative::Composition::Theme &) noexcept {}

/*static*/ IReactPropertyName Theme::ThemeChangedEventName() noexcept {
return nullptr;
}
const winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader &) noexcept {}

} // namespace winrt::Microsoft::ReactNative::Composition::implementation
3 changes: 1 addition & 2 deletions vnext/Microsoft.ReactNative/Theme.idl
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ namespace Microsoft.ReactNative.Composition
event Windows.Foundation.EventHandler<Object> ThemeChanged;

static Theme GetDefaultTheme(Microsoft.ReactNative.IReactContext context);
static void SetDefaultTheme(Microsoft.ReactNative.ReactInstanceSettings settings, Theme theme);
static Microsoft.ReactNative.IReactPropertyName ThemeChangedEventName { get; };
static void SetDefaultResources(Microsoft.ReactNative.ReactInstanceSettings settings, ICustomResourceLoader theme);
};

} // namespace Microsoft.ReactNative

0 comments on commit c15f1bb

Please sign in to comment.