mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-03 08:25: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.SurfaceView;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.Window;
|
||||
import android.view.WindowInsetsController;
|
||||
import android.view.inputmethod.BaseInputConnection;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
@@ -132,6 +134,70 @@ public final class GioView extends SurfaceView implements Choreographer.FrameCal
|
||||
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) {
|
||||
for (int j = 0; j < event.getHistorySize(); j++) {
|
||||
long time = event.getHistoricalEventTime(j);
|
||||
|
||||
@@ -42,7 +42,9 @@ import "C"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"gioui.org/internal/f32color"
|
||||
"image"
|
||||
"image/color"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
@@ -82,18 +84,22 @@ type window struct {
|
||||
// windowState tracks the View or Activity specific state lost when Android
|
||||
// re-creates our Activity.
|
||||
type windowState struct {
|
||||
cursor *pointer.CursorName
|
||||
cursor *pointer.CursorName
|
||||
navigationColor *color.NRGBA
|
||||
statusColor *color.NRGBA
|
||||
}
|
||||
|
||||
// gioView hold cached JNI methods for GioView.
|
||||
var gioView struct {
|
||||
once sync.Once
|
||||
getDensity C.jmethodID
|
||||
getFontScale C.jmethodID
|
||||
showTextInput C.jmethodID
|
||||
hideTextInput C.jmethodID
|
||||
postFrameCallback C.jmethodID
|
||||
setCursor C.jmethodID
|
||||
once sync.Once
|
||||
getDensity C.jmethodID
|
||||
getFontScale C.jmethodID
|
||||
showTextInput C.jmethodID
|
||||
hideTextInput C.jmethodID
|
||||
postFrameCallback C.jmethodID
|
||||
setCursor C.jmethodID
|
||||
setNavigationColor C.jmethodID
|
||||
setStatusColor C.jmethodID
|
||||
}
|
||||
|
||||
// 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.postFrameCallback = getMethodID(env, class, "postFrameCallback", "()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)
|
||||
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)
|
||||
views[handle] = w
|
||||
w.loadConfig(env, class)
|
||||
w.Option(wopts.opts)
|
||||
applyStateDiff(env, view, windowState{}, w.state)
|
||||
w.setStage(system.StagePaused)
|
||||
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) {
|
||||
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 {
|
||||
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) {
|
||||
@@ -728,6 +754,20 @@ func setCursor(env *C.JNIEnv, view C.jobject, name pointer.CursorName) {
|
||||
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.
|
||||
func (w *window) Close() {}
|
||||
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
package wm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gioui.org/internal/f32color"
|
||||
"image"
|
||||
"image/color"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall/js"
|
||||
@@ -22,6 +25,7 @@ import (
|
||||
type window struct {
|
||||
window js.Value
|
||||
document js.Value
|
||||
head js.Value
|
||||
clipboard js.Value
|
||||
cnv js.Value
|
||||
tarea js.Value
|
||||
@@ -61,6 +65,7 @@ func NewWindow(win Callbacks, opts *Options) error {
|
||||
document: doc,
|
||||
tarea: tarea,
|
||||
window: js.Global().Get("window"),
|
||||
head: doc.Get("head"),
|
||||
clipboard: js.Global().Get("navigator").Get("clipboard"),
|
||||
}
|
||||
w.requestAnimationFrame = w.window.Get("requestAnimationFrame")
|
||||
@@ -486,6 +491,9 @@ func (w *window) Option(opts *Options) {
|
||||
if o := opts.WindowMode; o != nil {
|
||||
w.windowMode(*o)
|
||||
}
|
||||
if o := opts.NavigationColor; o != nil {
|
||||
w.navigationColor(*o)
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
switch mode {
|
||||
case Windowed:
|
||||
if fs := w.document.Get("fullscreenElement"); !fs.Truthy() {
|
||||
if !w.document.Get("fullscreenElement").Truthy() {
|
||||
return // Browser is already Windowed.
|
||||
}
|
||||
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() {
|
||||
select {}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ package wm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"image/color"
|
||||
|
||||
"gioui.org/gpu"
|
||||
"gioui.org/io/event"
|
||||
@@ -20,11 +21,13 @@ type Size struct {
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
Size *Size
|
||||
MinSize *Size
|
||||
MaxSize *Size
|
||||
Title *string
|
||||
WindowMode *WindowMode
|
||||
Size *Size
|
||||
MinSize *Size
|
||||
MaxSize *Size
|
||||
Title *string
|
||||
WindowMode *WindowMode
|
||||
StatusColor *color.NRGBA
|
||||
NavigationColor *color.NRGBA
|
||||
}
|
||||
|
||||
type WindowMode uint8
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"time"
|
||||
|
||||
"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() {}
|
||||
|
||||
Reference in New Issue
Block a user