Merge branch 'android_master' into combine

This commit is contained in:
pengfei.zhou 2019-12-21 21:35:28 +08:00
commit 55334a11b2
59 changed files with 1206 additions and 246 deletions

View File

@ -6,3 +6,6 @@
/build
/captures
.externalNativeBuild
.project
.classpath
.settings/

201
doric-android/LICENSE Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [2019] [Doric.Pub]
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.

3
doric-android/README.md Normal file
View File

@ -0,0 +1,3 @@
# Doric Android SDK
## Usages

View File

@ -23,7 +23,8 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation "com.google.android.material:material:1.0.0"
implementation project(':devkit')
implementation "pub.doric:core:${rootProject.ext.Version}"
implementation "pub.doric:devkit:${rootProject.ext.Version}"
implementation 'com.github.bumptech.glide:glide:4.10.0'
implementation 'com.github.bumptech.glide:annotations:4.10.0'
implementation 'com.github.penfeizhou.android.animation:glide-plugin:1.3.1'

View File

@ -21,15 +21,6 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".DemoActivity"
android:theme="@style/Theme.Design.Light.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -1 +0,0 @@
../../../../../demo/bundle/src

View File

@ -0,0 +1 @@
*.js

View File

@ -33,7 +33,6 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import pub.doric.DoricActivity;
import pub.doric.devkit.ui.DemoDebugActivity;
import pub.doric.refresh.DoricSwipeLayout;
import pub.doric.utils.DoricUtils;
@ -63,7 +62,6 @@ public class MainActivity extends AppCompatActivity {
try {
String[] demos = getAssets().list("demo");
List<String> ret = new ArrayList<>();
ret.add("Test");
for (String str : demos) {
if (str.endsWith("js")) {
ret.add(str);
@ -107,20 +105,9 @@ public class MainActivity extends AppCompatActivity {
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (data[position].contains("Test")) {
Intent intent = new Intent(tv.getContext(), PullableActivity.class);
tv.getContext().startActivity(intent);
return;
}
if (data[position].contains("NavigatorDemo")) {
Intent intent = new Intent(tv.getContext(), DoricActivity.class);
intent.putExtra("scheme", "assets://demo/" + data[position]);
intent.putExtra("alias", data[position]);
tv.getContext().startActivity(intent);
return;
}
Intent intent = new Intent(tv.getContext(), DemoDebugActivity.class);
intent.putExtra("source", data[position]);
intent.putExtra("scheme", "assets://demo/" + data[position]);
intent.putExtra("alias", data[position]);
tv.getContext().startActivity(intent);
}
});

View File

@ -7,7 +7,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.2'
classpath 'com.android.tools.build:gradle:3.5.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
@ -23,8 +23,41 @@ allprojects {
}
maven { url 'https://jitpack.io' }
}
def needReplaceLocal = true
gradle.startParameter.taskNames.each {
if (it.contains('uploadArchives')) {
needReplaceLocal = false
}
}
if (needReplaceLocal) {
configurations.all {
resolutionStrategy {
dependencySubstitution {
substitute module('pub.doric:core') with project(":doric")
substitute module('pub.doric:devkit') with project(":devkit")
}
}
}
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
Properties properties = new Properties()
properties.load(project.rootProject.file('version.properties').newDataInputStream())
ext {
Version = properties.version
}
task publisCore dependsOn(":doric:uploadArchives") {
println "doric published"
}
task publishDevKit dependsOn(publisCore, ":devkit:uploadArchives") {
println "devkit published"
}
task PublishAll dependsOn(publisCore, publishDevKit) {
println "All published"
}

View File

@ -1,7 +1,5 @@
apply plugin: 'com.android.library'
def projectHome = project.rootDir.getParent() + "/demo"
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
@ -22,10 +20,6 @@ android {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
buildConfigField "String", "PROJECT_HOME", "\"${projectHome}\""
}
}
}
@ -33,7 +27,7 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.github.pengfeizhou:jsc4a:0.1.0'
implementation "pub.doric:core:${rootProject.ext.Version}"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation "com.google.android.material:material:1.0.0"
implementation 'com.squareup.okhttp3:okhttp:4.2.2'
@ -42,11 +36,10 @@ dependencies {
implementation 'com.github.tbruyelle:rxpermissions:0.10.2'
implementation "io.reactivex.rxjava2:rxjava:2.2.15"
api 'org.greenrobot:eventbus:3.1.1'
implementation 'com.lahm.library:easy-protector-release:1.1.0'
api 'org.nanohttpd:nanohttpd:2.3.1'
api project(':doric')
implementation 'com.lahm.library:easy-protector-release:1.1.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
apply from: rootProject.file('scripts/upload.gradle')

View File

@ -0,0 +1,3 @@
name=DoricDevKit
groupId=pub.doric
artifactId=devkit

View File

@ -2,9 +2,12 @@
package="pub.doric.devkit">
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<application>
<activity android:name=".ui.ScanQRCodeActivity" />
<activity android:name=".ui.DemoDebugActivity" />
<activity
android:name=".ui.DemoDebugActivity"
android:theme="@style/Theme.Design.Light.NoActionBar" />
</application>
</manifest>

View File

@ -1,14 +1,17 @@
package pub.doric.devkit;
import pub.doric.DoricContext;
import pub.doric.DoricContextManager;
import pub.doric.DoricNativeDriver;
public class DoricContextDebuggable {
private DoricContext doricContext;
private DoricDebugDriver doricDebugDriver;
public boolean isDebugging = false;
public DoricContextDebuggable(DoricContext doricContext) {
this.doricContext = doricContext;
public DoricContextDebuggable(String contextId) {
this.doricContext = DoricContextManager.getContext(contextId);
isDebugging = true;
}
public void startDebug() {
@ -22,8 +25,13 @@ public class DoricContextDebuggable {
}
public void stopDebug() {
isDebugging = false;
doricDebugDriver.destroy();
doricContext.setDriver(DoricNativeDriver.getInstance());
doricContext.reInit();
}
public DoricContext getContext() {
return doricContext;
}
}

View File

@ -79,6 +79,7 @@ public class WSClient extends WebSocketListener {
}
break;
case "SWITCH_TO_DEBUG": {
String contextId = jsonObject.optString("contextId");
EventBus.getDefault().post(new EnterDebugEvent());
}
break;

View File

@ -1,4 +1,5 @@
package pub.doric.devkit.event;
public class EnterDebugEvent {
}

View File

@ -0,0 +1,13 @@
package pub.doric.devkit.event;
public class StartDebugEvent {
private String contextId;
public StartDebugEvent(String contextId) {
this.contextId = contextId;
}
public String getContextId() {
return contextId;
}
}

View File

@ -0,0 +1,5 @@
package pub.doric.devkit.event;
public class StopDebugEvent {
}

View File

@ -25,7 +25,7 @@ import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import pub.doric.devkit.DevKit;
import pub.doric.devkit.IStatusCallback;
import pub.doric.devkit.event.QuitDebugEvent;
import pub.doric.devkit.event.StopDebugEvent;
public class RemoteJSExecutor {
private final WebSocket webSocket;
@ -59,7 +59,7 @@ public class RemoteJSExecutor {
System.out.println("remote js executor eof");
LockSupport.unpark(current);
EventBus.getDefault().post(new QuitDebugEvent());
EventBus.getDefault().post(new StopDebugEvent());
}
}

View File

@ -15,12 +15,14 @@ import androidx.fragment.app.DialogFragment;
import com.google.gson.JsonObject;
import org.greenrobot.eventbus.EventBus;
import pub.doric.DoricContext;
import pub.doric.DoricContextManager;
import pub.doric.devkit.BuildConfig;
import pub.doric.devkit.DoricDev;
import pub.doric.devkit.IDevKit;
import pub.doric.devkit.R;
import pub.doric.devkit.event.StartDebugEvent;
public class DebugContextPanel extends DialogFragment {
@ -69,9 +71,9 @@ public class DebugContextPanel extends DialogFragment {
cell.findViewById(R.id.debug_text_view).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EventBus.getDefault().post(new StartDebugEvent(doricContext.getContextId()));
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("contextId", doricContext.getContextId());
jsonObject.addProperty("projectHome", BuildConfig.PROJECT_HOME);
jsonObject.addProperty("source", doricContext.getSource().replace(".js", ".ts"));
DoricDev.sendDevCommand(IDevKit.Command.DEBUG, jsonObject);
dismissAllowingStateLoss();

View File

@ -17,46 +17,36 @@ package pub.doric.devkit.ui;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import pub.doric.DoricActivity;
import pub.doric.DoricContext;
import pub.doric.DoricContextManager;
import pub.doric.DoricPanel;
import pub.doric.devkit.DoricContextDebuggable;
import pub.doric.devkit.event.EnterDebugEvent;
import pub.doric.devkit.event.QuitDebugEvent;
import pub.doric.devkit.event.ReloadEvent;
import pub.doric.devkit.event.StartDebugEvent;
import pub.doric.devkit.event.StopDebugEvent;
import pub.doric.devkit.util.SensorManagerHelper;
import pub.doric.utils.DoricUtils;
/**
* @Description: pub.doric.demo
* @Author: pengfei.zhou
* @CreateDate: 2019-11-19
*/
public class DemoDebugActivity extends AppCompatActivity {
private DoricContext doricContext;
public class DemoDebugActivity extends DoricActivity {
private SensorManagerHelper sensorHelper;
private DoricContextDebuggable doricContextDebuggable;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String source = getIntent().getStringExtra("source");
DoricPanel doricPanel = new DoricPanel(this);
addContentView(doricPanel, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
doricPanel.config(DoricUtils.readAssetFile("demo/" + source), source);
doricContext = doricPanel.getDoricContext();
doricContextDebuggable = new DoricContextDebuggable(doricContext);
sensorHelper = new SensorManagerHelper(this);
sensorHelper.setOnShakeListener(new SensorManagerHelper.OnShakeListener() {
@Override
@ -73,34 +63,49 @@ public class DemoDebugActivity extends AppCompatActivity {
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
EventBus.getDefault().register(this);
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
EventBus.getDefault().unregister(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
sensorHelper.stop();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onStartDebugEvent(StartDebugEvent startDebugEvent) {
doricContextDebuggable = new DoricContextDebuggable(startDebugEvent.getContextId());
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEnterDebugEvent(EnterDebugEvent enterDebugEvent) {
doricContextDebuggable.startDebug();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onReloadEvent(ReloadEvent reloadEvent) {
for (DoricContext context : DoricContextManager.aliveContexts()) {
if (reloadEvent.source.contains(context.getSource())) {
context.reload(reloadEvent.script);
}
}
public void onQuitDebugEvent(StopDebugEvent quitDebugEvent) {
doricContextDebuggable.stopDebug();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onQuitDebugEvent(QuitDebugEvent quitDebugEvent) {
doricContextDebuggable.stopDebug();
public void onReloadEvent(ReloadEvent reloadEvent) {
for (DoricContext context : DoricContextManager.aliveContexts()) {
if (reloadEvent.source.contains(context.getSource())) {
if (doricContextDebuggable != null &&
doricContextDebuggable.isDebugging &&
doricContextDebuggable.getContext().getContextId().equals(context.getContextId())) {
System.out.println("is debugging context id: " + context.getContextId());
} else {
context.reload(reloadEvent.script);
}
}
}
}
@Override

View File

@ -25,35 +25,31 @@ android {
afterEvaluate {
buildJSBundle.exec()
buildDemo.exec()
//buildDebugger.exec()
}
task buildJSBundle(type: Exec) {
workingDir project.rootDir.getParent() + "/js-framework"
commandLine 'npm', 'run', 'build'
commandLine 'sh', project.rootDir.getParent() + "/bundle.sh"
}
task buildDemo(type: Exec) {
workingDir project.rootDir.getParent() + "/demo"
commandLine 'npm', 'run', 'build'
}
task buildDebugger(type: Exec) {
workingDir project.rootDir.getParent() + "/debugger"
commandLine 'npm', 'run', 'build'
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
api 'com.github.pengfeizhou:jsc4a:0.1.0'
api 'com.github.penfeizhou:jsc4a:0.1.0'
implementation 'com.squareup.okhttp3:okhttp:4.2.2'
implementation 'com.github.penfeizhou.android.animation:glide-plugin:1.3.1'
implementation 'jp.wasabeef:glide-transformations:4.1.0'
implementation 'com.google.code.gson:gson:2.8.6'
implementation "com.google.android.material:material:1.0.0"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
def nav_version = "2.1.0"
implementation "androidx.navigation:navigation-fragment:$nav_version"
implementation "androidx.navigation:navigation-ui:$nav_version"
}
apply from: rootProject.file('scripts/upload.gradle')

View File

@ -0,0 +1,4 @@
name=Doric
groupId=pub.doric
artifactId=core
version=0.1.0

View File

@ -1,7 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="pub.doric">
<uses-permission android:name="android.permission.CAMERA" />
<application>
<activity

View File

@ -1 +0,0 @@
../../../../../js-framework/bundle

View File

@ -0,0 +1 @@
*.js

View File

@ -26,8 +26,6 @@ import androidx.appcompat.app.AppCompatActivity;
* @CreateDate: 2019-11-19
*/
public class DoricActivity extends AppCompatActivity {
private DoricFragment doricFragment;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -35,19 +33,10 @@ public class DoricActivity extends AppCompatActivity {
if (savedInstanceState == null) {
String scheme = getIntent().getStringExtra("scheme");
String alias = getIntent().getStringExtra("alias");
doricFragment = DoricFragment.newInstance(scheme, alias);
DoricFragment doricFragment = DoricFragment.newInstance(scheme, alias);
getSupportFragmentManager().beginTransaction()
.add(R.id.container, doricFragment)
.commit();
}
}
@Override
public void onBackPressed() {
if (doricFragment.canPop()) {
doricFragment.pop();
} else {
super.onBackPressed();
}
}
}

View File

@ -15,7 +15,6 @@
*/
package pub.doric;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.content.Context;
@ -49,6 +48,7 @@ public class DoricContext {
private RootNode mRootNode = new RootNode(this);
private final String source;
private String script;
private String extra;
private JSONObject initParams;
private IDoricDriver doricDriver;
private final Map<String, ViewNode> mHeadNodes = new HashMap<>();
@ -72,10 +72,11 @@ public class DoricContext {
return mHeadNodes.get(id);
}
protected DoricContext(Context context, String contextId, String source) {
protected DoricContext(Context context, String contextId, String source, String extra) {
this.mContext = context;
this.mContextId = contextId;
this.source = source;
this.extra = extra;
}
public String getSource() {
@ -86,22 +87,25 @@ public class DoricContext {
return script;
}
public static DoricContext create(Context context, String script, String source) {
DoricContext doricContext = DoricContextManager.getInstance().createContext(context, script, source);
public static DoricContext create(Context context, String script, String source, String extra) {
DoricContext doricContext = DoricContextManager.getInstance().createContext(context, script, source, extra);
doricContext.script = script;
doricContext.extra = extra;
return doricContext;
}
public void init(float width, float height) {
this.initParams = new JSONBuilder()
.put("width", width)
.put("height", height).toJSONObject();
callEntity(DoricConstant.DORIC_ENTITY_INIT, this.initParams);
.put("height", height)
.toJSONObject();
callEntity(DoricConstant.DORIC_ENTITY_INIT, this.initParams, extra);
callEntity(DoricConstant.DORIC_ENTITY_CREATE);
}
public void reInit() {
callEntity(DoricConstant.DORIC_ENTITY_INIT, this.initParams);
this.mRootNode.setId("");
callEntity(DoricConstant.DORIC_ENTITY_INIT, this.initParams, extra);
callEntity(DoricConstant.DORIC_ENTITY_CREATE);
}
@ -165,7 +169,8 @@ public class DoricContext {
this.script = script;
this.mRootNode.setId("");
getDriver().createContext(mContextId, script, source);
callEntity(DoricConstant.DORIC_ENTITY_INIT, this.initParams);
callEntity(DoricConstant.DORIC_ENTITY_INIT, this.initParams, extra);
onShow();
}
public void onShow() {

View File

@ -48,9 +48,9 @@ public class DoricContextManager {
return Inner.sInstance;
}
DoricContext createContext(Context context, final String script, final String source) {
DoricContext createContext(Context context, final String script, final String source, String extra) {
final String contextId = String.valueOf(counter.incrementAndGet());
final DoricContext doricContext = new DoricContext(context, contextId, source);
final DoricContext doricContext = new DoricContext(context, contextId, source, extra);
doricContextMap.put(contextId, doricContext);
doricContext.getDriver().createContext(contextId, script, source);
return doricContext;

View File

@ -20,18 +20,19 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import pub.doric.navigator.IDoricNavigator;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
/**
* @Description: pub.doric
* @Author: pengfei.zhou
* @CreateDate: 2019-11-23
*/
public class DoricFragment extends Fragment implements IDoricNavigator {
public class DoricFragment extends Fragment {
public static DoricFragment newInstance(String scheme, String alias) {
Bundle args = new Bundle();
@ -42,6 +43,23 @@ public class DoricFragment extends Fragment implements IDoricNavigator {
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
OnBackPressedCallback callback = new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host);
if (!navController.popBackStack()) {
if (getActivity() != null) {
getActivity().finish();
}
}
}
};
requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
@ -51,34 +69,6 @@ public class DoricFragment extends Fragment implements IDoricNavigator {
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Bundle argument = getArguments();
if (argument != null) {
String alias = argument.getString("alias");
String scheme = argument.getString("scheme");
push(scheme, alias);
}
}
@Override
public void push(String scheme, String alias) {
getChildFragmentManager().beginTransaction()
.add(R.id.root, DoricPanelFragment.newInstance(scheme, alias))
.addToBackStack(scheme)
.commit();
}
@Override
public void pop() {
if (canPop()) {
getChildFragmentManager().popBackStack();
} else {
if (getActivity() != null) {
getActivity().finish();
}
}
}
public boolean canPop() {
return getChildFragmentManager().getBackStackEntryCount() > 1;
}
}

View File

@ -54,8 +54,8 @@ public class DoricPanel extends FrameLayout implements LifecycleObserver {
}
public void config(String script, String alias) {
DoricContext doricContext = DoricContext.create(getContext(), script, alias);
public void config(String script, String alias, String extra) {
DoricContext doricContext = DoricContext.create(getContext(), script, alias, extra);
config(doricContext);
}

View File

@ -23,6 +23,8 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import pub.doric.async.AsyncResult;
import pub.doric.loader.DoricJSLoaderManager;
@ -35,18 +37,8 @@ import pub.doric.utils.DoricLog;
* @Author: pengfei.zhou
* @CreateDate: 2019-11-23
*/
public class DoricPanelFragment extends Fragment {
public class DoricPanelFragment extends Fragment implements IDoricNavigator {
private DoricPanel doricPanel;
private BaseDoricNavBar navBar;
public static DoricPanelFragment newInstance(String scheme, String alias) {
Bundle args = new Bundle();
args.putString("scheme", scheme);
args.putString("alias", alias);
DoricPanelFragment fragment = new DoricPanelFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
@ -58,23 +50,26 @@ public class DoricPanelFragment extends Fragment {
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
doricPanel = view.findViewById(R.id.doric_panel);
navBar = view.findViewById(R.id.doric_nav_bar);
Bundle argument = getArguments();
if (argument == null) {
if (getActivity() != null && getActivity().getIntent() != null) {
argument = getActivity().getIntent().getExtras();
}
}
if (argument == null) {
DoricLog.e("DoricPanelFragment argument is null");
return;
}
final String alias = argument.getString("alias");
String scheme = argument.getString("scheme");
final String extra = argument.getString("extra");
DoricJSLoaderManager.getInstance().loadJSBundle(scheme).setCallback(new AsyncResult.Callback<String>() {
@Override
public void onResult(String result) {
doricPanel.config(result, alias);
doricPanel.config(result, alias, extra);
DoricContext context = doricPanel.getDoricContext();
Fragment fragment = getParentFragment();
if (fragment instanceof IDoricNavigator) {
context.setDoricNavigator((IDoricNavigator) fragment);
}
context.setDoricNavigator(DoricPanelFragment.this);
BaseDoricNavBar navBar = requireActivity().getWindow().getDecorView().findViewById(R.id.doric_nav_bar);
context.setDoricNavBar(navBar);
}
@ -89,4 +84,41 @@ public class DoricPanelFragment extends Fragment {
}
});
}
@Override
public void push(String scheme, String alias, String extra) {
Bundle argument = new Bundle();
argument.putString("scheme", scheme);
argument.putString("alias", alias);
argument.putString("extra", extra);
getNavController()
.navigate(R.id.action_doricPanelFragment_to_doricPanelFragment, argument);
}
@Override
public void pop() {
getNavController().popBackStack();
}
private NavController getNavController() {
return Navigation.findNavController(getView());
}
@Override
public void onResume() {
super.onResume();
doricPanel.onActivityResume();
}
@Override
public void onPause() {
super.onPause();
doricPanel.onActivityPause();
}
@Override
public void onDestroy() {
super.onDestroy();
doricPanel.onActivityDestroy();
}
}

View File

@ -30,6 +30,7 @@ import pub.doric.plugin.StoragePlugin;
import pub.doric.refresh.RefreshableNode;
import pub.doric.shader.HLayoutNode;
import pub.doric.shader.ImageNode;
import pub.doric.shader.InputNode;
import pub.doric.shader.ScrollerNode;
import pub.doric.shader.flowlayout.FlowLayoutItemNode;
import pub.doric.shader.flowlayout.FlowLayoutNode;
@ -40,6 +41,7 @@ import pub.doric.shader.StackNode;
import pub.doric.shader.TextNode;
import pub.doric.shader.VLayoutNode;
import pub.doric.shader.ViewNode;
import pub.doric.shader.slider.NestedSliderNode;
import pub.doric.shader.slider.SlideItemNode;
import pub.doric.shader.slider.SliderNode;
import pub.doric.utils.DoricMetaInfo;
@ -106,6 +108,8 @@ public class DoricRegistry {
this.registerViewNode(RefreshableNode.class);
this.registerViewNode(FlowLayoutNode.class);
this.registerViewNode(FlowLayoutItemNode.class);
this.registerViewNode(InputNode.class);
this.registerViewNode(NestedSliderNode.class);
initRegistry(this);
}

View File

@ -15,6 +15,9 @@
*/
package pub.doric.engine;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
@ -22,11 +25,13 @@ import android.os.Message;
import android.text.TextUtils;
import com.github.pengfeizhou.jscore.JSDecoder;
import com.github.pengfeizhou.jscore.JSONBuilder;
import com.github.pengfeizhou.jscore.JavaFunction;
import com.github.pengfeizhou.jscore.JavaValue;
import java.util.ArrayList;
import pub.doric.Doric;
import pub.doric.DoricRegistry;
import pub.doric.extension.bridge.DoricBridgeExtension;
import pub.doric.extension.timer.DoricTimerExtension;
@ -73,6 +78,27 @@ public class DoricJSEngine implements Handler.Callback, DoricTimerExtension.Time
}
private void injectGlobal() {
String appName = "";
String appVersion = "";
Context context = Doric.application();
try {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(
context.getPackageName(), 0);
int labelRes = packageInfo.applicationInfo.labelRes;
appName = context.getResources().getString(labelRes);
appVersion = packageInfo.versionName;
} catch (Exception e) {
e.printStackTrace();
}
mDoricJSE.injectGlobalJSObject(DoricConstant.INJECT_ENVIRONMENT, new JavaValue(new JSONBuilder()
.put("platform", "Android")
.put("platformVersion", String.valueOf(android.os.Build.VERSION.SDK_INT))
.put("appName", appName)
.put("appVersion", appVersion)
.put("screenWidth", DoricUtils.px2dp(DoricUtils.getScreenWidth()))
.put("screenHeight", DoricUtils.px2dp(DoricUtils.getScreenHeight()))
.toJSONObject()));
mDoricJSE.injectGlobalJSFunction(DoricConstant.INJECT_LOG, new JavaFunction() {
@Override
public JavaValue exec(JSDecoder[] args) {

View File

@ -21,7 +21,7 @@ package pub.doric.navigator;
* @CreateDate: 2019-11-23
*/
public interface IDoricNavigator {
void push(String scheme, String alias);
void push(String scheme, String alias, String extra);
void pop();
}

View File

@ -61,13 +61,6 @@ public class NavBarPlugin extends DoricJavaPlugin {
JSObject jsObject = jsDecoder.decode().asObject();
boolean hidden = jsObject.getProperty("hidden").asBoolean().value();
navBar.setHidden(hidden);
View v = getDoricContext().getRootNode().getNodeView();
ViewGroup.LayoutParams params = v.getLayoutParams();
if (params instanceof ViewGroup.MarginLayoutParams) {
((ViewGroup.MarginLayoutParams) params).topMargin =
hidden ? 0
: ((View) navBar).getMeasuredHeight();
}
promise.resolve();
} catch (ArchiveException e) {
e.printStackTrace();

View File

@ -18,10 +18,14 @@ package pub.doric.plugin;
import com.github.pengfeizhou.jscore.ArchiveException;
import com.github.pengfeizhou.jscore.JSDecoder;
import com.github.pengfeizhou.jscore.JSObject;
import com.github.pengfeizhou.jscore.JSValue;
import com.github.pengfeizhou.jscore.JavaValue;
import pub.doric.Doric;
import pub.doric.DoricContext;
import pub.doric.extension.bridge.DoricMethod;
import pub.doric.extension.bridge.DoricPlugin;
import pub.doric.extension.bridge.DoricPromise;
import pub.doric.navigator.IDoricNavigator;
import pub.doric.utils.ThreadMode;
@ -37,25 +41,47 @@ public class NavigatorPlugin extends DoricJavaPlugin {
}
@DoricMethod(thread = ThreadMode.UI)
public void push(JSDecoder jsDecoder) {
public void push(JSDecoder jsDecoder, DoricPromise promise) {
IDoricNavigator navigator = getDoricContext().getDoricNavigator();
if (navigator != null) {
try {
JSObject jsObject = jsDecoder.decode().asObject();
String scheme = jsObject.getProperty("scheme").asString().value();
String alias = scheme;
String extra = "";
JSValue config = jsObject.getProperty("config");
if (config.isObject()) {
JSValue aliasJS = config.asObject().getProperty("alias");
if (aliasJS.isString()) {
alias = aliasJS.asString().value();
}
JSValue extraJS = config.asObject().getProperty("extra");
if (extraJS.isString()) {
extra = extraJS.asString().value();
}
}
navigator.push(jsObject.getProperty("scheme").asString().value(),
jsObject.getProperty("alias").asString().value()
alias,
extra
);
promise.resolve();
} catch (ArchiveException e) {
e.printStackTrace();
promise.reject(new JavaValue(e.getLocalizedMessage()));
}
} else {
promise.reject(new JavaValue("Navigator not implemented"));
}
}
@DoricMethod(thread = ThreadMode.UI)
public void pop() {
public void pop(DoricPromise promise) {
IDoricNavigator navigator = getDoricContext().getDoricNavigator();
if (navigator != null) {
navigator.pop();
promise.resolve();
} else {
promise.reject(new JavaValue("Navigator not implemented"));
}
}
}

View File

@ -17,7 +17,6 @@ package pub.doric.plugin;
import android.text.TextUtils;
import com.github.pengfeizhou.jscore.JSDecoder;
import com.github.pengfeizhou.jscore.JSONBuilder;
import com.github.pengfeizhou.jscore.JSObject;
import com.github.pengfeizhou.jscore.JSValue;
@ -51,7 +50,8 @@ import pub.doric.extension.bridge.DoricPromise;
*/
@DoricPlugin(name = "network")
public class NetworkPlugin extends DoricJavaPlugin {
private OkHttpClient okHttpClient = new OkHttpClient();
private OkHttpClient okHttpClient = new OkHttpClient.Builder()
.build();
public NetworkPlugin(DoricContext doricContext) {
super(doricContext);
@ -79,9 +79,10 @@ public class NetworkPlugin extends DoricJavaPlugin {
MediaType mediaType = MediaType.parse(TextUtils.isEmpty(contentType) ? "application/json; charset=utf-8" : contentType);
RequestBody requestBody = HttpMethod.permitsRequestBody(method) ? RequestBody.create(mediaType, dataVal.isString() ? dataVal.asString().value() : "") : null;
Request.Builder requestBuilder = new Request.Builder();
requestBuilder.url(url)
.headers(headers)
.method(method, requestBody);
requestBuilder = requestBuilder.url(url).headers(headers);
if (HttpMethod.permitsRequestBody(method.toUpperCase())) {
requestBuilder = requestBuilder.method(method, requestBody);
}
if (timeoutVal.isNumber() && okHttpClient.connectTimeoutMillis() != timeoutVal.asNumber().toLong()) {
okHttpClient = okHttpClient.newBuilder().connectTimeout(timeoutVal.asNumber().toLong(), TimeUnit.MILLISECONDS).build();
}

View File

@ -31,8 +31,8 @@ import java.util.ArrayList;
* @CreateDate: 2019-07-20
*/
public abstract class GroupNode<F extends ViewGroup> extends SuperNode<F> {
private ArrayList<ViewNode> mChildNodes = new ArrayList<>();
private ArrayList<String> mChildViewIds = new ArrayList<>();
protected ArrayList<ViewNode> mChildNodes = new ArrayList<>();
protected ArrayList<String> mChildViewIds = new ArrayList<>();
public GroupNode(DoricContext doricContext) {
super(doricContext);
@ -57,7 +57,7 @@ public abstract class GroupNode<F extends ViewGroup> extends SuperNode<F> {
configChildNode();
}
private void configChildNode() {
protected void configChildNode() {
for (int idx = 0; idx < mChildViewIds.size(); idx++) {
String id = mChildViewIds.get(idx);
JSObject model = getSubModel(id);

View File

@ -17,11 +17,7 @@ package pub.doric.shader;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import androidx.annotation.Nullable;
import android.text.TextUtils;
import android.util.Base64;
import android.widget.ImageView;
@ -30,18 +26,21 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
import pub.doric.DoricContext;
import pub.doric.extension.bridge.DoricPlugin;
import pub.doric.utils.DoricUtils;
import com.github.pengfeizhou.jscore.JSONBuilder;
import com.github.pengfeizhou.jscore.JSObject;
import com.github.pengfeizhou.jscore.JSValue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import androidx.annotation.Nullable;
import jp.wasabeef.glide.transformations.BlurTransformation;
import pub.doric.DoricContext;
import pub.doric.extension.bridge.DoricPlugin;
import pub.doric.utils.DoricUtils;
/**
* @Description: com.github.penfeizhou.doric.widget
* @Author: pengfei.zhou
@ -50,6 +49,7 @@ import java.util.regex.Pattern;
@DoricPlugin(name = "Image")
public class ImageNode extends ViewNode<ImageView> {
private String loadCallbackId = "";
private boolean isBlur;
public ImageNode(DoricContext doricContext) {
super(doricContext);
@ -60,11 +60,29 @@ public class ImageNode extends ViewNode<ImageView> {
return new ImageView(getContext());
}
@Override
public void blend(JSObject jsObject) {
if(jsObject != null) {
JSValue jsValue = jsObject.getProperty("isBlur");
if(jsValue.isBoolean()) {
isBlur = jsValue.asBoolean().value();
}
}
super.blend(jsObject);
}
@Override
protected void blend(ImageView view, String name, JSValue prop) {
switch (name) {
case "imageUrl":
RequestOptions options;
if(isBlur) {
options = RequestOptions.bitmapTransform(new BlurTransformation(25, 3));
} else {
options = new RequestOptions();
}
Glide.with(getContext()).load(prop.asString().value())
.apply(options)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {

View File

@ -0,0 +1,153 @@
/*
* Copyright [2019] [Doric.Pub]
*
* 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 pub.doric.shader;
import android.text.Editable;
import android.text.InputType;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.widget.EditText;
import com.github.pengfeizhou.jscore.JSObject;
import com.github.pengfeizhou.jscore.JSValue;
import pub.doric.DoricContext;
import pub.doric.extension.bridge.DoricMethod;
import pub.doric.extension.bridge.DoricPlugin;
import pub.doric.extension.bridge.DoricPromise;
/**
* @Description: pub.doric.shader
* @Author: pengfei.zhou
* @CreateDate: 2019-12-06
*/
@DoricPlugin(name = "Input")
public class InputNode extends ViewNode<EditText> implements TextWatcher, View.OnFocusChangeListener {
private String onTextChangeId;
private String onFocusChangeId;
public InputNode(DoricContext doricContext) {
super(doricContext);
}
@Override
protected EditText build() {
EditText editText = new EditText(getContext());
editText.addTextChangedListener(this);
editText.setOnFocusChangeListener(this);
return editText;
}
@Override
protected void blend(EditText view, String name, JSValue prop) {
switch (name) {
case "text":
view.setText(prop.asString().toString());
break;
case "textSize":
view.setTextSize(TypedValue.COMPLEX_UNIT_DIP, prop.asNumber().toFloat());
break;
case "textColor":
view.setTextColor(prop.asNumber().toInt());
break;
case "textAlignment":
view.setGravity(prop.asNumber().toInt() | Gravity.CENTER_VERTICAL);
break;
case "hintText":
view.setHint(prop.asString().toString());
break;
case "hintTextColor":
view.setHintTextColor(prop.asNumber().toInt());
break;
case "multiline":
if (prop.asBoolean().value()) {
view.setInputType(view.getInputType() | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
} else {
view.setInputType(view.getInputType() & ~InputType.TYPE_TEXT_FLAG_MULTI_LINE);
}
break;
case "onTextChange":
if (prop.isString()) {
onTextChangeId = prop.asString().value();
} else {
onTextChangeId = null;
}
break;
case "onFocusChange":
if (prop.isString()) {
onFocusChangeId = prop.asString().value();
} else {
onFocusChangeId = null;
}
break;
default:
super.blend(view, name, prop);
break;
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (!TextUtils.isEmpty(onTextChangeId)) {
callJSResponse(onTextChangeId, s.toString());
}
}
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!TextUtils.isEmpty(onFocusChangeId)) {
callJSResponse(onFocusChangeId, hasFocus);
}
}
@DoricMethod
public String getText() {
return mView.getText().toString();
}
@DoricMethod
public void setSelection(JSObject jsObject, DoricPromise doricPromise) {
int start = jsObject.getProperty("start").asNumber().toInt();
int end = jsObject.getProperty("end").asNumber().toInt();
mView.setSelection(start, end);
doricPromise.resolve();
}
@DoricMethod
public void requestFocus(DoricPromise promise) {
mView.requestFocus();
promise.resolve();
}
@DoricMethod
public void releaseFocus(DoricPromise promise) {
mView.clearFocus();
promise.resolve();
}
}

View File

@ -85,6 +85,10 @@ public abstract class SuperNode<V extends View> extends ViewNode<V> {
subNodes.clear();
}
public void removeSubModel(String id) {
subNodes.remove(id);
}
protected abstract void blendSubNode(JSObject subProperties);
protected void blendSubLayoutConfig(ViewNode viewNode, JSObject jsObject) {

View File

@ -39,6 +39,7 @@ public class TextNode extends ViewNode<TextView> {
protected TextView build() {
TextView tv = new TextView(getContext());
tv.setGravity(Gravity.CENTER);
tv.setMaxLines(1);
return tv;
}
@ -57,7 +58,8 @@ public class TextNode extends ViewNode<TextView> {
case "textAlignment":
view.setGravity(prop.asNumber().toInt() | Gravity.CENTER_VERTICAL);
break;
case "numberOfLines":
case "maxLines":
view.setMaxLines(prop.asNumber().toInt());
break;
default:
super.blend(view, name, prop);

View File

@ -37,6 +37,7 @@ import androidx.annotation.NonNull;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
import androidx.interpolator.view.animation.LinearOutSlowInInterpolator;
import pub.doric.Doric;
import pub.doric.DoricContext;
import pub.doric.DoricRegistry;
import pub.doric.async.AsyncResult;
@ -55,6 +56,8 @@ import com.github.pengfeizhou.jscore.JSObject;
import com.github.pengfeizhou.jscore.JSValue;
import com.github.pengfeizhou.jscore.JavaValue;
import org.json.JSONObject;
import java.util.LinkedList;
/**
@ -214,6 +217,7 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
if (prop.isObject()) {
requireDoricLayer().setBorder(DoricUtils.dp2px(prop.asObject().getProperty("width").asNumber().toFloat()),
prop.asObject().getProperty("color").asNumber().toInt());
requireDoricLayer().invalidate();
}
break;
case "alpha":
@ -339,6 +343,16 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
setRotation(prop.asNumber().toFloat());
}
break;
case "padding":
if (prop.isObject()) {
setPadding(prop.asObject());
}
break;
case "hidden":
if (prop.isBoolean()) {
getNodeView().setVisibility(prop.asBoolean().value() ? View.GONE : View.VISIBLE);
}
break;
default:
break;
}
@ -409,6 +423,19 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
}
}
protected void setPadding(JSObject paddings) {
JSValue left = paddings.getProperty("left");
JSValue right = paddings.getProperty("right");
JSValue top = paddings.getProperty("top");
JSValue bottom = paddings.getProperty("bottom");
mView.setPadding(
left.isNumber() ? DoricUtils.dp2px(left.asNumber().toFloat()) : 0,
top.isNumber() ? DoricUtils.dp2px(top.asNumber().toFloat()) : 0,
right.isNumber() ? DoricUtils.dp2px(right.asNumber().toFloat()) : 0,
bottom.isNumber() ? DoricUtils.dp2px(bottom.asNumber().toFloat()) : 0
);
}
private void blendLayoutConfig(JSObject jsObject) {
JSValue margin = jsObject.getProperty("margin");
JSValue widthSpec = jsObject.getProperty("widthSpec");
@ -478,7 +505,7 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
if (mLayoutParams.width >= 0) {
return DoricUtils.px2dp(mLayoutParams.width);
} else {
return mView.getMeasuredWidth();
return DoricUtils.px2dp(mView.getMeasuredWidth());
}
}
@ -487,7 +514,7 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
if (mLayoutParams.width >= 0) {
return DoricUtils.px2dp(mLayoutParams.height);
} else {
return mView.getMeasuredHeight();
return DoricUtils.px2dp(mView.getMeasuredHeight());
}
}
@ -826,4 +853,14 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
return 0;
}
}
@DoricMethod
public JSONObject getLocationOnScreen() {
int[] position = new int[2];
getNodeView().getLocationOnScreen(position);
return new JSONBuilder()
.put("x", DoricUtils.px2dp(position[0]))
.put("y", DoricUtils.px2dp(position[1]))
.toJSONObject();
}
}

View File

@ -22,6 +22,7 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import com.github.pengfeizhou.jscore.JSArray;
import com.github.pengfeizhou.jscore.JSDecoder;
@ -65,15 +66,28 @@ class FlowAdapter extends RecyclerView.Adapter<FlowAdapter.DoricViewHolder> {
holder.flowLayoutItemNode.setId(jsObject.getProperty("id").asString().value());
holder.flowLayoutItemNode.blend(jsObject.getProperty("props").asObject());
}
if (position >= this.itemCount) {
this.flowLayoutNode.callJSResponse(this.flowLayoutNode.onLoadMoreFuncId);
StaggeredGridLayoutManager.LayoutParams layoutParams = new StaggeredGridLayoutManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
holder.itemView.getLayoutParams().height
);
layoutParams.setFullSpan(true);
holder.itemView.setLayoutParams(layoutParams);
}
}
@Override
public int getItemCount() {
return itemCount;
return this.itemCount + (this.flowLayoutNode.loadMore ? 1 : 0);
}
@Override
public int getItemViewType(int position) {
if (position >= itemCount) {
return Integer.MAX_VALUE;
}
JSValue value = getItemModel(position);
if (value.isObject()) {
if (value.asObject().getProperty("identifier").isString()) {
@ -84,6 +98,9 @@ class FlowAdapter extends RecyclerView.Adapter<FlowAdapter.DoricViewHolder> {
}
private JSValue getItemModel(final int position) {
if (position >= this.itemCount) {
return this.flowLayoutNode.getSubModel(this.flowLayoutNode.loadMoreViewId);
}
String id = itemValues.get(position);
if (TextUtils.isEmpty(id)) {
AsyncResult<JSDecoder> asyncResult = flowLayoutNode.callJSResponse(

View File

@ -41,15 +41,38 @@ public class FlowLayoutNode extends SuperNode<RecyclerView> {
private final FlowAdapter flowAdapter;
private final StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(
2,
StaggeredGridLayoutManager.VERTICAL);
StaggeredGridLayoutManager.VERTICAL) {
@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
try {
return super.scrollVerticallyBy(dy, recycler, state);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
@Override
public void onScrollStateChanged(int state) {
try {
super.onScrollStateChanged(state);
} catch (Exception e) {
e.printStackTrace();
}
}
};
private int columnSpace = 0;
private int rowSpace = 0;
private Rect padding = new Rect();
private final RecyclerView.ItemDecoration spacingItemDecoration = new RecyclerView.ItemDecoration() {
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
outRect.set(columnSpace / 2, rowSpace / 2, columnSpace / 2, rowSpace / 2);
}
};
String onLoadMoreFuncId;
boolean loadMore = false;
String loadMoreViewId;
public FlowLayoutNode(DoricContext doricContext) {
super(doricContext);
@ -80,11 +103,9 @@ public class FlowLayoutNode extends SuperNode<RecyclerView> {
switch (name) {
case "columnSpace":
columnSpace = DoricUtils.dp2px(prop.asNumber().toFloat());
mView.setPadding(-columnSpace / 2, mView.getPaddingTop(), -columnSpace / 2, mView.getPaddingBottom());
break;
case "rowSpace":
rowSpace = DoricUtils.dp2px(prop.asNumber().toFloat());
mView.setPadding(mView.getPaddingLeft(), -rowSpace / 2, mView.getPaddingRight(), -rowSpace / 2);
break;
case "columnCount":
staggeredGridLayoutManager.setSpanCount(prop.asNumber().toInt());
@ -93,23 +114,54 @@ public class FlowLayoutNode extends SuperNode<RecyclerView> {
this.flowAdapter.itemCount = prop.asNumber().toInt();
break;
case "renderItem":
this.flowAdapter.renderItemFuncId = prop.asString().value();
// If reset renderItem,should reset native cache.
this.flowAdapter.itemValues.clear();
clearSubModel();
String funcId = prop.asString().value();
if (!funcId.equals(this.flowAdapter.renderItemFuncId)) {
this.flowAdapter.renderItemFuncId = funcId;
// If reset renderItem,should reset native cache.
for (int index = 0; index < this.flowAdapter.itemValues.size(); index++) {
removeSubModel(this.flowAdapter.itemValues.valueAt(index));
}
this.flowAdapter.itemValues.clear();
}
break;
case "batchCount":
this.flowAdapter.batchCount = prop.asNumber().toInt();
break;
case "onLoadMore":
this.onLoadMoreFuncId = prop.asString().value();
break;
case "loadMoreView":
this.loadMoreViewId = prop.asString().value();
break;
case "loadMore":
this.loadMore = prop.asBoolean().value();
break;
default:
super.blend(view, name, prop);
break;
}
}
@Override
protected void setPadding(JSObject jsObject) {
JSValue left = jsObject.getProperty("left");
JSValue right = jsObject.getProperty("right");
JSValue top = jsObject.getProperty("top");
JSValue bottom = jsObject.getProperty("bottom");
padding.left = left.isNumber() ? DoricUtils.dp2px(left.asNumber().toFloat()) : 0;
padding.top = top.isNumber() ? DoricUtils.dp2px(top.asNumber().toFloat()) : 0;
padding.right = right.isNumber() ? DoricUtils.dp2px(right.asNumber().toFloat()) : 0;
padding.bottom = bottom.isNumber() ? DoricUtils.dp2px(bottom.asNumber().toFloat()) : 0;
}
@Override
public void blend(JSObject jsObject) {
super.blend(jsObject);
mView.setPadding(
padding.left - columnSpace / 2,
padding.top - rowSpace / 2,
padding.right - columnSpace / 2,
padding.bottom - rowSpace / 2);
if (mView != null) {
mView.post(new Runnable() {
@Override

View File

@ -16,7 +16,6 @@
package pub.doric.shader.list;
import android.text.TextUtils;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
@ -40,10 +39,6 @@ import pub.doric.shader.ViewNode;
class ListAdapter extends RecyclerView.Adapter<ListAdapter.DoricViewHolder> {
private final ListNode listNode;
String renderItemFuncId;
int itemCount = 0;
int batchCount = 15;
SparseArray<String> itemValues = new SparseArray<>();
ListAdapter(ListNode listNode) {
this.listNode = listNode;
@ -60,22 +55,28 @@ class ListAdapter extends RecyclerView.Adapter<ListAdapter.DoricViewHolder> {
@Override
public void onBindViewHolder(@NonNull DoricViewHolder holder, int position) {
JSValue jsValue = getItemModel(position);
if (jsValue.isObject()) {
if (jsValue != null && jsValue.isObject()) {
JSObject jsObject = jsValue.asObject();
holder.listItemNode.setId(jsObject.getProperty("id").asString().value());
holder.listItemNode.blend(jsObject.getProperty("props").asObject());
}
if (position >= this.listNode.itemCount) {
this.listNode.callJSResponse(this.listNode.onLoadMoreFuncId);
}
}
@Override
public int getItemCount() {
return itemCount;
return this.listNode.itemCount + (this.listNode.loadMore ? 1 : 0);
}
@Override
public int getItemViewType(int position) {
if (position >= this.listNode.itemCount) {
return Integer.MAX_VALUE;
}
JSValue value = getItemModel(position);
if (value.isObject()) {
if (value != null && value.isObject()) {
if (value.asObject().getProperty("identifier").isString()) {
return value.asObject().getProperty("identifier").asString().value().hashCode();
}
@ -84,12 +85,15 @@ class ListAdapter extends RecyclerView.Adapter<ListAdapter.DoricViewHolder> {
}
private JSValue getItemModel(final int position) {
String id = itemValues.get(position);
if (position >= this.listNode.itemCount) {
return this.listNode.getSubModel(this.listNode.loadMoreViewId);
}
String id = listNode.itemValues.get(position);
if (TextUtils.isEmpty(id)) {
AsyncResult<JSDecoder> asyncResult = listNode.callJSResponse(
"renderBunchedItems",
position,
batchCount);
listNode.batchCount);
try {
JSDecoder jsDecoder = asyncResult.synchronous().get();
JSValue result = jsDecoder.decode();
@ -98,10 +102,10 @@ class ListAdapter extends RecyclerView.Adapter<ListAdapter.DoricViewHolder> {
for (int i = 0; i < jsArray.size(); i++) {
JSObject itemModel = jsArray.get(i).asObject();
String itemId = itemModel.getProperty("id").asString().value();
itemValues.put(i + position, itemId);
listNode.itemValues.put(i + position, itemId);
listNode.setSubModel(itemId, itemModel);
}
return listNode.getSubModel(itemValues.get(position));
return listNode.getSubModel(listNode.itemValues.get(position));
}
} catch (Exception e) {
e.printStackTrace();
@ -119,8 +123,8 @@ class ListAdapter extends RecyclerView.Adapter<ListAdapter.DoricViewHolder> {
void blendSubNode(JSObject subProperties) {
for (int i = 0; i < itemValues.size(); i++) {
if (subProperties.getProperty("id").asString().value().equals(itemValues.valueAt(i))) {
for (int i = 0; i < listNode.itemValues.size(); i++) {
if (subProperties.getProperty("id").asString().value().equals(listNode.itemValues.valueAt(i))) {
notifyItemChanged(i);
}
}

View File

@ -15,6 +15,7 @@
*/
package pub.doric.shader.list;
import android.util.SparseArray;
import android.view.View;
import androidx.recyclerview.widget.LinearLayoutManager;
@ -36,6 +37,13 @@ import pub.doric.shader.ViewNode;
@DoricPlugin(name = "List")
public class ListNode extends SuperNode<RecyclerView> {
private final ListAdapter listAdapter;
private String renderItemFuncId;
String onLoadMoreFuncId;
int itemCount = 0;
int batchCount = 15;
SparseArray<String> itemValues = new SparseArray<>();
boolean loadMore = false;
String loadMoreViewId;
public ListNode(DoricContext doricContext) {
super(doricContext);
@ -82,16 +90,30 @@ public class ListNode extends SuperNode<RecyclerView> {
protected void blend(RecyclerView view, String name, JSValue prop) {
switch (name) {
case "itemCount":
this.listAdapter.itemCount = prop.asNumber().toInt();
this.itemCount = prop.asNumber().toInt();
break;
case "renderItem":
this.listAdapter.renderItemFuncId = prop.asString().value();
// If reset renderItem,should reset native cache.
this.listAdapter.itemValues.clear();
clearSubModel();
String funcId = prop.asString().value();
if (!funcId.equals(this.renderItemFuncId)) {
this.renderItemFuncId = funcId;
// If reset renderItem,should reset native cache.
for (int index = 0; index < this.itemValues.size(); index++) {
removeSubModel(this.itemValues.valueAt(index));
}
this.itemValues.clear();
}
break;
case "onLoadMore":
this.onLoadMoreFuncId = prop.asString().value();
break;
case "loadMoreView":
this.loadMoreViewId = prop.asString().value();
break;
case "batchCount":
this.listAdapter.batchCount = prop.asNumber().toInt();
this.batchCount = prop.asNumber().toInt();
break;
case "loadMore":
this.loadMore = prop.asBoolean().value();
break;
default:
super.blend(view, name, prop);

View File

@ -0,0 +1,207 @@
/*
* Copyright [2019] [Doric.Pub]
*
* 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 pub.doric.shader.slider;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.github.pengfeizhou.jscore.JSObject;
import com.github.pengfeizhou.jscore.JSValue;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import pub.doric.DoricContext;
import pub.doric.extension.bridge.DoricMethod;
import pub.doric.extension.bridge.DoricPlugin;
import pub.doric.extension.bridge.DoricPromise;
import pub.doric.shader.GroupNode;
import pub.doric.shader.ViewNode;
/**
* @Description: pub.doric.shader.slider
* @Author: pengfei.zhou
* @CreateDate: 2019-12-07
*/
@DoricPlugin(name = "NestedSlider")
public class NestedSliderNode extends GroupNode<ViewPager> implements ViewPager.OnPageChangeListener {
private ArrayList<View> slideItems = new ArrayList<>();
private String onPageSlidedFuncId;
public NestedSliderNode(DoricContext doricContext) {
super(doricContext);
}
@Override
protected ViewPager build() {
ViewPager viewPager = new ViewPager(getContext());
viewPager.setAdapter(new PagerAdapter() {
@Override
public int getCount() {
return slideItems.size();
}
@Override
public boolean isViewFromObject(@NonNull View view, @NotNull Object object) {
return view == object;
}
@Override
public void destroyItem(@NotNull ViewGroup container, int position, @NotNull Object object) {
container.removeView(slideItems.get(position));
}
@NotNull
@Override
public Object instantiateItem(@NotNull ViewGroup container, int position) {
container.addView(slideItems.get(position), 0);
return slideItems.get(position);
}
});
viewPager.addOnPageChangeListener(this);
return viewPager;
}
@Override
protected void blend(ViewPager view, String name, JSValue prop) {
switch (name) {
case "onPageSlided":
this.onPageSlidedFuncId = prop.asString().toString();
break;
default:
super.blend(view, name, prop);
break;
}
}
@Override
protected void configChildNode() {
for (int idx = 0; idx < mChildViewIds.size(); idx++) {
String id = mChildViewIds.get(idx);
JSObject model = getSubModel(id);
String type = model.getProperty("type").asString().value();
if (idx < mChildNodes.size()) {
ViewNode oldNode = mChildNodes.get(idx);
if (id.equals(oldNode.getId())) {
//The same,skip
} else {
if (mReusable) {
if (oldNode.getType().equals(type)) {
//Same type,can be reused
oldNode.setId(id);
oldNode.blend(model.getProperty("props").asObject());
} else {
//Replace this view
mChildNodes.remove(idx);
slideItems.remove(oldNode.getNodeView());
ViewNode newNode = ViewNode.create(getDoricContext(), type);
newNode.setId(id);
newNode.init(this);
newNode.blend(model.getProperty("props").asObject());
mChildNodes.add(idx, newNode);
slideItems.add(idx, newNode.getNodeView());
}
} else {
//Find in remain nodes
int position = -1;
for (int start = idx + 1; start < mChildNodes.size(); start++) {
ViewNode node = mChildNodes.get(start);
if (id.equals(node.getId())) {
//Found
position = start;
break;
}
}
if (position >= 0) {
//Found swap idx,position
ViewNode reused = mChildNodes.remove(position);
ViewNode abandoned = mChildNodes.remove(idx);
mChildNodes.set(idx, reused);
mChildNodes.set(position, abandoned);
//View swap index
slideItems.remove(reused.getNodeView());
slideItems.add(idx, reused.getNodeView());
slideItems.remove(abandoned.getNodeView());
slideItems.add(position, abandoned.getNodeView());
} else {
//Not found,insert
ViewNode newNode = ViewNode.create(getDoricContext(), type);
newNode.setId(id);
newNode.init(this);
newNode.blend(model.getProperty("props").asObject());
mChildNodes.add(idx, newNode);
slideItems.add(idx, newNode.getNodeView());
}
}
}
} else {
//Insert
ViewNode newNode = ViewNode.create(getDoricContext(), type);
newNode.setId(id);
newNode.init(this);
newNode.blend(model.getProperty("props").asObject());
mChildNodes.add(newNode);
slideItems.add(idx, newNode.getNodeView());
}
}
int size = mChildNodes.size();
for (int idx = mChildViewIds.size(); idx < size; idx++) {
ViewNode viewNode = mChildNodes.remove(mChildViewIds.size());
slideItems.remove(viewNode.getNodeView());
}
mView.getAdapter().notifyDataSetChanged();
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
if (!TextUtils.isEmpty(onPageSlidedFuncId)) {
callJSResponse(onPageSlidedFuncId, position);
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
@DoricMethod
public void slidePage(JSObject params, DoricPromise promise) {
int page = params.getProperty("page").asNumber().toInt();
boolean smooth = params.getProperty("smooth").asBoolean().value();
mView.setCurrentItem(page, smooth);
if (!TextUtils.isEmpty(onPageSlidedFuncId)) {
callJSResponse(onPageSlidedFuncId, page);
}
promise.resolve();
}
@DoricMethod
public int getSlidedPage() {
return mView.getCurrentItem();
}
}

View File

@ -43,7 +43,7 @@ class SlideAdapter extends RecyclerView.Adapter<SlideAdapter.DoricViewHolder> {
int itemCount = 0;
int batchCount = 3;
SparseArray<String> itemValues = new SparseArray<>();
String renderPageFuncId;
SlideAdapter(SliderNode sliderNode) {
this.sliderNode = sliderNode;
}

View File

@ -15,6 +15,7 @@
*/
package pub.doric.shader.slider;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.github.pengfeizhou.jscore.JSObject;
@ -50,7 +51,7 @@ public class SlideItemNode extends StackNode {
@Override
public void blend(JSObject jsObject) {
super.blend(jsObject);
getNodeView().getLayoutParams().width = getLayoutParams().width;
getNodeView().getLayoutParams().height = getLayoutParams().height;
getNodeView().getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
getNodeView().getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
}
}

View File

@ -15,8 +15,10 @@
*/
package pub.doric.shader.slider;
import android.text.TextUtils;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.PagerSnapHelper;
import androidx.recyclerview.widget.RecyclerView;
@ -25,7 +27,9 @@ import com.github.pengfeizhou.jscore.JSObject;
import com.github.pengfeizhou.jscore.JSValue;
import pub.doric.DoricContext;
import pub.doric.extension.bridge.DoricMethod;
import pub.doric.extension.bridge.DoricPlugin;
import pub.doric.extension.bridge.DoricPromise;
import pub.doric.shader.SuperNode;
import pub.doric.shader.ViewNode;
@ -37,6 +41,8 @@ import pub.doric.shader.ViewNode;
@DoricPlugin(name = "Slider")
public class SliderNode extends SuperNode<RecyclerView> {
private final SlideAdapter slideAdapter;
private String onPageSlidedFuncId;
private int lastPosition = 0;
public SliderNode(DoricContext doricContext) {
super(doricContext);
@ -47,12 +53,32 @@ public class SliderNode extends SuperNode<RecyclerView> {
protected RecyclerView build() {
RecyclerView recyclerView = new RecyclerView(getContext());
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
final LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(layoutManager);
PagerSnapHelper mPagerSnapHelper = new PagerSnapHelper();
mPagerSnapHelper.attachToRecyclerView(recyclerView);
final PagerSnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
recyclerView.setAdapter(this.slideAdapter);
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
View view = snapHelper.findSnapView(layoutManager);
if (view != null && !TextUtils.isEmpty(onPageSlidedFuncId)) {
int position = layoutManager.getPosition(view);
if (position != lastPosition) {
callJSResponse(onPageSlidedFuncId, position);
}
lastPosition = position;
}
}
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
});
return recyclerView;
}
@ -109,17 +135,46 @@ public class SliderNode extends SuperNode<RecyclerView> {
case "itemCount":
this.slideAdapter.itemCount = prop.asNumber().toInt();
break;
case "renderItem":
case "renderPage":
// If reset renderItem,should reset native cache.
this.slideAdapter.itemValues.clear();
clearSubModel();
String funcId = prop.asString().value();
if (!funcId.equals(this.slideAdapter.renderPageFuncId)) {
this.slideAdapter.itemValues.clear();
clearSubModel();
this.slideAdapter.renderPageFuncId = funcId;
}
break;
case "batchCount":
this.slideAdapter.batchCount = prop.asNumber().toInt();
break;
case "onPageSlided":
this.onPageSlidedFuncId = prop.asString().toString();
break;
default:
super.blend(view, name, prop);
break;
}
}
@DoricMethod
public void slidePage(JSObject params, DoricPromise promise) {
int page = params.getProperty("page").asNumber().toInt();
boolean smooth = params.getProperty("smooth").asBoolean().value();
if (smooth) {
mView.smoothScrollToPosition(page);
} else {
mView.scrollToPosition(page);
}
if (!TextUtils.isEmpty(onPageSlidedFuncId)) {
callJSResponse(onPageSlidedFuncId, page);
lastPosition = page;
}
promise.resolve();
}
@DoricMethod
public int getSlidedPage() {
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mView.getLayoutManager();
return linearLayoutManager != null ? linearLayoutManager.findFirstVisibleItemPosition() : 0;
}
}

View File

@ -26,6 +26,8 @@ public class DoricConstant {
public static final String DORIC_MODULE_LIB = "doric";
public static final String INJECT_ENVIRONMENT = "Environment";
public static final String INJECT_LOG = "nativeLog";
public static final String INJECT_REQUIRE = "nativeRequire";
public static final String INJECT_TIMER_SET = "nativeSetTimer";

View File

@ -669,6 +669,11 @@ public class HVScrollView extends FrameLayout implements NestedScrollingParent,
super.requestDisallowInterceptTouchEvent(disallowIntercept);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
/*
@ -715,8 +720,12 @@ public class HVScrollView extends FrameLayout implements NestedScrollingParent,
final int y = (int) ev.getY(pointerIndex);
final int xDiff = Math.abs(x - mLastMotionX);
final int yDiff = Math.abs(y - mLastMotionY);
if ((xDiff > mTouchSlop && (getNestedScrollAxes() & ViewCompat.SCROLL_AXIS_HORIZONTAL) == 0)
|| (yDiff > mTouchSlop && (getNestedScrollAxes() & ViewCompat.SCROLL_AXIS_VERTICAL) == 0)) {
if ((xDiff > mTouchSlop
&& (getNestedScrollAxes() & ViewCompat.SCROLL_AXIS_HORIZONTAL) == 0
&& canScrollHorizontally())
|| (yDiff > mTouchSlop
&& (getNestedScrollAxes() & ViewCompat.SCROLL_AXIS_VERTICAL) == 0
&& canScrollVertically())) {
mIsBeingDragged = true;
mLastMotionX = x;
mLastMotionY = y;

View File

@ -1,7 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:orientation="vertical">
</FrameLayout>
<pub.doric.navbar.BaseDoricNavBar
android:id="@+id/doric_nav_bar"
android:layout_width="match_parent"
android:layout_height="44dp" />
<fragment
android:id="@+id/nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/doric_navigation" />
</LinearLayout>

View File

@ -1,18 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<pub.doric.DoricPanel xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/doric_panel"
android:layout_width="match_parent"
android:layout_height="match_parent">
<pub.doric.DoricPanel
android:id="@+id/doric_panel"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:layout_marginTop="44dp" />
<pub.doric.navbar.BaseDoricNavBar
android:id="@+id/doric_nav_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</FrameLayout>
</pub.doric.DoricPanel>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/doric_navigation"
app:startDestination="@id/doricPanelFragment">
<fragment
android:id="@+id/doricPanelFragment"
android:name="pub.doric.DoricPanelFragment"
android:label="DoricPanelFragment">
<action
android:id="@+id/action_doricPanelFragment_to_doricPanelFragment"
app:destination="@id/doricPanelFragment" />
</fragment>
</navigation>

View File

@ -0,0 +1,2 @@
git=https://github.com/doric-pub/doric
site=https://github.com/doric-pub/doric

View File

@ -0,0 +1,39 @@
apply plugin: 'maven'
Properties properties = new Properties()
properties.load(project.rootProject.file('scripts/maven.properties').newDataInputStream())
properties.load(new FileInputStream("${projectDir}/pom.properties"))
properties.load(project.rootProject.file('local.properties').newDataInputStream())
apply plugin: 'maven'
uploadArchives {
repositories {
mavenDeployer {
pom.groupId = properties.groupId
pom.artifactId = properties.artifactId
pom.version = rootProject.ext.Version
pom.project {
description 'git rev-parse HEAD'.execute([], projectDir).text.trim()
}
repository(url: properties.releasesRepository + properties.name) {
authentication(userName: properties.user, password: properties.apiKey)
}
}
}
}
task uploadAar {
dependsOn clean, uploadArchives
}
//task androidSourcesJar(type: Jar) {
// classifier = "sources"
// from android.sourceSets.main.java.sourceFiles
//}
//
//artifacts {
// archives androidSourcesJar
//}

View File

@ -0,0 +1 @@
version=0.1.2