Commit ed3f8644 by 刘鹏

Merge branch 'release' into feat/lp/lp_sub_pay

# Conflicts:
#	m-consultant/src/main/res/values/styles.xml
parents 60b36471 e0af8ed2
......@@ -2,7 +2,7 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply from: "../../maven_push_api.gradle"
version = '1.0.2'
version = '1.0.3'
android {
compileSdkVersion rootProject.ext.android["compileSdkVersion"]
......
......@@ -23,6 +23,7 @@ interface IImService : IProvider {
// 直接打开聊天页面,不走分配导医
fun startChatBySessionId(context: Activity, toUid: String)
// 打开信息前置收集页
fun startP2PSession(context: Activity, location: Int, ffrom2: String?)
......@@ -183,4 +184,8 @@ interface IImService : IProvider {
fun initIm(app: Application, activity: Class<out Activity>, imInitBean: IMInitConfigBean)
fun isWifiOr3G(activity: Activity): Boolean
fun showConsultServiceDialog(activity: Activity, toUid: String, doctorId: String)
fun dismissConsultServiceDialog();
}
\ No newline at end of file
......@@ -23,6 +23,8 @@ import com.ydl.ydlcommon.utils.AppProgressUtils;
import com.ydl.ydlcommon.utils.Utils;
import com.yidianling.common.tools.LogUtil;
import com.yidianling.common.tools.ToastUtil;
import com.yidianling.consultant.preview.TestImageLoader;
import com.yidianling.consultant.preview.ZoomMediaLoader;
import com.yidianling.course.lifeCallback.CoursePlayLifecycle;
......@@ -48,7 +50,7 @@ public class ComponentTestApp extends BaseApp {
com.ydl.ydlcommon.utils.LogUtil.debug = BuildConfig.DEBUG;
webviewSetPath(this);
ZoomMediaLoader.getInstance().init(new TestImageLoader());
if (!BuildConfig.DEBUG && Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {//release包去除,debug包不去除,用于检测是否还有反射api的方法
//去掉在Android P上的提醒弹窗 Detected problems with API
......
......@@ -20,8 +20,8 @@ import java.util.List;
*/
public final class DemoGlobalConfig implements IConfigModule {
String APP_DOMAIN = "https://api.github.com/";
public static String appEnv = YDLConstants.ENV_TEST;
// public static String appEnv = YDLConstants.ENV_PROD;
// public static String appEnv = YDLConstants.ENV_TEST;
public static String appEnv = YDLConstants.ENV_PROD;
// public static String appEnv = YDLConstants.ENV_NEW_TEST;//配置未上传到maven库
@Override
......
......@@ -110,7 +110,7 @@ class JsMethod(private val webView: WebView?) {
if (callback.isNullOrBlank()) return true
webView?.post {
when (type) {
1 -> {//检查音频权限能力
1,2 -> {//检查音频权限能力
webView.loadUrl("javascript:$callback(1)")
}
else -> {
......
......@@ -2,8 +2,10 @@ package com.ydl.component.service.web;
import android.app.Activity;
import android.graphics.Rect;
import com.alibaba.android.arouter.launcher.ARouter;
import com.blankj.utilcode.util.ScreenUtils;
import com.ydl.confide.api.IConfideService;
import com.ydl.confide.home.event.ChangeAnotherExpertEvent;
import com.ydl.webview.H5JsBean;
......@@ -13,14 +15,20 @@ import com.ydl.ydl_router.manager.YDLRouterManager;
import com.ydl.ydl_router.manager.YDLRouterParams;
import com.ydl.ydlcommon.modular.ModularServiceManager;
import com.yidianling.common.tools.LogUtil;
import com.yidianling.consultant.preview.GPreviewBuilder;
import com.yidianling.consultant.preview.UserViewInfo;
import com.yidianling.im.api.service.IImService;
import com.yidianling.muse.activity.ChooseMusicActivity;
//import static com.ydl.ydlcommon.router.IYDLRouterConstant.ROUTER_MUSE_PLAY;
import de.greenrobot.event.EventBus;
import com.yidianling.im.event.CloseBottomWebviewEvent;
import java.util.ArrayList;
import java.util.List;
import de.greenrobot.event.EventBus;
/**
......@@ -296,7 +304,9 @@ public class WVClickAbstractListener implements WebViewClientClickListener {
@Override
public void shareAction(H5JsBean.H5JsCmd.Params params) {
if (mContext instanceof NewH5Activity) {
((NewH5Activity) mContext).showShareMenu(params);
}
}
@Override
......@@ -384,7 +394,7 @@ public class WVClickAbstractListener implements WebViewClientClickListener {
@Override
public void back() {
mContext.finish();
}
@Override
......@@ -495,6 +505,39 @@ public class WVClickAbstractListener implements WebViewClientClickListener {
}
@Override
public void resourceToPreview(H5JsBean.H5JsCmd.Params params) {
List<H5JsBean.MediaInfo> dataList = params.getDataList();
H5JsBean.DoctorInfo info = params.getInfo();
List<UserViewInfo> mThumbViewInfoList = new ArrayList<>();
for (H5JsBean.MediaInfo mediaInfo : dataList) {
UserViewInfo userViewInfo = new UserViewInfo(mediaInfo.getCover(), mediaInfo.getUrl(), mediaInfo.getSourcesType());
Rect bounds = new Rect();
bounds.left = ScreenUtils.getScreenWidth() / 2;
bounds.top = ScreenUtils.getScreenHeight() / 2;
bounds.right = ScreenUtils.getScreenWidth() / 2;
bounds.bottom = ScreenUtils.getScreenHeight() / 2;
userViewInfo.setBounds(bounds);
mThumbViewInfoList.add(userViewInfo);
}
GPreviewBuilder.form(mContext)
.setData(mThumbViewInfoList)
.setCurrentIndex(params.getPreview_index())
.setFullscreen(true)
.setToUid(info.getToUid() + "")
.setDoctorId(info.getDoctorId())
.setType(GPreviewBuilder.IndicatorType.Dot)
.start();
}
@Override
public void showDocBooking(H5JsBean.H5JsCmd.Params params) {
ModularServiceManager.INSTANCE.provide(IImService.class).showConsultServiceDialog(mContext, params.getToUid() + "", params.getDoctorId() + "");
}
@Override
public void switchSound(int mediaId, long meditationId, int meditationType, int businessType,
String buried, String mediaUrl, String mediaCoverUrl,
String title, String desc, int status) {
......@@ -506,9 +549,11 @@ public class WVClickAbstractListener implements WebViewClientClickListener {
businessType, buried, mediaUrl, mediaCoverUrl, title, desc, status);
}
}
@Override
public void chatCloseBottomWebView() {
EventBus.getDefault().post(new CloseBottomWebviewEvent(true));
ModularServiceManager.INSTANCE.provide(IImService.class).dismissConsultServiceDialog();
}
......@@ -521,8 +566,17 @@ public class WVClickAbstractListener implements WebViewClientClickListener {
@Override
public void setWebViewBG(String rgb, String alpha) {
if (mContext instanceof NewH5Activity) {
((NewH5Activity) mContext).setBG(rgb, alpha);
}
}
@Override
public void showCommentArticleDialog(H5JsBean.H5JsCmd.Params params) {
if (mContext instanceof NewH5Activity){
((NewH5Activity)mContext).setBG(rgb, alpha);
((NewH5Activity)mContext).showCommentArticleDialog(params.getTitle());
}
}
}
......@@ -460,6 +460,20 @@ class WebJavascriptHandler(private val webView: WebView?, private val wvEnventPr
wvEnventPro?.switchPushStatus(jsData.cmd?.params)
}
"open_article_comment_dialog" -> {
wvEnventPro?.showCommentArticleDialog(jsData.cmd?.params)
}
"resources_to_preview" -> {
wvEnventPro?.resourceToPreview(jsData.cmd?.params)
}
"doctor_booking" -> {
wvEnventPro?.showDocBooking(jsData.cmd?.params)
}
}
}
}
......@@ -203,4 +203,12 @@ public interface WebViewClientClickListener {
//h5页面是否需要打开推送
void switchPushStatus(H5JsBean.H5JsCmd.Params params);
//显示评论弹窗
void showCommentArticleDialog(H5JsBean.H5JsCmd.Params params);
void resourceToPreview(H5JsBean.H5JsCmd.Params params);
void showDocBooking(H5JsBean.H5JsCmd.Params params);
}
ext {
dev_mode = false //组件发布的时候需要设置为false
ydl2PublishVersion = "0.2.0.14"
dev_mode = false//组件发布的时候需要设置为false
ydl2PublishVersion = "0.2.0.17"
ydlPublishVersion = [
// -------------- 业务模块 --------------
//第三步 若干
......@@ -8,10 +8,10 @@ ext {
"m-consultant" : "0.0.60.78",
"m-fm" : "0.0.30.09",
"m-user" : "0.0.62.72",
"m-home" : "0.0.24.06",
"m-home" : "0.0.24.09",
"m-im" : "0.0.21.69",
"m-dynamic" : "0.0.7.80",
"m-article" : "0.0.0.10",
"m-article" : "0.0.0.11",
"m-muse" : "0.0.28.87",
"m-tests" : "0.0.24.24",
"m-course" : "0.0.43.39",
......@@ -22,7 +22,7 @@ ext {
"ydl-platform" : "0.0.41.54",
//第二步 若干
"ydl-webview" : "0.0.39.03",
"ydl-webview" : "0.2.0.7",
"ydl-media" : "0.0.21.52",
"ydl-pay" : "0.0.18.21",
"m-audioim" : "0.0.49.30.23",
......@@ -164,7 +164,7 @@ ext {
"systembartint" : "com.readystatesoftware.systembartint:systembartint:1.0.3",
"cube" : "in.srain.cube:cube-sdk:1.0.44@aar",
"support-multidex" : 'androidx.multidex:multidex:2.0.0',
"ydl-ijkplayer-jjdxm" : "com.ydl:jjdxm-ijkplayer:0.0.33",
"ydl-ijkplayer-jjdxm" : "com.ydl:jjdxm-ijkplayer:0.0.35",
"walle" : "com.meituan.android.walle:library:1.1.5",
"jpush" : "cn.jiguang.sdk:jpush:3.3.6",
"jcore" : "cn.jiguang.sdk:jcore:2.1.4",
......@@ -229,7 +229,7 @@ ext {
"ydl-m-user-api" : "com.ydl:m-user-api:1.0.0",
"ydl-m-fm-api" : "com.ydl:m-fm-api:1.0.0",
"ydl-m-tests-api" : "com.ydl:m-tests-api:1.0.0",
"ydl-m-im-api" : "com.ydl:m-im-api:1.0.2",
"ydl-m-im-api" : "com.ydl:m-im-api:1.0.3",
"ydl-m-home-api" : "com.ydl:m-home-api:${ydlPublishVersion["m-home-api"]}",
"ydl-m-consultant-api" : "com.ydl:m-consultant-api:1.0.3",
"ydl-m-dynamic-api" : "com.ydl:m-dynamic-api:1.0.0",
......
......@@ -52,6 +52,12 @@ dependencies {
kapt 'com.alibaba:arouter-compiler:1.2.2'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
implementation "androidx.lifecycle:lifecycle-runtime:2.0.0"
implementation 'io.github.scwang90:refresh-layout-kernel:2.0.5' //核心必须依赖
implementation 'io.github.scwang90:refresh-header-classics:2.0.5' //经典刷新头
api rootProject.ext.dependencies["ydl-user-router"]
if (rootProject.ext.dev_mode){
//开发时使用
......
......@@ -5,6 +5,8 @@
<application>
<activity android:name=".flutter.ArticleActivity"
android:screenOrientation="portrait"/>
<activity android:name="activity.ArticleHomeActivity"
android:screenOrientation="portrait"/>
</application>
</manifest>
\ No newline at end of file
package activity
import adapter.ArticlePagerAdapter
import android.annotation.SuppressLint
import android.graphics.Typeface
import android.text.SpannableString
import android.text.Spanned
import android.text.style.StyleSpan
import android.widget.ImageView
import androidx.viewpager2.widget.ViewPager2
import com.alibaba.android.arouter.facade.annotation.Route
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import com.ydl.ydlcommon.base.BaseActivity
import com.ydl.ydlcommon.utils.actionutil.ActionCountUtils
import com.yidianling.article.R
import fragment.ArticleHomeFragment
import http.ArticleHttp
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
@Route(path = "/article/list")
class ArticleHomeActivity : BaseActivity() {
private var TAG_IDS = mutableListOf(0)
private var mTabName = mutableListOf("推荐")
private var mTabLayout: TabLayout? = null
private var mViewPager: ViewPager2? = null
private var mFragments = mutableListOf(ArticleHomeFragment.newInstance(0))
override fun layoutResId(): Int {
return R.layout.article_home_activity_layout
}
override fun initDataAndEvent() {
mTabLayout = findViewById(R.id.tab_layout)
mViewPager = findViewById(R.id.view_pager)
mViewPager?.offscreenPageLimit = 3
findViewById<ImageView>(R.id.iv_back).setOnClickListener {
ActionCountUtils.record("article_list_main_page","article_list_return_click")
finish()
}
loadData()
}
@SuppressLint("CheckResult")
private fun loadData() {
ArticleHttp.getInstance().getArticleCategoryList()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { response ->
if (response.code == "200" && response.data != null && !response.data.articleCategoryResponseList.isNullOrEmpty()) {
var tabNameString = StringBuffer("推荐")
response.data.articleCategoryResponseList!!.forEach {
mTabName.add(it.name)
TAG_IDS.add(it.categoryId)
mFragments.add(ArticleHomeFragment.newInstance(it.categoryId))
tabNameString.append("|${it.name}")
}
ActionCountUtils.record(
"article_list_main_page",
"article_list_sort_visit",
tabNameString.toString()
)
mViewPager?.post {
mViewPager?.adapter = ArticlePagerAdapter(this, mFragments)
mTabLayout?.addOnTabSelectedListener(object :
TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) {
ActionCountUtils.record(
"article_list_main_page",
"article_list_toptitle_click",
tab?.text.toString() ?: ""
)
var text: String? = tab?.text.toString().trim()
val spStr = SpannableString(text)
val styleSpan = StyleSpan(Typeface.BOLD)
spStr.setSpan(
styleSpan,
0,
text?.length ?: 0,
Spanned.SPAN_INCLUSIVE_EXCLUSIVE
)
tab?.text = spStr
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
var text: String? = tab?.text.toString().trim()
val spStr = SpannableString(text)
val styleSpan = StyleSpan(Typeface.NORMAL)
spStr.setSpan(
styleSpan,
0,
text?.length ?: 0,
Spanned.SPAN_INCLUSIVE_EXCLUSIVE
)
tab?.text = spStr
}
override fun onTabReselected(tab: TabLayout.Tab?) {
}
})
TabLayoutMediator(mTabLayout!!, mViewPager!!) { tab, position ->
tab.text = mTabName[position]
}.attach()
}
}
}
}
}
\ No newline at end of file
package adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.AppCompatImageView
import androidx.appcompat.widget.AppCompatTextView
import androidx.recyclerview.widget.RecyclerView
import com.ydl.ydl_image.manager.YDLImageCacheManager
import com.yidianling.article.R
import data.ArticleBean
class ArticleHomeItemAdapter(private val mContext:Context):RecyclerView.Adapter<ArticleHomeItemAdapter.ArticleViewHolder>() {
private var mData = mutableListOf<ArticleBean>()
private var mListener:OnItemClickListener?=null
fun setOnItemClickListener(listener: OnItemClickListener){
mListener = listener
}
fun setData(data:MutableList<ArticleBean>){
mData.clear()
mData.addAll(data)
notifyDataSetChanged()
}
fun addData(data:MutableList<ArticleBean>){
mData.addAll(data)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, position: Int): ArticleViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.article_home_item_layout,parent,false)
return ArticleViewHolder(view)
}
override fun onBindViewHolder(holder: ArticleViewHolder, position: Int) {
holder.tvTitle.text = mData[position].title
holder.tvDesc.text = mData[position].desc
holder.tvAuthorName.text = mData[position].name
holder.tvArticleViewNum.text = "${mData[position].readNum}浏览"
holder.tvArticleLikeNum.text = "${mData[position].zanNum}点赞"
YDLImageCacheManager.showImage(mContext, mData[position]?.imgUrl, holder.ivArticleImage)
YDLImageCacheManager.showImage(mContext, mData[position]?.smallImage, holder.ivAuthorAvatar)
holder.itemView.setOnClickListener {
mListener?.onItemClick(mData[position])
}
}
override fun getItemCount(): Int {
return mData.size
}
inner class ArticleViewHolder(itemView:View):RecyclerView.ViewHolder(itemView){
var tvTitle:AppCompatTextView = itemView.findViewById(R.id.tv_article_title)
var tvDesc:AppCompatTextView = itemView.findViewById(R.id.tv_article_desc)
var ivArticleImage:AppCompatImageView = itemView.findViewById(R.id.iv_article_image)
var ivAuthorAvatar:AppCompatImageView = itemView.findViewById(R.id.iv_author_avatar)
var tvAuthorName:AppCompatTextView = itemView.findViewById(R.id.tv_author_name)
var tvArticleViewNum:AppCompatTextView = itemView.findViewById(R.id.tv_article_view_num)
var tvArticleLikeNum:AppCompatTextView = itemView.findViewById(R.id.tv_article_like_num)
}
interface OnItemClickListener{
fun onItemClick(articleBean: ArticleBean)
}
}
\ No newline at end of file
package adapter
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import fragment.ArticleHomeFragment
class ArticlePagerAdapter constructor(activity: FragmentActivity,list: MutableList<ArticleHomeFragment>):FragmentStateAdapter(activity) {
private var list = mutableListOf<ArticleHomeFragment>()
init {
this.list = list
}
override fun getItemCount(): Int {
return list.size
}
override fun createFragment(position: Int): Fragment {
return list[position]
}
}
\ No newline at end of file
......@@ -9,7 +9,7 @@ import org.json.JSONObject
* Created by harvie on 2019/9/6.
*/
@Route(path = "/article/list")
//@Route(path = "/article/list")
class ArticleActivity : BaseFlutterActivity() {
override fun initialRoute(): String {
......
package data
data class ArticleCategoryListBean(
val articleCategoryResponseList: MutableList<ArticleCategoryBean>?=null
)
data class ArticleCategoryBean(
val categoryId:Int,
val name: String
)
data class ArticleListBean(
val list:MutableList<ArticleBean>?=null,
val totalPage:Int = 0,
val currentPage:Int = 0
)
//"id": 12516,
//"readNum": 215,
//"title": "当你过于敏感焦虑,来试一下系统脱敏训练吧!",
//"desc": "解析阿辰过于敏感失眠的案例,分析过于敏感和外归因的影响,介绍系统脱敏训练方法,鼓励大家用系统脱敏训练来学会放松,缓解敏感焦虑。",
//"imgUrl": "https://img.ydlcdn.com/file/2022/07/05/z5g81dlgbbu6wjq1.jpg!/fw/270",
//"name": "徐姗姗",
//"doctorId": 33094,
//"smallImage": "http://ydl-userprivacy.ydl.com/2022_05_28_63195910000PWTRVQPVQQUQU.772.jpg",
//"pseudonym": "",
//"countOfFavorite": 2,
//"hUrl": "https://h2.yidianling.com/article/12516",
//"mUrl": "https://m.ydl.com/article/12516",
//"createTime": "Jul 5, 2022 9:58:24 AM",
//"createTimeFormat": "2022-07-05",
//"zanNum": 2,
//"url": "https://h2.yidianling.com/article/12516"
data class ArticleBean(
val id:Int,
val readNum:String = "0",
val title:String,
val desc:String,
val imgUrl:String,
val name:String,
val doctorId:Int,
val smallImage:String,
val pseudonym:String,
val countOfFavorite:Int,
val hUrl:String,
val mUrl:String,
val createTime:String,
val createTimeFormat:String,
val zanNum:String = "0",
val categoryId:Int,
val commentTotal:Int,
val label:String,
val content:String,
val status:Int,
val userType:Int,
val userDoctorId:Int,
val listAllUrl:String
)
package fragment
import adapter.ArticleHomeItemAdapter
import android.content.Context
import android.os.Bundle
import android.view.View
import android.widget.LinearLayout
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.scwang.smart.refresh.footer.ClassicsFooter
import com.scwang.smart.refresh.header.ClassicsHeader
import com.scwang.smart.refresh.layout.SmartRefreshLayout
import com.ydl.ydl_router.manager.YDLRouterManager
import com.ydl.ydl_router.manager.YDLRouterParams
import com.ydl.ydlcommon.base.BaseFragment
import com.ydl.ydlcommon.router.IYDLRouterConstant
import com.ydl.ydlcommon.utils.actionutil.ActionCountUtils
import com.yidianling.article.R
import data.ArticleBean
import http.ArticleHttp
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
class ArticleHomeFragment : BaseFragment() {
private lateinit var mSmartRefreshLayout: SmartRefreshLayout
private lateinit var mRvArticleContent: RecyclerView
private lateinit var mLlEmptyLayout: LinearLayout
private var mCurrentPage = 1
private var mTotalPage = 0
private var mTagId: Int = 0
private lateinit var mAdapter: ArticleHomeItemAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mTagId = arguments?.getInt(KEY_ARTICLE_TAG_ID, 0) ?: 0
}
override fun layoutResId(): Int {
return R.layout.article_fragment_layout
}
override fun initDataAndEventLazy() {
}
override fun initDataAndEvent() {
mSmartRefreshLayout = rootView.findViewById(R.id.smart_refresh_layout)
mRvArticleContent = rootView.findViewById(R.id.rv_article_content)
mLlEmptyLayout = rootView.findViewById(R.id.ll_empty)
mSmartRefreshLayout.setRefreshHeader(ClassicsHeader(activity))
mSmartRefreshLayout.setRefreshFooter(ClassicsFooter(activity))
mAdapter = ArticleHomeItemAdapter(activity as Context)
mAdapter.setOnItemClickListener(object : ArticleHomeItemAdapter.OnItemClickListener {
override fun onItemClick(articleBean: ArticleBean) {
ActionCountUtils.record("article_list_main_page","article_list_detail_click")
YDLRouterManager.router(
IYDLRouterConstant.ROUTER_H5_H5,
YDLRouterParams().putExtra(IYDLRouterConstant.EXTRA_URL, articleBean.listAllUrl!!), ""
)
}
})
mRvArticleContent.layoutManager =
LinearLayoutManager(activity, RecyclerView.VERTICAL, false)
mRvArticleContent.adapter = mAdapter
mSmartRefreshLayout.autoRefresh()
mSmartRefreshLayout.setOnRefreshListener {
if (mTagId == 0) {
getRecommendArticleList(isRefresh = true,isLoadMore = false)
} else {
getArticleList(isRefresh = true,isLoadMore = false)
}
mSmartRefreshLayout.finishRefresh()
}
mSmartRefreshLayout.setOnLoadMoreListener {
if (mTagId == 0) {
getRecommendArticleList(isRefresh = false,isLoadMore = true)
} else {
getArticleList(isRefresh = false,isLoadMore = true)
}
mSmartRefreshLayout.finishLoadMore()
}
}
override fun onResume() {
super.onResume()
mSmartRefreshLayout.autoRefresh()
}
private fun getRecommendArticleList(isRefresh: Boolean = true, isLoadMore: Boolean = false) {
ArticleHttp.getInstance().getRecommendArticleList(
perPageRows = 10, page = if (isRefresh) {
1
} else {
mCurrentPage + 1
}
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
if (it.code == "200" && it.data != null) {
if (it.data.list.isNullOrEmpty()) {
mLlEmptyLayout.visibility = View.VISIBLE
mRvArticleContent.visibility = View.GONE
} else {
mLlEmptyLayout.visibility = View.GONE
mRvArticleContent.visibility = View.VISIBLE
mCurrentPage = it.data.currentPage
mTotalPage = it.data.totalPage
mSmartRefreshLayout.setEnableLoadMore(mCurrentPage<mTotalPage)
val articles = it.data.list
if (articles != null) {
if (isRefresh) {
mAdapter.setData(articles)
}
if (isLoadMore) {
mAdapter.addData(articles)
}
}
}
} else {
mLlEmptyLayout.visibility = View.VISIBLE
mRvArticleContent.visibility = View.GONE
}
}
}
private fun getArticleList(isRefresh: Boolean = true, isLoadMore: Boolean = false) {
ArticleHttp.getInstance().getArticleList(
perPageRows = 10,
page = if (isRefresh) {
1
} else {
mCurrentPage + 1
},
tagId = mTagId
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
if (it.code == "200" && it.data != null) {
if (it.data.list.isNullOrEmpty()) {
mLlEmptyLayout.visibility = View.VISIBLE
mRvArticleContent.visibility = View.GONE
} else {
mLlEmptyLayout.visibility = View.GONE
mRvArticleContent.visibility = View.VISIBLE
mCurrentPage = it.data.currentPage
mTotalPage = it.data.totalPage
mSmartRefreshLayout.setEnableLoadMore(mCurrentPage<mTotalPage)
val articles = it.data.list
if (articles != null) {
if (isRefresh) {
mAdapter.setData(articles)
}
if (isLoadMore) {
mAdapter.addData(articles)
}
}
}
} else {
mLlEmptyLayout.visibility = View.VISIBLE
mRvArticleContent.visibility = View.GONE
}
}, {
mLlEmptyLayout.visibility = View.VISIBLE
mRvArticleContent.visibility = View.GONE
})
}
companion object {
const val KEY_ARTICLE_TAG_ID = "key_article_tag_id"
fun newInstance(tagId: Int): ArticleHomeFragment {
val args = Bundle()
args.putInt(KEY_ARTICLE_TAG_ID, tagId)
val fragment = ArticleHomeFragment()
fragment.arguments = args
return fragment
}
}
}
\ No newline at end of file
package http
import com.ydl.ydlcommon.base.config.YDL_DOMAIN
import com.ydl.ydlcommon.base.config.YDL_DOMAIN_JAVA
import com.ydl.ydlcommon.data.http.BaseAPIResponse
import data.ArticleCategoryListBean
import data.ArticleListBean
import io.reactivex.Observable
import retrofit2.http.GET
import retrofit2.http.Headers
import retrofit2.http.Query
interface ArticleApi {
//文章标签
@GET("newArticle/ArticleCate")
@Headers(YDL_DOMAIN + YDL_DOMAIN_JAVA)
fun getArticleTagList(): Observable<BaseAPIResponse<ArticleCategoryListBean>>
//文章列表
@GET("newArticle/list/all")
@Headers(YDL_DOMAIN + YDL_DOMAIN_JAVA)
fun getArticleList(
@Query("perPageRows") perPageRows: Int = 10,
@Query("page") page: Int = 1,
@Query("tagId") tagId: Int = 0
): Observable<BaseAPIResponse<ArticleListBean>>
//文章列表 推荐列表
@GET("newArticle/list/recommend")
@Headers(YDL_DOMAIN + YDL_DOMAIN_JAVA)
fun getRecommendArticleList(
@Query("perPageRows") perPageRows: Int = 10,
@Query("page") page: Int = 1
): Observable<BaseAPIResponse<ArticleListBean>>
}
\ No newline at end of file
package http
import com.ydl.ydlcommon.data.http.BaseAPIResponse
import com.ydl.ydlnet.YDLHttpUtils
import data.ArticleCategoryListBean
import data.ArticleListBean
import io.reactivex.Observable
class ArticleHttp {
companion object{
fun getInstance() = Holder.INSTANCE
}
object Holder{
val INSTANCE = ArticleHttp()
}
private var articleApi:ArticleApi?=null
private fun getArticleApi():ArticleApi{
if (articleApi == null){
articleApi = YDLHttpUtils.obtainApi(ArticleApi::class.java)
}
return articleApi!!
}
fun getArticleCategoryList():Observable<BaseAPIResponse<ArticleCategoryListBean>>{
return getArticleApi().getArticleTagList()
}
fun getRecommendArticleList(perPageRows:Int,page:Int):Observable<BaseAPIResponse<ArticleListBean>>{
return getArticleApi().getRecommendArticleList(perPageRows = perPageRows,page = page)
}
fun getArticleList(perPageRows:Int,page:Int,tagId:Int):Observable<BaseAPIResponse<ArticleListBean>>{
return getArticleApi().getArticleList(perPageRows = perPageRows,page = page,tagId = tagId)
}
}
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M15,3l-8,8l8,8"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#10233A"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
</vector>
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools">
<com.scwang.smart.refresh.layout.SmartRefreshLayout
android:id="@+id/smart_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="20dp"
android:clipToPadding="false">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_article_content"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
<LinearLayout
android:id="@+id/ll_empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="gone"
android:gravity="center"
tools:visibility="visible">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/platform_ydlcommon_blank"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="14dp"
android:text="暂无相应记录"
android:textColor="#b2b2b2"/>
</LinearLayout>
</FrameLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="45dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_back"
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_marginStart="9dp"
android:padding="9dp"
android:src="@drawable/article_home_back_icon"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="文章·阅读"
android:textColor="#000000"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#F8F8F8" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
style="@style/ArticleTabLayoutStyle"
android:layout_width="match_parent"
android:layout_height="38dp"
android:paddingTop="10dp"
app:tabBackground="@color/transparent"
app:tabIndicatorFullWidth="false"
app:tabMaxWidth="88dp"
app:tabMinWidth="64dp"
app:tabMode="scrollable"
app:tabRippleColor="@color/transparent"
app:tabTextAppearance="@style/TabLayoutTextStyle" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:paddingHorizontal="16dp"
android:paddingTop="4dp">
<androidx.cardview.widget.CardView
android:id="@+id/card_view_article_image"
android:layout_width="88dp"
android:layout_height="70dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:cardCornerRadius="8dp"
app:cardElevation="0dp">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_article_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
tools:src="@drawable/picture_album_bg"/>
</androidx.cardview.widget.CardView>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_article_title"
android:layout_width="0dp"
app:layout_constraintHorizontal_weight="1"
android:layout_height="wrap_content"
android:maxHeight="44dp"
android:maxLines="2"
app:layout_constraintEnd_toStartOf="@id/card_view_article_image"
android:ellipsize="end"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="#1C1F28"
android:layout_marginEnd="18dp"
android:lineSpacingExtra="1dp"
tools:text="最伟大的作品,是魔术啊,最伟大的作品,是魔术啊。"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/card_view_article_image"/>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_article_desc"
android:layout_width="0dp"
app:layout_constraintHorizontal_weight="1"
android:layout_height="18dp"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toStartOf="@id/card_view_article_image"
android:maxLines="1"
android:ellipsize="end"
android:textSize="13sp"
android:singleLine="true"
android:textColor="#9D9EA7"
android:layout_marginEnd="18dp"
tools:text="最伟大的作品,是魔术啊,最伟大的作品,是魔术啊。fdasfa"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_article_title"/>
<androidx.cardview.widget.CardView
android:id="@+id/card_view_avatar"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginTop="17dp"
app:layout_constraintStart_toStartOf="@id/tv_article_title"
app:layout_constraintTop_toBottomOf="@id/card_view_article_image"
app:cardElevation="0dp"
app:cardCornerRadius="8dp">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_author_avatar"
android:layout_width="16dp"
android:layout_height="16dp"
tools:src="@drawable/icon_meditation_share_wechat"/>
</androidx.cardview.widget.CardView>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_author_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:textSize="13sp"
android:textColor="#62636F"
tools:text="黄秀章"
app:layout_constraintStart_toEndOf="@id/card_view_avatar"
app:layout_constraintTop_toTopOf="@id/card_view_avatar"
app:layout_constraintBottom_toBottomOf="@id/card_view_avatar"/>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_article_view_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="2656浏览"
android:textSize="13sp"
android:layout_marginEnd="70dp"
android:textColor="#62636F"
app:layout_constraintBaseline_toBaselineOf="@id/tv_author_name"
app:layout_constraintEnd_toEndOf="parent"/>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_article_like_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="3327点赞"
android:textSize="13sp"
android:textColor="#62636F"
app:layout_constraintBaseline_toBaselineOf="@id/tv_author_name"
app:layout_constraintEnd_toEndOf="parent"/>
<View
android:id="@+id/homeModuleArticleItemViewBottomLine"
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="#EFEFF1"
android:layout_marginTop="20dp"
android:layout_marginBottom="30dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/card_view_avatar"/>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="color_1DA1F2">#1DA1F2</color>
<color name="color_999999">#999999</color>
<color name="color_000000">#000000</color>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="ArticleTabLayoutStyle" parent="TextAppearance.Design.Tab">
<item name="tabIndicatorColor">@color/color_1DA1F2</item>
<item name="tabIndicatorHeight">4dp</item>
<item name="tabIndicatorFullWidth">false</item>
<item name="android:textSize">16sp</item>
<item name="tabSelectedTextColor">@color/color_000000</item>
<item name="android:textColor">@color/color_999999</item>
<item name="android:textStyle">normal</item>
</style>
<style name="TabLayoutTextStyle" parent="TextAppearance.Design.Tab">
<item name="android:textSize">16sp</item>
</style>
</resources>
\ No newline at end of file
......@@ -283,7 +283,7 @@ class AudioHomeActivity :
LogUtil.e("[agora]发生警告回调$warn")
writeAgoraLog("声网警告回调($warn)")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "声网警告回调($warn)")
.sendRichLog(AliYunLogConfig.AGORA, "声网警告回调($warn) channelId:${channelId}")
//103:没有可用的频道资源。可能是因为服务端没法分配频道资源
//104:查找频道超时。在加入频道时 SDK 先要查找指定的频道,出现该警告一般是因为网络太差,连接不到服务器
//105:查找频道请求被服务器拒绝。服务器可能没有办法处理这个请求或请求是非法的
......@@ -301,7 +301,7 @@ class AudioHomeActivity :
uploadException("mRtcEventHandler-onError:errorCode--%${err}", callback = null)
writeAgoraLog("声网错误回调errorCode--%${err}")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "声网错误回调errorCode--%${err}")
.sendRichLog(AliYunLogConfig.AGORA, "声网错误回调errorCode--%${err} channelId:${channelId}")
//3:SDK 初始化失败。Agora 建议尝试以下处理方法
//7:SDK 尚未初始化,就调用其 API。请确认在调用 API 之前已创建 RtcEngine 对象并完成初始化
//9:没有操作权限。请检查用户是否授予 app 音视频设备使用权限。
......@@ -315,7 +315,10 @@ class AudioHomeActivity :
//110:生成的 Token 无效
//123:此用户被服务器禁止
LogUtil.e("[agora]发生错误回调$err")
YDLavManager.instances.callEndStatusUpdate(channelId!!, 4, "频道的错误回调信息$err")
if (err == 0 || err == 18) {
return
}
channelId?.let { YDLavManager.instances.callEndStatusUpdate(it, 4, "频道的错误回调信息$err") }
}
override fun onApiCallExecuted(error: Int, api: String?, result: String?) {
......@@ -367,7 +370,7 @@ class AudioHomeActivity :
super.onRtcStats(stats)
writeAgoraLog("声网onRtcStats:users:${stats?.users}")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "声网onRtcStats:users:${stats?.users}")
.sendRichLog(AliYunLogConfig.AGORA, "声网onRtcStats:users:${stats?.users} channelId:${channelId}")
// 不需要移动端做离开房间逻辑,服务端会判断进行踢人逻辑
//因为用户端直接加入了频道,防止该回调执行时,专家还未加入频道,因此在连接成功之后,才进行频道人数判断
// if (isConnectSuccess && null != stats?.users && stats.users == 1) {
......@@ -391,7 +394,7 @@ class AudioHomeActivity :
AliYunRichLogsHelper.getInstance()
.sendRichLog(
AliYunLogConfig.AGORA,
"通话结束:网络连接被服务器中止 该情况现在是因为后端踢人逻辑,原因(${reason})"
"通话结束:网络连接被服务器中止 该情况现在是因为后端踢人逻辑,原因(${reason}) channelId:${channelId}"
)
// com.yidianling.common.tools.ToastUtil.toastShort("专家已挂断")
//通话结束或挂断时,上传日志文件
......@@ -407,7 +410,7 @@ class AudioHomeActivity :
LogUtil.e("[agora]离开频道回调")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "离开频道回调")
.sendRichLog(AliYunLogConfig.AGORA, "离开频道回调 channelId:${channelId}")
//通话结束或挂断时,上传日志文件
uploadLog()
}
......@@ -419,7 +422,7 @@ class AudioHomeActivity :
LogUtil.e("[agora]远端用户/主播加入频道回调")
onPeerJoined()
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "远端用户/主播加入频道回调")
.sendRichLog(AliYunLogConfig.AGORA, "远端用户/主播加入频道回调 channelId:${channelId}")
}
override fun onUserOffline(uid: Int, elapsed: Int) {
......@@ -429,7 +432,7 @@ class AudioHomeActivity :
LogUtil.e("[agora]远端用户$uid 离开频道回调")
writeAgoraLog("接通后通话结束:对方已挂断")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "接通后通话结束:对方已挂断")
.sendRichLog(AliYunLogConfig.AGORA, "接通后通话结束:对方已挂断 channelId:${channelId}")
//通话结束或挂断时,上传日志文件
uploadLog()
showToast("专家已挂断")
......@@ -465,6 +468,8 @@ class AudioHomeActivity :
if (txQuality in 1..2 && rxQuality in 1..2) {
""
} else if (txQuality >= 5 || rxQuality >= 5) {
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "您的网络已断开 channelId:${channelId}")
"您的网络已断开"
} else {
status = if (txQuality >= 4 || rxQuality >= 4) {
......@@ -472,6 +477,8 @@ class AudioHomeActivity :
} else {
1
}
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "您的网络状况不佳 channelId:${channelId}")
"您的网络状况不佳"
}
}
......@@ -479,6 +486,8 @@ class AudioHomeActivity :
if (txQuality in 1..2 && rxQuality in 1..2) {
""
} else if (txQuality >= 5 || rxQuality >= 5) {
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "对方的网络已断开 channelId:${channelId}")
"对方的网络已断开"
} else {
status = if (txQuality >= 4 || rxQuality >= 4) {
......@@ -486,6 +495,8 @@ class AudioHomeActivity :
} else {
1
}
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "对方的网络状况不佳 channelId:${channelId}")
"对方的网络状况不佳"
}
}
......@@ -515,7 +526,7 @@ class AudioHomeActivity :
writeAgoraLog("通话页面打开的时候,RTM登录状态码:${YDLavManager.sdkStatus}")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.RTM, "通话页面打开的时候,RTM登录状态码:${YDLavManager.sdkStatus}")
.sendRichLog(AliYunLogConfig.RTM, "通话页面打开的时候,RTM登录状态码:${YDLavManager.sdkStatus} channelId:${channelId}")
if (YDLavManager.sdkStatus != Constants.CONNECTION_STATE_CONNECTED) {
//再次登录声网,确保声网登录状态
reLoginRTM()
......@@ -588,7 +599,7 @@ class AudioHomeActivity :
dialStatus = intent.getStringExtra(IntentConstants.INTENT_DIALSTATUS)
writeAgoraLog("专家的通话状态dialStatus:$dialStatus", false)
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "专家的通话状态dialStatus:$dialStatus")
.sendRichLog(AliYunLogConfig.AGORA, "专家的通话状态dialStatus:$dialStatus channelId:${channelId}")
isShowAXB = intent.getBooleanExtra(IntentConstants.INTENT_ISSHOWAXB, true)
val logBean = AgoraLogInfoBean(
......@@ -604,7 +615,7 @@ class AudioHomeActivity :
val content = Gson().toJson(logBean)
writeAgoraLog("主叫方发送的邀请通话消息内容:$content", true)
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "主叫方发送的邀请通话消息内容:$content")
.sendRichLog(AliYunLogConfig.AGORA, "主叫方发送的邀请通话消息内容:$content channelId:${channelId}")
localRemainTime = remainTime?.toInt() ?: 1500
handler = Handler()
......@@ -630,7 +641,7 @@ class AudioHomeActivity :
writeAgoraLog("RMT状态:${YDLavManager.sdkStatus},重新登录RMT")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.RTM, "RMT状态:${YDLavManager.sdkStatus},重新登录RMTt")
.sendRichLog(AliYunLogConfig.RTM, "RMT状态:${YDLavManager.sdkStatus},重新登录RMTt channelId:${channelId}")
val uid = YdlCommonRouterManager.getYdlCommonRoute().getUid().toString()
YDLavManager.instances.login(uid) { _isSuccess, _msg ->
// writeAgoraLog("拨打电话界面打开RTM重新登录,uid=${uid}")
......@@ -644,7 +655,7 @@ class AudioHomeActivity :
callEventSave("20", "通话页面打开")
writeAgoraLog("用户拨打电话界面开启")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "用户拨打电话界面开启")
.sendRichLog(AliYunLogConfig.AGORA, "用户拨打电话界面开启 channelId:${channelId}")
//水波纹view初始化
wave_view.setDuration(6000)
wave_view.setStyle(Paint.Style.STROKE)
......@@ -695,13 +706,13 @@ class AudioHomeActivity :
audio_mute_text.text = "麦克风已关"
voiceManage?.getVoiceApi()?.enableLocalAudio(false)
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "用户端点击:麦克风已关")
.sendRichLog(AliYunLogConfig.AGORA, "用户端点击:麦克风已关 channelId:${channelId}")
} else {
iv_mute_on_off.isSelected = true
iv_mute_on_off.setImageResource(R.drawable.audiohome_muteon)
audio_mute_text.text = "麦克风已开"
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "用户端点击:麦克风已开")
.sendRichLog(AliYunLogConfig.AGORA, "用户端点击:麦克风已开 channelId:${channelId}")
voiceManage?.getVoiceApi()?.enableLocalAudio(true)
}
}
......@@ -713,7 +724,7 @@ class AudioHomeActivity :
return@setOnClickListener
}
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "用户端点击:切换线路")
.sendRichLog(AliYunLogConfig.AGORA, "用户端点击:切换线路 channelId:${channelId}")
ActionCountUtils.record("call_phone_page", "call_phone_icon_click", "0", "4")
showChooseDialog(1)
......@@ -722,7 +733,7 @@ class AudioHomeActivity :
iv_hang_up.setOnClickListener {
if (!canHangUp) {
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "用户端点击:挂断,展示提示弹窗")
.sendRichLog(AliYunLogConfig.AGORA, "用户端点击:挂断,展示提示弹窗 channelId:${channelId}")
showHangUpTimeOnlineDialog()
return@setOnClickListener
}
......@@ -734,7 +745,7 @@ class AudioHomeActivity :
if (isConnectSuccess) {
writeAgoraLog("已接通:主叫主动挂断")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "已接通:主叫主动挂断")
.sendRichLog(AliYunLogConfig.AGORA, "已接通:主叫主动挂断 channelId:${channelId}")
updateExpertStatus(false, 1)
leaveChannel()
uploadLog()
......@@ -759,13 +770,13 @@ class AudioHomeActivity :
iv_hands_free.setImageResource(R.drawable.audioim_img_hands_free_unuse)
hands_free_text.text="扬声器已关"
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "用户端点击:免提,扬声器已关")
.sendRichLog(AliYunLogConfig.AGORA, "用户端点击:免提,扬声器已关 channelId:${channelId}")
} else {
iv_hands_free.isSelected = true
iv_hands_free.setImageResource(R.drawable.audioim_img_hands_free)
hands_free_text.text="扬声器已开"
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "用户端点击:免提,扬声器已开")
.sendRichLog(AliYunLogConfig.AGORA, "用户端点击:免提,扬声器已开 channelId:${channelId}")
}
//已经接通
......@@ -796,7 +807,7 @@ class AudioHomeActivity :
writeAgoraLog("请求音频权限通过")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "请求音频权限通过")
.sendRichLog(AliYunLogConfig.AGORA, "请求音频权限通过 channelId:${channelId}")
init()
}
......@@ -812,7 +823,7 @@ class AudioHomeActivity :
writeAgoraLog("拒绝请求音频权限")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "拒绝请求音频权限")
.sendRichLog(AliYunLogConfig.AGORA, "拒绝请求音频权限 channelId:${channelId}")
uploadLog()
showStorageDialog()
......@@ -823,7 +834,7 @@ class AudioHomeActivity :
callEventSave("80", "请求音频权限异常${e.message}")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "请求音频权限异常${e.message}")
.sendRichLog(AliYunLogConfig.AGORA, "请求音频权限异常${e.message} channelId:${channelId}")
init()
}
......@@ -934,7 +945,7 @@ class AudioHomeActivity :
writeAgoraLog("主叫(用户)发送通话邀请")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "主叫(用户)发送通话邀请$msgBean")
.sendRichLog(AliYunLogConfig.AGORA, "主叫(用户)发送通话邀请$msgBean channelId:${channelId}")
rtcCall()
//开始50s等待倒计时
......@@ -987,7 +998,7 @@ class AudioHomeActivity :
LogUtil.d(it.message)
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "倒计时异常${it.message}")
.sendRichLog(AliYunLogConfig.AGORA, "倒计时异常${it.message} channelId:${channelId}")
dismissHangUpTimeOnlineDialog()
......@@ -1007,7 +1018,7 @@ class AudioHomeActivity :
writeAgoraLog("未接通挂断:50s等待倒计时结束挂断")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "未接通挂断:50s等待倒计时结束挂断")
.sendRichLog(AliYunLogConfig.AGORA, "未接通挂断:50s等待倒计时结束挂断 channelId:${channelId}")
//提示切换传统线路
//发送消息通知专家用户已挂断
YDLavManager.instances.cancelCall(
......@@ -1021,7 +1032,7 @@ class AudioHomeActivity :
AliYunRichLogsHelper.getInstance()
.sendRichLog(
AliYunLogConfig.AGORA,
"未接听时:主叫(用户)主动挂断失败,msg=$msg($code),再次挂断"
"未接听时:主叫(用户)主动挂断失败,msg=$msg($code),再次挂断 channelId:${channelId}"
)
}
//通话结束或挂断时,上传日志文件
......@@ -1081,7 +1092,7 @@ class AudioHomeActivity :
writeAgoraLog("未接听时:主叫(用户)主动挂断,取消呼叫")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "未接听时:主叫(用户)主动挂断,取消呼叫")
.sendRichLog(AliYunLogConfig.AGORA, "未接听时:主叫(用户)主动挂断,取消呼叫 channelId:${channelId}")
LogUtil.e("未接听挂断")
//发送消息通知专家用户已挂断
YDLavManager.instances.cancelCall(
......@@ -1093,7 +1104,7 @@ class AudioHomeActivity :
writeAgoraLog("未接听时:主叫(用户)主动挂断失败,msg=$msg($code),再次挂断")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "未接听时:主叫(用户)主动挂断失败,msg=$msg($code),再次挂断")
.sendRichLog(AliYunLogConfig.AGORA, "未接听时:主叫(用户)主动挂断失败,msg=$msg($code),再次挂断 channelId:${channelId}")
}
//通话结束或挂断时,上传日志文件
uploadLog()
......@@ -1129,7 +1140,7 @@ class AudioHomeActivity :
writeAgoraLog("主叫点击切换AXB按钮")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "主叫点击切换AXB按钮")
.sendRichLog(AliYunLogConfig.AGORA, "主叫点击切换AXB按钮 channelId:${channelId}")
switchAXB()
}
......@@ -1155,7 +1166,7 @@ class AudioHomeActivity :
writeAgoraLog("离开房间成功,主叫切换AXB之后")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "离开房间成功,主叫切换AXB之后")
.sendRichLog(AliYunLogConfig.AGORA, "离开房间成功,主叫切换AXB之后 channelId:${channelId}")
mPresenter.getAXBPhone(ConnectCommand(listenId!!, "1"))
}
......@@ -1192,7 +1203,7 @@ class AudioHomeActivity :
writeAgoraLog("未接听时:主叫主动挂断失败,msg=$msg($code),再次挂断")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "未接听时:主叫主动挂断失败,msg=$msg($code),再次挂断")
.sendRichLog(AliYunLogConfig.AGORA, "未接听时:主叫主动挂断失败,msg=$msg($code),再次挂断 channelId:${channelId}")
}
leaveChannel()
}
......@@ -1419,7 +1430,7 @@ class AudioHomeActivity :
cmd.status = "CALL_OFF"
}
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "用户加入频道后,通知服务端发送推送")
.sendRichLog(AliYunLogConfig.AGORA, "用户加入频道后,通知服务端发送推送 channelId:${channelId}")
mPresenter.noticeServerPush(cmd)
}
......
......@@ -119,6 +119,18 @@ class ConsultantAudioHomeActivity :
*/
private var isConnectSuccess: Boolean = false
companion object {
const val PARAM: String = "param"
//0.未接听 1.已接听
const val STATUS_NOT_ANSWERED = 0
const val STATUS_ANSWERED = 1
//666.未接听,直接挂断 667.已接听,正常挂断 668:未接听,用户端取消了
const val RESULT_NOT_ANSWERED_CODE = 666
const val RESULT_ANSWERED_CODE = 667
const val RESULT_USER_CANCEL = 668
}
/**
* 事件回调 (SDK 通过指定的事件通知应用程序 SDK 的运行事件,如: 加入或离开频道,新用户加入频道等)
*/
......@@ -131,6 +143,8 @@ class ConsultantAudioHomeActivity :
*/
override fun onUserMuteAudio(uid: Int, muted: Boolean) {
callEventSave("80", "uid:${uid} 开启了静音 = ${muted}")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "咨询用户端:咨询用户端:uid:${uid} 开启了静音 = ${muted} channelId:${mAudioMessageBean?.channelId}")
// runOnUiThread {
// showToast("对方静音了,提醒他打开!")
// }
......@@ -143,12 +157,12 @@ class ConsultantAudioHomeActivity :
LogUtil.e("[agora]$uid 加入频道回调")
writeAgoraLog("被叫(用户)加入声网($channel)频道成功")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "被叫(用户)加入声网($channel)频道成功")
.sendRichLog(AliYunLogConfig.AGORA, "咨询用户端:被叫(用户)uid:${uid}加入声网($channel)频道成功")
runOnUiThread {
// 加入频道后再通知用户已接受
// YDLRTMClient.instances.acceptCall(mAudioMessageBean?.channelId)
YDLavManager.instances.acceptCall(
mAudioMessageBean!!.userId!!,
mAudioMessageBean?.userId!!,
mAudioMessageBean?.channelId,
Gson().toJson(mAudioMessageBean)
)
......@@ -174,7 +188,7 @@ class ConsultantAudioHomeActivity :
LogUtil.e("[agora]$uid 重新加入频道回调")
writeAgoraLog("被叫(用户)重新加入声网频道($channel)成功")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "被叫(用户)重新加入声网频道($channel)成功")
.sendRichLog(AliYunLogConfig.AGORA, "咨询用户端:被叫(用户)uid:${uid} 重新加入声网频道($channel)成功")
runOnUiThread {
if (!isConnectSuccess) {
......@@ -195,7 +209,7 @@ class ConsultantAudioHomeActivity :
LogUtil.e("[agora]远端用户加入频道回调")
writeAgoraLog("主叫(专家)加入声网频道成功")
AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "主叫(专家)加入声网频道成功")
AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "咨询用户端:主叫(专家)uid:${uid}加入声网频道成功 channelId:${mAudioMessageBean?.channelId}")
//另一方加入频道成功
runOnUiThread {
......@@ -269,7 +283,7 @@ class ConsultantAudioHomeActivity :
callEventSave("52", "自己离开频道回调")
LogUtil.e("[agora]自己离开频道回调")
AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "自己离开频道回调")
AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "咨询用户端:自己离开频道回调 channelId:${mAudioMessageBean?.channelId}")
//通知php 通话已结束
close(RESULT_ANSWERED_CODE, "")
......@@ -313,7 +327,7 @@ class ConsultantAudioHomeActivity :
showToast("对方已挂断")
writeAgoraLog("通话接通后挂断:主叫(专家)离开频道")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "通话接通后挂断:主叫(专家)离开频道")
.sendRichLog(AliYunLogConfig.AGORA, "咨询用户端:通话接通后挂断:主叫(专家)$uid 离开频道 channelId:${mAudioMessageBean?.channelId}")
if (null != totalDisposable) {
totalDisposable!!.dispose()
......@@ -331,7 +345,7 @@ class ConsultantAudioHomeActivity :
}
LogUtil.e("[agora]发生警告回调=$warn")
writeAgoraLog("声网警告回调码:($warn)")
AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "声网警告回调码:($warn)")
AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "咨询用户端:声网警告回调码:($warn) channelId:${mAudioMessageBean?.channelId}")
//103:没有可用的频道资源。可能是因为服务端没法分配频道资源
//104:查找频道超时。在加入频道时 SDK 先要查找指定的频道,出现该警告一般是因为网络太差,连接不到服务器
......@@ -359,7 +373,7 @@ class ConsultantAudioHomeActivity :
LogUtil.e("[agora] 发生错误回调 =$err")
writeAgoraLog("声网错误回调errorCode--%${err}")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "声网错误回调errorCode--%${err}")
.sendRichLog(AliYunLogConfig.AGORA, "咨询用户端:声网错误回调errorCode--%${err} channelId:${mAudioMessageBean?.channelId}")
//3:SDK 初始化失败。Agora 建议尝试以下处理方法
//7:SDK 尚未初始化,就调用其 API。请确认在调用 API 之前已创建 RtcEngine 对象并完成初始化
......@@ -408,10 +422,13 @@ class ConsultantAudioHomeActivity :
else -> {
}
}
if (err == 0 || err == 18) {
return@runOnUiThread
}
YDLavManager.instances.callEndStatusUpdate(
mAudioMessageBean?.channelId!!,
4,
"频道的错误回调信息${err}"
"频道的错误回调信息${err} "
)
}
}
......@@ -430,6 +447,8 @@ class ConsultantAudioHomeActivity :
if (txQuality in 1..2 && rxQuality in 1..2) {
""
} else if (txQuality >= 5 || rxQuality >= 5) {
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "咨询用户端:您的网络已断开 channelId:${mAudioMessageBean?.channelId}")
"您的网络已断开"
} else {
status = if (txQuality >= 4 || rxQuality >= 4) {
......@@ -437,6 +456,8 @@ class ConsultantAudioHomeActivity :
} else {
1
}
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "咨询用户端:您的网络状况不佳 channelId:${mAudioMessageBean?.channelId}")
"您的网络状况不佳"
}
}
......@@ -444,6 +465,8 @@ class ConsultantAudioHomeActivity :
if (txQuality in 1..2 && rxQuality in 1..2) {
""
} else if (txQuality >= 5 || rxQuality >= 5) {
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "咨询用户端:对方的网络已断开 channelId:${mAudioMessageBean?.channelId}")
"对方的网络已断开"
} else {
status = if (txQuality >= 4 || rxQuality >= 4) {
......@@ -451,6 +474,8 @@ class ConsultantAudioHomeActivity :
} else {
1
}
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "咨询用户端:对方的网络状况不佳 channelId:${mAudioMessageBean?.channelId}")
"对方的网络状况不佳"
}
}
......@@ -468,18 +493,7 @@ class ConsultantAudioHomeActivity :
return R.layout.audioim_cativity_consultant_audio_home
}
companion object {
const val PARAM: String = "param"
//0.未接听 1.已接听
const val STATUS_NOT_ANSWERED = 0
const val STATUS_ANSWERED = 1
//666.未接听,直接挂断 667.已接听,正常挂断 668:未接听,用户端取消了
const val RESULT_NOT_ANSWERED_CODE = 666
const val RESULT_ANSWERED_CODE = 667
const val RESULT_USER_CANCEL = 668
}
override fun initDataAndEvent() {
EventBus.getDefault().register(this)
......@@ -607,7 +621,7 @@ class ConsultantAudioHomeActivity :
callEventSave("90", "通话频道不存在")
LogUtil.e("[agora]token not null")
AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "token isEmpty ")
AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "咨询用户端:token isEmpty channelId:${mAudioMessageBean?.channelId}")
showToast("通话频道不存在")
finish()
......@@ -691,7 +705,7 @@ class ConsultantAudioHomeActivity :
LogUtil.e("[agora] joinChannel:$account")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "joinChannel:$account")
.sendRichLog(AliYunLogConfig.AGORA, "咨询用户端:joinChannel:$account channelId:${mAudioMessageBean?.channelId}")
voiceManage?.getVoiceApi()?.joinChannel(
channelToken
......@@ -929,7 +943,7 @@ class ConsultantAudioHomeActivity :
runOnUiThread {
LogUtil.e("[agora]close(code:$code,msg:$msg)")
AliYunRichLogsHelper.getInstance()
.sendRichLog(AliYunLogConfig.AGORA, "close(code:$code,msg:$msg)")
.sendRichLog(AliYunLogConfig.AGORA, "咨询用户端:close(code:$code,msg:$msg) channelId:${mAudioMessageBean?.channelId}")
//上传日志文件
uploadLog()
......@@ -940,6 +954,8 @@ class ConsultantAudioHomeActivity :
RESULT_ANSWERED_CODE -> {
//已接听,正常挂断
//离开频道
AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "咨询用户端:已接听,正常挂断 channelId:${mAudioMessageBean?.channelId}")
leaveChannel()
}
RESULT_NOT_ANSWERED_CODE -> {
......@@ -961,7 +977,7 @@ class ConsultantAudioHomeActivity :
}
ActivityManager.getInstance().removeStack(activity = this)
LogUtil.e("[agora]页面移除")
AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "页面移除")
AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "咨询用户端:页面移除 channelId:${mAudioMessageBean?.channelId}")
finish()
}
}
......@@ -977,15 +993,17 @@ class ConsultantAudioHomeActivity :
* 停止播放
*/
private fun stopPlaying() {
if (mPlayer != null) {
mPlayer!!.pause()
}
AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "咨询用户端:stopPlaying channelId:${mAudioMessageBean?.channelId}")
mPlayer?.pause()
}
/**
* 播放结束音频
*/
private fun playFinishMusic() {
AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "咨询用户端:playFinishMusic channelId:${mAudioMessageBean?.channelId}")
if (mPlayer == null) {
mPlayer = AudioPlayer(this, true)
}
......@@ -1012,6 +1030,8 @@ class ConsultantAudioHomeActivity :
1,
"被叫加入频道后主叫未加入超时"
)
AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "咨询用户端:15s后如果还是处于连接中,则直接退出当前页面 channelId:${mAudioMessageBean?.channelId}")
writeAgoraLog("通话未接通挂断:连接中的状态超过5s自动挂断")
showToast("用户已挂断")
close(RESULT_NOT_ANSWERED_CODE, "")
......@@ -1025,28 +1045,16 @@ class ConsultantAudioHomeActivity :
*/
private fun leaveChannel() {
uploadException("", "zhu", "108")
if (totalDisposable != null) {
totalDisposable!!.dispose()
}
if (connectingStatusDisposable != null) {
connectingStatusDisposable!!.dispose()
}
if (null != voiceManage && null != voiceManage!!.getVoiceApi()) {
voiceManage!!.getVoiceApi().leaveChannel()
voiceManage!!.getVoiceApi().destroy()
voiceManage = null
}
if (mPlayer != null) {
mPlayer!!.clear()
}
if (null != sensorManager) {
sensorManager!!.unregisterListener(this)
}
totalDisposable?.dispose()
connectingStatusDisposable?.dispose()
voiceManage?.getVoiceApi()?.leaveChannel()
voiceManage?.getVoiceApi()?.destroy()
voiceManage = null
mPlayer?.clear()
sensorManager?.unregisterListener(this)
//唤醒设备
if (null != localWakeLock && localWakeLock!!.isHeld) {
localWakeLock!!.release()
if (localWakeLock?.isHeld == true) {
localWakeLock?.release()
}
sensorManager = null
localWakeLock = null
......@@ -1054,9 +1062,7 @@ class ConsultantAudioHomeActivity :
}
private fun voiceDestory() {
if (null != voiceManage && null != voiceManage!!.getVoiceApi()) {
voiceManage!!.getVoiceApi().destroy()
}
voiceManage?.getVoiceApi()?.destroy()
voiceManage = null
}
......@@ -1108,6 +1114,8 @@ class ConsultantAudioHomeActivity :
override fun onDestroy() {
LogUtil.e("http-------------onDestory")
AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "咨询用户端:onDestroy channelId:${mAudioMessageBean?.channelId}")
leaveChannel()
voiceDestory()
isConnectSuccess = false
......@@ -1123,6 +1131,7 @@ class ConsultantAudioHomeActivity :
}
}
super.onDestroy()
}
......
......@@ -65,8 +65,9 @@ dependencies {
// 注意此处的依赖方式:kotlin中使用和java中使用方式有不同
kapt "com.alibaba:arouter-compiler:$arouter_compiler"
implementation 'com.alibaba:fastjson:1.2.38'
implementation "com.ydl:jjdxm-ijkplayer:0.0.33"
implementation(rootProject.ext.dependencies["ydl-ijkplayer-jjdxm"]) {
exclude group: 'com.android.support', module: 'appcompat-v7'
}
api rootProject.ext.dependencies["ydl-user-router"]
if (rootProject.ext.dev_mode){
//开发时使用
......
......@@ -133,13 +133,15 @@ class ConfideHomeEventImpl(context: Context, var confideHomeView: IConfideHomeCo
* @param linkUrl 跳转地址
*/
override fun consultantClick(doctorId: String?, confideId: String?, uid: String?,listenFree : Boolean?, expertUrl:String?) {
confideId?.let {
ConfideBottomSheetDialogFragment()
.showBottomSheetDialog(
mContext as FragmentActivity,
HttpConfig.MH5_URL + ConfideRoute.h5ConfideIntro(it),
doctorId!!, uid = uid, listenFree = listenFree ?: false,expertUrl = expertUrl?:""
)
doctorId?.let { doctorId ->
confideId?.let {confideId ->
ConfideBottomSheetDialogFragment()
.showBottomSheetDialog(
mContext as FragmentActivity,
HttpConfig.MH5_URL + ConfideRoute.h5ConfideIntro(confideId),
doctorId, uid = uid, listenFree = listenFree ?: false,expertUrl = expertUrl?:""
)
}
}
}
......
......@@ -433,7 +433,7 @@ internal fun VideoViewModel.mapOf(bean: ConfideHomeBodyBean): VideoViewModel {
avatar.set(bean.confidedIcon)
linkedUrl.set(bean.linkUrl)
val num = bean.confideNum?.replace("人", "") ?: "0"
count.set("倾诉人次 $num")
count.set("服务人次 $num")
intro.set(bean.confideContent)
title.set(bean.title)
val sb = StringBuilder()
......
......@@ -116,7 +116,7 @@
android:layout_height="wrap_content"
android:textSize="@dimen/platform_sp_12"
android:textColor="#69696A"
android:text="倾诉人次"
android:text="服务人次"
/>
</LinearLayout>
<LinearLayout
......
......@@ -47,6 +47,9 @@ dependencies {
kapt 'com.alibaba:arouter-compiler:1.2.2'
implementation rootProject.ext.dependencies["BaseRecyclerViewAdapterHelper"]
api rootProject.ext.dependencies["ydl-user-router"]
implementation(rootProject.ext.dependencies["ydl-ijkplayer-jjdxm"]) {
exclude group: 'com.android.support', module: 'appcompat-v7'
}
if (rootProject.ext.dev_mode){
//开发时使用
implementation project(":api:user")
......
......@@ -18,6 +18,14 @@
android:name=".ConsultAssistantCenterActivity"
android:screenOrientation="portrait"
android:theme="@style/consultant_Transparent"/>
<activity android:name=".preview.GridPreviewActivity"
android:screenOrientation="portrait"
android:theme="@style/consultant_Transparent"/>
<activity android:name=".preview.GPreviewActivity"
android:screenOrientation="portrait"
android:theme="@style/consultant_Transparent"/>
</application>
</manifest>
\ No newline at end of file
......@@ -330,9 +330,7 @@ class ExpertSearchFragment : BaseMvpFragment<IExpertSearchView, ExpertSearchPres
isShow = isVisibleToUser
if (isVisibleToUser && isResumed) {
startTime = System.currentTimeMillis()
showConsultAssistantDialog()
} else {
hideConsultAssistantDialog()
if (startTime != 0L) {
endTime = System.currentTimeMillis()
ActionCountUtils.count(
......
......@@ -240,6 +240,8 @@ class ExpertSearchPresenter : SimplePresenter<IExpertSearchView>() {
fieldsMap["open_chat_agency"] = true
fieldsMap["service_status"] = true
fieldsMap["is_free_today"] = true
fieldsMap["display_region"] = true
fieldsMap["has_servicefree_experience"] = true
map["fields"] = fieldsMap
val optionsMap = HashMap<String, Any?>()
......
......@@ -52,6 +52,8 @@ class HotSearchActivity : BaseMvpActivity<IHotSearchContract.View, IHotSearchCon
private var historyList: FixSizeLinkedList<String> = FixSizeLinkedList(15)
private val bannerList = ArrayList<String>()
private var lenovoResultSuccess = false // 联想结果 联想前false 联想成功后true
companion object {
private const val CACHE_CONSULT_SEARCH_HISTORY_DATA = "cache_consult_search_history_data"
private const val HOT_SEARCH_DOCTOR_NAME = "hot_search_doctor_name"
......@@ -111,7 +113,11 @@ class HotSearchActivity : BaseMvpActivity<IHotSearchContract.View, IHotSearchCon
// 搜索的关联词
var relatedWords = ""
var isRecommendWords = false
if (searchSuggestList.isNotEmpty() && searchSuggestList.size > 0) {
if (!lenovoResultSuccess && !etSearch.text.toString()
.isNullOrEmpty()
) { // 如果每次输入内容后联想词结果还没返回结果则直接进行搜索
doSearch(etSearch.text.toString(), relatedWords, isRecommendWords)
} else if (searchSuggestList.isNotEmpty() && searchSuggestList.size > 0) {
if (searchSuggestList[0].suggest_relations.size > 0) {
relatedWords = searchSuggestList[0].suggest_relations[0]
isRecommendWords = true
......@@ -120,7 +126,7 @@ class HotSearchActivity : BaseMvpActivity<IHotSearchContract.View, IHotSearchCon
relatedWords = searchSuggestList[0].suggest_content
}
if (searchSuggestList?.get(0)?.suggest_types?.contains(JUMP_WORD)) {
if (searchSuggestList[0].suggest_types.contains(JUMP_WORD)) {
NewH5Activity.start(this, H5Params(searchSuggestList[0].jump_url!!, null))
} else {
if (etSearch.text.toString().isNullOrEmpty()) {
......@@ -231,6 +237,7 @@ class HotSearchActivity : BaseMvpActivity<IHotSearchContract.View, IHotSearchCon
*/
private fun getSearchWords(searchContent: String, isClickWords: Boolean) {
if (!TextUtils.isEmpty(searchContent)) {
lenovoResultSuccess = false
mSearchContent = searchContent
val map = HashMap<String, Any>()
map["content"] = searchContent
......@@ -245,6 +252,7 @@ class HotSearchActivity : BaseMvpActivity<IHotSearchContract.View, IHotSearchCon
searchContent: String,
isClickWords: Boolean
) {
lenovoResultSuccess = true
if (isClickWords) {
//判断 suggest_classify_types 有值则通过 jump_url跳转
// 搜索的关联词
......
......@@ -177,14 +177,14 @@ class ExpertSearchAdapter(
//省市
if (!TextUtils.isEmpty(itemBean.province)) {
holder.tvCity.text = itemBean.province + "·" + itemBean.city
if (!TextUtils.isEmpty(itemBean.display_region)) {
holder.tvCity.text = itemBean.display_region
} else {
holder.tvCity.text = ""
}
//公益图标,不与其他图标冲突
if (1 == itemBean.has_servicefree_consult) {
if (1 == itemBean.has_servicefree_experience) {
if (null != itemBean.icons && !TextUtils.isEmpty(itemBean.icons.service_free_icon)) {
expertSearchView.showImage(
itemBean.icons.service_free_icon,
......
......@@ -108,11 +108,11 @@ data class ExpertServiceItem(
// */
// var listen_status: Int,
var open_chat_agency:Int,
var open_chat_agency: Int,
var service_status:Int,
var service_status: Int,
var is_free_today:Int,
var is_free_today: Int,
/**
* 私聊人数
......@@ -143,26 +143,39 @@ data class ExpertServiceItem(
/**
* 是否是头部headView
*/
val is_head_view:Boolean=false,
val is_head_view: Boolean = false,
/**
* 搜索词
*/
val search_content:String,
val search_content: String,
/**
* 联想词
*/
val related_word:String
val related_word: String,
/**
* 地区
*/
val display_region: String,
/**
* 是否展示公益图标
*/
val has_servicefree_experience: Int?
) {
constructor(is_head_view: Boolean,search_content: String,related_word:String) : this("","","","","",
1,1,1,"",false,true,
1f,false,0,"","","",1f,1f,
null,null,1,1,1,1,
"","","","",null,is_head_view,search_content,related_word)
constructor(is_head_view: Boolean, search_content: String, related_word: String) : this(
"", "", "", "", "",
1, 1, 1, "", false, true,
1f, false, 0, "", "", "", 1f, 1f,
null, null, 1, 1, 1, 1,
"", "", "", "", null, is_head_view, search_content, related_word, "", 1
)
}
data class FeatureTag(
val tag_id:String,
val tag_name:String,
val is_highlight:Boolean, // 是否高亮
val type:String // 标签类型
val tag_id: String,
val tag_name: String,
val is_highlight: Boolean, // 是否高亮
val type: String // 标签类型
)
\ No newline at end of file
......@@ -40,8 +40,9 @@ class ConsultAssistantDialogUtils private constructor() {
var consultAssistantDialogFromHomePage: ConsultAssistantDialog? = null // 首页展示的dialog
var consultAssistantDialogFromMine: ConsultAssistantDialog? = null // 我的展示的dialog
var consultAssistantFragmentDialog: ConsultAssistantDialog? = null //咨询师列表fragment页面展示的dialog
var expertSearchPageHasShown: Boolean = false // 专家咨询列表fragment页面是否已经展示
var consultAssistantActivityDialog: ConsultAssistantDialog? = null //咨询师列表activity页面展示的dialog
var expertSearchPageHasShown: Boolean = false // 专家咨询列表fragment页面是否已经展示
var confideListDialog: ConsultAssistantDialog? = null //倾诉列表activity页面展示的dialog
var expertSearchActivityPageHasShown: Boolean = false // 专家咨询列表activity页面是否已经展示
......@@ -86,22 +87,20 @@ class ConsultAssistantDialogUtils private constructor() {
origin: String,
fromActivity: Boolean = false
) {
// 请求接口判断导医咨询助理按钮是否展示
SearchApi.getSearchApi().getConsultAssistantRequest(origin)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
if (it.data) {
if (origin == "home_index") {
showFromYdlHome(activity)
} else if (origin == "doctor_list") {
show(activity, origin, fromActivity)
} else if (origin == "mine_index") {
showFromMine(activity)
}
}
consultAssistantDialogFromHomePage?.dismiss()
consultAssistantFragmentDialog?.dismiss()
consultAssistantDialogFromMine?.dismiss()
when (origin) {
"home_index" -> {
showFromYdlHome(activity)
}
"doctor_list" -> {
show(activity, origin, fromActivity)
}
"mine_index" -> {
showFromMine(activity)
}
}
}
////////////////////////////////////// 首页的展示隐藏逻辑 代码块start ///////////////////////////////////////////////////
......@@ -109,7 +108,7 @@ class ConsultAssistantDialogUtils private constructor() {
/**
* 首页页展示
*/
fun showFromYdlHome(activity: Activity) {
private fun showFromYdlHome(activity: Activity) {
if (!activity.isFinishing) {
if (consultAssistantDialogFromHomePage == null) {
consultAssistantDialogFromHomePage = ConsultAssistantDialog(
......@@ -268,7 +267,7 @@ class ConsultAssistantDialogUtils private constructor() {
/**
* 咨询师列表页展示浮层
*/
fun showDialog(origin: String, activity: Activity, fromActivity: Boolean = false) {
private fun showDialog(origin: String, activity: Activity, fromActivity: Boolean = false) {
if (!fromActivity) {
if (!activity.isFinishing) {
if (consultAssistantFragmentDialog == null) {
......
package com.yidianling.consultant.preview
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Bundle
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.SeekBar
import androidx.annotation.CallSuper
import androidx.core.view.ViewCompat
import androidx.fragment.app.Fragment
import com.dou361.ijkplayer.widget.IjkVideoView
import com.ydl.ydlcommon.ui.Loading.close
import com.ydl.ydlcommon.ui.Loading.show
import com.ydl.ydlcommon.view.dialog.CommonDialog
import com.yidianling.common.tools.RxNetTool
import com.yidianling.common.tools.ToastUtil
import com.yidianling.consultant.R
import com.yidianling.consultant.preview.SmoothImageView.*
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import tv.danmaku.ijk.media.player.IMediaPlayer
import java.util.concurrent.TimeUnit
/**
* @author rainb
* Deprecated: 图片预览单个图片的fragment
*/
class BasePhotoFragment : Fragment() {
var beanViewInfo: IThumbViewInfo? = null
private set
private var isTransPhoto = false
protected var imageView: SmoothImageView? = null
protected var rootView: View? = null
protected var loading: View? = null
protected var mySimpleTarget: MySimpleTarget? = null
protected var btnVideo: View? = null
private var btnLL: RelativeLayout? = null
private var videoContainer: RelativeLayout? = null
private var videoView: IjkVideoView? = null
private var disposable: Disposable? = null
private var seekBar: SeekBar? = null
private var ivPlay: View? = null
private var isPrepared = false
private var ivImg: ImageView? = null
private val keySp = "check_network_continue"
@Volatile
private var isTouch = false
private var isCompletion = false
private var isVisiable = false
private val ivBack: View? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_image_photo_layout, container, false)
}
@CallSuper
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initView(view)
initData()
}
@CallSuper
override fun onStop() {
ZoomMediaLoader.getInstance().loader.onStop(this)
super.onStop()
}
@CallSuper
override fun onDestroyView() {
super.onDestroyView()
release()
}
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
super.setUserVisibleHint(isVisibleToUser)
isVisiable = isVisibleToUser
if (!isVisibleToUser && beanViewInfo != null) {
videoView!!.seekTo(0)
seekBar!!.progress = 0
videoView!!.pause()
if (ivPlay != null && beanViewInfo?.sourcesType == 2) {
ivPlay?.visibility = VISIBLE
// if (ivImg != null) {
// ivImg?.visibility = VISIBLE
// }
} else if (ivPlay != null && beanViewInfo?.sourcesType == 1) {
ivPlay?.visibility = GONE
if (ivImg != null) {
ivImg!!.visibility = GONE
}
}
stopTiming()
}else if (isVisibleToUser && beanViewInfo != null && beanViewInfo?.sourcesType == 2) {
if (videoView != null) {
checkNetwork()
}
}
if (!isVisiable) {
videoView?.visibility = INVISIBLE
}
}
override fun onDestroy() {
super.onDestroy()
ZoomMediaLoader.getInstance().loader.clearMemory(requireActivity())
}
fun release() {
isTransPhoto = false
if (videoView != null) {
videoView!!.release(true)
stopTiming()
}
}
/**
* 初始化控件
*/
private fun initView(view: View) {
loading = view.findViewById(R.id.loading)
imageView = view.findViewById(R.id.photoView)
btnVideo = view.findViewById(R.id.btnVideo)
rootView = view.findViewById(R.id.rootView)
rootView?.setDrawingCacheEnabled(false)
imageView?.setDrawingCacheEnabled(false)
btnLL = view.findViewById(R.id.btnLL)
imageView?.setOnDragListener(object : OnDragListener {
override fun drag() {
(activity as GPreviewActivity?)!!.hindView()
}
override fun actionCancel() {
(activity as GPreviewActivity?)!!.showView()
}
})
videoContainer = view.findViewById(R.id.videoContainer)
videoView = view.findViewById(R.id.videoView)
seekBar = view.findViewById(R.id.seekbar)
ivPlay = view.findViewById(R.id.ivPlay)
ivImg = view.findViewById(R.id.ivImage)
mySimpleTarget = object : MySimpleTarget {
override fun onResourceReady() {
loading?.setVisibility(GONE)
imageView?.setBackgroundResource(R.color.transparent)
// String video = beanViewInfo.getVideoUrl();
// if (video != null && !video.isEmpty()) {
// btnVideo.setVisibility(View.VISIBLE);
// ViewCompat.animate(btnVideo).alpha(1).setDuration(1000).start();
// } else {
// btnVideo.setVisibility(View.GONE);
// }
}
override fun onLoadFailed(errorDrawable: Drawable?) {
loading?.setVisibility(GONE)
imageView?.setBackgroundResource(R.color.transparent)
if (isVisiable) {
ToastUtil.toastShort(activity, "加载失败")
}
if (errorDrawable != null) {
imageView?.setImageDrawable(errorDrawable)
}
}
}
}
/**
* 初始化数据
*/
private fun initData() {
val bundle = arguments
var isSingleFling = true
// 非动画进入的Fragment,默认背景为黑色
if (bundle != null) {
isSingleFling = bundle.getBoolean(KEY_SING_FILING)
//地址
beanViewInfo = bundle.getParcelable(KEY_PATH)
assert(beanViewInfo != null)
//imageView.setDrag(bundle.getBoolean(KEY_DRAG), bundle.getFloat(KEY_SEN));
imageView!!.setThumbRect(beanViewInfo?.getBounds())
rootView!!.tag = beanViewInfo?.getUrl()
//是否展示动画
isTransPhoto = bundle.getBoolean(KEY_TRANS_PHOTO, false)
if (beanViewInfo?.sourcesType == 1) {
ivPlay!!.visibility = GONE
if (beanViewInfo!!.getUrl().toLowerCase().contains(".gif")) {
imageView!!.visibility = VISIBLE
videoContainer!!.visibility = GONE
imageView!!.setZoomable(false)
//加载图
ZoomMediaLoader.getInstance().loader.displayGifImage(
this, beanViewInfo!!.getUrl(), imageView,
mySimpleTarget!!
)
} else {
//加载图
ZoomMediaLoader.getInstance().loader.displayImage(
this, beanViewInfo!!.getUrl(), imageView,
mySimpleTarget!!
)
}
} else if (beanViewInfo?.sourcesType == 2) {
// ivPlay!!.visibility = VISIBLE
videoContainer!!.visibility = VISIBLE
imageView!!.visibility = GONE
ZoomMediaLoader.getInstance().loader.displayImage(
this, beanViewInfo!!.cover, ivImg,
mySimpleTarget!!
)
val videoUlr = beanViewInfo!!.url
if (!TextUtils.isEmpty(videoUlr)) {
rootView!!.setBackgroundColor(Color.BLACK)
seekBar!!.visibility = VISIBLE
videoView!!.setVideoURI(Uri.parse(videoUlr))
videoView!!.setOnPreparedListener { iMediaPlayer ->
loading!!.visibility = GONE
isPrepared = true
val maxProgress = iMediaPlayer.duration.toInt()
if (maxProgress > 0) {
seekBar!!.max = maxProgress
} else {
seekBar!!.visibility = GONE
}
}
videoView!!.setOnCompletionListener {
isCompletion = true
videoView!!.seekTo(0)
stopTiming()
ivPlay!!.visibility = VISIBLE
}
videoView!!.setOnInfoListener { iMediaPlayer, what, extra ->
if (what == IMediaPlayer.MEDIA_INFO_BUFFERING_START && !isCompletion && isVisiable) {
show(context, "正在加载")
} else if (what == IMediaPlayer.MEDIA_INFO_BUFFERING_END) {
close()
}
true
}
if (isVisiable) {
ivPlay?.visibility = VISIBLE
checkNetwork()
}else {
ivPlay?.visibility = GONE
}
ivPlay!!.setOnClickListener {
checkNetwork()
}
videoContainer!!.setOnClickListener {
if (videoView!!.isPlaying) {
ivPlay!!.visibility = VISIBLE
stopTiming()
videoView!!.pause()
}
}
seekBar!!.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(
seekBar: SeekBar,
progress: Int,
fromUser: Boolean
) {
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
isTouch = true
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
isTouch = false
if (seekBar != null) {
videoView!!.seekTo(seekBar.progress)
videoView!!.start()
ivPlay!!.visibility = GONE
isCompletion = false
}
}
})
}
}
}
if (!isTransPhoto) {
rootView!!.setBackgroundColor(Color.BLACK)
} else {
imageView!!.minimumScale = 0.7f
}
if (isSingleFling) {
imageView!!.setOnViewTapListener { view, x, y -> }
imageView!!.setOnViewTapListener { view, x, y ->
if (imageView!!.checkMinScale()) {
(activity as GPreviewActivity?)!!.transformOut()
}
}
} else {
imageView!!.setOnPhotoTapListener(object : PhotoViewAttacher.OnPhotoTapListener {
override fun onPhotoTap(view: View, x: Float, y: Float) {
if (imageView!!.checkMinScale()) {
(activity as GPreviewActivity?)!!.transformOutAnim()
(activity as GPreviewActivity?)!!.transformOut()
}
}
override fun onOutsidePhotoTap() {}
})
}
imageView!!.setAlphaChangeListener { alpha ->
if (alpha == 255) {
val video = beanViewInfo!!.url
if (video != null && !video.isEmpty()) {
btnVideo!!.visibility = VISIBLE
} else {
btnVideo!!.visibility = GONE
}
} else {
btnVideo!!.visibility = GONE
}
rootView!!.setBackgroundColor(
getColorWithAlpha(
alpha / 255f,
Color.BLACK
)
)
}
imageView!!.setTransformOutListener { (activity as GPreviewActivity?)!!.transformOut() }
}
internal fun checkNetwork() {
val lastCheck =
context?.getSharedPreferences("temp_test", Context.MODE_PRIVATE)?.getLong(keySp, 0)
val duration = System.currentTimeMillis() - lastCheck!!
if (!RxNetTool.isWifi(requireActivity()!!) && duration > 24 * 60 * 60 * 1000) {
val dialog = CommonDialog.create(context)
.setTitle("提示")
.setMessage("当前处于非wifi环境下,播放会消耗流量,确定继续播放?")
.setLeftOnclick("继续播放") {
if (!isPrepared) {
loading?.visibility = VISIBLE
}
ivImg?.visibility = GONE
ivPlay?.visibility = GONE
startTiming()
videoView?.visibility = VISIBLE
videoView?.start()
isCompletion = false
context?.getSharedPreferences("temp_test", Context.MODE_PRIVATE)?.edit()
?.putLong(keySp, System.currentTimeMillis())?.apply()
}
.setLeftButton_color(R.color.platform_but_text_color_selected)
.setRightButton_color(R.color.platform_text_bright_color)
.setRightClick("取消") {
}
.setCancelAble(true)
dialog.setOnCancelListener {
dialog.dismiss()
}
dialog.show()
} else {
if (!isPrepared) {
loading?.visibility = VISIBLE
}
ivImg?.visibility = GONE
ivPlay?.visibility = GONE
startTiming()
videoView?.visibility = VISIBLE
videoView?.start()
isCompletion = false
}
}
fun transformIn() {
assert(imageView != null)
imageView!!.transformIn { rootView!!.setBackgroundColor(Color.BLACK) }
}
fun transformOut(listener: onTransformListener?) {
assert(imageView != null)
imageView!!.transformOut(listener)
}
fun changeBg(color: Int) {
ViewCompat.animate(btnVideo!!).alpha(0f).setDuration(getDuration().toLong()).start()
rootView!!.setBackgroundColor(color)
}
private fun startTiming() {
disposable = Observable.interval(3, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.computation())
.subscribe { // val pos = (video?.mMediaPlayer as IjkMediaPlayer?)?.currentPosition ?: 0
// if (pos > 0) {
//// if (vm?.isVideo == true) {
//// binding.ivCover.visibility = View.GONE
//// }
// if (!isTouch) {
// binding.seekbar.progress = pos.toInt()// video.bufferPercentage
// }
// if (video?.isPlaying == true) {
// when (vm?.isVideo) {
// true -> {
// binding.ivPlay.visibility = View.GONE
// }
// false -> {
// binding.voicePlay.start()
// }
// }
// }
// }
if (videoView != null && !isTouch) {
val currentPosition = videoView!!.currentPosition
seekBar!!.progress = currentPosition
}
}
}
private fun stopTiming() {
if (disposable != null) {
disposable!!.dispose()
disposable = null
}
}
interface OnDragListener {
fun drag()
fun actionCancel()
}
fun stopVideo() {
if (videoView != null && videoView!!.isPlaying) {
ivPlay!!.visibility = VISIBLE
stopTiming()
videoView!!.pause()
}
}
companion object {
/**
* 预览图片 类型
*/
private const val KEY_TRANS_PHOTO = "is_trans_photo"
private const val KEY_SING_FILING = "isSingleFling"
private const val KEY_PATH = "key_item"
private const val KEY_DRAG = "isDrag"
private const val KEY_SEN = "sensitivity"
// public static VideoClickListener listener;
fun getInstance(
fragmentClass: Class<out BasePhotoFragment>,
item: IThumbViewInfo?,
currentIndex: Boolean,
isSingleFling: Boolean,
isDrag: Boolean,
sensitivity: Float
): BasePhotoFragment {
val fragment: BasePhotoFragment
fragment = try {
fragmentClass.newInstance()
} catch (e: Exception) {
BasePhotoFragment()
}
val bundle = Bundle()
bundle.putParcelable(KEY_PATH, item)
bundle.putBoolean(KEY_TRANS_PHOTO, currentIndex)
bundle.putBoolean(KEY_SING_FILING, isSingleFling)
bundle.putBoolean(KEY_DRAG, isDrag)
bundle.putFloat(KEY_SEN, sensitivity)
fragment.arguments = bundle
return fragment
}
fun getColorWithAlpha(alpha: Float, baseColor: Int): Int {
val a = Math.min(255, Math.max(0, (alpha * 255).toInt())) shl 24
val rgb = 0x00ffffff and baseColor
return a + rgb
}
}
}
\ No newline at end of file
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.yidianling.consultant.preview;
import android.annotation.TargetApi;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.view.MotionEvent;
import android.view.View;
/**
* @author rainb
*/
public class Compat {
private static final int SIXTY_FPS_INTERVAL = 1000 / 60;
public static void postOnAnimation(View view, Runnable runnable) {
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
postOnAnimationJellyBean(view, runnable);
} else {
view.postDelayed(runnable, SIXTY_FPS_INTERVAL);
}
}
@TargetApi(16)
private static void postOnAnimationJellyBean(View view, Runnable runnable) {
view.postOnAnimation(runnable);
}
public static int getPointerIndex(int action) {
if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB)
return getPointerIndexHoneyComb(action);
else
return getPointerIndexEclair(action);
}
@SuppressWarnings("deprecation")
@TargetApi(VERSION_CODES.ECLAIR)
private static int getPointerIndexEclair(int action) {
return (action & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;
}
@TargetApi(VERSION_CODES.HONEYCOMB)
private static int getPointerIndexHoneyComb(int action) {
return (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
}
}
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.yidianling.consultant.preview;
import android.content.Context;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
/**
* @author rainb
*/
public class CupcakeGestureDetector implements GestureDetector {
protected OnGestureListener mListener;
private static final String LOG_TAG = "CupcakeGestureDetector";
float mLastTouchX;
float mLastTouchY;
final float mTouchSlop;
final float mMinimumVelocity;
@Override
public void setOnGestureListener(OnGestureListener listener) {
this.mListener = listener;
}
public CupcakeGestureDetector(Context context) {
final ViewConfiguration configuration = ViewConfiguration
.get(context);
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
mTouchSlop = configuration.getScaledTouchSlop();
}
private VelocityTracker mVelocityTracker;
private boolean mIsDragging;
float getActiveX(MotionEvent ev) {
return ev.getX();
}
float getActiveY(MotionEvent ev) {
return ev.getY();
}
@Override
public boolean isScaling() {
return false;
}
@Override
public boolean isDragging() {
return mIsDragging;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
mVelocityTracker = VelocityTracker.obtain();
if (null != mVelocityTracker) {
mVelocityTracker.addMovement(ev);
} else {
Log.i(LOG_TAG, "Velocity tracker is null");
}
mLastTouchX = getActiveX(ev);
mLastTouchY = getActiveY(ev);
mIsDragging = false;
break;
}
case MotionEvent.ACTION_MOVE: {
final float x = getActiveX(ev);
final float y = getActiveY(ev);
final float dx = x - mLastTouchX, dy = y - mLastTouchY;
if (!mIsDragging) {
// Use Pythagoras to see if drag length is larger than
// touch slop
mIsDragging = Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop;
}
if (mIsDragging) {
mListener.onDrag(dx, dy);
mLastTouchX = x;
mLastTouchY = y;
if (null != mVelocityTracker) {
mVelocityTracker.addMovement(ev);
}
}
break;
}
case MotionEvent.ACTION_CANCEL: {
// Recycle Velocity Tracker
if (null != mVelocityTracker) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
break;
}
case MotionEvent.ACTION_UP: {
if (mIsDragging) {
if (null != mVelocityTracker) {
mLastTouchX = getActiveX(ev);
mLastTouchY = getActiveY(ev);
// Compute velocity within the last 1000ms
mVelocityTracker.addMovement(ev);
mVelocityTracker.computeCurrentVelocity(1000);
final float vX = mVelocityTracker.getXVelocity(), vY = mVelocityTracker
.getYVelocity();
// If the velocity is greater than minVelocity, call
// listener
if (Math.max(Math.abs(vX), Math.abs(vY)) >= mMinimumVelocity) {
mListener.onFling(mLastTouchX, mLastTouchY, -vX,
-vY);
}
}
}
// Recycle Velocity Tracker
if (null != mVelocityTracker) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
break;
}
}
return true;
}
}
package com.yidianling.consultant.preview;
import android.graphics.RectF;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.widget.ImageView;
/**
* @author rainb
*/
public class DefaultOnDoubleTapListener implements GestureDetector.OnDoubleTapListener {
private PhotoViewAttacher photoViewAttacher;
/**
* Default constructor
*
* @param photoViewAttacher PhotoViewAttacher to bind to
*/
public DefaultOnDoubleTapListener(PhotoViewAttacher photoViewAttacher) {
setPhotoViewAttacher(photoViewAttacher);
}
/**
* Allows to change PhotoViewAttacher within range of single instance
*
* @param newPhotoViewAttacher PhotoViewAttacher to bind to
*/
public void setPhotoViewAttacher(PhotoViewAttacher newPhotoViewAttacher) {
this.photoViewAttacher = newPhotoViewAttacher;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
if (this.photoViewAttacher == null) {
return false;
}
ImageView imageView = photoViewAttacher.getImageView();
if (null != photoViewAttacher.getOnPhotoTapListener()) {
final RectF displayRect = photoViewAttacher.getDisplayRect();
if (null != displayRect) {
final float x = e.getX(), y = e.getY();
// Check to see if the user tapped on the photo
if (displayRect.contains(x, y)) {
float xResult = (x - displayRect.left)
/ displayRect.width();
float yResult = (y - displayRect.top)
/ displayRect.height();
photoViewAttacher.getOnPhotoTapListener().onPhotoTap(imageView, xResult, yResult);
return true;
} else {
photoViewAttacher.getOnPhotoTapListener().onOutsidePhotoTap();
}
}
}
if (null != photoViewAttacher.getOnViewTapListener()) {
photoViewAttacher.getOnViewTapListener().onViewTap(imageView, e.getX(), e.getY());
}
return false;
}
@Override
public boolean onDoubleTap(MotionEvent ev) {
if (photoViewAttacher == null) {
return false;
}
try {
float scale = photoViewAttacher.getScale();
float x = ev.getX();
float y = ev.getY();
if (scale < photoViewAttacher.getMediumScale()) {
photoViewAttacher.setScale(photoViewAttacher.getMediumScale(), x, y, true);
} else if (scale >= photoViewAttacher.getMediumScale() && scale < photoViewAttacher.getMaximumScale()) {
photoViewAttacher.setScale(photoViewAttacher.getMaximumScale(), x, y, true);
} else {
photoViewAttacher.setScale(photoViewAttacher.getMinimumScale(), x, y, true);
}
} catch (ArrayIndexOutOfBoundsException e) {
// Can sometimes happen when getX() and getY() is called
}
return true;
}
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
// Wait for the confirmed onDoubleTap() instead
return false;
}
}
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.yidianling.consultant.preview;
import android.annotation.TargetApi;
import android.content.Context;
import android.view.MotionEvent;
/**
* @author rainb
*/
@TargetApi(5)
public class EclairGestureDetector extends CupcakeGestureDetector {
private static final int INVALID_POINTER_ID = -1;
private int mActivePointerId = INVALID_POINTER_ID;
private int mActivePointerIndex = 0;
public EclairGestureDetector(Context context) {
super(context);
}
@Override
float getActiveX(MotionEvent ev) {
try {
return ev.getX(mActivePointerIndex);
} catch (Exception e) {
return ev.getX();
}
}
@Override
float getActiveY(MotionEvent ev) {
try {
return ev.getY(mActivePointerIndex);
} catch (Exception e) {
return ev.getY();
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mActivePointerId = ev.getPointerId(0);
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
mActivePointerId = INVALID_POINTER_ID;
break;
case MotionEvent.ACTION_POINTER_UP:
// Ignore deprecation, ACTION_POINTER_ID_MASK and
// ACTION_POINTER_ID_SHIFT has same value and are deprecated
// You can have either deprecation or lint target api warning
final int pointerIndex = Compat.getPointerIndex(ev.getAction());
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mActivePointerId = ev.getPointerId(newPointerIndex);
mLastTouchX = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
}
break;
}
mActivePointerIndex = ev
.findPointerIndex(mActivePointerId != INVALID_POINTER_ID ? mActivePointerId
: 0);
try {
return super.onTouchEvent(ev);
} catch (IllegalArgumentException e) {
// Fix for support lib bug, happening when onDestroy is
return true;
}
}
}
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.yidianling.consultant.preview;
import android.annotation.TargetApi;
import android.content.Context;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
/**
* @author rainb
*/
@TargetApi(8)
public class FroyoGestureDetector extends EclairGestureDetector {
protected final ScaleGestureDetector mDetector;
public FroyoGestureDetector(Context context) {
super(context);
ScaleGestureDetector.OnScaleGestureListener mScaleListener = new ScaleGestureDetector.OnScaleGestureListener() {
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scaleFactor = detector.getScaleFactor();
if (Float.isNaN(scaleFactor) || Float.isInfinite(scaleFactor)) {
return false;
}
mListener.onScale(scaleFactor,
detector.getFocusX(), detector.getFocusY());
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
// NO-OP
}
};
mDetector = new ScaleGestureDetector(context, mScaleListener);
}
@Override
public boolean isScaling() {
return mDetector.isInProgress();
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
try {
mDetector.onTouchEvent(ev);
return super.onTouchEvent(ev);
} catch (IllegalArgumentException e) {
// Fix for support lib bug, happening when onDestroy is
return true;
}
}
}
package com.yidianling.consultant.preview
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.graphics.Color
import android.os.Bundle
import android.view.View
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter
import androidx.viewpager.widget.ViewPager
import com.ydl.ydlcommon.modular.ModularServiceManager
import com.ydl.ydlcommon.utils.StatusBarUtils
import com.yidianling.consultant.R
import com.yidianling.consultant.preview.GPreviewBuilder.IndicatorType
import com.yidianling.consultant.preview.SmoothImageView.onTransformListener
import com.yidianling.im.api.listener.ApiStringResponseCallback
import com.yidianling.im.api.service.IImService
import kotlinx.android.synthetic.main.consultant_image_preview_photo.*
import kotlinx.android.synthetic.main.fragment_image_photo_layout.*
import java.util.*
/**
* @author rainb
*/
class GPreviewActivity : AppCompatActivity() {
protected var isTransformOut = false
/*** 图片的地址 */
private var imgUrls: MutableList<IThumbViewInfo>? = null
/*** 当前图片的位置 */
protected var currentIndex = 0
/***指示器类型枚举 */
private var type: IndicatorType? = null
/***默认显示 */
private var isShow = true
private var toUid: String? = null
private var doctorId: String? = null
/***
* 得到PhotoViewPager
* @return PhotoViewPager
*/
/*** 展示图片的viewPager */
var viewPager: PhotoViewPager? = null
private set
/*** 图片的展示的Fragment */
private var fragments: MutableList<BasePhotoFragment>? = ArrayList()
private var backIv: View? = null
private var btnLL: View? = null
private var titleBar: View? = null
private var selectPosition: TextView? = null
private var total: TextView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initData()
setContentView(R.layout.consultant_image_preview_photo)
setWindowStatusBarColor()
initView()
}
/**
* 初始化状态栏位置
*/
private fun setWindowStatusBarColor() {
StatusBarUtils.Companion.setWindowStatusBarColor(this, R.color.black)
StatusBarUtils.Companion.setStatusBarLightMode(this, false)
}
private fun initView() {
viewPager = findViewById(R.id.viewPager)
//viewPager的适配器
val adapter = PhotoPagerAdapter(supportFragmentManager)
viewPager?.adapter = adapter
viewPager?.currentItem = currentIndex
backIv = findViewById(R.id.ivBack)
btnLL = findViewById(R.id.btnLL)
selectPosition = findViewById(R.id.select_position)
total = findViewById(R.id.total)
titleBar = findViewById(R.id.titleBar)
chatBtn.setOnClickListener {
if (!toUid.isNullOrBlank()) {
ModularServiceManager.provide(IImService::class.java)
.startChat(this@GPreviewActivity, toUid.toString(), 0x001, 0, 0, false)
Timer().schedule(object : TimerTask() {
override fun run() {
runOnUiThread {
if (fragments != null && currentIndex < fragments!!.size) {
fragments!![currentIndex].stopVideo()
}
}
}
}, 2000)
}
}
bookingBtn.setOnClickListener {
ModularServiceManager.provide(IImService::class.java)
.showConsultServiceDialog(activity = this, toUid = toUid!!, doctorId = doctorId!!)
}
backIv?.setOnClickListener(View.OnClickListener {
transformOutAnim()
transformOut()
})
selectPosition?.setText((currentIndex + 1).toString() + "")
total?.setText(if (imgUrls == null) "0" else imgUrls!!.size.toString() + "")
viewPager?.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
override fun onPageScrolled(
position: Int,
positionOffset: Float,
positionOffsetPixels: Int
) {
}
override fun onPageSelected(position: Int) {
currentIndex = position;
selectPosition?.setText((position + 1).toString() + "")
}
override fun onPageScrollStateChanged(state: Int) {}
})
// viewPager.setOffscreenPageLimit(3);
}
override fun onResume() {
super.onResume()
if (toUid != null) {
//在uid用户类型确定为专家的情况下,根据uid调用接口判断是进入专家私聊还是助理私聊
try {
ModularServiceManager.provide(IImService::class.java)
.getChatUid(context = this, uid = toUid!!, callback = object :
ApiStringResponseCallback {
override fun onUidCallback(uid: String) {
val unReadNum =
ModularServiceManager.provide(IImService::class.java)
.getUnReadByUid(uid!!)
when {
unReadNum <= 0 -> {
un_read_num_ll.visibility = View.GONE
}
unReadNum > 99 -> {
un_read_num_ll.visibility = View.VISIBLE
un_read_num.text = "99"
}
else -> {
un_read_num_ll.visibility = View.VISIBLE
un_read_num.text = unReadNum.toString()
}
}
}
})
} catch (e: Exception) {
}
}
}
private fun initData() {
imgUrls = intent.getParcelableArrayListExtra("imagePaths")
currentIndex = intent.getIntExtra("position", -1)
type = intent.getSerializableExtra("type") as IndicatorType
isShow = intent.getBooleanExtra("isShow", true)
toUid = intent.getStringExtra("toUid")
doctorId = intent.getStringExtra("doctorId")
val isScale = intent.getBooleanExtra("isScale", false)
SmoothImageView.setIsScale(isScale)
initFragment(imgUrls, currentIndex, BasePhotoFragment::class.java)
}
private fun initFragment(
imgUrls: List<IThumbViewInfo>?,
currentIndex: Int,
className: Class<BasePhotoFragment>
) {
if (imgUrls != null) {
val size = imgUrls.size
for (i in 0 until size) {
fragments!!.add(
BasePhotoFragment.getInstance(
className, imgUrls[i],
currentIndex == i,
intent.getBooleanExtra("isSingleFling", false),
intent.getBooleanExtra("isDrag", false),
intent.getFloatExtra("sensitivity", 0.5f)
)
)
}
} else {
finish()
}
}
override fun onDestroy() {
ZoomMediaLoader.getInstance().loader.clearMemory(this)
if (viewPager != null) {
viewPager!!.adapter = null
viewPager!!.clearOnPageChangeListeners()
viewPager!!.removeAllViews()
viewPager = null
}
if (fragments != null) {
fragments!!.clear()
fragments = null
}
if (imgUrls != null) {
imgUrls!!.clear()
imgUrls = null
}
super.onDestroy()
}
/***
* 得到PhotoViewPager
* @return PhotoViewPager
*/
@JvmName("getViewPager1")
fun getViewPager(): PhotoViewPager? {
return viewPager
}
fun transformOut() {
if (isTransformOut) {
return
}
viewPager!!.isEnabled = false
isTransformOut = true
val currentItem = viewPager!!.currentItem
if (currentItem < imgUrls!!.size) {
if (imgUrls!![currentItem].sourcesType == 1) {
val fragment = fragments!![currentItem]
fragment.changeBg(Color.TRANSPARENT)
fragment.transformOut(onTransformListener {
getViewPager()?.setEnabled(true)
exit()
})
} else if (imgUrls!![currentItem].sourcesType == 2) {
exitNormal()
}
} else {
exit()
}
}
/**
* 关闭页面
*/
private fun exit() {
finish()
overridePendingTransition(0, 0)
}
private fun exitNormal() {
finish()
}
override fun onBackPressed() {
isTransformOut = false
transformOutAnim()
transformOut()
}
override fun finish() {
// BasePhotoFragment.listener=null;
super.finish()
}
/**
* pager的适配器
*/
private inner class PhotoPagerAdapter internal constructor(fm: FragmentManager?) :
FragmentStatePagerAdapter(fm!!) {
override fun getItem(position: Int): Fragment {
return fragments!![position]
}
override fun getCount(): Int {
return if (fragments == null) 0 else fragments!!.size
}
}
fun hindView() {
titleBar!!.visibility = View.GONE
btnLL!!.visibility = View.GONE
}
fun showView() {
titleBar!!.visibility = View.VISIBLE
btnLL!!.visibility = View.VISIBLE
}
@SuppressLint("ObjectAnimatorBinding")
fun transformOutAnim() {
val animator1 = ObjectAnimator.ofFloat(titleBar, "alpha", 1.0f, 0.0f)
animator1.duration = 200
animator1.start()
val animator2 = ObjectAnimator.ofFloat(btnLL, "alpha", 1.0f, 0.0f)
animator2.duration = 200
animator2.start()
}
}
\ No newline at end of file
package com.yidianling.consultant.preview;
import android.app.Activity;
import android.content.Intent;
import android.os.Parcelable;
import androidx.fragment.app.Fragment;
import java.util.ArrayList;
import java.util.List;
/**
* @author rainb
*/
public class GPreviewBuilder {
private Activity mContext;
private Intent intent;
private Class className;
private GPreviewBuilder(Activity activity) {
mContext = activity;
intent = new Intent();
}
public static GPreviewBuilder form(Activity activity) {
return new GPreviewBuilder(activity);
}
public static GPreviewBuilder from(Fragment fragment) {
return new GPreviewBuilder(fragment.getActivity());
}
/***
* 设置数据源
* @param imgUrls 数据
*@param <T> 你的实体类类型
* @return GPreviewBuilder
* **/
public <T extends IThumbViewInfo> GPreviewBuilder setData(List<T> imgUrls) {
intent.putParcelableArrayListExtra("imagePaths", new ArrayList<Parcelable>(imgUrls));
return this;
}
/***
* 设置默认索引
* @param currentIndex 数据
* @return GPreviewBuilder
* **/
public GPreviewBuilder setCurrentIndex(int currentIndex) {
intent.putExtra("position", currentIndex);
return this;
}
/***
* 设置指示器类型
* @param indicatorType 枚举
* @return GPreviewBuilder
* **/
public GPreviewBuilder setType(IndicatorType indicatorType) {
intent.putExtra("type", indicatorType);
return this;
}
public void start() {
if (className == null) {
intent.setClass(mContext, GPreviewActivity.class);
} else {
intent.setClass(mContext, className);
}
mContext.startActivity(intent);
mContext.overridePendingTransition(0, 0);
intent = null;
mContext = null;
}
public GPreviewBuilder setFullscreen(boolean isFullscreen) {
intent.putExtra("isFullscreen", isFullscreen);
return this;
}
public GPreviewBuilder setToUid(String toUid){
intent.putExtra("toUid", toUid);
return this;
}
public GPreviewBuilder setDoctorId(String doctorId){
intent.putExtra("doctorId", doctorId);
return this;
}
/***
* 指示器类型
* ***/
public enum IndicatorType {
Dot, Number
}
}
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.yidianling.consultant.preview;
import android.view.MotionEvent;
/**
* @author rainb
*/
public interface GestureDetector {
boolean onTouchEvent(MotionEvent ev);
boolean isScaling();
boolean isDragging();
void setOnGestureListener(OnGestureListener listener);
}
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.yidianling.consultant.preview;
import android.annotation.TargetApi;
import android.content.Context;
import android.widget.OverScroller;
/**
* @author rainb
*/
@TargetApi(9)
public class GingerScroller extends ScrollerProxy {
protected final OverScroller mScroller;
public GingerScroller(Context context) {
mScroller = new OverScroller(context);
}
@Override
public boolean computeScrollOffset() {
return mScroller.computeScrollOffset();
}
@Override
public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY,
int overX, int overY) {
mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, overX, overY);
}
@Override
public void forceFinished(boolean finished) {
mScroller.forceFinished(finished);
}
@Override
public boolean isFinished() {
return mScroller.isFinished();
}
@Override
public int getCurrX() {
return mScroller.getCurrX();
}
@Override
public int getCurrY() {
return mScroller.getCurrY();
}
}
\ No newline at end of file
package com.yidianling.consultant.preview;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import com.blankj.utilcode.util.ScreenUtils;
import com.bumptech.glide.Glide;
import com.ydl.ydlcommon.base.BaseActivity;
import com.ydl.ydlcommon.bean.StatusBarOptions;
import com.yidianling.consultant.R;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
/**
* @author fq
*/
public class GridPreviewActivity extends BaseActivity {
private ArrayList<UserViewInfo> mThumbViewInfoList = new ArrayList<>();
MyListAdapter adapter;
private GridView gridView;
@NotNull
@Override
public StatusBarOptions getStatusViewOptions() {
return new StatusBarOptions(true, true);
}
/**
* 查找信息
* 从第一个完整可见item逆序遍历,如果初始位置为0,则不执行方法内循环
*/
private void computeBoundsBackward(int firstCompletelyVisiblePos) {
for (int i = firstCompletelyVisiblePos; i < mThumbViewInfoList.size(); i++) {
View itemView = gridView.getChildAt(i - firstCompletelyVisiblePos);
Rect bounds = new Rect();
bounds.left = ScreenUtils.getScreenWidth() / 2;
bounds.top = ScreenUtils.getScreenHeight() / 2;
bounds.right = ScreenUtils.getScreenWidth() / 2;
bounds.bottom = ScreenUtils.getScreenHeight() / 2;
// if (itemView != null) {
// ImageView thumbView = (ImageView) itemView.findViewById(R.id.iv);
// thumbView.getGlobalVisibleRect(bounds);
// }
mThumbViewInfoList.get(i).setBounds(bounds);
}
}
@Override
protected int layoutResId() {
return R.layout.consultant_picture_preview;
}
@Override
protected void initDataAndEvent() {
gridView = findViewById(R.id.grid_view);
List<String> urls = ImageUrlConfig.getUrls();
for (int i = 0; i < urls.size(); i++) {
mThumbViewInfoList.add(new UserViewInfo(urls.get(i)));
}
// mThumbViewInfoList.add(4, new UserViewInfo("https://pic.ydlcdn.com/GGyHyDwKJ8.MP4", null));
adapter = new MyListAdapter();
gridView.setAdapter(adapter);
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
computeBoundsBackward(gridView.getFirstVisiblePosition());
GPreviewBuilder.form(GridPreviewActivity.this)
.setData(mThumbViewInfoList)
.setCurrentIndex(position)
.setFullscreen(true)
.setType(GPreviewBuilder.IndicatorType.Dot)
.start();
}
});
}
private class MyListAdapter extends BaseAdapter {
@Override
public int getCount() {
return mThumbViewInfoList.size();
}
@Override
public Object getItem(int position) {
return mThumbViewInfoList.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = getLayoutInflater().inflate(R.layout.consultant_item_image, null);
ImageView iv = (ImageView) view.findViewById(R.id.iv);
Glide.with(GridPreviewActivity.this)
.load(mThumbViewInfoList.get(position).getUrl())
.into(iv);
iv.setTag(R.id.iv, mThumbViewInfoList.get(position));
return view;
}
}
}
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.yidianling.consultant.preview;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.view.GestureDetector;
import android.view.View;
import android.widget.ImageView;
/**
* @author rainb
*/
public interface IPhotoView {
float DEFAULT_MAX_SCALE = 3.0f;
float DEFAULT_MID_SCALE = 1.75f;
float DEFAULT_MIN_SCALE = 1.0f;
int DEFAULT_ZOOM_DURATION = 200;
/**
* Returns true if the PhotoView is set to allow zooming of Photos.
*
* @return true if the PhotoView allows zooming.
*/
boolean canZoom();
/**
* Gets the Display Rectangle of the currently displayed Drawable. The Rectangle is relative to
* this View and includes all scaling and translations.
*
* @return - RectF of Displayed Drawable
*/
RectF getDisplayRect();
/**
* Sets the Display Matrix of the currently displayed Drawable. The Rectangle is considered
* relative to this View and includes all scaling and translations.
*
* @param finalMatrix target matrix to set PhotoView to
* @return - true if rectangle was applied successfully
*/
boolean setDisplayMatrix(Matrix finalMatrix);
/**
* Copies the Display Matrix of the currently displayed Drawable. The Rectangle is considered
* relative to this View and includes all scaling and translations.
*
* @param matrix target matrix to copy to
*/
void getDisplayMatrix(Matrix matrix);
/**
* @return The current minimum scale level. What this value represents depends on the current
* {@link ImageView.ScaleType}.
*/
float getMinimumScale();
/**
* @return The current medium scale level. What this value represents depends on the current
* {@link ImageView.ScaleType}.
*/
float getMediumScale();
/**
* @return The current maximum scale level. What this value represents depends on the current
* {@link ImageView.ScaleType}.
*/
float getMaximumScale();
/**
* Returns the current scale value
*
* @return float - current scale value
*/
float getScale();
/**
* Return the current scale type in use by the ImageView.
*
* @return current ImageView.ScaleType
*/
ImageView.ScaleType getScaleType();
/**
* Whether to allow the ImageView's parent to intercept the touch event when the photo is scroll
* to it's horizontal edge.
*
* @param allow whether to allow intercepting by parent element or not
*/
void setAllowParentInterceptOnEdge(boolean allow);
/**
* Sets the minimum scale level. What this value represents depends on the current {@link
* ImageView.ScaleType}.
*
* @param minimumScale minimum allowed scale
*/
void setMinimumScale(float minimumScale);
/**
* Sets the medium scale level. What this value represents depends on the current {@link ImageView.ScaleType}.
*
* @param mediumScale medium scale preset
*/
void setMediumScale(float mediumScale);
/**
* Sets the maximum scale level. What this value represents depends on the current {@link
* ImageView.ScaleType}.
*
* @param maximumScale maximum allowed scale preset
*/
void setMaximumScale(float maximumScale);
/**
* Allows to set all three scale levels at once, so you don't run into problem with setting
* medium/minimum scale before the maximum one
*
* @param minimumScale minimum allowed scale
* @param mediumScale medium allowed scale
* @param maximumScale maximum allowed scale preset
*/
void setScaleLevels(float minimumScale, float mediumScale, float maximumScale);
/**
* Register a callback to be invoked when the Photo displayed by this view is long-pressed.
*
* @param listener - Listener to be registered.
*/
void setOnLongClickListener(View.OnLongClickListener listener);
/**
* Register a callback to be invoked when the Matrix has changed for this View. An example would
* be the user panning or scaling the Photo.
*
* @param listener - Listener to be registered.
*/
void setOnMatrixChangeListener(PhotoViewAttacher.OnMatrixChangedListener listener);
/**
* Register a callback to be invoked when the Photo displayed by this View is tapped with a
* single tap.
*
* @param listener - Listener to be registered.
*/
void setOnPhotoTapListener(PhotoViewAttacher.OnPhotoTapListener listener);
/**
* Register a callback to be invoked when the View is tapped with a single tap.
*
* @param listener - Listener to be registered.
*/
void setOnViewTapListener(PhotoViewAttacher.OnViewTapListener listener);
/**
* Enables rotation via PhotoView internal functions.
*
* @param rotationDegree - Degree to rotate PhotoView to, should be in range 0 to 360
*/
void setRotationTo(float rotationDegree);
/**
* Enables rotation via PhotoView internal functions.
*
* @param rotationDegree - Degree to rotate PhotoView by, should be in range 0 to 360
*/
void setRotationBy(float rotationDegree);
/**
* Changes the current scale to the specified value.
*
* @param scale - Value to scale to
*/
void setScale(float scale);
/**
* Changes the current scale to the specified value.
*
* @param scale - Value to scale to
* @param animate - Whether to animate the scale
*/
void setScale(float scale, boolean animate);
/**
* Changes the current scale to the specified value, around the given focal point.
*
* @param scale - Value to scale to
* @param focalX - X Focus Point
* @param focalY - Y Focus Point
* @param animate - Whether to animate the scale
*/
void setScale(float scale, float focalX, float focalY, boolean animate);
/**
* Controls how the image should be resized or moved to match the size of the ImageView. Any
* scaling or panning will happen within the confines of this {@link
* ImageView.ScaleType}.
*
* @param scaleType - The desired scaling mode.
*/
void setScaleType(ImageView.ScaleType scaleType);
/**
* Allows you to enable/disable the zoom functionality on the ImageView. When disable the
* ImageView reverts to using the FIT_CENTER matrix.
*
* @param zoomable - Whether the zoom functionality is enabled.
*/
void setZoomable(boolean zoomable);
/**
* Extracts currently visible area to Bitmap object, if there is no image loaded yet or the
* ImageView is already destroyed, returns {@code null}
*
* @return currently visible area as bitmap or null
*/
Bitmap getVisibleRectangleBitmap();
/**
* Allows to change zoom transition speed, default value is 200 (PhotoViewAttacher.DEFAULT_ZOOM_DURATION).
* Will default to 200 if provided negative value
*
* @param milliseconds duration of zoom interpolation
*/
void setZoomTransitionDuration(int milliseconds);
/**
* Will return instance of IPhotoView (eg. PhotoViewAttacher), can be used to provide better
* integration
*
* @return IPhotoView implementation instance if available, null if not
*/
IPhotoView getIPhotoViewImplementation();
/**
* Sets custom double tap listener, to intercept default given functions. To reset behavior to
* default, you can just pass in "null" or public field of PhotoViewAttacher.defaultOnDoubleTapListener
*
* @param newOnDoubleTapListener custom OnDoubleTapListener to be set on ImageView
*/
void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener);
/**
* Will report back about scale changes
*
* @param onScaleChangeListener OnScaleChangeListener instance
*/
void setOnScaleChangeListener(PhotoViewAttacher.OnScaleChangeListener onScaleChangeListener);
/**
* Will report back about fling(single touch)
*
* @param onSingleFlingListener OnSingleFlingListener instance
*/
void setOnSingleFlingListener(PhotoViewAttacher.OnSingleFlingListener onSingleFlingListener);
}
package com.yidianling.consultant.preview;
import android.graphics.Rect;
import android.os.Parcelable;
/**
* Deprecated: 图片预览接口
*
* @author rainb
*/
public interface IThumbViewInfo extends Parcelable {
/****
* 图片地址
* @return String
* ****/
String getUrl();
/**
* 记录坐标
*
* @return Rect
***/
Rect getBounds();
/**
* 获取视频链接
***/
String getCover();
int getSourcesType();
}
package com.yidianling.consultant.preview;
import android.content.Context;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
/**
* Deprecated: 加载器接口
*
* @author rainb
*/
public interface IZoomMediaLoader {
/***
* @param context 容器
* @param path 图片你的路径
* @param simpleTarget 图片加载状态回调
* ***/
void displayImage(@NonNull Fragment context, @NonNull String path, ImageView imageView, @NonNull MySimpleTarget simpleTarget);
/***
* 加载gif 图
* @param context 容器
* @param path 图片你的路径
* @param simpleTarget 图片加载状态回调
* ***/
void displayGifImage(@NonNull Fragment context, @NonNull String path, ImageView imageView, @NonNull MySimpleTarget simpleTarget);
/**
* 停止
*
* @param context 容器
**/
void onStop(@NonNull Fragment context);
/**
* 停止
*
* @param c 容器
**/
void clearMemory(@NonNull Context c);
}
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.yidianling.consultant.preview;
import android.annotation.TargetApi;
import android.content.Context;
/**
* @author rainb
*/
@TargetApi(14)
public class IcsScroller extends GingerScroller {
public IcsScroller(Context context) {
super(context);
}
@Override
public boolean computeScrollOffset() {
return mScroller.computeScrollOffset();
}
}
package com.yidianling.consultant.preview;
import java.util.ArrayList;
import java.util.List;
/**
* ImageUrlConfig
*
* @author rainb
*/
public final class ImageUrlConfig {
private static List<String> sUrls = new ArrayList<>();
private static List<UserViewInfo> videos = new ArrayList<>();
public static List<UserViewInfo> getVideos() {
videos.clear();
// videos.add(new UserViewInfo("http://lmp4.vjshi.com/2017-09-13/f55a900d89679ac1c9837d5b5aaf632a.mp4",
// "http://pic.vjshi.com/2017-09-13/f55a900d89679ac1c9837d5b5aaf632a/online/puzzle.jpg?x-oss-process=style/resize_w_285_crop_h_428"));
// videos.add(new UserViewInfo("http://lmp4.vjshi.com/2017-09-13/f55a900d89679ac1c9837d5b5aaf632a.mp4",
// "http://pic.vjshi.com/2017-05-25/b146e104069c2bd0590bb919269193c4/online/puzzle.jpg?x-oss-process=style/resize_w_285_crop_h_428"));
// videos.add(new UserViewInfo("http://ac-QYgvX1CC.clouddn.com/36f0523ee1888a57.jpg"));
// videos.add(new UserViewInfo("http://lmp4.vjshi.com/2017-05-07/d0bbfc4ac4dd173cc93873ed4eb0be53.mp4",
// "http://pic.vjshi.com/2017-05-07/d0bbfc4ac4dd173cc93873ed4eb0be53/online/puzzle.jpg?x-oss-process=style/resize_w_285_crop_h_428"));
//
// videos.add(new UserViewInfo("http://lmp4.vjshi.com/2017-07-18/80d08ce1a84adfbaed5c7067b73d19ed.mp4",
// "http://pic.vjshi.com/2017-07-18/80d08ce1a84adfbaed5c7067b73d19ed/online/puzzle.jpg?x-oss-process=style/resize_w_285_crop_h_428"));
// videos.add(new UserViewInfo("http://img0.imgtn.bdimg.com/it/u=556618733,1205300389&fm=21&gp=0.jpg"));
// videos.add(new UserViewInfo("http://lmp4.vjshi.com/2017-09-13/f55a900d89679ac1c9837d5b5aaf632a.mp4",
// "http://pic.vjshi.com/2017-09-13/f55a900d89679ac1c9837d5b5aaf632a/online/puzzle.jpg?x-oss-process=style/resize_w_285_crop_h_428"));
// videos.add(new UserViewInfo("http://img0.imgtn.bdimg.com/it/u=556618733,1205300389&fm=21&gp=0.jpg"));
// videos.add(new UserViewInfo("http://lmp4.vjshi.com/2018-06-07/cf673556cce54ab9cf4633fd7d9d0d46.mp4",
// "http://pic.vjshi.com/2018-06-06/caa296729c8e6e41e6aff2aadf4feff3/online/puzzle.jpg?x-oss-process=style/resize_w_285_crop_h_428"));
// videos.add(new UserViewInfo("http://img44.photophoto.cn/20170730/0018090594006661_s.jpg"));
// videos.add(new UserViewInfo("http://lmp4.vjshi.com/2017-09-13/f55a900d89679ac1c9837d5b5aaf632a.mp4",
// "http://pic.vjshi.com/2017-09-13/f55a900d89679ac1c9837d5b5aaf632a/online/puzzle.jpg?x-oss-process=style/resize_w_285_crop_h_428"));
// videos.add(new UserViewInfo("http://ac-QYgvX1CC.clouddn.com/36f0523ee1888a57.jpg"));
// videos.add(new UserViewInfo("http://lmp4.vjshi.com/2018-01-27/5169bb7bdd7386ce7bd4ce1739229424.mp4",
// "http://pic.vjshi.com/2018-01-27/5169bb7bdd7386ce7bd4ce1739229424/online/puzzle.jpg?x-oss-process=style/resize_w_285_crop_h_428"));
// videos.add(new UserViewInfo("http://photocdn.sohu.com/20160307/mp62252655_1457334772519_2.png"));
// videos.add(new UserViewInfo("http://lmp4.vjshi.com/2017-09-27/9a6e69f7c257ff7b7832e8bac6fddf82.mp4",
// "http://pic.vjshi.com/2017-09-27/9a6e69f7c257ff7b7832e8bac6fddf82/online/puzzle.jpg?x-oss-process=style/resize_w_285_crop_h_428"));
videos.add(new UserViewInfo("http://photocdn.sohu.com/20160307/mp62252655_1457334772519_2.png"));
return videos;
}
public static List<String> getUrls() {
sUrls.clear();
sUrls.add("https://hellorfimg.zcool.cn/preview260/129132983.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/1156349101.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/1156349101.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/298757792.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/587590211.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/407797777.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/675219493.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/1045107625.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/551576716.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/1016991457.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/377604361.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/533952916.jpg");
sUrls.add("https://hellorfimg.zcool.cn/provider_image/preview260/2234602281.jpg");
sUrls.add("https://hellorfimg.zcool.cn/provider_image/preview260/2234602281.jpg");
sUrls.add("https://hellorfimg.zcool.cn/provider_image/preview260/2235502018.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/137983838.jpg");
sUrls.add("https://hellorfimg.zcool.cn/provider_image/preview260/2234677521.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/321745829.jpg");
sUrls.add("https://hellorfimg.zcool.cn/provider_image/preview260/2236891951.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/102396898.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/793540144.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/619468106.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/220323652.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/428018086.jpg");
sUrls.add("https://hellorfimg.zcool.cn/provider_image/preview260/2234609274.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/401555077.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/1034426839.jpg");
sUrls.add("https://hellorfimg.zcool.cn/provider_image/preview260/2234619039.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/298605944.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/393511423.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/253828555.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/400379983.jpg");
sUrls.add("https://hellorfimg.zcool.cn/provider_image/preview260/2237655331.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/606048908.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/181387775.jpg");
sUrls.add("https://hellorfimg.zcool.cn/provider_image/preview260/2234602281.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/326490512.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/521163331.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/1499307269.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/459494017.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/102396898.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/606363722.jpg");
sUrls.add("http://img44.photophoto.cn/20170729/0847085581124963_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170729/0847085226124343_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170729/0847085226124343_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170728/0847085200668628_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170728/0847085246003750_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170728/0847085012707934_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170729/0005018303330857_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170729/0847085231427344_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170729/0847085236829578_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170728/0847085729490157_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170727/0847085751995287_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170728/0847085729043617_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170729/0847085786392651_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170728/0847085761440022_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170727/0847085275244570_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170722/0847085858434984_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170721/0847085781987193_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170722/0847085707961800_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170722/0847085229451104_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170720/0847085716198074_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170720/0847085769259426_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170721/0847085717385169_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170721/0847085757949071_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170721/0847085789079771_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170722/0847085229451104_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170721/0847085757949071_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170728/0847085265005650_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170730/0008118269110532_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170731/0008118203762697_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170727/0008118269666722_s.jpg");
return sUrls;
}
public static List<UserViewInfo> getGifUrls() {
List<UserViewInfo> userViewInfos = new ArrayList<>();
userViewInfos.add(new UserViewInfo("https://hellorfimg.zcool.cn/preview260/658596682.jpg"));
userViewInfos.add(new UserViewInfo("https://hellorfimg.zcool.cn/preview260/123343987.jpg"));
userViewInfos.add(new UserViewInfo("https://hellorfimg.zcool.cn/preview260/658275328.jpg"));
userViewInfos.add(new UserViewInfo("http://img.soogif.com/SH0FB6FnTNgoCsVtxcAMtSNfV7XxXmo8.gif"));
userViewInfos.add(new UserViewInfo("http://img.soogif.com/SH0FB6FnTNgoCsVtxcAMtSNfV7XxXmo8.gif"));
userViewInfos.add(new UserViewInfo("http://img.soogif.com/KkB9WARG3PFrz9EEX4DJdiy6Vyg95fGl.gif"));
return userViewInfos;
}
}
package com.yidianling.consultant.preview;
import android.graphics.drawable.Drawable;
import androidx.annotation.Nullable;
/**
* Deprecated: 图片加载回调状态接口
*
* @author rainb
*/
public interface MySimpleTarget {
/**
* Callback when an image has been successfully loaded.
* <p>
* <strong>Note:</strong> You must not recycle the bitmap.
*/
void onResourceReady();
/**
* Callback indicating the image could not be successfully loaded.
*
* @param errorRes 内容
*/
void onLoadFailed(@Nullable Drawable errorRes);
}
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.yidianling.consultant.preview;
/**
* @author rainb
*/
public interface OnGestureListener {
void onDrag(float dx, float dy);
void onFling(float startX, float startY, float velocityX,
float velocityY);
void onScale(float scaleFactor, float focusX, float focusY);
}
\ No newline at end of file
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.yidianling.consultant.preview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.AttributeSet;
import android.view.GestureDetector;
public class PhotoView extends androidx.appcompat.widget.AppCompatImageView implements IPhotoView {
private PhotoViewAttacher mAttacher;
private ScaleType mPendingScaleType;
public PhotoView(Context context) {
this(context, null);
}
public PhotoView(Context context, AttributeSet attr) {
this(context, attr, 0);
}
public PhotoView(Context context, AttributeSet attr, int defStyle) {
super(context, attr, defStyle);
super.setScaleType(ScaleType.MATRIX);
init();
}
protected void init() {
if (null == mAttacher || null == mAttacher.getImageView()) {
mAttacher = new PhotoViewAttacher(this);
}
if (null != mPendingScaleType) {
setScaleType(mPendingScaleType);
mPendingScaleType = null;
}
}
@Override
public void setRotationTo(float rotationDegree) {
mAttacher.setRotationTo(rotationDegree);
}
@Override
public void setRotationBy(float rotationDegree) {
mAttacher.setRotationBy(rotationDegree);
}
@Override
public boolean canZoom() {
return mAttacher.canZoom();
}
@Override
public RectF getDisplayRect() {
return mAttacher.getDisplayRect();
}
@Override
public void getDisplayMatrix(Matrix matrix) {
mAttacher.getDisplayMatrix(matrix);
}
@Override
public boolean setDisplayMatrix(Matrix finalRectangle) {
return mAttacher.setDisplayMatrix(finalRectangle);
}
@Override
public float getMinimumScale() {
return mAttacher.getMinimumScale();
}
@Override
public float getMediumScale() {
return mAttacher.getMediumScale();
}
@Override
public float getMaximumScale() {
return mAttacher.getMaximumScale();
}
@Override
public float getScale() {
return mAttacher.getScale();
}
@Override
public ScaleType getScaleType() {
return mAttacher.getScaleType();
}
@Override
public Matrix getImageMatrix() {
return mAttacher.getImageMatrix();
}
@Override
public void setAllowParentInterceptOnEdge(boolean allow) {
mAttacher.setAllowParentInterceptOnEdge(allow);
}
@Override
public void setMinimumScale(float minimumScale) {
mAttacher.setMinimumScale(minimumScale);
}
@Override
public void setMediumScale(float mediumScale) {
mAttacher.setMediumScale(mediumScale);
}
@Override
public void setMaximumScale(float maximumScale) {
mAttacher.setMaximumScale(maximumScale);
}
@Override
public void setScaleLevels(float minimumScale, float mediumScale, float maximumScale) {
mAttacher.setScaleLevels(minimumScale, mediumScale, maximumScale);
}
@Override
// setImageBitmap calls through to this method
public void setImageDrawable(Drawable drawable) {
super.setImageDrawable(drawable);
if (null != mAttacher) {
mAttacher.update();
}
}
@Override
public void setImageResource(int resId) {
super.setImageResource(resId);
if (null != mAttacher) {
mAttacher.update();
}
}
@Override
public void setImageURI(Uri uri) {
super.setImageURI(uri);
if (null != mAttacher) {
mAttacher.update();
}
}
@Override
protected boolean setFrame(int l, int t, int r, int b) {
boolean changed = super.setFrame(l, t, r, b);
if (null != mAttacher) {
mAttacher.update();
}
return changed;
}
@Override
public void setOnMatrixChangeListener(PhotoViewAttacher.OnMatrixChangedListener listener) {
mAttacher.setOnMatrixChangeListener(listener);
}
@Override
public void setOnLongClickListener(OnLongClickListener l) {
mAttacher.setOnLongClickListener(l);
}
@Override
public void setOnPhotoTapListener(PhotoViewAttacher.OnPhotoTapListener listener) {
mAttacher.setOnPhotoTapListener(listener);
}
@Override
public void setOnViewTapListener(PhotoViewAttacher.OnViewTapListener listener) {
mAttacher.setOnViewTapListener(listener);
}
@Override
public void setScale(float scale) {
mAttacher.setScale(scale);
}
@Override
public void setScale(float scale, boolean animate) {
mAttacher.setScale(scale, animate);
}
@Override
public void setScale(float scale, float focalX, float focalY, boolean animate) {
mAttacher.setScale(scale, focalX, focalY, animate);
}
@Override
public void setScaleType(ScaleType scaleType) {
if (null != mAttacher) {
mAttacher.setScaleType(scaleType);
} else {
mPendingScaleType = scaleType;
}
}
@Override
public void setZoomable(boolean zoomable) {
mAttacher.setZoomable(zoomable);
}
@Override
public Bitmap getVisibleRectangleBitmap() {
return mAttacher.getVisibleRectangleBitmap();
}
@Override
public void setZoomTransitionDuration(int milliseconds) {
mAttacher.setZoomTransitionDuration(milliseconds);
}
@Override
public IPhotoView getIPhotoViewImplementation() {
return mAttacher;
}
@Override
public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener) {
mAttacher.setOnDoubleTapListener(newOnDoubleTapListener);
}
@Override
public void setOnScaleChangeListener(PhotoViewAttacher.OnScaleChangeListener onScaleChangeListener) {
mAttacher.setOnScaleChangeListener(onScaleChangeListener);
}
@Override
public void setOnSingleFlingListener(PhotoViewAttacher.OnSingleFlingListener onSingleFlingListener) {
mAttacher.setOnSingleFlingListener(onSingleFlingListener);
}
@Override
protected void onDetachedFromWindow() {
mAttacher.cleanup();
mAttacher.resetMatrix();
mAttacher = null;
super.onDetachedFromWindow();
}
@Override
protected void onAttachedToWindow() {
init();
super.onAttachedToWindow();
}
public void resetMatrix() {
if (mAttacher != null) {
mAttacher.cleanup();
mAttacher.resetMatrix();
}
}
}
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.yidianling.consultant.preview;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Matrix.ScaleToFit;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.ViewParent;
import android.view.ViewTreeObserver;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import androidx.core.view.MotionEventCompat;
import java.lang.ref.WeakReference;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;
public class PhotoViewAttacher implements IPhotoView, View.OnTouchListener,
OnGestureListener,
ViewTreeObserver.OnGlobalLayoutListener {
private static final String LOG_TAG = "PhotoViewAttacher";
// let debug flag be dynamic, but still Proguard can be used to remove from
// release builds
private static final boolean DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG);
private Interpolator mInterpolator = new AccelerateDecelerateInterpolator();
int ZOOM_DURATION = DEFAULT_ZOOM_DURATION;
static final int EDGE_NONE = -1;
static final int EDGE_LEFT = 0;
static final int EDGE_RIGHT = 1;
static final int EDGE_BOTH = 2;
static int SINGLE_TOUCH = 1;
private float mMinScale = DEFAULT_MIN_SCALE;
private float mMidScale = DEFAULT_MID_SCALE;
private float mMaxScale = DEFAULT_MAX_SCALE;
private boolean mAllowParentInterceptOnEdge = true;
private boolean mBlockParentIntercept = false;
private static void checkZoomLevels(float minZoom, float midZoom,
float maxZoom) {
if (minZoom >= midZoom) {
throw new IllegalArgumentException(
"Minimum zoom has to be less than Medium zoom. Call setMinimumZoom() with a more appropriate value");
} else if (midZoom >= maxZoom) {
throw new IllegalArgumentException(
"Medium zoom has to be less than Maximum zoom. Call setMaximumZoom() with a more appropriate value");
}
}
/**
* @return true if the ImageView exists, and its Drawable exists
*/
private static boolean hasDrawable(ImageView imageView) {
return null != imageView && null != imageView.getDrawable();
}
/**
* @return true if the ScaleType is supported.
*/
private static boolean isSupportedScaleType(final ScaleType scaleType) {
if (null == scaleType) {
return false;
}
switch (scaleType) {
case MATRIX:
throw new IllegalArgumentException(scaleType.name()
+ " is not supported in PhotoView");
default:
return true;
}
}
/**
* Sets the ImageView's ScaleType to Matrix.
*/
private static void setImageViewScaleTypeMatrix(ImageView imageView) {
/**
* PhotoView sets its own ScaleType to Matrix, then diverts all calls
* setScaleType to this.setScaleType automatically.
*/
if (null != imageView && !(imageView instanceof IPhotoView)) {
if (!ScaleType.MATRIX.equals(imageView.getScaleType())) {
imageView.setScaleType(ScaleType.MATRIX);
}
}
}
private WeakReference<ImageView> mImageView;
// Gesture Detectors
private GestureDetector mGestureDetector;
private com.yidianling.consultant.preview.GestureDetector mScaleDragDetector;
// These are set so we don't keep allocating them on the heap
private final Matrix mBaseMatrix = new Matrix();
private final Matrix mDrawMatrix = new Matrix();
private final Matrix mSuppMatrix = new Matrix();
private final RectF mDisplayRect = new RectF();
private final float[] mMatrixValues = new float[9];
// Listeners
private OnMatrixChangedListener mMatrixChangeListener;
private OnPhotoTapListener mPhotoTapListener;
private OnViewTapListener mViewTapListener;
private OnLongClickListener mLongClickListener;
private OnScaleChangeListener mScaleChangeListener;
private OnSingleFlingListener mSingleFlingListener;
private int mIvTop, mIvRight, mIvBottom, mIvLeft;
private FlingRunnable mCurrentFlingRunnable;
private int mScrollEdge = EDGE_BOTH;
private float mBaseRotation;
private boolean mZoomEnabled;
private ScaleType mScaleType = ScaleType.FIT_CENTER;
public PhotoViewAttacher(ImageView imageView) {
this(imageView, true);
}
public PhotoViewAttacher(ImageView imageView, boolean zoomable) {
mImageView = new WeakReference<>(imageView);
imageView.setDrawingCacheEnabled(true);
imageView.setOnTouchListener(this);
ViewTreeObserver observer = imageView.getViewTreeObserver();
if (null != observer)
observer.addOnGlobalLayoutListener(this);
// Make sure we using MATRIX Scale Type
setImageViewScaleTypeMatrix(imageView);
if (imageView.isInEditMode()) {
return;
}
// Create Gesture Detectors...
mScaleDragDetector = VersionedGestureDetector.newInstance(
imageView.getContext(), this);
mGestureDetector = new GestureDetector(imageView.getContext(),
new GestureDetector.SimpleOnGestureListener() {
// forward long click listener
@Override
public void onLongPress(MotionEvent e) {
if (null != getImageView() && null != mLongClickListener && getImageView().getY() == 0 && getImageView().getX() == 0) {
mLongClickListener.onLongClick(getImageView());
}
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
if (mSingleFlingListener != null) {
if (getScale() > DEFAULT_MIN_SCALE) {
return false;
}
if (MotionEventCompat.getPointerCount(e1) > SINGLE_TOUCH
|| MotionEventCompat.getPointerCount(e2) > SINGLE_TOUCH) {
return false;
}
return mSingleFlingListener.onFling(e1, e2, velocityX, velocityY);
}
return false;
}
});
mGestureDetector.setOnDoubleTapListener(new DefaultOnDoubleTapListener(this));
mBaseRotation = 0.0f;
// Finally, update the UI so that we're zoomable
setZoomable(zoomable);
}
@Override
public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener) {
if (newOnDoubleTapListener != null) {
this.mGestureDetector.setOnDoubleTapListener(newOnDoubleTapListener);
} else {
this.mGestureDetector.setOnDoubleTapListener(new DefaultOnDoubleTapListener(this));
}
}
@Override
public void setOnScaleChangeListener(OnScaleChangeListener onScaleChangeListener) {
this.mScaleChangeListener = onScaleChangeListener;
}
@Override
public void setOnSingleFlingListener(OnSingleFlingListener onSingleFlingListener) {
this.mSingleFlingListener = onSingleFlingListener;
}
@Override
public boolean canZoom() {
return mZoomEnabled;
}
@SuppressWarnings("deprecation")
public void cleanup() {
if (null == mImageView) {
return; // cleanup already done
}
final ImageView imageView = mImageView.get();
if (null != imageView) {
// Remove this as a global layout listener
ViewTreeObserver observer = imageView.getViewTreeObserver();
if (null != observer && observer.isAlive()) {
observer.removeGlobalOnLayoutListener(this);
}
// Remove the ImageView's reference to this
imageView.setOnTouchListener(null);
// make sure a pending fling runnable won't be run
cancelFling();
}
if (null != mGestureDetector) {
mGestureDetector.setOnDoubleTapListener(null);
}
// Clear listeners too
mMatrixChangeListener = null;
mPhotoTapListener = null;
mViewTapListener = null;
// Finally, clear ImageView
mImageView = null;
}
@Override
public RectF getDisplayRect() {
checkMatrixBounds();
return getDisplayRect(getDrawMatrix());
}
@Override
public boolean setDisplayMatrix(Matrix finalMatrix) {
if (finalMatrix == null) {
throw new IllegalArgumentException("Matrix cannot be null");
}
ImageView imageView = getImageView();
if (null == imageView) {
return false;
}
if (null == imageView.getDrawable()) {
return false;
}
mSuppMatrix.set(finalMatrix);
setImageViewMatrix(getDrawMatrix());
checkMatrixBounds();
return true;
}
public void setBaseRotation(final float degrees) {
mBaseRotation = degrees % 360;
update();
setRotationBy(mBaseRotation);
checkAndDisplayMatrix();
}
@Override
public void setRotationTo(float degrees) {
mSuppMatrix.setRotate(degrees % 360);
checkAndDisplayMatrix();
}
@Override
public void setRotationBy(float degrees) {
mSuppMatrix.postRotate(degrees % 360);
checkAndDisplayMatrix();
}
public ImageView getImageView() {
ImageView imageView = null;
if (null != mImageView) {
imageView = mImageView.get();
}
// If we don't have an ImageView, call cleanup()
if (null == imageView) {
cleanup();
Log.i(LOG_TAG,
"ImageView no longer exists. You should not use this PhotoViewAttacher any more.");
}
return imageView;
}
@Override
public float getMinimumScale() {
return mMinScale;
}
@Override
public float getMediumScale() {
return mMidScale;
}
@Override
public float getMaximumScale() {
return mMaxScale;
}
@Override
public float getScale() {
return (float) Math.sqrt((float) Math.pow(getValue(mSuppMatrix, Matrix.MSCALE_X), 2) + (float) Math.pow(getValue(mSuppMatrix, Matrix.MSKEW_Y), 2));
}
@Override
public ScaleType getScaleType() {
return mScaleType;
}
@Override
public void onDrag(float dx, float dy) {
if (mScaleDragDetector.isScaling()) {
return; // Do not drag if we are already scaling
}
if (DEBUG) {
Log.d(LOG_TAG,
String.format("onDrag: dx: %.2f. dy: %.2f", dx, dy));
}
ImageView imageView = getImageView();
mSuppMatrix.postTranslate(dx, dy);
checkAndDisplayMatrix();
/**
* Here we decide whether to let the ImageView's parent to start taking
* over the touch event.
*
* First we check whether this function is enabled. We never want the
* parent to take over if we're scaling. We then check the edge we're
* on, and the direction of the scroll (i.e. if we're pulling against
* the edge, aka 'overscrolling', let the parent take over).
*/
ViewParent parent = imageView.getParent();
if (mAllowParentInterceptOnEdge && !mScaleDragDetector.isScaling() && !mBlockParentIntercept) {
if (mScrollEdge == EDGE_BOTH
|| (mScrollEdge == EDGE_LEFT && dx >= 1f)
|| (mScrollEdge == EDGE_RIGHT && dx <= -1f)) {
if (null != parent) {
parent.requestDisallowInterceptTouchEvent(false);
}
}
} else {
if (null != parent) {
parent.requestDisallowInterceptTouchEvent(true);
}
}
}
@Override
public void onFling(float startX, float startY, float velocityX,
float velocityY) {
if (DEBUG) {
Log.d(
LOG_TAG,
"onFling. sX: " + startX + " sY: " + startY + " Vx: "
+ velocityX + " Vy: " + velocityY);
}
ImageView imageView = getImageView();
mCurrentFlingRunnable = new FlingRunnable(imageView.getContext());
mCurrentFlingRunnable.fling(getImageViewWidth(imageView),
getImageViewHeight(imageView), (int) velocityX, (int) velocityY);
imageView.post(mCurrentFlingRunnable);
}
@Override
public void onGlobalLayout() {
ImageView imageView = getImageView();
if (null != imageView) {
if (mZoomEnabled) {
final int top = imageView.getTop();
final int right = imageView.getRight();
final int bottom = imageView.getBottom();
final int left = imageView.getLeft();
/**
* We need to check whether the ImageView's bounds have changed.
* This would be easier if we targeted API 11+ as we could just use
* View.OnLayoutChangeListener. Instead we have to replicate the
* work, keeping track of the ImageView's bounds and then checking
* if the values change.
*/
if (top != mIvTop || bottom != mIvBottom || left != mIvLeft
|| right != mIvRight) {
// Update our base matrix, as the bounds have changed
updateBaseMatrix(imageView.getDrawable());
// Update values as something has changed
mIvTop = top;
mIvRight = right;
mIvBottom = bottom;
mIvLeft = left;
}
} else {
updateBaseMatrix(imageView.getDrawable());
}
}
}
@Override
public void onScale(float scaleFactor, float focusX, float focusY) {
if (DEBUG) {
Log.d(
LOG_TAG,
String.format("onScale: scale: %.2f. fX: %.2f. fY: %.2f",
scaleFactor, focusX, focusY));
}
if ((getScale() < mMaxScale || scaleFactor < 1f) && (getScale() > mMinScale || scaleFactor > 1f)) {
if (null != mScaleChangeListener) {
mScaleChangeListener.onScaleChange(scaleFactor, focusX, focusY);
}
mSuppMatrix.postScale(scaleFactor, scaleFactor, focusX, focusY);
checkAndDisplayMatrix();
}
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent ev) {
boolean handled = false;
if (mZoomEnabled && hasDrawable((ImageView) v)) {
ViewParent parent = v.getParent();
switch (ev.getAction()) {
case ACTION_DOWN:
// First, disable the Parent from intercepting the touch
// event
if (null != parent) {
parent.requestDisallowInterceptTouchEvent(true);
} else {
Log.i(LOG_TAG, "onTouch getParent() returned null");
}
// If we're flinging, and the user presses down, cancel
// fling
cancelFling();
break;
case ACTION_CANCEL:
case ACTION_UP:
// If the user has zoomed less than min scale, zoom back
// to min scale
if (getScale() < mMinScale) {
RectF rect = getDisplayRect();
if (null != rect) {
v.post(new AnimatedZoomRunnable(getScale(), mMinScale,
rect.centerX(), rect.centerY()));
handled = true;
}
}
default: {
}
break;
}
// Try the Scale/Drag detector
if (null != mScaleDragDetector) {
boolean wasScaling = mScaleDragDetector.isScaling();
boolean wasDragging = mScaleDragDetector.isDragging();
handled = mScaleDragDetector.onTouchEvent(ev);
boolean didntScale = !wasScaling && !mScaleDragDetector.isScaling();
boolean didntDrag = !wasDragging && !mScaleDragDetector.isDragging();
mBlockParentIntercept = didntScale && didntDrag;
}
// Check to see if the user double tapped
if (null != mGestureDetector && mGestureDetector.onTouchEvent(ev)) {
handled = true;
}
}
return handled;
}
@Override
public void setAllowParentInterceptOnEdge(boolean allow) {
mAllowParentInterceptOnEdge = allow;
}
@Override
public void setMinimumScale(float minimumScale) {
checkZoomLevels(minimumScale, mMidScale, mMaxScale);
mMinScale = minimumScale;
}
@Override
public void setMediumScale(float mediumScale) {
checkZoomLevels(mMinScale, mediumScale, mMaxScale);
mMidScale = mediumScale;
}
@Override
public void setMaximumScale(float maximumScale) {
checkZoomLevels(mMinScale, mMidScale, maximumScale);
mMaxScale = maximumScale;
}
@Override
public void setScaleLevels(float minimumScale, float mediumScale, float maximumScale) {
checkZoomLevels(minimumScale, mediumScale, maximumScale);
mMinScale = minimumScale;
mMidScale = mediumScale;
mMaxScale = maximumScale;
}
@Override
public void setOnLongClickListener(OnLongClickListener listener) {
mLongClickListener = listener;
}
@Override
public void setOnMatrixChangeListener(OnMatrixChangedListener listener) {
mMatrixChangeListener = listener;
}
@Override
public void setOnPhotoTapListener(OnPhotoTapListener listener) {
mPhotoTapListener = listener;
}
OnPhotoTapListener getOnPhotoTapListener() {
return mPhotoTapListener;
}
@Override
public void setOnViewTapListener(OnViewTapListener listener) {
mViewTapListener = listener;
}
OnViewTapListener getOnViewTapListener() {
return mViewTapListener;
}
@Override
public void setScale(float scale) {
setScale(scale, false);
}
@Override
public void setScale(float scale, boolean animate) {
ImageView imageView = getImageView();
if (null != imageView) {
setScale(scale,
(imageView.getRight()) / 2,
(imageView.getBottom()) / 2,
animate);
}
}
@Override
public void setScale(float scale, float focalX, float focalY,
boolean animate) {
ImageView imageView = getImageView();
if (null != imageView) {
// Check to see if the scale is within bounds
if (scale < mMinScale || scale > mMaxScale) {
Log.i(LOG_TAG,
"Scale must be within the range of minScale and maxScale");
return;
}
if (animate) {
imageView.post(new AnimatedZoomRunnable(getScale(), scale,
focalX, focalY));
} else {
mSuppMatrix.setScale(scale, scale, focalX, focalY);
checkAndDisplayMatrix();
}
}
}
/**
* Set the zoom interpolator
*
* @param interpolator the zoom interpolator
*/
public void setZoomInterpolator(Interpolator interpolator) {
mInterpolator = interpolator;
}
@Override
public void setScaleType(ScaleType scaleType) {
if (isSupportedScaleType(scaleType) && scaleType != mScaleType) {
mScaleType = scaleType;
// Finally update
update();
}
}
@Override
public void setZoomable(boolean zoomable) {
mZoomEnabled = zoomable;
update();
}
public void update() {
ImageView imageView = getImageView();
if (null != imageView) {
if (mZoomEnabled) {
// Make sure we using MATRIX Scale Type
setImageViewScaleTypeMatrix(imageView);
// Update the base matrix using the current drawable
updateBaseMatrix(imageView.getDrawable());
} else {
// Reset the Matrix...
resetMatrix();
}
}
}
/**
* Get the display matrix
*
* @param matrix target matrix to copy to
*/
@Override
public void getDisplayMatrix(Matrix matrix) {
matrix.set(getDrawMatrix());
}
/**
* Get the current support matrix
*/
public void getSuppMatrix(Matrix matrix) {
matrix.set(mSuppMatrix);
}
private Matrix getDrawMatrix() {
mDrawMatrix.set(mBaseMatrix);
mDrawMatrix.postConcat(mSuppMatrix);
return mDrawMatrix;
}
private void cancelFling() {
if (null != mCurrentFlingRunnable) {
mCurrentFlingRunnable.cancelFling();
mCurrentFlingRunnable = null;
}
}
public Matrix getImageMatrix() {
return mDrawMatrix;
}
/**
* Helper method that simply checks the Matrix, and then displays the result
*/
private void checkAndDisplayMatrix() {
if (checkMatrixBounds()) {
setImageViewMatrix(getDrawMatrix());
}
}
private void checkImageViewScaleType() {
ImageView imageView = getImageView();
/**
* PhotoView's getScaleType() will just divert to this.getScaleType() so
* only call if we're not attached to a PhotoView.
*/
if (null != imageView && !(imageView instanceof IPhotoView)) {
if (!ScaleType.MATRIX.equals(imageView.getScaleType())) {
throw new IllegalStateException(
"The ImageView's ScaleType has been changed since attaching a PhotoViewAttacher. You should call setScaleType on the PhotoViewAttacher instead of on the ImageView");
}
}
}
private boolean checkMatrixBounds() {
final ImageView imageView = getImageView();
if (null == imageView) {
return false;
}
final RectF rect = getDisplayRect(getDrawMatrix());
if (null == rect) {
return false;
}
final float height = rect.height(), width = rect.width();
float deltaX = 0, deltaY = 0;
final int viewHeight = getImageViewHeight(imageView);
if (height <= viewHeight) {
switch (mScaleType) {
case FIT_START:
deltaY = -rect.top;
break;
case FIT_END:
deltaY = viewHeight - height - rect.top;
break;
default:
deltaY = (viewHeight - height) / 2 - rect.top;
break;
}
} else if (rect.top > 0) {
deltaY = -rect.top;
} else if (rect.bottom < viewHeight) {
deltaY = viewHeight - rect.bottom;
}
final int viewWidth = getImageViewWidth(imageView);
if (width <= viewWidth) {
switch (mScaleType) {
case FIT_START:
deltaX = -rect.left;
break;
case FIT_END:
deltaX = viewWidth - width - rect.left;
break;
default:
deltaX = (viewWidth - width) / 2 - rect.left;
break;
}
mScrollEdge = EDGE_BOTH;
} else if (rect.left > 0) {
mScrollEdge = EDGE_LEFT;
deltaX = -rect.left;
} else if (rect.right < viewWidth) {
deltaX = viewWidth - rect.right;
mScrollEdge = EDGE_RIGHT;
} else {
mScrollEdge = EDGE_NONE;
}
// Finally actually translate the matrix
mSuppMatrix.postTranslate(deltaX, deltaY);
return true;
}
/**
* Helper method that maps the supplied Matrix to the current Drawable
*
* @param matrix - Matrix to map Drawable against
* @return RectF - Displayed Rectangle
*/
private RectF getDisplayRect(Matrix matrix) {
ImageView imageView = getImageView();
if (null != imageView) {
Drawable d = imageView.getDrawable();
if (null != d) {
mDisplayRect.set(0, 0, d.getIntrinsicWidth(),
d.getIntrinsicHeight());
matrix.mapRect(mDisplayRect);
return mDisplayRect;
}
}
return null;
}
@Override
public Bitmap getVisibleRectangleBitmap() {
ImageView imageView = getImageView();
return imageView == null ? null : imageView.getDrawingCache();
}
@Override
public void setZoomTransitionDuration(int milliseconds) {
if (milliseconds < 0)
milliseconds = DEFAULT_ZOOM_DURATION;
this.ZOOM_DURATION = milliseconds;
}
@Override
public IPhotoView getIPhotoViewImplementation() {
return this;
}
/**
* Helper method that 'unpacks' a Matrix and returns the required value
*
* @param matrix - Matrix to unpack
* @param whichValue - Which value from Matrix.M* to return
* @return float - returned value
*/
private float getValue(Matrix matrix, int whichValue) {
matrix.getValues(mMatrixValues);
return mMatrixValues[whichValue];
}
/**
* Resets the Matrix back to FIT_CENTER, and then displays it.s
*/
public void resetMatrix() {
mSuppMatrix.reset();
setRotationBy(mBaseRotation);
setImageViewMatrix(getDrawMatrix());
checkMatrixBounds();
}
private void setImageViewMatrix(Matrix matrix) {
ImageView imageView = getImageView();
if (null != imageView) {
checkImageViewScaleType();
imageView.setImageMatrix(matrix);
// Call MatrixChangedListener if needed
if (null != mMatrixChangeListener) {
RectF displayRect = getDisplayRect(matrix);
if (null != displayRect) {
mMatrixChangeListener.onMatrixChanged(displayRect);
}
}
}
}
/**
* Calculate Matrix for FIT_CENTER
*
* @param d - Drawable being displayed
*/
private void updateBaseMatrix(Drawable d) {
ImageView imageView = getImageView();
if (null == imageView || null == d) {
return;
}
final float viewWidth = getImageViewWidth(imageView);
final float viewHeight = getImageViewHeight(imageView);
final int drawableWidth = d.getIntrinsicWidth();
final int drawableHeight = d.getIntrinsicHeight();
mBaseMatrix.reset();
final float widthScale = viewWidth / drawableWidth;
final float heightScale = viewHeight / drawableHeight;
if (mScaleType == ScaleType.CENTER) {
mBaseMatrix.postTranslate((viewWidth - drawableWidth) / 2F,
(viewHeight - drawableHeight) / 2F);
} else if (mScaleType == ScaleType.CENTER_CROP) {
float scale = Math.max(widthScale, heightScale);
mBaseMatrix.postScale(scale, scale);
mBaseMatrix.postTranslate((viewWidth - drawableWidth * scale) / 2F,
(viewHeight - drawableHeight * scale) / 2F);
} else if (mScaleType == ScaleType.CENTER_INSIDE) {
float scale = Math.min(1.0f, Math.min(widthScale, heightScale));
mBaseMatrix.postScale(scale, scale);
mBaseMatrix.postTranslate((viewWidth - drawableWidth * scale) / 2F,
(viewHeight - drawableHeight * scale) / 2F);
} else {
RectF mTempSrc = new RectF(0, 0, drawableWidth, drawableHeight);
RectF mTempDst = new RectF(0, 0, viewWidth, viewHeight);
if ((int) mBaseRotation % 180 != 0) {
mTempSrc = new RectF(0, 0, drawableHeight, drawableWidth);
}
switch (mScaleType) {
case FIT_CENTER:
mBaseMatrix
.setRectToRect(mTempSrc, mTempDst, ScaleToFit.CENTER);
break;
case FIT_START:
mBaseMatrix.setRectToRect(mTempSrc, mTempDst, ScaleToFit.START);
break;
case FIT_END:
mBaseMatrix.setRectToRect(mTempSrc, mTempDst, ScaleToFit.END);
break;
case FIT_XY:
mBaseMatrix.setRectToRect(mTempSrc, mTempDst, ScaleToFit.FILL);
break;
default:
break;
}
}
resetMatrix();
}
private int getImageViewWidth(ImageView imageView) {
if (null == imageView)
return 0;
return imageView.getWidth() - imageView.getPaddingLeft() - imageView.getPaddingRight();
}
private int getImageViewHeight(ImageView imageView) {
if (null == imageView)
return 0;
return imageView.getHeight() - imageView.getPaddingTop() - imageView.getPaddingBottom();
}
/**
* Interface definition for a callback to be invoked when the internal Matrix has changed for
* this View.
*
* @author Chris Banes
*/
public interface OnMatrixChangedListener {
/**
* Callback for when the Matrix displaying the Drawable has changed. This could be because
* the View's bounds have changed, or the user has zoomed.
*
* @param rect - Rectangle displaying the Drawable's new bounds.
*/
void onMatrixChanged(RectF rect);
}
/**
* Interface definition for callback to be invoked when attached ImageView scale changes
*
* @author Marek Sebera
*/
public interface OnScaleChangeListener {
/**
* Callback for when the scale changes
*
* @param scaleFactor the scale factor (less than 1 for zoom out, greater than 1 for zoom in)
* @param focusX focal point X position
* @param focusY focal point Y position
*/
void onScaleChange(float scaleFactor, float focusX, float focusY);
}
/**
* Interface definition for a callback to be invoked when the Photo is tapped with a single
* tap.
*
* @author Chris Banes
*/
public interface OnPhotoTapListener {
/**
* A callback to receive where the user taps on a photo. You will only receive a callback if
* the user taps on the actual photo, tapping on 'whitespace' will be ignored.
*
* @param view - View the user tapped.
* @param x - where the user tapped from the of the Drawable, as percentage of the
* Drawable width.
* @param y - where the user tapped from the top of the Drawable, as percentage of the
* Drawable height.
*/
void onPhotoTap(View view, float x, float y);
/**
* A simple callback where out of photo happened;
*/
void onOutsidePhotoTap();
}
/**
* Interface definition for a callback to be invoked when the ImageView is tapped with a single
* tap.
*
* @author Chris Banes
*/
public interface OnViewTapListener {
/**
* A callback to receive where the user taps on a ImageView. You will receive a callback if
* the user taps anywhere on the view, tapping on 'whitespace' will not be ignored.
*
* @param view - View the user tapped.
* @param x - where the user tapped from the left of the View.
* @param y - where the user tapped from the top of the View.
*/
void onViewTap(View view, float x, float y);
}
/**
* Interface definition for a callback to be invoked when the ImageView is fling with a single
* touch
*
* @author tonyjs
*/
public interface OnSingleFlingListener {
/**
* A callback to receive where the user flings on a ImageView. You will receive a callback if
* the user flings anywhere on the view.
*
* @param e1 - MotionEvent the user first touch.
* @param e2 - MotionEvent the user last touch.
* @param velocityX - distance of user's horizontal fling.
* @param velocityY - distance of user's vertical fling.
*/
boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
}
private class AnimatedZoomRunnable implements Runnable {
private final float mFocalX, mFocalY;
private final long mStartTime;
private final float mZoomStart, mZoomEnd;
public AnimatedZoomRunnable(final float currentZoom, final float targetZoom,
final float focalX, final float focalY) {
mFocalX = focalX;
mFocalY = focalY;
mStartTime = System.currentTimeMillis();
mZoomStart = currentZoom;
mZoomEnd = targetZoom;
}
@Override
public void run() {
ImageView imageView = getImageView();
if (imageView == null) {
return;
}
float t = interpolate();
float scale = mZoomStart + t * (mZoomEnd - mZoomStart);
float deltaScale = scale / getScale();
onScale(deltaScale, mFocalX, mFocalY);
// We haven't hit our target scale yet, so post ourselves again
if (t < 1f) {
Compat.postOnAnimation(imageView, this);
}
}
private float interpolate() {
float t = 1f * (System.currentTimeMillis() - mStartTime) / ZOOM_DURATION;
t = Math.min(1f, t);
t = mInterpolator.getInterpolation(t);
return t;
}
}
private class FlingRunnable implements Runnable {
private final ScrollerProxy mScroller;
private int mCurrentX, mCurrentY;
public FlingRunnable(Context context) {
mScroller = ScrollerProxy.getScroller(context);
}
public void cancelFling() {
if (DEBUG) {
Log.d(LOG_TAG, "Cancel Fling");
}
mScroller.forceFinished(true);
}
public void fling(int viewWidth, int viewHeight, int velocityX,
int velocityY) {
final RectF rect = getDisplayRect();
if (null == rect) {
return;
}
final int startX = Math.round(-rect.left);
final int minX, maxX, minY, maxY;
if (viewWidth < rect.width()) {
minX = 0;
maxX = Math.round(rect.width() - viewWidth);
} else {
minX = maxX = startX;
}
final int startY = Math.round(-rect.top);
if (viewHeight < rect.height()) {
minY = 0;
maxY = Math.round(rect.height() - viewHeight);
} else {
minY = maxY = startY;
}
mCurrentX = startX;
mCurrentY = startY;
if (DEBUG) {
Log.d(
LOG_TAG,
"fling. StartX:" + startX + " StartY:" + startY
+ " MaxX:" + maxX + " MaxY:" + maxY);
}
// If we actually can move, fling the scroller
if (startX != maxX || startY != maxY) {
mScroller.fling(startX, startY, velocityX, velocityY, minX,
maxX, minY, maxY, 0, 0);
}
}
@Override
public void run() {
if (mScroller.isFinished()) {
return; // remaining post that should not be handled
}
ImageView imageView = getImageView();
if (null != imageView && mScroller.computeScrollOffset()) {
final int newX = mScroller.getCurrX();
final int newY = mScroller.getCurrY();
if (DEBUG) {
Log.d(
LOG_TAG,
"fling run(). CurrentX:" + mCurrentX + " CurrentY:"
+ mCurrentY + " NewX:" + newX + " NewY:"
+ newY);
}
mSuppMatrix.postTranslate(mCurrentX - newX, mCurrentY - newY);
setImageViewMatrix(getDrawMatrix());
mCurrentX = newX;
mCurrentY = newY;
// Post On animation
Compat.postOnAnimation(imageView, this);
}
}
}
}
package com.yidianling.consultant.preview;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import androidx.viewpager.widget.ViewPager;
/**
* Issues With ViewGroups
*
* @author rainb
*/
public class PhotoViewPager extends ViewPager {
public PhotoViewPager(Context context) {
super(context);
}
public PhotoViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
try {
return super.onInterceptTouchEvent(ev);
} catch (IllegalArgumentException e) {
e.printStackTrace();
return false;
}
}
}
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.yidianling.consultant.preview;
import android.content.Context;
import android.widget.Scroller;
/**
* @author rainb
*/
public class PreGingerScroller extends ScrollerProxy {
private final Scroller mScroller;
public PreGingerScroller(Context context) {
mScroller = new Scroller(context);
}
@Override
public boolean computeScrollOffset() {
return mScroller.computeScrollOffset();
}
@Override
public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY,
int overX, int overY) {
mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
}
@Override
public void forceFinished(boolean finished) {
mScroller.forceFinished(finished);
}
@Override
public boolean isFinished() {
return mScroller.isFinished();
}
@Override
public int getCurrX() {
return mScroller.getCurrX();
}
@Override
public int getCurrY() {
return mScroller.getCurrY();
}
}
\ No newline at end of file
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.yidianling.consultant.preview;
import android.content.Context;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
/**
* @author rainb
*/
public abstract class ScrollerProxy {
public static ScrollerProxy getScroller(Context context) {
if (VERSION.SDK_INT < VERSION_CODES.GINGERBREAD) {
return new PreGingerScroller(context);
} else if (VERSION.SDK_INT < VERSION_CODES.ICE_CREAM_SANDWICH) {
return new GingerScroller(context);
} else {
return new IcsScroller(context);
}
}
public abstract boolean computeScrollOffset();
public abstract void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY,
int maxY, int overX, int overY);
public abstract void forceFinished(boolean finished);
public abstract boolean isFinished();
public abstract int getCurrX();
public abstract int getCurrY();
}
package com.yidianling.consultant.preview;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.ImageView;
import com.ydl.ydlcommon.utils.StatusBarUtils;
import com.yidianling.consultant.R;
/**
* Deprecated: 缩放图片
***/
public class SmoothImageView extends PhotoView {
public enum Status {
STATE_NORMAL,
STATE_IN,
STATE_OUT,
STATE_MOVE,
}
private Status mStatus = Status.STATE_NORMAL;
private static int TRANSFORM_DURATION = 400;
private static boolean ISFUll = false;
private static boolean ISSCALE = false;
private Paint mPaint;
private Matrix matrix;
private Transform startTransform;
private Transform endTransform;
private Transform animTransform;
private Rect thumbRect;
private boolean transformStart;
private int bitmapWidth;
private int bitmapHeight;
private boolean isDrag;
ValueAnimator animator;
private float MAX_TRANS_SCALE = 0.2f;
private boolean isMaskPoint = false;
private BasePhotoFragment.OnDragListener onDragListener;
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
bitmapWidth = 0;
bitmapHeight = 0;
thumbRect = null;
onDragListener = null;
ISFUll = false;
if (animator != null) {
animator.cancel();
animator.clone();
animator = null;
}
}
private void initSmoothImageView() {
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(0xFF000000);
matrix = new Matrix();
setScaleType(ImageView.ScaleType.FIT_CENTER);
}
public boolean checkMinScale() {
if (getScale() != 1) {
setScale(1, true);
return false;
}
return true;
}
@Override
protected void onDraw(Canvas canvas) {
if (getDrawable() == null) {
return;
}
if (mStatus == Status.STATE_OUT || mStatus == Status.STATE_IN) {
if (startTransform == null || endTransform == null || animTransform == null) {
initTransform();
}
if (animTransform == null) {
super.onDraw(canvas);
return;
}
mPaint.setAlpha(animTransform.alpha);
canvas.drawPaint(mPaint);
int saveCount = canvas.getSaveCount();
matrix.setScale(animTransform.scale, animTransform.scale);
float translateX = -(bitmapWidth * animTransform.scale - animTransform.width) / 2;
float translateY = -(bitmapHeight * animTransform.scale - animTransform.height) / 2;
matrix.postTranslate(translateX, translateY);
canvas.translate(animTransform.left, animTransform.top);
canvas.clipRect(0, 0, animTransform.width, animTransform.height);
canvas.concat(matrix);
getDrawable().draw(canvas);
canvas.restoreToCount(saveCount);
if (transformStart) {
startTransform();
}
} else if (mStatus == Status.STATE_MOVE) {
mPaint.setAlpha(0);
canvas.drawPaint(mPaint);
super.onDraw(canvas);
} else {
mPaint.setAlpha(255);
canvas.drawPaint(mPaint);
super.onDraw(canvas);
}
}
private int downX, downY;
private boolean isMoved = false;
private boolean isDownPhoto = false;
private int alpha = 0;
private static final int MIN_TRANS_DEST = 5;
private void actionDown(MotionEvent event) {
isMaskPoint = false;
downX = (int) event.getX();
downY = (int) event.getY();
if (markTransform == null) {
initTransform();
}
isDownPhoto = false;
if (markTransform != null) {
int startY = (int) markTransform.top;
int endY = (int) (markTransform.height + markTransform.top);
if (downY >= startY && endY >= downY) {
isDownPhoto = true;
}
}
isMoved = false;
}
private boolean actionMove(MotionEvent event) {
if (!isDownPhoto && event.getPointerCount() == 1) {
return super.dispatchTouchEvent(event);
}
int mx = (int) event.getX();
int my = (int) event.getY();
int offsetX = mx - downX;
int offsetY = my - downY;
// 水平方向移动不予处理
boolean s = !isMoved && (Math.abs(offsetX) > Math.abs(offsetY) || Math.abs(offsetY) < MIN_TRANS_DEST);
if (s) {
return super.dispatchTouchEvent(event);
} else {
if (isDrag || isMaskPoint) {
return super.dispatchTouchEvent(event);
}
// 一指滑动时,才对图片进行移动缩放处理
if (event.getPointerCount() == 1) {
mStatus = Status.STATE_MOVE;
offsetLeftAndRight(offsetX);
offsetTopAndBottom(offsetY);
float scale = moveScale();
float scaleXY = 1 - scale * 0.1f;
setScaleY(scaleXY);
setScaleX(scaleXY);
isMoved = true;
alpha = (int) (255 * (1 - scale * 0.5f));
invalidate();
if (alpha < 0) {
alpha = 0;
}
if (onDragListener != null) {
onDragListener.drag();
}
if (alphaChangeListener != null) {
alphaChangeListener.onAlphaChange(alpha);
}
return true;
} else {
return super.dispatchTouchEvent(event);
}
}
}
private boolean actionCancel() {
if (moveScale() <= MAX_TRANS_SCALE) {
moveToOldPosition();
if (onDragListener != null) {
onDragListener.actionCancel();
}
} else {
changeTransform();
setTag(R.id.consultant_item_image_key, true);
if (transformOutListener != null) {
transformOutListener.onTransformOut();
}
}
return true;
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
if (ISSCALE) {
if (getScale() == 1) {
switch (action) {
case MotionEvent.ACTION_DOWN:
actionDown(event);
break;
case MotionEvent.ACTION_MOVE:
return actionMove(event);
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (isMoved) {
return actionCancel();
}
break;
default: {
}
}
return super.dispatchTouchEvent(event);
} else {
switch (action) {
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (isMoved && getScale() <= 1.0) {
return actionCancel();
}
break;
default: {
}
}
return super.dispatchTouchEvent(event);
}
} else {
switch (action) {
case MotionEvent.ACTION_DOWN:
actionDown(event);
break;
case MotionEvent.ACTION_MOVE:
return actionMove(event);
case MotionEvent.ACTION_POINTER_DOWN:
isMaskPoint = true;
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (isMoved) {
if (isMaskPoint) {
return true;
} else {
return actionCancel();
}
}
break;
default: {
}
}
return super.dispatchTouchEvent(event);
}
}
/**
* 未达到关闭的阈值松手时,返回到初始位置
*/
private void moveToOldPosition() {
ValueAnimator va = ValueAnimator.ofInt(getTop(), 0);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
int startValue = 0;
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (int) animation.getAnimatedValue();
if (startValue != 0) {
offsetTopAndBottom(value - startValue);
}
startValue = value;
}
});
ValueAnimator leftAnim = ValueAnimator.ofInt(getLeft(), 0);
leftAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
int startValue = 0;
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (int) animation.getAnimatedValue();
if (startValue != 0) {
offsetLeftAndRight(value - startValue);
}
startValue = value;
}
});
ValueAnimator alphaAnim = ValueAnimator.ofInt(alpha, 255);
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
if (alphaChangeListener != null) {
alphaChangeListener.onAlphaChange((Integer) animation.getAnimatedValue());
}
}
});
ValueAnimator scaleAnim = ValueAnimator.ofFloat(getScaleX(), 1);
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float scale = (float) animation.getAnimatedValue();
setScaleX(scale);
setScaleY(scale);
}
});
AnimatorSet as = new AnimatorSet();
as.setDuration(TRANSFORM_DURATION);
as.setInterpolator(new AccelerateDecelerateInterpolator());
as.playTogether(va, leftAnim, scaleAnim, alphaAnim);
as.start();
}
private float moveScale() {
if (markTransform == null) {
initTransform();
}
return Math.abs(getTop() / markTransform.height);
}
private OnAlphaChangeListener alphaChangeListener;
private OnTransformOutListener transformOutListener;
public void setTransformOutListener(OnTransformOutListener transformOutListener) {
this.transformOutListener = transformOutListener;
}
public void setAlphaChangeListener(OnAlphaChangeListener alphaChangeListener) {
this.alphaChangeListener = alphaChangeListener;
}
public interface OnTransformOutListener {
void onTransformOut();
}
public interface OnAlphaChangeListener {
void onAlphaChange(int alpha);
}
private Transform markTransform;
private void changeTransform() {
if (markTransform != null) {
Transform tempTransform = markTransform.clone();
tempTransform.top = markTransform.top + getTop();
tempTransform.left = markTransform.left + getLeft();
tempTransform.alpha = alpha;
tempTransform.scale = markTransform.scale - (1 - getScaleX()) * markTransform.scale;
animTransform = tempTransform.clone();
endTransform = tempTransform.clone();
}
}
private void startTransform() {
transformStart = false;
if (animTransform == null) {
return;
}
animator = new ValueAnimator();
animator.setDuration(TRANSFORM_DURATION);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
if (mStatus == Status.STATE_IN) {
PropertyValuesHolder scaleHolder = PropertyValuesHolder.ofFloat("animScale", startTransform.scale, endTransform.scale);
PropertyValuesHolder alphaHolder = PropertyValuesHolder.ofInt("animAlpha", startTransform.alpha, endTransform.alpha);
PropertyValuesHolder leftHolder = PropertyValuesHolder.ofFloat("animLeft", startTransform.left, endTransform.left);
PropertyValuesHolder topHolder = PropertyValuesHolder.ofFloat("animTop", startTransform.top, endTransform.top);
PropertyValuesHolder widthHolder = PropertyValuesHolder.ofFloat("animWidth", startTransform.width, endTransform.width);
PropertyValuesHolder heightHolder = PropertyValuesHolder.ofFloat("animHeight", startTransform.height, endTransform.height);
animator.setValues(scaleHolder, alphaHolder, leftHolder, topHolder, widthHolder, heightHolder);
} else if (mStatus == Status.STATE_OUT) {
PropertyValuesHolder scaleHolder = PropertyValuesHolder.ofFloat("animScale", endTransform.scale, startTransform.scale);
PropertyValuesHolder alphaHolder = PropertyValuesHolder.ofInt("animAlpha", endTransform.alpha, startTransform.alpha);
PropertyValuesHolder leftHolder = PropertyValuesHolder.ofFloat("animLeft", endTransform.left, startTransform.left);
PropertyValuesHolder topHolder = PropertyValuesHolder.ofFloat("animTop", endTransform.top, startTransform.top);
PropertyValuesHolder widthHolder = PropertyValuesHolder.ofFloat("animWidth", endTransform.width, startTransform.width);
PropertyValuesHolder heightHolder = PropertyValuesHolder.ofFloat("animHeight", endTransform.height, startTransform.height);
animator.setValues(scaleHolder, alphaHolder, leftHolder, topHolder, widthHolder, heightHolder);
}
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
animTransform.alpha = (Integer) animation.getAnimatedValue("animAlpha");
animTransform.scale = (float) animation.getAnimatedValue("animScale");
animTransform.left = (float) animation.getAnimatedValue("animLeft");
animTransform.top = (float) animation.getAnimatedValue("animTop");
animTransform.width = (float) animation.getAnimatedValue("animWidth");
animTransform.height = (float) animation.getAnimatedValue("animHeight");
invalidate();
}
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
if (getTag(R.id.consultant_item_image_key) != null) {
setTag(R.id.consultant_item_image_key, null);
setOnLongClickListener(null);
}
}
@Override
public void onAnimationEnd(Animator animation) {
/*
* 如果是进入的话,当然是希望最后停留在center_crop的区域。但是如果是out的话,就不应该是center_crop的位置了
* , 而应该是最后变化的位置,因为当out的时候结束时,不回复视图是Normal,要不然会有一个突然闪动回去的bug
*/
if (onTransformListener != null) {
onTransformListener.onTransformCompleted(mStatus);
}
if (mStatus == Status.STATE_IN) {
mStatus = Status.STATE_NORMAL;
}
}
});
animator.start();
}
public void transformIn(onTransformListener listener) {
setOnTransformListener(listener);
transformStart = true;
mStatus = Status.STATE_IN;
invalidate();
}
public void transformOut(onTransformListener listener) {
if (getTop() != 0) {
offsetTopAndBottom(-getTop());
}
if (getLeft() != 0) {
offsetLeftAndRight(-getLeft());
}
if (getScaleX() != 1) {
setScaleX(1);
setScaleY(1);
}
setOnTransformListener(listener);
transformStart = true;
mStatus = Status.STATE_OUT;
invalidate();
}
/**
* 设置起始位置图片的Rect
* g
*
* @param thumbRect 参数
*/
public void setThumbRect(Rect thumbRect) {
this.thumbRect = thumbRect;
}
public void setOnDragListener(BasePhotoFragment.OnDragListener dragListener) {
this.onDragListener = dragListener;
}
private void initTransform() {
if (getDrawable() == null) {
return;
}
if (startTransform != null && endTransform != null && animTransform != null) {
return;
}
if (getWidth() == 0 || getHeight() == 0) {
return;
}
if (getDrawable() instanceof BitmapDrawable) {
Bitmap mBitmap = ((BitmapDrawable) getDrawable()).getBitmap();
bitmapWidth = mBitmap.getWidth();
bitmapHeight = mBitmap.getHeight();
} else if (getDrawable() instanceof ColorDrawable) {
ColorDrawable colorDrawable = (ColorDrawable) getDrawable();
bitmapWidth = colorDrawable.getIntrinsicWidth();
bitmapHeight = colorDrawable.getIntrinsicHeight();
} else {
Bitmap mBitmap = Bitmap.createBitmap(getDrawable().getIntrinsicWidth(),
getDrawable().getIntrinsicHeight(), Bitmap.Config.RGB_565);
bitmapWidth = mBitmap.getWidth();
bitmapHeight = mBitmap.getHeight();
}
startTransform = new Transform();
startTransform.alpha = 0;
if (thumbRect == null) {
thumbRect = new Rect();
}
startTransform.left = thumbRect.left;
if (ISFUll) {
startTransform.top = thumbRect.top;
} else {
startTransform.top = thumbRect.top - StatusBarUtils.Companion.getStatusBarHeight(getContext().getApplicationContext());
}
startTransform.width = thumbRect.width();
startTransform.height = thumbRect.height();
//开始时以CenterCrop方式显示,缩放图片使图片的一边等于起始区域的一边,另一边大于起始区域
float startScaleX = (float) thumbRect.width() / bitmapWidth;
float startScaleY = (float) thumbRect.height() / bitmapHeight;
startTransform.scale = startScaleX > startScaleY ? startScaleX : startScaleY;
//结束时以fitCenter方式显示,缩放图片使图片的一边等于View的一边,另一边大于View
float endScaleX = (float) getWidth() / bitmapWidth;
float endScaleY = (float) getHeight() / bitmapHeight;
endTransform = new Transform();
endTransform.scale = endScaleX < endScaleY ? endScaleX : endScaleY;
endTransform.alpha = 255;
int endBitmapWidth = (int) (endTransform.scale * bitmapWidth);
int endBitmapHeight = (int) (endTransform.scale * bitmapHeight);
endTransform.left = (getWidth() - endBitmapWidth) / 2;
endTransform.top = (getHeight() - endBitmapHeight) / 2;
endTransform.width = endBitmapWidth;
endTransform.height = endBitmapHeight;
if (mStatus == Status.STATE_IN) {
animTransform = startTransform.clone();
} else if (mStatus == Status.STATE_OUT) {
animTransform = endTransform.clone();
}
markTransform = endTransform;
}
private onTransformListener onTransformListener;
public void setOnTransformListener(SmoothImageView.onTransformListener onTransformListener) {
this.onTransformListener = onTransformListener;
}
public interface onTransformListener {
void onTransformCompleted(Status status);
}
private class Transform implements Cloneable {
float left, top, width, height;
int alpha;
float scale;
@Override
public Transform clone() {
Transform obj = null;
try {
obj = (Transform) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return obj;
}
}
public SmoothImageView(Context context, AttributeSet attrs) {
super(context, attrs);
initSmoothImageView();
}
public SmoothImageView(Context context) {
super(context);
initSmoothImageView();
}
/***
* 设置图片拖拽返回
* @param isDrag true 可以 false 默认 true
* **/
public void setDrag(boolean isDrag, float sensitivity) {
this.isDrag = isDrag;
this.MAX_TRANS_SCALE = sensitivity;
}
/***
* 设置动画的时长
* @param duration 单位毫秒
* **/
public static void setDuration(int duration) {
TRANSFORM_DURATION = duration;
}
/***
* 获取动画的时长
* **/
public static int getDuration() {
return TRANSFORM_DURATION;
}
/***
* 设置是否全屏
* @param isFull true 全屏
* **/
public static void setFullscreen(boolean isFull) {
ISFUll = isFull;
}
/***
* 设置只有图片没有放大或者的缩小状态触退出
* @param isScale true false
* **/
public static void setIsScale(boolean isScale) {
ISSCALE = isScale;
}
}
package com.yidianling.consultant.preview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;
import com.yidianling.consultant.R;
import org.jetbrains.annotations.NotNull;
/**
* @author rainb
*/
public class TestImageLoader implements IZoomMediaLoader {
@Override
public void displayImage(@NonNull Fragment context, @NonNull String path, final ImageView imageView, @NonNull final MySimpleTarget simpleTarget) {
Glide.with(context).asBitmap().load(path).placeholder(R.drawable.consultant_bg_black).error(R.drawable.consultant_bg_black)
// .placeholder(android.R.color.darker_gray)
.fitCenter()
.into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(@NonNull @NotNull Bitmap resource, @Nullable @org.jetbrains.annotations.Nullable Transition<? super Bitmap> transition) {
simpleTarget.onResourceReady();
imageView.setImageBitmap(resource);
}
@Override
public void onLoadFailed(@Nullable @org.jetbrains.annotations.Nullable Drawable errorDrawable) {
simpleTarget.onLoadFailed(errorDrawable);
imageView.setImageDrawable(errorDrawable);
}
});
}
@Override
public void displayGifImage(@NonNull Fragment context, @NonNull String path, ImageView imageView, @NonNull final MySimpleTarget simpleTarget) {
}
@Override
public void onStop(@NonNull Fragment context) {
Glide.with(context).onStop();
}
@Override
public void clearMemory(@NonNull Context c) {
Glide.get(c).clearMemory();
}
}
package com.yidianling.consultant.preview;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Deprecated: 图片预览实体类
*
* @author rainb
*/
public class UserViewInfo implements IThumbViewInfo {
private String url; //图片地址
private Rect mBounds; // 记录坐标
private int sourcesType;
private String cover;
public UserViewInfo(String url) {
this.url = url;
}
public UserViewInfo(String cover, String url, int sourcesType) {
this.url = url;
this.cover = cover;
this.sourcesType = sourcesType;
}
@Override
public String getUrl() {//将你的图片地址字段返回
return url;
}
public void setUrl(String url) {
this.url = url;
}
@Override
public Rect getBounds() {//将你的图片显示坐标字段返回
return mBounds;
}
@Override
public String getCover() {
return cover;
}
@Override
public int getSourcesType() {
return sourcesType;
}
public void setBounds(Rect bounds) {
mBounds = bounds;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.url);
dest.writeParcelable(this.mBounds, flags);
dest.writeString(this.cover);
dest.writeInt(this.sourcesType);
}
protected UserViewInfo(Parcel in) {
this.url = in.readString();
this.mBounds = in.readParcelable(Rect.class.getClassLoader());
this.cover = in.readString();
this.sourcesType = in.readInt();
}
public static final Parcelable.Creator<UserViewInfo> CREATOR = new Parcelable.Creator<UserViewInfo>() {
@Override
public UserViewInfo createFromParcel(Parcel source) {
return new UserViewInfo(source);
}
@Override
public UserViewInfo[] newArray(int size) {
return new UserViewInfo[size];
}
};
}
package com.yidianling.consultant.preview;
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
import android.content.Context;
import android.os.Build;
/**
* @author rainb
*/
public final class VersionedGestureDetector {
public static GestureDetector newInstance(Context context,
OnGestureListener listener) {
final int sdkVersion = Build.VERSION.SDK_INT;
GestureDetector detector;
if (sdkVersion < Build.VERSION_CODES.ECLAIR) {
detector = new CupcakeGestureDetector(context);
} else if (sdkVersion < Build.VERSION_CODES.FROYO) {
detector = new EclairGestureDetector(context);
} else {
detector = new FroyoGestureDetector(context);
}
detector.setOnGestureListener(listener);
return detector;
}
}
\ No newline at end of file
package com.yidianling.consultant.preview;
/**
* Deprecated: 图片加载管理器
*
* @author rainb
*/
public class ZoomMediaLoader {
private volatile IZoomMediaLoader loader;
public static ZoomMediaLoader getInstance() {
return Holder.holder;
}
private ZoomMediaLoader() {
}
private static class Holder {
static ZoomMediaLoader holder = new ZoomMediaLoader();
}
/****
* 初始化加载图片类
* @param loader 自定义
* **/
public void init(IZoomMediaLoader loader) {
this.loader = loader;
}
public IZoomMediaLoader getLoader() {
if (loader == null) {
throw new NullPointerException("ZoomMediaLoader loader no init");
}
return loader;
}
}
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="MissingDefaultResource">
<corners android:radius="@dimen/platform_dp_23" />
<gradient
android:endColor="#48CC95"
android:startColor="#61CEAC" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="MissingDefaultResource">
<corners android:radius="@dimen/platform_dp_23" />
<gradient
android:endColor="#4BAFEC"
android:startColor="#65C4FF" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:shape="oval"
tools:ignore="MissingDefaultResource">
<solid android:color="#FF6565" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="@dimen/platform_dp_8"/>
<solid android:color="#40000000"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="MissingDefaultResource">
<corners android:radius="@dimen/platform_dp_19" />
<solid android:color="#80000000"></solid>
<stroke
android:width="0.5px"
android:color="#40FFFFFF" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<selector>
<item android:state_pressed="true">
<shape>
<corners android:radius="4dp" />
<solid android:color="#59FFFFFF" />
<stroke android:width="1dp" android:color="@color/transparent"/>
</shape>
</item>
<item>
<shape>
<corners android:radius="4dp" />
<solid android:color="#59FFFFFF" />
<stroke android:width="5dp" android:color="@color/transparent"/>
</shape>
</item>
</selector>
</item>
<item android:id="@android:id/secondaryProgress">
<clip>
<shape>
<corners android:radius="4dp" />
<solid android:color="@color/white" />
</shape>
</clip>
</item>
<item android:id="@android:id/progress">
<selector>
<item android:state_pressed="true">
<clip>
<shape>
<corners android:radius="4dp" />
<solid android:color="@color/white" />
<stroke android:width="1dp" android:color="@color/transparent"/>
</shape>
</clip>
</item>
<item>
<clip>
<shape>
<corners android:radius="4dp" />
<solid android:color="@color/white" />
<stroke android:width="5dp" android:color="@color/transparent"/>
</shape>
</clip>
</item>
</selector>
</item>
</layer-list>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="@color/white" />
<size android:width="6dp" android:height="8dp" />
<corners android:radius="2dp" />
</shape>
</item>
<item android:state_pressed="false">
<shape android:shape="oval">
<solid android:color="@color/white" />
<size android:width="8dp" android:height="8dp" />
<stroke android:width="2dp" android:color="@color/transparent" />
</shape>
</item>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent">
<com.yidianling.consultant.preview.PhotoViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent" />
<RelativeLayout
android:id="@+id/btnLL"
android:layout_width="match_parent"
android:layout_height="@dimen/platform_dp_60"
android:layout_alignParentBottom="true"
android:layout_marginBottom="@dimen/platform_dp_40">
<TextView
android:id="@+id/chatBtn"
android:layout_width="148dp"
android:layout_height="47dp"
android:layout_alignParentBottom="true"
android:layout_marginLeft="@dimen/platform_dp_20"
android:background="@drawable/consultant_bg_btn_chat"
android:gravity="center"
android:text="立即私聊"
android:textColor="@color/white"
android:textSize="17sp"
android:textStyle="bold" />
<TextView
android:id="@+id/bookingBtn"
android:layout_width="148dp"
android:layout_height="47dp"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_marginRight="@dimen/platform_dp_20"
android:background="@drawable/consultant_bg_btn_book"
android:gravity="center"
android:text="立即预约"
android:textColor="@color/white"
android:textSize="17sp"
android:textStyle="bold" />
<RelativeLayout
android:id="@+id/un_read_num_ll"
android:layout_width="@dimen/platform_dp_17"
android:layout_height="@dimen/platform_dp_17"
android:layout_alignTop="@+id/chatBtn"
android:layout_alignRight="@+id/chatBtn"
android:layout_marginTop="-10dp"
android:layout_marginRight="@dimen/platform_dp_10"
android:visibility="gone"
android:background="@drawable/consultant_bg_chat_unread_num">
<TextView
android:id="@+id/un_read_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textColor="@color/white"
android:textSize="@dimen/sp_12" />
</RelativeLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/titleBar"
android:layout_width="match_parent"
android:layout_height="@dimen/platform_dp_32"
android:layout_marginTop="@dimen/platform_dp_32">
<ImageView
android:id="@+id/ivBack"
android:layout_width="@dimen/platform_dp_28"
android:layout_height="@dimen/platform_dp_28"
android:layout_centerVertical="true"
android:layout_marginLeft="12dp"
android:src="@drawable/consultant_back"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="@dimen/platform_dp_24"
android:layout_centerInParent="true"
android:background="@drawable/consultant_bg_preview_photo_num"
android:gravity="center"
android:paddingLeft="@dimen/platform_dp_10"
android:paddingRight="@dimen/platform_dp_10">
<TextView
android:id="@+id/select_position"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="@dimen/platform_sp_14" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/platform_dp_1"
android:text="/"
android:textColor="@color/white"
android:textSize="@dimen/platform_sp_14" />
<TextView
android:id="@+id/total"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/platform_dp_1"
android:textColor="@color/white"
android:textSize="@dimen/platform_sp_14" />
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/iv"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:clickable="false"
android:contentDescription="@null"
android:focusable="false"
android:scaleType="centerCrop"/>
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
<GridView
android:id="@+id/grid_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="2"
android:layout_marginLeft="@dimen/platform_dp_10"
android:layout_marginRight="@dimen/platform_dp_10"
android:horizontalSpacing="@dimen/platform_dp_10"
android:verticalSpacing="@dimen/platform_dp_10"/>
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rootView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
tools:ignore="ResourceName">
<com.yidianling.consultant.preview.SmoothImageView
android:id="@+id/photoView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
android:scaleType="centerInside" />
<RelativeLayout
android:id="@+id/videoContainer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.dou361.ijkplayer.widget.IjkVideoView
android:id="@+id/videoView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:focusableInTouchMode="true" />
<ImageView
android:id="@+id/ivImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"/>
<ImageView
android:id="@+id/ivPlay"
android:layout_width="76dp"
android:layout_height="76dp"
android:layout_centerInParent="true"
android:src="@drawable/ic_video_play"
android:visibility="gone" />
</RelativeLayout>
<SeekBar
android:id="@+id/seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="120dp"
android:maxHeight="10dp"
android:paddingStart="0dp"
android:paddingTop="8dp"
android:paddingEnd="0dp"
android:paddingBottom="8dp"
android:progressDrawable="@drawable/consultant_seekbar_style"
android:splitTrack="false"
android:thumb="@drawable/consultant_seekbar_thumb"
android:visibility="gone"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<LinearLayout
android:id="@+id/loading"
android:layout_width="103dp"
android:layout_height="103dp"
android:layout_centerInParent="true"
android:background="@drawable/consultant_bg_loading"
android:gravity="center"
android:orientation="vertical">
<ProgressBar
style="?android:attr/progressBarStyleSmall"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/platform_dp_10"
android:text="正在加载"
android:textColor="@color/white" />
</LinearLayout>
<ImageView
android:id="@+id/btnVideo"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_centerInParent="true"
android:alpha="0"
android:visibility="gone" />
</RelativeLayout>
\ No newline at end of file
......@@ -8,4 +8,7 @@
<string name="consultant_reload_hint">加载失败,换个网络环境试试吧</string>
<item name="consultant_item_image_key" type="id" />
</resources>
<resources>
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="consultant_FilterTextViewStyle">
<item name="android:layout_height">40dp</item>
......@@ -38,9 +38,7 @@
<item name="android:backgroundDimEnabled">true</item>
</style>
<style name="consultant_Transparent" parent="@style/Base.Theme.AppCompat">
<item name="colorPrimary">@color/transparent</item>
<item name="colorPrimaryDark">@color/transparent</item>
<style name="consultant_Transparent" parent="Theme.AppCompat.DayNight.NoActionBar">
<item name="android:windowBackground">@color/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsTranslucent">true</item>
......
......@@ -45,6 +45,7 @@ import com.yidianling.tests.api.service.ITestsApiService
import com.yidianling.user.api.service.IUserService
import de.greenrobot.event.EventBus
import org.json.JSONObject
import java.net.URLDecoder
open class HomeBaseImpl : IHomeBaseEvent {
......@@ -539,11 +540,14 @@ open class HomeBaseImpl : IHomeBaseEvent {
return
}
ActionCountUtils.count(HomeBIConstants.YDL_USER_ARTICLE_CLICK, bean.id.toString())
ActionCountUtils.count(
HomeBIConstants.YDL_USER_ARTICLE_CLICK, bean.id.toString(),
bean.title ?: ""
)
YDLRouterManager.router(
IYDLRouterConstant.ROUTER_H5_H5,
YDLRouterParams().putExtra(IYDLRouterConstant.EXTRA_URL, bean.gethUrl()!!), ""
YDLRouterParams().putExtra(IYDLRouterConstant.EXTRA_URL, bean.listAllUrl!!), ""
)
}
......
......@@ -78,7 +78,7 @@ class HomeBaseHttp {
//首页文章请求
fun getArticleData(): Observable<BaseAPIResponse<HomeArticleBean>> {
articleListSize = if (YdlCommonOut.getApp().packageName == "com.cxzapp.xinlizixun") "6" else "4"
articleListSize = if (YdlCommonOut.getApp().packageName == "com.cxzapp.xinlizixun") "6" else "3"
return getHomePagerApi().getArticleData(perPageRows = articleListSize)
}
......
......@@ -96,10 +96,10 @@ interface HomeBasePagerApi {
@Headers(YDL_DOMAIN + YDL_DOMAIN_JAVA)
fun getFMData(@Query("perPageRows") perPageRows: String = "4"): Observable<BaseAPIResponse<HomeFMBean>>
//首页文章请求
@GET("article/list/all")
//首页文章请求 文章改版需求改为3条
@GET("newArticle/list/all")
@Headers(YDL_DOMAIN + YDL_DOMAIN_JAVA)
fun getArticleData(@Query("perPageRows") perPageRows: String = "4"): Observable<BaseAPIResponse<HomeArticleBean>>
fun getArticleData(@Query("perPageRows") perPageRows: String = "3"): Observable<BaseAPIResponse<HomeArticleBean>>
//首页问答 - 点赞
@FormUrlEncoded
......
......@@ -26,7 +26,7 @@ class HomeArticleBean : HomeItemBaseBean {
/**
* 收藏数
*/
var countOfFavorite: Int = 0
var countOfFavorite: String = "0"
var createTime: String? = null
var createTimeFormat: String? = null
/**
......@@ -55,7 +55,7 @@ class HomeArticleBean : HomeItemBaseBean {
/**
* 阅读次数
*/
var readNum: Int = 0
var readNum: String = "0"
/**
* 120*120小头像
*/
......@@ -72,5 +72,8 @@ class HomeArticleBean : HomeItemBaseBean {
fun sethUrl(hUrl: String) {
this.hUrl = hUrl
}
var listAllUrl:String?=null
}
}
......@@ -491,9 +491,7 @@ open class YdlHomeFragment : BaseMvpFragment<IHomeContract.View, HomePresenterIm
super.setUserVisibleHint(isVisibleToUser)
if (isVisibleToUser && isResumed) {
startTime=System.currentTimeMillis()
showConsultAssistantDialog()
} else {
hideConsultAssistantDialog()
if (startTime!=0L){
endTime=System.currentTimeMillis()
ActionCountUtils.count(HomeBIConstants.YDL_HOME_DWELL_TIME,(endTime-startTime).toString())
......@@ -506,11 +504,6 @@ open class YdlHomeFragment : BaseMvpFragment<IHomeContract.View, HomePresenterIm
}
}
private fun showConsultAssistantDialog() {
ModularServiceManager.provide(IConsultantService::class.java)
.showConsultAssistantDialog(mActivity)
}
private fun getBottomWord() {
ModularServiceManager.provide(IConsultantService::class.java)
.getbottomWord(2, object : OnBottomWordListener {
......@@ -558,7 +551,6 @@ open class YdlHomeFragment : BaseMvpFragment<IHomeContract.View, HomePresenterIm
}
ActionCountUtils.count(HomeBIConstants.YDL_USER_MAIN_PAGE_VISIT)
ActionCountUtils.count("daoyi_advertisement_page|daoyi_advertisement_visit","1")
showConsultAssistantDialog()
video_view?.setOnInfoListener { mp, what, extra ->
if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START){
......
......@@ -3,6 +3,7 @@ package com.yidianling.home.ui.view
import android.content.Context
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.widget.LinearLayout
import androidx.recyclerview.widget.RecyclerView
import com.ydl.ydl_image.manager.YDLImageCacheManager
......@@ -38,12 +39,12 @@ class HomeArticleItemView(private val mContext: Context, private var homeEvent:
homeModuleArticleItemViewTitle.text = bean?.title
homeModuleArticleItemViewContent.text = bean?.desc
homeModuleArticleItemViewAuthor.text = bean?.name
homeModuleArticleItemViewGreatNum.text = bean?.countOfFavorite.toString()
homeModuleArticleItemViewLookNum.text = bean?.readNum.toString()
homeModuleArticleItemViewGreatNum.text = "${bean?.countOfFavorite}点赞"
homeModuleArticleItemViewLookNum.text = "${bean?.readNum}浏览"
YDLImageCacheManager.showImage(mContext, bean?.imgUrl, homeModuleArticleItemViewImg)
YDLImageCacheManager.showImage(mContext, bean?.smallImage, homeModuleArticleItemViewIcon)
setOnClickListener {
homeEvent?.articleItemClick(bean)
}
}
......
......@@ -5,6 +5,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.recyclerview.widget.RecyclerView
import com.ydl.ydlcommon.utils.actionutil.ActionCountUtils
import com.yidianling.home.R
import com.yidianling.home.constract.HomeViewConfig
import com.yidianling.home.event.IHomeBaseEvent
......@@ -56,6 +57,8 @@ class HomeArticleView(private val mContext: Context, private var homeEvent: IHom
}
}
}
// 文章阅读新增埋点
ActionCountUtils.record("ydl_user_main_page", "ydl_user_article_visit")
}
}
......
......@@ -4,124 +4,128 @@
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:paddingLeft="@dimen/platform_dp_15"
android:paddingRight="@dimen/platform_dp_15"
android:paddingTop="@dimen/platform_dp_15">
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="4dp">
<androidx.cardview.widget.CardView
android:id="@+id/homeModuleArticleItemViewCardImg"
android:layout_width="@dimen/platform_dp_127"
android:layout_height="@dimen/platform_dp_88"
android:layout_width="88dp"
android:layout_height="70dp"
android:layout_alignParentRight="true"
app:cardCornerRadius="@dimen/platform_dp_6"
app:cardCornerRadius="8dp"
app:cardElevation="0dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:id="@+id/homeModuleArticleItemViewImg"
android:background="@drawable/home_image_default_back"/>
tools:src="@drawable/home_image_default_back"/>
</androidx.cardview.widget.CardView>
<TextView
android:id="@+id/homeModuleArticleItemViewTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxHeight="44dp"
android:maxLines="2"
android:ellipsize="end"
android:textSize="@dimen/platform_dp_18"
android:textSize="16sp"
android:textStyle="bold"
android:layout_marginTop="-2dp"
android:textColor="@color/platform_color_222222"
android:layout_alignParentTop="true"
android:textColor="#1C1F28"
android:lineSpacingExtra="@dimen/platform_dp_1"
tools:text="喧嚣的世界中,你的重要何以而来?喧嚣的世界中,你的重要何以而来?"
tools:text="喧嚣的世界中,你的重要何以而来?"
android:layout_alignParentLeft="true"
android:layout_alignTop="@id/homeModuleArticleItemViewCardImg"
android:layout_toLeftOf="@+id/homeModuleArticleItemViewCardImg"
android:layout_marginRight="@dimen/platform_dp_20"/>
android:layout_marginRight="18dp"/>
<TextView
android:id="@+id/homeModuleArticleItemViewContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
android:layout_height="18dp"
android:layout_marginTop="8dp"
android:maxLines="1"
android:gravity="center_vertical"
android:ellipsize="end"
android:textSize="@dimen/platform_dp_13"
android:layout_marginTop="@dimen/platform_dp_4"
android:textColor="@color/platform_color_666666"
android:textColor="#9D9EA7"
android:layout_alignParentLeft="true"
android:layout_below="@+id/homeModuleArticleItemViewTitle"
android:lineSpacingExtra="@dimen/platform_dp_3"
tools:text="喧嚣的世界中,你的重要何以而来?当我伫立在我所伫立之处..."
android:layout_toLeftOf="@+id/homeModuleArticleItemViewCardImg"
android:layout_marginRight="@dimen/platform_dp_20"/>
android:layout_below="@id/homeModuleArticleItemViewTitle"
android:layout_marginRight="18dp"/>
<LinearLayout
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/homeModuleArticleItemViewBottomLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:layout_below="@+id/homeModuleArticleItemViewCardImg"
android:layout_marginTop="@dimen/platform_dp_16">
android:layout_marginTop="17dp">
<ImageView
android:id="@+id/homeModuleArticleItemViewIcon"
android:layout_width="@dimen/platform_dp_12"
android:layout_height="@dimen/platform_dp_12"
android:src="@drawable/home_article_item_icon"
android:layout_alignParentLeft="true"/>
<androidx.cardview.widget.CardView
android:id="@+id/card_view_avatar"
android:layout_width="16dp"
android:layout_height="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:cardElevation="0dp"
app:cardCornerRadius="8dp">
<TextView
android:id="@+id/homeModuleArticleItemViewAuthor"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:textSize="@dimen/platform_dp_12"
android:textColor="@color/platform_color_242424"
android:layout_marginLeft="@dimen/platform_dp_3"
android:textStyle="bold"
tools:text="赵秀英"/>
<ImageView
android:id="@+id/homeModuleArticleItemViewIcon"
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/home_article_item_icon"/>
<TextView
android:id="@+id/homeModuleArticleItemViewGreatNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="3327"
android:textSize="@dimen/platform_dp_12"
android:textColor="@color/platform_color_242424"/>
</androidx.cardview.widget.CardView>
<TextView
android:id="@+id/homeModuleArticleItemViewAuthor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点赞"
android:textSize="@dimen/platform_dp_11"
android:layout_marginRight="@dimen/platform_dp_12"
android:textColor="@color/platform_color_666666"/>
android:textSize="13sp"
android:textColor="#62636F"
android:layout_marginLeft="5dp"
app:layout_constraintStart_toEndOf="@id/card_view_avatar"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:text="赵秀英"/>
<TextView
android:id="@+id/homeModuleArticleItemViewLookNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="2656"
android:textSize="@dimen/platform_dp_12"
android:textColor="@color/platform_color_242424"/>
android:layout_marginEnd="70dp"
tools:text="2656浏览"
android:textSize="13sp"
android:textColor="#62636F"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<TextView
android:id="@+id/homeModuleArticleItemViewGreatNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="浏览"
android:textSize="@dimen/platform_dp_11"
android:textColor="@color/platform_color_666666"/>
tools:text="3327点赞"
android:textSize="13sp"
android:textColor="#62636F"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<View
android:id="@+id/homeModuleArticleItemViewBottomLine"
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/platform_color_EBEBEB"
android:background="#EFEFF1"
android:layout_centerInParent="true"
android:layout_below="@+id/homeModuleArticleItemViewBottomLayout"
android:layout_marginTop="@dimen/platform_dp_16"/>
android:layout_marginTop="20dp"
android:layout_marginBottom="30dp"/>
</RelativeLayout>
......@@ -121,7 +121,7 @@
android:layout_height="wrap_content"
android:textSize="@dimen/platform_sp_12"
android:textColor="#69696A"
android:text="倾诉人次"
android:text="服务人次"
/>
</LinearLayout>
<LinearLayout
......
......@@ -43,6 +43,7 @@ import com.yidianling.im.ui.page.NewMultiMessageFragment
import com.yidianling.nimbase.common.media.picker.PickImageHelper
import com.yidianling.uikit.api.NimUIKit
import com.yidianling.uikit.business.session.helper.MessageListPanelHelper
import com.yidianling.uikit.custom.widget.expertConsultService.view.ExpertConsultServiceListDialog2
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
......@@ -53,6 +54,8 @@ import io.reactivex.schedulers.Schedulers
@Route(path = "/im/ImService")
class IMServiceImpl : IImService {
private var expertConsultServiceListDialog2: ExpertConsultServiceListDialog2 ?= null
override fun isHasUnread(): Boolean {
return MsgReceiveHelper.isHasUnread
}
......@@ -411,4 +414,21 @@ class IMServiceImpl : IImService {
override fun isWifiOr3G(activity: Activity): Boolean {
return NetworkUtil.isWifiOr3G(activity)
}
override fun showConsultServiceDialog(activity: Activity, toUid: String, doctorId: String) {
// 获取专家是否在繁忙状态
if (activity != null) {
expertConsultServiceListDialog2 =
ExpertConsultServiceListDialog2(
activity, null, false, toUid,
doctorId
)
expertConsultServiceListDialog2?.show()
}
}
override fun dismissConsultServiceDialog() {
expertConsultServiceListDialog2?.changeItem()
}
}
\ No newline at end of file
......@@ -98,12 +98,14 @@ import com.yidianling.uikit.custom.bridge.IP2PCustomActionHandler;
import com.yidianling.uikit.custom.http.ServiceImpl;
import com.yidianling.uikit.custom.http.response.CommonQuestionBean;
import com.yidianling.uikit.custom.http.response.NewUserMesBean;
import com.yidianling.uikit.custom.http.response.ServiceItemBean;
import com.yidianling.uikit.custom.http.response.UserQuestInfoBean;
import com.yidianling.uikit.custom.widget.ConfideOrderInfoView;
import com.yidianling.uikit.custom.widget.ExpertInfoDialog;
import com.yidianling.uikit.custom.widget.TitleBarBottom;
import com.yidianling.uikit.custom.widget.UserInfoDialog;
import com.yidianling.uikit.custom.widget.expertConsultService.view.ExpertConsultServiceListDialog;
import com.yidianling.uikit.custom.widget.expertConsultService.view.ExpertConsultServiceListDialog2;
import com.yidianling.user.api.service.IUserService;
import org.jetbrains.annotations.NotNull;
......@@ -154,6 +156,10 @@ public class YDLMessageFragment extends TFragment implements ModuleProxy {
private RelativeLayout rl_contain;
private boolean initHeightFinish;
public TitleBarBottom titleBar;
private List<ServiceItemBean> serviceItemBeanList;
public InputPanel getInputPanel() {
return inputPanel;
}
......@@ -208,6 +214,7 @@ public class YDLMessageFragment extends TFragment implements ModuleProxy {
private ExpertInfoDialog expertInfoDialog;
private ExpertConsultServiceListDialog expertConsultServiceListDialog;
private ExpertConsultServiceListDialog2 expertConsultServiceListDialog2;
private int IN_OUT_DURATION = 400;
......@@ -929,27 +936,27 @@ public class YDLMessageFragment extends TFragment implements ModuleProxy {
@SuppressLint("CheckResult")
private void initMenu() {
rela_zixun.setOnClickListener(view -> {
if (Utils.isFastClick()) {
//防止连击
return;
}
if (sessionId != null && ActionHandlerStorage.getL(sessionId) != null && ActionHandlerStorage.getL(sessionId).getInfo() != null) {
if (expertConsultServiceListDialog == null) {
ServiceImpl.Companion.getInstance().serviceList(ActionHandlerStorage.getL(sessionId).getInfo().doctorId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(res -> {
if (res.data != null && res.data.size() > 0) {
if (getActivity() != null && expertConsultServiceListDialog == null) {
expertConsultServiceListDialog = new ExpertConsultServiceListDialog(getActivity(), res.data,isBusy,sessionId,
ActionHandlerStorage.getL(sessionId).getInfo().doctorId
);
expertConsultServiceListDialog.show();
if (serviceItemBeanList == null || serviceItemBeanList.size() == 0) {
ServiceImpl.Companion.getInstance().serviceList(ActionHandlerStorage.getL(sessionId).getInfo().doctorId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(res -> {
if (res.data != null && res.data.size() > 0) {
serviceItemBeanList = res.data;
showConsultService(res.data,isBusy,sessionId, ActionHandlerStorage.getL(sessionId).getInfo().doctorId);
} else {
ToastUtil.toastShort("咨询师暂未发布服务");
}
} else {
ToastUtil.toastShort("咨询师暂未发布服务");
}
}, throwable -> {
});
} else {
expertConsultServiceListDialog.show();
}
}, throwable -> {
});
} else {
showConsultService(serviceItemBeanList, isBusy, sessionId, ActionHandlerStorage.getL(sessionId).getInfo().doctorId);
}
} else {
ToastUtil.toastShort("请退出聊天重试");
}
......@@ -1093,6 +1100,10 @@ public class YDLMessageFragment extends TFragment implements ModuleProxy {
comment_banner_view.onDestory();
EventBus.getDefault().unregister(this);
super.onDestroy();
if (serviceItemBeanList != null) {
serviceItemBeanList.clear();
serviceItemBeanList = null;
}
messageListPanel.onDestroy();
registerObservers(false);
if (inputPanel != null) {
......@@ -1175,7 +1186,7 @@ public class YDLMessageFragment extends TFragment implements ModuleProxy {
}
}
public void onEvent(CloseBottomWebviewEvent event){
expertConsultServiceListDialog.changeItem();
expertConsultServiceListDialog2.changeItem();
}
private void updateLocalMsg(Integer position,ArrayList<String> selectedPosition) {
IMMessage message=ImIn.INSTANCE.getImMessage();
......@@ -1604,4 +1615,15 @@ public class YDLMessageFragment extends TFragment implements ModuleProxy {
ActionCountUtils.Companion.count("under_age_alert_page|under_age_alert_page_visit");
}
private void showConsultService(List<ServiceItemBean> list, Boolean mIsBusy,
String toUid, String doctorID) {
if (getActivity() != null) {
expertConsultServiceListDialog2 = new ExpertConsultServiceListDialog2(getActivity(), list, isBusy, sessionId,
ActionHandlerStorage.getL(sessionId).getInfo().doctorId);
expertConsultServiceListDialog2.show();
}
}
}
......@@ -17,6 +17,7 @@ import com.yidianling.uikit.custom.http.response.ServiceItemBean
import com.yidianling.uikit.custom.widget.expertConsultService.callback.ConsultServiceViewCallback
import com.yidianling.user.api.service.IUserService
import kotlinx.android.synthetic.main.im_expert_consult_service_item_view.view.*
import java.text.DecimalFormat
/**
* 咨询服务, 预约item
......@@ -55,20 +56,36 @@ class ExpertConsultServiceItemView : LinearLayout {
View.inflate(mContext, R.layout.im_expert_consult_service_item_view, this)
}
fun updateBusyStatus(isBusy: Boolean) {
mIsBusy = isBusy
if (mIsBusy) {
im_expert_service_list_btn.visibility = View.GONE
tv_add.visibility = View.VISIBLE
tv_add.setOnClickListener {
mListener?.addTime()
}
} else {
im_expert_service_list_btn.visibility = View.VISIBLE
tv_add.visibility = View.GONE
}
}
/**
* 设置数据
*/
@SuppressLint("SetTextI18n")
fun setData(bean: ServiceItemBean.ProductsBean) {
if (mIsBusy) { // 是否繁忙 true繁忙
ll_not_busy.visibility = View.GONE
ll_busy.visibility = View.VISIBLE
im_expert_service_list_btn.visibility = View.GONE
tv_add.visibility = View.VISIBLE
tv_add.setOnClickListener {
mListener?.addTime()
}
} else {
ll_not_busy.visibility = View.VISIBLE
ll_busy.visibility = View.GONE
im_expert_service_list_btn.visibility = View.VISIBLE
tv_add.visibility = View.GONE
}
//是否是套餐
if (bean.productDto.isPackage == 2) {
......@@ -87,6 +104,7 @@ class ExpertConsultServiceItemView : LinearLayout {
//隐藏起售次数限制
service_item_low_buy_time.visibility = View.GONE
}
val mCompare: Comparator<ServiceItemBean.ProductsBean.ProductSpecDtosBean> =
Comparator { o1, o2 ->
val res = o1.price.compareTo(o2.price)
......@@ -100,10 +118,13 @@ class ExpertConsultServiceItemView : LinearLayout {
val mBean: ServiceItemBean.ProductsBean.ProductSpecDtosBean =
bean.productSpecDtos.sortedWith(mCompare).last()
//价格,取productSpecDtos数组最小价格,不保留小数
service_item_price.text = String.format(
"%.0f",
mBean.price
)
// service_item_price.text = String.format(
// "%.0f",
// mBean.price
// )
val decimalFormat = DecimalFormat("###.##")
service_item_price.text = decimalFormat.format(mBean.price)
service_item_price.paint.isFakeBoldText = true
//时间,取productSpecDtos数组最后一个的时间
// service_item_time.text = "/${bean.productDto.minOrderTime}分钟"
......@@ -129,13 +150,20 @@ class ExpertConsultServiceItemView : LinearLayout {
//销量
service_item_saleout_num.text = "销量${bean.productDto.saleAmount}"
// service_item_saleout_num.text = "销量${bean.productDto.saleAmount}"
service_item_saleout_num.text = "${bean.productDto.saleAmount}"
setOnClickListener {
mListener?.onItemClick(bean)
}
im_expert_service_list_btn.setOnClickListener {
mContext?.let {context ->
if (!ImIn.loginByOneKeyLogin(context, true)) {
return@setOnClickListener
}
}
if (ImIn.getUserService().isBindPhone()) {
NewH5Activity.start(
mContext,
......@@ -144,7 +172,7 @@ class ExpertConsultServiceItemView : LinearLayout {
null
)
)
}else{
} else {
//新增需求,如果没有绑定手机号,跳转到绑定手机号页面
bindPhoneDialog()
}
......
package com.yidianling.uikit.custom.widget.expertConsultService.view
import android.annotation.SuppressLint
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.view.*
import android.widget.FrameLayout
import androidx.fragment.app.FragmentActivity
import androidx.viewpager.widget.PagerAdapter
import com.alibaba.android.arouter.launcher.ARouter
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.netease.nimlib.sdk.NIMClient
import com.netease.nimlib.sdk.RequestCallback
import com.netease.nimlib.sdk.msg.MessageBuilder
import com.netease.nimlib.sdk.msg.MsgService
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum
import com.ydl.ydlcommon.data.http.BaseAPIResponse
import com.ydl.ydlcommon.utils.actionutil.ActionCountUtils
import com.yidianling.common.tools.RxDeviceTool
import com.yidianling.common.tools.RxImageTool
import com.yidianling.common.tools.ToastUtil
import com.yidianling.im.R
import com.yidianling.im.api.service.IImService
import com.yidianling.im.bean.BusyBean
import com.yidianling.im.router.ImIn
import com.yidianling.im.session.extension.CustomAttachSubScriptTime
import com.yidianling.uikit.business.session.helper.MessageListPanelHelper
import com.yidianling.uikit.custom.bridge.ActionHandlerStorage
import com.yidianling.uikit.custom.http.ServiceImpl
import com.yidianling.uikit.custom.http.ServiceImpl.Companion.instance
import com.yidianling.uikit.custom.http.response.ServiceItemBean
import com.yidianling.uikit.custom.widget.expertConsultService.callback.ConsultServiceViewCallback
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.Consumer
import io.reactivex.schedulers.Schedulers
import kotlinx.android.synthetic.main.im_expert_consult_service_list_dialog_layout.dialog_bottom_scroll_view
import kotlinx.android.synthetic.main.im_expert_consult_service_list_fragment_layout.*
class ExpertConsultServiceListDialog2(
val mContext: Context, val mList: List<ServiceItemBean>?, val mIsBusy: Boolean,
val toUid: String, val doctorID: String
) : BottomSheetDialogFragment() {
private var mConsultServiceListView: ExpertConsultServiceView? = null
private var mWebviewView: ExpertConsultWebview? = null
private var mViewList: ArrayList<View> = ArrayList()
private var mSelectType: String = "全部"
var bottomSheet: FrameLayout? = null
private var behavior: BottomSheetBehavior<*>? = null
fun changeItem() {
dialog_bottom_scroll_view.currentItem = 0
}
@SuppressLint("WrongConstant")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NORMAL, R.style.AppBottomSheet)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(
R.layout.im_expert_consult_service_list_fragment_layout,
container,
false
)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
var typeList: ArrayList<String> = ArrayList()
typeList.add(mSelectType)//默认选中
if (mList != null) {
dialog_ll_empty.visibility=View.GONE
mList.forEach { item ->
typeList.add(item.cateName)
}
onViewCreate(typeList, mList)
} else {
ServiceImpl.instance.serviceList(doctorID)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(Consumer<BaseAPIResponse<List<ServiceItemBean>>> { res: BaseAPIResponse<List<ServiceItemBean>> ->
if (res.data != null && res.data.size > 0) {
dialog_ll_empty.visibility=View.GONE
var serviceItemBeanList = res.data
serviceItemBeanList.forEach { item ->
typeList.add(item.cateName)
}
onViewCreate(typeList, serviceItemBeanList)
// 获取专家是否在繁忙状态
instance.queryDoctorIsBusy(doctorID)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ res: BaseAPIResponse<BusyBean> ->
var isBusy = res.data.success
mConsultServiceListView?.setBusyStatus(isBusy)
}
) { throwable: Throwable? -> }
} else {
dialog_ll_empty.visibility=View.VISIBLE
}
}, Consumer { throwable: Throwable? -> })
}
}
private fun onViewCreate(typeList: ArrayList<String>, mList: List<ServiceItemBean>) {
mConsultServiceListView = ExpertConsultServiceView(mContext, mIsBusy)
(mConsultServiceListView as ExpertConsultServiceView).setDataAndClick(
typeList,
mList,
object :
ConsultServiceViewCallback {
override fun onCloseClick() {
dismiss()
}
override fun onItemClick(serviceBean: ServiceItemBean.ProductsBean) {
mWebviewView?.setData(serviceBean)
dialog_bottom_scroll_view.currentItem = 1
}
override fun addTime() { // 提醒添加时间回调
if (!ImIn.isLogin(requireActivity(),true)){
return
}
// 埋点
if (ActionHandlerStorage.getL(toUid) != null){
ActionCountUtils.baiDuCountSign3(
"ydl_user_product_page", "remind_add_click", toUid,
ActionHandlerStorage.getL(toUid).info.name, ""
)
}
// 发送提醒消息
val customTime = CustomAttachSubScriptTime("请尽快添加可预约时间")
val message = MessageBuilder.createCustomMessage(
toUid,
SessionTypeEnum.P2P,
"请尽快添加可预约时间",
customTime
)
NIMClient.getService(MsgService::class.java).sendMessage(message, false)
.setCallback(object :
RequestCallback<Void> {
override fun onSuccess(param: Void?) {
MessageListPanelHelper.getInstance().notifyAddMessage(message)
ARouter.getInstance().navigation(IImService::class.java)
?.startChatBySessionId(requireActivity(), toUid!!)
dismiss()
}
override fun onException(exception: Throwable?) {
dismiss()
}
override fun onFailed(code: Int) {
dismiss()
}
})
}
})
consult_service_dialog_close.setOnTouchListener { v, event ->
when (event.action) {
MotionEvent.ACTION_DOWN -> {
behavior?.isHideable = true
}
}
true
}
mViewList.add(mConsultServiceListView as View)
mWebviewView = ExpertConsultWebview(mContext, doctorID = doctorID)
mViewList.add(mWebviewView as View)
dialog_bottom_scroll_view.adapter = ConsultServicePagerAdapter()
dialog_bottom_scroll_view.currentItem = 0
}
override fun setCancelable(cancelable: Boolean) {
val dialog = dialog
val touchOutsideView =
dialog?.window?.decorView?.findViewById<View>(com.google.android.material.R.id.touch_outside)
val bottomSheetView =
dialog?.window?.decorView?.findViewById<View>(com.google.android.material.R.id.design_bottom_sheet)
if (cancelable) {
touchOutsideView?.setOnClickListener(View.OnClickListener {
if (dialog.isShowing) {
dialog.cancel()
}
})
BottomSheetBehavior.from<View>(bottomSheetView!!).setHideable(true)
} else {
touchOutsideView?.setOnClickListener(null)
// if false 按返回键也无法取消
// dialog.setCancelable(false)
BottomSheetBehavior.from<View>(bottomSheetView!!).setHideable(false)
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog
dialog.setOnShowListener {
val layoutParams = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT
).apply { gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL }
bottomSheet =
(it as BottomSheetDialog).findViewById<View>(com.google.android.material.R.id.design_bottom_sheet) as FrameLayout?
behavior = BottomSheetBehavior.from(bottomSheet!!)
behavior?.peekHeight = RxDeviceTool.getScreenHeight(mContext) - RxImageTool.dp2px(100f)
behavior?.isHideable = false
setMaxHeight(RxDeviceTool.getScreenHeight(mContext) - RxImageTool.dp2px(100f))
//true是跳过peekHeight,直接滑下去,false是可以滑动到顶部还可以保持peekHeight在滑下去
// behavior?.skipCollapsed=true
behavior?.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
when (newState) {
BottomSheetBehavior.STATE_EXPANDED -> {
behavior?.state = BottomSheetBehavior.STATE_COLLAPSED
behavior?.isHideable = false
}
BottomSheetBehavior.STATE_DRAGGING -> {
}
BottomSheetBehavior.STATE_COLLAPSED -> {
behavior?.isHideable = false
}
}
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {}
})
}
return dialog
}
private fun setMaxHeight(height: Int) {
bottomSheet?.layoutParams?.height = height
bottomSheet?.requestLayout()
}
internal inner class ConsultServicePagerAdapter : PagerAdapter() {
override fun getCount(): Int {
return mViewList.size
}
override fun isViewFromObject(view: View, `object`: Any): Boolean {
return view === `object`
}
override fun instantiateItem(container: ViewGroup, position: Int): Any {
val view = mViewList[position]
container.addView(view)
return view
}
override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
container.removeView(`object` as View)
}
}
fun show() {
if (mContext is FragmentActivity) {
show(mContext.supportFragmentManager, "consult_bottom_showdialog")
}
}
}
\ No newline at end of file
......@@ -4,7 +4,6 @@ import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.LinearLayout
import com.yidianling.avchatkit.common.log.LogUtil
import com.yidianling.common.tools.RxDeviceTool
import com.yidianling.im.R
import com.yidianling.uikit.custom.http.response.ServiceItemBean
......@@ -53,7 +52,6 @@ class ExpertConsultServiceView : LinearLayout {
private fun initView() {
val mWidth: Int = RxDeviceTool.getScreenWidth(mContext)
val mHeight: Int = LayoutParams.MATCH_PARENT
......@@ -68,6 +66,15 @@ class ExpertConsultServiceView : LinearLayout {
View.inflate(mContext, R.layout.im_expert_consult_service_view, this)
}
fun setBusyStatus(isBusy: Boolean){
this.mIsBusy = isBusy
for(i in 0 until expert_consult_service_service_list.childCount){
val view = expert_consult_service_service_list.getChildAt(i)
if (view is ExpertConsultServiceItemView) {
view.updateBusyStatus(mIsBusy)
}
}
}
/**
* typeList 类型列表
* serviceList 服务列表
......@@ -78,9 +85,9 @@ class ExpertConsultServiceView : LinearLayout {
listener: ConsultServiceViewCallback?
) {
mListener = listener
consult_service_dialog_close.setOnClickListener {
mListener?.onCloseClick()
}
// consult_service_dialog_close.setOnClickListener {
// mListener?.onCloseClick()
// }
// 设置顶部滚动类型数据
if (typeList == null || typeList.size == 0) {
......@@ -101,7 +108,7 @@ class ExpertConsultServiceView : LinearLayout {
}
}
}
tv_title.paint.isFakeBoldText = true
typeSelectedIndex = 0 // 初始化为全部选中
mServiceList.clear()
mServiceList.addAll(allServiceList)
......
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#D7D7D7"/>
<corners android:radius="2dp"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:topLeftRadius="15dp"
android:topRightRadius="15dp" />
<solid android:color="#ffffff"/>
<solid android:color="@color/white"/>
</shape>
\ No newline at end of file
......@@ -2,7 +2,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="14dp" />
<corners android:radius="@dimen/platform_dp_18" />
<gradient android:startColor="#FF7A5C"
android:endColor="#FF406C"/>
......
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="@dimen/platform_dp_18" />
<solid android:color="#1DA1F2"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal">
android:layout_width="match_parent"
android:layout_height="112dp">
<LinearLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_marginLeft="18dp"
android:orientation="vertical"
android:paddingTop="10dp"
android:paddingBottom="18dp">
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TextView
android:id="@+id/service_item_title"
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="18dp"
android:layout_weight="1"
android:orientation="vertical"
android:paddingTop="@dimen/platform_dp_19"
android:paddingBottom="18dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text=" 调节孕期情绪烦躁,建立积极心态面对新生活"
android:textColor="#1A1A1A"
android:textSize="16dp"
android:textStyle="bold" />
<TextView
android:id="@+id/service_item_package"
android:layout_width="24dp"
android:layout_height="14dp"
android:gravity="center"
android:text="套餐"
android:visibility="gone"
android:layout_marginTop="3dp"
android:textColor="#ffffff"
android:textSize="10dp"
android:background="@drawable/im_service_package_bg"/>
</RelativeLayout>
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/service_item_title"
android:layout_width="match_parent"
android:layout_height="@dimen/platform_dp_48"
android:textColor="#1C1F28"
android:textFontWeight="500"
android:textSize="17sp"
android:textStyle="normal"
tools:text=" 调节孕期情绪烦躁,建立积极心态面对新生活" />
<TextView
android:id="@+id/service_item_package"
android:layout_width="24dp"
android:layout_height="14dp"
android:layout_marginTop="3dp"
android:background="@drawable/im_service_package_bg"
android:gravity="center"
android:text="套餐"
android:textColor="#ffffff"
android:textSize="10dp"
android:visibility="gone" />
</RelativeLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top"
android:layout_marginTop="@dimen/platform_dp_8"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="¥"
android:textColor="#FF5040"
android:textSize="12sp"
android:textStyle="bold"
android:gravity="bottom"
android:paddingBottom="4dp"
/>
android:layout_height="wrap_content"
android:text="咨询人数"
android:textColor="#9D9EA7"
android:textSize="@dimen/platform_sp_12" />
<TextView
android:id="@+id/service_item_price"
android:id="@+id/service_item_saleout_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:textColor="#FF5040"
android:textSize="18sp"
android:textStyle="bold"
android:layout_marginBottom="1dp"/>
android:layout_marginLeft="2dp"
android:text="9833"
android:textColor="#1A1A1A"
android:textSize="@dimen/platform_sp_12" />
<TextView
android:id="@+id/service_item_time"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="bottom"
android:layout_height="wrap_content"
android:text="/0分钟"
android:textColor="#999999"
android:textSize="12sp"
android:paddingBottom="4dp"
android:text="起"/>
</LinearLayout>
android:textSize="12dp"
android:visibility="gone" />
<TextView
android:id="@+id/service_item_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="/0分钟"
android:textColor="#999999"
android:visibility="gone"
android:textSize="12dp" />
<TextView
android:id="@+id/service_item_low_buy_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="(几次起售)"
android:visibility="gone"
android:textColor="#999999"
android:textSize="12dp" />
<TextView
android:id="@+id/tv_feedbackRate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="好评率"
android:layout_marginLeft="10dp"
android:textColor="#999999"
android:textSize="12dp" />
<TextView
android:id="@+id/tv_feedbackRate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="好评率"
android:textColor="#9D9EA7"
android:textSize="@dimen/platform_sp_12" />
<TextView
android:id="@+id/service_item_feddbackrate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0%"
android:layout_marginLeft="1dp"
android:textColor="#1A1A1A"
android:textSize="12dp" />
<TextView
android:id="@+id/service_item_feddbackrate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="2dp"
android:text="0%"
android:textColor="#1A1A1A"
android:textSize="@dimen/platform_sp_12" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/ll_not_busy"
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical|center"
android:paddingLeft="31dp"
android:paddingRight="18dp"
android:visibility="gone"
tools:visibility="visible"
android:orientation="vertical">
<TextView
android:id="@+id/im_expert_service_list_btn"
android:layout_width="68dp"
android:layout_height="27dp"
android:background="@drawable/im_expert_service_list_btn_bg"
android:gravity="center"
android:text="预约"
android:textColor="#ffffff"
android:textSize="14dp"
android:textStyle="bold" />
android:layout_height="match_parent">
<TextView
android:id="@+id/service_item_saleout_num"
<LinearLayout
android:id="@+id/ll_busy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="销量0"
android:textColor="#999999"
android:textSize="10dp" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_busy"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:paddingLeft="20dp"
android:paddingRight="18dp"
android:visibility="gone"
tools:visibility="visible">
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:paddingLeft="20dp"
android:paddingRight="18dp"
tools:visibility="visible">
<RelativeLayout
android:layout_width="74dp"
android:layout_height="@dimen/platform_dp_32">
<TextView
android:id="@+id/im_expert_service_list_btn"
android:layout_width="74dp"
android:layout_height="@dimen/platform_dp_32"
android:background="@drawable/im_expert_service_list_btn_bg"
android:gravity="center"
android:text="预约"
android:textColor="#ffffff"
android:textSize="14dp"
android:textStyle="bold" />
<LinearLayout
android:id="@+id/tv_add"
android:layout_width="74dp"
android:layout_height="@dimen/platform_dp_32"
android:background="@drawable/im_expert_service_list_busy_btn_bg"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="@dimen/platform_dp_2"
android:includeFontPadding="false"
android:text="已约满"
android:textColor="#ffffff"
android:textFontWeight="800"
android:textSize="@dimen/im_text_size_13"
android:textStyle="normal" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="@dimen/platform_dp_2"
android:includeFontPadding="false"
android:text="发送提醒"
android:textColor="#ffffff"
android:textSize="9sp" />
</LinearLayout>
</RelativeLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/platform_dp_14"
android:gravity="top"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="¥"
android:textFontWeight="800"
android:textColor="#EB892C"
android:textSize="12sp"
android:layout_marginBottom="1dp"/>
<TextView
android:id="@+id/service_item_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="bottom"
android:textStyle="normal"
android:textFontWeight="1500"
android:text="0"
android:textColor="#EB892C"
android:textSize="@dimen/im_text_size_18" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/platform_dp_3"
android:gravity="bottom"
android:layout_gravity="bottom"
android:text="起"
android:textColor="#9D9EA7"
android:layout_marginBottom="@dimen/platform_dp_1"
android:textSize="12sp" />
<TextView
android:id="@+id/service_item_low_buy_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#9D9EA7"
android:textSize="@dimen/sp_12"
android:visibility="gone"
android:layout_gravity="bottom"
android:layout_marginBottom="@dimen/platform_dp_1"
android:text="(8次起售)" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="预约时间已满" />
</LinearLayout>
<TextView
android:id="@+id/tv_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:drawableRight="@drawable/right_triangle"
android:padding="5dp"
android:text="提醒添加"
android:drawablePadding="2dp"
android:textColor="@color/platform_color_1DA1F2" />
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
</LinearLayout>
</LinearLayout>
\ No newline at end of file
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_alignParentBottom="true"
android:layout_marginLeft="@dimen/platform_dp_16"
android:layout_marginRight="@dimen/platform_dp_16"
android:background="@color/im_divide_color" />
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/im_expert_conslt_service_list_top_bg">
<LinearLayout
android:id="@+id/consult_service_dialog_close"
android:layout_width="match_parent"
android:layout_height="@dimen/platform_dp_29"
android:orientation="vertical">
<View
android:layout_width="@dimen/platform_dp_48"
android:layout_height="@dimen/platform_dp_5"
android:layout_marginTop="@dimen/platform_dp_12"
android:paddingLeft="@dimen/platform_dp_10"
android:paddingRight="@dimen/platform_dp_10"
android:background="@drawable/bg_consult_service_close"
android:layout_gravity="center" />
</LinearLayout>
<LinearLayout
android:id="@+id/dialog_ll_empty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/platform_dp_5"
android:gravity="center_horizontal"
android:orientation="vertical"
android:visibility="gone">
<TextView
android:id="@+id/empty_tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="选择服务主题"
android:textStyle="bold"
android:textColor="#1C1F28"
android:textSize="18sp" />
<TextView
android:id="@+id/dialog_empty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tv_title"
android:gravity="center_horizontal"
android:paddingTop="20dp"
android:text="暂未开通咨询服务"
android:textColor="@color/color_666666" />
</LinearLayout>
<com.ydl.ydlcommon.view.NoScrollViewPager
android:id="@+id/dialog_bottom_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"></com.ydl.ydlcommon.view.NoScrollViewPager>
</LinearLayout>
\ No newline at end of file
......@@ -6,22 +6,14 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="24dp"
>
<ImageView
android:id="@+id/consult_service_dialog_close"
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/im_expert_service_list_left_delete"
android:layout_marginLeft="14dp"
android:scaleType="centerCrop"
android:layout_centerVertical="true"/>
android:layout_marginTop="@dimen/platform_dp_5">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="咨询服务"
android:textColor="#242424"
android:textSize="18dp"
android:textStyle="bold"
android:text="选择服务主题"
android:textColor="#1C1F28"
android:textSize="18sp"
android:layout_centerInParent="true"/>
</RelativeLayout>
......@@ -29,7 +21,7 @@
android:id="@+id/expert_consult_service_top_scroll"
android:layout_width="match_parent"
android:layout_height="44dp"
android:layout_marginTop="6dp"
android:layout_marginTop="@dimen/platform_dp_10"
android:paddingLeft="15dp"
android:clipToPadding="false"
android:scrollbars="none">
......@@ -43,11 +35,6 @@
</LinearLayout>
</HorizontalScrollView>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="#EBEBEB"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
......
......@@ -138,5 +138,11 @@
<attr name="maxHeight" format="dimension" />
</declare-styleable>
<style name="AppBottomSheet" parent="Theme.Design.BottomSheetDialog">
<item name="bottomSheetStyle">@style/AppBottomSheetStyle</item>
</style>
<style name="AppBottomSheetStyle" parent="Widget.Design.BottomSheet.Modal">
<item name="backgroundTint">@android:color/transparent</item>
</style>
</resources>
......@@ -158,7 +158,6 @@ class MineFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, View.
endTime = System.currentTimeMillis()
count(UserMyPageEvent.YDL_USER_MY_PAGE_STAY_VISIT, (endTime - startTime).toString())
}
hideConsultAssistantDialog()
}
if (isVisibleToUser && isResumed) {
onResume()
......@@ -175,13 +174,6 @@ class MineFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, View.
private fun showConsultAssistantDialog() {
count("daoyi_advertisement_page|daoyi_advertisement_visit", "4")
mActivity?.let { provide(IConsultantService::class.java).showConsultAssistantMineDialog(it) }
}
private fun hideConsultAssistantDialog() {
provide(
IConsultantService::class.java
).hideConsultAssistantMineDialog()
}
/**
......
......@@ -39,8 +39,7 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
api(rootProject.ext.dependencies["" +
"ydl-ijkplayer-jjdxm"]) {
api(rootProject.ext.dependencies["ydl-ijkplayer-jjdxm"]) {
exclude group: 'com.android.support', module: 'appcompat-v7'
}
......
......@@ -258,18 +258,6 @@ class HttpConfig {
}else{
AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.API, "writeMaiDianDataError:$api---params:$params ---- message:$message")
}
}else{
var params = ""
if (request.method() == "GET") {
params = request.url().query().toString()
} else if (request.method() == "POST") {
params = RequestLogInterceptor.parseParams(request)
}
val message = originalResponse.message()
val api = request.url().encodedPath()
if (api.contains("maidian/writeMaiDianData")){
AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.API, "writeMaiDianDatacode$code:$api---params:$params ---- message:$message")
}
}
}
originalResponse
......
package com.ydl.view
import android.os.Bundle
import android.util.DisplayMetrics
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.fragment.app.DialogFragment
import com.blankj.utilcode.util.KeyboardUtils
import com.ydl.webview.R
import com.ydl.ydlcommon.utils.actionutil.ActionCountUtils
import com.ydl.ydlcommon.utils.remind.ToastHelper
class ArticleDialogFragment: DialogFragment() {
private lateinit var ivClose: ImageView
private lateinit var etComment: EditText
private lateinit var tvPublish: TextView
private lateinit var cslLayout:ConstraintLayout
private lateinit var mListener: OnPublishArticleCommentListener
private var mTitle:String = ""
fun setOnPublishListener(listener: OnPublishArticleCommentListener){
mListener = listener
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NO_TITLE, R.style.BottomDialogAnimation)
}
override fun onStart() {
super.onStart()
val displayMetrics = DisplayMetrics()
activity?.windowManager?.defaultDisplay?.getMetrics(displayMetrics)
val window = dialog?.window
window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.layout_comment_article,container)
initView(view)
return view
}
private fun initView(view: View){
mTitle = arguments?.getString(KEY_ARTICLE_TITLE)?:""
ivClose = view.findViewById(R.id.iv_close_dialog)
etComment = view.findViewById(R.id.et_article_comment)
tvPublish = view.findViewById(R.id.tv_publish_comment)
cslLayout = view.findViewById(R.id.csl_root_layout)
cslLayout.setOnClickListener {
ActionCountUtils.record("article_detail_page","article_detail_cancelcomment_click",mTitle)
dismiss()
}
KeyboardUtils.showSoftInput(etComment)
ivClose.setOnClickListener {
ActionCountUtils.record("article_detail_page","article_detail_cancelcomment_click",mTitle)
dismiss()
}
tvPublish.setOnClickListener {
if (etComment.text.toString().isNullOrBlank()){
ToastHelper.show("评论内容不能为空~")
return@setOnClickListener
}
mListener.onPublishClick(etComment.text.toString())
ActionCountUtils.record("article_detail_page","article_detail_issuecomment_click",mTitle)
etComment.setText("")
dismiss()
}
}
override fun dismiss() {
KeyboardUtils.hideSoftInput(etComment)
super.dismiss()
}
companion object {
private const val KEY_ARTICLE_TITLE = "key_share_title"
@JvmStatic
fun newInstance(title: String): ArticleDialogFragment {
val args = Bundle()
args.putString(KEY_ARTICLE_TITLE, title)
val fragment = ArticleDialogFragment()
fragment.arguments = args
return fragment
}
}
interface OnPublishArticleCommentListener{
fun onPublishClick(comment:String)
}
}
\ No newline at end of file
......@@ -40,7 +40,7 @@ class H5JsBean {
var isFromQingShu = 0//是否是从专家倾述主页跳转私聊界面 0: 不是 1:是
var docHead: String? = null//聊天头像
var doctorId: Int = 0//医生id
var confidedId: String?=null//医生id
var confidedId: String? = null//医生id
var listenerId: Int = 0
var orderStatus: Int = 0
var orderStatusDesc: String? = null
......@@ -65,7 +65,7 @@ class H5JsBean {
var succ: String? = null
var course_id: String? = null
var courseType: String? = null//课程类型:0 音频 1 视屏
var mediaType : String? = null//资料类型 1.音频 2.视频
var mediaType: String? = null//资料类型 1.音频 2.视频
var coursePlayUrl: String? = null//课程播放地址
var testResultId: Int? = 0
......@@ -73,6 +73,7 @@ class H5JsBean {
//群聊id
var tid: Int = 0
//专家id
var doctor_id: Int = 0
......@@ -114,66 +115,93 @@ class H5JsBean {
}
var test_items_id = 0
//倾诉线路类型
var confideType = 1 //1 axb 2双呼 3声网
//倾诉支付参数
var payTitle: String? = null
//订单金额
var orderPrice: Double? = null
//优惠金额
var coupnPrice: Double? = null
//测评题 优惠券金额
var couponMoney: String? = ""
//可用余额
var avliableMoney: Double? = null
//倾诉支付成功跳转地址
var confideUrl: String? = null
//打开与关闭右上角菜单
var toggleRightTopMenu: Int = 0 //0 关闭,1 打开
//打开与关闭分享菜单
var toggleShareMenu: Int = 0 //0 关闭,1 打开
//标识首页第几个tab
var selectTab:Int = 0
var selectTab: Int = 0
//倾诉拨打电话使用参数
var callType:String?=null
var callType: String? = null
var switchStatus = 1
var closeReplaceChat=false
var closeReplaceChat = false
var merchantType:String=""
var merchantType: String = ""
var day:String="" // 预约日期
var day: String = "" // 预约日期
// meditation start
// meditation start
// {"meditationId":21,"mediaId":15,"meditionType":1,"status":0,
// "coverImageUrl":"https://pic.ydlcdn.com/NsBRkaxNba.png",
// "title":"创建冥想-标题-20",
// "desc":"冥想测试数据基础入门1冥想测试数据基础入门1冥想测试数据基础入门1冥想测试数据基础入门1冥想测试数据基础入门1",
// "duration":250.9845}
var meditationId:Int?=null
var mediaId:Int?=null
var meditionType:Int?=null
var meditationId: Int? = null
var mediaId: Int? = null
var meditionType: Int? = null
var status = 0
var coverImageUrl:String?=null
var desc:String?=null
var mediaUrl:String?=null
var duration:Double?=null
var businessType:Int?=null
var share_url:String?=null
var cover:String?=null
var coverImageUrl: String? = null
var desc: String? = null
var mediaUrl: String? = null
var duration: Double? = null
var businessType: Int? = null
var share_url: String? = null
var cover: String? = null
var isDarkMode = false
var buried:String?=null
var buried: String? = null
val color:String?=null
val alpha:String?=null
val color: String? = null
val alpha: String? = null
// meditation end
var preview_type: Int = 0
var preview_index: Int = 0
val dataList: List<MediaInfo>? = null
var info: DoctorInfo? = null
}
}
class MediaInfo {
var url: String? = null
var sourcesType: Int = 0
var cover: String? = null
}
class DoctorInfo {
var doctorId: String? = null
var toUid: Int = 0
var utype: String? = null
}
}
......@@ -37,6 +37,7 @@ import com.umeng.socialize.bean.SHARE_MEDIA;
import com.ydl.utils.PopUtils;
import com.ydl.utils.ProxyCheckUtils;
import com.ydl.utils.WebUrlParamsUtils;
import com.ydl.view.ArticleDialogFragment;
import com.ydl.view.ShareMeditationDialog;
import com.ydl.ydl_router.manager.YDLRouterManager;
import com.ydl.ydlcommon.base.BaseActivity;
......@@ -128,6 +129,7 @@ public class NewH5Activity extends BaseActivity implements PtrHandler {
private boolean isDarkMode = false;
private ShareMeditationDialog shareMeditationDialog;
private ArticleDialogFragment commentArticleDialog;
protected PopupWindow popupWindow;
......@@ -1543,4 +1545,19 @@ public class NewH5Activity extends BaseActivity implements PtrHandler {
}
public void showCommentArticleDialog(String title){
if (commentArticleDialog == null) {
String titleStr = title==null?wv_content.getTitle():title;
commentArticleDialog = ArticleDialogFragment.newInstance(titleStr);
commentArticleDialog.setOnPublishListener(comment -> {
callJSFunc("sendComment('"+comment+"')");
});
}
if (commentArticleDialog != null && !commentArticleDialog.isAdded()) {
commentArticleDialog.show(getSupportFragmentManager(), "article_comment");
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
tools:ignore="MissingDefaultResource">
<translate
android:duration="@android:integer/config_mediumAnimTime"
android:fromYDelta="0"
android:interpolator="@android:anim/accelerate_interpolator"
android:toYDelta="100%p" />
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="@android:integer/config_mediumAnimTime"
android:fromYDelta="100%p"
android:interpolator="@android:anim/accelerate_interpolator"
android:toYDelta="0" />
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="4dp"/>
<solid android:color="#1DA1F2"/>
</shape>
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M-13,-228h375v813h-375z"
android:strokeWidth="1"
android:fillColor="#FAFAFB"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
<path
android:pathData="M-13,-76h375v333h-375z"
android:strokeWidth="1"
android:fillColor="#FFFFFF"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
<path
android:pathData="M-14,-246h376v854h-376z"
android:strokeAlpha="0.452821"
android:strokeWidth="1"
android:fillColor="#000000"
android:fillType="evenOdd"
android:strokeColor="#00000000"
android:fillAlpha="0.452821"/>
<path
android:pathData="M-5,-15L355,-15C359.4183,-15 363,-11.4183 363,-7L363,262L363,262L-13,262L-13,-7C-13,-11.4183 -9.4183,-15 -5,-15Z"
android:strokeWidth="1"
android:fillColor="#000000"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
<path
android:pathData="M-5,-15L355,-15C359.4183,-15 363,-11.4183 363,-7L363,262L363,262L-13,262L-13,-7C-13,-11.4183 -9.4183,-15 -5,-15Z"
android:strokeWidth="1"
android:fillColor="#FFFFFF"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
<path
android:pathData="M6.6504,17.4636L17.6504,6.4636M17.6504,17.4636L6.6504,6.4636"
android:strokeWidth="1.8"
android:fillColor="#00000000"
android:strokeColor="#242424"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
<path
android:pathData="M-13,-228h375v813h-375z"
android:strokeWidth="1"
android:fillColor="#FAFAFB"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
<path
android:pathData="M-13,-76h375v333h-375z"
android:strokeWidth="1"
android:fillColor="#FFFFFF"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
<path
android:pathData="M-14,-246h376v854h-376z"
android:strokeAlpha="0.452821"
android:strokeWidth="1"
android:fillColor="#000000"
android:fillType="evenOdd"
android:strokeColor="#00000000"
android:fillAlpha="0.452821"/>
<path
android:pathData="M-5,-15L355,-15C359.4183,-15 363,-11.4183 363,-7L363,262L363,262L-13,262L-13,-7C-13,-11.4183 -9.4183,-15 -5,-15Z"
android:strokeWidth="1"
android:fillColor="#000000"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
<path
android:pathData="M-5,-15L355,-15C359.4183,-15 363,-11.4183 363,-7L363,262L363,262L-13,262L-13,-7C-13,-11.4183 -9.4183,-15 -5,-15Z"
android:strokeWidth="1"
android:fillColor="#FFFFFF"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
<path
android:pathData="M6.6504,17.4636L17.6504,6.4636M17.6504,17.4636L6.6504,6.4636"
android:strokeWidth="1.8"
android:fillColor="#00000000"
android:strokeColor="#242424"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
</vector>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FFFFFFFF"/>
<corners
android:topLeftRadius="4dp"
android:topRightRadius="4dp"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/csl_root_layout">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/csl_comment_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_comment_article"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<ImageView
android:id="@+id/iv_close_dialog"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginTop="2dp"
android:padding="13dp"
android:src="@drawable/article_close_dialog"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发布评论"
android:textColor="#1C1F28"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@id/iv_close_dialog"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/iv_close_dialog" />
<TextView
android:id="@+id/tv_publish_comment"
android:layout_width="55dp"
android:layout_height="28dp"
android:layout_marginEnd="15dp"
android:background="@drawable/article_bg_publish"
android:gravity="center"
android:text="发布"
android:textColor="@color/white"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@id/iv_close_dialog"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/iv_close_dialog" />
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/et_article_comment"
android:layout_width="match_parent"
android:layout_height="240dp"
android:background="@null"
android:focusedByDefault="true"
android:gravity="start|top"
android:hint="说点什么吧..."
android:paddingHorizontal="20dp"
android:textColor="#1C1F28"
android:textColorHint="#C3C4CA"
android:textSize="16sp"
app:layout_constraintTop_toBottomOf="@id/iv_close_dialog"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
......@@ -9,4 +9,18 @@
</style>
<style name="BottomDialogAnimation" parent="Theme.Design.BottomSheetDialog">
<item name="android:windowIsFloating">true</item>
<item name="android:windowNoTitle">true</item>
<item name="android:background">@color/transparent</item>
<item name="android:windowBackground">@color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowFrame">@null</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowSoftInputMode">stateAlwaysVisible</item>
<item name="android:windowEnterAnimation">@anim/dialog_bottom_up</item>
<item name="android:windowExitAnimation">@anim/dialog_bottom_down</item>
</style>
</resources>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment