app, app/internal: [wasm,android] new Option to change navigation/status color

Signed-off-by: Inkeliz <inkeliz@inkeliz.com>
This commit is contained in:
Inkeliz
2021-04-18 08:22:41 +01:00
committed by Elias Naur
parent 2296c80d28
commit 9dae29844c
5 changed files with 158 additions and 15 deletions
+66
View File
@@ -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);
+49 -9
View File
@@ -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"
@@ -82,18 +84,22 @@ type window struct {
// windowState tracks the View or Activity specific state lost when Android // windowState tracks the View or Activity specific state lost when Android
// 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.
var gioView struct { var gioView struct {
once sync.Once once sync.Once
getDensity C.jmethodID getDensity C.jmethodID
getFontScale C.jmethodID getFontScale C.jmethodID
showTextInput C.jmethodID showTextInput C.jmethodID
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() {}
+20 -1
View File
@@ -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 {}
} }
+8 -5
View File
@@ -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"
@@ -20,11 +21,13 @@ type Size struct {
} }
type Options struct { type Options struct {
Size *Size Size *Size
MinSize *Size MinSize *Size
MaxSize *Size MaxSize *Size
Title *string Title *string
WindowMode *WindowMode WindowMode *WindowMode
StatusColor *color.NRGBA
NavigationColor *color.NRGBA
} }
type WindowMode uint8 type WindowMode uint8
+15
View File
@@ -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() {}