Skip to content

Commit

Permalink
refactor(android): theme handling for Light/Dark/DayNight and ActionBar
Browse files Browse the repository at this point in the history
  • Loading branch information
jquick-axway authored and sgtcoolguy committed Mar 5, 2021
1 parent 3704f2a commit ccb494a
Show file tree
Hide file tree
Showing 9 changed files with 162 additions and 72 deletions.
2 changes: 1 addition & 1 deletion android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
</intent>
</queries>

<application android:name=".TitaniumTestApplication" android:icon="@drawable/appicon" android:label="TitaniumTest" android:theme="@style/Base.Theme.Titanium" android:usesCleartextTraffic="true">
<application android:name=".TitaniumTestApplication" android:icon="@drawable/appicon" android:label="TitaniumTest" android:theme="@style/Theme.Titanium.App" android:usesCleartextTraffic="true">
<!-- The root Titanium splash activity which hosts the JS runtime. -->
<activity android:name=".TitaniumTestActivity" android:theme="@style/Theme.Titanium" android:alwaysRetainTaskState="true" android:configChanges="${tiActivityConfigChanges}">
<intent-filter>
Expand Down
21 changes: 10 additions & 11 deletions android/cli/commands/_build.js
Original file line number Diff line number Diff line change
Expand Up @@ -3250,20 +3250,19 @@ AndroidBuilder.prototype.generateTheme = async function generateTheme() {
this.logger.info(__('Generating theme file: %s', xmlFilePath.cyan));

// Set default theme to be used in "AndroidManifest.xml" and style resources.
let defaultAppThemeName = 'Theme.MaterialComponents.DayNight.DarkActionBar';
let defaultAppThemeName = 'Theme.Titanium.DayNight';
if (this.tiapp.fullscreen || this.tiapp['statusbar-hidden']) {
defaultAppThemeName = 'Theme.MaterialComponents.DayNight.Fullscreen';
defaultAppThemeName = 'Theme.Titanium.DayNight.Fullscreen';
} else if (this.tiapp['navbar-hidden']) {
defaultAppThemeName = 'Theme.MaterialComponents.DayNight.NoActionBar';
defaultAppThemeName = 'Theme.Titanium.DayNight.NoTitleBar';
}

// Set up "Base.Theme.Titanium.Customizable" inherited themes to use <application/> defined theme, if provided.
// Note: Do not assign it if set to a Titanium theme, which would cause a circular reference.
let customizableParentThemeName = 'Base.Theme.Titanium';
// Set up "Theme.AppDerived" to use the <application/> defined theme, if assigned.
let actualAppTheme = 'Theme.Titanium.App';
if (this.customAndroidManifest) {
const appTheme = this.customAndroidManifest.getAppAttribute('android:theme');
if (appTheme && !appTheme.startsWith('@style/Theme.Titanium') && !appTheme.startsWith('@style/Base.Theme.Titanium')) {
customizableParentThemeName = appTheme;
if (appTheme && !appTheme.startsWith('@style/Theme.AppDerived') && (appTheme !== '@style/Theme.Titanium')) {
actualAppTheme = appTheme;
}
}

Expand All @@ -3272,11 +3271,11 @@ AndroidBuilder.prototype.generateTheme = async function generateTheme() {
let xmlLines = [
'<?xml version="1.0" encoding="utf-8"?>',
'<resources>',
` <style name="Base.Theme.Titanium.RootStyle" parent="${defaultAppThemeName}"/>`,
` <style name="Base.Theme.Titanium.Customizable" parent="${customizableParentThemeName}"/>`,
` <style name="Theme.Titanium.App" parent="${defaultAppThemeName}"/>`,
` <style name="Theme.AppDerived" parent="${actualAppTheme}"/>`,
'',
' <!-- Theme used by "TiRootActivity" derived class which displays the splash screen. -->',
' <style name="Theme.Titanium" parent="@style/Base.Theme.Titanium.Splash">',
' <style name="Theme.Titanium" parent="Base.Theme.Titanium.Splash">',
' <item name="android:windowBackground">@drawable/background</item>',
' </style>',
'</resources>'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,10 @@ public void onCreate(Bundle savedInstanceState)
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

// set preview overlay
localOverlayProxy = overlayProxy;
this.localOverlayProxy = overlayProxy;
if (this.localOverlayProxy != null) {
this.localOverlayProxy.setActivity(this);
}

// set overall layout - will populate in onResume
previewLayout = new PreviewLayout(this);
Expand Down
2 changes: 1 addition & 1 deletion android/templates/build/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
android:label="<%- appLabel %>"
android:name="<%- classname %>Application"
android:usesCleartextTraffic="true"
android:theme="@style/Base.Theme.Titanium.Customizable">
android:theme="@style/Theme.Titanium.App">

<activity
android:name=".<%- classname %>Activity"
Expand Down
6 changes: 3 additions & 3 deletions android/titanium/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
<activity
android:name="org.appcelerator.titanium.TiTranslucentActivity"
android:configChanges="${tiActivityConfigChanges}"
android:theme="@style/Theme.Titanium.Translucent"/>
android:theme="@style/Theme.AppDerived.Translucent"/>
<activity
android:name="ti.modules.titanium.media.TiCameraActivity"
android:configChanges="${tiActivityConfigChanges}"
android:theme="@style/Theme.Titanium.Translucent.Fullscreen"/>
android:theme="@style/Theme.Titanium.Dark.Fullscreen"/>
<activity
android:name="ti.modules.titanium.media.TiVideoActivity"
android:configChanges="${tiActivityConfigChanges}"
android:theme="@style/Theme.Titanium.Fullscreen"/>
android:theme="@style/Theme.AppDerived.Fullscreen"/>
<activity android:name="ti.modules.titanium.ui.android.TiPreferencesActivity"/>

<provider
Expand Down
7 changes: 7 additions & 0 deletions android/titanium/res/values-land/values.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Set action bar height to be shorter in landscape compared to portrait. -->
<!-- This works-around bug in Google's material theme where it sets the height wrong. -->
<!-- https://github.com/material-components/material-components-android/issues/779 -->
<dimen name="ti_action_bar_height">48dip</dimen>
</resources>
11 changes: 3 additions & 8 deletions android/titanium/res/values-night/values.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Titanium's dark theme colors. -->
<color name="ti_primary">#92B4F2</color>
<color name="ti_primary_dark">#000000</color>
<color name="ti_accent">#92B4F2</color>
<color name="ti_surface">#353639</color>
<color name="ti_background">#202124</color>
<color name="ti_navigation_bar">#000000</color>
</resources>
<!-- Titanium style supporting dark/light theme switching. -->
<style name="Theme.Titanium.DayNight" parent="Theme.Titanium.Dark"/>
</resources>
165 changes: 124 additions & 41 deletions android/titanium/res/values/values.xml
Original file line number Diff line number Diff line change
@@ -1,44 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Titanium's light theme colors. -->
<color name="ti_primary">#3475E0</color>
<color name="ti_primary_dark">#303F9F</color>
<color name="ti_accent">#3273DB</color>
<color name="ti_surface">#FFFFFF</color>
<color name="ti_background">#FFFFFF</color>
<color name="ti_navigation_bar">#303F9F</color>
<color name="ti_light_primary">#3475E0</color>
<color name="ti_light_primary_dark">#303F9F</color>
<color name="ti_light_accent">#3273DB</color>
<color name="ti_light_surface">#FFFFFF</color>
<color name="ti_light_background">#FFFFFF</color>
<color name="ti_light_navigation_bar">@color/ti_light_primary_dark</color>
<color name="ti_light_status_bar">@color/ti_light_primary_dark</color>

<!-- Titanium's dark theme colors. -->
<color name="ti_dark_primary">#92B4F2</color>
<color name="ti_dark_primary_dark">#000000</color>
<color name="ti_dark_accent">#92B4F2</color>
<color name="ti_dark_surface">#353639</color>
<color name="ti_dark_background">#202124</color>
<color name="ti_dark_navigation_bar">@color/ti_dark_primary_dark</color>
<color name="ti_dark_status_bar">@color/ti_dark_primary_dark</color>

<!-- Define action bar height to be same size as toolbar for portrait. -->
<!-- See "values-land/values.xml" which fixes action bar height for landscape. -->
<dimen name="ti_action_bar_height">@dimen/mtrl_toolbar_default_height</dimen>

<!-- Titanium's button text style is not all-caps just like Google's apps. -->
<style name="TextAppearance.Titanium.Button" parent="TextAppearance.MaterialComponents.Button">
<item name="android:textAllCaps">false</item>
</style>
<style name="Widget.Titanium.Button" parent="@style/Widget.AppCompat.Button">
<style name="Widget.Titanium.Button" parent="Widget.AppCompat.Button">
<item name="android:textAllCaps">false</item>
</style>

<!-- Root theme inherited by all other Titanium themes. -->
<!-- Our "_build.js" will replace parent with ".NoActionBar" or ".Fullscreen" if set in "tiapp.xml". -->
<style name="Base.Theme.Titanium.RootStyle" parent="Theme.MaterialComponents.DayNight.DarkActionBar"/>
<!-- Titanium's dark material theme with an action bar. -->
<style name="Theme.Titanium.Dark" parent="Theme.MaterialComponents">
<item name="actionBarSize">@dimen/ti_action_bar_height</item>
<item name="actionBarStyle">@style/Widget.MaterialComponents.ActionBar.Surface</item>
<item name="colorPrimary">@color/ti_dark_primary</item>
<item name="colorPrimaryDark">@color/ti_dark_primary_dark</item>
<item name="colorAccent">@color/ti_dark_accent</item>
<item name="colorSurface">@color/ti_dark_surface</item>
<item name="android:colorBackground">@color/ti_dark_background</item>
<item name="android:navigationBarColor">@color/ti_dark_navigation_bar</item>
<item name="android:buttonStyle">@style/Widget.Titanium.Button</item>
<item name="android:statusBarColor">@color/ti_dark_status_bar</item>
<item name="buttonStyle">@style/Widget.Titanium.Button</item>
<item name="textAppearanceButton">@style/TextAppearance.Titanium.Button</item>
</style>

<!-- Titanium's custom theme applied to all activities. This theme is used by default. -->
<style name="Base.Theme.Titanium" parent="Base.Theme.Titanium.RootStyle">
<item name="colorPrimary">@color/ti_primary</item>
<item name="colorPrimaryDark">@color/ti_primary_dark</item>
<item name="colorAccent">@color/ti_accent</item>
<item name="colorSurface">@color/ti_surface</item>
<item name="android:colorBackground">@color/ti_background</item>
<item name="android:navigationBarColor">@color/ti_navigation_bar</item>
<!-- Titanium's dark material theme without an action bar. -->
<style name="Theme.Titanium.Dark.NoTitleBar" parent="Theme.Titanium.Dark">
<item name="android:windowActionBar">false</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>

<!-- Titanium's dark material theme without an action bar and status bar. -->
<style name="Theme.Titanium.Dark.Fullscreen" parent="Theme.Titanium.Dark.NoTitleBar">
<item name="android:windowFullscreen">true</item>
</style>

<!-- Titanium's light material theme with an action bar. -->
<style name="Theme.Titanium.Light" parent="Theme.MaterialComponents.Light.DarkActionBar">
<item name="actionBarSize">@dimen/ti_action_bar_height</item>
<item name="actionBarStyle">@style/Widget.AppCompat.Light.ActionBar.Solid</item>
<item name="colorPrimary">@color/ti_light_primary</item>
<item name="colorPrimaryDark">@color/ti_light_primary_dark</item>
<item name="colorAccent">@color/ti_light_accent</item>
<item name="colorSurface">@color/ti_light_surface</item>
<item name="android:colorBackground">@color/ti_light_background</item>
<item name="android:navigationBarColor">@color/ti_light_navigation_bar</item>
<item name="android:buttonStyle">@style/Widget.Titanium.Button</item>
<item name="android:statusBarColor">@color/ti_light_status_bar</item>
<item name="buttonStyle">@style/Widget.Titanium.Button</item>
<item name="textAppearanceButton">@style/TextAppearance.Titanium.Button</item>
</style>

<!-- Base theme applied to all Titanium activities except splash. -->
<!-- Our "_build.js" will replace parent if "AndroidManifest.xml" has custom application theme. -->
<style name="Base.Theme.Titanium.Customizable" parent="Base.Theme.Titanium"/>
<!-- Titanium's light material theme without an action bar. -->
<style name="Theme.Titanium.Light.NoTitleBar" parent="Theme.Titanium.Light">
<item name="android:windowActionBar">false</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>

<!-- Titanium's light material theme without an action bar and status bar. -->
<style name="Theme.Titanium.Light.Fullscreen" parent="Theme.Titanium.Light.NoTitleBar">
<item name="android:windowFullscreen">true</item>
</style>

<!-- Titanium style supporting dark/light theme switching with an action bar. -->
<style name="Theme.Titanium.DayNight" parent="Theme.Titanium.Light"/>

<!-- Titanium style supporting dark/light theme switching without an action bar. -->
<style name="Theme.Titanium.DayNight.NoTitleBar" parent="Theme.Titanium.DayNight">
<item name="android:windowActionBar">false</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>

<!-- Titanium style supporting dark/light theme switching without an action bar and status bar. -->
<style name="Theme.Titanium.DayNight.Fullscreen" parent="Theme.Titanium.DayNight.NoTitleBar">
<item name="android:windowFullscreen">true</item>
</style>

<!-- The default theme Titanium applies to the <application/> in the manifest. -->
<!-- Our "_build.js" will replace parent with ".NoTitleBar" or ".Fullscreen" if set in "tiapp.xml". -->
<style name="Theme.Titanium.App" parent="Theme.Titanium.DayNight"/>

<!-- The app theme which all Titanium activities will use by default. -->
<!-- Our "_build.js" will replace parent if "AndroidManifest.xml" was assigned a custom application theme. -->
<style name="Theme.AppDerived" parent="Theme.Titanium.App"/>

<!-- Base theme to be used by the "TiRootActivity" class. -->
<style name="Base.Theme.Titanium.Splash" parent="Base.Theme.Titanium.Customizable">
<style name="Base.Theme.Titanium.Splash" parent="Theme.AppDerived">
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
<item name="windowActionBar">false</item>
Expand All @@ -52,7 +130,7 @@
<style name="Theme.Titanium" parent="Base.Theme.Titanium.Splash"/>

<!-- Activity theme used to remove top title bar, but keeps status bar and app theme. -->
<style name="Theme.Titanium.NoTitleBar" parent="Base.Theme.Titanium.Customizable">
<style name="Theme.AppDerived.NoTitleBar" parent="Theme.AppDerived">
<item name="android:windowActionBar">false</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowNoTitle">true</item>
Expand All @@ -61,20 +139,20 @@
</style>

<!-- Activity theme used to remove top status bar and title bar while preserving app theme. -->
<style name="Theme.Titanium.Fullscreen" parent="Theme.Titanium.NoTitleBar">
<style name="Theme.AppDerived.Fullscreen" parent="Theme.AppDerived.NoTitleBar">
<item name="android:windowFullscreen">true</item>
</style>

<!-- Activity theme applying transparent background while preserving app theme. -->
<style name="Theme.Titanium.Translucent" parent="Base.Theme.Titanium.Customizable">
<style name="Theme.AppDerived.Translucent" parent="Theme.AppDerived">
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowAnimationStyle">@null</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowIsTranslucent">true</item>
</style>

<!-- Activity theme applying transparent background and removes title bar, while preserving app theme. -->
<style name="Theme.Titanium.Translucent.NoTitleBar" parent="Theme.Titanium.Translucent">
<style name="Theme.AppDerived.Translucent.NoTitleBar" parent="Theme.AppDerived.Translucent">
<item name="android:windowActionBar">false</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowNoTitle">true</item>
Expand All @@ -83,20 +161,31 @@
</style>

<!-- Activity theme with transparent background, removes status bar and title bar while preserving app theme. -->
<style name="Theme.Titanium.Translucent.Fullscreen" parent="Theme.Titanium.Translucent.NoTitleBar">
<style name="Theme.AppDerived.Translucent.Fullscreen" parent="Theme.AppDerived.Translucent.NoTitleBar">
<item name="android:windowFullscreen">true</item>
</style>

<!-- Inherits Google's "Theme.MaterialComponents.DayNight.DarkActionBar" and removes top status and title bar. -->
<style name="Theme.MaterialComponents.DayNight.Fullscreen" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<item name="android:windowActionBar">false</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowNoTitle">true</item>
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<!-- Simple error dialog theme with a dark red background and white text. -->
<!-- Note: Cannot derive from material theme in case it's displaying a theming error. -->
<style name="Theme.Titanium.Dialog.Error" parent="Theme.AppCompat.Dialog.Alert">
<item name="android:background">#8A0000</item>
</style>

<!-- DEPRECATED: Use "Theme.AppDerived.NoTitleBar" instead. -->
<style name="Theme.Titanium.NoTitleBar" parent="Theme.AppDerived.NoTitleBar"/>

<!-- DEPRECATED: Use "Theme.AppDerived.Fullscreen" instead. -->
<style name="Theme.Titanium.Fullscreen" parent="Theme.AppDerived.Fullscreen"/>

<!-- DEPRECATED: Use "Theme.AppDerived.Translucent" instead. -->
<style name="Theme.Titanium.Translucent" parent="Theme.AppDerived.Translucent"/>

<!-- DEPRECATED: Use "Theme.AppDerived.Translucent.NoTitleBar" instead. -->
<style name="Theme.Titanium.Translucent.NoTitleBar" parent="Theme.AppDerived.Translucent.NoTitleBar"/>

<!-- DEPRECATED: Use "Theme.AppDerived.Translucent.Fullscreen" instead. -->
<style name="Theme.Titanium.Translucent.Fullscreen" parent="Theme.AppDerived.Translucent.Fullscreen"/>

<!-- Inherits Google's "Theme.MaterialComponents.Bridge" and removes top status and title bar. -->
<!-- DEPRECATED: Should use non-bridge version of MaterialComponents theme to avoid material widget issues. -->
<style name="Theme.MaterialComponents.Fullscreen.Bridge" parent="Theme.MaterialComponents.Bridge">
Expand All @@ -108,12 +197,6 @@
<item name="windowNoTitle">true</item>
</style>

<!-- Simple error dialog theme with a dark red background and white text. -->
<!-- Note: Cannot derive from material theme in case it's displaying a theming error. -->
<style name="Theme.Titanium.Dialog.Error" parent="Theme.AppCompat.Dialog.Alert">
<item name="android:background">#8A0000</item>
</style>

<!-- Google's dark AppCompat activity theme without a top title bar. -->
<!-- DEPRECATED: Should use MaterialComponents theme instead in order to use material widgets. -->
<style name="Theme.AppCompat.NoTitleBar" parent="Theme.AppCompat">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@

import android.content.res.Configuration;
import android.content.res.TypedArray;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import org.appcelerator.kroll.common.Log;
import org.appcelerator.titanium.util.TiRHelper;

Expand Down Expand Up @@ -93,10 +94,12 @@ public static TiActionBarStyleHandler from(AppCompatActivity activity)
if (view instanceof Toolbar) {
// Toolbar found. Set up a Toolbar style handler.
toolbarStyleHandler = new TiToolbarStyleHandler((Toolbar) view);
int styleAttributeId = TiRHelper.getResource("attr.actionBarStyle");
int[] idArray = new int[] { TiRHelper.getResource("attr.titleTextStyle"),
TiRHelper.getResource("attr.subtitleTextStyle") };
TypedArray typedArray = activity.obtainStyledAttributes(null, idArray, styleAttributeId, 0);
TypedValue typedValue = new TypedValue();
activity.getTheme().resolveAttribute(android.R.attr.actionBarStyle, typedValue, true);
TypedArray typedArray = activity.obtainStyledAttributes(typedValue.resourceId, new int[] {
android.R.attr.titleTextStyle,
android.R.attr.subtitleTextStyle
});
toolbarStyleHandler.setTitleTextAppearanceId(typedArray.getResourceId(0, 0));
toolbarStyleHandler.setSubtitleTextAppearanceId(typedArray.getResourceId(1, 0));
typedArray.recycle();
Expand Down

0 comments on commit ccb494a

Please sign in to comment.