[2.13.0-arch-opt] wait to pull
@@ -6,6 +6,7 @@ import android.graphics.Bitmap;
|
||||
import com.mogo.eagle.core.data.map.entity.V2XRoadEventEntity;
|
||||
import com.mogo.eagle.core.function.v2x.R;
|
||||
import com.mogo.eagle.core.data.enums.EventTypeEnum;
|
||||
import com.mogo.eagle.core.function.v2x.events.view.V2XMarkerRoadEventView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
package com.mogo.eagle.core.function.v2x.events.view;
|
||||
|
||||
import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_V2X;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.SurfaceView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import com.mogo.cloud.trafficlive.api.ITrafficCarLiveCallBack;
|
||||
import com.mogo.cloud.trafficlive.api.MoGoAiCloudTrafficLive;
|
||||
import com.mogo.commons.voice.AIAssist;
|
||||
import com.mogo.eagle.core.data.map.MogoLocation;
|
||||
import com.mogo.eagle.core.function.call.map.CallerMapLocationListenerManager;
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
|
||||
import com.mogo.eagle.core.function.v2x.R;
|
||||
import com.mogo.eagle.core.function.v2x.events.voice.V2XVoiceCallbackListener;
|
||||
import com.mogo.eagle.core.function.v2x.events.voice.V2XVoiceConstants;
|
||||
import com.mogo.eagle.core.function.v2x.events.voice.V2XVoiceManager;
|
||||
import com.mogo.eagle.core.utilcode.util.Utils;
|
||||
import com.mogo.eagle.core.widget.RoundLayout;
|
||||
import com.mogo.map.location.IMogoLocationClient;
|
||||
|
||||
/**
|
||||
* @author liujing
|
||||
* @description 描述
|
||||
* @since: 2021/2/23
|
||||
*/
|
||||
public class CarZegoLiveVideoView extends RoundLayout {
|
||||
private static final String TAG = "CarZegoLiveVideoView";
|
||||
private SurfaceView mSurfaceView;
|
||||
private ProgressBar mLoading;
|
||||
private ConstraintLayout mClLoadError;
|
||||
private String liveSn;
|
||||
|
||||
// 重新刷新直播流
|
||||
private final V2XVoiceCallbackListener v2XVoiceCallbackRefreshListener = new V2XVoiceCallbackListener() {
|
||||
@Override
|
||||
public void onCallback(String command, Intent intent) {
|
||||
mLoading.setVisibility(VISIBLE);
|
||||
mClLoadError.setVisibility(GONE);
|
||||
startLive();
|
||||
}
|
||||
};
|
||||
|
||||
public CarZegoLiveVideoView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public CarZegoLiveVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
initView(context);
|
||||
}
|
||||
|
||||
private void initView(Context context) {
|
||||
LayoutInflater.from(context)
|
||||
.inflate(R.layout.view_video_layout_see_live, this);
|
||||
mSurfaceView = findViewById(R.id.surfaceView);
|
||||
mSurfaceView.setZOrderOnTop(true);
|
||||
mLoading = findViewById(R.id.loading);
|
||||
mLoading.getIndeterminateDrawable().setColorFilter(ContextCompat.getColor(context, R.color.live_video_progress_bar_loading_color), PorterDuff.Mode.MULTIPLY);
|
||||
|
||||
mClLoadError = findViewById(R.id.clLoadError);
|
||||
TextView mTvRefreshButton = findViewById(R.id.tvRefreshButton);
|
||||
mTvRefreshButton.setOnClickListener(v -> {
|
||||
mLoading.setVisibility(VISIBLE);
|
||||
mClLoadError.setVisibility(GONE);
|
||||
startLive();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始直播
|
||||
*/
|
||||
public void startLive() {
|
||||
if (mSurfaceView != null) {
|
||||
//AIAssist.getInstance(AbsMogoApplication.getApp()).speakTTSVoice(AbsMogoApplication.getApp().getString(R.string.v2x_voice_see_front_car_live));
|
||||
playLiveVideo();
|
||||
mClLoadError.setVisibility(GONE);
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "startLive");
|
||||
} else {
|
||||
//AIAssist.getInstance(AbsMogoApplication.getApp()).speakTTSVoice(AbsMogoApplication.getApp().getString(R.string.v2x_voice_see_front_car_live_error));
|
||||
mLoading.setVisibility(GONE);
|
||||
mClLoadError.setVisibility(VISIBLE);
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "没有找到可直播车机");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放直播流
|
||||
*/
|
||||
private void playLiveVideo() {
|
||||
if (mSurfaceView != null) {
|
||||
MogoLocation mogoLocation = CallerMapLocationListenerManager.INSTANCE.getCurrentLocation();
|
||||
if (mogoLocation != null) {
|
||||
MoGoAiCloudTrafficLive.viewFrontVehicleLive(mogoLocation.getLatitude(), mogoLocation.getLongitude(), ((int) mogoLocation.getBearing()), mSurfaceView, new ITrafficCarLiveCallBack() {
|
||||
@Override
|
||||
public void onLive(String liveSn) {
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "onLive");
|
||||
if (!TextUtils.isEmpty(liveSn)) {
|
||||
CarZegoLiveVideoView.this.liveSn = liveSn;
|
||||
}
|
||||
refreshStatusToListener(true);
|
||||
mLoading.setVisibility(GONE);
|
||||
mClLoadError.setVisibility(GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisConnect() {
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "失去连接onDisConnect");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String errorMsg) {
|
||||
refreshStatusToListener(false);
|
||||
AIAssist.getInstance(Utils.getApp()).speakTTSVoiceWithLevel("直播获取识败,可以对我说重试", AIAssist.LEVEL3);
|
||||
stopLive();
|
||||
mLoading.setVisibility(GONE);
|
||||
mClLoadError.setVisibility(VISIBLE);
|
||||
// 注册语音交互
|
||||
V2XVoiceManager.INSTANCE
|
||||
.registerWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_REFRESH_CAR_LIVE,
|
||||
v2XVoiceCallbackRefreshListener)
|
||||
.registerUnWakeVoice(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_REFRESH_LIVE_UN_WAKEUP,
|
||||
v2XVoiceCallbackRefreshListener);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void stopLive() {
|
||||
try {
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "心跳:关闭直播...");
|
||||
if (!TextUtils.isEmpty(liveSn)) {
|
||||
MoGoAiCloudTrafficLive.stopCarLive(liveSn);
|
||||
} else {
|
||||
CallerLogger.INSTANCE.e(M_V2X + TAG, "直播 liveSn is null");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
startLive();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
stopLive();
|
||||
mLoading.setVisibility(VISIBLE);
|
||||
// 反注册语音交互
|
||||
V2XVoiceManager.INSTANCE
|
||||
.unRegisterWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_REFRESH_CAR_LIVE)
|
||||
.unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_REFRESH_LIVE_UN_WAKEUP);
|
||||
super.onDetachedFromWindow();
|
||||
}
|
||||
|
||||
private void refreshStatusToListener(boolean videoPlaying) {
|
||||
if (onVideoStatusChange != null) {
|
||||
onVideoStatusChange.videoPlaying(videoPlaying);
|
||||
}
|
||||
}
|
||||
|
||||
private OnVideoStatusChange onVideoStatusChange;
|
||||
|
||||
public void addOnVideoStatusChangeListener(OnVideoStatusChange onVideoStatusChange) {
|
||||
this.onVideoStatusChange = onVideoStatusChange;
|
||||
}
|
||||
|
||||
public interface OnVideoStatusChange {
|
||||
void videoPlaying(boolean videoPlaying);
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
package com.mogo.eagle.core.function.v2x.events.view;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorInflater;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.mogo.commons.module.status.MogoStatusManager;
|
||||
import com.mogo.eagle.core.function.v2x.R;
|
||||
|
||||
|
||||
/**
|
||||
* 红心点赞按钮控件
|
||||
*
|
||||
* @author donghongyu
|
||||
*/
|
||||
public class HeartLikeView extends LinearLayout implements Animator.AnimatorListener {
|
||||
|
||||
private ImageView mIllegalParkingLike;
|
||||
private AnimatorSet mAnimatorSet;
|
||||
private OnClickCallListener mOnClickCallListener;
|
||||
|
||||
private boolean isAnimator = false;
|
||||
|
||||
public HeartLikeView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public HeartLikeView(Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public HeartLikeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.HeartLikeView, defStyleAttr,
|
||||
0);
|
||||
boolean isVrMode = MogoStatusManager.getInstance().isVrMode();
|
||||
|
||||
boolean showGrayBack = typedArray.getBoolean(R.styleable.HeartLikeView_showGrayBack, false);
|
||||
|
||||
if (showGrayBack) {
|
||||
inflate(context, R.layout.view_heart_like_gray_back, this);
|
||||
mIllegalParkingLike = findViewById(R.id.ivLikeForGrayBack);
|
||||
} else {
|
||||
inflate(context, isVrMode ? R.layout.view_heart_like_vr : R.layout.view_heart_like, this);
|
||||
mIllegalParkingLike = findViewById(R.id.ivIllegalParkingLike);
|
||||
}
|
||||
setOnClickListener(v -> {
|
||||
if (!isAnimator) {
|
||||
isAnimator = true;
|
||||
if (mAnimatorSet == null) {
|
||||
mAnimatorSet = (AnimatorSet) AnimatorInflater.loadAnimator(getContext(),
|
||||
isVrMode ? R.animator.v2x_like_heart_animation_vr : R.animator.v2x_like_heart_animation);
|
||||
mAnimatorSet.setTarget(mIllegalParkingLike);
|
||||
mAnimatorSet.addListener(this);
|
||||
}
|
||||
mAnimatorSet.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
isAnimator = false;
|
||||
if (mOnClickCallListener != null) {
|
||||
mOnClickCallListener.onClicked(HeartLikeView.this);
|
||||
}
|
||||
if (MogoStatusManager.getInstance().isVrMode()) {
|
||||
mIllegalParkingLike.setImageResource(R.drawable.module_common_icon_like_selected_vr);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
|
||||
}
|
||||
|
||||
public interface OnClickCallListener {
|
||||
/**
|
||||
* 点击回调
|
||||
*/
|
||||
void onClicked(View view);
|
||||
}
|
||||
|
||||
public void setOnClickCallListener(OnClickCallListener clickCallListener) {
|
||||
this.mOnClickCallListener = clickCallListener;
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
package com.mogo.eagle.core.function.v2x.events.view;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorInflater;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.mogo.commons.module.status.MogoStatusManager;
|
||||
import com.mogo.eagle.core.function.v2x.R;
|
||||
|
||||
|
||||
/**
|
||||
* 不喜欢按钮控件
|
||||
*
|
||||
* @author donghongyu
|
||||
*/
|
||||
public class HeartUnLikeView extends LinearLayout implements Animator.AnimatorListener {
|
||||
|
||||
private ImageView mIllegalParkingUnLike;
|
||||
private AnimatorSet mAnimatorSet;
|
||||
private OnClickCallListener mOnClickCallListener;
|
||||
private boolean isAnimator = false;
|
||||
private ImageView animationImageView;
|
||||
|
||||
public HeartUnLikeView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public HeartUnLikeView(Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public HeartUnLikeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
boolean isVrMode = MogoStatusManager.getInstance().isVrMode();
|
||||
inflate(context, isVrMode ? R.layout.view_heart_unlike_vr : R.layout.view_heart_unlike, this);
|
||||
mIllegalParkingUnLike = findViewById(R.id.ivIllegalParkingUnLike);
|
||||
animationImageView = findViewById(R.id.animationImage);
|
||||
setOnClickListener(v -> {
|
||||
if (!isAnimator) {
|
||||
isAnimator = true;
|
||||
|
||||
if (mAnimatorSet == null) {
|
||||
mAnimatorSet = (AnimatorSet) AnimatorInflater.loadAnimator(getContext(),
|
||||
isVrMode ?
|
||||
R.animator.v2x_unlike_heart_animation_vr : R.animator.v2x_unlike_heart_animation);
|
||||
mAnimatorSet.setTarget(mIllegalParkingUnLike);
|
||||
mAnimatorSet.addListener(this);
|
||||
}
|
||||
mAnimatorSet.start();
|
||||
}
|
||||
if (isVrMode) {
|
||||
animationImageView.setVisibility(View.VISIBLE);
|
||||
Animation animation = AnimationUtils.loadAnimation(getContext(), R.anim.v2x_unlike_heart_scale_ani_vr);
|
||||
animationImageView.startAnimation(animation);
|
||||
animationImageView.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
isAnimator = false;
|
||||
if (mOnClickCallListener != null) {
|
||||
mOnClickCallListener.onClicked(HeartUnLikeView.this);
|
||||
}
|
||||
if (MogoStatusManager.getInstance().isVrMode()) {
|
||||
mIllegalParkingUnLike.setImageResource(R.drawable.module_common_icon_unlike_selected_vr);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
|
||||
}
|
||||
|
||||
public interface OnClickCallListener {
|
||||
/**
|
||||
* 点击回调
|
||||
*/
|
||||
void onClicked(View view);
|
||||
}
|
||||
|
||||
public void setOnClickCallListener(OnClickCallListener clickCallListener) {
|
||||
this.mOnClickCallListener = clickCallListener;
|
||||
}
|
||||
}
|
||||
@@ -1,215 +0,0 @@
|
||||
package com.mogo.eagle.core.function.v2x.events.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.Surface
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.mogo.commons.module.status.MogoStatusManager
|
||||
import com.mogo.eagle.core.function.v2x.R
|
||||
import com.mogo.eagle.core.widget.glide.SkinAbleBitmapTarget
|
||||
import com.shuyu.gsyvideoplayer.GSYVideoManager
|
||||
import com.shuyu.gsyvideoplayer.utils.GSYVideoType
|
||||
import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer
|
||||
import com.shuyu.gsyvideoplayer.video.base.GSYVideoView
|
||||
import com.shuyu.gsyvideoplayer.video.base.GSYVideoViewBridge
|
||||
|
||||
|
||||
class SimpleCoverVideoPlayer : StandardGSYVideoPlayer {
|
||||
private lateinit var coverImage: ImageView
|
||||
private lateinit var start: ImageView
|
||||
private lateinit var fullscreen: ImageView
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val TAG: String = "SimpleCoverVideoPlayer.kt"
|
||||
}
|
||||
|
||||
constructor(context: Context?) : super(context)
|
||||
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
|
||||
constructor(context: Context?, fullFlag: Boolean?) : super(context, fullFlag)
|
||||
|
||||
override fun init(context: Context) {
|
||||
super.init(context)
|
||||
coverImage = findViewById(R.id.thumbImage)
|
||||
start = findViewById(R.id.start)
|
||||
fullscreen = findViewById(R.id.fullscreen)
|
||||
if (mThumbImageViewLayout != null
|
||||
&& (mCurrentState == -1 || mCurrentState == GSYVideoView.CURRENT_STATE_NORMAL || mCurrentState == GSYVideoView.CURRENT_STATE_ERROR)
|
||||
) {
|
||||
mThumbImageViewLayout.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLayoutId(): Int {
|
||||
if (MogoStatusManager.getInstance().isVrMode) {
|
||||
return R.layout.v2x_road_video_plyer_layout_vr
|
||||
}
|
||||
return R.layout.v2x_road_video_plyer_layout
|
||||
}
|
||||
|
||||
override fun getGSYVideoManager(): GSYVideoViewBridge {
|
||||
GSYVideoManager.instance().initContext(context.applicationContext)
|
||||
GSYVideoManager.instance().isNeedMute = true
|
||||
return GSYVideoManager.instance()
|
||||
}
|
||||
|
||||
override fun setProgressAndTime(progress: Int, secProgress: Int, currentTime: Int, totalTime: Int, forceChange: Boolean) {
|
||||
super.setProgressAndTime(progress, secProgress, currentTime, totalTime, forceChange)
|
||||
if (progress != 0) {
|
||||
mProgressBar.progress = progress
|
||||
}
|
||||
}
|
||||
|
||||
fun loadCoverImage(url: String, mContext: Context) {
|
||||
//加载图片
|
||||
val requestOptions = RequestOptions()
|
||||
// .placeholder(R.drawable.v2x_icon_live_logo)
|
||||
// .error(R.drawable.video_loading_img)
|
||||
Glide.with(mContext).asBitmap()
|
||||
.load(url)
|
||||
.apply(requestOptions)
|
||||
.into(SkinAbleBitmapTarget(coverImage, requestOptions))
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* 默认双击暂停 单击响应事件也=暂停/继续播放
|
||||
* 因为相应区域的关系 改为onClick方法实现
|
||||
* */
|
||||
override fun onClickUiToggle() {
|
||||
|
||||
// super.touchDoubleUp()
|
||||
}
|
||||
|
||||
override fun updateStartImage() {
|
||||
super.updateStartImage()
|
||||
|
||||
when (mCurrentState) {
|
||||
GSYVideoView.CURRENT_STATE_PAUSE -> start.visibility = View.VISIBLE
|
||||
else -> start.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
fun setFullClickListener(listener: OnClickListener) {
|
||||
fullscreen.setOnClickListener(listener)
|
||||
}
|
||||
|
||||
override fun changeUiToCompleteShow() {
|
||||
super.changeUiToCompleteShow()
|
||||
// setViewShowState(mBottomContainer, View.INVISIBLE)
|
||||
mBottomContainer.visibility = View.INVISIBLE
|
||||
mProgressBar.visibility = View.GONE
|
||||
}
|
||||
|
||||
override fun hideAllWidget() {
|
||||
super.hideAllWidget()
|
||||
mBottomContainer.visibility = View.INVISIBLE
|
||||
mProgressBar.visibility = View.GONE
|
||||
}
|
||||
|
||||
override fun changeUiToPrepareingClear() {
|
||||
super.changeUiToPrepareingClear()
|
||||
mBottomContainer.visibility = View.INVISIBLE
|
||||
mProgressBar.visibility = View.GONE
|
||||
}
|
||||
|
||||
override fun changeUiToPlayingBufferingClear() {
|
||||
super.changeUiToPlayingBufferingClear()
|
||||
mBottomContainer.visibility = View.INVISIBLE
|
||||
mProgressBar.visibility = View.GONE
|
||||
|
||||
}
|
||||
|
||||
override fun changeUiToClear() {
|
||||
super.changeUiToClear()
|
||||
mBottomContainer.visibility = View.INVISIBLE
|
||||
mProgressBar.visibility = View.GONE
|
||||
}
|
||||
|
||||
override fun changeUiToCompleteClear() {
|
||||
super.changeUiToCompleteClear()
|
||||
mBottomContainer.visibility = View.INVISIBLE
|
||||
mProgressBar.visibility = View.GONE
|
||||
}
|
||||
|
||||
override fun onAutoCompletion() {
|
||||
super.onAutoCompletion()
|
||||
mProgressBar.progress = 0
|
||||
}
|
||||
|
||||
override fun showWifiDialog() {
|
||||
//直接播放,不显示WIFI对话框
|
||||
startPlayLogic()
|
||||
}
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow()
|
||||
mProgressBar.progress = 0
|
||||
mFullPauseBitmap = null
|
||||
if (mAudioManager != null) {
|
||||
try {
|
||||
@Suppress("DEPRECATION")
|
||||
mAudioManager.abandonAudioFocus(onAudioFocusChangeListener)
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick(v: View?) {
|
||||
super.onClick(v)
|
||||
if (mCurrentState == CURRENT_STATE_PAUSE) {
|
||||
onVideoResume()
|
||||
} else if (mCurrentState == CURRENT_STATE_PLAYING) {
|
||||
onVideoPause()
|
||||
}
|
||||
v?.let {
|
||||
when (v) {
|
||||
start -> {
|
||||
onVideoResume()
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPrepared() {
|
||||
super.onPrepared()
|
||||
}
|
||||
|
||||
override fun onCompletion() {
|
||||
}
|
||||
|
||||
override fun onSurfaceUpdated(surface: Surface) {
|
||||
super.onSurfaceUpdated(surface)
|
||||
if (mThumbImageViewLayout != null && mThumbImageViewLayout.visibility == View.VISIBLE) {
|
||||
mThumbImageViewLayout.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
override fun setViewShowState(view: View?, visibility: Int) {
|
||||
if (view === mThumbImageViewLayout && visibility != View.VISIBLE) {
|
||||
return
|
||||
}
|
||||
super.setViewShowState(view, visibility)
|
||||
}
|
||||
|
||||
override fun onSurfaceAvailable(surface: Surface) {
|
||||
super.onSurfaceAvailable(surface)
|
||||
mProgressBar.visibility = View.GONE
|
||||
if (GSYVideoType.getRenderType() != GSYVideoType.TEXTURE) {
|
||||
if (mThumbImageViewLayout != null && mThumbImageViewLayout.visibility == View.VISIBLE) {
|
||||
mThumbImageViewLayout.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun showVolumeDialog(deltaY: Float, volumePercent: Int) {
|
||||
}
|
||||
|
||||
override fun touchSurfaceMove(deltaX: Float, deltaY: Float, y: Float) {
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package com.mogo.eagle.core.function.v2x.events.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.mogo.commons.debug.DebugConfig;
|
||||
import com.mogo.eagle.core.function.v2x.R;
|
||||
|
||||
/**
|
||||
* 事件面板的提示按钮
|
||||
*
|
||||
* @author donghongyu
|
||||
*/
|
||||
public class V2XEventPanelHistoryCountView extends LinearLayout {
|
||||
private RelativeLayout mLlEventMore;
|
||||
private TextView mTvEventCount;
|
||||
|
||||
public V2XEventPanelHistoryCountView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public V2XEventPanelHistoryCountView(Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public V2XEventPanelHistoryCountView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
LayoutInflater.from(context).inflate(R.layout.view_event_panel_history_count, this);
|
||||
|
||||
mLlEventMore = findViewById(R.id.llEventMore);
|
||||
mTvEventCount = findViewById(R.id.tvEventCount);
|
||||
|
||||
if (DebugConfig.getCarMachineType() != DebugConfig.CAR_MACHINE_TYPE_LENOVO) {
|
||||
mLlEventMore.setVisibility(VISIBLE);
|
||||
} else {
|
||||
mLlEventMore.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public void changeMsgCount(int count) {
|
||||
if (mTvEventCount != null) {
|
||||
if (count > 0) {
|
||||
mTvEventCount.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mTvEventCount.setVisibility(View.GONE);
|
||||
}
|
||||
mTvEventCount.setText("" + count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package com.mogo.eagle.core.function.v2x.events.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.mogo.eagle.core.function.v2x.R;
|
||||
|
||||
/**
|
||||
* 列表空白布局View
|
||||
*
|
||||
* @author donghongyu
|
||||
*/
|
||||
public class V2XListEmptyView extends LinearLayout {
|
||||
|
||||
private ImageView mIvEmptyView;
|
||||
private TextView mTvTrip;
|
||||
private TextView mBtnShear;
|
||||
private TextView mBtnRefresh;
|
||||
|
||||
private OnControlListener mOnControlListener;
|
||||
|
||||
public V2XListEmptyView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public V2XListEmptyView(Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public V2XListEmptyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
LayoutInflater.from(context).inflate(R.layout.view_history_empty, this);
|
||||
initView();
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
mIvEmptyView = findViewById(R.id.ivEmptyView);
|
||||
mTvTrip = findViewById(R.id.tvTrip);
|
||||
mBtnShear = findViewById(R.id.btnShear);
|
||||
mBtnRefresh = findViewById(R.id.btnRefresh);
|
||||
|
||||
mBtnShear.setOnClickListener(v -> {
|
||||
if (mOnControlListener != null) {
|
||||
mOnControlListener.onShearClick();
|
||||
}
|
||||
});
|
||||
mBtnRefresh.setOnClickListener(v -> {
|
||||
if (mOnControlListener != null) {
|
||||
mOnControlListener.onRefreshClick();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setTripMessage(String tripMsg) {
|
||||
if (mTvTrip != null) {
|
||||
mTvTrip.setText(tripMsg);
|
||||
}
|
||||
}
|
||||
|
||||
public void setShearVisibility(boolean visibility) {
|
||||
if (mBtnShear != null) {
|
||||
if (visibility) {
|
||||
mBtnShear.setVisibility(VISIBLE);
|
||||
} else {
|
||||
mBtnShear.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setRefreshVisibility(boolean visibility) {
|
||||
if (mBtnRefresh != null) {
|
||||
if (visibility) {
|
||||
mBtnRefresh.setVisibility(VISIBLE);
|
||||
} else {
|
||||
mBtnRefresh.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setOnControlListener(OnControlListener onControlListener) {
|
||||
this.mOnControlListener = onControlListener;
|
||||
}
|
||||
|
||||
public interface OnControlListener {
|
||||
void onShearClick();
|
||||
|
||||
void onRefreshClick();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,231 +0,0 @@
|
||||
package com.mogo.eagle.core.function.v2x.events.view;
|
||||
|
||||
import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_V2X;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.mogo.commons.voice.AIAssist;
|
||||
import com.mogo.eagle.core.data.map.entity.MarkerCarInfo;
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
|
||||
import com.mogo.eagle.core.function.v2x.R;
|
||||
import com.mogo.eagle.core.function.v2x.events.voice.V2XVoiceCallbackListener;
|
||||
import com.mogo.eagle.core.function.v2x.events.voice.V2XVoiceConstants;
|
||||
import com.mogo.eagle.core.function.v2x.events.voice.V2XVoiceManager;
|
||||
import com.mogo.eagle.core.network.utils.GsonUtil;
|
||||
import com.mogo.eagle.core.utilcode.util.Utils;
|
||||
import com.mogo.eagle.core.widget.RoundLayout;
|
||||
import com.tencent.rtmp.ITXLivePlayListener;
|
||||
import com.tencent.rtmp.TXLiveConstants;
|
||||
import com.tencent.rtmp.TXLivePlayConfig;
|
||||
import com.tencent.rtmp.TXLivePlayer;
|
||||
import com.tencent.rtmp.ui.TXCloudVideoView;
|
||||
|
||||
/**
|
||||
* author : donghongyu
|
||||
* e-mail : 1358506549@qq.com
|
||||
* date : 2020-02-0623:07
|
||||
* desc :
|
||||
* version: 1.0
|
||||
*/
|
||||
public class V2XLiveGSYVideoView extends RoundLayout {
|
||||
private final String TAG = "V2XLiveGSYVideoView";
|
||||
|
||||
private TXCloudVideoView mTxcVideoView;
|
||||
private ProgressBar mLoading;
|
||||
private TXLivePlayer mLivePlayer;
|
||||
private ConstraintLayout mClLoadError;
|
||||
|
||||
private MarkerCarInfo.CarLiveInfo mCarLiveInfo;
|
||||
// 重新刷新直播流
|
||||
private final V2XVoiceCallbackListener v2XVoiceCallbackRefreshListener = new V2XVoiceCallbackListener() {
|
||||
@Override
|
||||
public void onCallback(String command, Intent intent) {
|
||||
mLoading.setVisibility(VISIBLE);
|
||||
mClLoadError.setVisibility(GONE);
|
||||
if (mCarLiveInfo != null) {
|
||||
startLive(mCarLiveInfo);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public V2XLiveGSYVideoView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public V2XLiveGSYVideoView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public V2XLiveGSYVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
initView(context);
|
||||
|
||||
}
|
||||
|
||||
private void initView(Context context) {
|
||||
LayoutInflater.from(context)
|
||||
.inflate(R.layout.view_video_layout_normal, this);
|
||||
//mPlayerView 即 step1 中添加的界面 view
|
||||
mTxcVideoView = findViewById(R.id.txcVideoView);
|
||||
//创建 player 对象
|
||||
mLivePlayer = new TXLivePlayer(context);
|
||||
//关键 player 对象与界面 view
|
||||
mLivePlayer.setPlayerView(mTxcVideoView);
|
||||
mLivePlayer.setMute(true);
|
||||
|
||||
TXLivePlayConfig txLivePlayConfig = new TXLivePlayConfig();
|
||||
// 增加重试次数
|
||||
txLivePlayConfig.setConnectRetryCount(30);
|
||||
mLivePlayer.setConfig(txLivePlayConfig);
|
||||
|
||||
|
||||
mLivePlayer.enableHardwareDecode(true);
|
||||
|
||||
mLoading = findViewById(R.id.loading);
|
||||
mLoading.getIndeterminateDrawable().setColorFilter(ContextCompat.getColor(context, R.color.live_video_progress_bar_loading_color), PorterDuff.Mode.MULTIPLY);
|
||||
|
||||
mClLoadError = findViewById(R.id.clLoadError);
|
||||
TextView mTvRefreshButton = findViewById(R.id.tvRefreshButton);
|
||||
mTvRefreshButton.setOnClickListener(v -> {
|
||||
mLoading.setVisibility(VISIBLE);
|
||||
mClLoadError.setVisibility(GONE);
|
||||
if (mCarLiveInfo != null) {
|
||||
startLive(mCarLiveInfo);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置直播信息
|
||||
*/
|
||||
public void setCarLiveInfo(MarkerCarInfo.CarLiveInfo carLiveInfo) {
|
||||
mCarLiveInfo = carLiveInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始直播
|
||||
*
|
||||
* @param carLiveInfo 直播数据
|
||||
*/
|
||||
public void startLive(MarkerCarInfo.CarLiveInfo carLiveInfo) {
|
||||
// 进行直播播放
|
||||
if (mLivePlayer != null
|
||||
&& carLiveInfo != null) {
|
||||
if (!TextUtils.isEmpty(carLiveInfo.getVideoUrl())) {
|
||||
setCarLiveInfo(carLiveInfo);
|
||||
playLiveVideo(carLiveInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放直播流,且开始心跳
|
||||
*/
|
||||
private void playLiveVideo(MarkerCarInfo.CarLiveInfo carLiveInfo) {
|
||||
try {
|
||||
if (mLivePlayer != null) {
|
||||
mLivePlayer.startPlay(carLiveInfo.getVideoUrl(), TXLivePlayer.PLAY_TYPE_LIVE_RTMP);
|
||||
mLivePlayer.setPlayListener(new ITXLivePlayListener() {
|
||||
@Override
|
||||
public void onPlayEvent(int event, Bundle bundle) {
|
||||
// CallerLogger.INSTANCE.i(M_V2X + TAG,
|
||||
// "直播信息= " + GsonUtil.jsonFromObject(carLiveInfo) +
|
||||
// "\n播放器:onPlayEvent==" + event +
|
||||
// "\nbundle===" + bundle);
|
||||
if (event == TXLiveConstants.PLAY_EVT_PLAY_LOADING) {
|
||||
mLoading.setVisibility(VISIBLE);
|
||||
mClLoadError.setVisibility(GONE);
|
||||
} else if (event == TXLiveConstants.PLAY_EVT_PLAY_BEGIN) {
|
||||
mLoading.setVisibility(GONE);
|
||||
mClLoadError.setVisibility(GONE);
|
||||
} else if (event < 0) {
|
||||
AIAssist.getInstance(Utils.getApp()).speakTTSVoiceWithLevel("直播获取失败,可以对我说重试", AIAssist.LEVEL3);
|
||||
stopLive(mCarLiveInfo);
|
||||
mLoading.setVisibility(GONE);
|
||||
mClLoadError.setVisibility(VISIBLE);
|
||||
// 注册语音交互
|
||||
V2XVoiceManager.INSTANCE
|
||||
.registerWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_REFRESH_CAR_LIVE,
|
||||
v2XVoiceCallbackRefreshListener)
|
||||
.registerUnWakeVoice(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_REFRESH_LIVE_UN_WAKEUP,
|
||||
v2XVoiceCallbackRefreshListener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNetStatus(Bundle bundle) {
|
||||
// CallerLogger.INSTANCE.i(M_V2X + TAG, "播放器:onNetStatus===bundle===" + bundle);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
mLoading.setVisibility(GONE);
|
||||
mClLoadError.setVisibility(VISIBLE);
|
||||
CallerLogger.INSTANCE.e(M_V2X + TAG, "直播发生异常:carLiveInfo= " + GsonUtil.jsonFromObject(carLiveInfo));
|
||||
}
|
||||
}
|
||||
|
||||
public void stopLive(MarkerCarInfo.CarLiveInfo carLiveInfo) {
|
||||
try {
|
||||
//CallerLogger.INSTANCE.i(M_V2X + TAG, "心跳:关闭直播...");
|
||||
// 暂停
|
||||
mLivePlayer.pause();
|
||||
// true 代表清除最后一帧画面
|
||||
mLivePlayer.stopPlay(true);
|
||||
mTxcVideoView.onDestroy();
|
||||
|
||||
// if (carLiveInfo.getVideoUrl() != null) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// 停止推流
|
||||
// V2XServiceManager
|
||||
// .getV2XRefreshModel()
|
||||
// .livePush(new V2XRefreshCallback<V2XLivePushVoRes>() {
|
||||
// @Override
|
||||
// public void onSuccess(V2XLivePushVoRes result) {
|
||||
// CallerLogger.INSTANCE.d(M_V2X + TAG, "播放器:" + result);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onFail(String msg) {
|
||||
// CallerLogger.INSTANCE.e(M_V2X + TAG, "播放器:" + msg);
|
||||
// }
|
||||
// }, carLiveInfo.getVideoSn(), 1);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
if (mCarLiveInfo != null) {
|
||||
startLive(mCarLiveInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
stopLive(mCarLiveInfo);
|
||||
mLoading.setVisibility(VISIBLE);
|
||||
// 反注册语音交互
|
||||
V2XVoiceManager.INSTANCE
|
||||
.unRegisterWakeCmd(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_REFRESH_CAR_LIVE)
|
||||
.unRegisterUnWakeVoice(V2XVoiceConstants.COMMAND_ZHIDAO_V2X_REFRESH_LIVE_UN_WAKEUP);
|
||||
super.onDetachedFromWindow();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.mogo.eagle.core.function.v2x.events.marker
|
||||
package com.mogo.eagle.core.function.v2x.events.view
|
||||
|
||||
|
||||
import android.content.Context
|
||||
@@ -1,61 +0,0 @@
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:ordering="sequentially">
|
||||
|
||||
<set android:ordering="together">
|
||||
<objectAnimator
|
||||
android:duration="200"
|
||||
android:propertyName="scaleX"
|
||||
android:valueTo="0.95f" />
|
||||
<objectAnimator
|
||||
android:duration="200"
|
||||
android:propertyName="scaleY"
|
||||
android:valueTo="0.95f" />
|
||||
</set>
|
||||
|
||||
<set android:ordering="together">
|
||||
<objectAnimator
|
||||
android:duration="200"
|
||||
android:propertyName="scaleX"
|
||||
android:valueTo="1f" />
|
||||
<objectAnimator
|
||||
android:duration="200"
|
||||
android:propertyName="scaleY"
|
||||
android:valueTo="1f" />
|
||||
</set>
|
||||
|
||||
<set android:ordering="together">
|
||||
<objectAnimator
|
||||
android:duration="200"
|
||||
android:propertyName="scaleX"
|
||||
android:valueTo="1.25f" />
|
||||
<objectAnimator
|
||||
android:duration="200"
|
||||
android:propertyName="scaleY"
|
||||
android:valueTo="1.25f" />
|
||||
</set>
|
||||
|
||||
<set android:ordering="together">
|
||||
<objectAnimator
|
||||
android:duration="200"
|
||||
android:propertyName="scaleX"
|
||||
android:valueTo="0.95f" />
|
||||
|
||||
<objectAnimator
|
||||
android:duration="200"
|
||||
android:propertyName="scaleY"
|
||||
android:valueTo="0.95f" />
|
||||
</set>
|
||||
|
||||
<set android:ordering="together">
|
||||
<objectAnimator
|
||||
android:duration="200"
|
||||
android:propertyName="scaleX"
|
||||
android:valueTo="1f" />
|
||||
|
||||
<objectAnimator
|
||||
android:duration="200"
|
||||
android:propertyName="scaleY"
|
||||
android:valueTo="1f" />
|
||||
</set>
|
||||
|
||||
</set>
|
||||
@@ -1,4 +0,0 @@
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:ordering="sequentially">
|
||||
|
||||
</set>
|
||||
@@ -1,31 +0,0 @@
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:ordering="sequentially">
|
||||
<objectAnimator
|
||||
android:duration="100"
|
||||
android:propertyName="translationX"
|
||||
android:valueFrom="0"
|
||||
android:valueTo="-5"
|
||||
android:valueType="floatType" />
|
||||
|
||||
<objectAnimator
|
||||
android:duration="100"
|
||||
android:propertyName="translationX"
|
||||
android:valueFrom="-5"
|
||||
android:valueTo="0"
|
||||
android:valueType="floatType" />
|
||||
|
||||
<objectAnimator
|
||||
android:duration="100"
|
||||
android:propertyName="translationX"
|
||||
android:valueFrom="0"
|
||||
android:valueTo="5"
|
||||
android:valueType="floatType" />
|
||||
|
||||
<objectAnimator
|
||||
android:duration="100"
|
||||
android:propertyName="translationX"
|
||||
android:valueFrom="5"
|
||||
android:valueTo="0"
|
||||
android:valueType="floatType" />
|
||||
|
||||
</set>
|
||||
@@ -1,4 +0,0 @@
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:ordering="sequentially">
|
||||
|
||||
</set>
|
||||
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 715 B |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 843 B |
|
Before Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 465 B |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 857 B |
|
Before Width: | Height: | Size: 631 B |
|
Before Width: | Height: | Size: 659 B |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 817 B |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 674 B |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 20 KiB |