How to get an event from the application when the system theme changes? - uno-platform

Because the Theme Qualifier for iOS assets is not yet supported on Uno, I have to resort to a helper service in my project, to provide alternate paths to image which are created for dark mode. This however causes the assets URL to be evaluated once, and not when the system theme is changed while the app is running. Is there a way to get an event or method being called from the application when the system theme changes?

Just for completeness, you can also use the UISettings.ColorValuesChanged event to observe theme changes. Furthermore, Microsoft Community Toolkit provides a very nice wrapper around it - ThemeListener, which can also be used in Uno Platform apps.
Ideally, we would also like to support the theme qualifier for asset disambiguation - similarly to -scale-150, etc. it allows you to use a suffix to let the system choose light or dark assets. You can upvote this GitHub issue to help us prioritize that.

If you want some UI assets to change based on theme, you can use ThemeResource with ThemeDictionaries.
Example in an Uno project
Declaration of the theme resource in the theme dictionary
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Uno.Gallery.Views.Styles.Application">
<ResourceDictionary.ThemeDictionaries>
<!-- Light Theme -->
<ResourceDictionary x:Key="Light">
<x:String x:Key="UnoLogoImageSource">ms-appx:///Assets/UnoGalleryLogo_Light.png</x:String>
</ResourceDictionary>
<!-- Dark Theme -->
<ResourceDictionary x:Key="Dark">
<x:String x:Key="UnoLogoImageSource">ms-appx:///Assets/UnoGalleryLogo_Dark.png</x:String>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
Reference code:
https://github.com/unoplatform/Uno.Gallery/blob/master/Uno.Gallery/Uno.Gallery.UWP/Views/Colors.xaml#L11
Usage in a page
<Image Source="{ThemeResource UnoLogoImageSource}" />
Reference code: https://github.com/unoplatform/Uno.Gallery/blob/45e490668890c3a9db1e28a5b3de2a61822b07ca/Uno.Gallery/Uno.Gallery.UWP/Views/Shell.xaml#L45

Related

How to change a toolbar item (logo) for different theme

I have a question. I need to have few toolbar items related to different styles. I have created Theme Resources and with the help of settings plugin I am saving different themes. However I would also like to have different toolbar items dedicated for each theme. I have tried to add my image in Resource dictionary like this
<ResourceDictionary>
<Image x:Key="logo" Source="IconSettings.png"></Image>
</ResourceDictionary>
and then in Xaml use it like this
<ToolbarItem IconImageSource="{DynamicResource logo}"/>
But nothing is displayed. Do you maybe have any suggestions even different approach?
Also have tried to follow this solution https://forums.xamarin.com/discussion/152758/setting-icon-file-names-as-resources
As you can see in the link you provided, why don't you try something like this
<ResourceDictionary>
<x:String x:Key="logo">IconSettings.png</x:String>
</ResourceDictionary>
And use it in your XAML.
You were trying to add image at the place of string input, that's the reason it showed you nothing
Let me know if its working fine or not

How can a custom Xamarin.Forms theme specify a page's background color?

I am trying to create a custom theme following https://developer.xamarin.com/guides/xamarin-forms/themes/custom/, but it is unclear how a page's background color can be set via the theme.
I've tried creating an implicit style targeting a ContentPage. I've also tried creating a style class for the ContentPage. Neither works. It doesn't work since the actual page being loaded isn't a ContentPage, but rather subclassed page. In https://bugzilla.xamarin.com/show_bug.cgi?id=27659 Jason Smith states "Implicit styles do not apply to subclasses."
I'd love to take a look at the Xamarin.Forms.Themes source to see how the Forms team does it, but it doesn't appear to be available on GitHub.
#JoshuaLatusia said:
Hi, I found this to be working for all my pages.
By using "ApplyToDerivedTypes" you will set a generic style for all your Content pages.
Example:
<Style TargetType="ContentPage" ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor" Value="#eeecf6" />
</Style>
See https://forums.xamarin.com/discussion/comment/302323/#Comment_302323

How to use two different themes depending on the url with diazo?

I need a solution that meets following requirements:
use a diazo theme based on unstyled(!), Theme base (i.e. "Plone Default") with the URL diazotheme.domain.com
use "Sunburst Theme" (or any other Plone Theme) with the URL "sunburst.domain.com"
It seems that diazo not only uses the Base Theme for the diazo theme but also for the "Unthemed host names". Setting the Base Theme in diazo's "##theming-controlpanel" actually changes the Default skin of the Site.
I've posted a solution using diazo in combination with editskinswitcher: https://stackoverflow.com/a/23130398/1659599. I'd like to know whether this is possible without using editskinswitcher.
Take a look at the collective.behavior.localdiazo package.
You can see it in action in http://www.cfa.org.br/rba site, which has a different theme from http://www.cfa.org.br/ main site.
RBA is an instance of Microsite, a Dexterity-based content type defined in sc.microsite.
you'll definitely need a mechanism to activate different skins for the different parts of you site. editskinswitcher is one choice here.
you could also code your own traverser that applies the correct browserlayer and patches the portal_skins tool.
another approach is to allow skin selection in portal_skins and set the skin via a request variable.
the concept is outlined here: https://dev.plone.org/ticket/10311
Do you need to switch plone skin? Or would it be enough to change the diazo theme, using the same (more or less neutral) plone skin?
I use this approach to switch diazo rule set and index.html depending on the path. The two diazo themes uses different resources: images, styles, js, etc., and are very different.
My rules.xml - shortened:
<?xml version="1.0" encoding="UTF-8"?>
<rules
xmlns="http://namespaces.plone.org/diazo"
xmlns:css="http://namespaces.plone.org/diazo/css"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xi="http://www.w3.org/2001/XInclude">
<!-- The theme for my "app" -->
<rules if-path="/app_path /site/app_path">
<theme href="index_app.html"/>
<!-- rules for the specific path -->
</rules>
<!-- The default theme, used for standard Plone web pages -->
<theme href="index.html" css:if-content="#visual-portal-wrapper" />
<!-- Rules applying to a standard Plone web page -->
<rules css:if-content="#visual-portal-wrapper">
<!-- rules for the rest of the site -->
</rules>
</rules>
The same should be doable for domains using p.a.theming theme parameters: https://pypi.python.org/pypi/plone.app.theming#theme-parameters
and using "Conditions based on arbitrary parameters" from http://docs.diazo.org/en/latest/advanced.html
(replace the if-path with if="$host = 'domain'")
UNTESTED! :)

Load different .css basing on user-agent - GWT project

I developed a GWT aplication which was initially meant only for Desktop PC browser. Now I decided to make it available also to smartphones and tablets. I created a different .css for each user-agent. Now my question is, how can I decide which of these files to load basing on the type of user-agent? Is this strategy a good one, or there is a better practice?
To swap implementation according to the user-agent, you can use deferred binding, which is a built-in GWT feature.
In you module.gwt.xml type something like:
<module>
...
<inherits name='com.google.gwt.sample.mobilewebapp.FormFactor'/>
...
<!-- Use ClientFactoryImpl by default -->
<replace-with class="com.google.gwt.sample.mobilewebapp.client.ClientFactoryImpl">
<when-type-is class="com.google.gwt.sample.mobilewebapp.client.ClientFactory"/>
</replace-with>
<!-- Use ClientFactoryImplMobile for mobile form factor. -->
<replace-with class="com.google.gwt.sample.mobilewebapp.client.ClientFactoryImplMobile">
<when-type-is class="com.google.gwt.sample.mobilewebapp.client.ClientFactory"/>
<when-property-is name="formfactor" value="mobile"/>
</replace-with>
<!-- Use ClientFactoryImplTablet for tablet form factor. -->
<replace-with class="com.google.gwt.sample.mobilewebapp.client.ClientFactoryImplTablet">
<when-type-is class="com.google.gwt.sample.mobilewebapp.client.ClientFactory"/>
<when-property-is name="formfactor" value="tablet"/>
</replace-with>
</module>
Then just call GWT.create(ClientFactory.class) to get the proper implementation at runtime. For CSS, use a subclass of CSSResource or ClientBundle. Source is here.
I am using mgwt for creating mobile gwt apps.
There is a themeing based on user agent: https://code.google.com/p/mgwt/source/browse/src/main/java/com/googlecode/mgwt/ui/client/theme/MGWTThemeBaseThemeStandardImpl.java
In your Bundle you can seperate different css. If you don't use CssResources you may just use the StyleInjector

How can I use zope 3 / ztk layers without having a zope 2 skin layer in Plone 4?

We're trying to develop our Plone 4.1 product using only ZTK (Zope 3) views and hence haven't defined a portal skin. I'm trying to override a view from a different package and in the past have used the layer attribute to do this.
plone.theme allows you to mark the request with a "layer" interface conditional on the currently selected skin. I'd like to mark requests with a "layer" interface if my product is installed, without creating a skin layer. How do I do that?
I have my interface defined already in zcml
<interface
interface=".interfaces.IThemeSpecific"
type="zope.publisher.interfaces.browser.IBrowserSkinType"
name="My Theme"
/>
and declared
from zope.interface import Interface
class IThemeSpecific(Interface):
"""Marker interface for skins part of 'My Theme'
"""
You have to use a browserlayer.
So, if you don't need it for something else, you can remove the zcml interface declaration and keep only the python interface (maybe you can rename it something more specific like IMyPackageLayer). Then add a file browserlayer.xml in your generic setup profile with this:
<?xml version="1.0"?>
<!-- Register the package-specific browser layer, so that it will be activated
when this product is installed. -->
<layers>
<layer name="my.package.browserlayer"
interface="my.package.browser.interfaces.IThemeSpecific" />
</layers>
After that you can use the layer attribute as always:
<browser:page
name="my-view"
for="*"
layer="my.package.browser.interfaces.IThemeSpecific"
/>
Just remember to restart zope and reinstall you product to apply the new genericsetup configuration.
That's all.

Resources