This commit is contained in:
Gangphon 2024-02-02 18:09:54 +08:00
parent 9e1309090c
commit 03df39b539
39 changed files with 370 additions and 84 deletions

View File

@ -11,7 +11,7 @@ android {
minSdk 24
targetSdk 34
versionCode 1
versionName "1.0.20-sensor"
versionName "1.0.22-tts"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 680 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 929 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 748 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 877 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 923 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 866 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 698 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 647 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 669 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 966 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 569 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 964 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 971 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 833 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1003 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 964 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 787 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 904 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -23,11 +23,13 @@ public class EleVideo extends TextureView implements TextureView.SurfaceTextureL
IjkMediaPlayer ijkPlayer;
ExoPlayer exoPlayer;
long bitRate;
boolean isLive;
public EleVideo(Context context, String path, float vol) {
public EleVideo(Context context, String path, float vol, boolean isLive) {
super(context);
this.path = path;
this.vol = vol;
this.isLive = isLive;
initIjk();
}
@ -59,7 +61,7 @@ public class EleVideo extends TextureView implements TextureView.SurfaceTextureL
release();
initExo();
}
if(isShown()) start();
if(isShown() || isLive) start();
});
ijkPlayer.prepareAsync();
} catch (Throwable e) {
@ -127,7 +129,10 @@ public class EleVideo extends TextureView implements TextureView.SurfaceTextureL
@Override
public void onVisibilityAggregated(boolean isVisible) {
super.onVisibilityAggregated(isVisible);
if(isVisible) start();
if(isVisible) {
start();
if(isLive) ijkPlayer.setVolume(vol, vol);
} else if(isLive) ijkPlayer.setVolume(0, 0);
else pause();
}
}

View File

@ -18,6 +18,7 @@ import android.os.Environment;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.StatFs;
import android.os.StrictMode;
import android.view.Choreographer;
import android.view.View;
import android.webkit.WebView;
@ -78,6 +79,8 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
ins = this;
startService(new Intent(this, RestartService.class));
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().permitAll().build());
if(ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) init();
else {
Util.println("---- No permission, Try again ...");
@ -142,7 +145,7 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
intentFilter.addDataScheme("file");
registerReceiver(new BroadcastReceiver(){
long lastMs;
char [] pass = {'8','8','8'};
final char[] pass = {'8','8','8'};
@Override
public void onReceive(Context context, Intent intent) {
var path = intent.getData().getPath();
@ -167,16 +170,12 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
}
if(progJson==null) {
Util.println("No program File");
runOnUiThread(() -> {
Util.makeText(MainActivity.this, "No program File").show();
});
runOnUiThread(() -> Util.makeText(MainActivity.this, "No program File").show());
return;
}
if(size==0) {
Util.println("zip size is 0");
runOnUiThread(() -> {
Util.makeText(MainActivity.this, "zip size is 0").show();
});
runOnUiThread(() -> Util.makeText(MainActivity.this, "zip size is 0").show());
return;
}
Util.deleteFiles(size, null);
@ -189,9 +188,7 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
});
} catch (Exception e) {
Util.printStackTrace(e);
runOnUiThread(() -> {
Util.makeText(MainActivity.this, Util.toStr(e)).show();
});
runOnUiThread(() -> Util.makeText(MainActivity.this, Util.toStr(e)).show());
}
}).start();
}
@ -238,14 +235,14 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
var code = intent.getIntExtra("code", 0);
Util.println(" remote_control "+code);
if(progView == null || code > progView.pages.size()) return;
if(! progView.avas.isEmpty()) page(curAva).hide();
if(! progView.avas.isEmpty()) page(progView.curAva).hide();
var millis = (System.currentTimeMillis()+999)/1000*1000;
if(code > 0) {
progView.avas.clear();
progView.avas.add(code-1);
curAva = 0;
curTimes = 1;
waitTo = 0;
progView.curAva = 0;
progView.curTimes = 1;
progView.waitTo = 0; //点播
var page = page(0);
page.setMillis(millis);
if(state != 6) {
@ -253,7 +250,7 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
state = 6;
}
} else {
waitTo = Long.MAX_VALUE;
progView.waitTo = Long.MAX_VALUE;
syncProg(millis);
}
} catch (Throwable e) {
@ -360,8 +357,6 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
}
Choreographer choreographer = Choreographer.getInstance();
int curAva, curTimes = 1;
long waitTo = Long.MAX_VALUE;
boolean canAdd = true;
@Override
@ -372,34 +367,34 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
}
var milli = System.currentTimeMillis();
if(progView.avas.isEmpty()) {
if(milli >= waitTo) {
waitTo = Long.MAX_VALUE;
if(milli >= progView.waitTo) {
progView.waitTo = Long.MAX_VALUE;
Util.println("wait sync");
syncProg(milli);
}
} else {
var lastPage = page(curAva);
var lastPage = page(progView.curAva);
if(milli >= lastPage.endMilli) {
lastPage.hide();
if(waitTo>0) { //waitTo==0 为点播不换页
if(curTimes < lastPage.repeatTimes) curTimes++;
if(progView.waitTo > 0) { //waitTo==0 为点播不换页
if(progView.curTimes < lastPage.repeatTimes) progView.curTimes++;
else {
curTimes = 1;
curAva++;
if(curAva >= progView.avas.size()) {
progView.curTimes = 1;
progView.curAva++;
if(progView.curAva >= progView.avas.size()) {
var isDiff = milli-lastPage.endMilli>=1000;
if(Util.buf.length()>1000000) Util.buf.replace(0, 100000, "");
Util.println("isDiff: "+isDiff+" endMs: "+lastPage.endMilli+" millis:"+milli);
syncProg(isDiff ? milli : lastPage.endMilli);
Util.println("after. curAva: "+curAva+" endMs: "+page(curAva).endMilli);
Util.println("after. curAva: "+progView.curAva+" endMs: "+page(progView.curAva).endMilli);
choreographer.postFrameCallback(this);
canAdd = false;
return;
}
}
}
page(curAva).setMillis(lastPage.endMilli);
Util.println("curAva: "+curAva+" endMs: "+page(curAva).endMilli);
page(progView.curAva).setMillis(lastPage.endMilli);
Util.println("curAva: "+progView.curAva+" endMs: "+page(progView.curAva).endMilli);
} else {
for(var layer : lastPage.layers) {
for(var src : layer.srcs) {
@ -425,36 +420,42 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
}
void syncProg(long milli) {
curTimes = 1;
progView.curTimes = 1;
progView.avas.clear();
var dur = 0;
for(int i=0; i<progView.pages.size(); i++) if(progView.pages.get(i).isSchedule(milli+dur)) {
for(int i=0; i<progView.pages.size(); i++) if(progView.pages.get(i).isScheOn(milli+dur)) {
progView.avas.add(i);
dur += progView.pages.get(i).tDur;
}
if(dur==0) {
waitTo = milli + 1000;
if(state!=2) {
setContentView(backView);
state = 2;
for(int i=0; i<progView.pages.size(); i++) if(progView.pages.get(i).sches==null) {
progView.avas.add(i);
dur += progView.pages.get(i).tDur;
}
} else {
var start = milli / dur * dur;
curAva = 0;
if(start < milli) {
do {
start += page(curAva++).tDur;
} while(curAva < progView.avas.size() && start<=milli);
start -= page(--curAva).tDur;
syncMs = milli;
Util.println("Sync. dur: "+dur+" milli: "+milli+" start: "+start+" diff: "+(milli - start));
}
page(curAva).setMillis(start);
if(state != 6) {
setContentView(progView);
state = 6;
if(dur==0) {
progView.waitTo = milli + 1000;
if(state!=2) {
setContentView(backView);
state = 2;
}
return;
}
}
var start = milli / dur * dur;
progView.curAva = 0;
if(start < milli) {
do {
start += page(progView.curAva++).tDur;
} while(progView.curAva < progView.avas.size() && start<=milli);
start -= page(--progView.curAva).tDur;
syncMs = milli;
Util.println("Sync. dur: "+dur+" milli: "+milli+" start: "+start+" diff: "+(milli - start));
}
page(progView.curAva).setMillis(start);
if(state != 6) {
setContentView(progView);
state = 6;
}
}
Prog.Page page(int i) {
@ -468,9 +469,9 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
InputStream in = null;
OutputStream out = null;
try {
Util.println("Accepting ...");
Util.println("\nAccepting ...");
final var socket = serverSocket.accept();
Util.println("Accepted");
Util.println("\nAccepted");
in = socket.getInputStream();
out = socket.getOutputStream();
HashSet<String> hases = null;
@ -557,7 +558,7 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
writer.append("\n");
writer.append(" Launch: ").append(Fmt.format(launchMilli)).append("\n");
writer.append(" Sync: ").append(Fmt.format(syncMs)).append("\n");
writer.append("Page End: ").append(progView==null || progView.avas.isEmpty() ? "0" : Fmt.format(page(curAva).endMilli)).append(" CurPage: ").append(String.valueOf(curAva)).append(" / ").append(progView==null || progView.avas.isEmpty() ? "0" : String.valueOf(progView.avas.get(curAva))).append("\n");
writer.append("Page End: ").append(progView==null || progView.avas.isEmpty() ? "0" : Fmt.format(page(progView.curAva).endMilli)).append(" CurPage: ").append(String.valueOf(progView.curAva)).append(" / ").append(progView==null || progView.avas.isEmpty() ? "0" : String.valueOf(progView.avas.get(progView.curAva))).append("\n");
writer.append(" Current: ").append(Fmt.format(System.currentTimeMillis())).append("\n");
var statFs = new StatFs(Environment.getExternalStorageDirectory().getPath());
writer.append(" Disk: ").append(String.valueOf(statFs.getTotalBytes()/1000000)).append(" ").append(String.valueOf(statFs.getAvailableBytes()/1000000)).append(" ").append(String.valueOf(statFs.getFreeBytes()/1000000)).append(" (total avail free)\n");
@ -573,7 +574,7 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
var latch = new CountDownLatch(1);
runOnUiThread(() -> {
if(progView!=null && ! progView.avas.isEmpty()) {
var page = page(curAva);
var page = page(progView.curAva);
for(var layer : page.layers) for(var src : layer.srcs) if(src.view.getVisibility()==VISIBLE) {
try {
if(src.view instanceof EleVideo) {
@ -600,6 +601,9 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
writer.append("getPlaybackParameters: ").append(String.valueOf(view.exoPlayer.getPlaybackParameters())).append("\n");
}
writer.append("\n");
} else if(src.view instanceof SrcWeather) {
var view = (SrcWeather) src.view;
writer.append("SrcWeather html: ").append(view.html).append("\n");
} else if(src.view instanceof WebView) {
var view = (WebView) src.view;
writer.append("Title: ").append(view.getTitle()).append("\n");
@ -624,10 +628,7 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
if(files == null) return;
Arrays.sort(files, (f1, f2) -> (int) (f2.lastModified() - f1.lastModified()));
var writer = new OutputStreamWriter(out);
for(var file : files) {
var len = file.length();
writer.append(file.getName()).append(' ').append(String.valueOf(file.length())).append('\n');
}
for(var file : files) writer.append(file.getName()).append(' ').append(String.valueOf(file.length())).append('\n');
writer.append('\n');
writer.flush();
} else if("GetFile".equals(_type)) {
@ -644,19 +645,15 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra
Util.println(emsg);
continue;
}
MainActivity.ins.runOnUiThread(() -> {
Util.makeText(MainActivity.this, Util.toStr(e)).show();
});
MainActivity.ins.runOnUiThread(() -> Util.makeText(MainActivity.this, Util.toStr(e)).show());
Util.printStackTrace(e);
} finally {
O.close(in, out);
Util.println("conn end\n\n");
Util.println("conn end\n");
}
}
} catch (Throwable e) {
MainActivity.ins.runOnUiThread(() -> {
Util.makeText(MainActivity.this, Util.toStr(e)).show();
});
MainActivity.ins.runOnUiThread(() -> Util.makeText(MainActivity.this, Util.toStr(e)).show());
Util.printStackTrace(e);
}
}

View File

@ -3,6 +3,7 @@ package com.xixun.xixunplayer;
import android.annotation.SuppressLint;
import android.content.Context;
import android.net.Uri;
import android.speech.tts.TextToSpeech;
import android.view.View;
import android.webkit.WebView;
import android.webkit.WebViewClient;
@ -24,6 +25,8 @@ public class Prog extends AbsLayout {
ArrayList<Page> pages = new ArrayList<>();
ArrayList<Integer> avas = new ArrayList<>();
int curAva, curTimes = 1;
long waitTo = Long.MAX_VALUE;
public Prog(JSMap task, Context context) {
super(context);
@ -163,16 +166,30 @@ public class Prog extends AbsLayout {
imgView.setScaleType(ImageView.ScaleType.FIT_XY);
src.view = imgView;
}
} else if(src.type.equals("MultiPng") || src.type.equals("SplitText")) {
} else if(src.type.startsWith("MultiPng") || src.type.equals("SplitText")) {
JSList<JSMap> imgs = source.jslist("arrayPics");
if(imgs.isEmpty()) continue;
if(imgs.size()==1 && imgs.get(0).intg("picDuration")==0) src.view = new EleScroll(context, imgs.get(0));
else {
var mode = source.str("curchange");
var hasTTS = src.type.endsWith("Audio");
var speechRate = (float) source.dbl("voiceRate");
if(mode!=null ? mode.endsWith("roll") : (imgs.size()==1 && imgs.get(0).intg("picDuration")==0)) {
var img = imgs.get(0);
src.view = new EleScroll(context, img);
if(hasTTS) {
src.text = img.str("text");
if(src.text!=null) {
src.tts = new TextToSpeech(context, (int status)->{
Util.println("status: "+status+" "+(status==TextToSpeech.SUCCESS));
}, "com.iflytek.speechcloud");
src.tts.setSpeechRate(speechRate);
}
}
} else {
var start = src.startTime;
var ele0 = src;
for(var map : imgs) {
var picDur = map.intg("picDuration")*1000;
if(picDur==0) continue;
if(picDur==0) picDur = timeSpan / imgs.size();
src.type = "Image";
src.startTime = start;
src.endTime = start = src.startTime + picDur;
@ -185,6 +202,15 @@ public class Prog extends AbsLayout {
src.isEntryRand = ele0.isEntryRand;
src.isExitRand = ele0.isExitRand;
}
if(hasTTS) {
src.text = map.str("text");
if(src.text!=null) {
src.tts = new TextToSpeech(context, (int status)->{
Util.println("status: "+status+" "+(status==TextToSpeech.SUCCESS));
}, "com.iflytek.speechcloud");
src.tts.setSpeechRate(speechRate);
}
}
var imgView = new ImageView(context);
imgView.setImageURI(Uri.fromFile(new File(Util.programDir + "/" + map.stnn("id"))));
imgView.setScaleType(ImageView.ScaleType.FIT_XY);
@ -199,9 +225,12 @@ public class Prog extends AbsLayout {
} else if(src.type.equals("DigitalClock")) src.view = new SrcDigitalClock(context, source);
else if(src.type.startsWith("DigitalClock")) src.view = new SrcDigiClock(context, source);
else if(src.type.equals("AnalogClock")) src.view = new SrcAnaClock(geo.width, geo.height, Util.programDir + "/" + id, source, context);
else if(src.type.equals("Audio")) src.view = new EleVideo(context, Util.programDir + "/" +id, source.intg("vol", 100) / 100.0f);
else if(src.type.equals("Video")) {
var key = id + src.startTime + src.endTime;
else if(src.type.equals("Audio")) src.view = new EleVideo(context, Util.programDir + "/" +id, source.intg("vol", 100) / 100.0f, false);
else if(src.type.endsWith("Video")) {
var isLive = src.type.startsWith("Live");
var url = source.str("url");
if(isLive && url==null) continue;
var key = isLive?url:id + src.startTime + src.endTime;
var videoView = videoMap.get(key);
if(videoView!=null) {
var geoOld = (AbsLayout.LayoutParams) videoView.getLayoutParams();
@ -212,7 +241,7 @@ public class Prog extends AbsLayout {
src.view = new SrcCopy(context, videoView);
((SrcCopy) src.view).scaleX = 0;
} else {
src.view = new EleVideo(context, Util.programDir+"/"+id, source.intg("vol", 100) / 100.0f);
src.view = new EleVideo(context, isLive ? url : Util.programDir+"/"+id, source.intg("vol", 100) / 100.0f, isLive);
videoMap.put(key, (EleVideo) src.view);
}
} else if(src.type.equals("WebURL")) {
@ -229,6 +258,7 @@ public class Prog extends AbsLayout {
else if(src.type.equals("Timer")) src.view = new SrcTimer(context, source);
else if(src.type.equals("Countdown")) src.view = new SrcCountdown(context, source);
else if(src.type.startsWith("Environ")) src.view = new SrcEnviron(context, source);
else if(src.type.startsWith("Weather")) src.view = new SrcWeather(context, source);
else if(src.type.startsWith("MultiLineText")) src.view = new SrcSensor(context, source);
else continue;
if(src.view==null) continue;
@ -278,6 +308,7 @@ public class Prog extends AbsLayout {
setVisibility(GONE);
View view;
for(int cc=0; cc<getChildCount(); cc++) if((view = getChildAt(cc)) instanceof EleVideo) ((EleVideo) view).release();
for(var page : pages) for(var layer : page.layers) for(var src : layer.srcs) if(src.tts!=null) src.tts.shutdown();
} catch (Throwable e) {
Util.printStackTrace(e);
}
@ -291,6 +322,8 @@ public class Prog extends AbsLayout {
Effect entryEff, exitEff;
String type;
Uri uri;
TextToSpeech tts;
String text;
boolean isEntryRand, isExitRand;
void show() {
@ -301,11 +334,13 @@ public class Prog extends AbsLayout {
if(isExitRand) exitEff = Effect.values()[Util.rand.nextInt(Effect.values().length)];
resetEff();
doEff();
if(tts!=null) tts.speak(text, TextToSpeech.QUEUE_FLUSH, null, null);
}
void hide() {
if(view.getVisibility()!=VISIBLE) return;
view.setVisibility(GONE);
if(uri!=null) ((GifImageView) view).setImageURI(uri);
if(tts!=null && tts.isSpeaking()) tts.stop();
}
void doEff() {
var w = view.getLayoutParams().width;
@ -484,8 +519,8 @@ public class Prog extends AbsLayout {
}
}
}
public boolean isSchedule(long milli) {
if(sches==null) return true;
public boolean isScheOn(long milli) {
if(sches==null) return false;
var local = milli + Dates.zoneOff;
var time = local % 86400000L;
long week = -1;

View File

@ -142,7 +142,7 @@ public class Server extends Service {
proSize -= file.length();
hases.add(filename);
} else needDown.srcs.add(new Src(filename, url));
} else if(type.equals("MultiPng") || type.equals("SplitText")) {
} else if(type.startsWith("MultiPng") || type.equals("SplitText")) {
JSList<JSMap> imgs = source.jslist("arrayPics");
if(imgs.isEmpty()) continue;
for(var img : imgs) {

View File

@ -112,7 +112,7 @@ public class SrcEnviron extends View implements Choreographer.FrameCallback, Int
item.nums.add(img);
}
} else {
var num = ((Number) method.invoke(intent, item.key, -999)).doubleValue();
var num = ((Number) method.invoke(intent, item.key, -999)).floatValue();
var str = num==-999 || (num==-1 && ! item.key.endsWith("rature")) ? "--" : NumFmts.zz().format(num);
for(int cc=0; cc<str.length(); cc++) item.nums.add(imgMap.get(str.substring(cc, cc+1)));
}

View File

@ -36,15 +36,16 @@ public class SrcSensor extends WebView implements IntentReceiver {
try {
var htm = html;
var temp = intent.getFloatExtra("temperature", -99f);
var fa = temp * 1.8f + 32;
var noTemp = temp==-99f;
var t2 = noTemp ? "--" : NumFmts.fix2().format(temp);
var t1 = noTemp ? "--" : NumFmts.fix1().format(temp);
var tn = noTemp ? "--" : String.valueOf(temp);
var t0 = noTemp ? "--" : fmt0.format(temp);
var f2 = noTemp ? "--" : NumFmts.fix2().format(temp * 1.8 + 32);
var f1 = noTemp ? "--" : NumFmts.fix1().format(temp * 1.8 + 32);
var fn = noTemp ? "--" : String.valueOf(temp * 1.8 + 32);
var f0 = noTemp ? "--" : fmt0.format(temp * 1.8 + 32);
var f2 = noTemp ? "--" : NumFmts.fix2().format(fa);
var f1 = noTemp ? "--" : NumFmts.fix1().format(fa);
var fn = noTemp ? "--" : String.valueOf(fa);
var f0 = noTemp ? "--" : fmt0.format(fa);
var humi = intent.getFloatExtra("humidity", -1);
var h = humi == -1 ? "--" : String.valueOf(humi);

View File

@ -0,0 +1,248 @@
package com.xixun.xixunplayer;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.webkit.WebView;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.regex.Pattern;
import gnph.util.IOs;
import gnph.util.JSList;
import gnph.util.JSMap;
import gnph.util.NumFmts;
import gnph.util.Txts;
import gnph.util.URLConn;
@SuppressLint("ViewConstructor")
public class SrcWeather extends WebView {
String html, lineHeight, prefix, city;
int code;
boolean hasAQI, hasCur, hasDays;
public SrcWeather(Context context, JSMap json) {
super(context);
setBackgroundColor(Color.TRANSPARENT);
setVerticalScrollBarEnabled(false);
setHorizontalScrollBarEnabled(false);
setInitialScale(100);
html = json.stnn("html").replace("%{yesterday.", "%{arr.-1.");
lineHeight = json.str("lineHeight");
city = json.str("city");
code = json.intg("code");
prefix = "<body style=\"color:#fff;margin:0;padding:0;";
if(lineHeight!=null) prefix += "line-height:"+lineHeight+";";
prefix += "\">";
hasAQI = html.contains("%{aqi}");
hasCur = html.contains("%{current}") || html.contains("%{arr.0.");
hasDays = html.contains("%{arr.");
nextMs = System.currentTimeMillis() + 1800000;
refresh();
}
public void refresh() {
try {
var htm = html;
if(hasAQI) {
try {
JSList<JSMap> aqiForecast = JSMap.fromClose(new URLConn("https://www.ledokcloud.com/weather/whapi/json/alicityweather/aqiforecast5days").writeJson("{\"cityId\":"+code+"}").in()).jsmap("data").jslist("aqiForecast");
htm = htm.replace("%{aqi}", aqiForecast.get(1).stnn("value"));
} catch (Exception e) {
Util.printStackTrace(e);
}
}
String type = null;
if(hasCur) {
try {
var condition = JSMap.fromClose(new URLConn("https://www.ledokcloud.com/weather/whapi/json/alicityweather/condition").writeJson("{\"cityId\":"+code+"}").in()).jsmap("data").jsmap("condition");
htm = htm.replace("%{current}", condition.stnn("temp"));
htm = htm.replace("%{arr.0.type}", type = condition.stnn("condition"));
htm = htm.replace("%{arr.0.fx}", condition.stnn("windDir"));
htm = htm.replace("%{arr.0.fl}", condition.stnn("windLevel"));
} catch (Exception e) {
Util.printStackTrace(e);
}
}
if(hasDays) {
try {
JSList<JSMap> days = JSMap.fromClose(new URLConn("https://www.ledokcloud.com/weather/whapi/json/alicityweather/forecast15days").writeJson("{\"cityId\":"+code+"}").in()).jsmap("data").jslist("forecast");
int lastEnd = 0, appendIdx = 0;
var buf = new StringBuilder(htm.length()*3/2);
int start;
while((start = htm.indexOf("%{arr.", lastEnd)) > -1) {
int idxS = start+6, idxE;
try {
if(htm.charAt(idxS+1)=='.') idxE = idxS+1;
else if(htm.charAt(idxS+2)=='.') idxE = idxS+2;
else {
lastEnd = idxS;
continue;
}
var dd = Integer.parseInt(htm.substring(idxS, idxE))+1;
if(dd>=days.size()) {
lastEnd = idxE+1;
continue;
}
int fds = idxE+1, fde = idxE+2;
for(; fde<=fds+16; fde++) if(htm.charAt(fde)=='}') break;
if(fde > fds+16) {
lastEnd = fds;
continue;
}
var fd = htm.substring(fds, fde);
String replace = null;
if(fd.equals("date")) replace = days.get(dd).stnn("predictDate");
else if(fd.equals("type")) replace = days.get(dd).stnn("conditionDay");
else if(fd.equals("high")) replace = days.get(dd).stnn("tempDay");
else if(fd.equals("low")) replace = days.get(dd).stnn("tempNight");
else if(fd.equals("fx")) replace = days.get(dd).stnn("windDirDay");
else if(fd.equals("fl")) replace = days.get(dd).stnn("windLevelDay");
else if(fd.startsWith("img-")) {
var parts = Txts.split(fd, "-", 1);
String w = "32", h = "32";
if(parts.size()>=3) {
w = parts.get(1);
h = parts.get(2);
}
replace = "<img src=\"file:///android_asset/imgs/W" + dayImgMap.get(dd==1 ? type : days.get(dd).stnn("conditionDay")) + ".png\" style=\"width:"+w+"px; height:"+h+"px;\">";
}
lastEnd = fde+1;
if(replace!=null) {
buf.append(htm, appendIdx, start).append(replace);
appendIdx = lastEnd;
}
Util.println("Found: " + htm.substring(start, lastEnd)+" dd "+dd+" fd "+fd);
} catch (Exception e) {
lastEnd = idxS;
Util.printStackTrace(e);
}
}
if(buf.length()>0) {
if(appendIdx < htm.length()) buf.append(htm, appendIdx, htm.length());
htm = buf.toString();
}
} catch (Exception e) {
Util.printStackTrace(e);
}
}
loadDataWithBaseURL(null, prefix+htm+"</body>", "text/html", "UTF-8", null);
} catch (Exception e) {
Util.printStackTrace(e);
}
}
static HashMap<String, String> dayImgMap = new HashMap<>();
static HashMap<String, String> nitImgMap = new HashMap<>();
static{
dayImgMap.put("", "0");
dayImgMap.put("大部晴朗", "0");
dayImgMap.put("多云", "1");
dayImgMap.put("少云", "1");
dayImgMap.put("", "2");
dayImgMap.put("阵雨", "3");
dayImgMap.put("局部阵雨", "3");
dayImgMap.put("小阵雨", "3");
dayImgMap.put("强阵雨", "3");
dayImgMap.put("阵雪", "13");
dayImgMap.put("小阵雪", "13");
dayImgMap.put("", "18");
dayImgMap.put("冻雾", "18");
dayImgMap.put("沙尘暴", "20");
dayImgMap.put("浮尘", "29");
dayImgMap.put("尘卷风", "29");
dayImgMap.put("扬沙", "29");
dayImgMap.put("强沙尘暴", "20");
dayImgMap.put("", "45");
dayImgMap.put("雷阵雨", "4");
dayImgMap.put("雷电", "4");
dayImgMap.put("雷暴", "4");
dayImgMap.put("雷阵雨伴有冰雹", "5");
dayImgMap.put("冰雹", "5");
dayImgMap.put("冰针", "5");
dayImgMap.put("冰粒", "5");
dayImgMap.put("雨夹雪", "6");
dayImgMap.put("小雨", "7");
dayImgMap.put("中雨", "8");
dayImgMap.put("大雨", "9");
dayImgMap.put("暴雨", "10");
dayImgMap.put("大暴雨", "10");
dayImgMap.put("特大暴雨", "10");
dayImgMap.put("小雪", "14");
dayImgMap.put("中雪", "15");
dayImgMap.put("大雪", "16");
dayImgMap.put("暴雪", "17");
dayImgMap.put("冻雨", "19");
dayImgMap.put("", "15");
dayImgMap.put("", "8");
dayImgMap.put("小到中雨", "7");
dayImgMap.put("中到大雨", "9");
dayImgMap.put("大到暴雨", "10");
dayImgMap.put("小到中雪", "15");
dayImgMap.put("无天气类型", "unknown");
nitImgMap.put("", "30");
nitImgMap.put("大部晴朗", "30");
nitImgMap.put("多云", "31");
nitImgMap.put("少云", "31");
nitImgMap.put("", "2");
nitImgMap.put("阵雨", "33");
nitImgMap.put("局部阵雨", "33");
nitImgMap.put("小阵雨", "33");
nitImgMap.put("强阵雨", "33");
nitImgMap.put("阵雪", "34");
nitImgMap.put("小阵雪", "4");
nitImgMap.put("", "32");
nitImgMap.put("冻雾", "32");
nitImgMap.put("沙尘暴", "36");
nitImgMap.put("浮尘", "35");
nitImgMap.put("尘卷风", "5");
nitImgMap.put("扬沙", "35");
nitImgMap.put("强沙尘暴", "36");
nitImgMap.put("", "46");
nitImgMap.put("雷阵雨", "4");
nitImgMap.put("雷电", "4");
nitImgMap.put("雷暴", "4");
nitImgMap.put("雷阵雨伴有冰雹", "5");
nitImgMap.put("冰雹", "5");
nitImgMap.put("冰针", "5");
nitImgMap.put("冰粒", "5");
nitImgMap.put("雨夹雪", "6");
nitImgMap.put("小雨", "7");
nitImgMap.put("中雨", "8");
nitImgMap.put("大雨", "9");
nitImgMap.put("暴雨", "10");
nitImgMap.put("大暴雨", "10");
nitImgMap.put("特大暴雨", "10");
nitImgMap.put("小雪", "14");
nitImgMap.put("中雪", "15");
nitImgMap.put("大雪", "16");
nitImgMap.put("暴雪", "17");
nitImgMap.put("冻雨", "19");
nitImgMap.put("", "15");
nitImgMap.put("", "8");
nitImgMap.put("小到中雨", "7");
nitImgMap.put("中到大雨", "9");
nitImgMap.put("大到暴雨", "10");
nitImgMap.put("小到中雪", "15");
nitImgMap.put("无天气类型", "unknown");
}
long nextMs;
@Override
public void onVisibilityAggregated(boolean isVisible) {
super.onVisibilityAggregated(isVisible);
if(isVisible) {
var ms = System.currentTimeMillis();
if(ms>=nextMs) {
nextMs += 1800000;
refresh();
}
}
}
}