Skip to content

Commit

Permalink
Merge pull request #3729 from NoelDeMartin/MOBILE-4331
Browse files Browse the repository at this point in the history
MOBILE-4331: Implement native plugin
  • Loading branch information
crazyserver authored Jul 7, 2023
2 parents 670bb10 + ea40a68 commit a722e2c
Show file tree
Hide file tree
Showing 20 changed files with 1,415 additions and 54 deletions.
14 changes: 10 additions & 4 deletions .github/workflows/testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ jobs:
with:
node-version-file: '.nvmrc'
- name: Install npm packages
run: npm ci --no-audit
run: |
npm ci --no-audit
npm ci --no-audit --prefix cordova-plugin-moodleapp
- name: Check langindex
run: |
result=$(cat scripts/langindex.json | grep \"TBD\" | wc -l); test $result -eq 0
Expand Down Expand Up @@ -46,11 +48,15 @@ jobs:
echo "Found $found missing langkeys"
exit 1
fi
- name: Run Linter (ignore warnings)
run: npm run lint -- --quiet
- name: Run Linters (ignore warnings)
run: |
npm run lint -- --quiet
npm run lint --prefix cordova-plugin-moodleapp
- name: Run tests
run: npm run test:ci
- name: Production builds
run: npm run build:prod
run: |
npm run build:prod
npm run prod --prefix cordova-plugin-moodleapp
- name: JavaScript code compatibility
run: result=$(npx check-es-compat www/*.js 2> /dev/null | grep -v -E "Array\.prototype\.includes|Promise\.prototype\.finally|String\.prototype\.(matchAll|trimRight)|globalThis" | grep -Po "(?<=error).*?(?=\s+ecmascript)" | wc -l); test $result -eq 1
10 changes: 9 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,16 @@ FROM node:14 as build-stage

WORKDIR /app

# Prepare node dependencies
# Update platform dependencies
RUN apt-get update && apt-get install libsecret-1-0 -y

# Prepare native plugin
COPY ./cordova-plugin-moodleapp/package*.json /app/cordova-plugin-moodleapp/
RUN npm ci --prefix cordova-plugin-moodleapp
COPY ./cordova-plugin-moodleapp/ /app/cordova-plugin-moodleapp/
RUN npm run prod --prefix cordova-plugin-moodleapp

# Prepare node dependencies
COPY package*.json ./
COPY patches ./patches
RUN echo "unsafe-perm=true" > ./.npmrc
Expand Down
2 changes: 2 additions & 0 deletions cordova-plugin-moodleapp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
www
816 changes: 816 additions & 0 deletions cordova-plugin-moodleapp/package-lock.json

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions cordova-plugin-moodleapp/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "cordova-plugin-moodleapp",
"private": true,
"types": "./types/index.d.ts",
"version": "0.0.0",
"scripts": {
"dev": "concurrently \"npm run dev:ts\" \"npm run dev:cordova\"",
"dev:ts": "scripts/build.js --watch",
"dev:cordova": "chokidar www/index.js -c scripts/copy-javascript.js",
"prod": "NODE_ENV=production scripts/build.js",
"lint": "tsc --noEmit"
},
"devDependencies": {
"chokidar-cli": "^3.0.0",
"concurrently": "^8.2.0",
"esbuild": "^0.18.11",
"typescript": "^5.1.6"
}
}
16 changes: 16 additions & 0 deletions cordova-plugin-moodleapp/plugin.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" id="cordova-plugin-moodleapp" version="0.0.0">
<name>MoodleApp</name>
<description>Plugin with custom functionality for the Moodle App</description>
<js-module src="www/index.js" name="moodleapp">
<clobbers target="cordova.MoodleApp" />
</js-module>
<platform name="android">
<config-file target="res/xml/config.xml" parent="/*">
<feature name="SystemUI">
<param name="android-package" value="com.moodle.moodlemobile.SystemUI"/>
</feature>
</config-file>
<source-file src="src/android/SystemUI.java" target-dir="src/com/moodle/moodlemobile" />
</platform>
</plugin>
54 changes: 54 additions & 0 deletions cordova-plugin-moodleapp/scripts/build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env node

// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

const { readFileSync, writeFileSync } = require('fs');
const { resolve } = require('path');

function fixBundle() {
const bundlePath = resolve(__dirname, '../www/index.js');
const bundle = readFileSync(bundlePath).toString();

writeFileSync(bundlePath, bundle.replace('window.cordovaModule', 'module.exports'));
}

const options = {
entryPoints: [resolve(__dirname, '../src/ts/index.ts')],
tsconfig: resolve(__dirname, '../tsconfig.json'),
outdir: resolve(__dirname, '../www'),
minify: process.env.NODE_ENV === 'production',
bundle: true,
plugins: [{
name: 'moodleapp',
setup(build) {
build.onEnd(result => {
if (result.errors.length > 0) {
console.error('cordova-plugin-moodleapp build failed! ', result.errors);

return;
}

fixBundle();
console.log('cordova-plugin-moodleapp built');
});
},
}],
};

if (process.argv.includes('--watch')) {
require('esbuild').context(options).then(context => context.watch());
} else {
require('esbuild').build(options);
}
40 changes: 40 additions & 0 deletions cordova-plugin-moodleapp/scripts/copy-javascript.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env node

// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This script makes sure that javascript assets are kept up to date during development,
// otherwise it would be necessary to reinstall the plugin every time anything changes.

const { readFileSync, writeFileSync, existsSync } = require('fs');
const { resolve } = require('path');

const bundle = readFileSync(resolve(__dirname, '../www/index.js')).toString();
const template = readFileSync(resolve(__dirname, './templates/cordova-plugin.js')).toString();
const platformsPath = resolve(__dirname, '../../platforms/');
const filePaths = [
resolve(platformsPath, 'android/app/src/main/assets/www/plugins/cordova-plugin-moodleapp/www/index.js'),
resolve(platformsPath, 'android/platform_www/plugins/cordova-plugin-moodleapp/www/index.js'),
];
const pluginIndex = template
.replace('[[PLUGIN_NAME]]', 'cordova-plugin-moodleapp.moodleapp')
.replace('[[PLUGIN_CONTENTS]]', bundle);

for (const filePath of filePaths) {
if (!existsSync(filePath)) {
continue;
}

writeFileSync(filePath, pluginIndex);
}
3 changes: 3 additions & 0 deletions cordova-plugin-moodleapp/scripts/templates/cordova-plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
cordova.define("[[PLUGIN_NAME]]", function(require, exports, module) {
[[PLUGIN_CONTENTS]]
});
85 changes: 85 additions & 0 deletions cordova-plugin-moodleapp/src/android/SystemUI.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.moodle.moodlemobile;

import android.graphics.Color;
import android.os.Build;
import android.util.Log;
import android.view.Window;

import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CallbackContext;

import org.json.JSONArray;

public class SystemUI extends CordovaPlugin {

private static final String TAG = "SystemUI";

@Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
try {
switch (action) {
case "setNavigationBarColor":
this.setNavigationBarColor(args.getString(0));
callbackContext.success();

return true;
}
} catch (Throwable e) {
Log.e(TAG, "Failed executing action: " + action, e);
}

return false;
}

private void setNavigationBarColor(String color) {
if (Build.VERSION.SDK_INT < 21) {
return;
}

if (color == null || color.isEmpty()) {
return;
}

Log.d(TAG, "Setting navigation bar color to " + color);

this.cordova.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
final int FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000;
final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010;
final Window window = cordova.getActivity().getWindow();
int uiOptions = window.getDecorView().getSystemUiVisibility();

uiOptions = uiOptions | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
uiOptions = uiOptions & ~SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;

window.getDecorView().setSystemUiVisibility(uiOptions);

try {
// Using reflection makes sure any 5.0+ device will work without having to compile with SDK level 21
window.getClass().getDeclaredMethod("setNavigationBarColor", int.class).invoke(window, Color.parseColor(color));
} catch (IllegalArgumentException ignore) {
Log.e(TAG, "Invalid hexString argument, use f.i. '#999999'");
} catch (Exception ignore) {
// this should not happen, only in case Android removes this method in a version > 21
Log.w(TAG, "Method window.setNavigationBarColor not found for SDK level " + Build.VERSION.SDK_INT);
}
}
});
}

}
25 changes: 25 additions & 0 deletions cordova-plugin-moodleapp/src/ts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { SystemUI } from './plugins/SystemUI';

const api: MoodleAppPlugins = {
systemUI: new SystemUI(),
};

// This is necessary to work around the default transpilation behavior,
// which would wrap exported modules into UMD methods. Check out the
// fixBundle method in the /scripts/build.js file for more details.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(window as any).cordovaModule = api;
31 changes: 31 additions & 0 deletions cordova-plugin-moodleapp/src/ts/plugins/SystemUI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
* Manages system UI settings.
*/
export class SystemUI {

/**
* Set navigation bar color.
*
* @param color Color.
*/
async setNavigationBarColor(color: string): Promise<void> {
await new Promise((resolve, reject) => {
cordova.exec(resolve, reject, 'SystemUI', 'setNavigationBarColor', [color]);
});
}

}
16 changes: 16 additions & 0 deletions cordova-plugin-moodleapp/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"experimentalDecorators": true,
"baseUrl": "./"
},
"include": [
"src/ts/**/*.ts",
"types/**.d.ts"
]
}
27 changes: 27 additions & 0 deletions cordova-plugin-moodleapp/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { SystemUI } from '../src/ts/plugins/SystemUI';

declare global {

interface MoodleAppPlugins {
systemUI: SystemUI;
}

interface Cordova {
MoodleApp: MoodleAppPlugins; // eslint-disable-line @typescript-eslint/naming-convention
}

}
Loading

0 comments on commit a722e2c

Please sign in to comment.