mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-07 18:35:34 +00:00
app, app/internal: [wasm,android] new Option to change navigation/status color
Signed-off-by: Inkeliz <inkeliz@inkeliz.com>
This commit is contained in:
@@ -29,6 +29,8 @@ import android.view.WindowInsets;
|
|||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import android.view.SurfaceView;
|
import android.view.SurfaceView;
|
||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
|
import android.view.Window;
|
||||||
|
import android.view.WindowInsetsController;
|
||||||
import android.view.inputmethod.BaseInputConnection;
|
import android.view.inputmethod.BaseInputConnection;
|
||||||
import android.view.inputmethod.InputConnection;
|
import android.view.inputmethod.InputConnection;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
@@ -132,6 +134,70 @@ public final class GioView extends SurfaceView implements Choreographer.FrameCal
|
|||||||
setPointerIcon(pointerIcon);
|
setPointerIcon(pointerIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum Bar {
|
||||||
|
NAVIGATION,
|
||||||
|
STATUS,
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setBarColor(Bar t, int color, int luminance) {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Window window = ((Activity) this.getContext()).getWindow();
|
||||||
|
|
||||||
|
int insetsMask;
|
||||||
|
int viewMask;
|
||||||
|
|
||||||
|
switch (t) {
|
||||||
|
case STATUS:
|
||||||
|
insetsMask = WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
|
||||||
|
viewMask = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
|
||||||
|
window.setStatusBarColor(color);
|
||||||
|
break;
|
||||||
|
case NAVIGATION:
|
||||||
|
insetsMask = WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
|
||||||
|
viewMask = View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
|
||||||
|
window.setNavigationBarColor(color);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("invalid bar type");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||||
|
int flags = this.getSystemUiVisibility();
|
||||||
|
if (luminance > 128) {
|
||||||
|
flags |= viewMask;
|
||||||
|
} else {
|
||||||
|
flags &= ~viewMask;
|
||||||
|
}
|
||||||
|
this.setSystemUiVisibility(flags);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowInsetsController insetsController = window.getInsetsController();
|
||||||
|
if (insetsController == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (luminance > 128) {
|
||||||
|
insetsController.setSystemBarsAppearance(insetsMask, insetsMask);
|
||||||
|
} else {
|
||||||
|
insetsController.setSystemBarsAppearance(0, insetsMask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setStatusColor(int color, int luminance) {
|
||||||
|
this.setBarColor(Bar.STATUS, color, luminance);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setNavigationColor(int color, int luminance) {
|
||||||
|
this.setBarColor(Bar.NAVIGATION, color, luminance);
|
||||||
|
}
|
||||||
|
|
||||||
private void dispatchMotionEvent(MotionEvent event) {
|
private void dispatchMotionEvent(MotionEvent event) {
|
||||||
for (int j = 0; j < event.getHistorySize(); j++) {
|
for (int j = 0; j < event.getHistorySize(); j++) {
|
||||||
long time = event.getHistoricalEventTime(j);
|
long time = event.getHistoricalEventTime(j);
|
||||||
|
|||||||
@@ -42,7 +42,9 @@ import "C"
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"gioui.org/internal/f32color"
|
||||||
"image"
|
"image"
|
||||||
|
"image/color"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
@@ -83,6 +85,8 @@ type window struct {
|
|||||||
// re-creates our Activity.
|
// re-creates our Activity.
|
||||||
type windowState struct {
|
type windowState struct {
|
||||||
cursor *pointer.CursorName
|
cursor *pointer.CursorName
|
||||||
|
navigationColor *color.NRGBA
|
||||||
|
statusColor *color.NRGBA
|
||||||
}
|
}
|
||||||
|
|
||||||
// gioView hold cached JNI methods for GioView.
|
// gioView hold cached JNI methods for GioView.
|
||||||
@@ -94,6 +98,8 @@ var gioView struct {
|
|||||||
hideTextInput C.jmethodID
|
hideTextInput C.jmethodID
|
||||||
postFrameCallback C.jmethodID
|
postFrameCallback C.jmethodID
|
||||||
setCursor C.jmethodID
|
setCursor C.jmethodID
|
||||||
|
setNavigationColor C.jmethodID
|
||||||
|
setStatusColor C.jmethodID
|
||||||
}
|
}
|
||||||
|
|
||||||
// ViewEvent is sent whenever the Window's underlying Android view
|
// ViewEvent is sent whenever the Window's underlying Android view
|
||||||
@@ -220,6 +226,8 @@ func Java_org_gioui_GioView_onCreateView(env *C.JNIEnv, class C.jclass, view C.j
|
|||||||
m.hideTextInput = getMethodID(env, class, "hideTextInput", "()V")
|
m.hideTextInput = getMethodID(env, class, "hideTextInput", "()V")
|
||||||
m.postFrameCallback = getMethodID(env, class, "postFrameCallback", "()V")
|
m.postFrameCallback = getMethodID(env, class, "postFrameCallback", "()V")
|
||||||
m.setCursor = getMethodID(env, class, "setCursor", "(I)V")
|
m.setCursor = getMethodID(env, class, "setCursor", "(I)V")
|
||||||
|
m.setNavigationColor = getMethodID(env, class, "setNavigationColor", "(II)V")
|
||||||
|
m.setStatusColor = getMethodID(env, class, "setStatusColor", "(II)V")
|
||||||
})
|
})
|
||||||
view = C.gio_jni_NewGlobalRef(env, view)
|
view = C.gio_jni_NewGlobalRef(env, view)
|
||||||
wopts := <-mainWindow.out
|
wopts := <-mainWindow.out
|
||||||
@@ -235,6 +243,7 @@ func Java_org_gioui_GioView_onCreateView(env *C.JNIEnv, class C.jclass, view C.j
|
|||||||
handle := C.jlong(view)
|
handle := C.jlong(view)
|
||||||
views[handle] = w
|
views[handle] = w
|
||||||
w.loadConfig(env, class)
|
w.loadConfig(env, class)
|
||||||
|
w.Option(wopts.opts)
|
||||||
applyStateDiff(env, view, windowState{}, w.state)
|
applyStateDiff(env, view, windowState{}, w.state)
|
||||||
w.setStage(system.StagePaused)
|
w.setStage(system.StagePaused)
|
||||||
w.callbacks.Event(ViewEvent{View: uintptr(view)})
|
w.callbacks.Event(ViewEvent{View: uintptr(view)})
|
||||||
@@ -676,7 +685,18 @@ func (w *window) ReadClipboard() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) Option(opts *Options) {}
|
func (w *window) Option(opts *Options) {
|
||||||
|
if o := opts.NavigationColor; o != nil {
|
||||||
|
w.setState(func(state *windowState) {
|
||||||
|
state.navigationColor = o
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if o := opts.StatusColor; o != nil {
|
||||||
|
w.setState(func(state *windowState) {
|
||||||
|
state.statusColor = o
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (w *window) SetCursor(name pointer.CursorName) {
|
func (w *window) SetCursor(name pointer.CursorName) {
|
||||||
w.setState(func(state *windowState) {
|
w.setState(func(state *windowState) {
|
||||||
@@ -703,6 +723,12 @@ func applyStateDiff(env *C.JNIEnv, view C.jobject, old, state windowState) {
|
|||||||
if state.cursor != nil && old.cursor != state.cursor {
|
if state.cursor != nil && old.cursor != state.cursor {
|
||||||
setCursor(env, view, *state.cursor)
|
setCursor(env, view, *state.cursor)
|
||||||
}
|
}
|
||||||
|
if state.navigationColor != nil && old.navigationColor != state.navigationColor {
|
||||||
|
setNavigationColor(env, view, *state.navigationColor)
|
||||||
|
}
|
||||||
|
if state.statusColor != nil && old.statusColor != state.statusColor {
|
||||||
|
setStatusColor(env, view, *state.statusColor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setCursor(env *C.JNIEnv, view C.jobject, name pointer.CursorName) {
|
func setCursor(env *C.JNIEnv, view C.jobject, name pointer.CursorName) {
|
||||||
@@ -728,6 +754,20 @@ func setCursor(env *C.JNIEnv, view C.jobject, name pointer.CursorName) {
|
|||||||
callVoidMethod(env, view, gioView.setCursor, jvalue(curID))
|
callVoidMethod(env, view, gioView.setCursor, jvalue(curID))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setStatusColor(env *C.JNIEnv, view C.jobject, color color.NRGBA) {
|
||||||
|
callVoidMethod(env, view, gioView.setStatusColor,
|
||||||
|
jvalue(uint32(color.A)<<24|uint32(color.R)<<16|uint32(color.G)<<8|uint32(color.B)),
|
||||||
|
jvalue(int(f32color.LinearFromSRGB(color).Luminance()*255)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setNavigationColor(env *C.JNIEnv, view C.jobject, color color.NRGBA) {
|
||||||
|
callVoidMethod(env, view, gioView.setNavigationColor,
|
||||||
|
jvalue(uint32(color.A)<<24|uint32(color.R)<<16|uint32(color.G)<<8|uint32(color.B)),
|
||||||
|
jvalue(int(f32color.LinearFromSRGB(color).Luminance()*255)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Close the window. Not implemented for Android.
|
// Close the window. Not implemented for Android.
|
||||||
func (w *window) Close() {}
|
func (w *window) Close() {}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,10 @@
|
|||||||
package wm
|
package wm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"gioui.org/internal/f32color"
|
||||||
"image"
|
"image"
|
||||||
|
"image/color"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall/js"
|
"syscall/js"
|
||||||
@@ -22,6 +25,7 @@ import (
|
|||||||
type window struct {
|
type window struct {
|
||||||
window js.Value
|
window js.Value
|
||||||
document js.Value
|
document js.Value
|
||||||
|
head js.Value
|
||||||
clipboard js.Value
|
clipboard js.Value
|
||||||
cnv js.Value
|
cnv js.Value
|
||||||
tarea js.Value
|
tarea js.Value
|
||||||
@@ -61,6 +65,7 @@ func NewWindow(win Callbacks, opts *Options) error {
|
|||||||
document: doc,
|
document: doc,
|
||||||
tarea: tarea,
|
tarea: tarea,
|
||||||
window: js.Global().Get("window"),
|
window: js.Global().Get("window"),
|
||||||
|
head: doc.Get("head"),
|
||||||
clipboard: js.Global().Get("navigator").Get("clipboard"),
|
clipboard: js.Global().Get("navigator").Get("clipboard"),
|
||||||
}
|
}
|
||||||
w.requestAnimationFrame = w.window.Get("requestAnimationFrame")
|
w.requestAnimationFrame = w.window.Get("requestAnimationFrame")
|
||||||
@@ -486,6 +491,9 @@ func (w *window) Option(opts *Options) {
|
|||||||
if o := opts.WindowMode; o != nil {
|
if o := opts.WindowMode; o != nil {
|
||||||
w.windowMode(*o)
|
w.windowMode(*o)
|
||||||
}
|
}
|
||||||
|
if o := opts.NavigationColor; o != nil {
|
||||||
|
w.navigationColor(*o)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) SetCursor(name pointer.CursorName) {
|
func (w *window) SetCursor(name pointer.CursorName) {
|
||||||
@@ -567,7 +575,7 @@ func (w *window) config() (int, int, system.Insets, unit.Metric) {
|
|||||||
func (w *window) windowMode(mode WindowMode) {
|
func (w *window) windowMode(mode WindowMode) {
|
||||||
switch mode {
|
switch mode {
|
||||||
case Windowed:
|
case Windowed:
|
||||||
if fs := w.document.Get("fullscreenElement"); !fs.Truthy() {
|
if !w.document.Get("fullscreenElement").Truthy() {
|
||||||
return // Browser is already Windowed.
|
return // Browser is already Windowed.
|
||||||
}
|
}
|
||||||
if !w.document.Get("exitFullscreen").Truthy() {
|
if !w.document.Get("exitFullscreen").Truthy() {
|
||||||
@@ -583,6 +591,17 @@ func (w *window) windowMode(mode WindowMode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *window) navigationColor(c color.NRGBA) {
|
||||||
|
theme := w.head.Call("querySelector", `meta[name="theme-color"]`)
|
||||||
|
if !theme.Truthy() {
|
||||||
|
theme = w.document.Call("createElement", "meta")
|
||||||
|
theme.Set("name", "theme-color")
|
||||||
|
w.head.Call("appendChild", theme)
|
||||||
|
}
|
||||||
|
rgba := f32color.NRGBAToRGBA(c)
|
||||||
|
theme.Set("content", fmt.Sprintf("#%06X", []uint8{rgba.R, rgba.G, rgba.B}))
|
||||||
|
}
|
||||||
|
|
||||||
func Main() {
|
func Main() {
|
||||||
select {}
|
select {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package wm
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"image/color"
|
||||||
|
|
||||||
"gioui.org/gpu"
|
"gioui.org/gpu"
|
||||||
"gioui.org/io/event"
|
"gioui.org/io/event"
|
||||||
@@ -25,6 +26,8 @@ type Options struct {
|
|||||||
MaxSize *Size
|
MaxSize *Size
|
||||||
Title *string
|
Title *string
|
||||||
WindowMode *WindowMode
|
WindowMode *WindowMode
|
||||||
|
StatusColor *color.NRGBA
|
||||||
|
NavigationColor *color.NRGBA
|
||||||
}
|
}
|
||||||
|
|
||||||
type WindowMode uint8
|
type WindowMode uint8
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
|
"image/color"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gioui.org/io/event"
|
"gioui.org/io/event"
|
||||||
@@ -525,4 +526,18 @@ func MinSize(w, h unit.Value) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StatusColor sets the color of the Android status bar.
|
||||||
|
func StatusColor(color color.NRGBA) Option {
|
||||||
|
return func(opts *wm.Options) {
|
||||||
|
opts.StatusColor = &color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NavigationColor sets the color of the navigation bar on Android, or the address bar in browsers.
|
||||||
|
func NavigationColor(color color.NRGBA) Option {
|
||||||
|
return func(opts *wm.Options) {
|
||||||
|
opts.NavigationColor = &color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (driverEvent) ImplementsEvent() {}
|
func (driverEvent) ImplementsEvent() {}
|
||||||
|
|||||||
Reference in New Issue
Block a user