├── .github └── workflows │ └── push.yml ├── LICENSE ├── README.md ├── docs ├── ikws4.adaptive_color_bar.md ├── ikws4.system_variable.md └── ikws4.webview_custom_css.md ├── scope_config.lua ├── scripts ├── ikws4.adaptive_color_bar.lua ├── ikws4.example.lua ├── ikws4.system_variable.lua └── ikws4.webview_custom_css.lua └── stylua.toml /.github/workflows/push.yml: -------------------------------------------------------------------------------- 1 | name: Format 2 | 3 | on: push 4 | 5 | jobs: 6 | postprocessing: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v3 11 | 12 | - uses: JohnnyMorganz/stylua-action@v1.1.2 13 | with: 14 | token: ${{ secrets.GITHUB_TOKEN }} 15 | args: . 16 | 17 | - uses: stefanzweifel/git-auto-commit-action@v4 18 | with: 19 | commit_message: "chore: format with stylua" 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Devin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WeiJu2-Scripts 2 | 3 | - [ikws4.adaptive_color_bar](./docs/ikws4.adaptive_color_bar.md) 4 | - [ikws4.system_variable](./docs/ikws4.system_variable.md) 5 | - [ikws4.webview_custom_css](./docs/ikws4.webview_custom_css.md) 6 | -------------------------------------------------------------------------------- /docs/ikws4.adaptive_color_bar.md: -------------------------------------------------------------------------------- 1 | ### Usage 2 | 3 | ```lua 4 | require("ikws4.adaptive_color_bar").setup { 5 | status_bar = true, 6 | navigation_bar = true, 7 | samples = 10, 8 | refresh_rate = 125, 9 | } 10 | ``` 11 | 12 | ### Change Log 13 | 14 | #### [1.0.1] - 2023-2-15 15 | 16 | ##### Fixed 17 | 18 | - A null pointer, this happens when the local variable canvas has been recycled by the GC. 19 | 20 | ### Preview 21 | 22 | https://user-images.githubusercontent.com/47056144/190885640-ea7525ff-2de3-4637-88dd-8f6fb1352127.mp4 23 | 24 | -------------------------------------------------------------------------------- /docs/ikws4.system_variable.md: -------------------------------------------------------------------------------- 1 | ### Usage 2 | 3 | ```lua 4 | require("ikws4.system_variable").setup { 5 | build = { 6 | device = "coral", 7 | product = "coral", 8 | model = "Pixel 4 XL", 9 | brand = "google", 10 | android_version = "13", 11 | }, 12 | location = { 13 | longitude = 31.921279, 14 | latitude = 620.157480, 15 | }, 16 | display = { 17 | dpi = 320, 18 | language = "en-US", 19 | }, 20 | } 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/ikws4.webview_custom_css.md: -------------------------------------------------------------------------------- 1 | ### Usage 2 | 3 | ```lua 4 | require("ikws4.webview_custom_css").setup { 5 | css = [[ 6 | * { 7 | color: white; 8 | background: black; 9 | } 10 | ]], 11 | } 12 | ``` 13 | 14 | ### Preview 15 | 16 |
17 | 18 | 19 |
20 | -------------------------------------------------------------------------------- /scope_config.lua: -------------------------------------------------------------------------------- 1 | return { 2 | -- ["ikws4.example"] = ".*", 3 | ["ikws4.system_variable"] = ".*", 4 | ["ikws4.webview_custom_css"] = ".*", 5 | ["ikws4.adaptive_color_bar"] = ".*", 6 | } 7 | -------------------------------------------------------------------------------- /scripts/ikws4.adaptive_color_bar.lua: -------------------------------------------------------------------------------- 1 | --[==[ 2 | @metadata 3 | return { 4 | name = "adaptive_color_bar", 5 | author = "ikws4", 6 | version = "1.0.1", 7 | description = "Adaptive color for status and navigation bar", 8 | example = [=[ 9 | require("ikws4.adaptive_color_bar").setup { 10 | status_bar = true, 11 | navigation_bar = true, 12 | samples = 10, 13 | refresh_rate = 125, 14 | } 15 | ]=] 16 | } 17 | @end 18 | --]==] 19 | 20 | local config = { 21 | status_bar = true, 22 | navigation_bar = true, 23 | samples = 10, 24 | refresh_rate = 125, 25 | } 26 | 27 | local M = {} 28 | 29 | M.setup = function(opts) 30 | config = table.extend(config, opts or {}) 31 | 32 | local Activity = import("android.app.Activity") 33 | local Bundle = import("android.os.Bundle") 34 | local Canvas = import("android.graphics.Canvas") 35 | local Bitmap = import("android.graphics.Bitmap") 36 | local BitmapConfig = import("android.graphics.Bitmap.Config") 37 | local Runnable = import("java.lang.Runnable") 38 | local OnApplyWindowInsetsListener = import("android.view.View.OnApplyWindowInsetsListener") 39 | local Window = import("android.view.Window") 40 | local Rect = import("android.graphics.Rect") 41 | local ValueAnimator = import("android.animation.ValueAnimator") 42 | local ValueAnimatorAnimatorUpdateListener = import("android.animation.ValueAnimator.AnimatorUpdateListener") 43 | local AccelerateInterpolator = import("android.view.animation.AccelerateInterpolator") 44 | 45 | local decor_view_bitmap 46 | 47 | local function get_most_frequent_color(colors) 48 | local map = {} 49 | for _, color in ipairs(colors) do 50 | map[color] = map[color] and map[color] + 1 or 1 51 | end 52 | 53 | local max, res = 0, 0 54 | for k, v in pairs(map) do 55 | if v > max then 56 | max = v 57 | res = k 58 | end 59 | end 60 | 61 | return res 62 | end 63 | 64 | local function color_animator(old_color, new_color, duration, callback) 65 | local animator = ValueAnimator:ofArgb { old_color, new_color } 66 | animator:setDuration(duration) 67 | animator:addUpdateListener(object(ValueAnimatorAnimatorUpdateListener, { 68 | onAnimationUpdate = callback, 69 | })) 70 | animator:start() 71 | end 72 | 73 | hook { 74 | class = Activity, 75 | returns = void, 76 | method = "onCreate", 77 | params = { 78 | Bundle, 79 | }, 80 | after = function(this, params) 81 | local window = this:getWindow() 82 | local decorView = window:getDecorView() 83 | 84 | local status_bar_height, navigation_bar_height 85 | local canvas 86 | 87 | decorView:post(object(Runnable, { 88 | run = function(this) 89 | if not status_bar_height or not navigation_bar_height then 90 | local visible_rect = Rect() 91 | decorView:getWindowVisibleDisplayFrame(visible_rect) 92 | status_bar_height = visible_rect.top 93 | navigation_bar_height = decorView:getHeight() - visible_rect.bottom 94 | end 95 | 96 | if not decor_view_bitmap or decor_view_bitmap:isRecycled() or not canvas then 97 | decor_view_bitmap = Bitmap:createBitmap(decorView:getWidth(), decorView:getHeight(), BitmapConfig.ARGB_8888) 98 | canvas = Canvas(decor_view_bitmap) 99 | end 100 | 101 | decorView:draw(canvas) 102 | 103 | local width = decorView:getWidth() 104 | local step = math.floor(width / config.samples) 105 | 106 | -- compute and set status bar color 107 | if config.status_bar then 108 | local colors = {} 109 | for x = 0, decorView:getWidth() - 1, step do 110 | colors[#colors + 1] = decor_view_bitmap:getPixel(x, status_bar_height + 1) 111 | end 112 | local old_color = window:getStatusBarColor() 113 | local new_color = get_most_frequent_color(colors) 114 | if old_color ~= new_color then 115 | color_animator(old_color, new_color, config.refresh_rate, function(this, animation) 116 | window:setStatusBarColor(animation:getAnimatedValue()) 117 | end) 118 | end 119 | end 120 | 121 | -- compute and setnavigation bar color 122 | if config.navigation_bar then 123 | local colors = {} 124 | for x = 0, decorView:getWidth() - 1, step do 125 | colors[#colors + 1] = decor_view_bitmap:getPixel(x, decorView:getHeight() - (navigation_bar_height + 1)) 126 | end 127 | local old_color = window:getNavigationBarColor() 128 | local new_color = get_most_frequent_color(colors) 129 | if old_color ~= new_color then 130 | color_animator(old_color, new_color, config.refresh_rate, function(this, animation) 131 | window:setNavigationBarColor(animation:getAnimatedValue()) 132 | end) 133 | end 134 | end 135 | 136 | decorView:postDelayed(this, config.refresh_rate) 137 | end, 138 | })) 139 | end, 140 | } 141 | 142 | hook { 143 | class = Activity, 144 | returns = void, 145 | method = "onDestroy", 146 | after = function() 147 | if decor_view_bitmap and not decor_view_bitmap:isRecycled() then 148 | decor_view_bitmap:recycle() 149 | end 150 | end, 151 | } 152 | end 153 | 154 | return M 155 | -------------------------------------------------------------------------------- /scripts/ikws4.example.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | @metadata 3 | return { 4 | name = "example", 5 | author = "ikws4", 6 | version = "1.0.0", 7 | description = "A complete example to show you how to write scripts." 8 | } 9 | @end 10 | --]] 11 | 12 | local config = { 13 | toast_msg = nil, 14 | text = nil, 15 | } 16 | 17 | local M = {} 18 | 19 | M.setup = function(opts) 20 | config = table.extend(config, opts or {}) 21 | 22 | -- Easy to import any java class and support for private field, method and constructor access 23 | local Toast = import("android.widget.Toast") 24 | local Activity = import("android.app.Activity") 25 | local TextView = import("android.widget.TextView") 26 | local Bundle = import("android.os.Bundle") 27 | local CharSequence = import("java.lang.CharSequence") 28 | local BufferType = import("android.widget.TextView$BufferType") 29 | 30 | if config.toast_msg then 31 | -- Make a toast after activity created 32 | hook { 33 | class = Activity, 34 | returns = void, 35 | method = "onCreate", 36 | params = { 37 | Bundle, 38 | }, 39 | after = function(this, params) 40 | Toast:makeText(this, config.toast_msg, Toast.LENGTH_SHORT):show() 41 | -- ^ 42 | -- Note: `this` is the Activity instance 43 | end, 44 | } 45 | end 46 | 47 | if config.text then 48 | -- Change all the text to `config.text` 49 | hook { 50 | class = TextView, 51 | returns = void, 52 | method = "setText", 53 | params = { 54 | CharSequence, -- text 55 | BufferType, -- type 56 | boolean, -- nofityBefore 57 | int, -- oldLen 58 | }, 59 | before = function(this, params) 60 | -- Reset `text` value 61 | params[1] = config.text 62 | -- ^ 63 | -- Note: In lua, index is 1 based 64 | end, 65 | } 66 | end 67 | end 68 | 69 | return M 70 | -------------------------------------------------------------------------------- /scripts/ikws4.system_variable.lua: -------------------------------------------------------------------------------- 1 | --[=[ 2 | @metadata 3 | return { 4 | name = "system_variable", 5 | author = "ikws4", 6 | version = "1.1.1", 7 | description = "Configing the variables, like phone model, location, dpi etc...", 8 | example = [[ 9 | require("ikws4.system_variable").setup { 10 | build = { 11 | device = "coral", 12 | product = "coral", 13 | model = "Pixel 4 XL", 14 | brand = "google", 15 | android_version = "13", 16 | }, 17 | location = { 18 | longitude = 31.921279, 19 | latitude = 620.157480, 20 | }, 21 | display = { 22 | dpi = 320, 23 | language = "en-US", 24 | }, 25 | } 26 | ]] 27 | } 28 | @end 29 | --]=] 30 | 31 | local config = { 32 | build = { 33 | device = nil, 34 | product = nil, 35 | model = nil, 36 | brand = nil, 37 | android_version = nil, 38 | }, 39 | location = { 40 | -- See https://www.latlong.net/ 41 | longitude = nil, 42 | latitude = nil, 43 | }, 44 | display = { 45 | dpi = nil, 46 | -- See https://www.fincher.org/Utilities/CountryLanguageList.shtml 47 | language = nil, 48 | }, 49 | } 50 | 51 | local M = {} 52 | 53 | M.setup = function(opts) 54 | config = table.extend(config, opts or {}) 55 | 56 | local Build = import("android.os.Build") 57 | 58 | Build.DEVICE = config.build.device or Build.DEVICE 59 | Build.PRODUCT = config.build.product or Build.PRODUCT 60 | Build.MODEL = config.build.model or Build.MODEL 61 | Build.BRAND = config.build.brand or Build.BRAND 62 | Build.MANUFACTURER = config.build.brand or Build.MANUFACTURER 63 | Build.VERSION.RELEASE = config.build.android_version or Build.VERSION.RELEASE 64 | 65 | local location_classes = { 66 | "android.location.Location", -- Android 67 | "com.baidu.location.BDLocation", -- Baidu 68 | } 69 | 70 | for _, class in ipairs(location_classes) do 71 | local ok, class = pcall(import, class) 72 | 73 | if ok then 74 | if config.location.longitude then 75 | hook { 76 | class = class, 77 | returns = double, 78 | method = "getLongitude", 79 | replace = function(this, params) 80 | return config.location.longitude 81 | end, 82 | } 83 | end 84 | 85 | if config.location.latitude then 86 | hook { 87 | class = class, 88 | returns = double, 89 | method = "getLatitude", 90 | replace = function(this, params) 91 | return config.location.latitude 92 | end, 93 | } 94 | end 95 | end 96 | end 97 | 98 | if config.display.dpi or config.display.language then 99 | local ContextWrapper = import("android.content.ContextWrapper") 100 | local Configuration = import("android.content.res.Configuration") 101 | local Context = import("android.content.Context") 102 | 103 | hook { 104 | class = ContextWrapper, 105 | returns = void, 106 | method = "attachBaseContext", 107 | params = { 108 | Context, 109 | }, 110 | before = function(this, params) 111 | local context = params[1] 112 | 113 | -- Make a copy of the configuration, and then modify the dpi 114 | local new_configuration = Configuration(context:getResources():getConfiguration()) 115 | 116 | if config.display.dpi then 117 | new_configuration.densityDpi = config.display.dpi 118 | end 119 | 120 | -- Change the language 121 | if config.display.language then 122 | local String = import("java.lang.String") 123 | local Locale = import("java.util.Locale") 124 | 125 | local country_city = config.display.language:split("-") 126 | local locale = Locale(country_city[1], country_city[2]) 127 | Locale:setDefault(locale) 128 | new_configuration:setLocale(locale) 129 | end 130 | 131 | params[1] = context:createConfigurationContext(new_configuration) 132 | end, 133 | } 134 | end 135 | end 136 | 137 | return M 138 | -------------------------------------------------------------------------------- /scripts/ikws4.webview_custom_css.lua: -------------------------------------------------------------------------------- 1 | --[==[ 2 | @metadata 3 | return { 4 | name = "webview_custom_css", 5 | author = "ikws4", 6 | version = "1.0.1", 7 | description = "Inject custom css into WebView", 8 | example = [=[ 9 | require("ikws4.webview_custom_css").setup { 10 | css = [[ 11 | * { 12 | color: white; 13 | background: black; 14 | } 15 | ]], 16 | } 17 | ]=] 18 | } 19 | @end 20 | --]==] 21 | 22 | local config = { 23 | css = nil, 24 | } 25 | 26 | local M = {} 27 | 28 | M.setup = function(opts) 29 | config = table.extend(config, opts or {}) 30 | 31 | local WebViewClient = import("android.webkit.WebViewClient") 32 | local WebView = import("android.webkit.WebView") 33 | local String = import("java.lang.String") 34 | local Bitmap = import("android.graphics.Bitmap") 35 | 36 | if config.css then 37 | hook { 38 | class = WebViewClient, 39 | returns = void, 40 | method = "onPageStarted", 41 | params = { 42 | WebView, 43 | String, 44 | Bitmap, 45 | }, 46 | after = function(this, params) 47 | local view = params[1] 48 | local settings = view:getSettings() 49 | 50 | if not settings:getJavaScriptEnabled() then 51 | settings:setJavaScriptEnabled(true) 52 | end 53 | end, 54 | } 55 | 56 | hook { 57 | class = WebViewClient, 58 | returns = void, 59 | method = "onPageCommitVisible", 60 | params = { 61 | WebView, 62 | String, 63 | }, 64 | after = function(this, params) 65 | local view = params[1] 66 | local css = string.gsub(config.css, "\n", "\\n") 67 | 68 | -- inject custom css 69 | local injection = string.format( 70 | [[ 71 | (function() { 72 | var style = document.createElement('style'); 73 | style.type = 'text/css'; 74 | style.innerHTML = '%s'; 75 | document.head.appendChild(style); 76 | })() 77 | ]], 78 | css 79 | ) 80 | 81 | view:evaluateJavascript(injection, nil) 82 | end, 83 | } 84 | end 85 | end 86 | 87 | return M 88 | -------------------------------------------------------------------------------- /stylua.toml: -------------------------------------------------------------------------------- 1 | column_width = 120 2 | line_endings = "Unix" 3 | indent_type = "Spaces" 4 | indent_width = 2 5 | quote_style = "AutoPreferDouble" 6 | call_parentheses = "NoSingleTable" 7 | --------------------------------------------------------------------------------