Android/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Prog.java
2025-08-20 23:02:25 +08:00

887 lines
45 KiB
Java

package com.xixun.xixunplayer;
import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.net.Uri;
import android.os.CountDownTimer;
import android.speech.tts.TextToSpeech;
import android.view.Choreographer;
import android.view.View;
import android.webkit.JavascriptInterface;
import android.webkit.WebView;
import android.widget.ImageView;
import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import gnph.util.JSList;
import gnph.util.JSMap;
import pl.droidsonroids.gif.GifImageView;
@SuppressLint("ViewConstructor")
public class Prog extends AbsLayout {
ArrayList<Page> pages = new ArrayList<>();
ArrayList<Choreographer.FrameCallback> calls = new ArrayList<>();
boolean isInsert;
@SuppressLint("SetJavaScriptEnabled")
public Prog(JSMap task, Context context) {
super(context);
isInsert = task.bool("insert");
JSList<JSMap> jpages = task.jslist("items");
JSList<Long> partLengths = task.jslist("partLengths");
var isVertical = task.bool("isVertical");
var partObj = task;
if(partLengths==null) {
try {
var _program = jpages.get(0).jsmap("_program");
partLengths = _program.jslist("splitWidths");
isVertical = _program.bool("isVer");
partObj = _program;
} catch (Throwable ignored){}
}
var width = partObj.intg("width");
var height = partObj.intg("height");
if(Util.custom==Util.Custom.Yishi) {
if(width==0) width = Util.screenWidth;
if(height==0) height = Util.screenHeight;
}
AbsLayout box;
if(partLengths==null || partLengths.size() <= 1) box = this;
else {
box = new AbsLayout(context);
addView(box, new AbsLayout.LayoutParams(0, 0, width, height));
var mask = new View(context);
mask.setBackgroundColor(0xff000000);
var len0 = partLengths.get(0).intValue();
addView(mask, isVertical ? new AbsLayout.LayoutParams(0, len0, width, height - len0) : new AbsLayout.LayoutParams(len0, 0, width - len0, height));
int x = 0, y = 0;
for(int i=1; i<partLengths.size(); i++) {
var part = new SrcCopy(context, new Source(box));
if(isVertical) {
y -= partLengths.get(i-1);
x += width;
addView(part, new AbsLayout.LayoutParams(x, y, width, partLengths.get(i).intValue() - y));
} else {
x -= partLengths.get(i-1);
y += height;
addView(part, new AbsLayout.LayoutParams(x, y, partLengths.get(i).intValue() - x, height));
}
}
}
for(var pageMap : jpages) {
var _program = pageMap.jsmap("_program");
JSList<JSMap> layers = _program.jslist("layers");
var isSimple = _program.intg("version")==2;
if(layers==null || layers.isEmpty()) continue;
if(isSimple) {
width = _program.intg("width", Util.screenWidth);
height = _program.intg("height", Util.screenHeight);
}
var page = new Page();
page.id = _program.str("_id");
page.name = _program.str("name");
page.type = "advanced";
page.repeatTimes = pageMap.intg("repeatTimes", 1);
page.parse(pageMap.jslist("schedules"));
var waitAudio = pageMap.bool("waitAudio");
HashMap<String, Prog.Source> videoMap = new HashMap<>();
for(int ll=layers.size()-1; ll>=0; ll--) {
var layer = new Layer();
layer.isLoop = layers.get(ll).bool("repeat");
JSList<JSMap> sources = layers.get(ll).jslist("sources");
var border = layers.get(ll).jsmap("border");
SrcBorder bdEle = null;
int bdWidth = 0, bdStart = Integer.MAX_VALUE, bdEnd = 0;
if(border!=null) {
bdEle = new SrcBorder(this, Util.programDir+"/"+border.stnn("img"), border.stnn("eff"), border.intg("speed"));
bdWidth = bdEle.img.getHeight();
}
var src = new Source();
for(var source : sources) {
src.type = source.stnn("_type");
if(src.type.isEmpty()) continue;
var dur = source.intg("timeSpan")*1000;
if(dur==0) {
Util.println("\nError: timeSpan is 0. _type: "+src.type);
continue;
}
var geo = isSimple ? new AbsLayout.LayoutParams(0, 0, width, height) : new AbsLayout.LayoutParams(source.intg("left")+bdWidth, source.intg("top")+bdWidth, source.intg("width")-bdWidth-bdWidth, source.intg("height")-bdWidth-bdWidth);
var notAudio = ! src.type.equals("Audio");
if(notAudio) {
if(geo.width<=0 || geo.height<=0) {
if(Util.custom==Util.Custom.Yishi) {
geo.width = width;
geo.height = height;
} else {
Util.println("\nError: width or height is 0. _type: "+src.type+" width: "+geo.width+" height: "+geo.height);
continue;
}
}
if(box != this && ((geo.y>=height && height>0) || (geo.x>=width && width>0))) {
Util.println("\nError: y>=height or x>=width. _type: "+src.type+" width: "+width+" height: "+height+" x: "+geo.x+" y: "+geo.y);
continue;
}
}
src.startTime = isSimple ? (layer.srcs.isEmpty() ? 0 : layer.srcs.get(layer.srcs.size()-1).endTime) : source.intg("playTime")*1000;
if(bdStart > src.startTime) bdStart = src.startTime;
src.endTime = src.startTime + dur;
if(bdEnd < src.endTime) bdEnd = src.endTime;
if(layer.dur < src.endTime) layer.dur = src.endTime;
if(notAudio || waitAudio) {
if(page.sDur < src.endTime) page.sDur = src.endTime;
} else if(page.audioDur < src.endTime) page.audioDur = src.endTime;
src.entryDur = source.intg("entryEffectTimeSpan")*60;
if(src.entryDur > 0) {
var effect = source.str("entryEffect");
if(effect == null || effect.equalsIgnoreCase("None")) src.entryDur = 0;
else if(effect.equalsIgnoreCase("Random")) src.isEntryRand = true;
else {
effect = effect.replace("MOVING", "MOVE");
effect = effect.replace("LEFT_TOP", "TL");
effect = effect.replace("RIGHT_TOP", "TR");
effect = effect.replace("RIGHT_BOTTOM", "BR");
effect = effect.replace("LEFT_BOTTOM", "BL");
effect = effect.replace("ALPHA", "FADE");
effect = effect.replace("_IN", "");
effect = effect.replace("_OUT", "");
try {
src.entryEff = Effect.valueOf(effect);
} catch (Throwable e) {
if(effect.equalsIgnoreCase("ROTATE_RIGHT")) src.entryEff = Effect.ROTATE;
else if(effect.equalsIgnoreCase("ROTATE_LEFT")) src.entryEff = Effect.ROTATE_R;
else src.entryDur = 0;
}
}
}
src.exitDur = source.intg("exitEffectTimeSpan")*60;
if(src.exitDur > 0) {
var effect = source.str("exitEffect");
if(effect == null || effect.equalsIgnoreCase("None")) src.exitDur = 0;
else if(effect.equalsIgnoreCase("Random")) src.isExitRand = true;
else {
effect = effect.replace("MOVING", "MOVE");
effect = effect.replace("LEFT_TOP", "TL");
effect = effect.replace("RIGHT_TOP", "TR");
effect = effect.replace("RIGHT_BOTTOM", "BR");
effect = effect.replace("LEFT_BOTTOM", "BL");
effect = effect.replace("ALPHA", "FADE");
effect = effect.replace("_IN", "");
effect = effect.replace("_OUT", "");
try {
src.exitEff = Effect.valueOf(effect);
} catch (Throwable e) {
if(effect.equalsIgnoreCase("ROTATE_RIGHT")) src.exitEff = Effect.ROTATE;
else if(effect.equalsIgnoreCase("ROTATE_LEFT")) src.exitEff = Effect.ROTATE_R;
else src.exitDur = 0;
}
}
}
if(src.exitDur!=0) src.exitStart = dur*60/1000 - src.exitDur;
src.alpha = (float) source.dbl("opacity", 1);
var breathe = source.dbl("breathe");
if(breathe > 0) src.breathe = (int) Math.round(60 / breathe);
var blink = source.dbl("blink");
if(blink > 0) src.blinkHalf = (int) Math.round(30 / blink);
src.rotate = (float) source.dbl("rotate");
src.scaleX = (float) source.dbl("scaleX", 1);
src.scaleY = (float) source.dbl("scaleY", 1);
var id = source.str("id");
var fileExt = source.stnn("fileExt");
if(id!=null && fileExt.startsWith(".") && new File(Util.programDir + "/" + id + fileExt).exists()) id += fileExt;
src.view = null;
if(src.type.equals("Image")) {
if(id==null) continue;
var isGif = fileExt.toLowerCase().endsWith("gif");
if(isGif) {
var imgView = new GifImageView(context);
imgView.setImageURI(src.uri = Uri.fromFile(new File(Util.programDir + "/" + id)));
imgView.setScaleType(ImageView.ScaleType.FIT_XY);
src.view = imgView;
} else {
var imgView = new ImageView(context);
var file = Util.programDir+"/"+id;
new Thread(()->{
try {
var ttt = System.currentTimeMillis();
var img = BitmapFactory.decodeFile(file);
// if(img.getByteCount()>1500*1500*4) {
// var matrix = new Matrix();
// matrix.setScale(0.5f, 0.5f);
// img = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true);
// }
ttt = System.currentTimeMillis() - ttt;
Util.println(" img "+img.getWidth()+"x"+img.getHeight()+" "+ttt);
Bitmap finalImg = img;
MainActivity.ins.runOnUiThread(() -> imgView.setImageBitmap(finalImg));
} catch (Throwable e) {
var stackTrace = Util.toStackTrace(e);
Util.println(stackTrace);
var img = Bitmap.createBitmap(600, 400, Bitmap.Config.ARGB_8888);
var paint = new Paint();
paint.setColor(Color.RED);
new Canvas(img).drawText(stackTrace, 0, 0, paint);
MainActivity.ins.runOnUiThread(() -> imgView.setImageBitmap(img));
}
}).start();
imgView.setScaleType(ImageView.ScaleType.FIT_XY);
src.view = imgView;
}
} else if(src.type.endsWith("Video")) {
var isLive = src.type.startsWith("Live");
var url = source.str("url");
if(isLive) {
if(url==null) continue;
} else if(id==null) continue;
var key = isLive ? url : id + src.startTime + src.endTime;
var exist = videoMap.get(key);
if(exist!=null) {
if(geo.width * geo.height > exist.geo.width * exist.geo.height) {
var aaa = exist.geo;
exist.geo = geo;
geo = aaa;
}
src.view = new SrcCopy(context, exist);
((SrcCopy) src.view).scaleX = 0;
} else {
videoMap.put(key, src);
src.typ = 'V';
src.path = isLive ? url : Util.programDir+"/"+id;
src.vol = source.intg("vol", 100) / 100.0f;
src.dur = dur;
src.useSW = source.bool("useSW");
src.geo = geo;
src.box = source.bool("isPreSplit") ? this : box;
layer.srcs.add(src);
src = new Source();
}
} else if(src.type.equals("Audio")) {
if(id==null) continue;
src.typ = 'A';
src.path = Util.programDir + "/" +id;
src.vol = source.intg("vol", 100) / 100.0f;
src.dur = dur;
src.geo = geo;
src.box = box;
layer.srcs.add(src);
src = new Source();
} else if(src.type.equals("Scroll")) {
JSList<String> imgs = source.jslist("imgs");
if(imgs.isEmpty()) continue;
var images = new ArrayList<Bitmap>();
for(var img : imgs) images.add(BitmapFactory.decodeFile(Util.programDir+"/"+img));
var directStr = source.str("direct");
src.view = new SrcScroll(this, images, directStr==null ? 0 : directStr.charAt(0), source.dbl("speed"));
src.text = source.str("tts");
if(src.text!=null) {
src.tts = new TextToSpeech(context, (int status)->{
Util.println("status: "+status+" "+(status==TextToSpeech.SUCCESS));
}, "com.iflytek.speechcloud");
src.tts.setSpeechRate((float) source.dbl("speechRate"));
}
} else if(src.type.startsWith("MultiPng") || src.type.equals("SplitText")) {
JSList<JSMap> imgs = source.jslist("arrayPics");
if(imgs.isEmpty()) continue;
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);
var images = new ArrayList<Bitmap>();
images.add(BitmapFactory.decodeFile(Util.programDir+"/"+img.stnn("id")));
var speed = img.dbl("scrollSpeed");
if(speed==0) {
var scrollDur = img.dbl("effectSpeed");
if(scrollDur!=0) speed = 1000 / scrollDur;
}
char direct = 0;
var directStr = img.str("effect");
if(directStr!=null && ! directStr.equals("no")) {
int idx = directStr.lastIndexOf(' ');
if(idx > -1) direct = directStr.charAt(idx+1);
}
src.view = new SrcScroll(this, images, direct, speed);
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 ele0 = src;
for(var map : imgs) {
var picDur = map.intg("picDuration")*1000;
if(picDur==0) picDur = dur / imgs.size();
src.type = "Image";
if(src!=ele0) {
src.startTime = layer.srcs.get(layer.srcs.size()-1).endTime;
src.entryEff = ele0.entryEff;
src.exitEff = ele0.exitEff;
src.entryDur = ele0.entryDur;
src.exitDur = ele0.exitDur;
src.exitStart = ele0.exitStart;
src.isEntryRand = ele0.isEntryRand;
src.isExitRand = ele0.isExitRand;
src.alpha = ele0.alpha;
src.breathe = ele0.breathe;
src.blinkHalf = ele0.blinkHalf;
src.rotate = ele0.rotate;
src.scaleX = ele0.scaleX;
src.scaleY = ele0.scaleY;
}
src.endTime = src.startTime + picDur;
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);
src.view = imgView;
src.view.setVisibility(GONE);
src.view.setLayoutParams(geo);
box.addView(src.view);
layer.srcs.add(src);
src = new Source();
}
}
} else if(src.type.equals("DigitalClock")) src.view = new SrcDigitalClock(this, source);
else if(src.type.startsWith("DigitalClock")) src.view = new SrcDigiClock(this, source);
else if(src.type.equals("AnalogClock")) src.view = new SrcAnaClock(this, geo.width, geo.height, Util.programDir + "/" + id, source);
else if(src.type.equals("WebURL")) {
var url = source.str("url");
if(url!=null) src.view = new SrcWeb(this, url, source);
} else if(src.type.equals("Timer")) src.view = new SrcTimer(this, source);
else if(src.type.equals("Countdown")) src.view = new SrcCountdown(this, source);
else if(src.type.startsWith("Environ")) src.view = new SrcEnviron(this, source);
else if(src.type.startsWith("Weather")) src.view = new SrcWeather(context, source);
else if(src.type.startsWith("VistorSource")) src.view = new SrcVisitor(this, source);
else if(src.type.startsWith("MultiLineText")) src.view = new SrcSensor(this, source, geo.width, geo.height);
else if(src.type.startsWith("SingleLineText")) {
var webView = new WebView(context);
webView.getSettings().setJavaScriptEnabled(true);
webView.setVerticalScrollBarEnabled(false);
webView.setHorizontalScrollBarEnabled(false);
webView.setBackgroundColor(Color.TRANSPARENT);
webView.setInitialScale(100);
webView.setLayoutParams(new AbsLayout.LayoutParams(0, -geo.height, geo.width, geo.height));
var html = source.stnn("html");
var prefix = "<body style=\"color:#fff; margin:0; padding:0; white-space:nowrap; ";
var lineHeight = source.get("lineHeight");
if(lineHeight!=null) prefix += "line-height:"+lineHeight+";";
var fontSize = lineHeight instanceof Number ? geo.height / ((Number)lineHeight).doubleValue() : geo.height;
prefix += "height:"+geo.height+"; font-size:"+fontSize+"px;\">";
var suffix = "</body><script>window.onload = function() {\n" +
"window.java.setWidth(document.body.scrollWidth);};</script>";
var speed = source.dbl("speed");
if(speed!=0) speed = 1000.0 / speed;
var imgs = new ArrayList<Bitmap>();
imgs.add(Bitmap.createBitmap(geo.width, geo.height, Bitmap.Config.ARGB_8888));
var view = new SrcScroll(this, imgs, 'l', speed);
src.view = view;
webView.addJavascriptInterface(new Object() {
@JavascriptInterface
public void setWidth(int width) {
MainActivity.ins.runOnUiThread(() -> {
var hhh = view.imgs.get(0).getHeight();
var www = width + hhh;
webView.getLayoutParams().width = www;
view.imgs.set(0, Bitmap.createBitmap(www, hhh, Bitmap.Config.ARGB_8888));
addView(webView);
var atimer = new CountDownTimer(500, 500) {
@Override
public void onTick(long millisUntilFinished) {}
@Override
public void onFinish() {
var canvas = new Canvas(view.imgs.get(0));
webView.draw(canvas);
webView.setVisibility(GONE);
view.freshCnt = view.cur = 0;
if(view.direct=='l') view.end = -(view.imgs.get(0).getWidth()-view.step);
else if(view.direct=='r') view.end = view.imgs.get(0).getWidth()-view.step;
view.invalidate();
}
};
if(isShown()) atimer.start();
else timer = atimer;
});
}
}, "java");
webView.loadDataWithBaseURL(null, prefix+html+suffix, "text/html", "UTF-8", null);
}
else continue;
if(src.view==null) continue;
src.view.setVisibility(GONE);
src.view.setLayoutParams(geo);
(source.bool("isPreSplit") ? this : box).addView(src.view);
layer.srcs.add(src);
src = new Source();
}
if(bdEle!=null && bdStart < bdEnd) {
JSList<Long> geometry = border.jslist("geometry");
src.startTime = bdStart;
src.endTime = bdEnd;
src.rotate = (float) border.dbl("rotate");
src.view = bdEle;
src.view.setVisibility(GONE);
box.addView(src.view, new AbsLayout.LayoutParams(geometry.get(0).intValue(), geometry.get(1).intValue(), geometry.get(2).intValue(), geometry.get(3).intValue()));
layer.srcs.add(src);
}
if(! layer.srcs.isEmpty()) page.layers.add(layer);
}
if(page.sDur==0) {
if(page.audioDur > 0) page.sDur = page.audioDur;
else continue;
}
page.tDur = page.sDur * page.repeatTimes;
for_layer: for(int ll=0; ll<page.layers.size(); ll++) {
var layer = page.layers.get(ll);
for(int ss=0; ss<layer.srcs.size(); ss++) {
var src = layer.srcs.get(ss);
if(src.startTime >= page.sDur) {
if(layer.srcs.size() > 1) layer.srcs.remove(ss--);
else {
page.layers.remove(ll--);
continue for_layer;
}
} else if(src.endTime > page.sDur) src.endTime = page.sDur;
}
if(layer.dur > page.sDur) layer.dur = page.sDur;
if(layer.dur == page.sDur) layer.isLoop = false;
}
pages.add(page);
}
}
void release() {
try {
setVisibility(GONE);
View view;
for(int cc=0; cc<getChildCount(); cc++) if((view = getChildAt(cc)) instanceof SrcVideo) ((SrcVideo) 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);
}
}
CountDownTimer timer;
@Override
public void onVisibilityAggregated(boolean isVisible) {
super.onVisibilityAggregated(isVisible);
if(isVisible) {
if(timer!=null) {
timer.start();
timer = null;
}
}
}
public static class Source {
AbsLayout.LayoutParams geo;
View view;
float alpha = 1, rotate, scaleX = 1, scaleY = 1;
long startMilli, endMilli = Long.MAX_VALUE;
int startTime, entryDur, exitStart = Integer.MAX_VALUE, exitDur, endTime, ff, breathe, blinkHalf;
Effect entryEff, exitEff;
String type;
Uri uri;
TextToSpeech tts;
String text;
boolean isShow, isEntryRand, isExitRand;
char typ, alphaShow = 1;
AbsLayout box;
String path;
float vol;
int dur;
boolean useSW;
public Source() {
}
public Source(View view) {
this.view = view;
}
void show() {
if(typ=='V') {
if(alphaShow==1) return;
((SrcVideo)view).ijkPlayer.start();
view.setAlpha((alphaShow = 1) * alpha);
} else {
if(view.getVisibility()==VISIBLE) return;
view.setVisibility(VISIBLE);
}
ff = 0;
if(isEntryRand) entryEff = Effect.values()[Util.rand.nextInt(Effect.values().length)];
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(typ=='V') {
if(alphaShow==0) return;
view.setAlpha(alphaShow = 0);
((SrcVideo)view).ijkPlayer.pause();
((SrcVideo)view).ijkPlayer.seekTo(0);
} else {
if(view.getVisibility() != VISIBLE) return;
view.setVisibility(GONE);
}
if(view instanceof GifImageView) ((GifImageView) view).setImageURI(uri);
if(tts!=null && tts.isSpeaking()) tts.stop();
}
void prepare(long seek) {
var ms = System.currentTimeMillis();
if(view==null) {
var video = new SrcVideo(box.getContext(), path, vol, dur, seek, useSW);
video.setLayoutParams(geo);
video.setAlpha(alphaShow = 0);
video.setVisibility(VISIBLE);
box.addView(view = video);
}
ms = System.currentTimeMillis() - ms;
Util.println(" prepare ms "+ms);
}
void release() {
if(view instanceof SrcVideo) {
((SrcVideo)view).release();
box.removeView(view);
view = null;
}
}
void doEff() {
var w = view.getLayoutParams().width;
var h = view.getLayoutParams().height;
if(ff < entryDur) {
if(entryEff == Effect.EXPAND_HOR) setScaleX(ff / (float) entryDur);
else if(entryEff == Effect.EXPAND_VER) setScaleY(ff / (float) entryDur);
else if(entryEff == Effect.EXPAND_LEFT) {
setScaleX(ff / (float) entryDur);
view.setTranslationX((1 - view.getScaleX()) * w / 2);
} else if(entryEff == Effect.EXPAND_TOP) {
setScaleY(ff / (float) entryDur);
view.setTranslationY((1 - view.getScaleY()) * h / 2);
} else if(entryEff == Effect.EXPAND_RIGHT) {
setScaleX(ff / (float) entryDur);
view.setTranslationX((view.getScaleX() - 1) * w / 2);
} else if(entryEff == Effect.EXPAND_BOTTOM) {
setScaleY(ff / (float) entryDur);
view.setTranslationY((view.getScaleY() - 1) * h / 2);
}
else if(entryEff == Effect.MOVE_LEFT) view.setTranslationX(w - ff*w/(float) entryDur);
else if(entryEff == Effect.MOVE_TOP) view.setTranslationY(h - ff*h/(float) entryDur);
else if(entryEff == Effect.MOVE_RIGHT) view.setTranslationX(ff*w/(float) entryDur - w);
else if(entryEff == Effect.MOVE_BOTTOM) view.setTranslationY(ff*h/(float) entryDur - h);
else if(entryEff == Effect.FADE) view.setAlpha(alphaShow * alpha * ff / entryDur);
else if(entryEff == Effect.ZOOM) {
setScaleX(ff / (float) entryDur);
setScaleY(view.getScaleX());
} else if(entryEff == Effect.ZOOM_TL) {
var rate = ff / (float) entryDur;
view.setTranslationX((rate - 1) * w / 2);
view.setTranslationY((rate - 1) * h / 2);
setScaleX(rate);
setScaleY(rate);
} else if(entryEff == Effect.ZOOM_BR) {
var rate = ff / (float) entryDur;
view.setTranslationX((1 - rate) * w / 2);
view.setTranslationY((1 - rate) * h / 2);
setScaleX(rate);
setScaleY(rate);
} else if(entryEff == Effect.ZOOM_TR) {
var rate = ff / (float) entryDur;
view.setTranslationX((1 - rate) * w / 2);
view.setTranslationY((rate - 1) * h / 2);
setScaleX(rate);
setScaleY(rate);
} else if(entryEff == Effect.ZOOM_BL) {
var rate = ff / (float) entryDur;
view.setTranslationX((rate - 1) * w / 2);
view.setTranslationY((1 - rate) * h / 2);
setScaleX(rate);
setScaleY(rate);
} else if(entryEff == Effect.ROTATE) {
setScaleX(ff / (float) entryDur);
setScaleY(view.getScaleX());
view.setRotation(rotate + view.getScaleX() * 360);
} else if(entryEff == Effect.ROTATE_R) {
setScaleX(ff / (float) entryDur);
setScaleY(view.getScaleX());
view.setRotation(rotate - view.getScaleX() * 360);
}
} else if(ff>=exitStart) {
if(ff-1 <= exitStart && (blinkHalf!=0 || breathe!=0)) view.setAlpha(alphaShow * alpha);
var fff = ff - exitStart;
if(fff > exitDur) fff = exitDur;
if(exitEff == Effect.EXPAND_HOR) setScaleX(1 - fff / (float) exitDur);
else if(exitEff == Effect.EXPAND_VER) setScaleY(1 - fff / (float) exitDur);
else if(exitEff == Effect.EXPAND_LEFT) {
var rate = fff / (float) exitDur;
setScaleX(1 - rate);
view.setTranslationX(rate * w / 2);
} else if(exitEff == Effect.EXPAND_TOP) {
var rate = fff / (float) exitDur;
view.setScaleY(1 - rate);
view.setTranslationY(rate * h / 2);
} else if(exitEff == Effect.EXPAND_RIGHT) {
var rate = fff / (float) exitDur;
setScaleX(1 - rate);
view.setTranslationX(- rate * w / 2);
} else if(exitEff == Effect.EXPAND_BOTTOM) {
var rate = fff / (float) exitDur;
setScaleY(1 - rate);
view.setTranslationY(- rate * h / 2);
}
else if(exitEff == Effect.MOVE_LEFT) view.setTranslationX(- fff*w / (float) exitDur);
else if(exitEff == Effect.MOVE_RIGHT) view.setTranslationX(fff*w / (float) exitDur);
else if(exitEff == Effect.MOVE_TOP) view.setTranslationY(- fff*h / (float) exitDur);
else if(exitEff == Effect.MOVE_BOTTOM) view.setTranslationY(fff*h / (float) exitDur);
else if(exitEff == Effect.FADE) view.setAlpha(alphaShow * (alpha - alpha * fff / exitDur));
else if(exitEff == Effect.ZOOM) {
setScaleX(1 - fff / (float) exitDur);
setScaleY(view.getScaleX());
} else if(exitEff == Effect.ZOOM_TL) {
var rate = fff / (float) exitDur;
view.setTranslationX(- rate * w / 2);
view.setTranslationY(- rate * h / 2);
setScaleX(1 - rate);
setScaleY(1 - rate);
} else if(exitEff == Effect.ZOOM_BR) {
var rate = fff / (float) exitDur;
view.setTranslationX(rate * w / 2);
view.setTranslationY(rate * h / 2);
setScaleX(1 - rate);
setScaleY(1 - rate);
} else if(exitEff == Effect.ZOOM_TR) {
var rate = fff / (float) exitDur;
view.setTranslationX(rate * w / 2);
view.setTranslationY(- rate * h / 2);
setScaleX(1 - rate);
setScaleY(1 - rate);
} else if(exitEff == Effect.ZOOM_BL) {
var rate = fff / (float) exitDur;
view.setTranslationX(- rate * w / 2);
view.setTranslationY(rate * h / 2);
setScaleX(1 - rate);
setScaleY(1 - rate);
} else if(exitEff == Effect.ROTATE) {
var rate = fff / (float) exitDur;
setScaleX(1 - rate);
setScaleY(view.getScaleX());
view.setRotation(rotate + rate * 360);
} else if(exitEff == Effect.ROTATE_R) {
var rate = fff / (float) exitDur;
setScaleX(1 - rate);
setScaleY(view.getScaleX());
view.setRotation(rotate - rate * 360);
}
} else {
resetEff();
if(blinkHalf!=0) view.setAlpha((ff / blinkHalf & 1) == 0 ? alphaShow * alpha : 0);
else if(breathe!=0) view.setAlpha((float) (Math.cos(ff%breathe*2*Math.PI/breathe)/2+0.5));
}
ff++;
}
void resetEff() {
view.setTranslationX(0);
view.setTranslationY(0);
view.setAlpha(alphaShow * alpha);
view.setScaleX(scaleX);
view.setScaleY(scaleY);
view.setRotation(rotate);
}
void setScaleX(float val) {
view.setScaleX(scaleX*val);
}
void setScaleY(float val) {
view.setScaleY(scaleY*val);
}
}
public static class Layer {
ArrayList<Source> srcs = new ArrayList<>();
long endMilli = Long.MAX_VALUE;
int dur;
boolean isLoop;
}
public enum Effect {
EXPAND_HOR, EXPAND_VER, EXPAND_LEFT, EXPAND_TOP, EXPAND_RIGHT, EXPAND_BOTTOM,
ZOOM, ZOOM_TL, ZOOM_TR, ZOOM_BR, ZOOM_BL,
ROTATE, ROTATE_R,
FADE,
MOVE_LEFT, MOVE_TOP, MOVE_RIGHT, MOVE_BOTTOM,
}
public static class Sche {
long startDate = -1, endDate = -1;
int startTime = -1, endTime = -1;
HashSet<Integer> weeks;
}
public static class Page {
String id, name, type;
ArrayList<Layer> layers = new ArrayList<>();
ArrayList<Sche> sches;
long endMilli = Long.MAX_VALUE;
int sDur, tDur, repeatTimes, audioDur;
void hide() {
for(var layer : layers) for(var src : layer.srcs) src.hide();
}
void setMillis(long start, long cur, List<MainActivity.ShowHide> shows) {
endMilli = start + sDur;
for(var layer : layers) {
if(layer.isLoop) layer.endMilli = start + layer.dur;
for(var src : layer.srcs) {
src.endMilli = start + src.endTime;
src.startMilli = start + src.startTime;
if(src.startTime == 0) {
src.prepare(cur - src.startMilli);
shows.add(new MainActivity.ShowHide(src.startMilli+1000, src, 'S'));
src.isShow = true;
}
}
}
if(Util.logOn) {
var values = new ContentValues();
values.put("time", cur);
values.put("dur", sDur);
values.put("id", id);
values.put("name", name);
values.put("type", type);
values.put("lat", Util.lat);
values.put("lng", Util.lng);
LogThread.rows.add(values);
}
}
void showHideSrcs(long milli, List<MainActivity.ShowHide> shows) {
for(var layer : layers) {
for(var src : layer.srcs) {
if(src.isShow) {
if(milli >= src.endMilli) {
shows.add(new MainActivity.ShowHide(src.endMilli+1000, src, 'H'));
src.isShow = false;
}
else src.doEff();
} else if(milli < src.endMilli && milli >= src.startMilli) {
src.prepare(milli - src.startMilli);
shows.add(new MainActivity.ShowHide(src.startMilli+1000, src, 'S'));
src.isShow = true;
}
}
if(milli >= layer.endMilli) {
layer.endMilli += layer.dur;
for(var src : layer.srcs) {
src.endMilli += layer.dur;
src.startMilli += layer.dur;
if(src.startTime > 0) {
shows.add(new MainActivity.ShowHide(src.startMilli+1000, src, 'H'));
src.isShow = false;
} else {
src.prepare(0);
shows.add(new MainActivity.ShowHide(src.startMilli+1000, src, 'S'));
src.isShow = true;
}
}
}
}
}
boolean isScheOn(long milli) {
if(sches==null) return false;
var local = milli + TimeZone.getDefault().getOffset(milli);
int week = -1;
for(var sche : sches) {
if(notInRange(sche.startDate, local, sche.endDate)) continue;
if(notInRange(sche.startTime, local % 86400000L, sche.endTime)) continue;
if(sche.weeks==null) return true;
if(week==-1) week = ((int)(local / 86400000L) + 4) % 7;
if(sche.weeks.contains(week)) return true;
}
return false;
}
public boolean notInRange(long start, long val, long end) {
if(end==-1) return false;
return start <= end ? !(val >= start && val < end) : val >= end && val < start;
}
SimpleDateFormat dateFmt = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat timeFmt = new SimpleDateFormat("HH:mm:ss");
{
var zone = new SimpleTimeZone(0, "0");
dateFmt.getCalendar().setTimeZone(zone);
timeFmt.getCalendar().setTimeZone(zone);
}
public void parse(JSList<JSMap> schedules) {
if(schedules!=null) for(var schedule : schedules) {
var sche = new Sche();
var startTime = schedule.str("startTime");
if(startTime!=null) {
if(startTime.length()<=5) startTime += ":00";
try {
sche.startTime = (int)timeFmt.parse(startTime).getTime();
Util.println("startTime "+timeFmt.format(sche.startTime)+" "+sche.startTime);
} catch (ParseException e) {
Util.printStackTrace(e);
}
}
var endTime = schedule.str("endTime");
if(endTime!=null) {
if(endTime.length()<=5) endTime += ":00";
try {
sche.endTime = (int)timeFmt.parse(endTime).getTime();
Util.println("endTime "+timeFmt.format(sche.endTime)+" "+sche.endTime);
} catch (ParseException e) {
Util.printStackTrace(e);
}
}
if(sche.startTime==sche.endTime) sche.startTime = sche.endTime = -1;
var startDate = schedule.str("startDate");
if(startDate!=null) {
try {
sche.startDate = dateFmt.parse(startDate).getTime();
} catch (ParseException e) {
Util.printStackTrace(e);
}
}
var endDate = schedule.str("endDate");
if(endDate!=null) {
try {
sche.endDate = dateFmt.parse(endDate).getTime() + 86400000L;
} catch (ParseException e) {
Util.printStackTrace(e);
}
}
if(sche.startDate==sche.endDate) sche.startDate = sche.endDate = -1;
JSList<Long> weekFilter = schedule.jslist("weekFilter");
if(weekFilter!=null && ! weekFilter.isEmpty() && weekFilter.size() < 7) {
sche.weeks = new HashSet<>();
for(var week : weekFilter) sche.weeks.add(week.intValue() % 7);
}
if(sches==null) sches = new ArrayList<>();
sches.add(sche);
}
}
}
}